Skip to content

Commit ff2cb33

Browse files
committed
[Type checker] Factor "type check function body until" into a request.
Extend the "type check function body" request to also cover the case where we have a specific ending source location. Fold all of this functionality into a single request, so we consistently go through a request to compute a type-checked function body.
1 parent 1aa19b7 commit ff2cb33

File tree

8 files changed

+76
-78
lines changed

8 files changed

+76
-78
lines changed

include/swift/AST/Decl.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5798,14 +5798,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
57985798
setBodyKind(BodyKind::MemberwiseInitializer);
57995799
}
58005800

5801-
/// If a body has been loaded, flag that it's been type-checked.
5802-
/// This is kindof a hacky operation, but it avoids some unnecessary
5803-
/// duplication of work.
5804-
void setBodyTypeCheckedIfPresent() {
5805-
if (getBodyKind() == BodyKind::Parsed)
5806-
setBodyKind(BodyKind::TypeChecked);
5807-
}
5808-
58095801
/// Gets the body of this function, stripping the unused portions of #if
58105802
/// configs inside the body. If this function was not deserialized from a
58115803
/// .swiftmodule, this body is reconstructed from the original

include/swift/AST/TypeCheckRequests.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -689,13 +689,14 @@ class LazyStoragePropertyRequest :
689689
bool isCached() const { return true; }
690690
};
691691

692-
/// Request to type check the body of the given function.
692+
/// Request to type check the body of the given function up to the given
693+
/// source location.
693694
///
694695
/// Produces true if an error occurred, false otherwise.
695696
/// FIXME: it would be far better to return the type-checked body.
696-
class TypeCheckFunctionBodyRequest :
697-
public SimpleRequest<TypeCheckFunctionBodyRequest,
698-
bool(AbstractFunctionDecl *),
697+
class TypeCheckFunctionBodyUntilRequest :
698+
public SimpleRequest<TypeCheckFunctionBodyUntilRequest,
699+
bool(AbstractFunctionDecl *, SourceLoc),
699700
CacheKind::Cached> {
700701
public:
701702
using SimpleRequest::SimpleRequest;
@@ -705,7 +706,8 @@ class TypeCheckFunctionBodyRequest :
705706

706707
// Evaluation.
707708
llvm::Expected<bool>
708-
evaluate(Evaluator &evaluator, AbstractFunctionDecl *func) const;
709+
evaluate(Evaluator &evaluator, AbstractFunctionDecl *func,
710+
SourceLoc endTypeCheckLoc) const;
709711

710712
public:
711713
bool isCached() const { return true; }

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@ SWIFT_TYPEID(IsGetterMutatingRequest)
4040
SWIFT_TYPEID(IsSetterMutatingRequest)
4141
SWIFT_TYPEID(OpaqueReadOwnershipRequest)
4242
SWIFT_TYPEID(LazyStoragePropertyRequest)
43-
SWIFT_TYPEID(TypeCheckFunctionBodyRequest)
43+
SWIFT_TYPEID(TypeCheckFunctionBodyUntilRequest)

include/swift/Basic/SourceLoc.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ class SourceLoc {
7878
}
7979

8080
void dump(const SourceManager &SM) const;
81+
82+
friend size_t hash_value(SourceLoc loc) {
83+
return reinterpret_cast<uintptr_t>(loc.getOpaquePointerValue());
84+
}
85+
86+
friend void simple_display(raw_ostream &OS, const SourceLoc &loc) {
87+
// Nothing meaningful to print.
88+
}
8189
};
8290

8391
/// SourceRange in swift is a pair of locations. However, note that the end

lib/Sema/MiscDiagnostics.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,23 +2235,26 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
22352235
TypeChecker &TC;
22362236
AbstractFunctionDecl *Implementation;
22372237
OpaqueTypeDecl *OpaqueDecl;
2238+
BraceStmt *Body;
22382239
SmallVector<std::pair<Expr*, Type>, 4> Candidates;
22392240

22402241
bool HasInvalidReturn = false;
22412242

22422243
public:
22432244
OpaqueUnderlyingTypeChecker(TypeChecker &TC,
22442245
AbstractFunctionDecl *Implementation,
2245-
OpaqueTypeDecl *OpaqueDecl)
2246+
OpaqueTypeDecl *OpaqueDecl,
2247+
BraceStmt *Body)
22462248
: TC(TC),
22472249
Implementation(Implementation),
2248-
OpaqueDecl(OpaqueDecl)
2250+
OpaqueDecl(OpaqueDecl),
2251+
Body(Body)
22492252
{
22502253

22512254
}
22522255

