Skip to content

Commit 20c46d6

Browse files
committed
report unconstrained region in hidden types lazily
1 parent be4794c commit 20c46d6

5 files changed

Lines changed: 198 additions & 13 deletions

File tree

compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
2424
use tracing::{debug, instrument};
2525

2626
use super::reverse_sccs::ReverseSccGraph;
27-
use crate::BorrowckInferCtxt;
2827
use crate::consumers::RegionInferenceContext;
2928
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
3029
use crate::type_check::canonical::fully_perform_op_raw;
3130
use crate::type_check::free_region_relations::UniversalRegionRelations;
3231
use crate::type_check::{Locations, MirTypeckRegionConstraints};
3332
use crate::universal_regions::{RegionClassification, UniversalRegions};
33+
use crate::{BorrowckInferCtxt, CollectRegionConstraintsResult};
3434

3535
mod member_constraints;
3636
mod region_ctxt;
@@ -126,6 +126,31 @@ fn nll_var_to_universal_region<'tcx>(
126126
}
127127
}
128128

129+
/// Record info needed to report the same name error later.
130+
#[derive(Copy, Clone, Debug)]
131+
pub(crate) struct UnexpectedHiddenRegion<'tcx> {
132+
// The def_id of the body where this error occurs.
133+
// Needed to handle region vars with their corresponding `infcx`.
134+
def_id: LocalDefId,
135+
opaque_type_key: OpaqueTypeKey<'tcx>,
136+
hidden_type: ProvisionalHiddenType<'tcx>,
137+
member_region: Region<'tcx>,
138+
}
139+
140+
impl<'tcx> UnexpectedHiddenRegion<'tcx> {
141+
pub(crate) fn to_error(self) -> (LocalDefId, DeferredOpaqueTypeError<'tcx>) {
142+
let UnexpectedHiddenRegion { def_id, opaque_type_key, hidden_type, member_region } = self;
143+
(
144+
def_id,
145+
DeferredOpaqueTypeError::UnexpectedHiddenRegion {
146+
opaque_type_key,
147+
hidden_type,
148+
member_region,
149+
},
150+
)
151+
}
152+
}
153+
129154
/// Collect all defining uses of opaque types inside of this typeck root. This
130155
/// expects the hidden type to be mapped to the definition parameters of the opaque
131156
/// and errors if we end up with distinct hidden types.
@@ -176,11 +201,13 @@ struct DefiningUse<'tcx> {
176201
/// It also means that this whole function is not really soundness critical as we
177202
/// recheck all uses of the opaques regardless.
178203
pub(crate) fn compute_definition_site_hidden_types<'tcx>(
204+
def_id: LocalDefId,
179205
infcx: &BorrowckInferCtxt<'tcx>,
180206
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
181207
constraints: &MirTypeckRegionConstraints<'tcx>,
182208
location_map: Rc<DenseLocationMap>,
183209
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
210+
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
184211
opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
185212
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
186213
let mut errors = Vec::new();
@@ -204,8 +231,10 @@ pub(crate) fn compute_definition_site_hidden_types<'tcx>(
204231
// up equal to one of their choice regions and compute the actual hidden type of
205232
// the opaque type definition. This is stored in the `root_cx`.
206233
compute_definition_site_hidden_types_from_defining_uses(
234+
def_id,
207235
&rcx,
208236
hidden_types,
237+
unconstrained_hidden_type_errors,
209238
&defining_uses,
210239
&mut errors,
211240
);
@@ -274,8 +303,10 @@ fn collect_defining_uses<'tcx>(
274303

