-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Lower let-else in MIR #98574
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
Lower let-else in MIR #98574
Changes from all commits
6c529de
1cd30e7
8e4a971
5374688
947cbda
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 |
---|---|---|
|
@@ -102,7 +102,7 @@ fn is_needs_drop_and_init<'tcx>( | |
let field_needs_drop_and_init = |(f, f_ty, mpi)| { | ||
let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f)); | ||
let Some(mpi) = child else { | ||
return f_ty.needs_drop(tcx, param_env); | ||
return Ty::needs_drop(f_ty, tcx, param_env); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without this this code does not compile because the type of Here is a reason why this compiled with lowering in AST but not anymore with lowering in MIR. With AST lowering, this let...else was transformed to: if let Some(mpi) = child {
is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi)
} else {
return f_ty.needs_drop(tcx, param_env);
} Since the We no longer visit the expressions in this order with lowering MIR. This time, the return statement is visited first. We need to resolve the method call but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this change should not be necessary anymore since the order in typeck has been adjusted. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After the adjustment in order, even after moving the check on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh 🤦 now I see it. Thanks! I guess I'd prefer to annotate the |
||
}; | ||
|
||
is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// edition:2021 | ||
#![feature(let_else)] | ||
use std::rc::Rc; | ||
|
||
async fn foo(x: Option<bool>) { | ||
let Some(_) = x else { | ||
let r = Rc::new(()); | ||
bar().await | ||
}; | ||
} | ||
|
||
async fn bar() -> ! { | ||
panic!() | ||
} | ||
|
||
fn is_send<T: Send>(_: T) {} | ||
|
||
async fn foo2(x: Option<bool>) { | ||
let Some(_) = x else { | ||
bar2(Rc::new(())).await | ||
}; | ||
} | ||
|
||
async fn bar2<T>(_: T) -> ! { | ||
panic!() | ||
} | ||
|
||
async fn foo3(x: Option<bool>) { | ||
let Some(_) = x else { | ||
(Rc::new(()), bar().await); | ||
return; | ||
}; | ||
} | ||
|
||
async fn foo4(x: Option<bool>) { | ||
let Some(_) = x else { | ||
let r = Rc::new(()); | ||
bar().await; | ||
println!("{:?}", r); | ||
return; | ||
}; | ||
} | ||
|
||
fn main() { | ||
is_send(foo(Some(true))); | ||
//~^ ERROR future cannot be sent between threads safely | ||
is_send(foo2(Some(true))); | ||
//~^ ERROR future cannot be sent between threads safely | ||
is_send(foo3(Some(true))); | ||
//~^ ERROR future cannot be sent between threads safely | ||
is_send(foo4(Some(true))); | ||
//~^ ERROR future cannot be sent between threads safely | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
error: future cannot be sent between threads safely | ||
--> $DIR/async-await-let-else.rs:45:13 | ||
| | ||
LL | is_send(foo(Some(true))); | ||
| ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` | ||
| | ||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` | ||
note: future is not `Send` as this value is used across an await | ||
--> $DIR/async-await-let-else.rs:8:14 | ||
| | ||
LL | let r = Rc::new(()); | ||
| - has type `Rc<()>` which is not `Send` | ||
LL | bar().await | ||
| ^^^^^^ await occurs here, with `r` maybe used later | ||
LL | }; | ||
| - `r` is later dropped here | ||
note: required by a bound in `is_send` | ||
--> $DIR/async-await-let-else.rs:16:15 | ||
| | ||
LL | fn is_send<T: Send>(_: T) {} | ||
| ^^^^ required by this bound in `is_send` | ||
|
||
error: future cannot be sent between threads safely | ||
--> $DIR/async-await-let-else.rs:47:13 | ||
| | ||
LL | is_send(foo2(Some(true))); | ||
| ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send` | ||
| | ||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` | ||
note: future is not `Send` as this value is used across an await | ||
--> $DIR/async-await-let-else.rs:20:26 | ||
| | ||
LL | bar2(Rc::new(())).await | ||
| ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later | ||
| | | ||
| has type `Rc<()>` which is not `Send` | ||
LL | }; | ||
| - `Rc::new(())` is later dropped here | ||
note: required by a bound in `is_send` | ||
--> $DIR/async-await-let-else.rs:16:15 | ||
| | ||
LL | fn is_send<T: Send>(_: T) {} | ||
| ^^^^ required by this bound in `is_send` | ||
|
||
error: future cannot be sent between threads safely | ||
--> $DIR/async-await-let-else.rs:49:13 | ||
| | ||
LL | is_send(foo3(Some(true))); | ||
| ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` | ||
| | ||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` | ||
note: future is not `Send` as this value is used across an await | ||
--> $DIR/async-await-let-else.rs:30:28 | ||
| | ||
LL | (Rc::new(()), bar().await); | ||
| ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later | ||
| | | ||
| has type `Rc<()>` which is not `Send` | ||
note: `Rc::new(())` is later dropped here | ||
--> $DIR/async-await-let-else.rs:30:35 | ||
| | ||
LL | (Rc::new(()), bar().await); | ||
| ^ | ||
note: required by a bound in `is_send` | ||
--> $DIR/async-await-let-else.rs:16:15 | ||
| | ||
LL | fn is_send<T: Send>(_: T) {} | ||
| ^^^^ required by this bound in `is_send` | ||
|
||
error: future cannot be sent between threads safely | ||
--> $DIR/async-await-let-else.rs:51:13 | ||
| | ||
LL | is_send(foo4(Some(true))); | ||
| ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` | ||
| | ||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` | ||
note: future is not `Send` as this value is used across an await | ||
--> $DIR/async-await-let-else.rs:38:14 | ||
| | ||
LL | let r = Rc::new(()); | ||
| - has type `Rc<()>` which is not `Send` | ||
LL | bar().await; | ||
| ^^^^^^ await occurs here, with `r` maybe used later | ||
... | ||
LL | }; | ||
| - `r` is later dropped here | ||
note: required by a bound in `is_send` | ||
--> $DIR/async-await-let-else.rs:16:15 | ||
| | ||
LL | fn is_send<T: Send>(_: T) {} | ||
| ^^^^ required by this bound in `is_send` | ||
|
||
error: aborting due to 4 previous errors | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// run-pass | ||
#![feature(let_else)] | ||
|
||
use std::sync::atomic::{AtomicU8, Ordering}; | ||
|
||
static TRACKER: AtomicU8 = AtomicU8::new(0); | ||
|
||
#[derive(Default)] | ||
struct Droppy { | ||
inner: u32, | ||
} | ||
|
||
impl Drop for Droppy { | ||
fn drop(&mut self) { | ||
TRACKER.store(1, Ordering::Release); | ||
println!("I've been dropped"); | ||
} | ||
} | ||
|
||
fn main() { | ||
assert_eq!(TRACKER.load(Ordering::Acquire), 0); | ||
let 0 = Droppy::default().inner else { return }; | ||
assert_eq!(TRACKER.load(Ordering::Acquire), 1); | ||
println!("Should have dropped 👆"); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.