mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 17:28:09 +00:00
First stab at desugaring bounds for APIT
This commit is contained in:
parent
a9430865b3
commit
dbc14f9d57
3 changed files with 56 additions and 10 deletions
|
@ -53,10 +53,17 @@ pub struct GenericParams {
|
|||
/// associated type bindings like `Iterator<Item = u32>`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct WherePredicate {
|
||||
pub type_ref: TypeRef,
|
||||
pub target: WherePredicateTarget,
|
||||
pub bound: TypeBound,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum WherePredicateTarget {
|
||||
TypeRef(TypeRef),
|
||||
/// For desugared where predicates that can directly refer to a type param.
|
||||
TypeParam(LocalTypeParamId)
|
||||
}
|
||||
|
||||
type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>;
|
||||
|
||||
impl GenericParams {
|
||||
|
@ -190,18 +197,24 @@ impl GenericParams {
|
|||
return;
|
||||
}
|
||||
let bound = TypeBound::from_ast(bound);
|
||||
self.where_predicates.push(WherePredicate { type_ref, bound });
|
||||
self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound });
|
||||
}
|
||||
|
||||
fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
|
||||
type_ref.walk(&mut |type_ref| {
|
||||
if let TypeRef::ImplTrait(_) = type_ref {
|
||||
if let TypeRef::ImplTrait(bounds) = type_ref {
|
||||
let param = TypeParamData {
|
||||
name: None,
|
||||
default: None,
|
||||
provenance: TypeParamProvenance::ArgumentImplTrait,
|
||||
};
|
||||
let _param_id = self.types.alloc(param);
|
||||
let param_id = self.types.alloc(param);
|
||||
for bound in bounds {
|
||||
self.where_predicates.push(WherePredicate {
|
||||
target: WherePredicateTarget::TypeParam(param_id),
|
||||
bound: bound.clone()
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -211,6 +224,12 @@ impl GenericParams {
|
|||
.iter()
|
||||
.find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
|
||||
}
|
||||
|
||||
pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
|
||||
self.types
|
||||
.iter()
|
||||
.find_map(|(id, p)| if p.provenance == TypeParamProvenance::TraitSelf { Some(id) } else { None })
|
||||
}
|
||||
}
|
||||
|
||||
impl HasChildSource for GenericDefId {
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::sync::Arc;
|
|||
|
||||
use hir_def::{
|
||||
builtin_type::BuiltinType,
|
||||
generics::WherePredicate,
|
||||
generics::{WherePredicateTarget, WherePredicate},
|
||||
path::{GenericArg, Path, PathSegment, PathSegments},
|
||||
resolver::{HasResolver, Resolver, TypeNs},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
|
@ -505,7 +505,22 @@ impl GenericPredicate {
|
|||
ctx: &'a TyLoweringContext<'a, impl HirDatabase>,
|
||||
where_predicate: &'a WherePredicate,
|
||||
) -> impl Iterator<Item = GenericPredicate> + 'a {
|
||||
let self_ty = Ty::from_hir(ctx, &where_predicate.type_ref);
|
||||
let self_ty = match &where_predicate.target {
|
||||
WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref),
|
||||
WherePredicateTarget::TypeParam(param_id) => {
|
||||
let generic_def = ctx.resolver.generic_def().expect("generics in scope");
|
||||
let generics = generics(ctx.db, generic_def);
|
||||
let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id };
|
||||
let idx = generics.param_idx(param_id);
|
||||
match ctx.type_param_mode {
|
||||
TypeParamLoweringMode::Placeholder => {
|
||||
let name = generics.param_name(param_id);
|
||||
Ty::Param { idx, name }
|
||||
},
|
||||
TypeParamLoweringMode::Variable => Ty::Bound(idx),
|
||||
}
|
||||
},
|
||||
};
|
||||
GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty)
|
||||
}
|
||||
|
||||
|
@ -595,10 +610,18 @@ pub(crate) fn generic_predicates_for_param_query(
|
|||
) -> Arc<[GenericPredicate]> {
|
||||
let resolver = def.resolver(db);
|
||||
let ctx = TyLoweringContext::new(db, &resolver);
|
||||
let generics = generics(db, def);
|
||||
resolver
|
||||
.where_predicates_in_scope()
|
||||
// we have to filter out all other predicates *first*, before attempting to lower them
|
||||
.filter(|pred| Ty::from_hir_only_param(&ctx, &pred.type_ref) == Some(param_idx))
|
||||
.filter(|pred| match &pred.target {
|
||||
WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_idx),
|
||||
WherePredicateTarget::TypeParam(local_id) => {
|
||||
let param_id = hir_def::TypeParamId { parent: def, local_id: *local_id };
|
||||
let idx = generics.param_idx(param_id);
|
||||
idx == param_idx
|
||||
}
|
||||
})
|
||||
.flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred))
|
||||
.collect()
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use hir_def::{
|
|||
AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use hir_def::generics::WherePredicateTarget;
|
||||
|
||||
fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
|
||||
let resolver = trait_.resolver(db);
|
||||
|
@ -19,11 +20,14 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
|
|||
// lifetime problems, but since there usually shouldn't be more than a
|
||||
// few direct traits this should be fine (we could even use some kind of
|
||||
// SmallVec if performance is a concern)
|
||||
db.generic_params(trait_.into())
|
||||
let generic_params = db.generic_params(trait_.into());
|
||||
let trait_self = generic_params.find_trait_self_param();
|
||||
generic_params
|
||||
.where_predicates
|
||||
.iter()
|
||||
.filter_map(|pred| match &pred.type_ref {
|
||||
TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(),
|
||||
.filter_map(|pred| match &pred.target {
|
||||
WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => pred.bound.as_path(),
|
||||
WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => pred.bound.as_path(),
|
||||
_ => None,
|
||||
})
|
||||
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
|
||||
|
|
Loading…
Reference in a new issue