Auto merge of #49837 - nikomatsakis:chalkify-engine, r=scalexm

work towards chalkify-ing the engine

This work towards creating a "all program clauses needed for this goal" query

r? @scalexm
This commit is contained in:
bors 2018-04-24 08:32:52 +00:00
commit 898c9f7d71
30 changed files with 379 additions and 268 deletions

View File

@ -655,6 +655,7 @@ define_dep_nodes!( <'tcx>
[input] Features,
[] ProgramClausesFor(DefId),
[] ProgramClausesForEnv(ParamEnv<'tcx>),
[] WasmImportModuleMap(CrateNum),
[] ForeignModules(CrateNum),

View File

@ -107,8 +107,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
// information we encapsulate into
let def_data = match i.node {
ItemKind::Impl(..) => DefPathData::Impl,
ItemKind::Trait(..) => DefPathData::Trait(i.ident.name.as_str()),
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
ItemKind::Trait(..) | ItemKind::TraitAlias(..) |
ItemKind::TraitAlias(..) |
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
DefPathData::TypeNs(i.ident.name.as_str()),
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
@ -222,7 +223,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
let def_data = match ti.node {
TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
DefPathData::ValueNs(ti.ident.name.as_str()),
TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
TraitItemKind::Type(..) => DefPathData::AssocTypeInTrait(ti.ident.name.as_str()),
TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
};
@ -240,7 +241,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
let def_data = match ii.node {
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
DefPathData::ValueNs(ii.ident.name.as_str()),
ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_str()),
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
};

View File

@ -212,6 +212,9 @@ impl DefKey {
::std::mem::discriminant(data).hash(&mut hasher);
match *data {
DefPathData::TypeNs(name) |
DefPathData::Trait(name) |
DefPathData::AssocTypeInTrait(name) |
DefPathData::AssocTypeInImpl(name) |
DefPathData::ValueNs(name) |
DefPathData::Module(name) |
DefPathData::MacroDef(name) |
@ -358,6 +361,12 @@ pub enum DefPathData {
// Different kinds of items and item-like things:
/// An impl
Impl,
/// A trait
Trait(InternedString),
/// An associated type **declaration** (i.e., in a trait)
AssocTypeInTrait(InternedString),
/// An associated type **value** (i.e., in an impl)
AssocTypeInImpl(InternedString),
/// Something in the type NS
TypeNs(InternedString),
/// Something in the value NS
@ -639,6 +648,9 @@ impl DefPathData {
use self::DefPathData::*;
match *self {
TypeNs(name) |
Trait(name) |
AssocTypeInTrait(name) |
AssocTypeInImpl(name) |
ValueNs(name) |
Module(name) |
MacroDef(name) |
@ -663,6 +675,9 @@ impl DefPathData {
use self::DefPathData::*;
let s = match *self {
TypeNs(name) |
Trait(name) |
AssocTypeInTrait(name) |
AssocTypeInImpl(name) |
ValueNs(name) |
Module(name) |
MacroDef(name) |

View File

@ -1352,10 +1352,6 @@ impl_stable_hash_for!(
}
);
impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> {
region_outlives, ty_outlives
});
impl_stable_hash_for!(enum infer::canonical::Certainty {
Proven, Ambiguous
});
@ -1417,6 +1413,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> {
quantifier.hash_stable(hcx, hasher);
goal.hash_stable(hcx, hasher);
},
CannotProve => { },
}
}
}

View File

@ -42,7 +42,6 @@ use traits::{Obligation, ObligationCause, PredicateObligation};
use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags};
use ty::subst::{Kind, UnpackedKind};
use ty::fold::{TypeFoldable, TypeFolder};
use util::captures::Captures;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashMap;
@ -121,7 +120,7 @@ pub enum CanonicalTyVarKind {
#[derive(Clone, Debug)]
pub struct QueryResult<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
pub region_constraints: Vec<QueryRegionConstraint<'tcx>>,
pub certainty: Certainty,
pub value: R,
}
@ -181,12 +180,7 @@ impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> {
}
}
/// Subset of `RegionConstraintData` produced by trait query.
#[derive(Clone, Debug, Default)]
pub struct QueryRegionConstraints<'tcx> {
pub region_outlives: Vec<(Region<'tcx>, Region<'tcx>)>,
pub ty_outlives: Vec<(Ty<'tcx>, Region<'tcx>)>,
}
pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
/// Trait implemented by values that can be canonicalized. It mainly
/// serves to identify the interning table we will use.
@ -382,35 +376,29 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
unsubstituted_region_constraints: &'a QueryRegionConstraints<'tcx>,
unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
result_subst: &'a CanonicalVarValues<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> + Captures<'gcx> + 'a {
let QueryRegionConstraints {
region_outlives,
ty_outlives,
} = unsubstituted_region_constraints;
let region_obligations = region_outlives.iter().map(move |(r1, r2)| {
let r1 = substitute_value(self.tcx, result_subst, r1);
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
Box::new(unsubstituted_region_constraints.iter().map(move |constraint| {
let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
let k1 = substitute_value(self.tcx, result_subst, k1);
let r2 = substitute_value(self.tcx, result_subst, r2);
Obligation::new(
cause.clone(),
param_env,
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))),
)
});
match k1.unpack() {
UnpackedKind::Lifetime(r1) =>
Obligation::new(
cause.clone(),
param_env,
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))),
),
let ty_obligations = ty_outlives.iter().map(move |(t1, r2)| {
let t1 = substitute_value(self.tcx, result_subst, t1);
let r2 = substitute_value(self.tcx, result_subst, r2);
Obligation::new(
cause.clone(),
param_env,
ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))),
)
});
region_obligations.chain(ty_obligations)
UnpackedKind::Type(t1) =>
Obligation::new(
cause.clone(),
param_env,
ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))),
),
}
})) as Box<dyn Iterator<Item = _>>
}
/// Given two sets of values for the same set of canonical variables, unify them.
@ -913,19 +901,6 @@ BraceStructTypeFoldableImpl! {
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> {
region_outlives, ty_outlives
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> {
type Lifted = QueryRegionConstraints<'tcx>;
region_outlives, ty_outlives
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> {
var_values, region_constraints, certainty, value

View File

@ -1289,6 +1289,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"tell the linker to strip debuginfo when building without debuginfo enabled."),
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
"make the current crate share its generic instantiations"),
chalk: bool = (false, parse_bool, [TRACKED],
"enable the experimental Chalk-based trait solving engine"),
}
pub fn default_lib_output() -> CrateType {

View File

@ -282,13 +282,16 @@ pub enum QuantifierKind {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Goal<'tcx> {
Implies(&'tcx Slice<Clause<'tcx>>, &'tcx Goal<'tcx>),
Implies(Clauses<'tcx>, &'tcx Goal<'tcx>),
And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>),
Not(&'tcx Goal<'tcx>),
DomainGoal(DomainGoal<'tcx>),
Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>)
Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>),
CannotProve,
}
pub type Goals<'tcx> = &'tcx Slice<Goal<'tcx>>;
impl<'tcx> Goal<'tcx> {
pub fn from_poly_domain_goal<'a>(
domain_goal: PolyDomainGoal<'tcx>,
@ -318,6 +321,9 @@ pub enum Clause<'tcx> {
ForAll(ty::Binder<ProgramClause<'tcx>>),
}
/// Multiple clauses.
pub type Clauses<'tcx> = &'tcx Slice<Clause<'tcx>>;
/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
/// that the domain goal `D` is true if `G1...Gn` are provable. This
/// is equivalent to the implication `G1..Gn => D`; we usually write
@ -330,7 +336,7 @@ pub struct ProgramClause<'tcx> {
pub goal: DomainGoal<'tcx>,
/// ...if we can prove these hypotheses (there may be no hypotheses at all):
pub hypotheses: &'tcx Slice<Goal<'tcx>>,
pub hypotheses: Goals<'tcx>,
}
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;

View File

@ -491,6 +491,7 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> {
// FIXME: appropriate binder names
write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder())
}
CannotProve => write!(fmt, "CannotProve"),
}
}
}
@ -557,6 +558,7 @@ EnumTypeFoldableImpl! {
(traits::Goal::Not)(goal),
(traits::Goal::DomainGoal)(domain_goal),
(traits::Goal::Quantified)(qkind, goal),
(traits::Goal::CannotProve),
}
}

