Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #64127

Merged
merged 13 commits into from
Sep 3, 2019
Merged
3 changes: 3 additions & 0 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1636,6 +1636,9 @@ impl<'tcx> ObligationCause<'tcx> {
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
Error0644("closure/generator type that references itself")
}
TypeError::IntrinsicCast => {
Error0308("cannot coerce intrinsics to function pointers")
}
_ => Error0308("mismatched types"),
},
}
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2402,6 +2402,12 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_generic_adt(def_id, ty)
}

#[inline]
pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Ty<'tcx> {
let def_id = self.require_lang_item(item, None);
self.mk_generic_adt(def_id, ty)
}

#[inline]
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None);
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub enum TypeError<'tcx> {
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),

ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),

IntrinsicCast,
}

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
Expand Down Expand Up @@ -179,6 +181,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
ConstMismatch(ref values) => {
write!(f, "expected `{}`, found `{}`", values.expected, values.found)
}
IntrinsicCast => {
write!(f, "cannot coerce intrinsics to function pointers")
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
Sorts(ref x) => return tcx.lift(x).map(Sorts),
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
IntrinsicCast => IntrinsicCast,
})
}
}
Expand Down Expand Up @@ -1338,6 +1339,7 @@ EnumTypeFoldableImpl! {
(ty::error::TypeError::Sorts)(x),
(ty::error::TypeError::ExistentialMismatch)(x),
(ty::error::TypeError::ConstMismatch)(x),
(ty::error::TypeError::IntrinsicCast),
}
}

