[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
This commit is contained in:
Pavel Yaskevich
2024-09-10 21:06:55 -07:00
parent 854298ab3b
commit efd43b0f7d
2 changed files with 101 additions and 16 deletions

View File

@@ -13868,6 +13868,23 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
return genericParams;
};
auto fixInvalidSpecialization = [&](ValueDecl *decl) -> SolutionKind {
if (isa<AbstractFunctionDecl>(decl)) {
return recordFix(AllowFunctionSpecialization::create(
*this, decl, getConstraintLocator(locator)))
? SolutionKind::Error
: SolutionKind::Solved;
}
// Allow concrete macros to have specializations with just a warning.
return recordFix(AllowConcreteTypeSpecialization::create(
*this, type1, decl, getConstraintLocator(locator),
isa<MacroDecl>(decl) ? FixBehavior::DowngradeToWarning
: FixBehavior::Error))
? SolutionKind::Error
: SolutionKind::Solved;
};
ValueDecl *decl;
SmallVector<OpenedType, 2> openedTypes;
if (auto *bound = dyn_cast<TypeAliasType>(type1.getPointer())) {
@@ -13926,6 +13943,12 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
decl = overloadChoice.getDecl();
auto openedOverloadTypes = getOpenedTypes(overloadLocator);
// Attempting to specialize a non-generic declaration.
if (openedOverloadTypes.empty()) {
// Note that this is unconditional because the fix is
// downgraded to a warning in swift language modes < 6.
return fixInvalidSpecialization(decl);
}
auto genericParams = getGenericParams(decl);
if (genericParams) {
@@ -13941,22 +13964,8 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
}
auto genericParams = getGenericParams(decl);
if (!decl->getAsGenericContext() || !genericParams) {
if (isa<AbstractFunctionDecl>(decl)) {
return recordFix(AllowFunctionSpecialization::create(
*this, decl, getConstraintLocator(locator)))
? SolutionKind::Error
: SolutionKind::Solved;
}
// Allow concrete macros to have specializations with just a warning.
return recordFix(AllowConcreteTypeSpecialization::create(
*this, type1, decl, getConstraintLocator(locator),
isa<MacroDecl>(decl) ? FixBehavior::DowngradeToWarning
: FixBehavior::Error))
? SolutionKind::Error
: SolutionKind::Solved;
}
if (!decl->getAsGenericContext() || !genericParams)
return fixInvalidSpecialization(decl);
// Map the generic parameters we have over to their opened types.
bool hasParameterPack = false;

View File

@@ -0,0 +1,76 @@
// RUN: %empty-directory(%t/src)
// RUN: split-file %s %t/src
/// Build the library A
// RUN: %target-swift-frontend -emit-module %t/src/A.swift \
// RUN: -module-name A -swift-version 5 -enable-library-evolution \
// RUN: -emit-module-path %t/A.swiftmodule \
// RUN: -emit-module-interface-path %t/A.swiftinterface
/// Build the library B
// RUN: %target-swift-frontend -emit-module %t/src/B.swift \
// RUN: -module-name B -swift-version 5 -enable-library-evolution \
// RUN: -emit-module-path %t/B.swiftmodule \
// RUN: -emit-module-interface-path %t/B.swiftinterface
// Build the client AB (language mode 5)
// RUN: %target-swift-frontend -emit-module %t/src/ClientAB.swift \
// RUN: -module-name Client -I %t -swift-version 5 \
// RUN: -verify
// Build the client AB (language mode 6)
// RUN: %target-swift-frontend -emit-module %t/src/ClientAB.swift \
// RUN: -module-name Client -I %t -swift-version 6 \
// RUN: -verify
// Build the client BA (language mode 5)
// RUN: %target-swift-frontend -emit-module %t/src/ClientBA.swift \
// RUN: -module-name Client -I %t -swift-version 5 \
// RUN: -verify
// Build the client BA (language mode 6)
// RUN: %target-swift-frontend -emit-module %t/src/ClientBA.swift \
// RUN: -module-name Client -I %t -swift-version 6 \
// RUN: -verify
//--- A.swift
public protocol EventSource {
}
//--- B.swift
public struct Event<T> {
}
public class EventSource<Parameter> {
public var event: Event<Parameter> {
fatalError()
}
public init() {}
}
//--- ClientAB.swift
import B
// Note: import order is important in this case because successful match might
// mean that the other overload is not going to be attempted and we want
// to attempt protocol EventSource always.
import A
func test() {
let test: B.Event<Void>
test = EventSource<Void>().event
print(test)
}
//--- ClientBA.swift
import B
// Note: import order is important in this case because successful match might
// mean that the other overload is not going to be attempted and we want
// to attempt protocol EventSource always.
import A
func test() {
let test: B.Event<Void>
test = EventSource<Void>().event
print(test)
}