From 638100dc8bea69cc4093d15f1641ed39a8d27a43 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 29 Jun 2019 17:40:00 +0200 Subject: Refactor a bit & introduce Environment struct --- crates/ra_hir/src/ty/infer.rs | 7 ++-- crates/ra_hir/src/ty/infer/unify.rs | 20 ++++++++--- crates/ra_hir/src/ty/method_resolution.rs | 10 +++--- crates/ra_hir/src/ty/traits.rs | 31 ++++++++++++----- crates/ra_hir/src/ty/traits/chalk.rs | 56 ++++++++++++++++++++++++++++++- 5 files changed, 105 insertions(+), 19 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 52a49070a..84edd3d46 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -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()); diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index a24e5eb5c..ad2eefcaf 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs @@ -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 { let result = self.do_canonicalize_ty(ty); self.into_canonicalized(result) } - pub fn canonicalize_trait_ref(mut self, trait_ref: TraitRef) -> Canonicalized { - 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, + ) -> Canonicalized> { + 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( diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 76ace66ea..770e1964e 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, 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( 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, trait_: Trait, self_ty: Canonical, -) -> Canonical { +) -> Canonical> { 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() }), } } diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 3e28852b6..718970553 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs @@ -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: 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 { + pub environment: Arc, + pub value: T, +} + +impl InEnvironment { + pub fn new(environment: Arc, value: T) -> InEnvironment { + 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, + trait_ref: Canonical>, ) -> Option { 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 }; diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 4c3744b44..bee35fa62 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}; use crate::{ db::HirDatabase, generics::GenericDef, @@ -218,6 +218,60 @@ impl ToChalk for ProjectionTy { } } +impl ToChalk for Canonical +where + T: ToChalk, +{ + type Chalk = chalk_ir::Canonical; + + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Canonical { + 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) -> Canonical { + Canonical { num_vars: canonical.binders.len(), value: from_chalk(db, canonical.value) } + } +} + +impl ToChalk for Arc { + type Chalk = Arc; + + fn to_chalk(self, _db: &impl HirDatabase) -> Arc { + chalk_ir::Environment::new() + } + + fn from_chalk( + _db: &impl HirDatabase, + _env: Arc, + ) -> Arc { + Arc::new(super::Environment) + } +} + +impl ToChalk for super::InEnvironment { + type Chalk = chalk_ir::InEnvironment; + + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment { + 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, + ) -> super::InEnvironment { + super::InEnvironment { + environment: from_chalk(db, in_env.environment), + value: from_chalk(db, in_env.goal), + } + } +} + fn make_binders(value: T, num_vars: usize) -> chalk_ir::Binders { chalk_ir::Binders { value, -- cgit v1.2.3