Skip to content

Commit 5325758

Browse files
committed
Auto merge of #49626 - fanzier:chalk-lowering, r=scalexm
Implement Chalk lowering rule Normalize-From-Impl This extends the Chalk lowering pass with the "Normalize-From-Impl" rule for generating program clauses from a trait definition as part of #49177. r? @nikomatsakis
2 parents 9afed64 + 2ef8493 commit 5325758

File tree

6 files changed

+85
-5
lines changed

6 files changed

+85
-5
lines changed

src/librustc/ich/impls_ty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::DomainGoal<'tcx>
13731373
FromEnv(where_clause) => where_clause.hash_stable(hcx, hasher),
13741374

13751375
WellFormedTy(ty) => ty.hash_stable(hcx, hasher),
1376+
Normalize(projection) => projection.hash_stable(hcx, hasher),
13761377
FromEnvTy(ty) => ty.hash_stable(hcx, hasher),
13771378
RegionOutlives(predicate) => predicate.hash_stable(hcx, hasher),
13781379
TypeOutlives(predicate) => predicate.hash_stable(hcx, hasher),

src/librustc/traits/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ pub enum DomainGoal<'tcx> {
267267
WellFormed(WhereClauseAtom<'tcx>),
268268
FromEnv(WhereClauseAtom<'tcx>),
269269
WellFormedTy(Ty<'tcx>),
270+
Normalize(ty::ProjectionPredicate<'tcx>),
270271
FromEnvTy(Ty<'tcx>),
271272
RegionOutlives(ty::RegionOutlivesPredicate<'tcx>),
272273
TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),

src/librustc/traits/structural_impls.rs

+2
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
449449
FromEnv(Implemented(trait_ref)) => write!(fmt, "FromEnv({})", trait_ref),
450450
FromEnv(ProjectionEq(projection)) => write!(fmt, "FromEnv({})", projection),
451451
WellFormedTy(ty) => write!(fmt, "WellFormed({})", ty),
452+
Normalize(projection) => write!(fmt, "Normalize({})", projection),
452453
FromEnvTy(ty) => write!(fmt, "FromEnv({})", ty),
453454
RegionOutlives(predicate) => write!(fmt, "RegionOutlives({})", predicate),
454455
TypeOutlives(predicate) => write!(fmt, "TypeOutlives({})", predicate),
@@ -537,6 +538,7 @@ EnumTypeFoldableImpl! {
537538
(traits::DomainGoal::WellFormed)(wc),
538539
(traits::DomainGoal::FromEnv)(wc),
539540
(traits::DomainGoal::WellFormedTy)(ty),
541+
(traits::DomainGoal::Normalize)(projection),
540542
(traits::DomainGoal::FromEnvTy)(ty),
541543
(traits::DomainGoal::RegionOutlives)(predicate),
542544
(traits::DomainGoal::TypeOutlives)(predicate),

src/librustc_traits/lowering.rs

+65-4
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
106106
FromEnv(..) |
107107
WellFormedTy(..) |
108108
FromEnvTy(..) |
109+
Normalize(..) |
109110
RegionOutlives(..) |
110111
TypeOutlives(..) => self,
111112
}
@@ -116,10 +117,20 @@ crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
116117
-> Lrc<Vec<Clause<'tcx>>>
117118
{
118119
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
119-
let item = tcx.hir.expect_item(node_id);
120-
match item.node {
121-
hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
122-
hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
120+
let node = tcx.hir.find(node_id).unwrap();
121+
match node {
122+
hir::map::Node::NodeItem(item) => match item.node {
123+
hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
124+
hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
125+
_ => Lrc::new(vec![]),
126+
}
127+
hir::map::Node::NodeImplItem(item) => {
128+
if let hir::ImplItemKind::Type(..) = item.node {
129+
program_clauses_for_associated_type_value(tcx, def_id)
130+
} else {
131+
Lrc::new(vec![])
132+
}
133+
},
123134

124135
// FIXME: other constructions e.g. traits, associated types...
125136
_ => Lrc::new(vec![]),
@@ -229,6 +240,56 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
229240
Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))])
230241
}
231242

243+
pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
244+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
245+
item_id: DefId,
246+
) -> Lrc<Vec<Clause<'tcx>>> {
247+
// Rule Normalize-From-Impl (see rustc guide)
248+
//
249+
// ```impl<P0..Pn> Trait<A1..An> for A0
250+
// {
251+
// type AssocType<Pn+1..Pm> where WC = T;
252+
// }```
253+
//
254+
// ```
255+
// forall<P0..Pm> {
256+
// forall<Pn+1..Pm> {
257+
// Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
258+
// Implemented(A0: Trait<A1..An>) && WC
259+
// }
260+
// }
261+
// ```
262+
263+
let item = tcx.associated_item(item_id);
264+
debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
265+
let impl_id = if let ty::AssociatedItemContainer::ImplContainer(impl_id) = item.container {
266+
impl_id
267+
} else {
268+
bug!()
269+
};
270+
// `A0 as Trait<A1..An>`
271+
let trait_ref = tcx.impl_trait_ref(impl_id).unwrap();
272+
// `T`
273+
let ty = tcx.type_of(item_id);
274+
// `Implemented(A0: Trait<A1..An>)`
275+
let trait_implemented = ty::Binder::dummy(ty::TraitPredicate { trait_ref }.lower());
276+
// `WC`
277+
let item_where_clauses = tcx.predicates_of(item_id).predicates.lower();
278+
// `Implemented(A0: Trait<A1..An>) && WC`
279+
let mut where_clauses = vec![trait_implemented];
280+
where_clauses.extend(item_where_clauses);
281+
// `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
282+
let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.name);
283+
// `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
284+
let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
285+
// `Normalize(... -> T) :- ...`
286+
let clause = ProgramClause {
287+
goal: normalize_goal,
288+
hypotheses: where_clauses.into_iter().map(|wc| wc.into()).collect(),
289+
};
290+
Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))])
291+
}
292+
232293
pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
233294
if !tcx.features().rustc_attrs {
234295
return;

src/test/ui/chalkify/lower_impl.rs

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ trait Foo { }
1515
#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
1616
impl<T: 'static> Foo for T where T: Iterator<Item = i32> { }
1717

18+
trait Bar {
19+
type Assoc;
20+
}
21+
22+
impl<T> Bar for T where T: Iterator<Item = i32> {
23+
#[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
24+
type Assoc = Vec<T>;
25+
}
26+
1827
fn main() {
1928
println!("hello");
2029
}

src/test/ui/chalkify/lower_impl.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,11 @@ error: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i
44
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

7-
error: aborting due to previous error
7+
error: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
8+
--> $DIR/lower_impl.rs:23:5
9+
|
10+
LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
814

0 commit comments

Comments
 (0)