275304
#[instrument(level = "debug", skip(rcx, hidden_types, defining_uses, errors))]
276305
fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
306+
def_id: LocalDefId,
277307
rcx: &RegionCtxt<'_, 'tcx>,
278308
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
309+
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
279310
defining_uses: &[DefiningUse<'tcx>],
280311
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
281312
) {
@@ -293,16 +324,29 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
293324
Ok(hidden_type) => hidden_type,
294325
Err(r) => {
295326
debug!("UnexpectedHiddenRegion: {:?}", r);
296-
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
297-
hidden_type,
298-
opaque_type_key,
299-
member_region: ty::Region::new_var(tcx, r),
300-
});
301-
let guar = tcx.dcx().span_delayed_bug(
302-
hidden_type.span,
303-
"opaque type with non-universal region args",
304-
);
305-
ty::ProvisionalHiddenType::new_error(tcx, guar)
327+
// If we're using the next solver, the unconstrained region may be resolved by a
328+
// fully defining use from another body.
329+
// So we don't generate error eagerly here.
330+
if rcx.infcx.tcx.use_typing_mode_borrowck() {
331+
unconstrained_hidden_type_errors.push(UnexpectedHiddenRegion {
332+
def_id,
333+
hidden_type,
334+
opaque_type_key,
335+
member_region: ty::Region::new_var(tcx, r),
336+
});
337+
continue;
338+
} else {
339+
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
340+
hidden_type,
341+
opaque_type_key,
342+
member_region: ty::Region::new_var(tcx, r),
343+
});
344+
let guar = tcx.dcx().span_delayed_bug(
345+
hidden_type.span,
346+
"opaque type with non-universal region args",
347+
);
348+
ty::ProvisionalHiddenType::new_error(tcx, guar)
349+
}
306350
}
307351
};
308352

@@ -570,6 +614,40 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
570614
errors
571615
}
572616

617+
/// We handle `UnexpectedHiddenRegion` error lazily in the next solver as
618+
/// there may be a fully defining use in another body.
619+
///
620+
/// In case such a defining use does not exist, we register an error here.
621+
pub(crate) fn handle_unconstrained_hidden_type_errors<'tcx>(
622+
tcx: TyCtxt<'tcx>,
623+
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
624+
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
625+
collect_region_constraints_results: &mut FxIndexMap<
626+
LocalDefId,
627+
CollectRegionConstraintsResult<'tcx>,
628+
>,
629+
) {
630+
let mut unconstrained_hidden_type_errors = std::mem::take(unconstrained_hidden_type_errors);
631+
unconstrained_hidden_type_errors
632+
.retain(|unconstrained| !hidden_types.contains_key(&unconstrained.opaque_type_key.def_id));
633+
634+
unconstrained_hidden_type_errors.iter().for_each(|t| {
635+
tcx.dcx()
636+
.span_delayed_bug(t.hidden_type.span, "opaque type with non-universal region args");
637+
});
638+
639+
// `UnexpectedHiddenRegion` error contains region var which only makes sense in the
640+
// corresponding `infcx`.
641+
// So we need to insert the error to the body where it originates from.
642+
for error in unconstrained_hidden_type_errors {
643+
let (def_id, error) = error.to_error();
644+
let Some(result) = collect_region_constraints_results.get_mut(&def_id) else {
645+
unreachable!("the body should depend on opaques type if it has opaque use");
646+
};
647+
result.deferred_opaque_type_errors.push(error);
648+
}
649+
}
650+
573651
/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types.
574652
/// We do not check these new uses so this could be unsound.
575653
///

