Skip to content

Commit eecfdfb

Browse files
authored
Rollup merge of #99383 - ouz-a:issue_57961, r=oli-obk
Formalize defining_use_anchor This tackles issue #57961 Introduces new enum called `DefiningAnchor` that replaces `Option<LocalDefId>` of `defining_use_anchor`. Now every use of it is explicit and exhaustively matched, catching errors like one in the linked issue. This is not a perfect fix but it's a step in the right direction. r? `@oli-obk`
2 parents 3c3c5da + 64dc377 commit eecfdfb

18 files changed

+292
-184
lines changed

compiler/rustc_borrowck/src/consumers.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use rustc_hir::def_id::LocalDefId;
44
use rustc_index::vec::IndexVec;
5-
use rustc_infer::infer::TyCtxtInferExt;
5+
use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
66
use rustc_middle::mir::Body;
77
use rustc_middle::ty::{self, TyCtxt};
88

@@ -31,7 +31,7 @@ pub fn get_body_with_borrowck_facts<'tcx>(
3131
def: ty::WithOptConstParam<LocalDefId>,
3232
) -> BodyWithBorrowckFacts<'tcx> {
3333
let (input_body, promoted) = tcx.mir_promoted(def);
34-
tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
34+
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| {
3535
let input_body: &Body<'_> = &input_body.borrow();
3636
let promoted: &IndexVec<_, _> = &promoted.borrow();
3737
*super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()

compiler/rustc_borrowck/src/lib.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_hir as hir;
2424
use rustc_hir::def_id::LocalDefId;
2525
use rustc_index::bit_set::ChunkedBitSet;
2626
use rustc_index::vec::IndexVec;
27-
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
27+
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
2828
use rustc_middle::mir::{
2929
traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
3030
PlaceRef, VarDebugInfoContents,
@@ -130,11 +130,14 @@ fn mir_borrowck<'tcx>(
130130
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
131131
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
132132

133-
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
134-
let input_body: &Body<'_> = &input_body.borrow();
135-
let promoted: &IndexVec<_, _> = &promoted.borrow();
136-
do_mir_borrowck(&infcx, input_body, promoted, false).0
137-
});
133+
let opt_closure_req = tcx
134+
.infer_ctxt()
135+
.with_opaque_type_inference(DefiningAnchor::Bind(hir_owner))
136+
.enter(|infcx| {
137+
let input_body: &Body<'_> = &input_body.borrow();
138+
let promoted: &IndexVec<_, _> = &promoted.borrow();
139+
do_mir_borrowck(&infcx, input_body, promoted, false).0
140+
});
138141
debug!("mir_borrowck done");
139142

140143
tcx.arena.alloc(opt_closure_req)

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+54-48
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use rustc_data_structures::vec_map::VecMap;
33
use rustc_hir::def_id::LocalDefId;
44
use rustc_hir::OpaqueTyOrigin;
55
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
6-
use rustc_infer::infer::InferCtxt;
76
use rustc_infer::infer::TyCtxtInferExt as _;
7+
use rustc_infer::infer::{DefiningAnchor, InferCtxt};
88
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
99
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
1010
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
@@ -269,59 +269,65 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
269269
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
270270
let param_env = self.tcx.param_env(def_id);
271271
let body_id = self.tcx.local_def_id_to_hir_id(def_id);
272-
self.tcx.infer_ctxt().enter(move |infcx| {
273-
// Require the hidden type to be well-formed with only the generics of the opaque type.
274-
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
275-
// hidden type is well formed even without those bounds.
276-
let predicate =
277-
ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
278-
.to_predicate(infcx.tcx);
279-
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
280-
281-
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
282-
// the bounds that the function supplies.
283-
match infcx.register_hidden_type(
284-
OpaqueTypeKey { def_id, substs: id_substs },
285-
ObligationCause::misc(instantiated_ty.span, body_id),
286-
param_env,
287-
definition_ty,
288-
origin,
289-
) {
290-
Ok(infer_ok) => {
291-
for obligation in infer_ok.obligations {
292-
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
272+
// HACK This bubble is required for this tests to pass:
273+
// type-alias-impl-trait/issue-67844-nested-opaque.rs
274+
self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(
275+
move |infcx| {
276+
// Require the hidden type to be well-formed with only the generics of the opaque type.
277+
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
278+
// hidden type is well formed even without those bounds.
279+
let predicate =
280+
ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
281+
.to_predicate(infcx.tcx);
282+
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
283+
284+
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
285+
// the bounds that the function supplies.
286+
match infcx.register_hidden_type(
287+
OpaqueTypeKey { def_id, substs: id_substs },
288+
ObligationCause::misc(instantiated_ty.span, body_id),
289+
param_env,
290+
definition_ty,
291+
origin,
292+
) {
293+
Ok(infer_ok) => {
294+
for obligation in infer_ok.obligations {
295+
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
296+
}
297+
}
298+
Err(err) => {
299+
infcx
300+
.report_mismatched_types(
301+
&ObligationCause::misc(instantiated_ty.span, body_id),
302+
self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
303+
definition_ty,
304+
err,
305+
)
306+
.emit();
293307
}
294308
}
295-
Err(err) => {
296-
infcx
297-
.report_mismatched_types(
298-
&ObligationCause::misc(instantiated_ty.span, body_id),
299-
self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
300-
definition_ty,
301-
err,
302-
)
303-
.emit();
304-
}
305-
}
306309

307-
fulfillment_cx.register_predicate_obligation(
308-
&infcx,
309-
Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
310-
);
310+
fulfillment_cx.register_predicate_obligation(
311+
&infcx,
312+
Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
313+
);
311314

312-
// Check that all obligations are satisfied by the implementation's
313-
// version.
314-
let errors = fulfillment_cx.select_all_or_error(&infcx);
315+
// Check that all obligations are satisfied by the implementation's
316+
// version.
317+
let errors = fulfillment_cx.select_all_or_error(&infcx);
315318

316-
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
319+
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
320+
// tests to pass
321+
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
317322

318-
if errors.is_empty() {
319-
definition_ty
320-
} else {
321-
infcx.report_fulfillment_errors(&errors, None, false);
322-
self.tcx.ty_error()
323-
}
324-
})
323+
if errors.is_empty() {
324+
definition_ty
325+
} else {
326+
infcx.report_fulfillment_errors(&errors, None, false);
327+
self.tcx.ty_error()
328+
}
329+
},
330+
)
325331
} else {
326332
definition_ty
327333
}

compiler/rustc_infer/src/infer/mod.rs

+25-7
Original file line numberDiff line numberDiff line change
@@ -239,17 +239,31 @@ impl<'tcx> InferCtxtInner<'tcx> {
239239
}
240240
}
241241

