Skip to content

Commit 094a9c7

Browse files
nikomatsakisoli-obk
authored andcommitted
simplify constrain_opaque_types
1 parent af9b508 commit 094a9c7

29 files changed

+419
-331
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
689689
// them down.
690690
let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
691691

692+
// Convert to the SCC representative: sometimes we have inference
693+
// variables in the member constraint that wind up equated with
694+
// universal regions. The scc representative is the minimal numbered
695+
// one from the corresponding scc so it will be the universal region
696+
// if one exists.
697+
for c_r in &mut choice_regions {
698+
let scc = self.constraint_sccs.scc(*c_r);
699+
*c_r = self.scc_representatives[scc];
700+
}
701+
692702
// The 'member region' in a member constraint is part of the
693703
// hidden type, which must be in the root universe. Therefore,
694704
// it cannot have any placeholders in its value.

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
3636
use rustc_span::{Span, DUMMY_SP};
3737
use rustc_target::abi::VariantIdx;
3838
use rustc_trait_selection::infer::InferCtxtExt as _;
39-
use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt};
39+
use rustc_trait_selection::opaque_types::InferCtxtExt;
4040
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
4141
use rustc_trait_selection::traits::query::type_op;
4242
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -185,7 +185,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
185185
&region_bound_pairs,
186186
implicit_region_bound,
187187
&mut borrowck_context,
188-
&universal_region_relations,
189188
|mut cx| {
190189
cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
191190
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
@@ -253,15 +252,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
253252
}
254253

