Refactor a bit & introduce Environment struct

This commit is contained in:
Florian Diebold 2019-06-29 17:40:00 +02:00
parent 3210002201
commit 638100dc8b
7 changed files with 107 additions and 21 deletions

View File

@ -217,7 +217,7 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
fn implements(
&self,
krate: Crate,
goal: crate::ty::Canonical<crate::ty::TraitRef>,
goal: crate::ty::Canonical<crate::ty::InEnvironment<crate::ty::TraitRef>>,
) -> Option<crate::ty::traits::Solution>;
#[salsa::invoke(crate::ty::traits::normalize_query)]

View File

@ -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, 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

View File

@ -29,7 +29,8 @@ use test_utils::tested_by;
use super::{
autoderef, method_resolution, op, primitive,
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
ApplicationTy, CallableDef, ProjectionTy, Substs, TraitRef, Ty, TypableDef, TypeCtor,
ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitRef, Ty, TypableDef,
TypeCtor,
};
use crate::{
adt::VariantDef,
@ -330,7 +331,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
for obligation in obligations {
match &obligation {
Obligation::Trait(tr) => {
let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone());
let env = Arc::new(super::Environment); // FIXME add environment
let in_env = InEnvironment::new(env, tr.clone());
let canonicalized = self.canonicalizer().canonicalize_trait_ref(in_env);
let solution = self
.db
.implements(self.resolver.krate().unwrap(), canonicalized.value.clone());

View File

@ -2,7 +2,9 @@
use super::InferenceContext;
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,14 +107,24 @@ where
ProjectionPredicate { ty, projection_ty }
}
// 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_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
let result = self.do_canonicalize_ty(ty);
self.into_canonicalized(result)
}
pub fn canonicalize_trait_ref(mut self, trait_ref: TraitRef) -> Canonicalized<TraitRef> {
let result = self.do_canonicalize_trait_ref(trait_ref);
self.into_canonicalized(result)
pub fn canonicalize_trait_ref(
mut self,
trait_ref_in_env: InEnvironment<TraitRef>,
) -> Canonicalized<InEnvironment<TraitRef>> {
let result = self.do_canonicalize_trait_ref(trait_ref_in_env.value);
// FIXME canonicalize env
self.into_canonicalized(InEnvironment {
value: result,
environment: trait_ref_in_env.environment,
})
}
pub fn canonicalize_projection(

View File

@ -7,7 +7,7 @@ use std::sync::Arc;
use arrayvec::ArrayVec;
use rustc_hash::FxHashMap;
use super::{autoderef, Canonical, TraitRef};
use super::{autoderef, Canonical, Environment, InEnvironment, TraitRef};
use crate::{
generics::HasGenericParams,
impl_block::{ImplBlock, ImplId, ImplItem},
@ -209,7 +209,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());
let env = Arc::new(super::Environment); // FIXME add environment
let trait_ref = canonical_trait_ref(db, env, t, ty.clone());
if db.implements(krate, trait_ref).is_none() {
continue 'traits;
}
@ -279,9 +280,10 @@ impl Ty {
/// for all other parameters, to query Chalk with it.
fn canonical_trait_ref(
db: &impl HirDatabase,
env: Arc<Environment>,
trait_: Trait,
self_ty: Canonical<Ty>,
) -> Canonical<TraitRef> {
) -> Canonical<InEnvironment<TraitRef>> {
let mut substs = Vec::new();
let generics = trait_.generic_params(db);
let num_vars = self_ty.num_vars;
@ -296,6 +298,6 @@ fn canonical_trait_ref(
);
Canonical {
num_vars: substs.len() - 1 + self_ty.num_vars,
value: TraitRef { trait_, substs: substs.into() },
value: InEnvironment::new(env, TraitRef { trait_, substs: substs.into() }),
}
}

View File

@ -67,6 +67,27 @@ 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, PartialOrd, Ord)]
pub struct Environment;
/// Something (usually a goal), along with an environment.
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
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.
@ -97,16 +118,10 @@ pub struct ProjectionPredicate {
pub(crate) fn implements_query(
db: &impl HirDatabase,
krate: Crate,
trait_ref: Canonical<TraitRef>,
trait_ref: Canonical<InEnvironment<TraitRef>>,
) -> 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] };
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 };

View File

@ -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};
use crate::{
db::HirDatabase,
generics::GenericDef,
@ -218,6 +218,60 @@ impl ToChalk for ProjectionTy {
}
}
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> {
chalk_ir::Environment::new()
}
fn from_chalk(
_db: &impl HirDatabase,
_env: Arc<chalk_ir::Environment>,
) -> Arc<super::Environment> {
Arc::new(super::Environment)
}
}
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,