Skip to content

Commit d082959

Browse files
compiler-errorslcnr
authored andcommitted
omg wtf
1 parent 248d5b9 commit d082959

File tree

22 files changed

+276
-217
lines changed

22 files changed

+276
-217
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

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

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

351356
let args = match *origin {
@@ -359,42 +364,23 @@ fn check_opaque_meets_bounds<'tcx>(
359364
}),
360365
};
361366

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

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

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

434404
fn sanity_check_found_hidden_type<'tcx>(

compiler/rustc_infer/src/infer/at.rs

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

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

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

63-
param_env.defining_opaque_types = self.defining_opaque_types;
63+
param_env.opaque_type_mode = self.opaque_type_mode;
6464

6565
Canonicalizer::canonicalize_with_base(
6666
param_env,
@@ -544,7 +544,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
544544
max_universe: ty::UniverseIndex::ROOT,
545545
variables: List::empty(),
546546
value: (),
547-
defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(),
547+
opaque_type_mode: infcx.map(|i| i.opaque_type_mode).unwrap_or_default(),
548548
};
549549
Canonicalizer::canonicalize_with_base(
550550
base,
@@ -614,14 +614,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
614614
.max()
615615
.unwrap_or(ty::UniverseIndex::ROOT);
616616

617-
assert!(
618-
!infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types)
619-
);
617+
assert!(!infcx.is_some_and(|infcx| infcx.opaque_type_mode != base.opaque_type_mode));
620618
Canonical {
621619
max_universe,
622620
variables: canonical_variables,
623621
value: (base.value, out_value),
624-
defining_opaque_types: base.defining_opaque_types,
622+
opaque_type_mode: base.opaque_type_mode,
625623
}
626624
}
627625

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::*;
@@ -246,7 +248,7 @@ pub struct InferCtxt<'tcx> {
246248
pub tcx: TyCtxt<'tcx>,
247249

248250
/// The `DefIds` of the opaque types that may have their hidden types constrained.
249-
defining_opaque_types: &'tcx ty::List<LocalDefId>,
251+
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,
250252

251253
/// Whether this inference context should care about region obligations in
252254
/// the root universe. Most notably, this is used during hir typeck as region
@@ -373,8 +375,8 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
373375
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
374376
}
375377

376-
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
377-
self.defining_opaque_types
378+
fn opaque_type_mode(&self) -> ty::OpaqueTypeMode<TyCtxt<'tcx>> {
379+
self.opaque_type_mode
378380
}
379381

380382
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
@@ -621,7 +623,7 @@ impl fmt::Display for FixupError {
621623
/// Used to configure inference contexts before their creation.
622624
pub struct InferCtxtBuilder<'tcx> {
623625
tcx: TyCtxt<'tcx>,
624-
defining_opaque_types: &'tcx ty::List<LocalDefId>,
626+
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,
625627
considering_regions: bool,
626628
skip_leak_check: bool,
627629
/// Whether we are in coherence mode.
@@ -636,7 +638,7 @@ impl<'tcx> TyCtxt<'tcx> {
636638
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
637639
InferCtxtBuilder {
638640
tcx: self,
639-
defining_opaque_types: ty::List::empty(),
641+
opaque_type_mode: Default::default(),
640642
considering_regions: true,
641643
skip_leak_check: false,
642644
intercrate: false,
@@ -646,22 +648,23 @@ impl<'tcx> TyCtxt<'tcx> {
646648
}
647649

648650
impl<'tcx> InferCtxtBuilder<'tcx> {
651+
pub fn with_opaque_type_mode(
652+
mut self,
653+
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,
654+
) -> Self {
655+
self.opaque_type_mode = opaque_type_mode;
656+
self
657+
}
658+
649659
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
650660
/// you need to call this function. Otherwise the opaque type will be treated opaquely.
651661
///
652662
/// It is only meant to be called in two places, for typeck
653663
/// (via `Inherited::build`) and for the inference context used
654664
/// in mir borrowck.
655665
pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self {
656-
self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor);
657-
self
658-
}
659-
660-
pub fn with_defining_opaque_types(
661-
mut self,
662-
defining_opaque_types: &'tcx ty::List<LocalDefId>,
663-
) -> Self {
664-
self.defining_opaque_types = defining_opaque_types;
666+
let types = self.tcx.opaque_types_defined_by(defining_anchor);
667+
self.opaque_type_mode = ty::OpaqueTypeMode::Define(types);
665668
self
666669
}
667670

@@ -700,23 +703,23 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
700703
where
701704
T: TypeFoldable<TyCtxt<'tcx>>,
702705
{
703-
let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build();
706+
let infcx = self.with_opaque_type_mode(canonical.opaque_type_mode).build();
704707
let (value, args) = infcx.instantiate_canonical(span, canonical);
705708
(infcx, value, args)
706709
}
707710

708711
pub fn build(&mut self) -> InferCtxt<'tcx> {
709712
let InferCtxtBuilder {
710713
tcx,
711-
defining_opaque_types,
714+
opaque_type_mode: defining_opaque_types,
712715
considering_regions,
713716
skip_leak_check,
714717
intercrate,
715718
next_trait_solver,
716719
} = *self;
717720
InferCtxt {
718721
tcx,
719-
defining_opaque_types,
722+
opaque_type_mode: defining_opaque_types,
720723
considering_regions,
721724
skip_leak_check,
722725
inner: RefCell::new(InferCtxtInner::new()),
@@ -1240,10 +1243,30 @@ impl<'tcx> InferCtxt<'tcx> {
12401243
self.inner.borrow().opaque_type_storage.opaque_types.clone()
12411244
}
12421245

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

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

136139
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
@@ -139,8 +142,10 @@ impl<'tcx> InferCtxt<'tcx> {
139142
// no one encounters it in practice.
140143
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
141144
// where it is of no concern, so we only check for TAITs.
142-
if self.can_define_opaque_ty(b_def_id)
143-
&& self.tcx.is_type_alias_impl_trait(b_def_id)
145+
if matches!(
146+
self.treat_opaque_ty(param_env.reveal(), b_def_id),
147+
TreatOpaque::Define
148+
) && self.tcx.is_type_alias_impl_trait(b_def_id)
144149
{
145150
self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag {
146151
span: cause.span,
@@ -150,7 +155,7 @@ impl<'tcx> InferCtxt<'tcx> {
150155
}
151156
}
152157
Some(self.register_hidden_type(
153-
OpaqueTypeKey { def_id, args },
158+
OpaqueTypeKey { def_id: def_id.expect_local(), args },
154159
cause.clone(),
155160
param_env,
156161
b,

compiler/rustc_middle/src/infer/canonical.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
182182
max_universe: ty::UniverseIndex::ROOT,
183183
variables: List::empty(),
184184
value: key,
185-
defining_opaque_types: ty::List::empty(),
185+
opaque_type_mode: Default::default(),
186186
};
187187
}
188188

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
@@ -81,6 +81,13 @@ pub enum Reveal {
8181
All,
8282
}
8383

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

0 commit comments

Comments
 (0)