Auto merge of #111928 - c410-f3r:dqewdas, r=eholk

[RFC-2011] Expand more expressions

cc #44838

Expands `if`, `let`, `match` and also makes `generic_assert_internals` an allowed feature when using `assert!`. `#![feature(generic_assert)]` is still needed to activate everything.

```rust
#![feature(generic_assert)]

fn fun(a: Option<i32>, b: Option<i32>, c: Option<i32>) {
  assert!(
    if a.is_some() { 1 } else { 2 } == 3
      && if let Some(elem) = b { elem == 4 } else { false }
      && match c { Some(_) => true, None => false }
  );
}

fn main() {
  fun(Some(1), None, Some(2));
}

// Assertion failed: assert!(
//   if a.is_some() { 1 } else { 2 } == 3
//     && if let Some(elem) = b { elem == 4 } else { false }
//     && match c { Some(_) => true, None => false }
// );
//
// With captures:
//   a = Some(1)
//   b = None
//   c = Some(2)
```
This commit is contained in:
bors 2023-05-27 07:02:48 +00:00
commit a525c7ddba
9 changed files with 29 additions and 86 deletions

View File

@ -233,10 +233,19 @@ impl<'cx, 'a> Context<'cx, 'a> {
ExprKind::Cast(local_expr, _) => { ExprKind::Cast(local_expr, _) => {
self.manage_cond_expr(local_expr); self.manage_cond_expr(local_expr);
} }
ExprKind::If(local_expr, _, _) => {
self.manage_cond_expr(local_expr);
}
ExprKind::Index(prefix, suffix) => { ExprKind::Index(prefix, suffix) => {
self.manage_cond_expr(prefix); self.manage_cond_expr(prefix);
self.manage_cond_expr(suffix); self.manage_cond_expr(suffix);
} }
ExprKind::Let(_, local_expr, _) => {
self.manage_cond_expr(local_expr);
}
ExprKind::Match(local_expr, _) => {
self.manage_cond_expr(local_expr);
}
ExprKind::MethodCall(call) => { ExprKind::MethodCall(call) => {
for arg in &mut call.args { for arg in &mut call.args {
self.manage_cond_expr(arg); self.manage_cond_expr(arg);
@ -295,17 +304,14 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::Continue(_) | ExprKind::Continue(_)
| ExprKind::Err | ExprKind::Err
| ExprKind::Field(_, _) | ExprKind::Field(_, _)
| ExprKind::FormatArgs(_)
| ExprKind::ForLoop(_, _, _, _) | ExprKind::ForLoop(_, _, _, _)
| ExprKind::If(_, _, _) | ExprKind::FormatArgs(_)
| ExprKind::IncludedBytes(..) | ExprKind::IncludedBytes(..)
| ExprKind::InlineAsm(_) | ExprKind::InlineAsm(_)
| ExprKind::OffsetOf(_, _)
| ExprKind::Let(_, _, _)
| ExprKind::Lit(_) | ExprKind::Lit(_)
| ExprKind::Loop(_, _, _) | ExprKind::Loop(_, _, _)
| ExprKind::MacCall(_) | ExprKind::MacCall(_)
| ExprKind::Match(_, _) | ExprKind::OffsetOf(_, _)
| ExprKind::Path(_, _) | ExprKind::Path(_, _)
| ExprKind::Ret(_) | ExprKind::Ret(_)
| ExprKind::Try(_) | ExprKind::Try(_)

View File

@ -1427,7 +1427,7 @@ pub(crate) mod builtin {
#[rustc_builtin_macro] #[rustc_builtin_macro]
#[macro_export] #[macro_export]
#[rustc_diagnostic_item = "assert_macro"] #[rustc_diagnostic_item = "assert_macro"]
#[allow_internal_unstable(core_panic, edition_panic)] #[allow_internal_unstable(core_panic, edition_panic, generic_assert_internals)]
macro_rules! assert { macro_rules! assert {
($cond:expr $(,)?) => {{ /* compiler built-in */ }}; ($cond:expr $(,)?) => {{ /* compiler built-in */ }};
($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }}; ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};

View File

@ -5,7 +5,7 @@
// needs-unwind Asserting on contents of error message // needs-unwind Asserting on contents of error message
#![allow(path_statements, unused_allocation)] #![allow(path_statements, unused_allocation)]
#![feature(core_intrinsics, generic_assert, generic_assert_internals)] #![feature(core_intrinsics, generic_assert)]
macro_rules! test { macro_rules! test {
( (
@ -51,6 +51,7 @@ macro_rules! tests {
const FOO: Foo = Foo { bar: 1 }; const FOO: Foo = Foo { bar: 1 };
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
struct Foo { struct Foo {
bar: i32 bar: i32
@ -83,9 +84,18 @@ fn main() {
// cast // cast
[ elem as i32 == 3 ] => "Assertion failed: elem as i32 == 3\nWith captures:\n elem = 1\n" [ elem as i32 == 3 ] => "Assertion failed: elem as i32 == 3\nWith captures:\n elem = 1\n"
// if
[ if elem == 3 { true } else { false } ] => "Assertion failed: if elem == 3 { true } else { false }\nWith captures:\n elem = 1\n"
// index // index
[ [1i32, 1][elem as usize] == 3 ] => "Assertion failed: [1i32, 1][elem as usize] == 3\nWith captures:\n elem = 1\n" [ [1i32, 1][elem as usize] == 3 ] => "Assertion failed: [1i32, 1][elem as usize] == 3\nWith captures:\n elem = 1\n"
// let
[ if let 3 = elem { true } else { false } ] => "Assertion failed: if let 3 = elem { true } else { false }\nWith captures:\n elem = 1\n"
// match
[ match elem { 3 => true, _ => false, } ] => "Assertion failed: match elem { 3 => true, _ => false, }\nWith captures:\n elem = 1\n"
// method call // method call
[ FOO.add(elem, elem) == 3 ] => "Assertion failed: FOO.add(elem, elem) == 3\nWith captures:\n elem = 1\n" [ FOO.add(elem, elem) == 3 ] => "Assertion failed: FOO.add(elem, elem) == 3\nWith captures:\n elem = 1\n"
@ -107,77 +117,4 @@ fn main() {
// unary // unary
[ -elem == -3 ] => "Assertion failed: -elem == -3\nWith captures:\n elem = 1\n" [ -elem == -3 ] => "Assertion failed: -elem == -3\nWith captures:\n elem = 1\n"
); );
// ***** Disallowed *****
tests!(
let mut elem = 1i32;
// assign
[ { let local = elem; local } == 3 ] => "Assertion failed: { let local = elem; local } == 3"
// assign op
[ { elem += 1; elem } == 3 ] => "Assertion failed: { elem += 1; elem } == 3"
// async
[ { let _ = async { elem }; elem } == 3 ] => "Assertion failed: { let _ = async { elem }; elem } == 3"
// await
// block
[ { elem } == 3 ] => "Assertion failed: { elem } == 3"
// break
[ loop { break elem; } == 3 ] => "Assertion failed: loop { break elem; } == 3"
// closure
[(|| elem)() == 3 ] => "Assertion failed: (|| elem)() == 3"
// const block
// continue
// err
// field
[ FOO.bar == 3 ] => "Assertion failed: FOO.bar == 3"
// for loop
[ { for _ in 0..elem { elem; } elem } == 3 ] => "Assertion failed: { for _ in 0..elem { elem; } elem } == 3"
// if
[ if true { elem } else { elem } == 3 ] => "Assertion failed: if true { elem } else { elem } == 3"
// inline asm
// let
[ if let true = true { elem } else { elem } == 3 ] => "Assertion failed: if let true = true { elem } else { elem } == 3"
// lit
// loop
[ loop { elem; break elem; } == 3 ] => "Assertion failed: loop { elem; break elem; } == 3"
// mac call
// match
[ match elem { _ => elem } == 3 ] => "Assertion failed: (match elem { _ => elem, }) == 3"
// ret
[ (|| { return elem; })() == 3 ] => "Assertion failed: (|| { return elem; })() == 3"
// try
[ (|| { Some(Some(elem)?) })() == Some(3) ] => "Assertion failed: (|| { Some(Some(elem)?) })() == Some(3)"
// try block
// underscore
// while
[ { while false { elem; break; } elem } == 3 ] => "Assertion failed: { while false { elem; break; } elem } == 3"
// yeet
// yield
);
} }

View File

@ -4,7 +4,7 @@
// run-pass // run-pass
// needs-unwind Asserting on contents of error message // needs-unwind Asserting on contents of error message
#![feature(core_intrinsics, generic_assert, generic_assert_internals)] #![feature(core_intrinsics, generic_assert)]
extern crate common; extern crate common;

View File

@ -1,7 +1,7 @@
// compile-flags: --test // compile-flags: --test
// run-pass // run-pass
#![feature(core_intrinsics, generic_assert, generic_assert_internals)] #![feature(core_intrinsics, generic_assert)]
#[should_panic(expected = "Custom user message")] #[should_panic(expected = "Custom user message")]
#[test] #[test]

View File

@ -3,7 +3,7 @@
// run-pass // run-pass
// needs-unwind Asserting on contents of error message // needs-unwind Asserting on contents of error message
#![feature(core_intrinsics, generic_assert, generic_assert_internals)] #![feature(core_intrinsics, generic_assert)]
extern crate common; extern crate common;

View File

@ -2,7 +2,7 @@
// ignore-tidy-linelength // ignore-tidy-linelength
// run-pass // run-pass
#![feature(core_intrinsics, generic_assert, generic_assert_internals)] #![feature(core_intrinsics, generic_assert)]
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};

View File

@ -1,7 +1,7 @@
// check-pass // check-pass
// compile-flags: -Z unpretty=expanded // compile-flags: -Z unpretty=expanded
#![feature(core_intrinsics, generic_assert, generic_assert_internals)] #![feature(core_intrinsics, generic_assert)]
fn arbitrary_consuming_method_for_demonstration_purposes() { fn arbitrary_consuming_method_for_demonstration_purposes() {
let elem = 1i32; let elem = 1i32;

View File

@ -3,7 +3,7 @@
// check-pass // check-pass
// compile-flags: -Z unpretty=expanded // compile-flags: -Z unpretty=expanded
#![feature(core_intrinsics, generic_assert, generic_assert_internals)] #![feature(core_intrinsics, generic_assert)]
#[prelude_import] #[prelude_import]
use ::std::prelude::rust_2015::*; use ::std::prelude::rust_2015::*;
#[macro_use] #[macro_use]