View File

@ -38,7 +38,7 @@ use ty::subst::{Kind, Substs};
use ty::ReprOptions;
use ty::Instance;
use traits;
use traits::{Clause, Goal};
use traits::{Clause, Clauses, Goal, Goals};
use ty::{self, Ty, TypeAndMut};
use ty::{TyS, TypeVariants, Slice};
use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const};
@ -2517,7 +2517,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> &'tcx Slice<Clause<'tcx>> {
pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> Clauses<'tcx> {
if ts.len() == 0 {
Slice::empty()
} else {
@ -2525,7 +2525,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> &'tcx Slice<Goal<'tcx>> {
pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> Goals<'tcx> {
if ts.len() == 0 {
Slice::empty()
} else {
@ -2579,13 +2579,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
}
pub fn mk_clauses<I: InternAs<[Clause<'tcx>],
&'tcx Slice<Clause<'tcx>>>>(self, iter: I) -> I::Output {
pub fn mk_clauses<I: InternAs<[Clause<'tcx>], Clauses<'tcx>>>(self, iter: I) -> I::Output {
iter.intern_with(|xs| self.intern_clauses(xs))
}
pub fn mk_goals<I: InternAs<[Goal<'tcx>],
&'tcx Slice<Goal<'tcx>>>>(self, iter: I) -> I::Output {
pub fn mk_goals<I: InternAs<[Goal<'tcx>], Goals<'tcx>>>(self, iter: I) -> I::Output {
iter.intern_with(|xs| self.intern_goals(xs))
}

View File

@ -204,6 +204,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// finer-grained distinctions, e.g. between enum/struct).
data @ DefPathData::Misc |
data @ DefPathData::TypeNs(..) |
data @ DefPathData::Trait(..) |
data @ DefPathData::AssocTypeInTrait(..) |
data @ DefPathData::AssocTypeInImpl(..) |
data @ DefPathData::ValueNs(..) |
data @ DefPathData::Module(..) |
data @ DefPathData::TypeParam(..) |

View File

@ -717,6 +717,12 @@ 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>) -> String {
format!("generating chalk-style clauses for param env")
}
}
impl<'tcx> QueryDescription<'tcx> for queries::wasm_import_module_map<'tcx> {
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
format!("wasm import module map")

View File

@ -154,6 +154,15 @@ impl<'tcx> Key for Ty<'tcx> {
}
}
impl<'tcx> Key for ty::ParamEnv<'tcx> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
}
fn default_span(&self, _: TyCtxt) -> Span {
DUMMY_SP
}
}
impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
fn map_crate(&self) -> CrateNum {
self.value.map_crate()

View File

@ -37,8 +37,8 @@ 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, Slice, Ty, TyCtxt};
use traits::Clauses;
use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use ty::steal::Steal;
use ty::subst::Substs;
use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
@ -445,7 +445,11 @@ define_maps! { <'tcx>
[] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>,
[] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc<&'tcx Slice<Clause<'tcx>>>,
[] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>,
[] fn program_clauses_for_env: ProgramClausesForEnv(
ty::ParamEnv<'tcx>
) -> Clauses<'tcx>,
[] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc<Vec<DefId>>,
[] fn wasm_import_module_map: WasmImportModuleMap(CrateNum)

View File

@ -978,6 +978,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::DropckOutlives |
DepKind::SubstituteNormalizeAndTestPredicates |
DepKind::InstanceDefSizeEstimate |
DepKind::ProgramClausesForEnv |
// This one should never occur in this context
DepKind::Null => {

View File

@ -1138,6 +1138,11 @@ pub struct ProjectionPredicate<'tcx> {
pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>;
impl<'tcx> PolyProjectionPredicate<'tcx> {
/// Returns the def-id of the associated item being projected.
pub fn item_def_id(&self) -> DefId {
self.skip_binder().projection_ty.item_def_id
}
pub fn to_poly_trait_ref(&self, tcx: TyCtxt) -> PolyTraitRef<'tcx> {
// Note: unlike with TraitRef::to_poly_trait_ref(),
// self.0.trait_ref is permitted to have escaping regions.

View File

@ -268,14 +268,31 @@ impl PrintContext {
loop {
let key = tcx.def_key(item_def_id);
match key.disambiguated_data.data {
DefPathData::AssocTypeInTrait(_) |
DefPathData::AssocTypeInImpl(_) |
DefPathData::Trait(_) |
DefPathData::TypeNs(_) => {
break;
}
DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => {
DefPathData::ValueNs(_) |
DefPathData::EnumVariant(_) => {
is_value_path = true;
break;
}
_ => {
DefPathData::CrateRoot |
DefPathData::Misc |
DefPathData::Impl |
DefPathData::Module(_) |
DefPathData::MacroDef(_) |
DefPathData::ClosureExpr |
DefPathData::TypeParam(_) |
DefPathData::LifetimeDef(_) |
DefPathData::Field(_) |
DefPathData::StructCtor |
DefPathData::Initializer |
DefPathData::ImplTrait |
DefPathData::Typeof |
DefPathData::GlobalMetaData(_) => {
// if we're making a symbol for something, there ought
// to be a value or type-def or something in there
// *somewhere*

View File

@ -1155,6 +1155,10 @@ where
}
});
time(sess, "dumping chalk-like clauses", || {
rustc_traits::lowering::dump_program_clauses(tcx);
});
time(sess, "MIR effect checking", || {
for def_id in tcx.body_owners() {
mir::transform::check_unsafety::check_unsafety(tcx, def_id)
@ -1178,10 +1182,6 @@ where
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()));
},
)

View File

@ -37,6 +37,7 @@ pub fn provide(p: &mut Providers) {
normalize_ty_after_erasing_regions:
normalize_erasing_regions::normalize_ty_after_erasing_regions,
program_clauses_for: lowering::program_clauses_for,
program_clauses_for_env: lowering::program_clauses_for_env,
..*p
};
}

View File

@ -8,14 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::hir::{self, ImplPolarity};
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::ty::{self, Slice, TyCtxt};
use rustc::hir::map::definitions::DefPathData;
use rustc::hir::{self, ImplPolarity};
use rustc::traits::{Clause, Clauses, DomainGoal, Goal, PolyDomainGoal, ProgramClause,
WhereClauseAtom};
use rustc::ty::subst::Substs;
use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause, Goal};
use rustc::ty::{self, Slice, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use std::mem;
use syntax::ast;
use rustc_data_structures::sync::Lrc;
use std::iter;
@ -24,7 +27,10 @@ trait Lower<T> {
fn lower(&self) -> T;
}
impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> {
impl<T, U> Lower<Vec<U>> for Vec<T>
where
T: Lower<U>,
{
fn lower(&self) -> Vec<U> {
self.iter().map(|item| item.lower()).collect()
}
@ -42,7 +48,10 @@ impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::ProjectionPredicate<'tcx> {
}
}
impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> {
impl<'tcx, T> Lower<DomainGoal<'tcx>> for T
where
T: Lower<WhereClauseAtom<'tcx>>,
{
fn lower(&self) -> DomainGoal<'tcx> {
DomainGoal::Holds(self.lower())
}
@ -67,7 +76,8 @@ impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
/// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
/// `Binder<Holds(Implemented(TraitPredicate))>`.
impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>
where
T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>,
{
fn lower(&self) -> PolyDomainGoal<'tcx> {
self.map_bound_ref(|p| p.lower())
@ -84,10 +94,9 @@ impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
TypeOutlives(predicate) => predicate.lower(),
Projection(predicate) => predicate.lower(),
WellFormed(ty) => ty::Binder::dummy(DomainGoal::WellFormedTy(*ty)),
ObjectSafe(..) |
ClosureKind(..) |
Subtype(..) |
ConstEvaluatable(..) => unimplemented!(),
ObjectSafe(..) | ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) => {
unimplemented!()
}
}
}
}
@ -104,44 +113,88 @@ impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
use self::DomainGoal::*;
match self {
Holds(wc_atom) => FromEnv(wc_atom),
WellFormed(..) |
FromEnv(..) |
WellFormedTy(..) |
FromEnvTy(..) |
Normalize(..) |
RegionOutlives(..) |
TypeOutlives(..) => self,
WellFormed(..) | FromEnv(..) | WellFormedTy(..) | FromEnvTy(..) | Normalize(..)
| RegionOutlives(..) | TypeOutlives(..) => self,
}
}
}
crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Lrc<&'tcx Slice<Clause<'tcx>>>
{
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let node = tcx.hir.find(node_id).unwrap();
match node {
hir::map::Node::NodeItem(item) => match item.node {
hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
_ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
}
hir::map::Node::NodeImplItem(item) => {
if let hir::ImplItemKind::Type(..) = item.node {
program_clauses_for_associated_type_value(tcx, def_id)
} else {
Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()))
}
},
// FIXME: other constructions e.g. traits, associated types...
_ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
crate fn program_clauses_for<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> Clauses<'tcx> {
match tcx.def_key(def_id).disambiguated_data.data {
DefPathData::Trait(_) => program_clauses_for_trait(tcx, def_id),
DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id),
_ => Slice::empty(),
}
}
fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Lrc<&'tcx Slice<Clause<'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,
) -> Clauses<'tcx> {
// `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
// Rule Implemented-From-Env (see rustc guide)
@ -156,8 +209,8 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
let trait_pred = ty::TraitPredicate {
trait_ref: ty::TraitRef {
def_id,
substs: Substs::identity_for_item(tcx, def_id)
}
substs: Substs::identity_for_item(tcx, def_id),
},
};
// `FromEnv(Self: Trait<P1..Pn>)`
let from_env = Goal::from(DomainGoal::FromEnv(trait_pred.lower()));
@ -169,9 +222,7 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
goal: impl_trait,
hypotheses: tcx.mk_goals(iter::once(from_env)),
};
let clauses = iter::once(
Clause::ForAll(ty::Binder::dummy(implemented_from_env))
);
let clauses = iter::once(Clause::ForAll(ty::Binder::dummy(implemented_from_env)));
// Rule Implied-Bound-From-Trait
//
@ -186,11 +237,11 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
// FIXME: Remove the [1..] slice; this is a hack because the query
// predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`).
let where_clauses = &tcx.predicates_of(def_id).predicates;
let implied_bound_clauses =
where_clauses[1..].into_iter()
let implied_bound_clauses = where_clauses[1..]
.into_iter()
.map(|wc| implied_bound_from_trait(tcx, trait_pred, wc));
Lrc::new(tcx.mk_clauses(clauses.chain(implied_bound_clauses)))
tcx.mk_clauses(clauses.chain(implied_bound_clauses))
}
/// For a given `where_clause`, returns a clause `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`.
@ -203,19 +254,15 @@ fn implied_bound_from_trait<'a, 'tcx>(
let impl_trait = DomainGoal::FromEnv(WhereClauseAtom::Implemented(trait_pred));
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
Clause::ForAll(
where_clause.lower().map_bound(|goal| ProgramClause {
goal: goal.into_from_env_goal(),
hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))),
})
)
Clause::ForAll(where_clause.lower().map_bound(|goal| ProgramClause {
goal: goal.into_from_env_goal(),
hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))),
}))
}
fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Lrc<&'tcx Slice<Clause<'tcx>>>
{
fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> {
if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
return Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()));
return Slice::empty();
}
// Rule Implemented-From-Impl (see rustc guide)
@ -231,23 +278,25 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
// `Implemented(A0: Trait<A1..An>)`
let trait_pred = ty::TraitPredicate { trait_ref }.lower();
// `WC`
// `WC`
let where_clauses = tcx.predicates_of(def_id).predicates.lower();
// `Implemented(A0: Trait<A1..An>) :- WC`
// `Implemented(A0: Trait<A1..An>) :- WC`
let clause = ProgramClause {
goal: trait_pred,
hypotheses: tcx.mk_goals(
where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
)
where_clauses
.into_iter()
.map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
),
};
Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
}
pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
item_id: DefId,
) -> Lrc<&'tcx Slice<Clause<'tcx>>> {
) -> Clauses<'tcx> {
// Rule Normalize-From-Impl (see rustc guide)
//
// ```impl<P0..Pn> Trait<A1..An> for A0
@ -290,10 +339,12 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
let clause = ProgramClause {
goal: normalize_goal,
hypotheses: tcx.mk_goals(
where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
where_clauses
.into_iter()
.map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
),
};
Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
}
pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@ -302,27 +353,54 @@ pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
}
let mut visitor = ClauseDumper { tcx };
tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
tcx.hir
.krate()
.visit_all_item_likes(&mut visitor.as_deep_visitor());
}
struct ClauseDumper<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
impl<'a, 'tcx> ClauseDumper<'a, 'tcx > {
impl<'a, 'tcx> ClauseDumper<'a, 'tcx> {
fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
let def_id = self.tcx.hir.local_def_id(node_id);
for attr in attrs {
let mut clauses = None;
if attr.check_name("rustc_dump_program_clauses") {
let clauses = self.tcx.program_clauses_for(def_id);
for clause in *clauses {
// Skip the top-level binder for a less verbose output
let program_clause = match clause {
Clause::Implies(program_clause) => program_clause,
Clause::ForAll(program_clause) => program_clause.skip_binder(),
};
self.tcx.sess.struct_span_err(attr.span, &format!("{}", program_clause)).emit();
clauses = Some(self.tcx.program_clauses_for(def_id));
}
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));
}
if let Some(clauses) = clauses {
let mut err = self.tcx
.sess
.struct_span_err(attr.span, "program clause dump");
let mut strings: Vec<_> = clauses
.iter()
.map(|clause| {
// Skip the top-level binder for a less verbose output
let program_clause = match clause {
Clause::Implies(program_clause) => program_clause,
Clause::ForAll(program_clause) => program_clause.skip_binder(),
};
format!("{}", program_clause)
})
.collect();
strings.sort();
for string in strings {
err.note(&string);
}
err.emit();
}
}
}

