Skip to content
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
13 changes: 5 additions & 8 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5773,6 +5773,11 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
setBodyKind(BodyKind::Unparsed);
}

/// Provide the parsed body for the function.
void setBodyParsed(BraceStmt *S) {
setBody(S, BodyKind::Parsed);
}

/// Note that parsing for the body was delayed.
///
/// The function should return the body statement and a flag indicating
Expand All @@ -5793,14 +5798,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
setBodyKind(BodyKind::MemberwiseInitializer);
}

/// If a body has been loaded, flag that it's been type-checked.
/// This is kindof a hacky operation, but it avoids some unnecessary
/// duplication of work.
void setBodyTypeCheckedIfPresent() {
if (getBodyKind() == BodyKind::Parsed)
setBodyKind(BodyKind::TypeChecked);
}

/// Gets the body of this function, stripping the unused portions of #if
/// configs inside the body. If this function was not deserialized from a
/// .swiftmodule, this body is reconstructed from the original
Expand Down
12 changes: 7 additions & 5 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -689,13 +689,14 @@ class LazyStoragePropertyRequest :
bool isCached() const { return true; }
};

/// Request to type check the body of the given function.
/// Request to type check the body of the given function up to the given
/// source location.
///
/// 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 *),
class TypeCheckFunctionBodyUntilRequest :
public SimpleRequest<TypeCheckFunctionBodyUntilRequest,
bool(AbstractFunctionDecl *, SourceLoc),
CacheKind::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -705,7 +706,8 @@ class TypeCheckFunctionBodyRequest :

// Evaluation.
llvm::Expected<bool>
evaluate(Evaluator &evaluator, AbstractFunctionDecl *func) const;
evaluate(Evaluator &evaluator, AbstractFunctionDecl *func,
SourceLoc endTypeCheckLoc) const;

public:
bool isCached() const { return true; }
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ SWIFT_TYPEID(IsGetterMutatingRequest)
SWIFT_TYPEID(IsSetterMutatingRequest)
SWIFT_TYPEID(OpaqueReadOwnershipRequest)
SWIFT_TYPEID(LazyStoragePropertyRequest)
SWIFT_TYPEID(TypeCheckFunctionBodyRequest)
SWIFT_TYPEID(TypeCheckFunctionBodyUntilRequest)
8 changes: 8 additions & 0 deletions include/swift/Basic/SourceLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ class SourceLoc {
}

void dump(const SourceManager &SM) const;

friend size_t hash_value(SourceLoc loc) {
return reinterpret_cast<uintptr_t>(loc.getOpaquePointerValue());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird indentation here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, tabs. I'll clean it up, thanks!

}

friend void simple_display(raw_ostream &OS, const SourceLoc &loc) {
// Nothing meaningful to print.
}
};

/// SourceRange in swift is a pair of locations. However, note that the end
Expand Down
12 changes: 10 additions & 2 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3775,6 +3775,14 @@ DestructorDecl *ClassDecl::getDestructor() {
return cast<DestructorDecl>(results.front());
}

/// Synthesizer callback for an empty implicit function body.
static std::pair<BraceStmt *, bool>
synthesizeEmptyFunctionBody(AbstractFunctionDecl *afd, void *context) {
ASTContext &ctx = afd->getASTContext();
return { BraceStmt::create(ctx, afd->getLoc(), { }, afd->getLoc(), true),
/*isTypeChecked=*/true };
}

