about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2024-06-14 12:28:23 +0200
committerLeón Orell Valerian Liehr <me@fmease.dev>2024-07-23 01:23:54 +0200
commit898448ca5872aed82920dbb8342096e25e50aa5a (patch)
treedd25517ace57ec5573a90a90ba9c92b47286e9c2 /compiler
parentef121f28d8684d32306becb7577b4e36d7c0ff08 (diff)
downloadrust-898448ca5872aed82920dbb8342096e25e50aa5a.tar.gz
rust-898448ca5872aed82920dbb8342096e25e50aa5a.zip
HIR ty lowering: Refactor the way the projectee ("QSelf") gets passed to diagnostics
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl6
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs59
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs75
5 files changed, 86 insertions, 69 deletions
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index cc404daa51f..c209bf20c43 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -1,4 +1,4 @@
-hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$ty_param_name}`
+hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$qself}`
     .label = ambiguous associated {$assoc_kind} `{$assoc_name}`
 
 hir_analysis_ambiguous_lifetime_bound =
@@ -12,14 +12,14 @@ hir_analysis_assoc_item_is_private = {$kind} `{$name}` is private
     .label = private {$kind}
     .defined_here_label = the {$kind} is defined here
 
-hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
+hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$qself}`
 
 hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named ->
         [true] an
         *[false] a similarly named
     } associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}`
 hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found
-hir_analysis_assoc_item_not_found_other_sugg = `{$ty_param_name}` has the following associated {$assoc_kind}
+hir_analysis_assoc_item_not_found_other_sugg = `{$qself}` has the following associated {$assoc_kind}
 hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg = change the associated {$assoc_kind} name to use `{$suggested_name}` from `{$trait_name}`
 hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = and also change the associated {$assoc_kind} name
 hir_analysis_assoc_item_not_found_similar_sugg = there is an associated {$assoc_kind} with a similar name
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index d1f9ad9d58b..8e8b3b3d32a 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -22,7 +22,7 @@ pub struct AmbiguousAssocItem<'a> {
     pub span: Span,
     pub assoc_kind: &'static str,
     pub assoc_name: Ident,
-    pub ty_param_name: &'a str,
+    pub qself: &'a str,
 }
 
 #[derive(Diagnostic)]
@@ -75,7 +75,7 @@ pub struct AssocItemNotFound<'a> {
     pub span: Span,
     pub assoc_name: Ident,
     pub assoc_kind: &'static str,
-    pub ty_param_name: &'a str,
+    pub qself: &'a str,
     #[subdiagnostic]
     pub label: Option<AssocItemNotFoundLabel<'a>>,
     #[subdiagnostic]
@@ -134,7 +134,7 @@ pub enum AssocItemNotFoundSugg<'a> {
     Other {
         #[primary_span]
         span: Span,
-        ty_param_name: &'a str,
+        qself: &'a str,
         assoc_kind: &'static str,
         suggested_name: Symbol,
     },
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 6f9c481650b..214eb6b2f06 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -6,7 +6,6 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::bug;
-use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt};
 use rustc_span::symbol::Ident;
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
@@ -16,9 +15,8 @@ use smallvec::SmallVec;
 
 use crate::bounds::Bounds;
 use crate::errors;
-use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
-
-use super::RegionInferReason;
+use crate::hir_ty_lowering::HirTyLowerer;
+use crate::hir_ty_lowering::{AssocItemQSelf, OnlySelfBounds, PredicateFilter, RegionInferReason};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Add a `Sized` bound to the `bounds` if appropriate.
@@ -288,8 +286,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // one that does define it.
             self.probe_single_bound_for_assoc_item(
                 || traits::supertraits(tcx, trait_ref),
-                trait_ref.skip_binder().print_only_trait_name(),
-                None,
+                AssocItemQSelf::Trait(trait_ref.def_id()),
                 assoc_kind,
                 constraint.ident,
                 path_span,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 40675a1edba..ca741e4fbb6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -3,7 +3,7 @@ use crate::errors::{
     ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
 };
 use crate::fluent_generated as fluent;
-use crate::hir_ty_lowering::HirTyLowerer;
+use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
@@ -11,9 +11,9 @@ use rustc_errors::MultiSpan;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
 };
+use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{self as hir, Node};
+use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::query::Key;
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -116,8 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     pub(super) fn complain_about_assoc_item_not_found<I>(
         &self,
         all_candidates: impl Fn() -> I,
-        ty_param_name: &str,
-        ty_param_def_id: Option<LocalDefId>,
+        qself: AssocItemQSelf,
         assoc_kind: ty::AssocKind,
         assoc_name: Ident,
         span: Span,
@@ -139,7 +138,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             );
         }
 
