diff options
| author | Michael Goulet <michael@errs.io> | 2022-08-17 00:21:40 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2022-08-21 02:35:11 +0000 |
| commit | c8746766cb2e375c8b9eeb1bab656aca4cc2a9d1 (patch) | |
| tree | 5d445492be1b740eaee20d4dc667cbe8221ba8b3 /compiler | |
| parent | 70b29f7c2d6d4b86d5b1492f3aa63969a62b25bf (diff) | |
| download | rust-c8746766cb2e375c8b9eeb1bab656aca4cc2a9d1.tar.gz rust-c8746766cb2e375c8b9eeb1bab656aca4cc2a9d1.zip | |
Rework ambiguity errors
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_middle/src/ty/generics.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/fn_ctxt/checks.rs | 40 |
2 files changed, 48 insertions, 3 deletions
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index add2df25884..6e8afd4d539 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -122,6 +122,17 @@ pub struct Generics { } impl<'tcx> Generics { + pub fn param_def_id_to_index(&self, tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<u32> { + if let Some(idx) = self.param_def_id_to_index.get(&def_id) { + Some(*idx) + } else if let Some(parent) = self.parent { + let parent = tcx.generics_of(parent); + parent.param_def_id_to_index(tcx, def_id) + } else { + None + } + } + #[inline] pub fn count(&self) -> usize { self.parent_count + self.params.len() diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 204bb6a532d..35a3ae3ebf7 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -27,13 +27,14 @@ use rustc_infer::infer::InferOk; use rustc_infer::infer::TypeTrace; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty}; +use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; +use std::ops::ControlFlow; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1649,7 +1650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::Projection(pred) => pred.projection_ty.substs, _ => ty::List::empty(), }; - let param_to_point_at = predicate_substs.types().find_map(|ty| { + let mut param_to_point_at = predicate_substs.types().find_map(|ty| { ty.walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Param(param_ty) = ty.kind() @@ -1663,7 +1664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }) }); - let fallback_param_to_point_at = predicate_substs.types().find_map(|ty| { + let mut fallback_param_to_point_at = predicate_substs.types().find_map(|ty| { ty.walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Param(param_ty) = ty.kind() @@ -1676,6 +1677,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) }); + // Also skip over ambiguity errors, which have their own machinery + // to print a relevant error. + if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { + fallback_param_to_point_at = None; + param_to_point_at = + self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); + } + let hir = self.tcx.hir(); match hir.get(hir_id) { @@ -1737,6 +1746,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>( + &self, + item_def_id: DefId, + t: T, + ) -> Option<ty::GenericArg<'tcx>> { + struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId); + impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> { + type BreakTy = ty::GenericArg<'tcx>; + fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { + if let Some(origin) = self.0.type_var_origin(ty) + && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) + = origin.kind + && let generics = self.0.tcx.generics_of(self.1) + && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) + && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1).get(index as usize) + { + ControlFlow::Break(*subst) + } else { + ty.super_visit_with(self) + } + } + } + t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value() + } + fn point_at_args_if_possible( &self, error: &mut traits::FulfillmentError<'tcx>, |
