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
This commit is contained in:
commit
909f5a0494
|
@ -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",
|
||||
|
|
|
@ -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.
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
/// 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;
|
||||
|
||||
/// 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());
|
||||
|
||||
|
|
|
@ -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]>
|
||||
|
|
|
@ -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("}"))
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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);
|
||||
// Prevent:
|
||||
// * `fn foo<T>() -> Foo<T>`
|
||||
// * `fn foo<T: Bound + Other>() -> Foo<T>`
|
||||
// from being defining.
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
};
|
||||
// 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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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() {}
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue