Skip to content

Commit b234e44

Browse files
committed
Auto merge of #122077 - oli-obk:eager_opaque_checks4, r=lcnr
Pass list of defineable opaque types into canonical queries This eliminates `DefiningAnchor::Bubble` for good and brings the old solver closer to the new one wrt cycles and nested obligations. At that point the difference between `DefiningAnchor::Bind([])` and `DefiningAnchor::Error` was academic. We only used the difference for some sanity checks, which actually had to be worked around in places, so I just removed `DefiningAnchor` entirely and just stored the list of opaques that may be defined. fixes #108498 fixes #116877 * [x] run crater - #122077 (comment)
2 parents ab5bda1 + dc97b1e commit b234e44

File tree

59 files changed

+470
-388
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+470
-388
lines changed

compiler/rustc_borrowck/src/consumers.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use rustc_hir::def_id::LocalDefId;
44
use rustc_index::{IndexSlice, IndexVec};
55
use rustc_infer::infer::TyCtxtInferExt;
66
use rustc_middle::mir::{Body, Promoted};
7-
use rustc_middle::traits::DefiningAnchor;
87
use rustc_middle::ty::TyCtxt;
98
use std::rc::Rc;
109

@@ -106,7 +105,7 @@ pub fn get_body_with_borrowck_facts(
106105
options: ConsumerOptions,
107106
) -> BodyWithBorrowckFacts<'_> {
108107
let (input_body, promoted) = tcx.mir_promoted(def);
109-
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build();
108+
let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build();
110109
let input_body: &Body<'_> = &input_body.borrow();
111110
let promoted: &IndexSlice<_, _> = &promoted.borrow();
112111
*super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap()

compiler/rustc_borrowck/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ use rustc_infer::infer::{
3232
use rustc_middle::mir::tcx::PlaceTy;
3333
use rustc_middle::mir::*;
3434
use rustc_middle::query::Providers;
35-
use rustc_middle::traits::DefiningAnchor;
3635
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
3736
use rustc_session::lint::builtin::UNUSED_MUT;
3837
use rustc_span::{Span, Symbol};
@@ -126,7 +125,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
126125
return tcx.arena.alloc(result);
127126
}
128127

129-
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build();
128+
let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build();
130129
let promoted: &IndexSlice<_, _> = &promoted.borrow();
131130
let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0;
132131
debug!("mir_borrowck done");

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use rustc_infer::infer::TyCtxtInferExt as _;
77
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
88
use rustc_infer::traits::{Obligation, ObligationCause};
99
use rustc_macros::extension;
10-
use rustc_middle::traits::DefiningAnchor;
1110
use rustc_middle::ty::visit::TypeVisitableExt;
1211
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
1312
use rustc_middle::ty::{GenericArgKind, GenericArgs};
@@ -133,6 +132,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
133132

134133
let ty =
135134
infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type);
135+
136+
// Sometimes, when the hidden type is an inference variable, it can happen that
137+
// the hidden type becomes the opaque type itself. In this case, this was an opaque
138+
// usage of the opaque type and we can ignore it. This check is mirrored in typeck's
139+
// writeback.
140+
// FIXME(-Znext-solver): This should be unnecessary with the new solver.
141+
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind()
142+
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
143+
&& alias_ty.args == opaque_type_key.args
144+
{
145+
continue;
146+
}
136147
// Sometimes two opaque types are the same only after we remap the generic parameters
137148
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
138149
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
@@ -321,13 +332,13 @@ fn check_opaque_type_well_formed<'tcx>(
321332
parent_def_id = tcx.local_parent(parent_def_id);
322333
}
323334

324-
// FIXME(-Znext-solver): We probably should use `DefiningAnchor::Bind(&[])`
335+
// FIXME(-Znext-solver): We probably should use `&[]` instead of
325336
// and prepopulate this `InferCtxt` with known opaque values, rather than
326-
// using the `Bind` anchor here. For now it's fine.
337+
// allowing opaque types to be defined and checking them after the fact.
327338
let infcx = tcx
328339
.infer_ctxt()
329340
.with_next_trait_solver(next_trait_solver)
330-
.with_opaque_type_inference(DefiningAnchor::bind(tcx, parent_def_id))
341+
.with_opaque_type_inference(parent_def_id)
331342
.build();
332343
let ocx = ObligationCtxt::new(&infcx);
333344
let identity_args = GenericArgs::identity_for_item(tcx, def_id);

compiler/rustc_borrowck/src/type_check/canonical.rs

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
3939

4040
let TypeOpOutput { output, constraints, error_info } =
4141
op.fully_perform(self.infcx, locations.span(self.body))?;
42+
if cfg!(debug_assertions) {
43+
let data = self.infcx.take_and_reset_region_constraints();
44+
if !data.is_empty() {
45+
panic!("leftover region constraints: {data:#?}");
46+
}
47+
}
4248

4349
debug!(?output, ?constraints);
4450

