Auto merge of #55040 - scalexm:param-env, r=nikomatsakis

Replace `ParamEnv` with a new type in chalk context.

I left a few FIXMEs.

r? @nikomatsakis
This commit is contained in:
bors 2018-10-19 06:38:10 +00:00
commit dbab381da1
16 changed files with 553 additions and 116 deletions

View File

@ -70,6 +70,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use std::fmt;
use std::hash::Hash;
use syntax_pos::symbol::InternedString;
use traits;
use traits::query::{
CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal,
CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
@ -550,6 +551,7 @@ define_dep_nodes!( <'tcx>
[anon] TraitSelect,
[] ParamEnv(DefId),
[] Environment(DefId),
[] DescribeDef(DefId),
// FIXME(mw): DefSpans are not really inputs since they are derived from
@ -669,7 +671,7 @@ define_dep_nodes!( <'tcx>
[input] Features,
[] ProgramClausesFor(DefId),
[] ProgramClausesForEnv(ParamEnv<'tcx>),
[] ProgramClausesForEnv(traits::Environment<'tcx>),
[] WasmImportModuleMap(CrateNum),
[] ForeignModules(CrateNum),

View File

@ -1395,10 +1395,16 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> {
impl_stable_hash_for!(
impl<'tcx> for struct traits::ProgramClause<'tcx> {
goal, hypotheses
goal, hypotheses, category
}
);
impl_stable_hash_for!(enum traits::ProgramClauseCategory {
ImpliedBound,
WellFormed,
Other,
});
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Clause<'tcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
@ -1422,3 +1428,8 @@ impl_stable_hash_for!(struct ty::subst::UserSubsts<'tcx> { substs, user_self_ty
impl_stable_hash_for!(struct ty::subst::UserSelfTy<'tcx> { impl_def_id, self_ty });
impl_stable_hash_for!(
impl<'tcx> for struct traits::Environment<'tcx> {
clauses,
}
);

View File

@ -278,6 +278,8 @@ pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
/// * `DomainGoal`
/// * `Goal`
/// * `Clause`
/// * `Environment`
/// * `InEnvironment`
/// 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.
@ -335,6 +337,14 @@ impl<'tcx> DomainGoal<'tcx> {
pub fn into_goal(self) -> GoalKind<'tcx> {
GoalKind::DomainGoal(self)
}
pub fn into_program_clause(self) -> ProgramClause<'tcx> {
ProgramClause {
goal: self,
hypotheses: ty::List::empty(),
category: ProgramClauseCategory::Other,
}
}
}
impl<'tcx> GoalKind<'tcx> {
@ -360,6 +370,15 @@ pub enum Clause<'tcx> {
ForAll(ty::Binder<ProgramClause<'tcx>>),
}
impl Clause<'tcx> {
pub fn category(self) -> ProgramClauseCategory {
match self {
Clause::Implies(clause) => clause.category,
Clause::ForAll(clause) => clause.skip_binder().category,
}
}
}
/// Multiple clauses.
pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>;
@ -376,6 +395,38 @@ pub struct ProgramClause<'tcx> {
/// ...if we can prove these hypotheses (there may be no hypotheses at all):
pub hypotheses: Goals<'tcx>,
/// Useful for filtering clauses.
pub category: ProgramClauseCategory,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum ProgramClauseCategory {
ImpliedBound,
WellFormed,
Other,
}
/// A set of clauses that we assume to be true.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Environment<'tcx> {
pub clauses: Clauses<'tcx>,
}
impl Environment<'tcx> {
pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> {
InEnvironment {
environment: self,
goal,
}
}
}
/// Something (usually a goal), along with an environment.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct InEnvironment<'tcx, G> {
pub environment: Environment<'tcx>,
pub goal: G,
}
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;

View File

@ -496,7 +496,7 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> {
impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let traits::ProgramClause { goal, hypotheses } = self;
let traits::ProgramClause { goal, hypotheses, .. } = self;
write!(fmt, "{}", goal)?;
if !hypotheses.is_empty() {
write!(fmt, " :- ")?;
@ -647,10 +647,15 @@ impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for traits::ProgramClause<'tcx> {
goal,
hypotheses
hypotheses,
category,
}
}
CloneTypeFoldableAndLiftImpls! {
traits::ProgramClauseCategory,
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for traits::Clause<'tcx> {
(traits::Clause::Implies)(clause),
@ -658,7 +663,43 @@ EnumTypeFoldableImpl! {
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Clause<'tcx>> {
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for traits::Environment<'tcx> { clauses }
}
BraceStructTypeFoldableImpl! {
impl<'tcx, G> TypeFoldable<'tcx> for traits::InEnvironment<'tcx, G> {
environment,
goal
} where G: TypeFoldable<'tcx>
}
impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> {
type Lifted = traits::Environment<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.clauses).map(|clauses| {
traits::Environment {
clauses,
}
})
}
}
impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> {
type Lifted = traits::InEnvironment<'tcx, G::Lifted>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.environment).and_then(|environment| {
tcx.lift(&self.goal).map(|goal| {
traits::InEnvironment {
environment,
goal,
}
})
})
}
}
impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter()
.map(|t| t.fold_with(folder))

