Skip to content

Commit 4e92f76

Browse files
committed
Use the opaque_types_defined_by query to cheaply check for whether a hidden type may be registered for an opaque type
1 parent 6ae803e commit 4e92f76

File tree

17 files changed

+368
-162
lines changed

17 files changed

+368
-162
lines changed

Diff for: compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
735735
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
736736
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
737737
&& let Some(def_id) = def_id.as_local()
738-
&& self.opaque_type_origin(def_id, self.param_env).is_some() {
738+
&& self.opaque_type_origin(def_id).is_some() {
739739
return None;
740740
}
741741
}

Diff for: compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use crate::infer::opaque_types::may_define_impl_trait_in_assoc_ty_modulo_sig;
2-
31
use super::TypeErrCtxt;
42
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
53
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
64
use rustc_hir as hir;
7-
use rustc_middle::traits::ObligationCauseCode::{self, MiscObligation};
5+
use rustc_hir::def::DefKind;
6+
use rustc_middle::traits::ObligationCauseCode;
87
use rustc_middle::ty::error::ExpectedFound;
98
use rustc_middle::ty::print::Printer;
109
use rustc_middle::{
@@ -258,9 +257,9 @@ impl<T> Trait<T> for X {
258257
);
259258
}
260259
}
261-
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if matches!(cause.code(), MiscObligation) => {
262-
if let Some(def_id) = alias.def_id.as_local() {
263-
if may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, body_owner_def_id.expect_local(), def_id).is_some() {
260+
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => {
261+
if tcx.is_type_alias_impl_trait(alias.def_id) {
262+
if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
264263
diag.span_note(tcx.def_span(body_owner_def_id), "\
265264
this item must have the opaque type in its signature \
266265
in order to be able to register hidden types");

Diff for: compiler/rustc_infer/src/infer/opaque_types.rs

+8-118
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ use super::{DefineOpaqueTypes, InferResult};
33
use crate::errors::OpaqueHiddenTypeDiag;
44
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
55
use crate::traits;
6-
use hir::def::DefKind;
76
use hir::def_id::{DefId, LocalDefId};
87
use hir::OpaqueTyOrigin;
9-
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
8+
use rustc_data_structures::fx::FxIndexMap;
109
use rustc_data_structures::sync::Lrc;
1110
use rustc_hir as hir;
1211
use rustc_middle::traits::ObligationCause;
@@ -54,9 +53,7 @@ impl<'tcx> InferCtxt<'tcx> {
5453
}
5554
let mut obligations = vec![];
5655
let replace_opaque_type = |def_id: DefId| {
57-
def_id
58-
.as_local()
59-
.map_or(false, |def_id| self.opaque_type_origin(def_id, param_env).is_some())
56+
def_id.as_local().map_or(false, |def_id| self.opaque_type_origin(def_id).is_some())
6057
};
6158
let value = value.fold_with(&mut BottomUpFolder {
6259
tcx: self.tcx,
@@ -141,7 +138,7 @@ impl<'tcx> InferCtxt<'tcx> {
141138
// let x = || foo(); // returns the Opaque assoc with `foo`
142139
// }
143140
// ```
144-
self.opaque_type_origin(def_id, param_env)?
141+
self.opaque_type_origin(def_id)?
145142
}
146143
DefiningAnchor::Bubble => self.opaque_type_origin_unchecked(def_id),
147144
DefiningAnchor::Error => return None,
@@ -152,9 +149,8 @@ impl<'tcx> InferCtxt<'tcx> {
152149
// no one encounters it in practice.
153150
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
154151
// where it is of no concern, so we only check for TAITs.
155-
if let Some(OpaqueTyOrigin::TyAlias { .. }) = b_def_id
156-
.as_local()
157-
.and_then(|b_def_id| self.opaque_type_origin(b_def_id, param_env))
152+
if let Some(OpaqueTyOrigin::TyAlias { .. }) =
153+
b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
158154
{
159155
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
160156
span: cause.span,
@@ -370,12 +366,8 @@ impl<'tcx> InferCtxt<'tcx> {
370366

371367
/// Returns the origin of the opaque type `def_id` if we're currently
372368
/// in its defining scope.
373-
#[instrument(skip(self, param_env), level = "trace", ret)]
374-
pub fn opaque_type_origin(
375-
&self,
376-
def_id: LocalDefId,
377-
param_env: ty::ParamEnv<'tcx>,
378-
) -> Option<OpaqueTyOrigin> {
369+
#[instrument(skip(self), level = "trace", ret)]
370+
pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
379371
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
380372
let parent_def_id = match self.defining_use_anchor {
381373
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
@@ -391,7 +383,7 @@ impl<'tcx> InferCtxt<'tcx> {
391383
// Named `type Foo = impl Bar;`
392384
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
393385
if in_assoc_ty {
394-
may_define_impl_trait_in_assoc_ty(self.tcx, parent_def_id, def_id, param_env)
386+
self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id)
395387
} else {
396388
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
397389
}
@@ -654,105 +646,3 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi
654646
);
655647
res
656648
}
657-
658-
#[derive(Debug, TypeVisitable, Clone)]
659-
/// Helper datastructure containing the signature
660-
/// that the opaque type extraction logic uses for determining
661-
/// whether an opaque type may have its hidden types registered
662-
/// by an item.
663-
enum FnSigOrTy<'tcx> {
664-
FnSig(ty::PolyFnSig<'tcx>),
665-
Ty(Ty<'tcx>),
666-
}
667-
668-
/// Checks that the item may register hidden types for the
669-
/// opaque type, if the opaque type shows up in its signature.
670-
#[instrument(level = "debug", skip(tcx), ret)]
671-
pub fn may_define_impl_trait_in_assoc_ty_modulo_sig<'tcx>(
672-
tcx: TyCtxt<'tcx>,
673-
def_id: LocalDefId,
674-
opaque_def_id: LocalDefId,
675-
) -> Option<impl TypeVisitable<TyCtxt<'tcx>>> {
676-
let sig = match tcx.def_kind(def_id) {
677-
DefKind::AssocFn => FnSigOrTy::FnSig(tcx.fn_sig(def_id).subst_identity()),
678-
DefKind::AssocConst | DefKind::AssocTy => {
679-
FnSigOrTy::Ty(tcx.type_of(def_id).subst_identity())
680-
}
681-
_ => return None,
682-
};
683-
let impl_id = tcx.local_parent(def_id);
684-
trace!(?impl_id);
685-
let mut assoc_id = opaque_def_id;
686-
// Peel nested opaque types.
687-
while let DefKind::OpaqueTy = tcx.def_kind(assoc_id) {
688-
trace!(?assoc_id);
689-
assoc_id = tcx.local_parent(assoc_id);
690-
}
691-
trace!(?assoc_id);
692-
if !matches!(tcx.def_kind(assoc_id), DefKind::AssocTy) {
693-
tcx.sess
694-
.delay_span_bug(tcx.def_span(opaque_def_id), format!("{:?}", tcx.def_kind(assoc_id)));
695-
}
696-
let assoc_impl_id = tcx.local_parent(assoc_id);
697-
trace!(?assoc_impl_id);
698-
699-
if impl_id != assoc_impl_id {
700-
return None;
701-
}
702-
703-
Some(sig)
704-
}
705-
706-
#[instrument(level = "debug", skip(tcx, param_env), ret)]
707-
fn may_define_impl_trait_in_assoc_ty<'tcx>(
708-
tcx: TyCtxt<'tcx>,
709-
def_id: LocalDefId,
710-
opaque_def_id: LocalDefId,
711-
param_env: ty::ParamEnv<'tcx>,
712-
) -> bool {
713-
let Some(sig) = may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, def_id, opaque_def_id) else {
714-
return false;
715-
};
716-
717-
struct Visitor<'tcx> {
718-
opaque_def_id: LocalDefId,
719-
param_env: ty::ParamEnv<'tcx>,
720-
tcx: TyCtxt<'tcx>,
721-
seen: FxHashSet<LocalDefId>,
722-
}
723-
724-
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
725-
type BreakTy = ();
726-
#[instrument(level = "trace", skip(self), ret)]
727-
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
728-
// FIXME(oli-obk): We should be checking if the associated type
729-
// is mentioned instead of normalizing to find the opaque type.
730-
// But that requires a way to figure out that a projection refers
731-
// to a specific opaque type. That is probably doable by checking for
732-
// `Self` as the `substs[0]`.
733-
let normalized_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
734-
if let ty::Alias(ty::Opaque, alias) = normalized_ty.kind() {
735-
if let Some(def_id) = alias.def_id.as_local() {
736-
trace!(?alias.def_id);
737-
if def_id == self.opaque_def_id {
738-
return ControlFlow::Break(());
739-
}
740-
741-
if self.seen.insert(def_id) {
742-
// Look into nested obligations like `impl Trait<Assoc = impl OtherTrait>`.
743-
for (pred, _) in self
744-
.tcx
745-
.explicit_item_bounds(alias.def_id)
746-
.subst_iter_copied(self.tcx, alias.substs)
747-
{
748-
pred.visit_with(self)?;
749-
}
750-
}
751-
}
752-
}
753-
normalized_ty.super_visit_with(self)
754-
}
755-
}
756-
sig.visit_with(&mut Visitor { opaque_def_id, param_env, tcx, seen: Default::default() })
757-
.is_break()
758-
}

Diff for: compiler/rustc_middle/src/query/erase.rs

+4
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
172172
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
173173
}
174174

175+
impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
176+
type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
177+
}
178+
175179
impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
176180
type Result = [u8; size_of::<(&'static (), &'static ())>()];
177181
}

Diff for: compiler/rustc_middle/src/ty/sty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ impl<'tcx> AliasTy<'tcx> {
12651265

12661266
/// Extracts the underlying trait reference and own substs from this projection.
12671267
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
1268-
/// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
1268+
/// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own substs
12691269
pub fn trait_ref_and_own_substs(
12701270
self,
12711271
tcx: TyCtxt<'tcx>,

Diff for: compiler/rustc_middle/src/ty/util.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ pub struct Discr<'tcx> {
3636
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3737
pub enum CheckRegions {
3838
No,
39+
/// Only permit early bound regions. This is useful for Adts which
40+
/// can never have late bound regions.
3941
OnlyEarlyBound,
42+
/// Permit both late bound and early bound regions. Use this for functions,
43+
/// which frequently have late bound regions.
44+
Bound,
4045
}
4146

4247
#[derive(Copy, Clone, Debug)]
@@ -471,15 +476,21 @@ impl<'tcx> TyCtxt<'tcx> {
471476
ignore_regions: CheckRegions,
472477
) -> Result<(), NotUniqueParam<'tcx>> {
473478
let mut seen = GrowableBitSet::default();
479+
let mut seen_late = FxHashSet::default();
474480
for arg in substs {
475481
match arg.unpack() {
476482
GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) {
477-
(CheckRegions::OnlyEarlyBound, ty::ReEarlyBound(p)) => {
483+
(CheckRegions::Bound, ty::ReLateBound(di, reg)) => {
484+
if !seen_late.insert((di, reg)) {
485+
return Err(NotUniqueParam::DuplicateParam(lt.into()));
486+
}
487+
}
488+
(CheckRegions::OnlyEarlyBound | CheckRegions::Bound, ty::ReEarlyBound(p)) => {
478489
if !seen.insert(p.index) {
479490
return Err(NotUniqueParam::DuplicateParam(lt.into()));
480491
}
481492
}
482-
(CheckRegions::OnlyEarlyBound, _) => {
493+
(CheckRegions::OnlyEarlyBound | CheckRegions::Bound, _) => {
483494
return Err(NotUniqueParam::NotParam(lt.into()));
484495
}
485496
(CheckRegions::No, _) => {}

Diff for: compiler/rustc_ty_utils/messages.ftl

+8
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,11 @@ ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with
5555
ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes}
5656
5757
ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}`
58+
59+
ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope
60+
.label = generic argument `{$arg}` used twice
61+
.note = for this opaque type
62+
63+
ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope
64+
.label = argument `{$arg}` is not a generic parameter
65+
.note = for this opaque type

Diff for: compiler/rustc_ty_utils/src/errors.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Errors emitted by ty_utils
22
33
use rustc_macros::{Diagnostic, Subdiagnostic};
4-
use rustc_middle::ty::Ty;
4+
use rustc_middle::ty::{GenericArg, Ty};
55
use rustc_span::Span;
66

77
#[derive(Diagnostic)]
@@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> {
100100
pub ty: Ty<'tcx>,
101101
pub e_ty: Ty<'tcx>,
102102
}
103+
104+
#[derive(Diagnostic)]
105+
#[diag(ty_utils_impl_trait_duplicate_arg)]
106+
pub struct DuplicateArg<'tcx> {
107+
pub arg: GenericArg<'tcx>,
108+
#[primary_span]
109+
#[label]
110+
pub span: Span,
111+
#[note]
112+
pub opaque_span: Span,
113+
}
114+
115+
#[derive(Diagnostic)]
116+
#[diag(ty_utils_impl_trait_not_param)]
117+
pub struct NotParam<'tcx> {
118+
pub arg: GenericArg<'tcx>,
119+
#[primary_span]
120+
#[label]
121+
pub span: Span,
122+
#[note]
123+
pub opaque_span: Span,
124+
}

0 commit comments

Comments
 (0)