Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit db68788

Browse files
committedMar 22, 2025
Auto merge of #138719 - lcnr:concrete_opaque_types-closures, r=oli-obk
merge opaque types defined in nested bodies A small step towards rust-lang/types-team#129 r? `@oli-obk`
2 parents 2a1c8be + cfc78ce commit db68788

19 files changed

+147
-153
lines changed
 

‎compiler/rustc_borrowck/src/lib.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ mod def_use;
7373
mod diagnostics;
7474
mod member_constraints;
7575
mod nll;
76+
mod opaque_types;
7677
mod path_utils;
7778
mod place_ext;
7879
mod places_conflict;
@@ -192,7 +193,7 @@ fn do_mir_borrowck<'tcx>(
192193
// Compute non-lexical lifetimes.
193194
let nll::NllOutput {
194195
regioncx,
195-
opaque_type_values,
196+
concrete_opaque_types,
196197
polonius_input,
197198
polonius_output,
198199
opt_closure_req,
@@ -222,7 +223,7 @@ fn do_mir_borrowck<'tcx>(
222223
body,
223224
&regioncx,
224225
&opt_closure_req,
225-
&opaque_type_values,
226+
&concrete_opaque_types,
226227
diags_buffer,
227228
);
228229

@@ -357,7 +358,7 @@ fn do_mir_borrowck<'tcx>(
357358
let tainted_by_errors = mbcx.emit_errors();
358359

359360
let result = BorrowCheckResult {
360-
concrete_opaque_types: opaque_type_values,
361+
concrete_opaque_types: concrete_opaque_types.into_inner(),
361362
closure_requirements: opt_closure_req,
362363
used_mut_upvars: mbcx.used_mut_upvars,
363364
tainted_by_errors,

‎compiler/rustc_borrowck/src/nll.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@ use std::str::FromStr;
66
use std::{env, io};
77

88
use polonius_engine::{Algorithm, Output};
9-
use rustc_data_structures::fx::FxIndexMap;
10-
use rustc_hir::def_id::LocalDefId;
119
use rustc_index::IndexSlice;
1210
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
1311
use rustc_middle::mir::{
1412
Body, ClosureOutlivesSubject, ClosureRegionRequirements, PassWhere, Promoted, create_dump_file,
1513
dump_enabled, dump_mir,
1614
};
1715
use rustc_middle::ty::print::with_no_trimmed_paths;
18-
use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
16+
use rustc_middle::ty::{self, TyCtxt};
1917
use rustc_mir_dataflow::ResultsCursor;
2018
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
2119
use rustc_mir_dataflow::move_paths::MoveData;
@@ -27,6 +25,7 @@ use tracing::{debug, instrument};
2725
use crate::borrow_set::BorrowSet;
2826
use crate::consumers::ConsumerOptions;
2927
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
28+
use crate::opaque_types::ConcreteOpaqueTypes;
3029
use crate::polonius::PoloniusDiagnosticsContext;
3130
use crate::polonius::legacy::{
3231
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
@@ -40,7 +39,7 @@ use crate::{BorrowckInferCtxt, polonius, renumber};
4039
/// closure requirements to propagate, and any generated errors.
4140
pub(crate) struct NllOutput<'tcx> {
4241
pub regioncx: RegionInferenceContext<'tcx>,
43-
pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
42+
pub concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
4443
pub polonius_input: Option<Box<PoloniusFacts>>,
4544
pub polonius_output: Option<Box<PoloniusOutput>>,
4645
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
@@ -99,6 +98,8 @@ pub(crate) fn compute_regions<'a, 'tcx>(
9998

10099
let location_map = Rc::new(DenseLocationMap::new(body));
101100

101+
let mut concrete_opaque_types = ConcreteOpaqueTypes::default();
102+
102103
// Run the MIR type-checker.
103104
let MirTypeckResults {
104105
constraints,
@@ -116,6 +117,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
116117
flow_inits,
117118
move_data,
118119
Rc::clone(&location_map),
120+
&mut concrete_opaque_types,
119121
);
120122

121123
// Create the region inference context, taking ownership of the
@@ -180,11 +182,11 @@ pub(crate) fn compute_regions<'a, 'tcx>(
180182
infcx.set_tainted_by_errors(guar);
181183
}
182184

183-
let remapped_opaque_tys = regioncx.infer_opaque_types(infcx, opaque_type_values);
185+
regioncx.infer_opaque_types(infcx, opaque_type_values, &mut concrete_opaque_types);
184186

185187
NllOutput {
186188
regioncx,
187-
opaque_type_values: remapped_opaque_tys,
189+
concrete_opaque_types,
188190
polonius_input: polonius_facts.map(Box::new),
189191
polonius_output,
190192
opt_closure_req: closure_region_requirements,
@@ -300,7 +302,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
300302
body: &Body<'tcx>,
301303
regioncx: &RegionInferenceContext<'tcx>,
302304
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
303-
opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
305+
concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>,
304306
diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
305307
) {
306308
let tcx = infcx.tcx;
@@ -343,8 +345,8 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
343345
err
344346
};
345347

346-
if !opaque_type_values.is_empty() {
347-
err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}"));
348+
if !concrete_opaque_types.is_empty() {
349+
err.note(format!("Inferred opaque type values:\n{concrete_opaque_types:#?}"));
348350
}
349351

350352
diagnostics_buffer.buffer_non_error(err);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use rustc_data_structures::fx::FxIndexMap;
2+
use rustc_hir::def_id::LocalDefId;
3+
use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt};
4+
5+
#[derive(Debug, Default)]
6+
pub(super) struct ConcreteOpaqueTypes<'tcx> {
7+
concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
8+
}
9+
10+
impl<'tcx> ConcreteOpaqueTypes<'tcx> {
11+
pub(super) fn is_empty(&self) -> bool {
12+
self.concrete_opaque_types.is_empty()
13+
}
14+
15+
pub(super) fn into_inner(self) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
16+
self.concrete_opaque_types
17+
}
18+
19+
/// Insert an opaque type into the list of opaque types defined by this function
20+
/// after mapping the hidden type to the generic parameters of the opaque type
21+
/// definition.
22+
pub(super) fn insert(
23+
&mut self,
24+
tcx: TyCtxt<'tcx>,
25+
def_id: LocalDefId,
26+
hidden_ty: OpaqueHiddenType<'tcx>,
27+
) {
28+
// Sometimes two opaque types are the same only after we remap the generic parameters
29+
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to
30+
// `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we
31+
// only know that once we convert the generic parameters to those of the opaque type.
32+
if let Some(prev) = self.concrete_opaque_types.get_mut(&def_id) {
33+
if prev.ty != hidden_ty.ty {
34+
let (Ok(guar) | Err(guar)) =
35+
prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit());
36+
prev.ty = Ty::new_error(tcx, guar);
37+
}
38+
// Pick a better span if there is one.
39+
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
40+
prev.span = prev.span.substitute_dummy(hidden_ty.span);
41+
} else {
42+
self.concrete_opaque_types.insert(def_id, hidden_ty);
43+
}
44+
}
45+
46+
pub(super) fn extend_from_nested_body(
47+
&mut self,
48+
tcx: TyCtxt<'tcx>,
49+
nested_body: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
50+
) {
51+
for (&def_id, &hidden_ty) in nested_body {
52+
self.insert(tcx, def_id, hidden_ty);
53+
}
54+
}
55+
}

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