-        let assoc_kind_str = super::assoc_kind_str(assoc_kind);
+        let assoc_kind_str = assoc_kind_str(assoc_kind);
+        let qself_str = qself.to_string(tcx);
 
         // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
         // valid span, so we point at the whole path segment instead.
@@ -149,7 +149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             span: if is_dummy { span } else { assoc_name.span },
             assoc_name,
             assoc_kind: assoc_kind_str,
-            ty_param_name,
+            qself: &qself_str,
             label: None,
             sugg: None,
         };
@@ -219,19 +219,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     suggested_name,
                     identically_named: suggested_name == assoc_name.name,
                 });
-                let hir = tcx.hir();
-                if let Some(def_id) = ty_param_def_id
-                    && let parent = hir.get_parent_item(tcx.local_def_id_to_hir_id(def_id))
-                    && let Some(generics) = hir.get_generics(parent.def_id)
+                if let AssocItemQSelf::TyParam(ty_param_def_id) = qself
+                    // Not using `self.item_def_id()` here as that would yield the opaque type itself if we're
+                    // inside an opaque type while we're interested in the overarching type alias (TAIT).
+                    // FIXME: However, for trait aliases, this incorrectly returns the enclosing module...
+                    && let item_def_id =
+                        tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id))
+                    // FIXME: ...which obviously won't have any generics.
+                    && let Some(generics) = tcx.hir().get_generics(item_def_id.def_id)
                 {
-                    if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any(
-                        |b| match b {
+                    // FIXME: Suggest adding supertrait bounds if we have a `Self` type param.
+                    // FIXME(trait_alias): Suggest adding `Self: Trait` to
+                    // `trait Alias = where Self::Proj:;` with `trait Trait { type Proj; }`.
+                    if generics
+                        .bounds_for_param(ty_param_def_id)
+                        .flat_map(|pred| pred.bounds.iter())
+                        .any(|b| match b {
                             hir::GenericBound::Trait(t, ..) => {
                                 t.trait_ref.trait_def_id() == Some(best_trait)
                             }
                             _ => false,
-                        },
-                    ) {
+                        })
+                    {
                         // The type param already has a bound for `trait_name`, we just need to
                         // change the associated item.
                         err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
@@ -247,7 +256,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         tcx,
                         generics,
                         &mut err,
-                        &ty_param_name,
+                        &qself_str,
                         &trait_name,
                         None,
                         None,
@@ -273,7 +282,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         if let [candidate_name] = all_candidate_names.as_slice() {
             err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
                 span: assoc_name.span,
-                ty_param_name,
+                qself: &qself_str,
                 assoc_kind: assoc_kind_str,
                 suggested_name: *candidate_name,
             });
@@ -339,10 +348,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         self.dcx().emit_err(errors::AssocKindMismatch {
             span,
-            expected: super::assoc_kind_str(expected),
-            got: super::assoc_kind_str(got),
+            expected: assoc_kind_str(expected),
+            got: assoc_kind_str(got),
             expected_because_label,
-            assoc_kind: super::assoc_kind_str(assoc_item.kind),
+            assoc_kind: assoc_kind_str(assoc_item.kind),
             def_span: tcx.def_span(assoc_item.def_id),
             bound_on_assoc_const_label,
             wrap_in_braces_sugg,
@@ -736,7 +745,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
             let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
             in_expr_or_pat = match grandparent {
-                Node::Expr(_) | Node::Pat(_) => true,
+                hir::Node::Expr(_) | hir::Node::Pat(_) => true,
                 _ => false,
             };
             match bound.trait_ref.path.segments {
@@ -1602,3 +1611,11 @@ fn generics_args_err_extend<'a>(
         _ => {}
     }
 }
+
+pub(super) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
+    match kind {
+        ty::AssocKind::Fn => "function",
+        ty::AssocKind::Const => "constant",
+        ty::AssocKind::Type => "type",
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index d6eb1a66902..8d9055076a3 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -55,7 +55,6 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
-use std::fmt::Display;
 use std::slice;
 
 /// A path segment that is semantically allowed to have generic arguments.
@@ -193,6 +192,25 @@ pub trait HirTyLowerer<'tcx> {
     }
 }
 
+/// The "qualified self" of an associated item path.
+///
+/// For diagnostic purposes only.
+enum AssocItemQSelf {
+    Trait(DefId),
+    TyParam(LocalDefId),
+    SelfTyAlias,
+}
+
+impl AssocItemQSelf {
+    fn to_string(&self, tcx: TyCtxt<'_>) -> String {
+        match *self {
+            Self::Trait(def_id) => tcx.def_path_str(def_id),
+            Self::TyParam(def_id) => tcx.hir().ty_param_name(def_id).to_string(),
+            Self::SelfTyAlias => kw::SelfUpper.to_string(),
+        }
+    }
+}
+
 /// New-typed boolean indicating whether explicit late-bound lifetimes
 /// are present in a set of generic arguments.
 ///
@@ -811,19 +829,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_name).predicates;
         debug!("predicates={:#?}", predicates);
 
-        let param_name = tcx.hir().ty_param_name(ty_param_def_id);
         self.probe_single_bound_for_assoc_item(
             || {
-                traits::transitive_bounds_that_define_assoc_item(
-                    tcx,
-                    predicates
-                        .iter()
-                        .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))),
-                    assoc_name,
-                )
+                let trait_refs = predicates
+                    .iter()
+                    .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref)));
+                traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name)
             },
