Skip to content

Commit 25ff82f

Browse files
committed
Loosen default argument mismatch diagnostics
This change makes: * #file compatible with #fileID in “Swift 6 mode” * #file compatible with #filePath and #fileID in Swift 5 mode * #file in Swift 5 mode code compatible with #file in “Swift 6 mode” code This should keep anyone from seeing XCTAssert-wrapping noise until they adopt “Swift 6 mode” (whatever version that ends up actually being).
1 parent cad5f62 commit 25ff82f

File tree

4 files changed

+157
-4
lines changed

4 files changed

+157
-4
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,10 +436,10 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
436436
auto calleeDefaultArg = getMagicIdentifierDefaultArgKind(calleeParam);
437437
auto callerDefaultArg = getMagicIdentifierDefaultArgKind(callerParam);
438438

439-
// If one of the parameters doesn't have a default arg, or they both have
440-
// the same one, everything's fine.
439+
// If one of the parameters doesn't have a default arg, or they're both
440+
// compatible, everything's fine.
441441
if (!calleeDefaultArg || !callerDefaultArg ||
442-
*calleeDefaultArg == *callerDefaultArg)
442+
areMagicIdentifiersCompatible(*calleeDefaultArg, *callerDefaultArg))
443443
return;
444444

445445
StringRef calleeDefaultArgString =
@@ -493,6 +493,52 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
493493
"getMagicIdentifierDefaultArgKind");
494494
}
495495

