Skip to content

Commit dbe99d7

Browse files
johnno1962slavapestov
authored andcommitted
Make Self available to member functions (SE-0068?) (#22863)
* Make Self available to instance member functions (SE-0068?) * Works for value types and static functions. * Further experiments with TypeExpr * Move Self processing off diagnostic path * diagnostic instead of assertion fail * TypeExpr of DynamicSelfType now working. * Update tests for availability of Self * Cast to Self fixed! * Self not available as type in classes except for return type * Could it be this simple? * Nearly there * Fix function decls using Self inside methods. * Fix validation-test/compiler_crashers_2_fixed/0164-sr7989.swift * Fix of ./validation-test/compiler_crashers_2_fixed/0179-rdar44963974.swift * "Un-fix" validation-test/compiler_crashers_2_fixed/0164-sr7989.swift * CHANGELOG entry * Update CHANGELOG.md Co-Authored-By: johnno1962 <[email protected]> * Update CHANGELOG.md
1 parent 98d2d5d commit dbe99d7

File tree

7 files changed

+151
-16
lines changed

7 files changed

+151
-16
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ CHANGELOG
2525
Swift 5.1
2626
---------
2727

28+
* [SE-0068][]:
29+
30+
`Self` can now be used inside member functions and for function arguments of structs and enums to refer to the containing type.
31+
2832
* [SR-7799][]:
2933

3034
Enum cases can now be matched against an optional enum without

lib/AST/DeclContext.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,8 @@ bool DeclContext::isTypeContext() const {
223223
DeclContext *DeclContext::getInnermostTypeContext() {
224224
auto dc = this;
225225
do {
226-
if (auto decl = dc->getAsDecl())
227-
if (isa<NominalTypeDecl>(decl) || isa<ExtensionDecl>(decl))
228-
return dc;
226+
if (dc->isTypeContext())
227+
return dc;
229228
} while ((dc = dc->getParent()));
230229

231230
return nullptr;

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,18 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) {
551551
};
552552

553553
if (!isConfused) {
554+
if (Name == Context.Id_Self) {
555+
if (DeclContext *typeContext = DC->getInnermostTypeContext()){
556+
Type SelfType = typeContext->getSelfInterfaceType();
557+
558+
if (typeContext->getSelfClassDecl())
559+
SelfType = DynamicSelfType::get(SelfType, Context);
560+
SelfType = DC->mapTypeIntoContext(SelfType);
561+
return new (Context) TypeExpr(TypeLoc(new (Context)
562+
FixedTypeRepr(SelfType, Loc)));
563+
}
564+
}
565+
554566
TypoCorrectionResults corrections(*this, Name, nameLoc);
555567
performTypoCorrection(DC, UDRE->getRefKind(), Type(),
556568
lookupOptions, corrections);

lib/Sema/TypeCheckType.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,10 +1057,23 @@ static Type diagnoseUnknownType(TypeResolution resolution,
10571057
NominalTypeDecl *nominal = nullptr;
10581058
if ((nominalDC = dc->getInnermostTypeContext()) &&
10591059
(nominal = nominalDC->getSelfNominalTypeDecl())) {
1060-
// Attempt to refer to 'Self' within a non-protocol nominal
1061-
// type. Fix this by replacing 'Self' with the nominal type name.
10621060
assert(!isa<ProtocolDecl>(nominal) && "Cannot be a protocol");
10631061

1062+
bool insideClass = nominalDC->getSelfClassDecl() != nullptr;
1063+
AbstractFunctionDecl *methodDecl = dc->getInnermostMethodContext();
1064+
bool declaringMethod = methodDecl &&
1065+
methodDecl->getDeclContext() == dc->getParentForLookup();
1066+
1067+
if (((!insideClass || !declaringMethod) &&
1068+
!options.is(TypeResolverContext::GenericRequirement)) ||
1069+
options.is(TypeResolverContext::ExplicitCastExpr)) {
1070+
Type SelfType = nominal->getSelfInterfaceType();
1071+
if (insideClass)
1072+
SelfType = DynamicSelfType::get(SelfType, ctx);
1073+
return resolution.mapTypeIntoContext(SelfType);
1074+
}
1075+
1076+
// Attempt to refer to 'Self' within a non-protocol nominal type.
10641077
// Produce a Fix-It replacing 'Self' with the nominal type name.
10651078
auto name = getDeclNameFromContext(dc, nominal);
10661079
diags.diagnose(comp->getIdLoc(), diag::self_in_nominal, name)

test/decl/func/dynamic_self.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ func inFunction() {
1010
}
1111

1212
struct S0 {
13-
func f() -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{15-19=S0}}
13+
func f() -> Self { }
1414

15-
func g(_ ds: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{16-20=S0}}
15+
func g(_ ds: Self) { }
1616
}
1717

1818
enum E0 {
19-
func f() -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'E0'?}}{{15-19=E0}}
19+
func f() -> Self { }
2020

21-
func g(_ ds: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'E0'?}}{{16-20=E0}}
21+
func g(_ ds: Self) { }
2222
}
2323

2424
class C0 {
@@ -85,11 +85,11 @@ class C1 {
8585
var x: Int = self // expected-error{{cannot convert value of type 'Self.Type' to specified type 'Int'}}
8686

8787
// Can't utter Self within the body of a method.
88-
var c1 = C1(int: 5) as Self // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C1'?}} {{28-32=C1}}
88+
var c1 = C1(int: 5) as Self // expected-error{{'C1' is not convertible to 'Self'; did you mean to use 'as!' to force downcast?}}
8989

9090
if b { return self.init(int: 5) }
9191

92-
return Self() // expected-error{{use of unresolved identifier 'Self'; did you mean 'self'?}}
92+
return Self() // expected-error{{non-nominal type 'Self' does not support explicit initialization}}
9393
}
9494

9595
// This used to crash because metatype construction went down a
@@ -412,4 +412,4 @@ class SelfOperator {
412412
func useSelfOperator() {
413413
let s = SelfOperator()
414414
_ = s + s
415-
}
415+
}

test/decl/nested/type_in_type.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,6 @@ extension OuterGeneric.MidNonGeneric {
417417
}
418418

419419
func doMoreStuffWrong() -> Self {
420-
// expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'OuterGeneric.MidNonGeneric'?}}
421420

422421
}
423422
}

test/type/self.swift

Lines changed: 111 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
// RUN: %target-typecheck-verify-swift -swift-version 5
22

33
struct S0<T> {
4-
func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{21-25=S0}}
4+
func foo(_ other: Self) { }
55
}
66

