From 5c15163cb9101d9a9cc8a41fe98b253cce351857 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 29 Jun 2018 05:31:59 -0400 Subject: [PATCH 1/5] prove defaults meet WF requirements, not that they are WF If we have ```rust struct Foo { .. } ``` the old code would have proven that `String: Copy` was WF -- this, incidentally, also proved that `String: Copy`. The new code just proves `String: Copy` directly. Co-authored-by: Tyler Mandry --- src/librustc_typeck/check/wfcheck.rs | 54 +++++++++++++++++--------- src/test/ui/type-check-defaults.stderr | 24 ++++++++++-- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index be42549df74..85fdcd417ff 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -364,15 +364,16 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Checks where clauses and inline bounds that are declared on def_id. -fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, - fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, - span: Span, - def_id: DefId) { +fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'gcx>, + fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, + span: Span, + def_id: DefId, +) { use ty::subst::Subst; use rustc::ty::TypeFoldable; - let mut predicates = fcx.tcx.predicates_of(def_id); - let mut substituted_predicates = Vec::new(); + let predicates = fcx.tcx.predicates_of(def_id); let generics = tcx.generics_of(def_id); let is_our_default = |def: &ty::GenericParamDef| { @@ -433,7 +434,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, } }); // Now we build the substituted predicates. - for &pred in predicates.predicates.iter() { + let default_obligations = predicates.predicates.iter().flat_map(|&pred| { struct CountParams { params: FxHashSet } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { @@ -455,21 +456,37 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, let substituted_pred = pred.subst(fcx.tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. - if substituted_pred.references_error() || param_count.params.len() > 1 - || has_region { - continue; + if { + substituted_pred.references_error() || param_count.params.len() > 1 + || has_region + } { + None + } else if predicates.predicates.contains(&substituted_pred) { + // Avoid duplication of predicates that contain no parameters, for example. + None + } else { + Some(substituted_pred) } - // Avoid duplication of predicates that contain no parameters, for example. - if !predicates.predicates.contains(&substituted_pred) { - substituted_predicates.push(substituted_pred); - } - } + }).map(|pred| { + // convert each of those into an obligation. So if you have + // something like `struct Foo`, we would + // take that predicate `T: Copy`, substitute to `String: Copy` + // (actually that happens in the previous `flat_map` call), + // and then try to prove it (in this case, we'll fail). + // + // Note the subtle difference from how we handle `predicates` + // below: there, we are not trying to prove those predicates + // to be *true* but merely *well-formed*. + let pred = fcx.normalize_associated_types_in(span, &pred); + let cause = traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def_id)); + traits::Obligation::new(cause, fcx.param_env, pred) + }); - predicates.predicates.extend(substituted_predicates); let predicates = predicates.instantiate_identity(fcx.tcx); let predicates = fcx.normalize_associated_types_in(span, &predicates); - let obligations = + debug!("check_where_clauses: predicates={:?}", predicates.predicates); + let wf_obligations = predicates.predicates .iter() .flat_map(|p| ty::wf::predicate_obligations(fcx, @@ -478,7 +495,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, p, span)); - for obligation in obligations { + for obligation in wf_obligations.chain(default_obligations) { + debug!("next obligation cause: {:?}", obligation.cause); fcx.register_predicate(obligation); } } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index aa124110243..f6d7086679a 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -30,7 +30,11 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa LL | struct Bounds(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | - = note: required by `std::marker::Copy` +note: required by `Bounds` + --> $DIR/type-check-defaults.rs:21:1 + | +LL | struct Bounds(T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:24:1 @@ -38,7 +42,11 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa LL | struct WhereClause(T) where T: Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | - = note: required by `std::marker::Copy` +note: required by `WhereClause` + --> $DIR/type-check-defaults.rs:24:1 + | +LL | struct WhereClause(T) where T: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:27:1 @@ -46,7 +54,11 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa LL | trait TraitBound {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | - = note: required by `std::marker::Copy` +note: required by `TraitBound` + --> $DIR/type-check-defaults.rs:27:1 + | +LL | trait TraitBound {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:31:1 @@ -68,7 +80,11 @@ LL | trait ProjectionPred> where T::Item : Add {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` | = help: the trait `std::ops::Add` is not implemented for `i32` - = note: required by `std::ops::Add` +note: required by `ProjectionPred` + --> $DIR/type-check-defaults.rs:34:1 + | +LL | trait ProjectionPred> where T::Item : Add {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors From c9d4f0615f20c5ba392c10c04d5c9e2ac57b9715 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 29 Jun 2018 06:59:00 -0400 Subject: [PATCH 2/5] use `ty::TraitRef::identity` where possible Co-authored-by: Tyler Mandry --- src/librustc/traits/object_safety.rs | 13 ++++--------- src/librustc/ty/sty.rs | 9 +++++++++ src/librustc_traits/lowering.rs | 6 +----- src/librustc_typeck/collect.rs | 12 ++++-------- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index fe2965146cb..83128ba75d5 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -23,7 +23,6 @@ use hir::def_id::DefId; use lint; use traits; use ty::{self, Ty, TyCtxt, TypeFoldable}; -use ty::subst::Substs; use ty::util::ExplicitSelf; use std::borrow::Cow; use syntax::ast; @@ -173,10 +172,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, supertraits_only: bool) -> bool { - let trait_ref = ty::Binder::dummy(ty::TraitRef { - def_id: trait_def_id, - substs: Substs::identity_for_item(self, trait_def_id) - }); + let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id)); let predicates = if supertraits_only { self.super_predicates_of(trait_def_id) } else { @@ -391,10 +387,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Compute supertraits of current trait lazily. if supertraits.is_none() { - let trait_ref = ty::Binder::bind(ty::TraitRef { - def_id: trait_def_id, - substs: Substs::identity_for_item(self, trait_def_id) - }); + let trait_ref = ty::Binder::bind( + ty::TraitRef::identity(self, trait_def_id), + ); supertraits = Some(traits::supertraits(self, trait_ref).collect()); } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 996ebd722fd..f93da53e043 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -614,6 +614,15 @@ impl<'tcx> TraitRef<'tcx> { TraitRef { def_id: def_id, substs: substs } } + /// Returns a TraitRef of the form `P0: Foo` where `Pi` + /// are the parameters defined on trait. + pub fn identity<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> TraitRef<'tcx> { + TraitRef { + def_id, + substs: Substs::identity_for_item(tcx, def_id), + } + } + pub fn self_ty(&self) -> Ty<'tcx> { self.substs.type_at(0) } diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 214376b2e53..5eb8c93b510 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -15,7 +15,6 @@ use rustc::hir::{self, ImplPolarity}; use rustc::traits::{Clause, Clauses, DomainGoal, Goal, PolyDomainGoal, ProgramClause, WhereClause, FromEnv, WellFormed}; use rustc::ty::query::Providers; -use rustc::ty::subst::Substs; use rustc::ty::{self, Slice, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use std::mem; @@ -225,10 +224,7 @@ fn program_clauses_for_trait<'a, 'tcx>( // `Self: Trait` let trait_pred = ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id, - substs: Substs::identity_for_item(tcx, def_id), - }, + trait_ref: ty::TraitRef::identity(tcx, def_id), }; // `Implemented(Self: Trait)` diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 852603ac51c..3c956d8b430 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -274,10 +274,9 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemTrait(_, _, ref generics, ..) => { // Implied `Self: Trait` and supertrait bounds. if param_id == item_node_id { - result.predicates.push(ty::TraitRef { - def_id: item_def_id, - substs: Substs::identity_for_item(tcx, item_def_id) - }.to_predicate()); + result.predicates.push( + ty::TraitRef::identity(tcx, item_def_id).to_predicate() + ); } generics } @@ -1359,10 +1358,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemUnion(_, ref generics) => generics, ItemTrait(_, _, ref generics, .., ref items) => { - is_trait = Some((ty::TraitRef { - def_id, - substs: Substs::identity_for_item(tcx, def_id) - }, items)); + is_trait = Some((ty::TraitRef::identity(tcx, def_id), items)); generics } ItemExistential(ref exist_ty) => { From 7bbbed9046d2c744e4b7717ad72ae38a1c24f38d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Jul 2018 10:33:18 -0400 Subject: [PATCH 3/5] drive-by nits and debug Co-authored-by: Tyler Mandry --- src/librustc/traits/select.rs | 5 +++++ src/librustc/ty/mod.rs | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index fe30b6a2f88..40171345f55 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1237,6 +1237,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let mut candidates: Vec = candidates?.into_iter().filter_map(|c| c).collect(); + debug!("winnowed to {} candidates for {:?}: {:?}", + candidates.len(), + stack, + candidates); + // If there are STILL multiple candidate, we can further // reduce the list by dropping duplicates -- including // resolving specializations. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1f647d811b0..ab6922cac70 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2862,8 +2862,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Compute the bounds on Self and the type parameters. - let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); - let predicates = bounds.predicates; + let InstantiatedPredicates { predicates } = + tcx.predicates_of(def_id).instantiate_identity(tcx); // Finally, we have to normalize the bounds in the environment, in // case they contain any associated type projections. This process From 327093007add511cdcca4032dda13f7a342f29ea Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Jul 2018 10:34:19 -0400 Subject: [PATCH 4/5] add `is_trait(DefId)` helper to `TyCtxt` Co-authored-by: Tyler Mandry --- src/librustc/ty/util.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 4e281231a41..f118d22c54d 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -518,10 +518,25 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { result } + /// True if `def_id` refers to a closure (e.g., `|x| x * 2`). Note + /// that closures have a def-id, but the closure *expression* also + /// has a `HirId` that is located within the context where the + /// closure appears (and, sadly, a corresponding `NodeId`, since + /// those are not yet phased out). The parent of the closure's + /// def-id will also be the context where it appears. pub fn is_closure(self, def_id: DefId) -> bool { self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr } + /// True if `def_id` refers to a trait (e.g., `trait Foo { ... }`). + pub fn is_trait(self, def_id: DefId) -> bool { + if let DefPathData::Trait(_) = self.def_key(def_id).disambiguated_data.data { + true + } else { + false + } + } + /// True if this def-id refers to the implicit constructor for /// a tuple struct like `struct Foo(u32)`. pub fn is_struct_constructor(self, def_id: DefId) -> bool { From 90ea49b891937eb7f121c1ded01ceacb66074e74 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Jul 2018 10:35:30 -0400 Subject: [PATCH 5/5] introduce `predicates_defined_on` for traits This new query returns only the predicates *directly defined* on an item (in contrast to the more common `predicates_of`, which returns the predicates that must be proven to reference an item). These two sets are almost always identical except for traits, where `predicates_of` includes an artificial `Self: Trait<...>` predicate (basically saying that you cannot use a trait item without proving that the trait is implemented for the type parameters). This new query is only used in chalk lowering, where this artificial `Self: Trait` predicate is problematic. We encode it in metadata but only where needed since it is kind of repetitive with existing information. Co-authored-by: Tyler Mandry --- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/ty/query/mod.rs | 33 +++++++++++++++--- src/librustc/ty/query/plumbing.rs | 1 + src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/decoder.rs | 7 ++++ src/librustc_metadata/encoder.rs | 27 +++++++++++++++ src/librustc_metadata/schema.rs | 2 ++ src/librustc_traits/lowering.rs | 6 ++-- src/librustc_typeck/collect.rs | 48 ++++++++++++++++++++------ src/test/ui/chalkify/lower_env1.stderr | 4 +-- 10 files changed, 109 insertions(+), 21 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 6cc61d74800..3c4472aef6b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -504,6 +504,7 @@ define_dep_nodes!( <'tcx> [] GenericsOfItem(DefId), [] PredicatesOfItem(DefId), [] ExplicitPredicatesOfItem(DefId), + [] PredicatesDefinedOnItem(DefId), [] InferredOutlivesOf(DefId), [] InferredOutlivesCrate(CrateNum), [] SuperPredicatesOfItem(DefId), diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 77644cdf02b..9ad93b4d5e2 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -101,11 +101,39 @@ define_queries! { <'tcx> [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its - /// associated generics and predicates. + /// associated generics. [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics, + + /// Maps from the def-id of an item (trait/struct/enum/fn) to the + /// predicates (where clauses) that must be proven true in order + /// to reference it. This is almost always the "predicates query" + /// that you want. + /// + /// `predicates_of` builds on `predicates_defined_on` -- in fact, + /// it is almost always the same as that query, except for the + /// case of traits. For traits, `predicates_of` contains + /// an additional `Self: Trait<...>` predicate that users don't + /// actually write. This reflects the fact that to invoke the + /// trait (e.g., via `Default::default`) you must supply types + /// that actually implement the trait. (However, this extra + /// predicate gets in the way of some checks, which are intended + /// to operate over only the actual where-clauses written by the + /// user.) [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + + /// Maps from the def-id of an item (trait/struct/enum/fn) to the + /// predicates (where clauses) directly defined on it. This is + /// equal to the `explicit_predicates_of` predicates plus the + /// `inferred_outlives_of` predicates. + [] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) -> ty::GenericPredicates<'tcx>, + + /// Returns the predicates written explicit by the user. [] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + /// Returns the inferred outlives predicates (e.g., for `struct + /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). + [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc>>, + /// Maps from the def-id of a trait to the list of /// super-predicates. This is a subset of the full list of /// predicates. We store these in a separate map because we must @@ -141,9 +169,6 @@ define_queries! { <'tcx> /// (inferred) variance. [] fn variances_of: ItemVariances(DefId) -> Lrc>, - /// Maps from def-id of a type to its (inferred) outlives. - [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc>>, - /// Maps from def-id of a type to its (inferred) outlives. [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum) -> Lrc>, diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index e17c6fba74c..874a62fb6a5 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1074,6 +1074,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TypeOfItem => { force!(type_of, def_id!()); } DepKind::GenericsOfItem => { force!(generics_of, def_id!()); } DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); } + DepKind::PredicatesDefinedOnItem => { force!(predicates_defined_on, def_id!()); } DepKind::ExplicitPredicatesOfItem => { force!(explicit_predicates_of, def_id!()); } DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); } DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d0e4e54e63d..14f63898a4f 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -107,6 +107,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess)) } predicates_of => { cdata.get_predicates(def_id.index, tcx) } + predicates_defined_on => { cdata.get_predicates_defined_on(def_id.index, tcx) } super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) } trait_def => { tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess)) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 1985900b3e1..d604ac819b8 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -563,6 +563,13 @@ impl<'a, 'tcx> CrateMetadata { self.entry(item_id).predicates.unwrap().decode((self, tcx)) } + pub fn get_predicates_defined_on(&self, + item_id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> ty::GenericPredicates<'tcx> { + self.entry(item_id).predicates_defined_on.unwrap().decode((self, tcx)) + } + pub fn get_super_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index d8a224d3bad..4c58eb8d5a0 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -627,6 +627,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), } @@ -664,6 +665,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { variances: LazySeq::empty(), generics: None, predicates: None, + predicates_defined_on: None, mir: None } @@ -704,6 +706,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { variances: LazySeq::empty(), generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, mir: None, } @@ -761,6 +764,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), } @@ -778,6 +782,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { self.lazy(&tcx.predicates_of(def_id)) } + fn encode_predicates_defined_on(&mut self, def_id: DefId) -> Lazy> { + debug!("IsolatedEncoder::encode_predicates_defined_on({:?})", def_id); + let tcx = self.tcx; + self.lazy(&tcx.predicates_defined_on(def_id)) + } + fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { debug!("IsolatedEncoder::encode_info_for_trait_item({:?})", def_id); let tcx = self.tcx; @@ -867,6 +877,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), } @@ -963,6 +974,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, mir: if mir { self.encode_optimized_mir(def_id) } else { None }, } @@ -1226,6 +1238,16 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { _ => None, }, + // The only time that `predicates_defined_on` is used (on + // an external item) is for traits, during chalk lowering, + // so only encode it in that case as an efficiency + // hack. (No reason not to expand it in the future if + // necessary.) + predicates_defined_on: match item.node { + hir::ItemTrait(..) => Some(self.encode_predicates_defined_on(def_id)), + _ => None, // not *wrong* for other kinds of items, but not needed + }, + mir: match item.node { hir::ItemStatic(..) => { self.encode_optimized_mir(def_id) @@ -1276,6 +1298,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { variances: LazySeq::empty(), generics: None, predicates: None, + predicates_defined_on: None, mir: None, } } @@ -1303,6 +1326,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { variances: LazySeq::empty(), generics: None, predicates: None, + predicates_defined_on: None, mir: None, } @@ -1347,6 +1371,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { variances: LazySeq::empty(), generics: Some(self.encode_generics(def_id)), predicates: None, + predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), } @@ -1374,6 +1399,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { variances: LazySeq::empty(), generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), } @@ -1575,6 +1601,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, mir: None, } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 21d6d15457a..a0b21e63ac5 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -273,6 +273,7 @@ pub struct Entry<'tcx> { pub variances: LazySeq, pub generics: Option>, pub predicates: Option>>, + pub predicates_defined_on: Option>>, pub mir: Option>>, } @@ -290,6 +291,7 @@ impl_stable_hash_for!(struct Entry<'tcx> { variances, generics, predicates, + predicates_defined_on, mir }); diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 5eb8c93b510..27daebbf8c1 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -252,10 +252,8 @@ fn program_clauses_for_trait<'a, 'tcx>( // ``` // `FromEnv(WC) :- FromEnv(Self: Trait)`, for each where clause WC - // FIXME: Remove the [1..] slice; this is a hack because the query - // predicates_of currently includes the trait itself (`Self: Trait`). - let where_clauses = &tcx.predicates_of(def_id).predicates; - let implied_bound_clauses = where_clauses[1..] + let where_clauses = &tcx.predicates_defined_on(def_id).predicates; + let implied_bound_clauses = where_clauses .into_iter() .map(|wc| wc.lower()) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 3c956d8b430..4e645c5433b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -67,6 +67,7 @@ pub fn provide(providers: &mut Providers) { type_of, generics_of, predicates_of, + predicates_defined_on, explicit_predicates_of, super_predicates_of, type_param_predicates, @@ -1309,10 +1310,10 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>( }) } -fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> ty::GenericPredicates<'tcx> { - let explicit = explicit_predicates_of(tcx, def_id); +fn predicates_defined_on<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> ty::GenericPredicates<'tcx> { + let explicit = tcx.explicit_predicates_of(def_id); let predicates = if tcx.sess.features_untracked().infer_outlives_requirements { [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat() } else { explicit.predicates }; @@ -1323,9 +1324,35 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::GenericPredicates<'tcx> { + let ty::GenericPredicates { parent, mut predicates } = + tcx.predicates_defined_on(def_id); + + if tcx.is_trait(def_id) { + // For traits, add `Self: Trait` predicate. This is + // not part of the predicates that a user writes, but it + // is something that one must prove in order to invoke a + // method or project an associated type. + // + // In the chalk setup, this predicate is not part of the + // "predicates" for a trait item. But it is useful in + // rustc because if you directly (e.g.) invoke a trait + // method like `Trait::method(...)`, you must naturally + // prove that the trait applies to the types that were + // used, and adding the predicate into this list ensures + // that this is done. + predicates.push(ty::TraitRef::identity(tcx, def_id).to_predicate()); + } + + ty::GenericPredicates { parent, predicates } +} + +fn explicit_predicates_of<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, +) -> ty::GenericPredicates<'tcx> { use rustc::hir::map::*; use rustc::hir::*; @@ -1340,7 +1367,10 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); let ast_generics = match node { - NodeTraitItem(item) => &item.generics, + NodeTraitItem(item) => { + &item.generics + } + NodeImplItem(item) => &item.generics, NodeItem(item) => { @@ -1405,12 +1435,8 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // and the explicit where-clauses, but to get the full set of predicates // on a trait we need to add in the supertrait bounds and bounds found on // associated types. - if let Some((trait_ref, _)) = is_trait { + if let Some((_trait_ref, _)) = is_trait { predicates = tcx.super_predicates_of(def_id).predicates; - - // Add in a predicate that `Self:Trait` (where `Trait` is the - // current trait). This is needed for builtin bounds. - predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); } // In default impls, we can assume that the self type implements diff --git a/src/test/ui/chalkify/lower_env1.stderr b/src/test/ui/chalkify/lower_env1.stderr index 3a280f85e76..812418a3053 100644 --- a/src/test/ui/chalkify/lower_env1.stderr +++ b/src/test/ui/chalkify/lower_env1.stderr @@ -4,7 +4,7 @@ error: program clause dump LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar). + = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar). = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar). = note: Implemented(Self: Bar) :- FromEnv(Self: Bar). @@ -14,7 +14,7 @@ error: program clause dump 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: FromEnv(Self: Foo) :- FromEnv(Self: Bar). = note: Implemented(Self: Bar) :- FromEnv(Self: Bar). = note: Implemented(Self: Foo) :- FromEnv(Self: Foo).