mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
on_unimplemented: add method-name checks and use them in Try
This commit is contained in:
parent
6dec953c5a
commit
efa09ea554
@ -21,7 +21,9 @@
|
||||
(or another type that implements `{Try}`)")]
|
||||
#[cfg_attr(not(stage0),
|
||||
rustc_on_unimplemented(
|
||||
on(all(direct, from_desugaring="?"),
|
||||
on(all(
|
||||
any(from_method="from_error", from_method="from_ok"),
|
||||
from_desugaring="?"),
|
||||
message="the `?` operator can only be used in a \
|
||||
function that returns `Result` \
|
||||
(or another type that implements `{Try}`)",
|
||||
|
@ -327,7 +327,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
.unwrap_or(trait_ref.def_id());
|
||||
let trait_ref = *trait_ref.skip_binder();
|
||||
|
||||
let s;
|
||||
let desugaring;
|
||||
let method;
|
||||
let mut flags = vec![];
|
||||
let direct = match obligation.cause.code {
|
||||
ObligationCauseCode::BuiltinDerivedObligation(..) |
|
||||
@ -340,10 +341,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
flags.push(("direct", None));
|
||||
}
|
||||
|
||||
if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
|
||||
// FIXME: maybe also have some way of handling methods
|
||||
// from other traits? That would require name resolution,
|
||||
// which we might want to be some sort of hygienic.
|
||||
//
|
||||
// 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).as_str();
|
||||
flags.push(("from_method", None));
|
||||
flags.push(("from_method", Some(&*method)));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
|
||||
s = k.as_symbol().as_str();
|
||||
desugaring = k.as_symbol().as_str();
|
||||
flags.push(("from_desugaring", None));
|
||||
flags.push(("from_desugaring", Some(&*s)));
|
||||
flags.push(("from_desugaring", Some(&*desugaring)));
|
||||
}
|
||||
|
||||
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
|
||||
|
@ -176,6 +176,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||
{
|
||||
let mut message = None;
|
||||
let mut label = 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 {
|
||||
@ -191,8 +193,13 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||
}
|
||||
}
|
||||
debug!("evaluate: {:?} succeeded", command);
|
||||
message = command.message.clone();
|
||||
label = command.label.clone();
|
||||
if let Some(ref message_) = command.message {
|
||||
message = Some(message_.clone());
|
||||
}
|
||||
|
||||
if let Some(ref label_) = command.label {
|
||||
label = Some(label_.clone());
|
||||
}
|
||||
}
|
||||
|
||||
OnUnimplementedNote {
|
||||
|
@ -13,9 +13,21 @@
|
||||
use std::ops::Try;
|
||||
|
||||
fn main() {
|
||||
// error for a `Try` type on a non-`Try` fn
|
||||
std::fs::File::open("foo")?;
|
||||
|
||||
// a non-`Try` type on a `Try` fn
|
||||
()?;
|
||||
|
||||
// an unrelated use of `Try`
|
||||
try_trait_generic::<()>();
|
||||
}
|
||||
|
||||
fn try_trait_generic<T: Try>() {}
|
||||
|
||||
|
||||
fn try_trait_generic<T: Try>() -> T {
|
||||
// and a non-`Try` object on a `Try` fn.
|
||||
()?;
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/try-operator-on-main.rs:16:5
|
||||
--> $DIR/try-operator-on-main.rs:17:5
|
||||
|
|
||||
16 | std::fs::File::open("foo")?;
|
||||
17 | std::fs::File::open("foo")?;
|
||||
| ---------------------------
|
||||
| |
|
||||
| cannot use the `?` operator in a function that returns `()`
|
||||
@ -11,12 +11,34 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
|
||||
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
|
||||
--> $DIR/try-operator-on-main.rs:18:5
|
||||
--> $DIR/try-operator-on-main.rs:20:5
|
||||
|
|
||||
18 | try_trait_generic::<()>();
|
||||
20 | ()?;
|
||||
| ---
|
||||
| |
|
||||
| the trait `std::ops::Try` is not implemented for `()`
|
||||
| in this macro invocation
|
||||
|
|
||||
= note: required by `std::ops::Try::into_result`
|
||||
|
||||
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
|
||||
--> $DIR/try-operator-on-main.rs:23:5
|
||||
|
|
||||
23 | try_trait_generic::<()>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()`
|
||||
|
|
||||
= note: required by `try_trait_generic`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
|
||||
--> $DIR/try-operator-on-main.rs:30:5
|
||||
|
|
||||
30 | ()?;
|
||||
| ---
|
||||
| |
|
||||
| the trait `std::ops::Try` is not implemented for `()`
|
||||
| in this macro invocation
|
||||
|
|
||||
= note: required by `std::ops::Try::into_result`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user