mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
Auto merge of #13725 - bvanjoi:resolve-const-triat-impls, r=flodiebold
feat: resolve const for trait impls Fixed #13694
This commit is contained in:
commit
a3ea20a142
6 changed files with 245 additions and 18 deletions
|
@ -351,6 +351,7 @@ pub fn eval_const(
|
||||||
.infer
|
.infer
|
||||||
.assoc_resolutions_for_expr(expr_id)
|
.assoc_resolutions_for_expr(expr_id)
|
||||||
.ok_or(ConstEvalError::SemanticError("unresolved assoc item"))?
|
.ok_or(ConstEvalError::SemanticError("unresolved assoc item"))?
|
||||||
|
.0
|
||||||
{
|
{
|
||||||
hir_def::AssocItemId::FunctionId(_) => {
|
hir_def::AssocItemId::FunctionId(_) => {
|
||||||
Err(ConstEvalError::NotSupported("assoc function"))
|
Err(ConstEvalError::NotSupported("assoc function"))
|
||||||
|
|
|
@ -349,7 +349,7 @@ pub struct InferenceResult {
|
||||||
/// For each struct literal or pattern, records the variant it resolves to.
|
/// For each struct literal or pattern, records the variant it resolves to.
|
||||||
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
|
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
|
||||||
/// For each associated item record what it resolves to
|
/// For each associated item record what it resolves to
|
||||||
assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
|
assoc_resolutions: FxHashMap<ExprOrPatId, (AssocItemId, Option<Substitution>)>,
|
||||||
pub diagnostics: Vec<InferenceDiagnostic>,
|
pub diagnostics: Vec<InferenceDiagnostic>,
|
||||||
pub type_of_expr: ArenaMap<ExprId, Ty>,
|
pub type_of_expr: ArenaMap<ExprId, Ty>,
|
||||||
/// For each pattern record the type it resolves to.
|
/// For each pattern record the type it resolves to.
|
||||||
|
@ -379,11 +379,17 @@ impl InferenceResult {
|
||||||
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
|
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
|
||||||
self.variant_resolutions.get(&id.into()).copied()
|
self.variant_resolutions.get(&id.into()).copied()
|
||||||
}
|
}
|
||||||
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
|
pub fn assoc_resolutions_for_expr(
|
||||||
self.assoc_resolutions.get(&id.into()).copied()
|
&self,
|
||||||
|
id: ExprId,
|
||||||
|
) -> Option<(AssocItemId, Option<Substitution>)> {
|
||||||
|
self.assoc_resolutions.get(&id.into()).cloned()
|
||||||
}
|
}
|
||||||
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
|
pub fn assoc_resolutions_for_pat(
|
||||||
self.assoc_resolutions.get(&id.into()).copied()
|
&self,
|
||||||
|
id: PatId,
|
||||||
|
) -> Option<(AssocItemId, Option<Substitution>)> {
|
||||||
|
self.assoc_resolutions.get(&id.into()).cloned()
|
||||||
}
|
}
|
||||||
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
|
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
|
||||||
self.type_mismatches.get(&expr.into())
|
self.type_mismatches.get(&expr.into())
|
||||||
|
@ -647,8 +653,13 @@ impl<'a> InferenceContext<'a> {
|
||||||
self.result.variant_resolutions.insert(id, variant);
|
self.result.variant_resolutions.insert(id, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
|
fn write_assoc_resolution(
|
||||||
self.result.assoc_resolutions.insert(id, item);
|
&mut self,
|
||||||
|
id: ExprOrPatId,
|
||||||
|
item: AssocItemId,
|
||||||
|
subs: Option<Substitution>,
|
||||||
|
) {
|
||||||
|
self.result.assoc_resolutions.insert(id, (item, subs));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
|
fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
|
||||||
|
|
|
@ -212,7 +212,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
AssocItemId::TypeAliasId(_) => unreachable!(),
|
AssocItemId::TypeAliasId(_) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.write_assoc_resolution(id, item);
|
self.write_assoc_resolution(id, item, Some(trait_ref.substitution.clone()));
|
||||||
Some((def, Some(trait_ref.substitution)))
|
Some((def, Some(trait_ref.substitution)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +273,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
|
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.write_assoc_resolution(id, item);
|
self.write_assoc_resolution(id, item, substs.clone());
|
||||||
Some((def, substs))
|
Some((def, substs))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -642,6 +642,30 @@ pub(crate) fn iterate_method_candidates<T>(
|
||||||
slot
|
slot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lookup_impl_const(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
env: Arc<TraitEnvironment>,
|
||||||
|
const_id: ConstId,
|
||||||
|
subs: Substitution,
|
||||||
|
) -> ConstId {
|
||||||
|
let trait_id = match const_id.lookup(db.upcast()).container {
|
||||||
|
ItemContainerId::TraitId(id) => id,
|
||||||
|
_ => return const_id,
|
||||||
|
};
|
||||||
|
let substitution = Substitution::from_iter(Interner, subs.iter(Interner));
|
||||||
|
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution };
|
||||||
|
|
||||||
|
let const_data = db.const_data(const_id);
|
||||||
|
let name = match const_data.name.as_ref() {
|
||||||
|
Some(name) => name,
|
||||||
|
None => return const_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name)
|
||||||
|
.and_then(|assoc| if let AssocItemId::ConstId(id) = assoc { Some(id) } else { None })
|
||||||
|
.unwrap_or(const_id)
|
||||||
|
}
|
||||||
|
|
||||||
/// Looks up the impl method that actually runs for the trait method `func`.
|
/// Looks up the impl method that actually runs for the trait method `func`.
|
||||||
///
|
///
|
||||||
/// Returns `func` if it's not a method defined in a trait or the lookup failed.
|
/// 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(
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = &db.function_data(func).name;
|
let name = &db.function_data(func).name;
|
||||||
lookup_impl_method_for_trait_ref(trait_ref, db, env, name).unwrap_or(func)
|
lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name)
|
||||||
|
.and_then(|assoc| if let AssocItemId::FunctionId(id) = assoc { Some(id) } else { None })
|
||||||
|
.unwrap_or(func)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_impl_method_for_trait_ref(
|
fn lookup_impl_assoc_item_for_trait_ref(
|
||||||
trait_ref: TraitRef,
|
trait_ref: TraitRef,
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
env: Arc<TraitEnvironment>,
|
env: Arc<TraitEnvironment>,
|
||||||
name: &Name,
|
name: &Name,
|
||||||
) -> Option<FunctionId> {
|
) -> Option<AssocItemId> {
|
||||||
let self_ty = trait_ref.self_type_parameter(Interner);
|
let self_ty = trait_ref.self_type_parameter(Interner);
|
||||||
let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
|
let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
|
||||||
let impls = db.trait_impls_in_deps(env.krate);
|
let impls = db.trait_impls_in_deps(env.krate);
|
||||||
|
@ -681,7 +707,15 @@ fn lookup_impl_method_for_trait_ref(
|
||||||
|
|
||||||
let impl_data = find_matching_impl(impls, table, trait_ref)?;
|
let impl_data = find_matching_impl(impls, table, trait_ref)?;
|
||||||
impl_data.items.iter().find_map(|it| match it {
|
impl_data.items.iter().find_map(|it| match it {
|
||||||
AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
|
AssocItemId::FunctionId(f) => {
|
||||||
|
(db.function_data(*f).name == *name).then(|| AssocItemId::FunctionId(*f))
|
||||||
|
}
|
||||||
|
AssocItemId::ConstId(c) => db
|
||||||
|
.const_data(*c)
|
||||||
|
.name
|
||||||
|
.as_ref()
|
||||||
|
.map(|n| *n == *name)
|
||||||
|
.and_then(|result| if result { Some(AssocItemId::ConstId(*c)) } else { None }),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ use hir_def::{
|
||||||
path::{ModPath, Path, PathKind},
|
path::{ModPath, Path, PathKind},
|
||||||
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||||
type_ref::Mutability,
|
type_ref::Mutability,
|
||||||
AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
|
AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
|
||||||
Lookup, ModuleDefId, TraitId, VariantId,
|
LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId,
|
||||||
};
|
};
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
builtin_fn_macro::BuiltinFnLikeExpander,
|
builtin_fn_macro::BuiltinFnLikeExpander,
|
||||||
|
@ -482,7 +482,7 @@ impl SourceAnalyzer {
|
||||||
let infer = self.infer.as_deref()?;
|
let infer = self.infer.as_deref()?;
|
||||||
if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
|
if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
|
||||||
let expr_id = self.expr_id(db, &path_expr.into())?;
|
let expr_id = self.expr_id(db, &path_expr.into())?;
|
||||||
if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) {
|
if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) {
|
||||||
let assoc = match assoc {
|
let assoc = match assoc {
|
||||||
AssocItemId::FunctionId(f_in_trait) => {
|
AssocItemId::FunctionId(f_in_trait) => {
|
||||||
match infer.type_of_expr.get(expr_id) {
|
match infer.type_of_expr.get(expr_id) {
|
||||||
|
@ -501,7 +501,13 @@ impl SourceAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AssocItemId::ConstId(const_id) => {
|
||||||
|
if let Some(subs) = subs {
|
||||||
|
self.resolve_impl_const_or_trait_def(db, const_id, subs).into()
|
||||||
|
} else {
|
||||||
|
assoc
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => assoc,
|
_ => assoc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -515,7 +521,7 @@ impl SourceAnalyzer {
|
||||||
prefer_value_ns = true;
|
prefer_value_ns = true;
|
||||||
} else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
|
} else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
|
||||||
let pat_id = self.pat_id(&path_pat.into())?;
|
let pat_id = self.pat_id(&path_pat.into())?;
|
||||||
if let Some(assoc) = infer.assoc_resolutions_for_pat(pat_id) {
|
if let Some((assoc, _)) = infer.assoc_resolutions_for_pat(pat_id) {
|
||||||
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
|
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
|
||||||
}
|
}
|
||||||
if let Some(VariantId::EnumVariantId(variant)) =
|
if let Some(VariantId::EnumVariantId(variant)) =
|
||||||
|
@ -792,6 +798,24 @@ impl SourceAnalyzer {
|
||||||
method_resolution::lookup_impl_method(db, env, func, substs)
|
method_resolution::lookup_impl_method(db, env, func, substs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_impl_const_or_trait_def(
|
||||||
|
&self,
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
const_id: ConstId,
|
||||||
|
subs: Substitution,
|
||||||
|
) -> ConstId {
|
||||||
|
let krate = self.resolver.krate();
|
||||||
|
let owner = match self.resolver.body_owner() {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return const_id,
|
||||||
|
};
|
||||||
|
let env = owner.as_generic_def_id().map_or_else(
|
||||||
|
|| Arc::new(hir_ty::TraitEnvironment::empty(krate)),
|
||||||
|
|d| db.trait_environment(d),
|
||||||
|
);
|
||||||
|
method_resolution::lookup_impl_const(db, env, const_id, subs)
|
||||||
|
}
|
||||||
|
|
||||||
fn lang_trait_fn(
|
fn lang_trait_fn(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
|
|
|
@ -3657,6 +3657,163 @@ enum E {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hover_const_eval() {
|
fn hover_const_eval() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
trait T {
|
||||||
|
const B: bool = false;
|
||||||
|
}
|
||||||
|
impl T for <()> {
|
||||||
|
/// true
|
||||||
|
const B: bool = true;
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
<()>::B$0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*B*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const B: bool = true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
true
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct A {
|
||||||
|
i: i32
|
||||||
|
};
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
const AA: A = A {
|
||||||
|
i: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
impl T for i32 {
|
||||||
|
const AA: A = A {
|
||||||
|
i: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
<i32>::AA$0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*AA*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const AA: A = A {
|
||||||
|
i: 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
trait T {
|
||||||
|
/// false
|
||||||
|
const B: bool = false;
|
||||||
|
}
|
||||||
|
impl T for () {
|
||||||
|
/// true
|
||||||
|
const B: bool = true;
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
T::B$0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*B*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const B: bool = false
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
false
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
trait T {
|
||||||
|
/// false
|
||||||
|
const B: bool = false;
|
||||||
|
}
|
||||||
|
impl T for () {
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
<()>::B$0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*B*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const B: bool = false
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
false
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
trait T {
|
||||||
|
/// false
|
||||||
|
const B: bool = false;
|
||||||
|
}
|
||||||
|
impl T for () {
|
||||||
|
/// true
|
||||||
|
const B: bool = true;
|
||||||
|
}
|
||||||
|
impl T for i32 {}
|
||||||
|
fn main() {
|
||||||
|
<i32>::B$0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*B*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const B: bool = false
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
false
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
|
||||||
// show hex for <10
|
// show hex for <10
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
|
|
Loading…
Reference in a new issue