Repository: rust-analyzer/rust-analyzer (rust)

Issue:
clone on PathBuf is unknown
In the following Code:
```rust
use std::path::PathBuf;

fn main() {
    let p = PathBuf::new();
    let p2 = p.clone();
}
```
Hovering on `clone` or `p2` gives `{unknown}`, even though `p` is indicated as `PathBuf` which implements `Clone`.

`clone` is also not shown in autocompletion:
![image](https://user-images.githubusercontent.com/23530209/79955513-31d55900-847f-11ea-844c-752820e178e1.png)

System Info:
rust-analyzer version: 2020-04-20
vscode version 1.44.2
Rust version 1.42.0

Pull request description:
Use core instead of std for builtin derive macros
Fixed #4087.

We can't use `$crate` here right now because : 

1. We have to able to detect `macro` 2.0 in collecting phase for finding `rustc_builtin_macro` attrs.
2. And we have to make hygiene works for builtin derive macro.

r= @flodiebold 

Patch:
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index bb45b0f1da..e60f879a39 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
 };
 
 use crate::db::AstDatabase;
-use crate::{name, quote, LazyMacroId, MacroDefId, MacroDefKind};
+use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind};
 
 macro_rules! register_builtin {
     ( $($trait:ident => $expand:ident),* ) => {
@@ -153,76 +153,113 @@ fn expand_simple_derive(
     Ok(expanded)
 }
 
+fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
+    // FIXME: make hygiene works for builtin derive macro
+    // such that $crate can be used here.
+
+    let m: MacroCallId = id.into();
+    let file_id = m.as_file().original_file(db);
+    let cg = db.crate_graph();
+    let krates = db.relevant_crates(file_id);
+    let krate = match krates.get(0) {
+        Some(krate) => krate,
+        None => {
+            let tt = quote! { core };
+            return tt.token_trees[0].clone();
+        }
+    };
+
+    // XXX
+    //  All crates except core itself should have a dependency on core,
+    //  We detect `core` by seeing whether it doesn't have such a dependency.
+    let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") {
+        quote! { core }
+    } else {
+        quote! { crate }
+    };
+
+    tt.token_trees[0].clone()
+}
+
 fn copy_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::marker::Copy })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::marker::Copy })
 }
 
 fn clone_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::clone::Clone })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::clone::Clone })
 }
 
 fn default_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::default::Default })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::default::Default })
 }
 
 fn debug_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::fmt::Debug })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::fmt::Debug })
 }
 
 fn hash_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::hash::Hash })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::hash::Hash })
 }
 
 fn eq_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::cmp::Eq })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::cmp::Eq })
 }
 
 fn partial_eq_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::cmp::PartialEq })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::cmp::PartialEq })
 }
 
 fn ord_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::cmp::Ord })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::cmp::Ord })
 }
 
 fn partial_ord_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
+    db: &dyn AstDatabase,
+    id: LazyMacroId,
     tt: &tt::Subtree,
 ) -> Result<tt::Subtree, mbe::ExpandError> {
-    expand_simple_derive(tt, quote! { std::cmp::PartialOrd })
+    let krate = find_builtin_crate(db, id);
+    expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd })
 }
 
 #[cfg(test)]
