From 24dcf6f7a29d7577a3c3448046d2d48b2fee59de Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 3 Nov 2020 17:07:18 -0300 Subject: [PATCH 01/28] Allow to use super trait bounds in where clauses --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/query/keys.rs | 13 +- compiler/rustc_typeck/src/astconv/mod.rs | 19 ++- .../rustc_typeck/src/check/fn_ctxt/mod.rs | 28 ++++- compiler/rustc_typeck/src/collect.rs | 113 ++++++++++++++++-- .../super-trait-referencing.rs | 15 +++ 6 files changed, 167 insertions(+), 23 deletions(-) create mode 100644 src/test/ui/associated-type-bounds/super-trait-referencing.rs diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7822ecc2c1f76..ed032220b54a2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -438,7 +438,7 @@ rustc_queries! { /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> { + query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the bounds for type parameter `{}`", { let id = tcx.hir().local_def_id_to_hir_id(key.1); tcx.hir().ty_param_name(id) diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index a005990264cf1..339a068205c8e 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -7,7 +7,7 @@ use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_query_system::query::DefaultCacheSelector; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; /// The `Key` trait controls what types can legally be used as the key @@ -149,6 +149,17 @@ impl Key for (LocalDefId, DefId) { } } +impl Key for (DefId, LocalDefId, Ident) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.1.default_span(tcx) + } +} + impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2f64597a510f0..e891ea3403f47 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -49,9 +49,10 @@ pub trait AstConv<'tcx> { fn default_constness_for_trait_bounds(&self) -> Constness; - /// Returns predicates in scope of the form `X: Foo`, where `X` is - /// a type parameter `X` with the given id `def_id`. This is a - /// subset of the full set of predicates. + /// Returns predicates in scope of the form `X: Foo`, where `X` + /// is a type parameter `X` with the given id `def_id` and T + /// matches assoc_name. This is a subset of the full set of + /// predicates. /// /// This is used for one specific purpose: resolving "short-hand" /// associated type references like `T::Item`. In principle, we @@ -60,7 +61,12 @@ pub trait AstConv<'tcx> { /// but this can lead to cycle errors. The problem is that we have /// to do this resolution *in order to create the predicates in /// the first place*. Hence, we have this "special pass". - fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>; + fn get_type_parameter_bounds( + &self, + span: Span, + def_id: DefId, + assoc_name: Ident, + ) -> ty::GenericPredicates<'tcx>; /// Returns the lifetime to use when a lifetime is omitted (and not elided). fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) @@ -1361,8 +1367,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty_param_def_id, assoc_name, span, ); - let predicates = - &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates; + let predicates = &self + .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name) + .predicates; debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index f635e0b6f931c..96ebb781f0bcd 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::Session; +use rustc_span::symbol::Ident; use rustc_span::{self, Span}; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; @@ -183,7 +184,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } - fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + fn get_type_parameter_bounds( + &self, + _: Span, + def_id: DefId, + assoc_name: Ident, + ) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let item_id = tcx.hir().ty_param_owner(hir_id); @@ -196,9 +202,23 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.param_env.caller_bounds().iter().filter_map(|predicate| { match predicate.skip_binders() { ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); - Some((predicate, span)) + let trait_did = data.def_id(); + if tcx + .associated_items(trait_did) + .find_by_name_and_kind( + tcx, + assoc_name, + ty::AssocKind::Type, + trait_did, + ) + .is_some() + { + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); + Some((predicate, span)) + } else { + None + } } _ => None, } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index dee0e6c2ebbef..756147ca54c2c 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -310,8 +310,17 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } } - fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { - self.tcx.at(span).type_param_predicates((self.item_def_id, def_id.expect_local())) + fn get_type_parameter_bounds( + &self, + span: Span, + def_id: DefId, + assoc_name: Ident, + ) -> ty::GenericPredicates<'tcx> { + self.tcx.at(span).type_param_predicates(( + self.item_def_id, + def_id.expect_local(), + assoc_name, + )) } fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option> { @@ -492,7 +501,7 @@ fn get_new_lifetime_name<'tcx>( /// `X: Foo` where `X` is the type parameter `def_id`. fn type_param_predicates( tcx: TyCtxt<'_>, - (item_def_id, def_id): (DefId, LocalDefId), + (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; @@ -517,7 +526,7 @@ fn type_param_predicates( let mut result = parent .map(|parent| { let icx = ItemCtxt::new(tcx, parent); - icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id()) + icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name) }) .unwrap_or_default(); let mut extend = None; @@ -560,12 +569,18 @@ fn type_param_predicates( let icx = ItemCtxt::new(tcx, item_def_id); let extra_predicates = extend.into_iter().chain( - icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true)) - .into_iter() - .filter(|(predicate, _)| match predicate.skip_binders() { - ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index), - _ => false, - }), + icx.type_parameter_bounds_in_generics( + ast_generics, + param_id, + ty, + OnlySelfBounds(true), + Some(assoc_name), + ) + .into_iter() + .filter(|(predicate, _)| match predicate.skip_binders() { + ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index), + _ => false, + }), ); result.predicates = tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates)); @@ -583,6 +598,7 @@ impl ItemCtxt<'tcx> { param_id: hir::HirId, ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, + assoc_name: Option, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let constness = self.default_constness_for_trait_bounds(); let from_ty_params = ast_generics @@ -593,6 +609,10 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bounds| bounds.iter()) + .filter(|b| match assoc_name { + Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), + None => true, + }) .flat_map(|b| predicates_from_bound(self, ty, b, constness)); let from_where_clauses = ast_generics @@ -611,12 +631,43 @@ impl ItemCtxt<'tcx> { } else { None }; - bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) + bp.bounds + .iter() + .filter(|b| match assoc_name { + Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), + None => true, + }) + .filter_map(move |b| bt.map(|bt| (bt, b))) }) .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness)); from_ty_params.chain(from_where_clauses).collect() } + + fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { + debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name); + + match b { + hir::GenericBound::Trait(poly_trait_ref, _) => { + let trait_ref = &poly_trait_ref.trait_ref; + let trait_did = trait_ref.trait_def_id().unwrap(); + let traits_did = super_traits_of(self.tcx, trait_did); + + traits_did.iter().any(|trait_did| { + self.tcx + .associated_items(*trait_did) + .find_by_name_and_kind( + self.tcx, + assoc_name, + ty::AssocKind::Type, + *trait_did, + ) + .is_some() + }) + } + _ => false, + } + } } /// Tests whether this is the AST for a reference to the type @@ -1017,6 +1068,7 @@ fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredi item.hir_id, self_param_ty, OnlySelfBounds(!is_trait_alias), + None, ); // Combine the two lists to form the complete set of superbounds: @@ -1034,6 +1086,45 @@ fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredi ty::GenericPredicates { parent: None, predicates: superbounds } } +pub fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> impl Iterator { + let mut set = FxHashSet::default(); + let mut stack = vec![trait_def_id]; + while let Some(trait_did) = stack.pop() { + if !set.insert(trait_did) { + continue; + } + + if trait_did.is_local() { + let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_did.expect_local()); + + let item = match tcx.hir().get(trait_hir_id) { + Node::Item(item) => item, + _ => bug!("super_trait_of {} is not an item", trait_hir_id), + }; + + let supertraits = match item.kind { + hir::ItemKind::Trait(.., ref supertraits, _) => supertraits, + hir::ItemKind::TraitAlias(_, ref supertraits) => supertraits, + _ => span_bug!(item.span, "super_trait_of invoked on non-trait"), + }; + + for supertrait in supertraits.iter() { + let trait_ref = supertrait.trait_ref(); + if let Some(trait_did) = trait_ref.and_then(|trait_ref| trait_ref.trait_def_id()) { + stack.push(trait_did); + } + } + } else { + let generic_predicates = tcx.super_predicates_of(trait_did); + for (predicate, _) in generic_predicates.predicates { + if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { + stack.push(data.def_id()); + } + } + } + } +} + fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let item = tcx.hir().expect_item(hir_id); diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing.rs b/src/test/ui/associated-type-bounds/super-trait-referencing.rs new file mode 100644 index 0000000000000..fde6b91e6c4e2 --- /dev/null +++ b/src/test/ui/associated-type-bounds/super-trait-referencing.rs @@ -0,0 +1,15 @@ +// check-pass +trait Foo { + type Item; +} + +trait Bar {} + +fn baz() +where + T: Foo, + T: Bar, +{ +} + +fn main() {} From 2ca4964db5d263a8f9222846bd70a7f26cf414cf Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 13 Nov 2020 14:01:16 -0300 Subject: [PATCH 02/28] Allow to self reference associated types in where clauses --- compiler/rustc_infer/src/traits/util.rs | 35 +++++ compiler/rustc_middle/src/query/mod.rs | 10 ++ compiler/rustc_middle/src/ty/query/keys.rs | 11 ++ .../rustc_trait_selection/src/traits/mod.rs | 3 +- compiler/rustc_typeck/src/astconv/mod.rs | 49 +++++- compiler/rustc_typeck/src/collect.rs | 141 +++++++++++------- .../rustc_typeck/src/collect/item_bounds.rs | 6 +- .../super-trait-referencing-self.rs | 12 ++ 8 files changed, 204 insertions(+), 63 deletions(-) create mode 100644 src/test/ui/associated-type-bounds/super-trait-referencing-self.rs diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 8273c2d291d09..26f6fcd5dab68 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -4,6 +4,7 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness}; +use rustc_span::symbol::Ident; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, @@ -89,6 +90,32 @@ pub fn elaborate_trait_refs<'tcx>( elaborate_predicates(tcx, predicates) } +pub fn elaborate_trait_refs_that_define_assoc_type<'tcx>( + tcx: TyCtxt<'tcx>, + trait_refs: impl Iterator>, + assoc_name: Ident, +) -> FxHashSet> { + let mut stack: Vec<_> = trait_refs.collect(); + let mut trait_refs = FxHashSet::default(); + + while let Some(trait_ref) = stack.pop() { + if trait_refs.insert(trait_ref) { + let super_predicates = + tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), Some(assoc_name))); + for (super_predicate, _) in super_predicates.predicates { + let bound_predicate = super_predicate.bound_atom(); + let subst_predicate = super_predicate + .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder())); + if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() { + stack.push(binder.value); + } + } + } + } + + trait_refs +} + pub fn elaborate_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl Iterator>, @@ -287,6 +314,14 @@ pub fn transitive_bounds<'tcx>( elaborate_trait_refs(tcx, bounds).filter_to_traits() } +pub fn transitive_bounds_that_define_assoc_type<'tcx>( + tcx: TyCtxt<'tcx>, + bounds: impl Iterator>, + assoc_name: Ident, +) -> FxHashSet> { + elaborate_trait_refs_that_define_assoc_type(tcx, bounds, assoc_name) +} + /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ed032220b54a2..c19943e1f8ccd 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -436,6 +436,16 @@ rustc_queries! { desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } } + /// Maps from the `DefId` 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 + /// evaluate them even during type conversion, often before the + /// full predicates are available (note that supertraits have + /// additional acyclicity requirements). + query super_predicates_that_define_assoc_type(key: (DefId, Option)) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key.0) } + } + /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index 339a068205c8e..3949c303f727a 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -149,6 +149,17 @@ impl Key for (LocalDefId, DefId) { } } +impl Key for (DefId, Option) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.0) + } +} + impl Key for (DefId, LocalDefId, Ident) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2d7df2ddd119d..d027628828441 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,7 +65,8 @@ pub use self::util::{ get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, }; pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, + supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, + SupertraitDefIds, Supertraits, }; pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index e891ea3403f47..d8fbcb633cd3e 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -6,6 +6,7 @@ mod errors; mod generics; use crate::bounds::Bounds; +use crate::collect::super_traits_of; use crate::collect::PlaceholderHirTyCollector; use crate::errors::{ AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, @@ -768,7 +769,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { + pub fn is_unsized(&self, ast_bounds: &[&hir::GenericBound<'_>], span: Span) -> bool { let tcx = self.tcx(); // Try to find an unbound in bounds. @@ -826,7 +827,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn add_bounds( &self, param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], + ast_bounds: &[&hir::GenericBound<'_>], bounds: &mut Bounds<'tcx>, ) { let mut trait_bounds = Vec::new(); @@ -844,7 +845,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self .instantiate_lang_item_trait_ref( - lang_item, span, hir_id, args, param_ty, bounds, + *lang_item, *span, *hir_id, args, param_ty, bounds, ), hir::GenericBound::Outlives(ref l) => region_bounds.push(l), } @@ -878,7 +879,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn compute_bounds( &self, param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], + ast_bounds: &[&hir::GenericBound<'_>], sized_by_default: SizedByDefault, span: Span, ) -> Bounds<'tcx> { @@ -896,6 +897,39 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bounds } + pub fn compute_bounds_that_match_assoc_type( + &self, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound<'_>], + sized_by_default: SizedByDefault, + span: Span, + assoc_name: Ident, + ) -> Bounds<'tcx> { + let mut result = Vec::new(); + + for ast_bound in ast_bounds { + if let Some(trait_ref) = ast_bound.trait_ref() { + if let Some(trait_did) = trait_ref.trait_def_id() { + if super_traits_of(self.tcx(), trait_did).any(|trait_did| { + self.tcx() + .associated_items(trait_did) + .find_by_name_and_kind( + self.tcx(), + assoc_name, + ty::AssocKind::Type, + trait_did, + ) + .is_some() + }) { + result.push(ast_bound); + } + } + } + } + + self.compute_bounds(param_ty, &result, sized_by_default, span) + } + /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates /// onto `bounds`. /// @@ -1050,7 +1084,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` // parameter to have a skipped binder. let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs); - self.add_bounds(param_ty, ast_bounds, bounds); + let ast_bounds: Vec<_> = ast_bounds.iter().collect(); + self.add_bounds(param_ty, &ast_bounds, bounds); } } Ok(()) @@ -1377,12 +1412,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_name = tcx.hir().ty_param_name(param_hir_id); self.one_bound_for_assoc_type( || { - traits::transitive_bounds( + traits::transitive_bounds_that_define_assoc_type( tcx, predicates.iter().filter_map(|(p, _)| { p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value) }), + assoc_name, ) + .into_iter() }, || param_name.to_string(), assoc_name, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 756147ca54c2c..8b457c7ceec27 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function @@ -79,6 +80,7 @@ pub fn provide(providers: &mut Providers) { projection_ty_from_predicates, explicit_predicates_of, super_predicates_of, + super_predicates_that_define_assoc_type, trait_explicit_predicates_and_bounds, type_param_predicates, trait_def, @@ -651,17 +653,10 @@ impl ItemCtxt<'tcx> { hir::GenericBound::Trait(poly_trait_ref, _) => { let trait_ref = &poly_trait_ref.trait_ref; let trait_did = trait_ref.trait_def_id().unwrap(); - let traits_did = super_traits_of(self.tcx, trait_did); - - traits_did.iter().any(|trait_did| { + super_traits_of(self.tcx, trait_did).any(|trait_did| { self.tcx - .associated_items(*trait_did) - .find_by_name_and_kind( - self.tcx, - assoc_name, - ty::AssocKind::Type, - *trait_did, - ) + .associated_items(trait_did) + .find_by_name_and_kind(self.tcx, assoc_name, ty::AssocKind::Type, trait_did) .is_some() }) } @@ -1035,55 +1030,91 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef { /// the transitive super-predicates are converted. fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> { debug!("super_predicates(trait_def_id={:?})", trait_def_id); - let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); + tcx.super_predicates_that_define_assoc_type((trait_def_id, None)) +} - let item = match tcx.hir().get(trait_hir_id) { - Node::Item(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_hir_id), - }; +/// Ensures that the super-predicates of the trait with a `DefId` +/// of `trait_def_id` are converted and stored. This also ensures that +/// the transitive super-predicates are converted. +fn super_predicates_that_define_assoc_type( + tcx: TyCtxt<'_>, + (trait_def_id, assoc_name): (DefId, Option), +) -> ty::GenericPredicates<'_> { + debug!( + "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})", + trait_def_id, assoc_name + ); + if trait_def_id.is_local() { + debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id); + let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); - let (generics, bounds) = match item.kind { - hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), - _ => span_bug!(item.span, "super_predicates invoked on non-trait"), - }; + let item = match tcx.hir().get(trait_hir_id) { + Node::Item(item) => item, + _ => bug!("trait_node_id {} is not an item", trait_hir_id), + }; - let icx = ItemCtxt::new(tcx, trait_def_id); - - // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. - let self_param_ty = tcx.types.self_param; - let superbounds1 = - AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); - - let superbounds1 = superbounds1.predicates(tcx, self_param_ty); - - // Convert any explicit superbounds in the where-clause, - // e.g., `trait Foo where Self: Bar`. - // In the case of trait aliases, however, we include all bounds in the where-clause, - // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` - // as one of its "superpredicates". - let is_trait_alias = tcx.is_trait_alias(trait_def_id); - let superbounds2 = icx.type_parameter_bounds_in_generics( - generics, - item.hir_id, - self_param_ty, - OnlySelfBounds(!is_trait_alias), - None, - ); + let (generics, bounds) = match item.kind { + hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), + hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), + _ => span_bug!(item.span, "super_predicates invoked on non-trait"), + }; - // Combine the two lists to form the complete set of superbounds: - let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); + let icx = ItemCtxt::new(tcx, trait_def_id); - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. - for &(pred, span) in superbounds { - debug!("superbound: {:?}", pred); - if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() { - tcx.at(span).super_predicates_of(bound.def_id()); + // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. + let self_param_ty = tcx.types.self_param; + let superbounds1 = if let Some(assoc_name) = assoc_name { + AstConv::compute_bounds_that_match_assoc_type( + &icx, + self_param_ty, + &bounds, + SizedByDefault::No, + item.span, + assoc_name, + ) + } else { + let bounds: Vec<_> = bounds.iter().collect(); + AstConv::compute_bounds(&icx, self_param_ty, &bounds, SizedByDefault::No, item.span) + }; + + let superbounds1 = superbounds1.predicates(tcx, self_param_ty); + + // Convert any explicit superbounds in the where-clause, + // e.g., `trait Foo where Self: Bar`. + // In the case of trait aliases, however, we include all bounds in the where-clause, + // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` + // as one of its "superpredicates". + let is_trait_alias = tcx.is_trait_alias(trait_def_id); + let superbounds2 = icx.type_parameter_bounds_in_generics( + generics, + item.hir_id, + self_param_ty, + OnlySelfBounds(!is_trait_alias), + assoc_name, + ); + + // Combine the two lists to form the complete set of superbounds: + let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); + + // Now require that immediate supertraits are converted, + // which will, in turn, reach indirect supertraits. + if assoc_name.is_none() { + // FIXME: move this into the `super_predicates_of` query + for &(pred, span) in superbounds { + debug!("superbound: {:?}", pred); + if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() { + tcx.at(span).super_predicates_of(bound.def_id()); + } + } } - } - ty::GenericPredicates { parent: None, predicates: superbounds } + ty::GenericPredicates { parent: None, predicates: superbounds } + } else { + // if `assoc_name` is None, then the query should've been redirected to an + // external provider + assert!(assoc_name.is_some()); + tcx.super_predicates_of(trait_def_id) + } } pub fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> impl Iterator { @@ -1123,6 +1154,8 @@ pub fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> impl Iterator, def_id: DefId) -> ty::TraitDef { @@ -1976,8 +2009,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP index += 1; let sized = SizedByDefault::Yes; - let bounds = - AstConv::compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span); + let bounds: Vec<_> = param.bounds.iter().collect(); + let bounds = AstConv::compute_bounds(&icx, param_ty, &bounds, sized, param.span); predicates.extend(bounds.predicates(tcx, param_ty)); } GenericParamKind::Const { .. } => { diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index e596dd1a396c9..62586d793b468 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -25,10 +25,11 @@ fn associated_type_bounds<'tcx>( InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); + let bounds: Vec<_> = bounds.iter().collect(); let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, assoc_item_def_id), item_ty, - bounds, + &bounds, SizedByDefault::Yes, span, ); @@ -65,10 +66,11 @@ fn opaque_type_bounds<'tcx>( let item_ty = tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id)); + let bounds: Vec<_> = bounds.iter().collect(); let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, opaque_def_id), item_ty, - bounds, + &bounds, SizedByDefault::Yes, span, ) diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs b/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs new file mode 100644 index 0000000000000..c82ec01f4d61d --- /dev/null +++ b/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs @@ -0,0 +1,12 @@ +// check-pass +trait Foo { + type Bar; +} +trait Qux: Foo + AsRef {} +trait Foo2 {} + +trait Qux2: Foo2 + AsRef { + type Bar; +} + +fn main() {} From 4406805c4c127b5c292a42d0ba137f0524dcaab6 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 17 Nov 2020 18:31:33 -0300 Subject: [PATCH 03/28] Update tests --- .../cycle-projection-based-on-where-clause.rs | 24 ------------------- ...le-projection-based-on-where-clause.stderr | 16 ------------- .../cycle-trait-supertrait-direct.stderr | 7 +++++- .../cycle-trait-supertrait-indirect.stderr | 10 ++++++++ src/test/ui/issues/issue-12511.stderr | 10 ++++++++ src/test/ui/issues/issue-20772.stderr | 2 +- src/test/ui/issues/issue-20825.stderr | 2 +- src/test/ui/issues/issue-22673.rs | 5 ++-- src/test/ui/issues/issue-22673.stderr | 16 ------------- 9 files changed, 31 insertions(+), 61 deletions(-) delete mode 100644 src/test/ui/cycle-projection-based-on-where-clause.rs delete mode 100644 src/test/ui/cycle-projection-based-on-where-clause.stderr delete mode 100644 src/test/ui/issues/issue-22673.stderr diff --git a/src/test/ui/cycle-projection-based-on-where-clause.rs b/src/test/ui/cycle-projection-based-on-where-clause.rs deleted file mode 100644 index d3609acfdff63..0000000000000 --- a/src/test/ui/cycle-projection-based-on-where-clause.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Example cycle where a bound on `T` uses a shorthand for `T`. This -// creates a cycle because we have to know the bounds on `T` to figure -// out what trait defines `Item`, but we can't know the bounds on `T` -// without knowing how to handle `T::Item`. -// -// Note that in the future cases like this could perhaps become legal, -// if we got more fine-grained about our cycle detection or changed -// how we handle `T::Item` resolution. - -use std::ops::Add; - -// Preamble. -trait Trait { type Item; } - -struct A - where T : Trait, - T : Add - //~^ ERROR cycle detected -{ - data: T -} - -fn main() { -} diff --git a/src/test/ui/cycle-projection-based-on-where-clause.stderr b/src/test/ui/cycle-projection-based-on-where-clause.stderr deleted file mode 100644 index 2c337cc6bf903..0000000000000 --- a/src/test/ui/cycle-projection-based-on-where-clause.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0391]: cycle detected when computing the bounds for type parameter `T` - --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 - | -LL | T : Add - | ^^^^^^^ - | - = note: ...which again requires computing the bounds for type parameter `T`, completing the cycle -note: cycle used when computing explicit predicates of `A` - --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 - | -LL | T : Add - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr index 8aa3ac8abf52c..235f9088710c7 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr @@ -1,9 +1,14 @@ error[E0391]: cycle detected when computing the supertraits of `Chromosome` + --> $DIR/cycle-trait-supertrait-direct.rs:3:1 + | +LL | trait Chromosome: Chromosome { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing the supertraits of `Chromosome`... --> $DIR/cycle-trait-supertrait-direct.rs:3:19 | LL | trait Chromosome: Chromosome { | ^^^^^^^^^^ - | = note: ...which again requires computing the supertraits of `Chromosome`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-supertrait-direct.rs:3:1 diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr index 9740f43a4ba97..2df311f282ad8 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr @@ -1,9 +1,19 @@ error[E0391]: cycle detected when computing the supertraits of `B` + --> $DIR/cycle-trait-supertrait-indirect.rs:7:1 + | +LL | trait B: C { + | ^^^^^^^^^^ + | +note: ...which requires computing the supertraits of `B`... --> $DIR/cycle-trait-supertrait-indirect.rs:7:10 | LL | trait B: C { | ^ +note: ...which requires computing the supertraits of `C`... + --> $DIR/cycle-trait-supertrait-indirect.rs:11:1 | +LL | trait C: B { } + | ^^^^^^^^^^ note: ...which requires computing the supertraits of `C`... --> $DIR/cycle-trait-supertrait-indirect.rs:11:10 | diff --git a/src/test/ui/issues/issue-12511.stderr b/src/test/ui/issues/issue-12511.stderr index 37e38ff60ae4b..6450b7cad0c7a 100644 --- a/src/test/ui/issues/issue-12511.stderr +++ b/src/test/ui/issues/issue-12511.stderr @@ -1,9 +1,19 @@ error[E0391]: cycle detected when computing the supertraits of `T1` + --> $DIR/issue-12511.rs:1:1 + | +LL | trait T1 : T2 { + | ^^^^^^^^^^^^^ + | +note: ...which requires computing the supertraits of `T1`... --> $DIR/issue-12511.rs:1:12 | LL | trait T1 : T2 { | ^^ +note: ...which requires computing the supertraits of `T2`... + --> $DIR/issue-12511.rs:5:1 | +LL | trait T2 : T1 { + | ^^^^^^^^^^^^^ note: ...which requires computing the supertraits of `T2`... --> $DIR/issue-12511.rs:5:12 | diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index d64636310a368..6165337d02456 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -7,7 +7,7 @@ LL | | {} | |__^ | = note: ...which again requires computing the supertraits of `T`, completing the cycle -note: cycle used when collecting item types in top-level module +note: cycle used when computing the supertraits of `T` --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator diff --git a/src/test/ui/issues/issue-20825.stderr b/src/test/ui/issues/issue-20825.stderr index 5f9709d1c649b..a09a5290c378a 100644 --- a/src/test/ui/issues/issue-20825.stderr +++ b/src/test/ui/issues/issue-20825.stderr @@ -5,7 +5,7 @@ LL | pub trait Processor: Subscriber { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which again requires computing the supertraits of `Processor`, completing the cycle -note: cycle used when collecting item types in top-level module +note: cycle used when computing the supertraits of `Processor` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { diff --git a/src/test/ui/issues/issue-22673.rs b/src/test/ui/issues/issue-22673.rs index ba8057b684de8..4b9b4d6b23da4 100644 --- a/src/test/ui/issues/issue-22673.rs +++ b/src/test/ui/issues/issue-22673.rs @@ -1,5 +1,6 @@ -trait Expr : PartialEq { - //~^ ERROR: cycle detected +// check-pass + +trait Expr: PartialEq { type Item; } diff --git a/src/test/ui/issues/issue-22673.stderr b/src/test/ui/issues/issue-22673.stderr deleted file mode 100644 index 9e7e4b218b1c6..0000000000000 --- a/src/test/ui/issues/issue-22673.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0391]: cycle detected when computing the supertraits of `Expr` - --> $DIR/issue-22673.rs:1:1 - | -LL | trait Expr : PartialEq { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which again requires computing the supertraits of `Expr`, completing the cycle -note: cycle used when collecting item types in top-level module - --> $DIR/issue-22673.rs:1:1 - | -LL | trait Expr : PartialEq { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0391`. From 4a97c52630f9d8c5df3c229b1c2c0fb0fa3f3ca2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 14 Nov 2020 09:53:03 -0500 Subject: [PATCH 04/28] Add test to check that we do not get a cycle due to resolving `Self::Bar` in the where clauses --- .../super-trait-where-referencing-self.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs diff --git a/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs b/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs new file mode 100644 index 0000000000000..72a6be9ffc388 --- /dev/null +++ b/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs @@ -0,0 +1,27 @@ +// check-pass + +// Test that we do not get a cycle due to +// resolving `Self::Bar` in the where clauses +// on a trait definition (in particular, in +// a where clause that is defining a superpredicate). + +trait Foo { + type Bar; +} +trait Qux +where + Self: Foo, + Self: AsRef, +{ +} +trait Foo2 {} + +trait Qux2 +where + Self: Foo2, + Self: AsRef, +{ + type Bar; +} + +fn main() {} From 5b6f206d23b003b89a0883d2c0e5461330ab1068 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 19 Nov 2020 18:37:26 -0300 Subject: [PATCH 05/28] Fix super_traits_of to consider where bounds --- compiler/rustc_typeck/src/collect.rs | 30 ++++++++++++++++--- .../associated-item-through-where-clause.rs | 21 +++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 8b457c7ceec27..6a33bc8868572 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1133,10 +1133,12 @@ pub fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> impl Iterator bug!("super_trait_of {} is not an item", trait_hir_id), }; - let supertraits = match item.kind { - hir::ItemKind::Trait(.., ref supertraits, _) => supertraits, - hir::ItemKind::TraitAlias(_, ref supertraits) => supertraits, - _ => span_bug!(item.span, "super_trait_of invoked on non-trait"), + let (generics, supertraits) = match item.kind { + hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => { + (generics, supertraits) + } + hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), + _ => span_bug!(item.span, "super_predicates invoked on non-trait"), }; for supertrait in supertraits.iter() { @@ -1145,6 +1147,26 @@ pub fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> impl Iterator` would include `u32: PartialEq` + // as one of its "superpredicates". + let is_trait_alias = tcx.is_trait_alias(trait_did); + let self_param_ty = tcx.types.self_param; + for (predicate, _) in icx.type_parameter_bounds_in_generics( + generics, + item.hir_id, + self_param_ty, + OnlySelfBounds(!is_trait_alias), + None, + ) { + if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { + stack.push(data.def_id()); + } + } } else { let generic_predicates = tcx.super_predicates_of(trait_did); for (predicate, _) in generic_predicates.predicates { diff --git a/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs b/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs new file mode 100644 index 0000000000000..3eb50ab554735 --- /dev/null +++ b/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs @@ -0,0 +1,21 @@ +// check-pass + +trait Foo { + type Item; +} + +trait Bar +where + Self: Foo, +{ +} + +#[allow(dead_code)] +fn foo(_m: M) +where + M: Bar, + M::Item: Send, +{ +} + +fn main() {} From 3c8cf6d80204d0963cc91965042b00655a1c676d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 19 Nov 2020 19:03:59 -0300 Subject: [PATCH 06/28] Avoid ICEing when associated type bound trait is missing --- compiler/rustc_typeck/src/collect.rs | 22 +++++++++++++------ .../missing-trait-bound-for-assoc-fails.rs | 10 +++++++++ ...missing-trait-bound-for-assoc-fails.stderr | 16 ++++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs create mode 100644 src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 6a33bc8868572..eef80478531c3 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -652,13 +652,21 @@ impl ItemCtxt<'tcx> { match b { hir::GenericBound::Trait(poly_trait_ref, _) => { let trait_ref = &poly_trait_ref.trait_ref; - let trait_did = trait_ref.trait_def_id().unwrap(); - super_traits_of(self.tcx, trait_did).any(|trait_did| { - self.tcx - .associated_items(trait_did) - .find_by_name_and_kind(self.tcx, assoc_name, ty::AssocKind::Type, trait_did) - .is_some() - }) + if let Some(trait_did) = trait_ref.trait_def_id() { + super_traits_of(self.tcx, trait_did).any(|trait_did| { + self.tcx + .associated_items(trait_did) + .find_by_name_and_kind( + self.tcx, + assoc_name, + ty::AssocKind::Type, + trait_did, + ) + .is_some() + }) + } else { + false + } } _ => false, } diff --git a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs new file mode 100644 index 0000000000000..07d0f8f8769e5 --- /dev/null +++ b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs @@ -0,0 +1,10 @@ +#[allow(dead_code)] +fn foo(_m: M) +where + M::Item: Temp, + //~^ ERROR cannot find trait `Temp` in this scope [E0405] + //~| ERROR associated type `Item` not found for `M` [E0220] +{ +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr new file mode 100644 index 0000000000000..bc2807b03961c --- /dev/null +++ b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr @@ -0,0 +1,16 @@ +error[E0405]: cannot find trait `Temp` in this scope + --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:14 + | +LL | M::Item: Temp, + | ^^^^ not found in this scope + +error[E0220]: associated type `Item` not found for `M` + --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:8 + | +LL | M::Item: Temp, + | ^^^^ associated type `Item` not found + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0220, E0405. +For more information about an error, try `rustc --explain E0220`. From a6d2235de12b09cdcbeb23db4a164e559fe44483 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 20 Nov 2020 11:22:36 -0300 Subject: [PATCH 07/28] Add test for a still ambiguous scenario --- .../ambiguous-associated-type2.rs | 10 ++++++++++ .../ambiguous-associated-type2.stderr | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs create mode 100644 src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs new file mode 100644 index 0000000000000..92b5dc1a1fbad --- /dev/null +++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs @@ -0,0 +1,10 @@ +trait Foo { + type Item; +} +trait Bar { + type Item; +} +trait Baz: Foo + Bar {} +//~^ ERROR cycle detected when computing the supertraits of `Baz` [E0391] + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr new file mode 100644 index 0000000000000..1a168a595416e --- /dev/null +++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr @@ -0,0 +1,16 @@ +error[E0391]: cycle detected when computing the supertraits of `Baz` + --> $DIR/ambiguous-associated-type2.rs:7:1 + | +LL | trait Baz: Foo + Bar {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ...which again requires computing the supertraits of `Baz`, completing the cycle +note: cycle used when computing the supertraits of `Baz` + --> $DIR/ambiguous-associated-type2.rs:7:1 + | +LL | trait Baz: Foo + Bar {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. From f76d6e013937872e7cbcce0dd57dc4bc25de9220 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 20 Nov 2020 11:24:21 -0300 Subject: [PATCH 08/28] Add description on test --- src/test/ui/associated-type-bounds/super-trait-referencing.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing.rs b/src/test/ui/associated-type-bounds/super-trait-referencing.rs index fde6b91e6c4e2..2e97535157fd2 100644 --- a/src/test/ui/associated-type-bounds/super-trait-referencing.rs +++ b/src/test/ui/associated-type-bounds/super-trait-referencing.rs @@ -1,4 +1,8 @@ // check-pass + +// The goal of this test is to ensure that T: Bar +// in the where clause does not cycle + trait Foo { type Item; } From aa1cafd4079c9f246d495addd6c23cc47b266a8b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 20 Nov 2020 17:45:20 -0300 Subject: [PATCH 09/28] Add `` to variable name in docs --- compiler/rustc_typeck/src/astconv/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index d8fbcb633cd3e..f7eb6720e1ebf 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -52,7 +52,7 @@ pub trait AstConv<'tcx> { /// Returns predicates in scope of the form `X: Foo`, where `X` /// is a type parameter `X` with the given id `def_id` and T - /// matches assoc_name. This is a subset of the full set of + /// matches `assoc_name`. This is a subset of the full set of /// predicates. /// /// This is used for one specific purpose: resolving "short-hand" From 30e933cd794b90d2ea9164112dcf20c23c1eba5f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 20 Nov 2020 17:57:44 -0300 Subject: [PATCH 10/28] Extract trait_may_define_assoc_type helper function --- compiler/rustc_typeck/src/astconv/mod.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index f7eb6720e1ebf..3cb85250e2a4c 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -910,17 +910,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for ast_bound in ast_bounds { if let Some(trait_ref) = ast_bound.trait_ref() { if let Some(trait_did) = trait_ref.trait_def_id() { - if super_traits_of(self.tcx(), trait_did).any(|trait_did| { - self.tcx() - .associated_items(trait_did) - .find_by_name_and_kind( - self.tcx(), - assoc_name, - ty::AssocKind::Type, - trait_did, - ) - .is_some() - }) { + if self.trait_may_define_assoc_type(trait_did, assoc_name) { result.push(ast_bound); } } @@ -930,6 +920,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.compute_bounds(param_ty, &result, sized_by_default, span) } + /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` + /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. + fn trait_may_define_assoc_type(&self, trait_def_id: DefId, assoc_name: Ident) -> bool { + super_traits_of(self.tcx(), trait_def_id).any(|trait_did| { + self.tcx() + .associated_items(trait_did) + .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_did) + .is_some() + }) + } + /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates /// onto `bounds`. /// From 6631215e5413a7e963c93c8c94f7ac980254623a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 20 Nov 2020 17:59:41 -0300 Subject: [PATCH 11/28] Remove unneeded logic --- .../rustc_typeck/src/check/fn_ctxt/mod.rs | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 96ebb781f0bcd..20c639a003109 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -188,7 +188,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { &self, _: Span, def_id: DefId, - assoc_name: Ident, + _: Ident, ) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); @@ -202,23 +202,9 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.param_env.caller_bounds().iter().filter_map(|predicate| { match predicate.skip_binders() { ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { - let trait_did = data.def_id(); - if tcx - .associated_items(trait_did) - .find_by_name_and_kind( - tcx, - assoc_name, - ty::AssocKind::Type, - trait_did, - ) - .is_some() - { - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); - Some((predicate, span)) - } else { - None - } + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); + Some((predicate, span)) } _ => None, } From b60a214c51413b112935eadde5777998c3aa3458 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 21 Nov 2020 18:13:04 -0300 Subject: [PATCH 12/28] super_traits_of is now a query --- compiler/rustc_middle/src/query/mod.rs | 8 +++++++- compiler/rustc_typeck/src/astconv/mod.rs | 7 +++---- compiler/rustc_typeck/src/collect.rs | 11 ++++++----- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c19943e1f8ccd..37dd1a1cf5f82 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -433,7 +433,13 @@ rustc_queries! { /// full predicates are available (note that supertraits have /// additional acyclicity requirements). query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } + desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } + } + + /// Maps from the `DefId` of a trait to the list of + /// all the ancestors super traits. + query super_traits_of(key: DefId) -> FxHashSet { + desc { |tcx| "computing the super traits of `{}`", tcx.def_path_str(key) } } /// Maps from the `DefId` of a trait to the list of diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 3cb85250e2a4c..4e87940efd34c 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -6,7 +6,6 @@ mod errors; mod generics; use crate::bounds::Bounds; -use crate::collect::super_traits_of; use crate::collect::PlaceholderHirTyCollector; use crate::errors::{ AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, @@ -923,10 +922,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. fn trait_may_define_assoc_type(&self, trait_def_id: DefId, assoc_name: Ident) -> bool { - super_traits_of(self.tcx(), trait_def_id).any(|trait_did| { + self.tcx().super_traits_of(trait_def_id).iter().any(|trait_did| { self.tcx() - .associated_items(trait_did) - .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_did) + .associated_items(*trait_did) + .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, *trait_did) .is_some() }) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index eef80478531c3..d7da7f2a5d9cb 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -80,6 +80,7 @@ pub fn provide(providers: &mut Providers) { projection_ty_from_predicates, explicit_predicates_of, super_predicates_of, + super_traits_of, super_predicates_that_define_assoc_type, trait_explicit_predicates_and_bounds, type_param_predicates, @@ -653,14 +654,14 @@ impl ItemCtxt<'tcx> { hir::GenericBound::Trait(poly_trait_ref, _) => { let trait_ref = &poly_trait_ref.trait_ref; if let Some(trait_did) = trait_ref.trait_def_id() { - super_traits_of(self.tcx, trait_did).any(|trait_did| { + self.tcx.super_traits_of(trait_did).iter().any(|trait_did| { self.tcx - .associated_items(trait_did) + .associated_items(*trait_did) .find_by_name_and_kind( self.tcx, assoc_name, ty::AssocKind::Type, - trait_did, + *trait_did, ) .is_some() }) @@ -1125,7 +1126,7 @@ fn super_predicates_that_define_assoc_type( } } -pub fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> impl Iterator { +fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> FxHashSet { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; while let Some(trait_did) = stack.pop() { @@ -1185,7 +1186,7 @@ pub fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> impl Iterator, def_id: DefId) -> ty::TraitDef { From c0007a2d7eec702a9b10f90200cfa2e33881ab6c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 21 Nov 2020 18:16:24 -0300 Subject: [PATCH 13/28] Extract function trait_may_define_assoc_type --- compiler/rustc_middle/src/ty/context.rs | 12 +++++++++++- compiler/rustc_typeck/src/astconv/mod.rs | 13 +------------ compiler/rustc_typeck/src/collect.rs | 12 +----------- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7207e5a179e4f..b2a8b33e4ff5f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -51,7 +51,7 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Session; use rustc_span::source_map::MultiSpan; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; @@ -2085,6 +2085,16 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) } + /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` + /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. + pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool { + self.super_traits_of(trait_def_id).iter().any(|trait_did| { + self.associated_items(*trait_did) + .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, *trait_did) + .is_some() + }) + } + /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 4e87940efd34c..3ec0919bb8a3f 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -909,7 +909,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for ast_bound in ast_bounds { if let Some(trait_ref) = ast_bound.trait_ref() { if let Some(trait_did) = trait_ref.trait_def_id() { - if self.trait_may_define_assoc_type(trait_did, assoc_name) { + if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) { result.push(ast_bound); } } @@ -919,17 +919,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.compute_bounds(param_ty, &result, sized_by_default, span) } - /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` - /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. - fn trait_may_define_assoc_type(&self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.tcx().super_traits_of(trait_def_id).iter().any(|trait_did| { - self.tcx() - .associated_items(*trait_did) - .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, *trait_did) - .is_some() - }) - } - /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates /// onto `bounds`. /// diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index d7da7f2a5d9cb..8d5e518c151d2 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -654,17 +654,7 @@ impl ItemCtxt<'tcx> { hir::GenericBound::Trait(poly_trait_ref, _) => { let trait_ref = &poly_trait_ref.trait_ref; if let Some(trait_did) = trait_ref.trait_def_id() { - self.tcx.super_traits_of(trait_did).iter().any(|trait_did| { - self.tcx - .associated_items(*trait_did) - .find_by_name_and_kind( - self.tcx, - assoc_name, - ty::AssocKind::Type, - *trait_did, - ) - .is_some() - }) + self.tcx.trait_may_define_assoc_type(trait_did, assoc_name) } else { false } From dd267fecd64d6e5351424cd5459e1475d0bb2716 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 21 Nov 2020 19:12:08 -0300 Subject: [PATCH 14/28] compute_bounds takes &[GenericBound] --- compiler/rustc_typeck/src/astconv/mod.rs | 39 ++++++++++++------- compiler/rustc_typeck/src/collect.rs | 5 +-- .../rustc_typeck/src/collect/item_bounds.rs | 2 - 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 3ec0919bb8a3f..c0c4e5b517ea6 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -878,22 +878,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn compute_bounds( &self, param_ty: Ty<'tcx>, - ast_bounds: &[&hir::GenericBound<'_>], + ast_bounds: &[hir::GenericBound<'_>], sized_by_default: SizedByDefault, span: Span, ) -> Bounds<'tcx> { - let mut bounds = Bounds::default(); - - self.add_bounds(param_ty, ast_bounds, &mut bounds); - bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); - - bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } - } else { - None - }; - - bounds + let ast_bounds: Vec<_> = ast_bounds.iter().collect(); + self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span) } pub fn compute_bounds_that_match_assoc_type( @@ -916,7 +906,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - self.compute_bounds(param_ty, &result, sized_by_default, span) + self.compute_bounds_inner(param_ty, &result, sized_by_default, span) + } + + fn compute_bounds_inner( + &self, + param_ty: Ty<'tcx>, + ast_bounds: &[&hir::GenericBound<'_>], + sized_by_default: SizedByDefault, + span: Span, + ) -> Bounds<'tcx> { + let mut bounds = Bounds::default(); + + self.add_bounds(param_ty, ast_bounds, &mut bounds); + bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); + + bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { + if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } + } else { + None + }; + + bounds } /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 8d5e518c151d2..32527a7793423 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1072,7 +1072,6 @@ fn super_predicates_that_define_assoc_type( assoc_name, ) } else { - let bounds: Vec<_> = bounds.iter().collect(); AstConv::compute_bounds(&icx, self_param_ty, &bounds, SizedByDefault::No, item.span) }; @@ -2030,8 +2029,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP index += 1; let sized = SizedByDefault::Yes; - let bounds: Vec<_> = param.bounds.iter().collect(); - let bounds = AstConv::compute_bounds(&icx, param_ty, &bounds, sized, param.span); + let bounds = + AstConv::compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span); predicates.extend(bounds.predicates(tcx, param_ty)); } GenericParamKind::Const { .. } => { diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 62586d793b468..dd1da7d9cff2d 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -25,7 +25,6 @@ fn associated_type_bounds<'tcx>( InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); - let bounds: Vec<_> = bounds.iter().collect(); let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, assoc_item_def_id), item_ty, @@ -66,7 +65,6 @@ fn opaque_type_bounds<'tcx>( let item_ty = tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id)); - let bounds: Vec<_> = bounds.iter().collect(); let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, opaque_def_id), item_ty, From 6ab8fe223ec75b74c01b4e4fa84db12a5c62f648 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 21 Nov 2020 20:25:09 -0300 Subject: [PATCH 15/28] Bless tests --- src/test/incremental/cyclic-trait-hierarchy.rs | 10 +++++----- .../cycle-trait/cycle-trait-supertrait-direct.stderr | 4 ++-- .../cycle-trait/cycle-trait-supertrait-indirect.stderr | 6 +++--- src/test/ui/issues/issue-12511.stderr | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/test/incremental/cyclic-trait-hierarchy.rs b/src/test/incremental/cyclic-trait-hierarchy.rs index 03bb5eea765cc..b502e7207d561 100644 --- a/src/test/incremental/cyclic-trait-hierarchy.rs +++ b/src/test/incremental/cyclic-trait-hierarchy.rs @@ -3,11 +3,11 @@ // revisions: rpass1 cfail2 #[cfg(rpass1)] -pub trait T2 { } +pub trait T2 {} #[cfg(cfail2)] -pub trait T2: T1 { } -//[cfail2]~^ ERROR cycle detected when computing the supertraits of `T2` +pub trait T2: T1 {} +//[cfail2]~^ ERROR cycle detected when computing the super predicates of `T2` -pub trait T1: T2 { } +pub trait T1: T2 {} -fn main() { } +fn main() {} diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr index 235f9088710c7..3635803a1c57a 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing the supertraits of `Chromosome` +error[E0391]: cycle detected when computing the super predicates of `Chromosome` --> $DIR/cycle-trait-supertrait-direct.rs:3:1 | LL | trait Chromosome: Chromosome { @@ -9,7 +9,7 @@ note: ...which requires computing the supertraits of `Chromosome`... | LL | trait Chromosome: Chromosome { | ^^^^^^^^^^ - = note: ...which again requires computing the supertraits of `Chromosome`, completing the cycle + = note: ...which again requires computing the super predicates of `Chromosome`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-supertrait-direct.rs:3:1 | diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr index 2df311f282ad8..74cc41665f529 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing the supertraits of `B` +error[E0391]: cycle detected when computing the super predicates of `B` --> $DIR/cycle-trait-supertrait-indirect.rs:7:1 | LL | trait B: C { @@ -9,7 +9,7 @@ note: ...which requires computing the supertraits of `B`... | LL | trait B: C { | ^ -note: ...which requires computing the supertraits of `C`... +note: ...which requires computing the super predicates of `C`... --> $DIR/cycle-trait-supertrait-indirect.rs:11:1 | LL | trait C: B { } @@ -19,7 +19,7 @@ note: ...which requires computing the supertraits of `C`... | LL | trait C: B { } | ^ - = note: ...which again requires computing the supertraits of `B`, completing the cycle + = note: ...which again requires computing the super predicates of `B`, completing the cycle note: cycle used when computing the supertraits of `A` --> $DIR/cycle-trait-supertrait-indirect.rs:4:10 | diff --git a/src/test/ui/issues/issue-12511.stderr b/src/test/ui/issues/issue-12511.stderr index 6450b7cad0c7a..d1b0e63054f24 100644 --- a/src/test/ui/issues/issue-12511.stderr +++ b/src/test/ui/issues/issue-12511.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing the supertraits of `T1` +error[E0391]: cycle detected when computing the super predicates of `T1` --> $DIR/issue-12511.rs:1:1 | LL | trait T1 : T2 { @@ -9,7 +9,7 @@ note: ...which requires computing the supertraits of `T1`... | LL | trait T1 : T2 { | ^^ -note: ...which requires computing the supertraits of `T2`... +note: ...which requires computing the super predicates of `T2`... --> $DIR/issue-12511.rs:5:1 | LL | trait T2 : T1 { @@ -19,7 +19,7 @@ note: ...which requires computing the supertraits of `T2`... | LL | trait T2 : T1 { | ^^ - = note: ...which again requires computing the supertraits of `T1`, completing the cycle + = note: ...which again requires computing the super predicates of `T1`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-12511.rs:1:1 | From b916ac6322592b5baf4eee7c98cecf1e300f208b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 22 Nov 2020 20:08:00 -0300 Subject: [PATCH 16/28] adjust super_predicates_that_define_assoc_type query description --- compiler/rustc_middle/src/query/mod.rs | 5 ++++- .../ambiguous-associated-type2.rs | 4 +++- .../ambiguous-associated-type2.stderr | 10 +++++----- .../cycle-trait/cycle-trait-supertrait-direct.stderr | 2 +- .../cycle-trait/cycle-trait-supertrait-indirect.stderr | 6 +++--- src/test/ui/issues/issue-12511.stderr | 4 ++-- src/test/ui/issues/issue-20772.stderr | 6 +++--- src/test/ui/issues/issue-20825.stderr | 6 +++--- 8 files changed, 24 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 37dd1a1cf5f82..d7718dea43789 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -449,7 +449,10 @@ rustc_queries! { /// full predicates are available (note that supertraits have /// additional acyclicity requirements). query super_predicates_that_define_assoc_type(key: (DefId, Option)) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key.0) } + desc { |tcx| "computing the super traits of `{}`{}", + tcx.def_path_str(key.0), + if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() }, + } } /// To avoid cycles within the predicates of a single item we compute diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs index 92b5dc1a1fbad..1b6d6d0ff599f 100644 --- a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs +++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + trait Foo { type Item; } @@ -5,6 +7,6 @@ trait Bar { type Item; } trait Baz: Foo + Bar {} -//~^ ERROR cycle detected when computing the supertraits of `Baz` [E0391] +//~^ ERROR cycle detected when computing the super traits of `Baz` with associated type name `Item` [E0391] fn main() {} diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr index 1a168a595416e..bda1debeac0d6 100644 --- a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr +++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr @@ -1,12 +1,12 @@ -error[E0391]: cycle detected when computing the supertraits of `Baz` - --> $DIR/ambiguous-associated-type2.rs:7:1 +error[E0391]: cycle detected when computing the super traits of `Baz` with associated type name `Item` + --> $DIR/ambiguous-associated-type2.rs:9:1 | LL | trait Baz: Foo + Bar {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the supertraits of `Baz`, completing the cycle -note: cycle used when computing the supertraits of `Baz` - --> $DIR/ambiguous-associated-type2.rs:7:1 + = note: ...which again requires computing the super traits of `Baz` with associated type name `Item`, completing the cycle +note: cycle used when computing the super traits of `Baz` + --> $DIR/ambiguous-associated-type2.rs:9:1 | LL | trait Baz: Foo + Bar {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr index 3635803a1c57a..ee54b2fd151d7 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the super predicates of `Chromosome` LL | trait Chromosome: Chromosome { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires computing the supertraits of `Chromosome`... +note: ...which requires computing the super traits of `Chromosome`... --> $DIR/cycle-trait-supertrait-direct.rs:3:19 | LL | trait Chromosome: Chromosome { diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr index 74cc41665f529..0a2284e0efbca 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the super predicates of `B` LL | trait B: C { | ^^^^^^^^^^ | -note: ...which requires computing the supertraits of `B`... +note: ...which requires computing the super traits of `B`... --> $DIR/cycle-trait-supertrait-indirect.rs:7:10 | LL | trait B: C { @@ -14,13 +14,13 @@ note: ...which requires computing the super predicates of `C`... | LL | trait C: B { } | ^^^^^^^^^^ -note: ...which requires computing the supertraits of `C`... +note: ...which requires computing the super traits of `C`... --> $DIR/cycle-trait-supertrait-indirect.rs:11:10 | LL | trait C: B { } | ^ = note: ...which again requires computing the super predicates of `B`, completing the cycle -note: cycle used when computing the supertraits of `A` +note: cycle used when computing the super traits of `A` --> $DIR/cycle-trait-supertrait-indirect.rs:4:10 | LL | trait A: B { diff --git a/src/test/ui/issues/issue-12511.stderr b/src/test/ui/issues/issue-12511.stderr index d1b0e63054f24..5f2b98c5237db 100644 --- a/src/test/ui/issues/issue-12511.stderr +++ b/src/test/ui/issues/issue-12511.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the super predicates of `T1` LL | trait T1 : T2 { | ^^^^^^^^^^^^^ | -note: ...which requires computing the supertraits of `T1`... +note: ...which requires computing the super traits of `T1`... --> $DIR/issue-12511.rs:1:12 | LL | trait T1 : T2 { @@ -14,7 +14,7 @@ note: ...which requires computing the super predicates of `T2`... | LL | trait T2 : T1 { | ^^^^^^^^^^^^^ -note: ...which requires computing the supertraits of `T2`... +note: ...which requires computing the super traits of `T2`... --> $DIR/issue-12511.rs:5:12 | LL | trait T2 : T1 { diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index 6165337d02456..4aecc7eab4628 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing the supertraits of `T` +error[E0391]: cycle detected when computing the super traits of `T` with associated type name `Item` --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator @@ -6,8 +6,8 @@ LL | | LL | | {} | |__^ | - = note: ...which again requires computing the supertraits of `T`, completing the cycle -note: cycle used when computing the supertraits of `T` + = note: ...which again requires computing the super traits of `T` with associated type name `Item`, completing the cycle +note: cycle used when computing the super traits of `T` --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator diff --git a/src/test/ui/issues/issue-20825.stderr b/src/test/ui/issues/issue-20825.stderr index a09a5290c378a..ccbe06d9c0d56 100644 --- a/src/test/ui/issues/issue-20825.stderr +++ b/src/test/ui/issues/issue-20825.stderr @@ -1,11 +1,11 @@ -error[E0391]: cycle detected when computing the supertraits of `Processor` +error[E0391]: cycle detected when computing the super traits of `Processor` with associated type name `Input` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the supertraits of `Processor`, completing the cycle -note: cycle used when computing the supertraits of `Processor` + = note: ...which again requires computing the super traits of `Processor` with associated type name `Input`, completing the cycle +note: cycle used when computing the super traits of `Processor` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { From af38d71b173616bb08133207d794fab51d45aa0c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 22 Nov 2020 20:12:20 -0300 Subject: [PATCH 17/28] Add super_traits_of docs --- compiler/rustc_typeck/src/collect.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 32527a7793423..6cd4acf5de62c 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1115,6 +1115,9 @@ fn super_predicates_that_define_assoc_type( } } +/// Ensures that the super traits of the trait with a `DefId` +/// of `trait_def_id` are converted and stored. This also ensures that +/// the transitive super traits are converted. fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> FxHashSet { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; From a175f36c954abf69aaf4021a321ea13c8573cb40 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 24 Nov 2020 16:58:25 -0300 Subject: [PATCH 18/28] Document compute_bounds_that_match_assoc_type --- compiler/rustc_typeck/src/astconv/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index c0c4e5b517ea6..e9965b47344f5 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -886,6 +886,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span) } + /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type + /// named `assoc_name` into ty::Bounds. Ignore the rest. pub fn compute_bounds_that_match_assoc_type( &self, param_ty: Ty<'tcx>, From 9e0538bd07292d6b2d4d215d0cb91d5c9d05aee4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 24 Nov 2020 16:59:57 -0300 Subject: [PATCH 19/28] Document elaborate_trait_refs_that_define_assoc_type --- compiler/rustc_infer/src/traits/util.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 26f6fcd5dab68..b7d6e8f0bf6fd 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -90,6 +90,11 @@ pub fn elaborate_trait_refs<'tcx>( elaborate_predicates(tcx, predicates) } +/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may +/// define the given associated type `assoc_name`. It uses the +/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that +/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or +/// `T::Item` and helps to avoid cycle errors (see e.g. #35237). pub fn elaborate_trait_refs_that_define_assoc_type<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, From 28446ef19eebaee31bbbd2706fed29632ee7b7f9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 24 Nov 2020 17:02:54 -0300 Subject: [PATCH 20/28] Inline elaborate_trait_refs_that_define_assoc_type into transitive_bounds_that_define_assoc_type --- compiler/rustc_infer/src/traits/util.rs | 56 +++++++++++-------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index b7d6e8f0bf6fd..e084530d17a5e 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -90,37 +90,6 @@ pub fn elaborate_trait_refs<'tcx>( elaborate_predicates(tcx, predicates) } -/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may -/// define the given associated type `assoc_name`. It uses the -/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that -/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or -/// `T::Item` and helps to avoid cycle errors (see e.g. #35237). -pub fn elaborate_trait_refs_that_define_assoc_type<'tcx>( - tcx: TyCtxt<'tcx>, - trait_refs: impl Iterator>, - assoc_name: Ident, -) -> FxHashSet> { - let mut stack: Vec<_> = trait_refs.collect(); - let mut trait_refs = FxHashSet::default(); - - while let Some(trait_ref) = stack.pop() { - if trait_refs.insert(trait_ref) { - let super_predicates = - tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), Some(assoc_name))); - for (super_predicate, _) in super_predicates.predicates { - let bound_predicate = super_predicate.bound_atom(); - let subst_predicate = super_predicate - .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder())); - if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() { - stack.push(binder.value); - } - } - } - } - - trait_refs -} - pub fn elaborate_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl Iterator>, @@ -319,12 +288,35 @@ pub fn transitive_bounds<'tcx>( elaborate_trait_refs(tcx, bounds).filter_to_traits() } +/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may +/// define the given associated type `assoc_name`. It uses the +/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that +/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or +/// `T::Item` and helps to avoid cycle errors (see e.g. #35237). pub fn transitive_bounds_that_define_assoc_type<'tcx>( tcx: TyCtxt<'tcx>, bounds: impl Iterator>, assoc_name: Ident, ) -> FxHashSet> { - elaborate_trait_refs_that_define_assoc_type(tcx, bounds, assoc_name) + let mut stack: Vec<_> = bounds.collect(); + let mut trait_refs = FxHashSet::default(); + + while let Some(trait_ref) = stack.pop() { + if trait_refs.insert(trait_ref) { + let super_predicates = + tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), Some(assoc_name))); + for (super_predicate, _) in super_predicates.predicates { + let bound_predicate = super_predicate.bound_atom(); + let subst_predicate = super_predicate + .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder())); + if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() { + stack.push(binder.value); + } + } + } + } + + trait_refs } /////////////////////////////////////////////////////////////////////////// From ac1845a6f053d5b1294c13cfb7be202105c34198 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 24 Nov 2020 17:04:44 -0300 Subject: [PATCH 21/28] Fix super_predicates_that_define_assoc_type API doc --- compiler/rustc_middle/src/query/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d7718dea43789..925a05c879bd9 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -442,12 +442,10 @@ rustc_queries! { desc { |tcx| "computing the super traits of `{}`", tcx.def_path_str(key) } } - /// Maps from the `DefId` 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 - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). + /// The `Option` is the name of an associated type. If it is `None`, then this query + /// returns the full set of predicates. If `Some`, then the query returns only the + /// subset of super-predicates that reference traits that define the given associated type. + /// This is used to avoid cycles in resolving types like `T::Item`. query super_predicates_that_define_assoc_type(key: (DefId, Option)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super traits of `{}`{}", tcx.def_path_str(key.0), From 1895e52505b59f49e6675376c44ad8e251c4501c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 24 Nov 2020 17:05:54 -0300 Subject: [PATCH 22/28] Fix super_traits_of API doc --- compiler/rustc_typeck/src/collect.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 6cd4acf5de62c..1ee29001c8468 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1115,9 +1115,9 @@ fn super_predicates_that_define_assoc_type( } } -/// Ensures that the super traits of the trait with a `DefId` -/// of `trait_def_id` are converted and stored. This also ensures that -/// the transitive super traits are converted. +/// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) +/// does not compute the full elaborated super-predicates but just the set of def-ids. It is used +/// to identify which traits may define a given associated type to help avoid cycle errors. fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> FxHashSet { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; From 67ea9b227f7e7f5599ff9e194566ae769e34847d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 24 Nov 2020 17:36:36 -0300 Subject: [PATCH 23/28] Make super_traits_of return Lrc for cheaper clone --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_typeck/src/collect.rs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 925a05c879bd9..aba534ac19f94 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -438,7 +438,7 @@ rustc_queries! { /// Maps from the `DefId` of a trait to the list of /// all the ancestors super traits. - query super_traits_of(key: DefId) -> FxHashSet { + query super_traits_of(key: DefId) -> Lrc> { desc { |tcx| "computing the super traits of `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 1ee29001c8468..21d450eaf6e6c 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -26,6 +26,7 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -1118,7 +1119,8 @@ fn super_predicates_that_define_assoc_type( /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used /// to identify which traits may define a given associated type to help avoid cycle errors. -fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> FxHashSet { +/// Returns `Lrc>` so that cloning is cheaper. +fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Lrc> { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; while let Some(trait_did) = stack.pop() { @@ -1178,7 +1180,7 @@ fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> FxHashSet { } } - set + Lrc::new(set) } fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { From b02a905d93cc1f0134dd3390d1b69991c8e82814 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 25 Nov 2020 10:31:48 -0300 Subject: [PATCH 24/28] Add test to check that we handle predicates that can define assoc types correctly --- .../handle-predicates-that-can-define-assoc-type.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs diff --git a/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs b/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs new file mode 100644 index 0000000000000..b1e54ec04493b --- /dev/null +++ b/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs @@ -0,0 +1,10 @@ +// check-pass + +trait Foo {} +trait Bar { + type A; + type B; +} +trait Baz: Bar + Foo {} + +fn main() {} From a6136d8b8324afbbed8fc7e4c3533d3e509a91fc Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 25 Nov 2020 12:49:48 -0300 Subject: [PATCH 25/28] Simplify super_traits_of --- compiler/rustc_typeck/src/collect.rs | 52 +++------------------------- 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 21d450eaf6e6c..316e88b53840b 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1128,54 +1128,10 @@ fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Lrc continue; } - if trait_did.is_local() { - let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_did.expect_local()); - - let item = match tcx.hir().get(trait_hir_id) { - Node::Item(item) => item, - _ => bug!("super_trait_of {} is not an item", trait_hir_id), - }; - - let (generics, supertraits) = match item.kind { - hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => { - (generics, supertraits) - } - hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), - _ => span_bug!(item.span, "super_predicates invoked on non-trait"), - }; - - for supertrait in supertraits.iter() { - let trait_ref = supertrait.trait_ref(); - if let Some(trait_did) = trait_ref.and_then(|trait_ref| trait_ref.trait_def_id()) { - stack.push(trait_did); - } - } - - let icx = ItemCtxt::new(tcx, trait_did); - // Convert any explicit superbounds in the where-clause, - // e.g., `trait Foo where Self: Bar`. - // In the case of trait aliases, however, we include all bounds in the where-clause, - // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` - // as one of its "superpredicates". - let is_trait_alias = tcx.is_trait_alias(trait_did); - let self_param_ty = tcx.types.self_param; - for (predicate, _) in icx.type_parameter_bounds_in_generics( - generics, - item.hir_id, - self_param_ty, - OnlySelfBounds(!is_trait_alias), - None, - ) { - if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { - stack.push(data.def_id()); - } - } - } else { - let generic_predicates = tcx.super_predicates_of(trait_did); - for (predicate, _) in generic_predicates.predicates { - if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { - stack.push(data.def_id()); - } + let generic_predicates = tcx.super_predicates_of(trait_did); + for (predicate, _) in generic_predicates.predicates { + if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { + stack.push(data.def_id()); } } } From 35bf466a2764abde4c78389c5fc91ca9c4e9ab28 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 25 Nov 2020 12:53:52 -0300 Subject: [PATCH 26/28] Remove super_traits_of query, just leave a helper function --- compiler/rustc_middle/src/query/mod.rs | 6 ------ compiler/rustc_middle/src/ty/context.rs | 23 +++++++++++++++++++++++ compiler/rustc_typeck/src/collect.rs | 25 ------------------------- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index aba534ac19f94..b516810205fef 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -436,12 +436,6 @@ rustc_queries! { desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } } - /// Maps from the `DefId` of a trait to the list of - /// all the ancestors super traits. - query super_traits_of(key: DefId) -> Lrc> { - desc { |tcx| "computing the super traits of `{}`", tcx.def_path_str(key) } - } - /// The `Option` is the name of an associated type. If it is `None`, then this query /// returns the full set of predicates. If `Some`, then the query returns only the /// subset of super-predicates that reference traits that define the given associated type. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b2a8b33e4ff5f..6a60d65661a70 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2095,6 +2095,29 @@ impl<'tcx> TyCtxt<'tcx> { }) } + /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) + /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used + /// to identify which traits may define a given associated type to help avoid cycle errors. + /// Returns `Lrc>` so that cloning is cheaper. + fn super_traits_of(self, trait_def_id: DefId) -> Lrc> { + let mut set = FxHashSet::default(); + let mut stack = vec![trait_def_id]; + while let Some(trait_did) = stack.pop() { + if !set.insert(trait_did) { + continue; + } + + let generic_predicates = self.super_predicates_of(trait_did); + for (predicate, _) in generic_predicates.predicates { + if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { + stack.push(data.def_id()); + } + } + } + + Lrc::new(set) + } + /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 316e88b53840b..28c4da1a7432e 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -26,7 +26,6 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -81,7 +80,6 @@ pub fn provide(providers: &mut Providers) { projection_ty_from_predicates, explicit_predicates_of, super_predicates_of, - super_traits_of, super_predicates_that_define_assoc_type, trait_explicit_predicates_and_bounds, type_param_predicates, @@ -1116,29 +1114,6 @@ fn super_predicates_that_define_assoc_type( } } -/// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) -/// does not compute the full elaborated super-predicates but just the set of def-ids. It is used -/// to identify which traits may define a given associated type to help avoid cycle errors. -/// Returns `Lrc>` so that cloning is cheaper. -fn super_traits_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Lrc> { - let mut set = FxHashSet::default(); - let mut stack = vec![trait_def_id]; - while let Some(trait_did) = stack.pop() { - if !set.insert(trait_did) { - continue; - } - - let generic_predicates = tcx.super_predicates_of(trait_did); - for (predicate, _) in generic_predicates.predicates { - if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { - stack.push(data.def_id()); - } - } - } - - Lrc::new(set) -} - fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let item = tcx.hir().expect_item(hir_id); From 504d27cb0c705a51f437e0e02a19f2e7512fa8ab Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 25 Nov 2020 13:24:05 -0300 Subject: [PATCH 27/28] Make super_traits_of return an iterator --- compiler/rustc_middle/src/ty/context.rs | 27 ++++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6a60d65661a70..744aa39b96c23 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2088,9 +2088,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.super_traits_of(trait_def_id).iter().any(|trait_did| { - self.associated_items(*trait_did) - .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, *trait_did) + self.super_traits_of(trait_def_id).any(|trait_did| { + self.associated_items(trait_did) + .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did) .is_some() }) } @@ -2098,24 +2098,27 @@ impl<'tcx> TyCtxt<'tcx> { /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used /// to identify which traits may define a given associated type to help avoid cycle errors. - /// Returns `Lrc>` so that cloning is cheaper. - fn super_traits_of(self, trait_def_id: DefId) -> Lrc> { + /// Returns a `DefId` iterator. + fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator + 'tcx { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; - while let Some(trait_did) = stack.pop() { - if !set.insert(trait_did) { - continue; - } + set.insert(trait_def_id); + + iter::from_fn(move || -> Option { + let trait_did = stack.pop()?; let generic_predicates = self.super_predicates_of(trait_did); + for (predicate, _) in generic_predicates.predicates { if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { - stack.push(data.def_id()); + if set.insert(data.def_id()) { + stack.push(data.def_id()); + } } } - } - Lrc::new(set) + Some(trait_did) + }) } /// Given a closure signature, returns an equivalent fn signature. Detuples From ada7c1f4292400ca536ec1d65438e5e024ffac18 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 27 Nov 2020 18:45:34 -0300 Subject: [PATCH 28/28] Return FxIndexSet instead of FxHashSet to avoid order errors on different platforms --- compiler/rustc_infer/src/traits/util.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index e084530d17a5e..93863ef1d50c8 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use smallvec::smallvec; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness}; use rustc_span::symbol::Ident; @@ -297,9 +297,9 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>( tcx: TyCtxt<'tcx>, bounds: impl Iterator>, assoc_name: Ident, -) -> FxHashSet> { +) -> FxIndexSet> { let mut stack: Vec<_> = bounds.collect(); - let mut trait_refs = FxHashSet::default(); + let mut trait_refs = FxIndexSet::default(); while let Some(trait_ref) = stack.pop() { if trait_refs.insert(trait_ref) {