Repository: rust-analyzer/rust-analyzer
Pull request #3145 (2020-02-14 19:39:35)

Make Self implement the trait inside trait default methods


Patch:
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<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 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_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 250255813e..fef405b7f5 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -418,10 +418,8 @@ pub fn get_rustc_cfg_options() -> CfgOptions {
     // Some nightly-only cfgs, which are required for stdlib
     {
         cfg_options.insert_atom("target_thread_local".into());
-        for &target_has_atomic in ["8", "16", "32", "64", "cas", "ptr"].iter() {
-            cfg_options.insert_key_value("target_has_atomic".into(), target_has_atomic.into());
-            cfg_options
-                .insert_key_value("target_has_atomic_load_store".into(), target_has_atomic.into());
+        for &target_has_atomic in ["16", "32", "64", "8", "cas", "ptr"].iter() {
+            cfg_options.insert_key_value("target_has_atomic".into(), target_has_atomic.into())
         }
     }
 
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc
index 1badba94fa..b9ecc70555 100644
--- a/docs/user/readme.adoc
+++ b/docs/user/readme.adoc
@@ -11,9 +11,6 @@ This manual focuses on a specific usage of the library -- the implementation of
 https://microsoft.github.io/language-server-protocol/[Language Server Protocol].
 LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic feature like completion or goto definition by talking to an external language server process.
 
-To improve this document, send a pull request against
-https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/readme.adoc[this file].
-
 == Installation
 
 In theory, one should be able to just install the server binary and have it automatically work with any editor.
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 2bcd76d60b..25b64301c7 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -109,8 +109,11 @@ fn install_clippy() -> Result<()> {
 
 pub fn run_fuzzer() -> Result<()> {
     let _d = pushd("./crates/ra_syntax");
-    if run!("cargo fuzz --help").is_err() {
-        run!("cargo install cargo-fuzz")?;
+    match run!("cargo fuzz --help") {
+        Ok(_) => (),
+        _ => {
+            run!("cargo install cargo-fuzz")?;
+        }
     };
 
     run!("rustup run nightly -- cargo fuzz run parser")?;


Test patch:
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