Skip to content

Commit 7012b50

Browse files
committed
feat: resolve const for trait impls(close rust-lang#13694)
1 parent a2beeb8 commit 7012b50

File tree

6 files changed

+245
-18
lines changed

6 files changed

+245
-18
lines changed

crates/hir-ty/src/consteval.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ pub fn eval_const(
351351
.infer
352352
.assoc_resolutions_for_expr(expr_id)
353353
.ok_or(ConstEvalError::SemanticError("unresolved assoc item"))?
354+
.0
354355
{
355356
hir_def::AssocItemId::FunctionId(_) => {
356357
Err(ConstEvalError::NotSupported("assoc function"))

crates/hir-ty/src/infer.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ pub struct InferenceResult {
330330
/// For each struct literal or pattern, records the variant it resolves to.
331331
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
332332
/// For each associated item record what it resolves to
333-
assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
333+
assoc_resolutions: FxHashMap<ExprOrPatId, (AssocItemId, Option<Substitution>)>,
334334
pub diagnostics: Vec<InferenceDiagnostic>,
335335
pub type_of_expr: ArenaMap<ExprId, Ty>,
336336
/// For each pattern record the type it resolves to.
@@ -360,11 +360,17 @@ impl InferenceResult {
360360
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
361361
self.variant_resolutions.get(&id.into()).copied()
362362
}
363-
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
364-
self.assoc_resolutions.get(&id.into()).copied()
363+
pub fn assoc_resolutions_for_expr(
364+
&self,
365+
id: ExprId,
366+
) -> Option<(AssocItemId, Option<Substitution>)> {
367+
self.assoc_resolutions.get(&id.into()).cloned()
365368
}
366-
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
367-
self.assoc_resolutions.get(&id.into()).copied()
369+
pub fn assoc_resolutions_for_pat(
370+
&self,
371+
id: PatId,
372+
) -> Option<(AssocItemId, Option<Substitution>)> {
373+
self.assoc_resolutions.get(&id.into()).cloned()
368374
}
369375
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
370376
self.type_mismatches.get(&expr.into())
@@ -621,8 +627,13 @@ impl<'a> InferenceContext<'a> {
621627
self.result.variant_resolutions.insert(id, variant);
622628
}
623629

624-
fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
625-
self.result.assoc_resolutions.insert(id, item);
630+
fn write_assoc_resolution(
631+
&mut self,
632+
id: ExprOrPatId,
633+
item: AssocItemId,
634+
subs: Option<Substitution>,
635+
) {
636+
self.result.assoc_resolutions.insert(id, (item, subs));
626637
}
627638

628639
fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl<'a> InferenceContext<'a> {
212212
AssocItemId::TypeAliasId(_) => unreachable!(),
213213
};
214214

215-
self.write_assoc_resolution(id, item);
215+
self.write_assoc_resolution(id, item, Some(trait_ref.substitution.clone()));
216216
Some((def, Some(trait_ref.substitution)))
217217
}
218218

@@ -273,7 +273,7 @@ impl<'a> InferenceContext<'a> {
273273
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
274274
};
275275

276-
self.write_assoc_resolution(id, item);
276+
self.write_assoc_resolution(id, item, substs.clone());
277277
Some((def, substs))
278278
},
279279
)

crates/hir-ty/src/method_resolution.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,30 @@ pub(crate) fn iterate_method_candidates<T>(
642642
slot
643643
}
644644

645+
pub fn lookup_impl_const(
646+
db: &dyn HirDatabase,
647+
env: Arc<TraitEnvironment>,
648+
const_id: ConstId,
649+
subs: Substitution,
650+
) -> ConstId {
651+
let trait_id = match const_id.lookup(db.upcast()).container {
652+
ItemContainerId::TraitId(id) => id,
653+
_ => return const_id,
654+
};
655+
let substitution = Substitution::from_iter(Interner, subs.iter(Interner));
656+
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution };
657+
658+
let const_data = db.const_data(const_id);
659+
let name = match const_data.name.as_ref() {
660+
Some(name) => name,
661+
None => return const_id,
662+
};
663+
664+
lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name)
665+
.and_then(|assoc| if let AssocItemId::ConstId(id) = assoc { Some(id) } else { None })
666+
.unwrap_or(const_id)
667+
}
668+
645669
/// Looks up the impl method that actually runs for the trait method `func`.
646670
///
647671
/// Returns `func` if it's not a method defined in a trait or the lookup failed.
@@ -663,15 +687,17 @@ pub fn lookup_impl_method(
663687
};
664688

