@@ -8934,9 +8934,6 @@ BraceStmt *AbstractFunctionDecl::getTypecheckedBody() const {
89348934}
89358935
89368936void AbstractFunctionDecl::setBody (BraceStmt *S, BodyKind NewBodyKind) {
8937- assert (getBodyKind () != BodyKind::Skipped &&
8938- " cannot set a body if it was skipped" );
8939-
89408937 llvm::Optional<Fingerprint> fp = llvm::None;
89418938 if (getBodyKind () == BodyKind::TypeChecked ||
89428939 getBodyKind () == BodyKind::Parsed) {
@@ -8952,6 +8949,72 @@ void AbstractFunctionDecl::setBody(BraceStmt *S, BodyKind NewBodyKind) {
89528949 }
89538950}
89548951
8952+ bool AbstractFunctionDecl::isBodySkipped () const {
8953+ return evaluateOrDefault (getASTContext ().evaluator ,
8954+ IsFunctionBodySkippedRequest{this }, false );
8955+ }
8956+
8957+ // / Determines whether typechecking can be skipped for a function body. Bodies
8958+ // / are skipped as a performance optimization when an
8959+ // / `-experimental-skip-*-function-bodies` flag is specified and the body meets
8960+ // / the criteria for skipping. If a body is skipped during typechecking, it is
8961+ // / also skipped during SILGen. Some bodies cannot be skipped, even when they
8962+ // / otherwise meet the criteria, because typechecking them has essential
8963+ // / side-effects that are required for correctness of the AST.
8964+ bool IsFunctionBodySkippedRequest::evaluate (
8965+ Evaluator &evaluator, const AbstractFunctionDecl *afd) const {
8966+ auto &Ctx = afd->getASTContext ();
8967+ auto skippingMode = Ctx.TypeCheckerOpts .SkipFunctionBodies ;
8968+ if (skippingMode == FunctionBodySkipping::None)
8969+ return false ;
8970+
8971+ // Functions that have been synthesized for clang modules will be serialized
8972+ // because they have shared linkage.
8973+ if (isa<ClangModuleUnit>(afd->getDeclContext ()->getModuleScopeContext ()))
8974+ return false ;
8975+
8976+ if (auto *accessor = dyn_cast<AccessorDecl>(afd)) {
8977+ // didSet accessors needs to be checked to determine whether to keep their
8978+ // parameters.
8979+ if (accessor->getAccessorKind () == AccessorKind::DidSet)
8980+ return false ;
8981+
8982+ // Synthesized accessors with forced static dispatch are emitted on-demand
8983+ // and are serialized. Since they are serialized we must be willing to
8984+ // typecheck them.
8985+ if (accessor->hasForcedStaticDispatch ())
8986+ return false ;
8987+
8988+ if (auto *varDecl = dyn_cast<VarDecl>(accessor->getStorage ())) {
8989+ // FIXME: If we don't typecheck the synthesized accessors of lazy storage
8990+ // properties then SILGen crashes when emitting the initializer.
8991+ if (varDecl->getAttrs ().hasAttribute <LazyAttr>() && accessor->isSynthesized ())
8992+ return false ;
8993+ }
8994+ }
8995+
8996+ // Actor initializers need to be checked to determine delegation status.
8997+ if (auto *ctor = dyn_cast<ConstructorDecl>(afd))
8998+ if (auto *nom = ctor->getParent ()->getSelfNominalTypeDecl ())
8999+ if (nom->isAnyActor ())
9000+ return false ;
9001+
9002+ // Skipping all bodies won't serialize anything, so we can skip everything
9003+ // else.
9004+ if (skippingMode == FunctionBodySkipping::All)
9005+ return true ;
9006+
9007+ // If we want all types (for LLDB) then we can't skip functions with nested
9008+ // types. We could probably improve upon this and type-check only the nested
9009+ // types instead for better performances.
9010+ if (afd->hasNestedTypeDeclarations () &&
9011+ skippingMode == FunctionBodySkipping::NonInlinableWithoutTypes)
9012+ return false ;
9013+
9014+ // Skip functions that don't need to be serialized.
9015+ return afd->getResilienceExpansion () != ResilienceExpansion::Minimal;
9016+ }
9017+
89559018void AbstractFunctionDecl::setBodyToBeReparsed (SourceRange bodyRange) {
89569019 assert (bodyRange.isValid ());
89579020 assert (getBodyKind () == BodyKind::Unparsed ||
@@ -8986,7 +9049,6 @@ SourceRange AbstractFunctionDecl::getBodySourceRange() const {
89869049
89879050 return SourceRange ();
89889051
8989- case BodyKind::Skipped:
89909052 case BodyKind::Unparsed:
89919053 return BodyRange;
89929054 }
@@ -9396,7 +9458,6 @@ bool AbstractFunctionDecl::hasInlinableBodyText() const {
93969458
93979459 case BodyKind::None:
93989460 case BodyKind::Synthesize:
9399- case BodyKind::Skipped:
94009461 case BodyKind::SILSynthesize:
94019462 return false ;
94029463 }
@@ -9847,8 +9908,7 @@ SourceRange FuncDecl::getSourceRange() const {
98479908 if (StartLoc.isInvalid ())
98489909 return SourceRange ();
98499910
9850- if (getBodyKind () == BodyKind::Unparsed ||
9851- getBodyKind () == BodyKind::Skipped)
9911+ if (getBodyKind () == BodyKind::Unparsed)
98529912 return { StartLoc, BodyRange.End };
98539913
98549914 SourceLoc RBraceLoc = getOriginalBodySourceRange ().End ;
@@ -10530,7 +10590,6 @@ ParseAbstractFunctionBodyRequest::getCachedResult() const {
1053010590 case BodyKind::Deserialized:
1053110591 case BodyKind::SILSynthesize:
1053210592 case BodyKind::None:
10533- case BodyKind::Skipped:
1053410593 return BodyAndFingerprint{};
1053510594
1053610595 case BodyKind::TypeChecked:
@@ -10552,7 +10611,6 @@ void ParseAbstractFunctionBodyRequest::cacheResult(
1055210611 case BodyKind::Deserialized:
1055310612 case BodyKind::SILSynthesize:
1055410613 case BodyKind::None:
10555- case BodyKind::Skipped:
1055610614 // The body is always empty, so don't cache anything.
1055710615 assert (!value.getFingerprint ().has_value () && value.getBody () == nullptr );
1055810616 return ;
@@ -10569,6 +10627,27 @@ void ParseAbstractFunctionBodyRequest::cacheResult(
1056910627 }
1057010628}
1057110629
10630+ llvm::Optional<bool > IsFunctionBodySkippedRequest::getCachedResult () const {
10631+ using BodySkippedStatus = AbstractFunctionDecl::BodySkippedStatus;
10632+ auto afd = std::get<0 >(getStorage ());
10633+ switch (afd->getBodySkippedStatus ()) {
10634+ case BodySkippedStatus::Unknown:
10635+ return llvm::None;
10636+ case BodySkippedStatus::Skipped:
10637+ return true ;
10638+ case BodySkippedStatus::NotSkipped:
10639+ return false ;
10640+ }
10641+ llvm_unreachable (" bad BodySkippedStatus" );
10642+ }
10643+
10644+ void IsFunctionBodySkippedRequest::cacheResult (bool isSkipped) const {
10645+ using BodySkippedStatus = AbstractFunctionDecl::BodySkippedStatus;
10646+ auto afd = std::get<0 >(getStorage ());
10647+ const_cast <AbstractFunctionDecl *>(afd)->setBodySkippedStatus (
10648+ isSkipped ? BodySkippedStatus::Skipped : BodySkippedStatus::NotSkipped);
10649+ }
10650+
1057210651void swift::simple_display (llvm::raw_ostream &out, BodyAndFingerprint value) {
1057310652 out << " (" ;
1057410653 simple_display (out, value.getBody ());
0 commit comments