Skip to content

Commit

Permalink
Auto merge of #64127 - Centril:rollup-dfgb9h8, r=Centril
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #64049 (Emit a single error on if expr with expectation and no else clause)
 - #64056 (Account for arbitrary self types in E0599)
 - #64058 (librustc_errors: Extract sugg/subst handling into method)
 - #64071 (use just one name when parameters and fields are the same)
 - #64104 (Emit error on intrinsic to fn ptr casts)

Failed merges:

r? @ghost
  • Loading branch information
bors committed Sep 3, 2019
2 parents 815dec9 + 24e3b1d commit b9de4ef
Show file tree
Hide file tree
Showing 26 changed files with 269 additions and 145 deletions.
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

0 comments on commit b9de4ef

Please sign in to comment.