Skip to content

Commit 6a7bf6f

Browse files
authored
Merge pull request #85188 from hamishknight/tuple-trouble
[CS] Upgrade a couple of tuple warnings to error for future lang mode
2 parents e0ca132 + 00d8774 commit 6a7bf6f

File tree

14 files changed

+135
-74
lines changed

14 files changed

+135
-74
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,9 +1586,9 @@ WARNING(coercion_may_fail_warning,none,
15861586
"coercion from %0 to %1 may fail; use 'as?' or 'as!' instead",
15871587
(Type, Type))
15881588

1589-
WARNING(tuple_label_mismatch_warning,none,
1590-
"tuple conversion from %0 to %1 mismatches labels",
1591-
(Type, Type))
1589+
ERROR(tuple_label_mismatch,none,
1590+
"tuple conversion from %0 to %1 mismatches labels",
1591+
(Type, Type))
15921592

15931593
ERROR(missing_explicit_conversion,none,
15941594
"%0 is not implicitly convertible to %1; "
@@ -7833,9 +7833,14 @@ ERROR(result_builder_buildpartialblock_accumulated_not_accessible,none,
78337833
// MARK: Tuple Shuffle Diagnostics
78347834
//------------------------------------------------------------------------------
78357835

7836-
WARNING(warn_reordering_tuple_shuffle_deprecated,Deprecation,
7837-
"expression shuffles the elements of this tuple; "
7838-
"this behavior is deprecated", ())
7836+
ERROR(reordering_tuple_shuffle,none,
7837+
"cannot implicitly reorder tuple elements from '%0' to '%1'",
7838+
(StringRef, StringRef))
7839+
7840+
WARNING(warn_reordering_tuple_shuffle_deprecated,Deprecation,
7841+
"implicit reordering of tuple elements from '%0' to '%1' is deprecated"
7842+
"; this will be an error in a future Swift language mode",
7843+
(StringRef, StringRef))
78397844

78407845
//------------------------------------------------------------------------------
78417846
// MARK: Implicit conversion diagnostics

include/swift/Sema/CSFix.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3458,7 +3458,8 @@ class AllowInvalidStaticMemberRefOnProtocolMetatype final
34583458
}
34593459
};
34603460