242+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
243+
pub enum DefiningAnchor {
244+
/// `DefId` of the item.
245+
Bind(LocalDefId),
246+
/// When opaque types are not resolved, we `Bubble` up, meaning
247+
/// return the opaque/hidden type pair from query, for caller of query to handle it.
248+
Bubble,
249+
/// Used to catch type mismatch errors when handling opaque types.
250+
Error,
251+
}
252+
242253
pub struct InferCtxt<'a, 'tcx> {
243254
pub tcx: TyCtxt<'tcx>,
244255

245256
/// The `DefId` of the item in whose context we are performing inference or typeck.
246257
/// It is used to check whether an opaque type use is a defining use.
247258
///
248-
/// If it is `None`, we can't resolve opaque types here and need to bubble up
259+
/// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up
249260
/// the obligation. This frequently happens for
250261
/// short lived InferCtxt within queries. The opaque type obligations are forwarded
251262
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
252-
pub defining_use_anchor: Option<LocalDefId>,
263+
///
264+
/// It is default value is `DefiningAnchor::Error`, this way it is easier to catch errors that
265+
/// might come up during inference or typeck.
266+
pub defining_use_anchor: DefiningAnchor,
253267

254268
/// During type-checking/inference of a body, `in_progress_typeck_results`
255269
/// contains a reference to the typeck results being built up, which are
@@ -526,7 +540,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
526540
pub struct InferCtxtBuilder<'tcx> {
527541
tcx: TyCtxt<'tcx>,
528542
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
529-
defining_use_anchor: Option<LocalDefId>,
543+
defining_use_anchor: DefiningAnchor,
530544
}
531545

532546
pub trait TyCtxtInferExt<'tcx> {
@@ -535,7 +549,11 @@ pub trait TyCtxtInferExt<'tcx> {
535549

536550
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
537551
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
538-
InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
552+
InferCtxtBuilder {
553+
tcx: self,
554+
defining_use_anchor: DefiningAnchor::Error,
555+
fresh_typeck_results: None,
556+
}
539557
}
540558
}
541559

@@ -545,7 +563,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
545563
/// Will also change the scope for opaque type defining use checks to the given owner.
546564
pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
547565
self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
548-
self.with_opaque_type_inference(table_owner)
566+
self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
549567
}
550568

551569
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
@@ -554,8 +572,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
554572
/// It is only meant to be called in two places, for typeck
555573
/// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
556574
/// in mir borrowck.
557-
pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
558-
self.defining_use_anchor = Some(defining_use_anchor);
575+
pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
576+
self.defining_use_anchor = defining_use_anchor;
559577
self
560578
}
561579

compiler/rustc_infer/src/infer/opaque_types.rs

