Skip to content

Commit 007fbb6

Browse files
authored
Merge pull request #23932 from xymus/IsFinalRequest
Sema: implement `isFinal` using a request evaluator
2 parents 9f96244 + b48eabd commit 007fbb6

13 files changed

+195
-89
lines changed

include/swift/AST/Decl.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2339,10 +2339,18 @@ class ValueDecl : public Decl {
23392339
/// the declaration will go through an extra level of indirection that
23402340
/// allows the entity to be replaced at runtime.
23412341
unsigned isDynamic : 1;
2342-
} LazySemanticInfo;
2342+
2343+
/// Whether the "isFinal" bit has been computed yet.
2344+
unsigned isFinalComputed : 1;
2345+
2346+
/// Whether this declaration is 'final'. A final class can't be subclassed,
2347+
/// a final class member can't be overriden.
2348+
unsigned isFinal : 1;
2349+
} LazySemanticInfo = { };
23432350

23442351
friend class OverriddenDeclsRequest;
23452352
friend class IsObjCRequest;
2353+
friend class IsFinalRequest;
23462354
friend class IsDynamicRequest;
23472355

23482356
protected:
@@ -2353,12 +2361,6 @@ class ValueDecl : public Decl {
23532361
Bits.ValueDecl.AlreadyInLookupTable = false;
23542362
Bits.ValueDecl.CheckedRedeclaration = false;
23552363
Bits.ValueDecl.IsUserAccessible = true;
2356-
LazySemanticInfo.isObjCComputed = false;
2357-
LazySemanticInfo.isObjC = false;
2358-
LazySemanticInfo.hasOverriddenComputed = false;
2359-
LazySemanticInfo.hasOverridden = false;
2360-
LazySemanticInfo.isDynamicComputed = false;
2361-
LazySemanticInfo.isDynamic = false;
23622364
}
23632365

23642366
// MemberLookupTable borrows a bit from this type
@@ -2599,10 +2601,8 @@ class ValueDecl : public Decl {
25992601
/// Note whether this declaration is known to be exposed to Objective-C.
26002602
void setIsObjC(bool Value);
26012603

2602-
/// Is this declaration marked with 'final'?
2603-
bool isFinal() const {
2604-
return getAttrs().hasAttribute<FinalAttr>();
2605-
}
2604+
/// Is this declaration 'final'?
2605+
bool isFinal() const;
26062606

26072607
/// Is this declaration marked with 'dynamic'?
26082608
bool isDynamic() const;

include/swift/AST/TypeCheckRequests.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,32 @@ class IsObjCRequest :
187187
void cacheResult(bool value) const;
188188
};
189189

190+
/// Determine whether the given declaration is 'final'.
191+
class IsFinalRequest :
192+
public SimpleRequest<IsFinalRequest,
193+
CacheKind::SeparatelyCached,
194+
bool,
195+
ValueDecl *> {
196+
public:
197+
using SimpleRequest::SimpleRequest;
198+
199+
private:
200+
friend SimpleRequest;
201+
202+
// Evaluation.
203+
llvm::Expected<bool> evaluate(Evaluator &evaluator, ValueDecl *decl) const;
204+
205+
public:
206+
// Cycle handling
207+
void diagnoseCycle(DiagnosticEngine &diags) const;
208+
void noteCycleStep(DiagnosticEngine &diags) const;
209+
210+
// Separate caching.
211+
bool isCached() const { return true; }
212+
Optional<bool> getCachedResult() const;
213+
void cacheResult(bool value) const;
214+
};
215+
190216
/// Determine whether the given declaration is 'dynamic''.
191217
class IsDynamicRequest :
192218
public SimpleRequest<IsDynamicRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ SWIFT_TYPEID(SuperclassTypeRequest)
1919
SWIFT_TYPEID(EnumRawTypeRequest)
2020
SWIFT_TYPEID(OverriddenDeclsRequest)
2121
SWIFT_TYPEID(IsObjCRequest)
22+
SWIFT_TYPEID(IsFinalRequest)
2223
SWIFT_TYPEID(IsDynamicRequest)
2324
SWIFT_TYPEID(RequirementRequest)
2425
SWIFT_TYPEID(USRGenerationRequest)

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,8 @@ namespace {
776776
}
777777
}
778778

779-
if (VD->isFinal())
779+
auto VarD = dyn_cast<VarDecl>(VD);
780+
if (VD->isFinal() && !(VarD && VarD->isLet()))
780781
OS << " final";
781782
if (VD->isObjC())
782783
OS << " @objc";