3461-
/// Emit a warning for mismatched tuple labels.
3461+
/// Emit a warning for mismatched tuple labels, which is upgraded to an error
3462+
/// for a future language mode.
34623463
class AllowTupleLabelMismatch final : public ContextualMismatch {
34633464
AllowTupleLabelMismatch(ConstraintSystem &cs, Type fromType, Type toType,
34643465
ConstraintLocator *locator)

lib/Sema/CSApply.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5822,22 +5822,23 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr,
58225822

58235823
// Convert each OpaqueValueExpr to the correct type.
58245824
SmallVector<Expr *, 4> converted;
5825+
SmallVector<Identifier, 4> origLabels;
58255826
SmallVector<Identifier, 4> labels;
58265827
SmallVector<TupleTypeElt, 4> convertedElts;
58275828

58285829
bool anythingShuffled = false;
58295830
for (unsigned i = 0, e = sources.size(); i != e; ++i) {
58305831
unsigned source = sources[i];
58315832
auto *fromElt = destructured[source];
5833+
auto fromLabel = fromTuple->getElement(i).getName();
58325834

58335835
// Actually convert the source element.
58345836
auto toEltType = toTuple->getElementType(i);
58355837
auto toLabel = toTuple->getElement(i).getName();
58365838

58375839
// If we're shuffling positions and labels, we have to warn about this
58385840
// conversion.
5839-
if (i != sources[i] &&
5840-
fromTuple->getElement(i).getName() != toLabel)
5841+
if (i != sources[i] && fromLabel != toLabel)
58415842
anythingShuffled = true;
58425843

58435844
auto *toElt
@@ -5849,15 +5850,36 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr,
58495850

58505851
converted.push_back(toElt);
58515852
labels.push_back(toLabel);
5853+
origLabels.push_back(fromLabel);
58525854
convertedElts.emplace_back(toEltType, toLabel);
58535855
}
58545856

58555857
// Shuffling tuple elements is an anti-pattern worthy of a diagnostic. We
58565858
// will form the shuffle for now, but a future compiler should decline to
58575859
// do so and begin the process of removing them altogether.
58585860
if (anythingShuffled) {
5859-
ctx.Diags.diagnose(
5860-
expr->getLoc(), diag::warn_reordering_tuple_shuffle_deprecated);
5861+
auto concatLabels = [](SmallVectorImpl<Identifier> &labels,
5862+
SmallVectorImpl<char> &out) {
5863+
llvm::raw_svector_ostream OS(out);
5864+
for (auto label : labels) {
5865+
DeclName(label).print(OS, /*skipEmpty*/ false, /*escapeIfNeeded*/ true);
5866+
OS << ':';
5867+
}
5868+
};
5869+
SmallString<16> fromLabelStr;
5870+
concatLabels(origLabels, fromLabelStr);
5871+
SmallString<16> toLabelStr;
5872+
concatLabels(labels, toLabelStr);
5873+
5874+
using namespace version;
5875+
if (ctx.isSwiftVersionAtLeast(Version::getFutureMajorLanguageVersion())) {
5876+
ctx.Diags.diagnose(expr->getLoc(), diag::reordering_tuple_shuffle,
5877+
fromLabelStr, toLabelStr);
5878+
} else {
5879+
ctx.Diags.diagnose(expr->getLoc(),
5880+
diag::warn_reordering_tuple_shuffle_deprecated,
5881+
fromLabelStr, toLabelStr);
5882+
}
58615883
}
58625884

58635885
// Create the result tuple, written in terms of the destructured

lib/Sema/CSDiagnostics.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9419,8 +9419,9 @@ bool InvalidWeakAttributeUse::diagnoseAsError() {
94199419
}
94209420

94219421
bool TupleLabelMismatchWarning::diagnoseAsError() {
9422-
emitDiagnostic(diag::tuple_label_mismatch_warning, getFromType(), getToType())
9423-
.highlight(getSourceRange());
9422+
emitDiagnostic(diag::tuple_label_mismatch, getFromType(), getToType())
9423+
.highlight(getSourceRange())
9424+
.warnUntilFutureSwiftVersion();
94249425
return true;
94259426
}
94269427

lib/Sema/CSDiagnostics.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3009,7 +3009,8 @@ class InvalidWeakAttributeUse final : public FailureDiagnostic {
30093009
bool diagnoseAsError() override;
30103010
};
30113011

3012-
/// Emit a warning for mismatched tuple labels.
3012+
/// Emit a warning for mismatched tuple labels, which is upgraded to an error
3013+
/// for a future language mode.
30133014
class TupleLabelMismatchWarning final : public ContextualFailure {
30143015
public:
30153016
TupleLabelMismatchWarning(const Solution &solution, Type fromType,

test/Constraints/tuple.swift

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -342,27 +342,6 @@ optionalTuple = (bignum, 1) // expected-error {{cannot assign value of type '(In
342342
optionalTuple = optionalTuple2 // expected-error {{cannot assign value of type '(Int64, Int)?' to type '(Int, Int)?'}}
343343
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('(Int64, Int)' and '(Int, Int)') are expected to be equal}}
344344

345-
func testTupleLabelMismatchFuncConversion(fn1: @escaping ((x: Int, y: Int)) -> Void,
346-
fn2: @escaping () -> (x: Int, Int)) {
347-
// Warn on mismatches
348-
let _: ((a: Int, b: Int)) -> Void = fn1 // expected-warning {{tuple conversion from '(a: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}}
349-
let _: ((x: Int, b: Int)) -> Void = fn1 // expected-warning {{tuple conversion from '(x: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}}
350-
351-
let _: () -> (y: Int, Int) = fn2 // expected-warning {{tuple conversion from '(x: Int, Int)' to '(y: Int, Int)' mismatches labels}}
352-
let _: () -> (y: Int, k: Int) = fn2 // expected-warning {{tuple conversion from '(x: Int, Int)' to '(y: Int, k: Int)' mismatches labels}}
353-
354-
// Attempting to shuffle has always been illegal here
355-
let _: () -> (y: Int, x: Int) = fn2 // expected-error {{cannot convert value of type '() -> (x: Int, Int)' to specified type '() -> (y: Int, x: Int)'}}
356-
357-
// Losing labels is okay though.
358-
let _: () -> (Int, Int) = fn2
359-
360-
// Gaining labels also okay.
361-
let _: ((x: Int, Int)) -> Void = fn1
362-
let _: () -> (x: Int, y: Int) = fn2
363-
let _: () -> (Int, y: Int) = fn2
364-
}
365-
366345
func testTupleLabelMismatchKeyPath() {
367346
// FIXME: The warning should be upgraded to an error for key paths.
368347
let _: KeyPath<(x: Int, y: Int), Int> = \(a: Int, b: Int).x
Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,50 @@
1-
// RUN: %target-typecheck-verify-swift -swift-version 5
2-
3-
func consume<T>(_ x: T) {} // Suppress unused variable warnings
4-
5-
func shuffle_through_initialization() {
6-
let a = (x: 1, y: 2)
7-
let b: (y: Int, x: Int)
8-
b = a // expected-warning {{expression shuffles the elements of this tuple}}
9-
consume(b)
10-
}
11-
12-
func shuffle_through_destructuring() {
13-
let a = (x: 1, y: 2)
14-
let (y: b, x: c) = a // expected-warning {{expression shuffles the elements of this tuple}}
15-
consume((b, c))
16-
}
17-
18-
func shuffle_through_call() {
19-
func foo(_ : (x: Int, y: Int)) {}
20-
foo((y: 5, x: 10)) // expected-warning {{expression shuffles the elements of this tuple}}
21-
}
22-
23-
func shuffle_through_cast() {
24-
let x = ((a: Int(), b: Int()) as (b: Int, a: Int)).0 // expected-warning {{expression shuffles the elements of this tuple}}
25-
26-
// Ah, the famous double-shuffle
27-
let (c1, (c2, c3)): (c: Int, (b: Int, a: Int)) = ((a: Int(), b: Int()), c: Int())
28-
// expected-warning@-1 {{expression shuffles the elements of this tuple}}
29-
// expected-warning@-2 {{expression shuffles the elements of this tuple}}
30-
consume((x, c1, c2, c3))
31-
}
1+
// RUN: %target-typecheck-verify-swift -swift-version 6 -verify-additional-prefix swift6-
2+
// RUN: %target-typecheck-verify-swift -swift-version 7 -verify-additional-prefix swift7-
3+
4+
// REQUIRES: swift7
5+
6+
func consume<T>(_ x: T) {} // Suppress unused variable warnings
7+
8+
func shuffle_through_initialization() {
9+
let a = (x: 1, y: 2)
10+
let b: (y: Int, x: Int)
11+
b = a
12+
// 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}}
13+
// expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from 'x:y:' to 'y:x:'}}
14+
consume(b)
15+
}
16+
17+
func shuffle_raw_label(_ t: (`a b`: Int, `c d`: Int)) {
18+
let _: (`c d`: Int, `a b`: Int) = t
19+
// 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}}
20+
// expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from '`a b`:`c d`:' to '`c d`:`a b`:'}}
21+
}
22+
23+
func shuffle_through_destructuring() {
24+
let a = (x: 1, y: 2)
25+
let (y: b, x: c) = a
26+
// 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}}
27+
// expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from 'x:y:' to 'y:x:'}}
28+
consume((b, c))
29+
}
30+
31+
func shuffle_through_call() {
32+
func foo(_ : (x: Int, y: Int)) {}
33+
foo((y: 5, x: 10))
34+
// 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}}
35+
// expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from 'y:x:' to 'x:y:'}}
36+
}
37+
38+
func shuffle_through_cast() {
39+
let x = ((a: Int(), b: Int()) as (b: Int, a: Int)).0
40+
// 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}}
41+
// expected-swift7-error@-2 {{cannot implicitly reorder tuple elements from 'a:b:' to 'b:a:'}}
42+
43+
// Ah, the famous double-shuffle
44+
let (c1, (c2, c3)): (c: Int, (b: Int, a: Int)) = ((a: Int(), b: Int()), c: Int())
45+
// 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}}
46+
// 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}}
47+
// expected-swift7-error@-3 {{cannot implicitly reorder tuple elements from 'a:b:' to 'b:a:'}}
48+
// expected-swift7-error@-4 {{cannot implicitly reorder tuple elements from '_:c:' to 'c:_:'}}
49+
consume((x, c1, c2, c3))
50+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %target-typecheck-verify-swift -language-mode 6 -verify-additional-prefix swift6-
2+
// RUN: %target-typecheck-verify-swift -language-mode 7 -verify-additional-prefix swift7-
3+
// REQUIRES: swift7
4+
5+
func testTupleLabelMismatchFuncConversion(fn1: @escaping ((x: Int, y: Int)) -> Void,
6+
fn2: @escaping () -> (x: Int, Int)) {
7+
// Warn on mismatches in Swift 6, upgrading to an error for Swift 7
8+
let _: ((a: Int, b: Int)) -> Void = fn1
9+
// expected-swift6-warning@-1 {{tuple conversion from '(a: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}}
10+
// expected-swift7-error@-2 {{tuple conversion from '(a: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}}
11+
let _: ((x: Int, b: Int)) -> Void = fn1
12+
// expected-swift6-warning@-1 {{tuple conversion from '(x: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}}
13+
// expected-swift7-error@-2 {{tuple conversion from '(x: Int, b: Int)' to '(x: Int, y: Int)' mismatches labels}}
14+
15+
let _: () -> (y: Int, Int) = fn2
16+
// expected-swift6-warning@-1 {{tuple conversion from '(x: Int, Int)' to '(y: Int, Int)' mismatches labels}}
17+
// expected-swift7-error@-2 {{tuple conversion from '(x: Int, Int)' to '(y: Int, Int)' mismatches labels}}
18+
let _: () -> (y: Int, k: Int) = fn2
19+
// expected-swift6-warning@-1 {{tuple conversion from '(x: Int, Int)' to '(y: Int, k: Int)' mismatches labels}}
20+
// expected-swift7-error@-2 {{tuple conversion from '(x: Int, Int)' to '(y: Int, k: Int)' mismatches labels}}
21+
22+
// Attempting to shuffle has always been illegal here
23+
let _: () -> (y: Int, x: Int) = fn2
24+
// expected-error@-1 {{cannot convert value of type '() -> (x: Int, Int)' to specified type '() -> (y: Int, x: Int)'}}
25+
26+
// Losing labels is okay though.
27+
let _: () -> (Int, Int) = fn2
28+
29+
// Gaining labels also okay.
30+
let _: ((x: Int, Int)) -> Void = fn1
31+
let _: () -> (x: Int, y: Int) = fn2
32+
let _: () -> (Int, y: Int) = fn2
33+
}

test/Parse/omit_return.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ func ff_implicitInjectIntoOptionalExpr(_ int: Int) -> Int? {
474474
}
475475

476476
func ff_implicitTupleShuffle(_ input: (one: Int, two: Int)) -> (two: Int, one: Int) {
477-
input // expected-warning {{expression shuffles the elements of this tuple; this behavior is deprecated}}
477+
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}}
478478
}
479479

480480
func ff_implicitCollectionUpcast(_ derived: [Derived]) -> [Base] {

test/Parse/omit_return_ifdecl.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ func ff_implicitInjectIntoOptionalExpr(_ int: Int) -> Int? {
676676

677677
func ff_implicitTupleShuffle(_ input: (one: Int, two: Int)) -> (two: Int, one: Int) {
678678
#if true
679-
input // expected-warning {{expression shuffles the elements of this tuple; this behavior is deprecated}}
679+
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}}
680680
#endif
681681
}
682682

0 commit comments

Comments
 (0)