From 62df97329384c308de91feb2126953a0da049d8c Mon Sep 17 00:00:00 2001 From: scalexm Date: Wed, 10 Oct 2018 17:14:33 +0200 Subject: [PATCH 1/8] Use `Environment` instead of `ty::ParamEnv` in chalk context --- src/librustc/dep_graph/dep_node.rs | 4 +- src/librustc/ich/impls_ty.rs | 8 ++ src/librustc/traits/mod.rs | 30 +++++ src/librustc/traits/structural_impls.rs | 38 +++++- src/librustc/ty/query/config.rs | 11 +- src/librustc/ty/query/keys.rs | 10 ++ src/librustc/ty/query/mod.rs | 4 +- src/librustc/ty/query/plumbing.rs | 1 + src/librustc_traits/chalk_context.rs | 71 +++++----- src/librustc_traits/lowering/environment.rs | 127 ++++++++++++++++++ .../{lowering.rs => lowering/mod.rs} | 70 +--------- 11 files changed, 271 insertions(+), 103 deletions(-) create mode 100644 src/librustc_traits/lowering/environment.rs rename src/librustc_traits/{lowering.rs => lowering/mod.rs} (89%) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 994bbe727fcf8..de03892b994ef 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -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), diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index e54968c5274bf..8df249d734179 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1418,7 +1418,15 @@ impl_stable_hash_for!(enum traits::QuantifierKind { Existential }); +<<<<<<< HEAD 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, + } +); +>>>>>>> Use `Environment` instead of `ty::ParamEnv` in chalk context diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 6e4abee32c077..d95b0844e87f5 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -278,6 +278,8 @@ pub type TraitObligations<'tcx> = Vec>; /// * `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. @@ -378,6 +380,33 @@ pub struct ProgramClause<'tcx> { pub hypotheses: Goals<'tcx>, } +/// 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(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, +} + +/// Compute the environment of the given item. +fn environment<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, _def_id: DefId) -> Environment<'tcx> { + panic!() +} + pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; #[derive(Clone,Debug)] @@ -1080,6 +1109,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_methods, substitute_normalize_and_test_predicates, + environment, ..*providers }; } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 1524f89af291d..7b7446e27d231 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -658,7 +658,43 @@ EnumTypeFoldableImpl! { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { +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 { + 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 { + 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)) diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index 79eab3c6f34b9..d0c3109da52f1 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -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() } } diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index 96b0a768001a8..f2d7a6792b563 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -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 diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index c4f39ffcd2067..83c8eab0f39ac 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -377,6 +377,8 @@ define_queries! { <'tcx> // might want to use `reveal_all()` method to change modes. [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, + [] fn environment: Environment(DefId) -> traits::Environment<'tcx>, + // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, // `ty.is_copy()`, etc, since that will prune the environment where possible. [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, @@ -664,7 +666,7 @@ 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>, }, diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 39a59cf090ea8..f83f8bcf1a12d 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -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!()); } diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs index 536c15234064f..2fd8aa0c3af35 100644 --- a/src/librustc_traits/chalk_context.rs +++ b/src/librustc_traits/chalk_context.rs @@ -23,7 +23,9 @@ use rustc::traits::{ Goal, GoalKind, ProgramClause, - QuantifierKind + 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>; - 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>; @@ -105,17 +107,17 @@ impl context::Context for ChalkArenas<'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> 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>, ) -> Option>> { unimplemented!() @@ -124,7 +126,10 @@ impl context::AggregateOps> for ChalkContext<'cx, 'gcx> { impl context::ContextOps> 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> for ChalkContext<'cx, 'gcx> { /// - the environment and goal found by substitution `S` into `arg` fn instantiate_ucanonical_goal( &self, - _arg: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>, + _arg: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, _op: impl context::WithInstantiatedUCanonicalGoal, Output = R>, ) -> R { unimplemented!() @@ -175,19 +180,19 @@ impl context::ContextOps> 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> 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,10 @@ impl context::InferenceTable, ChalkArenas<'tcx>> fn add_clauses( &mut self, - _env: &ty::ParamEnv<'tcx>, + _env: &Environment<'tcx>, _clauses: Vec>, - ) -> ty::ParamEnv<'tcx> { - panic!("FIXME no method to add clauses to ParamEnv yet") + ) -> Environment<'tcx> { + panic!("FIXME no method to add clauses to Environment yet") } } @@ -279,7 +284,7 @@ impl context::ResolventOps, ChalkArenas<'tcx>> { fn resolvent_clause( &mut self, - _environment: &ty::ParamEnv<'tcx>, + _environment: &Environment<'tcx>, _goal: &DomainGoal<'tcx>, _subst: &CanonicalVarValues<'tcx>, _clause: &ProgramClause<'tcx>, @@ -290,8 +295,8 @@ impl context::ResolventOps, 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> { panic!() @@ -303,8 +308,8 @@ impl context::TruncateOps, ChalkArenas<'tcx>> { fn truncate_goal( &mut self, - subgoal: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>, - ) -> Option>> { + subgoal: &InEnvironment<'tcx, Goal<'tcx>>, + ) -> Option>> { Some(*subgoal) // FIXME we should truncate at some point! } @@ -321,7 +326,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> { fn program_clauses( &self, - _environment: &ty::ParamEnv<'tcx>, + _environment: &Environment<'tcx>, goal: &DomainGoal<'tcx>, ) -> Vec> { use rustc::traits::WhereClause::*; @@ -389,8 +394,8 @@ impl context::UnificationOps, 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 +417,9 @@ impl context::UnificationOps, 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 +427,14 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn invert_goal( &mut self, - _value: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>, - ) -> Option>> { + _value: &InEnvironment<'tcx, Goal<'tcx>>, + ) -> Option>> { 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> { diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs new file mode 100644 index 0000000000000..b04766b087e53 --- /dev/null +++ b/src/librustc_traits/lowering/environment.rs @@ -0,0 +1,127 @@ +// 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 rustc::traits::{ + Clause, + Clauses, + DomainGoal, + FromEnv, + Goal, + ProgramClause, + Environment, +}; +use rustc::ty::{TyCtxt, Ty}; +use rustc_data_structures::fx::FxHashSet; + +struct ClauseVisitor<'set, 'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + round: &'set mut FxHashSet>, +} + +impl ClauseVisitor<'set, 'a, 'tcx> { + fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, round: &'set mut FxHashSet>) -> Self { + ClauseVisitor { + tcx, + round, + } + } + + fn visit_ty(&mut self, _ty: Ty<'tcx>) { + + } + + 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() + .cloned() + ); + } + + FromEnv::Ty(ty) => self.visit_ty(ty), + } + } + + fn visit_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) { + if let DomainGoal::FromEnv(from_env) = domain_goal { + self.visit_from_env(from_env); + } + } + + fn visit_goal(&mut self, goal: Goal<'tcx>) { + match goal { + Goal::Implies(clauses, goal) => { + for clause in clauses { + self.visit_clause(*clause); + } + self.visit_goal(*goal); + } + + Goal::And(goal1, goal2) => { + self.visit_goal(*goal1); + self.visit_goal(*goal2); + } + + Goal::Not(goal) => self.visit_goal(*goal), + Goal::DomainGoal(domain_goal) => self.visit_domain_goal(domain_goal), + Goal::Quantified(_, goal) => self.visit_goal(**goal.skip_binder()), + Goal::CannotProve => (), + } + } + + fn visit_program_clause(&mut self, clause: ProgramClause<'tcx>) { + self.visit_domain_goal(clause.goal); + for goal in clause.hypotheses { + self.visit_goal(*goal); + } + } + + 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 { + visitor.visit_clause(clause); + } + last_round = next_round.drain() + .filter(|&clause| closure.insert(clause)) + .collect(); + } + + debug!("program_clauses_for_env: closure = {:#?}", closure); + + return tcx.mk_clauses( + closure.into_iter() + ); +} diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering/mod.rs similarity index 89% rename from src/librustc_traits/lowering.rs rename to src/librustc_traits/lowering/mod.rs index 1e3f0a21cefb3..07a5d6a31dd0a 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -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; @@ -25,8 +27,6 @@ use rustc::traits::{ }; 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 +34,7 @@ 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, ..*p }; } @@ -173,66 +173,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 { - 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, @@ -595,8 +535,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 { From 81131804da3e14a67804a301008c796f5c8ea950 Mon Sep 17 00:00:00 2001 From: scalexm Date: Thu, 11 Oct 2018 14:40:14 +0200 Subject: [PATCH 2/8] Visit tys in `program_clauses_for_env` --- src/librustc_traits/lowering/environment.rs | 95 ++++++++++++++------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index b04766b087e53..338cad8154ff0 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -13,11 +13,10 @@ use rustc::traits::{ Clauses, DomainGoal, FromEnv, - Goal, ProgramClause, Environment, }; -use rustc::ty::{TyCtxt, Ty}; +use rustc::ty::{self, TyCtxt, Ty}; use rustc_data_structures::fx::FxHashSet; struct ClauseVisitor<'set, 'a, 'tcx: 'a> { @@ -33,8 +32,63 @@ impl ClauseVisitor<'set, 'a, 'tcx> { } } - fn visit_ty(&mut self, _ty: Ty<'tcx>) { + 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() + .cloned() + ); + } + + // forall<'a, T> { `Outlives(T, 'a) :- FromEnv(&'a T)` } + ty::Ref(_region, _sub_ty, ..) => { + // FIXME: we need bound tys in order to 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() + .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() + .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>) { @@ -52,37 +106,20 @@ impl ClauseVisitor<'set, 'a, 'tcx> { } 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_goal(&mut self, goal: Goal<'tcx>) { - match goal { - Goal::Implies(clauses, goal) => { - for clause in clauses { - self.visit_clause(*clause); - } - self.visit_goal(*goal); - } - - Goal::And(goal1, goal2) => { - self.visit_goal(*goal1); - self.visit_goal(*goal2); - } - - Goal::Not(goal) => self.visit_goal(*goal), - Goal::DomainGoal(domain_goal) => self.visit_domain_goal(domain_goal), - Goal::Quantified(_, goal) => self.visit_goal(**goal.skip_binder()), - Goal::CannotProve => (), - } - } - fn visit_program_clause(&mut self, clause: ProgramClause<'tcx>) { self.visit_domain_goal(clause.goal); - for goal in clause.hypotheses { - self.visit_goal(*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>) { @@ -102,8 +139,8 @@ crate fn program_clauses_for_env<'a, 'tcx>( let mut last_round = FxHashSet(); { let mut visitor = ClauseVisitor::new(tcx, &mut last_round); - for clause in environment.clauses { - visitor.visit_clause(*clause); + for &clause in environment.clauses { + visitor.visit_clause(clause); } } From 079b97c54391af0a589f9dc8e28af56c9c950424 Mon Sep 17 00:00:00 2001 From: scalexm Date: Thu, 11 Oct 2018 16:26:43 +0200 Subject: [PATCH 3/8] Implement the `environment` query --- src/librustc/traits/mod.rs | 13 +++++------ src/librustc/ty/query/mod.rs | 1 + src/librustc_traits/lowering/environment.rs | 24 +++++++++++++++++++++ src/librustc_traits/lowering/mod.rs | 1 + 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index d95b0844e87f5..7bfb6f060cd4a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -337,6 +337,13 @@ 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(), + } + } } impl<'tcx> GoalKind<'tcx> { @@ -402,11 +409,6 @@ pub struct InEnvironment<'tcx, G> { pub goal: G, } -/// Compute the environment of the given item. -fn environment<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, _def_id: DefId) -> Environment<'tcx> { - panic!() -} - pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; #[derive(Clone,Debug)] @@ -1109,7 +1111,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_methods, substitute_normalize_and_test_predicates, - environment, ..*providers }; } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 83c8eab0f39ac..adb5883fd5e26 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -377,6 +377,7 @@ define_queries! { <'tcx> // might want to use `reveal_all()` method to change modes. [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, + // Get the chalk-style environment of the given item. [] fn environment: Environment(DefId) -> traits::Environment<'tcx>, // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 338cad8154ff0..1774db3d85a87 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -17,6 +17,7 @@ use rustc::traits::{ 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> { @@ -162,3 +163,26 @@ crate fn program_clauses_for_env<'a, 'tcx>( closure.into_iter() ); } + +crate fn environment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Environment<'tcx> { + use super::{Lower, IntoFromEnvGoal}; + + // 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(|dg| dg.into_from_env_goal())) + .map(|domain_goal| domain_goal.map_bound(|dg| dg.into_program_clause())) + .map(Clause::ForAll); + + Environment { + clauses: tcx.mk_clauses(clauses), + } +} diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 07a5d6a31dd0a..a6bf28b6ad8ac 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -35,6 +35,7 @@ crate fn provide(p: &mut Providers) { *p = Providers { program_clauses_for, program_clauses_for_env: environment::program_clauses_for_env, + environment: environment::environment, ..*p }; } From e1926080db954fea5ac6abb75267bde762d478c5 Mon Sep 17 00:00:00 2001 From: scalexm Date: Thu, 11 Oct 2018 17:57:45 +0200 Subject: [PATCH 4/8] Add `FromEnv` for input types in the environment --- src/librustc/ty/query/mod.rs | 6 +- src/librustc_traits/lowering/environment.rs | 70 +++++++++++++++++++-- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index adb5883fd5e26..b61bc8b4fd952 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -377,9 +377,6 @@ define_queries! { <'tcx> // might want to use `reveal_all()` method to change modes. [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, - // Get the chalk-style environment of the given item. - [] fn environment: Environment(DefId) -> traits::Environment<'tcx>, - // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, // `ty.is_copy()`, etc, since that will prune the environment where possible. [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, @@ -669,6 +666,9 @@ define_queries! { <'tcx> [] fn program_clauses_for_env: ProgramClausesForEnv( traits::Environment<'tcx> ) -> Clauses<'tcx>, + + // Get the chalk-style environment of the given item. + [] fn environment: Environment(DefId) -> traits::Environment<'tcx>, }, Linking { diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 1774db3d85a87..1f3fec4699066 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -45,7 +45,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { // forall<'a, T> { `Outlives(T, 'a) :- FromEnv(&'a T)` } ty::Ref(_region, _sub_ty, ..) => { - // FIXME: we need bound tys in order to write the above rule + // FIXME: we'd need bound tys in order to properly write the above rule } ty::Dynamic(..) => { @@ -166,8 +166,9 @@ crate fn program_clauses_for_env<'a, 'tcx>( 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 + // 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); } @@ -178,10 +179,71 @@ crate fn environment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> En let clauses = predicates.into_iter() .map(|predicate| predicate.lower()) - .map(|domain_goal| domain_goal.map_bound(|dg| dg.into_from_env_goal())) - .map(|domain_goal| domain_goal.map_bound(|dg| dg.into_program_clause())) + .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 constitutents are + // well-formed. + if is_fn { + let fn_sig = tcx.fn_sig(def_id) + .no_late_bound_regions() + .expect("only early bound regions"); + input_tys.extend( + fn_sig.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), } From a1931d31f7895bb3b15d24d2784e47ba6598ef2f Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 12 Oct 2018 19:24:18 +0200 Subject: [PATCH 5/8] Categorize chalk clauses --- src/librustc/ich/impls_ty.rs | 8 +++++++- src/librustc/traits/mod.rs | 22 ++++++++++++++++++++- src/librustc/traits/structural_impls.rs | 9 +++++++-- src/librustc_traits/lowering/environment.rs | 11 ++++++++--- src/librustc_traits/lowering/mod.rs | 13 +++++++++++- 5 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 8df249d734179..36c0f30f0bf13 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1395,10 +1395,16 @@ impl<'a, 'tcx> HashStable> 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> for traits::Clause<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 7bfb6f060cd4a..d129cd486cf05 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -341,7 +341,8 @@ impl<'tcx> DomainGoal<'tcx> { pub fn into_program_clause(self) -> ProgramClause<'tcx> { ProgramClause { goal: self, - hypotheses: &ty::List::empty(), + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::Other, } } } @@ -369,6 +370,15 @@ pub enum Clause<'tcx> { ForAll(ty::Binder>), } +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>; @@ -385,6 +395,16 @@ 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. diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 7b7446e27d231..c50c9703eb557 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -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), diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 1f3fec4699066..a1cdb622f3702 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -14,6 +14,7 @@ use rustc::traits::{ DomainGoal, FromEnv, ProgramClause, + ProgramClauseCategory, Environment, }; use rustc::ty::{self, TyCtxt, Ty}; @@ -39,6 +40,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { self.round.extend( self.tcx.program_clauses_for(data.item_def_id) .iter() + .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound) .cloned() ); } @@ -56,6 +58,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { self.round.extend( self.tcx.program_clauses_for(def.did) .iter() + .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound) .cloned() ); } @@ -68,6 +71,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { self.round.extend( self.tcx.program_clauses_for(def_id) .iter() + .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound) .cloned() ); } @@ -98,6 +102,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { self.round.extend( self.tcx.program_clauses_for(predicate.def_id()) .iter() + .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound) .cloned() ); } @@ -176,7 +181,7 @@ crate fn environment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> En // 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())) @@ -185,7 +190,7 @@ crate fn environment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> En // `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); @@ -243,7 +248,7 @@ crate fn environment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> En .map(|domain_goal| domain_goal.into_program_clause()) .map(Clause::Implies) ); - + Environment { clauses: tcx.mk_clauses(clauses), } diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index a6bf28b6ad8ac..fb598a335482b 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -22,6 +22,7 @@ use rustc::traits::{ GoalKind, PolyDomainGoal, ProgramClause, + ProgramClauseCategory, WellFormed, WhereClause, }; @@ -204,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))); @@ -231,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); @@ -257,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))); @@ -299,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)))) } @@ -335,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))); @@ -360,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); @@ -407,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 @@ -425,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 @@ -441,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) @@ -506,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)))) } From b5d1aac8837d053df75996a7f5b5e6d0760d8006 Mon Sep 17 00:00:00 2001 From: scalexm Date: Sat, 13 Oct 2018 16:23:42 +0200 Subject: [PATCH 6/8] Add tests for `program_clauses_for_env` --- src/librustc_traits/lowering/environment.rs | 11 +++++---- src/test/ui/chalkify/lower_env1.stderr | 3 --- src/test/ui/chalkify/lower_env2.rs | 26 +++++++++++++++++++++ src/test/ui/chalkify/lower_env2.stderr | 25 ++++++++++++++++++++ src/test/ui/chalkify/lower_env3.rs | 26 +++++++++++++++++++++ src/test/ui/chalkify/lower_env3.stderr | 20 ++++++++++++++++ 6 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/chalkify/lower_env2.rs create mode 100644 src/test/ui/chalkify/lower_env2.stderr create mode 100644 src/test/ui/chalkify/lower_env3.rs create mode 100644 src/test/ui/chalkify/lower_env3.stderr diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index a1cdb622f3702..f0ce2037723a4 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -231,14 +231,15 @@ crate fn environment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> En input_tys.extend(trait_ref.self_ty().walk()); } - // In an fn, we assume that the arguments and all their constitutents are + // 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) - .no_late_bound_regions() - .expect("only early bound regions"); + let fn_sig = tcx.fn_sig(def_id); input_tys.extend( - fn_sig.inputs().iter().flat_map(|ty| ty.walk()) + // 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()) ); } diff --git a/src/test/ui/chalkify/lower_env1.stderr b/src/test/ui/chalkify/lower_env1.stderr index 4a3e14ac03472..3aa04cfeb67d4 100644 --- a/src/test/ui/chalkify/lower_env1.stderr +++ b/src/test/ui/chalkify/lower_env1.stderr @@ -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 diff --git a/src/test/ui/chalkify/lower_env2.rs b/src/test/ui/chalkify/lower_env2.rs new file mode 100644 index 0000000000000..0b50dbfdf95c6 --- /dev/null +++ b/src/test/ui/chalkify/lower_env2.rs @@ -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 or the MIT license +// , 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) { +} + +fn main() { +} diff --git a/src/test/ui/chalkify/lower_env2.stderr b/src/test/ui/chalkify/lower_env2.stderr new file mode 100644 index 0000000000000..3b88ac1f22bea --- /dev/null +++ b/src/test/ui/chalkify/lower_env2.stderr @@ -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 + diff --git a/src/test/ui/chalkify/lower_env3.rs b/src/test/ui/chalkify/lower_env3.rs new file mode 100644 index 0000000000000..1f8bc49e30996 --- /dev/null +++ b/src/test/ui/chalkify/lower_env3.rs @@ -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 or the MIT license +// , 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 Foo for T where T: Clone { + #[rustc_dump_env_program_clauses] //~ ERROR program clause dump + fn foo(&self) { + } +} + +fn main() { +} diff --git a/src/test/ui/chalkify/lower_env3.stderr b/src/test/ui/chalkify/lower_env3.stderr new file mode 100644 index 0000000000000..ac0f8e34cd437 --- /dev/null +++ b/src/test/ui/chalkify/lower_env3.stderr @@ -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 + From 7ec8269d0aead891c25a20b4e4c4cc5d73eccf79 Mon Sep 17 00:00:00 2001 From: scalexm Date: Sat, 13 Oct 2018 16:29:21 +0200 Subject: [PATCH 7/8] Implement `InferenceTable::add_clauses` --- src/librustc_traits/chalk_context.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs index 2fd8aa0c3af35..371fa46f37010 100644 --- a/src/librustc_traits/chalk_context.rs +++ b/src/librustc_traits/chalk_context.rs @@ -22,7 +22,7 @@ use rustc::traits::{ ExClauseLift, Goal, GoalKind, - ProgramClause, + Clause, QuantifierKind, Environment, InEnvironment, @@ -100,9 +100,9 @@ impl context::Context for ChalkArenas<'tcx> { type Parameter = Kind<'tcx>; - type ProgramClause = ProgramClause<'tcx>; + type ProgramClause = Clause<'tcx>; - type ProgramClauses = Vec>; + type ProgramClauses = Vec>; type UnificationResult = InferOk<'tcx, ()>; @@ -272,10 +272,14 @@ impl context::InferenceTable, ChalkArenas<'tcx>> fn add_clauses( &mut self, - _env: &Environment<'tcx>, - _clauses: Vec>, + env: &Environment<'tcx>, + clauses: Vec>, ) -> Environment<'tcx> { - panic!("FIXME no method to add clauses to Environment yet") + Environment { + clauses: self.infcx.tcx.mk_clauses( + env.clauses.iter().cloned().chain(clauses.into_iter()) + ) + } } } @@ -287,7 +291,7 @@ impl context::ResolventOps, ChalkArenas<'tcx>> _environment: &Environment<'tcx>, _goal: &DomainGoal<'tcx>, _subst: &CanonicalVarValues<'tcx>, - _clause: &ProgramClause<'tcx>, + _clause: &Clause<'tcx>, ) -> chalk_engine::fallible::Fallible>> { panic!() } @@ -328,7 +332,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> &self, _environment: &Environment<'tcx>, goal: &DomainGoal<'tcx>, - ) -> Vec> { + ) -> Vec> { use rustc::traits::WhereClause::*; match goal { From 55ce7a266958aaed4774927ed1765576f561aa2d Mon Sep 17 00:00:00 2001 From: scalexm Date: Sat, 13 Oct 2018 17:10:56 +0200 Subject: [PATCH 8/8] Re-use memory in `program_clauses_for_env` --- src/librustc/ich/impls_ty.rs | 3 --- src/librustc_traits/lowering/environment.rs | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 36c0f30f0bf13..43448ad0d15ad 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1424,15 +1424,12 @@ impl_stable_hash_for!(enum traits::QuantifierKind { Existential }); -<<<<<<< HEAD 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, } ); ->>>>>>> Use `Environment` instead of `ty::ParamEnv` in chalk context diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index f0ce2037723a4..3d1e7cf17a659 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -21,7 +21,7 @@ use rustc::ty::{self, TyCtxt, Ty}; use rustc::hir::def_id::DefId; use rustc_data_structures::fx::FxHashSet; -struct ClauseVisitor<'set, 'a, 'tcx: 'a> { +struct ClauseVisitor<'set, 'a, 'tcx: 'a + 'set> { tcx: TyCtxt<'a, 'tcx, 'tcx>, round: &'set mut FxHashSet>, } @@ -154,12 +154,12 @@ crate fn program_clauses_for_env<'a, 'tcx>( let mut next_round = FxHashSet(); while !last_round.is_empty() { let mut visitor = ClauseVisitor::new(tcx, &mut next_round); - for clause in last_round { + for clause in last_round.drain() { visitor.visit_clause(clause); } - last_round = next_round.drain() - .filter(|&clause| closure.insert(clause)) - .collect(); + last_round.extend( + next_round.drain().filter(|&clause| closure.insert(clause)) + ); } debug!("program_clauses_for_env: closure = {:#?}", closure);