-            param_name,
-            Some(ty_param_def_id),
+            AssocItemQSelf::TyParam(ty_param_def_id),
             ty::AssocKind::Type,
             assoc_name,
             span,
@@ -835,12 +848,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ///
     /// This fails if there is no such bound in the list of candidates or if there are multiple
     /// candidates in which case it reports ambiguity.
-    #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, constraint), ret)]
+    #[instrument(level = "debug", skip(self, all_candidates, qself, constraint), ret)]
     fn probe_single_bound_for_assoc_item<I>(
         &self,
         all_candidates: impl Fn() -> I,
-        ty_param_name: impl Display,
-        ty_param_def_id: Option<LocalDefId>,
+        qself: AssocItemQSelf,
         assoc_kind: ty::AssocKind,
         assoc_name: Ident,
         span: Span,
@@ -858,8 +870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let Some(bound) = matching_candidates.next() else {
             let reported = self.complain_about_assoc_item_not_found(
                 all_candidates,
-                &ty_param_name.to_string(),
-                ty_param_def_id,
+                qself,
                 assoc_kind,
                 assoc_name,
                 span,
@@ -872,13 +883,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         if let Some(bound2) = matching_candidates.next() {
             debug!(?bound2);
 
-            let assoc_kind_str = assoc_kind_str(assoc_kind);
-            let ty_param_name = &ty_param_name.to_string();
+            let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
+            let qself_str = qself.to_string(tcx);
             let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
                 span,
                 assoc_kind: assoc_kind_str,
                 assoc_name,
-                ty_param_name,
+                qself: &qself_str,
             });
             // Provide a more specific error code index entry for equality bindings.
             err.code(
@@ -929,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         err.span_suggestion_verbose(
                             span.with_hi(assoc_name.span.lo()),
                             "use fully-qualified syntax to disambiguate",
-                            format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()),
+                            format!("<{qself_str} as {}>::", bound.print_only_trait_path()),
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -943,7 +954,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             if !where_bounds.is_empty() {
                 err.help(format!(
                     "consider introducing a new type parameter `T` and adding `where` constraints:\
-                     \n    where\n        T: {ty_param_name},\n{}",
+                     \n    where\n        T: {qself_str},\n{}",
                     where_bounds.join(",\n"),
                 ));
             }
@@ -997,11 +1008,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let tcx = self.tcx();
 
         let assoc_ident = assoc_segment.ident;
-        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
-            path.res
-        } else {
-            Res::Err
-        };
 
         // Check if we have an enum variant or an inherent associated type.
         let mut variant_resolution = None;
@@ -1038,6 +1044,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
+        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
+            path.res
+        } else {
+            Res::Err
+        };
+
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
         let bound = match (&qself_ty.kind(), qself_res) {
@@ -1056,8 +1068,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             ty::Binder::dummy(trait_ref.instantiate_identity()),
                         )
                     },
-                    kw::SelfUpper,
-                    None,
+                    AssocItemQSelf::SelfTyAlias,
                     ty::AssocKind::Type,
                     assoc_ident,
                     span,
@@ -2522,11 +2533,3 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         Some(r)
     }
 }
-
-fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
-    match kind {
-        ty::AssocKind::Fn => "function",
-        ty::AssocKind::Const => "constant",
-        ty::AssocKind::Type => "type",
-    }
-}