Skip to content

Commit d75338e

Browse files
authored
Rollup merge of rust-lang#65902 - gilescope:issue62570, r=estebank
Make ItemContext available for better diagnositcs Fix rust-lang#62570
2 parents 48a9f59 + d7869ec commit d75338e

File tree

8 files changed

+166
-2
lines changed

8 files changed

+166
-2
lines changed

src/libcore/ops/try.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
/// extracting those success or failure values from an existing instance and
66
/// creating a new instance from a success or failure value.
77
#[unstable(feature = "try_trait", issue = "42327")]
8-
#[rustc_on_unimplemented(
8+
#[cfg_attr(bootstrap, rustc_on_unimplemented(
99
on(all(
1010
any(from_method="from_error", from_method="from_ok"),
1111
from_desugaring="QuestionMark"),
@@ -17,7 +17,20 @@
1717
message="the `?` operator can only be applied to values \
1818
that implement `{Try}`",
1919
label="the `?` operator cannot be applied to type `{Self}`")
20-
)]
20+
))]
21+
#[cfg_attr(not(bootstrap), rustc_on_unimplemented(
22+
on(all(
23+
any(from_method="from_error", from_method="from_ok"),
24+
from_desugaring="QuestionMark"),
25+
message="the `?` operator can only be used in {ItemContext} \
26+
that returns `Result` or `Option` \
27+
(or another type that implements `{Try}`)",
28+
label="cannot use the `?` operator in {ItemContext} that returns `{Self}`"),
29+
on(all(from_method="into_result", from_desugaring="QuestionMark"),
30+
message="the `?` operator can only be applied to values \
31+
that implement `{Try}`",
32+
label="the `?` operator cannot be applied to type `{Self}`")
33+
))]
2134
#[doc(alias = "?")]
2235
pub trait Try {
2336
/// The type of this value when viewed as successful.

src/librustc/traits/error_reporting.rs

+49
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,52 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
353353
}
354354
}
355355

