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

Issue:
"{unkown}" type annotations could be more useful as "impl Trait"
Minimal example:

```rust
trait T {}

struct S;

impl T for S {}

fn f ()-> impl T {
    S {}
}

fn main() {
    let t = f();
}
```

In VSCode with the Rust Analyzer, if I hover over `t` (in `main`) I get `{unknown}`. I suppose it's too much to hope for the analyzer to look into the definition of `f` and compute that the type is `S` (in particular since in a more complete example the type might be unnameable). However, it would be quite useful if the Analyzer could tell me `impl T` instead of just `{unknown}`.

Pull request description:
Impl/dyn trait
This adds support for `impl Trait` and `dyn Trait` types as far as possible without Chalk. So we can represent them in the type system, and handle them in method resolution, but Chalk doesn't know about them yet. There's a small temporary hack here where we bypass Chalk during method resolution, so we can handle simple method calls on them and completion works.

Fixes #1608.

Patch:
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index e75337cdf7..d6728cc9f4 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -11,7 +11,7 @@ use crate::{
     db::{AstDatabase, DefDatabase, HirDatabase},
     name::SELF_TYPE,
     path::Path,
-    type_ref::TypeRef,
+    type_ref::{TypeBound, TypeRef},
     AdtDef, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
     Trait, TypeAlias, Union,
 };
@@ -35,10 +35,12 @@ pub struct GenericParams {
 
 /// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
 /// where clauses like `where T: Foo + Bar` are turned into multiple of these.
+/// It might still result in multiple actual predicates though, because of
+/// associated type bindings like `Iterator<Item = u32>`.
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct WherePredicate {
     pub(crate) type_ref: TypeRef,
-    pub(crate) trait_ref: Path,
+    pub(crate) bound: TypeBound,
 }
 
 // FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
@@ -143,18 +145,8 @@ impl GenericParams {
             // FIXME: remove this bound
             return;
         }
-        let path = bound
-            .type_ref()
-            .and_then(|tr| match tr {
-                ast::TypeRef::PathType(path) => path.path(),
-                _ => None,
-            })
-            .and_then(Path::from_ast);
-        let path = match path {
-            Some(p) => p,
-            None => return,
-        };
-        self.where_predicates.push(WherePredicate { type_ref, trait_ref: path });
+        let bound = TypeBound::from_ast(bound);
+        self.where_predicates.push(WherePredicate { type_ref, bound });
     }
 
     pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 642dd02cbe..b54c803185 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -161,14 +161,28 @@ pub enum Ty {
         name: Name,
     },
 
-    /// A bound type variable. Only used during trait resolution to represent
-    /// Chalk variables.
+    /// A bound type variable. Used during trait resolution to represent Chalk
+    /// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type.
     Bound(u32),
 
     /// A type variable used during type checking. Not to be confused with a
     /// type parameter.
     Infer(InferTy),
 
+    /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
+    ///
+    /// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
+    /// represents the `Self` type inside the bounds. This is currently
+    /// implicit; Chalk has the `Binders` struct to make it explicit, but it
+    /// didn't seem worth the overhead yet.
+    Dyn(Arc<[GenericPredicate]>),
+
+    /// An opaque type (`impl Trait`).
+    ///
+    /// The predicates are quantified over the `Self` type; see `Ty::Dyn` for
+    /// more.
+    Opaque(Arc<[GenericPredicate]>),
+
     /// A placeholder for a type which could not be computed; this is propagated
     /// to avoid useless error messages. Doubles as a placeholder where type
     /// variables are inserted before type checking, since we want to try to
@@ -194,6 +208,12 @@ impl Substs {
         Substs(self.0.iter().cloned().take(n).collect::<Vec<_>>().into())
     }
 
+    pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
+        for t in self.0.iter() {
+            t.walk(f);
+        }
+    }
+
     pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
         // Without an Arc::make_mut_slice, we can't avoid the clone here:
         let mut v: Vec<_> = self.0.iter().cloned().collect();
@@ -270,6 +290,14 @@ impl TraitRef {
         });
         self
     }
