Skip to content

Conversation

@slavapestov
Copy link
Contributor

Today, we open the type of an overload after we make the decision to bind it. The opening generates new type variables and constraints from the overload's generic signature. This results in exponential space usage in the solver arena when exploring a large search space, because we also form other structures such as function types, substitution maps, etc that involve these new type variables, but we never re-use those type variables or the structures built up from them after we backtrack. (We also don't incrementally roll back the solver arena when we backtrack, because that would require trail-recording changes to all the folding sets in the AST, which would probably not be worth the overhead.)

Instead, we're going to open the overload type when forming the disjunction, at scope N; this will generate new type variables and constraints without actually introducing them into the constraint system, and also build the opened type. The opened type, together with the type variables and constraints, will be stored in a PreparedOverloadChoice. When we attempt the disjunction, we will create scope N+1, and then introduce the prepared type variables and constraints.

This increases overhead in the case that some choices in a disjunction are never explored, because then we build the opened type and never use it. But it will pay off -- exponentially -- for expressions involving operators and other global overloads that are looked up at the outermost decision level, but are then repeatedly bound with different other combinations as we search.

This also won't help with member overloads as much, like foo.bar.baz, because the qualified lookups happen in nested decision levels, so we may still re-generate new opened types and type variables.

Preserving the "identity" of the type variables and constraints associated with an overload choice while we explore different parts of the search space should also help us implement non-chronological backtracking.

@slavapestov slavapestov marked this pull request as draft July 9, 2025 19:01
@slavapestov slavapestov force-pushed the prepared-overloads branch from 04ad48b to 751edee Compare July 9, 2025 19:01
@slavapestov
Copy link
Contributor Author

@swift-ci Please smoke test

@slavapestov
Copy link
Contributor Author

@swift-ci Please test source compatibility

@slavapestov slavapestov changed the title Sema: Opening overloads at the outer decision level Sema: Opening overloads at the outer decision level, part 1 Jul 9, 2025
@slavapestov slavapestov marked this pull request as ready for review July 10, 2025 02:14
@slavapestov
Copy link
Contributor Author

This is just a preliminary refactoring, and I'll have more cleanups shortly.

@slavapestov slavapestov merged commit cdbbe7a into swiftlang:main Jul 10, 2025
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