From bd53bd80bff9a1f320615a975235399b1fa4792e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 25 Nov 2019 12:45:45 +0300 Subject: Push resolver up --- crates/ra_hir/src/ty/autoderef.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 41c99d227..86b08ae6f 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs @@ -8,10 +8,14 @@ use std::iter::successors; use hir_def::{lang_item::LangItemTarget, resolver::Resolver}; use hir_expand::name; use log::{info, warn}; +use ra_db::CrateId; use crate::{db::HirDatabase, Trait}; -use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; +use super::{ + traits::{InEnvironment, Solution}, + Canonical, Substs, Ty, TypeWalk, +}; const AUTODEREF_RECURSION_LIMIT: usize = 10; @@ -31,16 +35,17 @@ pub(crate) fn deref( if let Some(derefed) = ty.value.builtin_deref() { Some(Canonical { value: derefed, num_vars: ty.num_vars }) } else { - deref_by_trait(db, resolver, ty) + let krate = resolver.krate()?; + let environment = super::lower::trait_env(db, resolver); + deref_by_trait(db, krate, InEnvironment { value: ty, environment }) } } fn deref_by_trait( db: &impl HirDatabase, - resolver: &Resolver, - ty: &Canonical, + krate: CrateId, + ty: InEnvironment<&Canonical>, ) -> Option> { - let krate = resolver.krate()?; let deref_trait = match db.lang_item(krate.into(), "deref".into())? { LangItemTarget::TraitId(t) => Trait::from(t), _ => return None, @@ -56,10 +61,8 @@ fn deref_by_trait( // FIXME make the Canonical handling nicer - let env = super::lower::trait_env(db, resolver); - let parameters = Substs::build_for_generics(&generic_params) - .push(ty.value.clone().shift_bound_vars(1)) + .push(ty.value.value.clone().shift_bound_vars(1)) .build(); let projection = super::traits::ProjectionPredicate { @@ -69,9 +72,9 @@ fn deref_by_trait( let obligation = super::Obligation::Projection(projection); - let in_env = super::traits::InEnvironment { value: obligation, environment: env }; + let in_env = InEnvironment { value: obligation, environment: ty.environment }; - let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: in_env }; + let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; let solution = db.trait_solve(krate.into(), canonical)?; @@ -89,14 +92,14 @@ fn deref_by_trait( // the case. for i in 1..vars.0.num_vars { if vars.0.value[i] != Ty::Bound((i - 1) as u32) { - warn!("complex solution for derefing {:?}: {:?}, ignoring", ty, solution); + warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); return None; } } Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) } Solution::Ambig(_) => { - info!("Ambiguous solution for derefing {:?}: {:?}", ty, solution); + info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution); None } } -- cgit v1.2.3 From 8c3e372835243c922b0eff7ca23f79f227991e88 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 25 Nov 2019 13:10:26 +0300 Subject: Remove Resolver from autoderef Resolver holds onto too much context, including local scopes. Let's try to pass in only what is necessary -- the trait environment. --- crates/ra_hir/src/source_binder.rs | 10 ++++++-- crates/ra_hir/src/ty/autoderef.rs | 24 ++++++++++--------- crates/ra_hir/src/ty/infer.rs | 3 +-- crates/ra_hir/src/ty/infer/coerce.rs | 13 ++++++---- crates/ra_hir/src/ty/infer/expr.rs | 40 ++++++++++++++++++++----------- crates/ra_hir/src/ty/lower.rs | 21 ++++++++-------- crates/ra_hir/src/ty/method_resolution.rs | 11 +++++---- 7 files changed, 73 insertions(+), 49 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 31390bb7f..b4f0e81d3 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -26,7 +26,10 @@ use ra_syntax::{ use crate::{ db::HirDatabase, expr::{BodySourceMap, ExprScopes, ScopeId}, - ty::method_resolution::{self, implements_trait}, + ty::{ + method_resolution::{self, implements_trait}, + TraitEnvironment, + }, Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function, GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty, TypeAlias, }; @@ -408,7 +411,10 @@ impl SourceAnalyzer { // There should be no inference vars in types passed here // FIXME check that? let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; - crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) + let krate = self.resolver.krate(); + let environment = TraitEnvironment::lower(db, &self.resolver); + let ty = crate::ty::InEnvironment { value: canonical, environment }; + crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value) } /// Checks that particular type `ty` implements `std::future::Future`. diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 86b08ae6f..44547197c 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs @@ -5,7 +5,7 @@ use std::iter::successors; -use hir_def::{lang_item::LangItemTarget, resolver::Resolver}; +use hir_def::lang_item::LangItemTarget; use hir_expand::name; use log::{info, warn}; use ra_db::CrateId; @@ -21,23 +21,25 @@ const AUTODEREF_RECURSION_LIMIT: usize = 10; pub(crate) fn autoderef<'a>( db: &'a impl HirDatabase, - resolver: &'a Resolver, - ty: Canonical, + krate: Option, + ty: InEnvironment>, ) -> impl Iterator> + 'a { - successors(Some(ty), move |ty| deref(db, resolver, ty)).take(AUTODEREF_RECURSION_LIMIT) + let InEnvironment { value: ty, environment } = ty; + successors(Some(ty), move |ty| { + deref(db, krate?, InEnvironment { value: ty, environment: environment.clone() }) + }) + .take(AUTODEREF_RECURSION_LIMIT) } pub(crate) fn deref( db: &impl HirDatabase, - resolver: &Resolver, - ty: &Canonical, + krate: CrateId, + ty: InEnvironment<&Canonical>, ) -> Option> { - if let Some(derefed) = ty.value.builtin_deref() { - Some(Canonical { value: derefed, num_vars: ty.num_vars }) + if let Some(derefed) = ty.value.value.builtin_deref() { + Some(Canonical { value: derefed, num_vars: ty.value.num_vars }) } else { - let krate = resolver.krate()?; - let environment = super::lower::trait_env(db, resolver); - deref_by_trait(db, krate, InEnvironment { value: ty, environment }) + deref_by_trait(db, krate, ty) } } diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index ddc7d262a..6fd00d457 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -34,7 +34,6 @@ use ra_prof::profile; use test_utils::tested_by; use super::{ - lower, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, TypeCtor, TypeWalk, Uncertain, @@ -216,7 +215,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), + trait_env: TraitEnvironment::lower(db, &resolver), coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), db, owner, diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs index 54765da35..4b53bba73 100644 --- a/crates/ra_hir/src/ty/infer/coerce.rs +++ b/crates/ra_hir/src/ty/infer/coerce.rs @@ -14,7 +14,7 @@ use crate::{ Adt, Mutability, }; -use super::{InferTy, InferenceContext, TypeVarValue}; +use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue}; impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// Unify two types, but may coerce the first one to the second one @@ -320,9 +320,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone()); let to_ty = self.resolve_ty_shallow(&to_ty); // FIXME: Auto DerefMut - for derefed_ty in - autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone()) - { + for derefed_ty in autoderef::autoderef( + self.db, + self.resolver.krate(), + InEnvironment { + value: canonicalized.value.clone(), + environment: self.trait_env.clone(), + }, + ) { let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) { // Stop when constructor matches. diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index 663ff9435..194e55819 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs @@ -15,9 +15,9 @@ use crate::{ db::HirDatabase, expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, ty::{ - autoderef, method_resolution, op, CallableDef, InferTy, IntTy, Mutability, Namespace, - Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, - Uncertain, + autoderef, method_resolution, op, traits::InEnvironment, CallableDef, InferTy, IntTy, + Mutability, Namespace, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, + TypeCtor, TypeWalk, Uncertain, }, Adt, Name, }; @@ -245,8 +245,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); let ty = autoderef::autoderef( self.db, - &self.resolver.clone(), - canonicalized.value.clone(), + self.resolver.krate(), + InEnvironment { + value: canonicalized.value.clone(), + environment: self.trait_env.clone(), + }, ) .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) { Ty::Apply(a_ty) => match a_ty.ctor { @@ -337,16 +340,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Expr::UnaryOp { expr, op } => { let inner_ty = self.infer_expr(*expr, &Expectation::none()); match op { - UnaryOp::Deref => { - let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty); - if let Some(derefed_ty) = - autoderef::deref(self.db, &self.resolver, &canonicalized.value) - { - canonicalized.decanonicalize_ty(derefed_ty.value) - } else { - Ty::Unknown + UnaryOp::Deref => match self.resolver.krate() { + Some(krate) => { + let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty); + match autoderef::deref( + self.db, + krate, + InEnvironment { + value: &canonicalized.value, + environment: self.trait_env.clone(), + }, + ) { + Some(derefed_ty) => { + canonicalized.decanonicalize_ty(derefed_ty.value) + } + None => Ty::Unknown, + } } - } + None => Ty::Unknown, + }, UnaryOp::Neg => { match &inner_ty { Ty::Apply(a_ty) => match a_ty.ctor { diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index a39beb2a0..b76929501 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -19,8 +19,8 @@ use hir_def::{ use ra_arena::map::ArenaMap; use super::{ - FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, - TypeWalk, + FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, + Ty, TypeCtor, TypeWalk, }; use crate::{ db::HirDatabase, @@ -591,16 +591,15 @@ pub(crate) fn generic_predicates_for_param_query( .collect() } -pub(crate) fn trait_env( - db: &impl HirDatabase, - resolver: &Resolver, -) -> Arc { - let predicates = resolver - .where_predicates_in_scope() - .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) - .collect::>(); +impl TraitEnvironment { + pub(crate) fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { + let predicates = resolver + .where_predicates_in_scope() + .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) + .collect::>(); - Arc::new(super::TraitEnvironment { predicates }) + Arc::new(TraitEnvironment { predicates }) + } } /// Resolve the where clause(s) of an item with generics. diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index caa5f5f74..f7905b5ff 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -15,7 +15,7 @@ use crate::{ AssocItem, Crate, Function, ImplBlock, Module, Mutability, Name, Trait, }; -use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; +use super::{autoderef, Canonical, InEnvironment, TraitEnvironment, TraitRef}; /// This is used as a key for indexing impls. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -179,8 +179,9 @@ pub(crate) fn iterate_method_candidates( // Also note that when we've got a receiver like &S, even if the method we // find in the end takes &self, we still do the autoderef step (just as // rustc does an autoderef and then autoref again). - - for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { + let environment = TraitEnvironment::lower(db, resolver); + let ty = InEnvironment { value: ty.clone(), environment }; + for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { if let Some(result) = iterate_inherent_methods( &derefed_ty, db, @@ -230,7 +231,7 @@ fn iterate_trait_method_candidates( ) -> 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); + let env = TraitEnvironment::lower(db, resolver); // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope let inherent_trait = ty.value.inherent_trait().into_iter(); // if we have `T: Trait` in the param env, the trait doesn't need to be in scope @@ -324,7 +325,7 @@ pub(crate) fn implements_trait( // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet return true; } - let env = lower::trait_env(db, resolver); + let env = TraitEnvironment::lower(db, resolver); let goal = generic_implements_goal(db, env, trait_, ty.clone()); let solution = db.trait_solve(krate, goal); -- cgit v1.2.3