View File

@ -12,6 +12,7 @@ use dep_graph::SerializedDepNodeIndex;
use dep_graph::DepNode;
use hir::def_id::{CrateNum, DefId, DefIndex};
use mir::interpret::GlobalId;
use traits;
use traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal,
CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
@ -826,8 +827,14 @@ impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> {
}
impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for_env<'tcx> {
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: ty::ParamEnv<'tcx>) -> Cow<'static, str> {
"generating chalk-style clauses for param env".into()
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: traits::Environment<'tcx>) -> Cow<'static, str> {
"generating chalk-style clauses for environment".into()
}
}
impl<'tcx> QueryDescription<'tcx> for queries::environment<'tcx> {
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> {
"return a chalk-style environment".into()
}
}

View File

@ -12,6 +12,7 @@
use infer::canonical::Canonical;
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
use traits;
use ty::{self, Ty, TyCtxt};
use ty::subst::Substs;
use ty::fast_reject::SimplifiedType;
@ -181,6 +182,15 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
}
}
impl<'tcx> Key for traits::Environment<'tcx> {
fn query_crate(&self) -> CrateNum {
LOCAL_CRATE
}
fn default_span(&self, _: TyCtxt<'_, '_, '_>) -> Span {
DUMMY_SP
}
}
impl Key for InternedString {
fn query_crate(&self) -> CrateNum {
LOCAL_CRATE

View File

@ -664,8 +664,11 @@ define_queries! { <'tcx>
[] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>,
[] fn program_clauses_for_env: ProgramClausesForEnv(
ty::ParamEnv<'tcx>
traits::Environment<'tcx>
) -> Clauses<'tcx>,
// Get the chalk-style environment of the given item.
[] fn environment: Environment(DefId) -> traits::Environment<'tcx>,
},
Linking {

View File

@ -1156,6 +1156,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::CheckMatch => { force!(check_match, def_id!()); }
DepKind::ParamEnv => { force!(param_env, def_id!()); }
DepKind::Environment => { force!(environment, def_id!()); }
DepKind::DescribeDef => { force!(describe_def, def_id!()); }
DepKind::DefSpan => { force!(def_span, def_id!()); }
DepKind::LookupStability => { force!(lookup_stability, def_id!()); }

View File

@ -22,8 +22,10 @@ use rustc::traits::{
ExClauseLift,
Goal,
GoalKind,
ProgramClause,
QuantifierKind
Clause,
QuantifierKind,
Environment,
InEnvironment,
};
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use rustc::ty::subst::Kind;
@ -68,10 +70,10 @@ BraceStructTypeFoldableImpl! {
impl context::Context for ChalkArenas<'tcx> {
type CanonicalExClause = Canonical<'tcx, ExClause<Self>>;
type CanonicalGoalInEnvironment = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Goal<'tcx>>>;
type CanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>;
// u-canonicalization not yet implemented
type UCanonicalGoalInEnvironment = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Goal<'tcx>>>;
type UCanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>;
type CanonicalConstrainedSubst = Canonical<'tcx, ConstrainedSubst<'tcx>>;
@ -82,13 +84,13 @@ impl context::Context for ChalkArenas<'tcx> {
type InferenceNormalizedSubst = CanonicalVarValues<'tcx>;
type GoalInEnvironment = ty::ParamEnvAnd<'tcx, Goal<'tcx>>;
type GoalInEnvironment = InEnvironment<'tcx, Goal<'tcx>>;
type RegionConstraint = QueryRegionConstraint<'tcx>;
type Substitution = CanonicalVarValues<'tcx>;
type Environment = ty::ParamEnv<'tcx>;
type Environment = Environment<'tcx>;
type Goal = Goal<'tcx>;
@ -98,24 +100,24 @@ impl context::Context for ChalkArenas<'tcx> {
type Parameter = Kind<'tcx>;
type ProgramClause = ProgramClause<'tcx>;
type ProgramClause = Clause<'tcx>;
type ProgramClauses = Vec<ProgramClause<'tcx>>;
type ProgramClauses = Vec<Clause<'tcx>>;
type UnificationResult = InferOk<'tcx, ()>;
fn goal_in_environment(
env: &ty::ParamEnv<'tcx>,
env: &Environment<'tcx>,
goal: Goal<'tcx>,
) -> ty::ParamEnvAnd<'tcx, Goal<'tcx>> {
env.and(goal)
) -> InEnvironment<'tcx, Goal<'tcx>> {
env.with(goal)
}
}
impl context::AggregateOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
fn make_solution(
&self,
_root_goal: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
_root_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
_simplified_answers: impl context::AnswerStream<ChalkArenas<'gcx>>,
) -> Option<Canonical<'gcx, QueryResponse<'gcx, ()>>> {
unimplemented!()
@ -124,7 +126,10 @@ impl context::AggregateOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
/// True if this is a coinductive goal -- e.g., proving an auto trait.
fn is_coinductive(&self, _goal: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>) -> bool {
fn is_coinductive(
&self,
_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>
) -> bool {
unimplemented!()
}
@ -142,7 +147,7 @@ impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
/// - the environment and goal found by substitution `S` into `arg`
fn instantiate_ucanonical_goal<R>(
&self,
_arg: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
_arg: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
_op: impl context::WithInstantiatedUCanonicalGoal<ChalkArenas<'gcx>, Output = R>,
) -> R {
unimplemented!()
@ -175,19 +180,19 @@ impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
}
fn canonical(
u_canon: &'a Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
) -> &'a Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> {
u_canon: &'a Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
) -> &'a Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>> {
u_canon
}
fn is_trivial_substitution(
_u_canon: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
_u_canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
_canonical_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>,
) -> bool {
unimplemented!()
}
fn num_universes(_: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>) -> usize {
fn num_universes(_: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>) -> usize {
0 // FIXME
}
@ -196,8 +201,8 @@ impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
/// but for the universes of universally quantified names.
fn map_goal_from_canonical(
_map: &UniverseMap,
value: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
) -> Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> {
value: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
) -> Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>> {
*value // FIXME universe maps not implemented yet
}
@ -267,10 +272,14 @@ impl context::InferenceTable<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
fn add_clauses(
&mut self,
_env: &ty::ParamEnv<'tcx>,
_clauses: Vec<ProgramClause<'tcx>>,
) -> ty::ParamEnv<'tcx> {
panic!("FIXME no method to add clauses to ParamEnv yet")
env: &Environment<'tcx>,
clauses: Vec<Clause<'tcx>>,
) -> Environment<'tcx> {
Environment {
clauses: self.infcx.tcx.mk_clauses(
env.clauses.iter().cloned().chain(clauses.into_iter())
)
}
}
}
@ -279,10 +288,10 @@ impl context::ResolventOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
{
fn resolvent_clause(
&mut self,
_environment: &ty::ParamEnv<'tcx>,
_environment: &Environment<'tcx>,
_goal: &DomainGoal<'tcx>,
_subst: &CanonicalVarValues<'tcx>,
_clause: &ProgramClause<'tcx>,
_clause: &Clause<'tcx>,
) -> chalk_engine::fallible::Fallible<Canonical<'gcx, ChalkExClause<'gcx>>> {
panic!()
}
@ -290,8 +299,8 @@ impl context::ResolventOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
fn apply_answer_subst(
&mut self,
_ex_clause: ChalkExClause<'tcx>,
_selected_goal: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>,
_answer_table_goal: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
_selected_goal: &InEnvironment<'tcx, Goal<'tcx>>,
_answer_table_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
_canonical_answer_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>,
) -> chalk_engine::fallible::Fallible<ChalkExClause<'tcx>> {
panic!()
@ -303,8 +312,8 @@ impl context::TruncateOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
{
fn truncate_goal(
&mut self,
subgoal: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>,
) -> Option<ty::ParamEnvAnd<'tcx, Goal<'tcx>>> {
subgoal: &InEnvironment<'tcx, Goal<'tcx>>,
) -> Option<InEnvironment<'tcx, Goal<'tcx>>> {
Some(*subgoal) // FIXME we should truncate at some point!
}
@ -321,9 +330,9 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
{
fn program_clauses(
&self,
_environment: &ty::ParamEnv<'tcx>,
_environment: &Environment<'tcx>,
goal: &DomainGoal<'tcx>,
) -> Vec<ProgramClause<'tcx>> {
) -> Vec<Clause<'tcx>> {
use rustc::traits::WhereClause::*;
match goal {
@ -389,8 +398,8 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
fn canonicalize_goal(
&mut self,
value: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>,
) -> Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> {
value: &InEnvironment<'tcx, Goal<'tcx>>,
) -> Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>> {
let mut _orig_values = OriginalQueryValues::default();
self.infcx.canonicalize_query(value, &mut _orig_values)
}
@ -412,9 +421,9 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
fn u_canonicalize_goal(
&mut self,
value: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
value: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
) -> (
Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
UniverseMap,
) {
(value.clone(), UniverseMap)
@ -422,14 +431,14 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
fn invert_goal(
&mut self,
_value: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>,
) -> Option<ty::ParamEnvAnd<'tcx, Goal<'tcx>>> {
_value: &InEnvironment<'tcx, Goal<'tcx>>,
) -> Option<InEnvironment<'tcx, Goal<'tcx>>> {
panic!("goal inversion not yet implemented")
}
fn unify_parameters(
&mut self,
_environment: &ty::ParamEnv<'tcx>,
_environment: &Environment<'tcx>,
_a: &Kind<'tcx>,
_b: &Kind<'tcx>,
) -> ChalkEngineFallible<InferOk<'tcx, ()>> {

View File

@ -0,0 +1,256 @@
// 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.
use rustc::traits::{
Clause,
Clauses,
DomainGoal,
FromEnv,
ProgramClause,
ProgramClauseCategory,
Environment,
};
use rustc::ty::{self, TyCtxt, Ty};
use rustc::hir::def_id::DefId;
use rustc_data_structures::fx::FxHashSet;
struct ClauseVisitor<'set, 'a, 'tcx: 'a + 'set> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
round: &'set mut FxHashSet<Clause<'tcx>>,
}
impl ClauseVisitor<'set, 'a, 'tcx> {
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, round: &'set mut FxHashSet<Clause<'tcx>>) -> Self {
ClauseVisitor {
tcx,
round,
}
}
fn visit_ty(&mut self, ty: Ty<'tcx>) {
match ty.sty {
ty::Projection(data) => {
self.round.extend(
self.tcx.program_clauses_for(data.item_def_id)
.iter()
.filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
.cloned()
);
}
// forall<'a, T> { `Outlives(T, 'a) :- FromEnv(&'a T)` }
ty::Ref(_region, _sub_ty, ..) => {
// FIXME: we'd need bound tys in order to properly write the above rule
}
ty::Dynamic(..) => {
// FIXME: trait object rules are not yet implemented
}
ty::Adt(def, ..) => {
self.round.extend(
self.tcx.program_clauses_for(def.did)
.iter()
.filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
.cloned()
);
}
ty::Foreign(def_id) |
ty::FnDef(def_id, ..) |
ty::Closure(def_id, ..) |
ty::Generator(def_id, ..) |
ty::Opaque(def_id, ..) => {
self.round.extend(
self.tcx.program_clauses_for(def_id)
.iter()
.filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
.cloned()
);
}
ty::Bool |
ty::Char |
ty::Int(..) |
ty::Uint(..) |
ty::Float(..) |
ty::Str |
ty::Array(..) |
ty::Slice(..) |
ty::RawPtr(..) |
ty::FnPtr(..) |
ty::Never |
ty::Tuple(..) |
ty::GeneratorWitness(..) |
ty::UnnormalizedProjection(..) |
ty::Param(..) |
ty::Infer(..) |
ty::Error => (),
}
}
fn visit_from_env(&mut self, from_env: FromEnv<'tcx>) {
match from_env {
FromEnv::Trait(predicate) => {
self.round.extend(
self.tcx.program_clauses_for(predicate.def_id())
.iter()
.filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
.cloned()
);
}
FromEnv::Ty(ty) => self.visit_ty(ty),
}
}
fn visit_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) {
// The only domain goals we can find in an environment are:
// * `DomainGoal::Holds(..)`
// * `DomainGoal::FromEnv(..)`
// The former do not lead to any implied bounds. So we only need
// to visit the latter.
if let DomainGoal::FromEnv(from_env) = domain_goal {
self.visit_from_env(from_env);
}
}
fn visit_program_clause(&mut self, clause: ProgramClause<'tcx>) {
self.visit_domain_goal(clause.goal);
// No need to visit `clause.hypotheses`: they are always of the form
// `FromEnv(...)` and were visited at a previous round.
}
fn visit_clause(&mut self, clause: Clause<'tcx>) {
match clause {
Clause::Implies(clause) => self.visit_program_clause(clause),
Clause::ForAll(clause) => self.visit_program_clause(*clause.skip_binder()),
}
}
}
crate fn program_clauses_for_env<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
environment: Environment<'tcx>,
) -> Clauses<'tcx> {
debug!("program_clauses_for_env(environment={:?})", environment);
let mut last_round = FxHashSet();
{
let mut visitor = ClauseVisitor::new(tcx, &mut last_round);
for &clause in environment.clauses {
visitor.visit_clause(clause);
}
}
let mut closure = last_round.clone();
let mut next_round = FxHashSet();
while !last_round.is_empty() {
let mut visitor = ClauseVisitor::new(tcx, &mut next_round);
for clause in last_round.drain() {
visitor.visit_clause(clause);
}
last_round.extend(
next_round.drain().filter(|&clause| closure.insert(clause))
);
}
debug!("program_clauses_for_env: closure = {:#?}", closure);
return tcx.mk_clauses(
closure.into_iter()
);
}
crate fn environment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Environment<'tcx> {
use super::{Lower, IntoFromEnvGoal};
use rustc::hir::{Node, TraitItemKind, ImplItemKind, ItemKind, ForeignItemKind};
// The environment of an impl Trait type is its defining function's environment.
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
return environment(tcx, parent);
}
// Compute the bounds on `Self` and the type parameters.
let ty::InstantiatedPredicates { predicates } =
tcx.predicates_of(def_id).instantiate_identity(tcx);
let clauses = predicates.into_iter()
.map(|predicate| predicate.lower())
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_from_env_goal()))
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_program_clause()))
// `ForAll` because each `domain_goal` is a `PolyDomainGoal` and
// could bound lifetimes.
.map(Clause::ForAll);
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let node = tcx.hir.get(node_id);
let mut is_fn = false;
let mut is_impl = false;
match node {
Node::TraitItem(item) => match item.node {
TraitItemKind::Method(..) => is_fn = true,
_ => (),
}
Node::ImplItem(item) => match item.node {
ImplItemKind::Method(..) => is_fn = true,
_ => (),
}
Node::Item(item) => match item.node {
ItemKind::Impl(..) => is_impl = true,
ItemKind::Fn(..) => is_fn = true,
_ => (),
}
Node::ForeignItem(item) => match item.node {
ForeignItemKind::Fn(..) => is_fn = true,
_ => (),
}
// FIXME: closures?
_ => (),
}
let mut input_tys = FxHashSet::default();
// In an impl, we assume that the receiver type and all its constituents
// are well-formed.
if is_impl {
let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
input_tys.extend(trait_ref.self_ty().walk());
}
// In an fn, we assume that the arguments and all their constituents are
// well-formed.
if is_fn {
let fn_sig = tcx.fn_sig(def_id);
input_tys.extend(
// FIXME: `skip_binder` seems ok for now? In a real setting,
// the late bound regions would next be instantiated with things
// in the inference table.
fn_sig.skip_binder().inputs().iter().flat_map(|ty| ty.walk())
);
}
let clauses = clauses.chain(
input_tys.into_iter()
.map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty)))
.map(|domain_goal| domain_goal.into_program_clause())
.map(Clause::Implies)
);
Environment {
clauses: tcx.mk_clauses(clauses),
}
}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
mod environment;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::hir::map::definitions::DefPathData;
@ -20,13 +22,12 @@ use rustc::traits::{
GoalKind,
PolyDomainGoal,
ProgramClause,
ProgramClauseCategory,
WellFormed,
WhereClause,
};
use rustc::ty::query::Providers;
use rustc::ty::{self, List, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use std::mem;
use syntax::ast;
use std::iter;
@ -34,7 +35,8 @@ use std::iter;
crate fn provide(p: &mut Providers) {
*p = Providers {
program_clauses_for,
program_clauses_for_env,
program_clauses_for_env: environment::program_clauses_for_env,
environment: environment::environment,
..*p
};
}
@ -173,66 +175,6 @@ crate fn program_clauses_for<'a, 'tcx>(
}
}
crate fn program_clauses_for_env<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Clauses<'tcx> {
debug!("program_clauses_for_env(param_env={:?})", param_env);
let mut last_round = FxHashSet();
last_round.extend(
param_env
.caller_bounds
.iter()
.flat_map(|&p| predicate_def_id(p)),
);
let mut closure = last_round.clone();
let mut next_round = FxHashSet();
while !last_round.is_empty() {
next_round.extend(
last_round
.drain()
.flat_map(|def_id| {
tcx.predicates_of(def_id)
.instantiate_identity(tcx)
.predicates
})
.flat_map(|p| predicate_def_id(p))
.filter(|&def_id| closure.insert(def_id)),
);
mem::swap(&mut next_round, &mut last_round);
}
debug!("program_clauses_for_env: closure = {:#?}", closure);
return tcx.mk_clauses(
closure
.into_iter()
.flat_map(|def_id| tcx.program_clauses_for(def_id).iter().cloned()),
);
/// Given that `predicate` is in the environment, returns the
/// def-id of something (e.g., a trait, associated item, etc)
/// whose predicates can also be assumed to be true. We will
/// compute the transitive closure of such things.
fn predicate_def_id<'tcx>(predicate: ty::Predicate<'tcx>) -> Option<DefId> {
match predicate {
ty::Predicate::Trait(predicate) => Some(predicate.def_id()),
ty::Predicate::Projection(projection) => Some(projection.item_def_id()),
ty::Predicate::WellFormed(..)
| ty::Predicate::RegionOutlives(..)
| ty::Predicate::TypeOutlives(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => None,
}
}
}
fn program_clauses_for_trait<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
@ -263,6 +205,7 @@ fn program_clauses_for_trait<'a, 'tcx>(
let implemented_from_env = ProgramClause {
goal: impl_trait,
hypotheses,
category: ProgramClauseCategory::ImpliedBound,
};
let clauses = iter::once(Clause::ForAll(ty::Binder::dummy(implemented_from_env)));
@ -290,6 +233,7 @@ fn program_clauses_for_trait<'a, 'tcx>(
.map(|wc| wc.map_bound(|goal| ProgramClause {
goal: goal.into_from_env_goal(),
hypotheses,
category: ProgramClauseCategory::ImpliedBound,
}))
.map(Clause::ForAll);
@ -316,6 +260,7 @@ fn program_clauses_for_trait<'a, 'tcx>(
hypotheses: tcx.mk_goals(
wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
),
category: ProgramClauseCategory::WellFormed,
};
let wf_clause = iter::once(Clause::ForAll(ty::Binder::dummy(wf_clause)));
@ -358,6 +303,7 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
where_clauses
.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
),
category: ProgramClauseCategory::Other,
};
tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
}
@ -394,6 +340,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
.cloned()
.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
),
category: ProgramClauseCategory::WellFormed,
};
let well_formed_clause = iter::once(Clause::ForAll(ty::Binder::dummy(well_formed)));
@ -419,6 +366,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
.map(|wc| wc.map_bound(|goal| ProgramClause {
goal: goal.into_from_env_goal(),
hypotheses,
category: ProgramClauseCategory::ImpliedBound,
}))
.map(Clause::ForAll);
@ -466,7 +414,8 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
let projection_eq_clause = ProgramClause {
goal: DomainGoal::Holds(projection_eq),
hypotheses: &ty::List::empty(),
hypotheses: ty::List::empty(),
category: ProgramClauseCategory::Other,
};
// Rule WellFormed-AssocTy
@ -484,6 +433,7 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
let wf_clause = ProgramClause {
goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
hypotheses: tcx.mk_goals(iter::once(hypothesis)),
category: ProgramClauseCategory::Other,
};
// Rule Implied-Trait-From-AssocTy
@ -500,6 +450,7 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
let from_env_clause = ProgramClause {
goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
hypotheses: tcx.mk_goals(iter::once(hypothesis)),
category: ProgramClauseCategory::ImpliedBound,
};
let clauses = iter::once(projection_eq_clause)
@ -565,6 +516,7 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
.into_iter()
.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
),
category: ProgramClauseCategory::Other,
};
tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
}
@ -595,8 +547,8 @@ impl<'a, 'tcx> ClauseDumper<'a, 'tcx> {
}
if attr.check_name("rustc_dump_env_program_clauses") {
let param_env = self.tcx.param_env(def_id);
clauses = Some(self.tcx.program_clauses_for_env(param_env));
let environment = self.tcx.environment(def_id);
clauses = Some(self.tcx.program_clauses_for_env(environment));
}
if let Some(clauses) = clauses {

View File

@ -18,9 +18,6 @@ LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
= note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
= note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo).
= note: WellFormed(Self: Foo) :- Implemented(Self: Foo).
= note: WellFormed(Self: std::marker::Sized) :- Implemented(Self: std::marker::Sized).
error: aborting due to 2 previous errors