View File

@ -9,8 +9,7 @@
// except according to those terms.
use rustc::infer::InferCtxt;
use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryRegionConstraints,
QueryResult};
use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryResult};
use rustc::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc::traits::{FulfillmentContext, TraitEngine};
use rustc::traits::query::NoSolution;
@ -62,7 +61,7 @@ where
let region_obligations = infcx.take_registered_region_obligations();
let (region_outlives, ty_outlives) = infcx.with_region_constraints(|region_constraints| {
let region_constraints = infcx.with_region_constraints(|region_constraints| {
let RegionConstraintData {
constraints,
verifys,
@ -72,24 +71,32 @@ where
assert!(verifys.is_empty());
assert!(givens.is_empty());
let region_outlives: Vec<_> = constraints
let mut outlives: Vec<_> = constraints
.into_iter()
.map(|(k, _)| match *k {
Constraint::VarSubVar(v1, v2) => {
(tcx.mk_region(ty::ReVar(v1)), tcx.mk_region(ty::ReVar(v2)))
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
tcx.mk_region(ty::ReVar(v1)).into(),
tcx.mk_region(ty::ReVar(v2)),
),
Constraint::VarSubReg(v1, r2) => {
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v1)).into(), r2)
}
Constraint::VarSubReg(v1, r2) => (tcx.mk_region(ty::ReVar(v1)), r2),
Constraint::RegSubVar(r1, v2) => (r1, tcx.mk_region(ty::ReVar(v2))),
Constraint::RegSubReg(r1, r2) => (r1, r2),
Constraint::RegSubVar(r1, v2) => {
ty::OutlivesPredicate(r1.into(), tcx.mk_region(ty::ReVar(v2)))
}
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r1.into(), r2),
})
.map(ty::Binder) // no bound regions in the code above
.collect();
let ty_outlives: Vec<_> = region_obligations
.into_iter()
.map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
.collect();
outlives.extend(
region_obligations
.into_iter()
.map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
.map(ty::Binder) // no bound regions in the code above
);
(region_outlives, ty_outlives)
outlives
});
let certainty = if ambig_errors.is_empty() {
@ -100,10 +107,7 @@ where
let (canonical_result, _) = infcx.canonicalize_response(&QueryResult {
var_values: inference_vars,
region_constraints: QueryRegionConstraints {
region_outlives,
ty_outlives,
},
region_constraints,
certainty,
value: answer,
});

View File

@ -0,0 +1,24 @@
// 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
trait Bar where Self: Foo { }
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
fn bar<T: Bar>() {
}
fn main() {
}

View File

@ -0,0 +1,24 @@
error: program clause dump
--> $DIR/lower_env1.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
error: program clause dump
--> $DIR/lower_env1.rs:19:1
|
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= 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).
error: aborting due to 2 previous errors