void ClassDecl::addImplicitDestructor() {
if (hasDestructor() || isInvalid())
return;
Expand All @@ -3785,8 +3793,8 @@ void ClassDecl::addImplicitDestructor() {
DD->setImplicit();
DD->setValidationToChecked();

// Create an empty body for the destructor.
DD->setBody(BraceStmt::create(ctx, getLoc(), { }, getLoc(), true));
// Synthesize an empty body for the destructor as needed.
DD->setBodySynthesizer(synthesizeEmptyFunctionBody);
addMember(DD);

// Propagate access control and versioned-ness.
Expand Down
10 changes: 5 additions & 5 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4636,9 +4636,9 @@ ParserStatus Parser::parseGetSet(ParseDeclOptions Flags,
Indices, ElementTy, StaticLoc, Flags, AccessorKind::Get,
storage, this, /*AccessorKeywordLoc*/ SourceLoc());
CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
getter->setBody(BraceStmt::create(Context, Tok.getLoc(),
ASTNode(CCE), Tok.getLoc(),
/*implicit*/ true));
getter->setBodyParsed(BraceStmt::create(Context, Tok.getLoc(),
ASTNode(CCE), Tok.getLoc(),
/*implicit*/ true));
accessors.add(getter);
CodeCompletion->setParsedDecl(getter);
} else {
Expand Down Expand Up @@ -5763,7 +5763,7 @@ void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) {
ParserResult<BraceStmt> Body = parseBraceItemList(diag::invalid_diagnostic);
if (!Body.isNull()) {
BraceStmt * BS = Body.get();
AFD->setBody(BS);
AFD->setBodyParsed(BS);

// If the body consists of a single expression, turn it into a return
// statement.
Expand Down Expand Up @@ -5853,7 +5853,7 @@ bool Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) {
// FIXME: Should do some sort of error recovery here?
return true;
} else {
AFD->setBody(Body.get());
AFD->setBodyParsed(Body.get());
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,7 @@ ParserResult<Stmt> Parser::parseStmtDefer() {
if (Body.isNull())
return nullptr;
Status |= Body;
tempDecl->setBody(Body.get());
tempDecl->setBodyParsed(Body.get());
}

SourceLoc loc = tempDecl->getBodySourceRange().Start;
Expand Down
40 changes: 9 additions & 31 deletions lib/Sema/BuilderTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,47 +476,25 @@ static bool hasReturnStmt(Stmt *stmt) {
return finder.hasReturnStmt;
}

bool TypeChecker::typeCheckFunctionBuilderFuncBody(FuncDecl *FD,
Type builderType) {
BraceStmt *
TypeChecker::applyFunctionBuilderBodyTransform(FuncDecl *FD,
BraceStmt *body,
Type builderType) {
// Try to build a single result expression.
BuilderClosureVisitor visitor(Context, nullptr,
/*wantExpr=*/true, builderType);
Expr *returnExpr = visitor.visit(FD->getBody());
Expr *returnExpr = visitor.visit(body);
if (!returnExpr)
return true;
return nullptr;

// Make sure we have a usable result type for the body.
Type returnType = AnyFunctionRef(FD).getBodyResultType();
if (!returnType || returnType->hasError())
return true;

TypeCheckExprOptions options = {};
if (auto opaque = returnType->getAs<OpaqueTypeArchetypeType>()) {
if (opaque->getDecl()->isOpaqueReturnTypeOfFunction(FD))
options |= TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType;
}

// If we are performing code-completion inside the functions body, supress
// diagnostics to workaround typechecking performance problems.
if (Context.SourceMgr.rangeContainsCodeCompletionLoc(
FD->getBody()->getSourceRange()))
options |= TypeCheckExprFlags::SuppressDiagnostics;

// Type-check the single result expression.
Type returnExprType = typeCheckExpression(returnExpr, FD,
TypeLoc::withoutLoc(returnType),
CTP_ReturnStmt, options);
if (!returnExprType)
return true;
assert(returnExprType->isEqual(returnType));
return nullptr;

auto returnStmt = new (Context) ReturnStmt(SourceLoc(), returnExpr);
auto origBody = FD->getBody();
auto fakeBody = BraceStmt::create(Context, origBody->getLBraceLoc(),
{ returnStmt },
origBody->getRBraceLoc());
FD->setBody(fakeBody);
return false;
return BraceStmt::create(Context, body->getLBraceLoc(), { returnStmt },
body->getRBraceLoc());
}

ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
Expand Down
20 changes: 12 additions & 8 deletions lib/Sema/MiscDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2235,23 +2235,26 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
TypeChecker &TC;
AbstractFunctionDecl *Implementation;
OpaqueTypeDecl *OpaqueDecl;
BraceStmt *Body;
SmallVector<std::pair<Expr*, Type>, 4> Candidates;

bool HasInvalidReturn = false;

public:
OpaqueUnderlyingTypeChecker(TypeChecker &TC,
AbstractFunctionDecl *Implementation,
OpaqueTypeDecl *OpaqueDecl)
OpaqueTypeDecl *OpaqueDecl,
BraceStmt *Body)
: TC(TC),
Implementation(Implementation),
OpaqueDecl(OpaqueDecl)
OpaqueDecl(OpaqueDecl),
Body(Body)
{

}

void check() {
Implementation->getBody()->walk(*this);
Body->walk(*this);

// If given function has any invalid returns in the body
// let's not try to validate the types, since it wouldn't
Expand Down Expand Up @@ -2835,26 +2838,27 @@ performTopLevelDeclDiagnostics(TypeChecker &TC, TopLevelCodeDecl *TLCD) {

/// Perform diagnostics for func/init/deinit declarations.
void swift::performAbstractFuncDeclDiagnostics(TypeChecker &TC,
AbstractFunctionDecl *AFD) {
assert(AFD->getBody() && "Need a body to check");
AbstractFunctionDecl *AFD,
BraceStmt *body) {
assert(body && "Need a body to check");

// Don't produce these diagnostics for implicitly generated code.
if (AFD->getLoc().isInvalid() || AFD->isImplicit() || AFD->isInvalid())
return;

// Check for unused variables, as well as variables that are could be
// declared as constants.
AFD->getBody()->walk(VarDeclUsageChecker(TC, AFD));
body->walk(VarDeclUsageChecker(TC, AFD));

// If the function has an opaque return type, check the return expressions
// to determine the underlying type.
if (auto opaqueResultTy = AFD->getOpaqueResultTypeDecl()) {
OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy).check();
OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy, body).check();
} else if (auto accessor = dyn_cast<AccessorDecl>(AFD)) {
if (accessor->isGetter()) {
if (auto opaqueResultTy
= accessor->getStorage()->getOpaqueResultTypeDecl()) {
OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy).check();
OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy, body).check();
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/MiscDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ void performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E,
void performStmtDiagnostics(TypeChecker &TC, const Stmt *S);

void performAbstractFuncDeclDiagnostics(TypeChecker &TC,
AbstractFunctionDecl *AFD);
AbstractFunctionDecl *AFD,
BraceStmt *body);

/// Perform diagnostics on the top level code declaration.
void performTopLevelDeclDiagnostics(TypeChecker &TC, TopLevelCodeDecl *TLCD);
Expand Down
17 changes: 12 additions & 5 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5599,6 +5599,16 @@ void TypeChecker::synthesizeMemberForLookup(NominalTypeDecl *target,
}
}

/// Synthesizer callback for a function body consisting of "return".
static std::pair<BraceStmt *, bool>
synthesizeSingleReturnFunctionBody(AbstractFunctionDecl *afd, void *) {
ASTContext &ctx = afd->getASTContext();
SmallVector<ASTNode, 1> stmts;
stmts.push_back(new (ctx) ReturnStmt(afd->getLoc(), nullptr));
return { BraceStmt::create(ctx, afd->getLoc(), stmts, afd->getLoc(), true),
/*isTypeChecked=*/true };
}

void TypeChecker::defineDefaultConstructor(NominalTypeDecl *decl) {
FrontendStatsTracer StatsTracer(Context.Stats, "define-default-ctor", decl);
PrettyStackTraceDecl stackTrace("defining default constructor for",
Expand All @@ -5624,11 +5634,8 @@ void TypeChecker::defineDefaultConstructor(NominalTypeDecl *decl) {
// Add the constructor.
decl->addMember(ctor);

// Create an empty body for the default constructor.
SmallVector<ASTNode, 1> stmts;
stmts.push_back(new (Context) ReturnStmt(decl->getLoc(), nullptr));
ctor->setBody(BraceStmt::create(Context, SourceLoc(), stmts, SourceLoc()),
AbstractFunctionDecl::BodyKind::TypeChecked);
// Lazily synthesize an empty body for the default constructor.
ctor->setBodySynthesizer(synthesizeSingleReturnFunctionBody);
}

static void validateAttributes(TypeChecker &TC, Decl *D) {
Expand Down
Loading