255254
#[instrument(
256-
skip(
257-
infcx,
258-
body,
259-
promoted,
260-
region_bound_pairs,
261-
borrowck_context,
262-
universal_region_relations,
263-
extra
264-
),
255+
skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra),
265256
level = "debug"
266257
)]
267258
fn type_check_internal<'a, 'tcx, R>(
@@ -272,7 +263,6 @@ fn type_check_internal<'a, 'tcx, R>(
272263
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
273264
implicit_region_bound: ty::Region<'tcx>,
274265
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
275-
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
276266
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
277267
) -> R {
278268
let mut checker = TypeChecker::new(
@@ -282,7 +272,6 @@ fn type_check_internal<'a, 'tcx, R>(
282272
region_bound_pairs,
283273
implicit_region_bound,
284274
borrowck_context,
285-
universal_region_relations,
286275
);
287276
let errors_reported = {
288277
let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
@@ -901,7 +890,6 @@ struct TypeChecker<'a, 'tcx> {
901890
implicit_region_bound: ty::Region<'tcx>,
902891
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
903892
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
904-
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
905893
}
906894

907895
struct BorrowCheckContext<'a, 'tcx> {
@@ -1050,7 +1038,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
10501038
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
10511039
implicit_region_bound: ty::Region<'tcx>,
10521040
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
1053-
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
10541041
) -> Self {
10551042
let mut checker = Self {
10561043
infcx,
@@ -1062,7 +1049,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
10621049
implicit_region_bound,
10631050
borrowck_context,
10641051
reported_errors: Default::default(),
1065-
universal_region_relations,
10661052
};
10671053
checker.check_user_type_annotations();
10681054
checker
@@ -1322,8 +1308,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13221308
),
13231309
)?;
13241310

1325-
let universal_region_relations = self.universal_region_relations;
1326-
13271311
// Finally, if we instantiated the anon types successfully, we
13281312
// have to solve any bounds (e.g., `-> impl Iterator` needs to
13291313
// prove that `T: Iterator` where `T` is the type we
@@ -1335,12 +1319,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13351319
ConstraintCategory::OpaqueType,
13361320
CustomTypeOp::new(
13371321
|infcx| {
1338-
infcx.constrain_opaque_type(
1339-
opaque_type_key,
1340-
&opaque_decl,
1341-
GenerateMemberConstraints::IfNoStaticBound,
1342-
universal_region_relations,
1343-
);
1322+
infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
13441323
Ok(InferOk { value: (), obligations: vec![] })
13451324
},
13461325
|| "opaque_type_map".to_string(),

compiler/rustc_trait_selection/src/opaque_types.rs

Lines changed: 16 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use rustc_data_structures::sync::Lrc;
44
use rustc_hir as hir;
55
use rustc_hir::def_id::{DefId, LocalDefId};
66
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
7-
use rustc_infer::infer::free_regions::FreeRegionRelations;
87
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
98
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
109
use rustc_infer::infer::{self, InferCtxt, InferOk};
@@ -37,14 +36,12 @@ pub trait InferCtxtExt<'tcx> {
3736
value_span: Span,
3837
) -> InferOk<'tcx, T>;
3938

40-
fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR);
39+
fn constrain_opaque_types(&self);
4140

42-
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
41+
fn constrain_opaque_type(
4342
&self,
4443
opaque_type_key: OpaqueTypeKey<'tcx>,
4544
opaque_defn: &OpaqueTypeDecl<'tcx>,
46-
mode: GenerateMemberConstraints,
47-
free_region_relations: &FRR,
4845
);
4946

5047
/*private*/
@@ -270,26 +267,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
270267
/// - `opaque_types` -- the map produced by `instantiate_opaque_types`
271268
/// - `free_region_relations` -- something that can be used to relate
272269
/// the free regions (`'a`) that appear in the impl trait.
273-
fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR) {
270+
fn constrain_opaque_types(&self) {
274271
let opaque_types = self.inner.borrow().opaque_types.clone();
275272
for (opaque_type_key, opaque_defn) in opaque_types {
276-
self.constrain_opaque_type(
277-
opaque_type_key,
278-
&opaque_defn,
279-
GenerateMemberConstraints::WhenRequired,
280-
free_region_relations,
281-
);
273+
self.constrain_opaque_type(opaque_type_key, &opaque_defn);
282274
}
283275
}
284276

285277
/// See `constrain_opaque_types` for documentation.
286-
#[instrument(level = "debug", skip(self, free_region_relations))]
287-
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
278+
#[instrument(level = "debug", skip(self))]
279+
fn constrain_opaque_type(
288280
&self,
289281
opaque_type_key: OpaqueTypeKey<'tcx>,
290282
opaque_defn: &OpaqueTypeDecl<'tcx>,
291-
mode: GenerateMemberConstraints,
292-
free_region_relations: &FRR,
293283
) {
294284
let def_id = opaque_type_key.def_id;
295285

@@ -347,6 +337,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
347337
debug!("{:#?}", bounds);
348338
let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
349339

340+
// (A) The regions that appear in the hidden type must be equal to
341+
// one of the regions in scope for the opaque type.
342+
self.generate_member_constraint(
343+
concrete_ty,
344+
opaque_defn,
345+
opaque_type_key,
346+
first_own_region,
347+
);
348+
349+
// (B) We can also generate outlives bounds that must be enforced.
350350
let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds);
351351
if !required_region_bounds.is_empty() {
352352
for required_region in required_region_bounds {
@@ -355,81 +355,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
355355
op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
356356
});
357357
}
358-
if let GenerateMemberConstraints::IfNoStaticBound = mode {
359-
self.generate_member_constraint(
360-
concrete_ty,
361-
opaque_defn,
362-
opaque_type_key,
363-
first_own_region,
364-
);
365-
}
366-
return;
367358
}
368-
369-
// There were no `required_region_bounds`,
370-
// so we have to search for a `least_region`.
371-
// Go through all the regions used as arguments to the
372-
// opaque type. These are the parameters to the opaque
373-
// type; so in our example above, `substs` would contain
374-
// `['a]` for the first impl trait and `'b` for the
375-
// second.
376-
let mut least_region = None;
377-
378-
for subst_arg in &opaque_type_key.substs[first_own_region..] {
379-
let subst_region = match subst_arg.unpack() {
380-
GenericArgKind::Lifetime(r) => r,
381-
GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue,
382-
};
383-
384-
// Compute the least upper bound of it with the other regions.
385-
debug!(?least_region);
386-
debug!(?subst_region);
387-
match least_region {
388-
None => least_region = Some(subst_region),
389-
Some(lr) => {
390-
if free_region_relations.sub_free_regions(self.tcx, lr, subst_region) {
391-
// keep the current least region
392-
} else if free_region_relations.sub_free_regions(self.tcx, subst_region, lr) {
393-
// switch to `subst_region`
394-
least_region = Some(subst_region);
395-
} else {
396-
// There are two regions (`lr` and
397-
// `subst_region`) which are not relatable. We
398-
// can't find a best choice. Therefore,
399-
// instead of creating a single bound like
400-
// `'r: 'a` (which is our preferred choice),
401-
// we will create a "in bound" like `'r in
402-
// ['a, 'b, 'c]`, where `'a..'c` are the
403-
// regions that appear in the impl trait.
404-
405-
return self.generate_member_constraint(
406-
concrete_ty,
407-
opaque_defn,
408-
opaque_type_key,
409-
first_own_region,
410-
);
411-
}
412-
}
413-
}
414-
}
415-
416-
let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
417-
debug!(?least_region);
418-
419-
if let GenerateMemberConstraints::IfNoStaticBound = mode {
420-
if least_region != tcx.lifetimes.re_static {
421-
self.generate_member_constraint(
422-
concrete_ty,
423-
opaque_defn,
424-
opaque_type_key,
425-
first_own_region,
426-
);
427-
}
428-
}
429-
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
430-
tcx,
431-
op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
432-
});
433359
}
434360