View File

@ -12,7 +12,7 @@
trait Foo { }
#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
#[rustc_dump_program_clauses] //~ ERROR program clause dump
impl<T: 'static> Foo for T where T: Iterator<Item = i32> { }
trait Bar {
@ -20,7 +20,7 @@ trait Bar {
}
impl<T> Bar for T where T: Iterator<Item = i32> {
#[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
#[rustc_dump_program_clauses] //~ ERROR program clause dump
type Assoc = Vec<T>;
}

View File

@ -1,14 +1,18 @@
error: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized).
error: program clause dump
--> $DIR/lower_impl.rs:15:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized).
error: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
error: program clause dump
--> $DIR/lower_impl.rs:23:5
|
LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
error: aborting due to 2 previous errors

View File

@ -10,10 +10,7 @@
#![feature(rustc_attrs)]
#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
//~| ERROR FromEnv
//~| ERROR FromEnv
//~| ERROR FromEnv
#[rustc_dump_program_clauses] //~ ERROR program clause dump
trait Foo<S, T, U> {
fn s(S) -> S;
fn t(T) -> T;

View File

@ -1,26 +1,13 @@
error: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
error: program clause dump
--> $DIR/lower_trait.rs:13:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
--> $DIR/lower_trait.rs:13:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
= note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
= note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
= note: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
--> $DIR/lower_trait.rs:13:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
--> $DIR/lower_trait.rs:13:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
error: aborting due to previous error

View File

@ -10,10 +10,7 @@
#![feature(rustc_attrs)]
#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
//~| ERROR FromEnv
//~| ERROR FromEnv
//~| ERROR FromEnv
#[rustc_dump_program_clauses] //~ ERROR program clause dump
trait Foo<F> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
{
fn s(F) -> F;

View File

@ -1,26 +1,13 @@
error: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>).
error: program clause dump
--> $DIR/lower_trait_higher_rank.rs:13:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>).
--> $DIR/lower_trait_higher_rank.rs:13:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>).
= note: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>).
= note: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>).
= note: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>).
error: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>).
--> $DIR/lower_trait_higher_rank.rs:13:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>).
--> $DIR/lower_trait_higher_rank.rs:13:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
error: aborting due to previous error

View File

@ -13,13 +13,7 @@
use std::fmt::{Debug, Display};
use std::borrow::Borrow;
#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
//~| ERROR FromEnv
//~| ERROR FromEnv
//~| ERROR FromEnv
//~| ERROR FromEnv
//~| ERROR RegionOutlives
//~| ERROR TypeOutlives
#[rustc_dump_program_clauses] //~ ERROR program clause dump
trait Foo<'a, 'b, S, T, U> where S: Debug, T: Borrow<U>, U: ?Sized, 'a: 'b, U: 'b {
fn s(S) -> S;
fn t(T) -> T;

View File

@ -1,44 +1,16 @@
error: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
error: program clause dump
--> $DIR/lower_trait_where_clause.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
--> $DIR/lower_trait_where_clause.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
--> $DIR/lower_trait_where_clause.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
--> $DIR/lower_trait_where_clause.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
--> $DIR/lower_trait_where_clause.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
--> $DIR/lower_trait_where_clause.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
--> $DIR/lower_trait_where_clause.rs:16:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors
error: aborting due to previous error