@@ -234,8 +271,18 @@ mod tests {
 
     fn expand_builtin_derive(s: &str, name: Name) -> String {
         let def = find_builtin_derive(&name).unwrap();
+        let fixture = format!(
+            r#"//- /main.rs crate:main deps:core
+<|>
+{}
+//- /lib.rs crate:core
+// empty
+"#,
+            s
+        );
 
-        let (db, file_id) = TestDB::with_single_file(&s);
+        let (db, file_pos) = TestDB::with_position(&fixture);
+        let file_id = file_pos.file_id;
         let parsed = db.parse(file_id);
         let items: Vec<_> =
             parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect();
@@ -264,7 +311,7 @@ mod tests {
             known::Copy,
         );
 
-        assert_eq!(expanded, "impl< >std::marker::CopyforFoo< >{}");
+        assert_eq!(expanded, "impl< >core::marker::CopyforFoo< >{}");
     }
 
     #[test]
@@ -279,7 +326,7 @@ mod tests {
 
         assert_eq!(
             expanded,
-            "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}"
+            "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"
         );
     }
 
@@ -297,7 +344,7 @@ mod tests {
 
         assert_eq!(
             expanded,
-            "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}"
+            "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"
         );
     }
 
@@ -313,7 +360,7 @@ mod tests {
 
         assert_eq!(
             expanded,
-            "impl<T0:std::clone::Clone,T1:std::clone::Clone>std::clone::CloneforFoo<T0,T1>{}"
+            "impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"
         );
     }
 }
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index a8ef32ec59..279c06d65d 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -487,18 +487,6 @@ impl<T> Binders<T> {
     pub fn new(num_binders: usize, value: T) -> Self {
         Self { num_binders, value }
     }
-
-    pub fn as_ref(&self) -> Binders<&T> {
-        Binders { num_binders: self.num_binders, value: &self.value }
-    }
-
-    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> {
-        Binders { num_binders: self.num_binders, value: f(self.value) }
-    }
-
-    pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
-        Some(Binders { num_binders: self.num_binders, value: f(self.value)? })
-    }
 }
 
 impl<T: Clone> Binders<&T> {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index a6f893037f..b572142966 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -28,11 +28,11 @@ use crate::{
     db::HirDatabase,
     primitive::{FloatTy, IntTy},
     utils::{
-        all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
-        make_mut_slice, variant_data,
+        all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice,
+        variant_data,
     },
     Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
-    ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
+    ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
 };
 
 #[derive(Debug)]
@@ -256,7 +256,7 @@ impl Ty {
         if remaining_segments.len() == 1 {
             // resolve unselected assoc types
             let segment = remaining_segments.first().unwrap();
-            (Ty::select_associated_type(ctx, res, segment), None)
+            (Ty::select_associated_type(ctx, ty, res, segment), None)
         } else if remaining_segments.len() > 1 {
             // FIXME report error (ambiguous associated type)
             (Ty::Unknown, None)
@@ -380,20 +380,21 @@ impl Ty {
 
     fn select_associated_type(
         ctx: &TyLoweringContext<'_>,
+        self_ty: Ty,
         res: Option<TypeNs>,
         segment: PathSegment<'_>,
     ) -> Ty {
         let traits_from_env: Vec<_> = match res {
             Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) {
                 None => return Ty::Unknown,
-                Some(trait_ref) => vec![trait_ref.value],
+                Some(trait_ref) => vec![trait_ref.value.trait_],
             },
             Some(TypeNs::GenericParam(param_id)) => {
                 let predicates = ctx.db.generic_predicates_for_param(param_id);
                 let mut traits_: Vec<_> = predicates
                     .iter()
                     .filter_map(|pred| match &pred.value {
-                        GenericPredicate::Implemented(tr) => Some(tr.clone()),
+                        GenericPredicate::Implemented(tr) => Some(tr.trait_),
                         _ => None,
                     })
                     .collect();
@@ -403,37 +404,20 @@ impl Ty {
                     if generics.params.types[param_id.local_id].provenance
                         == TypeParamProvenance::TraitSelf
                     {
-                        let trait_ref = TraitRef {
-                            trait_: trait_id,
-                            substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
-                        };
-                        traits_.push(trait_ref);
+                        traits_.push(trait_id);
                     }
                 }
                 traits_
             }
             _ => return Ty::Unknown,
         };
-        let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t));
+        let traits = traits_from_env.into_iter().flat_map(|t| all_super_traits(ctx.db.upcast(), t));
         for t in traits {
-            if let Some(associated_ty) =
-                ctx.db.trait_data(t.trait_).associated_type_by_name(&segment.name)
+            if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name)
             {
-                let substs = match ctx.type_param_mode {
-                    TypeParamLoweringMode::Placeholder => {
-                        // if we're lowering to placeholders, we have to put
-                        // them in now
-                        let s = Substs::type_params(
-                            ctx.db,
-                            ctx.resolver
-                                .generic_def()
-                                .expect("there should be generics if there's a generic param"),
-                        );
-                        t.substs.subst_bound_vars(&s)
-                    }
-                    TypeParamLoweringMode::Variable => t.substs,
-                };
-                // FIXME handle (forbid) type parameters on the segment
+                let substs =
+                    Substs::build_for_def(ctx.db, t).push(self_ty).fill_with_unknown().build();
+                // FIXME handle type parameters on the segment
                 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
             }
         }
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index f98350bf92..1e5022fa4c 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -14,8 +14,6 @@ use hir_def::{
 };
 use hir_expand::name::{name, Name};
 
-use crate::{db::HirDatabase, GenericPredicate, TraitRef};
-
 fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
     let resolver = trait_.resolver(db);
     // returning the iterator directly doesn't easily work because of
@@ -43,28 +41,6 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
         .collect()
 }
 
-fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> {
-    // returning the iterator directly doesn't easily work because of
-    // lifetime problems, but since there usually shouldn't be more than a
-    // few direct traits this should be fine (we could even use some kind of
-    // SmallVec if performance is a concern)
-    let generic_params = db.generic_params(trait_ref.trait_.into());
-    let trait_self = match generic_params.find_trait_self_param() {
-        Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p },
-        None => return Vec::new(),
-    };
-    db.generic_predicates_for_param(trait_self)
-        .iter()
-        .filter_map(|pred| {
-            pred.as_ref().filter_map(|pred| match pred {
-                GenericPredicate::Implemented(tr) => Some(tr.clone()),
-                _ => None,
-            })
-        })
-        .map(|pred| pred.subst(&trait_ref.substs))
-        .collect()
-}
-
 /// Returns an iterator over the whole super trait hierarchy (including the
 /// trait itself).
 pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
@@ -86,30 +62,6 @@ pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<Tra
     result
 }
 
-/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
-/// super traits. The original trait ref will be included. So the difference to
-/// `all_super_traits` is that we keep track of type parameters; for example if
-/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
-/// `Self: OtherTrait<i32>`.
-pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> {
-    // we need to take care a bit here to avoid infinite loops in case of cycles
-    // (i.e. if we have `trait A: B; trait B: A;`)
-    let mut result = vec![trait_ref];
-    let mut i = 0;
-    while i < result.len() {
-        let t = &result[i];
-        // yeah this is quadratic, but trait hierarchies should be flat
-        // enough that this doesn't matter
-        for tt in direct_super_trait_refs(db, t) {
-            if !result.iter().any(|tr| tr.trait_ == tt.trait_) {
-                result.push(tt);
-            }
-        }
-        i += 1;
-    }
-    result
-}
-
 /// Finds a path from a trait to one of its super traits. Returns an empty
 /// vector if there is no path.
 pub(super) fn find_super_trait_path(
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc
index 76d065d35b..ce57048366 100644
--- a/docs/user/readme.adoc
+++ b/docs/user/readme.adoc
@@ -23,7 +23,7 @@ https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/readme.adoc
 
 == Installation
 
-In theory, one should be able to just install the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> and have it automatically work with any editor.
+In theory, one should be able to just install the server binary and have it automatically work with any editor.
 We are not there yet, so some editor specific setup is required.
 
 Additionally, rust-analyzer needs the sources of the standard library.
@@ -108,26 +108,15 @@ Here are some useful self-diagnostic commands:
 * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel.
 * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools.
 
-=== rust-analyzer Language Server Binary
+=== Language Server Binary
 
 Other editors generally require the `rust-analyzer` binary to be in `$PATH`.
 You can download the pre-built binary from the https://github.com/rust-analyzer/rust-analyzer/releases[releases] page. Typically, you then need to rename the binary for your platform, e.g. `rust-analyzer-mac` if you're on Mac OS, to `rust-analzyer` and make it executable in addition to moving it into a directory in your `$PATH`.
 
-On Linux to install the `rust-analyzer` binary into `~/.local/bin`, this commands could be used
-
-[source,bash]
-----
-$ curl -L https://github.com/rust-analyzer/rust-analyzer/releases/latest/download/rust-analyzer-linux -o ~/.local/bin/rust-analyzer
-$ chmod +x ~/.local/bin/rust-analyzer
-----
-
-Ensure `~/.local/bin` is listed in the `$PATH` variable.
-
 Alternatively, you can install it from source using the following command:
 
 [source,bash]
 ----
-$ git clone https://github.com/rust-analyzer/rust-analyzer.git && cd rust-analyzer
 $ cargo xtask install --server
 ----
 
@@ -150,19 +139,15 @@ $ yay -S rust-analyzer-bin
 
 === Emacs
 
-Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
+Emacs support is maintained https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-rust.el[upstream].
 
-Emacs support is maintained as part of the https://github.com/emacs-lsp/lsp-mode[Emacs-LSP] package in https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-rust.el[lsp-rust.el].
-
-1. Install the most recent version of `emacs-lsp` package by following the https://github.com/emacs-lsp/lsp-mode[Emacs-LSP instructions].
+1. Install the most recent version of `emacs-lsp` package by following the instructions https://github.com/emacs-lsp/lsp-mode[here].
 2. Set `lsp-rust-server` to `'rust-analyzer`.
 3. Run `lsp` in a Rust buffer.
 4. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys.
 
 === Vim
 
-Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
-
 The are several LSP client implementations for vim:
 
 ==== coc-rust-analyzer
@@ -220,7 +205,7 @@ Once `neovim/nvim-lsp` is installed, use `+lua require'nvim_lsp'.rust_analyzer.s
 
 === Sublime Text 3
 
-Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
+Prerequisites: You have installed the <<language-server-binary,`rust-analyzer` binary>>.
 
 You also need the `LSP` package. To install it:
 
@@ -233,7 +218,7 @@ Finally, with your Rust project open, in the command palette, run `LSP: Enable L
 
 If it worked, you should see "rust-analzyer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available.
 
-If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> section on installing the language server binary.
+If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<language-server-binary,section on installing the language server binary>>.
 
 == Usage
 


Test patch:
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 6b52672325..5ddecbdc68 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -622,14 +622,14 @@ fn main() {
 fn infer_derive_clone_simple() {
     let (db, pos) = TestDB::with_position(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core
 #[derive(Clone)]
 struct S;
 fn test() {
     S.clone()<|>;
 }
 
-//- /lib.rs crate:std
+//- /lib.rs crate:core
 #[prelude_import]
 use clone::*;
 mod clone {
@@ -642,11 +642,36 @@ mod clone {
     assert_eq!("S", type_at_pos(&db, pos));
 }
 
+#[test]
+fn infer_derive_clone_in_core() {
+    let (db, pos) = TestDB::with_position(
+        r#"
+//- /lib.rs crate:core
+#[prelude_import]
+use clone::*;
+mod clone {
+    trait Clone {
+        fn clone(&self) -> Self;
+    }
+}
+#[derive(Clone)]
+pub struct S;
+
+//- /main.rs crate:main deps:core
+use core::S;
+fn test() {
+    S.clone()<|>;
+}
+"#,
+    );
+    assert_eq!("S", type_at_pos(&db, pos));
+}
+
 #[test]
 fn infer_derive_clone_with_params() {
     let (db, pos) = TestDB::with_position(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core
 #[derive(Clone)]
 struct S;
 #[derive(Clone)]
@@ -656,7 +681,7 @@ fn test() {
     (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
 }
 
-//- /lib.rs crate:std
+//- /lib.rs crate:core
 #[prelude_import]
 use clone::*;
 mod clone {
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index e555c879a0..f51cdd4964 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1897,36 +1897,6 @@ fn test() {
     assert_eq!(t, "u32");
 }
 
-#[test]
-fn unselected_projection_chalk_fold() {
-    let t = type_at(
-        r#"
-//- /main.rs
-trait Interner {}
-trait Fold<I: Interner, TI = I> {
-    type Result;
-}
-
-struct Ty<I: Interner> {}
-impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> {
-    type Result = Ty<TI>;
-}
-
-fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result
-where
-    T: Fold<I, I>,
-{
-    loop {}
-}
-
-fn foo<I: Interner>(interner: &I, t: Ty<I>) {
-    fold(interner, t)<|>;
-}
-"#,
-    );
-    assert_eq!(t, "Ty<I>");
-}
-
 #[test]
 fn trait_impl_self_ty() {
     let t = type_at(