From 1271f0bd2519d63b427ea36a752f7de32bc5a7a2 Mon Sep 17 00:00:00 2001 From: scalexm Date: Sat, 10 Mar 2018 12:44:33 +0100 Subject: [PATCH 1/6] Add MVP for chalkification --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/ich/impls_ty.rs | 83 +++++++++++ src/librustc/traits/lowering.rs | 147 +++++++++++++++++++ src/librustc/traits/mod.rs | 56 ++++++++ src/librustc/traits/structural_impls.rs | 183 ++++++++++++++++++++++++ src/librustc/ty/maps/config.rs | 6 + src/librustc/ty/maps/mod.rs | 3 + src/librustc/ty/maps/plumbing.rs | 2 + src/librustc_driver/driver.rs | 2 + src/libsyntax/feature_gate.rs | 7 + src/test/ui/chalkify/lower_impl.rs | 20 +++ src/test/ui/chalkify/lower_impl.stderr | 8 ++ 12 files changed, 519 insertions(+) create mode 100644 src/librustc/traits/lowering.rs create mode 100644 src/test/ui/chalkify/lower_impl.rs create mode 100644 src/test/ui/chalkify/lower_impl.stderr diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 8d7fef90b754e..744e3a5eaabcc 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -648,6 +648,8 @@ define_dep_nodes!( <'tcx> [] GetSymbolExportLevel(DefId), [input] Features, + + [] ProgramClausesFor(DefId), ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 4eb4f0edafe40..868ce831d13e0 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1286,3 +1286,86 @@ impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> { impl_stable_hash_for!(enum infer::canonical::Certainty { Proven, Ambiguous }); + +impl<'a, 'tcx> HashStable> for traits::WhereClauseAtom<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use traits::WhereClauseAtom::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Implemented(ref trait_ref) => trait_ref.hash_stable(hcx, hasher), + ProjectionEq(ref projection) => projection.hash_stable(hcx, hasher), + } + } +} + +impl<'a, 'tcx> HashStable> for traits::DomainGoal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use traits::DomainGoal::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Holds(ref where_clause) | + WellFormed(ref where_clause) | + FromEnv(ref where_clause) => where_clause.hash_stable(hcx, hasher), + + WellFormedTy(ref ty) => ty.hash_stable(hcx, hasher), + FromEnvTy(ref ty) => ty.hash_stable(hcx, hasher), + RegionOutlives(ref predicate) => predicate.hash_stable(hcx, hasher), + TypeOutlives(ref predicate) => predicate.hash_stable(hcx, hasher), + } + } +} + +impl<'a, 'tcx> HashStable> for traits::LeafGoal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use traits::LeafGoal::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + DomainGoal(ref domain_goal) => domain_goal.hash_stable(hcx, hasher), + } + } +} + +impl<'a, 'tcx> HashStable> for traits::Goal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use traits::Goal::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Implies(ref hypotheses, ref goal) => { + hypotheses.hash_stable(hcx, hasher); + goal.hash_stable(hcx, hasher); + }, + And(ref goal1, ref goal2) => { + goal1.hash_stable(hcx, hasher); + goal2.hash_stable(hcx, hasher); + } + Not(ref goal) => goal.hash_stable(hcx, hasher), + Leaf(ref leaf_goal) => leaf_goal.hash_stable(hcx, hasher), + Quantified(quantifier, ref goal) => { + quantifier.hash_stable(hcx, hasher); + goal.hash_stable(hcx, hasher); + }, + } + } +} + +impl_stable_hash_for!(enum traits::QuantifierKind { + Universal, + Existential +}); + +impl_stable_hash_for!(struct traits::ProgramClause<'tcx> { + consequence, + conditions +}); diff --git a/src/librustc/traits/lowering.rs b/src/librustc/traits/lowering.rs new file mode 100644 index 0000000000000..4f7e66628d484 --- /dev/null +++ b/src/librustc/traits/lowering.rs @@ -0,0 +1,147 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir::{self, ImplPolarity}; +use hir::def_id::DefId; +use hir::intravisit::{self, NestedVisitorMap, Visitor}; +use ty::{self, PolyTraitPredicate, TraitPredicate, PolyProjectionPredicate, TyCtxt, Predicate}; +use super::{DomainGoal, ProgramClause, WhereClauseAtom}; +use rustc_data_structures::sync::Lrc; +use syntax::ast; + +trait Lower { + fn lower(&self) -> T; +} + +impl Lower> for Vec where T: Lower { + fn lower(&self) -> Vec { + self.iter().map(|item| item.lower()).collect() + } +} + +impl<'tcx> Lower> for PolyTraitPredicate<'tcx> { + fn lower(&self) -> WhereClauseAtom<'tcx> { + WhereClauseAtom::Implemented(*self) + } +} + +impl<'tcx> Lower> for PolyProjectionPredicate<'tcx> { + fn lower(&self) -> WhereClauseAtom<'tcx> { + WhereClauseAtom::ProjectionEq(*self) + } +} + +impl<'tcx, T> Lower> for T where T: Lower> { + fn lower(&self) -> DomainGoal<'tcx> { + DomainGoal::Holds(self.lower()) + } +} + +impl<'tcx> Lower> for Predicate<'tcx> { + fn lower(&self) -> DomainGoal<'tcx> { + use self::Predicate::*; + + match *self { + Trait(predicate) => predicate.lower(), + RegionOutlives(predicate) => DomainGoal::RegionOutlives(predicate), + TypeOutlives(predicate) => DomainGoal::TypeOutlives(predicate), + Projection(predicate) => predicate.lower(), + WellFormed(ty) => DomainGoal::WellFormedTy(ty), + ObjectSafe(..) | + ClosureKind(..) | + Subtype(..) | + ConstEvaluatable(..) => unimplemented!(), + + } + } +} + +pub fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) + -> Lrc>> +{ + 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), + _ => Lrc::new(vec![]), + } +} + +fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) + -> Lrc>> +{ + if let ImplPolarity::Negative = tcx.impl_polarity(def_id) { + return Lrc::new(vec![]); + } + + let trait_ref = tcx.impl_trait_ref(def_id).unwrap(); + let trait_ref = ty::Binder(TraitPredicate { trait_ref }).lower(); + let where_clauses = tcx.predicates_of(def_id).predicates.lower(); + + let clause = ProgramClause { + consequence: trait_ref, + conditions: where_clauses.into_iter().map(|wc| wc.into()).collect(), + }; + + 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); + } +} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a2a5aa246cf77..8b2f96ce87557 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -29,6 +29,7 @@ use infer::{InferCtxt}; use rustc_data_structures::sync::Lrc; use std::rc::Rc; +use std::convert::From; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; @@ -62,6 +63,7 @@ mod specialize; mod structural_impls; pub mod trans; mod util; +mod lowering; pub mod query; @@ -244,6 +246,59 @@ pub type Obligations<'tcx, O> = Vec>; pub type PredicateObligations<'tcx> = Vec>; pub type TraitObligations<'tcx> = Vec>; +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum WhereClauseAtom<'tcx> { + Implemented(ty::PolyTraitPredicate<'tcx>), + ProjectionEq(ty::PolyProjectionPredicate<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum DomainGoal<'tcx> { + Holds(WhereClauseAtom<'tcx>), + WellFormed(WhereClauseAtom<'tcx>), + FromEnv(WhereClauseAtom<'tcx>), + WellFormedTy(Ty<'tcx>), + FromEnvTy(Ty<'tcx>), + RegionOutlives(ty::PolyRegionOutlivesPredicate<'tcx>), + TypeOutlives(ty::PolyTypeOutlivesPredicate<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum LeafGoal<'tcx> { + DomainGoal(DomainGoal<'tcx>), +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum QuantifierKind { + Universal, + Existential, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum Goal<'tcx> { + Implies(Vec>, Box>), + And(Box>, Box>), + Not(Box>), + Leaf(LeafGoal<'tcx>), + Quantified(QuantifierKind, Box>>) +} + +impl<'tcx> From> for Goal<'tcx> { + fn from(domain_goal: DomainGoal<'tcx>) -> Self { + Goal::Leaf(LeafGoal::DomainGoal(domain_goal)) + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct ProgramClause<'tcx> { + pub consequence: DomainGoal<'tcx>, + pub conditions: Vec>, +} + +pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + lowering::dump_program_clauses(tcx) +} + pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; #[derive(Clone,Debug)] @@ -915,6 +970,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, trans_fulfill_obligation: trans::trans_fulfill_obligation, + program_clauses_for: lowering::program_clauses_for, vtable_methods, substitute_normalize_and_test_predicates, ..*providers diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index a2d98a456f49a..62881013c4c5e 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -425,3 +425,186 @@ BraceStructTypeFoldableImpl! { obligations } where T: TypeFoldable<'tcx> } + +impl<'tcx> fmt::Display for traits::WhereClauseAtom<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use traits::WhereClauseAtom::*; + match *self { + Implemented(ref trait_ref) => write!(fmt, "Implemented({})", trait_ref), + ProjectionEq(ref projection) => write!(fmt, "ProjectionEq({})", projection), + } + } +} + +impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use traits::DomainGoal::*; + use traits::WhereClauseAtom::*; + match *self { + Holds(wc) => write!(fmt, "{}", wc), + WellFormed(Implemented(ref trait_ref)) => write!(fmt, "WellFormed({})", trait_ref), + WellFormed(ProjectionEq(ref projection)) => write!(fmt, "WellFormed({})", projection), + FromEnv(Implemented(ref trait_ref)) => write!(fmt, "FromEnv({})", trait_ref), + FromEnv(ProjectionEq(ref projection)) => write!(fmt, "FromEnv({})", projection), + WellFormedTy(ref ty) => write!(fmt, "WellFormed({})", ty), + FromEnvTy(ref ty) => write!(fmt, "FromEnv({})", ty), + RegionOutlives(ref predicate) => write!(fmt, "RegionOutlives({})", predicate), + TypeOutlives(ref predicate) => write!(fmt, "TypeOutlives({})", predicate), + } + } +} + +impl fmt::Display for traits::QuantifierKind { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use traits::QuantifierKind::*; + match *self { + Universal => write!(fmt, "forall"), + Existential => write!(fmt, "exists"), + } + } +} + +impl<'tcx> fmt::Display for traits::LeafGoal<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use traits::LeafGoal::*; + match *self { + DomainGoal(ref domain_goal) => write!(fmt, "{}", domain_goal), + } + } +} + +impl<'tcx> fmt::Display for traits::Goal<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use traits::Goal::*; + match *self { + Implies(ref hypotheses, ref goal) => { + write!(fmt, "if (")?; + for (index, hyp) in hypotheses.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", hyp)?; + } + write!(fmt, ") {{ {} }}", goal) + } + And(ref goal1, ref goal2) => write!(fmt, "({}, {})", goal1, goal2), + Not(ref goal) => write!(fmt, "not {{ {} }}", goal), + Leaf(ref goal) => write!(fmt, "{}", goal), + Quantified(qkind, ref goal) => { + // FIXME: appropriate binder names + write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder()) + } + } + } +} + +impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", self.consequence)?; + if self.conditions.is_empty() { + write!(fmt, ".")?; + } else { + write!(fmt, " :- ")?; + for (index, condition) in self.conditions.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", condition)?; + } + } + Ok(()) + } +} + +impl<'tcx> TypeFoldable<'tcx> for traits::WhereClauseAtom<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use traits::WhereClauseAtom::*; + match *self { + Implemented(ref trait_ref) => Implemented(trait_ref.fold_with(folder)), + ProjectionEq(ref projection) => ProjectionEq(projection.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use traits::WhereClauseAtom::*; + match *self { + Implemented(ref trait_ref) => trait_ref.visit_with(visitor), + ProjectionEq(ref projection) => projection.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for traits::DomainGoal<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use traits::DomainGoal::*; + match *self { + Holds(ref wc) => Holds(wc.fold_with(folder)), + WellFormed(ref wc) => WellFormed(wc.fold_with(folder)), + FromEnv(ref wc) => FromEnv(wc.fold_with(folder)), + WellFormedTy(ref ty) => WellFormedTy(ty.fold_with(folder)), + FromEnvTy(ref ty) => FromEnvTy(ty.fold_with(folder)), + RegionOutlives(ref predicate) => RegionOutlives(predicate.fold_with(folder)), + TypeOutlives(ref predicate) => TypeOutlives(predicate.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use traits::DomainGoal::*; + match *self { + Holds(ref wc) | + WellFormed(ref wc) | + FromEnv(ref wc) => wc.visit_with(visitor), + WellFormedTy(ref ty) | + FromEnvTy(ref ty) => ty.visit_with(visitor), + RegionOutlives(ref predicate) => predicate.visit_with(visitor), + TypeOutlives(ref predicate) => predicate.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for traits::LeafGoal<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use traits::LeafGoal::*; + match *self { + DomainGoal(ref domain_goal) => DomainGoal(domain_goal.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use traits::LeafGoal::*; + match *self { + DomainGoal(ref domain_goal) => domain_goal.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use traits::Goal::*; + match *self { + Implies(ref hypotheses, ref goal) => { + Implies( + hypotheses.iter().map(|hyp| hyp.fold_with(folder)).collect(), + goal.fold_with(folder) + ) + }, + And(ref goal1, ref goal2) => And(goal1.fold_with(folder), goal2.fold_with(folder)), + Not(ref goal) => Not(goal.fold_with(folder)), + Leaf(ref leaf_goal) => Leaf(leaf_goal.fold_with(folder)), + Quantified(qkind, ref goal) => Quantified(qkind, goal.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use traits::Goal::*; + match *self { + Implies(ref hypotheses, ref goal) => { + hypotheses.iter().any(|hyp| hyp.visit_with(visitor)) || goal.visit_with(visitor) + } + And(ref goal1, ref goal2) => goal1.visit_with(visitor) || goal2.visit_with(visitor), + Not(ref goal) => goal.visit_with(visitor), + Leaf(ref leaf_goal) => leaf_goal.visit_with(visitor), + Quantified(_, ref goal) => goal.visit_with(visitor), + } + } +} diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index dbfe7770bbde0..abda7a2cd09ec 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -681,6 +681,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> { + fn describe(_tcx: TyCtxt, _: DefId) -> String { + format!("generating chalk-style clauses") + } +} + macro_rules! impl_disk_cacheable_query( ($query_name:ident, |$key:tt| $cond:expr) => { impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 7d726d2e3cd5d..087c7d6d44df6 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -38,6 +38,7 @@ use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::specialization_graph; +use traits::ProgramClause; use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use ty::steal::Steal; use ty::subst::Substs; @@ -417,6 +418,8 @@ define_maps! { <'tcx> -> usize, [] fn features_query: features_node(CrateNum) -> Lrc, + + [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc>>, } ////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index bc7186f781a82..dd65d4b419071 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -935,6 +935,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } DepKind::Features => { force!(features_query, LOCAL_CRATE); } + + DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); } } true diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 542f818c3818a..69257e3e11392 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1089,6 +1089,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, time(sess, "lint checking", || lint::check_crate(tcx)); + time(time_passes, "dumping chalk-like clauses", || traits::dump_program_clauses(tcx)); + return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); }) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ec9a15d9f2b44..ea2d907331a6d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -831,6 +831,13 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG across crates and will never be stable", cfg_fn!(rustc_attrs))), + ("rustc_dump_program_clauses", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", + "the `#[rustc_dump_program_clauses]` \ + attribute is just used for rustc unit \ + tests and will never be stable", + cfg_fn!(rustc_attrs))), + // RFC #2094 ("nll", Whitelisted, Gated(Stability::Unstable, "nll", diff --git a/src/test/ui/chalkify/lower_impl.rs b/src/test/ui/chalkify/lower_impl.rs new file mode 100644 index 0000000000000..2083ada6d2de5 --- /dev/null +++ b/src/test/ui/chalkify/lower_impl.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +trait Foo { } + +#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :- +impl Foo for T where T: Iterator { } + +fn main() { + println!("hello"); +} diff --git a/src/test/ui/chalkify/lower_impl.stderr b/src/test/ui/chalkify/lower_impl.stderr new file mode 100644 index 0000000000000..8645e4506efa8 --- /dev/null +++ b/src/test/ui/chalkify/lower_impl.stderr @@ -0,0 +1,8 @@ +error: Implemented(T: Foo) :- ProjectionEq(::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized) + --> $DIR/lower_impl.rs:15:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 04b228c3e26dab45c0f9d597b0424eda707c1515 Mon Sep 17 00:00:00 2001 From: scalexm Date: Wed, 14 Mar 2018 13:38:03 +0100 Subject: [PATCH 2/6] Address niko's nits --- src/librustc/ich/impls_ty.rs | 70 ++++----- src/librustc/traits/lowering.rs | 59 +++++--- src/librustc/traits/mod.rs | 32 ++-- src/librustc/traits/structural_impls.rs | 190 +++++++++--------------- src/librustc/ty/maps/mod.rs | 4 +- src/librustc/ty/mod.rs | 9 +- src/librustc_driver/driver.rs | 2 +- src/test/ui/chalkify/lower_impl.stderr | 2 +- 8 files changed, 173 insertions(+), 195 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 868ce831d13e0..78407e33d98b8 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1294,9 +1294,9 @@ impl<'a, 'tcx> HashStable> for traits::WhereClauseAtom< use traits::WhereClauseAtom::*; mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - Implemented(ref trait_ref) => trait_ref.hash_stable(hcx, hasher), - ProjectionEq(ref projection) => projection.hash_stable(hcx, hasher), + match self { + Implemented(trait_ref) => trait_ref.hash_stable(hcx, hasher), + ProjectionEq(projection) => projection.hash_stable(hcx, hasher), } } } @@ -1308,54 +1308,59 @@ impl<'a, 'tcx> HashStable> for traits::DomainGoal<'tcx> use traits::DomainGoal::*; mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - Holds(ref where_clause) | - WellFormed(ref where_clause) | - FromEnv(ref where_clause) => where_clause.hash_stable(hcx, hasher), - - WellFormedTy(ref ty) => ty.hash_stable(hcx, hasher), - FromEnvTy(ref ty) => ty.hash_stable(hcx, hasher), - RegionOutlives(ref predicate) => predicate.hash_stable(hcx, hasher), - TypeOutlives(ref predicate) => predicate.hash_stable(hcx, hasher), + match self { + Holds(where_clause) | + WellFormed(where_clause) | + FromEnv(where_clause) => where_clause.hash_stable(hcx, hasher), + + WellFormedTy(ty) => ty.hash_stable(hcx, hasher), + FromEnvTy(ty) => ty.hash_stable(hcx, hasher), + RegionOutlives(predicate) => predicate.hash_stable(hcx, hasher), + TypeOutlives(predicate) => predicate.hash_stable(hcx, hasher), } } } -impl<'a, 'tcx> HashStable> for traits::LeafGoal<'tcx> { +impl<'a, 'tcx> HashStable> for traits::Goal<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use traits::LeafGoal::*; + use traits::Goal::*; mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - DomainGoal(ref domain_goal) => domain_goal.hash_stable(hcx, hasher), + match self { + Implies(hypotheses, goal) => { + hypotheses.hash_stable(hcx, hasher); + goal.hash_stable(hcx, hasher); + }, + And(goal1, goal2) => { + goal1.hash_stable(hcx, hasher); + goal2.hash_stable(hcx, hasher); + } + Not(goal) => goal.hash_stable(hcx, hasher), + DomainGoal(domain_goal) => domain_goal.hash_stable(hcx, hasher), + Quantified(quantifier, goal) => { + quantifier.hash_stable(hcx, hasher); + goal.hash_stable(hcx, hasher); + }, } } } -impl<'a, 'tcx> HashStable> for traits::Goal<'tcx> { +impl<'a, 'tcx> HashStable> for traits::Clause<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use traits::Goal::*; + use traits::Clause::*; mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - Implies(ref hypotheses, ref goal) => { + match self { + Implies(hypotheses, goal) => { hypotheses.hash_stable(hcx, hasher); goal.hash_stable(hcx, hasher); - }, - And(ref goal1, ref goal2) => { - goal1.hash_stable(hcx, hasher); - goal2.hash_stable(hcx, hasher); } - Not(ref goal) => goal.hash_stable(hcx, hasher), - Leaf(ref leaf_goal) => leaf_goal.hash_stable(hcx, hasher), - Quantified(quantifier, ref goal) => { - quantifier.hash_stable(hcx, hasher); - goal.hash_stable(hcx, hasher); - }, + DomainGoal(domain_goal) => domain_goal.hash_stable(hcx, hasher), + ForAll(clause) => clause.hash_stable(hcx, hasher), } } } @@ -1364,8 +1369,3 @@ impl_stable_hash_for!(enum traits::QuantifierKind { Universal, Existential }); - -impl_stable_hash_for!(struct traits::ProgramClause<'tcx> { - consequence, - conditions -}); diff --git a/src/librustc/traits/lowering.rs b/src/librustc/traits/lowering.rs index 4f7e66628d484..f31e474963ee2 100644 --- a/src/librustc/traits/lowering.rs +++ b/src/librustc/traits/lowering.rs @@ -11,8 +11,8 @@ use hir::{self, ImplPolarity}; use hir::def_id::DefId; use hir::intravisit::{self, NestedVisitorMap, Visitor}; -use ty::{self, PolyTraitPredicate, TraitPredicate, PolyProjectionPredicate, TyCtxt, Predicate}; -use super::{DomainGoal, ProgramClause, WhereClauseAtom}; +use ty::{self, TyCtxt}; +use super::{QuantifierKind, Goal, DomainGoal, Clause, WhereClauseAtom}; use rustc_data_structures::sync::Lrc; use syntax::ast; @@ -26,13 +26,13 @@ impl Lower> for Vec where T: Lower { } } -impl<'tcx> Lower> for PolyTraitPredicate<'tcx> { +impl<'tcx> Lower> for ty::TraitPredicate<'tcx> { fn lower(&self) -> WhereClauseAtom<'tcx> { WhereClauseAtom::Implemented(*self) } } -impl<'tcx> Lower> for PolyProjectionPredicate<'tcx> { +impl<'tcx> Lower> for ty::ProjectionPredicate<'tcx> { fn lower(&self) -> WhereClauseAtom<'tcx> { WhereClauseAtom::ProjectionEq(*self) } @@ -44,27 +44,52 @@ impl<'tcx, T> Lower> for T where T: Lower } } -impl<'tcx> Lower> for Predicate<'tcx> { +impl<'tcx> Lower> for ty::RegionOutlivesPredicate<'tcx> { fn lower(&self) -> DomainGoal<'tcx> { - use self::Predicate::*; + DomainGoal::RegionOutlives(*self) + } +} + +impl<'tcx> Lower> for ty::TypeOutlivesPredicate<'tcx> { + fn lower(&self) -> DomainGoal<'tcx> { + DomainGoal::TypeOutlives(*self) + } +} + +impl<'tcx, T> Lower> for ty::Binder + where T: Lower> + 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())) + ), + } + } +} - match *self { +impl<'tcx> Lower> for ty::Predicate<'tcx> { + fn lower(&self) -> Goal<'tcx> { + use ty::Predicate::*; + + match self { Trait(predicate) => predicate.lower(), - RegionOutlives(predicate) => DomainGoal::RegionOutlives(predicate), - TypeOutlives(predicate) => DomainGoal::TypeOutlives(predicate), + RegionOutlives(predicate) => predicate.lower(), + TypeOutlives(predicate) => predicate.lower(), Projection(predicate) => predicate.lower(), - WellFormed(ty) => DomainGoal::WellFormedTy(ty), + WellFormed(ty) => DomainGoal::WellFormedTy(*ty).into(), ObjectSafe(..) | ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) => unimplemented!(), - } } } pub fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Lrc>> + -> Lrc>> { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let item = tcx.hir.expect_item(node_id); @@ -75,21 +100,17 @@ pub fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) } fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Lrc>> + -> Lrc>> { if let ImplPolarity::Negative = tcx.impl_polarity(def_id) { return Lrc::new(vec![]); } let trait_ref = tcx.impl_trait_ref(def_id).unwrap(); - let trait_ref = ty::Binder(TraitPredicate { trait_ref }).lower(); + let trait_ref = ty::TraitPredicate { trait_ref }.lower(); let where_clauses = tcx.predicates_of(def_id).predicates.lower(); - let clause = ProgramClause { - consequence: trait_ref, - conditions: where_clauses.into_iter().map(|wc| wc.into()).collect(), - }; - + let clause = Clause::Implies(where_clauses, trait_ref); Lrc::new(vec![clause]) } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 8b2f96ce87557..ea3db0c6e9260 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -248,8 +248,8 @@ pub type TraitObligations<'tcx> = Vec>; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum WhereClauseAtom<'tcx> { - Implemented(ty::PolyTraitPredicate<'tcx>), - ProjectionEq(ty::PolyProjectionPredicate<'tcx>), + Implemented(ty::TraitPredicate<'tcx>), + ProjectionEq(ty::ProjectionPredicate<'tcx>), } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] @@ -259,13 +259,8 @@ pub enum DomainGoal<'tcx> { FromEnv(WhereClauseAtom<'tcx>), WellFormedTy(Ty<'tcx>), FromEnvTy(Ty<'tcx>), - RegionOutlives(ty::PolyRegionOutlivesPredicate<'tcx>), - TypeOutlives(ty::PolyTypeOutlivesPredicate<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum LeafGoal<'tcx> { - DomainGoal(DomainGoal<'tcx>), + RegionOutlives(ty::RegionOutlivesPredicate<'tcx>), + TypeOutlives(ty::TypeOutlivesPredicate<'tcx>), } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -276,23 +271,30 @@ pub enum QuantifierKind { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum Goal<'tcx> { - Implies(Vec>, Box>), + Implies(Vec>, Box>), And(Box>, Box>), Not(Box>), - Leaf(LeafGoal<'tcx>), + DomainGoal(DomainGoal<'tcx>), Quantified(QuantifierKind, Box>>) } impl<'tcx> From> for Goal<'tcx> { fn from(domain_goal: DomainGoal<'tcx>) -> Self { - Goal::Leaf(LeafGoal::DomainGoal(domain_goal)) + Goal::DomainGoal(domain_goal) + } +} + +impl<'tcx> From> for Clause<'tcx> { + fn from(domain_goal: DomainGoal<'tcx>) -> Self { + Clause::DomainGoal(domain_goal) } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct ProgramClause<'tcx> { - pub consequence: DomainGoal<'tcx>, - pub conditions: Vec>, +pub enum Clause<'tcx> { + Implies(Vec>, DomainGoal<'tcx>), + DomainGoal(DomainGoal<'tcx>), + ForAll(Box>>), } pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 62881013c4c5e..d6e6f0e98adc4 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -429,9 +429,10 @@ BraceStructTypeFoldableImpl! { impl<'tcx> fmt::Display for traits::WhereClauseAtom<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use traits::WhereClauseAtom::*; - match *self { - Implemented(ref trait_ref) => write!(fmt, "Implemented({})", trait_ref), - ProjectionEq(ref projection) => write!(fmt, "ProjectionEq({})", projection), + + match self { + Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref), + ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection), } } } @@ -440,16 +441,17 @@ impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use traits::DomainGoal::*; use traits::WhereClauseAtom::*; - match *self { + + match self { Holds(wc) => write!(fmt, "{}", wc), - WellFormed(Implemented(ref trait_ref)) => write!(fmt, "WellFormed({})", trait_ref), - WellFormed(ProjectionEq(ref projection)) => write!(fmt, "WellFormed({})", projection), - FromEnv(Implemented(ref trait_ref)) => write!(fmt, "FromEnv({})", trait_ref), - FromEnv(ProjectionEq(ref projection)) => write!(fmt, "FromEnv({})", projection), - WellFormedTy(ref ty) => write!(fmt, "WellFormed({})", ty), - FromEnvTy(ref ty) => write!(fmt, "FromEnv({})", ty), - RegionOutlives(ref predicate) => write!(fmt, "RegionOutlives({})", predicate), - TypeOutlives(ref predicate) => write!(fmt, "TypeOutlives({})", predicate), + WellFormed(Implemented(trait_ref)) => write!(fmt, "WellFormed({})", trait_ref), + WellFormed(ProjectionEq(projection)) => write!(fmt, "WellFormed({})", projection), + FromEnv(Implemented(trait_ref)) => write!(fmt, "FromEnv({})", trait_ref), + FromEnv(ProjectionEq(projection)) => write!(fmt, "FromEnv({})", projection), + WellFormedTy(ty) => write!(fmt, "WellFormed({})", ty), + FromEnvTy(ty) => write!(fmt, "FromEnv({})", ty), + RegionOutlives(predicate) => write!(fmt, "RegionOutlives({})", predicate), + TypeOutlives(predicate) => write!(fmt, "TypeOutlives({})", predicate), } } } @@ -457,27 +459,20 @@ impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { impl fmt::Display for traits::QuantifierKind { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use traits::QuantifierKind::*; - match *self { + + match self { Universal => write!(fmt, "forall"), Existential => write!(fmt, "exists"), } } } -impl<'tcx> fmt::Display for traits::LeafGoal<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - use traits::LeafGoal::*; - match *self { - DomainGoal(ref domain_goal) => write!(fmt, "{}", domain_goal), - } - } -} - impl<'tcx> fmt::Display for traits::Goal<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use traits::Goal::*; - match *self { - Implies(ref hypotheses, ref goal) => { + + match self { + Implies(hypotheses, goal) => { write!(fmt, "if (")?; for (index, hyp) in hypotheses.iter().enumerate() { if index > 0 { @@ -487,10 +482,10 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> { } write!(fmt, ") {{ {} }}", goal) } - And(ref goal1, ref goal2) => write!(fmt, "({}, {})", goal1, goal2), - Not(ref goal) => write!(fmt, "not {{ {} }}", goal), - Leaf(ref goal) => write!(fmt, "{}", goal), - Quantified(qkind, ref goal) => { + And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2), + Not(goal) => write!(fmt, "not {{ {} }}", goal), + DomainGoal(goal) => write!(fmt, "{}", goal), + Quantified(qkind, goal) => { // FIXME: appropriate binder names write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder()) } @@ -498,113 +493,70 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> { } } -impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> { +impl<'tcx> fmt::Display for traits::Clause<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}", self.consequence)?; - if self.conditions.is_empty() { - write!(fmt, ".")?; - } else { - write!(fmt, " :- ")?; - for (index, condition) in self.conditions.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; + use traits::Clause::*; + + match self { + Implies(hypotheses, goal) => { + write!(fmt, "{}", goal)?; + if !hypotheses.is_empty() { + write!(fmt, " :- ")?; + for (index, condition) in hypotheses.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", condition)?; + } } - write!(fmt, "{}", condition)?; + write!(fmt, ".") + } + DomainGoal(domain_goal) => write!(fmt, "{}.", domain_goal), + ForAll(clause) => { + // FIXME: appropriate binder names + write!(fmt, "forall<> {{ {} }}", clause.skip_binder()) } } - Ok(()) } } -impl<'tcx> TypeFoldable<'tcx> for traits::WhereClauseAtom<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - use traits::WhereClauseAtom::*; - match *self { - Implemented(ref trait_ref) => Implemented(trait_ref.fold_with(folder)), - ProjectionEq(ref projection) => ProjectionEq(projection.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - use traits::WhereClauseAtom::*; - match *self { - Implemented(ref trait_ref) => trait_ref.visit_with(visitor), - ProjectionEq(ref projection) => projection.visit_with(visitor), - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::WhereClauseAtom<'tcx> { + (traits::WhereClauseAtom::Implemented)(trait_ref), + (traits::WhereClauseAtom::ProjectionEq)(projection), } } -impl<'tcx> TypeFoldable<'tcx> for traits::DomainGoal<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - use traits::DomainGoal::*; - match *self { - Holds(ref wc) => Holds(wc.fold_with(folder)), - WellFormed(ref wc) => WellFormed(wc.fold_with(folder)), - FromEnv(ref wc) => FromEnv(wc.fold_with(folder)), - WellFormedTy(ref ty) => WellFormedTy(ty.fold_with(folder)), - FromEnvTy(ref ty) => FromEnvTy(ty.fold_with(folder)), - RegionOutlives(ref predicate) => RegionOutlives(predicate.fold_with(folder)), - TypeOutlives(ref predicate) => TypeOutlives(predicate.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - use traits::DomainGoal::*; - match *self { - Holds(ref wc) | - WellFormed(ref wc) | - FromEnv(ref wc) => wc.visit_with(visitor), - WellFormedTy(ref ty) | - FromEnvTy(ref ty) => ty.visit_with(visitor), - RegionOutlives(ref predicate) => predicate.visit_with(visitor), - TypeOutlives(ref predicate) => predicate.visit_with(visitor), - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::DomainGoal<'tcx> { + (traits::DomainGoal::Holds)(wc), + (traits::DomainGoal::WellFormed)(wc), + (traits::DomainGoal::FromEnv)(wc), + (traits::DomainGoal::WellFormedTy)(ty), + (traits::DomainGoal::FromEnvTy)(ty), + (traits::DomainGoal::RegionOutlives)(predicate), + (traits::DomainGoal::TypeOutlives)(predicate), } } -impl<'tcx> TypeFoldable<'tcx> for traits::LeafGoal<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - use traits::LeafGoal::*; - match *self { - DomainGoal(ref domain_goal) => DomainGoal(domain_goal.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - use traits::LeafGoal::*; - match *self { - DomainGoal(ref domain_goal) => domain_goal.visit_with(visitor), - } - } +CloneTypeFoldableImpls! { + traits::QuantifierKind, } -impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - use traits::Goal::*; - match *self { - Implies(ref hypotheses, ref goal) => { - Implies( - hypotheses.iter().map(|hyp| hyp.fold_with(folder)).collect(), - goal.fold_with(folder) - ) - }, - And(ref goal1, ref goal2) => And(goal1.fold_with(folder), goal2.fold_with(folder)), - Not(ref goal) => Not(goal.fold_with(folder)), - Leaf(ref leaf_goal) => Leaf(leaf_goal.fold_with(folder)), - Quantified(qkind, ref goal) => Quantified(qkind, goal.fold_with(folder)), - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { + (traits::Goal::Implies)(hypotheses, goal), + (traits::Goal::And)(goal1, goal2), + (traits::Goal::Not)(goal), + (traits::Goal::DomainGoal)(domain_goal), + (traits::Goal::Quantified)(qkind, goal), } +} - fn super_visit_with>(&self, visitor: &mut V) -> bool { - use traits::Goal::*; - match *self { - Implies(ref hypotheses, ref goal) => { - hypotheses.iter().any(|hyp| hyp.visit_with(visitor)) || goal.visit_with(visitor) - } - And(ref goal1, ref goal2) => goal1.visit_with(visitor) || goal2.visit_with(visitor), - Not(ref goal) => goal.visit_with(visitor), - Leaf(ref leaf_goal) => leaf_goal.visit_with(visitor), - Quantified(_, ref goal) => goal.visit_with(visitor), - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::Clause<'tcx> { + (traits::Clause::Implies)(hypotheses, goal), + (traits::Clause::DomainGoal)(domain_goal), + (traits::Clause::ForAll)(clause), } } diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 087c7d6d44df6..50dfbeb9724ca 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -38,7 +38,7 @@ use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::specialization_graph; -use traits::ProgramClause; +use traits::Clause; use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use ty::steal::Steal; use ty::subst::Substs; @@ -419,7 +419,7 @@ define_maps! { <'tcx> [] fn features_query: features_node(CrateNum) -> Lrc, - [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc>>, + [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc>>, } ////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index fc1d26b0e0910..ea116b4cd0a41 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1073,9 +1073,12 @@ impl<'tcx> PolyTraitPredicate<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct OutlivesPredicate(pub A, pub B); // `A : B` pub type PolyOutlivesPredicate = ty::Binder>; -pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate, - ty::Region<'tcx>>; -pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region<'tcx>>; +pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate, + ty::Region<'tcx>>; +pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, + ty::Region<'tcx>>; +pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder>; +pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder>; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct SubtypePredicate<'tcx> { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 69257e3e11392..68c9c946215d1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1089,7 +1089,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, time(sess, "lint checking", || lint::check_crate(tcx)); - time(time_passes, "dumping chalk-like clauses", || traits::dump_program_clauses(tcx)); + time(sess, "dumping chalk-like clauses", || traits::dump_program_clauses(tcx)); return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); }) diff --git a/src/test/ui/chalkify/lower_impl.stderr b/src/test/ui/chalkify/lower_impl.stderr index 8645e4506efa8..b5d791d640ada 100644 --- a/src/test/ui/chalkify/lower_impl.stderr +++ b/src/test/ui/chalkify/lower_impl.stderr @@ -1,4 +1,4 @@ -error: Implemented(T: Foo) :- ProjectionEq(::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized) +error: Implemented(T: Foo) :- ProjectionEq(::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). --> $DIR/lower_impl.rs:15:1 | LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :- From 2bbd16de13c6c9d67e3d94455b3740bbc9a81055 Mon Sep 17 00:00:00 2001 From: scalexm Date: Wed, 14 Mar 2018 14:45:30 +0100 Subject: [PATCH 3/6] Move code into librustc_traits --- src/librustc/traits/mod.rs | 6 ------ src/librustc_driver/driver.rs | 4 +++- src/librustc_traits/lib.rs | 2 ++ .../traits => librustc_traits}/lowering.rs | 16 ++++++++-------- 4 files changed, 13 insertions(+), 15 deletions(-) rename src/{librustc/traits => librustc_traits}/lowering.rs (93%) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index ea3db0c6e9260..dce1a89d14260 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -63,7 +63,6 @@ mod specialize; mod structural_impls; pub mod trans; mod util; -mod lowering; pub mod query; @@ -297,10 +296,6 @@ pub enum Clause<'tcx> { ForAll(Box>>), } -pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - lowering::dump_program_clauses(tcx) -} - pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; #[derive(Clone,Debug)] @@ -972,7 +967,6 @@ pub fn provide(providers: &mut ty::maps::Providers) { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, trans_fulfill_obligation: trans::trans_fulfill_obligation, - program_clauses_for: lowering::program_clauses_for, vtable_methods, substitute_normalize_and_test_predicates, ..*providers diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 68c9c946215d1..61335391dab70 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1089,7 +1089,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, time(sess, "lint checking", || lint::check_crate(tcx)); - time(sess, "dumping chalk-like clauses", || traits::dump_program_clauses(tcx)); + time(sess, + "dumping chalk-like clauses", + || rustc_traits::lowering::dump_program_clauses(tcx)); return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); }) diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 45d23a2733a2a..2a0f076cefde3 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -29,6 +29,7 @@ mod dropck_outlives; mod normalize_projection_ty; mod normalize_erasing_regions; mod util; +pub mod lowering; use rustc::ty::maps::Providers; @@ -39,6 +40,7 @@ pub fn provide(p: &mut Providers) { normalize_projection_ty: normalize_projection_ty::normalize_projection_ty, normalize_ty_after_erasing_regions: normalize_erasing_regions::normalize_ty_after_erasing_regions, + program_clauses_for: lowering::program_clauses_for, ..*p }; } diff --git a/src/librustc/traits/lowering.rs b/src/librustc_traits/lowering.rs similarity index 93% rename from src/librustc/traits/lowering.rs rename to src/librustc_traits/lowering.rs index f31e474963ee2..b69d97b67e83b 100644 --- a/src/librustc/traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::{self, ImplPolarity}; -use hir::def_id::DefId; -use hir::intravisit::{self, NestedVisitorMap, Visitor}; -use ty::{self, TyCtxt}; -use super::{QuantifierKind, Goal, DomainGoal, Clause, WhereClauseAtom}; -use rustc_data_structures::sync::Lrc; +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}; use syntax::ast; +use rustc_data_structures::sync::Lrc; trait Lower { fn lower(&self) -> T; @@ -72,7 +72,7 @@ impl<'tcx, T> Lower> for ty::Binder impl<'tcx> Lower> for ty::Predicate<'tcx> { fn lower(&self) -> Goal<'tcx> { - use ty::Predicate::*; + use rustc::ty::Predicate::*; match self { Trait(predicate) => predicate.lower(), @@ -88,7 +88,7 @@ impl<'tcx> Lower> for ty::Predicate<'tcx> { } } -pub fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) +crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Lrc>> { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); From e8f3ed5db26981d2b5417a9de1d16f33770d8ff4 Mon Sep 17 00:00:00 2001 From: scalexm Date: Wed, 14 Mar 2018 15:19:17 +0100 Subject: [PATCH 4/6] Add documentation --- src/librustc/traits/mod.rs | 12 ++++++++++++ src/librustc_traits/lowering.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index dce1a89d14260..8c5c36c369986 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -245,6 +245,14 @@ pub type Obligations<'tcx, O> = Vec>; pub type PredicateObligations<'tcx> = Vec>; pub type TraitObligations<'tcx> = Vec>; +/// The following types: +/// * `WhereClauseAtom` +/// * `DomainGoal` +/// * `Goal` +/// * `Clause` +/// are used for representing the trait system in the form of +/// logic programming clauses. They are part of the interface +/// for the chalk SLG solver. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum WhereClauseAtom<'tcx> { Implemented(ty::TraitPredicate<'tcx>), @@ -270,6 +278,7 @@ pub enum QuantifierKind { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum Goal<'tcx> { + // FIXME: use interned refs instead of `Box` Implies(Vec>, Box>), And(Box>, Box>), Not(Box>), @@ -289,8 +298,11 @@ impl<'tcx> From> for Clause<'tcx> { } } +/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary +/// Harrop Formulas". #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum Clause<'tcx> { + // FIXME: again, use interned refs instead of `Box` Implies(Vec>, DomainGoal<'tcx>), DomainGoal(DomainGoal<'tcx>), ForAll(Box>>), diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index b69d97b67e83b..296ad18c480b6 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -17,6 +17,7 @@ use syntax::ast; use rustc_data_structures::sync::Lrc; trait Lower { + /// Lower a rustc construction (e.g. `ty::TraitPredicate`) to a chalk-like type. fn lower(&self) -> T; } @@ -56,6 +57,15 @@ impl<'tcx> Lower> for ty::TypeOutlivesPredicate<'tcx> { } } +/// `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))` 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`. +/// +/// 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. impl<'tcx, T> Lower> for ty::Binder where T: Lower> + ty::fold::TypeFoldable<'tcx> + Copy { @@ -95,6 +105,8 @@ crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI let item = tcx.hir.expect_item(node_id); match item.node { hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id), + + // FIXME: other constructions e.g. traits, associated types... _ => Lrc::new(vec![]), } } From 4eaa85d3be27ceec2247eb1b83ca83b2ac92b3da Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 15 Mar 2018 14:27:00 -0400 Subject: [PATCH 5/6] add xref to rust-guide --- src/librustc_traits/lowering.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 296ad18c480b6..ae52e83cdc248 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -117,6 +117,10 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId if let ImplPolarity::Negative = tcx.impl_polarity(def_id) { return Lrc::new(vec![]); } + + // Rule Implemented-From-Impl + // + // (see rustc guide) let trait_ref = tcx.impl_trait_ref(def_id).unwrap(); let trait_ref = ty::TraitPredicate { trait_ref }.lower(); From ef3b4e1f5bfb8cf5347b086ed60aefd519a3335d Mon Sep 17 00:00:00 2001 From: Alexandre Martin Date: Thu, 15 Mar 2018 23:20:06 +0100 Subject: [PATCH 6/6] Fix tidy --- src/librustc_traits/lowering.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index ae52e83cdc248..c9666f55d440e 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -117,7 +117,7 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId if let ImplPolarity::Negative = tcx.impl_polarity(def_id) { return Lrc::new(vec![]); } - + // Rule Implemented-From-Impl // // (see rustc guide)