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};
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;
/// 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`
/// 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())
param_env,
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)),
));
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(
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,
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<_>>();
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; };