+
+    pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
+        self.substs.walk(f);
+    }
+
+    pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
+        self.substs.walk_mut(f);
+    }
 }
 
 /// Like `generics::WherePredicate`, but with resolved types: A condition on the
@@ -299,6 +327,20 @@ impl GenericPredicate {
             GenericPredicate::Error => self,
         }
     }
+
+    pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
+        match self {
+            GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
+            GenericPredicate::Error => {}
+        }
+    }
+
+    pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
+        match self {
+            GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f),
+            GenericPredicate::Error => {}
+        }
+    }
 }
 
 /// Basically a claim (currently not validated / checked) that the contained
@@ -386,6 +428,11 @@ impl Ty {
                     t.walk(f);
                 }
             }
+            Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
+                for p in predicates.iter() {
+                    p.walk(f);
+                }
+            }
             Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
         }
         f(self);
@@ -402,6 +449,13 @@ impl Ty {
             Ty::UnselectedProjection(p_ty) => {
                 p_ty.parameters.walk_mut(f);
             }
+            Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
+                let mut v: Vec<_> = predicates.iter().cloned().collect();
+                for p in &mut v {
+                    p.walk_mut(f);
+                }
+                *predicates = v.into();
+            }
             Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
         }
         f(self);
@@ -529,6 +583,19 @@ impl Ty {
             ty => ty,
         })
     }
+
+    /// If this is an `impl Trait` or `dyn Trait`, returns that trait.
+    pub fn inherent_trait(&self) -> Option<Trait> {
+        match self {
+            Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
+                predicates.iter().find_map(|pred| match pred {
+                    GenericPredicate::Implemented(tr) => Some(tr.trait_),
+                    _ => None,
+                })
+            }
+            _ => None,
+        }
+    }
 }
 
 impl HirDisplay for &Ty {
@@ -669,6 +736,28 @@ impl HirDisplay for Ty {
             Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?,
             Ty::Param { name, .. } => write!(f, "{}", name)?,
             Ty::Bound(idx) => write!(f, "?{}", idx)?,
+            Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
+                match self {
+                    Ty::Dyn(_) => write!(f, "dyn ")?,
+                    Ty::Opaque(_) => write!(f, "impl ")?,
+                    _ => unreachable!(),
+                };
+                // looping by hand here just to format the bounds in a slightly nicer way
+                let mut first = true;
+                for p in predicates.iter() {
+                    if !first {
+                        write!(f, " + ")?;
+                    }
+                    first = false;
+                    match p {
+                        // don't show the $0 self type
+                        GenericPredicate::Implemented(trait_ref) => {
+                            trait_ref.hir_fmt_ext(f, false)?
+                        }
+                        GenericPredicate::Error => p.hir_fmt(f)?,
+                    }
+                }
+            }
             Ty::Unknown => write!(f, "{{unknown}}")?,
             Ty::Infer(..) => write!(f, "_")?,
         }
@@ -676,14 +765,16 @@ impl HirDisplay for Ty {
     }
 }
 
