Skip to content

Commit

Permalink
Auto merge of #48985 - scalexm:lowering, r=nikomatsakis
Browse files Browse the repository at this point in the history
MVP for chalkification

r? @nikomatsakis
  • Loading branch information
bors committed Mar 18, 2018
2 parents 5e3ecdc + ef3b4e1 commit 7c396eb
Show file tree
Hide file tree
Showing 14 changed files with 526 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,8 @@ define_dep_nodes!( <'tcx>
[] GetSymbolExportLevel(DefId),

[input] Features,

[] ProgramClausesFor(DefId),
);

trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
Expand Down
83 changes: 83 additions & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1285,3 +1285,86 @@ impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> {
impl_stable_hash_for!(enum infer::canonical::Certainty {
Proven, Ambiguous
});

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::WhereClauseAtom<'tcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
use traits::WhereClauseAtom::*;

mem::discriminant(self).hash_stable(hcx, hasher);
match self {
Implemented(trait_ref) => trait_ref.hash_stable(hcx, hasher),
ProjectionEq(projection) => projection.hash_stable(hcx, hasher),
}
}
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::DomainGoal<'tcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
use traits::DomainGoal::*;

mem::discriminant(self).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<StableHashingContext<'a>> for traits::Goal<'tcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
use traits::Goal::*;

mem::discriminant(self).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<StableHashingContext<'a>> for traits::Clause<'tcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
use traits::Clause::*;

mem::discriminant(self).hash_stable(hcx, hasher);
match self {
Implies(hypotheses, goal) => {
hypotheses.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),
}
}
}

impl_stable_hash_for!(enum traits::QuantifierKind {
Universal,
Existential
});
64 changes: 64 additions & 0 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -244,6 +245,69 @@ pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;

/// 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>),
ProjectionEq(ty::ProjectionPredicate<'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::RegionOutlivesPredicate<'tcx>),
TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum QuantifierKind {
Universal,
Existential,
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Goal<'tcx> {
// FIXME: use interned refs instead of `Box`
Implies(Vec<Clause<'tcx>>, Box<Goal<'tcx>>),
And(Box<Goal<'tcx>>, Box<Goal<'tcx>>),
Not(Box<Goal<'tcx>>),
DomainGoal(DomainGoal<'tcx>),
Quantified(QuantifierKind, Box<ty::Binder<Goal<'tcx>>>)
}

impl<'tcx> From<DomainGoal<'tcx>> for Goal<'tcx> {
fn from(domain_goal: DomainGoal<'tcx>) -> Self {
Goal::DomainGoal(domain_goal)
}
}

impl<'tcx> From<DomainGoal<'tcx>> for Clause<'tcx> {
fn from(domain_goal: DomainGoal<'tcx>) -> Self {
Clause::DomainGoal(domain_goal)
}
}

/// 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<Goal<'tcx>>, DomainGoal<'tcx>),
DomainGoal(DomainGoal<'tcx>),
ForAll(Box<ty::Binder<Clause<'tcx>>>),
}

pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;

#[derive(Clone,Debug)]
Expand Down
135 changes: 135 additions & 0 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,138 @@ 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(trait_ref) => write!(fmt, "Implemented({})", trait_ref),
ProjectionEq(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(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),
}
}
}

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::Goal<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use traits::Goal::*;

match self {
Implies(hypotheses, goal) => {
write!(fmt, "if (")?;
for (index, hyp) in hypotheses.iter().enumerate() {
if index > 0 {
write!(fmt, ", ")?;
}
write!(fmt, "{}", hyp)?;
}
write!(fmt, ") {{ {} }}", 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())
}
}
}
}

impl<'tcx> fmt::Display for traits::Clause<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
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, ".")
}
DomainGoal(domain_goal) => write!(fmt, "{}.", domain_goal),
ForAll(clause) => {
// FIXME: appropriate binder names
write!(fmt, "forall<> {{ {} }}", clause.skip_binder())
}
}
}
}

EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for traits::WhereClauseAtom<'tcx> {
(traits::WhereClauseAtom::Implemented)(trait_ref),
(traits::WhereClauseAtom::ProjectionEq)(projection),
}
}

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),
}
}

CloneTypeFoldableImpls! {
traits::QuantifierKind,
}

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),
}
}

EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for traits::Clause<'tcx> {
(traits::Clause::Implies)(hypotheses, goal),
(traits::Clause::DomainGoal)(domain_goal),
(traits::Clause::ForAll)(clause),
}
}
6 changes: 6 additions & 0 deletions src/librustc/ty/maps/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,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> {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/ty/maps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::Clause;
use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use ty::steal::Steal;
use ty::subst::Substs;
Expand Down Expand Up @@ -417,6 +418,8 @@ define_maps! { <'tcx>
-> usize,

[] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>,

[] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc<Vec<Clause<'tcx>>>,
}

//////////////////////////////////////////////////////////////////////
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/ty/maps/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,9 +1073,12 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<ty::Region<'tcx>,
ty::Region<'tcx>>;
pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>,
ty::Region<'tcx>>;
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>,
ty::Region<'tcx>>;
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>;
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<TypeOutlivesPredicate<'tcx>>;

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct SubtypePredicate<'tcx> {
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,10 @@ 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",
|| rustc_traits::lowering::dump_program_clauses(tcx));

return Ok(f(tcx, analysis, rx, tcx.sess.compile_status()));
})
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_traits/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
};
}
Loading

0 comments on commit 7c396eb

Please sign in to comment.