rust/src/librustc_traits/lowering.rs

185 lines
6.2 KiB
Rust
Raw Normal View History

2018-03-10 12:44:33 +01:00
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
2018-03-14 14:45:30 +01:00
use rustc::hir::{self, ImplPolarity};
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::ty::{self, TyCtxt};
use rustc::traits::{QuantifierKind, Goal, DomainGoal, Clause, WhereClauseAtom};
2018-03-10 12:44:33 +01:00
use syntax::ast;
2018-03-14 14:45:30 +01:00
use rustc_data_structures::sync::Lrc;
2018-03-10 12:44:33 +01:00
trait Lower<T> {
2018-03-14 15:19:17 +01:00
/// Lower a rustc construction (e.g. `ty::TraitPredicate`) to a chalk-like type.
2018-03-10 12:44:33 +01:00
fn lower(&self) -> T;
}
impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> {
fn lower(&self) -> Vec<U> {
self.iter().map(|item| item.lower()).collect()
}
}
2018-03-14 13:38:03 +01:00
impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::TraitPredicate<'tcx> {
2018-03-10 12:44:33 +01:00
fn lower(&self) -> WhereClauseAtom<'tcx> {
WhereClauseAtom::Implemented(*self)
}
}
2018-03-14 13:38:03 +01:00
impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::ProjectionPredicate<'tcx> {
2018-03-10 12:44:33 +01:00
fn lower(&self) -> WhereClauseAtom<'tcx> {
WhereClauseAtom::ProjectionEq(*self)
}
}
impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> {
fn lower(&self) -> DomainGoal<'tcx> {
DomainGoal::Holds(self.lower())
}
}
2018-03-14 13:38:03 +01:00
impl<'tcx> Lower<DomainGoal<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
2018-03-10 12:44:33 +01:00
fn lower(&self) -> DomainGoal<'tcx> {
2018-03-14 13:38:03 +01:00
DomainGoal::RegionOutlives(*self)
}
}
impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
fn lower(&self) -> DomainGoal<'tcx> {
DomainGoal::TypeOutlives(*self)
}
}
2018-03-14 15:19:17 +01:00
/// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
/// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
/// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous
/// example), we model them with quantified goals, e.g. as for the previous example:
/// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
/// `Binder<Holds(Implemented(TraitPredicate))>`.
///
/// Also, if `self` does not contain generic lifetimes, we can safely drop the binder and we
/// can directly lower to a leaf goal instead of a quantified goal.
2018-03-14 13:38:03 +01:00
impl<'tcx, T> Lower<Goal<'tcx>> for ty::Binder<T>
where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx> + Copy
{
fn lower(&self) -> Goal<'tcx> {
match self.no_late_bound_regions() {
Some(p) => p.lower().into(),
None => Goal::Quantified(
QuantifierKind::Universal,
Box::new(self.map_bound(|p| p.lower().into()))
),
}
}
}
2018-03-10 12:44:33 +01:00
2018-03-14 13:38:03 +01:00
impl<'tcx> Lower<Goal<'tcx>> for ty::Predicate<'tcx> {
fn lower(&self) -> Goal<'tcx> {
2018-03-14 14:45:30 +01:00
use rustc::ty::Predicate::*;
2018-03-14 13:38:03 +01:00
match self {
2018-03-10 12:44:33 +01:00
Trait(predicate) => predicate.lower(),
2018-03-14 13:38:03 +01:00
RegionOutlives(predicate) => predicate.lower(),
TypeOutlives(predicate) => predicate.lower(),
2018-03-10 12:44:33 +01:00
Projection(predicate) => predicate.lower(),
2018-03-14 13:38:03 +01:00
WellFormed(ty) => DomainGoal::WellFormedTy(*ty).into(),
2018-03-10 12:44:33 +01:00
ObjectSafe(..) |
ClosureKind(..) |
Subtype(..) |
ConstEvaluatable(..) => unimplemented!(),
}
}
}
2018-03-14 14:45:30 +01:00
crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
2018-03-14 13:38:03 +01:00
-> Lrc<Vec<Clause<'tcx>>>
2018-03-10 12:44:33 +01:00
{
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let item = tcx.hir.expect_item(node_id);
match item.node {
hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
2018-03-14 15:19:17 +01:00
// FIXME: other constructions e.g. traits, associated types...
2018-03-10 12:44:33 +01:00
_ => Lrc::new(vec![]),
}
}
fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
2018-03-14 13:38:03 +01:00
-> Lrc<Vec<Clause<'tcx>>>
2018-03-10 12:44:33 +01:00
{
if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
return Lrc::new(vec![]);
}
2018-03-15 23:20:06 +01:00
2018-03-15 14:27:00 -04:00
// Rule Implemented-From-Impl
//
// (see rustc guide)
2018-03-10 12:44:33 +01:00
let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
2018-03-14 13:38:03 +01:00
let trait_ref = ty::TraitPredicate { trait_ref }.lower();
2018-03-10 12:44:33 +01:00
let where_clauses = tcx.predicates_of(def_id).predicates.lower();
2018-03-14 13:38:03 +01:00
let clause = Clause::Implies(where_clauses, trait_ref);
2018-03-10 12:44:33 +01:00
Lrc::new(vec![clause])
}
pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
if !tcx.features().rustc_attrs {
return;
}
let mut visitor = ClauseDumper { tcx };
tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
}
struct ClauseDumper<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
impl <'a, 'tcx> ClauseDumper<'a, 'tcx > {
fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
let def_id = self.tcx.hir.local_def_id(node_id);
for attr in attrs {
if attr.check_name("rustc_dump_program_clauses") {
let clauses = self.tcx.program_clauses_for(def_id);
for clause in &*clauses {
self.tcx.sess.struct_span_err(attr.span, &format!("{}", clause)).emit();
}
}
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.tcx.hir)
}
fn visit_item(&mut self, item: &'tcx hir::Item) {
self.process_attrs(item.id, &item.attrs);
intravisit::walk_item(self, item);
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
self.process_attrs(trait_item.id, &trait_item.attrs);
intravisit::walk_trait_item(self, trait_item);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.process_attrs(impl_item.id, &impl_item.attrs);
intravisit::walk_impl_item(self, impl_item);
}
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
self.process_attrs(s.id, &s.attrs);
intravisit::walk_struct_field(self, s);
}
}