-
Notifications
You must be signed in to change notification settings - Fork 32
Add #[no_panic_if] #1492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add #[no_panic_if] #1492
Changes from all commits
ee8d1cd
8572f78
c4080b9
3862989
c638bde
e42e7be
83a3ca0
9cd5581
a7bac84
72dcf09
036f5e6
a42776d
55d90a8
ec89c48
eeb51ab
06a6c67
3c74bf1
7f47124
5513c2b
2fb3e28
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -53,6 +53,8 @@ enum SyntaxAttr { | |||||
| Hide, | ||||||
| /// a `#[opaque]` attribute | ||||||
| Opaque, | ||||||
| /// A `#[no_panic_if(...)]` attribute | ||||||
| NoPanicIf(Expr), | ||||||
| } | ||||||
|
|
||||||
| #[derive(Default)] | ||||||
|
|
@@ -92,6 +94,14 @@ impl ParsedAttrs { | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| fn no_panic_if(&mut self) -> Option<Expr> { | ||||||
| let pos = self | ||||||
| .syntax | ||||||
| .iter() | ||||||
| .position(|x| matches!(x, SyntaxAttr::NoPanicIf(_)))?; | ||||||
| if let SyntaxAttr::NoPanicIf(expr) = self.syntax.remove(pos) { Some(expr) } else { None } | ||||||
| } | ||||||
|
|
||||||
| fn invariant(&mut self) -> Option<Expr> { | ||||||
| let pos = self | ||||||
| .syntax | ||||||
|
|
@@ -278,9 +288,10 @@ fn ident_path(cx: &mut ParseCtxt, ident: Ident) -> ExprPath { | |||||
|
|
||||||
| fn parse_detached_fn_sig( | ||||||
| cx: &mut ParseCtxt, | ||||||
| attrs: ParsedAttrs, | ||||||
| mut attrs: ParsedAttrs, | ||||||
| ) -> ParseResult<DetachedItem<FnSig>> { | ||||||
| let fn_sig = parse_fn_sig(cx, token::Semi)?; | ||||||
| let mut fn_sig = parse_fn_sig(cx, token::Semi)?; | ||||||
| fn_sig.no_panic = attrs.no_panic_if(); | ||||||
| let span = fn_sig.span; | ||||||
| let ident = fn_sig | ||||||
| .ident | ||||||
|
|
@@ -411,6 +422,10 @@ fn parse_attr(cx: &mut ParseCtxt, attrs: &mut ParsedAttrs) -> ParseResult { | |||||
| attrs | ||||||
| .syntax | ||||||
| .push(SyntaxAttr::Invariant(delimited(cx, Parenthesis, |cx| parse_expr(cx, true))?)); | ||||||
| } else if lookahead.advance_if(sym::no_panic_if) { | ||||||
| attrs | ||||||
| .syntax | ||||||
| .push(SyntaxAttr::NoPanicIf(parse_expr(cx, true)?)); | ||||||
|
||||||
| .push(SyntaxAttr::NoPanicIf(parse_expr(cx, true)?)); | |
| .push(SyntaxAttr::NoPanicIf(delimited(cx, Parenthesis, |cx| parse_expr(cx, true))?)); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,7 @@ symbols! { | |
| Set, | ||
| int, | ||
| no_panic, | ||
| no_panic_if, | ||
| ptr_size, | ||
| real, | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| #[flux::no_panic] //~ ERROR: duplicated attribute | ||
| #[flux::no_panic_if(x > 0)] | ||
| fn bar() -> i32 { | ||
| 3 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| #[flux::assoc(fn foo_no_panic() -> bool)] | ||
| trait MyTrait { | ||
| #[flux::sig(fn foo(&Self) -> i32)] | ||
| #[flux::no_panic_if(Self::foo_no_panic())] | ||
| fn foo(&self) -> i32; | ||
| } | ||
|
|
||
| struct MyStruct; | ||
|
|
||
| #[flux::assoc(fn foo_no_panic() -> bool { false })] | ||
| impl MyTrait for MyStruct { | ||
| #[flux::sig(fn foo(&Self) -> i32)] | ||
| #[flux::no_panic_if(Self::foo_no_panic())] | ||
| fn foo(&self) -> i32 { | ||
| panic!("oops") | ||
| } | ||
| } | ||
|
|
||
| #[flux::sig(fn bar(x: &M) -> i32)] | ||
| #[flux::no_panic_if(M::foo_no_panic())] | ||
| fn bar<M>(my_impl: &M) -> i32 | ||
| where | ||
| M: MyTrait, | ||
| { | ||
| // calling `foo` generically is ok, because the no_panic condition is `M::foo_no_panic()`. | ||
| my_impl.foo(); | ||
| let s = MyStruct; | ||
| // `MyStruct::foo` may panic, because the no_panic condition is `MyStruct::foo_no_panic()`, which is false. | ||
| s.foo() //~ ERROR: may panic | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[flux::no_panic] //~ ERROR: duplicated attribute | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[flux::no_panic_if(true)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn my_fn() -> i32 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | |
| } | |
| // Positive test 1: simple no_panic_if(true) on a function that does not panic | |
| #[flux::no_panic_if(true)] | |
| fn my_fn_ok() -> i32 { | |
| 42 | |
| } | |
| // Positive test 2: conditional no_panic_if(x > 0) with a valid call | |
| #[flux::no_panic_if(x > 0)] | |
| fn my_fn_conditional(x: i32) -> i32 { | |
| x | |
| } | |
| fn use_my_fn_conditional() { | |
| let _ = my_fn_conditional(1); | |
| } | |
| // Positive test 3: trait/impl scenario where the condition is true | |
| trait NoPanicTrait { | |
| #[flux::no_panic_if(true)] | |
| fn do_something(&self) -> i32; | |
| } | |
| struct NoPanicImpl; | |
| impl NoPanicTrait for NoPanicImpl { | |
| #[flux::no_panic_if(true)] | |
| fn do_something(&self) -> i32 { | |
| 0 | |
| } | |
| } | |
| fn use_trait_impl() { | |
| let v = NoPanicImpl; | |
| let _ = v.do_something(); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nested if-else can be simplified for better readability. The inner if-expression can be converted to use
then_someor restructured with the outer if-let pattern.