compiler/rustc_borrowck/src/root_cx.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ use smallvec::SmallVec;
1212
use crate::consumers::BorrowckConsumer;
1313
use crate::nll::compute_closure_requirements_modulo_opaques;
1414
use crate::region_infer::opaque_types::{
15-
apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
15+
UnexpectedHiddenRegion, apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
1616
compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
17+
handle_unconstrained_hidden_type_errors,
1718
};
1819
use crate::type_check::{Locations, constraint_conversion};
1920
use crate::{
@@ -26,7 +27,12 @@ use crate::{
2627
pub(super) struct BorrowCheckRootCtxt<'tcx> {
2728
pub tcx: TyCtxt<'tcx>,
2829
root_def_id: LocalDefId,
30+
/// This contains fully resolved hidden types or `ty::Error`.
2931
hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
32+
/// This contains unconstrained regions in hidden types.
33+
/// Only used for deferred error reporting. See
34+
/// [`crate::region_infer::opaque_types::handle_unconstrained_hidden_type_errors`]
35+
unconstrained_hidden_type_errors: Vec<UnexpectedHiddenRegion<'tcx>>,
3036
/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
3137
/// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
3238
/// their parents.
@@ -49,6 +55,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
4955
tcx,
5056
root_def_id,
5157
hidden_types: Default::default(),
58+
unconstrained_hidden_type_errors: Default::default(),
5259
collect_region_constraints_results: Default::default(),
5360
propagated_borrowck_results: Default::default(),
5461
tainted_by_errors: None,
@@ -84,23 +91,32 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
8491

8592
fn handle_opaque_type_uses(&mut self) {
8693
let mut per_body_info = Vec::new();
87-
for input in self.collect_region_constraints_results.values_mut() {
94+
for (def_id, input) in &mut self.collect_region_constraints_results {
8895
let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
8996
&input.infcx,
9097
&input.universal_region_relations,
9198
&mut input.constraints,
9299
);
93100
input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
101+
*def_id,
94102
&input.infcx,
95103
&input.universal_region_relations,
96104
&input.constraints,
97105
Rc::clone(&input.location_map),
98106
&mut self.hidden_types,
107+
&mut self.unconstrained_hidden_type_errors,
99108
&opaque_types,
100109
);
101110
per_body_info.push((num_entries, opaque_types));
102111
}
103112

113+
handle_unconstrained_hidden_type_errors(
114+
self.tcx,
115+
&mut self.hidden_types,
116+
&mut self.unconstrained_hidden_type_errors,
117+
&mut self.collect_region_constraints_results,
118+
);
119+
104120
for (input, (opaque_types_storage_num_entries, opaque_types)) in
105121
self.collect_region_constraints_results.values_mut().zip(per_body_info)
106122
{
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ check-pass
2+
//@ compile-flags: -Znext-solver
3+
4+
// Regression test for trait-system-refactor-initiative#264.
5+
//
6+
// Some defining uses of opaque types can't constrain captured regions to universals.
7+
// Previouly, we eagerly report error in this case.
8+
// Now we report error only if there's no fully defining use from all bodies of the typeck root.
9+
10+
struct Inv<'a>(*mut &'a ());
11+
12+
fn mk_static() -> Inv<'static> { todo!() }
13+
14+
fn guide_closure_sig<'a>(f: impl FnOnce() -> Inv<'a>) {}
15+
16+
fn unconstrained_in_closure() -> impl Sized {
17+
guide_closure_sig(|| unconstrained_in_closure());
18+
mk_static()
19+
}
20+
21+
fn main() {}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//@ compile-flags: -Znext-solver
2+
3+
// Just for diagnostics completeness.
4+
// This is probably unimportant as we only report one error for such case in HIR typeck.
5+
6+
#![feature(type_alias_impl_trait)]
7+
8+
struct Invar<'a>(*mut &'a ());
9+
10+
fn mk_invar<'a>(a: &'a i32) -> Invar<'a> {
11+
todo!()
12+
}
13+
14+
type MultiUse = impl Sized;
15+
16+
#[define_opaque(MultiUse)]
17+
fn capture_different_universals_not_on_bounds<'a, 'b, 'c>(a: &'a i32, b: &'b i32, c: &'c i32) {
18+
let _ = || -> MultiUse {
19+
//~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
20+
mk_invar(a)
21+
};
22+
let _ = || -> MultiUse {
23+
//~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
24+
mk_invar(b)
25+
};
26+
let _ = || {
27+
let _ = || -> MultiUse {
28+
//~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
29+
mk_invar(c)
30+
};
31+
};
32+
}
33+
34+
fn main() {}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
2+
--> $DIR/report-all-unexpected-hidden-errors.rs:18:19
3+
|
4+
LL | type MultiUse = impl Sized;
5+
| ---------- opaque type defined here
6+
...
7+
LL | let _ = || -> MultiUse {
8+
| ^^^^^^^^
9+
|
10+
= note: hidden type `Invar<'_>` captures lifetime `'_`
11+
12+
error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
13+
--> $DIR/report-all-unexpected-hidden-errors.rs:22:19
14+
|
15+
LL | type MultiUse = impl Sized;
16+
| ---------- opaque type defined here
17+
...
18+
LL | let _ = || -> MultiUse {
19+
| ^^^^^^^^
20+
|
21+
= note: hidden type `Invar<'_>` captures lifetime `'_`
22+
23+
error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
24+
--> $DIR/report-all-unexpected-hidden-errors.rs:27:23
25+
|
26+
LL | type MultiUse = impl Sized;
27+
| ---------- opaque type defined here
28+
...
29+
LL | let _ = || -> MultiUse {
30+
| ^^^^^^^^
31+
|
32+
= note: hidden type `Invar<'_>` captures lifetime `'_`
33+
34+
error: aborting due to 3 previous errors
35+
36+
For more information about this error, try `rustc --explain E0700`.

0 commit comments

Comments
 (0)