Skip to content

Commit 88742f5

Browse files
authored
Merge pull request #17227 from slavapestov/init-declname-hack
Sema: Fudge backward compatibility for `init` special declname
2 parents 6257ebe + 75bef7c commit 88742f5

File tree

6 files changed

+123
-7
lines changed

6 files changed

+123
-7
lines changed

lib/FrontendTool/ReferenceDependencies.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,11 +354,16 @@ bool swift::emitReferenceDependencies(DiagnosticEngine &diags, SourceFile *SF,
354354
llvm::array_pod_sort(sortedMembers.begin(), sortedMembers.end(),
355355
[](const TableEntryTy *lhs,
356356
const TableEntryTy *rhs) -> int {
357-
if (lhs->first.first == rhs->first.first)
358-
return lhs->first.second.compare(rhs->first.second);
357+
if (auto cmp = lhs->first.first->getName().compare(rhs->first.first->getName()))
358+
return cmp;
359359

360-
if (lhs->first.first->getName() != rhs->first.first->getName())
361-
return lhs->first.first->getName().compare(rhs->first.first->getName());
360+
if (auto cmp = lhs->first.second.compare(rhs->first.second))
361+
return cmp;
362+
363+
// We can have two entries with the same member name if one of them
364+
// was the special 'init' name and the other is the plain 'init' token.
365+
if (lhs->second != rhs->second)
366+
return lhs->second ? -1 : 1;
362367

363368
// Break type name ties by mangled name.
364369
auto lhsMangledName = mangleTypeAsContext(lhs->first.first);

lib/Sema/CSSimplify.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3123,9 +3123,18 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
31233123
// Look for members within the base.
31243124
LookupResult &lookup = lookupMember(instanceTy, memberName);
31253125

3126+
// If this is true, we're using type construction syntax (Foo()) rather
3127+
// than an explicit call to `init` (Foo.init()).
3128+
bool isImplicitInit = false;
31263129
TypeBase *favoredType = nullptr;
31273130
if (memberName.isSimpleName(DeclBaseName::createConstructor())) {
3128-
if (auto anchor = memberLocator->getAnchor()) {
3131+
SmallVector<LocatorPathElt, 2> parts;
3132+
if (auto *anchor = memberLocator->getAnchor()) {
3133+
auto path = memberLocator->getPath();
3134+
if (!path.empty())
3135+
if (path.back().getKind() == ConstraintLocator::ConstructorMember)
3136+
isImplicitInit = true;
3137+
31293138
if (auto applyExpr = dyn_cast<ApplyExpr>(anchor)) {
31303139
auto argExpr = applyExpr->getArg();
31313140
favoredType = getFavoredType(argExpr);
@@ -3340,6 +3349,20 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
33403349
/*isBridged=*/false,
33413350
/*isUnwrappedOptional=*/false));
33423351

3352+
// Backward compatibility hack. In Swift 4, `init` and init were
3353+
// the same name, so you could write "foo.init" to look up a
3354+
// method or property named `init`.
3355+
if (!TC.Context.isSwiftVersionAtLeast(5) &&
3356+
memberName.getBaseName() == DeclBaseName::createConstructor() &&
3357+
!isImplicitInit) {
3358+
auto &compatLookup = lookupMember(instanceTy,
3359+
TC.Context.getIdentifier("init"));
3360+
for (auto result : compatLookup)
3361+
addChoice(getOverloadChoice(result.getValueDecl(),
3362+
/*isBridged=*/false,
3363+
/*isUnwrappedOptional=*/false));
3364+
}
3365+
33433366
// If the instance type is a bridged to an Objective-C type, perform
33443367
// a lookup into that Objective-C type.
33453368
if (bridgedType) {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 4
2+
3+
// https://bugs.swift.org/browse/SR-1660
4+
5+
enum DayOfTheWeek : Int {
6+
case monday = 0
7+
case `inout` = 1
8+
case `init` = 2
9+
case friday = 3
10+
case tuesday = 4
11+
}
12+
13+
let _: DayOfTheWeek = DayOfTheWeek.init
14+
15+
let _: DayOfTheWeek = DayOfTheWeek.`init`
16+
17+
func match(_ d: DayOfTheWeek) {
18+
switch d {
19+
case .monday: break
20+
case .`inout`: break
21+
case .`init`: break
22+
case .friday: break
23+
case .tuesday: break
24+
}
25+
}
26+
27+
enum Fox {
28+
case `init`(Int)
29+
30+
init() {
31+
self = .`init`(10)
32+
}
33+
}
34+
35+
let _: Fox = Fox(10)
36+
// expected-error@-1 {{argument passed to call that takes no arguments}}
37+
38+
let _: () -> Fox = Fox.init
39+
let _: (Int) -> Fox = Fox.`init`
40+
41+
func match(_ f: Fox) {
42+
switch f {
43+
case .`init`(let n): _ = n
44+
}
45+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 4
2+
3+
protocol P1 {
4+
static func `init`(_: Int) // expected-note {{protocol requires function 'init' with type '(Int) -> ()'; do you want to add a stub?}}
5+
// expected-note@-1 {{did you mean 'init'?}}
6+
}
7+
8+
struct S11 : P1 {
9+
static func `init`(_: Int) {}
10+
}
11+
12+
struct S12 : P1 { // expected-error {{type 'S12' does not conform to protocol 'P1'}}
13+
init(_: Int) {}
14+
}
15+
16+
protocol P2 {
17+
init(_: Int) // expected-note {{protocol requires initializer 'init' with type 'Int'; do you want to add a stub?}}
18+
}
19+
20+
struct S21 : P2 { // expected-error {{type 'S21' does not conform to protocol 'P2'}}
21+
// expected-note@-1 {{candidate has non-matching type '()'}}
22+
static func `init`(_: Int) {}
23+
}
24+
25+
struct S22 : P2 {
26+
init(_: Int) {}
27+
}
28+
29+
_ = S11(0) // expected-error {{argument passed to call that takes no arguments}}
30+
_ = S11.init(0)
31+
_ = S11.`init`(0)
32+
33+
_ = S12(0)
34+
_ = S12.init(0)
35+
_ = S12.`init`(0) // expected-error {{type 'S12' has no member 'init'}}
36+
37+
_ = S21(0) // expected-error {{argument passed to call that takes no arguments}}
38+
_ = S21.init(0)
39+
_ = S21.`init`(0)
40+
41+
_ = S22(0)
42+
_ = S22.init(0)
43+
_ = S22.`init`(0) // expected-error {{type 'S22' has no member 'init'}}

test/decl/enum/special_case_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 5
22

33
// https://bugs.swift.org/browse/SR-1660
44

test/decl/func/special_func_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 5
22

33
protocol P1 {
44
static func `init`(_: Int) // expected-note {{protocol requires function 'init' with type '(Int) -> ()'; do you want to add a stub?}}

0 commit comments

Comments
 (0)