diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
5 files changed, 91 insertions, 23 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9447612d026..812e20e4338 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -318,7 +318,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let (expected, found) = if expected_str == found_str { (join_path_syms(&expected_abs), join_path_syms(&found_abs)) } else { - (expected_str.clone(), found_str.clone()) + (expected_str, found_str) }; // We've displayed "expected `a::b`, found `a::b`". We add context to diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 40a27c9aebe..f6dbbeb51ca 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -32,8 +32,8 @@ use rustc_middle::ty::print::{ }; use rustc_middle::ty::{ self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast, suggest_arbitrary_trait_bound, - suggest_constraining_type_param, + TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, TypeckResults, Upcast, + suggest_arbitrary_trait_bound, suggest_constraining_type_param, }; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::LocalDefId; @@ -263,6 +263,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (false, None), }; + let mut finder = ParamFinder { .. }; + finder.visit_binder(&trait_pred); + // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. loop { @@ -411,6 +414,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Fn(..), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + generics, + trait_item_def_id: None, + kind: hir::ImplItemKind::Fn(..), + .. + }) if finder.can_suggest_bound(generics) => { + // Missing generic type parameter bound. + suggest_arbitrary_trait_bound( + self.tcx, + generics, + err, + trait_pred, + associated_ty, + ); + } hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics, _) @@ -423,7 +446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Const(_, generics, _, _) | hir::ItemKind::TraitAlias(_, generics, _), .. - }) if !param_ty => { + }) if finder.can_suggest_bound(generics) => { // Missing generic type parameter bound. if suggest_arbitrary_trait_bound( self.tcx, @@ -5068,8 +5091,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);` // is not. Look for invalid "bare" parameter uses, and suggest using indirection. - let mut visitor = - FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false }; + let mut visitor = FindTypeParam { param: param.name.ident().name, .. }; visitor.visit_item(item); if visitor.invalid_spans.is_empty() { return false; @@ -5228,7 +5250,7 @@ fn hint_missing_borrow<'tcx>( /// Used to suggest replacing associated types with an explicit type in `where` clauses. #[derive(Debug)] pub struct SelfVisitor<'v> { - pub paths: Vec<&'v hir::Ty<'v>>, + pub paths: Vec<&'v hir::Ty<'v>> = Vec::new(), pub name: Option<Symbol>, } @@ -5599,7 +5621,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>( ); // Search for the associated type `Self::{name}`, get // its type and suggest replacing the bound with it. - let mut visitor = SelfVisitor { paths: vec![], name: Some(name) }; + let mut visitor = SelfVisitor { name: Some(name), .. }; visitor.visit_trait_ref(trait_ref); for path in visitor.paths { err.span_suggestion_verbose( @@ -5610,7 +5632,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>( ); } } else { - let mut visitor = SelfVisitor { paths: vec![], name: None }; + let mut visitor = SelfVisitor { name: None, .. }; visitor.visit_trait_ref(trait_ref); let span: MultiSpan = visitor.paths.iter().map(|p| p.span).collect::<Vec<Span>>().into(); @@ -5640,8 +5662,8 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) { /// `param: ?Sized` would be a valid constraint. struct FindTypeParam { param: rustc_span::Symbol, - invalid_spans: Vec<Span>, - nested: bool, + invalid_spans: Vec<Span> = Vec::new(), + nested: bool = false, } impl<'v> Visitor<'v> for FindTypeParam { @@ -5679,3 +5701,38 @@ impl<'v> Visitor<'v> for FindTypeParam { } } } + +/// Look for type parameters in predicates. We use this to identify whether a bound is suitable in +/// on a given item. +struct ParamFinder { + params: Vec<Symbol> = Vec::new(), +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamFinder { + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + match t.kind() { + ty::Param(p) => self.params.push(p.name), + _ => {} + } + t.super_visit_with(self) + } +} + +impl ParamFinder { + /// Whether the `hir::Generics` of the current item can suggest the evaluated bound because its + /// references to type parameters are present in the generics. + fn can_suggest_bound(&self, generics: &hir::Generics<'_>) -> bool { + if self.params.is_empty() { + // There are no references to type parameters at all, so suggesting the bound + // would be reasonable. + return true; + } + generics.params.iter().any(|p| match p.name { + hir::ParamName::Plain(p_name) => { + // All of the parameters in the bound can be referenced in the current item. + self.params.iter().any(|p| *p == p_name.name || *p == kw::SelfUpper) + } + _ => true, + }) + } +} diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index e2b22f7bab7..fc0cf8f140a 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -19,6 +19,7 @@ #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_patterns)] +#![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iterator_try_reduce)] diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index f58961683a9..5d200c4d340 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -13,4 +13,20 @@ pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }; +use rustc_middle::query::Providers; +use rustc_middle::ty::TyCtxt; pub use select::InferCtxtSelectExt; + +fn evaluate_root_goal_for_proof_tree_raw<'tcx>( + tcx: TyCtxt<'tcx>, + canonical_input: CanonicalInput<TyCtxt<'tcx>>, +) -> (QueryResult<TyCtxt<'tcx>>, &'tcx inspect::Probe<TyCtxt<'tcx>>) { + evaluate_root_goal_for_proof_tree_raw_provider::<SolverDelegate<'tcx>, TyCtxt<'tcx>>( + tcx, + canonical_input, + ) +} + +pub fn provide(providers: &mut Providers) { + *providers = Providers { evaluate_root_goal_for_proof_tree_raw, ..*providers }; +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 308486811e6..342d7121fc3 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -37,7 +37,7 @@ pub struct InspectGoal<'a, 'tcx> { orig_values: Vec<ty::GenericArg<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>, result: Result<Certainty, NoSolution>, - evaluation_kind: inspect::GoalEvaluationKind<TyCtxt<'tcx>>, + final_revision: &'tcx inspect::Probe<TyCtxt<'tcx>>, normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, source: GoalSource, } @@ -249,7 +249,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // `InspectGoal::new` so that the goal has the right result (and maintains // the impression that we don't do this normalizes-to infer hack at all). let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span); - let nested_goals_result = nested.and_then(|(nested, _)| { + let nested_goals_result = nested.and_then(|nested| { normalizes_to_term_hack.constrain_and( infcx, span, @@ -391,15 +391,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { pub fn candidates(&'a self) -> Vec<InspectCandidate<'a, 'tcx>> { let mut candidates = vec![]; - let last_eval_step = match &self.evaluation_kind { - // An annoying edge case in case the recursion limit is 0. - inspect::GoalEvaluationKind::Overflow => return vec![], - inspect::GoalEvaluationKind::Evaluation { final_revision } => final_revision, - }; - let mut nested_goals = vec![]; - self.candidates_recur(&mut candidates, &mut nested_goals, &last_eval_step); - + self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision); candidates } @@ -426,7 +419,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { ) -> Self { let infcx = <&SolverDelegate<'tcx>>::from(infcx); - let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, kind, result } = root; + let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, final_revision, result } = + root; // If there's a normalizes-to goal, AND the evaluation result with the result of // constraining the normalizes-to RHS and computing the nested goals. let result = result.and_then(|ok| { @@ -441,7 +435,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { orig_values, goal: eager_resolve_vars(infcx, uncanonicalized_goal), result, - evaluation_kind: kind, + final_revision, normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n), source, } |
