2397: Remove Resolver from autoderef r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2019-11-25 10:12:03 +00:00 committed by GitHub
commit 9f7fcc6ecd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 58 deletions

View File

@ -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`.

View File

@ -5,42 +5,49 @@
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;
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;
pub(crate) fn autoderef<'a>(
db: &'a impl HirDatabase,
resolver: &'a Resolver,
ty: Canonical<Ty>,
krate: Option<CrateId>,
ty: InEnvironment<Canonical<Ty>>,
) -> impl Iterator<Item = Canonical<Ty>> + '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<Ty>,
krate: CrateId,
ty: InEnvironment<&Canonical<Ty>>,
) -> Option<Canonical<Ty>> {
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 {
deref_by_trait(db, resolver, ty)
deref_by_trait(db, krate, ty)
}
}
fn deref_by_trait(
db: &impl HirDatabase,
resolver: &Resolver,
ty: &Canonical<Ty>,
krate: CrateId,
ty: InEnvironment<&Canonical<Ty>>,
) -> Option<Canonical<Ty>> {
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 +63,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 +74,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 +94,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
}
}

View File

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

View File

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

View File

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

View File

@ -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<super::TraitEnvironment> {
let predicates = resolver
.where_predicates_in_scope()
.flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
.collect::<Vec<_>>();
impl TraitEnvironment {
pub(crate) fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> {
let predicates = resolver
.where_predicates_in_scope()
.flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
.collect::<Vec<_>>();
Arc::new(super::TraitEnvironment { predicates })
Arc::new(TraitEnvironment { predicates })
}
}
/// Resolve the where clause(s) of an item with generics.

View File

@ -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<T>(
// 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<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);
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);