Skip to content

Commit fbdeceb

Browse files
committed
AST: Restore unqualified lookup quirk for Swift 3 mode
In Swift 3, unqualified lookup would skip static methods when performing a lookup from instance context. In Swift 4 mode, if a module method is shadowed by a static method, you will need to qualify the module method with the module name. It would have been nice to isolate the quirk in Sema and not AST, but unfortunately UnqualifiedLookup only proceeds to lookup in the module if scope-based lookup failed to find anything, and I don't want to change that since it risks introducing performance regressions. Fixes <rdar://problem/29961715>.
1 parent 8fff45d commit fbdeceb

File tree

6 files changed

+67
-9
lines changed

6 files changed

+67
-9
lines changed

lib/AST/NameLookup.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -649,13 +649,16 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
649649
ValueDecl *MetaBaseDecl = nullptr;
650650
GenericParamList *GenericParams = nullptr;
651651
Type ExtendedType;
652-
652+
bool isTypeLookup = false;
653+
653654
// If this declcontext is an initializer for a static property, then we're
654655
// implicitly doing a static lookup into the parent declcontext.
655656
if (auto *PBI = dyn_cast<PatternBindingInitializer>(DC))
656657
if (!DC->getParent()->isModuleScopeContext()) {
657-
if (PBI->getBinding())
658+
if (auto *PBD = PBI->getBinding()) {
659+
isTypeLookup = PBD->isStatic();
658660
DC = DC->getParent();
661+
}
659662
}
660663

661664
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
@@ -694,6 +697,10 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
694697
->getAsNominalTypeOrNominalTypeExtensionContext();
695698
DC = DC->getParent();
696699

700+
if (auto *FD = dyn_cast<FuncDecl>(AFD))
701+
if (FD->isStatic())
702+
isTypeLookup = true;
703+
697704
// If we're not in the body of the function, the base declaration
698705
// is the nominal type, not 'self'.
699706
if (Loc.isValid() &&
@@ -780,6 +787,23 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
780787
DC->lookupQualified(ExtendedType, Name, options, TypeResolver, Lookup);
781788
bool FoundAny = false;
782789
for (auto Result : Lookup) {
790+
// In Swift 3 mode, unqualified lookup skips static methods when
791+
// performing lookup from instance context.
792+
//
793+
// We don't want to carry this forward to Swift 4, since it makes
794+
// for poor diagnostics.
795+
//
796+
// Also, it was quite a special case and not as general as it
797+
// should be -- it didn't apply to properties or subscripts, and
798+
// the opposite case where we're in static context and an instance
799+
// member shadows the module member wasn't handled either.
800+
if (Ctx.isSwiftVersion3() &&
801+
!isTypeLookup &&
802+
isa<FuncDecl>(Result) &&
803+
cast<FuncDecl>(Result)->isStatic()) {
804+
continue;
805+
}
806+
783807
// Classify this declaration.
784808
FoundAny = true;
785809

test/Compatibility/members.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 3
2+
3+
struct X {
4+
func f1(_ i: Int) { }
5+
mutating func f1(_ f: Float) { }
6+
}
7+
8+
func g0(_: (inout X) -> (Float) -> ()) {}
9+
10+
// This becomes an error in Swift 4 mode -- probably a bug
11+
g0(X.f1)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 3
2+
3+
// Stupid Swift 3 unqualified lookup quirk
4+
5+
func f3(_ x: Int, _ y: Int, z: Int) { } // expected-note{{did you mean 'f3'?}}
6+
7+
struct S0 {
8+
func testS0() {
9+
_ = f3(_:y:z:) // expected-error{{use of unresolved identifier 'f3(_:y:z:)'}}
10+
}
11+
12+
static func f3(_ x: Int, y: Int, z: Int) -> S0 { return S0() }
13+
}
14+
15+
extension Float {
16+
func isClose(to: Float, epiValue: Float = 1e-5) -> Bool {
17+
// Float.abs() and Swift.abs() are both visible here, but
18+
// Swift 3 drops 'Float.abs()'.
19+
return abs(self - to) < epiValue
20+
}
21+
}

test/Constraints/members.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
2-
3-
import Swift
1+
// RUN: %target-typecheck-verify-swift -swift-version 4
42

53
////
64
// Members of structs
@@ -9,9 +7,9 @@ import Swift
97
struct X {
108
func f0(_ i: Int) -> X { }
119

12-
func f1(_ i: Int) { }
10+
func f1(_ i: Int) { } // expected-note {{found this candidate}}
1311

14-
mutating func f1(_ f: Float) { }
12+
mutating func f1(_ f: Float) { } // expected-note {{found this candidate}}
1513

1614
func f2<T>(_ x: T) -> T { }
1715
}
@@ -29,7 +27,11 @@ func g0(_: (inout X) -> (Float) -> ()) {}
2927

3028
_ = x.f0(i)
3129
x.f0(i).f1(i)
30+
31+
// FIXME: Is this a bug in Swift 4 mode?
3232
g0(X.f1)
33+
// expected-error@-1 {{ambiguous reference to member 'f1'}}
34+
3335
_ = x.f0(x.f2(1))
3436
_ = x.f0(1).f2(i)
3537
_ = yf.f0(1)

test/expr/primary/unqualified_name.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -swift-version 4
22

33
func f0(_ x: Int, y: Int, z: Int) { }
44
func f1(_ x: Int, while: Int) { }

test/expr/unary/selector/property.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -disable-objc-attr-requires-foundation-module -typecheck -primary-file %s %S/Inputs/property_helper.swift -verify
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -disable-objc-attr-requires-foundation-module -typecheck -primary-file %s %S/Inputs/property_helper.swift -verify -swift-version 4
22
import ObjectiveC
33

44
// REQUIRES: objc_interop

0 commit comments

Comments
 (0)