mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Merge #2397
2397: Remove Resolver from autoderef r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
9f7fcc6ecd
7 changed files with 85 additions and 58 deletions
|
@ -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`.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue