about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2022-10-08 18:14:59 -0700
committerGitHub <noreply@github.com>2022-10-08 18:14:59 -0700
commit5ba30a680cb272d607883ebdc2da931e9b69ede7 (patch)
treeccf3f8e229034c0501b34011cf0cd8a028c2f2d5
parentbf37054b1ff25e42c077e5b52c6dc492125d8f91 (diff)
parent048e637e9ee4c9fe8813109d89f97e140776b0a4 (diff)
downloadrust-5ba30a680cb272d607883ebdc2da931e9b69ede7.tar.gz
rust-5ba30a680cb272d607883ebdc2da931e9b69ede7.zip
Rollup merge of #102514 - b-naber:binder-print-fixes, r=jackh726
Don't repeat lifetime names from outer binder in print

Fixes https://github.com/rust-lang/rust/issues/102392
Fixes https://github.com/rust-lang/rust/issues/102414

r? ```@lcnr```
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs75
-rw-r--r--src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr2
-rw-r--r--src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr4
-rw-r--r--src/test/ui/lifetimes/nested-binder-print.rs10
-rw-r--r--src/test/ui/lifetimes/nested-binder-print.stderr14
-rw-r--r--src/test/ui/lifetimes/re-empty-in-error.stderr2
-rw-r--r--src/test/ui/regions/issue-102392.rs6
-rw-r--r--src/test/ui/regions/issue-102392.stderr14
-rw-r--r--src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr4
-rw-r--r--src/test/ui/where-clauses/higher-ranked-fn-type.rs2
10 files changed, 114 insertions, 19 deletions
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 82d7c0a97cb..c0607a102a9 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2055,7 +2055,14 @@ struct RegionFolder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     current_index: ty::DebruijnIndex,
     region_map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
-    name: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
+    name: &'a mut (
+                dyn FnMut(
+        Option<ty::DebruijnIndex>, // Debruijn index of the folded late-bound region
+        ty::DebruijnIndex,         // Index corresponding to binder level
+        ty::BoundRegion,
+    ) -> ty::Region<'tcx>
+                    + 'a
+            ),
 }
 
 impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
@@ -2086,7 +2093,9 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         let name = &mut self.name;
         let region = match *r {
-            ty::ReLateBound(_, br) => *self.region_map.entry(br).or_insert_with(|| name(br)),
+            ty::ReLateBound(db, br) if db >= self.current_index => {
+                *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br))
+            }
             ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
                 // If this is an anonymous placeholder, don't rename. Otherwise, in some
                 // async fns, we get a `for<'r> Send` bound
@@ -2095,7 +2104,10 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
                     _ => {
                         // Index doesn't matter, since this is just for naming and these never get bound
                         let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
-                        *self.region_map.entry(br).or_insert_with(|| name(br))
+                        *self
+                            .region_map
+                            .entry(br)
+                            .or_insert_with(|| name(None, self.current_index, br))
                     }
                 }
             }