-impl HirDisplay for TraitRef {
-    fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
-        write!(
-            f,
-            "{}: {}",
-            self.substs[0].display(f.db),
-            self.trait_.name(f.db).unwrap_or_else(Name::missing)
-        )?;
+impl TraitRef {
+    fn hir_fmt_ext(
+        &self,
+        f: &mut HirFormatter<impl HirDatabase>,
+        with_self_ty: bool,
+    ) -> fmt::Result {
+        if with_self_ty {
+            write!(f, "{}: ", self.substs[0].display(f.db),)?;
+        }
+        write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?;
         if self.substs.len() > 1 {
             write!(f, "<")?;
             f.write_joined(&self.substs[1..], ", ")?;
@@ -693,6 +784,28 @@ impl HirDisplay for TraitRef {
     }
 }
 
+impl HirDisplay for TraitRef {
+    fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
+        self.hir_fmt_ext(f, true)
+    }
+}
+
+impl HirDisplay for &GenericPredicate {
+    fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
+        HirDisplay::hir_fmt(*self, f)
+    }
+}
+
+impl HirDisplay for GenericPredicate {
+    fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
+        match self {
+            GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
+            GenericPredicate::Error => write!(f, "{{error}}")?,
+        }
+        Ok(())
+    }
+}
+
 impl HirDisplay for Obligation {
     fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
         match self {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index debedcbb8b..47d1612770 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -17,7 +17,7 @@ use crate::{
     path::{GenericArg, PathSegment},
     resolve::{Resolution, Resolver},
     ty::AdtDef,
-    type_ref::TypeRef,
+    type_ref::{TypeBound, TypeRef},
     BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct,
     StructField, Trait, TypeAlias, Union,
 };
@@ -58,6 +58,22 @@ impl Ty {
                 let sig = Substs(inner_tys.into());
                 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
             }
+            TypeRef::DynTrait(bounds) => {
+                let self_ty = Ty::Bound(0);
+                let predicates = bounds
+                    .iter()
+                    .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()))
+                    .collect::<Vec<_>>();
+                Ty::Dyn(predicates.into())
+            }
+            TypeRef::ImplTrait(bounds) => {
+                let self_ty = Ty::Bound(0);
+                let predicates = bounds
+                    .iter()
+                    .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()))
+                    .collect::<Vec<_>>();
+                Ty::Opaque(predicates.into())
+            }
             TypeRef::Error => Ty::Unknown,
         }
     }
@@ -310,13 +326,46 @@ impl TraitRef {
         TraitRef { trait_, substs }
     }
 
-    pub(crate) fn for_where_predicate(
+    pub(crate) fn from_where_predicate(
         db: &impl HirDatabase,
         resolver: &Resolver,
         pred: &WherePredicate,
     ) -> Option<TraitRef> {
         let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
-        TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty))
+        TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty)
+    }
+
+    pub(crate) fn from_type_bound(
+        db: &impl HirDatabase,
+        resolver: &Resolver,
+        bound: &TypeBound,
+        self_ty: Ty,
+    ) -> Option<TraitRef> {
+        match bound {
+            TypeBound::Path(path) => TraitRef::from_path(db, resolver, path, Some(self_ty)),
+            TypeBound::Error => None,
+        }
+    }
+}
+
+impl GenericPredicate {
+    pub(crate) fn from_where_predicate(
+        db: &impl HirDatabase,
+        resolver: &Resolver,
+        where_predicate: &WherePredicate,
+    ) -> GenericPredicate {
+        TraitRef::from_where_predicate(db, &resolver, where_predicate)
+            .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
+    }
+
+    pub(crate) fn from_type_bound(
+        db: &impl HirDatabase,
+        resolver: &Resolver,
+        bound: &TypeBound,
+        self_ty: Ty,
+    ) -> GenericPredicate {
+        TraitRef::from_type_bound(db, &resolver, bound, self_ty)
+            .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
     }
 }
 
@@ -376,10 +425,7 @@ pub(crate) fn trait_env(
 ) -> Arc<super::TraitEnvironment> {
     let predicates = resolver
         .where_predicates_in_scope()
-        .map(|pred| {
-            TraitRef::for_where_predicate(db, &resolver, pred)
-                .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
-        })
+        .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
         .collect::<Vec<_>>();
 
     Arc::new(super::TraitEnvironment { predicates })
@@ -393,10 +439,7 @@ pub(crate) fn generic_predicates_query(
     let resolver = def.resolver(db);
     let predicates = resolver
         .where_predicates_in_scope()
-        .map(|pred| {
-            TraitRef::for_where_predicate(db, &resolver, pred)
-                .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
-        })
+        .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
         .collect::<Vec<_>>();
     predicates.into()
 }
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 3f4c43aee8..9873a0440b 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -211,12 +211,19 @@ fn iterate_trait_method_candidates<T>(
     let krate = resolver.krate()?;
     // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
     let env = lower::trait_env(db, resolver);
-    'traits: for t in resolver.traits_in_scope(db) {
+    // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
+    let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db));
+    'traits: for t in traits {
         let data = t.trait_data(db);
