summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs498
1 files changed, 264 insertions, 234 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 1217d264a..dda7b2b2f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1,34 +1,40 @@
+mod ambiguity;
pub mod on_unimplemented;
pub mod suggestions;
use super::{
- FulfillmentContext, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
- Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
- OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
- SelectionContext, SelectionError, TraitNotObjectSafe,
+ FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause,
+ ObligationCauseCode, ObligationCtxt, OutputTypeParameterMismatch, Overflow,
+ PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
};
-
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::infer::{self, InferCtxt, TyCtxtInferExt};
-use rustc_data_structures::fx::FxHashMap;
+use crate::infer::{self, InferCtxt};
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::query::normalize::QueryNormalizeExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
+use crate::traits::NormalizeExt;
+use on_unimplemented::OnUnimplementedNote;
+use on_unimplemented::TypeErrCtxtExt as _;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan, Style,
};
use rustc_hir as hir;
+use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::GenericParam;
use rustc_hir::Item;
use rustc_hir::Node;
use rustc_infer::infer::error_reporting::TypeErrCtxt;
-use rustc_infer::infer::TypeTrace;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::print::{FmtPrinter, Print};
use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable,
@@ -40,11 +46,6 @@ use rustc_span::{ExpnKind, Span, DUMMY_SP};
use std::fmt;
use std::iter;
use std::ops::ControlFlow;
-
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::query::normalize::AtExt as _;
-use crate::traits::specialize::to_pretty_impl_header;
-use on_unimplemented::TypeErrCtxtExt as _;
use suggestions::TypeErrCtxtExt as _;
pub use rustc_infer::traits::error_reporting::*;
@@ -70,7 +71,7 @@ pub trait InferCtxtExt<'tcx> {
/// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>;
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>;
/// Reports an error when the number of arguments needed by a
/// trait match doesn't match the number that the expression
@@ -82,6 +83,7 @@ pub trait InferCtxtExt<'tcx> {
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
+ closure_pipe_span: Option<Span>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
@@ -97,24 +99,36 @@ pub trait InferCtxtExt<'tcx> {
}
pub trait TypeErrCtxtExt<'tcx> {
+ fn report_overflow_error<T>(
+ &self,
+ predicate: &T,
+ span: Span,
+ suggest_increasing_limit: bool,
+ mutate: impl FnOnce(&mut Diagnostic),
+ ) -> !
+ where
+ T: fmt::Display
+ + TypeFoldable<'tcx>
+ + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
+ <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
+
fn report_fulfillment_errors(
&self,
errors: &[FulfillmentError<'tcx>],
body_id: Option<hir::BodyId>,
- fallback_has_occurred: bool,
) -> ErrorGuaranteed;
- fn report_overflow_error<T>(
+ fn report_overflow_obligation<T>(
&self,
obligation: &Obligation<'tcx, T>,
suggest_increasing_limit: bool,
) -> !
where
- T: fmt::Display + TypeFoldable<'tcx>;
+ T: ToPredicate<'tcx> + Clone;
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
- fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
+ fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
/// The `root_obligation` parameter should be the `root_obligation` field
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
@@ -124,7 +138,6 @@ pub trait TypeErrCtxtExt<'tcx> {
obligation: PredicateObligation<'tcx>,
root_obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>,
- fallback_has_occurred: bool,
);
}
@@ -133,15 +146,16 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)> {
let sm = self.tcx.sess.source_map();
let hir = self.tcx.hir();
Some(match node {
Node::Expr(&hir::Expr {
- kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
+ kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }),
..
}) => (
fn_decl_span,
+ fn_arg_span,
hir.body(body)
.params
.iter()
@@ -172,6 +186,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
kind: hir::TraitItemKind::Fn(ref sig, _), ..
}) => (
sig.span,
+ None,
sig.decl
.inputs
.iter()
@@ -186,7 +201,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
),
Node::Ctor(ref variant_data) => {
let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
- (span, vec![ArgKind::empty(); variant_data.fields().len()])
+ (span, None, vec![ArgKind::empty(); variant_data.fields().len()])
}
_ => panic!("non-FnLike node found: {:?}", node),
})
@@ -202,6 +217,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
+ closure_arg_span: Option<Span>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let kind = if is_closure { "closure" } else { "function" };
@@ -239,24 +255,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
if let Some(found_span) = found_span {
err.span_label(found_span, format!("takes {}", found_str));
- // move |_| { ... }
- // ^^^^^^^^-- def_span
- //
- // move |_| { ... }
- // ^^^^^-- prefix
- let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
- // move |_| { ... }
- // ^^^-- pipe_span
- let pipe_span =
- if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
-
// Suggest to take and ignore the arguments with expected_args_length `_`s if
// found arguments is empty (assume the user just wants to ignore args in this case).
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
if found_args.is_empty() && is_closure {
let underscores = vec!["_"; expected_args.len()].join(", ");
err.span_suggestion_verbose(
- pipe_span,
+ closure_arg_span.unwrap_or(found_span),
&format!(
"consider changing the closure to take and ignore the expected argument{}",
pluralize!(expected_args.len())
@@ -344,22 +349,19 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
span: DUMMY_SP,
kind: TypeVariableOriginKind::MiscVariable,
});
- let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
+ let trait_ref = self.tcx.mk_trait_ref(trait_def_id, [ty.skip_binder(), var]);
let obligation = Obligation::new(
+ self.tcx,
ObligationCause::dummy(),
param_env,
- ty.rebind(ty::TraitPredicate {
- trait_ref: ty::TraitRef::new(trait_def_id, substs),
- constness,
- polarity,
- })
- .to_predicate(self.tcx),
+ ty.rebind(ty::TraitPredicate { trait_ref, constness, polarity }),
);
- let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
- fulfill_cx.register_predicate_obligation(self, obligation);
- if fulfill_cx.select_all_or_error(self).is_empty() {
+ let ocx = ObligationCtxt::new_in_snapshot(self);
+ ocx.register_obligation(obligation);
+ if ocx.select_all_or_error().is_empty() {
return Ok((
- ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
+ self.tcx
+ .fn_trait_kind_from_def_id(trait_def_id)
.expect("expected to map DefId to ClosureKind"),
ty.rebind(self.resolve_vars_if_possible(var)),
));
@@ -375,7 +377,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&self,
errors: &[FulfillmentError<'tcx>],
body_id: Option<hir::BodyId>,
- fallback_has_occurred: bool,
) -> ErrorGuaranteed {
#[derive(Debug)]
struct ErrorDescriptor<'tcx> {
@@ -383,7 +384,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
index: Option<usize>, // None if this is an old error
}
- let mut error_map: FxHashMap<_, Vec<_>> = self
+ let mut error_map: FxIndexMap<_, Vec<_>> = self
.reported_trait_errors
.borrow()
.iter()
@@ -452,7 +453,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
for (error, suppressed) in iter::zip(errors, is_suppressed) {
if !suppressed {
- self.report_fulfillment_error(error, body_id, fallback_has_occurred);
+ self.report_fulfillment_error(error, body_id);
}
}
@@ -467,39 +468,84 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
/// occurrences in any case.
fn report_overflow_error<T>(
&self,
- obligation: &Obligation<'tcx, T>,
+ predicate: &T,
+ span: Span,
suggest_increasing_limit: bool,
+ mutate: impl FnOnce(&mut Diagnostic),
) -> !
where
- T: fmt::Display + TypeFoldable<'tcx>,
+ T: fmt::Display
+ + TypeFoldable<'tcx>
+ + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
+ <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
{
- let predicate = self.resolve_vars_if_possible(obligation.predicate.clone());
+ let predicate = self.resolve_vars_if_possible(predicate.clone());
+ let mut pred_str = predicate.to_string();
+
+ if pred_str.len() > 50 {
+ // We don't need to save the type to a file, we will be talking about this type already
+ // in a separate note when we explain the obligation, so it will be available that way.
+ pred_str = predicate
+ .print(FmtPrinter::new_with_limit(
+ self.tcx,
+ Namespace::TypeNS,
+ rustc_session::Limit(6),
+ ))
+ .unwrap()
+ .into_buffer();
+ }
let mut err = struct_span_err!(
self.tcx.sess,
- obligation.cause.span,
+ span,
E0275,
"overflow evaluating the requirement `{}`",
- predicate
+ pred_str,
);
if suggest_increasing_limit {
self.suggest_new_overflow_limit(&mut err);
}
- self.note_obligation_cause_code(
- &mut err,
- &obligation.predicate,
- obligation.param_env,
- obligation.cause.code(),
- &mut vec![],
- &mut Default::default(),
- );
+ mutate(&mut err);
err.emit();
self.tcx.sess.abort_if_errors();
bug!();
}
+ /// Reports that an overflow has occurred and halts compilation. We
+ /// halt compilation unconditionally because it is important that
+ /// overflows never be masked -- they basically represent computations
+ /// whose result could not be truly determined and thus we can't say
+ /// if the program type checks or not -- and they are unusual
+ /// occurrences in any case.
+ fn report_overflow_obligation<T>(
+ &self,
+ obligation: &Obligation<'tcx, T>,
+ suggest_increasing_limit: bool,
+ ) -> !
+ where
+ T: ToPredicate<'tcx> + Clone,
+ {
+ let predicate = obligation.predicate.clone().to_predicate(self.tcx);
+ let predicate = self.resolve_vars_if_possible(predicate);
+ self.report_overflow_error(
+ &predicate,
+ obligation.cause.span,
+ suggest_increasing_limit,
+ |err| {
+ self.note_obligation_cause_code(
+ err,
+ &predicate,
+ obligation.param_env,
+ obligation.cause.code(),
+ &mut vec![],
+ &mut Default::default(),
+ );
+ },
+ );
+ }
+
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
let suggested_limit = match self.tcx.recursion_limit() {
Limit(0) => Limit(2),
@@ -514,11 +560,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
/// Reports that a cycle was detected which led to overflow and halts
- /// compilation. This is equivalent to `report_overflow_error` except
+ /// compilation. This is equivalent to `report_overflow_obligation` except
/// that we can give a more helpful error message (and, in particular,
/// we do not suggest increasing the overflow limit, which is not
/// going to help).
- fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
+ fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
let cycle = self.resolve_vars_if_possible(cycle.to_owned());
assert!(!cycle.is_empty());
@@ -526,7 +572,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// The 'deepest' obligation is most likely to have a useful
// cause 'backtrace'
- self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false);
+ self.report_overflow_obligation(
+ cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
+ false,
+ );
}
fn report_selection_error(
@@ -534,22 +583,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
mut obligation: PredicateObligation<'tcx>,
root_obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>,
- fallback_has_occurred: bool,
) {
- self.set_tainted_by_errors();
let tcx = self.tcx;
let mut span = obligation.cause.span;
+ // FIXME: statically guarantee this by tainting after the diagnostic is emitted
+ self.set_tainted_by_errors(
+ tcx.sess.delay_span_bug(span, "`report_selection_error` did not emit an error"),
+ );
let mut err = match *error {
- SelectionError::Ambiguous(ref impls) => {
- let mut err = self.tcx.sess.struct_span_err(
- obligation.cause.span,
- &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
- );
- self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
- err.emit();
- return;
- }
SelectionError::Unimplemented => {
// If this obligation was generated as a result of well-formedness checking, see if we
// can get a better error message by performing HIR-based well-formedness checking.
@@ -582,7 +624,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(trait_predicate) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
let trait_predicate = bound_predicate.rebind(trait_predicate);
let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate);
@@ -663,40 +705,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
))
);
- if is_try_conversion {
- let none_error = self
- .tcx
- .get_diagnostic_item(sym::none_error)
- .map(|def_id| tcx.type_of(def_id));
- let should_convert_option_to_result =
- Some(trait_ref.skip_binder().substs.type_at(1)) == none_error;
- let should_convert_result_to_option =
- Some(trait_ref.self_ty().skip_binder()) == none_error;
- if should_convert_option_to_result {
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- "consider converting the `Option<T>` into a `Result<T, _>` \
- using `Option::ok_or` or `Option::ok_or_else`",
- ".ok_or_else(|| /* error value */)",
- Applicability::HasPlaceholders,
- );
- } else if should_convert_result_to_option {
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- "consider converting the `Result<T, _>` into an `Option<T>` \
- using `Result::ok`",
- ".ok()",
- Applicability::MachineApplicable,
- );
- }
- if let Some(ret_span) = self.return_type_span(&obligation) {
- err.span_label(
- ret_span,
- &format!(
- "expected `{}` because of this",
- trait_ref.skip_binder().self_ty()
- ),
- );
+ if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
+ err.span_label(
+ ret_span,
+ &format!(
+ "expected `{}` because of this",
+ trait_ref.skip_binder().self_ty()
+ ),
+ );
+ }
+
+ if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
+ match obligation.cause.code().peel_derives() {
+ ObligationCauseCode::RustCall => {
+ err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
+ }
+ ObligationCauseCode::BindingObligation(def_id, _)
+ | ObligationCauseCode::ItemObligation(def_id)
+ if tcx.is_fn_trait(*def_id) =>
+ {
+ err.code(rustc_errors::error_code!(E0059));
+ err.set_primary_message(format!(
+ "type parameter to bare `{}` trait must be a tuple",
+ tcx.def_path_str(*def_id)
+ ));
+ }
+ _ => {}
}
}
@@ -848,12 +882,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}
- let is_fn_trait = [
- self.tcx.lang_items().fn_trait(),
- self.tcx.lang_items().fn_mut_trait(),
- self.tcx.lang_items().fn_once_trait(),
- ]
- .contains(&Some(trait_ref.def_id()));
+ let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id());
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
*trait_ref.skip_binder().self_ty().kind()
{
@@ -883,7 +912,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
// to implement.
let selected_kind =
- ty::ClosureKind::from_def_id(self.tcx, trait_ref.def_id())
+ self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
.expect("expected to map DefId to ClosureKind");
if !implemented_kind.extends(selected_kind) {
err.note(
@@ -974,7 +1003,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// useful for less general traits.
if peeled
&& !self.tcx.trait_is_auto(def_id)
- && !self.tcx.lang_items().items().contains(&Some(def_id))
+ && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
{
let trait_ref = trait_pred.to_poly_trait_ref();
let impl_candidates =
@@ -1000,16 +1029,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// variable that used to fallback to `()` now falling back to `!`. Issue a
// note informing about the change in behaviour.
if trait_predicate.skip_binder().self_ty().is_never()
- && fallback_has_occurred
+ && self.fallback_has_occurred
{
- let predicate = trait_predicate.map_bound(|mut trait_pred| {
- trait_pred.trait_ref.substs = self.tcx.mk_substs_trait(
- self.tcx.mk_unit(),
- &trait_pred.trait_ref.substs[1..],
- );
- trait_pred
+ let predicate = trait_predicate.map_bound(|trait_pred| {
+ trait_pred.with_self_type(self.tcx, self.tcx.mk_unit())
});
- let unit_obligation = obligation.with(predicate.to_predicate(tcx));
+ let unit_obligation = obligation.with(tcx, predicate);
if self.predicate_may_hold(&unit_obligation) {
err.note(
"this error might have been caused by changes to \
@@ -1062,9 +1087,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
}
- ty::PredicateKind::RegionOutlives(..)
- | ty::PredicateKind::Projection(..)
- | ty::PredicateKind::TypeOutlives(..) => {
+ ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
+ | ty::PredicateKind::Clause(ty::Clause::Projection(..))
+ | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => {
let predicate = self.resolve_vars_if_possible(obligation.predicate);
struct_span_err!(
self.tcx.sess,
@@ -1177,6 +1202,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
}
+ ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
+
ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
span,
"TypeWellFormedFromEnv predicate should only exist in the environment"
@@ -1260,13 +1287,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
obligation.cause.code(),
)
} else {
- let (closure_span, found) = found_did
+ let (closure_span, closure_arg_span, found) = found_did
.and_then(|did| {
let node = self.tcx.hir().get_if_local(did)?;
- let (found_span, found) = self.get_fn_like_arguments(node)?;
- Some((Some(found_span), found))
+ let (found_span, closure_arg_span, found) =
+ self.get_fn_like_arguments(node)?;
+ Some((Some(found_span), closure_arg_span, found))
})
- .unwrap_or((found_span, found));
+ .unwrap_or((found_span, None, found));
self.report_arg_count_mismatch(
span,
@@ -1274,6 +1302,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
expected,
found,
found_trait_ty.is_closure(),
+ closure_arg_span,
)
}
}
@@ -1366,7 +1395,6 @@ trait InferCtxtPrivExt<'tcx> {
&self,
error: &FulfillmentError<'tcx>,
body_id: Option<hir::BodyId>,
- fallback_has_occurred: bool,
);
fn report_projection_error(
@@ -1483,9 +1511,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// FIXME: It should be possible to deal with `ForAll` in a cleaner way.
let bound_error = error.kind();
let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) {
- (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error)) => {
- (cond, bound_error.rebind(error))
- }
+ (
+ ty::PredicateKind::Clause(ty::Clause::Trait(..)),
+ ty::PredicateKind::Clause(ty::Clause::Trait(error)),
+ ) => (cond, bound_error.rebind(error)),
_ => {
// FIXME: make this work in other cases too.
return false;
@@ -1494,7 +1523,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
let bound_predicate = obligation.predicate.kind();
- if let ty::PredicateKind::Trait(implication) = bound_predicate.skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(implication)) =
+ bound_predicate.skip_binder()
+ {
let error = error.to_poly_trait_ref();
let implication = bound_predicate.rebind(implication.trait_ref);
// FIXME: I'm just not taking associated types at all here.
@@ -1516,7 +1547,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&self,
error: &FulfillmentError<'tcx>,
body_id: Option<hir::BodyId>,
- fallback_has_occurred: bool,
) {
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
@@ -1524,7 +1554,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
error.obligation.clone(),
&error.root_obligation,
selection_error,
- fallback_has_occurred,
);
}
FulfillmentErrorCode::CodeProjectionError(ref e) => {
@@ -1567,7 +1596,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
diag.emit();
}
FulfillmentErrorCode::CodeCycle(ref cycle) => {
- self.report_overflow_error_cycle(cycle);
+ self.report_overflow_obligation_cycle(cycle);
}
}
}
@@ -1585,29 +1614,26 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
self.probe(|_| {
- let mut err = error.err;
- let mut values = None;
+ let ocx = ObligationCtxt::new_in_snapshot(self);
// try to find the mismatched types to report the error with.
//
// this can fail if the problem was higher-ranked, in which
// cause I have no idea for a good error message.
let bound_predicate = predicate.kind();
- if let ty::PredicateKind::Projection(data) = bound_predicate.skip_binder() {
- let mut selcx = SelectionContext::new(self);
+ let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
+ bound_predicate.skip_binder()
+ {
let data = self.replace_bound_vars_with_fresh_vars(
obligation.cause.span,
infer::LateBoundRegionConversionTime::HigherRankedType,
bound_predicate.rebind(data),
);
- let mut obligations = vec![];
- let normalized_ty = super::normalize_projection_type(
- &mut selcx,
+ let normalized_ty = ocx.normalize(
+ &obligation.cause,
obligation.param_env,
- data.projection_ty,
- obligation.cause.clone(),
- 0,
- &mut obligations,
+ self.tcx
+ .mk_projection(data.projection_ty.item_def_id, data.projection_ty.substs),
);
debug!(?obligation.cause, ?obligation.param_env);
@@ -1623,25 +1649,40 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::ObjectCastObligation(..)
| ObligationCauseCode::OpaqueType
);
- if let Err(new_err) = self.at(&obligation.cause, obligation.param_env).eq_exp(
+ let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error());
+
+ // constrain inference variables a bit more to nested obligations from normalize so
+ // we can have more helpful errors.
+ ocx.select_where_possible();
+
+ if let Err(new_err) = ocx.eq_exp(
+ &obligation.cause,
+ obligation.param_env,
is_normalized_ty_expected,
normalized_ty,
- data.term,
+ expected_ty,
) {
- values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
- err = new_err;
+ (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err)
+ } else {
+ (None, error.err)
}
- }
+ } else {
+ (None, error.err)
+ };
let msg = values
.and_then(|(predicate, _, normalized_ty, expected_ty)| {
- self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
+ self.maybe_detailed_projection_msg(
+ predicate,
+ normalized_ty.into(),
+ expected_ty.into(),
+ )
})
.unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
let secondary_span = match predicate.kind().skip_binder() {
- ty::PredicateKind::Projection(proj) => self
+ ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self
.tcx
.opt_associated_item(proj.projection_ty.item_def_id)
.and_then(|trait_assoc_item| {
@@ -1677,11 +1718,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&mut diag,
&obligation.cause,
secondary_span,
- values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
+ values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
infer::ValuePairs::Terms(ExpectedFound::new(
is_normalized_ty_expected,
- normalized_ty,
- term,
+ normalized_ty.into(),
+ expected_ty.into(),
))
}),
err,
@@ -1733,7 +1774,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Bool => Some(0),
ty::Char => Some(1),
ty::Str => Some(2),
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did()) => Some(2),
+ ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => Some(2),
ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
@@ -1811,7 +1852,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&self,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Vec<ImplCandidate<'tcx>> {
- self.tcx
+ let mut candidates: Vec<_> = self
+ .tcx
.all_impls(trait_pred.def_id())
.filter_map(|def_id| {
if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
@@ -1827,7 +1869,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
.map(|similarity| ImplCandidate { trait_ref: imp, similarity })
})
- .collect()
+ .collect();
+ if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
+ // If any of the candidates is a perfect match, we don't want to show all of them.
+ // This is particularly relevant for the case of numeric types (as they all have the
+ // same cathegory).
+ candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
+ }
+ candidates
}
fn report_similar_impl_candidates(
@@ -1898,7 +1947,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let def_id = trait_ref.def_id();
if impl_candidates.is_empty() {
if self.tcx.trait_is_auto(def_id)
- || self.tcx.lang_items().items().contains(&Some(def_id))
+ || self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
|| self.tcx.get_diagnostic_name(def_id).is_some()
{
// Mentioning implementers of `Copy`, `Debug` and friends is not useful.
@@ -1935,14 +1984,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return report(normalized_impl_candidates, err);
}
- let normalize = |candidate| {
- let infcx = self.tcx.infer_ctxt().build();
- infcx
- .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
- .normalize(candidate)
- .map_or(candidate, |normalized| normalized.value)
- };
-
// Sort impl candidates so that ordering is consistent for UI tests.
// because the ordering of `impl_candidates` may not be deterministic:
// https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
@@ -1952,7 +1993,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut normalized_impl_candidates_and_similarities = impl_candidates
.into_iter()
.map(|ImplCandidate { trait_ref, similarity }| {
- let normalized = normalize(trait_ref);
+ // FIXME(compiler-errors): This should be using `NormalizeExt::normalize`
+ let normalized = self
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .query_normalize(trait_ref)
+ .map_or(trait_ref, |normalized| normalized.value);
(similarity, normalized)
})
.collect::<Vec<_>>();
@@ -2032,15 +2077,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
) -> PredicateObligation<'tcx> {
- let trait_pred = trait_ref_and_ty.map_bound_ref(|(tr, new_self_ty)| ty::TraitPredicate {
- trait_ref: ty::TraitRef {
- substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]),
- ..tr.trait_ref
- },
- ..*tr
- });
+ let trait_pred = trait_ref_and_ty
+ .map_bound(|(tr, new_self_ty)| tr.with_self_type(self.tcx, new_self_ty));
- Obligation::new(ObligationCause::dummy(), param_env, trait_pred.to_predicate(self.tcx))
+ Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
}
#[instrument(skip(self), level = "debug")]
@@ -2064,7 +2104,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(data) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
let trait_ref = bound_predicate.rebind(data.trait_ref);
debug!(?trait_ref);
@@ -2088,7 +2128,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
- if !self.is_tainted_by_errors() {
+ if let None = self.tainted_by_errors() {
self.emit_inference_failure_err(
body_id,
span,
@@ -2128,21 +2168,27 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
};
- let obligation = Obligation::new(
- obligation.cause.clone(),
- obligation.param_env,
- trait_ref.to_poly_trait_predicate(),
- );
- let mut selcx = SelectionContext::with_query_mode(
- &self,
- crate::traits::TraitQueryMode::Standard,
- );
+ let obligation = obligation.with(self.tcx, trait_ref);
+ let mut selcx = SelectionContext::new(&self);
match selcx.select_from_obligation(&obligation) {
- Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
- self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ Ok(None) => {
+ let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
+ let has_non_region_infer =
+ trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
+ // It doesn't make sense to talk about applicable impls if there are more
+ // than a handful of them.
+ if impls.len() > 1 && impls.len() < 5 && has_non_region_infer {
+ self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ } else {
+ if self.tainted_by_errors().is_some() {
+ err.cancel();
+ return;
+ }
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
}
_ => {
- if self.is_tainted_by_errors() {
+ if self.tainted_by_errors().is_some() {
err.cancel();
return;
}
@@ -2160,7 +2206,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if generics.params.iter().any(|p| p.name != kw::SelfUpper)
&& !snippet.ends_with('>')
&& !generics.has_impl_trait()
- && !self.tcx.fn_trait_kind_from_lang_item(def_id).is_some()
+ && !self.tcx.is_fn_trait(def_id)
{
// FIXME: To avoid spurious suggestions in functions where type arguments
// where already supplied, we check the snippet to make sure it doesn't
@@ -2245,7 +2291,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
] = path.segments
&& data.trait_ref.def_id == *trait_id
&& self.tcx.trait_of_item(*item_id) == Some(*trait_id)
- && !self.is_tainted_by_errors()
+ && let None = self.tainted_by_errors()
{
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
ty::AssocKind::Const => ("refer to the", "constant"),
@@ -2314,7 +2360,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// with error messages.
if arg.references_error()
|| self.tcx.sess.has_errors().is_some()
- || self.is_tainted_by_errors()
+ || self.tainted_by_errors().is_some()
{
return;
}
@@ -2325,7 +2371,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::Subtype(data) => {
if data.references_error()
|| self.tcx.sess.has_errors().is_some()
- || self.is_tainted_by_errors()
+ || self.tainted_by_errors().is_some()
{
// no need to overload user in such cases
return;
@@ -2335,8 +2381,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
assert!(a.is_ty_var() && b.is_ty_var());
self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true)
}
- ty::PredicateKind::Projection(data) => {
- if predicate.references_error() || self.is_tainted_by_errors() {
+ ty::PredicateKind::Clause(ty::Clause::Projection(data)) => {
+ if predicate.references_error() || self.tainted_by_errors().is_some() {
return;
}
let subst = data
@@ -2370,7 +2416,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
ty::PredicateKind::ConstEvaluatable(data) => {
- if predicate.references_error() || self.is_tainted_by_errors() {
+ if predicate.references_error() || self.tainted_by_errors().is_some() {
return;
}
let subst = data.walk().find(|g| g.is_non_region_infer());
@@ -2397,7 +2443,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
_ => {
- if self.tcx.sess.has_errors().is_some() || self.is_tainted_by_errors() {
+ if self.tcx.sess.has_errors().is_some() || self.tainted_by_errors().is_some() {
return;
}
let mut err = struct_span_err!(
@@ -2435,14 +2481,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
}
- let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
crate_names.sort();
crate_names.dedup();
post.sort();
post.dedup();
- if self.is_tainted_by_errors()
+ if self.tainted_by_errors().is_some()
&& (crate_names.len() == 1
&& spans.len() == 0
&& ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
@@ -2456,13 +2501,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.downgrade_to_delayed_bug();
return;
}
- let post = if post.len() > 4 {
- format!(
- ":\n{}\nand {} more",
- post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
- post.len() - 4,
- )
- } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+
+ let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+ let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
} else if post.len() == 1 {
format!(": `{}`", post[0])
@@ -2541,24 +2582,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
self.probe(|_| {
- let mut selcx = SelectionContext::new(self);
-
let cleaned_pred =
pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
- let cleaned_pred = super::project::normalize(
- &mut selcx,
- param_env,
- ObligationCause::dummy(),
- cleaned_pred,
- )
- .value;
-
- let obligation = Obligation::new(
- ObligationCause::dummy(),
- param_env,
- cleaned_pred.to_predicate(selcx.tcx()),
- );
+ let InferOk { value: cleaned_pred, .. } =
+ self.infcx.at(&ObligationCause::dummy(), param_env).normalize(cleaned_pred);
+
+ let obligation =
+ Obligation::new(self.tcx, ObligationCause::dummy(), param_env, cleaned_pred);
self.predicate_may_hold(&obligation)
})
@@ -2586,7 +2617,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err: &mut Diagnostic,
obligation: &PredicateObligation<'tcx>,
) {
- let ty::PredicateKind::Trait(pred) = obligation.predicate.kind().skip_binder() else { return; };
+ let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = obligation.predicate.kind().skip_binder() else { return; };
let (ObligationCauseCode::BindingObligation(item_def_id, span)
| ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..))
= *obligation.cause.code().peel_derives() else { return; };
@@ -2612,11 +2643,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let Some(param) = generics.params.iter().find(|param| param.span == span) else {
return;
};
- let param_def_id = self.tcx.hir().local_def_id(param.hir_id);
// Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
// `Sized` bound is there intentionally and we don't need to suggest relaxing it.
let explicitly_sized = generics
- .bounds_for_param(param_def_id)
+ .bounds_for_param(param.def_id)
.flat_map(|bp| bp.bounds)
.any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
if explicitly_sized {
@@ -2639,7 +2669,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => {}
};
// Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
- let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param_def_id)
+ let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param.def_id)
{
(s, " +")
} else {