Rollup merge of #122661 - estebank:assert-macro-span, r=petrochenkov
Change the desugaring of `assert!` for better error output
In the desugaring of `assert!`, we now expand to a `match` expression instead of `if !cond {..}`.
The span of incorrect conditions will point only at the expression, and not the whole `assert!` invocation.
```
error[E0308]: mismatched types
--> $DIR/issue-14091.rs:2:13
|
LL | assert!(1,1);
| ^ expected `bool`, found integer
```
We no longer mention the expression needing to implement the `Not` trait.
```
error[E0308]: mismatched types
--> $DIR/issue-14091-2.rs:15:13
|
LL | assert!(x, x);
| ^ expected `bool`, found `BytePos`
```
Now `assert!(val)` desugars to:
```rust
match val {
true => {},
_ => $crate::panic::panic_2021!(),
}
```
Fix #122159.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
mod context;
|
||||
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
@@ -29,7 +29,7 @@ pub(crate) fn expand_assert<'cx>(
|
||||
|
||||
// `core::panic` and `std::panic` are different macros, so we use call-site
|
||||
// context to pick up whichever is currently in scope.
|
||||
let call_site_span = cx.with_call_site_ctxt(span);
|
||||
let call_site_span = cx.with_call_site_ctxt(cond_expr.span);
|
||||
|
||||
let panic_path = || {
|
||||
if use_panic_2021(span) {
|
||||
@@ -63,7 +63,7 @@ pub(crate) fn expand_assert<'cx>(
|
||||
}),
|
||||
})),
|
||||
);
|
||||
expr_if_not(cx, call_site_span, cond_expr, then, None)
|
||||
assert_cond_check(cx, call_site_span, cond_expr, then)
|
||||
}
|
||||
// If `generic_assert` is enabled, generates rich captured outputs
|
||||
//
|
||||
@@ -88,26 +88,33 @@ pub(crate) fn expand_assert<'cx>(
|
||||
)),
|
||||
)],
|
||||
);
|
||||
expr_if_not(cx, call_site_span, cond_expr, then, None)
|
||||
assert_cond_check(cx, call_site_span, cond_expr, then)
|
||||
};
|
||||
|
||||
ExpandResult::Ready(MacEager::expr(expr))
|
||||
}
|
||||
|
||||
/// `assert!($cond_expr, $custom_message)`
|
||||
struct Assert {
|
||||
cond_expr: Box<Expr>,
|
||||
custom_message: Option<TokenStream>,
|
||||
}
|
||||
|
||||
// if !{ ... } { ... } else { ... }
|
||||
fn expr_if_not(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
cond: Box<Expr>,
|
||||
then: Box<Expr>,
|
||||
els: Option<Box<Expr>>,
|
||||
) -> Box<Expr> {
|
||||
cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
|
||||
/// `match <cond> { true => {} _ => <then> }`
|
||||
fn assert_cond_check(cx: &ExtCtxt<'_>, span: Span, cond: Box<Expr>, then: Box<Expr>) -> Box<Expr> {
|
||||
// Instead of expanding to `if !<cond> { <then> }`, we expand to
|
||||
// `match <cond> { true => {} _ => <then> }`.
|
||||
// This allows us to always complain about mismatched types instead of "cannot apply unary
|
||||
// operator `!` to type `X`" when passing an invalid `<cond>`, while also allowing `<cond>` to
|
||||
// be `&true`.
|
||||
let els = cx.expr_block(cx.block(span, thin_vec![]));
|
||||
let mut arms = thin_vec![];
|
||||
arms.push(cx.arm(span, cx.pat_lit(span, cx.expr_bool(span, true)), els));
|
||||
arms.push(cx.arm(span, cx.pat_wild(span), then));
|
||||
|
||||
// We wrap the `match` in a statement to limit the length of any borrows introduced in the
|
||||
// condition.
|
||||
cx.expr_block(cx.block(span, [cx.stmt_expr(cx.expr_match(span, cond, arms))].into()))
|
||||
}
|
||||
|
||||
fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
|
||||
|
||||
Reference in New Issue
Block a user