22532256
void check() {
2254-
Implementation->getBody()->walk(*this);
2257+
Body->walk(*this);
22552258

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

28362839
/// Perform diagnostics for func/init/deinit declarations.
28372840
void swift::performAbstractFuncDeclDiagnostics(TypeChecker &TC,
2838-
AbstractFunctionDecl *AFD) {
2839-
assert(AFD->getBody() && "Need a body to check");
2841+
AbstractFunctionDecl *AFD,
2842+
BraceStmt *body) {
2843+
assert(body && "Need a body to check");
28402844

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

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

28492853
// If the function has an opaque return type, check the return expressions
28502854
// to determine the underlying type.
28512855
if (auto opaqueResultTy = AFD->getOpaqueResultTypeDecl()) {
2852-
OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy).check();
2856+
OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy, body).check();
28532857
} else if (auto accessor = dyn_cast<AccessorDecl>(AFD)) {
28542858
if (accessor->isGetter()) {
28552859
if (auto opaqueResultTy
28562860
= accessor->getStorage()->getOpaqueResultTypeDecl()) {
2857-
OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy).check();
2861+
OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy, body).check();
28582862
}
28592863
}
28602864
}

lib/Sema/MiscDiagnostics.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ void performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E,
4343
void performStmtDiagnostics(TypeChecker &TC, const Stmt *S);
4444

4545
void performAbstractFuncDeclDiagnostics(TypeChecker &TC,
46-
AbstractFunctionDecl *AFD);
46+
AbstractFunctionDecl *AFD,
47+
BraceStmt *body);
4748

4849
/// Perform diagnostics on the top level code declaration.
4950
void performTopLevelDeclDiagnostics(TypeChecker &TC, TopLevelCodeDecl *TLCD);

lib/Sema/TypeCheckStmt.cpp

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,49 +1925,7 @@ static Type getFunctionBuilderType(FuncDecl *FD) {
19251925
}
19261926

19271927
bool TypeChecker::typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD) {
1928-
return evaluateOrDefault(Context.evaluator,
1929-
TypeCheckFunctionBodyRequest{AFD},
1930-
true);
1931-
}
1932-
1933-
llvm::Expected<bool>
1934-
TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
1935-
AbstractFunctionDecl *func) const {
1936-
ASTContext &ctx = func->getASTContext();
1937-
if (!func->hasInterfaceType()) {
1938-
TypeChecker &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
1939-
tc.validateDecl(func);
1940-
}
1941-
1942-
// HACK: don't type-check the same function body twice. This will eventually
1943-
// be handled by the request-evaluator's caching mechanism.
1944-
(void)func->getBody();
1945-
if (func->isBodyTypeChecked())
1946-
return false;
1947-
1948-
FrontendStatsTracer StatsTracer(ctx.Stats, "typecheck-fn", func);
1949-
PrettyStackTraceDecl StackEntry("type-checking", func);
1950-
1951-
if (ctx.Stats)
1952-
ctx.Stats->getFrontendCounters().NumFunctionsTypechecked++;
1953-
1954-
Optional<FunctionBodyTimer> timer;
1955-
TypeChecker &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
1956-
if (tc.DebugTimeFunctionBodies || tc.WarnLongFunctionBodies)
1957-
timer.emplace(func, tc.DebugTimeFunctionBodies, tc.WarnLongFunctionBodies);
1958-
1959-
tc.requestRequiredNominalTypeLayoutForParameters(func->getParameters());
1960-
1961-
bool error = tc.typeCheckAbstractFunctionBodyUntil(func, SourceLoc());
1962-
func->setBodyTypeCheckedIfPresent();
1963-
1964-
if (error)
1965-
return true;
1966-
1967-
if (func->getBody())
1968-
performAbstractFuncDeclDiagnostics(tc, func);
1969-
1970-
return false;
1928+
return typeCheckAbstractFunctionBodyUntil(AFD, SourceLoc());
19711929
}
19721930

19731931
static Expr* constructCallToSuperInit(ConstructorDecl *ctor,
@@ -2163,18 +2121,37 @@ static void checkClassConstructorBody(ClassDecl *classDecl,
21632121
}
21642122
}
21652123

2166-
bool TypeChecker::typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
2167-
SourceLoc EndTypeCheckLoc) {
2168-
validateDecl(AFD);
2169-
checkDefaultArguments(AFD->getParameters(), AFD);
2124+
llvm::Expected<bool>
2125+
TypeCheckFunctionBodyUntilRequest::evaluate(Evaluator &evaluator,
2126+
AbstractFunctionDecl *AFD,
2127+
SourceLoc endTypeCheckLoc) const {
2128+
ASTContext &ctx = AFD->getASTContext();
2129+
2130+
// Accounting for type checking of function bodies.
2131+
// FIXME: We could probably take this away, given that the request-evaluator
2132+
// does much of it for us.
2133+
FrontendStatsTracer StatsTracer(ctx.Stats, "typecheck-fn", AFD);
2134+
PrettyStackTraceDecl StackEntry("type-checking", AFD);
2135+
2136+
if (ctx.Stats)
2137+
ctx.Stats->getFrontendCounters().NumFunctionsTypechecked++;
2138+
2139+
Optional<FunctionBodyTimer> timer;
2140+
TypeChecker &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
2141+
if (tc.DebugTimeFunctionBodies || tc.WarnLongFunctionBodies)
2142+
timer.emplace(AFD, tc.DebugTimeFunctionBodies, tc.WarnLongFunctionBodies);
2143+
2144+
tc.validateDecl(AFD);
2145+
tc.requestRequiredNominalTypeLayoutForParameters(AFD->getParameters());
2146+
tc.checkDefaultArguments(AFD->getParameters(), AFD);
21702147

21712148
BraceStmt *body = AFD->getBody();
21722149
if (!body || AFD->isBodyTypeChecked())
21732150
return false;
21742151

21752152
if (auto *func = dyn_cast<FuncDecl>(AFD)) {
21762153
if (Type builderType = getFunctionBuilderType(func)) {
2177-
body = applyFunctionBuilderBodyTransform(func, body, builderType);
2154+
body = tc.applyFunctionBuilderBodyTransform(func, body, builderType);
21782155
if (!body)
21792156
return true;
21802157
} else if (func->hasSingleExpressionBody()) {
@@ -2195,15 +2172,15 @@ bool TypeChecker::typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
21952172
// simplifies SILGen.
21962173
SmallVector<ASTNode, 8> Elts(body->getElements().begin(),
21972174
body->getElements().end());
2198-
Elts.push_back(new (Context) ReturnStmt(body->getRBraceLoc(),
2199-
/*value*/nullptr,
2200-
/*implicit*/true));
2201-
body = BraceStmt::create(Context, body->getLBraceLoc(), Elts,
2175+
Elts.push_back(new (ctx) ReturnStmt(body->getRBraceLoc(),
2176+
/*value*/nullptr,
2177+
/*implicit*/true));
2178+
body = BraceStmt::create(ctx, body->getLBraceLoc(), Elts,
22022179
body->getRBraceLoc(), body->isImplicit());
22032180
}
22042181

2205-
StmtChecker SC(*this, AFD);
2206-
SC.EndTypeCheckLoc = EndTypeCheckLoc;
2182+
StmtChecker SC(tc, AFD);
2183+
SC.EndTypeCheckLoc = endTypeCheckLoc;
22072184
bool hadError = SC.typeCheckBody(body);
22082185

22092186
// If this was a function with a single expression body, let's see
@@ -2222,16 +2199,30 @@ bool TypeChecker::typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
22222199
}
22232200
}
22242201

2202+
// Class constructor checking.
22252203
if (auto *ctor = dyn_cast<ConstructorDecl>(AFD)) {
22262204
if (auto classDecl = ctor->getDeclContext()->getSelfClassDecl()) {
22272205
checkClassConstructorBody(classDecl, ctor, body);
22282206
}
22292207
}
22302208

2209+
// If nothing went wrong yet, perform extra checking.
2210+
if (!hadError && endTypeCheckLoc.isInvalid())
2211+
performAbstractFuncDeclDiagnostics(tc, AFD, body);
2212+
2213+
// Wire up the function body now.
22312214
AFD->setBody(body, AbstractFunctionDecl::BodyKind::TypeChecked);
22322215
return hadError;
22332216
}
22342217

2218+
bool TypeChecker::typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
2219+
SourceLoc EndTypeCheckLoc) {
2220+
return evaluateOrDefault(
2221+
Context.evaluator,
2222+
TypeCheckFunctionBodyUntilRequest{AFD, EndTypeCheckLoc},
2223+
true);
2224+
}
2225+
22352226
bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) {
22362227
checkParameterAttributes(closure->getParameters());
22372228

lib/Sema/TypeChecker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ class TypeChecker final : public LazyResolver {
626626
TypeChecker(ASTContext &Ctx);
627627
friend class ASTContext;
628628
friend class constraints::ConstraintSystem;
629-
friend class TypeCheckFunctionBodyRequest;
629+
friend class TypeCheckFunctionBodyUntilRequest;
630630

631631
public:
632632
/// Create a new type checker instance for the given ASTContext, if it

0 commit comments

Comments
 (0)