diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f43f5cf3e3ff4..17d3acc0f2030 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1164,6 +1164,11 @@ 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. @@ -1934,9 +1939,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..954625536ea9d 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,11 @@ 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 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), traits::Reveal::UserFacing); @@ -2742,6 +2747,22 @@ 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 { + match tcx.def_key(def_id).disambiguated_data.data { + DefPathData::Trait(_) => true, + _ => 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 aea84791fe86b..e01d791676979 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -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,33 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { .collect() } + fn nominal_trait_obligations(&mut self, + trait_ref: &ty::TraitRef<'tcx>) + -> Vec> + { + // 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_predicate()) + } else { + None + }; + + 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)); + + self_trait.into_iter() + .chain(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>) { 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)); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index c9e53fa7674d4..b97edea7822ed 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, @@ -182,7 +181,31 @@ 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); + + // 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 { + ty::Predicate::Trait(trait_ref) => { + if trait_ref.def_id() == trait_def_id { + 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 + } + }); + } // Check region bounds. check_region_bounds_on_impl_method(tcx, @@ -213,6 +236,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. 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); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2ebbd64cab90e..c8fb97927f2cc 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 = 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) => &item.generics, + NodeTraitItem(item) => { + is_trait_item = true; + &item.generics + } + NodeImplItem(item) => &item.generics, NodeItem(item) => { @@ -1401,12 +1406,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 @@ -1421,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. 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).