add tests for async await
This commit is contained in:
parent
8e4a971084
commit
5374688e1d
8 changed files with 162 additions and 15 deletions
|
@ -1296,7 +1296,6 @@ pub struct Stmt<'hir> {
|
||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
pub enum StmtKind<'hir> {
|
pub enum StmtKind<'hir> {
|
||||||
/// A local (`let`) binding.
|
/// A local (`let`) binding.
|
||||||
/// FIXME: bundle the last two components into another `struct`
|
|
||||||
Local(&'hir Local<'hir>),
|
Local(&'hir Local<'hir>),
|
||||||
|
|
||||||
/// An item binding.
|
/// An item binding.
|
||||||
|
|
|
@ -1058,9 +1058,9 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) {
|
||||||
|
|
||||||
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
|
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
|
||||||
visitor.visit_id(statement.hir_id);
|
visitor.visit_id(statement.hir_id);
|
||||||
match &statement.kind {
|
match statement.kind {
|
||||||
StmtKind::Local(ref local) => visitor.visit_local(local),
|
StmtKind::Local(ref local) => visitor.visit_local(local),
|
||||||
StmtKind::Item(item) => visitor.visit_nested_item(*item),
|
StmtKind::Item(item) => visitor.visit_nested_item(item),
|
||||||
StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
|
StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
|
||||||
visitor.visit_expr(expression)
|
visitor.visit_expr(expression)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
use crate::infer::type_variable::TypeVariableOriginKind;
|
use crate::infer::type_variable::TypeVariableOriginKind;
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use hir::LocalSource;
|
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local};
|
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
|
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||||
|
|
|
@ -48,7 +48,7 @@ impl<'tcx> Cx<'tcx> {
|
||||||
.filter_map(|(index, stmt)| {
|
.filter_map(|(index, stmt)| {
|
||||||
let hir_id = stmt.hir_id;
|
let hir_id = stmt.hir_id;
|
||||||
let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
|
let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
|
||||||
match &stmt.kind {
|
match stmt.kind {
|
||||||
hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
|
hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
|
||||||
let stmt = Stmt {
|
let stmt = Stmt {
|
||||||
kind: StmtKind::Expr {
|
kind: StmtKind::Expr {
|
||||||
|
@ -66,7 +66,7 @@ impl<'tcx> Cx<'tcx> {
|
||||||
// ignore for purposes of the MIR
|
// ignore for purposes of the MIR
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
hir::StmtKind::Local(local) => {
|
hir::StmtKind::Local(ref local) => {
|
||||||
let remainder_scope = region::Scope {
|
let remainder_scope = region::Scope {
|
||||||
id: block_id,
|
id: block_id,
|
||||||
data: region::ScopeData::Remainder(region::FirstStatementIndex::new(
|
data: region::ScopeData::Remainder(region::FirstStatementIndex::new(
|
||||||
|
|
|
@ -1215,12 +1215,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
|
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
|
||||||
let pat_ty = self.node_ty(decl.pat.hir_id);
|
let pat_ty = self.node_ty(decl.pat.hir_id);
|
||||||
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
|
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
|
||||||
}
|
|
||||||
|
|
||||||
/// Type check a `let` statement.
|
if let Some(blk) = decl.els {
|
||||||
pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
|
|
||||||
self.check_decl(local.into());
|
|
||||||
if let Some(blk) = local.els {
|
|
||||||
let previous_diverges = self.diverges.get();
|
let previous_diverges = self.diverges.get();
|
||||||
let else_ty = self.check_block_with_expected(blk, NoExpectation);
|
let else_ty = self.check_block_with_expected(blk, NoExpectation);
|
||||||
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
|
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
|
||||||
|
@ -1233,6 +1229,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Type check a `let` statement.
|
||||||
|
pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
|
||||||
|
self.check_decl(local.into());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) {
|
pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) {
|
||||||
// Don't do all the complex logic below for `DeclItem`.
|
// Don't do all the complex logic below for `DeclItem`.
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
|
|
|
@ -16,19 +16,20 @@ pub(super) struct Declaration<'a> {
|
||||||
pub ty: Option<&'a hir::Ty<'a>>,
|
pub ty: Option<&'a hir::Ty<'a>>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub init: Option<&'a hir::Expr<'a>>,
|
pub init: Option<&'a hir::Expr<'a>>,
|
||||||
|
pub els: Option<&'a hir::Block<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
|
impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
|
||||||
fn from(local: &'a hir::Local<'a>) -> Self {
|
fn from(local: &'a hir::Local<'a>) -> Self {
|
||||||
let hir::Local { hir_id, pat, ty, span, init, .. } = *local;
|
let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
|
||||||
Declaration { hir_id, pat, ty, span, init }
|
Declaration { hir_id, pat, ty, span, init, els }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
|
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
|
||||||
fn from(let_expr: &'a hir::Let<'a>) -> Self {
|
fn from(let_expr: &'a hir::Let<'a>) -> Self {
|
||||||
let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
|
let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
|
||||||
Declaration { hir_id, pat, ty, span, init: Some(init) }
|
Declaration { hir_id, pat, ty, span, init: Some(init), els: None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
53
src/test/ui/async-await/async-await-let-else.rs
Normal file
53
src/test/ui/async-await/async-await-let-else.rs
Normal file
|
@ -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
|
||||||
|
}
|
94
src/test/ui/async-await/async-await-let-else.stderr
Normal file
94
src/test/ui/async-await/async-await-let-else.stderr
Normal file
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue