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 c57ec9ef78f68..5e0808792532f 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 439a113ef3811..87d826021b703 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 61b3f0ca2847c..bd97f6f090646 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 75e2ba58f33fb..874909bf486c8 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 3fdc2da9f1e2e..5ac392914e57b 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 ad14d6b7521bc..355f0754ab1b8 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 94def69008677..6256c4a01d386 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 8c1eaeb6aa7b9..b839015f97f61 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 60a7f20444680..6d144a4be6ed3 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 cc247bbcb1199..7f15c1c1f5770 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