Skip to content

Commit b1b1207

Browse files
committed
Start handling environment in trait resolution
I.e. if we are inside a function with some where clauses, we assume these where clauses hold.
1 parent 638100d commit b1b1207

File tree

6 files changed

+103
-14
lines changed

6 files changed

+103
-14
lines changed

crates/ra_hir/src/ty/infer.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ use ra_prof::profile;
2727
use test_utils::tested_by;
2828

2929
use super::{
30-
autoderef, method_resolution, op, primitive,
30+
autoderef, lower, method_resolution, op, primitive,
3131
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
32-
ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitRef, Ty, TypableDef,
33-
TypeCtor,
32+
ApplicationTy, CallableDef, Environment, InEnvironment, ProjectionTy, Substs, TraitRef, Ty,
33+
TypableDef, TypeCtor,
3434
};
3535
use crate::{
3636
adt::VariantDef,
@@ -166,6 +166,7 @@ struct InferenceContext<'a, D: HirDatabase> {
166166
body: Arc<Body>,
167167
resolver: Resolver,
168168
var_unification_table: InPlaceUnificationTable<TypeVarId>,
169+
trait_env: Arc<Environment>,
169170
obligations: Vec<Obligation>,
170171
method_resolutions: FxHashMap<ExprId, Function>,
171172
field_resolutions: FxHashMap<ExprId, StructField>,
@@ -189,6 +190,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
189190
var_unification_table: InPlaceUnificationTable::new(),
190191
obligations: Vec::default(),
191192
return_ty: Ty::Unknown, // set in collect_fn_signature
193+
trait_env: lower::trait_env(db, &resolver),
192194
db,
193195
body,
194196
resolver,
@@ -331,8 +333,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
331333
for obligation in obligations {
332334
match &obligation {
333335
Obligation::Trait(tr) => {
334-
let env = Arc::new(super::Environment); // FIXME add environment
335-
let in_env = InEnvironment::new(env, tr.clone());
336+
let in_env = InEnvironment::new(self.trait_env.clone(), tr.clone());
336337
let canonicalized = self.canonicalizer().canonicalize_trait_ref(in_env);
337338
let solution = self
338339
.db

crates/ra_hir/src/ty/lower.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,18 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
317317
Ty::from_hir(db, &resolver, type_ref)
318318
}
319319

320+
pub(crate) fn trait_env(db: &impl HirDatabase, resolver: &Resolver) -> Arc<super::Environment> {
321+
let predicates = resolver
322+
.where_predicates_in_scope()
323+
.map(|pred| {
324+
TraitRef::for_where_predicate(db, &resolver, pred)
325+
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
326+
})
327+
.collect::<Vec<_>>();
328+
329+
Arc::new(super::Environment { predicates })
330+
}
331+
320332
/// Resolve the where clause(s) of an item with generics.
321333
pub(crate) fn generic_predicates_query(
322334
db: &impl HirDatabase,

crates/ra_hir/src/ty/method_resolution.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::sync::Arc;
77
use arrayvec::ArrayVec;
88
use rustc_hash::FxHashMap;
99

10-
use super::{autoderef, Canonical, Environment, InEnvironment, TraitRef};
10+
use super::{autoderef, lower, Canonical, Environment, InEnvironment, TraitRef};
1111
use crate::{
1212
generics::HasGenericParams,
1313
impl_block::{ImplBlock, ImplId, ImplItem},
@@ -198,6 +198,8 @@ fn iterate_trait_method_candidates<T>(
198198
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
199199
) -> Option<T> {
200200
let krate = resolver.krate()?;
201+
// FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
202+
let env = lower::trait_env(db, resolver);
201203
'traits: for t in resolver.traits_in_scope(db) {
202204
let data = t.trait_data(db);
203205
// we'll be lazy about checking whether the type implements the
@@ -209,8 +211,7 @@ fn iterate_trait_method_candidates<T>(
209211
let data = m.data(db);
210212
if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
211213
if !known_implemented {
212-
let env = Arc::new(super::Environment); // FIXME add environment
213-
let trait_ref = canonical_trait_ref(db, env, t, ty.clone());
214+
let trait_ref = canonical_trait_ref(db, env.clone(), t, ty.clone());
214215
if db.implements(krate, trait_ref).is_none() {
215216
continue 'traits;
216217
}

crates/ra_hir/src/ty/tests.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2950,6 +2950,66 @@ fn test(o: O<S>) {
29502950
assert_eq!(t, "&str");
29512951
}
29522952

2953+
#[test]
2954+
fn generic_param_env_1() {
2955+
let t = type_at(
2956+
r#"
2957+
//- /main.rs
2958+
trait Clone {}
2959+
trait Trait { fn foo(self) -> u128; }
2960+
struct S;
2961+
impl Clone for S {}
2962+
impl<T> Trait for T where T: Clone {}
2963+
fn test<T: Clone>(t: T) { t.foo()<|>; }
2964+
"#,
2965+
);
2966+
assert_eq!(t, "u128");
2967+
}
2968+
2969+
#[test]
2970+
fn generic_param_env_1_not_met() {
2971+
let t = type_at(
2972+
r#"
2973+
//- /main.rs
2974+
trait Clone {}
2975+
trait Trait { fn foo(self) -> u128; }
2976+
struct S;
2977+
impl Clone for S {}
2978+
impl<T> Trait for T where T: Clone {}
2979+
fn test<T>(t: T) { t.foo()<|>; }
2980+
"#,
2981+
);
2982+
assert_eq!(t, "{unknown}");
2983+
}
2984+
2985+
#[test]
2986+
fn generic_param_env_2() {
2987+
let t = type_at(
2988+
r#"
2989+
//- /main.rs
2990+
trait Trait { fn foo(self) -> u128; }
2991+
struct S;
2992+
impl Trait for S {}
2993+
fn test<T: Trait>(t: T) { t.foo()<|>; }
2994+
"#,
2995+
);
2996+
assert_eq!(t, "u128");
2997+
}
2998+
2999+
#[test]
3000+
fn generic_param_env_2_not_met() {
3001+
let t = type_at(
3002+
r#"
3003+
//- /main.rs
3004+
trait Trait { fn foo(self) -> u128; }
3005+
struct S;
3006+
impl Trait for S {}
3007+
fn test<T>(t: T) { t.foo()<|>; }
3008+
"#,
3009+
);
3010+
assert_eq!(t, "{unknown}");
3011+
}
3012+
29533013
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
29543014
let file = db.parse(pos.file_id).ok().unwrap();
29553015
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();

crates/ra_hir/src/ty/traits.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,13 @@ fn solve(
7272
/// fn foo<T: Default>(t: T) {}
7373
/// ```
7474
/// we assume that `T: Default`.
75-
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
76-
pub struct Environment;
75+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
76+
pub struct Environment {
77+
pub predicates: Vec<GenericPredicate>,
78+
}
7779

7880
/// Something (usually a goal), along with an environment.
79-
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
81+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8082
pub struct InEnvironment<T> {
8183
pub environment: Arc<Environment>,
8284
pub value: T,

crates/ra_hir/src/ty/traits/chalk.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,15 +239,28 @@ where
239239
impl ToChalk for Arc<super::Environment> {
240240
type Chalk = Arc<chalk_ir::Environment>;
241241

242-
fn to_chalk(self, _db: &impl HirDatabase) -> Arc<chalk_ir::Environment> {
243-
chalk_ir::Environment::new()
242+
fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment> {
243+
let mut clauses = Vec::new();
244+
for pred in &self.predicates {
245+
if pred.is_error() {
246+
// for env, we just ignore errors
247+
continue;
248+
}
249+
if let GenericPredicate::Implemented(trait_ref) = pred {
250+
if blacklisted_trait(db, trait_ref.trait_) {
251+
continue;
252+
}
253+
}
254+
clauses.push(pred.clone().to_chalk(db).cast());
255+
}
256+
chalk_ir::Environment::new().add_clauses(clauses)
244257
}
245258

246259
fn from_chalk(
247260
_db: &impl HirDatabase,
248261
_env: Arc<chalk_ir::Environment>,
249262
) -> Arc<super::Environment> {
250-
Arc::new(super::Environment)
263+
unimplemented!()
251264
}
252265
}
253266

0 commit comments

Comments
 (0)