356+
fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
357+
self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| {
358+
match gen_kind {
359+
hir::GeneratorKind::Gen => "a generator",
360+
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block",
361+
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function",
362+
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure",
363+
}
364+
})
365+
}
366+
367+
/// Used to set on_unimplemented's `ItemContext`
368+
/// to be the enclosing (async) block/function/closure
369+
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
370+
let hir = &self.tcx.hir();
371+
let node = hir.find(hir_id)?;
372+
if let hir::Node::Item(
373+
hir::Item{kind: hir::ItemKind::Fn(_ ,fn_header ,_ , body_id), .. }) = &node {
374+
self.describe_generator(*body_id).or_else(||
375+
Some(if let hir::FnHeader{ asyncness: hir::IsAsync::Async, .. } = fn_header {
376+
"an async function"
377+
} else {
378+
"a function"
379+
})
380+
)
381+
} else if let hir::Node::Expr(hir::Expr {
382+
kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), .. }) = &node {
383+
self.describe_generator(*body_id).or_else(||
384+
Some(if gen_movability.is_some() {
385+
"an async closure"
386+
} else {
387+
"a closure"
388+
})
389+
)
390+
} else if let hir::Node::Expr(hir::Expr { .. }) = &node {
391+
let parent_hid = hir.get_parent_node(hir_id);
392+
if parent_hid != hir_id {
393+
return self.describe_enclosure(parent_hid);
394+
} else {
395+
None
396+
}
397+
} else {
398+
None
399+
}
400+
}
401+
356402
fn on_unimplemented_note(
357403
&self,
358404
trait_ref: ty::PolyTraitRef<'tcx>,
@@ -363,6 +409,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
363409
let trait_ref = *trait_ref.skip_binder();
364410

365411
let mut flags = vec![];
412+
flags.push((sym::item_context,
413+
self.describe_enclosure(obligation.cause.body_id).map(|s|s.to_owned())));
414+
366415
match obligation.cause.code {
367416
ObligationCauseCode::BuiltinDerivedObligation(..) |
368417
ObligationCauseCode::ImplDerivedObligation(..) => {}

src/librustc/traits/on_unimplemented.rs

+5
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ impl<'tcx> OnUnimplementedFormatString {
248248
Position::ArgumentNamed(s) if s == sym::from_method => (),
249249
// `{from_desugaring}` is allowed
250250
Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
251+
// `{ItemContext}` is allowed
252+
Position::ArgumentNamed(s) if s == sym::item_context => (),
251253
// So is `{A}` if A is a type parameter
252254
Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
253255
param.name == s
@@ -296,6 +298,7 @@ impl<'tcx> OnUnimplementedFormatString {
296298

297299
let s = self.0.as_str();
298300
let parser = Parser::new(&s, None, vec![], false);
301+
let item_context = (options.get(&sym::item_context)).unwrap_or(&empty_string);
299302
parser.map(|p|
300303
match p {
301304
Piece::String(s) => s,
@@ -311,6 +314,8 @@ impl<'tcx> OnUnimplementedFormatString {
311314
} else if s == sym::from_desugaring || s == sym::from_method {
312315
// don't break messages using these two arguments incorrectly
313316
&empty_string
317+
} else if s == sym::item_context {
318+
&item_context
314319
} else {
315320
bug!("broken on_unimplemented {:?} for {:?}: \
316321
no argument matching {:?}",

src/libsyntax_pos/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ symbols! {
370370
issue_5723_bootstrap,
371371
issue_tracker_base_url,
372372
item,
373+
item_context: "ItemContext",
373374
item_like_imports,
374375
iter,
375376
Iterator,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![feature(try_trait, async_closure)]
2+
// edition:2018
3+
fn main() {}
4+
5+
async fn an_async_block() -> u32 {
6+
async {
7+
let x: Option<u32> = None;
8+
x?; //~ ERROR the `?` operator
9+
22
10+
}.await
11+
}
12+
13+
async fn async_closure_containing_fn() -> u32 {
14+
let async_closure = async || {
15+
let x: Option<u32> = None;
16+
x?; //~ ERROR the `?` operator
17+
22_u32
18+
};
19+
20+
async_closure().await
21+
}
22+
23+
async fn an_async_function() -> u32 {
24+
let x: Option<u32> = None;
25+
x?; //~ ERROR the `?` operator
26+
22
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
2+
--> $DIR/try-on-option-in-async.rs:8:9
3+
|
4+
LL | x?;
5+
| ^^ cannot use the `?` operator in an async block that returns `{integer}`
6+
|
7+
= help: the trait `std::ops::Try` is not implemented for `{integer}`
8+
= note: required by `std::ops::Try::from_error`
9+
10+
error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
11+
--> $DIR/try-on-option-in-async.rs:16:9
12+
|
13+
LL | x?;
14+
| ^^ cannot use the `?` operator in an async closure that returns `u32`
15+
|
16+
= help: the trait `std::ops::Try` is not implemented for `u32`
17+
= note: required by `std::ops::Try::from_error`
18+
19+
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
20+
--> $DIR/try-on-option-in-async.rs:25:5
21+
|
22+
LL | x?;
23+
| ^^ cannot use the `?` operator in an async function that returns `u32`
24+
|
25+
= help: the trait `std::ops::Try` is not implemented for `u32`
26+
= note: required by `std::ops::Try::from_error`
27+
28+
error: aborting due to 3 previous errors
29+
30+
For more information about this error, try `rustc --explain E0277`.
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(try_trait)]
2+
// edition:2018
3+
fn main() {}
4+
5+
fn a_function() -> u32 {
6+
let x: Option<u32> = None;
7+
x?; //~ ERROR the `?` operator
8+
22
9+
}
10+
11+
fn a_closure() -> u32 {
12+
let a_closure = || {
13+
let x: Option<u32> = None;
14+
x?; //~ ERROR the `?` operator
15+
22
16+
};
17+
a_closure()
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
2+
--> $DIR/try-on-option-diagnostics.rs:7:5
3+
|
4+
LL | x?;
5+
| ^^ cannot use the `?` operator in a function that returns `u32`
6+
|
7+
= help: the trait `std::ops::Try` is not implemented for `u32`
8+
= note: required by `std::ops::Try::from_error`
9+
10+
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
11+
--> $DIR/try-on-option-diagnostics.rs:14:9
12+
|
13+
LL | x?;
14+
| ^^ cannot use the `?` operator in a closure that returns `{integer}`
15+
|
16+
= help: the trait `std::ops::Try` is not implemented for `{integer}`
17+
= note: required by `std::ops::Try::from_error`
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)