Skip to content

Commit 77f788e

Browse files
compiler-errorslcnr
authored andcommitted
omg wtf
1 parent 748e1a2 commit 77f788e

File tree

22 files changed

+274
-221
lines changed

22 files changed

+274
-221
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+19-49
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,12 @@ fn check_opaque_meets_bounds<'tcx>(
344344
};
345345
let param_env = tcx.param_env(defining_use_anchor);
346346

347-
let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build();
347+
let infcx = tcx
348+
.infer_ctxt()
349+
.with_opaque_type_mode(ty::OpaqueTypeMode::Reveal(
350+
tcx.opaque_types_defined_by(defining_use_anchor),
351+
))
352+
.build();
348353
let ocx = ObligationCtxt::new(&infcx);
349354

350355
let args = match *origin {
@@ -358,42 +363,23 @@ fn check_opaque_meets_bounds<'tcx>(
358363
}),
359364
};
360365

361-
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
362-
363-
// `ReErased` regions appear in the "parent_args" of closures/coroutines.
364-
// We're ignoring them here and replacing them with fresh region variables.
365-
// See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs.
366-
//
367-
// FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
368-
// here rather than using ReErased.
369-
let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args);
370-
let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() {
371-
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
372-
_ => re,
373-
});
374-
375366
let misc_cause = traits::ObligationCause::misc(span, def_id);
376-
377-
match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
378-
Ok(()) => {}
379-
Err(ty_err) => {
380-
// Some types may be left "stranded" if they can't be reached
381-
// from a lowered rustc_middle bound but they're mentioned in the HIR.
382-
// This will happen, e.g., when a nested opaque is inside of a non-
383-
// existent associated type, like `impl Trait<Missing = impl Trait>`.
384-
// See <tests/ui/impl-trait/stranded-opaque.rs>.
385-
let ty_err = ty_err.to_string(tcx);
386-
let guar = tcx.dcx().span_delayed_bug(
387-
span,
388-
format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
389-
);
390-
return Err(guar);
391-
}
392-
}
367+
let predicates: Vec<_> = tcx.item_bounds(def_id).iter_instantiated(tcx, args).collect();
368+
let predicates = ocx.normalize(&misc_cause, param_env, predicates);
369+
ocx.register_obligations(
370+
predicates
371+
.into_iter()
372+
.map(|clause| Obligation::new(tcx, misc_cause.clone(), param_env, clause)),
373+
);
393374

394375
// Additionally require the hidden type to be well-formed with only the generics of the opaque type.
395376
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
396377
// hidden type is well formed even without those bounds.
378+
let hidden_ty =
379+
tcx.fold_regions(tcx.type_of(def_id).instantiate(tcx, args), |re, _| match *re {
380+
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
381+
_ => re,
382+
});
397383
let predicate =
398384
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into())));
399385
ocx.register_obligation(Obligation::new(tcx, misc_cause.clone(), param_env, predicate));
@@ -411,23 +397,7 @@ fn check_opaque_meets_bounds<'tcx>(
411397
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
412398
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
413399

414-
if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
415-
// HACK: this should also fall through to the hidden type check below, but the original
416-
// implementation had a bug where equivalent lifetimes are not identical. This caused us
417-
// to reject existing stable code that is otherwise completely fine. The real fix is to
418-
// compare the hidden types via our type equivalence/relation infra instead of doing an
419-
// identity check.
420-
let _ = infcx.take_opaque_types();
421-
Ok(())
422-
} else {
423-
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
424-
for (mut key, mut ty) in infcx.take_opaque_types() {
425-
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
426-
key = infcx.resolve_vars_if_possible(key);
427-
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
428-
}
429-
Ok(())
430-
}
400+
Ok(())
431401
}
432402

433403
fn sanity_check_found_hidden_type<'tcx>(