+45-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::infer::{InferCtxt, InferOk};
1+
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
22
use crate::traits;
33
use hir::def_id::{DefId, LocalDefId};
44
use hir::{HirId, OpaqueTyOrigin};
@@ -101,44 +101,46 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
101101
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
102102
ty::Opaque(def_id, substs) if def_id.is_local() => {
103103
let def_id = def_id.expect_local();
104-
let origin = if self.defining_use_anchor.is_some() {
105-
// Check that this is `impl Trait` type is
106-
// declared by `parent_def_id` -- i.e., one whose
107-
// value we are inferring. At present, this is
108-
// always true during the first phase of
109-
// type-check, but not always true later on during
110-
// NLL. Once we support named opaque types more fully,
111-
// this same scenario will be able to arise during all phases.
112-
//
113-
// Here is an example using type alias `impl Trait`
114-
// that indicates the distinction we are checking for:
115-
//
116-
// ```rust
117-
// mod a {
118-
// pub type Foo = impl Iterator;
119-
// pub fn make_foo() -> Foo { .. }
120-
// }
121-
//
122-
// mod b {
123-
// fn foo() -> a::Foo { a::make_foo() }
124-
// }
125-
// ```
126-
//
127-
// Here, the return type of `foo` references an
128-
// `Opaque` indeed, but not one whose value is
129-
// presently being inferred. You can get into a
130-
// similar situation with closure return types
131-
// today:
132-
//
133-
// ```rust
134-
// fn foo() -> impl Iterator { .. }
135-
// fn bar() {
136-
// let x = || foo(); // returns the Opaque assoc with `foo`
137-
// }
138-
// ```
139-
self.opaque_type_origin(def_id, cause.span)?
140-
} else {
141-
self.opaque_ty_origin_unchecked(def_id, cause.span)
104+
let origin = match self.defining_use_anchor {
105+
DefiningAnchor::Bind(_) => {
106+
// Check that this is `impl Trait` type is
107+
// declared by `parent_def_id` -- i.e., one whose
108+
// value we are inferring. At present, this is
109+
// always true during the first phase of
110+
// type-check, but not always true later on during
111+
// NLL. Once we support named opaque types more fully,
112+
// this same scenario will be able to arise during all phases.
113+
//
114+
// Here is an example using type alias `impl Trait`
115+
// that indicates the distinction we are checking for:
116+
//
117+
// ```rust
118+
// mod a {
119+
// pub type Foo = impl Iterator;
120+
// pub fn make_foo() -> Foo { .. }
121+
// }
122+
//
123+
// mod b {
124+
// fn foo() -> a::Foo { a::make_foo() }
125+
// }
126+
// ```
127+
//
128+
// Here, the return type of `foo` references an
129+
// `Opaque` indeed, but not one whose value is
130+
// presently being inferred. You can get into a
131+
// similar situation with closure return types
132+
// today:
133+
//
134+
// ```rust
135+
// fn foo() -> impl Iterator { .. }
136+
// fn bar() {
137+
// let x = || foo(); // returns the Opaque assoc with `foo`
138+
// }
139+
// ```
140+
self.opaque_type_origin(def_id, cause.span)?
141+
}
142+
DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
143+
DefiningAnchor::Error => return None,
142144
};
143145
if let ty::Opaque(did2, _) = *b.kind() {
144146
// We could accept this, but there are various ways to handle this situation, and we don't
@@ -407,7 +409,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
407409
#[instrument(skip(self), level = "trace")]
408410
pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
409411
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
410-
let parent_def_id = self.defining_use_anchor?;
412+
let parent_def_id = match self.defining_use_anchor {
413+
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
414+
DefiningAnchor::Bind(bind) => bind,
415+
};
411416
let item_kind = &self.tcx.hir().expect_item(def_id).kind;
412417

413418
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {

compiler/rustc_trait_selection/src/traits/codegen.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// seems likely that they should eventually be merged into more
44
// general routines.
55

6-
use crate::infer::TyCtxtInferExt;
6+
use crate::infer::{DefiningAnchor, TyCtxtInferExt};
77
use crate::traits::{
88
FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
99
Unimplemented,
@@ -30,7 +30,9 @@ pub fn codegen_fulfill_obligation<'tcx>(
3030

3131
// Do the initial selection for the obligation. This yields the
3232
// shallow result we are looking for -- that is, what specific impl.
33-
tcx.infer_ctxt().enter(|infcx| {
33+
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(|infcx| {
34+
//~^ HACK `Bubble` is required for
35+
// this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
3436
let mut selcx = SelectionContext::new(&infcx);
3537

3638
let obligation_cause = ObligationCause::dummy();
@@ -69,7 +71,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
6971

7072
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
7173
// as they will get constrained elsewhere, too.
72-
let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
74+
// (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
75+
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
7376

7477
debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
7578
Ok(&*tcx.arena.alloc(impl_source))

0 commit comments

Comments
 (0)