about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-07-09 02:53:20 +0000
committerbors <bors@rust-lang.org>2019-07-09 02:53:20 +0000
commit909f5a049415a815b23502a5498de9a99bbf276b (patch)
tree12723b9672bc78d2b0dd2771a20ed67396981129
parent09ab31bc64f4ede9f9498440cb4225c173767c1e (diff)
parent4e5bccc46df06bb1d010283cf774401bdaa606e5 (diff)
downloadrust-909f5a049415a815b23502a5498de9a99bbf276b.tar.gz
rust-909f5a049415a815b23502a5498de9a99bbf276b.zip
Auto merge of #62511 - Centril:rollup-ojzb35x, r=Centril
Rollup of 4 pull requests

Successful merges:

 - #60458 (Add key and value methods to DebugMap)
 - #62090 (typeck: merge opaque type inference logic)
 - #62403 (Replace SliceConcatExt trait with inherent methods and SliceConcat helper trait)
 - #62494 (Remove unused dependencies)

Failed merges:

r? @ghost
-rw-r--r--Cargo.lock3
-rw-r--r--src/doc/unstable-book/src/library-features/debug-map-key-value.md9
-rw-r--r--src/liballoc/prelude/v1.rs1
-rw-r--r--src/liballoc/slice.rs129
-rw-r--r--src/liballoc/str.rs14
-rw-r--r--src/libcore/fmt/builders.rs160
-rw-r--r--src/libcore/tests/fmt/builders.rs93
-rw-r--r--src/libcore/tests/lib.rs1
-rw-r--r--src/librustc/infer/opaque_types/mod.rs76
-rw-r--r--src/librustc_codegen_ssa/Cargo.toml1
-rw-r--r--src/librustc_driver/Cargo.toml1
-rw-r--r--src/librustc_interface/Cargo.toml1
-rw-r--r--src/librustc_typeck/check/writeback.rs153
-rw-r--r--src/libstd/prelude/mod.rs3
-rw-r--r--src/libstd/prelude/v1.rs3
-rw-r--r--src/test/ui/impl-trait/issue-55872-1.rs22
-rw-r--r--src/test/ui/impl-trait/issue-55872-1.stderr33
-rw-r--r--src/test/ui/impl-trait/issue-55872-2.rs20
-rw-r--r--src/test/ui/impl-trait/issue-55872-2.stderr21
-rw-r--r--src/test/ui/impl-trait/issue-55872.rs19
-rw-r--r--src/test/ui/impl-trait/issue-55872.stderr12
21 files changed, 531 insertions, 244 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6b5499ec6f3..f2ef5f5aaca 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2985,7 +2985,6 @@ dependencies = [
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
- "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_allocator 0.0.0",
  "rustc_apfloat 0.0.0",
  "rustc_codegen_utils 0.0.0",
@@ -3064,7 +3063,6 @@ dependencies = [
  "rustc_target 0.0.0",
  "rustc_traits 0.0.0",
  "rustc_typeck 0.0.0",
- "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serialize 0.0.0",
  "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntax 0.0.0",
@@ -3128,7 +3126,6 @@ dependencies = [
  "rustc_resolve 0.0.0",
  "rustc_traits 0.0.0",
  "rustc_typeck 0.0.0",
- "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serialize 0.0.0",
  "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntax 0.0.0",
diff --git a/src/doc/unstable-book/src/library-features/debug-map-key-value.md b/src/doc/unstable-book/src/library-features/debug-map-key-value.md
new file mode 100644
index 00000000000..ae839bf2ac3
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/debug-map-key-value.md
@@ -0,0 +1,9 @@
+# `debug_map_key_value`
+
+The tracking issue for this feature is: [#62482]
+
+[#62482]: https://github.com/rust-lang/rust/issues/62482
+
+------------------------
+
+Add the methods `key` and `value` to `DebugMap` so that an entry can be formatted across multiple calls without additional buffering.
diff --git a/src/liballoc/prelude/v1.rs b/src/liballoc/prelude/v1.rs
index b6b01395ad6..3cb285bf049 100644
--- a/src/liballoc/prelude/v1.rs
+++ b/src/liballoc/prelude/v1.rs
@@ -6,6 +6,5 @@
 
 #[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::borrow::ToOwned;
 #[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::boxed::Box;
-#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::slice::SliceConcatExt;
 #[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::string::{String, ToString};
 #[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::vec::Vec;
diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index f7b0a5e703c..bc4ae167984 100644
--- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -484,6 +484,56 @@ impl<T> [T] {
         }
         buf
     }
+
+    /// Flattens a slice of `T` into a single value `Self::Output`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert_eq!(["hello", "world"].concat(), "helloworld");
+    /// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn concat<Separator: ?Sized>(&self) -> T::Output
+        where T: SliceConcat<Separator>
+    {
+        SliceConcat::concat(self)
+    }
+
+    /// Flattens a slice of `T` into a single value `Self::Output`, placing a
+    /// given separator between each.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert_eq!(["hello", "world"].join(" "), "hello world");
+    /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
+    /// ```
+    #[stable(feature = "rename_connect_to_join", since = "1.3.0")]
+    pub fn join<Separator: ?Sized>(&self, sep: &Separator) -> T::Output
+        where T: SliceConcat<Separator>
+    {
+        SliceConcat::join(self, sep)
+    }
+
+    /// Flattens a slice of `T` into a single value `Self::Output`, placing a
+    /// given separator between each.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![allow(deprecated)]
+    /// assert_eq!(["hello", "world"].connect(" "), "hello world");
+    /// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")]
+    pub fn connect<Separator: ?Sized>(&self, sep: &Separator) -> T::Output
+        where T: SliceConcat<Separator>
+    {
+        SliceConcat::join(self, sep)
+    }
+
 }
 
 #[lang = "slice_u8_alloc"]
@@ -527,87 +577,46 @@ impl [u8] {
 ////////////////////////////////////////////////////////////////////////////////
 // Extension traits for slices over specific kinds of data
 ////////////////////////////////////////////////////////////////////////////////
-#[unstable(feature = "slice_concat_ext",
-           reason = "trait should not have to exist",
-           issue = "27747")]
-/// An extension trait for concatenating slices
-///
-/// While this trait is unstable, the methods are stable. `SliceConcatExt` is
-/// included in the [standard library prelude], so you can use [`join()`] and
-/// [`concat()`] as if they existed on `[T]` itself.
-///
-/// [standard library prelude]: ../../std/prelude/index.html
-/// [`join()`]: #tymethod.join
-/// [`concat()`]: #tymethod.concat
-pub trait SliceConcatExt<T: ?Sized> {
-    #[unstable(feature = "slice_concat_ext",
-               reason = "trait should not have to exist",
-               issue = "27747")]
+
+/// Helper trait for [`[T]::concat`](../../std/primitive.slice.html#method.concat)
+/// and [`[T]::join`](../../std/primitive.slice.html#method.join)
+#[unstable(feature = "slice_concat_trait", issue = "27747")]
+pub trait SliceConcat<Separator: ?Sized>: Sized {
+    #[unstable(feature = "slice_concat_trait", issue = "27747")]
     /// The resulting type after concatenation
     type Output;
 
-    /// Flattens a slice of `T` into a single value `Self::Output`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// assert_eq!(["hello", "world"].concat(), "helloworld");
-    /// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn concat(&self) -> Self::Output;
-
-    /// Flattens a slice of `T` into a single value `Self::Output`, placing a
-    /// given separator between each.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// assert_eq!(["hello", "world"].join(" "), "hello world");
-    /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
-    /// ```
-    #[stable(feature = "rename_connect_to_join", since = "1.3.0")]
-    fn join(&self, sep: &T) -> Self::Output;
+    /// Implementation of [`[T]::concat`](../../std/primitive.slice.html#method.concat)
+    #[unstable(feature = "slice_concat_trait", issue = "27747")]
+    fn concat(slice: &[Self]) -> Self::Output;
 
-    /// Flattens a slice of `T` into a single value `Self::Output`, placing a
-    /// given separator between each.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![allow(deprecated)]
-    /// assert_eq!(["hello", "world"].connect(" "), "hello world");
-    /// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")]
-    fn connect(&self, sep: &T) -> Self::Output {
-        self.join(sep)
-    }
+    /// Implementation of [`[T]::join`](../../std/primitive.slice.html#method.join)
+    #[unstable(feature = "slice_concat_trait", issue = "27747")]
+    fn join(slice: &[Self], sep: &Separator) -> Self::Output;
 }
 
 #[unstable(feature = "slice_concat_ext",
            reason = "trait should not have to exist",
            issue = "27747")]
-impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
+impl<T: Clone, V: Borrow<[T]>> SliceConcat<T> for V {
     type Output = Vec<T>;
 
-    fn concat(&self) -> Vec<T> {
-        let size = self.iter().map(|slice| slice.borrow().len()).sum();
+    fn concat(slice: &[Self]) -> Vec<T> {
+        let size = slice.iter().map(|slice| slice.borrow().len()).sum();
         let mut result = Vec::with_capacity(size);
-        for v in self {
+        for v in slice {
             result.extend_from_slice(v.borrow())
         }
         result
     }
 
-    fn join(&self, sep: &T) -> Vec<T> {
-        let mut iter = self.iter();
+    fn join(slice: &[Self], sep: &T) -> Vec<T> {
+        let mut iter = slice.iter();
         let first = match iter.next() {
             Some(first) => first,
             None => return vec![],
         };
-        let size = self.iter().map(|slice| slice.borrow().len()).sum::<usize>() + self.len() - 1;
+        let size = slice.iter().map(|slice| slice.borrow().len()).sum::<usize>() + slice.len() - 1;
         let mut result = Vec::with_capacity(size);
         result.extend_from_slice(first.borrow());
 
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs
index 70a93157c9e..37a1046d094 100644
--- a/src/liballoc/str.rs
+++ b/src/liballoc/str.rs
@@ -37,7 +37,7 @@ use core::unicode::conversions;
 
 use crate::borrow::ToOwned;
 use crate::boxed::Box;
-use crate::slice::{SliceConcatExt, SliceIndex};
+use crate::slice::{SliceConcat, SliceIndex};
 use crate::string::String;
 use crate::vec::Vec;
 
@@ -74,16 +74,16 @@ pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode};
 #[unstable(feature = "slice_concat_ext",
            reason = "trait should not have to exist",
            issue = "27747")]
-impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
+impl<S: Borrow<str>> SliceConcat<str> for S {
     type Output = String;
 
-    fn concat(&self) -> String {
-        self.join("")
+    fn concat(slice: &[Self]) -> String {
+        Self::join(slice, "")
     }
 
-    fn join(&self, sep: &str) -> String {
+    fn join(slice: &[Self], sep: &str) -> String {
         unsafe {
-            String::from_utf8_unchecked( join_generic_copy(self, sep.as_bytes()) )
+            String::from_utf8_unchecked( join_generic_copy(slice, sep.as_bytes()) )
         }
     }
 }
@@ -126,7 +126,7 @@ macro_rules! copy_slice_and_advance {
 
 // Optimized join implementation that works for both Vec<T> (T: Copy) and String's inner vec
 // Currently (2018-05-13) there is a bug with type inference and specialization (see issue #36262)
-// For this reason SliceConcatExt<T> is not specialized for T: Copy and SliceConcatExt<str> is the
+// For this reason SliceConcat<T> is not specialized for T: Copy and SliceConcat<str> is the
 // only user of this function. It is left in place for the time when that is fixed.
 //
 // the bounds for String-join are S: Borrow<str> and for Vec-join Borrow<[T]>
diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs
index df86da5fc39..cb4e32622ff 100644
--- a/src/libcore/fmt/builders.rs
+++ b/src/libcore/fmt/builders.rs
@@ -1,37 +1,50 @@
 use crate::fmt;
 
-struct PadAdapter<'a> {
-    buf: &'a mut (dyn fmt::Write + 'a),
+struct PadAdapter<'buf, 'state> {
+    buf: &'buf mut (dyn fmt::Write + 'buf),
+    state: &'state mut PadAdapterState,
+}
+
+struct PadAdapterState {
     on_newline: bool,
 }
 
-impl<'a> PadAdapter<'a> {
-    fn wrap<'b, 'c: 'a+'b>(fmt: &'c mut fmt::Formatter<'_>, slot: &'b mut Option<Self>)
-                        -> fmt::Formatter<'b> {
+impl Default for PadAdapterState {
+    fn default() -> Self {
+        PadAdapterState {
+            on_newline: true,
+        }
+    }
+}
+
+impl<'buf, 'state> PadAdapter<'buf, 'state> {
+    fn wrap<'slot, 'fmt: 'buf+'slot>(fmt: &'fmt mut fmt::Formatter<'_>,
+                                     slot: &'slot mut Option<Self>,
+                                     state: &'state mut PadAdapterState) -> fmt::Formatter<'slot> {
         fmt.wrap_buf(move |buf| {
             *slot = Some(PadAdapter {
                 buf,
-                on_newline: true,
+                state,
             });
             slot.as_mut().unwrap()
         })
     }
 }
 
-impl fmt::Write for PadAdapter<'_> {
+impl fmt::Write for PadAdapter<'_, '_> {
     fn write_str(&mut self, mut s: &str) -> fmt::Result {
         while !s.is_empty() {
-            if self.on_newline {
+            if self.state.on_newline {
                 self.buf.write_str("    ")?;
             }
 
             let split = match s.find('\n') {
                 Some(pos) => {
-                    self.on_newline = true;
+                    self.state.on_newline = true;
                     pos + 1
                 }
                 None => {
-                    self.on_newline = false;
+                    self.state.on_newline = false;
                     s.len()
                 }
             };
@@ -133,7 +146,8 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
                     self.fmt.write_str(" {\n")?;
                 }
                 let mut slot = None;
-                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
+                let mut state = Default::default();
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
                 writer.write_str(name)?;
                 writer.write_str(": ")?;
                 value.fmt(&mut writer)?;
@@ -279,7 +293,8 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
                     self.fmt.write_str("(\n")?;
                 }
                 let mut slot = None;
-                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
+                let mut state = Default::default();
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
                 value.fmt(&mut writer)?;
                 writer.write_str(",\n")
             } else {
@@ -349,7 +364,8 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
                     self.fmt.write_str("\n")?;
                 }
                 let mut slot = None;
-                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
+                let mut state = Default::default();
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
                 entry.fmt(&mut writer)?;
                 writer.write_str(",\n")
             } else {
@@ -676,6 +692,9 @@ pub struct DebugMap<'a, 'b: 'a> {
     fmt: &'a mut fmt::Formatter<'b>,
     result: fmt::Result,
     has_fields: bool,
+    has_key: bool,
+    // The state of newlines is tracked between keys and values
+    state: PadAdapterState,
 }
 
 pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> {
@@ -684,6 +703,8 @@ pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b
         fmt,
         result,
         has_fields: false,
+        has_key: false,
+        state: Default::default(),
     }
 }
 
@@ -712,25 +733,123 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
     pub fn entry(&mut self, key: &dyn fmt::Debug, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
+        self.key(key).value(value)
+    }
+
+    /// Adds the key part of a new entry to the map output.
+    ///
+    /// This method, together with `value`, is an alternative to `entry` that
+    /// can be used when the complete entry isn't known upfront. Prefer the `entry`
+    /// method when it's possible to use.
+    ///
+    /// # Panics
+    ///
+    /// `key` must be called before `value` and each call to `key` must be followed
+    /// by a corresponding call to `value`. Otherwise this method will panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(debug_map_key_value)]
+    /// use std::fmt;
+    ///
+    /// struct Foo(Vec<(String, i32)>);
+    ///
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         fmt.debug_map()
+    ///            .key(&"whole").value(&self.0) // We add the "whole" entry.
+    ///            .finish()
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(
+    ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
+    ///     "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
+    /// );
+    /// ```
+    #[unstable(feature = "debug_map_key_value",
+               reason = "recently added",
+               issue = "62482")]
+    pub fn key(&mut self, key: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
+        assert!(!self.has_key, "attempted to begin a new map entry \
+                                without completing the previous one");
+
         self.result = self.result.and_then(|_| {
             if self.is_pretty() {
                 if !self.has_fields {
                     self.fmt.write_str("\n")?;
                 }
                 let mut slot = None;
-                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
+                self.state = Default::default();
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
                 key.fmt(&mut writer)?;
                 writer.write_str(": ")?;
-                value.fmt(&mut writer)?;
-                writer.write_str(",\n")
             } else {
                 if self.has_fields {
                     self.fmt.write_str(", ")?
                 }
                 key.fmt(self.fmt)?;
                 self.fmt.write_str(": ")?;
-                value.fmt(self.fmt)
             }
+
+            self.has_key = true;
+            Ok(())
+        });
+
+        self
+    }
+
+    /// Adds the value part of a new entry to the map output.
+    ///
+    /// This method, together with `key`, is an alternative to `entry` that
+    /// can be used when the complete entry isn't known upfront. Prefer the `entry`
+    /// method when it's possible to use.
+    ///
+    /// # Panics
+    ///
+    /// `key` must be called before `value` and each call to `key` must be followed
+    /// by a corresponding call to `value`. Otherwise this method will panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(debug_map_key_value)]
+    /// use std::fmt;
+    ///
+    /// struct Foo(Vec<(String, i32)>);
+    ///
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         fmt.debug_map()
+    ///            .key(&"whole").value(&self.0) // We add the "whole" entry.
+    ///            .finish()
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(
+    ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
+    ///     "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
+    /// );
+    /// ```
+    #[unstable(feature = "debug_map_key_value",
+               reason = "recently added",
+               issue = "62482")]
+    pub fn value(&mut self, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
+        assert!(self.has_key, "attempted to format a map value before its key");
+
+        self.result = self.result.and_then(|_| {
+            if self.is_pretty() {
+                let mut slot = None;
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
+                value.fmt(&mut writer)?;
+                writer.write_str(",\n")?;
+            } else {
+                value.fmt(self.fmt)?;
+            }
+
+            self.has_key = false;
+            Ok(())
         });
 
         self.has_fields = true;
@@ -775,6 +894,11 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
 
     /// Finishes output and returns any error encountered.
     ///
+    /// # Panics
+    ///
+    /// `key` must be called before `value` and each call to `key` must be followed
+    /// by a corresponding call to `value`. Otherwise this method will panic.
+    ///
     /// # Examples
     ///
     /// ```
@@ -797,6 +921,8 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
     pub fn finish(&mut self) -> fmt::Result {
+        assert!(!self.has_key, "attempted to finish a map with a partial entry");
+
         self.result.and_then(|_| self.fmt.write_str("}"))
     }
 
diff --git a/src/libcore/tests/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs
index 62fe09c5eb3..200659b91bb 100644
--- a/src/libcore/tests/fmt/builders.rs
+++ b/src/libcore/tests/fmt/builders.rs
@@ -211,9 +211,9 @@ mod debug_map {
 
     #[test]
     fn test_single() {
-        struct Foo;
+        struct Entry;
 
-        impl fmt::Debug for Foo {
+        impl fmt::Debug for Entry {
             fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                 fmt.debug_map()
                     .entry(&"bar", &true)
@@ -221,19 +221,32 @@ mod debug_map {
             }
         }
 
-        assert_eq!("{\"bar\": true}", format!("{:?}", Foo));
+        struct KeyValue;
+
+        impl fmt::Debug for KeyValue {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar").value(&true)
+                    .finish()
+            }
+        }
+
+        assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
+        assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+
+        assert_eq!("{\"bar\": true}", format!("{:?}", Entry));
         assert_eq!(
 "{
     \"bar\": true,
 }",
-                   format!("{:#?}", Foo));
+                   format!("{:#?}", Entry));
     }
 
     #[test]
     fn test_multiple() {
-        struct Foo;
+        struct Entry;
 
-        impl fmt::Debug for Foo {
+        impl fmt::Debug for Entry {
             fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                 fmt.debug_map()
                     .entry(&"bar", &true)
@@ -242,13 +255,27 @@ mod debug_map {
             }
         }
 
-        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{:?}", Foo));
+        struct KeyValue;
+
+        impl fmt::Debug for KeyValue {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar").value(&true)
+                    .key(&10).value(&format_args!("{}/{}", 10, 20))
+                    .finish()
+            }
+        }
+
+        assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
+        assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+
+        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{:?}", Entry));
         assert_eq!(
 "{
     \"bar\": true,
     10: 10/20,
 }",
-                   format!("{:#?}", Foo));
+                   format!("{:#?}", Entry));
     }
 
     #[test]
@@ -291,6 +318,56 @@ mod debug_map {
 }",
                    format!("{:#?}", Bar));
     }