compiler/rustc_infer/src/infer/at.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl<'tcx> InferCtxt<'tcx> {
7575
pub fn fork_with_intercrate(&self, intercrate: bool) -> Self {
7676
Self {
7777
tcx: self.tcx,
78-
defining_opaque_types: self.defining_opaque_types,
78+
opaque_type_mode: self.opaque_type_mode,
7979
considering_regions: self.considering_regions,
8080
skip_leak_check: self.skip_leak_check,
8181
inner: self.inner.clone(),

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl<'tcx> InferCtxt<'tcx> {
5959
},
6060
);
6161

62-
param_env.defining_opaque_types = self.defining_opaque_types;
62+
param_env.opaque_type_mode = self.opaque_type_mode;
6363

6464
Canonicalizer::canonicalize_with_base(
6565
param_env,
@@ -543,7 +543,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
543543
max_universe: ty::UniverseIndex::ROOT,
544544
variables: List::empty(),
545545
value: (),
546-
defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(),
546+
opaque_type_mode: infcx.map(|i| i.opaque_type_mode).unwrap_or_default(),
547547
};
548548
Canonicalizer::canonicalize_with_base(
549549
base,
@@ -613,14 +613,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
613613
.max()
614614
.unwrap_or(ty::UniverseIndex::ROOT);
615615

616-
assert!(
617-
!infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types)
618-
);
616+
assert!(!infcx.is_some_and(|infcx| infcx.opaque_type_mode != base.opaque_type_mode));
619617
Canonical {
620618
max_universe,
621619
variables: canonical_variables,
622620
value: (base.value, out_value),
623-
defining_opaque_types: base.defining_opaque_types,
621+
opaque_type_mode: base.opaque_type_mode,
624622
}
625623
}
626624

compiler/rustc_infer/src/infer/mod.rs

+44-21
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ pub use relate::combine::CombineFields;
55
pub use relate::combine::ObligationEmittingRelation;
66
pub use relate::StructurallyRelateAliases;
77
pub use rustc_macros::{TypeFoldable, TypeVisitable};
8+
use rustc_middle::traits::Reveal;
9+
use rustc_middle::traits::TreatOpaque;
810
pub use rustc_middle::ty::IntVarValue;
911
pub use BoundRegionConversionTime::*;
1012
pub use RegionVariableOrigin::*;
@@ -245,7 +247,7 @@ pub struct InferCtxt<'tcx> {
245247
pub tcx: TyCtxt<'tcx>,
246248

247249
/// The `DefIds` of the opaque types that may have their hidden types constrained.
248-
defining_opaque_types: &'tcx ty::List<LocalDefId>,
250+
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,
249251

250252
/// Whether this inference context should care about region obligations in
251253
/// the root universe. Most notably, this is used during hir typeck as region
@@ -393,8 +395,8 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
393395
self.probe_const_var(vid).ok()
394396
}
395397

396-
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
397-
self.defining_opaque_types
398+
fn opaque_type_mode(&self) -> ty::OpaqueTypeMode<TyCtxt<'tcx>> {
399+
self.opaque_type_mode
398400
}
399401
}
400402