665689
let name = &db.function_data(func).name;
666-
lookup_impl_method_for_trait_ref(trait_ref, db, env, name).unwrap_or(func)
690+
lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name)
691+
.and_then(|assoc| if let AssocItemId::FunctionId(id) = assoc { Some(id) } else { None })
692+
.unwrap_or(func)
667693
}
668694

669-
fn lookup_impl_method_for_trait_ref(
695+
fn lookup_impl_assoc_item_for_trait_ref(
670696
trait_ref: TraitRef,
671697
db: &dyn HirDatabase,
672698
env: Arc<TraitEnvironment>,
673699
name: &Name,
674-
) -> Option<FunctionId> {
700+
) -> Option<AssocItemId> {
675701
let self_ty = trait_ref.self_type_parameter(Interner);
676702
let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
677703
let impls = db.trait_impls_in_deps(env.krate);
@@ -681,7 +707,15 @@ fn lookup_impl_method_for_trait_ref(
681707

682708
let impl_data = find_matching_impl(impls, table, trait_ref)?;
683709
impl_data.items.iter().find_map(|it| match it {
684-
AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
710+
AssocItemId::FunctionId(f) => {
711+
(db.function_data(*f).name == *name).then(|| AssocItemId::FunctionId(*f))
712+
}
713+
AssocItemId::ConstId(c) => db
714+
.const_data(*c)
715+
.name
716+
.as_ref()
717+
.map(|n| *n == *name)
718+
.and_then(|result| if result { Some(AssocItemId::ConstId(*c)) } else { None }),
685719
_ => None,
686720
})
687721
}

crates/hir/src/source_analyzer.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use hir_def::{
2121
path::{ModPath, Path, PathKind},
2222
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
2323
type_ref::Mutability,
24-
AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
25-
Lookup, ModuleDefId, TraitId, VariantId,
24+
AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
25+
LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId,
2626
};
2727
use hir_expand::{
2828
builtin_fn_macro::BuiltinFnLikeExpander,
@@ -482,7 +482,7 @@ impl SourceAnalyzer {
482482
let infer = self.infer.as_deref()?;
483483
if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
484484
let expr_id = self.expr_id(db, &path_expr.into())?;
485-
if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) {
485+
if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) {
486486
let assoc = match assoc {
487487
AssocItemId::FunctionId(f_in_trait) => {
488488
match infer.type_of_expr.get(expr_id) {
@@ -501,7 +501,13 @@ impl SourceAnalyzer {
501501
}
502502
}
503503
}
504-
504+
AssocItemId::ConstId(const_id) => {
505+
if let Some(subs) = subs {
506+
self.resolve_impl_const_or_trait_def(db, const_id, subs).into()
507+
} else {
508+
assoc
509+
}
510+
}
505511
_ => assoc,
506512
};
507513

@@ -515,7 +521,7 @@ impl SourceAnalyzer {
515521
prefer_value_ns = true;
516522
} else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
517523
let pat_id = self.pat_id(&path_pat.into())?;
518-
if let Some(assoc) = infer.assoc_resolutions_for_pat(pat_id) {
524+
if let Some((assoc, _)) = infer.assoc_resolutions_for_pat(pat_id) {
519525
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
520526
}
521527
if let Some(VariantId::EnumVariantId(variant)) =
@@ -792,6 +798,24 @@ impl SourceAnalyzer {
792798
method_resolution::lookup_impl_method(db, env, func, substs)
793799
}
794800

801+
fn resolve_impl_const_or_trait_def(
802+
&self,
803+
db: &dyn HirDatabase,
804+
const_id: ConstId,
805+
subs: Substitution,
806+
) -> ConstId {
807+
let krate = self.resolver.krate();
808+
let owner = match self.resolver.body_owner() {
809+
Some(it) => it,
810+
None => return const_id,
811+
};
812+
let env = owner.as_generic_def_id().map_or_else(
813+
|| Arc::new(hir_ty::TraitEnvironment::empty(krate)),
814+
|d| db.trait_environment(d),
815+
);
816+
method_resolution::lookup_impl_const(db, env, const_id, subs)
817+
}
818+
795819
fn lang_trait_fn(
796820
&self,
797821
db: &dyn HirDatabase,

crates/ide/src/hover/tests.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3636,6 +3636,163 @@ enum E {
36363636

36373637
#[test]
36383638
fn hover_const_eval() {
3639+
check(
3640+
r#"
3641+
trait T {
3642+
const B: bool = false;
3643+
}
3644+
impl T for <()> {
3645+
/// true
3646+
const B: bool = true;
3647+
}
3648+
fn main() {
3649+
<()>::B$0;
3650+
}
3651+
"#,
3652+
expect![[r#"
3653+
*B*
3654+
3655+
```rust
3656+
test
3657+
```
3658+
3659+
```rust
3660+
const B: bool = true
3661+
```
3662+
3663+
---
3664+
3665+
true
3666+
"#]],
3667+
);
3668+
3669+
check(
3670+
r#"
3671+
struct A {
3672+
i: i32
3673+
};
3674+
3675+
trait T {
3676+
const AA: A = A {
3677+
i: 1
3678+
};
3679+
}
3680+
impl T for i32 {
3681+
const AA: A = A {
3682+
i: 2
3683+
}
3684+
}
3685+
fn main() {
3686+
<i32>::AA$0;
3687+
}
3688+
"#,
3689+
expect![[r#"
3690+
*AA*
3691+
3692+
```rust
3693+
test
3694+
```
3695+
3696+
```rust
3697+
const AA: A = A {
3698+
i: 2
3699+
}
3700+
```
3701+
"#]],
3702+
);
3703+
3704+
check(
3705+
r#"
3706+
trait T {
3707+
/// false
3708+
const B: bool = false;
3709+
}
3710+
impl T for () {
3711+
/// true
3712+
const B: bool = true;
3713+
}
3714+
fn main() {
3715+
T::B$0;
3716+
}
3717+
"#,
3718+
expect![[r#"
3719+
*B*
3720+
3721+
```rust
3722+
test
3723+
```
3724+
3725+
```rust
3726+
const B: bool = false
3727+
```
3728+
3729+
---
3730+
3731+
false
3732+
"#]],
3733+
);
3734+
3735+
check(
3736+
r#"
3737+
trait T {
3738+
/// false
3739+
const B: bool = false;
3740+
}
3741+
impl T for () {
3742+
}
3743+
fn main() {
3744+
<()>::B$0;
3745+
}
3746+
"#,
3747+
expect![[r#"
3748+
*B*
3749+
3750+
```rust
3751+
test
3752+
```
3753+
3754+
```rust
3755+
const B: bool = false
3756+
```
3757+
3758+
---
3759+
3760+
false
3761+
"#]],
3762+
);
3763+
3764+
check(
3765+
r#"
3766+
trait T {
3767+
/// false
3768+
const B: bool = false;
3769+
}
3770+
impl T for () {
3771+
/// true
3772+
const B: bool = true;
3773+
}
3774+
impl T for i32 {}
3775+
fn main() {
3776+
<i32>::B$0;
3777+
}
3778+
"#,
3779+
expect![[r#"
3780+
*B*
3781+
3782+
```rust
3783+
test
3784+
```
3785+
3786+
```rust
3787+
const B: bool = false
3788+
```
3789+
3790+
---
3791+
3792+
false
3793+
"#]],
3794+
);
3795+
36393796
// show hex for <10
36403797
check(
36413798
r#"

0 commit comments

Comments
 (0)