From 3dab259cb9f9ccdce2e86e45dad565f5e2123428 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 2 Feb 2023 18:50:25 +0000 Subject: [PATCH 1/4] Split super_predicates_that_define_assoc_type query from super_predicates_of --- compiler/rustc_hir_analysis/src/collect.rs | 5 +++-- .../rustc_hir_analysis/src/collect/resolve_bound_vars.rs | 3 +-- compiler/rustc_infer/src/traits/util.rs | 6 ++---- compiler/rustc_middle/src/query/keys.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 6 +++--- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 50862e3426238..e8f05ebd61075 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -64,8 +64,9 @@ pub fn provide(providers: &mut Providers) { predicates_defined_on, explicit_predicates_of: predicates_of::explicit_predicates_of, super_predicates_of: predicates_of::super_predicates_of, - super_predicates_that_define_assoc_type: - predicates_of::super_predicates_that_define_assoc_type, + super_predicates_that_define_assoc_type: |tcx, (def_id, assoc_name)| { + predicates_of::super_predicates_that_define_assoc_type(tcx, (def_id, Some(assoc_name))) + }, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 5e4f377a1e7ea..e758fe95d9c29 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1749,8 +1749,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if trait_defines_associated_type_named(def_id) { break Some(bound_vars.into_iter().collect()); } - let predicates = - tcx.super_predicates_that_define_assoc_type((def_id, Some(assoc_name))); + let predicates = tcx.super_predicates_that_define_assoc_type((def_id, assoc_name)); let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index c7f7ed149407a..5ea41177c88af 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -381,10 +381,8 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>( while let Some(trait_ref) = stack.pop() { let anon_trait_ref = tcx.anonymize_bound_vars(trait_ref); if visited.insert(anon_trait_ref) { - let super_predicates = tcx.super_predicates_that_define_assoc_type(( - trait_ref.def_id(), - Some(assoc_name), - )); + let super_predicates = + tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), assoc_name)); for (super_predicate, _) in super_predicates.predicates { let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref); if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() { diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 4a096a2c0e840..3b0eec683de0e 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -230,7 +230,7 @@ impl Key for (LocalDefId, LocalDefId) { } } -impl Key for (DefId, Option) { +impl Key for (DefId, Ident) { type CacheSelector = DefaultCacheSelector; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a0fce4b47ca30..36964b097c934 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -631,10 +631,10 @@ rustc_queries! { /// 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 `{}`{}", + query super_predicates_that_define_assoc_type(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the super traits of `{}` with associated type name `{}`", tcx.def_path_str(key.0), - if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() }, + key.1 } } From 25c342f30a3947323e0112af3ac5baa24a363396 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 2 Feb 2023 20:37:02 +0000 Subject: [PATCH 2/4] Split implied and super predicate queries --- compiler/rustc_hir_analysis/src/collect.rs | 7 +- .../src/collect/predicates_of.rs | 113 +++++++++++++----- compiler/rustc_infer/src/traits/util.rs | 2 +- .../src/rmeta/decoder/cstore_impl.rs | 14 ++- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 +- compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- compiler/rustc_middle/src/query/mod.rs | 6 + .../rustc_trait_selection/src/traits/util.rs | 2 +- .../ambiguous-associated-type2.stderr | 2 +- tests/ui/associated-types/issue-20825.stderr | 2 +- .../cycle-trait-supertrait-direct.stderr | 9 +- .../cycle-trait-supertrait-indirect.stderr | 14 +-- .../infinite-trait-alias-recursion.stderr | 17 +-- tests/ui/issues/issue-12511.stderr | 12 +- tests/ui/issues/issue-20772.stderr | 2 +- .../cyclic-trait-resolution.stderr | 9 +- 16 files changed, 125 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e8f05ebd61075..cbbaf8f857dac 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -64,9 +64,9 @@ pub fn provide(providers: &mut Providers) { predicates_defined_on, explicit_predicates_of: predicates_of::explicit_predicates_of, super_predicates_of: predicates_of::super_predicates_of, - super_predicates_that_define_assoc_type: |tcx, (def_id, assoc_name)| { - predicates_of::super_predicates_that_define_assoc_type(tcx, (def_id, Some(assoc_name))) - }, + implied_predicates_of: predicates_of::implied_predicates_of, + super_predicates_that_define_assoc_type: + predicates_of::super_predicates_that_define_assoc_type, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, @@ -597,6 +597,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } hir::ItemKind::TraitAlias(..) => { tcx.ensure().generics_of(def_id); + tcx.at(it.span).implied_predicates_of(def_id); tcx.at(it.span).super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index fdab87b6acea7..9358ed612921f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -125,7 +125,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // on a trait we need to add in the supertrait bounds and bounds found on // associated types. if let Some(_trait_ref) = is_trait { - predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned()); + predicates.extend(tcx.implied_predicates_of(def_id).predicates.iter().cloned()); } // In default impls, we can assume that the self type implements @@ -534,6 +534,19 @@ pub(super) fn explicit_predicates_of<'tcx>( } } +#[derive(Copy, Clone, Debug)] +pub enum PredicateFilter { + /// All predicates may be implied by the trait + All, + + /// Only traits that reference `Self: ..` are implied by the trait + SelfOnly, + + /// Only traits that reference `Self: ..` and define an associated type + /// with the given ident are implied by the trait + SelfThatDefines(Ident), +} + /// 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. @@ -541,24 +554,42 @@ pub(super) fn super_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { - tcx.super_predicates_that_define_assoc_type((trait_def_id.to_def_id(), None)) + implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly) +} + +pub(super) fn super_predicates_that_define_assoc_type( + tcx: TyCtxt<'_>, + (trait_def_id, assoc_name): (DefId, Ident), +) -> ty::GenericPredicates<'_> { + implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name)) +} + +pub(super) fn implied_predicates_of( + tcx: TyCtxt<'_>, + trait_def_id: LocalDefId, +) -> ty::GenericPredicates<'_> { + if tcx.is_trait_alias(trait_def_id.to_def_id()) { + implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All) + } else { + tcx.super_predicates_of(trait_def_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. -pub(super) fn super_predicates_that_define_assoc_type( +pub(super) fn implied_predicates_with_filter( tcx: TyCtxt<'_>, - (trait_def_id, assoc_name): (DefId, Option), + trait_def_id: DefId, + filter: PredicateFilter, ) -> ty::GenericPredicates<'_> { let Some(trait_def_id) = trait_def_id.as_local() else { // if `assoc_name` is None, then the query should've been redirected to an // external provider - assert!(assoc_name.is_some()); + assert!(matches!(filter, PredicateFilter::SelfThatDefines(_))); return tcx.super_predicates_of(trait_def_id); }; - debug!("local trait"); let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id); let Node::Item(item) = tcx.hir().get(trait_hir_id) else { @@ -573,40 +604,58 @@ pub(super) fn super_predicates_that_define_assoc_type( 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 = if let Some(assoc_name) = assoc_name { - icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name) - } else { - icx.astconv().compute_bounds(self_param_ty, bounds) + let (superbounds, where_bounds_that_match) = match filter { + PredicateFilter::All => ( + // Convert the bounds that follow the colon (or equal in trait aliases) + icx.astconv().compute_bounds(self_param_ty, bounds), + // Also include all where clause bounds + icx.type_parameter_bounds_in_generics( + generics, + item.owner_id.def_id, + self_param_ty, + OnlySelfBounds(false), + None, + ), + ), + PredicateFilter::SelfOnly => ( + // Convert the bounds that follow the colon (or equal in trait aliases) + icx.astconv().compute_bounds(self_param_ty, bounds), + // Include where clause bounds for `Self` + icx.type_parameter_bounds_in_generics( + generics, + item.owner_id.def_id, + self_param_ty, + OnlySelfBounds(true), + None, + ), + ), + PredicateFilter::SelfThatDefines(assoc_name) => ( + // Convert the bounds that follow the colon (or equal) that reference the associated name + icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name), + // Include where clause bounds for `Self` that reference the associated name + icx.type_parameter_bounds_in_generics( + generics, + item.owner_id.def_id, + self_param_ty, + OnlySelfBounds(true), + Some(assoc_name), + ), + ), }; - let superbounds1 = superbounds1.predicates(); - - // 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.to_def_id()); - let superbounds2 = icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_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)); - debug!(?superbounds); + let implied_bounds = &*tcx + .arena + .alloc_from_iter(superbounds.predicates().into_iter().chain(where_bounds_that_match)); + debug!(?implied_bounds); // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. - if assoc_name.is_none() { + if matches!(filter, PredicateFilter::SelfOnly) { // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. - for &(pred, span) in superbounds { + for &(pred, span) in implied_bounds { debug!("superbound: {:?}", pred); if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() { tcx.at(span).super_predicates_of(bound.def_id()); @@ -614,7 +663,7 @@ pub(super) fn super_predicates_that_define_assoc_type( } } - ty::GenericPredicates { parent: None, predicates: superbounds } + ty::GenericPredicates { parent: None, predicates: implied_bounds } } /// Returns the predicates defined on `item_def_id` of the form diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 5ea41177c88af..1f7c7652d94f2 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -192,7 +192,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { // Get predicates declared on the trait. - let predicates = tcx.super_predicates_of(data.def_id()); + let predicates = tcx.implied_predicates_of(data.def_id()); let obligations = predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 3a50d7c93635c..31798afb852c5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -253,7 +253,19 @@ provide! { tcx, def_id, other, cdata, .get(cdata, def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) - } + } + implied_predicates_of => { + cdata + .root + .tables + .implied_predicates_of + .get(cdata, def_id.index) + .map(|lazy| lazy.decode((cdata, tcx))) + .unwrap_or_else(|| { + debug_assert_eq!(tcx.def_kind(def_id), DefKind::Trait); + tcx.super_predicates_of(def_id) + }) + } associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 77ec03165fbf2..dc8fa1ab7d31d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1316,9 +1316,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let default = self.tcx.object_lifetime_default(def_id); record!(self.tables.object_lifetime_default[def_id] <- default); } - if let DefKind::Trait | DefKind::TraitAlias = def_kind { + if let DefKind::Trait = def_kind { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); } + if let DefKind::TraitAlias = def_kind { + record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); + record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); + } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(def_id); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 6dc6041b284ea..569fd20fdfe63 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -372,6 +372,9 @@ define_tables! { explicit_predicates_of: Table>>, generics_of: Table>, super_predicates_of: Table>>, + // As an optimization, we only store this for trait aliases, + // since it's identical to super_predicates_of for traits. + implied_predicates_of: Table>>, type_of: Table>>>, variances_of: Table>, fn_sig: Table>>>, @@ -383,7 +386,6 @@ define_tables! { mir_for_ctfe: Table>>, mir_generator_witnesses: Table>>, promoted_mir: Table>>>, - // FIXME(compiler-errors): Why isn't this a LazyArray? thir_abstract_const: Table>>, impl_parent: Table, impl_polarity: Table, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 36964b097c934..2f6b7a3c860b7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -627,6 +627,12 @@ rustc_queries! { separate_provide_extern } + query implied_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the implied predicates of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } + /// 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_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 00c9a35225881..60630979b34e4 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -115,7 +115,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { } // Get components of trait alias. - let predicates = tcx.super_predicates_of(trait_ref.def_id()); + let predicates = tcx.implied_predicates_of(trait_ref.def_id()); debug!(?predicates); let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { diff --git a/tests/ui/associated-type-bounds/ambiguous-associated-type2.stderr b/tests/ui/associated-type-bounds/ambiguous-associated-type2.stderr index 4162cdaa8dcd8..575b00e09b02c 100644 --- a/tests/ui/associated-type-bounds/ambiguous-associated-type2.stderr +++ b/tests/ui/associated-type-bounds/ambiguous-associated-type2.stderr @@ -5,7 +5,7 @@ LL | trait Baz: Foo + Bar {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which immediately requires computing the super traits of `Baz` with associated type name `Item` again -note: cycle used when computing the super traits of `Baz` +note: cycle used when computing the super predicates of `Baz` --> $DIR/ambiguous-associated-type2.rs:7:1 | LL | trait Baz: Foo + Bar {} diff --git a/tests/ui/associated-types/issue-20825.stderr b/tests/ui/associated-types/issue-20825.stderr index be2bbd448007b..c4dea68b884a2 100644 --- a/tests/ui/associated-types/issue-20825.stderr +++ b/tests/ui/associated-types/issue-20825.stderr @@ -5,7 +5,7 @@ LL | pub trait Processor: Subscriber { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which immediately requires computing the super traits of `Processor` with associated type name `Input` again -note: cycle used when computing the super traits of `Processor` +note: cycle used when computing the super predicates of `Processor` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { diff --git a/tests/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/tests/ui/cycle-trait/cycle-trait-supertrait-direct.stderr index f6ffcc4b5aadc..e2b2aac05ac94 100644 --- a/tests/ui/cycle-trait/cycle-trait-supertrait-direct.stderr +++ b/tests/ui/cycle-trait/cycle-trait-supertrait-direct.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when computing the super predicates of `Chromosome` - --> $DIR/cycle-trait-supertrait-direct.rs:3:1 - | -LL | trait Chromosome: Chromosome { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `Chromosome`... --> $DIR/cycle-trait-supertrait-direct.rs:3:19 | LL | trait Chromosome: Chromosome { | ^^^^^^^^^^ - = note: ...which again requires computing the super predicates of `Chromosome`, completing the cycle + | + = note: ...which immediately requires computing the super predicates of `Chromosome` again note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-supertrait-direct.rs:3:1 | diff --git a/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr b/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr index 0a2284e0efbca..c903e11465768 100644 --- a/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr +++ b/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr @@ -1,26 +1,16 @@ error[E0391]: cycle detected when computing the super predicates of `B` - --> $DIR/cycle-trait-supertrait-indirect.rs:7:1 - | -LL | trait B: C { - | ^^^^^^^^^^ - | -note: ...which requires computing the super traits of `B`... --> $DIR/cycle-trait-supertrait-indirect.rs:7:10 | LL | trait B: C { | ^ -note: ...which requires computing the super predicates of `C`... - --> $DIR/cycle-trait-supertrait-indirect.rs:11:1 | -LL | trait C: B { } - | ^^^^^^^^^^ -note: ...which requires computing the super traits of `C`... +note: ...which requires computing the super predicates 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 super traits of `A` +note: cycle used when computing the super predicates of `A` --> $DIR/cycle-trait-supertrait-indirect.rs:4:10 | LL | trait A: B { diff --git a/tests/ui/infinite/infinite-trait-alias-recursion.stderr b/tests/ui/infinite/infinite-trait-alias-recursion.stderr index b925b3b018c0a..683987b4943da 100644 --- a/tests/ui/infinite/infinite-trait-alias-recursion.stderr +++ b/tests/ui/infinite/infinite-trait-alias-recursion.stderr @@ -1,30 +1,15 @@ error[E0391]: cycle detected when computing the super predicates of `T1` - --> $DIR/infinite-trait-alias-recursion.rs:3:1 - | -LL | trait T1 = T2; - | ^^^^^^^^ - | -note: ...which requires computing the super traits of `T1`... --> $DIR/infinite-trait-alias-recursion.rs:3:12 | LL | trait T1 = T2; | ^^ -note: ...which requires computing the super predicates of `T2`... - --> $DIR/infinite-trait-alias-recursion.rs:6:1 | -LL | trait T2 = T3; - | ^^^^^^^^ -note: ...which requires computing the super traits of `T2`... +note: ...which requires computing the super predicates of `T2`... --> $DIR/infinite-trait-alias-recursion.rs:6:12 | LL | trait T2 = T3; | ^^ note: ...which requires computing the super predicates of `T3`... - --> $DIR/infinite-trait-alias-recursion.rs:8:1 - | -LL | trait T3 = T1 + T3; - | ^^^^^^^^ -note: ...which requires computing the super traits of `T3`... --> $DIR/infinite-trait-alias-recursion.rs:8:12 | LL | trait T3 = T1 + T3; diff --git a/tests/ui/issues/issue-12511.stderr b/tests/ui/issues/issue-12511.stderr index 789a1141c04f9..558aad10946ec 100644 --- a/tests/ui/issues/issue-12511.stderr +++ b/tests/ui/issues/issue-12511.stderr @@ -1,20 +1,10 @@ error[E0391]: cycle detected when computing the super predicates of `T1` - --> $DIR/issue-12511.rs:1:1 - | -LL | trait T1 : T2 { - | ^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `T1`... --> $DIR/issue-12511.rs:1:12 | LL | trait T1 : T2 { | ^^ -note: ...which requires computing the super predicates of `T2`... - --> $DIR/issue-12511.rs:5:1 | -LL | trait T2 : T1 { - | ^^^^^^^^^^^^^ -note: ...which requires computing the super traits of `T2`... +note: ...which requires computing the super predicates of `T2`... --> $DIR/issue-12511.rs:5:12 | LL | trait T2 : T1 { diff --git a/tests/ui/issues/issue-20772.stderr b/tests/ui/issues/issue-20772.stderr index 22b9f5bd4cb9f..416fd8c062fa3 100644 --- a/tests/ui/issues/issue-20772.stderr +++ b/tests/ui/issues/issue-20772.stderr @@ -5,7 +5,7 @@ LL | trait T : Iterator | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which immediately requires computing the super traits of `T` with associated type name `Item` again -note: cycle used when computing the super traits of `T` +note: cycle used when computing the super predicates of `T` --> $DIR/issue-20772.rs:1:1 | LL | trait T : Iterator diff --git a/tests/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr b/tests/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr index 15faab16abeaf..ca98e1831507e 100644 --- a/tests/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr +++ b/tests/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when computing the super predicates of `A` - --> $DIR/cyclic-trait-resolution.rs:1:1 - | -LL | trait A: B + A {} - | ^^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `A`... --> $DIR/cyclic-trait-resolution.rs:1:14 | LL | trait A: B + A {} | ^ - = note: ...which again requires computing the super predicates of `A`, completing the cycle + | + = note: ...which immediately requires computing the super predicates of `A` again note: cycle used when collecting item types in top-level module --> $DIR/cyclic-trait-resolution.rs:1:1 | From 4560b61cd15aa026a03a64c99ead1edf7896826f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 31 Jan 2023 21:22:11 +0000 Subject: [PATCH 3/4] Broken tests --- tests/ui/closures/self-supertrait-bounds.rs | 14 ++++++++ .../ui/lint/unused/trait-alias-supertrait.rs | 15 +++++++++ .../traits/alias/dont-elaborate-non-self.rs | 10 ++++++ .../alias-where-clause-isnt-supertrait.rs | 33 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 tests/ui/closures/self-supertrait-bounds.rs create mode 100644 tests/ui/lint/unused/trait-alias-supertrait.rs create mode 100644 tests/ui/traits/alias/dont-elaborate-non-self.rs create mode 100644 tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs diff --git a/tests/ui/closures/self-supertrait-bounds.rs b/tests/ui/closures/self-supertrait-bounds.rs new file mode 100644 index 0000000000000..f4f1cea6b8176 --- /dev/null +++ b/tests/ui/closures/self-supertrait-bounds.rs @@ -0,0 +1,14 @@ +// check-pass + +// Makes sure that we only consider `Self` supertrait predicates while +// elaborating during closure signature deduction. + +#![feature(trait_alias)] + +trait Confusing = Fn(i32) where F: Fn(u32); + +fn alias, F>(_: T, _: F) {} + +fn main() { + alias(|_| {}, |_| {}); +} diff --git a/tests/ui/lint/unused/trait-alias-supertrait.rs b/tests/ui/lint/unused/trait-alias-supertrait.rs new file mode 100644 index 0000000000000..46f00c06bf1ca --- /dev/null +++ b/tests/ui/lint/unused/trait-alias-supertrait.rs @@ -0,0 +1,15 @@ +// check-pass + +// Make sure that we only consider *Self* supertrait predicates +// in the `unused_must_use` lint. + +#![feature(trait_alias)] +#![deny(unused_must_use)] + +trait Foo = Sized where T: Iterator; + +fn test() -> impl Foo {} + +fn main() { + test::>(); +} diff --git a/tests/ui/traits/alias/dont-elaborate-non-self.rs b/tests/ui/traits/alias/dont-elaborate-non-self.rs new file mode 100644 index 0000000000000..4f9eaacb8ed06 --- /dev/null +++ b/tests/ui/traits/alias/dont-elaborate-non-self.rs @@ -0,0 +1,10 @@ +#![feature(trait_alias)] + +use std::future::Future; + +trait F> = Fn() -> Fut; + +fn f(a: dyn F) {} +//~^ ERROR the size for values of type `(dyn Fn() -> Fut + 'static)` cannot be known at compilation time + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs new file mode 100644 index 0000000000000..4a5e445d1efbe --- /dev/null +++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs @@ -0,0 +1,33 @@ +#![feature(trait_upcasting)] +#![feature(trait_alias)] + +// Although we *elaborate* `T: Alias` to `i32: B`, we should +// not consider `B` to be a supertrait of the type. +trait Alias = A where i32: B; + +trait A {} + +trait B { + fn test(&self); +} + +trait C: Alias {} + +impl A for () {} + +impl C for () {} + +impl B for i32 { + fn test(&self) { + println!("hi {self}"); + } +} + +fn test(x: &dyn C) -> &dyn B { + x + //~^ ERROR mismatched types +} + +fn main() { + let x: &dyn C = &(); +} From 7ec72efe10df28fcf5c6ec13c2a487572041be59 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 2 Feb 2023 21:22:02 +0000 Subject: [PATCH 4/4] Allow the elaborator to only filter to real supertraits --- .../rustc_hir_analysis/src/astconv/mod.rs | 68 ++++++++++--------- compiler/rustc_hir_typeck/src/closure.rs | 5 +- compiler/rustc_infer/src/traits/util.rs | 41 +++++++---- compiler/rustc_lint/src/unused.rs | 2 + .../src/solve/assembly/mod.rs | 5 +- .../alias/dont-elaborate-non-self.stderr | 20 ++++++ .../alias-where-clause-isnt-supertrait.stderr | 14 ++++ 7 files changed, 107 insertions(+), 48 deletions(-) create mode 100644 tests/ui/traits/alias/dont-elaborate-non-self.stderr create mode 100644 tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 37c894348cd4b..8cb95610da080 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1663,39 +1663,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) }); - let existential_projections = projection_bounds.iter().map(|(bound, _)| { - bound.map_bound(|mut b| { - assert_eq!(b.projection_ty.self_ty(), dummy_self); - - // Like for trait refs, verify that `dummy_self` did not leak inside default type - // parameters. - let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return true; + let existential_projections = projection_bounds + .iter() + // We filter out traits that don't have `Self` as their self type above, + // we need to do the same for projections. + .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self) + .map(|(bound, _)| { + bound.map_bound(|mut b| { + assert_eq!(b.projection_ty.self_ty(), dummy_self); + + // Like for trait refs, verify that `dummy_self` did not leak inside default type + // parameters. + let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return true; + } + false + }); + if references_self { + let guar = tcx.sess.delay_span_bug( + span, + "trait object projection bounds reference `Self`", + ); + let substs: Vec<_> = b + .projection_ty + .substs + .iter() + .map(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return tcx.ty_error(guar).into(); + } + arg + }) + .collect(); + b.projection_ty.substs = tcx.mk_substs(&substs); } - false - }); - if references_self { - let guar = tcx - .sess - .delay_span_bug(span, "trait object projection bounds reference `Self`"); - let substs: Vec<_> = b - .projection_ty - .substs - .iter() - .map(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return tcx.ty_error(guar).into(); - } - arg - }) - .collect(); - b.projection_ty.substs = tcx.mk_substs(&substs); - } - ty::ExistentialProjection::erase_self_ty(tcx, b) - }) - }); + ty::ExistentialProjection::erase_self_ty(tcx, b) + }) + }); let regular_trait_predicates = existential_trait_refs .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 15eec42d78641..8c2495e1dd8c5 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -210,7 +210,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // and we want to keep inference generally in the same order of // the registered obligations. predicates.rev(), - ) { + ) + // We only care about self bounds + .filter_only_self() + { debug!(?pred); let bound_predicate = pred.kind(); diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 1f7c7652d94f2..ef01d5d513bbc 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -69,6 +69,7 @@ impl<'tcx> Extend> for PredicateSet<'tcx> { pub struct Elaborator<'tcx, O> { stack: Vec, visited: PredicateSet<'tcx>, + only_self: bool, } /// Describes how to elaborate an obligation into a sub-obligation. @@ -170,7 +171,8 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( tcx: TyCtxt<'tcx>, obligations: impl IntoIterator, ) -> Elaborator<'tcx, O> { - let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) }; + let mut elaborator = + Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), only_self: false }; elaborator.extend_deduped(obligations); elaborator } @@ -185,14 +187,25 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate()))); } + /// Filter to only the supertraits of trait predicates, i.e. only the predicates + /// that have `Self` as their self type, instead of all implied predicates. + pub fn filter_only_self(mut self) -> Self { + self.only_self = true; + self + } + fn elaborate(&mut self, elaboratable: &O) { let tcx = self.visited.tcx; let bound_predicate = elaboratable.predicate().kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { - // Get predicates declared on the trait. - let predicates = tcx.implied_predicates_of(data.def_id()); + // Get predicates implied by the trait, or only super predicates if we only care about self predicates. + let predicates = if self.only_self { + tcx.super_predicates_of(data.def_id()) + } else { + tcx.implied_predicates_of(data.def_id()) + }; let obligations = predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| { @@ -350,18 +363,16 @@ pub fn supertraits<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> impl Iterator> { - let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx); - FilterToTraits::new(elaborate(tcx, [pred])) + elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits() } pub fn transitive_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, ) -> impl Iterator> { - FilterToTraits::new(elaborate( - tcx, - trait_refs.map(|trait_ref| -> ty::Predicate<'tcx> { trait_ref.to_predicate(tcx) }), - )) + elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx))) + .filter_only_self() + .filter_to_traits() } /// A specialized variant of `elaborate` that only elaborates trait references that may @@ -402,18 +413,18 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>( // Other /////////////////////////////////////////////////////////////////////////// +impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> { + fn filter_to_traits(self) -> FilterToTraits { + FilterToTraits { base_iterator: self } + } +} + /// A filter around an iterator of predicates that makes it yield up /// just trait references. pub struct FilterToTraits { base_iterator: I, } -impl FilterToTraits { - fn new(base: I) -> FilterToTraits { - FilterToTraits { base_iterator: base } - } -} - impl<'tcx, I: Iterator>> Iterator for FilterToTraits { type Item = ty::PolyTraitRef<'tcx>; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 35c461f5acee8..1159d11e5c0c8 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -255,6 +255,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned()) + // We only care about self bounds for the impl-trait + .filter_only_self() .find_map(|(pred, _span)| { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Clause(ty::Clause::Trait( diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 12ee80b6722b1..3fb1d49b33808 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -498,7 +498,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let tcx = self.tcx(); let own_bounds: FxIndexSet<_> = bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect(); - for assumption in elaborate(tcx, own_bounds.iter().copied()) { + for assumption in elaborate(tcx, own_bounds.iter().copied()) + // we only care about bounds that match the `Self` type + .filter_only_self() + { // FIXME: Predicates are fully elaborated in the object type's existential bounds // list. We want to only consider these pre-elaborated projections, and not other // projection predicates that we reach by elaborating the principal trait ref, diff --git a/tests/ui/traits/alias/dont-elaborate-non-self.stderr b/tests/ui/traits/alias/dont-elaborate-non-self.stderr new file mode 100644 index 0000000000000..247a4f8128073 --- /dev/null +++ b/tests/ui/traits/alias/dont-elaborate-non-self.stderr @@ -0,0 +1,20 @@ +error[E0277]: the size for values of type `(dyn Fn() -> Fut + 'static)` cannot be known at compilation time + --> $DIR/dont-elaborate-non-self.rs:7:11 + | +LL | fn f(a: dyn F) {} + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Fn() -> Fut + 'static)` + = help: unsized fn params are gated as an unstable feature +help: you can use `impl Trait` as the argument type + | +LL | fn f(a: impl F) {} + | ~~~~ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn f(a: &dyn F) {} + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr new file mode 100644 index 0000000000000..5574a0320895e --- /dev/null +++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/alias-where-clause-isnt-supertrait.rs:27:5 + | +LL | fn test(x: &dyn C) -> &dyn B { + | ------ expected `&dyn B` because of return type +LL | x + | ^ expected trait `B`, found trait `C` + | + = note: expected reference `&dyn B` + found reference `&dyn C` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`.