Use the opaque_types_defined_by query to cheaply check for whether a hidden type may be registered for an opaque type
This commit is contained in:
parent
6ae803eedf
commit
4e92f761fe
17 changed files with 368 additions and 162 deletions
|
@ -1,7 +1,7 @@
|
|||
//! Errors emitted by ty_utils
|
||||
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::{GenericArg, Ty};
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> {
|
|||
pub ty: Ty<'tcx>,
|
||||
pub e_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ty_utils_impl_trait_duplicate_arg)]
|
||||
pub struct DuplicateArg<'tcx> {
|
||||
pub arg: GenericArg<'tcx>,
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[note]
|
||||
pub opaque_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ty_utils_impl_trait_not_param)]
|
||||
pub struct NotParam<'tcx> {
|
||||
pub arg: GenericArg<'tcx>,
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[note]
|
||||
pub opaque_span: Span,
|
||||
}
|
||||
|
|
|
@ -1,46 +1,165 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::{def::DefKind, def_id::LocalDefId};
|
||||
use rustc_middle::ty::util::CheckRegions;
|
||||
use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use rustc_span::Span;
|
||||
use rustc_type_ir::AliasKind;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::errors::{DuplicateArg, NotParam};
|
||||
|
||||
struct OpaqueTypeCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaques: Vec<LocalDefId>,
|
||||
/// The `DefId` of the item which we are collecting opaque types for.
|
||||
item: LocalDefId,
|
||||
|
||||
/// Avoid infinite recursion due to recursive declarations.
|
||||
seen: FxHashSet<LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> OpaqueTypeCollector<'tcx> {
|
||||
fn collect(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: LocalDefId,
|
||||
val: ty::Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>,
|
||||
) -> Vec<LocalDefId> {
|
||||
let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() };
|
||||
val.skip_binder().visit_with(&mut collector);
|
||||
collector.opaques
|
||||
}
|
||||
|
||||
fn span(&self) -> Span {
|
||||
self.tcx.def_span(self.item)
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<LocalDefId> {
|
||||
match self.tcx.def_kind(self.item) {
|
||||
DefKind::Fn => 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:?}"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
|
||||
type BreakTy = ErrorGuaranteed;
|
||||
|
||||
#[instrument(skip(self), ret, level = "trace")]
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> {
|
||||
match t.kind() {
|
||||
ty::Alias(AliasKind::Opaque, alias_ty) => {
|
||||
if let Some(def_id) = alias_ty.def_id.as_local() {
|
||||
if self
|
||||
.tcx
|
||||
.uses_unique_generic_params(alias_ty.substs, CheckRegions::OnlyEarlyBound)
|
||||
.is_ok()
|
||||
{
|
||||
self.opaques.push(def_id);
|
||||
return ControlFlow::Continue(());
|
||||
} else {
|
||||
warn!(?t, "opaque types with non-unique params in sig: {t:?}");
|
||||
ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
|
||||
if !self.seen.insert(alias_ty.def_id.expect_local()) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) {
|
||||
Ok(()) => {
|
||||
// FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
|
||||
// supported at all, so this is sound to do, but once we want to support them, you'll
|
||||
// start seeing the error below.
|
||||
|
||||
self.opaques.push(alias_ty.def_id.expect_local());
|
||||
|
||||
// Collect opaque types nested within the associated type bounds of this opaque type.
|
||||
for (pred, _span) in self
|
||||
.tcx
|
||||
.explicit_item_bounds(alias_ty.def_id)
|
||||
.subst_iter_copied(self.tcx, alias_ty.substs)
|
||||
{
|
||||
trace!(?pred);
|
||||
pred.visit_with(self)?;
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
Err(NotUniqueParam::NotParam(arg)) => {
|
||||
let err = self.tcx.sess.emit_err(NotParam {
|
||||
arg,
|
||||
span: self.span(),
|
||||
opaque_span: self.tcx.def_span(alias_ty.def_id),
|
||||
});
|
||||
ControlFlow::Break(err)
|
||||
}
|
||||
Err(NotUniqueParam::DuplicateParam(arg)) => {
|
||||
let err = self.tcx.sess.emit_err(DuplicateArg {
|
||||
arg,
|
||||
span: self.span(),
|
||||
opaque_span: self.tcx.def_span(alias_ty.def_id),
|
||||
});
|
||||
ControlFlow::Break(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
ty::Alias(AliasKind::Projection, alias_ty) => {
|
||||
if let Some(parent) = self.parent() {
|
||||
trace!(?alias_ty);
|
||||
let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx);
|
||||
|
||||
trace!(?trait_ref, ?own_substs);
|
||||
// This avoids having to do normalization of `Self::AssocTy` by only
|
||||
// supporting the case of a method defining opaque types from assoc types
|
||||
// in the same impl block.
|
||||
if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() {
|
||||
for assoc in self.tcx.associated_items(parent).in_definition_order() {
|
||||
trace!(?assoc);
|
||||
if assoc.trait_item_def_id == Some(alias_ty.def_id) {
|
||||
// We reconstruct the generic args of the associated type within the impl
|
||||
// from the impl's generics and the generic args passed to the type via the
|
||||
// projection.
|
||||
let substs = ty::InternalSubsts::identity_for_item(
|
||||
self.tcx,
|
||||
parent.to_def_id(),
|
||||
);
|
||||
trace!(?substs);
|
||||
let substs: Vec<_> =
|
||||
substs.iter().chain(own_substs.iter().copied()).collect();
|
||||
trace!(?substs);
|
||||
// Find opaque types in this associated type.
|
||||
return self
|
||||
.tcx
|
||||
.type_of(assoc.def_id)
|
||||
.subst(self.tcx, &substs)
|
||||
.visit_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] {
|
||||
// FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT.
|
||||
match tcx.def_kind(item) {
|
||||
DefKind::Fn | DefKind::AssocFn => {
|
||||
let sig = tcx.fn_sig(item).subst_identity();
|
||||
let mut collector = OpaqueTypeCollector { tcx, opaques: Vec::new() };
|
||||
sig.visit_with(&mut collector);
|
||||
tcx.arena.alloc_from_iter(collector.opaques)
|
||||
let kind = tcx.def_kind(item);
|
||||
trace!(?kind);
|
||||
// FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types.
|
||||
match kind {
|
||||
// We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
|
||||
let defined_opaques = match kind {
|
||||
DefKind::Fn => {
|
||||
OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity())
|
||||
}
|
||||
DefKind::AssocFn => {
|
||||
OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity())
|
||||
}
|
||||
DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect(
|
||||
tcx,
|
||||
item,
|
||||
ty::Binder::dummy(tcx.type_of(item).subst_identity()),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
tcx.arena.alloc_from_iter(defined_opaques)
|
||||
}
|
||||
DefKind::Mod
|
||||
| DefKind::Struct
|
||||
|
@ -51,13 +170,11 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [
|
|||
| DefKind::TyAlias
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::AssocTy
|
||||
| DefKind::TyParam
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Ctor(_, _)
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Macro(_)
|
||||
| DefKind::ExternCrate
|
||||
| DefKind::Use
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue