From b9144185ca618b0eafff9fbe731c7bad35b803e7 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 16 Apr 2018 14:01:49 -0500 Subject: [PATCH 01/11] WIP: Remove Self:Trait from predicates_of --- src/librustc/infer/mod.rs | 14 ++++++--- src/librustc/traits/select.rs | 3 -- src/librustc/ty/mod.rs | 18 ++++++++++- src/librustc_typeck/check/compare_method.rs | 1 - src/librustc_typeck/collect.rs | 35 +++++++++++++++++++-- 5 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 40cc43c3ca670..eeea274c5cade 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -750,13 +750,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> UnitResult<'tcx> where T: at::ToTrace<'tcx> { + debug!("can_sub({:?}, {:?})", a, b); let origin = &ObligationCause::dummy(); - self.probe(|_| { + let result = self.probe(|_| { self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| { // Ignore obligations, since we are unrolling // everything anyway. }) - }) + }); + debug!("can_sub({:?}, {:?}) returning {:?}", a, b, result); + result } pub fn can_eq(&self, @@ -766,13 +769,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> UnitResult<'tcx> where T: at::ToTrace<'tcx> { + debug!("can_eq({:?}, {:?})", a, b); let origin = &ObligationCause::dummy(); - self.probe(|_| { + let result = self.probe(|_| { self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| { // Ignore obligations, since we are unrolling // everything anyway. }) - }) + }); + debug!("can_eq({:?}, {:?}) returning {:?}", a, b, result); + result } pub fn sub_regions(&self, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f43f5cf3e3ff4..39279630c17b5 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1934,9 +1934,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // attempt to evaluate recursive bounds to see if they are // satisfied. - /// Returns true if `candidate_i` should be dropped in favor of - /// `candidate_j`. Generally speaking we will drop duplicate - /// candidates and prefer where-clause candidates. /// Returns true if `victim` should be dropped in favor of /// `other`. Generally speaking we will drop duplicate /// candidates and prefer where-clause candidates. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index de04366841076..18f266417d732 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2718,7 +2718,7 @@ 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 mut predicates = bounds.predicates; // Finally, we have to normalize the bounds in the environment, in // case they contain any associated type projections. This process @@ -2732,6 +2732,22 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + debug!("param_env: handling def_id={:?}, id={:?}", def_id, id); + + if let Some(hir::map::NodeItem(item)) = tcx.hir.find(id) { + debug!(" param_env: self node: {:?}", item.node); + if let hir::ItemTrait(..) = item.node { + debug!(" param_env: self is trait!"); + let trait_ref = ty::TraitRef { + def_id: def_id, + substs: Substs::identity_for_item(tcx, def_id) + }; + predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + } + } + debug!(" param_env predicates: {:?}", predicates); + let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index c9e53fa7674d4..f8872372c35a9 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -30,7 +30,6 @@ use super::{Inherited, FnCtxt}; /// - impl_m_span: span to use for reporting errors /// - trait_m: the method in the trait /// - impl_trait_ref: the TraitRef corresponding to the trait implementation - pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_m: &ty::AssociatedItem, impl_m_span: Span, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2ebbd64cab90e..345f46eeda56c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1321,12 +1321,17 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node = tcx.hir.get(node_id); let mut is_trait = None; + let mut is_trait_item = None; let mut is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); let ast_generics = match node { - NodeTraitItem(item) => &item.generics, + NodeTraitItem(item) => { + is_trait_item = Some(()); + &item.generics + } + NodeImplItem(item) => &item.generics, NodeItem(item) => { @@ -1401,13 +1406,37 @@ 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()); + //predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + } + + if let Some(()) = is_trait_item { + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + debug!("explicit_predicates_of: handling def_id={:?}, id={:?}", def_id, id); + + let parent_id = tcx.hir.get_parent(id); + let parent_def_id = tcx.hir.local_def_id(parent_id); + if let Some(hir::map::NodeItem(parent_item)) = tcx.hir.find(parent_id) { + debug!(" explicit_predicates_of: has parent, node: {:?}", parent_item.node); + if let hir::ItemTrait(..) = parent_item.node { + debug!(" explicit_predicates_of: parent is trait!"); + let trait_ref = ty::TraitRef { + def_id: parent_def_id, + substs: Substs::identity_for_item(tcx, parent_def_id) + }; + predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + } else { + debug!(" explicit_predicates_of: parent is not trait :(("); + } + } else { + debug!(" explicit_predicates_of: no parent :("); + } } + debug!("explicit_predicates_of: predicates={:?}", predicates); // In default impls, we can assume that the self type implements // the trait. So in: From 75884d4f90fd8d1be15dda027149e5252915abf4 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 20 Apr 2018 18:47:21 -0500 Subject: [PATCH 02/11] Filter out trait predicate in compare_predicate_entailment --- src/librustc/traits/select.rs | 17 +++++++++++++++++ src/librustc_typeck/check/compare_method.rs | 19 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 39279630c17b5..601e6622b187b 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1164,11 +1164,28 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } }).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. if candidates.len() > 1 { let mut i = 0; + //candidates.retain(|c| { + // match c.candidate { + // ParamCandidate(poly_trait_ref) => { + // if poly_trait_ref == stack.obligation.predicate.map_bound(|x| x.trait_ref) { + // debug!("Dropping candidate (== obligation): {:?}", c); + // return false; + // } + // } + // _ => {} + // } + // true + //}); while i < candidates.len() { let is_dup = (0..candidates.len()) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index f8872372c35a9..716e5f2eed6db 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -181,7 +181,22 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl_m_generics = tcx.generics_of(impl_m.def_id); let trait_m_generics = tcx.generics_of(trait_m.def_id); let impl_m_predicates = tcx.predicates_of(impl_m.def_id); - let trait_m_predicates = tcx.predicates_of(trait_m.def_id); + let mut trait_m_predicates = tcx.predicates_of(trait_m.def_id); + + if let Some(trait_def_id) = trait_m_predicates.parent { + trait_m_predicates.predicates.retain(|pred| { + match pred { + ty::Predicate::Trait(trait_ref) => { + if trait_ref.def_id() == trait_def_id { + false + } else { + true + } + } + _ => true + } + }); + } // Check region bounds. check_region_bounds_on_impl_method(tcx, @@ -212,6 +227,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hybrid_preds.predicates .extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); + debug!("compare_impl_method: impl_bounds+trait_bounds={:?}", hybrid_preds); + // Construct trait parameter environment and then shift it into the skolemized viewpoint. // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. From 32a0a76123f7f0ec8c2497d8c6a12ee7fe9e1d56 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 23 Apr 2018 11:43:10 -0500 Subject: [PATCH 03/11] Fix panic, tidy error --- src/librustc/traits/select.rs | 12 ------------ src/librustc/ty/mod.rs | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 601e6622b187b..17d3acc0f2030 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1174,18 +1174,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // resolving specializations. if candidates.len() > 1 { let mut i = 0; - //candidates.retain(|c| { - // match c.candidate { - // ParamCandidate(poly_trait_ref) => { - // if poly_trait_ref == stack.obligation.predicate.map_bound(|x| x.trait_ref) { - // debug!("Dropping candidate (== obligation): {:?}", c); - // return false; - // } - // } - // _ => {} - // } - // true - //}); while i < candidates.len() { let is_dup = (0..candidates.len()) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 18f266417d732..f9419abe84f93 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2732,21 +2732,21 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - debug!("param_env: handling def_id={:?}, id={:?}", def_id, id); - - if let Some(hir::map::NodeItem(item)) = tcx.hir.find(id) { - debug!(" param_env: self node: {:?}", item.node); - if let hir::ItemTrait(..) = item.node { - debug!(" param_env: self is trait!"); - let trait_ref = ty::TraitRef { - def_id: def_id, - substs: Substs::identity_for_item(tcx, def_id) - }; - predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + if let Some(id) = tcx.hir.as_local_node_id(def_id) { + debug!("param_env: handling def_id={:?}, id={:?}", def_id, id); + if let Some(hir::map::NodeItem(item)) = tcx.hir.find(id) { + debug!(" param_env: self node: {:?}", item.node); + if let hir::ItemTrait(..) = item.node { + debug!(" param_env: self is trait!"); + let trait_ref = ty::TraitRef { + def_id: def_id, + substs: Substs::identity_for_item(tcx, def_id) + }; + predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + } } + debug!(" param_env predicates: {:?}", predicates); } - debug!(" param_env predicates: {:?}", predicates); let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing); From defc7e9758376d6a9b85ffc6969efff8c95ec946 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 23 Apr 2018 11:50:12 -0500 Subject: [PATCH 04/11] Remove slice hack from lowering module Fixes #49953. --- src/librustc_traits/lowering.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index b6a086f609d04..f30f0b10cdf68 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -234,10 +234,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 implied_bound_clauses = where_clauses .into_iter() .map(|wc| implied_bound_from_trait(tcx, trait_pred, wc)); From f52d4de063d281106ed86347a73bf07c4a9b3a36 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 27 Apr 2018 15:18:13 -0500 Subject: [PATCH 05/11] Update chalkify test --- src/test/ui/chalkify/lower_env1.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/chalkify/lower_env1.stderr b/src/test/ui/chalkify/lower_env1.stderr index 3a280f85e7694..812418a3053e9 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). From edeb9c4a2f1f70e753f3cb80d51592c173fb6226 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 27 Apr 2018 15:18:39 -0500 Subject: [PATCH 06/11] ty::wf: Add `Self: Trait` predicate back in --- src/librustc/ty/wf.rs | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index aea84791fe86b..4525911420a68 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -13,7 +13,7 @@ use middle::const_val::ConstVal; use infer::InferCtxt; use ty::subst::Substs; use traits; -use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; use std::iter::once; use syntax::ast; use syntax_pos::Span; @@ -170,10 +170,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// Pushes the obligations required for `trait_ref` to be WF into /// `self.out`. fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { - let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); + let param_env = self.param_env; + + let obligations = self.nominal_trait_obligations(trait_ref); let cause = self.cause(traits::MiscObligation); - let param_env = self.param_env; if let Elaborate::All = elaborate { let predicates = obligations.iter() @@ -449,6 +450,37 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { .collect() } + fn nominal_trait_obligations(&mut self, + trait_ref: &ty::TraitRef<'tcx>) + -> Vec> + { + let mut predicates = self.infcx.tcx.predicates_of(trait_ref.def_id); + + // Add in a predicate that `Self:Trait` (where `Trait` is the + // current trait). + // trait_ref can probably be added in as a predicate directly after + // instantiation, rather than erasing the substituted type and then + // re-instantiating this bound. + let identity_trait_ref = ty::TraitRef { + def_id: trait_ref.def_id, + substs: Substs::identity_for_item(self.infcx.tcx, trait_ref.def_id) + }; + predicates.predicates.push(identity_trait_ref.to_poly_trait_ref().to_predicate()); + + debug!("nominal_trait_obligations: trait_ref={:?} predicates={:?}", + trait_ref, predicates.predicates); + + let cause = self.cause(traits::ItemObligation(trait_ref.def_id)); + predicates.instantiate(self.infcx.tcx, trait_ref.substs) + .predicates + .into_iter() + .map(|pred| traits::Obligation::new(cause.clone(), + self.param_env, + pred)) + .filter(|pred| !pred.has_escaping_regions()) + .collect() + } + fn from_object_ty(&mut self, ty: Ty<'tcx>, data: ty::Binder<&'tcx ty::Slice>>, region: ty::Region<'tcx>) { From 0faf7fb3f96f6273d9e19c34c8d6f8798d8455d4 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 1 May 2018 14:21:23 -0600 Subject: [PATCH 07/11] compare_impl_method: Make trait predicate filter specific to Self --- src/librustc_typeck/check/compare_method.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 716e5f2eed6db..6ef8a1830c69f 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -188,10 +188,17 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match pred { ty::Predicate::Trait(trait_ref) => { if trait_ref.def_id() == trait_def_id { - false - } else { - true + use ty::TypeVariants::TyParam; + if let TyParam(param) = trait_ref.skip_binder().self_ty().sty { + if param.is_self() { + debug!( + "compare_impl_method: removing `{:?}` from trait_m_predicates", + pred); + return false; + } + } } + true } _ => true } From 9374cd26de4131d7bff103a81e304767a9b63366 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 1 May 2018 20:09:26 -0500 Subject: [PATCH 08/11] compute_trait_ref: Restore original order of predicates This can matter for obligation causes that get reported as errors, when there are more than one of the same obligation in the forest. --- src/librustc/ty/wf.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 4525911420a68..dbd5cdda4d5e9 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -465,7 +465,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { def_id: trait_ref.def_id, substs: Substs::identity_for_item(self.infcx.tcx, trait_ref.def_id) }; - predicates.predicates.push(identity_trait_ref.to_poly_trait_ref().to_predicate()); + predicates.predicates.insert(0, identity_trait_ref.to_poly_trait_ref().to_predicate()); debug!("nominal_trait_obligations: trait_ref={:?} predicates={:?}", trait_ref, predicates.predicates); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9c4807bec2f08..f874090ceb92a 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -447,6 +447,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, let predicates = predicates.instantiate_identity(fcx.tcx); let predicates = fcx.normalize_associated_types_in(span, &predicates); + debug!("check_where_clauses: predicates={:?}", predicates.predicates); let obligations = predicates.predicates .iter() @@ -457,6 +458,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, span)); for obligation in obligations { + debug!("next obligation cause: {:?}", obligation.cause); fcx.register_predicate(obligation); } } From 4a98f866d292283e30b56f0e5b62ef0d38fef03c Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 1 May 2018 21:08:26 -0500 Subject: [PATCH 09/11] compute_trait_ref: Optimize Self:Trait predicate --- src/librustc/ty/wf.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index dbd5cdda4d5e9..f0a70013986f9 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -454,26 +454,22 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { trait_ref: &ty::TraitRef<'tcx>) -> Vec> { - let mut predicates = self.infcx.tcx.predicates_of(trait_ref.def_id); - // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). - // trait_ref can probably be added in as a predicate directly after - // instantiation, rather than erasing the substituted type and then - // re-instantiating this bound. - let identity_trait_ref = ty::TraitRef { - def_id: trait_ref.def_id, - substs: Substs::identity_for_item(self.infcx.tcx, trait_ref.def_id) + let self_trait = if !trait_ref.has_escaping_regions() { + Some(trait_ref.to_poly_trait_ref().to_predicate()) + } else { + None }; - predicates.predicates.insert(0, identity_trait_ref.to_poly_trait_ref().to_predicate()); - debug!("nominal_trait_obligations: trait_ref={:?} predicates={:?}", - trait_ref, predicates.predicates); + let predicates = self.infcx.tcx.predicates_of(trait_ref.def_id) + .instantiate(self.infcx.tcx, trait_ref.substs) + .predicates; let cause = self.cause(traits::ItemObligation(trait_ref.def_id)); - predicates.instantiate(self.infcx.tcx, trait_ref.substs) - .predicates - .into_iter() + + self_trait.into_iter() + .chain(predicates.into_iter()) .map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred)) From 1d888a4cae71416f0d4e0a8cbf79cb10527ab4b6 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 1 May 2018 23:03:43 -0500 Subject: [PATCH 10/11] Clean up `Self: Trait` predicate code --- src/librustc/infer/mod.rs | 14 +++----- src/librustc/ty/mod.rs | 34 ++++++++++-------- src/librustc/ty/sty.rs | 8 +++++ src/librustc/ty/wf.rs | 4 +-- src/librustc_typeck/check/compare_method.rs | 2 ++ src/librustc_typeck/collect.rs | 40 ++++++--------------- 6 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index eeea274c5cade..40cc43c3ca670 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -750,16 +750,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> UnitResult<'tcx> where T: at::ToTrace<'tcx> { - debug!("can_sub({:?}, {:?})", a, b); let origin = &ObligationCause::dummy(); - let result = self.probe(|_| { + self.probe(|_| { self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| { // Ignore obligations, since we are unrolling // everything anyway. }) - }); - debug!("can_sub({:?}, {:?}) returning {:?}", a, b, result); - result + }) } pub fn can_eq(&self, @@ -769,16 +766,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> UnitResult<'tcx> where T: at::ToTrace<'tcx> { - debug!("can_eq({:?}, {:?})", a, b); let origin = &ObligationCause::dummy(); - let result = self.probe(|_| { + self.probe(|_| { self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| { // Ignore obligations, since we are unrolling // everything anyway. }) - }); - debug!("can_eq({:?}, {:?}) returning {:?}", a, b, result); - result + }) } pub fn sub_regions(&self, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f9419abe84f93..e23826ee992a1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2732,20 +2732,9 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. - if let Some(id) = tcx.hir.as_local_node_id(def_id) { - debug!("param_env: handling def_id={:?}, id={:?}", def_id, id); - if let Some(hir::map::NodeItem(item)) = tcx.hir.find(id) { - debug!(" param_env: self node: {:?}", item.node); - if let hir::ItemTrait(..) = item.node { - debug!(" param_env: self is trait!"); - let trait_ref = ty::TraitRef { - def_id: def_id, - substs: Substs::identity_for_item(tcx, def_id) - }; - predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); - } - } - debug!(" param_env predicates: {:?}", predicates); + if is_trait(tcx, def_id) { + // Add `Self: Trait` into the ParamEnv. + predicates.push(ty::TraitRef::identity(tcx, def_id).to_predicate()); } let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), @@ -2758,6 +2747,23 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) } +pub fn is_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { + if let Some(id) = tcx.hir.as_local_node_id(def_id) { + is_trait_node(tcx, id) + } else { + false + } +} + +pub fn is_trait_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> bool { + if let Some(hir::map::NodeItem(item)) = tcx.hir.find(id) { + if let hir::ItemTrait(..) = item.node { + return true; + } + } + false +} + fn crate_disambiguator<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> CrateDisambiguator { assert_eq!(crate_num, LOCAL_CRATE); diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0dfae13cc753a..8c43c411548bb 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -550,6 +550,14 @@ impl<'tcx> TraitRef<'tcx> { TraitRef { def_id: def_id, substs: substs } } + /// Returns a TraitRef of the form `Self: Foo`. + 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/ty/wf.rs b/src/librustc/ty/wf.rs index f0a70013986f9..e01d791676979 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -13,7 +13,7 @@ use middle::const_val::ConstVal; use infer::InferCtxt; use ty::subst::Substs; use traits; -use ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use std::iter::once; use syntax::ast; use syntax_pos::Span; @@ -457,7 +457,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). let self_trait = if !trait_ref.has_escaping_regions() { - Some(trait_ref.to_poly_trait_ref().to_predicate()) + Some(trait_ref.to_predicate()) } else { None }; diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 6ef8a1830c69f..b97edea7822ed 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -183,6 +183,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl_m_predicates = tcx.predicates_of(impl_m.def_id); let mut trait_m_predicates = tcx.predicates_of(trait_m.def_id); + // A `Self: Trait` predicate on trait items breaks selection, so filter it out. + // FIXME: This is a big hack! if let Some(trait_def_id) = trait_m_predicates.parent { trait_m_predicates.predicates.retain(|pred| { match pred { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 345f46eeda56c..c8fb97927f2cc 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1321,14 +1321,14 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node = tcx.hir.get(node_id); let mut is_trait = None; - let mut is_trait_item = None; + let mut is_trait_item = false; let mut is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); let ast_generics = match node { NodeTraitItem(item) => { - is_trait_item = Some(()); + is_trait_item = true; &item.generics } @@ -1408,36 +1408,8 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // associated types. 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()); } - if let Some(()) = is_trait_item { - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - debug!("explicit_predicates_of: handling def_id={:?}, id={:?}", def_id, id); - - let parent_id = tcx.hir.get_parent(id); - let parent_def_id = tcx.hir.local_def_id(parent_id); - if let Some(hir::map::NodeItem(parent_item)) = tcx.hir.find(parent_id) { - debug!(" explicit_predicates_of: has parent, node: {:?}", parent_item.node); - if let hir::ItemTrait(..) = parent_item.node { - debug!(" explicit_predicates_of: parent is trait!"); - let trait_ref = ty::TraitRef { - def_id: parent_def_id, - substs: Substs::identity_for_item(tcx, parent_def_id) - }; - predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); - } else { - debug!(" explicit_predicates_of: parent is not trait :(("); - } - } else { - debug!(" explicit_predicates_of: no parent :("); - } - } - debug!("explicit_predicates_of: predicates={:?}", predicates); - // In default impls, we can assume that the self type implements // the trait. So in: // @@ -1450,6 +1422,14 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); } + // For trait items, add `Self: Trait` predicate. + if is_trait_item { + let parent_id = tcx.hir.get_parent(node_id); + let parent_def_id = tcx.hir.local_def_id(parent_id); + debug_assert!(ty::is_trait_node(tcx, parent_id)); + predicates.push(ty::TraitRef::identity(tcx, parent_def_id).to_predicate()); + } + // Collect the region predicates that were declared inline as // well. In the case of parameters declared on a fn or method, we // have to be careful to only iterate over early-bound regions. From 671ede207df9ea440644a4497ed73d921738c43f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 4 Jun 2018 09:30:00 -0500 Subject: [PATCH 11/11] Fix DefId handling in ty::is_trait --- src/librustc/ty/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e23826ee992a1..954625536ea9d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2748,10 +2748,9 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn is_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - if let Some(id) = tcx.hir.as_local_node_id(def_id) { - is_trait_node(tcx, id) - } else { - false + match tcx.def_key(def_id).disambiguated_data.data { + DefPathData::Trait(_) => true, + _ => false, } }