Skip to content

Commit efa09ea

Browse files
committed
on_unimplemented: add method-name checks and use them in Try
1 parent 6dec953 commit efa09ea

File tree

5 files changed

+69
-12
lines changed

5 files changed

+69
-12
lines changed

src/libcore/ops/try.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
(or another type that implements `{Try}`)")]
2222
#[cfg_attr(not(stage0),
2323
rustc_on_unimplemented(
24-
on(all(direct, from_desugaring="?"),
24+
on(all(
25+
any(from_method="from_error", from_method="from_ok"),
26+
from_desugaring="?"),
2527
message="the `?` operator can only be used in a \
2628
function that returns `Result` \
2729
(or another type that implements `{Try}`)",

src/librustc/traits/error_reporting.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
327327
.unwrap_or(trait_ref.def_id());
328328
let trait_ref = *trait_ref.skip_binder();
329329

330-
let s;
330+
let desugaring;
331+
let method;
331332
let mut flags = vec![];
332333
let direct = match obligation.cause.code {
333334
ObligationCauseCode::BuiltinDerivedObligation(..) |
@@ -340,10 +341,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
340341
flags.push(("direct", None));
341342
}
342343

344+
if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
345+
// FIXME: maybe also have some way of handling methods
346+
// from other traits? That would require name resolution,
347+
// which we might want to be some sort of hygienic.
348+
//
349+
// Currently I'm leaving it for what I need for `try`.
350+
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
351+
method = self.tcx.item_name(item).as_str();
352+
flags.push(("from_method", None));
353+
flags.push(("from_method", Some(&*method)));
354+
}
355+
}
356+
343357
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
344-
s = k.as_symbol().as_str();
358+
desugaring = k.as_symbol().as_str();
345359
flags.push(("from_desugaring", None));
346-
flags.push(("from_desugaring", Some(&*s)));
360+
flags.push(("from_desugaring", Some(&*desugaring)));
347361
}
348362

349363
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(

src/librustc/traits/on_unimplemented.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
176176
{
177177
let mut message = None;
178178
let mut label = None;
179+
info!("evaluate({:?}, trait_ref={:?}, options={:?})",
180+
self, trait_ref, options);
179181

180182
for command in self.subcommands.iter().chain(Some(self)).rev() {
181183
if let Some(ref condition) = command.condition {
@@ -191,8 +193,13 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
191193
}
192194
}
193195
debug!("evaluate: {:?} succeeded", command);
194-
message = command.message.clone();
195-
label = command.label.clone();
196+
if let Some(ref message_) = command.message {
197+
message = Some(message_.clone());
198+
}
199+
200+
if let Some(ref label_) = command.label {
201+
label = Some(label_.clone());
202+
}
196203
}
197204

198205
OnUnimplementedNote {

src/test/ui/suggestions/try-operator-on-main.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,21 @@
1313
use std::ops::Try;
1414

1515
fn main() {
16+
// error for a `Try` type on a non-`Try` fn
1617
std::fs::File::open("foo")?;
1718

19+
// a non-`Try` type on a `Try` fn
20+
()?;
21+
22+
// an unrelated use of `Try`
1823
try_trait_generic::<()>();
1924
}
2025

21-
fn try_trait_generic<T: Try>() {}
26+
27+
28+
fn try_trait_generic<T: Try>() -> T {
29+
// and a non-`Try` object on a `Try` fn.
30+
()?;
31+
32+
loop {}
33+
}
Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
2-
--> $DIR/try-operator-on-main.rs:16:5
2+
--> $DIR/try-operator-on-main.rs:17:5
33
|
4-
16 | std::fs::File::open("foo")?;
4+
17 | std::fs::File::open("foo")?;
55
| ---------------------------
66
| |
77
| 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
1111
= note: required by `std::ops::Try::from_error`
1212

1313
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
14-
--> $DIR/try-operator-on-main.rs:18:5
14+
--> $DIR/try-operator-on-main.rs:20:5
1515
|
16-
18 | try_trait_generic::<()>();
16+
20 | ()?;
17+
| ---
18+
| |
19+
| the trait `std::ops::Try` is not implemented for `()`
20+
| in this macro invocation
21+
|
22+
= note: required by `std::ops::Try::into_result`
23+
24+
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
25+
--> $DIR/try-operator-on-main.rs:23:5
26+
|
27+
23 | try_trait_generic::<()>();
1728
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()`
1829
|
1930
= note: required by `try_trait_generic`
2031

21-
error: aborting due to 2 previous errors
32+
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
33+
--> $DIR/try-operator-on-main.rs:30:5
34+
|
35+
30 | ()?;
36+
| ---
37+
| |
38+
| the trait `std::ops::Try` is not implemented for `()`
39+
| in this macro invocation
40+
|
41+
= note: required by `std::ops::Try::into_result`
42+
43+
error: aborting due to 4 previous errors
2244

0 commit comments

Comments
 (0)