diff options
| author | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2023-04-25 08:07:44 +0000 |
|---|---|---|
| committer | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2023-05-12 10:26:50 +0000 |
| commit | 4e92f761fe54fc602ec2bf63819e8c973d1facd5 (patch) | |
| tree | ad4824e716785fd097f0c53e5ff4ce74c61770eb /compiler/rustc_ty_utils/src | |
| parent | 6ae803eedfeb57944cd0d2930d9a8b7a606baf4a (diff) | |
| download | rust-4e92f761fe54fc602ec2bf63819e8c973d1facd5.tar.gz rust-4e92f761fe54fc602ec2bf63819e8c973d1facd5.zip | |
Use the opaque_types_defined_by query to cheaply check for whether a hidden type may be registered for an opaque type
Diffstat (limited to 'compiler/rustc_ty_utils/src')
| -rw-r--r-- | compiler/rustc_ty_utils/src/errors.rs | 24 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/opaque_types.rs | 165 |
2 files changed, 164 insertions, 25 deletions
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 3d3fc50e6e5..553bf40ef3a 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -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, +} diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index cdb8e4a439d..25ebb333bf7 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -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 |
