Fix: substitute generic type parameters when resolving typealiases#1463
Merged
krzysztofzablocki merged 2 commits intoMay 27, 2026
Conversation
added 2 commits
May 21, 2026 16:44
When a generic typealias (e.g. `typealias Foo<T> = Bar<T, Never>`) is
resolved, the placeholder type parameters from the definition were used
directly in `actualTypeName` without substituting the concrete types
from the usage site. This caused template code accessing
`variable.typeName.actualTypeName.generic.typeParameters` to see the
raw placeholder name (e.g. `Value`) instead of the actual concrete
type (e.g. `[SomeType]?`).
The fix detects when a typealias has generic parameters and maps the
usage-site type arguments to the corresponding placeholder positions
in the typealias RHS, replacing placeholders with concrete types.
Example:
typealias CurrentValuePublisher<Value> = AnyPublisher<Value, Never>
protocol MyPublishing {
var dataPublisher: CurrentValuePublisher<[String]?> { get }
}
Before: actualTypeName.generic.typeParameters[0].typeName = "Value"
After: actualTypeName.generic.typeParameters[0].typeName = "[String]?"
Three test cases covering: - Single placeholder substitution (MyPublisher<[String]?> → Result<[String]?, Never>) - Multiple placeholder substitution (MyResult<String, Error> → Result<String, Error>) - Concrete RHS types not substituted (Never remains Never when it exists in type map)
bf3a6ed
into
krzysztofzablocki:master
1 of 2 checks passed
Owner
|
thank you! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a generic typealias (e.g.
typealias Foo<T> = Bar<T, Never>) is resolved, the placeholder type parameters from the definition were used directly inactualTypeNamewithout substituting the concrete types from the usage site. This caused template code accessingvariable.typeName.actualTypeName.generic.typeParametersto see the raw placeholder name (e.g.Value) instead of the actual concrete type (e.g.[String]?).Fixes #1462
Reproduction
Before:
actualTypeName.generic.typeParameters[0].typeName = ValueAfter:
actualTypeName.generic.typeParameters[0].typeName = [String]?Difference from #1326
Issue #1326 (fixed by PR #1327) addressed method-level generic type parameters being incorrectly replaced by unrelated global typealiases. That fix added a guard to skip substitution when the type parameter name matches a method's own generic parameter.
This issue is about typealias-level generic parameter forward substitution — an orthogonal code path in
actualTypeName(for:containingType:)that was never handled.Changes
ParserResultsComposed.swift— InactualTypeName(for:containingType:):Never)TypeNameComposerSpec.swift— 3 new test cases:MyPublisher<[String]?>→Result<[String]?, Never>)MyResult<String, Error>→Result<String, Error>)NeverremainsNeverwhen it exists in the type map)Test Results
ComposerSpec.swift