Skip to content

Add and use AbstractFunctionDecl::getTypecheckedBody #33806

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/AST/AnyFunctionRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ class AnyFunctionRef {
return cast<AutoClosureExpr>(ACE)->getBody();
}

void setBody(BraceStmt *stmt, bool isSingleExpression) {
void setTypecheckedBody(BraceStmt *stmt, bool isSingleExpression) {
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
AFD->setBody(stmt);
AFD->setBody(stmt, AbstractFunctionDecl::BodyKind::TypeChecked);
AFD->setHasSingleExpressionBody(isSingleExpression);
return;
}
Expand Down
8 changes: 7 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5852,6 +5852,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
};

friend class ParseAbstractFunctionBodyRequest;
friend class TypeCheckFunctionBodyRequest;

CaptureInfo Captures;

Expand Down Expand Up @@ -5985,7 +5986,12 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
/// \sa hasBody()
BraceStmt *getBody(bool canSynthesize = true) const;

void setBody(BraceStmt *S, BodyKind NewBodyKind = BodyKind::Parsed);
/// Retrieve the type-checked body of the given function, or \c nullptr if
/// there's no body available.
BraceStmt *getTypecheckedBody() const;

/// Set a new body for the function.
void setBody(BraceStmt *S, BodyKind NewBodyKind);

/// Note that the body was skipped for this function. Function body
/// cannot be attached after this call.
Expand Down
18 changes: 9 additions & 9 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -884,25 +884,25 @@ class LazyStoragePropertyRequest :
bool isCached() const { return true; }
};

/// Request to type check the body of the given function.
///
/// Produces true if an error occurred, false otherwise.
/// FIXME: it would be far better to return the type-checked body.
class TypeCheckFunctionBodyRequest :
public SimpleRequest<TypeCheckFunctionBodyRequest,
bool(AbstractFunctionDecl *),
RequestFlags::Cached|RequestFlags::DependencySource> {
/// Request to retrieve the type-checked body of the given function.
class TypeCheckFunctionBodyRequest
: public SimpleRequest<
TypeCheckFunctionBodyRequest, BraceStmt *(AbstractFunctionDecl *),
RequestFlags::SeparatelyCached | RequestFlags::DependencySource> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
bool evaluate(Evaluator &evaluator, AbstractFunctionDecl *func) const;
BraceStmt *evaluate(Evaluator &evaluator, AbstractFunctionDecl *func) const;

public:
// Separate caching.
bool isCached() const { return true; }
Optional<BraceStmt *> getCachedResult() const;
void cacheResult(BraceStmt *body) const;

public:
// Incremental dependencies.
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ SWIFT_REQUEST(TypeChecker, SynthesizeAccessorRequest,
SWIFT_REQUEST(TypeChecker, TangentStoredPropertyRequest,
llvm::Expected<VarDecl *>(VarDecl *, CanType), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyRequest,
bool(AbstractFunctionDecl *), Cached, NoLocationInfo)
BraceStmt *(AbstractFunctionDecl *), SeparatelyCached,
NoLocationInfo)
SWIFT_REQUEST(TypeChecker, TypeCheckASTNodeAtLocRequest,
bool(DeclContext *, SourceLoc),
Uncached, NoLocationInfo)
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6779,6 +6779,13 @@ BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const {
nullptr);
}

BraceStmt *AbstractFunctionDecl::getTypecheckedBody() const {
auto &ctx = getASTContext();
auto *mutableThis = const_cast<AbstractFunctionDecl *>(this);
return evaluateOrDefault(
ctx.evaluator, TypeCheckFunctionBodyRequest{mutableThis}, nullptr);
}

