summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/astconv/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/astconv/mod.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs458
1 files changed, 323 insertions, 135 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 78d204d47..6435b05ce 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -3,8 +3,11 @@
//! instance of `AstConv`.
mod errors;
-mod generics;
+pub mod generics;
+use crate::astconv::generics::{
+ check_generic_arg_count, create_substs_for_generic_args, prohibit_assoc_ty_binding,
+};
use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector;
use crate::errors::{
@@ -24,13 +27,12 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
-use rustc_middle::ty::DynKind;
use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{
- self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable,
-};
+use rustc_middle::ty::{self, Const, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{DynKind, EarlyBinder};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
@@ -108,11 +110,12 @@ pub trait AstConv<'tcx> {
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx>;
- /// Normalize an associated type coming from the user.
- ///
- /// This should only be used by astconv. Use `FnCtxt::normalize`
- /// or `ObligationCtxt::normalize` in downstream crates.
- fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
+ /// Returns `AdtDef` if `ty` is an ADT.
+ /// Note that `ty` might be a projection type that needs normalization.
+ /// This used to get the enum variants in scope of the type.
+ /// For example, `Self::A` could refer to an associated type
+ /// or to an enum variant depending on the result of this function.
+ fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>>;
/// Invoked when we encounter an error from some prior pass
/// (e.g., resolve) that is translated into a ty-error. This is
@@ -121,6 +124,13 @@ pub trait AstConv<'tcx> {
fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
+
+ fn astconv(&self) -> &dyn AstConv<'tcx>
+ where
+ Self: Sized,
+ {
+ self
+ }
}
#[derive(Debug)]
@@ -280,7 +290,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+ prohibit_assoc_ty_binding(self.tcx(), b.span);
}
substs
@@ -350,7 +360,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assert!(self_ty.is_none());
}
- let arg_count = Self::check_generic_arg_count(
+ let arg_count = check_generic_arg_count(
tcx,
span,
def_id,
@@ -487,13 +497,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Avoid ICE #86756 when type error recovery goes awry.
return tcx.ty_error().into();
}
- self.astconv
- .normalize_ty(
- self.span,
- EarlyBinder(tcx.at(self.span).type_of(param.def_id))
- .subst(tcx, substs),
- )
- .into()
+ tcx.at(self.span).bound_type_of(param.def_id).subst(tcx, substs).into()
} else if infer_args {
self.astconv.ty_infer(Some(param), self.span).into()
} else {
@@ -507,9 +511,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return tcx.const_error(ty).into();
}
if !infer_args && has_default {
- tcx.bound_const_param_default(param.def_id)
- .subst(tcx, substs.unwrap())
- .into()
+ tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
if infer_args {
self.astconv.ct_infer(ty, Some(param), self.span).into()
@@ -531,7 +533,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
inferred_params: vec![],
infer_args,
};
- let substs = Self::create_substs_for_generic_args(
+ let substs = create_substs_for_generic_args(
tcx,
def_id,
parent_substs,
@@ -567,17 +569,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.bindings
.iter()
.map(|binding| {
- let kind = match binding.kind {
- hir::TypeBindingKind::Equality { ref term } => match term {
- hir::Term::Ty(ref ty) => {
+ let kind = match &binding.kind {
+ hir::TypeBindingKind::Equality { term } => match term {
+ hir::Term::Ty(ty) => {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
}
- hir::Term::Const(ref c) => {
+ hir::Term::Const(c) => {
let c = Const::from_anon_const(self.tcx(), c.def_id);
ConvertedBindingKind::Equality(c.into())
}
},
- hir::TypeBindingKind::Constraint { ref bounds } => {
+ hir::TypeBindingKind::Constraint { bounds } => {
ConvertedBindingKind::Constraint(bounds)
}
};
@@ -617,7 +619,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
if let Some(b) = item_segment.args().bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+ prohibit_assoc_ty_binding(self.tcx(), b.span);
}
args
@@ -680,10 +682,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
let poly_trait_ref =
- ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
+ ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
debug!(?poly_trait_ref, ?assoc_bindings);
- bounds.trait_bounds.push((poly_trait_ref, span, constness));
+ bounds.push_trait_bound(tcx, poly_trait_ref, span, constness);
let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings {
@@ -811,9 +813,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
constness,
);
if let Some(b) = trait_segment.args().bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+ prohibit_assoc_ty_binding(self.tcx(), b.span);
}
- ty::TraitRef::new(trait_def_id, substs)
+ self.tcx().mk_trait_ref(trait_def_id, substs)
}
#[instrument(level = "debug", skip(self, span))]
@@ -854,18 +856,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
/// Sets `implicitly_sized` to true on `Bounds` if necessary
- pub(crate) fn add_implicitly_sized<'hir>(
+ pub(crate) fn add_implicitly_sized(
&self,
- bounds: &mut Bounds<'hir>,
- ast_bounds: &'hir [hir::GenericBound<'hir>],
- self_ty_where_predicates: Option<(LocalDefId, &'hir [hir::WherePredicate<'hir>])>,
+ bounds: &mut Bounds<'tcx>,
+ self_ty: Ty<'tcx>,
+ ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+ self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
span: Span,
) {
let tcx = self.tcx();
// Try to find an unbound in bounds.
let mut unbound = None;
- let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| {
+ let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
for ab in ast_bounds {
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() {
@@ -913,7 +916,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// No lang item for `Sized`, so we can't add it as a bound.
return;
}
- bounds.implicitly_sized = Some(span);
+ bounds.push_sized(tcx, self_ty, span);
}
/// This helper takes a *converted* parameter type (`param_ty`)
@@ -964,10 +967,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
hir::GenericBound::Outlives(lifetime) => {
let region = self.ast_region_to_region(lifetime, None);
- bounds.region_bounds.push((
- ty::Binder::bind_with_vars(region, bound_vars),
+ bounds.push_region_bound(
+ self.tcx(),
+ ty::Binder::bind_with_vars(
+ ty::OutlivesPredicate(param_ty, region),
+ bound_vars,
+ ),
lifetime.ident.span,
- ));
+ );
}
}
}
@@ -985,7 +992,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// ```
///
/// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
- /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
+ /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
/// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
///
/// `span` should be the declaration size of the parameter.
@@ -1146,10 +1153,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!(?substs_trait_ref_and_assoc_item);
- ty::ProjectionTy {
- item_def_id: assoc_item.def_id,
- substs: substs_trait_ref_and_assoc_item,
- }
+ self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
});
if !speculative {
@@ -1195,7 +1199,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// the "projection predicate" for:
//
// `<T as Iterator>::Item = u32`
- let assoc_item_def_id = projection_ty.skip_binder().item_def_id;
+ let assoc_item_def_id = projection_ty.skip_binder().def_id;
let def_kind = tcx.def_kind(assoc_item_def_id);
match (def_kind, term.unpack()) {
(hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
@@ -1203,17 +1207,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(_, _) => {
let got = if let Some(_) = term.ty() { "type" } else { "constant" };
let expected = def_kind.descr(assoc_item_def_id);
- let reported = tcx
- .sess
- .struct_span_err(
+ let mut err = tcx.sess.struct_span_err(
+ binding.span,
+ &format!("expected {expected} bound, found {got}"),
+ );
+ err.span_note(
+ tcx.def_span(assoc_item_def_id),
+ &format!("{expected} defined here"),
+ );
+
+ if let hir::def::DefKind::AssocConst = def_kind
+ && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
+ && tcx.features().associated_const_equality {
+ err.span_suggestion(
binding.span,
- &format!("expected {expected} bound, found {got}"),
- )
- .span_note(
- tcx.def_span(assoc_item_def_id),
- &format!("{expected} defined here"),
- )
- .emit();
+ "if equating a const, try wrapping with braces",
+ format!("{} = {{ const }}", binding.item_name),
+ Applicability::HasPlaceholders,
+ );
+ }
+ let reported = err.emit();
term = match def_kind {
hir::def::DefKind::AssocTy => {
tcx.ty_error_with_guaranteed(reported).into()
@@ -1229,13 +1242,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
}
}
- bounds.projection_bounds.push((
- projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
- projection_ty,
- term: term,
- }),
+ bounds.push_projection_bound(
+ tcx,
+ projection_ty
+ .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
binding.span,
- ));
+ );
}
ConvertedBindingKind::Constraint(ast_bounds) => {
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
@@ -1244,7 +1256,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
//
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder.
- let param_ty = tcx.mk_ty(ty::Projection(projection_ty.skip_binder()));
+ let param_ty = tcx.mk_ty(ty::Alias(ty::Projection, projection_ty.skip_binder()));
self.add_bounds(param_ty, ast_bounds.iter(), bounds, candidate.bound_vars());
}
}
@@ -1258,16 +1270,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment: &hir::PathSegment<'_>,
) -> Ty<'tcx> {
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
- self.normalize_ty(
- span,
- EarlyBinder(self.tcx().at(span).type_of(did)).subst(self.tcx(), substs),
- )
+ self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs)
}
fn conv_object_ty_poly_trait_ref(
&self,
span: Span,
- trait_bounds: &[hir::PolyTraitRef<'_>],
+ hir_trait_bounds: &[hir::PolyTraitRef<'_>],
lifetime: &hir::Lifetime,
borrowed: bool,
representation: DynKind,
@@ -1277,7 +1286,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut bounds = Bounds::default();
let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self;
- for trait_bound in trait_bounds.iter().rev() {
+ for trait_bound in hir_trait_bounds.iter().rev() {
if let GenericArgCountResult {
correct:
Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
@@ -1294,10 +1303,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
+ let mut trait_bounds = vec![];
+ let mut projection_bounds = vec![];
+ for (pred, span) in bounds.predicates() {
+ let bound_pred = pred.kind();
+ match bound_pred.skip_binder() {
+ ty::PredicateKind::Clause(clause) => match clause {
+ ty::Clause::Trait(trait_pred) => {
+ assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
+ trait_bounds.push((
+ bound_pred.rebind(trait_pred.trait_ref),
+ span,
+ trait_pred.constness,
+ ));
+ }
+ ty::Clause::Projection(proj) => {
+ projection_bounds.push((bound_pred.rebind(proj), span));
+ }
+ ty::Clause::TypeOutlives(_) => {
+ // Do nothing, we deal with regions separately
+ }
+ ty::Clause::RegionOutlives(_) => bug!(),
+ },
+ ty::PredicateKind::WellFormed(_)
+ | ty::PredicateKind::ObjectSafe(_)
+ | ty::PredicateKind::ClosureKind(_, _, _)
+ | ty::PredicateKind::Subtype(_)
+ | ty::PredicateKind::Coerce(_)
+ | ty::PredicateKind::ConstEvaluatable(_)
+ | ty::PredicateKind::ConstEquate(_, _)
+ | ty::PredicateKind::TypeWellFormedFromEnv(_)
+ | ty::PredicateKind::Ambiguous => bug!(),
+ }
+ }
+
// Expand trait aliases recursively and check that only one regular (non-auto) trait
// is used and no 'maybe' bounds are used.
let expanded_traits =
- traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+ traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
.filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
@@ -1334,8 +1378,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
if regular_traits.is_empty() && auto_traits.is_empty() {
- let trait_alias_span = bounds
- .trait_bounds
+ let trait_alias_span = trait_bounds
.iter()
.map(|&(trait_ref, _, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
@@ -1366,8 +1409,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Use a `BTreeSet` to keep output in a more consistent order.
let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
- let regular_traits_refs_spans = bounds
- .trait_bounds
+ let regular_traits_refs_spans = trait_bounds
.into_iter()
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
@@ -1421,7 +1463,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits.
- bounds.projection_bounds.push((pred, span));
+ projection_bounds.push((pred, span));
}
}
_ => (),
@@ -1429,7 +1471,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
- for (projection_bound, _) in &bounds.projection_bounds {
+ for (projection_bound, _) in &projection_bounds {
for def_ids in associated_types.values_mut() {
def_ids.remove(&projection_bound.projection_def_id());
}
@@ -1438,7 +1480,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.complain_about_missing_associated_types(
associated_types,
potential_assoc_types,
- trait_bounds,
+ hir_trait_bounds,
);
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
@@ -1455,7 +1497,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
assert_eq!(trait_ref.self_ty(), dummy_self);
- // Verify that `dummy_self` did not leak inside default type parameters. This
+ // Verify that `dummy_self` did not leak inside default type parameters. This
// could not be done at path creation, since we need to see through trait aliases.
let mut missing_type_params = vec![];
let mut references_self = false;
@@ -1480,7 +1522,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let substs = tcx.intern_substs(&substs[..]);
let span = i.bottom().1;
- let empty_generic_args = trait_bounds.iter().any(|hir_bound| {
+ let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
&& hir_bound.span.contains(span)
});
@@ -1512,7 +1554,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
});
- let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
+ let existential_projections = projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|mut b| {
assert_eq!(b.projection_ty.self_ty(), dummy_self);
@@ -1600,8 +1642,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
fn report_ambiguous_associated_type(
&self,
span: Span,
- type_str: &str,
- trait_str: &str,
+ types: &[String],
+ traits: &[String],
name: Symbol,
) -> ErrorGuaranteed {
let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
@@ -1612,19 +1654,92 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.keys()
.any(|full_span| full_span.contains(span))
{
- err.span_suggestion(
+ err.span_suggestion_verbose(
span.shrink_to_lo(),
"you are looking for the module in `std`, not the primitive type",
"std::",
Applicability::MachineApplicable,
);
} else {
- err.span_suggestion(
- span,
- "use fully-qualified syntax",
- format!("<{} as {}>::{}", type_str, trait_str, name),
- Applicability::HasPlaceholders,
- );
+ match (types, traits) {
+ ([], []) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a type named `Type` that implements a trait named \
+ `Trait` with associated type `{name}`, you could use the \
+ fully-qualified path",
+ ),
+ format!("<Type as Trait>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([], [trait_str]) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a type named `Example` that implemented `{trait_str}`, \
+ you could use the fully-qualified path",
+ ),
+ format!("<Example as {trait_str}>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([], traits) => {
+ err.span_suggestions(
+ span,
+ &format!(
+ "if there were a type named `Example` that implemented one of the \
+ traits with associated type `{name}`, you could use the \
+ fully-qualified path",
+ ),
+ traits
+ .iter()
+ .map(|trait_str| format!("<Example as {trait_str}>::{name}"))
+ .collect::<Vec<_>>(),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([type_str], []) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a trait named `Example` with associated type `{name}` \
+ implemented for `{type_str}`, you could use the fully-qualified path",
+ ),
+ format!("<{type_str} as Example>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ (types, []) => {
+ err.span_suggestions(
+ span,
+ &format!(
+ "if there were a trait named `Example` with associated type `{name}` \
+ implemented for one of the types, you could use the fully-qualified \
+ path",
+ ),
+ types
+ .into_iter()
+ .map(|type_str| format!("<{type_str} as Example>::{name}")),
+ Applicability::HasPlaceholders,
+ );
+ }
+ (types, traits) => {
+ let mut suggestions = vec![];
+ for type_str in types {
+ for trait_str in traits {
+ suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
+ }
+ }
+ err.span_suggestions(
+ span,
+ "use the fully-qualified path",
+ suggestions,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
}
err.emit()
}
@@ -1793,7 +1908,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ok(bound)
}
- // Create a type from a path to an associated type.
+ // Create a type from a path to an associated type or to an enum variant.
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
// and item_segment is the path segment for `D`. We return a type and a def for
// the whole path.
@@ -1813,7 +1928,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
let tcx = self.tcx();
let assoc_ident = assoc_segment.ident;
- let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
+ let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
path.res
} else {
Res::Err
@@ -1821,7 +1936,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Check if we have an enum variant.
let mut variant_resolution = None;
- if let ty::Adt(adt_def, adt_substs) = qself_ty.kind() {
+ if let Some(adt_def) = self.probe_adt(span, qself_ty) {
if adt_def.is_enum() {
let variant_def = adt_def
.variants()
@@ -1856,8 +1971,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return;
};
let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
- hir::QPath::Resolved(_, ref path)
- ) = qself.kind {
+ hir::QPath::Resolved(_, path)
+ ) = &qself.kind {
// If the path segment already has type params, we want to overwrite
// them.
match &path.segments[..] {
@@ -1923,6 +2038,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
continue;
};
+ let ty::Adt(_, adt_substs) = qself_ty.kind() else {
+ // FIXME(inherent_associated_types)
+ bug!("unimplemented: non-adt self of inherent assoc ty");
+ };
let item_substs = self.create_substs_for_associated_item(
span,
assoc_ty_did,
@@ -1930,7 +2049,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
adt_substs,
);
let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs);
- let ty = self.normalize_ty(span, ty);
return Ok((ty, DefKind::AssocTy, assoc_ty_did));
}
}
@@ -1948,7 +2066,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
self.one_bound_for_assoc_type(
- || traits::supertraits(tcx, ty::Binder::dummy(trait_ref)),
+ || traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())),
|| "Self".to_string(),
assoc_ident,
span,
@@ -2004,12 +2122,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.emit()
} else if let Err(reported) = qself_ty.error_reported() {
reported
+ } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
+ // `<impl Trait as OtherTrait>::Assoc` makes no sense.
+ struct_span_err!(
+ tcx.sess,
+ tcx.def_span(alias_ty.def_id),
+ E0667,
+ "`impl Trait` is not allowed in path parameters"
+ )
+ .emit() // Already reported in an earlier stage.
} else {
+ // Find all the `impl`s that `qself_ty` has for any trait that has the
+ // associated type, so that we suggest the right one.
+ let infcx = tcx.infer_ctxt().build();
+ // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
+ // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
+ let param_env = ty::ParamEnv::empty();
+ let traits: Vec<_> = self
+ .tcx()
+ .all_traits()
+ .filter(|trait_def_id| {
+ // Consider only traits with the associated type
+ tcx.associated_items(*trait_def_id)
+ .in_definition_order()
+ .any(|i| {
+ i.kind.namespace() == Namespace::TypeNS
+ && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+ && matches!(i.kind, ty::AssocKind::Type)
+ })
+ // Consider only accessible traits
+ && tcx.visibility(*trait_def_id)
+ .is_accessible_from(self.item_def_id(), tcx)
+ && tcx.all_impls(*trait_def_id)
+ .any(|impl_def_id| {
+ let trait_ref = tcx.impl_trait_ref(impl_def_id);
+ trait_ref.map_or(false, |trait_ref| {
+ let impl_ = trait_ref.subst(
+ tcx,
+ infcx.fresh_substs_for_item(span, impl_def_id),
+ );
+ infcx
+ .can_eq(
+ param_env,
+ tcx.erase_regions(impl_.self_ty()),
+ tcx.erase_regions(qself_ty),
+ )
+ .is_ok()
+ })
+ && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+ })
+ })
+ .map(|trait_def_id| tcx.def_path_str(trait_def_id))
+ .collect();
+
// Don't print `TyErr` to the user.
self.report_ambiguous_associated_type(
span,
- &qself_ty.to_string(),
- "Trait",
+ &[qself_ty.to_string()],
+ &traits,
assoc_ident.name,
)
};
@@ -2027,7 +2197,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
- let ty = self.normalize_ty(span, ty);
if let Some(variant_def_id) = variant_resolution {
tcx.struct_span_lint_hir(
@@ -2128,16 +2297,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let is_part_of_self_trait_constraints = def_id == trait_def_id;
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
- let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
- "Self"
+ let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
+ vec!["Self".to_string()]
} else {
- "Type"
+ // Find all the types that have an `impl` for the trait.
+ tcx.all_impls(trait_def_id)
+ .filter(|impl_def_id| {
+ // Consider only accessible traits
+ tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
+ && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+ })
+ .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
+ .map(|impl_| impl_.subst_identity().self_ty())
+ // We don't care about blanket impls.
+ .filter(|self_ty| !self_ty.has_non_region_param())
+ .map(|self_ty| tcx.erase_regions(self_ty).to_string())
+ .collect()
};
-
+ // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
+ // references the trait. Relevant for the first case in
+ // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
let reported = self.report_ambiguous_associated_type(
span,
- type_name,
- &path_str,
+ &type_names,
+ &[path_str],
item_segment.ident.name,
);
return tcx.ty_error_with_guaranteed(reported)
@@ -2163,7 +2346,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
- self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
+ tcx.mk_projection(item_def_id, item_substs)
}
pub fn prohibit_generics<'a>(
@@ -2243,7 +2426,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
),
"s",
),
- [only] => (format!("{only}"), ""),
+ [only] => (only.to_string(), ""),
[] => unreachable!(),
};
let last_span = *arg_spans.last().unwrap();
@@ -2266,7 +2449,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let Some(b) = segment.args().bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+ prohibit_assoc_ty_binding(self.tcx(), b.span);
return true;
}
}
@@ -2280,6 +2463,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Option<Ty<'tcx>>,
kind: DefKind,
def_id: DefId,
+ span: Span,
) -> Vec<PathSeg> {
// We need to extract the type parameters supplied by the user in
// the path `path`. Due to the current setup, this is a bit of a
@@ -2347,8 +2531,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Case 2. Reference to a variant constructor.
DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => {
- let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap());
- let (generics_def_id, index) = if let Some(adt_def) = adt_def {
+ let (generics_def_id, index) = if let Some(self_ty) = self_ty {
+ let adt_def = self.probe_adt(span, self_ty).unwrap();
debug_assert!(adt_def.is_enum());
(adt_def.did(), last)
} else if last >= 1 && segments[last - 1].args.is_some() {
@@ -2424,7 +2608,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.note("`impl Trait` types can't have type parameters");
});
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
- self.normalize_ty(span, tcx.mk_opaque(did, substs))
+ tcx.mk_opaque(did, substs)
}
Res::Def(
DefKind::Enum
@@ -2444,7 +2628,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assert_eq!(opt_self_ty, None);
let path_segs =
- self.def_ids_for_value_path_segments(path.segments, None, kind, def_id);
+ self.def_ids_for_value_path_segments(path.segments, None, kind, def_id, span);
let generic_segs: FxHashSet<_> =
path_segs.iter().map(|PathSeg(_, index)| index).collect();
self.prohibit_generics(
@@ -2576,7 +2760,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"generic `Self` types are currently not permitted in anonymous constants",
);
if let Some(hir::Node::Item(&hir::Item {
- kind: hir::ItemKind::Impl(ref impl_),
+ kind: hir::ItemKind::Impl(impl_),
..
})) = tcx.hir().get_if_local(def_id)
{
@@ -2584,7 +2768,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
tcx.ty_error_with_guaranteed(err.emit())
} else {
- self.normalize_ty(span, ty)
+ ty
}
}
Res::Def(DefKind::AssocTy, def_id) => {
@@ -2633,7 +2817,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let e = self
.tcx()
.sess
- .delay_span_bug(path.span, "path with `Res:Err` but no error emitted");
+ .delay_span_bug(path.span, "path with `Res::Err` but no error emitted");
self.set_tainted_by_errors(e);
self.tcx().ty_error_with_guaranteed(e)
}
@@ -2648,7 +2832,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
/// Parses the programmer's textual representation of a type into our
- /// internal notion of a type. This is meant to be used within a path.
+ /// internal notion of a type. This is meant to be used within a path.
pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
self.ast_ty_to_ty_inner(ast_ty, false, true)
}
@@ -2659,12 +2843,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
let tcx = self.tcx();
- let result_ty = match ast_ty.kind {
- hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
- hir::TyKind::Ptr(ref mt) => {
+ let result_ty = match &ast_ty.kind {
+ hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
+ hir::TyKind::Ptr(mt) => {
tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
}
- hir::TyKind::Rptr(ref region, ref mt) => {
+ hir::TyKind::Ref(region, mt) => {
let r = self.ast_region_to_region(region, None);
debug!(?r);
let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
@@ -2684,7 +2868,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Some(ast_ty),
))
}
- hir::TyKind::TraitObject(bounds, ref lifetime, repr) => {
+ hir::TyKind::TraitObject(bounds, lifetime, repr) => {
self.maybe_lint_bare_trait(ast_ty, in_path);
let repr = match repr {
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
@@ -2692,12 +2876,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
}
- hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
+ hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
debug!(?maybe_qself, ?path);
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
self.res_to_ty(opt_self_ty, path, false)
}
- hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
+ &hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
let opaque_ty = tcx.hir().item(item_id);
let def_id = item_id.owner_id.to_def_id();
@@ -2708,14 +2892,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
}
}
- hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
+ hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
debug!(?qself, ?segment);
let ty = self.ast_ty_to_ty_inner(qself, false, true);
self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
.map(|(ty, _, _)| ty)
.unwrap_or_else(|_| tcx.ty_error())
}
- hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
+ &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
let def_id = tcx.require_lang_item(lang_item, Some(span));
let (substs, _) = self.create_substs_for_ast_path(
span,
@@ -2727,10 +2911,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
None,
ty::BoundConstness::NotConst,
);
- EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
- .subst(tcx, substs)
+ EarlyBinder(tcx.at(span).type_of(def_id)).subst(tcx, substs)
}
- hir::TyKind::Array(ref ty, ref length) => {
+ hir::TyKind::Array(ty, length) => {
let length = match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
hir::ArrayLen::Body(constant) => {
@@ -2738,10 +2921,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
};
- let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
- self.normalize_ty(ast_ty.span, array_ty)
+ tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length))
}
- hir::TyKind::Typeof(ref e) => {
+ hir::TyKind::Typeof(e) => {
let ty_erased = tcx.type_of(e.def_id);
let ty = tcx.fold_regions(ty_erased, |r, _| {
if r.is_erased() { tcx.lifetimes.re_static } else { r }
@@ -2943,7 +3125,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
hir.get(fn_hir_id) else { return None };
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
- hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
+ hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") };
let trait_ref = self.instantiate_mono_trait_ref(
i.of_trait.as_ref()?,
@@ -3123,7 +3305,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
- diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
+ if self_ty.span.can_be_used_for_suggestions() {
+ diag.multipart_suggestion_verbose(
+ label,
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.emit();