Skip to content

Commit a3ea20a

Browse files
committed
Auto merge of rust-lang#13725 - bvanjoi:resolve-const-triat-impls, r=flodiebold
feat: resolve const for trait impls Fixed rust-lang#13694
2 parents 632f804 + 7012b50 commit a3ea20a

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
@@ -349,7 +349,7 @@ pub struct InferenceResult {
349349
/// For each struct literal or pattern, records the variant it resolves to.
350350
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
351351
/// For each associated item record what it resolves to
352-
assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
352+
assoc_resolutions: FxHashMap<ExprOrPatId, (AssocItemId, Option<Substitution>)>,
353353
pub diagnostics: Vec<InferenceDiagnostic>,
354354
pub type_of_expr: ArenaMap<ExprId, Ty>,
355355
/// For each pattern record the type it resolves to.
@@ -379,11 +379,17 @@ impl InferenceResult {
379379
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
380380
self.variant_resolutions.get(&id.into()).copied()
381381
}
382-
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
383-
self.assoc_resolutions.get(&id.into()).copied()
382+
pub fn assoc_resolutions_for_expr(
383+
&self,
384+
id: ExprId,
385+
) -> Option<(AssocItemId, Option<Substitution>)> {
386+
self.assoc_resolutions.get(&id.into()).cloned()
384387
}
385-
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
386-
self.assoc_resolutions.get(&id.into()).copied()
388+
pub fn assoc_resolutions_for_pat(
389+
&self,
390+
id: PatId,
391+
) -> Option<(AssocItemId, Option<Substitution>)> {
392+
self.assoc_resolutions.get(&id.into()).cloned()
387393
}
388394
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
389395
self.type_mismatches.get(&expr.into())
@@ -647,8 +653,13 @@ impl<'a> InferenceContext<'a> {
647653
self.result.variant_resolutions.insert(id, variant);
648654
}
649655

650-
fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
651-
self.result.assoc_resolutions.insert(id, item);
656+
fn write_assoc_resolution(
657+
&mut self,
658+
id: ExprOrPatId,
659+
item: AssocItemId,
660+
subs: Option<Substitution>,
661+
) {
662+
self.result.assoc_resolutions.insert(id, (item, subs));
652663
}
653664

654665
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
@@ -3657,6 +3657,163 @@ enum E {
36573657

36583658
#[test]
36593659
fn hover_const_eval() {
3660+
check(
3661+
r#"
3662+
trait T {
3663+
const B: bool = false;
3664+
}
3665+
impl T for <()> {
3666+
/// true
3667+
const B: bool = true;
3668+
}
3669+
fn main() {
3670+
<()>::B$0;
3671+
}
3672+
"#,
3673+
expect![[r#"
3674+
*B*
3675+
3676+
```rust
3677+
test
3678+
```
3679+
3680+
```rust
3681+
const B: bool = true
3682+
```
3683+
3684+
---
3685+
3686+
true
3687+
"#]],
3688+
);
3689+
3690+
check(
3691+
r#"
3692+
struct A {
3693+
i: i32
3694+
};
3695+
3696+
trait T {
3697+
const AA: A = A {
3698+
i: 1
3699+
};
3700+
}
3701+
impl T for i32 {
3702+
const AA: A = A {
3703+
i: 2
3704+
}
3705+
}
3706+
fn main() {
3707+
<i32>::AA$0;
3708+
}
3709+
"#,
3710+
expect![[r#"
3711+
*AA*
3712+
3713+
```rust
3714+
test
3715+
```
3716+
3717+
```rust
3718+
const AA: A = A {
3719+
i: 2
3720+
}
3721+
```
3722+
"#]],
3723+
);
3724+
3725+
check(
3726+
r#"
3727+
trait T {
3728+
/// false
3729+
const B: bool = false;
3730+
}
3731+
impl T for () {
3732+
/// true
3733+
const B: bool = true;
3734+
}
3735+
fn main() {
3736+
T::B$0;
3737+
}
3738+
"#,
3739+
expect![[r#"
3740+
*B*
3741+
3742+
```rust
3743+
test
3744+
```
3745+
3746+
```rust
3747+
const B: bool = false
3748+
```
3749+
3750+
---
3751+
3752+
false
3753+
"#]],
3754+
);
3755+
3756+
check(
3757+
r#"
3758+
trait T {
3759+
/// false
3760+
const B: bool = false;
3761+
}
3762+
impl T for () {
3763+
}
3764+
fn main() {
3765+
<()>::B$0;
3766+
}
3767+
"#,
3768+
expect![[r#"
3769+
*B*
3770+
3771+
```rust
3772+
test
3773+
```
3774+
3775+
```rust
3776+
const B: bool = false
3777+
```
3778+
3779+
---
3780+
3781+
false
3782+
"#]],
3783+
);
3784+
3785+
check(
3786+
r#"
3787+
trait T {
3788+
/// false
3789+
const B: bool = false;
3790+
}
3791+
impl T for () {
3792+
/// true
3793+
const B: bool = true;
3794+
}
3795+
impl T for i32 {}
3796+
fn main() {
3797+
<i32>::B$0;
3798+
}
3799+
"#,
3800+
expect![[r#"
3801+
*B*
3802+
3803+
```rust
3804+
test
3805+
```
3806+
3807+
```rust
3808+
const B: bool = false
3809+
```
3810+
3811+
---
3812+
3813+
false
3814+
"#]],
3815+
);
3816+
36603817
// show hex for <10
36613818
check(
36623819
r#"

0 commit comments

Comments
 (0)