Skip to content

Commit ebd701c

Browse files
committed
Represent the name of destructors by a special DeclBaseName
No longer use the known identifier `deinit` for destructors. This allows classes to have functions called `deinit`.
1 parent 2eb36e4 commit ebd701c

File tree

18 files changed

+75
-46
lines changed

18 files changed

+75
-46
lines changed

include/swift/AST/Decl.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4866,8 +4866,6 @@ class AbstractFunctionDecl : public ValueDecl, public GenericContext {
48664866
}
48674867

48684868
public:
4869-
Identifier getName() const { return getFullName().getBaseIdentifier(); }
4870-
48714869
/// Returns the string for the base name, or "_" if this is unnamed.
48724870
StringRef getNameStr() const {
48734871
assert(!getFullName().isSpecial() && "Cannot get string for special names");
@@ -5200,6 +5198,8 @@ class FuncDecl final : public AbstractFunctionDecl,
52005198
TypeLoc FnRetType, DeclContext *Parent,
52015199
ClangNode ClangN = ClangNode());
52025200

5201+
Identifier getName() const { return getFullName().getBaseIdentifier(); }
5202+
52035203
bool isStatic() const {
52045204
return FuncDeclBits.IsStatic;
52055205
}
@@ -5648,6 +5648,8 @@ class ConstructorDecl : public AbstractFunctionDecl {
56485648
GenericParamList *GenericParams,
56495649
DeclContext *Parent);
56505650

5651+
Identifier getName() const { return getFullName().getBaseIdentifier(); }
5652+
56515653
void setParameterLists(ParamDecl *selfParam, ParameterList *bodyParams);
56525654