435361
/// As a fallback, we sometimes generate an "in constraint". For

compiler/rustc_typeck/src/check/regionck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
296296
self.visit_body(body);
297297
self.visit_region_obligations(body_id.hir_id);
298298

299-
self.constrain_opaque_types(self.outlives_environment.free_region_map());
299+
self.constrain_opaque_types();
300300
}
301301

302302
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
11
error: lifetime may not live long enough
2-
--> $DIR/ret-impl-trait-one.rs:10:65
2+
--> $DIR/ret-impl-trait-one.rs:10:85
3+
|
4+
LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
5+
| ________________________________--__--_______________________________________________^
6+
| | | |
7+
| | | lifetime `'b` defined here
8+
| | lifetime `'a` defined here
9+
LL | |
10+
LL | | (a, b)
11+
LL | | }
12+
| |_^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
13+
|
14+
= help: consider adding the following bound: `'a: 'b`
15+
16+
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
17+
--> $DIR/ret-impl-trait-one.rs:16:65
318
|
419
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
5-
| -- -- ^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
6-
| | |
7-
| | lifetime `'b` defined here
8-
| lifetime `'a` defined here
20+
| -- ^^^^^^^^^^^^^^
21+
| |
22+
| hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
23+
|
24+
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
925
|
10-
= help: consider adding the following bound: `'b: 'a`
26+
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
27+
| ++++
1128

12-
error: aborting due to previous error
29+
error: aborting due to 2 previous errors
1330

31+
For more information about this error, try `rustc --explain E0700`.

src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@
66
trait Trait<'a> { }
77
impl<T> Trait<'_> for T { }
88

9+
// Fails to recognize that both 'a and 'b are mentioned and should thus be accepted
10+
async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
11+
//~^ ERROR lifetime mismatch
12+
(a, b)
13+
}
14+
915
// Only `'a` permitted in return type, not `'b`.
1016
async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
11-
//~^ ERROR lifetime mismatch
17+
//~^ ERROR captures lifetime that does not appear in bounds
18+
//~| ERROR captures lifetime that does not appear in bounds
1219
(a, b)
1320
}
1421

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,40 @@
11
error[E0623]: lifetime mismatch
22
--> $DIR/ret-impl-trait-one.rs:10:65
33
|
4+
LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
5+
| ------ ^^^^^^^^^^^^^^^^^^^
6+
| | |
7+
| | ...but data from `a` is held across an await point here
8+
| | this `async fn` implicitly returns an `impl Future<Output = impl Trait<'a> + 'b>`
9+
| this parameter and the returned future are declared with different lifetimes...
10+
11+
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
12+
--> $DIR/ret-impl-trait-one.rs:16:65
13+
|
414
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
5-
| ------ ^^^^^^^^^^^^^^
6-
| | |
7-
| | ...but data from `b` is held across an await point here
8-
| | this `async fn` implicitly returns an `impl Future<Output = impl Trait<'a>>`
9-
| this parameter and the returned future are declared with different lifetimes...
15+
| -- ^^^^^^^^^^^^^^
16+
| |
17+
| hidden type `(&u8, &u8)` captures the lifetime `'b` as defined here
18+
|
19+
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
20+
|
21+
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
22+
| ++++
23+
24+
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
25+
--> $DIR/ret-impl-trait-one.rs:16:65
26+
|
27+
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
28+
| -- ^^^^^^^^^^^^^^
29+
| |
30+
| hidden type `(&u8, &u8)` captures the lifetime `'b` as defined here
31+
|
32+
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
33+
|
34+
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
35+
| ++++
1036

11-
error: aborting due to previous error
37+
error: aborting due to 3 previous errors
1238

13-
For more information about this error, try `rustc --explain E0623`.
39+
Some errors have detailed explanations: E0623, E0700.
40+
For more information about an error, try `rustc --explain E0623`.

0 commit comments

Comments
 (0)