77
class C0<T> {
88
func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C0'?}}{{21-25=C0}}
99
}
1010

1111
enum E0<T> {
12-
func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'E0'?}}{{21-25=E0}}
12+
func foo(_ other: Self) { }
1313
}
1414

1515
// rdar://problem/21745221
@@ -23,7 +23,7 @@ extension X {
2323
}
2424

2525
extension X.Inner {
26-
func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'X.Inner'?}}{{21-25=X.Inner}}
26+
func foo(_ other: Self) { }
2727
}
2828

2929
// SR-695
@@ -43,3 +43,111 @@ final class FinalMario : Mario {
4343
}
4444
}
4545

46+
// These references to Self are now possible (SE-0068)
47+
48+
class A<T> {
49+
let b: Int
50+
required init(a: Int) {
51+
print("\(Self.self).\(#function)")
52+
Self.y()
53+
b = a
54+
}
55+
static func z(n: Self? = nil) {
56+
// expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'A'?}}
57+
print("\(Self.self).\(#function)")
58+
}
59+
class func y() {
60+
print("\(Self.self).\(#function)")
61+
Self.z()
62+
}
63+
func x() -> A? {
64+
print("\(Self.self).\(#function)")
65+
Self.y()
66+
Self.z()
67+
let _: Self = Self.init(a: 66)
68+
// expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'A'?}}
69+
return Self.init(a: 77) as? Self as? A
70+
// expected-warning@-1 {{conditional cast from 'Self' to 'Self' always succeeds}}
71+
// expected-warning@-2 {{conditional downcast from 'Self?' to 'A<T>' is equivalent to an implicit conversion to an optional 'A<T>'}}
72+
}
73+
}
74+
75+
class B: A<Int> {
76+
let a: Int
77+
required convenience init(a: Int) {
78+
print("\(Self.self).\(#function)")
79+
self.init()
80+
}
81+
init() {
82+
print("\(Self.self).\(#function)")
83+
Self.y()
84+
Self.z()
85+
a = 99
86+
super.init(a: 88)
87+
}
88+
override class func y() {
89+
print("override \(Self.self).\(#function)")
90+
}
91+
}
92+
93+
class C {
94+
required init() {
95+
}
96+
func f() {
97+
func g(_: Self) {}
98+
}
99+
func g() {
100+
_ = Self.init() as? Self
101+
// expected-warning@-1 {{conditional cast from 'Self' to 'Self' always succeeds}}
102+
}
103+
}
104+
105+
struct S2 {
106+
let x = 99
107+
struct S3<T> {
108+
let x = 99
109+
static func x() {
110+
Self.y()
111+
}
112+
func f() {
113+
func g(_: Self) {}
114+
}
115+
static func y() {
116+
print("HERE")
117+
}
118+
func foo(a: [Self]) -> Self? {
119+
Self.x()
120+
return Self.init() as? Self
121+
// expected-warning@-1 {{conditional cast from 'S2.S3<T>' to 'S2.S3<T>' always succeeds}}
122+
}
123+
}
124+
}
125+
126+
extension S2 {
127+
static func x() {
128+
Self.y()
129+
}
130+
static func y() {
131+
print("HERE")
132+
}
133+
func f() {
134+
func g(_: Self) {}
135+
}
136+
func foo(a: [Self]) -> Self? {
137+
Self.x()
138+
return Self.init() as? Self
139+
// expected-warning@-1 {{conditional cast from 'S2' to 'S2' always succeeds}}
140+
}
141+
}
142+
143+
enum E {
144+
static func f() {
145+
func g(_: Self) {}
146+
print("f()")
147+
}
148+
case e
149+
func h(h: Self) -> Self {
150+
Self.f()
151+
return .e
152+
}
153+
}

0 commit comments

Comments
 (0)