mirror of
https://github.com/apple/swift.git
synced 2026-06-27 12:25:55 +02:00
Merge pull request #10965 from ahoppen/deinit-special-name
This commit is contained in:
@@ -4866,8 +4866,6 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
Identifier getName() const { return getFullName().getBaseIdentifier(); }
|
||||
|
||||
/// Returns the string for the base name, or "_" if this is unnamed.
|
||||
StringRef getNameStr() const {
|
||||
assert(!getFullName().isSpecial() && "Cannot get string for special names");
|
||||
@@ -5200,6 +5198,8 @@ public:
|
||||
TypeLoc FnRetType, DeclContext *Parent,
|
||||
ClangNode ClangN = ClangNode());
|
||||
|
||||
Identifier getName() const { return getFullName().getBaseIdentifier(); }
|
||||
|
||||
bool isStatic() const {
|
||||
return FuncDeclBits.IsStatic;
|
||||
}
|
||||
@@ -5648,6 +5648,8 @@ public:
|
||||
GenericParamList *GenericParams,
|
||||
DeclContext *Parent);
|
||||
|
||||
Identifier getName() const { return getFullName().getBaseIdentifier(); }
|
||||
|
||||
void setParameterLists(ParamDecl *selfParam, ParameterList *bodyParams);
|
||||
|
||||
SourceLoc getConstructorLoc() const { return getNameLoc(); }
|
||||
@@ -5839,8 +5841,8 @@ public:
|
||||
class DestructorDecl : public AbstractFunctionDecl {
|
||||
ParameterList *SelfParameter;
|
||||
public:
|
||||
DestructorDecl(Identifier NameHack, SourceLoc DestructorLoc,
|
||||
ParamDecl *selfDecl, DeclContext *Parent);
|
||||
DestructorDecl(SourceLoc DestructorLoc, ParamDecl *selfDecl,
|
||||
DeclContext *Parent);
|
||||
|
||||
void setSelfDecl(ParamDecl *selfDecl);
|
||||
|
||||
|
||||
@@ -214,7 +214,8 @@ class DeclBaseName {
|
||||
public:
|
||||
enum class Kind: uint8_t {
|
||||
Normal,
|
||||
Subscript
|
||||
Subscript,
|
||||
Destructor
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -223,6 +224,8 @@ private:
|
||||
/// This is an implementation detail that should never leak outside of
|
||||
/// DeclName.
|
||||
static void *SubscriptIdentifierData;
|
||||
/// As above, for special destructor DeclNames.
|
||||
static void *DestructorIdentifierData;
|
||||
|
||||
Identifier Ident;
|
||||
|
||||
@@ -235,9 +238,15 @@ public:
|
||||
return DeclBaseName(Identifier((const char *)SubscriptIdentifierData));
|
||||
}
|
||||
|
||||
static DeclBaseName createDestructor() {
|
||||
return DeclBaseName(Identifier((const char *)DestructorIdentifierData));
|
||||
}
|
||||
|
||||
Kind getKind() const {
|
||||
if (Ident.get() == SubscriptIdentifierData) {
|
||||
return Kind::Subscript;
|
||||
} else if (Ident.get() == DestructorIdentifierData) {
|
||||
return Kind::Destructor;
|
||||
} else {
|
||||
return Kind::Normal;
|
||||
}
|
||||
@@ -273,6 +282,8 @@ public:
|
||||
return getIdentifier().str();
|
||||
case Kind::Subscript:
|
||||
return "subscript";
|
||||
case Kind::Destructor:
|
||||
return "deinit";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ IDENTIFIER(decode)
|
||||
IDENTIFIER(decodeIfPresent)
|
||||
IDENTIFIER(Decoder)
|
||||
IDENTIFIER(decoder)
|
||||
IDENTIFIER(deinit)
|
||||
IDENTIFIER(Element)
|
||||
IDENTIFIER(Encodable)
|
||||
IDENTIFIER(encode)
|
||||
|
||||
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
|
||||
/// in source control, you should also update the comment to briefly
|
||||
/// describe what change you made. The content of this comment isn't important;
|
||||
/// it just ensures a conflict if two people change the module format.
|
||||
const uint16_t VERSION_MINOR = 353; // Last change: count inherited conformances
|
||||
const uint16_t VERSION_MINOR = 354; // Last change: special destructor names
|
||||
|
||||
using DeclID = PointerEmbeddedInt<unsigned, 31>;
|
||||
using DeclIDField = BCFixed<31>;
|
||||
@@ -345,7 +345,8 @@ using OptionalTypeKindField = BCFixed<2>;
|
||||
// VERSION_MAJOR.
|
||||
enum class DeclNameKind: uint8_t {
|
||||
Normal,
|
||||
Subscript
|
||||
Subscript,
|
||||
Destructor
|
||||
};
|
||||
|
||||
// These IDs must \em not be renumbered or reordered without incrementing
|
||||
@@ -359,6 +360,8 @@ enum SpecialIdentifierID : uint8_t {
|
||||
OBJC_HEADER_MODULE_ID,
|
||||
/// Special value for the special subscript name
|
||||
SUBSCRIPT_ID,
|
||||
/// Special value for the special destructor name
|
||||
DESTRUCTOR_ID,
|
||||
|
||||
/// The number of special Identifier IDs. This value should never be encoded;
|
||||
/// it should only be used to count the number of names above. As such, it
|
||||
|
||||
@@ -548,6 +548,8 @@ void ASTMangler::appendDeclName(const ValueDecl *decl) {
|
||||
case DeclBaseName::Kind::Subscript:
|
||||
appendIdentifier("subscript");
|
||||
break;
|
||||
case DeclBaseName::Kind::Destructor:
|
||||
llvm_unreachable("Destructors are not mangled using appendDeclName");
|
||||
}
|
||||
} else {
|
||||
assert(AllowNamelessEntities && "attempt to mangle unnamed decl");
|
||||
|
||||
+20
-12
@@ -420,7 +420,7 @@ bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const {
|
||||
if (auto AFD = dyn_cast<AbstractFunctionDecl>(D)) {
|
||||
// Hide '~>' functions (but show the operator, because it defines
|
||||
// precedence).
|
||||
if (AFD->getNameStr() == "~>")
|
||||
if (isa<FuncDecl>(AFD) && AFD->getNameStr() == "~>")
|
||||
return true;
|
||||
|
||||
// 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,
|
||||
}
|
||||
|
||||
DestructorDecl *ClassDecl::getDestructor() {
|
||||
auto name = getASTContext().Id_deinit;
|
||||
auto results = lookupDirect(name);
|
||||
auto results = lookupDirect(DeclBaseName::createDestructor());
|
||||
assert(!results.empty() && "Class without destructor?");
|
||||
assert(results.size() == 1 && "More than one destructor?");
|
||||
return cast<DestructorDecl>(results.front());
|
||||
@@ -4572,7 +4571,20 @@ ObjCSelector AbstractFunctionDecl::getObjCSelector(
|
||||
}
|
||||
|
||||
auto &ctx = getASTContext();
|
||||
auto baseName = getName();
|
||||
|
||||
Identifier baseName;
|
||||
if (isa<DestructorDecl>(this)) {
|
||||
// Deinitializers are always called "dealloc".
|
||||
return ObjCSelector(ctx, 0, ctx.Id_dealloc);
|
||||
} else if (auto func = dyn_cast<FuncDecl>(this)) {
|
||||
// Otherwise cast this to be able to access getName()
|
||||
baseName = func->getName();
|
||||
} else if (auto ctor = dyn_cast<ConstructorDecl>(this)) {
|
||||
baseName = ctor->getName();
|
||||
} else {
|
||||
llvm_unreachable("Unknown subclass of AbstractFunctionDecl");
|
||||
}
|
||||
|
||||
auto argNames = getFullName().getArgumentNames();
|
||||
|
||||
// Use the preferred name if specified
|
||||
@@ -4596,11 +4608,6 @@ ObjCSelector AbstractFunctionDecl::getObjCSelector(
|
||||
}
|
||||
}
|
||||
|
||||
// Deinitializers are always called "dealloc".
|
||||
if (isa<DestructorDecl>(this)) {
|
||||
return ObjCSelector(ctx, 0, ctx.Id_dealloc);
|
||||
}
|
||||
|
||||
|
||||
// If this is a zero-parameter initializer with a long selector
|
||||
// name, form that selector.
|
||||
@@ -4960,9 +4967,10 @@ bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const {
|
||||
return params->get(0)->getInterfaceType()->isVoid();
|
||||
}
|
||||
|
||||
DestructorDecl::DestructorDecl(Identifier NameHack, SourceLoc DestructorLoc,
|
||||
ParamDecl *selfDecl, DeclContext *Parent)
|
||||
: AbstractFunctionDecl(DeclKind::Destructor, Parent, NameHack, DestructorLoc,
|
||||
DestructorDecl::DestructorDecl(SourceLoc DestructorLoc, ParamDecl *selfDecl,
|
||||
DeclContext *Parent)
|
||||
: AbstractFunctionDecl(DeclKind::Destructor, Parent,
|
||||
DeclBaseName::createDestructor(), DestructorLoc,
|
||||
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
|
||||
/*NumParameterLists=*/1, nullptr) {
|
||||
setSelfDecl(selfDecl);
|
||||
|
||||
@@ -806,7 +806,7 @@ unsigned DeclContext::printContext(raw_ostream &OS, unsigned indent) const {
|
||||
break;
|
||||
case DeclContextKind::AbstractFunctionDecl: {
|
||||
auto *AFD = cast<AbstractFunctionDecl>(this);
|
||||
OS << " name=" << AFD->getName();
|
||||
OS << " name=" << AFD->getFullName();
|
||||
if (AFD->hasInterfaceType())
|
||||
OS << " : " << AFD->getInterfaceType();
|
||||
else
|
||||
|
||||
@@ -22,6 +22,8 @@ using namespace swift;
|
||||
|
||||
void *DeclBaseName::SubscriptIdentifierData =
|
||||
&DeclBaseName::SubscriptIdentifierData;
|
||||
void *DeclBaseName::DestructorIdentifierData =
|
||||
&DeclBaseName::DestructorIdentifierData;
|
||||
|
||||
raw_ostream &llvm::operator<<(raw_ostream &OS, Identifier I) {
|
||||
if (I.get() == nullptr)
|
||||
|
||||
@@ -211,6 +211,8 @@ DeclBaseName SerializedSwiftName::toDeclBaseName(ASTContext &Context) const {
|
||||
return Context.getIdentifier(Name);
|
||||
case DeclBaseName::Kind::Subscript:
|
||||
return DeclBaseName::createSubscript();
|
||||
case DeclBaseName::Kind::Destructor:
|
||||
return DeclBaseName::createDestructor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,6 +831,9 @@ void SwiftLookupTable::dump() const {
|
||||
case DeclBaseName::Kind::Subscript:
|
||||
llvm::errs() << " subscript:\n";
|
||||
break;
|
||||
case DeclBaseName::Kind::Destructor:
|
||||
llvm::errs() << " deinit:\n";
|
||||
break;
|
||||
}
|
||||
const auto &entries = LookupTable.find(baseName)->second;
|
||||
for (const auto &entry : entries) {
|
||||
|
||||
@@ -82,6 +82,8 @@ struct SerializedSwiftName {
|
||||
return Name;
|
||||
case DeclBaseName::Kind::Subscript:
|
||||
return "subscript";
|
||||
case DeclBaseName::Kind::Destructor:
|
||||
return "deinit";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5792,8 +5792,8 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
|
||||
auto *SelfDecl = ParamDecl::createUnboundSelf(DestructorLoc, CurDeclContext);
|
||||
|
||||
Scope S(this, ScopeKind::DestructorBody);
|
||||
auto *DD = new (Context) DestructorDecl(Context.Id_deinit, DestructorLoc,
|
||||
SelfDecl, CurDeclContext);
|
||||
auto *DD = new (Context) DestructorDecl(DestructorLoc, SelfDecl,
|
||||
CurDeclContext);
|
||||
|
||||
// Parse the body.
|
||||
if (Tok.is(tok::l_brace)) {
|
||||
|
||||
@@ -434,9 +434,6 @@ bool SILParser::parseSILIdentifier(Identifier &Result, SourceLoc &Loc,
|
||||
// A binary operator can be part of a SILDeclRef.
|
||||
Result = P.Context.getIdentifier(P.Tok.getText());
|
||||
break;
|
||||
case tok::kw_deinit:
|
||||
Result = P.Context.Id_deinit;
|
||||
break;
|
||||
case tok::kw_init:
|
||||
Result = P.Context.Id_init;
|
||||
break;
|
||||
@@ -1148,6 +1145,10 @@ bool SILParser::parseSILDottedPathWithoutPound(ValueDecl *&Decl,
|
||||
P.consumeToken();
|
||||
FullName.push_back(DeclBaseName::createSubscript());
|
||||
break;
|
||||
case tok::kw_deinit:
|
||||
P.consumeToken();
|
||||
FullName.push_back(DeclBaseName::createDestructor());
|
||||
break;
|
||||
default:
|
||||
if (parseSILIdentifier(Id, diag::expected_sil_constant))
|
||||
return true;
|
||||
|
||||
@@ -1626,6 +1626,8 @@ static SelectorFamily getSelectorFamily(SILDeclRef c) {
|
||||
return getSelectorFamily(declName.getIdentifier());
|
||||
case DeclBaseName::Kind::Subscript:
|
||||
return SelectorFamily::None;
|
||||
case DeclBaseName::Kind::Destructor:
|
||||
return SelectorFamily::None;
|
||||
}
|
||||
}
|
||||
return SelectorFamily::None;
|
||||
|
||||
@@ -239,7 +239,8 @@ static void printValueDecl(ValueDecl *Decl, raw_ostream &OS) {
|
||||
|
||||
if (Decl->isOperator()) {
|
||||
OS << '"' << Decl->getBaseName() << '"';
|
||||
} else if (Decl->getBaseName() == "subscript") {
|
||||
} else if (Decl->getBaseName() == "subscript" ||
|
||||
Decl->getBaseName() == "deinit") {
|
||||
OS << '`' << Decl->getBaseName() << '`';
|
||||
} else {
|
||||
OS << Decl->getBaseName();
|
||||
|
||||
+3
-4
@@ -2532,6 +2532,9 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
|
||||
if (memberName.getBaseName().getKind() == DeclBaseName::Kind::Subscript) {
|
||||
diagnose(loc, diag::type_not_subscriptable, baseObjTy)
|
||||
.highlight(baseRange);
|
||||
} else if (memberName.getBaseName() == "deinit") {
|
||||
// Specialised diagnostic if trying to access deinitialisers
|
||||
diagnose(loc, diag::destructor_not_accessible).highlight(baseRange);
|
||||
} else if (auto metatypeTy = baseObjTy->getAs<MetatypeType>()) {
|
||||
auto instanceTy = metatypeTy->getInstanceType();
|
||||
tryTypoCorrection();
|
||||
@@ -2691,10 +2694,6 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
|
||||
|
||||
return;
|
||||
}
|
||||
case MemberLookupResult::UR_DestructorInaccessible: {
|
||||
diagnose(nameLoc, diag::destructor_not_accessible);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3206,11 +3206,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
|
||||
// reasonable choice.
|
||||
auto addChoice = [&](ValueDecl *cand, bool isBridged,
|
||||
bool isUnwrappedOptional) {
|
||||
// Destructors cannot be referenced manually
|
||||
if (isa<DestructorDecl>(cand)) {
|
||||
result.addUnviable(cand, MemberLookupResult::UR_DestructorInaccessible);
|
||||
return;
|
||||
}
|
||||
// If the result is invalid, skip it.
|
||||
TC.validateDecl(cand);
|
||||
if (cand->isInvalid()) {
|
||||
|
||||
@@ -2185,8 +2185,7 @@ void TypeChecker::addImplicitDestructor(ClassDecl *CD) {
|
||||
|
||||
auto *selfDecl = ParamDecl::createSelf(CD->getLoc(), CD);
|
||||
|
||||
auto *DD = new (Context) DestructorDecl(Context.Id_deinit, CD->getLoc(),
|
||||
selfDecl, CD);
|
||||
auto *DD = new (Context) DestructorDecl(CD->getLoc(), selfDecl, CD);
|
||||
|
||||
DD->setImplicit();
|
||||
|
||||
|
||||
@@ -840,9 +840,6 @@ struct MemberLookupResult {
|
||||
|
||||
/// The member is inaccessible (e.g. a private member in another file).
|
||||
UR_Inaccessible,
|
||||
|
||||
// A type's destructor cannot be referenced
|
||||
UR_DestructorInaccessible,
|
||||
};
|
||||
|
||||
/// This is a list of considered, but rejected, candidates, along with a
|
||||
|
||||
@@ -4969,12 +4969,10 @@ static void recordConformanceDependency(DeclContext *DC,
|
||||
Conformance->getDeclContext()->getParentModule())
|
||||
return;
|
||||
|
||||
auto &Context = DC->getASTContext();
|
||||
|
||||
// FIXME: 'deinit' is being used as a dummy identifier here. Really we
|
||||
// don't care about /any/ of the type's members, only that it conforms to
|
||||
// the protocol.
|
||||
tracker->addUsedMember({Adoptee, Context.Id_deinit},
|
||||
tracker->addUsedMember({Adoptee, DeclBaseName::createDestructor()},
|
||||
DC->isCascadingContextForLookup(InExpression));
|
||||
}
|
||||
|
||||
|
||||
@@ -1623,6 +1623,8 @@ DeclBaseName ModuleFile::getDeclBaseName(IdentifierID IID) {
|
||||
llvm_unreachable("Cannot get DeclBaseName of special module id");
|
||||
case SUBSCRIPT_ID:
|
||||
return DeclBaseName::createSubscript();
|
||||
case serialization::DESTRUCTOR_ID:
|
||||
return DeclBaseName::createDestructor();
|
||||
case NUM_SPECIAL_IDS:
|
||||
llvm_unreachable("implementation detail only");
|
||||
}
|
||||
@@ -1805,6 +1807,7 @@ ModuleDecl *ModuleFile::getModule(ModuleID MID) {
|
||||
return clangImporter->getImportedHeaderModule();
|
||||
}
|
||||
case SUBSCRIPT_ID:
|
||||
case DESTRUCTOR_ID:
|
||||
llvm_unreachable("Modules cannot be named with special names");
|
||||
case NUM_SPECIAL_IDS:
|
||||
llvm_unreachable("implementation detail only");
|
||||
@@ -3550,8 +3553,7 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
if (declOrOffset.isComplete())
|
||||
return declOrOffset;
|
||||
|
||||
auto dtor = createDecl<DestructorDecl>(ctx.Id_deinit, SourceLoc(),
|
||||
/*selfpat*/nullptr, DC);
|
||||
auto dtor = createDecl<DestructorDecl>(SourceLoc(), /*selfpat*/nullptr, DC);
|
||||
declOrOffset = dtor;
|
||||
|
||||
configureGenericEnvironment(dtor, genericEnvID);
|
||||
|
||||
@@ -341,6 +341,8 @@ public:
|
||||
}
|
||||
case static_cast<uint8_t>(DeclNameKind::Subscript):
|
||||
return {DeclBaseName::Kind::Subscript, StringRef()};
|
||||
case static_cast<uint8_t>(DeclNameKind::Destructor):
|
||||
return {DeclBaseName::Kind::Destructor, StringRef()};
|
||||
default:
|
||||
llvm_unreachable("Unknown DeclNameKind");
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ namespace {
|
||||
return llvm::HashString(key.getIdentifier().str());
|
||||
case DeclBaseName::Kind::Subscript:
|
||||
return static_cast<uint8_t>(DeclNameKind::Subscript);
|
||||
case DeclBaseName::Kind::Destructor:
|
||||
return static_cast<uint8_t>(DeclNameKind::Destructor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +121,9 @@ namespace {
|
||||
case DeclBaseName::Kind::Subscript:
|
||||
writer.write<uint8_t>(static_cast<uint8_t>(DeclNameKind::Subscript));
|
||||
break;
|
||||
case DeclBaseName::Kind::Destructor:
|
||||
writer.write<uint8_t>(static_cast<uint8_t>(DeclNameKind::Destructor));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,6 +514,8 @@ IdentifierID Serializer::addDeclBaseNameRef(DeclBaseName ident) {
|
||||
}
|
||||
case DeclBaseName::Kind::Subscript:
|
||||
return SUBSCRIPT_ID;
|
||||
case DeclBaseName::Kind::Destructor:
|
||||
return DESTRUCTOR_ID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1784,7 +1791,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
|
||||
bool isProtocolExt = fn->getDeclContext()->getAsProtocolExtensionContext();
|
||||
XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
||||
addTypeRef(ty),
|
||||
addDeclBaseNameRef(fn->getName()),
|
||||
addDeclBaseNameRef(fn->getBaseName()),
|
||||
isProtocolExt,
|
||||
fn->isStatic());
|
||||
|
||||
|
||||
@@ -443,7 +443,7 @@ class LazyProperties {
|
||||
// CHECK-SEARCHES-NEXT: DefaultArgument {{.*}} [166:32 - 166:32] expanded
|
||||
// CHECK-SEARCHES-NEXT: Module name=scope_map
|
||||
// CHECK-SEARCHES-NEXT: FileUnit file="{{.*}}scope_map.swift"
|
||||
// CHECK-SEARCHES-NEXT: AbstractFunctionDecl name=defaultArguments : (Int, Int) -> ()
|
||||
// CHECK-SEARCHES-NEXT: AbstractFunctionDecl name=defaultArguments(i:j:) : (Int, Int) -> ()
|
||||
// CHECK-SEARCHES-NEXT: {{.*}} Initializer DefaultArgument index=0
|
||||
|
||||
// CHECK-SEARCHES-LABEL: ***Scope at 179:18***
|
||||
|
||||
@@ -183,3 +183,12 @@ class SubscriptAsFunction {
|
||||
// CHECK-LABEL: sil_vtable SubscriptAsFunction {
|
||||
// CHECK-NOT: #SubscriptAsFunction.subscript
|
||||
// CHECK: #SubscriptAsFunction.`subscript`!1
|
||||
|
||||
|
||||
class DeinitAsFunction {
|
||||
func `deinit`() {}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil_vtable DeinitAsFunction {
|
||||
// CHECK: #DeinitAsFunction.`deinit`!1
|
||||
// CHECK: #DeinitAsFunction.deinit!deallocator
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// A class with no initializers (which has non-initialized properties so a
|
||||
// default constructor can be synthesized) should produce an error.
|
||||
class NoInitializers { // expected-error {{class 'NoInitializers' has no initializers}}
|
||||
// expected-note@-1 {{did you mean 'deinit'?}}
|
||||
var x: Double // expected-note {{stored property 'x' without initial value prevents synthesized initializers}}
|
||||
|
||||
func foo() {
|
||||
|
||||
@@ -54,3 +54,26 @@ let sr3043 = SR3043Derived()
|
||||
sr3043.deinit() // expected-error {{deinitializers cannot be accessed}}
|
||||
sr3043.deinit // expected-error {{deinitializers cannot be accessed}}
|
||||
SR3043Derived.deinit() // expected-error {{deinitializers cannot be accessed}}
|
||||
|
||||
// Allow deinit functions in classes
|
||||
|
||||
class ClassWithDeinitFunc {
|
||||
func `deinit`() {
|
||||
}
|
||||
|
||||
func `deinit`(a: SR3043Base) {
|
||||
}
|
||||
}
|
||||
|
||||
let instanceWithDeinitFunc = ClassWithDeinitFunc()
|
||||
instanceWithDeinitFunc.deinit()
|
||||
_ = instanceWithDeinitFunc.deinit(a:)
|
||||
_ = instanceWithDeinitFunc.deinit as () -> Void
|
||||
SR3043Derived.deinit() // expected-error {{deinitializers cannot be accessed}}
|
||||
|
||||
class ClassWithDeinitMember {
|
||||
var `deinit`: SR3043Base?
|
||||
}
|
||||
|
||||
let instanceWithDeinitMember = ClassWithDeinitMember()
|
||||
_ = instanceWithDeinitMember.deinit
|
||||
|
||||
Reference in New Issue
Block a user