Rollup merge of #47613 - estebank:rustc_on_unimplemented, r=nikomatsakis
Add filtering options to `rustc_on_unimplemented` - Add filtering options to `rustc_on_unimplemented` for local traits, filtering on `Self` and type arguments. - Add a way to provide custom notes. - Tweak binops text. - Add filter to detect wether `Self` is local or belongs to another crate. - Add filter to `Iterator` diagnostic for `&str`. Partly addresses #44755 with a different syntax, as a first approach. Fixes #46216, fixes #37522, CC #34297, #46806.
This commit is contained in:
commit
aee22556a9
@ -530,9 +530,12 @@ impl<'a> Display for Arguments<'a> {
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \
|
||||
defined in your crate, add `#[derive(Debug)]` or \
|
||||
manually implement it"]
|
||||
#[rustc_on_unimplemented(
|
||||
on(crate_local, label="`{Self}` cannot be formatted using `:?`; \
|
||||
add `#[derive(Debug)]` or manually implement `{Debug}`"),
|
||||
message="`{Self}` doesn't implement `{Debug}`",
|
||||
label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`",
|
||||
)]
|
||||
#[lang = "debug_trait"]
|
||||
pub trait Debug {
|
||||
/// Formats the value using the given formatter.
|
||||
@ -593,9 +596,11 @@ pub trait Debug {
|
||||
///
|
||||
/// println!("The origin is: {}", origin);
|
||||
/// ```
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default \
|
||||
formatter; try using `:?` instead if you are using \
|
||||
a format string"]
|
||||
#[rustc_on_unimplemented(
|
||||
message="`{Self}` doesn't implement `{Display}`",
|
||||
label="`{Self}` cannot be formatted with the default formatter; \
|
||||
try using `:?` instead if you are using a format string",
|
||||
)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Display {
|
||||
/// Formats the value using the given formatter.
|
||||
|
@ -28,8 +28,13 @@ fn _assert_is_object_safe(_: &Iterator<Item=()>) {}
|
||||
/// [module-level documentation]: index.html
|
||||
/// [impl]: index.html#implementing-iterator
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \
|
||||
`.iter()` or a similar method"]
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
_Self="&str",
|
||||
label="`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
|
||||
),
|
||||
label="`{Self}` is not an iterator; maybe try calling `.iter()` or a similar method"
|
||||
)]
|
||||
#[doc(spotlight)]
|
||||
pub trait Iterator {
|
||||
/// The type of the elements being iterated over.
|
||||
|
@ -75,7 +75,18 @@
|
||||
/// ```
|
||||
#[lang = "add"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"]
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
all(_Self="{integer}", RHS="{float}"),
|
||||
message="cannot add a float to an integer",
|
||||
),
|
||||
on(
|
||||
all(_Self="{float}", RHS="{integer}"),
|
||||
message="cannot add an integer to a float",
|
||||
),
|
||||
message="cannot add `{RHS}` to `{Self}`",
|
||||
label="no implementation for `{Self} + {RHS}`",
|
||||
)]
|
||||
pub trait Add<RHS=Self> {
|
||||
/// The resulting type after applying the `+` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -170,7 +181,8 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
|
||||
/// ```
|
||||
#[lang = "sub"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="cannot substract `{RHS}` from `{Self}`",
|
||||
label="no implementation for `{Self} - {RHS}`")]
|
||||
pub trait Sub<RHS=Self> {
|
||||
/// The resulting type after applying the `-` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -287,7 +299,8 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
|
||||
/// ```
|
||||
#[lang = "mul"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`",
|
||||
label="no implementation for `{Self} * {RHS}`")]
|
||||
pub trait Mul<RHS=Self> {
|
||||
/// The resulting type after applying the `*` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -408,7 +421,8 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
|
||||
/// ```
|
||||
#[lang = "div"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`",
|
||||
label="no implementation for `{Self} / {RHS}`")]
|
||||
pub trait Div<RHS=Self> {
|
||||
/// The resulting type after applying the `/` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -490,7 +504,8 @@ div_impl_float! { f32 f64 }
|
||||
/// ```
|
||||
#[lang = "rem"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`",
|
||||
label="no implementation for `{Self} % {RHS}`")]
|
||||
pub trait Rem<RHS=Self> {
|
||||
/// The resulting type after applying the `%` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -647,7 +662,8 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 }
|
||||
/// ```
|
||||
#[lang = "add_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`",
|
||||
label="no implementation for `{Self} += {Rhs}`")]
|
||||
pub trait AddAssign<Rhs=Self> {
|
||||
/// Performs the `+=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
@ -700,7 +716,8 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
|
||||
/// ```
|
||||
#[lang = "sub_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="cannot substract-assign `{Rhs}` from `{Self}`",
|
||||
label="no implementation for `{Self} -= {Rhs}`")]
|
||||
pub trait SubAssign<Rhs=Self> {
|
||||
/// Performs the `-=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
@ -744,7 +761,8 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
|
||||
/// ```
|
||||
#[lang = "mul_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`",
|
||||
label="no implementation for `{Self} *= {Rhs}`")]
|
||||
pub trait MulAssign<Rhs=Self> {
|
||||
/// Performs the `*=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
@ -788,7 +806,8 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
|
||||
/// ```
|
||||
#[lang = "div_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`",
|
||||
label="no implementation for `{Self} /= {Rhs}`")]
|
||||
pub trait DivAssign<Rhs=Self> {
|
||||
/// Performs the `/=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
@ -835,7 +854,8 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
|
||||
/// ```
|
||||
#[lang = "rem_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``",
|
||||
label="no implementation for `{Self} %= {Rhs}`")]
|
||||
pub trait RemAssign<Rhs=Self> {
|
||||
/// Performs the `%=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
|
@ -120,7 +120,8 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
/// ```
|
||||
#[lang = "bitand"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} & {RHS}`",
|
||||
label="no implementation for `{Self} & {RHS}`")]
|
||||
pub trait BitAnd<RHS=Self> {
|
||||
/// The resulting type after applying the `&` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -201,7 +202,8 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
/// ```
|
||||
#[lang = "bitor"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} | {RHS}`",
|
||||
label="no implementation for `{Self} | {RHS}`")]
|
||||
pub trait BitOr<RHS=Self> {
|
||||
/// The resulting type after applying the `|` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -285,7 +287,8 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
/// ```
|
||||
#[lang = "bitxor"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} ^ {RHS}`",
|
||||
label="no implementation for `{Self} ^ {RHS}`")]
|
||||
pub trait BitXor<RHS=Self> {
|
||||
/// The resulting type after applying the `^` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -365,7 +368,8 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
/// ```
|
||||
#[lang = "shl"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`",
|
||||
label="no implementation for `{Self} << {RHS}`")]
|
||||
pub trait Shl<RHS> {
|
||||
/// The resulting type after applying the `<<` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -466,7 +470,8 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 }
|
||||
/// ```
|
||||
#[lang = "shr"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`",
|
||||
label="no implementation for `{Self} >> {RHS}`")]
|
||||
pub trait Shr<RHS> {
|
||||
/// The resulting type after applying the `>>` operator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -579,7 +584,8 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
|
||||
/// ```
|
||||
#[lang = "bitand_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} &= {Rhs}`",
|
||||
label="no implementation for `{Self} &= {Rhs}`")]
|
||||
pub trait BitAndAssign<Rhs=Self> {
|
||||
/// Performs the `&=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
@ -626,7 +632,8 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
/// ```
|
||||
#[lang = "bitor_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} |= {Rhs}`",
|
||||
label="no implementation for `{Self} |= {Rhs}`")]
|
||||
pub trait BitOrAssign<Rhs=Self> {
|
||||
/// Performs the `|=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
@ -673,7 +680,8 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
/// ```
|
||||
#[lang = "bitxor_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} ^= {Rhs}`",
|
||||
label="no implementation for `{Self} ^= {Rhs}`")]
|
||||
pub trait BitXorAssign<Rhs=Self> {
|
||||
/// Performs the `^=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
@ -718,7 +726,8 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
/// ```
|
||||
#[lang = "shl_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`",
|
||||
label="no implementation for `{Self} <<= {Rhs}`")]
|
||||
pub trait ShlAssign<Rhs> {
|
||||
/// Performs the `<<=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
@ -784,7 +793,8 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
|
||||
/// ```
|
||||
#[lang = "shr_assign"]
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"]
|
||||
#[rustc_on_unimplemented(message="no implementation for `{Self} >>= {Rhs}`",
|
||||
label="no implementation for `{Self} >>= {Rhs}`")]
|
||||
pub trait ShrAssign<Rhs=Self> {
|
||||
/// Performs the `>>=` operation.
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
|
@ -348,7 +348,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
if direct {
|
||||
// this is a "direct", user-specified, rather than derived,
|
||||
// obligation.
|
||||
flags.push(("direct", None));
|
||||
flags.push(("direct".to_string(), None));
|
||||
}
|
||||
|
||||
if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
|
||||
@ -359,21 +359,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// Currently I'm leaving it for what I need for `try`.
|
||||
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
|
||||
method = self.tcx.item_name(item);
|
||||
flags.push(("from_method", None));
|
||||
flags.push(("from_method", Some(&*method)));
|
||||
flags.push(("from_method".to_string(), None));
|
||||
flags.push(("from_method".to_string(), Some(method.to_string())));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
|
||||
desugaring = k.as_symbol().as_str();
|
||||
flags.push(("from_desugaring", None));
|
||||
flags.push(("from_desugaring", Some(&*desugaring)));
|
||||
flags.push(("from_desugaring".to_string(), None));
|
||||
flags.push(("from_desugaring".to_string(), Some(desugaring.to_string())));
|
||||
}
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let self_ty_str = self_ty.to_string();
|
||||
flags.push(("_Self".to_string(), Some(self_ty_str.clone())));
|
||||
|
||||
for param in generics.types.iter() {
|
||||
let name = param.name.as_str().to_string();
|
||||
let ty = trait_ref.substs.type_for_def(param);
|
||||
let ty_str = ty.to_string();
|
||||
flags.push((name.clone(),
|
||||
Some(ty_str.clone())));
|
||||
}
|
||||
|
||||
if let Some(true) = self_ty.ty_to_def_id().map(|def_id| def_id.is_local()) {
|
||||
flags.push(("crate_local".to_string(), None));
|
||||
}
|
||||
|
||||
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
|
||||
self.tcx, trait_ref.def_id, def_id
|
||||
) {
|
||||
command.evaluate(self.tcx, trait_ref, &flags)
|
||||
command.evaluate(self.tcx, trait_ref, &flags[..])
|
||||
} else {
|
||||
OnUnimplementedNote::empty()
|
||||
}
|
||||
@ -549,7 +565,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
.map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
|
||||
.unwrap_or((String::new(), String::new()));
|
||||
|
||||
let OnUnimplementedNote { message, label }
|
||||
let OnUnimplementedNote { message, label, note }
|
||||
= self.on_unimplemented_note(trait_ref, obligation);
|
||||
let have_alt_message = message.is_some() || label.is_some();
|
||||
|
||||
@ -578,6 +594,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
trait_ref,
|
||||
trait_ref.self_ty()));
|
||||
}
|
||||
if let Some(ref s) = note {
|
||||
// If it has a custom "#[rustc_on_unimplemented]" note, let's display it
|
||||
err.note(s.as_str());
|
||||
}
|
||||
|
||||
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
|
||||
|
||||
|
@ -29,16 +29,18 @@ pub struct OnUnimplementedDirective {
|
||||
pub subcommands: Vec<OnUnimplementedDirective>,
|
||||
pub message: Option<OnUnimplementedFormatString>,
|
||||
pub label: Option<OnUnimplementedFormatString>,
|
||||
pub note: Option<OnUnimplementedFormatString>,
|
||||
}
|
||||
|
||||
pub struct OnUnimplementedNote {
|
||||
pub message: Option<String>,
|
||||
pub label: Option<String>,
|
||||
pub note: Option<String>,
|
||||
}
|
||||
|
||||
impl OnUnimplementedNote {
|
||||
pub fn empty() -> Self {
|
||||
OnUnimplementedNote { message: None, label: None }
|
||||
OnUnimplementedNote { message: None, label: None, note: None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,6 +91,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||
|
||||
let mut message = None;
|
||||
let mut label = None;
|
||||
let mut note = None;
|
||||
let mut subcommands = vec![];
|
||||
for item in item_iter {
|
||||
if item.check_name("message") && message.is_none() {
|
||||
@ -103,8 +106,14 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||
tcx, trait_def_id, label_.as_str(), span)?);
|
||||
continue;
|
||||
}
|
||||
} else if item.check_name("note") && note.is_none() {
|
||||
if let Some(note_) = item.value_str() {
|
||||
note = Some(OnUnimplementedFormatString::try_parse(
|
||||
tcx, trait_def_id, note_.as_str(), span)?);
|
||||
continue;
|
||||
}
|
||||
} else if item.check_name("on") && is_root &&
|
||||
message.is_none() && label.is_none()
|
||||
message.is_none() && label.is_none() && note.is_none()
|
||||
{
|
||||
if let Some(items) = item.meta_item_list() {
|
||||
if let Ok(subcommand) =
|
||||
@ -128,7 +137,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||
if errored {
|
||||
Err(ErrorReported)
|
||||
} else {
|
||||
Ok(OnUnimplementedDirective { condition, message, label, subcommands })
|
||||
Ok(OnUnimplementedDirective { condition, message, label, subcommands, note })
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +163,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||
message: None,
|
||||
subcommands: vec![],
|
||||
label: Some(OnUnimplementedFormatString::try_parse(
|
||||
tcx, trait_def_id, value.as_str(), attr.span)?)
|
||||
tcx, trait_def_id, value.as_str(), attr.span)?),
|
||||
note: None,
|
||||
}))
|
||||
} else {
|
||||
return Err(parse_error(tcx, attr.span,
|
||||
@ -169,20 +179,20 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||
pub fn evaluate(&self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
options: &[(&str, Option<&str>)])
|
||||
options: &[(String, Option<String>)])
|
||||
-> OnUnimplementedNote
|
||||
{
|
||||
let mut message = None;
|
||||
let mut label = None;
|
||||
info!("evaluate({:?}, trait_ref={:?}, options={:?})",
|
||||
self, trait_ref, options);
|
||||
let mut note = None;
|
||||
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
|
||||
|
||||
for command in self.subcommands.iter().chain(Some(self)).rev() {
|
||||
if let Some(ref condition) = command.condition {
|
||||
if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
|
||||
options.contains(&(&c.name().as_str(),
|
||||
match c.value_str().map(|s| s.as_str()) {
|
||||
Some(ref s) => Some(s),
|
||||
options.contains(&(c.name().as_str().to_string(),
|
||||
match c.value_str().map(|s| s.as_str().to_string()) {
|
||||
Some(s) => Some(s),
|
||||
None => None
|
||||
}))
|
||||
}) {
|
||||
@ -198,11 +208,16 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||
if let Some(ref label_) = command.label {
|
||||
label = Some(label_.clone());
|
||||
}
|
||||
|
||||
if let Some(ref note_) = command.note {
|
||||
note = Some(note_.clone());
|
||||
}
|
||||
}
|
||||
|
||||
OnUnimplementedNote {
|
||||
label: label.map(|l| l.format(tcx, trait_ref)),
|
||||
message: message.map(|m| m.format(tcx, trait_ref))
|
||||
message: message.map(|m| m.format(tcx, trait_ref)),
|
||||
note: note.map(|n| n.format(tcx, trait_ref)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -761,6 +761,18 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
|
||||
let mut err = self.struct_span_err(self.span,
|
||||
&format!("expected identifier, found {}",
|
||||
self.this_token_descr()));
|
||||
if let Some(token_descr) = self.token_descr() {
|
||||
err.span_label(self.span, format!("expected identifier, found {}", token_descr));
|
||||
} else {
|
||||
err.span_label(self.span, "expected identifier");
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
|
||||
self.parse_ident_common(true)
|
||||
}
|
||||
@ -769,15 +781,7 @@ impl<'a> Parser<'a> {
|
||||
match self.token {
|
||||
token::Ident(i) => {
|
||||
if self.token.is_reserved_ident() {
|
||||
let mut err = self.struct_span_err(self.span,
|
||||
&format!("expected identifier, found {}",
|
||||
self.this_token_descr()));
|
||||
if let Some(token_descr) = self.token_descr() {
|
||||
err.span_label(self.span, format!("expected identifier, found {}",
|
||||
token_descr));
|
||||
} else {
|
||||
err.span_label(self.span, "expected identifier");
|
||||
}
|
||||
let mut err = self.expected_ident_found();
|
||||
if recover {
|
||||
err.emit();
|
||||
} else {
|
||||
@ -791,14 +795,7 @@ impl<'a> Parser<'a> {
|
||||
Err(if self.prev_token_kind == PrevTokenKind::DocComment {
|
||||
self.span_fatal_err(self.prev_span, Error::UselessDocComment)
|
||||
} else {
|
||||
let mut err = self.fatal(&format!("expected identifier, found `{}`",
|
||||
self.this_token_to_string()));
|
||||
if let Some(token_descr) = self.token_descr() {
|
||||
err.span_label(self.span, format!("expected identifier, found {}",
|
||||
token_descr));
|
||||
} else {
|
||||
err.span_label(self.span, "expected identifier");
|
||||
}
|
||||
let mut err = self.expected_ident_found();
|
||||
if self.token == token::Underscore {
|
||||
err.note("`_` is a wildcard pattern, not an identifier");
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ const A_I8_T
|
||||
: [u32; (i8::MAX as i8 + 1u8) as usize]
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected i8, found u8
|
||||
//~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied
|
||||
//~| ERROR cannot add `u8` to `i8`
|
||||
= [0; (i8::MAX as usize) + 1];
|
||||
|
||||
|
||||
|
@ -12,7 +12,7 @@ use std::ops::Add;
|
||||
|
||||
fn main() {
|
||||
<i32 as Add<u32>>::add(1, 2);
|
||||
//~^ ERROR `i32: std::ops::Add<u32>` is not satisfied
|
||||
//~^ ERROR cannot add `u32` to `i32`
|
||||
<i32 as Add<i32>>::add(1u32, 2);
|
||||
//~^ ERROR mismatched types
|
||||
<i32 as Add<i32>>::add(1, 2u32);
|
||||
|
@ -32,7 +32,7 @@ fn sum_to(n: u32) -> impl Foo {
|
||||
0
|
||||
} else {
|
||||
n + sum_to(n - 1)
|
||||
//~^ ERROR the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
|
||||
//~^ ERROR cannot add `impl Foo` to `u32`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ error[E0308]: mismatched types
|
||||
= note: expected type `i32`
|
||||
found type `u32`
|
||||
|
||||
error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
|
||||
error[E0277]: cannot add `impl Foo` to `u32`
|
||||
--> $DIR/equality.rs:34:11
|
||||
|
|
||||
34 | n + sum_to(n - 1)
|
||||
|
@ -9,10 +9,10 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
1 + Some(1); //~ ERROR is not satisfied
|
||||
2 as usize - Some(1); //~ ERROR is not satisfied
|
||||
3 * (); //~ ERROR is not satisfied
|
||||
4 / ""; //~ ERROR is not satisfied
|
||||
1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}`
|
||||
2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize`
|
||||
3 * (); //~ ERROR cannot multiply `()` to `{integer}`
|
||||
4 / ""; //~ ERROR cannot divide `{integer}` by `&str`
|
||||
5 < String::new(); //~ ERROR is not satisfied
|
||||
6 == Ok(1); //~ ERROR is not satisfied
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{integer}>>` is not satisfied
|
||||
error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}`
|
||||
--> $DIR/binops.rs:12:7
|
||||
|
|
||||
12 | 1 + Some(1); //~ ERROR is not satisfied
|
||||
12 | 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}`
|
||||
| ^ no implementation for `{integer} + std::option::Option<{integer}>`
|
||||
|
|
||||
= help: the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
|
||||
error[E0277]: cannot substract `std::option::Option<{integer}>` from `usize`
|
||||
--> $DIR/binops.rs:13:16
|
||||
|
|
||||
13 | 2 as usize - Some(1); //~ ERROR is not satisfied
|
||||
13 | 2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize`
|
||||
| ^ no implementation for `usize - std::option::Option<{integer}>`
|
||||
|
|
||||
= help: the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
|
||||
error[E0277]: cannot multiply `()` to `{integer}`
|
||||
--> $DIR/binops.rs:14:7
|
||||
|
|
||||
14 | 3 * (); //~ ERROR is not satisfied
|
||||
14 | 3 * (); //~ ERROR cannot multiply `()` to `{integer}`
|
||||
| ^ no implementation for `{integer} * ()`
|
||||
|
|
||||
= help: the trait `std::ops::Mul<()>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
|
||||
error[E0277]: cannot divide `{integer}` by `&str`
|
||||
--> $DIR/binops.rs:15:7
|
||||
|
|
||||
15 | 4 / ""; //~ ERROR is not satisfied
|
||||
15 | 4 / ""; //~ ERROR cannot divide `{integer}` by `&str`
|
||||
| ^ no implementation for `{integer} / &str`
|
||||
|
|
||||
= help: the trait `std::ops::Div<&str>` is not implemented for `{integer}`
|
||||
|
14
src/test/ui/on-unimplemented/auxiliary/no_debug.rs
Normal file
14
src/test/ui/on-unimplemented/auxiliary/no_debug.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub struct Bar;
|
27
src/test/ui/on-unimplemented/no-debug.rs
Normal file
27
src/test/ui/on-unimplemented/no-debug.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:no_debug.rs
|
||||
|
||||
extern crate no_debug;
|
||||
|
||||
use no_debug::Bar;
|
||||
|
||||
struct Foo;
|
||||
|
||||
fn main() {
|
||||
println!("{:?} {:?}", Foo, Bar);
|
||||
println!("{} {}", Foo, Bar);
|
||||
}
|
||||
//~^^^ ERROR `Foo` doesn't implement `std::fmt::Debug`
|
||||
//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Debug`
|
||||
//~^^^^ ERROR `Foo` doesn't implement `std::fmt::Display`
|
||||
//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Display`
|
||||
|
38
src/test/ui/on-unimplemented/no-debug.stderr
Normal file
38
src/test/ui/on-unimplemented/no-debug.stderr
Normal file
@ -0,0 +1,38 @@
|
||||
error[E0277]: `Foo` doesn't implement `std::fmt::Debug`
|
||||
--> $DIR/no-debug.rs:20:27
|
||||
|
|
||||
20 | println!("{:?} {:?}", Foo, Bar);
|
||||
| ^^^ `Foo` cannot be formatted using `:?`; add `#[derive(Debug)]` or manually implement `std::fmt::Debug`
|
||||
|
|
||||
= help: the trait `std::fmt::Debug` is not implemented for `Foo`
|
||||
= note: required by `std::fmt::Debug::fmt`
|
||||
|
||||
error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug`
|
||||
--> $DIR/no-debug.rs:20:32
|
||||
|
|
||||
20 | println!("{:?} {:?}", Foo, Bar);
|
||||
| ^^^ `no_debug::Bar` cannot be formatted using `:?` because it doesn't implement `std::fmt::Debug`
|
||||
|
|
||||
= help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar`
|
||||
= note: required by `std::fmt::Debug::fmt`
|
||||
|
||||
error[E0277]: `Foo` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/no-debug.rs:21:23
|
||||
|
|
||||
21 | println!("{} {}", Foo, Bar);
|
||||
| ^^^ `Foo` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
|
||||
|
|
||||
= help: the trait `std::fmt::Display` is not implemented for `Foo`
|
||||
= note: required by `std::fmt::Display::fmt`
|
||||
|
||||
error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/no-debug.rs:21:28
|
||||
|
|
||||
21 | println!("{} {}", Foo, Bar);
|
||||
| ^^^ `no_debug::Bar` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
|
||||
|
|
||||
= help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar`
|
||||
= note: required by `std::fmt::Display::fmt`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
@ -20,7 +20,7 @@ fn main() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
let z = 3;
|
||||
foo(1 as u32 + //~ ERROR not satisfied
|
||||
foo(1 as u32 + //~ ERROR cannot add `()` to `u32`
|
||||
|
||||
bar(x,
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
|
||||
error[E0277]: cannot add `()` to `u32`
|
||||
--> $DIR/multiline-span-simple.rs:23:18
|
||||
|
|
||||
23 | foo(1 as u32 + //~ ERROR not satisfied
|
||||
23 | foo(1 as u32 + //~ ERROR cannot add `()` to `u32`
|
||||
| ^ no implementation for `u32 + ()`
|
||||
|
|
||||
= help: the trait `std::ops::Add<()>` is not implemented for `u32`
|
||||
|
@ -2,7 +2,7 @@ error[E0277]: the trait bound `&str: std::iter::Iterator` is not satisfied
|
||||
--> $DIR/for-c-in-str.rs:14:14
|
||||
|
|
||||
14 | for c in "asdf" {
|
||||
| ^^^^^^ `&str` is not an iterator; maybe try calling `.iter()` or a similar method
|
||||
| ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
|
||||
|
|
||||
= help: the trait `std::iter::Iterator` is not implemented for `&str`
|
||||
= note: required by `std::iter::IntoIterator::into_iter`
|
||||
|
Loading…
x
Reference in New Issue
Block a user