Skip to content

Sema: Improve the infinite opaque return type check #83141

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 10 commits into from
Jul 19, 2025

Conversation

slavapestov
Copy link
Contributor

@slavapestov slavapestov commented Jul 17, 2025

The underlying type of an opaque return type may refer to other opaque return types, and their underlying types may refer to other opaque return types, and so on.

In a valid program, replacing each one with its underlying type must eventually terminate. We had a couple of places where we check for recursion; once in MiscDiagnostics when we try to catch this in Sema, and in another spot where would silently bail out without reporting anything, which could then cause a runtime crash in the user's program.

The old check did not catch all cases, and it replaced an earlier check that was too conservative. This termination problem is undecidable in general, so we can't actually "catch" the cycle by analyzing the problem instance.

Instead, replace both checks with a simpler one based on a counter. This diagnoses more cases that were not caught before in Sema. It is still possible to construct something where the recursion is only apparent after SIL optimization, in which case we now assert, instead of crashing with a stack overflow.

Eventually, I'd like to always diagnose something, even if we're in the SIL optimizer.

Fixes rdar://82992151.

@slavapestov slavapestov requested review from hborla and xedin as code owners July 17, 2025 18:17
@slavapestov slavapestov force-pushed the fix-rdar82992151 branch 2 times, most recently from 5dbcd18 to 9a5811c Compare July 18, 2025 15:13
release/6.2 chokes on this file. Nice work @xedin :)
…transformRec()

The semantics of SubstFlags::SubstituteOpaqueArchetypes are changing
so this is no longer useful here.
…lying types

Tracking seen declarations and substitution maps only detects the
situation where the opaque type's underlying type contains itself
with the same substitution map. However, it is also possible to
recurse with a different substitution map.

In general termination is undecidable with a problem like this,
so instead of trying to catch cycles, just impose a termination
limit.

This converts a stack overflow into an assertion, which is still
not ideal; we should really diagnose something instead. But this
is a first step.
Now look through other opaque return types that appear in the
underlying type. This catches various forms of recursion that
otherwise would cause a SILGen or SILOptimizer crash.

- Fixes rdar://82992151.
A substitution map contains conformances, and a conformance can contain
a substitution map. This will always be a DAG, but not a tree, and to
avoid exponential blowup in certain edge cases, let's cache the work to
avoid visiting the same substitution map repeatedly, if multiple
conformances refer to the same substitution map.
Now that we cache substituted substitution maps inside the
InFlightSubstitution, we can re-enable this.
@slavapestov
Copy link
Contributor Author

@swift-ci Please smoke test

@slavapestov
Copy link
Contributor Author

@swift-ci Please test source compatibility

@slavapestov slavapestov merged commit bb4f61e into swiftlang:main Jul 19, 2025
3 of 5 checks passed
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.

1 participant