Skip to content

Commit 6d2f11a

Browse files
committed
[Type checker] Synthesize Error._code witnesses as 'final' within a class.
When synthesizing the witness for Error._code, synthesize it as final. This isn't meant to be user-visible (and, therefore, isn't meant to be user-overridable), so it's a minor efficiency win. Moreover, we weren't making sure this member got synthesized in in cross-module situations, leading to runtime crashes. Fixes rdar://problem/27335637.
1 parent b5aca66 commit 6d2f11a

File tree

6 files changed

+56
-11
lines changed

6 files changed

+56
-11
lines changed

lib/Sema/DerivedConformanceError.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ static ValueDecl *deriveError_code(TypeChecker &tc, Decl *parentDecl,
150150

151151
// Define the getter.
152152
auto getterDecl = declareDerivedPropertyGetter(tc, parentDecl, nominal,
153-
intTy, intTy);
153+
intTy, intTy,
154+
/*isStatic=*/false,
155+
/*isFinal=*/true);
154156
if (isa<EnumDecl>(nominal))
155157
getterDecl->setBodySynthesizer(&deriveBodyError_enum_code);
156158
else
@@ -161,7 +163,8 @@ static ValueDecl *deriveError_code(TypeChecker &tc, Decl *parentDecl,
161163
PatternBindingDecl *pbDecl;
162164
std::tie(propDecl, pbDecl)
163165
= declareDerivedReadOnlyProperty(tc, parentDecl, nominal, C.Id_code_,
164-
intTy, intTy, getterDecl);
166+
intTy, intTy, getterDecl,
167+
/*isStatic=*/false, /*isFinal=*/true);
165168

166169
auto dc = cast<IterableDeclContext>(parentDecl);
167170
dc->addMember(getterDecl);
@@ -231,7 +234,8 @@ static ValueDecl *deriveBridgedNSError_enum_nsErrorDomain(TypeChecker &tc,
231234
// Define the getter.
232235
auto getterDecl = declareDerivedPropertyGetter(tc, parentDecl, enumDecl,
233236
stringTy, stringTy,
234-
/*isStatic=*/true);
237+
/*isStatic=*/true,
238+
/*isFinal=*/true);
235239
getterDecl->setBodySynthesizer(&deriveBodyBridgedNSError_enum_nsErrorDomain);
236240

237241
// Define the property.
@@ -241,7 +245,8 @@ static ValueDecl *deriveBridgedNSError_enum_nsErrorDomain(TypeChecker &tc,
241245
= declareDerivedReadOnlyProperty(tc, parentDecl, enumDecl,
242246
C.Id_nsErrorDomain,
243247
stringTy, stringTy,
244-
getterDecl, /*isStatic=*/true);
248+
getterDecl, /*isStatic=*/true,
249+
/*isFinal=*/true);
245250

246251
auto dc = cast<IterableDeclContext>(parentDecl);
247252
dc->addMember(getterDecl);

lib/Sema/DerivedConformanceRawRepresentable.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ static VarDecl *deriveRawRepresentable_raw(TypeChecker &tc,
133133
// Define the getter.
134134
auto getterDecl = declareDerivedPropertyGetter(tc, parentDecl, enumDecl,
135135
rawInterfaceType,
136-
rawType);
136+
rawType,
137+
/*isStatic=*/false,
138+
/*isFinal=*/false);
137139
getterDecl->setBodySynthesizer(&deriveBodyRawRepresentable_raw);
138140

139141
// Define the property.
@@ -144,7 +146,9 @@ static VarDecl *deriveRawRepresentable_raw(TypeChecker &tc,
144146
C.Id_rawValue,
145147
rawInterfaceType,
146148
rawType,
147-
getterDecl);
149+
getterDecl,
150+
/*isStatic=*/false,
151+
/*isFinal=*/false);
148152

149153
auto dc = cast<IterableDeclContext>(parentDecl);
150154
dc->addMember(getterDecl);