lib/AST/ASTPrinter.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,20 @@ void PrintAST::printAttributes(const Decl *D) {
972972

973973
D->getAttrs().print(Printer, Options, D);
974974

975+
// Print the implicit 'final' attribute.
976+
if (auto VD = dyn_cast<ValueDecl>(D)) {
977+
auto VarD = dyn_cast<VarDecl>(D);
978+
if (VD->isFinal() &&
979+
!VD->getAttrs().hasAttribute<FinalAttr>() &&
980+
// Don't print a redundant 'final' if printing a 'let' or 'static' decl.
981+
!(VarD && VarD->isLet()) &&
982+
getCorrectStaticSpelling(D) != StaticSpellingKind::KeywordStatic &&
983+
VD->getKind() != DeclKind::Accessor) {
984+
Printer.printAttrName("final");
985+
Printer << " ";
986+
}
987+
}
988+
975989
// Explicitly print 'mutating' and 'nonmutating' before getters and setters
976990
// for which that is true.
977991
if (auto accessor = dyn_cast<AccessorDecl>(D)) {

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,6 +2411,12 @@ void ValueDecl::setIsObjC(bool value) {
24112411
LazySemanticInfo.isObjC = value;
24122412
}
24132413

2414+
bool ValueDecl::isFinal() const {
2415+
return evaluateOrDefault(getASTContext().evaluator,
2416+
IsFinalRequest { const_cast<ValueDecl *>(this) },
2417+
getAttrs().hasAttribute<FinalAttr>());
2418+
}
2419+
24142420
bool ValueDecl::isDynamic() const {
24152421
ASTContext &ctx = getASTContext();
24162422
return evaluateOrDefault(ctx.evaluator,

lib/AST/TypeCheckRequests.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,40 @@ void IsObjCRequest::cacheResult(bool value) const {
220220
decl->setIsObjC(value);
221221
}
222222

223+
//----------------------------------------------------------------------------//
224+
// isFinal computation.
225+
//----------------------------------------------------------------------------//
226+
227+
void IsFinalRequest::diagnoseCycle(DiagnosticEngine &diags) const {
228+
// FIXME: Improve this diagnostic.
229+
auto decl = std::get<0>(getStorage());
230+
diags.diagnose(decl, diag::circular_reference);
231+
}
232+
233+
void IsFinalRequest::noteCycleStep(DiagnosticEngine &diags) const {
234+
auto decl = std::get<0>(getStorage());
235+
// FIXME: Customize this further.
236+
diags.diagnose(decl, diag::circular_reference_through);
237+
}
238+
239+
Optional<bool> IsFinalRequest::getCachedResult() const {
240+
auto decl = std::get<0>(getStorage());
241+
if (decl->LazySemanticInfo.isFinalComputed)
242+
return decl->LazySemanticInfo.isFinal;
243+
244+
return None;
245+
}
246+
247+
void IsFinalRequest::cacheResult(bool value) const {
248+
auto decl = std::get<0>(getStorage());
249+
decl->LazySemanticInfo.isFinalComputed = true;
250+
decl->LazySemanticInfo.isFinal = value;
251+
252+
// Register Final in attributes, to preserve print order
253+
if (value && !decl->getAttrs().hasAttribute<FinalAttr>())
254+
decl->getAttrs().add(new (decl->getASTContext()) FinalAttr(/*Implicit=*/true));
255+
}
256+
223257
//----------------------------------------------------------------------------//
224258
// isDynamic computation.
225259
//----------------------------------------------------------------------------//

lib/IDE/CodeCompletion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4168,7 +4168,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
41684168
if (D->shouldHideFromEditor())
41694169
return;
41704170

4171-
if (D->getAttrs().hasAttribute<FinalAttr>() ||
4171+
if (D->isFinal() ||
41724172
// A 'class' member with an initial value cannot be overriden either.
41734173
(D->isStatic() && D->getAttrs().hasAttribute<HasInitialValueAttr>()))
41744174
return;

lib/Sema/CodeSynthesis.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,6 @@ createCoroutineAccessorPrototype(AbstractStorageDecl *storage,
367367
if (isStatic)
368368
accessor->setStatic();
369369

370-
// The accessor is final if the storage is.
371-
if (storage->isFinal())
372-
makeFinal(ctx, accessor);
373-
374370
// If the storage does not provide this accessor as an opaque accessor,
375371
// we can't add a dynamically-dispatched method entry for the accessor,
376372
// so force it to be statically dispatched. ("final" would be inappropriate

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) {
10391039
initDecl->setBodySynthesizer(&deriveBodyDecodable_init);
10401040

10411041
// This constructor should be marked as `required` for non-final classes.
1042-
if (classDecl && !classDecl->getAttrs().hasAttribute<FinalAttr>()) {
1042+
if (classDecl && !classDecl->isFinal()) {
10431043
auto *reqAttr = new (C) RequiredAttr(/*IsImplicit=*/true);
10441044
initDecl->getAttrs().add(reqAttr);
10451045
}

lib/Sema/DerivedConformances.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,6 @@ DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc,
280280
VarDecl *property,
281281
Type propertyContextType) {
282282
bool isStatic = property->isStatic();
283-
bool isFinal = property->isFinal();
284283

285284
auto &C = tc.Context;
286285
auto parentDC = property->getDeclContext();
@@ -298,11 +297,6 @@ DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc,
298297
getterDecl->setImplicit();
299298
getterDecl->setStatic(isStatic);
300299

301-
// If this is supposed to be a final method, mark it as such.
302-
assert(isFinal || !parentDC->getSelfClassDecl());
303-
if (isFinal && parentDC->getSelfClassDecl() && !getterDecl->isFinal())
304-
getterDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
305-
306300
// Compute the interface type of the getter.
307301
if (auto env = parentDC->getGenericEnvironmentOfContext())
308302
getterDecl->setGenericEnvironment(env);
@@ -332,11 +326,6 @@ DerivedConformance::declareDerivedProperty(Identifier name,
332326
propDecl->setInterfaceType(propertyInterfaceType);
333327
propDecl->setValidationToChecked();
334328

335-
// If this is supposed to be a final property, mark it as such.
336-
assert(isFinal || !parentDC->getSelfClassDecl());
337-
if (isFinal && parentDC->getSelfClassDecl() && !propDecl->isFinal())
338-
propDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
339-
340329
Pattern *propPat = new (C) NamedPattern(propDecl, /*implicit*/ true);
341330
propPat->setType(propertyContextType);
342331

0 commit comments

Comments
 (0)