Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower/path.rs')
-rw-r--r--crates/hir-ty/src/lower/path.rs98
1 files changed, 55 insertions, 43 deletions
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index 517f67b828..d47d696259 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -2,7 +2,7 @@
use either::Either;
use hir_def::{
- GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
+ GenericDefId, GenericParamId, Lookup, TraitId, TypeParamId,
expr_store::{
ExpressionStore, HygieneId,
path::{
@@ -17,7 +17,6 @@ use hir_def::{
signatures::TraitFlags,
type_ref::{TypeRef, TypeRefId},
};
-use hir_expand::name::Name;
use rustc_type_ir::{
AliasTerm, AliasTy, AliasTyKind,
inherent::{GenericArgs as _, Region as _, Ty as _},
@@ -31,13 +30,10 @@ use crate::{
consteval::{unknown_const, unknown_const_as_generic},
db::HirDatabase,
generics::{Generics, generics},
- lower::{
- GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData,
- named_associated_type_shorthand_candidates,
- },
+ lower::{GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData},
next_solver::{
- Binder, Clause, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Predicate,
- ProjectionPredicate, Region, TraitRef, Ty,
+ Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, GenericArgs,
+ Predicate, ProjectionPredicate, Region, TraitRef, Ty,
},
};
@@ -479,43 +475,59 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
#[tracing::instrument(skip(self), ret)]
fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> {
let interner = self.ctx.interner;
- let Some(res) = res else {
- return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
- };
+ let db = self.ctx.db;
let def = self.ctx.def;
let segment = self.current_or_prev_segment;
let assoc_name = segment.name;
- let check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
- if name != assoc_name {
- return None;
+ let error_ty = || Ty::new_error(self.ctx.interner, ErrorGuaranteed);
+ let (assoc_type, trait_args) = match res {
+ Some(TypeNs::GenericParam(param)) => {
+ let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand(
+ db,
+ def,
+ param,
+ assoc_name.clone(),
+ ) else {
+ return error_ty();
+ };
+ assoc_type
+ .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
+ .skip_binder()
}
-
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`t.substitution`).
- let substs =
- self.substs_from_path_segment(associated_ty.into(), infer_args, None, true);
-
- let substs = GenericArgs::new_from_iter(
- interner,
- t.args.iter().chain(substs.iter().skip(t.args.len())),
- );
-
- Some(Ty::new_alias(
- interner,
- AliasTyKind::Projection,
- AliasTy::new_from_args(interner, associated_ty.into(), substs),
- ))
+ Some(TypeNs::SelfType(impl_)) => {
+ let Some(impl_trait) = db.impl_trait(impl_) else {
+ return error_ty();
+ };
+ let impl_trait = impl_trait.instantiate_identity();
+ // Searching for `Self::Assoc` in `impl Trait for Type` is like searching for `Self::Assoc` in `Trait`.
+ let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand(
+ db,
+ impl_trait.def_id.0.into(),
+ TypeParamId::trait_self(impl_trait.def_id.0),
+ assoc_name.clone(),
+ ) else {
+ return error_ty();
+ };
+ let (assoc_type, trait_args) = assoc_type
+ .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
+ .skip_binder();
+ (assoc_type, EarlyBinder::bind(trait_args).instantiate(interner, impl_trait.args))
+ }
+ _ => return error_ty(),
};
- named_associated_type_shorthand_candidates(
+
+ // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+ // generic params. It's inefficient to splice the `Substitution`s, so we may want
+ // that method to optionally take parent `Substitution` as we already know them at
+ // this point (`t.substitution`).
+ let substs = self.substs_from_path_segment(assoc_type.into(), infer_args, None, true);
+
+ let substs = GenericArgs::new_from_iter(
interner,
- def,
- res,
- Some(assoc_name.clone()),
- check_alias,
- )
- .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
+ trait_args.iter().chain(substs.iter().skip(trait_args.len())),
+ );
+
+ Ty::new_projection_from_args(interner, assoc_type.into(), substs)
}
fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
@@ -860,9 +872,9 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
let found = associated_type_by_name_including_super_traits(
self.ctx.db,
trait_ref,
- &binding.name,
+ binding.name.clone(),
);
- let (super_trait_ref, associated_ty) = match found {
+ let (associated_ty, super_trait_args) = match found {
None => return SmallVec::new(),
Some(t) => t,
};
@@ -876,7 +888,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
binding.args.as_ref(),
associated_ty.into(),
false, // this is not relevant
- Some(super_trait_ref.self_ty()),
+ Some(super_trait_args.type_at(0)),
PathGenericsSource::AssocType {
segment: this.current_segment_u32(),
assoc_type: binding_idx as u32,
@@ -887,7 +899,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
});
let args = GenericArgs::new_from_iter(
interner,
- super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())),
+ super_trait_args.iter().chain(args.iter().skip(super_trait_args.len())),
);
let projection_term =
AliasTerm::new_from_args(interner, associated_ty.into(), args);