+
+    #[test]
+    #[should_panic]
+    fn test_invalid_key_when_entry_is_incomplete() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar")
+                    .key(&"invalid")
+                    .finish()
+            }
+        }
+
+        format!("{:?}", Foo);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_invalid_finish_incomplete_entry() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar")
+                    .finish()
+            }
+        }
+
+        format!("{:?}", Foo);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_invalid_value_before_key() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .value(&"invalid")
+                    .key(&"bar")
+                    .finish()
+            }
+        }
+
+        format!("{:?}", Foo);
+    }
 }
 
 mod debug_set {
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index bf072a9243b..4b48d122590 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -3,6 +3,7 @@
 #![feature(cell_update)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
+#![feature(debug_map_key_value)]
 #![feature(dec2flt)]
 #![feature(euclidean_division)]
 #![feature(exact_size_is_empty)]
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index c127e667ce9..f3dc4d3f72a 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -4,6 +4,7 @@ use crate::hir::Node;
 use crate::infer::outlives::free_region_map::FreeRegionRelations;
 use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
 use crate::middle::region;
+use crate::mir::interpret::ConstValue;
 use crate::traits::{self, PredicateObligation};
 use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind};
@@ -553,6 +554,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         def_id: DefId,
         opaque_defn: &OpaqueTypeDecl<'tcx>,
         instantiated_ty: Ty<'tcx>,
+        span: Span,
     ) -> Ty<'tcx> {
         debug!(
             "infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})",
@@ -584,6 +586,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             def_id,
             map,
             instantiated_ty,
+            span,
         ));
         debug!("infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty);
 
@@ -761,6 +764,9 @@ struct ReverseMapper<'tcx> {
 
     /// initially `Some`, set to `None` once error has been reported
     hidden_ty: Option<Ty<'tcx>>,
+
+    /// Span of function being checked.
+    span: Span,
 }
 
 impl ReverseMapper<'tcx> {
@@ -770,6 +776,7 @@ impl ReverseMapper<'tcx> {
         opaque_type_def_id: DefId,
         map: FxHashMap<Kind<'tcx>, Kind<'tcx>>,
         hidden_ty: Ty<'tcx>,
+        span: Span,
     ) -> Self {
         Self {
             tcx,
@@ -778,6 +785,7 @@ impl ReverseMapper<'tcx> {
             map,
             map_missing_regions_to_empty: false,
             hidden_ty: Some(hidden_ty),
+            span,
         }
     }
 
@@ -812,10 +820,11 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
             _ => { }
         }
 
+        let generics = self.tcx().generics_of(self.opaque_type_def_id);
         match self.map.get(&r.into()).map(|k| k.unpack()) {
             Some(UnpackedKind::Lifetime(r1)) => r1,
             Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
-            None => {
+            None if generics.parent.is_some() => {
                 if !self.map_missing_regions_to_empty && !self.tainted_by_errors {
                     if let Some(hidden_ty) = self.hidden_ty.take() {
                         unexpected_hidden_region_diagnostic(
@@ -829,6 +838,21 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                 }
                 self.tcx.lifetimes.re_empty
             }
+            None => {
+                self.tcx.sess
+                    .struct_span_err(
+                        self.span,
+                        "non-defining existential type use in defining scope"
+                    )
+                    .span_label(
+                        self.span,
+                        format!("lifetime `{}` is part of concrete type but not used in \
+                                 parameter list of existential type", r),
+                    )
+                    .emit();
+
+                self.tcx().global_tcx().mk_region(ty::ReStatic)
+            },
         }
     }
 
@@ -890,9 +914,59 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                 self.tcx.mk_generator(def_id, ty::GeneratorSubsts { substs }, movability)
             }
 
+            ty::Param(..) => {
+                // Look it up in the substitution list.
+                match self.map.get(&ty.into()).map(|k| k.unpack()) {
+                    // Found it in the substitution list; replace with the parameter from the
+                    // existential type.
+                    Some(UnpackedKind::Type(t1)) => t1,
+                    Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
+                    None => {
+                        self.tcx.sess
+                            .struct_span_err(
+                                self.span,
+                                &format!("type parameter `{}` is part of concrete type but not \
+                                          used in parameter list for existential type", ty),
+                            )
+                            .emit();
+
+                        self.tcx().types.err
+                    }
+                }
+            }
+
             _ => ty.super_fold_with(self),
         }
     }