lib/Sema/DerivedConformances.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ FuncDecl *DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc,
106106
NominalTypeDecl *typeDecl,
107107
Type propertyInterfaceType,
108108
Type propertyContextType,
109-
bool isStatic) {
109+
bool isStatic,
110+
bool isFinal) {
110111
auto &C = tc.Context;
111112
auto parentDC = cast<DeclContext>(parentDecl);
112113
auto selfDecl = ParamDecl::createUnboundSelf(SourceLoc(), parentDC, isStatic);
@@ -125,6 +126,12 @@ FuncDecl *DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc,
125126
getterDecl->setImplicit();
126127
getterDecl->setStatic(isStatic);
127128

129+
// If this is supposed to be a final method, mark it as such.
130+
assert(isFinal || !parentDC->getAsClassOrClassExtensionContext());
131+
if (isFinal && parentDC->getAsClassOrClassExtensionContext() &&
132+
!getterDecl->isFinal())
133+
getterDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
134+
128135
// Compute the type of the getter.
129136
GenericParamList *genericParams = getterDecl->getGenericParamsOfContext();
130137
Type type = FunctionType::get(TupleType::getEmpty(C),
@@ -171,7 +178,8 @@ DerivedConformance::declareDerivedReadOnlyProperty(TypeChecker &tc,
171178
Type propertyInterfaceType,
172179
Type propertyContextType,
173180
FuncDecl *getterDecl,
174-
bool isStatic) {
181+
bool isStatic,
182+
bool isFinal) {
175183
auto &C = tc.Context;
176184
auto parentDC = cast<DeclContext>(parentDecl);
177185

@@ -185,6 +193,12 @@ DerivedConformance::declareDerivedReadOnlyProperty(TypeChecker &tc,
185193
propDecl->setAccessibility(getterDecl->getFormalAccess());
186194
propDecl->setInterfaceType(propertyInterfaceType);
187195

196+
// If this is supposed to be a final property, mark it as such.
197+
assert(isFinal || !parentDC->getAsClassOrClassExtensionContext());
198+
if (isFinal && parentDC->getAsClassOrClassExtensionContext() &&
199+
!propDecl->isFinal())
200+
propDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
201+
188202
Pattern *propPat = new (C) NamedPattern(propDecl, /*implicit*/ true);
189203
propPat->setType(propertyContextType);
190204
propPat = new (C) TypedPattern(propPat,

lib/Sema/DerivedConformances.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ FuncDecl *declareDerivedPropertyGetter(TypeChecker &tc,
113113
NominalTypeDecl *typeDecl,
114114
Type propertyInterfaceType,
115115
Type propertyContextType,
116-
bool isStatic = false);
116+
bool isStatic,
117+
bool isFinal);
117118

118119
/// Declare a read-only property with an existing getter.
119120
std::pair<VarDecl *, PatternBindingDecl *>
@@ -124,7 +125,8 @@ declareDerivedReadOnlyProperty(TypeChecker &tc,
124125
Type propertyInterfaceType,
125126
Type propertyContextType,
126127
FuncDecl *getterDecl,
127-
bool isStatic = false);
128+
bool isStatic,
129+
bool isFinal);
128130

129131

130132
/// Build a reference to the 'self' decl of a derived function.

test/SILGen/Inputs/errors_other.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Parse of the 'errors' test.
2+
import Swift
3+
4+
class OtherError : Error { }
5+
6+

test/SILGen/errors.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -parse-stdlib -emit-silgen -verify %s | FileCheck %s
1+
// RUN: %target-swift-frontend -parse-stdlib -emit-silgen -verify -primary-file %s %S/Inputs/errors_other.swift | FileCheck %s
22

33
import Swift
44

@@ -885,3 +885,17 @@ func testOptionalTryNeverFailsAddressOnly<T>(_ obj: T) {
885885
func testOptionalTryNeverFailsAddressOnlyVar<T>(_ obj: T) {
886886
var copy = try? obj // expected-warning {{no calls to throwing functions occur within 'try' expression}} expected-warning {{initialization of variable 'copy' was never used; consider replacing with assignment to '_' or removing it}}
887887
}
888+
889+
class SomeErrorClass : Error { }
890+
891+
// CHECK-LABEL: sil_vtable SomeErrorClass
892+
// CHECK-NEXT: #SomeErrorClass.deinit!deallocator: _TFC6errors14SomeErrorClassD
893+
// CHECK-NEXT: #SomeErrorClass.init!initializer.1: _TFC6errors14SomeErrorClasscfT_S0_
894+
// CHECK-NEXT: }
895+
896+
class OtherErrorSub : OtherError { }
897+
898+
// CHECK-LABEL: sil_vtable OtherErrorSub {
899+
// CHECK-NEXT: #OtherError.init!initializer.1: _TFC6errors13OtherErrorSubcfT_S0_ // OtherErrorSub.init() -> OtherErrorSub
900+
// CHECK-NEXT: #OtherErrorSub.deinit!deallocator: _TFC6errors13OtherErrorSubD // OtherErrorSub.__deallocating_deinit
901+
// CHECK-NEXT:}

0 commit comments

Comments
 (0)