@@ -2234,24 +2246,63 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             })
         } else {
             let tcx = self.tcx;
-            let mut name = |br: ty::BoundRegion| {
-                start_or_continue(&mut self, "for<", ", ");
-                let kind = match br.kind {
+
+            // Closure used in `RegionFolder` to create names for anonymous late-bound
+            // regions. We use two `DebruijnIndex`es (one for the currently folded
+            // late-bound region and the other for the binder level) to determine
+            // whether a name has already been created for the currently folded region,
+            // see issue #102392.
+            let mut name = |lifetime_idx: Option<ty::DebruijnIndex>,
+                            binder_level_idx: ty::DebruijnIndex,
+                            br: ty::BoundRegion| {
+                let (name, kind) = match br.kind {
                     ty::BrAnon(_) | ty::BrEnv => {
                         let name = next_name(&self);
-                        do_continue(&mut self, name);
-                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
+
+                        if let Some(lt_idx) = lifetime_idx {
+                            if lt_idx > binder_level_idx {
+                                let kind = ty::BrNamed(CRATE_DEF_ID.to_def_id(), name);
+                                return tcx.mk_region(ty::ReLateBound(
+                                    ty::INNERMOST,
+                                    ty::BoundRegion { var: br.var, kind },
+                                ));
+                            }
+                        }
+
+                        (name, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name))
                     }
                     ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
                         let name = next_name(&self);
-                        do_continue(&mut self, name);
-                        ty::BrNamed(def_id, name)
+
+                        if let Some(lt_idx) = lifetime_idx {
+                            if lt_idx > binder_level_idx {
+                                let kind = ty::BrNamed(def_id, name);
+                                return tcx.mk_region(ty::ReLateBound(
+                                    ty::INNERMOST,
+                                    ty::BoundRegion { var: br.var, kind },
+                                ));
+                            }
+                        }
+
+                        (name, ty::BrNamed(def_id, name))
                     }
                     ty::BrNamed(_, name) => {
-                        do_continue(&mut self, name);
-                        br.kind
+                        if let Some(lt_idx) = lifetime_idx {
+                            if lt_idx > binder_level_idx {
+                                let kind = br.kind;
+                                return tcx.mk_region(ty::ReLateBound(
+                                    ty::INNERMOST,
+                                    ty::BoundRegion { var: br.var, kind },
+                                ));
+                            }
+                        }
+
+                        (name, br.kind)
                     }
                 };
+
+                start_or_continue(&mut self, "for<", ", ");
+                do_continue(&mut self, name);
                 tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
             };
             let mut folder = RegionFolder {
diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
index 85f7d1dd674..7fb88116665 100644
--- a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
+++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
@@ -18,7 +18,7 @@ LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
    |  ___________________________________________________________________^
 LL | | }
    | |_^
-   = note: required because it captures the following types: `ResumeTy`, `impl for<'a, 'b, 'c> Future<Output = ()>`, `()`
+   = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()`
 note: required because it's used within this `async` block
   --> $DIR/issue-70935-complex-spans.rs:16:16
    |
diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
index cfcef9699f3..7dabd97b94e 100644
--- a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
+++ b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
@@ -1,10 +1,10 @@
-error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(for<'r> fn(&'r ()))`
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`
   --> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
    |
 LL | impl Trait for for<'r> fn(fn(&'r ())) {}
    | ------------------------------------- first implementation here
 LL | impl<'a> Trait for fn(fn(&'a ())) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(for<'r> fn(&'r ()))`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
    |
    = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
 
diff --git a/src/test/ui/lifetimes/nested-binder-print.rs b/src/test/ui/lifetimes/nested-binder-print.rs
new file mode 100644
index 00000000000..f97f349fd82
--- /dev/null
+++ b/src/test/ui/lifetimes/nested-binder-print.rs
@@ -0,0 +1,10 @@
+struct TwoLt<'a, 'b>(&'a (), &'b ());
+type Foo<'a> = fn(TwoLt<'_, 'a>);
+
+fn foo() {
+    let y: for<'a> fn(Foo<'a>);
+    let x: u32 = y;
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/nested-binder-print.stderr b/src/test/ui/lifetimes/nested-binder-print.stderr
new file mode 100644
index 00000000000..32dd896932d
--- /dev/null
+++ b/src/test/ui/lifetimes/nested-binder-print.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/nested-binder-print.rs:6:18
+   |
+LL |     let x: u32 = y;
+   |            ---   ^ expected `u32`, found fn pointer
+   |            |
+   |            expected due to this
+   |
+   = note:    expected type `u32`
+           found fn pointer `for<'a> fn(for<'b> fn(TwoLt<'b, 'a>))`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lifetimes/re-empty-in-error.stderr b/src/test/ui/lifetimes/re-empty-in-error.stderr
index 840707d9470..c35d8ecec5e 100644
--- a/src/test/ui/lifetimes/re-empty-in-error.stderr
+++ b/src/test/ui/lifetimes/re-empty-in-error.stderr
@@ -4,7 +4,7 @@ error: higher-ranked lifetime error
 LL |     foo(&10);
    |     ^^^^^^^^
    |
-   = note: could not prove `for<'b, 'a> &'b (): 'a`
+   = note: could not prove `for<'b> &'b (): 'a`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/issue-102392.rs b/src/test/ui/regions/issue-102392.rs
new file mode 100644
index 00000000000..87cc1a8e7a8
--- /dev/null
+++ b/src/test/ui/regions/issue-102392.rs
@@ -0,0 +1,6 @@
+fn g(f: for<'a> fn(fn(&str, &'a str))) -> bool {
+    f
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/regions/issue-102392.stderr b/src/test/ui/regions/issue-102392.stderr
new file mode 100644
index 00000000000..56f4c0c5db4
--- /dev/null
+++ b/src/test/ui/regions/issue-102392.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-102392.rs:2:5
+   |
+LL | fn g(f: for<'a> fn(fn(&str, &'a str))) -> bool {
+   |                                           ---- expected `bool` because of return type
+LL |     f
+   |     ^ expected `bool`, found fn pointer
+   |
+   = note:    expected type `bool`
+           found fn pointer `for<'a> fn(for<'b> fn(&'b str, &'a str))`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr b/src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
index d9950a3d9b7..30248a7a397 100644
--- a/src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
+++ b/src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `for<'b> for<'b> fn(&'b ()): Foo` is not satisfied
+error[E0277]: the trait bound `for<'b> fn(&'b ()): Foo` is not satisfied
   --> $DIR/higher-ranked-fn-type.rs:20:5
    |
 LL |     called()
-   |     ^^^^^^ the trait `for<'b> Foo` is not implemented for `for<'b> fn(&'b ())`
+   |     ^^^^^^ the trait `for<'b> Foo` is not implemented for `fn(&'b ())`
    |
 note: required by a bound in `called`
   --> $DIR/higher-ranked-fn-type.rs:12:25
diff --git a/src/test/ui/where-clauses/higher-ranked-fn-type.rs b/src/test/ui/where-clauses/higher-ranked-fn-type.rs
index 0d8893e08d3..ab6edde4ee7 100644
--- a/src/test/ui/where-clauses/higher-ranked-fn-type.rs
+++ b/src/test/ui/where-clauses/higher-ranked-fn-type.rs
@@ -18,7 +18,7 @@ where
     (for<'a> fn(&'a ())): Foo,
 {
     called()
-    //[quiet]~^ ERROR the trait bound `for<'b> for<'b> fn(&'b ()): Foo` is not satisfied
+    //[quiet]~^ ERROR the trait bound `for<'b> fn(&'b ()): Foo` is not satisfied
     //[verbose]~^^ ERROR the trait bound `for<'b> fn(&ReLateBound(
 }