From 1781faba1aa35bf0ebd7b50e9b4639502bcba304 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 29 Oct 2025 15:14:23 +0000 Subject: [PATCH] [CS] Upgrade tuple label mismatch warning to error for future lang mode I missed upgrading this to an error for Swift 6 mode, let's upgrade it to an error for a future language mode. It's important we reject these cases since we're otherwise allowing subtyping to be a weaker constraint than conversion. --- include/swift/AST/DiagnosticsSema.def | 6 ++-- include/swift/Sema/CSFix.h | 3 +- lib/Sema/CSDiagnostics.cpp | 5 +-- lib/Sema/CSDiagnostics.h | 3 +- test/Constraints/tuple.swift | 21 ------------ .../tuple_subtype_label_mismatch.swift | 33 +++++++++++++++++++ 6 files changed, 43 insertions(+), 28 deletions(-) create mode 100644 test/Constraints/tuple_subtype_label_mismatch.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 87d6440a32e..b5466173068 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1586,9 +1586,9 @@ WARNING(coercion_may_fail_warning,none, "coercion from %0 to %1 may fail; use 'as?' or 'as!' instead", (Type, Type)) -WARNING(tuple_label_mismatch_warning,none, - "tuple conversion from %0 to %1 mismatches labels", - (Type, Type)) +ERROR(tuple_label_mismatch,none, + "tuple conversion from %0 to %1 mismatches labels", + (Type, Type)) ERROR(missing_explicit_conversion,none, "%0 is not implicitly convertible to %1; " diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 0955ec98688..e347c4a6877 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -3458,7 +3458,8 @@ public: } }; -/// Emit a warning for mismatched tuple labels. +/// Emit a warning for mismatched tuple labels, which is upgraded to an error +/// for a future language mode. class AllowTupleLabelMismatch final : public ContextualMismatch { AllowTupleLabelMismatch(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 78498d1ec96..975b57d9125 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -9419,8 +9419,9 @@ bool InvalidWeakAttributeUse::diagnoseAsError() { } bool TupleLabelMismatchWarning::diagnoseAsError() { - emitDiagnostic(diag::tuple_label_mismatch_warning, getFromType(), getToType()) - .highlight(getSourceRange()); + emitDiagnostic(diag::tuple_label_mismatch, getFromType(), getToType()) + .highlight(getSourceRange()) + .warnUntilFutureSwiftVersion(); return true; } diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index b1816b51d2b..f25f798aded 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -3009,7 +3009,8 @@ public: bool diagnoseAsError() override; }; -/// Emit a warning for mismatched tuple labels. +/// Emit a warning for mismatched tuple labels, which is upgraded to an error +/// for a future language mode. class TupleLabelMismatchWarning final : public ContextualFailure { public: TupleLabelMismatchWarning(const Solution &solution, Type fromType, diff --git a/test/Constraints/tuple.swift b/test/Constraints/tuple.swift index 51187eed1be..7d7952a424d 100644 --- a/test/Constraints/tuple.swift +++ b/test/Constraints/tuple.swift @@ -342,27 +342,6 @@ optionalTuple = (bignum, 1) // expected-error {{cannot assign value of type '(In optionalTuple = optionalTuple2 // expected-error {{cannot assign value of type '(Int64, Int)?' to type '(Int, Int)?'}} // expected-note@-1 {{arguments to generic parameter 'Wrapped' ('(Int64, Int)' and '(Int, Int)') are expected to be equal}} -func testTupleLabelMismatchFuncConversion(fn1: @escaping ((x: Int, y: Int)) -> Void, - fn2: @escaping () -> (x: Int, Int)) { - // Warn on mismatches - let _: ((a: Int, b: Int)) -> Void = fn1 // expected-warning {{tuple conversion from '(a: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}} - let _: ((x: Int, b: Int)) -> Void = fn1 // expected-warning {{tuple conversion from '(x: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}} - - let _: () -> (y: Int, Int) = fn2 // expected-warning {{tuple conversion from '(x: Int, Int)' to '(y: Int, Int)' mismatches labels}} - let _: () -> (y: Int, k: Int) = fn2 // expected-warning {{tuple conversion from '(x: Int, Int)' to '(y: Int, k: Int)' mismatches labels}} - - // Attempting to shuffle has always been illegal here - let _: () -> (y: Int, x: Int) = fn2 // expected-error {{cannot convert value of type '() -> (x: Int, Int)' to specified type '() -> (y: Int, x: Int)'}} - - // Losing labels is okay though. - let _: () -> (Int, Int) = fn2 - - // Gaining labels also okay. - let _: ((x: Int, Int)) -> Void = fn1 - let _: () -> (x: Int, y: Int) = fn2 - let _: () -> (Int, y: Int) = fn2 -} - func testTupleLabelMismatchKeyPath() { // FIXME: The warning should be upgraded to an error for key paths. let _: KeyPath<(x: Int, y: Int), Int> = \(a: Int, b: Int).x diff --git a/test/Constraints/tuple_subtype_label_mismatch.swift b/test/Constraints/tuple_subtype_label_mismatch.swift new file mode 100644 index 00000000000..55d8edd0091 --- /dev/null +++ b/test/Constraints/tuple_subtype_label_mismatch.swift @@ -0,0 +1,33 @@ +// RUN: %target-typecheck-verify-swift -language-mode 6 -verify-additional-prefix swift6- +// RUN: %target-typecheck-verify-swift -language-mode 7 -verify-additional-prefix swift7- +// REQUIRES: swift7 + +func testTupleLabelMismatchFuncConversion(fn1: @escaping ((x: Int, y: Int)) -> Void, + fn2: @escaping () -> (x: Int, Int)) { + // Warn on mismatches in Swift 6, upgrading to an error for Swift 7 + let _: ((a: Int, b: Int)) -> Void = fn1 + // expected-swift6-warning@-1 {{tuple conversion from '(a: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}} + // expected-swift7-error@-2 {{tuple conversion from '(a: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}} + let _: ((x: Int, b: Int)) -> Void = fn1 + // expected-swift6-warning@-1 {{tuple conversion from '(x: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}} + // expected-swift7-error@-2 {{tuple conversion from '(x: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}} + + let _: () -> (y: Int, Int) = fn2 + // expected-swift6-warning@-1 {{tuple conversion from '(x: Int, Int)' to '(y: Int, Int)' mismatches labels}} + // expected-swift7-error@-2 {{tuple conversion from '(x: Int, Int)' to '(y: Int, Int)' mismatches labels}} + let _: () -> (y: Int, k: Int) = fn2 + // expected-swift6-warning@-1 {{tuple conversion from '(x: Int, Int)' to '(y: Int, k: Int)' mismatches labels}} + // expected-swift7-error@-2 {{tuple conversion from '(x: Int, Int)' to '(y: Int, k: Int)' mismatches labels}} + + // Attempting to shuffle has always been illegal here + let _: () -> (y: Int, x: Int) = fn2 + // expected-error@-1 {{cannot convert value of type '() -> (x: Int, Int)' to specified type '() -> (y: Int, x: Int)'}} + + // Losing labels is okay though. + let _: () -> (Int, Int) = fn2 + + // Gaining labels also okay. + let _: ((x: Int, Int)) -> Void = fn1 + let _: () -> (x: Int, y: Int) = fn2 + let _: () -> (Int, y: Int) = fn2 +}