From 001dd6a2000ce4adada0ab6e4ed8fd67cb8eb569 Mon Sep 17 00:00:00 2001
From: Florian Diebold <florian.diebold@freiheit.com>
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 05cf4646a89..e2b228e80d3 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 df24c16a3f8..6a2aded021c 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<TraitEnvironment> {
         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::<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 })
     }
 }
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
index 0f754eb9c75..ae47855e958 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 17611ddbfa4..aa2018944ce 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