Skip to content

Commit

Permalink
Fix expression tree nesting with await bug
Browse files Browse the repository at this point in the history
Summary:
The lowerer introduces lambdas to allow lists of statements in expression trees, e.g. ``ExampleDsl`{$x = 1; $y = 2;}` `` lowers to ``ExampleDsl`(() ==> {$x = 1; $y = 2;})()` `` before desugaring. This is an expression tree lambda, not a Hack lambda, and thus processing it shouldn't interfere with the code looking for awaits and yields should they appear in splices, nor should we forget if we are in an enclosing async Hack function. However, the call to `reset_for_function_body` was doing exactly that.

Improve error message if a yield appears in an expression tree

Reviewed By: andrewjkennedy

Differential Revision: D66822415

fbshipit-source-id: 1b89af3ab838473c51d641331fdce73bdab010a4
  • Loading branch information
Scott Owens authored and facebook-github-bot committed Dec 6, 2024
1 parent 54551f8 commit fa0ef51
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 7 deletions.
5 changes: 5 additions & 0 deletions hphp/hack/src/parser/lowerer/desugar_expression_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1609,6 +1609,11 @@ impl RewriteState {
));
unchanged_result
}
Yield(_) => {
self.errors
.push((pos, "`yield` is not supported in expression trees.".into()));
unchanged_result
}
_ => {
self.errors
.push((pos, "Unsupported expression tree syntax.".into()));
Expand Down
7 changes: 3 additions & 4 deletions hphp/hack/src/parser/lowerer/lowerer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ pub struct Env<'a> {
pub empty_ns_env: Arc<NamespaceEnv>,

// Whether we have encountered an yield expression
pub found_yield: bool,
found_yield: bool,
// Whether we have encountered an await expression
found_await: bool,
// Whether we are in the body of an async function
Expand Down Expand Up @@ -2377,8 +2377,7 @@ fn p_prefixed_code_expr<'a>(
let pos = p_pos(&c.body, env);
let suspension_kind = SuspensionKind::SKSync;
// Take the body and create a no argument lambda expression
let (body, yield_) =
env.reset_for_function_body(&c.body, suspension_kind, p_function_body)?;
let body = p_function_body(&c.body, env)?;
let external = c.body.is_external();
let fun = ast::Fun_ {
span: pos.clone(),
Expand All @@ -2387,7 +2386,7 @@ fn p_prefixed_code_expr<'a>(
readonly_ret: None,
ret: ast::TypeHint((), None),
body: ast::FuncBody { fb_ast: body },
fun_kind: mk_fun_kind(suspension_kind, yield_),
fun_kind: mk_fun_kind(suspension_kind, false),
params: vec![],
ctxs: None,
unsafe_ctxs: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Internal error: Return type is not a generator (Other[0000])
ERROR: File "async_generator.php", line 6, characters 14-38:
Expression trees only support simple lambdas, without features like `async`, generators or capabilities. (Parsing[1002])
ERROR: File "async_generator.php", line 6, characters 29-35:
Unsupported expression tree syntax. (Parsing[1002])
`yield` is not supported in expression trees. (Parsing[1002])
ERROR: File "async_generator.php", line 6, characters 14-38:
You cannot return a value in a generator (a generator is a function that uses `yield`) (NastCheck[3019])
ERROR: File "async_generator.php", line 6, characters 14-38:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Internal error: Return type is not a generator (Other[0000])
ERROR: File "generator.php", line 6, characters 14-32:
Expression trees only support simple lambdas, without features like `async`, generators or capabilities. (Parsing[1002])
ERROR: File "generator.php", line 6, characters 23-29:
Unsupported expression tree syntax. (Parsing[1002])
`yield` is not supported in expression trees. (Parsing[1002])
ERROR: File "generator.php", line 6, characters 14-32:
You cannot return a value in a generator (a generator is a function that uses `yield`) (NastCheck[3019])
ERROR: File "generator.php", line 6, characters 14-32:
Expand Down
33 changes: 33 additions & 0 deletions hphp/hack/test/typecheck/expression_trees/nesting/await.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?hh
<<file: __EnableUnstableFeatures('expression_trees')>>

async function g(): Awaitable<ExampleDslExpression<ExampleInt>> {
return ExampleDsl`1`;
}

async function f(): Awaitable<void> {
ExampleDsl`${ExampleDsl`${await g()}`}`;
ExampleDsl`{
${await g()};
}`;
ExampleDsl`${
ExampleDsl`{
1;
${await g()};
}`
}`;
ExampleDsl`{
${ExampleDsl`${await g()}`};
}`;
ExampleDsl`{
${await g()};
${ExampleDsl`${await g()}`};
}`;
ExampleDsl`{
${
ExampleDsl`{
${await g()};
}`
};
}`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No errors
2 changes: 1 addition & 1 deletion hphp/test/slow/expression_trees/blocks_yield.php.expectf
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Fatal error: Expression trees only support simple lambdas, without features like `async`, generators or capabilities. in %s/blocks_yield.php on line 14
Fatal error: `yield` is not supported in expression trees. in %s/blocks_yield.php on line 12

0 comments on commit fa0ef51

Please sign in to comment.