Skip to content

Commit efd43b0

Browse files
committed
[CSSimplify] Specialization: Fix a crash when specialized declaration is not generic
Check whether there are any opened generic parameters associated with a declaration and if not, produce a fix which would be later diagnosed as either a warning (in Swift 5 mode) or an error (if it was a concrete type or the compiler is in Swift 6 language mode). Resolves: rdar://135610320
1 parent 854298a commit efd43b0

File tree

2 files changed

+101
-16
lines changed

2 files changed

+101
-16
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13868,6 +13868,23 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1386813868
return genericParams;
1386913869
};
1387013870

13871+
auto fixInvalidSpecialization = [&](ValueDecl *decl) -> SolutionKind {
13872+
if (isa<AbstractFunctionDecl>(decl)) {
13873+
return recordFix(AllowFunctionSpecialization::create(
13874+
*this, decl, getConstraintLocator(locator)))
13875+
? SolutionKind::Error
13876+
: SolutionKind::Solved;
13877+
}
13878+
13879+
// Allow concrete macros to have specializations with just a warning.
13880+
return recordFix(AllowConcreteTypeSpecialization::create(
13881+
*this, type1, decl, getConstraintLocator(locator),
13882+
isa<MacroDecl>(decl) ? FixBehavior::DowngradeToWarning
13883+
: FixBehavior::Error))
13884+
? SolutionKind::Error
13885+
: SolutionKind::Solved;
13886+
};
13887+
1387113888
ValueDecl *decl;
1387213889
SmallVector<OpenedType, 2> openedTypes;
1387313890
if (auto *bound = dyn_cast<TypeAliasType>(type1.getPointer())) {
@@ -13926,6 +13943,12 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1392613943
decl = overloadChoice.getDecl();
1392713944

1392813945
auto openedOverloadTypes = getOpenedTypes(overloadLocator);
13946+
// Attempting to specialize a non-generic declaration.
13947+
if (openedOverloadTypes.empty()) {
13948+
// Note that this is unconditional because the fix is
13949+
// downgraded to a warning in swift language modes < 6.
13950+
return fixInvalidSpecialization(decl);
13951+
}
1392913952

1393013953
auto genericParams = getGenericParams(decl);
1393113954
if (genericParams) {
@@ -13941,22 +13964,8 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1394113964
}
1394213965

1394313966
auto genericParams = getGenericParams(decl);
13944-
if (!decl->getAsGenericContext() || !genericParams) {
13945-
if (isa<AbstractFunctionDecl>(decl)) {
13946-
return recordFix(AllowFunctionSpecialization::create(
13947-
*this, decl, getConstraintLocator(locator)))
13948-
? SolutionKind::Error
13949-
: SolutionKind::Solved;
13950-
}
13951-
13952-
// Allow concrete macros to have specializations with just a warning.
13953-
return recordFix(AllowConcreteTypeSpecialization::create(
13954-
*this, type1, decl, getConstraintLocator(locator),
13955-
isa<MacroDecl>(decl) ? FixBehavior::DowngradeToWarning
13956-
: FixBehavior::Error))
13957-
? SolutionKind::Error
13958-
: SolutionKind::Solved;
13959-
}
13967+
if (!decl->getAsGenericContext() || !genericParams)
13968+
return fixInvalidSpecialization(decl);
1396013969

1396113970
// Map the generic parameters we have over to their opened types.
1396213971
bool hasParameterPack = false;
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: split-file %s %t/src
3+
4+
/// Build the library A
5+
// RUN: %target-swift-frontend -emit-module %t/src/A.swift \
6+
// RUN: -module-name A -swift-version 5 -enable-library-evolution \
7+
// RUN: -emit-module-path %t/A.swiftmodule \
8+
// RUN: -emit-module-interface-path %t/A.swiftinterface
9+
10+
/// Build the library B
11+
// RUN: %target-swift-frontend -emit-module %t/src/B.swift \
12+
// RUN: -module-name B -swift-version 5 -enable-library-evolution \
13+
// RUN: -emit-module-path %t/B.swiftmodule \
14+
// RUN: -emit-module-interface-path %t/B.swiftinterface
15+
16+
// Build the client AB (language mode 5)
17+
// RUN: %target-swift-frontend -emit-module %t/src/ClientAB.swift \
18+
// RUN: -module-name Client -I %t -swift-version 5 \
19+
// RUN: -verify
20+
21+
// Build the client AB (language mode 6)
22+
// RUN: %target-swift-frontend -emit-module %t/src/ClientAB.swift \
23+
// RUN: -module-name Client -I %t -swift-version 6 \
24+
// RUN: -verify
25+
26+
// Build the client BA (language mode 5)
27+
// RUN: %target-swift-frontend -emit-module %t/src/ClientBA.swift \
28+
// RUN: -module-name Client -I %t -swift-version 5 \
29+
// RUN: -verify
30+
31+
// Build the client BA (language mode 6)
32+
// RUN: %target-swift-frontend -emit-module %t/src/ClientBA.swift \
33+
// RUN: -module-name Client -I %t -swift-version 6 \
34+
// RUN: -verify
35+
36+
//--- A.swift
37+
public protocol EventSource {
38+
}
39+
40+
//--- B.swift
41+
public struct Event<T> {
42+
}
43+
44+
public class EventSource<Parameter> {
45+
public var event: Event<Parameter> {
46+
fatalError()
47+
}
48+
49+
public init() {}
50+
}
51+
52+
//--- ClientAB.swift
53+
import B
54+
// Note: import order is important in this case because successful match might
55+
// mean that the other overload is not going to be attempted and we want
56+
// to attempt protocol EventSource always.
57+
import A
58+
59+
func test() {
60+
let test: B.Event<Void>
61+
test = EventSource<Void>().event
62+
print(test)
63+
}
64+
65+
//--- ClientBA.swift
66+
import B
67+
// Note: import order is important in this case because successful match might
68+
// mean that the other overload is not going to be attempted and we want
69+
// to attempt protocol EventSource always.
70+
import A
71+
72+
func test() {
73+
let test: B.Event<Void>
74+
test = EventSource<Void>().event
75+
print(test)
76+
}

0 commit comments

Comments
 (0)