diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f8d55192a37..63711f5804d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3781,6 +3781,7 @@ impl<'hir> Node<'hir> { ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => Some(ty), + ItemKind::Impl(impl_item) => Some(&impl_item.self_ty), _ => None, }, Node::TraitItem(it) => match it.kind { diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 1a9de150041..dabe25589a0 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(assert_matches)] +#![feature(associated_type_defaults)] #![feature(iterator_try_collect)] #![feature(let_chains)] #![feature(if_let_guard)] @@ -39,6 +40,7 @@ mod layout_sanity_check; mod needs_drop; mod opaque_types; pub mod representability; +pub mod sig_types; mod structural_match; mod ty; diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 0010570e7b3..90a939c8644 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -53,14 +53,10 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { fn parent(&self) -> Option { match self.tcx.def_kind(self.item) { - DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias => None, DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { Some(self.tcx.local_parent(self.item)) } - other => span_bug!( - self.tcx.def_span(self.item), - "unhandled item with opaque types: {other:?}" - ), + _ => None, } } @@ -98,14 +94,6 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { hir_id == scope } - fn collect_body_and_predicate_taits(&mut self) { - // Look at all where bounds. - self.tcx.predicates_of(self.item).instantiate_identity(self.tcx).visit_with(self); - // An item is allowed to constrain opaques declared within its own body (but not nested within - // nested functions). - self.collect_taits_declared_in_body(); - } - #[instrument(level = "trace", skip(self))] fn collect_taits_declared_in_body(&mut self) { let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(self.item)).value; @@ -132,6 +120,13 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } } +impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> { + fn visit(&mut self, span: Span, value: impl TypeVisitable>) -> ControlFlow { + self.visit_spanned(span, value); + ControlFlow::Continue(()) + } +} + impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { #[instrument(skip(self), ret, level = "trace")] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { @@ -273,37 +268,20 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ let kind = tcx.def_kind(item); trace!(?kind); let mut collector = OpaqueTypeCollector::new(tcx, item); + super::sig_types::walk_types(tcx, item, &mut collector); match kind { - // Walk over the signature of the function-like to find the opaques. - DefKind::AssocFn | DefKind::Fn => { - let ty_sig = tcx.fn_sig(item).instantiate_identity(); - let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap(); - // Walk over the inputs and outputs manually in order to get good spans for them. - collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output()); - for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) { - collector.visit_spanned(hir.span, ty.map_bound(|x| *x)); - } - collector.collect_body_and_predicate_taits(); + DefKind::AssocFn + | DefKind::Fn + | DefKind::Static(_) + | DefKind::Const + | DefKind::AssocConst + | DefKind::AnonConst => { + collector.collect_taits_declared_in_body(); } - // Walk over the type of the item to find opaques. - DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { - let span = match tcx.hir().get_by_def_id(item).ty() { - Some(ty) => ty.span, - _ => tcx.def_span(item), - }; - collector.visit_spanned(span, tcx.type_of(item).instantiate_identity()); - collector.collect_body_and_predicate_taits(); - } - // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` - DefKind::TyAlias | DefKind::AssocTy => { - tcx.type_of(item).instantiate_identity().visit_with(&mut collector); - } - DefKind::OpaqueTy => { - for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() { - collector.visit_spanned(span, pred); - } - } - DefKind::Mod + DefKind::OpaqueTy + | DefKind::TyAlias + | DefKind::AssocTy + | DefKind::Mod | DefKind::Struct | DefKind::Union | DefKind::Enum @@ -322,9 +300,10 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Impl { .. } => {} - // Closures and coroutines are type checked with their parent, so there is no difference here. + // Closures and coroutines are type checked with their parent, so we need to allow all + // opaques from the closure signature *and* from the parent body. DefKind::Closure | DefKind::Coroutine | DefKind::InlineConst => { - return tcx.opaque_types_defined_by(tcx.local_parent(item)); + collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item))); } } tcx.arena.alloc_from_iter(collector.opaques) diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs new file mode 100644 index 00000000000..1ab39974e0f --- /dev/null +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -0,0 +1,129 @@ +//! This module contains helpers for walking all types of +//! a signature, while preserving spans as much as possible + +use std::ops::ControlFlow; + +use rustc_hir::{def::DefKind, def_id::LocalDefId}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::Span; +use rustc_type_ir::visit::TypeVisitable; + +pub trait SpannedTypeVisitor<'tcx> { + type BreakTy = !; + fn visit( + &mut self, + span: Span, + value: impl TypeVisitable>, + ) -> ControlFlow; +} + +pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( + tcx: TyCtxt<'tcx>, + item: LocalDefId, + visitor: &mut V, +) -> ControlFlow { + let kind = tcx.def_kind(item); + trace!(?kind); + match kind { + DefKind::Coroutine => { + match tcx.type_of(item).instantiate_identity().kind() { + ty::Coroutine(_, args, _) => visitor.visit(tcx.def_span(item), args.as_coroutine().sig())?, + _ => bug!(), + } + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + // Walk over the signature of the function-like + DefKind::Closure | DefKind::AssocFn | DefKind::Fn => { + let ty_sig = match kind { + DefKind::Closure => match tcx.type_of(item).instantiate_identity().kind() { + ty::Closure(_, args) => args.as_closure().sig(), + _ => bug!(), + }, + _ => tcx.fn_sig(item).instantiate_identity(), + }; + let hir_sig = tcx.hir().get_by_def_id(item).fn_decl().unwrap(); + // Walk over the inputs and outputs manually in order to get good spans for them. + visitor.visit(hir_sig.output.span(), ty_sig.output()); + for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) { + visitor.visit(hir.span, ty.map_bound(|x| *x))?; + } + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + // Walk over the type behind the alias + DefKind::TyAlias {..} | DefKind::AssocTy | + // Walk over the type of the item + DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { + let span = match tcx.hir().get_by_def_id(item).ty() { + Some(ty) => ty.span, + _ => tcx.def_span(item), + }; + visitor.visit(span, tcx.type_of(item).instantiate_identity()); + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + DefKind::OpaqueTy => { + for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() { + visitor.visit(span, pred)?; + } + } + // Look at field types + DefKind::Struct | DefKind::Union | DefKind::Enum => { + let span = tcx.def_ident_span(item).unwrap(); + visitor.visit(span, tcx.type_of(item).instantiate_identity()); + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + // Does not have a syntactical signature + DefKind::InlineConst => {} + DefKind::Impl { of_trait } => { + if of_trait { + let span = tcx.hir().get_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span; + let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..]; + visitor.visit(span, args)?; + } + let span = match tcx.hir().get_by_def_id(item).ty() { + Some(ty) => ty.span, + _ => tcx.def_span(item), + }; + visitor.visit(span, tcx.type_of(item).instantiate_identity()); + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + }} + DefKind::Trait => { + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + DefKind::TraitAlias => { + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + | DefKind::Variant + | DefKind::ForeignTy + | DefKind::TyParam + | DefKind::ConstParam + | DefKind::Ctor(_, _) + | DefKind::Field + | DefKind::LifetimeParam => { + span_bug!( + tcx.def_span(item), + "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help" + ) + } + // These don't have any types. + | DefKind::ExternCrate + | DefKind::ForeignMod + | DefKind::Macro(_) + | DefKind::GlobalAsm + | DefKind::Mod + | DefKind::Use => {} + } + ControlFlow::Continue(()) +}