Skip to content

Commit f697075

Browse files
committed
[Migrator] Add Swift. prefix to type(of:) expressions in Swift 3
This changed to be resolved by overload resolution in Swift 4, and so can suddenly be shadowed by similarly named properties and functions that are visible at the expression's location. When in Swift 3 mode, if there is a visible declaration named "type", add the `Swift.` prefix to disambiguate in Swift 4 mode. rdar://problem/31997321
1 parent 4a12ab5 commit f697075

File tree

5 files changed

+94
-2
lines changed

5 files changed

+94
-2
lines changed

lib/Migrator/SyntacticMigratorPass.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "swift/AST/NameLookup.h"
1314
#include "swift/AST/USRGeneration.h"
1415
#include "swift/AST/ASTVisitor.h"
1516
#include "swift/Frontend/Frontend.h"
@@ -536,6 +537,38 @@ struct SyntacticMigratorPass::Implementation : public SourceEntityWalker {
536537
return;
537538
}
538539

540+
/// If the expression is `type(of:)`, in Swift 3 it's a special 'dynamic type
541+
/// expression'. In Swift 4, this is resolved by overload resolution, so
542+
/// if there is a func type(of:) or even var type, it can shadow
543+
/// Swift.type(of:), which is probably not what people want.
544+
///
545+
/// This migration operation adds `Swift.` to disambiguate in Swift 4.
546+
void handleTypeOfFunction(const DynamicTypeExpr *DTE) {
547+
if (!SF->getASTContext().LangOpts.isSwiftVersion3()) {
548+
return;
549+
}
550+
const auto CSR = Lexer::getCharSourceRangeFromSourceRange(SM,
551+
DTE->getSourceRange());
552+
if (SM.extractText(CSR).startswith("Swift.")) {
553+
return;
554+
}
555+
556+
UnqualifiedLookup Lookup {
557+
{ SF->getASTContext().getIdentifier("type") },
558+
SF->getModuleScopeContext(),
559+
/*TypeResolver=*/nullptr,
560+
/*IsKnownPrivate=*/false,
561+
DTE->getLoc()
562+
};
563+
if (Lookup.Results.empty()) {
564+
// There won't be a name shadowing here in Swift 4, so we don't need to
565+
// do anything.
566+
return;
567+
}
568+
569+
Editor.insertBefore(DTE->getLoc(), "Swift.");
570+
}
571+
539572
bool walkToExprPre(Expr *E) override {
540573
if (auto *CE = dyn_cast<CallExpr>(E)) {
541574
handleTupleArgumentMismatches(CE);
@@ -566,6 +599,11 @@ struct SyntacticMigratorPass::Implementation : public SourceEntityWalker {
566599
break;
567600
}
568601
}
602+
603+
if (const auto *DTE = dyn_cast<DynamicTypeExpr>(E)) {
604+
handleTypeOfFunction(DTE);
605+
}
606+
569607
return true;
570608
}
571609

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// rdar://problem/32025974
2+
// XFAIL: linux
3+
// RUN: rm -rf %t && mkdir -p %t && %target-swift-frontend -c -update-code -primary-file %s -emit-migrated-file-path %t/prefix_typeof_expr.swift.result -emit-remap-file-path %t/member.swift.remap -o /dev/null
4+
// RUN: diff -u %S/prefix_typeof_expr.swift.expected %t/prefix_typeof_expr.swift.result
5+
6+
class HasTypeVar {
7+
var type: Int {
8+
precondition(true, "\(type(of: self)) should never be asked for its type")
9+
_ = Swift.type(of: 1) // Don't add another prefix to this one
10+
return 1
11+
}
12+
}
13+
14+
class HasTypeMethod {
15+
func type<T>(of: T) -> Int {
16+
_ = type(of: 1)
17+
_ = Swift.type(of: 1) // Don't add another prefix to this one
18+
return 1
19+
}
20+
}
21+
22+
func type<T>(of: T) -> Int {
23+
return 1
24+
}
25+
26+
_ = type(of: 1)
27+
_ = Swift.type(of: 1) // Don't add another prefix to this one
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// rdar://problem/32025974
2+
// XFAIL: linux
3+
// RUN: rm -rf %t && mkdir -p %t && %target-swift-frontend -c -update-code -primary-file %s -emit-migrated-file-path %t/prefix_typeof_expr.swift.result -emit-remap-file-path %t/member.swift.remap -o /dev/null
4+
// RUN: diff -u %S/prefix_typeof_expr.swift.expected %t/prefix_typeof_expr.swift.result
5+
6+
class HasTypeVar {
7+
var type: Int {
8+
precondition(true, "\(Swift.type(of: self)) should never be asked for its type")
9+
_ = Swift.type(of: 1) // Don't add another prefix to this one
10+
return 1
11+
}
12+
}
13+
14+
class HasTypeMethod {
15+
func type<T>(of: T) -> Int {
16+
_ = Swift.type(of: 1)
17+
_ = Swift.type(of: 1) // Don't add another prefix to this one
18+
return 1
19+
}
20+
}
21+
22+
func type<T>(of: T) -> Int {
23+
return 1
24+
}
25+
26+
_ = Swift.type(of: 1)
27+
_ = Swift.type(of: 1) // Don't add another prefix to this one

test/Migrator/tuple-arguments.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// FIXME: Figure out why this is not working on linux
1+
// rdar://problem/32025974
22
// XFAIL: linux
33

44
// RUN: %target-swift-frontend -typecheck %s -swift-version 3

test/Migrator/tuple-arguments.swift.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// FIXME: Figure out why this is not working on linux
1+
// rdar://problem/32025974
22
// XFAIL: linux
33

44
// RUN: %target-swift-frontend -typecheck %s -swift-version 3

0 commit comments

Comments
 (0)