From e8af7257b32c18eeaf1cc84b7272b0f68ce3f21a Mon Sep 17 00:00:00 2001 From: Xiangfei Ding Date: Fri, 4 Jul 2025 15:14:08 +0000 Subject: [PATCH] draft for supertrait item in subtrait impls --- compiler/rustc_ast/src/ast.rs | 16 ++- compiler/rustc_ast/src/visit.rs | 11 +- compiler/rustc_ast_ir/src/lib.rs | 18 +++ compiler/rustc_ast_lowering/src/lib.rs | 10 +- .../rustc_ast_passes/src/ast_validation.rs | 20 ++- compiler/rustc_expand/src/build.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 4 + compiler/rustc_hir/src/hir.rs | 12 +- compiler/rustc_hir_analysis/src/collect.rs | 1 + .../src/collect/predicates_of.rs | 27 ++++ .../src/hir_ty_lowering/bounds.rs | 44 ++++++- compiler/rustc_hir_pretty/src/lib.rs | 9 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 5 + .../src/rmeta/decoder/cstore_impl.rs | 4 + compiler/rustc_metadata/src/rmeta/encoder.rs | 4 + compiler/rustc_metadata/src/rmeta/mod.rs | 4 + compiler/rustc_middle/src/query/mod.rs | 10 ++ .../rustc_middle/src/query/on_disk_cache.rs | 1 + compiler/rustc_middle/src/ty/codec.rs | 11 ++ compiler/rustc_middle/src/ty/context.rs | 4 + compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_middle/src/ty/parameterized.rs | 1 + .../rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse/src/parser/generics.rs | 4 +- compiler/rustc_parse/src/parser/item.rs | 8 +- compiler/rustc_parse/src/parser/path.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 55 ++++++--- compiler/rustc_resolve/messages.ftl | 3 + .../rustc_resolve/src/build_reduced_graph.rs | 5 +- compiler/rustc_resolve/src/diagnostics.rs | 10 ++ compiler/rustc_resolve/src/errors.rs | 10 ++ compiler/rustc_resolve/src/late.rs | 116 ++++++++++++++++-- .../rustc_resolve/src/late/diagnostics.rs | 1 + compiler/rustc_resolve/src/lib.rs | 24 ++++ compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/clean/types.rs | 1 + src/librustdoc/html/format.rs | 2 +- src/librustdoc/json/conversions.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 7 +- tests/ui/stats/input-stats.stderr | 6 +- .../supertrait-in-subtrait-impl.rs | 17 +++ .../supertrait-in-subtrait-impl.stderr | 32 +++++ 42 files changed, 467 insertions(+), 61 deletions(-) create mode 100644 tests/ui/traits/super-subtraits/supertrait-in-subtrait-impl.rs create mode 100644 tests/ui/traits/super-subtraits/supertrait-in-subtrait-impl.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 491a9bbda79b1..ea62ef0b293a2 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -23,7 +23,7 @@ use std::{cmp, fmt}; pub use GenericArgs::*; pub use UnsafeSource::*; -pub use rustc_ast_ir::{Movability, Mutability, Pinnedness}; +pub use rustc_ast_ir::{Movability, Mutability, Pinnedness, TraitRefSource}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -1386,6 +1386,7 @@ impl Expr { ThinVec::new(), path.clone(), TraitBoundModifiers::NONE, + TraitRefSource::Any, self.span, Parens::No, ))), @@ -3382,6 +3383,11 @@ pub struct PolyTraitRef { /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`. pub trait_ref: TraitRef, + /// The source of this trait ref + /// and whether this trait ref should be regarded as + /// a nominal subtrait-supertrait relation. + pub source: TraitRefSource, + pub span: Span, /// When `Yes`, the first and last character of `span` are an opening @@ -3389,11 +3395,18 @@ pub struct PolyTraitRef { pub parens: Parens, } +impl PolyTraitRef { + pub fn is_supertrait(&self) -> bool { + matches!(self.source, TraitRefSource::Supertrait) + } +} + impl PolyTraitRef { pub fn new( generic_params: ThinVec, path: Path, modifiers: TraitBoundModifiers, + source: TraitRefSource, span: Span, parens: Parens, ) -> Self { @@ -3401,6 +3414,7 @@ impl PolyTraitRef { bound_generic_params: generic_params, modifiers, trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID }, + source, span, parens, } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index f8ecff69a7635..db81b807eb019 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -15,6 +15,7 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span}; use thin_vec::ThinVec; @@ -52,7 +53,7 @@ pub enum BoundKind { /// Super traits of a trait. /// E.g., `trait A: B` - SuperTraits, + SuperTraits { subtrait: LocalDefId }, } impl BoundKind { pub fn descr(self) -> &'static str { @@ -60,7 +61,7 @@ impl BoundKind { BoundKind::Bound => "bounds", BoundKind::Impl => "`impl Trait`", BoundKind::TraitObject => "`dyn` trait object bounds", - BoundKind::SuperTraits => "supertrait bounds", + BoundKind::SuperTraits { .. } => "supertrait bounds", } } } @@ -266,8 +267,8 @@ macro_rules! common_visitor_and_walkers { walk_trait_ref(self, t) } - fn visit_param_bound(&mut self, bounds: &$($lt)? $($mut)? GenericBound, _ctxt: BoundKind) -> Self::Result { - walk_param_bound(self, bounds) + fn visit_param_bound(&mut self, bound: &$($lt)? $($mut)? GenericBound, _ctxt: BoundKind) -> Self::Result { + walk_param_bound(self, bound) } fn visit_precise_capturing_arg(&mut self, arg: &$($lt)? $($mut)? PreciseCapturingArg) -> Self::Result { @@ -1142,7 +1143,7 @@ macro_rules! common_visitor_and_walkers { vis: &mut V, p: &$($lt)? $($mut)? PolyTraitRef, ) -> V::Result { - let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ } = p; + let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, .. } = p; try_visit!(visit_modifiers(vis, modifiers)); try_visit!(visit_generic_params(vis, bound_generic_params)); try_visit!(vis.visit_trait_ref(trait_ref)); diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index 0898433a74c53..0146bb3331e4d 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -101,3 +101,21 @@ pub enum Pinnedness { Not, Pinned, } + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +pub enum TraitRefSource { + /// This source excludes all of the other relationships + Any, + /// The trait ref source establishes a subtrait-supertrait + /// relationship + Supertrait, + /// The trait ref source establishes a subtrait-supertrait + /// relationship and we are obliged to assert that the supertrait + /// is a marker trait and generate an automatic `impl` for this + /// marker trait + SupertraitAutoImpl, +} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0706bdb119f01..eef647e9159b6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1208,6 +1208,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bound_generic_params: ThinVec::new(), modifiers: TraitBoundModifiers::NONE, trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, + source: TraitRefSource::Any, span: t.span, parens: ast::Parens::No, }, @@ -2018,7 +2019,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bound_generic_params = self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); let trait_ref = self.lower_trait_ref(p.modifiers, &p.trait_ref, itctx); - let modifiers = self.lower_trait_bound_modifiers(p.modifiers); + let modifiers = self.lower_trait_bound_modifiers(p.modifiers, p.source); hir::PolyTraitRef { bound_generic_params, modifiers, @@ -2253,8 +2254,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_bound_modifiers( &mut self, modifiers: TraitBoundModifiers, + source: TraitRefSource, ) -> hir::TraitBoundModifiers { - hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity } + hir::TraitBoundModifiers { + constness: modifiers.constness, + polarity: modifiers.polarity, + source, + } } // Helper methods for building HIR. diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 53e2a1c695a8f..e24ad48e10831 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -36,6 +36,7 @@ use rustc_session::lint::builtin::{ PATTERNS_IN_FNS_WITHOUT_BODY, }; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; +use rustc_span::def_id::{DefIndex, LocalDefId}; use rustc_span::{Ident, Span, kw, sym}; use rustc_target::spec::{AbiMap, AbiMapping}; use thin_vec::thin_vec; @@ -1149,7 +1150,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span }); self.with_tilde_const(disallowed, |this| { this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) + walk_list!( + this, + visit_param_bound, + bounds, + BoundKind::SuperTraits { + subtrait: LocalDefId { local_def_index: DefIndex::ZERO } + } + ) }); self.with_in_trait(item.span, is_const_trait, |this| { walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); @@ -1373,9 +1381,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match bound { GenericBound::Trait(trait_ref) => { match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds() => - { + ( + BoundKind::SuperTraits { .. }, + BoundConstness::Never, + BoundPolarity::Maybe(_), + ) if !self.features.more_maybe_bounds() => { self.sess .create_feature_err( errors::OptionalTraitSupertrait { @@ -1438,7 +1448,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { GenericBound::Outlives(_) => {} GenericBound::Use(_, span) => match ctxt { BoundKind::Impl => {} - BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => { + BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits { .. } => { self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere { loc: ctxt.descr(), span: *span, diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 85683c1a03ff2..97c970763c6bd 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -194,6 +194,7 @@ impl<'a> ExtCtxt<'a> { asyncness: ast::BoundAsyncness::Normal, }, trait_ref: self.trait_ref(path), + source: ast::TraitRefSource::Any, span, parens: ast::Parens::No, } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 7d9915d7f68b7..4aa379f2e3407 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1260,6 +1260,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ TEST, pattern_complexity_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing, EncodeCrossCrate::No, ), + rustc_attr!( + TEST, rustc_supertrait_in_subtrait_impl, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes, + ), ]; pub fn is_builtin_attr_name(name: Symbol) -> bool { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 559a771931e9c..9527ced6674b5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -12,7 +12,7 @@ use rustc_ast::{ pub use rustc_ast::{ AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, - MetaItemInner, MetaItemLit, Movability, Mutability, UnOp, + MetaItemInner, MetaItemLit, Movability, Mutability, TraitRefSource, UnOp, }; use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fingerprint::Fingerprint; @@ -707,11 +707,15 @@ pub enum GenericArgsParentheses { pub struct TraitBoundModifiers { pub constness: BoundConstness, pub polarity: BoundPolarity, + pub source: TraitRefSource, } impl TraitBoundModifiers { - pub const NONE: Self = - TraitBoundModifiers { constness: BoundConstness::Never, polarity: BoundPolarity::Positive }; + pub const NONE: Self = TraitBoundModifiers { + constness: BoundConstness::Never, + polarity: BoundPolarity::Positive, + source: TraitRefSource::Any, + }; } #[derive(Clone, Copy, Debug, HashStable_Generic)] @@ -4966,7 +4970,7 @@ mod size_asserts { static_assert_size!(ForeignItem<'_>, 96); static_assert_size!(ForeignItemKind<'_>, 56); static_assert_size!(GenericArg<'_>, 16); - static_assert_size!(GenericBound<'_>, 64); + static_assert_size!(GenericBound<'_>, 72); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); static_assert_size!(ImplItem<'_>, 88); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 25064c327d051..a8eb378257018 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -79,6 +79,7 @@ pub(crate) fn provide(providers: &mut Providers) { predicates_of: predicates_of::predicates_of, explicit_predicates_of: predicates_of::explicit_predicates_of, explicit_super_predicates_of: predicates_of::explicit_super_predicates_of, + supertrait_auto_impls: predicates_of::supertrait_auto_impls, explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of, explicit_supertraits_containing_assoc_item: predicates_of::explicit_supertraits_containing_assoc_item, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a93e58b101fe5..c86a71bfbd2d1 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -713,6 +713,33 @@ pub(super) fn implied_predicates_with_filter<'tcx>( ty::EarlyBinder::bind(implied_bounds) } +/// This query collects supertraits that should be implicitly `impl`ed +/// within the context of a subtrait `impl`. +/// In doing so, this subtrait may authorise the compiler to generate `impl`s +/// on marker supertraits. +/// This query also reports the authorisation. +pub(super) fn supertrait_auto_impls<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, hir::TraitRefSource)]> { + let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else { + bug!("trait_def_id {trait_def_id:?} is not an item"); + }; + + let superbounds = match item.kind { + hir::ItemKind::Trait(_, _, _, _, supertraits, _) + | hir::ItemKind::TraitAlias(_, _, supertraits) => supertraits, + _ => span_bug!(item.span, "supertrait_auto_impls invoked on non-trait"), + }; + + let icx = ItemCtxt::new(tcx, trait_def_id); + + let self_param_ty = tcx.types.self_param; + let mut bounds = vec![]; + icx.lowerer().lower_supertrait_auto_impls(self_param_ty, superbounds, &mut bounds); + ty::EarlyBinder::bind(&*tcx.arena.alloc_from_iter(bounds)) +} + // Make sure when elaborating supertraits, probing for associated types, etc., // we really truly are elaborating clauses that have `ty` as their self type. // This is very important since downstream code relies on this being correct. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 4784cfb5235b3..e9844142ae0ba 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -482,7 +482,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { - let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; + let hir::TraitBoundModifiers { constness, polarity, source: _ } = + poly_trait_ref.modifiers; let _ = self.lower_poly_trait_ref( &poly_trait_ref.trait_ref, poly_trait_ref.span, @@ -516,6 +517,47 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + pub(crate) fn lower_supertrait_auto_impls<'hir>( + &self, + param_ty: Ty<'tcx>, + hir_bounds: impl IntoIterator>, + supertrait_auto_impl: &mut Vec<(ty::Clause<'tcx>, hir::TraitRefSource)>, + ) where + 'tcx: 'hir, + { + let predicate_filter = PredicateFilter::SelfOnly; + for hir_bound in hir_bounds { + if self.should_skip_sizedness_bound(hir_bound) { + continue; + } + let hir::GenericBound::Trait(poly_trait_ref) = hir_bound else { continue }; + let hir::TraitBoundModifiers { constness, polarity, source } = poly_trait_ref.modifiers; + if !matches!( + source, + hir::TraitRefSource::Supertrait | hir::TraitRefSource::SupertraitAutoImpl + ) { + continue; + } + let mut bounds = vec![]; + let _ = self.lower_poly_trait_ref( + &poly_trait_ref.trait_ref, + poly_trait_ref.span, + constness, + polarity, + param_ty, + &mut bounds, + predicate_filter, + ); + supertrait_auto_impl.extend(bounds.into_iter().filter_map(|(clause, _)| { + if matches!(clause.kind().skip_binder(), ty::ClauseKind::Trait(..)) { + Some((clause, source)) + } else { + None + } + })); + } + } + /// Lower an associated item constraint from the HIR into `bounds`. /// /// ### A Note on Binders diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index c523a03e012e4..8b6ec6f47d039 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -779,7 +779,14 @@ impl<'a> State<'a> { } fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) { - let hir::TraitBoundModifiers { constness, polarity } = t.modifiers; + let hir::TraitBoundModifiers { constness, polarity, source } = t.modifiers; + match source { + ast::TraitRefSource::Any | ast::TraitRefSource::Supertrait => {} + ast::TraitRefSource::SupertraitAutoImpl => { + self.word("auto"); + self.word("impl"); + } + } match constness { hir::BoundConstness::Never => {} hir::BoundConstness::Always(_) => self.word("const"), diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e6aedc61338bd..e8030e35769a7 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1312,6 +1312,11 @@ impl<'a> CrateMetadataRef<'a> { } } + fn get_module_supertraits(self, id: DefIndex, sess: &'a Session) -> impl Iterator { + let supertraits = self.root.tables.module_supertraits.get(self, id); + supertraits.decode((self, sess)).into_iter() + } + fn is_ctfe_mir_available(self, id: DefIndex) -> bool { self.root.tables.mir_for_ctfe.get(self, id).is_some() } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 6943d4198df43..3e79756715a96 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -247,6 +247,7 @@ provide! { tcx, def_id, other, cdata, inferred_outlives_of => { table_defaulted_array } explicit_super_predicates_of => { table_defaulted_array } explicit_implied_predicates_of => { table_defaulted_array } + supertrait_auto_impls => { table_defaulted_array } type_of => { table } type_alias_is_lazy => { table_direct } variances_of => { table } @@ -389,6 +390,9 @@ provide! { tcx, def_id, other, cdata, module_children => { tcx.arena.alloc_from_iter(cdata.get_module_children(def_id.index, tcx.sess)) } + module_supertraits => { + tcx.arena.alloc_from_iter(cdata.get_module_supertraits(def_id.index, tcx.sess)) + } lib_features => { cdata.get_lib_features() } stability_implications => { cdata.get_stability_implications(tcx).iter().copied().collect() diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b0ec605a85fe5..3448c85c0e60c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1534,6 +1534,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let module_children = self.tcx.module_children_local(local_id); record_array!(self.tables.module_children_non_reexports[def_id] <- module_children.iter().map(|child| child.res.def_id().index)); + record_defaulted_array!(self.tables.module_supertraits[def_id] <- + self.tcx.module_supertraits_local(local_id)); + record_defaulted_array!(self.tables.supertrait_auto_impls[def_id] <- + self.tcx.supertrait_auto_impls(local_id).skip_binder()); if self.tcx.is_const_trait(def_id) { record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id] <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder()); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a962a787a4287..845fd644911da 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -410,6 +410,10 @@ define_tables! { // That's why the encoded list needs to contain `ModChild` structures describing all the names // individually instead of `DefId`s. module_children_reexports: Table>, + // We only propagate just supertrait defs in spite of multiplicity + // because this is only to help with name resolution + module_supertraits: Table>, + supertrait_auto_impls: Table, ty::TraitRefSource)>>, cross_crate_inlinable: Table, - optional: diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 17a29c9ae4b21..bcc3b3df4bf29 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -824,6 +824,12 @@ rustc_queries! { separate_provide_extern } + query supertrait_auto_impls(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, ty::TraitRefSource)]> { + desc { |tcx| "computing the supertrait auto-impls of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } + /// The predicates of the trait that are implied during elaboration. /// /// This is a superset of the super-predicates of the trait, but a subset of the predicates @@ -2140,6 +2146,10 @@ rustc_queries! { desc { |tcx| "collecting child items of module `{}`", tcx.def_path_str(def_id) } separate_provide_extern } + query module_supertraits(def_id: DefId) -> &'tcx [DefId] { + desc { |tcx| "collecting supertraits of module `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + } query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option { desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) } } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index a7ac34428986e..1673e886861a4 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -804,6 +804,7 @@ impl_ref_decoder! {<'tcx> rustc_span::def_id::DefId, rustc_span::def_id::LocalDefId, (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo), + (ty::Clause<'tcx>, ty::TraitRefSource), ty::DeducedParamAttrs, } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 335b889b14dc1..14590159cf480 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -415,6 +415,17 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Spa } } +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> + for [(ty::Clause<'tcx>, ty::TraitRefSource)] +{ + fn decode(decoder: &mut D) -> &'tcx Self { + decoder + .interner() + .arena + .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder))) + } +} + impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::PolyTraitRef<'tcx>, Span)] { fn decode(decoder: &mut D) -> &'tcx Self { decoder diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98b2ce01d89b2..d05a4f4424363 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3357,6 +3357,10 @@ impl<'tcx> TyCtxt<'tcx> { self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..]) } + pub fn module_supertraits_local(self, def_id: LocalDefId) -> &'tcx [DefId] { + self.resolutions(()).module_supertraits.get(&def_id).map_or(&[], |v| &v[..]) + } + pub fn resolver_for_lowering(self) -> &'tcx Steal<(ty::ResolverAstLowering, Arc)> { self.resolver_for_lowering_raw(()).0 } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f1b16ea54e634..83689806a0942 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,7 +27,7 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; -pub use rustc_ast_ir::{Movability, Mutability, try_visit}; +pub use rustc_ast_ir::{Movability, Mutability, TraitRefSource, try_visit}; use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -185,6 +185,7 @@ pub struct ResolverGlobalCtxt { pub extern_crate_map: UnordMap, pub maybe_unused_trait_imports: FxIndexSet, pub module_children: LocalDefIdMap>, + pub module_supertraits: LocalDefIdMap>, pub glob_map: FxIndexMap>, pub main_def: Option, pub trait_impls: FxIndexMap>, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 3858778bfc8fb..ce15d143171a0 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -83,6 +83,7 @@ trivially_parameterized_over_tcx! { ty::IntrinsicDef, rustc_ast::Attribute, rustc_ast::DelimArgs, + rustc_ast::TraitRefSource, rustc_ast::expand::StrippedCfgItem, rustc_attr_data_structures::ConstStability, rustc_attr_data_structures::DefaultBodyStability, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 1df0ccbd8af76..640e1838ffa20 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1670,7 +1670,7 @@ impl<'a> Parser<'a> { } self.bump(); // `+` - let _bounds = self.parse_generic_bounds()?; + let _bounds = self.parse_generic_bounds(false)?; let sub = match &ty.kind { TyKind::Ref(_lifetime, mut_ty) => { let lo = mut_ty.ty.span.shrink_to_lo(); diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 86326341a75ae..db3ff8e5e6d87 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -84,7 +84,7 @@ impl<'a> Parser<'a> { } self.restore_snapshot(snapshot); } - self.parse_generic_bounds()? + self.parse_generic_bounds(false)? } else { Vec::new() }; @@ -528,7 +528,7 @@ impl<'a> Parser<'a> { // or with mandatory equality sign and the second type. let ty = self.parse_ty_for_where_clause()?; if self.eat(exp!(Colon)) { - let bounds = self.parse_generic_bounds()?; + let bounds = self.parse_generic_bounds(false)?; Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate { bound_generic_params: lifetime_defs, bounded_ty: ty, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9ed7124a11c38..817da17422c4a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -898,7 +898,7 @@ impl<'a> Parser<'a> { // Parse optional colon and supertrait bounds. let had_colon = self.eat(exp!(Colon)); let span_at_colon = self.prev_token.span; - let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() }; + let bounds = if had_colon { self.parse_generic_bounds(true)? } else { Vec::new() }; let span_before_eq = self.prev_token.span; if self.eat(exp!(Eq)) { @@ -908,7 +908,8 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::BoundsNotAllowedOnTraitAliases { span }); } - let bounds = self.parse_generic_bounds()?; + // We should collect trait aliases as supertraits. + let bounds = self.parse_generic_bounds(true)?; generics.where_clause = self.parse_where_clause()?; self.expect_semi()?; @@ -995,7 +996,8 @@ impl<'a> Parser<'a> { let mut generics = self.parse_generics()?; // Parse optional colon and param bounds. - let bounds = if self.eat(exp!(Colon)) { self.parse_generic_bounds()? } else { Vec::new() }; + let bounds = + if self.eat(exp!(Colon)) { self.parse_generic_bounds(false)? } else { Vec::new() }; let before_where_clause = self.parse_where_clause()?; let ty = if self.eat(exp!(Eq)) { Some(self.parse_ty()?) } else { None }; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1f4049f197fa8..9339d97e62dd9 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -745,7 +745,7 @@ impl<'a> Parser<'a> { )); } let kind = if self.eat(exp!(Colon)) { - AssocItemConstraintKind::Bound { bounds: self.parse_generic_bounds()? } + AssocItemConstraintKind::Bound { bounds: self.parse_generic_bounds(false)? } } else if self.eat(exp!(Eq)) { self.parse_assoc_equality_term( ident, diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 0c57a8cc5e1a5..9f595538fbe30 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -4,8 +4,8 @@ use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, - Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, - TyKind, UnsafeBinderTy, + Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, + TraitRefSource, Ty, TyKind, UnsafeBinderTy, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult}; @@ -469,7 +469,7 @@ impl<'a> Parser<'a> { }); } Ok(TyKind::TraitObject( - self.parse_generic_bounds_common(allow_plus)?, + self.parse_generic_bounds_common(allow_plus, false)?, TraitObjectSyntax::None, )) } @@ -516,6 +516,7 @@ impl<'a> Parser<'a> { generic_params, path, TraitBoundModifiers::NONE, + TraitRefSource::Any, lo.to(self.prev_token.span), parens, ); @@ -531,7 +532,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, TyKind> { if plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded - bounds.append(&mut self.parse_generic_bounds()?); + bounds.append(&mut self.parse_generic_bounds(false)?); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } @@ -760,7 +761,7 @@ impl<'a> Parser<'a> { } // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds()?; + let bounds = self.parse_generic_bounds(false)?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus; @@ -819,7 +820,7 @@ impl<'a> Parser<'a> { let syntax = TraitObjectSyntax::Dyn; // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds()?; + let bounds = self.parse_generic_bounds(false)?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus; Ok(TyKind::TraitObject(bounds, syntax)) } @@ -850,14 +851,21 @@ impl<'a> Parser<'a> { } } - pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> { - self.parse_generic_bounds_common(AllowPlus::Yes) + pub(super) fn parse_generic_bounds( + &mut self, + in_supertrait_context: bool, + ) -> PResult<'a, GenericBounds> { + self.parse_generic_bounds_common(AllowPlus::Yes, in_supertrait_context) } /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`. /// /// See `parse_generic_bound` for the `BOUND` grammar. - fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> { + fn parse_generic_bounds_common( + &mut self, + allow_plus: AllowPlus, + in_supertrait_context: bool, + ) -> PResult<'a, GenericBounds> { let mut bounds = Vec::new(); // In addition to looping while we find generic bounds: @@ -878,7 +886,7 @@ impl<'a> Parser<'a> { suggestion: self.prev_token.span.until(self.token.span), }); } - bounds.push(self.parse_generic_bound()?); + bounds.push(self.parse_generic_bound(in_supertrait_context)?); if allow_plus == AllowPlus::No || !self.eat_plus() { break; } @@ -906,7 +914,7 @@ impl<'a> Parser<'a> { /// ```ebnf /// BOUND = TY_BOUND | LT_BOUND /// ``` - fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { + fn parse_generic_bound(&mut self, in_supertrait_context: bool) -> PResult<'a, GenericBound> { let lo = self.token.span; let leading_token = self.prev_token; let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No }; @@ -921,7 +929,7 @@ impl<'a> Parser<'a> { let (args, args_span) = self.parse_precise_capturing_args()?; GenericBound::Use(args, use_span.to(args_span)) } else { - self.parse_generic_ty_bound(lo, parens, &leading_token)? + self.parse_generic_ty_bound(lo, parens, in_supertrait_context, &leading_token)? }; Ok(bound) @@ -1112,8 +1120,15 @@ impl<'a> Parser<'a> { &mut self, lo: Span, parens: ast::Parens, + in_supertrait_context: bool, leading_token: &Token, ) -> PResult<'a, GenericBound> { + let auto_impl = if in_supertrait_context && self.eat_keyword(exp!(Auto)) { + self.expect_keyword(exp!(Impl))?; + true + } else { + false + }; let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; let modifiers_lo = self.token.span; @@ -1223,8 +1238,20 @@ impl<'a> Parser<'a> { } } - let poly_trait = - PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens); + let poly_trait = PolyTraitRef::new( + lifetime_defs, + path, + modifiers, + if auto_impl { + TraitRefSource::SupertraitAutoImpl + } else if in_supertrait_context { + TraitRefSource::Supertrait + } else { + TraitRefSource::Any + }, + lo.to(self.prev_token.span), + parens, + ); Ok(GenericBound::Trait(poly_trait)) } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index aa818cc9c4649..7560da8692226 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -403,6 +403,9 @@ resolve_tool_was_already_registered = tool `{$tool}` was already registered .label = already registered here +resolve_supertrait_impl_ambiguous = + `{$name}` is ambiguous among supertraits, it could refer to either `{$one}` or `{$another}` + resolve_trait_impl_duplicate = duplicate definitions with name `{$name}`: .label = duplicate definition diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 650a827ba5644..cc5d4a7014d8d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -201,6 +201,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let parent_scope = ParentScope::module(module, self); self.build_reduced_graph_for_external_crate_res(child, parent_scope) } + // Populate the supertrait `DefId`s if the module is allowed + // to refer to their associated items. + module.supertraits.borrow_mut().extend(self.tcx.module_supertraits(module.def_id())); } /// Builds the reduced graph for a single item in an external crate. @@ -1427,7 +1430,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.feed_visibility(feed, vis); } - if ctxt == AssocCtxt::Trait { + if matches!(ctxt, AssocCtxt::Trait) { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c99bc747fd21d..23687d6fa9cfa 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -20,6 +20,7 @@ use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::print::{FmtPrinter, Printer}; use rustc_session::Session; use rustc_session::lint::builtin::{ ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, @@ -973,6 +974,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trait_item_span, }) .with_code(code), + ResolutionError::SupertraitImplAmbiguous { name, one, another } => { + let mut fmt = FmtPrinter::new(self.tcx, Namespace::ValueNS); + let _ = fmt.print_def_path(one, &[]); + let one = fmt.into_buffer(); + let mut fmt = FmtPrinter::new(self.tcx, Namespace::ValueNS); + let _ = fmt.print_def_path(another, &[]); + let another = fmt.into_buffer(); + self.dcx().create_err(errors::SupertraitImplAmbiguous { span, name, one, another }) + } ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self .dcx() .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }), diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index b34bcb38f844c..7901b915e185f 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1230,6 +1230,16 @@ pub(crate) struct ItemWasCfgOut { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag(resolve_supertrait_impl_ambiguous)] +pub(crate) struct SupertraitImplAmbiguous { + #[primary_span] + pub(crate) span: Span, + pub(crate) name: Ident, + pub(crate) another: String, + pub(crate) one: String, +} + #[derive(Diagnostic)] #[diag(resolve_trait_impl_mismatch)] pub(crate) struct TraitImplMismatch { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 08c4a485f2681..1317bbf3b89e7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -770,6 +770,8 @@ struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Count the number of places a lifetime is used. lifetime_uses: FxHashMap, + + current_subtrait_did: Option, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. @@ -994,16 +996,23 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc span, |this| { this.visit_generic_params(&tref.bound_generic_params, false); - this.smart_resolve_path( - tref.trait_ref.ref_id, - &None, - &tref.trait_ref.path, - PathSource::Trait(AliasPossibility::Maybe), - ); + if tref.is_supertrait() + && let Some(subtrait) = this.current_subtrait_did + { + this.collect_supertrait_defs(subtrait, &tref.trait_ref); + } else { + this.smart_resolve_path( + tref.trait_ref.ref_id, + &None, + &tref.trait_ref.path, + PathSource::Trait(AliasPossibility::Maybe), + ); + } this.visit_trait_ref(&tref.trait_ref); }, ); } + fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id)); let def_kind = self.r.local_def_kind(foreign_item.id); @@ -1449,6 +1458,18 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.resolve_anon_const(v, AnonConstKind::FieldDefaultValue); } } + + #[instrument(level = "debug", skip(self))] + fn visit_param_bound(&mut self, bound: &'ast GenericBound, ctxt: BoundKind) { + if let BoundKind::SuperTraits { subtrait } = ctxt { + let prev_subtrait_did = self.current_subtrait_did; + self.current_subtrait_did = Some(subtrait); + visit::walk_param_bound(self, bound); + self.current_subtrait_did = prev_subtrait_did; + } else { + visit::walk_param_bound(self, bound); + } + } } impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { @@ -1475,6 +1496,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // errors at module scope should always be reported in_func_body: false, lifetime_uses: Default::default(), + current_subtrait_did: None, } } @@ -2604,6 +2626,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn resolve_item(&mut self, item: &'ast Item) { let mod_inner_docs = matches!(item.kind, ItemKind::Mod(..)) && rustdoc::inner_docs(&item.attrs); @@ -2672,12 +2695,21 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Item, generics.span, |this| { - let local_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { - this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits); - this.resolve_trait_items(items); - }); + let local_def_id = this.r.local_def_id(item.id); + this.with_self_rib( + Res::SelfTyParam { trait_: local_def_id.to_def_id() }, + |this| { + this.visit_generics(generics); + debug!(?bounds); + walk_list!( + this, + visit_param_bound, + bounds, + BoundKind::SuperTraits { subtrait: local_def_id } + ); + this.resolve_trait_items(items); + }, + ); }, ); } @@ -3142,7 +3174,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn with_optional_trait_ref( &mut self, opt_trait_ref: Option<&TraitRef>, - self_type: &'ast Ty, + self_type: &Ty, f: impl FnOnce(&mut Self, Option) -> T, ) -> T { let mut new_val = None; @@ -3423,6 +3455,39 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } + #[instrument(level = "debug", skip(self))] + fn collect_supertrait_defs(&mut self, subtrait: LocalDefId, supertrait_ref: &TraitRef) { + let subtrait_module = self.r.expect_module(subtrait.to_def_id()); + let mut subtrait_module_supertraits = subtrait_module.supertraits.borrow_mut(); + + let supertrait_path: Vec<_> = Segment::from_path(&supertrait_ref.path); + let res = self.smart_resolve_path_fragment( + &None, + &supertrait_path, + PathSource::Trait(AliasPossibility::Maybe), + Finalize::new(supertrait_ref.ref_id, supertrait_ref.path.span), + RecordPartialRes::Yes, + None, + ); + + if let Some(did) = res.expect_full_res().opt_def_id() + && did != subtrait.to_def_id() + && subtrait_module_supertraits.insert(did) + && let Some(module) = self.r.get_module(did) + { + let module_supertraits = self.r.supertraits(module).borrow(); + let all_supertraits = module_supertraits.iter().copied().chain([module.def_id()]); + let resolver_module_supertraits = + self.r.module_supertraits.entry(subtrait).or_default(); + // These are the supertraits that come into scope in the future, too + for supertrait in all_supertraits { + resolver_module_supertraits.insert(supertrait); + subtrait_module_supertraits.insert(supertrait); + } + } + } + + #[instrument(level = "debug", skip(self, seen_trait_items, err), fields(current_trait = ?self.current_trait_ref))] fn check_trait_item( &mut self, id: NodeId, @@ -3443,6 +3508,31 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let key = BindingKey::new(ident, ns); let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); debug!(?binding); + if binding.is_none() { + // First resolve the name again in the supertraits + // and we need to resolve it against all of them + // to reject ambiguity. + + for &supertrait in &*module.supertraits.borrow() { + let Some(supertrait_mod) = self.r.get_module(supertrait) else { continue }; + if let Some(supertrait_binding) = + self.r.resolution(supertrait_mod, key).try_borrow().ok().and_then(|r| r.binding) + { + if let Some(another_binding) = binding { + self.report_error( + span, + ResolutionError::SupertraitImplAmbiguous { + name: ident, + one: another_binding.res().def_id(), + another: supertrait_binding.res().def_id(), + }, + ) + } else { + binding = Some(supertrait_binding); + } + } + } + } if binding.is_none() { // We could not find the trait item in the correct namespace. // Check the other namespace to report an error. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a4022691995e7..298f440bef536 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3831,6 +3831,7 @@ fn mk_where_bound_predicate( path: ast::Path { segments: modified_segments, span: DUMMY_SP, tokens: None }, ref_id: DUMMY_NODE_ID, }, + source: ast::TraitRefSource::Any, span: DUMMY_SP, parens: ast::Parens::No, })], diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7162f3a77d350..12d2e5ced7698 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -7,6 +7,7 @@ //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`. // tidy-alphabetical-start +#![allow(unused)] #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] @@ -62,6 +63,7 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::span_bug; +use rustc_middle::ty::data_structures::{IndexMap, IndexSet}; use rustc_middle::ty::{ self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed, @@ -304,6 +306,8 @@ enum ResolutionError<'ra> { }, /// Error E0201: multiple impl items for the same trait item. TraitImplDuplicate { name: Ident, trait_item_span: Span, old_span: Span }, + /// Error E????: supertrait item is ambiguous + SupertraitImplAmbiguous { name: Ident, one: DefId, another: DefId }, /// Inline asm `sym` operand must refer to a `fn` or `static`. InvalidAsmSym, /// `self` used instead of `Self` in a generic parameter @@ -580,6 +584,9 @@ struct ModuleData<'ra> { /// Used to memoize the traits in this module for faster searches through all traits in scope. traits: RefCell)]>>>, + /// In case supertraits are relevant in the module, the DefIds are collected, too. + supertraits: RefCell>, + /// Span of the module itself. Used for error reporting. span: Span, @@ -627,6 +634,7 @@ impl<'ra> ModuleData<'ra> { glob_importers: RefCell::new(Vec::new()), globs: RefCell::new(Vec::new()), traits: RefCell::new(None), + supertraits: RefCell::new(Default::default()), span, expansion, } @@ -1229,6 +1237,7 @@ pub struct Resolver<'ra, 'tcx> { // that were encountered during resolution. These names are used to generate item names // for APITs, so we don't want to leak details of resolution into these names. impl_trait_names: FxHashMap, + module_supertraits: IndexMap>, } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1486,6 +1495,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { extra_lifetime_params_map: Default::default(), extern_crate_map: Default::default(), module_children: Default::default(), + module_supertraits: Default::default(), trait_map: NodeMap::default(), underscore_disambiguator: 0, empty_module, @@ -1669,6 +1679,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { effective_visibilities, extern_crate_map, module_children: self.module_children, + module_supertraits: self + .module_supertraits + .into_iter() + .map(|(did, supertraits)| (did, supertraits.into_iter().collect())) + .collect(), glob_map, maybe_unused_trait_imports, main_def, @@ -1807,6 +1822,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { found_traits } + /// Collect all trait items in the given module fn traits_in_module( &mut self, module: Module<'ra>, @@ -1881,6 +1897,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &module.0.0.lazy_resolutions } + fn supertraits(&mut self, module: Module<'ra>) -> &'ra RefCell> { + if module.populate_on_access.get() { + module.populate_on_access.set(false); + self.build_reduced_graph_external(module); + } + &module.0.0.supertraits + } + fn resolution( &mut self, module: Module<'ra>, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 09f01d8704e2a..cfe85daf52653 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1899,6 +1899,7 @@ symbols! { rustc_specialization_trait, rustc_std_internal_symbol, rustc_strict_coherence, + rustc_supertrait_in_subtrait_impl, rustc_symbol_name, rustc_test_marker, rustc_then_this_would_need, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index de920469fdca6..a587772e03754 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1279,6 +1279,7 @@ impl GenericBound { hir::TraitBoundModifiers { polarity: hir::BoundPolarity::Maybe(DUMMY_SP), constness: hir::BoundConstness::Never, + source: hir::TraitRefSource::Any, }, ) } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bcb3e57c84428..b0c4652027f45 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -269,7 +269,7 @@ impl clean::GenericBound { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), clean::GenericBound::TraitBound(ty, modifiers) => { // `const` and `[const]` trait bounds are experimental; don't render them. - let hir::TraitBoundModifiers { polarity, constness: _ } = modifiers; + let hir::TraitBoundModifiers { polarity, constness: _, source: _ } = modifiers; f.write_str(match polarity { hir::BoundPolarity::Positive => "", hir::BoundPolarity::Maybe(_) => "?", diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f51b35097f66a..ca4b41378c9e7 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -517,7 +517,7 @@ impl FromClean for TraitBoundModifier { _renderer: &JsonRenderer<'_>, ) -> Self { use rustc_hir as hir; - let hir::TraitBoundModifiers { constness, polarity } = modifiers; + let hir::TraitBoundModifiers { constness, polarity, source: _ } = modifiers; match (constness, polarity) { (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None, (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c37231d093129..56423b3c0755b 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1223,9 +1223,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } pub fn hash_modifiers(&mut self, modifiers: TraitBoundModifiers) { - let TraitBoundModifiers { constness, polarity } = modifiers; + let TraitBoundModifiers { + constness, + polarity, + source, + } = modifiers; std::mem::discriminant(&polarity).hash(&mut self.s); std::mem::discriminant(&constness).hash(&mut self.s); + std::mem::discriminant(&source).hash(&mut self.s); } pub fn hash_stmt(&mut self, b: &Stmt<'_>) { diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index eb038bbcaf1a2..af855f74d9b0c 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -90,9 +90,9 @@ hir-stats Pat 360 (NN.N%) 5 72 hir-stats - Struct 72 (NN.N%) 1 hir-stats - Wild 72 (NN.N%) 1 hir-stats - Binding 216 (NN.N%) 3 +hir-stats GenericBound 288 (NN.N%) 4 72 +hir-stats - Trait 288 (NN.N%) 4 hir-stats Block 288 (NN.N%) 6 48 -hir-stats GenericBound 256 (NN.N%) 4 64 -hir-stats - Trait 256 (NN.N%) 4 hir-stats Attribute 200 (NN.N%) 5 40 hir-stats Variant 144 (NN.N%) 2 72 hir-stats GenericArgs 144 (NN.N%) 3 48 @@ -119,5 +119,5 @@ hir-stats Mod 32 (NN.N%) 1 32 hir-stats Lifetime 28 (NN.N%) 1 28 hir-stats ForeignItemRef 24 (NN.N%) 1 24 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_716 173 +hir-stats Total 8_748 173 hir-stats ================================================================ diff --git a/tests/ui/traits/super-subtraits/supertrait-in-subtrait-impl.rs b/tests/ui/traits/super-subtraits/supertrait-in-subtrait-impl.rs new file mode 100644 index 0000000000000..138dc20c4608b --- /dev/null +++ b/tests/ui/traits/super-subtraits/supertrait-in-subtrait-impl.rs @@ -0,0 +1,17 @@ +#![feature(rustc_attrs)] + +trait Sup { + type A; +} + +#[rustc_supertrait_in_subtrait_impl] +trait Sub: Sup {} + +struct S; +impl Sub for S { + //~^ ERROR: the trait bound `S: Sup` is not satisfied + type A = (); + //~^ ERROR: the trait bound `S: Sup` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/super-subtraits/supertrait-in-subtrait-impl.stderr b/tests/ui/traits/super-subtraits/supertrait-in-subtrait-impl.stderr new file mode 100644 index 0000000000000..da419f21abc6e --- /dev/null +++ b/tests/ui/traits/super-subtraits/supertrait-in-subtrait-impl.stderr @@ -0,0 +1,32 @@ +error[E0277]: the trait bound `S: Sup` is not satisfied + --> $DIR/supertrait-in-subtrait-impl.rs:13:14 + | +LL | type A = (); + | ^^ the trait `Sup` is not implemented for `S` + | +help: this trait has no implementations, consider adding one + --> $DIR/supertrait-in-subtrait-impl.rs:3:1 + | +LL | trait Sup { + | ^^^^^^^^^ + +error[E0277]: the trait bound `S: Sup` is not satisfied + --> $DIR/supertrait-in-subtrait-impl.rs:11:14 + | +LL | impl Sub for S { + | ^ the trait `Sup` is not implemented for `S` + | +help: this trait has no implementations, consider adding one + --> $DIR/supertrait-in-subtrait-impl.rs:3:1 + | +LL | trait Sup { + | ^^^^^^^^^ +note: required by a bound in `Sub` + --> $DIR/supertrait-in-subtrait-impl.rs:8:12 + | +LL | trait Sub: Sup {} + | ^^^ required by this bound in `Sub` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.