Expand Down
4 changes: 1 addition & 3 deletions src/librustc_errors/annotate_snippet_emitter_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@ pub struct AnnotateSnippetEmitterWriter {
impl Emitter for AnnotateSnippetEmitterWriter {
/// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
let primary_span = db.span.clone();
let children = db.children.clone();
// FIXME(#59346): Collect suggestions (see emitter.rs)
let suggestions: &[_] = &[];
let (primary_span, suggestions) = self.primary_span_formatted(&db);

// FIXME(#59346): Add `fix_multispans_in_std_macros` function from emitter.rs

Expand Down
40 changes: 31 additions & 9 deletions src/librustc_errors/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,25 @@ pub trait Emitter {
fn should_show_explain(&self) -> bool {
true
}
}

impl Emitter for EmitterWriter {
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
/// Formats the substitutions of the primary_span
///
/// The are a lot of conditions to this method, but in short:
///
/// * If the current `Diagnostic` has only one visible `CodeSuggestion`,
/// we format the `help` suggestion depending on the content of the
/// substitutions. In that case, we return the modified span only.
///
/// * If the current `Diagnostic` has multiple suggestions,
/// we return the original `primary_span` and the original suggestions.
fn primary_span_formatted<'a>(
&mut self,
db: &'a DiagnosticBuilder<'_>
) -> (MultiSpan, &'a [CodeSuggestion]) {
let mut primary_span = db.span.clone();
let mut children = db.children.clone();
let mut suggestions: &[_] = &[];

if let Some((sugg, rest)) = db.suggestions.split_first() {
if rest.is_empty() &&
// ^ if there is only one suggestion
// don't display multi-suggestions as labels
sugg.substitutions.len() == 1 &&
// don't display multipart suggestions as labels
Expand All @@ -216,21 +225,34 @@ impl Emitter for EmitterWriter {
{
let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
let msg = if substitution.len() == 0 || sugg.style.hide_inline() {
// This substitution is only removal or we explicitly don't want to show the
// code inline, don't show it
// This substitution is only removal OR we explicitly don't want to show the
// code inline (`hide_inline`). Therefore, we don't show the substitution.
format!("help: {}", sugg.msg)
} else {
// Show the default suggestion text with the substitution
format!("help: {}: `{}`", sugg.msg, substitution)
};
primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);

// We return only the modified primary_span
(primary_span, &[])
} else {
// if there are multiple suggestions, print them all in full
// to be consistent. We could try to figure out if we can
// make one (or the first one) inline, but that would give
// undue importance to a semi-random suggestion
suggestions = &db.suggestions;
(primary_span, &db.suggestions)
}
} else {
(primary_span, &db.suggestions)
}
}
}

impl Emitter for EmitterWriter {
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
let mut children = db.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(&db);

self.fix_multispans_in_std_macros(&mut primary_span,
&mut children,
Expand Down
30 changes: 21 additions & 9 deletions src/librustc_typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,19 +112,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

self.diverges.set(pats_diverge);
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
let arm_ty = if source_if && if_no_else && i != 0 && self.if_fallback_coercion(
expr.span,
&arms[0].body,
&mut coercion,
) {
tcx.types.err
} else {
// Only call this if this is not an `if` expr with an expected type and no `else`
// clause to avoid duplicated type errors. (#60254)
self.check_expr_with_expectation(&arm.body, expected)
};
all_arms_diverge &= self.diverges.get();

let span = expr.span;

if source_if {
let then_expr = &arms[0].body;
match (i, if_no_else) {
(0, _) => coercion.coerce(self, &self.misc(span), &arm.body, arm_ty),
(_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion),
(0, _) => coercion.coerce(self, &self.misc(expr.span), &arm.body, arm_ty),
(_, true) => {} // Handled above to avoid duplicated type errors (#60254).
(_, _) => {
let then_ty = prior_arm_ty.unwrap();
let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty);
let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty);
coercion.coerce(self, &cause, &arm.body, arm_ty);
}
}
Expand All @@ -139,7 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// The reason for the first arm to fail is not that the match arms diverge,
// but rather that there's a prior obligation that doesn't hold.
0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
_ => (span, ObligationCauseCode::MatchExpressionArm {
_ => (expr.span, ObligationCauseCode::MatchExpressionArm {
arm_span,
source: match_src,
prior_arms: other_arms.clone(),
Expand Down Expand Up @@ -180,16 +187,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

/// Handle the fallback arm of a desugared if(-let) like a missing else.
///
/// Returns `true` if there was an error forcing the coercion to the `()` type.
fn if_fallback_coercion(
&self,
span: Span,
then_expr: &'tcx hir::Expr,
coercion: &mut CoerceMany<'tcx, '_, rustc::hir::Arm>,
) {
) -> bool {
// If this `if` expr is the parent's function return expr,
// the cause of the type coercion is the return type, point at it. (#25228)
let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span);
let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse);
let mut error = false;
coercion.coerce_forced_unit(self, &cause, &mut |err| {
if let Some((span, msg)) = &ret_reason {
err.span_label(*span, msg.as_str());
Expand All @@ -200,7 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
err.note("`if` expressions without `else` evaluate to `()`");
err.help("consider adding an `else` block that evaluates to the expected type");
error = true;
}, ret_reason.is_none());
error
}

fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> {
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_typeck/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use rustc::ty::{self, Ty, TypeFoldable, TypeAndMut};
use rustc::ty::subst::SubstsRef;
use rustc::ty::adjustment::AllowTwoPhase;
use rustc::ty::cast::{CastKind, CastTy};
use rustc::ty::error::TypeError;
use rustc::middle::lang_items;
use syntax::ast;
use syntax_pos::Span;
Expand Down Expand Up @@ -461,6 +462,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
self.expr_ty,
fcx.tcx.mk_fn_ptr(f),
AllowTwoPhase::No);
if let Err(TypeError::IntrinsicCast) = res {
return Err(CastError::IllegalCast);
}
if res.is_err() {
return Err(CastError::NonScalar);
}
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ use std::ops::Deref;
use syntax::feature_gate;
use syntax::symbol::sym;
use syntax_pos;
use rustc_target::spec::abi::Abi;

struct Coerce<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
Expand Down Expand Up @@ -689,6 +690,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
match b.sty {
ty::FnPtr(_) => {
let a_sig = a.fn_sig(self.tcx);
// Intrinsics are not coercible to function pointers
if a_sig.abi() == Abi::RustIntrinsic ||
a_sig.abi() == Abi::PlatformIntrinsic {
return Err(TypeError::IntrinsicCast);
}
let InferOk { value: a_sig, mut obligations } =
self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig);

Expand Down
88 changes: 68 additions & 20 deletions src/librustc_typeck/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::check::fatally_break_rust;
use crate::check::report_unexpected_variant_res;
use crate::check::Needs;
use crate::check::TupleArgumentsFlag::DontTupleArguments;
use crate::check::method::SelfSource;
use crate::check::method::{probe, SelfSource, MethodError};
use crate::util::common::ErrorReported;
use crate::util::nodemap::FxHashMap;
use crate::astconv::AstConv as _;
Expand All @@ -29,6 +29,7 @@ use rustc::hir::def::{CtorKind, Res, DefKind};
use rustc::hir::ptr::P;
use rustc::infer;
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc::middle::lang_items;
use rustc::mir::interpret::GlobalId;
use rustc::ty;
use rustc::ty::adjustment::{
Expand Down Expand Up @@ -775,35 +776,80 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// no need to check for bot/err -- callee does that
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);

let method = match self.lookup_method(rcvr_t,
segment,
span,
expr,
rcvr) {
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
Ok(method) => {
self.write_method_call(expr.hir_id, method);
Ok(method)
}
Err(error) => {
if segment.ident.name != kw::Invalid {
self.report_method_error(span,
rcvr_t,
segment.ident,
SelfSource::MethodCall(rcvr),
error,
Some(args));
self.report_extended_method_error(segment, span, args, rcvr_t, error);
}
Err(())
}
};

// Call the generic checker.
self.check_method_argument_types(span,
expr.span,
method,
&args[1..],
DontTupleArguments,
expected)
self.check_method_argument_types(
span,
expr.span,
method,
&args[1..],
DontTupleArguments,
expected,
)
}

fn report_extended_method_error(
&self,
segment: &hir::PathSegment,
span: Span,
args: &'tcx [hir::Expr],
rcvr_t: Ty<'tcx>,
error: MethodError<'tcx>
) {
let rcvr = &args[0];
let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| {
if let Ok(pick) = self.lookup_probe(
span,
segment.ident,
new_rcvr_t,
rcvr,
probe::ProbeScope::AllTraits,
) {
err.span_label(
pick.item.ident.span,
&format!("the method is available for `{}` here", new_rcvr_t),
);
}
};

if let Some(mut err) = self.report_method_error(
span,
rcvr_t,
segment.ident,
SelfSource::MethodCall(rcvr),
error,
Some(args),
) {
if let ty::Adt(..) = rcvr_t.sty {
// Try alternative arbitrary self types that could fulfill this call.
// FIXME: probe for all types that *could* be arbitrary self-types, not
// just this whitelist.
let box_rcvr_t = self.tcx.mk_box(rcvr_t);
try_alt_rcvr(&mut err, box_rcvr_t);
let pin_rcvr_t = self.tcx.mk_lang_item(
rcvr_t,
lang_items::PinTypeLangItem,
);
try_alt_rcvr(&mut err, pin_rcvr_t);
let arc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Arc);
try_alt_rcvr(&mut err, arc_rcvr_t);
let rc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Rc);
try_alt_rcvr(&mut err, rc_rcvr_t);
}
err.emit();
}
}

fn check_expr_cast(
Expand Down Expand Up @@ -1466,8 +1512,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let struct_variant_def = def.non_enum_variant();
let field_names = self.available_field_names(struct_variant_def);
if !field_names.is_empty() {
err.note(&format!("available fields are: {}",
self.name_series_display(field_names)));
err.note(&format!(
"available fields are: {}",
self.name_series_display(field_names),
));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(result.callee)
}

fn lookup_probe(
pub fn lookup_probe(
&self,
span: Span,
method_name: ast::Ident,
Expand Down
Loading