Skip to content

Commit dbc14f9

Browse files
committed
First stab at desugaring bounds for APIT
1 parent a943086 commit dbc14f9

File tree

3 files changed

+56
-10
lines changed

3 files changed

+56
-10
lines changed

crates/ra_hir_def/src/generics.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,17 @@ pub struct GenericParams {
5353
/// associated type bindings like `Iterator<Item = u32>`.
5454
#[derive(Clone, PartialEq, Eq, Debug)]
5555
pub struct WherePredicate {
56-
pub type_ref: TypeRef,
56+
pub target: WherePredicateTarget,
5757
pub bound: TypeBound,
5858
}
5959

60+
#[derive(Clone, PartialEq, Eq, Debug)]
61+
pub enum WherePredicateTarget {
62+
TypeRef(TypeRef),
63+
/// For desugared where predicates that can directly refer to a type param.
64+
TypeParam(LocalTypeParamId)
65+
}
66+
6067
type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>;
6168

6269
impl GenericParams {
@@ -190,18 +197,24 @@ impl GenericParams {
190197
return;
191198
}
192199
let bound = TypeBound::from_ast(bound);
193-
self.where_predicates.push(WherePredicate { type_ref, bound });
200+
self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound });
194201
}
195202

196203
fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
197204
type_ref.walk(&mut |type_ref| {
198-
if let TypeRef::ImplTrait(_) = type_ref {
205+
if let TypeRef::ImplTrait(bounds) = type_ref {
199206
let param = TypeParamData {
200207
name: None,
201208
default: None,
202209
provenance: TypeParamProvenance::ArgumentImplTrait,
203210
};
204-
let _param_id = self.types.alloc(param);
211+
let param_id = self.types.alloc(param);
212+
for bound in bounds {
213+
self.where_predicates.push(WherePredicate {
214+
target: WherePredicateTarget::TypeParam(param_id),
215+
bound: bound.clone()
216+
});
217+
}
205218
}
206219
});
207220
}
@@ -211,6 +224,12 @@ impl GenericParams {
211224
.iter()
212225
.find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
213226
}
227+
228+
pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
229+
self.types
230+
.iter()
231+
.find_map(|(id, p)| if p.provenance == TypeParamProvenance::TraitSelf { Some(id) } else { None })
232+
}
214233
}
215234

216235
impl HasChildSource for GenericDefId {

crates/ra_hir_ty/src/lower.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::sync::Arc;
1010

1111
use hir_def::{
1212
builtin_type::BuiltinType,
13-
generics::WherePredicate,
13+
generics::{WherePredicateTarget, WherePredicate},
1414
path::{GenericArg, Path, PathSegment, PathSegments},
1515
resolver::{HasResolver, Resolver, TypeNs},
1616
type_ref::{TypeBound, TypeRef},
@@ -505,7 +505,22 @@ impl GenericPredicate {
505505
ctx: &'a TyLoweringContext<'a, impl HirDatabase>,
506506
where_predicate: &'a WherePredicate,
507507
) -> impl Iterator<Item = GenericPredicate> + 'a {
508-
let self_ty = Ty::from_hir(ctx, &where_predicate.type_ref);
508+
let self_ty = match &where_predicate.target {
509+
WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref),
510+
WherePredicateTarget::TypeParam(param_id) => {
511+
let generic_def = ctx.resolver.generic_def().expect("generics in scope");
512+
let generics = generics(ctx.db, generic_def);
513+
let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id };
514+
let idx = generics.param_idx(param_id);
515+
match ctx.type_param_mode {
516+
TypeParamLoweringMode::Placeholder => {
517+
let name = generics.param_name(param_id);
518+
Ty::Param { idx, name }
519+
},
520+
TypeParamLoweringMode::Variable => Ty::Bound(idx),
521+
}
522+
},
523+
};
509524
GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty)
510525
}
511526

@@ -595,10 +610,18 @@ pub(crate) fn generic_predicates_for_param_query(
595610
) -> Arc<[GenericPredicate]> {
596611
let resolver = def.resolver(db);
597612
let ctx = TyLoweringContext::new(db, &resolver);
613+
let generics = generics(db, def);
598614
resolver
599615
.where_predicates_in_scope()
600616
// we have to filter out all other predicates *first*, before attempting to lower them
601-
.filter(|pred| Ty::from_hir_only_param(&ctx, &pred.type_ref) == Some(param_idx))
617+
.filter(|pred| match &pred.target {
618+
WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_idx),
619+
WherePredicateTarget::TypeParam(local_id) => {
620+
let param_id = hir_def::TypeParamId { parent: def, local_id: *local_id };
621+
let idx = generics.param_idx(param_id);
622+
idx == param_idx
623+
}
624+
})
602625
.flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred))
603626
.collect()
604627
}

crates/ra_hir_ty/src/utils.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,22 @@ use hir_def::{
1212
AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
1313
};
1414
use hir_expand::name::{name, Name};
15+
use hir_def::generics::WherePredicateTarget;
1516

1617
fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
1718
let resolver = trait_.resolver(db);
1819
// returning the iterator directly doesn't easily work because of
1920
// lifetime problems, but since there usually shouldn't be more than a
2021
// few direct traits this should be fine (we could even use some kind of
2122
// SmallVec if performance is a concern)
22-
db.generic_params(trait_.into())
23+
let generic_params = db.generic_params(trait_.into());
24+
let trait_self = generic_params.find_trait_self_param();
25+
generic_params
2326
.where_predicates
2427
.iter()
25-
.filter_map(|pred| match &pred.type_ref {
26-
TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(),
28+
.filter_map(|pred| match &pred.target {
29+
WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => pred.bound.as_path(),
30+
WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => pred.bound.as_path(),
2731
_ => None,
2832
})
2933
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {

0 commit comments

Comments
 (0)