Skip to content

Commit

Permalink
Don't anonymize bound region names during typeck
Browse files Browse the repository at this point in the history
Once this anonymization has performed, we have no
way of recovering the original names during NLL
borrow checking. Keeping the original names allows
error messages in full NLL mode to contain the original
bound region names.

As a result, the typeck results may contain types that
differ only in the names used for their bound regions. However,
anonimization of bound regions does not guarantee that
all distinct types are unqual (e.g. not subtypes of each other).
For example, `for<'a> fn(&'a u32, &'a u32)` and
`for<'b, 'c> fn(&'b u32, &'c u32)` are subtypes of each other,
as explained here:

https://github.com/rust-lang/rust/blob/63cc2bb3d07d6c726dfcdc5f95cbe5ed4760641a/compiler/rustc_infer/src/infer/nll_relate/mod.rs#L682-L690

Therefore, any code handling types with higher-ranked regions already
needs to handle the case where two distinct `Ty`s are 'actually'
equal.
  • Loading branch information
Aaron1011 committed Sep 25, 2021
1 parent 63cc2bb commit 78013f2
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 22 deletions.
28 changes: 27 additions & 1 deletion compiler/rustc_typeck/src/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,14 +732,40 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
}
}

struct EraseEarlyRegions<'tcx> {
tcx: TyCtxt<'tcx>,
}

impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
ty.super_fold_with(self)
} else {
ty
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased }
}
}

impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
self.tcx
}

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match self.infcx.fully_resolve(t) {
Ok(t) => self.infcx.tcx.erase_regions(t),
Ok(t) => {
// Do not anonymize late-bound regions
// (e.g. keep `for<'a>` named `for<'a>`).
// This allows NLL to generate error messages that
// refer to the higher-ranked lifetime names written by the user.
EraseEarlyRegions { tcx: self.infcx.tcx }.fold_ty(t)
}
Err(_) => {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
self.report_type_error(t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u3
LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
| |_____________________________________________- in this macro invocation
|
= note: expected enum `Option<for<'r, 's> fn(&'r u32, &'s u32) -> &'r u32>`
found enum `Option<for<'r> fn(&'r u32, &'r u32) -> &'r u32>`
= note: expected enum `Option<for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32>`
found enum `Option<for<'a> fn(&'a u32, &'a u32) -> &'a u32>`
= note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
LL | | fn(&'x u32)) }
| |______________- in this macro invocation
|
= note: expected enum `Option<for<'r> fn(&'r u32)>`
= note: expected enum `Option<for<'a> fn(&'a u32)>`
found enum `Option<fn(&u32)>`
= note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
| |__________________________________- in this macro invocation
|
= note: expected enum `Option<for<'r, 's> fn(Inv<'r>, Inv<'s>)>`
found enum `Option<for<'r> fn(Inv<'r>, Inv<'r>)>`
= note: expected enum `Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
found enum `Option<for<'a> fn(Inv<'a>, Inv<'a>)>`
= note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
Expand All @@ -22,8 +22,8 @@ LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
| |__________________________________- in this macro invocation
|
= note: expected enum `Option<for<'r, 's> fn(Inv<'r>, Inv<'s>)>`
found enum `Option<for<'r> fn(Inv<'r>, Inv<'r>)>`
= note: expected enum `Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
found enum `Option<for<'a> fn(Inv<'a>, Inv<'a>)>`
= note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ error[E0308]: mismatched types
LL | _ => y,
| ^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's> fn(&'r u8, &'s u8) -> &'r u8`
found fn pointer `for<'r> fn(&'r u8, &'r u8) -> &'r u8`
= note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`

error: aborting due to previous error

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ error[E0308]: mismatched types
LL | _ => y,
| ^ one type is more general than the other
|
= note: expected trait object `dyn for<'r, 's> Foo<&'r u8, &'s u8>`
found trait object `dyn for<'r> Foo<&'r u8, &'r u8>`
= note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
found trait object `dyn for<'a> Foo<&'a u8, &'a u8>`

error[E0308]: mismatched types
--> $DIR/old-lub-glb-object.rs:10:14
|
LL | _ => y,
| ^ one type is more general than the other
|
= note: expected trait object `dyn for<'r, 's> Foo<&'r u8, &'s u8>`
found trait object `dyn for<'r> Foo<&'r u8, &'r u8>`
= note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
found trait object `dyn for<'a> Foo<&'a u8, &'a u8>`

error: aborting due to 2 previous errors

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/nll/relate_tys/fn-subtype.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0308]: mismatched types
LL | let y: for<'a> fn(&'a ()) = x;
| ^ one type is more general than the other
|
= note: expected fn pointer `for<'r> fn(&'r ())`
= note: expected fn pointer `for<'a> fn(&'a ())`
found fn pointer `fn(&())`

error: aborting due to previous error
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0308]: mismatched types
LL | let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
| ^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's> fn(&'r u32, &'s u32) -> &'r u32`
= note: expected fn pointer `for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32`
found fn pointer `for<'a> fn(&'a u32, &'a u32) -> &'a u32`

error[E0308]: mismatched types
Expand All @@ -14,7 +14,7 @@ LL | let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32`
found fn pointer `for<'r> fn(&'r u32, &'r u32) -> &'r u32`
found fn pointer `for<'a> fn(&'a u32, &'a u32) -> &'a u32`

error: aborting due to 2 previous errors

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/nll/relate_tys/trait-hrtb.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0308]: mismatched types
LL | let y: Box<dyn for<'a> Foo<'a>> = x;
| ^ one type is more general than the other
|
= note: expected trait object `dyn for<'r> Foo<'r>`
= note: expected trait object `dyn for<'a> Foo<'a>`
found trait object `dyn Foo<'_>`

error: aborting due to previous error
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/rfc1623.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ LL | |
LL | | };
| |_^ one type is more general than the other
|
= note: expected type `for<'r, 's> Fn<(&'r Foo<'s>,)>`
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
found type `Fn<(&Foo<'_>,)>`

error[E0308]: mismatched types
Expand All @@ -46,7 +46,7 @@ LL | |
LL | | };
| |_^ one type is more general than the other
|
= note: expected type `for<'r, 's> Fn<(&'r Foo<'s>,)>`
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
found type `Fn<(&Foo<'_>,)>`

error: implementation of `FnOnce` is not general enough
Expand All @@ -61,7 +61,7 @@ LL | |
LL | | };
| |_^ implementation of `FnOnce` is not general enough
|
= note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'_>,)>`, for any lifetime `'1`...
= note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`

error: implementation of `FnOnce` is not general enough
Expand All @@ -76,7 +76,7 @@ LL | |
LL | | };
| |_^ implementation of `FnOnce` is not general enough
|
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&Foo<'1>,)>`, for any lifetime `'1`...
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`

error: aborting due to 5 previous errors
Expand Down

0 comments on commit 78013f2

Please sign in to comment.