mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 06:03:58 +00:00
Merge #3145
3145: Make Self implement the trait inside trait default methods r=matklad a=flodiebold Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
This commit is contained in:
commit
6fb36dfdcb
4 changed files with 78 additions and 9 deletions
|
@ -542,11 +542,7 @@ impl Resolver {
|
||||||
|
|
||||||
fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver {
|
fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver {
|
||||||
let params = db.generic_params(def);
|
let params = db.generic_params(def);
|
||||||
if params.types.is_empty() {
|
self.push_scope(Scope::GenericParams { def, params })
|
||||||
self
|
|
||||||
} else {
|
|
||||||
self.push_scope(Scope::GenericParams { def, params })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_impl_block_scope(self, impl_block: ImplId) -> Resolver {
|
fn push_impl_block_scope(self, impl_block: ImplId) -> Resolver {
|
||||||
|
|
|
@ -14,9 +14,9 @@ use hir_def::{
|
||||||
path::{GenericArg, Path, PathSegment, PathSegments},
|
path::{GenericArg, Path, PathSegment, PathSegments},
|
||||||
resolver::{HasResolver, Resolver, TypeNs},
|
resolver::{HasResolver, Resolver, TypeNs},
|
||||||
type_ref::{TypeBound, TypeRef},
|
type_ref::{TypeBound, TypeRef},
|
||||||
AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
|
AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule,
|
||||||
LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
|
ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
|
||||||
VariantId,
|
UnionId, VariantId,
|
||||||
};
|
};
|
||||||
use ra_arena::map::ArenaMap;
|
use ra_arena::map::ArenaMap;
|
||||||
use ra_db::CrateId;
|
use ra_db::CrateId;
|
||||||
|
@ -672,11 +672,35 @@ impl TraitEnvironment {
|
||||||
pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> {
|
pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> {
|
||||||
let ctx = TyLoweringContext::new(db, &resolver)
|
let ctx = TyLoweringContext::new(db, &resolver)
|
||||||
.with_type_param_mode(TypeParamLoweringMode::Placeholder);
|
.with_type_param_mode(TypeParamLoweringMode::Placeholder);
|
||||||
let predicates = resolver
|
let mut predicates = resolver
|
||||||
.where_predicates_in_scope()
|
.where_predicates_in_scope()
|
||||||
.flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred))
|
.flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if let Some(def) = resolver.generic_def() {
|
||||||
|
let container: Option<AssocContainerId> = match def {
|
||||||
|
// FIXME: is there a function for this?
|
||||||
|
GenericDefId::FunctionId(f) => Some(f.lookup(db).container),
|
||||||
|
GenericDefId::AdtId(_) => None,
|
||||||
|
GenericDefId::TraitId(_) => None,
|
||||||
|
GenericDefId::TypeAliasId(t) => Some(t.lookup(db).container),
|
||||||
|
GenericDefId::ImplId(_) => None,
|
||||||
|
GenericDefId::EnumVariantId(_) => None,
|
||||||
|
GenericDefId::ConstId(c) => Some(c.lookup(db).container),
|
||||||
|
};
|
||||||
|
if let Some(AssocContainerId::TraitId(trait_id)) = container {
|
||||||
|
// add `Self: Trait<T1, T2, ...>` to the environment in trait
|
||||||
|
// function default implementations (and hypothetical code
|
||||||
|
// inside consts or type aliases)
|
||||||
|
test_utils::tested_by!(trait_self_implements_self);
|
||||||
|
let substs = Substs::type_params(db, trait_id);
|
||||||
|
let trait_ref = TraitRef { trait_: trait_id, substs };
|
||||||
|
let pred = GenericPredicate::Implemented(trait_ref);
|
||||||
|
|
||||||
|
predicates.push(pred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Arc::new(TraitEnvironment { predicates })
|
Arc::new(TraitEnvironment { predicates })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,5 @@ test_utils::marks!(
|
||||||
type_var_resolves_to_int_var
|
type_var_resolves_to_int_var
|
||||||
match_ergonomics_ref
|
match_ergonomics_ref
|
||||||
coerce_merge_fail_fallback
|
coerce_merge_fail_fallback
|
||||||
|
trait_self_implements_self
|
||||||
);
|
);
|
||||||
|
|
|
@ -299,6 +299,54 @@ fn test() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trait_default_method_self_bound_implements_trait() {
|
||||||
|
test_utils::covers!(trait_self_implements_self);
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
trait Trait {
|
||||||
|
fn foo(&self) -> i64;
|
||||||
|
fn bar(&self) -> {
|
||||||
|
let x = self.foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[27; 31) 'self': &Self
|
||||||
|
[53; 57) 'self': &Self
|
||||||
|
[62; 97) '{ ... }': ()
|
||||||
|
[76; 77) 'x': i64
|
||||||
|
[80; 84) 'self': &Self
|
||||||
|
[80; 90) 'self.foo()': i64
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trait_default_method_self_bound_implements_super_trait() {
|
||||||
|
test_utils::covers!(trait_self_implements_self);
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
trait SuperTrait {
|
||||||
|
fn foo(&self) -> i64;
|
||||||
|
}
|
||||||
|
trait Trait: SuperTrait {
|
||||||
|
fn bar(&self) -> {
|
||||||
|
let x = self.foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[32; 36) 'self': &Self
|
||||||
|
[86; 90) 'self': &Self
|
||||||
|
[95; 130) '{ ... }': ()
|
||||||
|
[109; 110) 'x': i64
|
||||||
|
[113; 117) 'self': &Self
|
||||||
|
[113; 123) 'self.foo()': i64
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_project_associated_type() {
|
fn infer_project_associated_type() {
|
||||||
// y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
|
// y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
|
||||||
|
|
Loading…
Reference in a new issue