diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 87d6440a32e15..4b95dc4fcf6e9 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; " @@ -7833,9 +7833,14 @@ ERROR(result_builder_buildpartialblock_accumulated_not_accessible,none, // MARK: Tuple Shuffle Diagnostics //------------------------------------------------------------------------------ - WARNING(warn_reordering_tuple_shuffle_deprecated,Deprecation, - "expression shuffles the elements of this tuple; " - "this behavior is deprecated", ()) +ERROR(reordering_tuple_shuffle,none, + "cannot implicitly reorder tuple elements from '%0' to '%1'", + (StringRef, StringRef)) + +WARNING(warn_reordering_tuple_shuffle_deprecated,Deprecation, + "implicit reordering of tuple elements from '%0' to '%1' is deprecated" + "; this will be an error in a future Swift language mode", + (StringRef, StringRef)) //------------------------------------------------------------------------------ // MARK: Implicit conversion diagnostics diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 0955ec9868816..e347c4a6877ba 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -3458,7 +3458,8 @@ class AllowInvalidStaticMemberRefOnProtocolMetatype final } }; -/// 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/CSApply.cpp b/lib/Sema/CSApply.cpp index e6de2b0a5a83a..c7116226d1c08 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5818,6 +5818,7 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, // Convert each OpaqueValueExpr to the correct type. SmallVector converted; + SmallVector origLabels; SmallVector labels; SmallVector convertedElts; @@ -5825,6 +5826,7 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, for (unsigned i = 0, e = sources.size(); i != e; ++i) { unsigned source = sources[i]; auto *fromElt = destructured[source]; + auto fromLabel = fromTuple->getElement(i).getName(); // Actually convert the source element. auto toEltType = toTuple->getElementType(i); @@ -5832,8 +5834,7 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, // If we're shuffling positions and labels, we have to warn about this // conversion. - if (i != sources[i] && - fromTuple->getElement(i).getName() != toLabel) + if (i != sources[i] && fromLabel != toLabel) anythingShuffled = true; auto *toElt @@ -5845,6 +5846,7 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, converted.push_back(toElt); labels.push_back(toLabel); + origLabels.push_back(fromLabel); convertedElts.emplace_back(toEltType, toLabel); } @@ -5852,8 +5854,28 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, // will form the shuffle for now, but a future compiler should decline to // do so and begin the process of removing them altogether. if (anythingShuffled) { - ctx.Diags.diagnose( - expr->getLoc(), diag::warn_reordering_tuple_shuffle_deprecated); + auto concatLabels = [](SmallVectorImpl &labels, + SmallVectorImpl &out) { + llvm::raw_svector_ostream OS(out); + for (auto label : labels) { + DeclName(label).print(OS, /*skipEmpty*/ false, /*escapeIfNeeded*/ true); + OS << ':'; + } + }; + SmallString<16> fromLabelStr; + concatLabels(origLabels, fromLabelStr); + SmallString<16> toLabelStr; + concatLabels(labels, toLabelStr); + + using namespace version; + if (ctx.isSwiftVersionAtLeast(Version::getFutureMajorLanguageVersion())) { + ctx.Diags.diagnose(expr->getLoc(), diag::reordering_tuple_shuffle, + fromLabelStr, toLabelStr); + } else { + ctx.Diags.diagnose(expr->getLoc(), + diag::warn_reordering_tuple_shuffle_deprecated, + fromLabelStr, toLabelStr); + } } // Create the result tuple, written in terms of the destructured diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 78498d1ec9691..975b57d9125d2 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 b1816b51d2b21..f25f798adedbf 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -3009,7 +3009,8 @@ class InvalidWeakAttributeUse final : public FailureDiagnostic { 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 51187eed1be35..7d7952a424d4a 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_shuffle.swift b/test/Constraints/tuple_shuffle.swift index 2d27f19cf6770..f8a265b284444 100644 --- a/test/Constraints/tuple_shuffle.swift +++ b/test/Constraints/tuple_shuffle.swift @@ -1,31 +1,50 @@ -// RUN: %target-typecheck-verify-swift -swift-version 5 - - func consume(_ x: T) {} // Suppress unused variable warnings - - func shuffle_through_initialization() { - let a = (x: 1, y: 2) - let b: (y: Int, x: Int) - b = a // expected-warning {{expression shuffles the elements of this tuple}} - consume(b) - } - - func shuffle_through_destructuring() { - let a = (x: 1, y: 2) - let (y: b, x: c) = a // expected-warning {{expression shuffles the elements of this tuple}} - consume((b, c)) - } - - func shuffle_through_call() { - func foo(_ : (x: Int, y: Int)) {} - foo((y: 5, x: 10)) // expected-warning {{expression shuffles the elements of this tuple}} - } - - func shuffle_through_cast() { - let x = ((a: Int(), b: Int()) as (b: Int, a: Int)).0 // expected-warning {{expression shuffles the elements of this tuple}} - - // Ah, the famous double-shuffle - let (c1, (c2, c3)): (c: Int, (b: Int, a: Int)) = ((a: Int(), b: Int()), c: Int()) - // expected-warning@-1 {{expression shuffles the elements of this tuple}} - // expected-warning@-2 {{expression shuffles the elements of this tuple}} - consume((x, c1, c2, c3)) - } +// RUN: %target-typecheck-verify-swift -swift-version 6 -verify-additional-prefix swift6- +// RUN: %target-typecheck-verify-swift -swift-version 7 -verify-additional-prefix swift7- + +// REQUIRES: swift7 + +func consume(_ x: T) {} // Suppress unused variable warnings + +func shuffle_through_initialization() { + let a = (x: 1, y: 2) + let b: (y: Int, x: Int) + b = a + // expected-swift6-warning@-1 {{implicit reordering of tuple elements from 'x:y:' to 'y:x:' is deprecated; this will be an error in a future Swift language mode}} + // expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from 'x:y:' to 'y:x:'}} + consume(b) +} + +func shuffle_raw_label(_ t: (`a b`: Int, `c d`: Int)) { + let _: (`c d`: Int, `a b`: Int) = t + // expected-swift6-warning@-1 {{implicit reordering of tuple elements from '`a b`:`c d`:' to '`c d`:`a b`:' is deprecated; this will be an error in a future Swift language mode}} + // expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from '`a b`:`c d`:' to '`c d`:`a b`:'}} +} + +func shuffle_through_destructuring() { + let a = (x: 1, y: 2) + let (y: b, x: c) = a + // expected-swift6-warning@-1 {{implicit reordering of tuple elements from 'x:y:' to 'y:x:' is deprecated; this will be an error in a future Swift language mode}} + // expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from 'x:y:' to 'y:x:'}} + consume((b, c)) +} + +func shuffle_through_call() { + func foo(_ : (x: Int, y: Int)) {} + foo((y: 5, x: 10)) + // expected-swift6-warning@-1 {{implicit reordering of tuple elements from 'y:x:' to 'x:y:' is deprecated; this will be an error in a future Swift language mode}} + // expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from 'y:x:' to 'x:y:'}} +} + +func shuffle_through_cast() { + let x = ((a: Int(), b: Int()) as (b: Int, a: Int)).0 + // expected-swift6-warning@-1 {{implicit reordering of tuple elements from 'a:b:' to 'b:a:' is deprecated; this will be an error in a future Swift language mode}} + // expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from 'a:b:' to 'b:a:'}} + + // Ah, the famous double-shuffle + let (c1, (c2, c3)): (c: Int, (b: Int, a: Int)) = ((a: Int(), b: Int()), c: Int()) + // expected-swift6-warning@-1 {{implicit reordering of tuple elements from 'a:b:' to 'b:a:' is deprecated; this will be an error in a future Swift language mode}} + // expected-swift6-warning@-2 {{implicit reordering of tuple elements from '_:c:' to 'c:_:' is deprecated; this will be an error in a future Swift language mode}} + // expected-swift7-error@-3 {{cannot implicitly reorder tuple elements from 'a:b:' to 'b:a:'}} + // expected-swift7-error@-4 {{cannot implicitly reorder tuple elements from '_:c:' to 'c:_:'}} + consume((x, c1, c2, c3)) +} diff --git a/test/Constraints/tuple_subtype_label_mismatch.swift b/test/Constraints/tuple_subtype_label_mismatch.swift new file mode 100644 index 0000000000000..55d8edd0091b3 --- /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 +} diff --git a/test/Parse/omit_return.swift b/test/Parse/omit_return.swift index e18d8e0d67221..e19c241e5d623 100644 --- a/test/Parse/omit_return.swift +++ b/test/Parse/omit_return.swift @@ -474,7 +474,7 @@ func ff_implicitInjectIntoOptionalExpr(_ int: Int) -> Int? { } func ff_implicitTupleShuffle(_ input: (one: Int, two: Int)) -> (two: Int, one: Int) { - input // expected-warning {{expression shuffles the elements of this tuple; this behavior is deprecated}} + input // expected-warning {{implicit reordering of tuple elements from 'one:two:' to 'two:one:' is deprecated; this will be an error in a future Swift language mode}} } func ff_implicitCollectionUpcast(_ derived: [Derived]) -> [Base] { diff --git a/test/Parse/omit_return_ifdecl.swift b/test/Parse/omit_return_ifdecl.swift index 27dd699806962..3d0beca5cb00b 100644 --- a/test/Parse/omit_return_ifdecl.swift +++ b/test/Parse/omit_return_ifdecl.swift @@ -676,7 +676,7 @@ func ff_implicitInjectIntoOptionalExpr(_ int: Int) -> Int? { func ff_implicitTupleShuffle(_ input: (one: Int, two: Int)) -> (two: Int, one: Int) { #if true - input // expected-warning {{expression shuffles the elements of this tuple; this behavior is deprecated}} + input // expected-warning {{implicit reordering of tuple elements from 'one:two:' to 'two:one:' is deprecated; this will be an error in a future Swift language mode}} #endif } diff --git a/test/Sema/diag_unowned_immediate_deallocation.swift b/test/Sema/diag_unowned_immediate_deallocation.swift index 315a23c9e989c..523bca378e645 100644 --- a/test/Sema/diag_unowned_immediate_deallocation.swift +++ b/test/Sema/diag_unowned_immediate_deallocation.swift @@ -452,10 +452,10 @@ func testGenericWeakClassDiag() { // The diagnostic doesn't currently support tuple shuffles. func testDontDiagnoseThroughTupleShuffles() { unowned let (c1, (c2, c3)): (c: C, (b: C, a: C)) = ((a: D(), b: C()), c: D()) - // expected-warning@-1 {{expression shuffles the elements of this tuple; this behavior is deprecated}} - // expected-warning@-2 {{expression shuffles the elements of this tuple; this behavior is deprecated}} + // expected-warning@-1 {{implicit reordering of tuple elements from 'a:b:' to 'b:a:' is deprecated; this will be an error in a future Swift language mode}} + // expected-warning@-2 {{implicit reordering of tuple elements from '_:c:' to 'c:_:' is deprecated; this will be an error in a future Swift language mode}} unowned let c4 = ((a: C(), b: C()) as (b: C, a: C)).0 - // expected-warning@-1 {{expression shuffles the elements of this tuple; this behavior is deprecated}} + // expected-warning@-1 {{implicit reordering of tuple elements from 'a:b:' to 'b:a:' is deprecated; this will be an error in a future Swift language mode}} _ = c1; _ = c2; _ = c3; _ = c4 } diff --git a/test/decl/func/operator.swift b/test/decl/func/operator.swift index d6f9f04b471a3..8564c2c212a85 100644 --- a/test/decl/func/operator.swift +++ b/test/decl/func/operator.swift @@ -155,7 +155,7 @@ var f2 : (Int) -> Int = (+-+) var f3 : (inout Int) -> Int = (-+-) // expected-error{{ambiguous use of operator '-+-'}} var f4 : (inout Int, Int) -> Int = (+-+=) var r5 : (a : (Int, Int) -> Int, b : (Int, Int) -> Int) = (+, -) -var r6 : (a : (Int, Int) -> Int, b : (Int, Int) -> Int) = (b : +, a : -) // expected-warning {{expression shuffles the elements of this tuple; this behavior is deprecated}} +var r6 : (a : (Int, Int) -> Int, b : (Int, Int) -> Int) = (b : +, a : -) // expected-warning {{implicit reordering of tuple elements from 'b:a:' to 'a:b:' is deprecated; this will be an error in a future Swift language mode}} struct f6_S { subscript(op : (Int, Int) -> Int) -> Int { diff --git a/test/expr/closure/closures.swift b/test/expr/closure/closures.swift index 8e13cfd346726..b8af7e06c653c 100644 --- a/test/expr/closure/closures.swift +++ b/test/expr/closure/closures.swift @@ -56,7 +56,7 @@ func funcdecl5(_ a: Int, _ y: Int) { var b = a.1+a.f // Tuple expressions with named elements. - var i : (y : Int, x : Int) = (x : 42, y : 11) // expected-warning {{expression shuffles the elements of this tuple; this behavior is deprecated}} + var i : (y : Int, x : Int) = (x : 42, y : 11) // expected-warning {{implicit reordering of tuple elements from 'x:y:' to 'y:x:' is deprecated; this will be an error in a future Swift language mode}} funcdecl1(123, 444) // Calls. diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index 878b73a439553..b4416db19c5bd 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -194,7 +194,7 @@ func test5() { let c: (a: Int, b: Int) = (1,2) - let _: (b: Int, a: Int) = c // expected-warning {{expression shuffles the elements of this tuple; this behavior is deprecated}} + let _: (b: Int, a: Int) = c // expected-warning {{implicit reordering of tuple elements from 'a:b:' to 'b:a:' is deprecated; this will be an error in a future Swift language mode}} }