on_unimplemented: add method-name checks and use them in Try

This commit is contained in:
Ariel Ben-Yehuda 2017-08-31 21:46:03 +03:00
parent 6dec953c5a
commit efa09ea554
5 changed files with 69 additions and 12 deletions

View File

@ -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}`)",

View File

@ -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(

View File

@ -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 {

View File

@ -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 {}
}

View File

@ -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