From 4b353882673e2cc7b1a91a35075914d169e6114c Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 29 Sep 2021 10:40:07 -0700 Subject: [PATCH 1/5] Document auto trait inference for async blocks We are in the process of changing this (rust-lang/#69663), but it would be good to document the existing rules before changing them. This should also help explain the compilation errors people are getting in the meantime. --- src/expressions/block-expr.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index a68b27e56..49af0f83d 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -117,6 +117,24 @@ loop { } ``` +### Auto traits and `async` blocks + +Auto trait inference for `async` blocks follow the same [rules as closures] except that [temporary values that are in scope][temporary-scopes] at an `await` expression are also considered. For example, consider the following block: + +```rust +#fn bar() -> i32 { 42 } +#async fn foo() {} +async { + match bar() { + _ => foo().await, + } +} +#; +``` + +Here the result of `bar()` is in scope during the await of `foo()`, so the result of `bar()` will impact the inferred auto traits. +If `bar()` is not `Send`, then the future for the whole match block will also not be `Send`. + ## `unsafe` blocks > **Syntax**\ @@ -189,3 +207,5 @@ fn is_unix_platform() -> bool { [tuple expressions]: tuple-expr.md [unsafe operations]: ../unsafety.md [value expressions]: ../expressions.md#place-expressions-and-value-expressions +[rules as closures]: ../special-types-and-traits.md#auto-traits +[temporary-scopes]: ../destructors.md#temporary-scopes From 00fce4a28636d9f4b68836d8574b65696347b21d Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 29 Sep 2021 11:26:56 -0700 Subject: [PATCH 2/5] Fix tests --- src/expressions/block-expr.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index 49af0f83d..8fbbce18a 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -122,14 +122,14 @@ loop { Auto trait inference for `async` blocks follow the same [rules as closures] except that [temporary values that are in scope][temporary-scopes] at an `await` expression are also considered. For example, consider the following block: ```rust -#fn bar() -> i32 { 42 } -#async fn foo() {} +# fn bar() -> i32 { 42 } +# async fn foo() {} async { match bar() { _ => foo().await, } } -#; +# ; ``` Here the result of `bar()` is in scope during the await of `foo()`, so the result of `bar()` will impact the inferred auto traits. From 89a6f57e02bac577c19bc9d922c9d0be00dc546d Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 30 Aug 2021 13:57:55 -0700 Subject: [PATCH 3/5] Add description of auto traits in async blocks This documents the proposed liveness-based rules for inferring auto traits for async block. Currently we use a scope-based approach, so this also serves as a description of we would like to change. --- src/expressions/block-expr.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index 8fbbce18a..8851dc9b2 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -119,21 +119,23 @@ loop { ### Auto traits and `async` blocks -Auto trait inference for `async` blocks follow the same [rules as closures] except that [temporary values that are in scope][temporary-scopes] at an `await` expression are also considered. For example, consider the following block: - +Auto trait inference for `async` blocks follow the same [rules as closures] except that values that are live across an `await` expression are also considered. +Live values are variables or temporaries that are defined before an `await` expression and potentially used afterwards. +As an example, see below: ```rust -# fn bar() -> i32 { 42 } # async fn foo() {} async { - match bar() { - _ => foo().await, - } + let x = Bar; + foo().await + drop(x); } # ; ``` +Here the resulting future will be `Send` if `Bar` is send, since `x` is defined before the await and used afterwards. + +Note that for values of types that implement `Drop`, there is an implicit use of the value at the end of its lifetime in order to run the destructor. -Here the result of `bar()` is in scope during the await of `foo()`, so the result of `bar()` will impact the inferred auto traits. -If `bar()` is not `Send`, then the future for the whole match block will also not be `Send`. +Besides named variables, temporary values also count. For example in `foo(&bar, baz.await)`, the value `&bar` is considered live across the `await` point. This is also true of the scrutinee of the match expression, since [the scrutinee is live for the entire match block][temporary-scopes]. ## `unsafe` blocks From c91c1265fca94346b6b7a1135c8cc51570d405a1 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 31 Aug 2021 14:17:11 -0700 Subject: [PATCH 4/5] More precise wording around temporaries --- src/expressions/block-expr.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index 8851dc9b2..95b2d1d55 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -135,7 +135,9 @@ Here the resulting future will be `Send` if `Bar` is send, since `x` is defined Note that for values of types that implement `Drop`, there is an implicit use of the value at the end of its lifetime in order to run the destructor. -Besides named variables, temporary values also count. For example in `foo(&bar, baz.await)`, the value `&bar` is considered live across the `await` point. This is also true of the scrutinee of the match expression, since [the scrutinee is live for the entire match block][temporary-scopes]. +Besides named variables, temporary values also affect auto trait inference. +For example in `foo(&bar, baz.await)`, the value `&bar` is considered live across the `await` point. +This is also true of the scrutinee of the match expression, since [the scrutinee is live for the entire match block][temporary-scopes]. ## `unsafe` blocks From 6b72eef820f6740ec41a287b5839872343ad5917 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 29 Sep 2021 13:31:45 -0700 Subject: [PATCH 5/5] Fix test and update wording --- src/expressions/block-expr.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index 95b2d1d55..2d660a062 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -123,15 +123,17 @@ Auto trait inference for `async` blocks follow the same [rules as closures] exce Live values are variables or temporaries that are defined before an `await` expression and potentially used afterwards. As an example, see below: ```rust +# struct Bar; # async fn foo() {} async { let x = Bar; - foo().await + foo().await; drop(x); } # ; ``` Here the resulting future will be `Send` if `Bar` is send, since `x` is defined before the await and used afterwards. +If the `drop(x)` line were removed, then `x` would not be considered in auto trait inference because it is not live across the await point. Note that for values of types that implement `Drop`, there is an implicit use of the value at the end of its lifetime in order to run the destructor.