From 2a6cc12a63dc9d34cd260f55e09580968f84cbb5 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 29 Aug 2024 00:11:01 -0700 Subject: [PATCH 1/2] [ConstraintSystem] Downgrade some invalid specialization uses to a warning until Swift 6 language mode Some invalid specializations were previously allowed by the compiler and we found some existing code that used that (albeit invalid) syntax, so we need to stage that error as a warning until Swift 6 language mode to avoid source compatibility break. Resolves: rdar://134740240 --- include/swift/AST/DiagnosticsSema.def | 4 +- include/swift/Sema/CSFix.h | 20 +++++----- lib/Sema/CSDiagnostics.cpp | 5 ++- lib/Sema/CSDiagnostics.h | 10 +++-- lib/Sema/CSFix.cpp | 17 ++++++--- lib/Sema/CSSimplify.cpp | 14 ++++--- test/Parse/generic_disambiguation.swift | 7 +++- test/Sema/generic_specialization.swift | 50 +++++++++++++++++++------ 8 files changed, 85 insertions(+), 42 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ff72ec007f068..8710c077c49ff 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4606,8 +4606,8 @@ NOTE(duplicated_key_declared_here, none, "duplicate key declared here", ()) // Generic specializations -ERROR(cannot_explicitly_specialize_generic_function,none, - "cannot explicitly specialize a generic function", ()) +ERROR(cannot_explicitly_specialize_function,none, + "cannot explicitly specialize a%select{| generic}0 function", (bool)) ERROR(not_a_generic_type,none, "cannot specialize non-generic type %0", (Type)) ERROR(not_a_generic_macro,none, diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 8a113aeddba08..69cd40329e566 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -465,8 +465,8 @@ enum class FixKind : uint8_t { /// Ignore an attempt to specialize a non-generic type. AllowConcreteTypeSpecialization, - /// Ignore an attempt to specialize a generic function. - AllowGenericFunctionSpecialization, + /// Ignore an attempt to specialize a (generic) function reference. + AllowFunctionSpecialization, /// Ignore an out-of-place \c then statement. IgnoreOutOfPlaceThenStmt, @@ -3750,17 +3750,19 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix { } }; -class AllowGenericFunctionSpecialization final : public ConstraintFix { +class AllowFunctionSpecialization final : public ConstraintFix { ValueDecl *Decl; - AllowGenericFunctionSpecialization(ConstraintSystem &cs, ValueDecl *decl, - ConstraintLocator *locator) - : ConstraintFix(cs, FixKind::AllowGenericFunctionSpecialization, locator), + AllowFunctionSpecialization(ConstraintSystem &cs, ValueDecl *decl, + ConstraintLocator *locator, + FixBehavior fixBehavior) + : ConstraintFix(cs, FixKind::AllowFunctionSpecialization, locator, + fixBehavior), Decl(decl) {} public: std::string getName() const override { - return "allow generic function specialization"; + return "allow (generic) function specialization"; } bool diagnose(const Solution &solution, bool asNote = false) const override; @@ -3769,11 +3771,11 @@ class AllowGenericFunctionSpecialization final : public ConstraintFix { return diagnose(*commonFixes.front().first); } - static AllowGenericFunctionSpecialization * + static AllowFunctionSpecialization * create(ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { - return fix->getKind() == FixKind::AllowGenericFunctionSpecialization; + return fix->getKind() == FixKind::AllowFunctionSpecialization; } }; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index fc1beeed7d75f..01648b4c92bad 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -9365,8 +9365,9 @@ bool ConcreteTypeSpecialization::diagnoseAsError() { return true; } -bool GenericFunctionSpecialization::diagnoseAsError() { - emitDiagnostic(diag::cannot_explicitly_specialize_generic_function); +bool InvalidFunctionSpecialization::diagnoseAsError() { + emitDiagnostic(diag::cannot_explicitly_specialize_function, + bool(Decl->getAsGenericContext())); emitDiagnosticAt(Decl, diag::decl_declared_here, Decl); return true; } diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 044b25c6da3fb..7b13d08305d70 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -3133,13 +3133,15 @@ class ConcreteTypeSpecialization final : public FailureDiagnostic { bool diagnoseAsError() override; }; -class GenericFunctionSpecialization final : public FailureDiagnostic { +/// Diagnose attempts to specialize (generic) function references. +class InvalidFunctionSpecialization final : public FailureDiagnostic { ValueDecl *Decl; public: - GenericFunctionSpecialization(const Solution &solution, ValueDecl *decl, - ConstraintLocator *locator) - : FailureDiagnostic(solution, locator), Decl(decl) {} + InvalidFunctionSpecialization(const Solution &solution, ValueDecl *decl, + ConstraintLocator *locator, + FixBehavior fixBehavior) + : FailureDiagnostic(solution, locator, fixBehavior), Decl(decl) {} bool diagnoseAsError() override; }; diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 6dcd552a00ab2..4af8a95d9fbe4 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -2618,16 +2618,21 @@ AllowConcreteTypeSpecialization *AllowConcreteTypeSpecialization::create( cs, concreteTy, decl, locator, fixBehavior); } -bool AllowGenericFunctionSpecialization::diagnose(const Solution &solution, - bool asNote) const { - GenericFunctionSpecialization failure(solution, Decl, getLocator()); +bool AllowFunctionSpecialization::diagnose(const Solution &solution, + bool asNote) const { + InvalidFunctionSpecialization failure(solution, Decl, getLocator(), + fixBehavior); return failure.diagnose(asNote); } -AllowGenericFunctionSpecialization *AllowGenericFunctionSpecialization::create( - ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator) { +AllowFunctionSpecialization * +AllowFunctionSpecialization::create(ConstraintSystem &cs, ValueDecl *decl, + ConstraintLocator *locator) { + auto fixBehavior = cs.getASTContext().isSwiftVersionAtLeast(6) + ? FixBehavior::Error + : FixBehavior::DowngradeToWarning; return new (cs.getAllocator()) - AllowGenericFunctionSpecialization(cs, decl, locator); + AllowFunctionSpecialization(cs, decl, locator, fixBehavior); } bool IgnoreOutOfPlaceThenStmt::diagnose(const Solution &solution, diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 033eb4bc18447..8976ab801c54a 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -14069,6 +14069,13 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint( auto genericParams = getGenericParams(decl); if (!decl->getAsGenericContext() || !genericParams) { + if (isa(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), @@ -14111,10 +14118,7 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint( // FIXME: We could support explicit function specialization. if (openedGenericParams.empty() || (isa(decl) && !hasParameterPack)) { - if (!shouldAttemptFixes()) - return SolutionKind::Error; - - return recordFix(AllowGenericFunctionSpecialization::create( + return recordFix(AllowFunctionSpecialization::create( *this, decl, getConstraintLocator(locator))) ? SolutionKind::Error : SolutionKind::Solved; @@ -15246,7 +15250,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AllowAssociatedValueMismatch: case FixKind::GenericArgumentsMismatch: case FixKind::AllowConcreteTypeSpecialization: - case FixKind::AllowGenericFunctionSpecialization: + case FixKind::AllowFunctionSpecialization: case FixKind::IgnoreGenericSpecializationArityMismatch: case FixKind::IgnoreKeyPathSubscriptIndexMismatch: case FixKind::AllowMemberRefOnExistential: { diff --git a/test/Parse/generic_disambiguation.swift b/test/Parse/generic_disambiguation.swift index b7c5be29e729a..e6cea4ca2896e 100644 --- a/test/Parse/generic_disambiguation.swift +++ b/test/Parse/generic_disambiguation.swift @@ -1,4 +1,5 @@ -// RUN: %target-typecheck-verify-swift +// RUN: %target-typecheck-verify-swift -verify-additional-prefix swift5- +// RUN: %target-typecheck-verify-swift -swift-version 6 -verify-additional-prefix swift6- struct A { // expected-note{{generic type 'A' declared here}} init(x:Int) {} @@ -40,7 +41,9 @@ _ = (a < b, c > d) _ = a>(b) _ = a > (b) -generic(0) // expected-error{{cannot explicitly specialize a generic function}} +generic(0) +// expected-swift5-warning@-1{{cannot explicitly specialize a generic function}} +// expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} A.c() A>.c() diff --git a/test/Sema/generic_specialization.swift b/test/Sema/generic_specialization.swift index d9e16b81ac3ca..f6a33ab84ad8c 100644 --- a/test/Sema/generic_specialization.swift +++ b/test/Sema/generic_specialization.swift @@ -1,7 +1,8 @@ -// RUN: %target-typecheck-verify-swift +// RUN: %target-typecheck-verify-swift -verify-additional-prefix swift5- +// RUN: %target-typecheck-verify-swift -swift-version 6 -verify-additional-prefix swift6- extension Int { - func foo() -> Int {} + func foo() -> Int {} // expected-note 2 {{'foo()' declared here}} var bar: Int { get {} } @@ -14,28 +15,53 @@ extension Int { // https://github.com/swiftlang/swift/issues/74857 func test(i: Int) { - let _ = i.foo() // expected-error {{cannot specialize non-generic type '() -> Int'}} + let _ = i.foo() + // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} + // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} - let _ = i.gen() // expected-error {{cannot explicitly specialize a generic function}} - // expected-error@-1 {{generic parameter 'T' could not be inferred}} + let _ = i.gen() + // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} + // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} + // expected-error@-3 {{generic parameter 'T' could not be inferred}} - let _ = 0.foo() // expected-error {{cannot specialize non-generic type '() -> Int'}} + let _ = 0.foo() + // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} + // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} - let _ = i.gen // expected-error {{cannot explicitly specialize a generic function}} - // expected-error@-1 {{generic parameter 'T' could not be inferred}} - let _ = i.bar // expected-error {{cannot specialize non-generic type 'Int'}} - let _ = 0.bar // expected-error {{cannot specialize non-generic type 'Int'}} + let _ = i.gen + // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} + // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} + // expected-error@-3 {{generic parameter 'T' could not be inferred}} + let _ = i.bar + // expected-swift5-error@-1 {{cannot specialize non-generic type 'Int'}} + // expected-swift6-error@-2 {{cannot specialize non-generic type 'Int'}} + let _ = 0.bar + // expected-swift5-error@-1 {{cannot specialize non-generic type 'Int'}} + // expected-swift6-error@-2 {{cannot specialize non-generic type 'Int'}} } extension Bool { func foo() -> T {} // expected-note {{'foo()' declared here}} } -let _: () -> Bool = false.foo // expected-error {{cannot explicitly specialize a generic function}} +let _: () -> Bool = false.foo +// expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} +// expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} func foo(_ x: Int) { _ = { - _ = x // expected-error {{cannot specialize non-generic type 'Int'}} + _ = x + // expected-swift5-error@-1 {{cannot specialize non-generic type 'Int'}} + // expected-swift6-error@-2 {{cannot specialize non-generic type 'Int'}} } } +do { + struct Test { + init(_: (T) -> Void) {} // expected-note {{'init(_:)' declared here}} + } + + _ = Test.init({ (_: Int) -> Void in }) + // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} + // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} +} From b6fd5fe1baf6745cd81777fc709fe7db2c0cc074 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 29 Aug 2024 00:13:44 -0700 Subject: [PATCH 2/2] [CSDiangostics] Adjust phrasing of invalid specialization diagnostic Instead of "a generic function" which is too abstract and not always correct, let's actually point to a kind of the declaration being referenced. --- include/swift/AST/DiagnosticsSema.def | 2 +- lib/Sema/CSDiagnostics.cpp | 3 +-- test/Parse/generic_disambiguation.swift | 4 ++-- test/Sema/generic_specialization.swift | 24 ++++++++++++------------ 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 8710c077c49ff..3384406f961ba 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4607,7 +4607,7 @@ NOTE(duplicated_key_declared_here, none, // Generic specializations ERROR(cannot_explicitly_specialize_function,none, - "cannot explicitly specialize a%select{| generic}0 function", (bool)) + "cannot explicitly specialize %kind0", (ValueDecl *)) ERROR(not_a_generic_type,none, "cannot specialize non-generic type %0", (Type)) ERROR(not_a_generic_macro,none, diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 01648b4c92bad..c08e7a797bc0c 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -9366,8 +9366,7 @@ bool ConcreteTypeSpecialization::diagnoseAsError() { } bool InvalidFunctionSpecialization::diagnoseAsError() { - emitDiagnostic(diag::cannot_explicitly_specialize_function, - bool(Decl->getAsGenericContext())); + emitDiagnostic(diag::cannot_explicitly_specialize_function, Decl); emitDiagnosticAt(Decl, diag::decl_declared_here, Decl); return true; } diff --git a/test/Parse/generic_disambiguation.swift b/test/Parse/generic_disambiguation.swift index e6cea4ca2896e..bcada136169a0 100644 --- a/test/Parse/generic_disambiguation.swift +++ b/test/Parse/generic_disambiguation.swift @@ -42,8 +42,8 @@ _ = a>(b) _ = a > (b) generic(0) -// expected-swift5-warning@-1{{cannot explicitly specialize a generic function}} -// expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} +// expected-swift5-warning@-1{{cannot explicitly specialize global function 'generic'}} +// expected-swift6-error@-2 {{cannot explicitly specialize global function 'generic'}} A.c() A>.c() diff --git a/test/Sema/generic_specialization.swift b/test/Sema/generic_specialization.swift index f6a33ab84ad8c..dff0dcdde4219 100644 --- a/test/Sema/generic_specialization.swift +++ b/test/Sema/generic_specialization.swift @@ -16,21 +16,21 @@ extension Int { // https://github.com/swiftlang/swift/issues/74857 func test(i: Int) { let _ = i.foo() - // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} - // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} + // expected-swift5-warning@-1 {{cannot explicitly specialize instance method 'foo()'}} + // expected-swift6-error@-2 {{cannot explicitly specialize instance method 'foo()'}} let _ = i.gen() - // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} - // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} + // expected-swift5-warning@-1 {{cannot explicitly specialize instance method 'gen()'}} + // expected-swift6-error@-2 {{cannot explicitly specialize instance method 'gen()'}} // expected-error@-3 {{generic parameter 'T' could not be inferred}} let _ = 0.foo() - // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} - // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} + // expected-swift5-warning@-1 {{cannot explicitly specialize instance method 'foo()'}} + // expected-swift6-error@-2 {{cannot explicitly specialize instance method 'foo()'}} let _ = i.gen - // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} - // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} + // expected-swift5-warning@-1 {{cannot explicitly specialize instance method 'gen()'}} + // expected-swift6-error@-2 {{cannot explicitly specialize instance method 'gen()'}} // expected-error@-3 {{generic parameter 'T' could not be inferred}} let _ = i.bar // expected-swift5-error@-1 {{cannot specialize non-generic type 'Int'}} @@ -45,8 +45,8 @@ extension Bool { } let _: () -> Bool = false.foo -// expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} -// expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} +// expected-swift5-warning@-1 {{cannot explicitly specialize instance method 'foo()'}} +// expected-swift6-error@-2 {{cannot explicitly specialize instance method 'foo()'}} func foo(_ x: Int) { _ = { @@ -62,6 +62,6 @@ do { } _ = Test.init({ (_: Int) -> Void in }) - // expected-swift5-warning@-1 {{cannot explicitly specialize a generic function}} - // expected-swift6-error@-2 {{cannot explicitly specialize a generic function}} + // expected-swift5-warning@-1 {{cannot explicitly specialize initializer 'init(_:)'}} + // expected-swift6-error@-2 {{cannot explicitly specialize initializer 'init(_:)'}} }