+
+    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        trace!("checking const {:?}", ct);
+        // Find a const parameter
+        match ct.val {
+            ConstValue::Param(..) => {
+                // Look it up in the substitution list.
+                match self.map.get(&ct.into()).map(|k| k.unpack()) {
+                    // Found it in the substitution list, replace with the parameter from the
+                    // existential type.
+                    Some(UnpackedKind::Const(c1)) => c1,
+                    Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
+                    None => {
+                        self.tcx.sess
+                            .struct_span_err(
+                                self.span,
+                                &format!("const parameter `{}` is part of concrete type but not \
+                                          used in parameter list for existential type", ct)
+                            )
+                            .emit();
+
+                        self.tcx().consts.err
+                    }
+                }
+            }
+
+            _ => ct,
+        }
+    }
 }
 
 struct Instantiator<'a, 'tcx> {
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index 343596feed2..e7ee06df7e1 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -13,7 +13,6 @@ test = false
 bitflags = "1.0.4"
 cc = "1.0.1"
 num_cpus = "1.0"
-rustc-demangle = "0.1.15"
 memmap = "0.6"
 log = "0.4.5"
 libc = "0.2.44"
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index b28b015db75..9a8473e1409 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -15,7 +15,6 @@ graphviz = { path = "../libgraphviz" }
 log = "0.4"
 env_logger = { version = "0.5", default-features = false }
 rayon = { version = "0.2.0", package = "rustc-rayon" }
-scoped-tls = "1.0"
 rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
 rustc_target = { path = "../librustc_target" }
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 82880d21987..2712355d537 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -13,7 +13,6 @@ doctest = false
 log = "0.4"
 rayon = { version = "0.2.0", package = "rustc-rayon" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
-scoped-tls = "1.0"
 syntax = { path = "../libsyntax" }
 syntax_ext = { path = "../libsyntax_ext" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 9d389669ff4..145b37ff907 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -9,10 +9,8 @@ use rustc::hir::def_id::{DefId, DefIndex};
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::infer::InferCtxt;
 use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast};
-use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder};
-use rustc::ty::subst::UnpackedKind;
+use rustc::ty::fold::{TypeFoldable, TypeFolder};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::mir::interpret::ConstValue;
 use rustc::util::nodemap::DefIdSet;
 use rustc_data_structures::sync::Lrc;
 use std::mem;
@@ -440,141 +438,20 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
             debug_assert!(!instantiated_ty.has_escaping_bound_vars());
 
-            let generics = self.tcx().generics_of(def_id);
-
-            let definition_ty = if generics.parent.is_some() {
-                // `impl Trait`
-                self.fcx.infer_opaque_definition_from_instantiation(
-                    def_id,
-                    opaque_defn,
-                    instantiated_ty,
-                )
-            } else {
-                // Prevent:
-                // * `fn foo<T>() -> Foo<T>`
-                // * `fn foo<T: Bound + Other>() -> Foo<T>`
-                // from being defining.
-
-                // Also replace all generic params with the ones from the existential type
-                // definition so that
-                // ```rust
-                // existential type Foo<T>: 'static;
-                // fn foo<U>() -> Foo<U> { .. }
-                // ```
-                // figures out the concrete type with `U`, but the stored type is with `T`.
-                instantiated_ty.fold_with(&mut BottomUpFolder {
-                    tcx: self.tcx().global_tcx(),
-                    ty_op: |ty| {
-                        trace!("checking type {:?}", ty);
-                        // Find a type parameter.
-                        if let ty::Param(..) = ty.sty {
-                            // Look it up in the substitution list.
-                            assert_eq!(opaque_defn.substs.len(), generics.params.len());
-                            for (subst, param) in opaque_defn.substs.iter().zip(&generics.params) {
-                                if let UnpackedKind::Type(subst) = subst.unpack() {
-                                    if subst == ty {
-                                        // Found it in the substitution list; replace with the
-                                        // parameter from the existential type.
-                                        return self.tcx()
-                                            .global_tcx()
-                                            .mk_ty_param(param.index, param.name);
-                                    }
-                                }
-                            }
-                            self.tcx()
-                                .sess
-                                .struct_span_err(
-                                    span,
-                                    &format!(
-                                        "type parameter `{}` is part of concrete type but not used \
-                                         in parameter list for existential type",
-                                        ty,
-                                    ),
-                                )
-                                .emit();
-                            return self.tcx().types.err;
-                        }
-                        ty
-                    },
-                    lt_op: |region| {
-                        match region {
-                            // Skip static and bound regions: they don't require substitution.
-                            ty::ReStatic | ty::ReLateBound(..) => region,
-                            _ => {
-                                trace!("checking {:?}", region);
-                                for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) {
-                                    if let UnpackedKind::Lifetime(subst) = subst.unpack() {
-                                        if subst == region {
-                                            // Found it in the substitution list; replace with the
-                                            // parameter from the existential type.
-                                            let reg = ty::EarlyBoundRegion {
-                                                def_id: p.def_id,
-                                                index: p.index,
-                                                name: p.name,
-                                            };
-                                            trace!("replace {:?} with {:?}", region, reg);
-                                            return self.tcx()
-                                                .global_tcx()
-                                                .mk_region(ty::ReEarlyBound(reg));
-                                        }
-                                    }
-                                }
-                                trace!("opaque_defn: {:#?}", opaque_defn);
-                                trace!("generics: {:#?}", generics);
-                                self.tcx()
-                                    .sess
-                                    .struct_span_err(
-                                        span,
-                                        "non-defining existential type use in defining scope",
-                                    )
-                                    .span_label(
-                                        span,
-                                        format!(
-                                            "lifetime `{}` is part of concrete type but not used \
-                                             in parameter list of existential type",
-                                            region,
-                                        ),
-                                    )
-                                    .emit();
-                                self.tcx().global_tcx().mk_region(ty::ReStatic)
-                            }
-                        }
-                    },
-                    ct_op: |ct| {
-                        trace!("checking const {:?}", ct);
-                        // Find a const parameter
-                        if let ConstValue::Param(..) = ct.val {
-                            // look it up in the substitution list
-                            assert_eq!(opaque_defn.substs.len(), generics.params.len());
-                            for (subst, param) in opaque_defn.substs.iter()
-                                                                    .zip(&generics.params) {
-                                if let UnpackedKind::Const(subst) = subst.unpack() {
-                                    if subst == ct {
-                                        // found it in the substitution list, replace with the
-                                        // parameter from the existential type
-                                        return self.tcx()
-                                            .global_tcx()
-                                            .mk_const_param(param.index, param.name, ct.ty);
-                                    }
-                                }
-                            }
-                            self.tcx()
-                                .sess
-                                .struct_span_err(
-                                    span,
-                                    &format!(
-                                        "const parameter `{}` is part of concrete type but not \
-                                            used in parameter list for existential type",
-                                        ct,
-                                    ),
-                                )
-                                .emit();
-                            return self.tcx().consts.err;
-                        }
-                        ct
-                    }
-                })
-            };
+            // Prevent:
+            // * `fn foo<T>() -> Foo<T>`
+            // * `fn foo<T: Bound + Other>() -> Foo<T>`
+            // from being defining.
+
+            // Also replace all generic params with the ones from the existential type
+            // definition so that
+            // ```rust
+            // existential type Foo<T>: 'static;
+            // fn foo<U>() -> Foo<U> { .. }
+            // ```
+            // figures out the concrete type with `U`, but the stored type is with `T`.
+            let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
+                def_id, opaque_defn, instantiated_ty, span);
 
             if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty {
                 if def_id == defin_ty_def_id {
diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs
index 551e982a3c6..3085c3d8296 100644
--- a/src/libstd/prelude/mod.rs
+++ b/src/libstd/prelude/mod.rs
@@ -71,9 +71,6 @@
 //! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions
 //!   that may succeed or fail. Like [`Option`], its variants are exported as
 //!   well.
-//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical
-//!   reasons, but shouldn't have to exist. It provides a few useful methods on
-//!   slices.
 //! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
 //! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated
 //!   vector.
diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs
index ce1e8e3319c..a863bebf4a2 100644
--- a/src/libstd/prelude/v1.rs
+++ b/src/libstd/prelude/v1.rs
@@ -60,9 +60,6 @@ pub use crate::boxed::Box;
 pub use crate::borrow::ToOwned;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
-pub use crate::slice::SliceConcatExt;
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(no_inline)]
 pub use crate::string::{String, ToString};
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs
new file mode 100644
index 00000000000..5095b26f8a4
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-55872-1.rs
@@ -0,0 +1,22 @@
+// ignore-tidy-linelength
+#![feature(existential_type)]
+
+pub trait Bar
+{
+    type E: Copy;
+
+    fn foo<T>() -> Self::E;
+}
+
+impl<S: Default> Bar for S {
+    existential type E: Copy;
+    //~^ ERROR the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` [E0277]
+    //~^^ ERROR the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` [E0277]
+
+    fn foo<T: Default>() -> Self::E {
+    //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for existential type
+        (S::default(), T::default())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr
new file mode 100644
index 00000000000..04b4d2d4a50
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-55872-1.stderr
@@ -0,0 +1,33 @@
+error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)`
+  --> $DIR/issue-55872-1.rs:12:5
+   |
+LL |     existential type E: Copy;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S`
+   |
+   = help: consider adding a `where S: std::marker::Copy` bound
+   = note: required because it appears within the type `(S, T)`
+   = note: the return type of a function must have a statically known size
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)`
+  --> $DIR/issue-55872-1.rs:12:5
+   |
+LL |     existential type E: Copy;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T`
+   |
+   = help: consider adding a `where T: std::marker::Copy` bound
+   = note: required because it appears within the type `(S, T)`
+   = note: the return type of a function must have a statically known size
+
+error: type parameter `T` is part of concrete type but not used in parameter list for existential type
+  --> $DIR/issue-55872-1.rs:16:37
+   |
+LL |       fn foo<T: Default>() -> Self::E {
+   |  _____________________________________^
+LL | |
+LL | |         (S::default(), T::default())
+LL | |     }
+   | |_____^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs
new file mode 100644
index 00000000000..2bdeb14bdc3
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-55872-2.rs
@@ -0,0 +1,20 @@
+// edition:2018
+// ignore-tidy-linelength
+#![feature(async_await, existential_type)]
+
+pub trait Bar {
+    type E: Copy;
+
+    fn foo<T>() -> Self::E;
+}
+
+impl<S> Bar for S {
+    existential type E: Copy;
+    //~^ ERROR the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied [E0277]
+    fn foo<T>() -> Self::E {
+    //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for existential type
+        async {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr
new file mode 100644
index 00000000000..2505a82ee23
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-55872-2.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied
+  --> $DIR/issue-55872-2.rs:12:5
+   |
+LL |     existential type E: Copy;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `impl std::future::Future`
+   |
+   = note: the return type of a function must have a statically known size
+
+error: type parameter `T` is part of concrete type but not used in parameter list for existential type
+  --> $DIR/issue-55872-2.rs:14:28
+   |
+LL |       fn foo<T>() -> Self::E {
+   |  ____________________________^
+LL | |
+LL | |         async {}
+LL | |     }
+   | |_____^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/issue-55872.rs b/src/test/ui/impl-trait/issue-55872.rs
new file mode 100644
index 00000000000..95604545c37
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-55872.rs
@@ -0,0 +1,19 @@
+// ignore-tidy-linelength
+#![feature(existential_type)]
+
+pub trait Bar {
+    type E: Copy;
+
+    fn foo<T>() -> Self::E;
+}
+
+impl<S> Bar for S {
+    existential type E: Copy;
+
+    fn foo<T>() -> Self::E {
+    //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for existential type
+        || ()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-55872.stderr b/src/test/ui/impl-trait/issue-55872.stderr
new file mode 100644
index 00000000000..487f276e317
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-55872.stderr
@@ -0,0 +1,12 @@
+error: type parameter `T` is part of concrete type but not used in parameter list for existential type
+  --> $DIR/issue-55872.rs:13:28
+   |
+LL |       fn foo<T>() -> Self::E {
+   |  ____________________________^
+LL | |
+LL | |         || ()
+LL | |     }
+   | |_____^
+
+error: aborting due to previous error
+