Start handling environment in trait resolution
I.e. if we are inside a function with some where clauses, we assume these where clauses hold.
This commit is contained in:
parent
638100dc8b
commit
b1b12072ed
6 changed files with 103 additions and 14 deletions
|
@ -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<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>,
|
||||
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<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
|
||||
|
@ -209,8 +211,7 @@ 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 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;
|
||||
}
|
||||
|
|
|
@ -2950,6 +2950,66 @@ 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}");
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
|
@ -72,11 +72,13 @@ fn solve(
|
|||
/// fn foo<T: Default>(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<GenericPredicate>,
|
||||
}
|
||||
|
||||
/// 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<T> {
|
||||
pub environment: Arc<Environment>,
|
||||
pub value: T,
|
||||
|
|
|
@ -239,15 +239,28 @@ where
|
|||
impl ToChalk for Arc<super::Environment> {
|
||||
type Chalk = Arc<chalk_ir::Environment>;
|
||||
|
||||
fn to_chalk(self, _db: &impl HirDatabase) -> Arc<chalk_ir::Environment> {
|
||||
chalk_ir::Environment::new()
|
||||
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> {
|
||||
Arc::new(super::Environment)
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue