]> git.proxmox.com Git - rustc.git/blob - src/librustc_traits/lowering/mod.rs
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / librustc_traits / lowering / mod.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 mod environment;
12
13 use rustc::hir::def_id::DefId;
14 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
15 use rustc::hir::map::definitions::DefPathData;
16 use rustc::hir::{self, ImplPolarity};
17 use rustc::traits::{
18 Clause,
19 Clauses,
20 DomainGoal,
21 FromEnv,
22 GoalKind,
23 PolyDomainGoal,
24 ProgramClause,
25 ProgramClauseCategory,
26 WellFormed,
27 WhereClause,
28 };
29 use rustc::ty::query::Providers;
30 use rustc::ty::{self, List, TyCtxt};
31 use syntax::ast;
32
33 use std::iter;
34
35 crate fn provide(p: &mut Providers) {
36 *p = Providers {
37 program_clauses_for,
38 program_clauses_for_env: environment::program_clauses_for_env,
39 environment: environment::environment,
40 ..*p
41 };
42 }
43
44 crate trait Lower<T> {
45 /// Lower a rustc construct (e.g. `ty::TraitPredicate`) to a chalk-like type.
46 fn lower(&self) -> T;
47 }
48
49 impl<T, U> Lower<Vec<U>> for Vec<T>
50 where
51 T: Lower<U>,
52 {
53 fn lower(&self) -> Vec<U> {
54 self.iter().map(|item| item.lower()).collect()
55 }
56 }
57
58 impl<'tcx> Lower<WhereClause<'tcx>> for ty::TraitPredicate<'tcx> {
59 fn lower(&self) -> WhereClause<'tcx> {
60 WhereClause::Implemented(*self)
61 }
62 }
63
64 impl<'tcx> Lower<WhereClause<'tcx>> for ty::ProjectionPredicate<'tcx> {
65 fn lower(&self) -> WhereClause<'tcx> {
66 WhereClause::ProjectionEq(*self)
67 }
68 }
69
70 impl<'tcx> Lower<WhereClause<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
71 fn lower(&self) -> WhereClause<'tcx> {
72 WhereClause::RegionOutlives(*self)
73 }
74 }
75
76 impl<'tcx> Lower<WhereClause<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
77 fn lower(&self) -> WhereClause<'tcx> {
78 WhereClause::TypeOutlives(*self)
79 }
80 }
81
82 impl<'tcx, T> Lower<DomainGoal<'tcx>> for T
83 where
84 T: Lower<WhereClause<'tcx>>,
85 {
86 fn lower(&self) -> DomainGoal<'tcx> {
87 DomainGoal::Holds(self.lower())
88 }
89 }
90
91 /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
92 /// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
93 /// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous
94 /// example), we model them with quantified domain goals, e.g. as for the previous example:
95 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
96 /// `Binder<Holds(Implemented(TraitPredicate))>`.
97 impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
98 where
99 T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>,
100 {
101 fn lower(&self) -> PolyDomainGoal<'tcx> {
102 self.map_bound_ref(|p| p.lower())
103 }
104 }
105
106 impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
107 fn lower(&self) -> PolyDomainGoal<'tcx> {
108 use rustc::ty::Predicate;
109
110 match self {
111 Predicate::Trait(predicate) => predicate.lower(),
112 Predicate::RegionOutlives(predicate) => predicate.lower(),
113 Predicate::TypeOutlives(predicate) => predicate.lower(),
114 Predicate::Projection(predicate) => predicate.lower(),
115 Predicate::WellFormed(ty) => {
116 ty::Binder::dummy(DomainGoal::WellFormed(WellFormed::Ty(*ty)))
117 }
118 Predicate::ObjectSafe(..)
119 | Predicate::ClosureKind(..)
120 | Predicate::Subtype(..)
121 | Predicate::ConstEvaluatable(..) => unimplemented!(),
122 }
123 }
124 }
125
126 /// Used for implied bounds related rules (see rustc guide).
127 trait IntoFromEnvGoal {
128 /// Transforms an existing goal into a `FromEnv` goal.
129 fn into_from_env_goal(self) -> Self;
130 }
131
132 /// Used for well-formedness related rules (see rustc guide).
133 trait IntoWellFormedGoal {
134 /// Transforms an existing goal into a `WellFormed` goal.
135 fn into_well_formed_goal(self) -> Self;
136 }
137
138 impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
139 fn into_from_env_goal(self) -> DomainGoal<'tcx> {
140 use self::WhereClause::*;
141
142 match self {
143 DomainGoal::Holds(Implemented(trait_ref)) => {
144 DomainGoal::FromEnv(FromEnv::Trait(trait_ref))
145 }
146 other => other,
147 }
148 }
149 }
150
151 impl<'tcx> IntoWellFormedGoal for DomainGoal<'tcx> {
152 fn into_well_formed_goal(self) -> DomainGoal<'tcx> {
153 use self::WhereClause::*;
154
155 match self {
156 DomainGoal::Holds(Implemented(trait_ref)) => {
157 DomainGoal::WellFormed(WellFormed::Trait(trait_ref))
158 }
159 other => other,
160 }
161 }
162 }
163
164 crate fn program_clauses_for<'a, 'tcx>(
165 tcx: TyCtxt<'a, 'tcx, 'tcx>,
166 def_id: DefId,
167 ) -> Clauses<'tcx> {
168 match tcx.def_key(def_id).disambiguated_data.data {
169 DefPathData::Trait(_) => program_clauses_for_trait(tcx, def_id),
170 DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
171 DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id),
172 DefPathData::AssocTypeInTrait(..) => program_clauses_for_associated_type_def(tcx, def_id),
173 DefPathData::TypeNs(..) => program_clauses_for_type_def(tcx, def_id),
174 _ => List::empty(),
175 }
176 }
177
178 fn program_clauses_for_trait<'a, 'tcx>(
179 tcx: TyCtxt<'a, 'tcx, 'tcx>,
180 def_id: DefId,
181 ) -> Clauses<'tcx> {
182 // `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
183
184 // Rule Implemented-From-Env (see rustc guide)
185 //
186 // ```
187 // forall<Self, P1..Pn> {
188 // Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
189 // }
190 // ```
191
192 // `Self: Trait<P1..Pn>`
193 let trait_pred = ty::TraitPredicate {
194 trait_ref: ty::TraitRef::identity(tcx, def_id),
195 };
196
197 // `Implemented(Self: Trait<P1..Pn>)`
198 let impl_trait: DomainGoal = trait_pred.lower();
199
200 // `FromEnv(Self: Trait<P1..Pn>)`
201 let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal());
202 let hypotheses = tcx.intern_goals(&[from_env_goal]);
203
204 // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
205 let implemented_from_env = ProgramClause {
206 goal: impl_trait,
207 hypotheses,
208 category: ProgramClauseCategory::ImpliedBound,
209 };
210
211 let clauses = iter::once(Clause::ForAll(ty::Binder::dummy(implemented_from_env)));
212
213 let where_clauses = &tcx.predicates_defined_on(def_id).predicates
214 .into_iter()
215 .map(|(wc, _)| wc.lower())
216 .collect::<Vec<_>>();
217
218 // Rule Implied-Bound-From-Trait
219 //
220 // For each where clause WC:
221 // ```
222 // forall<Self, P1..Pn> {
223 // FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn)
224 // }
225 // ```
226
227 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
228 let implied_bound_clauses = where_clauses
229 .iter()
230 .cloned()
231
232 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
233 .map(|wc| wc.map_bound(|goal| ProgramClause {
234 goal: goal.into_from_env_goal(),
235 hypotheses,
236 category: ProgramClauseCategory::ImpliedBound,
237 }))
238 .map(Clause::ForAll);
239
240 // Rule WellFormed-TraitRef
241 //
242 // Here `WC` denotes the set of all where clauses:
243 // ```
244 // forall<Self, P1..Pn> {
245 // WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
246 // }
247 // ```
248
249 // `Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
250 let wf_conditions = iter::once(ty::Binder::dummy(trait_pred.lower()))
251 .chain(
252 where_clauses
253 .into_iter()
254 .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal()))
255 );
256
257 // `WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
258 let wf_clause = ProgramClause {
259 goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
260 hypotheses: tcx.mk_goals(
261 wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
262 ),
263 category: ProgramClauseCategory::WellFormed,
264 };
265 let wf_clause = iter::once(Clause::ForAll(ty::Binder::dummy(wf_clause)));
266
267 tcx.mk_clauses(
268 clauses
269 .chain(implied_bound_clauses)
270 .chain(wf_clause)
271 )
272 }
273
274 fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> {
275 if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
276 return List::empty();
277 }
278
279 // Rule Implemented-From-Impl (see rustc guide)
280 //
281 // `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
282 //
283 // ```
284 // forall<P0..Pn> {
285 // Implemented(A0: Trait<A1..An>) :- WC
286 // }
287 // ```
288
289 let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
290
291 // `Implemented(A0: Trait<A1..An>)`
292 let trait_pred = ty::TraitPredicate { trait_ref }.lower();
293
294 // `WC`
295 let where_clauses = tcx.predicates_of(def_id).predicates
296 .into_iter()
297 .map(|(wc, _)| wc.lower());
298
299 // `Implemented(A0: Trait<A1..An>) :- WC`
300 let clause = ProgramClause {
301 goal: trait_pred,
302 hypotheses: tcx.mk_goals(
303 where_clauses
304 .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
305 ),
306 category: ProgramClauseCategory::Other,
307 };
308 tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
309 }
310
311 pub fn program_clauses_for_type_def<'a, 'tcx>(
312 tcx: TyCtxt<'a, 'tcx, 'tcx>,
313 def_id: DefId,
314 ) -> Clauses<'tcx> {
315 // Rule WellFormed-Type
316 //
317 // `struct Ty<P1..Pn> where WC1, ..., WCm`
318 //
319 // ```
320 // forall<P1..Pn> {
321 // WellFormed(Ty<...>) :- WC1, ..., WCm`
322 // }
323 // ```
324
325 // `Ty<...>`
326 let ty = tcx.type_of(def_id);
327
328 // `WC`
329 let where_clauses = tcx.predicates_of(def_id).predicates
330 .into_iter()
331 .map(|(wc, _)| wc.lower())
332 .collect::<Vec<_>>();
333
334 // `WellFormed(Ty<...>) :- WC1, ..., WCm`
335 let well_formed = ProgramClause {
336 goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
337 hypotheses: tcx.mk_goals(
338 where_clauses
339 .iter()
340 .cloned()
341 .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
342 ),
343 category: ProgramClauseCategory::WellFormed,
344 };
345
346 let well_formed_clause = iter::once(Clause::ForAll(ty::Binder::dummy(well_formed)));
347
348 // Rule FromEnv-Type
349 //
350 // For each where clause `WC`:
351 // ```
352 // forall<P1..Pn> {
353 // FromEnv(WC) :- FromEnv(Ty<...>)
354 // }
355 // ```
356
357 // `FromEnv(Ty<...>)`
358 let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal());
359 let hypotheses = tcx.intern_goals(&[from_env_goal]);
360
361 // For each where clause `WC`:
362 let from_env_clauses = where_clauses
363 .into_iter()
364
365 // `FromEnv(WC) :- FromEnv(Ty<...>)`
366 .map(|wc| wc.map_bound(|goal| ProgramClause {
367 goal: goal.into_from_env_goal(),
368 hypotheses,
369 category: ProgramClauseCategory::ImpliedBound,
370 }))
371
372 .map(Clause::ForAll);
373
374 tcx.mk_clauses(well_formed_clause.chain(from_env_clauses))
375 }
376
377 pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
378 tcx: TyCtxt<'a, 'tcx, 'tcx>,
379 item_id: DefId,
380 ) -> Clauses<'tcx> {
381 // Rule ProjectionEq-Skolemize
382 //
383 // ```
384 // trait Trait<P1..Pn> {
385 // type AssocType<Pn+1..Pm>;
386 // }
387 // ```
388 //
389 // `ProjectionEq` can succeed by skolemizing, see "associated type"
390 // chapter for more:
391 // ```
392 // forall<Self, P1..Pn, Pn+1..Pm> {
393 // ProjectionEq(
394 // <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
395 // (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
396 // )
397 // }
398 // ```
399
400 let item = tcx.associated_item(item_id);
401 debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
402 let trait_id = match item.container {
403 ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id,
404 _ => bug!("not an trait container"),
405 };
406 let trait_ref = ty::TraitRef::identity(tcx, trait_id);
407
408 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
409 let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty));
410 let projection_eq = WhereClause::ProjectionEq(ty::ProjectionPredicate {
411 projection_ty,
412 ty: placeholder_ty,
413 });
414
415 let projection_eq_clause = ProgramClause {
416 goal: DomainGoal::Holds(projection_eq),
417 hypotheses: ty::List::empty(),
418 category: ProgramClauseCategory::Other,
419 };
420
421 // Rule WellFormed-AssocTy
422 // ```
423 // forall<Self, P1..Pn, Pn+1..Pm> {
424 // WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
425 // :- Implemented(Self: Trait<P1..Pn>)
426 // }
427 // ```
428
429 let trait_predicate = ty::TraitPredicate { trait_ref };
430 let hypothesis = tcx.mk_goal(
431 DomainGoal::Holds(WhereClause::Implemented(trait_predicate)).into_goal()
432 );
433 let wf_clause = ProgramClause {
434 goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
435 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
436 category: ProgramClauseCategory::WellFormed,
437 };
438
439 // Rule Implied-Trait-From-AssocTy
440 // ```
441 // forall<Self, P1..Pn, Pn+1..Pm> {
442 // FromEnv(Self: Trait<P1..Pn>)
443 // :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
444 // }
445 // ```
446
447 let hypothesis = tcx.mk_goal(
448 DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal()
449 );
450 let from_env_clause = ProgramClause {
451 goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
452 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
453 category: ProgramClauseCategory::ImpliedBound,
454 };
455
456 let clauses = iter::once(projection_eq_clause)
457 .chain(iter::once(wf_clause))
458 .chain(iter::once(from_env_clause));
459 let clauses = clauses.map(|clause| Clause::ForAll(ty::Binder::dummy(clause)));
460 tcx.mk_clauses(clauses)
461 }
462
463 pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
464 tcx: TyCtxt<'a, 'tcx, 'tcx>,
465 item_id: DefId,
466 ) -> Clauses<'tcx> {
467 // Rule Normalize-From-Impl (see rustc guide)
468 //
469 // ```
470 // impl<P0..Pn> Trait<A1..An> for A0 {
471 // type AssocType<Pn+1..Pm> = T;
472 // }
473 // ```
474 //
475 // FIXME: For the moment, we don't account for where clauses written on the associated
476 // ty definition (i.e. in the trait def, as in `type AssocType<T> where T: Sized`).
477 // ```
478 // forall<P0..Pm> {
479 // forall<Pn+1..Pm> {
480 // Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
481 // Implemented(A0: Trait<A1..An>)
482 // }
483 // }
484 // ```
485
486 let item = tcx.associated_item(item_id);
487 debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
488 let impl_id = match item.container {
489 ty::AssociatedItemContainer::ImplContainer(impl_id) => impl_id,
490 _ => bug!("not an impl container"),
491 };
492
493 // `A0 as Trait<A1..An>`
494 let trait_ref = tcx.impl_trait_ref(impl_id).unwrap();
495
496 // `T`
497 let ty = tcx.type_of(item_id);
498
499 // `Implemented(A0: Trait<A1..An>)`
500 let trait_implemented = ty::Binder::dummy(ty::TraitPredicate { trait_ref }.lower());
501
502 // `Implemented(A0: Trait<A1..An>)`
503 let hypotheses = vec![trait_implemented];
504
505 // `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
506 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
507
508 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
509 let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
510
511 // `Normalize(... -> T) :- ...`
512 let clause = ProgramClause {
513 goal: normalize_goal,
514 hypotheses: tcx.mk_goals(
515 hypotheses
516 .into_iter()
517 .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
518 ),
519 category: ProgramClauseCategory::Other,
520 };
521 tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
522 }
523
524 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
525 if !tcx.features().rustc_attrs {
526 return;
527 }
528
529 let mut visitor = ClauseDumper { tcx };
530 tcx.hir
531 .krate()
532 .visit_all_item_likes(&mut visitor.as_deep_visitor());
533 }
534
535 struct ClauseDumper<'a, 'tcx: 'a> {
536 tcx: TyCtxt<'a, 'tcx, 'tcx>,
537 }
538
539 impl<'a, 'tcx> ClauseDumper<'a, 'tcx> {
540 fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
541 let def_id = self.tcx.hir.local_def_id(node_id);
542 for attr in attrs {
543 let mut clauses = None;
544
545 if attr.check_name("rustc_dump_program_clauses") {
546 clauses = Some(self.tcx.program_clauses_for(def_id));
547 }
548
549 if attr.check_name("rustc_dump_env_program_clauses") {
550 let environment = self.tcx.environment(def_id);
551 clauses = Some(self.tcx.program_clauses_for_env(environment));
552 }
553
554 if let Some(clauses) = clauses {
555 let mut err = self
556 .tcx
557 .sess
558 .struct_span_err(attr.span, "program clause dump");
559
560 let mut strings: Vec<_> = clauses
561 .iter()
562 .map(|clause| {
563 // Skip the top-level binder for a less verbose output
564 let program_clause = match clause {
565 Clause::Implies(program_clause) => program_clause,
566 Clause::ForAll(program_clause) => program_clause.skip_binder(),
567 };
568 program_clause.to_string()
569 })
570 .collect();
571
572 strings.sort();
573
574 for string in strings {
575 err.note(&string);
576 }
577
578 err.emit();
579 }
580 }
581 }
582 }
583
584 impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> {
585 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
586 NestedVisitorMap::OnlyBodies(&self.tcx.hir)
587 }
588
589 fn visit_item(&mut self, item: &'tcx hir::Item) {
590 self.process_attrs(item.id, &item.attrs);
591 intravisit::walk_item(self, item);
592 }
593
594 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
595 self.process_attrs(trait_item.id, &trait_item.attrs);
596 intravisit::walk_trait_item(self, trait_item);
597 }
598
599 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
600 self.process_attrs(impl_item.id, &impl_item.attrs);
601 intravisit::walk_impl_item(self, impl_item);
602 }
603
604 fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
605 self.process_attrs(s.id, &s.attrs);
606 intravisit::walk_struct_field(self, s);
607 }
608 }