+8-29
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
1515
use tracing::{debug, instrument};
1616

1717
use super::RegionInferenceContext;
18+
use crate::opaque_types::ConcreteOpaqueTypes;
1819
use crate::session_diagnostics::{LifetimeMismatchOpaqueParam, NonGenericOpaqueTypeParam};
1920
use crate::universal_regions::RegionClassification;
2021

@@ -67,8 +68,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
6768
&self,
6869
infcx: &InferCtxt<'tcx>,
6970
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
70-
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
71-
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
71+
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
72+
) {
7273
let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
7374
FxIndexMap::default();
7475

@@ -143,33 +144,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
143144
continue;
144145
}
145146
}
146-
// Sometimes two opaque types are the same only after we remap the generic parameters
147-
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to
148-
// `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we
149-
// only know that once we convert the generic parameters to those of the opaque type.
150-
if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
151-
if prev.ty != ty {
152-
let guar = ty.error_reported().err().unwrap_or_else(|| {
153-
let (Ok(e) | Err(e)) = prev
154-
.build_mismatch_error(
155-
&OpaqueHiddenType { ty, span: concrete_type.span },
156-
infcx.tcx,
157-
)
158-
.map(|d| d.emit());
159-
e
160-
});
161-
prev.ty = Ty::new_error(infcx.tcx, guar);
162-
}
163-
// Pick a better span if there is one.
164-
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
165-
prev.span = prev.span.substitute_dummy(concrete_type.span);
166-
} else {
167-
result.insert(
168-
opaque_type_key.def_id,
169-
OpaqueHiddenType { ty, span: concrete_type.span },
170-
);
171-
}
172147

148+
concrete_opaque_types.insert(
149+
infcx.tcx,
150+
opaque_type_key.def_id,
151+
OpaqueHiddenType { ty, span: concrete_type.span },
152+
);
173153
// Check that all opaque types have the same region parameters if they have the same
174154
// non-region parameters. This is necessary because within the new solver we perform
175155
// various query operations modulo regions, and thus could unsoundly select some impls
@@ -193,7 +173,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
193173
});
194174
}
195175
}
196-
result
197176
}
198177

199178
/// Map the regions in the type to named regions. This is similar to what