496+
static bool
497+
areMagicIdentifiersCompatible(MagicIdentifierLiteralExpr::Kind a,
498+
MagicIdentifierLiteralExpr::Kind b) {
499+
if (a == b)
500+
return true;
501+
502+
// The rest of this handles special compatibility rules between the
503+
// `*SpelledAsFile` cases and various other File-related cases.
504+
//
505+
// The way we're going to do this is a bit magical. We will arrange the
506+
// cases in MagicIdentifierLiteralExpr::Kind so that that they sort in
507+
// this order:
508+
//
509+
// #fileID < Swift 6 #file < #filePath < Swift 5 #file < others
510+
//
511+
// Before we continue, let's verify that this holds.
512+
513+
using Kind = MagicIdentifierLiteralExpr::Kind;
514+
515+
static_assert(Kind::FileID < Kind::FileIDSpelledAsFile,
516+
"#fileID < Swift 6 #file");
517+
static_assert(Kind::FileIDSpelledAsFile < Kind::FilePath,
518+
"Swift 6 #file < #filePath");
519+
static_assert(Kind::FilePath < Kind::FilePathSpelledAsFile,
520+
"#filePath < Swift 5 #file");
521+
522+
static_assert(Kind::FilePathSpelledAsFile < Kind::Line,
523+
"Swift 5 #file < #line");
524+
static_assert(Kind::FilePathSpelledAsFile < Kind::Column,
525+
"Swift 5 #file < #column");
526+
static_assert(Kind::FilePathSpelledAsFile < Kind::Function,
527+
"Swift 5 #file < #function");
528+
static_assert(Kind::FilePathSpelledAsFile < Kind::DSOHandle,
529+
"Swift 5 #file < #dsohandle");
530+
531+
// The rules are all commutative, so we will take the greater of the two
532+
// kinds.
533+
auto maxKind = std::max(a, b);
534+
535+
// Both Swift 6 #file and Swift 5 #file are greater than all of the cases
536+
// they're compatible with. So if `maxCase` is one of those two, the other
537+
// case must have been compatible with it!
538+
return maxKind == Kind::FileIDSpelledAsFile ||
539+
maxKind == Kind::FilePathSpelledAsFile;
540+
}
541+
496542
void checkUseOfModule(DeclRefExpr *E) {
497543
// Allow module values as a part of:
498544
// - ignored base expressions;

test/Sema/diag_mismatched_magic_literals.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-typecheck-verify-swift -enable-experimental-concise-pound-file
3+
4+
// The test cases in this file work the same in both Swift 5 and "Swift 6" mode.
5+
// See the _swift5 and _swift6 files for version-specific test cases.
26

37
func callee(file: String = #file) {} // expected-note {{'file' declared here}}
48
func callee(optFile: String? = #file) {} // expected-note {{'optFile' declared here}}
9+
func callee(fileID: String = #fileID) {} // expected-note {{'fileID' declared here}}
10+
func callee(filePath: String = #filePath) {} // expected-note {{'filePath' declared here}}
511
func callee(arbitrary: String) {}
612

713
class SomeClass {
@@ -22,6 +28,9 @@ class SomeClass {
2228
// `#file`-defaulted argument.
2329
func bad(function: String = #function) {
2430
// expected-note@-1 3{{did you mean for parameter 'function' to default to '#file'?}} {{29-38=#file}}
31+
// expected-note@-2 {{did you mean for parameter 'function' to default to '#fileID'?}} {{29-38=#fileID}}
32+
// expected-note@-3 {{did you mean for parameter 'function' to default to '#filePath'?}} {{29-38=#filePath}}
33+
2534
callee(file: function)
2635
// expected-warning@-1 {{parameter 'function' with default argument '#function' passed to parameter 'file', whose default argument is '#file'}}
2736
// expected-note@-2 {{add parentheses to silence this warning}} {{16-16=(}} {{24-24=)}}
@@ -33,16 +42,28 @@ func bad(function: String = #function) {
3342
SomeClass().callee(file: function)
3443
// expected-warning@-1 {{parameter 'function' with default argument '#function' passed to parameter 'file', whose default argument is '#file'}}
3544
// expected-note@-2 {{add parentheses to silence this warning}} {{28-28=(}} {{36-36=)}}
45+
46+
callee(fileID: function)
47+
// expected-warning@-1 {{parameter 'function' with default argument '#function' passed to parameter 'fileID', whose default argument is '#fileID'}}
48+
// expected-note@-2 {{add parentheses to silence this warning}} {{18-18=(}} {{26-26=)}}
49+
50+
callee(filePath: function)
51+
// expected-warning@-1 {{parameter 'function' with default argument '#function' passed to parameter 'filePath', whose default argument is '#filePath'}}
52+
// expected-note@-2 {{add parentheses to silence this warning}} {{20-20=(}} {{28-28=)}}
3653
}
3754

3855
// We should not warn when we pass a `#file`-defaulted argument to a
3956
// `#file`-defaulted argument.
40-
func good(file: String = #file) {
57+
func good(file: String = #file, fileID: String = #fileID, filePath: String = #filePath) {
4158
callee(file: file)
4259

4360
SomeClass.callee(file: file)
4461

4562
SomeClass().callee(file: file)
63+
64+
callee(fileID: fileID)
65+
66+
callee(filePath: filePath)
4667
}
4768

4869
// We should not warn when we surround the `#function`-defaulted argument
@@ -53,6 +74,10 @@ func disabled(function: String = #function) {
5374
SomeClass.callee(file: (function))
5475

5576
SomeClass().callee(file: (function))
77+
78+
callee(fileID: (function))
79+
80+
callee(filePath: (function))
5681
}
5782

5883
//
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
func callee(file: String = #file) {}
4+
func callee(fileID: String = #fileID) {} // expected-note {{'fileID' declared here}}
5+
func callee(filePath: String = #filePath) {} // expected-note {{'filePath' declared here}}
6+
7+
//
8+
// #file equivalence
9+
//
10+
// These cases vary depending on -enable-experimental-concise-pound-file.
11+
//
12+
13+
func passingToFile(fileID: String = #fileID, filePath: String = #filePath) {
14+
callee(file: fileID)
15+
16+
callee(file: filePath)
17+
}
18+
19+
func passingToFileID(file: String = #file, filePath: String = #filePath) {
20+
// expected-note@-1 {{did you mean for parameter 'filePath' to default to '#fileID'?}} {{63-72=#fileID}}
21+
22+
callee(fileID: file)
23+
24+
callee(fileID: filePath)
25+
// expected-warning@-1 {{parameter 'filePath' with default argument '#filePath' passed to parameter 'fileID', whose default argument is '#fileID'}}
26+
// expected-note@-2 {{add parentheses to silence this warning}} {{18-18=(}} {{26-26=)}}
27+
}
28+
29+
func passingToFilePath(file: String = #file, fileID: String = #fileID) {
30+
// expected-note@-1 {{did you mean for parameter 'fileID' to default to '#filePath'?}} {{63-70=#filePath}}
31+
32+
callee(filePath: file)
33+
34+
callee(filePath: fileID)
35+
// expected-warning@-1 {{parameter 'fileID' with default argument '#fileID' passed to parameter 'filePath', whose default argument is '#filePath'}}
36+
// expected-note@-2 {{add parentheses to silence this warning}} {{20-20=(}} {{26-26=)}}
37+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// The future "Swift 6 mode" behavior is staged in behind `-enable-experimental-concise-pound-file`.
2+
// RUN: %target-typecheck-verify-swift -enable-experimental-concise-pound-file
3+
4+
func callee(file: String = #file) {} // expected-note {{'file' declared here}}
5+
func callee(fileID: String = #fileID) {} // expected-note {{'fileID' declared here}}
6+
func callee(filePath: String = #filePath) {} // expected-note 2 {{'filePath' declared here}}
7+
8+
//
9+
// #file equivalence
10+
//
11+
// These cases vary depending on -enable-experimental-concise-pound-file.
12+
//
13+
14+
func passingToFile(fileID: String = #fileID, filePath: String = #filePath) {
15+
// expected-note@-1 {{did you mean for parameter 'filePath' to default to '#file'?}} {{65-74=#file}}
16+
17+
callee(file: fileID)
18+
19+
callee(file: filePath)
20+
// expected-warning@-1 {{parameter 'filePath' with default argument '#filePath' passed to parameter 'file', whose default argument is '#file'}}
21+
// expected-note@-2 {{add parentheses to silence this warning}} {{16-16=(}} {{24-24=)}}
22+
}
23+
24+
func passingToFileID(file: String = #file, filePath: String = #filePath) {
25+
// expected-note@-1 {{did you mean for parameter 'filePath' to default to '#fileID'?}} {{63-72=#fileID}}
26+
27+
callee(fileID: file)
28+
29+
callee(fileID: filePath)
30+
// expected-warning@-1 {{parameter 'filePath' with default argument '#filePath' passed to parameter 'fileID', whose default argument is '#fileID'}}
31+
// expected-note@-2 {{add parentheses to silence this warning}} {{18-18=(}} {{26-26=)}}
32+
}
33+
34+
func passingToFilePath(file: String = #file, fileID: String = #fileID) {
35+
// expected-note@-1 {{did you mean for parameter 'fileID' to default to '#filePath'?}} {{63-70=#filePath}}
36+
// expected-note@-2 {{did you mean for parameter 'file' to default to '#filePath'?}} {{39-44=#filePath}}
37+
38+
callee(filePath: file)
39+
// expected-warning@-1 {{parameter 'file' with default argument '#file' passed to parameter 'filePath', whose default argument is '#filePath'}}
40+
// expected-note@-2 {{add parentheses to silence this warning}} {{20-20=(}} {{24-24=)}}
41+
42+
callee(filePath: fileID)
43+
// expected-warning@-1 {{parameter 'fileID' with default argument '#fileID' passed to parameter 'filePath', whose default argument is '#filePath'}}
44+
// expected-note@-2 {{add parentheses to silence this warning}} {{20-20=(}} {{26-26=)}}
45+
}

0 commit comments

Comments
 (0)