+
+        // FIXME this is a bit of a hack, since Chalk should say the same thing
+        // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
+        let inherently_implemented = ty.value.inherent_trait() == Some(t);
+
         // we'll be lazy about checking whether the type implements the
         // trait, but if we find out it doesn't, we'll skip the rest of the
         // iteration
-        let mut known_implemented = false;
+        let mut known_implemented = inherently_implemented;
         for item in data.items() {
             if let TraitItem::Function(m) = *item {
                 let data = m.data(db);
@@ -271,6 +278,11 @@ pub(crate) fn implements_trait(
     krate: Crate,
     trait_: Trait,
 ) -> bool {
+    if ty.value.inherent_trait() == Some(trait_) {
+        // FIXME this is a bit of a hack, since Chalk should say the same thing
+        // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
+        return true;
+    }
     let env = lower::trait_env(db, resolver);
     let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
     let solution = db.trait_solve(krate, goal);
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 6df7094c58..2ebc06135a 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -80,7 +80,9 @@ impl ToChalk for Ty {
             // FIXME this is clearly incorrect, but probably not too incorrect
             // and I'm not sure what to actually do with Ty::Unknown
             // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
-            Ty::Unknown => {
+            //
+            // FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet
+            Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => {
                 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty()
             }
         }
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs
index b92a0b55ac..fa91bfb22f 100644
--- a/crates/ra_hir/src/type_ref.rs
+++ b/crates/ra_hir/src/type_ref.rs
@@ -1,7 +1,7 @@
 //! HIR for references to types. Paths in these are not yet resolved. They can
 //! be directly created from an ast::TypeRef, without further queries.
 
-use ra_syntax::ast::{self, TypeAscriptionOwner};
+use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner};
 
 use crate::Path;
 
@@ -49,8 +49,16 @@ pub enum TypeRef {
     /// A fn pointer. Last element of the vector is the return type.
     Fn(Vec<TypeRef>),
     // For
-    // ImplTrait,
-    // DynTrait,
+    ImplTrait(Vec<TypeBound>),
+    DynTrait(Vec<TypeBound>),
+    Error,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum TypeBound {
+    Path(Path),
+    // also for<> bounds
+    // also Lifetimes
     Error,
 }
 
@@ -95,8 +103,12 @@ impl TypeRef {
             }
             // for types are close enough for our purposes to the inner type for now...
             ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
-            ast::TypeRef::ImplTraitType(_inner) => TypeRef::Error,
-            ast::TypeRef::DynTraitType(_inner) => TypeRef::Error,
+            ast::TypeRef::ImplTraitType(inner) => {
+                TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list()))
+            }
+            ast::TypeRef::DynTraitType(inner) => {
+                TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list()))
+            }
         }
     }
 
@@ -112,3 +124,30 @@ impl TypeRef {
         TypeRef::Tuple(Vec::new())
     }
 }
