From 78013f296acd79af84dede7dae1580fd36480c7c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 25 Sep 2021 13:04:00 -0500 Subject: [PATCH] Don't anonymize bound region names during typeck 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. --- compiler/rustc_typeck/src/check/writeback.rs | 28 ++++++++++++++++++- ...ound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr | 4 +-- .../hr-subtype.bound_a_vs_free_x.nll.stderr | 2 +- ...pe.bound_inv_a_b_vs_bound_inv_a.nll.stderr | 8 +++--- .../lub-glb/old-lub-glb-hr-noteq1.nll.stderr | 4 +-- .../ui/lub-glb/old-lub-glb-object.nll.stderr | 8 +++--- src/test/ui/nll/relate_tys/fn-subtype.stderr | 2 +- .../ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr | 4 +-- src/test/ui/nll/relate_tys/trait-hrtb.stderr | 2 +- src/test/ui/rfc1623.nll.stderr | 8 +++--- 10 files changed, 48 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index c57ec9ef78f6..5e0808792532 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -732,6 +732,26 @@ 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 @@ -739,7 +759,13 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, '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); diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr index 439a113ef381..87d826021b70 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr @@ -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 fn(&'r u32, &'s u32) -> &'r u32>` - found enum `Option fn(&'r u32, &'r u32) -> &'r u32>` + = note: expected enum `Option fn(&'a u32, &'b u32) -> &'a u32>` + found enum `Option 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 diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr index 61b3f0ca2847..bd97f6f09064 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr @@ -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 fn(&'r u32)>` + = note: expected enum `Option fn(&'a u32)>` found enum `Option` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr index 75e2ba58f33f..874909bf486c 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr @@ -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 fn(Inv<'r>, Inv<'s>)>` - found enum `Option fn(Inv<'r>, Inv<'r>)>` + = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` + found enum `Option 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 @@ -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 fn(Inv<'r>, Inv<'s>)>` - found enum `Option fn(Inv<'r>, Inv<'r>)>` + = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` + found enum `Option 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 diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr index 3fdc2da9f1e2..5ac392914e57 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr @@ -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 diff --git a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr index ad14d6b7521b..355f0754ab1b 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr @@ -4,8 +4,8 @@ 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 @@ -13,8 +13,8 @@ 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: aborting due to 2 previous errors diff --git a/src/test/ui/nll/relate_tys/fn-subtype.stderr b/src/test/ui/nll/relate_tys/fn-subtype.stderr index 94def6900867..6256c4a01d38 100644 --- a/src/test/ui/nll/relate_tys/fn-subtype.stderr +++ b/src/test/ui/nll/relate_tys/fn-subtype.stderr @@ -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 diff --git a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr index 8c1eaeb6aa7b..b839015f97f6 100644 --- a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr +++ b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr @@ -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 @@ -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 diff --git a/src/test/ui/nll/relate_tys/trait-hrtb.stderr b/src/test/ui/nll/relate_tys/trait-hrtb.stderr index 60a7f2044468..6d144a4be6ed 100644 --- a/src/test/ui/nll/relate_tys/trait-hrtb.stderr +++ b/src/test/ui/nll/relate_tys/trait-hrtb.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let y: Box 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 diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr index cc247bbcb119..7f15c1c1f577 100644 --- a/src/test/ui/rfc1623.nll.stderr +++ b/src/test/ui/rfc1623.nll.stderr @@ -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 @@ -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 @@ -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 @@ -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