diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ff72ec007f0..8710c077c49 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 8a113aeddba..69cd40329e5 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 @@ public: } }; -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 @@ public: 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 fc1beeed7d7..01648b4c92b 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 044b25c6da3..7b13d08305d 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -3133,13 +3133,15 @@ public: 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 6dcd552a00a..4af8a95d9fb 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 033eb4bc184..8976ab801c5 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 b7c5be29e72..e6cea4ca289 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 d9e16b81ac3..f6a33ab84ad 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}} +}