View File

@ -0,0 +1,26 @@
// 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.
#![feature(rustc_attrs)]
#![allow(dead_code)]
trait Foo { }
#[rustc_dump_program_clauses] //~ ERROR program clause dump
struct S<'a, T> where T: Foo {
data: &'a T,
}
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
fn bar<'a, T: Foo>(x: S<T>) {
}
fn main() {
}

View File

@ -0,0 +1,25 @@
error: program clause dump
--> $DIR/lower_env2.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(T: Foo) :- FromEnv(S<'a, T>).
= note: FromEnv(T: std::marker::Sized) :- FromEnv(S<'a, T>).
= note: TypeOutlives(T : 'a) :- FromEnv(S<'a, T>).
= note: WellFormed(S<'a, T>) :- Implemented(T: std::marker::Sized), Implemented(T: Foo), TypeOutlives(T : 'a).
error: program clause dump
--> $DIR/lower_env2.rs:21:1
|
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(T: Foo) :- FromEnv(S<'a, T>).
= note: FromEnv(T: std::marker::Sized) :- FromEnv(S<'a, T>).
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
= note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
= note: TypeOutlives(T : 'a) :- FromEnv(S<'a, T>).
error: aborting due to 2 previous errors

View File

@ -0,0 +1,26 @@
// 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.
#![feature(rustc_attrs)]
#![allow(dead_code)]
trait Foo {
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
fn foo(&self);
}
impl<T> Foo for T where T: Clone {
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
fn foo(&self) {
}
}
fn main() {
}

View File

@ -0,0 +1,20 @@
error: program clause dump
--> $DIR/lower_env3.rs:15:5
|
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
error: program clause dump
--> $DIR/lower_env3.rs:20:5
|
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(Self: std::marker::Sized) :- FromEnv(Self: std::clone::Clone).
= note: Implemented(Self: std::clone::Clone) :- FromEnv(Self: std::clone::Clone).
= note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
error: aborting due to 2 previous errors