diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 84edd3d46d..f8839ebd23 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -27,10 +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, InEnvironment, ProjectionTy, Substs, TraitRef, Ty, TypableDef,
- TypeCtor,
+ ApplicationTy, CallableDef, Environment, InEnvironment, ProjectionTy, Substs, TraitRef, Ty,
+ TypableDef, TypeCtor,
};
use crate::{
adt::VariantDef,
@@ -166,6 +166,7 @@ struct InferenceContext<'a, D: HirDatabase> {
body: Arc
,
resolver: Resolver,
var_unification_table: InPlaceUnificationTable,
+ trait_env: Arc,
obligations: Vec,
method_resolutions: FxHashMap,
field_resolutions: FxHashMap,
@@ -189,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,
@@ -331,8 +333,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
for obligation in obligations {
match &obligation {
Obligation::Trait(tr) => {
- let env = Arc::new(super::Environment); // FIXME add environment
- let in_env = InEnvironment::new(env, tr.clone());
+ let in_env = InEnvironment::new(self.trait_env.clone(), tr.clone());
let canonicalized = self.canonicalizer().canonicalize_trait_ref(in_env);
let solution = self
.db
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 {
+ let predicates = resolver
+ .where_predicates_in_scope()
+ .map(|pred| {
+ TraitRef::for_where_predicate(db, &resolver, pred)
+ .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
+ })
+ .collect::>();
+
+ 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 770e1964ed..40f5eabf0f 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -7,7 +7,7 @@ use std::sync::Arc;
use arrayvec::ArrayVec;
use rustc_hash::FxHashMap;
-use super::{autoderef, Canonical, Environment, InEnvironment, TraitRef};
+use super::{autoderef, lower, Canonical, Environment, InEnvironment, TraitRef};
use crate::{
generics::HasGenericParams,
impl_block::{ImplBlock, ImplId, ImplItem},
@@ -198,6 +198,8 @@ fn iterate_trait_method_candidates(
mut callback: impl FnMut(&Ty, Function) -> Option,
) -> Option {
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
@@ -209,8 +211,7 @@ fn iterate_trait_method_candidates(
let data = m.data(db);
if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
if !known_implemented {
- let env = Arc::new(super::Environment); // FIXME add environment
- let trait_ref = canonical_trait_ref(db, env, t, ty.clone());
+ let trait_ref = canonical_trait_ref(db, env.clone(), t, ty.clone());
if db.implements(krate, trait_ref).is_none() {
continue 'traits;
}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index fe5e89f2d3..594e82af24 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2950,6 +2950,66 @@ fn test(o: O) {
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 Trait for T where T: Clone {}
+fn test(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 Trait for T where T: Clone {}
+fn test(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: 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.foo()<|>; }
+"#,
+ );
+ assert_eq!(t, "{unknown}");
+}
+
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::(file.syntax(), pos.offset).unwrap();
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 718970553b..e0c93550a1 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -72,11 +72,13 @@ fn solve(
/// fn foo(t: T) {}
/// ```
/// we assume that `T: Default`.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct Environment;
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Environment {
+ pub predicates: Vec,
+}
/// Something (usually a goal), along with an environment.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct InEnvironment {
pub environment: Arc,
pub value: T,
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index bee35fa628..f36ff2fc63 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -239,15 +239,28 @@ where
impl ToChalk for Arc {
type Chalk = Arc;
- fn to_chalk(self, _db: &impl HirDatabase) -> Arc {
- chalk_ir::Environment::new()
+ fn to_chalk(self, db: &impl HirDatabase) -> Arc {
+ 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,
) -> Arc {
- Arc::new(super::Environment)
+ unimplemented!()
}
}