‎compiler/rustc_borrowck/src/type_check/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use crate::borrow_set::BorrowSet;
4545
use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
4646
use crate::diagnostics::UniverseInfo;
4747
use crate::member_constraints::MemberConstraintSet;
48+
use crate::opaque_types::ConcreteOpaqueTypes;
4849
use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
4950
use crate::polonius::{PoloniusContext, PoloniusLivenessContext};
5051
use crate::region_infer::TypeTest;
@@ -111,6 +112,7 @@ pub(crate) fn type_check<'a, 'tcx>(
111112
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
112113
move_data: &MoveData<'tcx>,
113114
location_map: Rc<DenseLocationMap>,
115+
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
114116
) -> MirTypeckResults<'tcx> {
115117
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
116118
let mut constraints = MirTypeckRegionConstraints {
@@ -165,6 +167,7 @@ pub(crate) fn type_check<'a, 'tcx>(
165167
polonius_facts,
166168
borrow_set,
167169
constraints: &mut constraints,
170+
concrete_opaque_types,
168171
polonius_liveness,
169172
};
170173

@@ -230,6 +233,7 @@ struct TypeChecker<'a, 'tcx> {
230233
polonius_facts: &'a mut Option<PoloniusFacts>,
231234
borrow_set: &'a BorrowSet<'tcx>,
232235
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
236+
concrete_opaque_types: &'a mut ConcreteOpaqueTypes<'tcx>,
233237
/// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints.
234238
polonius_liveness: Option<PoloniusLivenessContext>,
235239
}
@@ -2499,7 +2503,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
24992503
args: GenericArgsRef<'tcx>,
25002504
locations: Locations,
25012505
) -> ty::InstantiatedPredicates<'tcx> {
2502-
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
2506+
let closure_borrowck_results = tcx.mir_borrowck(def_id);
2507+
self.concrete_opaque_types
2508+
.extend_from_nested_body(tcx, &closure_borrowck_results.concrete_opaque_types);
2509+
2510+
if let Some(closure_requirements) = &closure_borrowck_results.closure_requirements {
25032511
constraint_conversion::ConstraintConversion::new(
25042512
self.infcx,
25052513
self.universal_regions,

‎compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs

+1-13
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,6 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
258258
self.tcx
259259
}
260260
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
261-
if let hir::ExprKind::Closure(closure) = ex.kind {
262-
self.check(closure.def_id);
263-
}
264261
intravisit::walk_expr(self, ex);
265262
}
266263
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
@@ -371,14 +368,8 @@ impl RpitConstraintChecker<'_> {
371368
// Use borrowck to get the type with unerased regions.
372369
let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
373370
debug!(?concrete_opaque_types);
374-
for (&def_id, &concrete_type) in concrete_opaque_types {
375-
if def_id != self.def_id {
376-
// Ignore constraints for other opaque types.
377-
continue;
378-
}
379-
371+
if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
380372
debug!(?concrete_type, "found constraint");
381-
382373
if concrete_type.ty != self.found.ty {
383374
if let Ok(d) = self.found.build_mismatch_error(&concrete_type, self.tcx) {
384375
d.emit();
@@ -395,9 +386,6 @@ impl<'tcx> intravisit::Visitor<'tcx> for RpitConstraintChecker<'tcx> {
395386
self.tcx
396387
}
397388
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
398-
if let hir::ExprKind::Closure(closure) = ex.kind {
399-
self.check(closure.def_id);
400-
}
401389
intravisit::walk_expr(self, ex);
402390
}
403391
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {

‎tests/crashes/122904.rs

-12
This file was deleted.

‎tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
use std::fmt::Debug;
33

44
fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
5-
//~^ ERROR cannot resolve opaque type
6-
//~| WARNING elided lifetime has a name
5+
//~^ WARNING elided lifetime has a name
76
|x| x
87
//~^ ERROR expected generic lifetime parameter, found `'_`
98
}

‎tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr

+4-14
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,14 @@ LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
77
= note: `#[warn(elided_named_lifetimes)]` on by default
88

99
error[E0792]: expected generic lifetime parameter, found `'_`
10-
--> $DIR/impl-fn-predefined-lifetimes.rs:7:9
10+
--> $DIR/impl-fn-predefined-lifetimes.rs:6:9
1111
|
1212
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
1313
| -- this generic parameter must be used with a generic lifetime parameter
14-
...
14+
LL |
1515
LL | |x| x
1616
| ^
1717

18-
error[E0720]: cannot resolve opaque type
19-
--> $DIR/impl-fn-predefined-lifetimes.rs:4:35
20-
|
21-
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
22-
| ^^^^^^^^^^^^^^^ recursive opaque type
23-
...
24-
LL | |x| x
25-
| ----- returning here with type `{closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8}`
26-
27-
error: aborting due to 2 previous errors; 1 warning emitted
18+
error: aborting due to 1 previous error; 1 warning emitted
2819

29-
Some errors have detailed explanations: E0720, E0792.
30-
For more information about an error, try `rustc --explain E0720`.
20+
For more information about this error, try `rustc --explain E0792`.

‎tests/ui/impl-trait/issues/issue-86800.rs

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ impl Context {
4040
f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>,
4141
) -> TransactionResult<O> {
4242
//~^ ERROR expected generic lifetime parameter, found `'_`
43-
//~| ERROR: item does not constrain
4443
let mut conn = Connection {};
4544
let mut transaction = TestTransaction { conn: &mut conn };
4645
f(&mut transaction).await
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.