Skip to content

Construct AutoClosureExpr With Deeper Parent Contexts #38244

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

Merged
merged 1 commit into from
Jul 6, 2021

Conversation

CodaFi
Copy link
Contributor

@CodaFi CodaFi commented Jul 3, 2021

AutoClosureExprs created by the constraint system used to be constructed
with the decl context of the constraint system itself. This meant that
autoclosures in expressions nested in closures would initially be
parented onto any enclosing functions rather than the deepest closure
context. When we ran capture analysis and lookup from inside of the body
of these nascent values, we would fail to find declarations brought into
scope by those parent closures. This is especially relevant when
pre-typechecked code is involved since captures for those declarations
will be forced before their bodies have been recontextualized. See
issue #34230 for why we need to force things so early.

The attached test case demonstrates both bugs: The former a bogus lookup
through the parent context that would incorrectly reject this otherwise
well-formed code. The latter is a crash in SILGen when the capture
computation would fail to note $0.

Use the decl context of the solution application target, which is always
going to be the deepest user-written closure expression available to us,
and therefore the deepest scope that can introduce capturable variables.

rdar://79248469

@CodaFi CodaFi requested a review from slavapestov July 3, 2021 00:01
@CodaFi
Copy link
Contributor Author

CodaFi commented Jul 3, 2021

Definitely not happy with this. But it's not the worst solution.

@CodaFi
Copy link
Contributor Author

CodaFi commented Jul 3, 2021

@swift-ci smoke test

Copy link
Contributor

@slavapestov slavapestov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable to me, maybe @hborla wants to take a look.

func foo() -> Int {
// Make sure the decl context for the autoclosure passed to ?? is deep
// enough that it can 'see' the capture of $0 from the outer closure.
lazy var nest: (Int) -> Int = { Optional<Int>.none ?? $0 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you FileCheck the SIL function definitions to ensure they have capture arguments too, just in case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Followed the other tests and checked the AST dump. The SILGen test is now being used to make sure we don't crash.

@slavapestov
Copy link
Contributor

“ Definitely not happy with this.” Why not?

@CodaFi
Copy link
Contributor Author

CodaFi commented Jul 3, 2021

It relies on the structure of the AST - in a reasonable way but it’s a dependency nonetheless. I’d really like for capture computation to be more request-like but there’s structural barriers to that. In particular, it’d be nice if typechecked ASTs were always correctly constructed so we could ditch recontextualization…

AutoClosureExprs created by the constraint system used to be constructed
with the decl context of the constraint system itself. This meant that
autoclosures in expressions nested in closures would initially be
parented onto any enclosing functions rather than the deepest closure
context. When we ran capture analysis and lookup from inside of the body
of these nascent values, we would fail to find declarations brought into
scope by those parent closures. This is especially relevant when
pre-typechecked code is involved since captures for those declarations
will be forced before their bodies have been recontextualized. See
issue swiftlang#34230 for why we need to force things so early.

The attached test case demonstrates both bugs: The former a bogus lookup
through the parent context that would incorrectly reject this otherwise
well-formed code. The latter is a crash in SILGen when the capture
computation would fail to note $0.

Use the decl context of the solution application target, which is always
going to be the deepest user-written closure expression available to us,
and therefore the deepest scope that can introduce capturable variables.

rdar://79248469
@CodaFi
Copy link
Contributor Author

CodaFi commented Jul 6, 2021

@swift-ci smoke test and merge

@swift-ci swift-ci merged commit 830d3db into swiftlang:main Jul 6, 2021
@CodaFi CodaFi deleted the klozura branch July 6, 2021 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants