Skip to content

Commit d6cf318

Browse files
committed
feat: support inherent associated type paths
Add support for resolving paths for inherent associated types
1 parent a1c07fd commit d6cf318

2 files changed

Lines changed: 79 additions & 1 deletion

File tree

crates/hir-ty/src/lower/path.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use either::Either;
44
use hir_def::{
5-
GenericDefId, GenericParamId, Lookup, TraitId, TypeParamId,
5+
AssocItemId, GenericDefId, GenericParamId, HasModule, Lookup, TraitId, TypeParamId,
66
expr_store::{
77
ExpressionStore, HygieneId,
88
path::{
@@ -19,6 +19,7 @@ use hir_def::{
1919
};
2020
use rustc_type_ir::{
2121
AliasTerm, AliasTy, AliasTyKind,
22+
fast_reject::{TreatParams, simplify_type},
2223
inherent::{GenericArgs as _, Region as _, Ty as _},
2324
};
2425
use smallvec::SmallVec;
@@ -34,6 +35,7 @@ use crate::{
3435
AssocTypeShorthandResolution, GenericPredicateSource, LifetimeElisionKind,
3536
PathDiagnosticCallbackData,
3637
},
38+
method_resolution::InherentImpls,
3739
next_solver::{
3840
Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, GenericArgs,
3941
Predicate, ProjectionPredicate, Region, TraitRef, Ty,
@@ -520,6 +522,51 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
520522
.skip_binder();
521523
(assoc_type, EarlyBinder::bind(trait_args).instantiate(interner, impl_trait.args))
522524
}
525+
// associated types in inherent impl
526+
Some(TypeNs::AdtId(adt)) => {
527+
let adt_ty = Ty::new_adt(
528+
interner,
529+
adt,
530+
GenericArgs::identity_for_item(interner, adt.into()),
531+
);
532+
let Some(simplified) = simplify_type(interner, adt_ty, TreatParams::AsRigid) else {
533+
return error_ty();
534+
};
535+
536+
let module = adt.module(db);
537+
let krate = module.krate(db);
538+
let block = module.block(db);
539+
540+
let mut found_alias = None;
541+
InherentImpls::for_each_crate_and_block(db, krate, block, &mut |impls| {
542+
if found_alias.is_some() {
543+
return;
544+
}
545+
for &impl_id in impls.for_self_ty(&simplified) {
546+
// skip trait impl, only need inherent impl
547+
if db.impl_signature(impl_id).target_trait.is_some() {
548+
continue;
549+
}
550+
for (name, item) in impl_id.impl_items(db).items.iter() {
551+
if name == assoc_name
552+
&& let AssocItemId::TypeAliasId(alias_id) = item
553+
{
554+
found_alias = Some(*alias_id);
555+
break;
556+
}
557+
}
558+
if found_alias.is_some() {
559+
break;
560+
}
561+
}
562+
});
563+
564+
let Some(alias_id) = found_alias else {
565+
return error_ty();
566+
};
567+
568+
return self.lower_path_inner(TyDefId::TypeAliasId(alias_id), infer_args);
569+
}
523570
_ => return error_ty(),
524571
};
525572

crates/hir-ty/src/tests/traits.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5142,3 +5142,34 @@ fn foo(v: Struct<f32>) {
51425142
"#,
51435143
);
51445144
}
5145+
5146+
#[test]
5147+
fn inherent_associated_type_path() {
5148+
check_infer(
5149+
r#"
5150+
#![feature(inherent_associated_types)]
5151+
5152+
struct A;
5153+
impl A {
5154+
type B = i32;
5155+
}
5156+
5157+
trait C { fn foo() -> Self; }
5158+
impl C for A::B {
5159+
fn foo() -> Self { 1 }
5160+
}
5161+
5162+
fn main() {
5163+
let x: A::B = C::foo();
5164+
}
5165+
"#,
5166+
expect![[r#"
5167+
149..154 '{ 1 }': i32
5168+
151..152 '1': i32
5169+
168..199 '{ ...o(); }': ()
5170+
178..179 'x': i32
5171+
188..194 'C::foo': fn foo<i32>() -> i32
5172+
188..196 'C::foo()': i32
5173+
"#]],
5174+
);
5175+
}

0 commit comments

Comments
 (0)