Skip to content

Commit 44efcb3

Browse files
authored
Merge pull request #84460 from hamishknight/open-and-shut
[CS] Fix typealias handling in InferableTypeOpener
2 parents 05dcc6b + b2854b2 commit 44efcb3

File tree

8 files changed

+112
-23
lines changed

8 files changed

+112
-23
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 & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,16 +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-
openGenericTypeRequirements(substTy->getDecl(),
272-
substTy->getSubstitutionMap());
273-
return substTy;
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));
274288
}
275289

276290
Type transformErrorType(ErrorType *errTy) {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %empty-directory(%t/modules)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/modules/A.swiftmodule -module-name A %t/a.swift
5+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/modules/B.swiftmodule -module-name B -I %t/modules %t/b.swift
6+
// RUN: %target-swift-frontend -typecheck -I %t/modules %t/c.swift
7+
8+
//--- a.swift
9+
10+
public struct S<T> {
11+
public init(_ x: T) {}
12+
}
13+
14+
//--- b.swift
15+
16+
import A
17+
public typealias S = A.S
18+
19+
//--- c.swift
20+
21+
import A
22+
import B
23+
24+
_ = S(0)
Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,43 @@
11
// RUN: %target-typecheck-verify-swift
22

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

67
struct S1<T: Q>: ExpressibleByArrayLiteral { // expected-note 2{{where 'T' = 'K<Int>'}}
78
init(_ x: T) {}
89
init(arrayLiteral: T...) {}
910
}
1011

11-
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>'}}
1213

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

17-
let _: S1<K> = [x] // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
18-
// FIXME: We ought to be able to infer 'U' here.
19-
let _: R1<K> = [x] // expected-error 2 {{generic type alias 'R1' requires that 'K<U>' conform to 'Q'}}
20-
// 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'}}
2120
}
2221

2322
protocol P2 {
2423
associatedtype A
2524
}
2625

2726
struct S2<A: Q>: P2 {} // expected-note 3{{where 'A' = 'K<Int>'}}
28-
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>'}}
2928

3029
// Same as S2, but without the Q requirement.
3130
struct S3<A>: P2 {}
32-
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>'}}
3332

3433
func foo<T: P2>(_ y: T.A.Type) -> T {}
3534
let _ = foo(K<Int>.self) as S2<K> // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
3635
let _ = foo(K<Int>.self) as R2<K> // expected-error {{generic type alias 'R2' requires that 'K<Int>' conform to 'Q'}}
3736
let _ = foo(K<Int>.self) as R3<K> // expected-error {{generic type alias 'R3' requires that 'K<Int>' conform to 'Q'}}
3837

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

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

5450
_ = 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+
}

test/decl/typealias/generic.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,3 +465,19 @@ func testSugar(_ gx: GX<Int>, _ gy: GX<Int>.GY<Double>, gz: GX<Int>.GY<Double>.E
465465
let i2: Int = gy // expected-error{{cannot convert value of type 'GX<Int>.GY<Double>' (aka 'Array<Double>') to specified type 'Int'}}
466466
let i3: Int = gz // expected-error{{cannot convert value of type 'GX<Int>.GY<Double>.Element' (aka 'Double') to specified type 'Int'}}
467467
}
468+
469+
func testLocalRequirementInference<T>(_ x: T, y: Int, s: S) {
470+
typealias X<U: P> = (T, U) where T == U.A
471+
func foo<V>(_ x: X<V>) {} // expected-note {{where 'V' = 'Int'}} expected-note {{where 'T' = 'T', 'V.A' = 'S.A' (aka 'Float')}}
472+
foo((x, y)) // expected-error {{local function 'foo' requires that 'Int' conform to 'P'}}
473+
foo((x, s)) // expected-error {{local function 'foo' requires the types 'T' and 'S.A' (aka 'Float') be equivalent}}
474+
}
475+
476+
struct TestNestedRequirementInference<T> {
477+
typealias X<U: P> = (T, U) where T == U.A
478+
func foo<V>(_ x: X<V>) {} // expected-note {{where 'V' = 'Int'}} expected-note {{where 'T' = 'T', 'V.A' = 'S.A' (aka 'Float')}}
479+
func bar(_ x: T, y: Int, s: S) {
480+
foo((x, y)) // expected-error {{instance method 'foo' requires that 'Int' conform to 'P'}}
481+
foo((x, s)) // expected-error {{instance method 'foo' requires the types 'T' and 'S.A' (aka 'Float') be equivalent}}
482+
}
483+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// {"kind":"typecheck","signature":"swift::constraints::ConstraintSystem::openGenericParameters(swift::DeclContext*, swift::GenericSignature, llvm::SmallVectorImpl<std::__1::pair<swift::GenericTypeParamType*, swift::TypeVariableType*>>&, swift::constraints::ConstraintLocatorBuilder, swift::constraints::PreparedOverloadBuilder*)","signatureAssert":"Assertion failed: (sig), function openGenericParameters"}
2+
// RUN: not %target-swift-frontend -typecheck %s
3+
class a<b
4+
func c -> d
5+
typealias c : a
6+
c
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// {"kind":"typecheck","original":"0df5dc82","signature":"swift::constraints::ConstraintSystem::typeVarOccursInType(swift::TypeVariableType*, swift::Type, bool*)","signatureAssert":"Assertion failed: ((!typeVariables.empty() || hasError()) && \"Did not find type variables!\"), function getTypeVariables"}
2+
// RUN: not %target-swift-frontend -typecheck %s
3+
struct a<each b {
4+
typealias d<c> = (
5+
> func 1 {
6+
typealias e = f
7+
e
8+
typealias e = d

0 commit comments

Comments
 (0)