Repository: rust-analyzer/rust-analyzer
Pull request #1515 (2019-07-08 20:05:11)

Trait environment
This adds the environment, i.e. the set of `where` clauses in scope, when solving trait goals. That means that e.g. in
```rust
fn foo<T: SomeTrait>(t: T) {}
```
, we are able to complete methods of `SomeTrait` on the `t`. This affects the trait APIs quite a bit (since every method that needs to be able to solve for some trait needs to get this environment somehow), so I thought I'd do it rather sooner than later ;)


Patch:
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 0e6e3fdb73..b0c0276315 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -213,18 +213,11 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
     #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)]
     fn impl_datum(&self, krate: Crate, impl_id: chalk_ir::ImplId) -> Arc<chalk_rust_ir::ImplDatum>;
 
-    #[salsa::invoke(crate::ty::traits::implements_query)]
-    fn implements(
+    #[salsa::invoke(crate::ty::traits::solve_query)]
+    fn solve(
         &self,
         krate: Crate,
-        goal: crate::ty::Canonical<crate::ty::TraitRef>,
-    ) -> Option<crate::ty::traits::Solution>;
-
-    #[salsa::invoke(crate::ty::traits::normalize_query)]
-    fn normalize(
-        &self,
-        krate: Crate,
-        goal: crate::ty::Canonical<crate::ty::ProjectionPredicate>,
+        goal: crate::ty::Canonical<crate::ty::InEnvironment<crate::ty::Obligation>>,
     ) -> Option<crate::ty::traits::Solution>;
 }
 
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d8c7945e1d..9accffcbc8 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -26,7 +26,7 @@ pub(crate) use lower::{
     callable_item_sig, generic_defaults_query, generic_predicates_query, type_for_def,
     type_for_field, TypableDef,
 };
-pub(crate) use traits::ProjectionPredicate;
+pub(crate) use traits::{Environment, InEnvironment, Obligation, ProjectionPredicate};
 
 /// A type constructor or type name: this might be something like the primitive
 /// type `bool`, a struct like `Vec`, or things like function pointers or
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 90c1ae630e..c265138719 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -52,6 +52,8 @@ fn deref_by_trait(
 
     // FIXME make the Canonical handling nicer
 
+    let env = super::lower::trait_env(db, resolver);
+
     let projection = super::traits::ProjectionPredicate {
         ty: Ty::Bound(0),
         projection_ty: super::ProjectionTy {
@@ -60,9 +62,13 @@ fn deref_by_trait(
         },
     };
 
-    let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: projection };
+    let obligation = super::Obligation::Projection(projection);
+
+    let in_env = super::traits::InEnvironment { value: obligation, environment: env };
+
+    let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: in_env };
 
