X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_trait_selection%2Fsrc%2Ftraits%2Ferror_reporting%2Fmod.rs;h=e8468567cba0f9d220a6069a9df0181fcabbeaa9;hb=7481ba7746fc5f5b82aaff0fe20cbf55c48d8fd9;hp=ef3d300020a39086edaa7cb0f0a2ee80c20f83ba;hpb=37c352159755d8c7c9a35c653af3d4141c7d2680;p=rust.git 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 ef3d300020a..3379279dd15 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -4,16 +4,16 @@ 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}; @@ -29,8 +29,7 @@ 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; @@ -72,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)>; + fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option, Vec)>; /// Reports an error when the number of arguments needed by a /// trait match doesn't match the number that the expression @@ -84,6 +83,7 @@ fn report_arg_count_mismatch( expected_args: Vec, found_args: Vec, is_closure: bool, + closure_pipe_span: Option, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` @@ -136,15 +136,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)> { + fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option, Vec)> { 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() @@ -175,6 +176,7 @@ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec)> kind: hir::TraitItemKind::Fn(ref sig, _), .. }) => ( sig.span, + None, sig.decl .inputs .iter() @@ -189,7 +191,7 @@ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec)> ), 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), }) @@ -205,6 +207,7 @@ fn report_arg_count_mismatch( expected_args: Vec, found_args: Vec, is_closure: bool, + closure_arg_span: Option, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let kind = if is_closure { "closure" } else { "function" }; @@ -242,24 +245,13 @@ fn report_arg_count_mismatch( 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()) @@ -354,11 +346,12 @@ fn type_implements_fn_trait( param_env, ty.rebind(ty::TraitPredicate { trait_ref, constness, polarity }), ); - let mut fulfill_cx = >::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)), )); @@ -589,7 +582,7 @@ fn report_selection_error( 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); @@ -687,7 +680,7 @@ fn report_selection_error( } 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!( @@ -847,8 +840,7 @@ fn report_selection_error( ); } - 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() { @@ -878,7 +870,7 @@ fn report_selection_error( // 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( @@ -1053,9 +1045,9 @@ fn report_selection_error( 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, @@ -1253,13 +1245,14 @@ fn report_selection_error( 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, @@ -1267,6 +1260,7 @@ fn report_selection_error( expected, found, found_trait_ty.is_closure(), + closure_arg_span, ) } } @@ -1475,9 +1469,10 @@ fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'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; @@ -1486,7 +1481,9 @@ fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'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. @@ -1575,29 +1572,26 @@ fn report_projection_error( } 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); @@ -1613,25 +1607,40 @@ fn report_projection_error( | 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| { @@ -1667,11 +1676,11 @@ fn report_projection_error( &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, @@ -1925,14 +1934,6 @@ fn report_similar_impl_candidates( 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 @@ -1942,7 +1943,11 @@ fn report_similar_impl_candidates( 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::>(); @@ -2049,7 +2054,7 @@ fn maybe_report_ambiguity( 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); @@ -2113,11 +2118,8 @@ fn maybe_report_ambiguity( ) }; - 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); @@ -2154,7 +2156,7 @@ fn maybe_report_ambiguity( 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 @@ -2329,7 +2331,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { 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; } @@ -2530,18 +2532,11 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'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 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); @@ -2572,7 +2567,7 @@ fn suggest_unsized_bound_if_applicable( 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; };