void AbstractFunctionDecl::setBody(BraceStmt *S, BodyKind NewBodyKind) {
assert(getBodyKind() != BodyKind::Skipped &&
"cannot set a body if it was skipped");
Expand Down
27 changes: 27 additions & 0 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,33 @@ void TypeCheckSourceFileRequest::cacheResult(evaluator::SideEffect) const {
// TypeCheckFunctionBodyRequest computation.
//----------------------------------------------------------------------------//

Optional<BraceStmt *> TypeCheckFunctionBodyRequest::getCachedResult() const {
using BodyKind = AbstractFunctionDecl::BodyKind;
auto *afd = std::get<0>(getStorage());
switch (afd->getBodyKind()) {
case BodyKind::Deserialized:
case BodyKind::MemberwiseInitializer:
case BodyKind::None:
case BodyKind::Skipped:
// These cases don't have any body available.
return nullptr;

case BodyKind::TypeChecked:
return afd->Body;

case BodyKind::Synthesize:
case BodyKind::Parsed:
case BodyKind::Unparsed:
return None;
}
llvm_unreachable("Unhandled BodyKind in switch");
}

void TypeCheckFunctionBodyRequest::cacheResult(BraceStmt *body) const {
auto *afd = std::get<0>(getStorage());
afd->setBody(body, AbstractFunctionDecl::BodyKind::TypeChecked);
}

evaluator::DependencySource
TypeCheckFunctionBodyRequest::readDependencySource(
const evaluator::DependencyRecorder &e) const {
Expand Down
12 changes: 6 additions & 6 deletions lib/SILGen/SILGenConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,9 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
emitMemberInitializers(ctor, selfDecl, nominal);
}

emitProfilerIncrement(ctor->getBody());
emitProfilerIncrement(ctor->getTypecheckedBody());
// Emit the constructor body.
emitStmt(ctor->getBody());
emitStmt(ctor->getTypecheckedBody());


// Build a custom epilog block, since the AST representation of the
Expand Down Expand Up @@ -622,7 +622,7 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
SILValue initedSelfValue = emitApplyWithRethrow(Loc, initVal.forward(*this),
initTy, subMap, args);

emitProfilerIncrement(ctor->getBody());
emitProfilerIncrement(ctor->getTypecheckedBody());

// Return the initialized 'self'.
B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
Expand All @@ -632,7 +632,7 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
MagicFunctionName = SILGenModule::getMagicFunctionName(ctor);

assert(ctor->getBody() && "Class constructor without a body?");
assert(ctor->getTypecheckedBody() && "Class constructor without a body?");

// True if this constructor delegates to a peer constructor with self.init().
bool isDelegating = false;
Expand Down Expand Up @@ -775,9 +775,9 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
emitMemberInitializers(ctor, selfDecl, selfClassDecl);
}

emitProfilerIncrement(ctor->getBody());
emitProfilerIncrement(ctor->getTypecheckedBody());
// Emit the constructor body.
emitStmt(ctor->getBody());
emitStmt(ctor->getTypecheckedBody());

// Emit the call to super.init() right before exiting from the initializer.
if (NeedsBoxForSelf) {
Expand Down
10 changes: 5 additions & 5 deletions lib/SILGen/SILGenDestructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
// We won't actually emit the block until we finish with the destructor body.
prepareEpilog(false, false, CleanupLocation::get(Loc));

emitProfilerIncrement(dd->getBody());
emitProfilerIncrement(dd->getTypecheckedBody());
// Emit the destructor body.
emitStmt(dd->getBody());
emitStmt(dd->getTypecheckedBody());

Optional<SILValue> maybeReturnValue;
SILLocation returnLoc(Loc);
Expand Down Expand Up @@ -151,7 +151,7 @@ void SILGenFunction::emitDeallocatingDestructor(DestructorDecl *dd) {
selfForDealloc = B.createUncheckedRefCast(loc, selfForDealloc, classTy);
B.createDeallocRef(loc, selfForDealloc, false);

emitProfilerIncrement(dd->getBody());
emitProfilerIncrement(dd->getTypecheckedBody());

// Return.
B.createReturn(loc, emitEmptyTuple(loc));
Expand Down Expand Up @@ -212,9 +212,9 @@ void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) {
// We won't actually emit the block until we finish with the destructor body.
prepareEpilog(false, false, CleanupLocation::get(loc));

emitProfilerIncrement(dd->getBody());
emitProfilerIncrement(dd->getTypecheckedBody());
// Emit the destructor body.
emitStmt(dd->getBody());
emitStmt(dd->getTypecheckedBody());

Optional<SILValue> maybeReturnValue;
SILLocation returnLoc(loc);
Expand Down
4 changes: 2 additions & 2 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,8 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc());
prepareEpilog(true, fd->hasThrows(), CleanupLocation(fd));

emitProfilerIncrement(fd->getBody());
emitStmt(fd->getBody());
emitProfilerIncrement(fd->getTypecheckedBody());
emitStmt(fd->getTypecheckedBody());

emitEpilog(fd);

Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSClosure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
if (!newBody)
return SolutionApplicationToFunctionResult::Failure;

fn.setBody(newBody, /*isSingleExpression=*/false);
fn.setTypecheckedBody(newBody, /*isSingleExpression=*/false);
if (closure) {
solution.setExprTypes(closure);
}
Expand Down
8 changes: 6 additions & 2 deletions lib/Sema/DerivedConformanceEquatableHashable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,10 @@ deriveBodyEquatable_enum_noAssociatedValues_eq(AbstractFunctionDecl *eqDecl,
AccessSemantics::Ordinary, fnType);

fnType = fnType->getResult()->castTo<FunctionType>();
cmpFuncExpr = new (C) DotSyntaxCallExpr(ref, SourceLoc(), base, fnType);
cmpFuncExpr->setImplicit();
auto *callExpr = new (C) DotSyntaxCallExpr(ref, SourceLoc(), base, fnType);
callExpr->setImplicit();
callExpr->setThrows(false);
cmpFuncExpr = callExpr;
} else {
cmpFuncExpr = new (C) DeclRefExpr(cmpFunc, DeclNameLoc(),
/*implicit*/ true,
Expand All @@ -142,6 +144,7 @@ deriveBodyEquatable_enum_noAssociatedValues_eq(AbstractFunctionDecl *eqDecl,
auto *cmpExpr = new (C) BinaryExpr(
cmpFuncExpr, abTuple, /*implicit*/ true,
fnType->castTo<FunctionType>()->getResult());
cmpExpr->setThrows(false);
statements.push_back(new (C) ReturnStmt(SourceLoc(), cmpExpr));

BraceStmt *body = BraceStmt::create(C, SourceLoc(), statements, SourceLoc());
Expand Down Expand Up @@ -839,6 +842,7 @@ deriveBodyHashable_hashValue(AbstractFunctionDecl *hashValueDecl, void *) {
auto callExpr = CallExpr::createImplicit(C, hashExpr,
{ selfRef }, { C.Id_for });
callExpr->setType(hashFuncResultType);
callExpr->setThrows(false);

auto returnStmt = new (C) ReturnStmt(SourceLoc(), callExpr);

Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/PCMacro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ class Instrumenter : InstrumenterBase {
NB = prependLoggerCall(NB, {StartLoc, EndLoc});

if (NB != B) {
FD->setBody(NB);
FD->setBody(NB, AbstractFunctionDecl::BodyKind::TypeChecked);
TypeChecker::checkFunctionEffects(FD);
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/PlaygroundTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ class Instrumenter : InstrumenterBase {
TargetKindSetter TKS(BracePairs, BracePair::TargetKinds::Return);
BraceStmt *NB = transformBraceStmt(B);
if (NB != B) {
FD->setBody(NB);
FD->setBody(NB, AbstractFunctionDecl::BodyKind::TypeChecked);
TypeChecker::checkFunctionEffects(FD);
}
}
Expand Down Expand Up @@ -892,7 +892,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) {
Instrumenter I(ctx, FD, RNG, HighPerformance, TmpNameIndex);
BraceStmt *NewBody = I.transformBraceStmt(Body);
if (NewBody != Body) {
FD->setBody(NewBody);
FD->setBody(NewBody, AbstractFunctionDecl::BodyKind::TypeChecked);
TypeChecker::checkFunctionEffects(FD);
}
return false;
Expand Down
6 changes: 3 additions & 3 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2299,7 +2299,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
FD->diagnose(diag::func_decl_without_brace);
} else if (FD->getDeclContext()->isLocalContext()) {
// Check local function bodies right away.
TypeChecker::typeCheckAbstractFunctionBody(FD);
(void)FD->getTypecheckedBody();
} else if (shouldSkipBodyTypechecking(FD)) {
FD->setBodySkipped(FD->getBodySourceRange());
} else {
Expand Down Expand Up @@ -2642,7 +2642,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
CD->diagnose(diag::missing_initializer_def);
} else if (CD->getDeclContext()->isLocalContext()) {
// Check local function bodies right away.
TypeChecker::typeCheckAbstractFunctionBody(CD);
(void)CD->getTypecheckedBody();
} else if (shouldSkipBodyTypechecking(CD)) {
CD->setBodySkipped(CD->getBodySourceRange());
} else {
Expand All @@ -2657,7 +2657,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {

if (DD->getDeclContext()->isLocalContext()) {
// Check local function bodies right away.
TypeChecker::typeCheckAbstractFunctionBody(DD);
(void)DD->getTypecheckedBody();
} else if (shouldSkipBodyTypechecking(DD)) {
DD->setBodySkipped(DD->getBodySourceRange());
} else {
Expand Down
38 changes: 24 additions & 14 deletions lib/Sema/TypeCheckStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1700,14 +1700,6 @@ static Type getFunctionBuilderType(FuncDecl *FD) {
return builderType;
}

bool TypeChecker::typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD) {
auto res = evaluateOrDefault(AFD->getASTContext().evaluator,
TypeCheckFunctionBodyRequest{AFD}, true);
TypeChecker::checkFunctionEffects(AFD);
TypeChecker::computeCaptures(AFD);
return res;
}

static Expr* constructCallToSuperInit(ConstructorDecl *ctor,
ClassDecl *ClDecl) {
ASTContext &Context = ctor->getASTContext();
Expand Down Expand Up @@ -2028,7 +2020,7 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(Evaluator &evaluator,
return false;
}

bool
BraceStmt *
TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
AbstractFunctionDecl *AFD) const {
ASTContext &ctx = AFD->getASTContext();
Expand All @@ -2039,8 +2031,22 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
timer.emplace(AFD);

BraceStmt *body = AFD->getBody();
if (!body || AFD->isBodyTypeChecked())
return false;
assert(body && "Expected body to type-check");

// It's possible we sythesized an already type-checked body, in which case
// we're done.
if (AFD->isBodyTypeChecked())
return body;

auto errorBody = [&]() {
// If we had an error, return an ErrorExpr body instead of returning the
// un-type-checked body.
// FIXME: This should be handled by typeCheckExpression.
auto range = AFD->getBodySourceRange();
return BraceStmt::create(ctx, range.Start,
{new (ctx) ErrorExpr(range, ErrorType::get(ctx))},
range.End);
};

bool alreadyTypeChecked = false;
if (auto *func = dyn_cast<FuncDecl>(AFD)) {
Expand All @@ -2049,7 +2055,7 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
TypeChecker::applyFunctionBuilderBodyTransform(
func, builderType)) {
if (!*optBody)
return true;
return errorBody();

body = *optBody;
alreadyTypeChecked = true;
Expand Down Expand Up @@ -2113,14 +2119,18 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
}
}

// Wire up the function body now.
// Temporarily wire up the function body for some extra checks.
// FIXME: Eliminate this.
AFD->setBody(body, AbstractFunctionDecl::BodyKind::TypeChecked);

// If nothing went wrong yet, perform extra checking.
if (!hadError)
performAbstractFuncDeclDiagnostics(AFD);

return hadError;
TypeChecker::checkFunctionEffects(AFD);
TypeChecker::computeCaptures(AFD);

return hadError ? errorBody() : body;
}

bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) {
Expand Down
3 changes: 1 addition & 2 deletions lib/Sema/TypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,7 @@ static void typeCheckDelayedFunctions(SourceFile &SF) {
++currentFunctionIdx) {
auto *AFD = SF.DelayedFunctions[currentFunctionIdx];
assert(!AFD->getDeclContext()->isLocalContext());

TypeChecker::typeCheckAbstractFunctionBody(AFD);
(void)AFD->getTypecheckedBody();
}

// Type check synthesized functions and their bodies.
Expand Down
Loading