Skip to content

Commit b2854b2

Browse files
committed
[CS] Fix typealias handling in InferableTypeOpener
For non-generic cases we can simply recurse into the underlying type, ensuring we don't crash with a null GenericSignature. For generic cases, ensure we bind outer generic parameters to their archetypes, and apply the substitutions to the original underlying type to ensure we correctly handle cases where e.g an unbound generic is passed as a generic argument to a generic typealias. rdar://160135085
1 parent 20202f5 commit b2854b2

File tree

4 files changed

+58
-22
lines changed

4 files changed

+58
-22
lines changed

include/swift/AST/Types.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2345,7 +2345,11 @@ class TypeAliasType final
23452345

23462346
/// Retrieve the substitution map applied to the declaration's underlying
23472347
/// to produce the described type.
2348-
SubstitutionMap getSubstitutionMap() const;
2348+
///
2349+
/// \param wantContextualType If \c true, the substitution map will bind
2350+
/// outer local generic parameters to archetypes. Otherwise they will be left
2351+
/// unchanged.
2352+
SubstitutionMap getSubstitutionMap(bool wantContextualType = false) const;
23492353

23502354
/// Get the direct generic arguments, which correspond to the generic
23512355
/// arguments that are directly applied to the typealias declaration

lib/AST/Type.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2155,7 +2155,8 @@ GenericSignature TypeAliasType::getGenericSignature() const {
21552155
return typealias->getGenericSignature();
21562156
}
21572157