-    let solution = db.normalize(krate, canonical)?;
+    let solution = db.solve(krate, canonical)?;
 
     match &solution {
         Solution::Unique(vars) => {
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 52a49070a1..1f74108a44 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -27,9 +27,10 @@ use ra_prof::profile;
 use test_utils::tested_by;
 
 use super::{
-    autoderef, method_resolution, op, primitive,
+    autoderef, lower, method_resolution, op, primitive,
     traits::{Guidance, Obligation, ProjectionPredicate, Solution},
-    ApplicationTy, CallableDef, ProjectionTy, Substs, TraitRef, Ty, TypableDef, TypeCtor,
+    ApplicationTy, CallableDef, Environment, InEnvironment, ProjectionTy, Substs, TraitRef, Ty,
+    TypableDef, TypeCtor,
 };
 use crate::{
     adt::VariantDef,
@@ -165,6 +166,7 @@ struct InferenceContext<'a, D: HirDatabase> {
     body: Arc<Body>,
     resolver: Resolver,
     var_unification_table: InPlaceUnificationTable<TypeVarId>,
+    trait_env: Arc<Environment>,
     obligations: Vec<Obligation>,
     method_resolutions: FxHashMap<ExprId, Function>,
     field_resolutions: FxHashMap<ExprId, StructField>,
@@ -188,6 +190,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
             var_unification_table: InPlaceUnificationTable::new(),
             obligations: Vec::default(),
             return_ty: Ty::Unknown, // set in collect_fn_signature
+            trait_env: lower::trait_env(db, &resolver),
             db,
             body,
             resolver,
@@ -328,51 +331,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
     fn resolve_obligations_as_possible(&mut self) {
         let obligations = mem::replace(&mut self.obligations, Vec::new());
         for obligation in obligations {
-            match &obligation {
-                Obligation::Trait(tr) => {
-                    let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone());
-                    let solution = self
-                        .db
-                        .implements(self.resolver.krate().unwrap(), canonicalized.value.clone());
-                    match solution {
-                        Some(Solution::Unique(substs)) => {
-                            canonicalized.apply_solution(self, substs.0);
-                        }
-                        Some(Solution::Ambig(Guidance::Definite(substs))) => {
-                            canonicalized.apply_solution(self, substs.0);
-                            self.obligations.push(obligation);
-                        }
-                        Some(_) => {
-                            // FIXME use this when trying to resolve everything at the end
-                            self.obligations.push(obligation);
-                        }
-                        None => {
-                            // FIXME obligation cannot be fulfilled => diagnostic
-                        }
-                    };
+            let in_env = InEnvironment::new(self.trait_env.clone(), obligation.clone());
+            let canonicalized = self.canonicalizer().canonicalize_obligation(in_env);
+            let solution =
+                self.db.solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
+
+            match solution {
+                Some(Solution::Unique(substs)) => {
+                    canonicalized.apply_solution(self, substs.0);
                 }
-                Obligation::Projection(pr) => {
-                    let canonicalized = self.canonicalizer().canonicalize_projection(pr.clone());
-                    let solution = self
-                        .db
-                        .normalize(self.resolver.krate().unwrap(), canonicalized.value.clone());
-
-                    match solution {
-                        Some(Solution::Unique(substs)) => {
-                            canonicalized.apply_solution(self, substs.0);
-                        }
-                        Some(Solution::Ambig(Guidance::Definite(substs))) => {
-                            canonicalized.apply_solution(self, substs.0);
-                            self.obligations.push(obligation);
-                        }
-                        Some(_) => {
-                            // FIXME use this when trying to resolve everything at the end
-                            self.obligations.push(obligation);
-                        }
-                        None => {
-                            // FIXME obligation cannot be fulfilled => diagnostic
-                        }
-                    };
+                Some(Solution::Ambig(Guidance::Definite(substs))) => {
+                    canonicalized.apply_solution(self, substs.0);
+                    self.obligations.push(obligation);
+                }
+                Some(_) => {
+                    // FIXME use this when trying to resolve everything at the end
+                    self.obligations.push(obligation);
+                }
+                None => {
+                    // FIXME obligation cannot be fulfilled => diagnostic
                 }
             };
         }
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index a24e5eb5c6..e7e8825d1a 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -1,8 +1,10 @@
 //! Unification and canonicalization logic.
 
-use super::InferenceContext;
+use super::{InferenceContext, Obligation};
 use crate::db::HirDatabase;
-use crate::ty::{Canonical, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty};
+use crate::ty::{
+    Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty,
+};
 
 impl<'a, D: HirDatabase> InferenceContext<'a, D> {
     pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
@@ -105,22 +107,28 @@ where
         ProjectionPredicate { ty, projection_ty }
     }
 
-    pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
-        let result = self.do_canonicalize_ty(ty);
-        self.into_canonicalized(result)
-    }
+    // FIXME: add some point, we need to introduce a `Fold` trait that abstracts
+    // over all the things that can be canonicalized (like Chalk and rustc have)
 
-    pub fn canonicalize_trait_ref(mut self, trait_ref: TraitRef) -> Canonicalized<TraitRef> {
-        let result = self.do_canonicalize_trait_ref(trait_ref);
+    pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
+        let result = self.do_canonicalize_ty(ty);
         self.into_canonicalized(result)
     }
 
-    pub fn canonicalize_projection(
+    pub(crate) fn canonicalize_obligation(
         mut self,
-        projection: ProjectionPredicate,
-    ) -> Canonicalized<ProjectionPredicate> {
-        let result = self.do_canonicalize_projection_predicate(projection);
-        self.into_canonicalized(result)
+        obligation: InEnvironment<Obligation>,
+    ) -> Canonicalized<InEnvironment<Obligation>> {
+        let result = match obligation.value {
+            Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize_trait_ref(tr)),
+            Obligation::Projection(pr) => {
+                Obligation::Projection(self.do_canonicalize_projection_predicate(pr))
+            }
+        };
+        self.into_canonicalized(InEnvironment {
+            value: result,
+            environment: obligation.environment,
+        })
     }
 }
 
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index b48ada760f..ca47d6e96b 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -317,6 +317,18 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
     Ty::from_hir(db, &resolver, type_ref)
 }
 
+pub(crate) fn trait_env(db: &impl HirDatabase, resolver: &Resolver) -> Arc<super::Environment> {
+    let predicates = resolver
+        .where_predicates_in_scope()
+        .map(|pred| {
+            TraitRef::for_where_predicate(db, &resolver, pred)
+                .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
+        })
+        .collect::<Vec<_>>();
+
+    Arc::new(super::Environment { predicates })
+}
+
 /// Resolve the where clause(s) of an item with generics.
 pub(crate) fn generic_predicates_query(
     db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index f65ad08a8b..e214bf1af4 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -7,14 +7,14 @@ use std::sync::Arc;
 use arrayvec::ArrayVec;
 use rustc_hash::FxHashMap;
 
-use super::{autoderef, Canonical, TraitRef};
+use super::{autoderef, lower, Canonical, Environment, InEnvironment, TraitRef};
 use crate::{
     generics::HasGenericParams,
     impl_block::{ImplBlock, ImplId, ImplItem},
     nameres::CrateModuleId,
     resolve::Resolver,
     traits::TraitItem,
-    ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy},
+    ty::primitive::{UncertainFloatTy, UncertainIntTy},
     ty::{Ty, TypeCtor},
     Crate, Function, HirDatabase, Module, Name, Trait,
 };
@@ -132,11 +132,9 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV
             TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()),
             TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"),
             TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"),
-            TypeCtor::Float(UncertainFloatTy::Known(f)) => match f.bitness {
-                // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
-                FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"),
-                FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"),
-            },
+            TypeCtor::Float(UncertainFloatTy::Known(f)) => {
+                lang_item_crate!(db, cur_crate, f.ty_to_string())
+            }
             TypeCtor::Int(UncertainIntTy::Known(i)) => {
                 lang_item_crate!(db, cur_crate, i.ty_to_string())
             }
@@ -200,6 +198,8 @@ fn iterate_trait_method_candidates<T>(
     mut callback: impl FnMut(&Ty, Function) -> Option<T>,
 ) -> Option<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) {
         let data = t.trait_data(db);
         // we'll be lazy about checking whether the type implements the
@@ -211,8 +211,8 @@ fn iterate_trait_method_candidates<T>(
                 let data = m.data(db);
                 if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                     if !known_implemented {
-                        let trait_ref = canonical_trait_ref(db, t, ty.clone());
-                        if db.implements(krate, trait_ref).is_none() {
+                        let goal = generic_implements_goal(db, env.clone(), t, ty.clone());
+                        if db.solve(krate, goal).is_none() {
                             continue 'traits;
                         }
                     }
@@ -279,11 +279,12 @@ impl Ty {
 
 /// This creates Substs for a trait with the given Self type and type variables
 /// for all other parameters, to query Chalk with it.
-fn canonical_trait_ref(
+fn generic_implements_goal(
     db: &impl HirDatabase,
+    env: Arc<Environment>,
     trait_: Trait,
     self_ty: Canonical<Ty>,
-) -> Canonical<TraitRef> {
+) -> Canonical<InEnvironment<super::Obligation>> {
     let mut substs = Vec::new();
     let generics = trait_.generic_params(db);
     let num_vars = self_ty.num_vars;
@@ -296,8 +297,8 @@ fn canonical_trait_ref(
             .enumerate()
             .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
     );
-    Canonical {
-        num_vars: substs.len() - 1 + self_ty.num_vars,
-        value: TraitRef { trait_, substs: substs.into() },
-    }
+    let num_vars = substs.len() - 1 + self_ty.num_vars;
+    let trait_ref = TraitRef { trait_, substs: substs.into() };
+    let obligation = super::Obligation::Trait(trait_ref);
+    Canonical { num_vars, value: InEnvironment::new(env, obligation) }
 }
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 3e28852b6b..d998433195 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -67,10 +67,33 @@ fn solve(
     solution
 }
 
+/// A set of clauses that we assume to be true. E.g. if we are inside this function:
+/// ```rust
+/// fn foo<T: Default>(t: T) {}
+/// ```
+/// we assume that `T: Default`.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Environment {
+    pub predicates: Vec<GenericPredicate>,
+}
+
+/// Something (usually a goal), along with an environment.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct InEnvironment<T> {
+    pub environment: Arc<Environment>,
+    pub value: T,
+}
+
+impl<T> InEnvironment<T> {
+    pub fn new(environment: Arc<Environment>, value: T) -> InEnvironment<T> {
+        InEnvironment { environment, value }
+    }
+}
+
 /// Something that needs to be proven (by Chalk) during type checking, e.g. that
 /// a certain type implements a certain trait. Proving the Obligation might
 /// result in additional information about inference variables.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum Obligation {
     /// Prove that a certain type implements a trait (the type is the `Self` type
     /// parameter to the `TraitRef`).
@@ -93,44 +116,14 @@ pub struct ProjectionPredicate {
     pub ty: Ty,
 }
 
-/// Check using Chalk whether trait is implemented for given parameters including `Self` type.
-pub(crate) fn implements_query(
+/// Solve a trait goal using Chalk.
+pub(crate) fn solve_query(
     db: &impl HirDatabase,
     krate: Crate,
-    trait_ref: Canonical<TraitRef>,
+    trait_ref: Canonical<InEnvironment<Obligation>>,
 ) -> Option<Solution> {
     let _p = profile("implements_query");
-    let goal: chalk_ir::Goal = trait_ref.value.to_chalk(db).cast();
-    debug!("goal: {:?}", goal);
-    let env = chalk_ir::Environment::new();
-    let in_env = chalk_ir::InEnvironment::new(&env, goal);
-    let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT);
-    let canonical =
-        chalk_ir::Canonical { value: in_env, binders: vec![parameter; trait_ref.num_vars] };
-    // We currently don't deal with universes (I think / hope they're not yet
-    // relevant for our use cases?)
-    let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
-    let solution = solve(db, krate, &u_canonical);
-    solution.map(|solution| solution_from_chalk(db, solution))
-}
-
-pub(crate) fn normalize_query(
-    db: &impl HirDatabase,
-    krate: Crate,
-    projection: Canonical<ProjectionPredicate>,
-) -> Option<Solution> {
-    let goal: chalk_ir::Goal = chalk_ir::Normalize {
-        projection: projection.value.projection_ty.to_chalk(db),
-        ty: projection.value.ty.to_chalk(db),
-    }
-    .cast();
-    debug!("goal: {:?}", goal);
-    // FIXME unify with `implements`
-    let env = chalk_ir::Environment::new();
-    let in_env = chalk_ir::InEnvironment::new(&env, goal);
-    let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT);
-    let canonical =
-        chalk_ir::Canonical { value: in_env, binders: vec![parameter; projection.num_vars] };
+    let canonical = trait_ref.to_chalk(db).cast();
     // We currently don't deal with universes (I think / hope they're not yet
     // relevant for our use cases?)
     let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 4c3744b442..2df4dd13f8 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -12,7 +12,7 @@ use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
 use ra_db::salsa::{InternId, InternKey};
 use test_utils::tested_by;
 
-use super::ChalkContext;
+use super::{Canonical, ChalkContext, Obligation};
 use crate::{
     db::HirDatabase,
     generics::GenericDef,
@@ -218,6 +218,103 @@ impl ToChalk for ProjectionTy {
     }
 }
 
+impl ToChalk for super::ProjectionPredicate {
+    type Chalk = chalk_ir::Normalize;
+
+    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize {
+        chalk_ir::Normalize {
+            projection: self.projection_ty.to_chalk(db),
+            ty: self.ty.to_chalk(db),
+        }
+    }
+
+    fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self {
+        unimplemented!()
+    }
+}
+
+impl ToChalk for Obligation {
+    type Chalk = chalk_ir::DomainGoal;
+
+    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal {
+        match self {
+            Obligation::Trait(tr) => tr.to_chalk(db).cast(),
+            Obligation::Projection(pr) => pr.to_chalk(db).cast(),
+        }
+    }
+
+    fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self {
+        unimplemented!()
+    }
+}
+
+impl<T> ToChalk for Canonical<T>
+where
+    T: ToChalk,
+{
+    type Chalk = chalk_ir::Canonical<T::Chalk>;
+
+    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
+        let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT);
+        let value = self.value.to_chalk(db);
+        let canonical = chalk_ir::Canonical { value, binders: vec![parameter; self.num_vars] };
+        canonical
+    }
+
+    fn from_chalk(db: &impl HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
+        Canonical { num_vars: canonical.binders.len(), value: from_chalk(db, canonical.value) }
+    }
+}
+
+impl ToChalk for Arc<super::Environment> {
+    type Chalk = Arc<chalk_ir::Environment>;
+
+    fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment> {
+        let mut clauses = Vec::new();
+        for pred in &self.predicates {
+            if pred.is_error() {
+                // for env, we just ignore errors
+                continue;
+            }
+            if let GenericPredicate::Implemented(trait_ref) = pred {
+                if blacklisted_trait(db, trait_ref.trait_) {
+                    continue;
+                }
+            }
+            clauses.push(pred.clone().to_chalk(db).cast());
+        }
+        chalk_ir::Environment::new().add_clauses(clauses)
+    }
+
+    fn from_chalk(
+        _db: &impl HirDatabase,
+        _env: Arc<chalk_ir::Environment>,
+    ) -> Arc<super::Environment> {
+        unimplemented!()
+    }
+}
+
+impl<T: ToChalk> ToChalk for super::InEnvironment<T> {
+    type Chalk = chalk_ir::InEnvironment<T::Chalk>;
+
+    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
+        chalk_ir::InEnvironment {
+            environment: self.environment.to_chalk(db),
+            goal: self.value.to_chalk(db),
+        }
+    }
+
+    fn from_chalk(
+        db: &impl HirDatabase,
+        in_env: chalk_ir::InEnvironment<T::Chalk>,
+    ) -> super::InEnvironment<T> {
+        super::InEnvironment {
+            environment: from_chalk(db, in_env.environment),
+            value: from_chalk(db, in_env.goal),
+        }
+    }
+}
+
 fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
     chalk_ir::Binders {
         value,
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 2a1af0a0a3..efc9a92deb 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -295,8 +295,7 @@ impl RootDatabase {
             hir::db::TraitDatumQuery
             hir::db::StructDatumQuery
             hir::db::ImplDatumQuery
-            hir::db::ImplementsQuery
-            hir::db::NormalizeQuery
+            hir::db::SolveQuery
         ];
         acc.sort_by_key(|it| std::cmp::Reverse(it.1));
         acc


Test patch:
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index fe5e89f2d3..7340bb9bd7 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2950,6 +2950,85 @@ fn test(o: O<S>) {
     assert_eq!(t, "&str");
 }
 
+#[test]
+fn generic_param_env_1() {
+    let t = type_at(
+        r#"
+//- /main.rs
+trait Clone {}
+trait Trait { fn foo(self) -> u128; }
+struct S;
+impl Clone for S {}
+impl<T> Trait for T where T: Clone {}
+fn test<T: Clone>(t: T) { t.foo()<|>; }
+"#,
+    );
+    assert_eq!(t, "u128");
+}
+
+#[test]
+fn generic_param_env_1_not_met() {
+    let t = type_at(
+        r#"
+//- /main.rs
+trait Clone {}
+trait Trait { fn foo(self) -> u128; }
+struct S;
+impl Clone for S {}
+impl<T> Trait for T where T: Clone {}
+fn test<T>(t: T) { t.foo()<|>; }
+"#,
+    );
+    assert_eq!(t, "{unknown}");
+}
+
+#[test]
+fn generic_param_env_2() {
+    let t = type_at(
+        r#"
+//- /main.rs
+trait Trait { fn foo(self) -> u128; }
+struct S;
+impl Trait for S {}
+fn test<T: Trait>(t: T) { t.foo()<|>; }
+"#,
+    );
+    assert_eq!(t, "u128");
+}
+
+#[test]
+fn generic_param_env_2_not_met() {
+    let t = type_at(
+        r#"
+//- /main.rs
+trait Trait { fn foo(self) -> u128; }
+struct S;
+impl Trait for S {}
+fn test<T>(t: T) { t.foo()<|>; }
+"#,
+    );
+    assert_eq!(t, "{unknown}");
+}
+
+#[test]
+fn generic_param_env_deref() {
+    let t = type_at(
+        r#"
+//- /main.rs
+#[lang = "deref"]
+trait Deref {
+    type Target;
+}
+trait Trait {}
+impl<T> Deref for T where T: Trait {
+    type Target = i128;
+}
+fn test<T: Trait>(t: T) { (*t)<|>; }
+"#,
+    );
+    assert_eq!(t, "i128");
+}
+
 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();