Factor signature type walking out of opaque_types_defined_by

This commit is contained in:
Oli Scherer 2023-07-14 11:56:16 +00:00
parent 5c9a74d88b
commit 3121576d70
4 changed files with 155 additions and 44 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -53,14 +53,10 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
fn parent(&self) -> Option<LocalDefId> {
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<TyCtxt<'tcx>>) -> ControlFlow<!> {
self.visit_spanned(span, value);
ControlFlow::Continue(())
}
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> 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)

View File

@ -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<TyCtxt<'tcx>>,
) -> ControlFlow<Self::BreakTy>;
}
pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
tcx: TyCtxt<'tcx>,
item: LocalDefId,
visitor: &mut V,
) -> ControlFlow<V::BreakTy> {
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(())
}