2158-
SubstitutionMap TypeAliasType::getSubstitutionMap() const {
2158+
SubstitutionMap
2159+
TypeAliasType::getSubstitutionMap(bool wantContextualType) const {
21592160
auto genericSig = typealias->getGenericSignature();
21602161
if (!genericSig)
21612162
return SubstitutionMap();
@@ -2164,8 +2165,14 @@ SubstitutionMap TypeAliasType::getSubstitutionMap() const {
21642165
DeclContext *dc = typealias->getDeclContext();
21652166

21662167
if (dc->isLocalContext()) {
2167-
if (auto parentSig = dc->getGenericSignatureOfContext())
2168-
parentSubMap = parentSig->getIdentitySubstitutionMap();
2168+
if (auto parentSig = dc->getGenericSignatureOfContext()) {
2169+
if (wantContextualType) {
2170+
parentSubMap =
2171+
parentSig.getGenericEnvironment()->getForwardingSubstitutionMap();
2172+
} else {
2173+
parentSubMap = parentSig->getIdentitySubstitutionMap();
2174+
}
2175+
}
21692176
} else if (auto parent = getParent()) {
21702177
parentSubMap = parent->getContextSubstitutionMap(dc);
21712178
}

lib/Sema/TypeOfReference.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,14 +261,30 @@ class InferableTypeOpener final {
261261
}
262262

263263
Type transformTypeAliasType(TypeAliasType *aliasTy) {
264+
auto *TAD = aliasTy->getDecl();
265+
266+
// For a non-generic typealias, we can simply recurse into the underlying
267+
// type. The constraint system doesn't properly handle opened types in
268+
// the underlying type of a typealias (e.g TypeWalker won't visit them),
269+
// so we don't preserve the sugar.
270+
if (!TAD->getGenericSignature())
271+
return transform(aliasTy->getSinglyDesugaredType());
272+
273+
// Otherwise we have a generic typealias, or typealias in a generic context,
274+
// and need to open any requirements introduced. Then we need to
275+
// re-substitute any opened types into the underlying type. Like the
276+
// non-generic codepath we also don't want to preserve sugar.
264277
SmallVector<Type, 4> genericArgs;
265278
for (auto arg : aliasTy->getDirectGenericArgs())
266279
genericArgs.push_back(transform(arg));
267280

268-
auto substTy = TypeAliasType::get(
269-
aliasTy->getDecl(), transform(aliasTy->getParent()), genericArgs,
270-
transform(aliasTy->getSinglyDesugaredType()));
271-
return substTy->getSinglyDesugaredType();
281+
auto parentTy = transform(aliasTy->getParent());
282+
auto subMap = TypeAliasType::get(TAD, parentTy, genericArgs,
283+
aliasTy->getSinglyDesugaredType())
284+
->getSubstitutionMap(/*wantContextualType*/ true);
285+
286+
openGenericTypeRequirements(TAD, subMap);
287+
return transform(TAD->getUnderlyingType().subst(subMap));
272288
}
273289

274290
Type transformErrorType(ErrorType *errTy) {
Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,43 @@
11
// RUN: %target-typecheck-verify-swift
2-
// REQUIRES: rdar160135085
32

4-
struct K<U> {} // expected-note 6{{'U' declared as parameter to type 'K'}}
3+
struct K<U> {}
54
protocol Q {}
5+
struct ConformingType: Q {}
66

77
struct S1<T: Q>: ExpressibleByArrayLiteral { // expected-note 2{{where 'T' = 'K<Int>'}}
88
init(_ x: T) {}
99
init(arrayLiteral: T...) {}
1010
}
1111

12-
typealias R1<T: Q> = S1<T> // expected-note {{where 'T' = 'K<Int>'}} expected-note 2{{where 'T' = 'K<U>'}}
12+
typealias R1<T: Q> = S1<T> // expected-note 2{{where 'T' = 'K<Int>'}}
1313

1414
func foo(_ x: K<Int>) {
1515
let _ = [x] as S1<K> // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
1616
let _ = [x] as R1<K> // expected-error {{generic type alias 'R1' requires that 'K<Int>' conform to 'Q'}}
1717

18-
let _: S1<K> = [x] // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
19-
// FIXME: We ought to be able to infer 'U' here.
20-
let _: R1<K> = [x] // expected-error 2 {{generic type alias 'R1' requires that 'K<U>' conform to 'Q'}}
21-
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
18+
let _: S1<K> = [x] // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
19+
let _: R1<K> = [x] // expected-error {{generic type alias 'R1' requires that 'K<Int>' conform to 'Q'}}
2220
}
2321

2422
protocol P2 {
2523
associatedtype A
2624
}
2725

2826
struct S2<A: Q>: P2 {} // expected-note 3{{where 'A' = 'K<Int>'}}
29-
typealias R2<A: Q> = S2<A> // expected-note 2{{where 'A' = 'K<Int>'}} expected-note 2{{where 'A' = 'K<U>'}}
27+
typealias R2<A: Q> = S2<A> // expected-note 3{{where 'A' = 'K<Int>'}}
3028

3129
// Same as S2, but without the Q requirement.
3230
struct S3<A>: P2 {}
33-
typealias R3<A: Q> = S3<A> // expected-note {{where 'A' = 'K<Int>'}} expected-note {{where 'A' = 'K<U>'}}
31+
typealias R3<A: Q> = S3<A> // expected-note 2{{where 'A' = 'K<Int>'}}
3432

3533
func foo<T: P2>(_ y: T.A.Type) -> T {}
3634
let _ = foo(K<Int>.self) as S2<K> // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
3735
let _ = foo(K<Int>.self) as R2<K> // expected-error {{generic type alias 'R2' requires that 'K<Int>' conform to 'Q'}}
3836
let _ = foo(K<Int>.self) as R3<K> // expected-error {{generic type alias 'R3' requires that 'K<Int>' conform to 'Q'}}
3937

4038
let _: S2<K> = foo(K<Int>.self) // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
41-
// FIXME: We ought to be able to infer 'U' here.
42-
let _: R2<K> = foo(K<Int>.self) // expected-error 2{{generic type alias 'R2' requires that 'K<U>' conform to 'Q'}}
43-
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
44-
let _: R3<K> = foo(K<Int>.self) // expected-error {{generic type alias 'R3' requires that 'K<U>' conform to 'Q'}}
45-
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
39+
let _: R2<K> = foo(K<Int>.self) // expected-error {{generic type alias 'R2' requires that 'K<Int>' conform to 'Q'}}
40+
let _: R3<K> = foo(K<Int>.self) // expected-error {{generic type alias 'R3' requires that 'K<Int>' conform to 'Q'}}
4641

4742
func foo<T: P2>(_ x: T.Type, _ y: T.A.Type) {}
4843
foo(S2<_>.self, K<Int>.self) // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
@@ -53,3 +48,17 @@ struct S4<T: Q> { // expected-note {{where 'T' = 'Int'}}
5348
}
5449

5550
_ = S4<_>(0) // expected-error {{generic struct 'S4' requires that 'Int' conform to 'Q'}}
51+
52+
func testLocalOuterGeneric<T>(_ x: T) {
53+
typealias X<U: Q> = (T, U) // expected-note {{where 'U' = 'String'}}
54+
let _: X<_> = (x, "") // expected-error {{generic type alias 'X' requires that 'String' conform to 'Q'}}
55+
let _: X<_> = (x, ConformingType())
56+
}
57+
58+
struct TestParentGeneric<T> {
59+
typealias X<U: Q> = (T, U) // expected-note {{where 'U' = 'String'}}
60+
func bar(_ x: T) {
61+
let _: X<_> = (x, "") // expected-error {{generic type alias 'X' requires that 'String' conform to 'Q'}}
62+
let _: X<_> = (x, ConformingType())
63+
}
64+
}

0 commit comments

Comments
 (0)