compiler/rustc_hir_analysis/src/check/check.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
1313
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
1414
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
1515
use rustc_middle::middle::stability::EvalResult;
16-
use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
16+
use rustc_middle::traits::ObligationCauseCode;
1717
use rustc_middle::ty::fold::BottomUpFolder;
1818
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
1919
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
@@ -345,10 +345,7 @@ fn check_opaque_meets_bounds<'tcx>(
345345
};
346346
let param_env = tcx.param_env(defining_use_anchor);
347347

348-
let infcx = tcx
349-
.infer_ctxt()
350-
.with_opaque_type_inference(DefiningAnchor::bind(tcx, defining_use_anchor))
351-
.build();
348+
let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build();
352349
let ocx = ObligationCtxt::new(&infcx);
353350

354351
let args = match *origin {
@@ -1567,7 +1564,7 @@ pub(super) fn check_coroutine_obligations(
15671564
.ignoring_regions()
15681565
// Bind opaque types to type checking root, as they should have been checked by borrowck,
15691566
// but may show up in some cases, like when (root) obligations are stalled in the new solver.
1570-
.with_opaque_type_inference(DefiningAnchor::bind(tcx, typeck.hir_owner.def_id))
1567+
.with_opaque_type_inference(typeck.hir_owner.def_id)
15711568
.build();
15721569

15731570
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -730,8 +730,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
730730
for ty in ret_ty.walk() {
731731
if let ty::GenericArgKind::Type(ty) = ty.unpack()
732732
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
733-
&& let Some(def_id) = def_id.as_local()
734-
&& self.opaque_type_origin(def_id).is_some()
733+
&& self.can_define_opaque_ty(def_id)
735734
{
736735
return None;
737736
}

compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use rustc_hir as hir;
55
use rustc_hir::def_id::LocalDefId;
66
use rustc_hir::HirIdMap;
77
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
8-
use rustc_middle::traits::DefiningAnchor;
98
use rustc_middle::ty::visit::TypeVisitableExt;
109
use rustc_middle::ty::{self, Ty, TyCtxt};
1110
use rustc_span::def_id::LocalDefIdMap;
@@ -78,11 +77,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
7877
pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
7978
let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner;
8079

81-
let infcx = tcx
82-
.infer_ctxt()
83-
.ignoring_regions()
84-
.with_opaque_type_inference(DefiningAnchor::bind(tcx, def_id))
85-
.build();
80+
let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build();
8681
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
8782

8883
TypeckRootCtxt {

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_use_anchor: self.defining_use_anchor,
78+
defining_opaque_types: self.defining_opaque_types,
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

+13-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl<'tcx> InferCtxt<'tcx> {
4242
V: TypeFoldable<TyCtxt<'tcx>>,
4343
{
4444
let (param_env, value) = value.into_parts();
45-
let param_env = self.tcx.canonical_param_env_cache.get_or_insert(
45+
let mut param_env = self.tcx.canonical_param_env_cache.get_or_insert(
4646
self.tcx,
4747
param_env,
4848
query_state,
@@ -59,6 +59,8 @@ impl<'tcx> InferCtxt<'tcx> {
5959
},
6060
);
6161

62+
param_env.defining_opaque_types = self.defining_opaque_types;
63+
6264
Canonicalizer::canonicalize_with_base(
6365
param_env,
6466
value,
@@ -541,6 +543,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
541543
max_universe: ty::UniverseIndex::ROOT,
542544
variables: List::empty(),
543545
value: (),
546+
defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(),
544547
};
545548
Canonicalizer::canonicalize_with_base(
546549
base,
@@ -610,7 +613,15 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
610613
.max()
611614
.unwrap_or(ty::UniverseIndex::ROOT);
612615

613-
Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) }
616+
assert!(
617+
!infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types)
618+
);
619+
Canonical {
620+
max_universe,
621+
variables: canonical_variables,
622+
value: (base.value, out_value),
623+
defining_opaque_types: base.defining_opaque_types,
624+
}
614625
}
615626

616627
/// Creates a canonical variable replacing `kind` from the input,

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

+3-6
Original file line numberDiff line numberDiff line change
@@ -505,12 +505,9 @@ impl<'tcx> InferCtxt<'tcx> {
505505
let b = instantiate_value(self.tcx, &result_args, b);
506506
debug!(?a, ?b, "constrain opaque type");
507507
// We use equate here instead of, for example, just registering the
508-
// opaque type's hidden value directly, because we may be instantiating
509-
// a query response that was canonicalized in an InferCtxt that had
510-
// a different defining anchor. In that case, we may have inferred
511-
// `NonLocalOpaque := LocalOpaque` but can only instantiate it in
512-
// the other direction as `LocalOpaque := NonLocalOpaque`. Using eq
513-
// here allows us to try both directions (in `InferCtxt::handle_opaque_type`).
508+
// opaque type's hidden value directly, because the hidden type may have been an inference
509+
// variable that got constrained to the opaque type itself. In that case we want to equate
510+
// the generic args of the opaque with the generic params of its hidden type version.
514511
obligations.extend(
515512
self.at(cause, param_env)
516513
.eq(

compiler/rustc_infer/src/infer/mod.rs

+29-21
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin
3434
use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
3535
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
3636
use rustc_middle::mir::ConstraintCategory;
37-
use rustc_middle::traits::{select, DefiningAnchor};
37+
use rustc_middle::traits::select;
3838
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3939
use rustc_middle::ty::fold::BoundVarReplacerDelegate;
4040
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@@ -243,18 +243,8 @@ impl<'tcx> InferCtxtInner<'tcx> {
243243
pub struct InferCtxt<'tcx> {
244244
pub tcx: TyCtxt<'tcx>,
245245

246-
/// The `DefId` of the item in whose context we are performing inference or typeck.
247-
/// It is used to check whether an opaque type use is a defining use.
248-
///
249-
/// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up
250-
/// the obligation. This frequently happens for
251-
/// short lived InferCtxt within queries. The opaque type obligations are forwarded
252-
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
253-
///
254-
/// Its default value is `DefiningAnchor::Bind(&[])`, which means no opaque types may be defined.
255-
/// This way it is easier to catch errors that
256-
/// might come up during inference or typeck.
257-
pub defining_use_anchor: DefiningAnchor<'tcx>,
246+
/// The `DefIds` of the opaque types that may have their hidden types constrained.
247+
defining_opaque_types: &'tcx ty::List<LocalDefId>,
258248

259249
/// Whether this inference context should care about region obligations in
260250
/// the root universe. Most notably, this is used during hir typeck as region
@@ -401,6 +391,10 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
401391
fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
402392
self.probe_const_var(vid).ok()
403393
}
394+
395+
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
396+
self.defining_opaque_types
397+
}
404398
}
405399

406400
/// See the `error_reporting` module for more details.
@@ -615,7 +609,7 @@ impl fmt::Display for FixupError {
615609
/// Used to configure inference contexts before their creation.
616610
pub struct InferCtxtBuilder<'tcx> {
617611
tcx: TyCtxt<'tcx>,
618-
defining_use_anchor: DefiningAnchor<'tcx>,
612+
defining_opaque_types: &'tcx ty::List<LocalDefId>,
619613
considering_regions: bool,
620614
skip_leak_check: bool,
621615
/// Whether we are in coherence mode.
@@ -630,7 +624,7 @@ impl<'tcx> TyCtxt<'tcx> {
630624
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
631625
InferCtxtBuilder {
632626
tcx: self,
633-
defining_use_anchor: DefiningAnchor::Bind(ty::List::empty()),
627+
defining_opaque_types: ty::List::empty(),
634628
considering_regions: true,
635629
skip_leak_check: false,
636630
intercrate: false,
@@ -646,8 +640,16 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
646640
/// It is only meant to be called in two places, for typeck
647641
/// (via `Inherited::build`) and for the inference context used
648642
/// in mir borrowck.
649-
pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor<'tcx>) -> Self {
650-
self.defining_use_anchor = defining_use_anchor;
643+
pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self {
644+
self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor);
645+
self
646+
}
647+
648+
pub fn with_defining_opaque_types(
649+
mut self,
650+
defining_opaque_types: &'tcx ty::List<LocalDefId>,
651+
) -> Self {
652+
self.defining_opaque_types = defining_opaque_types;
651653
self
652654
}
653655

@@ -679,30 +681,30 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
679681
/// the bound values in `C` to their instantiated values in `V`
680682
/// (in other words, `S(C) = V`).
681683
pub fn build_with_canonical<T>(
682-
&mut self,
684+
self,
683685
span: Span,
684686
canonical: &Canonical<'tcx, T>,
685687
) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
686688
where
687689
T: TypeFoldable<TyCtxt<'tcx>>,
688690
{
689-
let infcx = self.build();
691+
let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build();
690692
let (value, args) = infcx.instantiate_canonical(span, canonical);
691693
(infcx, value, args)
692694
}
693695

694696
pub fn build(&mut self) -> InferCtxt<'tcx> {
695697
let InferCtxtBuilder {
696698
tcx,
697-
defining_use_anchor,
699+
defining_opaque_types,
698700
considering_regions,
699701
skip_leak_check,
700702
intercrate,
701703
next_trait_solver,
702704
} = *self;
703705
InferCtxt {
704706
tcx,
705-
defining_use_anchor,
707+
defining_opaque_types,
706708
considering_regions,
707709
skip_leak_check,
708710
inner: RefCell::new(InferCtxtInner::new()),
@@ -1230,6 +1232,12 @@ impl<'tcx> InferCtxt<'tcx> {
12301232
self.inner.borrow().opaque_type_storage.opaque_types.clone()
12311233
}
12321234

1235+
#[inline(always)]
1236+
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
1237+
let Some(id) = id.into().as_local() else { return false };
1238+
self.defining_opaque_types.contains(&id)
1239+
}
1240+
12331241
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
12341242
self.resolve_vars_if_possible(t).to_string()
12351243
}

0 commit comments

Comments
 (0)