56535655
SourceLoc getConstructorLoc() const { return getNameLoc(); }
@@ -5839,8 +5841,8 @@ class ConstructorDecl : public AbstractFunctionDecl {
58395841
class DestructorDecl : public AbstractFunctionDecl {
58405842
ParameterList *SelfParameter;
58415843
public:
5842-
DestructorDecl(Identifier NameHack, SourceLoc DestructorLoc,
5843-
ParamDecl *selfDecl, DeclContext *Parent);
5844+
DestructorDecl(SourceLoc DestructorLoc, ParamDecl *selfDecl,
5845+
DeclContext *Parent);
58445846

58455847
void setSelfDecl(ParamDecl *selfDecl);
58465848

include/swift/AST/KnownIdentifiers.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ IDENTIFIER(decode)
4343
IDENTIFIER(decodeIfPresent)
4444
IDENTIFIER(Decoder)
4545
IDENTIFIER(decoder)
46-
IDENTIFIER(deinit)
4746
IDENTIFIER(Element)
4847
IDENTIFIER(Encodable)
4948
IDENTIFIER(encode)

lib/AST/Decl.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const {
420420
if (auto AFD = dyn_cast<AbstractFunctionDecl>(D)) {
421421
// Hide '~>' functions (but show the operator, because it defines
422422
// precedence).
423-
if (AFD->getNameStr() == "~>")
423+
if (isa<FuncDecl>(AFD) && AFD->getNameStr() == "~>")
424424
return true;
425425

426426
// If it's a function with a parameter with leading underscore, it's a
@@ -2557,8 +2557,7 @@ ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
25572557
}
25582558

25592559
DestructorDecl *ClassDecl::getDestructor() {
2560-
auto name = getASTContext().Id_deinit;
2561-
auto results = lookupDirect(name);
2560+
auto results = lookupDirect(DeclBaseName::createDestructor());
25622561
assert(!results.empty() && "Class without destructor?");
25632562
assert(results.size() == 1 && "More than one destructor?");
25642563
return cast<DestructorDecl>(results.front());
@@ -4572,7 +4571,20 @@ ObjCSelector AbstractFunctionDecl::getObjCSelector(
45724571
}
45734572

45744573
auto &ctx = getASTContext();
4575-
auto baseName = getName();
4574+
4575+
Identifier baseName;
4576+
if (isa<DestructorDecl>(this)) {
4577+
// Deinitializers are always called "dealloc".
4578+
return ObjCSelector(ctx, 0, ctx.Id_dealloc);
4579+
} else if (auto func = dyn_cast<FuncDecl>(this)) {
4580+
// Otherwise cast this to be able to access getName()
4581+
baseName = func->getName();
4582+
} else if (auto ctor = dyn_cast<ConstructorDecl>(this)) {
4583+
baseName = ctor->getName();
4584+
} else {
4585+
llvm_unreachable("Unknown subclass of AbstractFunctionDecl");
4586+
}
4587+
45764588
auto argNames = getFullName().getArgumentNames();
45774589

45784590
// Use the preferred name if specified
@@ -4596,11 +4608,6 @@ ObjCSelector AbstractFunctionDecl::getObjCSelector(
45964608
}
45974609
}
45984610

4599-
// Deinitializers are always called "dealloc".
4600-
if (isa<DestructorDecl>(this)) {
4601-
return ObjCSelector(ctx, 0, ctx.Id_dealloc);
4602-
}
4603-
46044611

46054612
// If this is a zero-parameter initializer with a long selector
46064613
// name, form that selector.
@@ -4960,9 +4967,10 @@ bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const {
49604967
return params->get(0)->getInterfaceType()->isVoid();
49614968
}
49624969

4963-
DestructorDecl::DestructorDecl(Identifier NameHack, SourceLoc DestructorLoc,
4964-
ParamDecl *selfDecl, DeclContext *Parent)
4965-
: AbstractFunctionDecl(DeclKind::Destructor, Parent, NameHack, DestructorLoc,
4970+
DestructorDecl::DestructorDecl(SourceLoc DestructorLoc, ParamDecl *selfDecl,
4971+
DeclContext *Parent)
4972+
: AbstractFunctionDecl(DeclKind::Destructor, Parent,
4973+
DeclBaseName::createDestructor(), DestructorLoc,
49664974
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
49674975
/*NumParameterLists=*/1, nullptr) {
49684976
setSelfDecl(selfDecl);

lib/AST/DeclContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ unsigned DeclContext::printContext(raw_ostream &OS, unsigned indent) const {
806806
break;
807807
case DeclContextKind::AbstractFunctionDecl: {
808808
auto *AFD = cast<AbstractFunctionDecl>(this);
809-
OS << " name=" << AFD->getName();
809+
OS << " name=" << AFD->getFullName();
810810
if (AFD->hasInterfaceType())
811811
OS << " : " << AFD->getInterfaceType();
812812
else

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5768,8 +5768,8 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
57685768
auto *SelfDecl = ParamDecl::createUnboundSelf(DestructorLoc, CurDeclContext);
57695769

57705770
Scope S(this, ScopeKind::DestructorBody);
5771-
auto *DD = new (Context) DestructorDecl(Context.Id_deinit, DestructorLoc,
5772-
SelfDecl, CurDeclContext);
5771+
auto *DD = new (Context) DestructorDecl(DestructorLoc, SelfDecl,
5772+
CurDeclContext);
57735773

57745774
// Parse the body.
57755775
if (Tok.is(tok::l_brace)) {

lib/ParseSIL/ParseSIL.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -434,9 +434,6 @@ bool SILParser::parseSILIdentifier(Identifier &Result, SourceLoc &Loc,
434434
// A binary operator can be part of a SILDeclRef.
435435
Result = P.Context.getIdentifier(P.Tok.getText());
436436
break;
437-
case tok::kw_deinit:
438-
Result = P.Context.Id_deinit;
439-
break;
440437
case tok::kw_init:
441438
Result = P.Context.Id_init;
442439
break;
@@ -1148,6 +1145,10 @@ bool SILParser::parseSILDottedPathWithoutPound(ValueDecl *&Decl,
11481145
P.consumeToken();
11491146
FullName.push_back(DeclBaseName::createSubscript());
11501147
break;
1148+
case tok::kw_deinit:
1149+
P.consumeToken();
1150+
FullName.push_back(DeclBaseName::createDestructor());
1151+
break;
11511152
default:
11521153
if (parseSILIdentifier(Id, diag::expected_sil_constant))
11531154
return true;

lib/SIL/SILPrinter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ static void printValueDecl(ValueDecl *Decl, raw_ostream &OS) {
239239

240240
if (Decl->isOperator()) {
241241
OS << '"' << Decl->getBaseName() << '"';
242-
} else if (Decl->getBaseName() == "subscript") {
242+
} else if (Decl->getBaseName() == "subscript" ||
243+
Decl->getBaseName() == "deinit") {
243244
OS << '`' << Decl->getBaseName() << '`';
244245
} else {
245246
OS << Decl->getBaseName();

lib/Sema/CSDiag.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,6 +2532,9 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
25322532
if (memberName.getBaseName().getKind() == DeclBaseName::Kind::Subscript) {
25332533
diagnose(loc, diag::type_not_subscriptable, baseObjTy)
25342534
.highlight(baseRange);
2535+
} else if (memberName.getBaseName() == "deinit") {
2536+
// Specialised diagnostic if trying to access deinitialisers
2537+
diagnose(loc, diag::destructor_not_accessible).highlight(baseRange);
25352538
} else if (auto metatypeTy = baseObjTy->getAs<MetatypeType>()) {
25362539
auto instanceTy = metatypeTy->getInstanceType();
25372540
tryTypoCorrection();
@@ -2691,10 +2694,6 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
26912694

26922695
return;
26932696
}
2694-
case MemberLookupResult::UR_DestructorInaccessible: {
2695-
diagnose(nameLoc, diag::destructor_not_accessible);
2696-
return;
2697-
}
26982697
}
26992698
}
27002699

lib/Sema/CSSimplify.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3206,11 +3206,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
32063206
// reasonable choice.
32073207
auto addChoice = [&](ValueDecl *cand, bool isBridged,
32083208
bool isUnwrappedOptional) {
3209-
// Destructors cannot be referenced manually
3210-
if (isa<DestructorDecl>(cand)) {
3211-
result.addUnviable(cand, MemberLookupResult::UR_DestructorInaccessible);
3212-
return;
3213-
}
32143209
// If the result is invalid, skip it.
32153210
TC.validateDecl(cand);
32163211
if (cand->isInvalid()) {

lib/Sema/CodeSynthesis.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2185,8 +2185,7 @@ void TypeChecker::addImplicitDestructor(ClassDecl *CD) {
21852185

21862186
auto *selfDecl = ParamDecl::createSelf(CD->getLoc(), CD);
21872187

2188-
auto *DD = new (Context) DestructorDecl(Context.Id_deinit, CD->getLoc(),
2189-
selfDecl, CD);
2188+
auto *DD = new (Context) DestructorDecl(CD->getLoc(), selfDecl, CD);
21902189

21912190
DD->setImplicit();
21922191

lib/Sema/ConstraintSystem.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -840,9 +840,6 @@ struct MemberLookupResult {
840840

841841
/// The member is inaccessible (e.g. a private member in another file).
842842
UR_Inaccessible,
843-
844-
// A type's destructor cannot be referenced
845-
UR_DestructorInaccessible,
846843
};
847844

848845
/// This is a list of considered, but rejected, candidates, along with a

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4969,12 +4969,10 @@ static void recordConformanceDependency(DeclContext *DC,
49694969
Conformance->getDeclContext()->getParentModule())
49704970
return;
49714971

4972-
auto &Context = DC->getASTContext();
4973-
49744972
// FIXME: 'deinit' is being used as a dummy identifier here. Really we
49754973
// don't care about /any/ of the type's members, only that it conforms to
49764974
// the protocol.
4977-
tracker->addUsedMember({Adoptee, Context.Id_deinit},
4975+
tracker->addUsedMember({Adoptee, DeclBaseName::createDestructor()},
49784976
DC->isCascadingContextForLookup(InExpression));
49794977
}
49804978

lib/Serialization/Deserialization.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3553,8 +3553,7 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
35533553
if (declOrOffset.isComplete())
35543554
return declOrOffset;
35553555

3556-
auto dtor = createDecl<DestructorDecl>(ctx.Id_deinit, SourceLoc(),
3557-
/*selfpat*/nullptr, DC);
3556+
auto dtor = createDecl<DestructorDecl>(SourceLoc(), /*selfpat*/nullptr, DC);
35583557
declOrOffset = dtor;
35593558

35603559
configureGenericEnvironment(dtor, genericEnvID);

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1791,7 +1791,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
17911791
bool isProtocolExt = fn->getDeclContext()->getAsProtocolExtensionContext();
17921792
XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
17931793
addTypeRef(ty),
1794-
addDeclBaseNameRef(fn->getName()),
1794+
addDeclBaseNameRef(fn->getBaseName()),
17951795
isProtocolExt,
17961796
fn->isStatic());
17971797

test/NameBinding/scope_map.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ class LazyProperties {
443443
// CHECK-SEARCHES-NEXT: DefaultArgument {{.*}} [166:32 - 166:32] expanded
444444
// CHECK-SEARCHES-NEXT: Module name=scope_map
445445
// CHECK-SEARCHES-NEXT: FileUnit file="{{.*}}scope_map.swift"
446-
// CHECK-SEARCHES-NEXT: AbstractFunctionDecl name=defaultArguments : (Int, Int) -> ()
446+
// CHECK-SEARCHES-NEXT: AbstractFunctionDecl name=defaultArguments(i:j:) : (Int, Int) -> ()
447447
// CHECK-SEARCHES-NEXT: {{.*}} Initializer DefaultArgument index=0
448448

449449
// CHECK-SEARCHES-LABEL: ***Scope at 179:18***

test/SILGen/vtables.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,12 @@ class SubscriptAsFunction {
183183
// CHECK-LABEL: sil_vtable SubscriptAsFunction {
184184
// CHECK-NOT: #SubscriptAsFunction.subscript
185185
// CHECK: #SubscriptAsFunction.`subscript`!1
186+
187+
188+
class DeinitAsFunction {
189+
func `deinit`() {}
190+
}
191+
192+
// CHECK-LABEL: sil_vtable DeinitAsFunction {
193+
// CHECK: #DeinitAsFunction.`deinit`!1
194+
// CHECK: #DeinitAsFunction.deinit!deallocator

test/decl/protocol/special/coding/class_codable_default_initializer.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// A class with no initializers (which has non-initialized properties so a
44
// default constructor can be synthesized) should produce an error.
55
class NoInitializers { // expected-error {{class 'NoInitializers' has no initializers}}
6-
// expected-note@-1 {{did you mean 'deinit'?}}
76
var x: Double // expected-note {{stored property 'x' without initial value prevents synthesized initializers}}
87

98
func foo() {

test/expr/postfix/dot/dot_keywords.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,26 @@ let sr3043 = SR3043Derived()
5454
sr3043.deinit() // expected-error {{deinitializers cannot be accessed}}
5555
sr3043.deinit // expected-error {{deinitializers cannot be accessed}}
5656
SR3043Derived.deinit() // expected-error {{deinitializers cannot be accessed}}
57+
58+
// Allow deinit functions in classes
59+
60+
class ClassWithDeinitFunc {
61+
func `deinit`() {
62+
}
63+
64+
func `deinit`(a: SR3043Base) {
65+
}
66+
}
67+
68+
let instanceWithDeinitFunc = ClassWithDeinitFunc()
69+
instanceWithDeinitFunc.deinit()
70+
_ = instanceWithDeinitFunc.deinit(a:)
71+
_ = instanceWithDeinitFunc.deinit as () -> Void
72+
SR3043Derived.deinit() // expected-error {{deinitializers cannot be accessed}}
73+
74+
class ClassWithDeinitMember {
75+
var `deinit`: SR3043Base?
76+
}
77+
78+
let instanceWithDeinitMember = ClassWithDeinitMember()
79+
_ = instanceWithDeinitMember.deinit

0 commit comments

Comments
 (0)