From 001dd6a2000ce4adada0ab6e4ed8fd67cb8eb569 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 19:16:42 +0100 Subject: [PATCH] Make Self implement the trait inside trait default methods --- crates/ra_hir_def/src/resolver.rs | 6 +--- crates/ra_hir_ty/src/lower.rs | 32 ++++++++++++++++--- crates/ra_hir_ty/src/marks.rs | 1 + crates/ra_hir_ty/src/tests/traits.rs | 48 ++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 9 deletions(-) diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 05cf4646a8..e2b228e80d 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs @@ -542,11 +542,7 @@ impl Resolver { fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver { let params = db.generic_params(def); - if params.types.is_empty() { - self - } else { - self.push_scope(Scope::GenericParams { def, params }) - } + self.push_scope(Scope::GenericParams { def, params }) } fn push_impl_block_scope(self, impl_block: ImplId) -> Resolver { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index df24c16a3f..6a2aded021 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -14,9 +14,9 @@ use hir_def::{ path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, - AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, - LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, - VariantId, + AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, + ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, + UnionId, VariantId, }; use ra_arena::map::ArenaMap; use ra_db::CrateId; @@ -672,11 +672,35 @@ impl TraitEnvironment { pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { let ctx = TyLoweringContext::new(db, &resolver) .with_type_param_mode(TypeParamLoweringMode::Placeholder); - let predicates = resolver + let mut predicates = resolver .where_predicates_in_scope() .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) .collect::>(); + if let Some(def) = resolver.generic_def() { + let container: Option = 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` 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 }) } } diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs index 0f754eb9c7..ae47855e95 100644 --- a/crates/ra_hir_ty/src/marks.rs +++ b/crates/ra_hir_ty/src/marks.rs @@ -6,4 +6,5 @@ test_utils::marks!( type_var_resolves_to_int_var match_ergonomics_ref coerce_merge_fail_fallback + trait_self_implements_self ); diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 17611ddbfa..aa2018944c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -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] fn infer_project_associated_type() { // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234