@@ -610,7 +612,7 @@ impl fmt::Display for FixupError {
610612
/// Used to configure inference contexts before their creation.
611613
pub struct InferCtxtBuilder<'tcx> {
612614
tcx: TyCtxt<'tcx>,
613-
defining_opaque_types: &'tcx ty::List<LocalDefId>,
615+
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,
614616
considering_regions: bool,
615617
skip_leak_check: bool,
616618
/// Whether we are in coherence mode.
@@ -625,7 +627,7 @@ impl<'tcx> TyCtxt<'tcx> {
625627
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
626628
InferCtxtBuilder {
627629
tcx: self,
628-
defining_opaque_types: ty::List::empty(),
630+
opaque_type_mode: Default::default(),
629631
considering_regions: true,
630632
skip_leak_check: false,
631633
intercrate: false,
@@ -635,22 +637,23 @@ impl<'tcx> TyCtxt<'tcx> {
635637
}
636638

637639
impl<'tcx> InferCtxtBuilder<'tcx> {
640+
pub fn with_opaque_type_mode(
641+
mut self,
642+
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,
643+
) -> Self {
644+
self.opaque_type_mode = opaque_type_mode;
645+
self
646+
}
647+
638648
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
639649
/// you need to call this function. Otherwise the opaque type will be treated opaquely.
640650
///
641651
/// It is only meant to be called in two places, for typeck
642652
/// (via `Inherited::build`) and for the inference context used
643653
/// in mir borrowck.
644654
pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self {
645-
self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor);
646-
self
647-
}
648-
649-
pub fn with_defining_opaque_types(
650-
mut self,
651-
defining_opaque_types: &'tcx ty::List<LocalDefId>,
652-
) -> Self {
653-
self.defining_opaque_types = defining_opaque_types;
655+
let types = self.tcx.opaque_types_defined_by(defining_anchor);
656+
self.opaque_type_mode = ty::OpaqueTypeMode::Define(types);
654657
self
655658
}
656659

@@ -689,23 +692,23 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
689692
where
690693
T: TypeFoldable<TyCtxt<'tcx>>,
691694
{
692-
let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build();
695+
let infcx = self.with_opaque_type_mode(canonical.opaque_type_mode).build();
693696
let (value, args) = infcx.instantiate_canonical(span, canonical);
694697
(infcx, value, args)
695698
}
696699

697700
pub fn build(&mut self) -> InferCtxt<'tcx> {
698701
let InferCtxtBuilder {
699702
tcx,
700-
defining_opaque_types,
703+
opaque_type_mode: defining_opaque_types,
701704
considering_regions,
702705
skip_leak_check,
703706
intercrate,
704707
next_trait_solver,
705708
} = *self;
706709
InferCtxt {
707710
tcx,
708-
defining_opaque_types,
711+
opaque_type_mode: defining_opaque_types,
709712
considering_regions,
710713
skip_leak_check,
711714
inner: RefCell::new(InferCtxtInner::new()),
@@ -1234,10 +1237,30 @@ impl<'tcx> InferCtxt<'tcx> {
12341237
self.inner.borrow().opaque_type_storage.opaque_types.clone()
12351238
}
12361239

1237-
#[inline(always)]
1238-
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
1239-
let Some(id) = id.into().as_local() else { return false };
1240-
self.defining_opaque_types.contains(&id)
1240+
pub fn treat_opaque_ty(&self, reveal: Reveal, def_id: DefId) -> TreatOpaque {
1241+
if self.intercrate {
1242+
return TreatOpaque::Ambiguous;
1243+
}
1244+
1245+
match reveal {
1246+
Reveal::All => return TreatOpaque::Reveal,
1247+
Reveal::UserFacing => {}
1248+
}
1249+
1250+
match self.opaque_type_mode {
1251+
ty::OpaqueTypeMode::Define(list) => {
1252+
if def_id.as_local().is_some_and(|def_id| list.contains(&def_id)) {
1253+
return TreatOpaque::Define;
1254+
}
1255+
}
1256+
ty::OpaqueTypeMode::Reveal(list) => {
1257+
if def_id.as_local().is_some_and(|def_id| list.contains(&def_id)) {
1258+
return TreatOpaque::Reveal;
1259+
}
1260+
}
1261+
}
1262+
1263+
TreatOpaque::Rigid
12411264
}
12421265

12431266
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {

compiler/rustc_infer/src/infer/opaque_types/mod.rs

+22-17
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use hir::def_id::{DefId, LocalDefId};
77
use rustc_data_structures::fx::FxIndexMap;
88
use rustc_data_structures::sync::Lrc;
99
use rustc_hir as hir;
10-
use rustc_middle::traits::ObligationCause;
10+
use rustc_middle::traits::{ObligationCause, TreatOpaque};
1111
use rustc_middle::ty::error::{ExpectedFound, TypeError};
1212
use rustc_middle::ty::fold::BottomUpFolder;
1313
use rustc_middle::ty::GenericArgKind;
@@ -59,7 +59,10 @@ impl<'tcx> InferCtxt<'tcx> {
5959
ct_op: |ct| ct,
6060
ty_op: |ty| match *ty.kind() {
6161
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
62-
if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() =>
62+
if matches!(
63+
self.treat_opaque_ty(param_env.reveal(), def_id),
64+
TreatOpaque::Define
65+
) && !ty.has_escaping_bound_vars() =>
6366
{
6467
let def_span = self.tcx.def_span(def_id);
6568
let span = if span.contains(def_span) { def_span } else { span };
@@ -86,16 +89,6 @@ impl<'tcx> InferCtxt<'tcx> {
8689
) -> InferResult<'tcx, ()> {
8790
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
8891
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
89-
let def_id = def_id.expect_local();
90-
if self.intercrate {
91-
// See comment on `insert_hidden_type` for why this is sufficient in coherence
92-
return Some(self.register_hidden_type(
93-
OpaqueTypeKey { def_id, args },
94-
cause.clone(),
95-
param_env,
96-
b,
97-
));
98-
}
9992
// Check that this is `impl Trait` type is
10093
// declared by `parent_def_id` -- i.e., one whose
10194
// value we are inferring. At present, this is
@@ -130,8 +123,18 @@ impl<'tcx> InferCtxt<'tcx> {
130123
// let x = || foo(); // returns the Opaque assoc with `foo`
131124
// }
132125
// ```
133-
if !self.can_define_opaque_ty(def_id) {
134-
return None;
126+
match self.treat_opaque_ty(param_env.reveal(), def_id) {
127+
TreatOpaque::Define => {}
128+
TreatOpaque::Reveal | TreatOpaque::Rigid => return None,
129+
TreatOpaque::Ambiguous => {
130+
// See comment on `insert_hidden_type` for why this is sufficient in coherence
131+
return Some(self.register_hidden_type(
132+
OpaqueTypeKey { def_id: def_id.expect_local(), args },
133+
cause.clone(),
134+
param_env,
135+
b,
136+
));
137+
}
135138
}
136139

137140
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
@@ -140,8 +143,10 @@ impl<'tcx> InferCtxt<'tcx> {
140143
// no one encounters it in practice.
141144
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
142145
// where it is of no concern, so we only check for TAITs.
143-
if self.can_define_opaque_ty(b_def_id)
144-
&& self.tcx.is_type_alias_impl_trait(b_def_id)
146+
if matches!(
147+
self.treat_opaque_ty(param_env.reveal(), b_def_id),
148+
TreatOpaque::Define
149+
) && self.tcx.is_type_alias_impl_trait(b_def_id)
145150
{
146151
self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag {
147152
span: cause.span,
@@ -151,7 +156,7 @@ impl<'tcx> InferCtxt<'tcx> {
151156
}
152157
}
153158
Some(self.register_hidden_type(
154-
OpaqueTypeKey { def_id, args },
159+
OpaqueTypeKey { def_id: def_id.expect_local(), args },
155160
cause.clone(),
156161
param_env,
157162
b,

compiler/rustc_middle/src/infer/canonical.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
325325
max_universe: ty::UniverseIndex::ROOT,
326326
variables: List::empty(),
327327
value: key,
328-
defining_opaque_types: ty::List::empty(),
328+
opaque_type_mode: Default::default(),
329329
};
330330
}
331331

compiler/rustc_middle/src/query/plumbing.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ macro_rules! define_callbacks {
325325
// Increase this limit if necessary, but do try to keep the size low if possible
326326
#[cfg(target_pointer_width = "64")]
327327
const _: () = {
328-
if mem::size_of::<Key<'static>>() > 72 {
328+
if mem::size_of::<Key<'static>>() > 84 {
329329
panic!("{}", concat!(
330330
"the query `",
331331
stringify!($name),

compiler/rustc_middle/src/traits/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ pub enum Reveal {
8282
All,
8383
}
8484

85+
pub enum TreatOpaque {
86+
Reveal,
87+
Define,
88+
Rigid,
89+
Ambiguous,
90+
}
91+
8592
/// The reason why we incurred this obligation; used for error reporting.
8693
///
8794
/// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the

0 commit comments

Comments
 (0)