use super::{
FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause,
- ObligationCauseCode, OutputTypeParameterMismatch, Overflow, PredicateObligation,
- SelectionContext, SelectionError, TraitNotObjectSafe,
+ 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 crate::traits::engine::TraitEngineExt as _;
+use crate::infer::{self, InferCtxt};
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::query::normalize::AtExt 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};
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,
/// 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
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`
suggest_increasing_limit: bool,
) -> !
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;
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
/// 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()
kind: hir::TraitItemKind::Fn(ref sig, _), ..
}) => (
sig.span,
+ None,
sig.decl
.inputs
.iter()
),
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),
})
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" };
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())
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,
- }),
+ ty.rebind(ty::TraitPredicate { trait_ref, constness, polarity }),
);
- let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx);
- 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)),
));
suggest_increasing_limit: bool,
) -> !
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 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,
E0275,
"overflow evaluating the requirement `{}`",
- predicate
+ pred_str,
);
if suggest_increasing_limit {
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);
}
ObligationCauseCode::BindingObligation(def_id, _)
| ObligationCauseCode::ItemObligation(def_id)
- if ty::ClosureKind::from_def_id(tcx, *def_id).is_some() =>
+ if tcx.is_fn_trait(*def_id) =>
{
err.code(rustc_errors::error_code!(E0059));
err.set_primary_message(format!(
);
}
- let is_fn_trait =
- ty::ClosureKind::from_def_id(tcx, trait_ref.def_id()).is_some();
+ 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()
{
// 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(
if trait_predicate.skip_binder().self_ty().is_never()
&& 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(tcx, predicate);
if self.predicate_may_hold(&unit_obligation) {
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,
)
}
+ ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
+
ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
span,
"TypeWellFormedFromEnv predicate should only exist in the environment"
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,
expected,
found,
found_trait_ty.is_closure(),
+ closure_arg_span,
)
}
}
// 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;
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.
}
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);
| 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();
+
+ // 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| {
&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,
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(..)
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
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<_>>();
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(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
}
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);
)
};
- let obligation = obligation.with(self.tcx, 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) {
Ok(None) => {
let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
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
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) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(data)) => {
if predicate.references_error() || self.tainted_by_errors().is_some() {
return;
}
}
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 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);
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; };