+
+pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> {
+    if let Some(type_bounds) = type_bounds_opt {
+        type_bounds.bounds().map(TypeBound::from_ast).collect()
+    } else {
+        vec![]
+    }
+}
+
+impl TypeBound {
+    pub(crate) fn from_ast(node: ast::TypeBound) -> Self {
+        match node.kind() {
+            ast::TypeBoundKind::PathType(path_type) => {
+                let path = match path_type.path() {
+                    Some(p) => p,
+                    None => return TypeBound::Error,
+                };
+                let path = match Path::from_ast(path) {
+                    Some(p) => p,
+                    None => return TypeBound::Error,
+                };
+                TypeBound::Path(path)
+            }
+            ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
+        }
+    }
+}
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 6f04896172..afdfca66e3 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -15,7 +15,7 @@ use crate::{
 
 pub use self::{
     expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp},
-    extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind},
+    extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind},
     generated::*,
     tokens::*,
     traits::*,
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index efe261fc23..e0ea3e5ab1 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -382,7 +382,36 @@ impl ast::WherePred {
     }
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum TypeBoundKind {
+    /// Trait
+    PathType(ast::PathType),
+    /// for<'a> ...
+    ForType(ast::ForType),
+    /// 'a
+    Lifetime(ast::SyntaxToken),
+}
+
 impl ast::TypeBound {
+    pub fn kind(&self) -> TypeBoundKind {
+        if let Some(path_type) = children(self).next() {
+            TypeBoundKind::PathType(path_type)
+        } else if let Some(for_type) = children(self).next() {
+            TypeBoundKind::ForType(for_type)
+        } else if let Some(lifetime) = self.lifetime() {
+            TypeBoundKind::Lifetime(lifetime)
+        } else {
+            unreachable!()
+        }
+    }
+
+    fn lifetime(&self) -> Option<SyntaxToken> {
+        self.syntax()
+            .children_with_tokens()
+            .filter_map(|it| it.into_token())
+            .find(|it| it.kind() == LIFETIME)
+    }
+
     pub fn question_mark_token(&self) -> Option<SyntaxToken> {
         self.syntax()
             .children_with_tokens()


Test patch:
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 57fd5492d8..c5818b738f 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3273,6 +3273,181 @@ fn test<T: ApplyL>(t: T) {
     assert_eq!(t, "{unknown}");
 }
 
+#[test]
+fn impl_trait() {
+    assert_snapshot_matches!(
+        infer(r#"
+trait Trait<T> {
+    fn foo(&self) -> T;
+    fn foo2(&self) -> i64;
+}
+fn bar() -> impl Trait<u64> {}
+
+fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
+    x;
+    y;
+    let z = bar();
+    x.foo();
+    y.foo();
+    z.foo();
+    x.foo2();
+    y.foo2();
+    z.foo2();
+}
+"#),
+        @r###"
+   ⋮
+   ⋮[30; 34) 'self': &Self
+   ⋮[55; 59) 'self': &Self
+   ⋮[99; 101) '{}': ()
+   ⋮[111; 112) 'x': impl Trait<u64>
+   ⋮[131; 132) 'y': &impl Trait<u64>
+   ⋮[152; 269) '{     ...2(); }': ()
+   ⋮[158; 159) 'x': impl Trait<u64>
+   ⋮[165; 166) 'y': &impl Trait<u64>
+   ⋮[176; 177) 'z': impl Trait<u64>
+   ⋮[180; 183) 'bar': fn bar() -> impl Trait<u64>
+   ⋮[180; 185) 'bar()': impl Trait<u64>
+   ⋮[191; 192) 'x': impl Trait<u64>
+   ⋮[191; 198) 'x.foo()': {unknown}
+   ⋮[204; 205) 'y': &impl Trait<u64>
+   ⋮[204; 211) 'y.foo()': {unknown}
+   ⋮[217; 218) 'z': impl Trait<u64>
+   ⋮[217; 224) 'z.foo()': {unknown}
+   ⋮[230; 231) 'x': impl Trait<u64>
+   ⋮[230; 238) 'x.foo2()': i64
+   ⋮[244; 245) 'y': &impl Trait<u64>
+   ⋮[244; 252) 'y.foo2()': i64
+   ⋮[258; 259) 'z': impl Trait<u64>
+   ⋮[258; 266) 'z.foo2()': i64
+    "###
+    );
+}
+
+#[test]
+fn dyn_trait() {
+    assert_snapshot_matches!(
+        infer(r#"
+trait Trait<T> {
+    fn foo(&self) -> T;
+    fn foo2(&self) -> i64;
+}
+fn bar() -> dyn Trait<u64> {}
+
+fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
+    x;
+    y;
+    let z = bar();
+    x.foo();
+    y.foo();
+    z.foo();
+    x.foo2();
+    y.foo2();
+    z.foo2();
+}
+"#),
+        @r###"
+   ⋮
+   ⋮[30; 34) 'self': &Self
+   ⋮[55; 59) 'self': &Self
+   ⋮[98; 100) '{}': ()
+   ⋮[110; 111) 'x': dyn Trait<u64>
+   ⋮[129; 130) 'y': &dyn Trait<u64>
+   ⋮[149; 266) '{     ...2(); }': ()
+   ⋮[155; 156) 'x': dyn Trait<u64>
+   ⋮[162; 163) 'y': &dyn Trait<u64>
+   ⋮[173; 174) 'z': dyn Trait<u64>
+   ⋮[177; 180) 'bar': fn bar() -> dyn Trait<u64>
+   ⋮[177; 182) 'bar()': dyn Trait<u64>
+   ⋮[188; 189) 'x': dyn Trait<u64>
+   ⋮[188; 195) 'x.foo()': {unknown}
+   ⋮[201; 202) 'y': &dyn Trait<u64>
+   ⋮[201; 208) 'y.foo()': {unknown}
+   ⋮[214; 215) 'z': dyn Trait<u64>
+   ⋮[214; 221) 'z.foo()': {unknown}
+   ⋮[227; 228) 'x': dyn Trait<u64>
+   ⋮[227; 235) 'x.foo2()': i64
+   ⋮[241; 242) 'y': &dyn Trait<u64>
+   ⋮[241; 249) 'y.foo2()': i64
+   ⋮[255; 256) 'z': dyn Trait<u64>
+   ⋮[255; 263) 'z.foo2()': i64
+    "###
+    );
+}
+
+#[test]
+fn dyn_trait_bare() {
+    assert_snapshot_matches!(
+        infer(r#"
+trait Trait {
+    fn foo(&self) -> u64;
+}
+fn bar() -> Trait {}
+
+fn test(x: Trait, y: &Trait) -> u64 {
+    x;
+    y;
+    let z = bar();
+    x.foo();
+    y.foo();
+    z.foo();
+}
+"#),
+        @r###"
+   ⋮
+   ⋮[27; 31) 'self': &Self
+   ⋮[61; 63) '{}': ()
+   ⋮[73; 74) 'x': {unknown}
+   ⋮[83; 84) 'y': &{unknown}
+   ⋮[101; 176) '{     ...o(); }': ()
+   ⋮[107; 108) 'x': {unknown}
+   ⋮[114; 115) 'y': &{unknown}
+   ⋮[125; 126) 'z': {unknown}
+   ⋮[129; 132) 'bar': fn bar() -> {unknown}
+   ⋮[129; 134) 'bar()': {unknown}
+   ⋮[140; 141) 'x': {unknown}
+   ⋮[140; 147) 'x.foo()': {unknown}
+   ⋮[153; 154) 'y': &{unknown}
+   ⋮[153; 160) 'y.foo()': {unknown}
+   ⋮[166; 167) 'z': {unknown}
+   ⋮[166; 173) 'z.foo()': {unknown}
+    "###
+    );
+}
+
+#[test]
+fn weird_bounds() {
+    assert_snapshot_matches!(
+        infer(r#"
+trait Trait {}
+fn test() {
+    let a: impl Trait + 'lifetime = foo;
+    let b: impl 'lifetime = foo;
+    let b: impl (Trait) = foo;
+    let b: impl ('lifetime) = foo;
+    let d: impl ?Sized = foo;
+    let e: impl Trait + ?Sized = foo;
+}
+"#),
+        @r###"
+   ⋮
+   ⋮[26; 237) '{     ...foo; }': ()
+   ⋮[36; 37) 'a': impl Trait + {error}
+   ⋮[64; 67) 'foo': impl Trait + {error}
+   ⋮[77; 78) 'b': impl {error}
+   ⋮[97; 100) 'foo': impl {error}
+   ⋮[110; 111) 'b': impl Trait
+   ⋮[128; 131) 'foo': impl Trait
+   ⋮[141; 142) 'b': impl {error}
+   ⋮[163; 166) 'foo': impl {error}
+   ⋮[176; 177) 'd': impl {error}
+   ⋮[193; 196) 'foo': impl {error}
+   ⋮[206; 207) 'e': impl Trait + {error}
+   ⋮[231; 234) 'foo': impl Trait + {error}
+    "###
+    );
+}
+
 fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
     let file = db.parse(pos.file_id).ok().unwrap();
     let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();