summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/astconv
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_hir_analysis/src/astconv
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src/astconv')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs63
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs99
4 files changed, 124 insertions, 57 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index ba152cd48..21611e9c5 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -427,7 +427,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let bound_vars = tcx.late_bound_vars(binding.hir_id);
ty::Binder::bind_with_vars(subst_output, bound_vars)
} else {
- // Include substitutions for generic parameters of associated types
+ // Append the generic arguments of the associated type to the `trait_ref`.
candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment {
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index bd311c98f..ed4dde419 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -110,16 +110,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
// 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.
- let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span };
+ let is_dummy = assoc_name.span == DUMMY_SP;
+
let mut err = struct_span_err!(
self.tcx().sess,
- span,
+ if is_dummy { span } else { assoc_name.span },
E0220,
"associated type `{}` not found for `{}`",
assoc_name,
ty_param_name
);
+ if is_dummy {
+ err.span_label(span, format!("associated type `{assoc_name}` not found"));
+ return err.emit();
+ }
+
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
@@ -131,10 +137,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
.collect();
- if let (Some(suggested_name), true) = (
- find_best_match_for_name(&all_candidate_names, assoc_name.name, None),
- assoc_name.span != DUMMY_SP,
- ) {
+ if let Some(suggested_name) =
+ find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
+ {
err.span_suggestion(
assoc_name.span,
"there is an associated type with a similar name",
@@ -172,10 +177,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
.collect();
- if let (Some(suggested_name), true) = (
- find_best_match_for_name(&wider_candidate_names, assoc_name.name, None),
- assoc_name.span != DUMMY_SP,
- ) {
+ if let Some(suggested_name) =
+ find_best_match_for_name(&wider_candidate_names, assoc_name.name, None)
+ {
if let [best_trait] = visible_traits
.iter()
.filter(|trait_def_id| {
@@ -197,7 +201,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
- err.span_label(span, format!("associated type `{assoc_name}` not found"));
+ // If we still couldn't find any associated type, and only one associated type exists,
+ // suggests using it.
+
+ if all_candidate_names.len() == 1 {
+ // this should still compile, except on `#![feature(associated_type_defaults)]`
+ // where it could suggests `type A = Self::A`, thus recursing infinitely
+ let applicability = if self.tcx().features().associated_type_defaults {
+ Applicability::Unspecified
+ } else {
+ Applicability::MaybeIncorrect
+ };
+
+ err.span_suggestion(
+ assoc_name.span,
+ format!("`{ty_param_name}` has the following associated type"),
+ all_candidate_names.first().unwrap().to_string(),
+ applicability,
+ );
+ } else {
+ err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found"));
+ }
+
err.emit()
}
@@ -597,7 +622,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
}
- if !suggestions.is_empty() {
+ suggestions.sort_by_key(|&(span, _)| span);
+ // There are cases where one bound points to a span within another bound's span, like when
+ // you have code like the following (#115019), so we skip providing a suggestion in those
+ // cases to avoid having a malformed suggestion.
+ //
+ // pub struct Flatten<I> {
+ // inner: <IntoIterator<Item: IntoIterator<Item: >>::IntoIterator as Item>::core,
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // | ^^^^^^^^^^^^^^^^^^^^^
+ // | |
+ // | associated types `Item`, `IntoIter` must be specified
+ // associated types `Item`, `IntoIter` must be specified
+ // }
+ let overlaps = suggestions.windows(2).any(|pair| pair[0].0.overlaps(pair[1].0));
+ if !suggestions.is_empty() && !overlaps {
err.multipart_suggestion(
format!("specify the associated type{}", pluralize!(types_count)),
suggestions,
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index 1372cc896..e3621ef93 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -139,22 +139,22 @@ fn generic_arg_mismatch_err(
err.emit()
}
-/// Creates the relevant generic argument substitutions
+/// Creates the relevant generic arguments
/// corresponding to a set of generic parameters. This is a
/// rather complex function. Let us try to explain the role
/// of each of its parameters:
///
-/// To start, we are given the `def_id` of the thing we are
-/// creating the substitutions for, and a partial set of
-/// substitutions `parent_args`. In general, the substitutions
-/// for an item begin with substitutions for all the "parents" of
+/// To start, we are given the `def_id` of the thing whose generic
+/// parameters we are instantiating, and a partial set of
+/// arguments `parent_args`. In general, the generic arguments
+/// for an item begin with arguments for all the "parents" of
/// that item -- e.g., for a method it might include the
/// parameters from the impl.
///
/// Therefore, the method begins by walking down these parents,
/// starting with the outermost parent and proceed inwards until
/// it reaches `def_id`. For each parent `P`, it will check `parent_args`
-/// first to see if the parent's substitutions are listed in there. If so,
+/// first to see if the parent's arguments are listed in there. If so,
/// we can append those and move on. Otherwise, it invokes the
/// three callback functions:
///
@@ -188,7 +188,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
stack.push((def_id, parent_defs));
}
- // We manually build up the substitution, rather than using convenience
+ // We manually build up the generic arguments, rather than using convenience
// methods in `subst.rs`, so that we can iterate over the arguments and
// parameters in lock-step linearly, instead of trying to match each pair.
let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
@@ -196,7 +196,8 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
while let Some((def_id, defs)) = stack.pop() {
let mut params = defs.params.iter().peekable();
- // If we have already computed substitutions for parents, we can use those directly.
+ // If we have already computed the generic arguments for parents,
+ // we can use those directly.
while let Some(&param) = params.peek() {
if let Some(&kind) = parent_args.get(param.index as usize) {
args.push(kind);
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 668763f9b..56b1fd369 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -268,9 +268,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// (*) -- not late-bound, won't change
}
- Some(rbv::ResolvedArg::Error(_)) => {
- bug!("only ty/ct should resolve as ResolvedArg::Error")
- }
+ Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar),
None => {
self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
@@ -291,7 +289,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
- /// returns an appropriate set of substitutions for this particular reference to `I`.
+ /// returns an appropriate set of generic arguments for this particular reference to `I`.
pub fn ast_path_args_for_ty(
&self,
span: Span,
@@ -317,7 +315,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Given the type/lifetime/const arguments provided to some path (along with
/// an implicit `Self`, if this is a trait reference), returns the complete
- /// set of substitutions. This may involve applying defaulted type parameters.
+ /// set of generic arguments. This may involve applying defaulted type parameters.
/// Constraints on associated types are created from `create_assoc_bindings_for_generic_args`.
///
/// Example:
@@ -523,7 +521,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ty::new_misc_error(tcx).into()
}
}
- GenericParamDefKind::Const { has_default } => {
+ GenericParamDefKind::Const { has_default, .. } => {
let ty = tcx
.at(self.span)
.type_of(param.def_id)
@@ -910,19 +908,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) -> Ty<'tcx> {
let tcx = self.tcx();
let args = self.ast_path_args_for_ty(span, did, item_segment);
- let ty = tcx.at(span).type_of(did);
- if let DefKind::TyAlias { lazy } = tcx.def_kind(did)
- && (lazy || ty.skip_binder().has_opaque_types())
+ if let DefKind::TyAlias = tcx.def_kind(did)
+ && tcx.type_alias_is_lazy(did)
{
- // Type aliases referring to types that contain opaque types (but aren't just directly
- // referencing a single opaque type) as well as those defined in crates that have the
+ // Type aliases defined in crates that have the
// feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
// then actually instantiate the where bounds of.
let alias_ty = tcx.mk_alias_ty(did, args);
Ty::new_alias(tcx, ty::Weak, alias_ty)
} else {
- ty.instantiate(tcx, args)
+ tcx.at(span).type_of(did).instantiate(tcx, args)
}
}
@@ -2161,7 +2157,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
Res::Def(
DefKind::Enum
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::Struct
| DefKind::Union
| DefKind::ForeignTy,
@@ -2200,27 +2196,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.span_note(span, format!("type parameter `{name}` defined here"));
}
});
-
- match tcx.named_bound_var(hir_id) {
- Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
- let name =
- tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local()));
- let br = ty::BoundTy {
- var: ty::BoundVar::from_u32(index),
- kind: ty::BoundTyKind::Param(def_id, name),
- };
- Ty::new_bound(tcx, debruijn, br)
- }
- Some(rbv::ResolvedArg::EarlyBound(_)) => {
- let def_id = def_id.expect_local();
- let item_def_id = tcx.hir().ty_param_owner(def_id);
- let generics = tcx.generics_of(item_def_id);
- let index = generics.param_def_id_to_index[&def_id.to_def_id()];
- Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id))
- }
- Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar),
- arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
- }
+ self.hir_id_to_bound_ty(hir_id)
}
Res::SelfTyParam { .. } => {
// `Self` in trait or type alias.
@@ -2389,6 +2365,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
+ // Converts a hir id corresponding to a type parameter to
+ // a early-bound `ty::Param` or late-bound `ty::Bound`.
+ pub(crate) fn hir_id_to_bound_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> {
+ let tcx = self.tcx();
+ match tcx.named_bound_var(hir_id) {
+ Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
+ let name = tcx.item_name(def_id);
+ let br = ty::BoundTy {
+ var: ty::BoundVar::from_u32(index),
+ kind: ty::BoundTyKind::Param(def_id, name),
+ };
+ Ty::new_bound(tcx, debruijn, br)
+ }
+ Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
+ let def_id = def_id.expect_local();
+ let item_def_id = tcx.hir().ty_param_owner(def_id);
+ let generics = tcx.generics_of(item_def_id);
+ let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+ Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id))
+ }
+ Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar),
+ arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
+ }
+ }
+
+ // Converts a hir id corresponding to a const parameter to
+ // a early-bound `ConstKind::Param` or late-bound `ConstKind::Bound`.
+ pub(crate) fn hir_id_to_bound_const(
+ &self,
+ hir_id: hir::HirId,
+ param_ty: Ty<'tcx>,
+ ) -> Const<'tcx> {
+ let tcx = self.tcx();
+ match tcx.named_bound_var(hir_id) {
+ Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
+ // Find the name and index of the const parameter by indexing the generics of
+ // the parent item and construct a `ParamConst`.
+ let item_def_id = tcx.parent(def_id);
+ let generics = tcx.generics_of(item_def_id);
+ let index = generics.param_def_id_to_index[&def_id];
+ let name = tcx.item_name(def_id);
+ ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)
+ }
+ Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
+ ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty)
+ }
+ Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty),
+ arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
+ }
+ }
+
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
@@ -2747,7 +2774,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) {
for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br {
- ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
+ ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon | ty::BrEnv => {
"an anonymous lifetime".to_string()
}
ty::BrNamed(_, name) => format!("lifetime `{name}`"),
@@ -2755,7 +2782,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut err = generate_err(&br_name);
- if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
+ if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon = *br {
// The only way for an anonymous lifetime to wind up
// in the return type but **also** be unconstrained is
// if it only appears in "associated types" in the