about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-08-17 00:21:40 +0000
committerMichael Goulet <michael@errs.io>2022-08-21 02:35:11 +0000
commitc8746766cb2e375c8b9eeb1bab656aca4cc2a9d1 (patch)
tree5d445492be1b740eaee20d4dc667cbe8221ba8b3 /compiler
parent70b29f7c2d6d4b86d5b1492f3aa63969a62b25bf (diff)
downloadrust-c8746766cb2e375c8b9eeb1bab656aca4cc2a9d1.tar.gz
rust-c8746766cb2e375c8b9eeb1bab656aca4cc2a9d1.zip
Rework ambiguity errors
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs11
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs40
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>,