Skip to content

Commit 371526b

Browse files
committed
Add a high-level request to type check a file
1 parent b7537cf commit 371526b

File tree

9 files changed

+105
-43
lines changed

9 files changed

+105
-43
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ SWIFT_TYPEID_NAMED(ParamDecl *, ParamDecl)
4949
SWIFT_TYPEID_NAMED(PatternBindingEntry *, PatternBindingEntry)
5050
SWIFT_TYPEID_NAMED(PrecedenceGroupDecl *, PrecedenceGroupDecl)
5151
SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl)
52+
SWIFT_TYPEID_NAMED(SourceFile *, SourceFile)
5253
SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl)
5354
SWIFT_TYPEID_NAMED(ValueDecl *, ValueDecl)
5455
SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)

include/swift/AST/ASTTypeIDs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct PropertyWrapperMutability;
5050
class ProtocolDecl;
5151
class Requirement;
5252
enum class ResilienceExpansion : unsigned;
53+
class SourceFile;
5354
class Type;
5455
class ValueDecl;
5556
class VarDecl;

include/swift/AST/SourceFile.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,11 @@ inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMainClassWithScript() {
482482
return !res;
483483
}
484484

485+
inline void simple_display(llvm::raw_ostream &out, const SourceFile *SF) {
486+
assert(SF && "Cannot display null source file!");
487+
488+
out << "source_file " << '\"' << SF->getFilename() << '\"';
489+
}
485490
} // end namespace swift
486491

487492
#endif

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,6 +1948,27 @@ class DynamicallyReplacedDeclRequest
19481948
bool isCached() const { return true; }
19491949
};
19501950

1951+
class TypeCheckSourceFileRequest :
1952+
public SimpleRequest<TypeCheckSourceFileRequest,
1953+
bool (SourceFile *, unsigned),
1954+
CacheKind::SeparatelyCached> {
1955+
public:
1956+
using SimpleRequest::SimpleRequest;
1957+
1958+
private:
1959+
friend SimpleRequest;
1960+
1961+
// Evaluation.
1962+
llvm::Expected<bool> evaluate(Evaluator &evaluator,
1963+
SourceFile *SF, unsigned StartElem) const;
1964+
1965+
public:
1966+
// Separate caching.
1967+
bool isCached() const { return true; }
1968+
Optional<bool> getCachedResult() const;
1969+
void cacheResult(bool result) const;
1970+
};
1971+
19511972
// Allow AnyValue to compare two Type values, even though Type doesn't
19521973
// support ==.
19531974
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,
205205
bool(NominalTypeDecl *), Cached, NoLocationInfo)
206206
SWIFT_REQUEST(TypeChecker, SynthesizeDefaultInitRequest,
207207
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
208+
SWIFT_REQUEST(TypeChecker, TypeCheckSourceFileRequest,
209+
bool(SouceFile *, unsigned), SeparatelyCached, NoLocationInfo)
208210
SWIFT_REQUEST(TypeChecker, TypeWitnessRequest,
209211
TypeWitnessAndDecl(NormalProtocolConformance *,
210212
AssociatedTypeDecl *),

lib/AST/TypeCheckRequests.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
#include "swift/AST/NameLookup.h"
1919
#include "swift/AST/PropertyWrappers.h"
2020
#include "swift/AST/ProtocolConformance.h"
21+
#include "swift/AST/SourceFile.h"
2122
#include "swift/AST/TypeCheckRequests.h"
2223
#include "swift/AST/TypeLoc.h"
2324
#include "swift/AST/TypeRepr.h"
2425
#include "swift/AST/Types.h"
26+
#include "swift/Subsystems.h"
2527

2628
using namespace swift;
2729

@@ -1238,3 +1240,48 @@ void CallerSideDefaultArgExprRequest::cacheResult(Expr *expr) const {
12381240
auto *defaultExpr = std::get<0>(getStorage());
12391241
defaultExpr->ContextOrCallerSideExpr = expr;
12401242
}
1243+
1244+
//----------------------------------------------------------------------------//
1245+
// TypeCheckSourceFileRequest computation.
1246+
//----------------------------------------------------------------------------//
1247+
1248+
Optional<bool> TypeCheckSourceFileRequest::getCachedResult() const {
1249+
auto *SF = std::get<0>(getStorage());
1250+
if (SF->ASTStage == SourceFile::TypeChecked)
1251+
return true;
1252+
1253+
return None;
1254+
}
1255+
1256+
void TypeCheckSourceFileRequest::cacheResult(bool result) const {
1257+
auto *SF = std::get<0>(getStorage());
1258+
1259+
// Verify that we've checked types correctly.
1260+
SF->ASTStage = SourceFile::TypeChecked;
1261+
1262+
{
1263+
auto &Ctx = SF->getASTContext();
1264+
FrontendStatsTracer tracer(Ctx.Stats, "AST verification");
1265+
// Verify the SourceFile.
1266+
swift::verify(*SF);
1267+
1268+
// Verify imported modules.
1269+
//
1270+
// Skip per-file verification in whole-module mode. Verifying imports
1271+
// between files could cause the importer to cache declarations without
1272+
// adding them to the ASTContext. This happens when the importer registers a
1273+
// declaration without a valid TypeChecker instance, as is the case during
1274+
// verification. A subsequent file may require that declaration to be fully
1275+
// imported (e.g. to synthesized a function body), but since it has already
1276+
// been cached, it will never be added to the ASTContext. The solution is to
1277+
// skip verification and avoid caching it.
1278+
#ifndef NDEBUG
1279+
if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking &&
1280+
SF->Kind != SourceFileKind::REPL &&
1281+
SF->Kind != SourceFileKind::SIL &&
1282+
!Ctx.LangOpts.DebuggerSupport) {
1283+
Ctx.verifyAllLoadedModules();
1284+
}
1285+
#endif
1286+
}
1287+
}

lib/Frontend/Frontend.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/FileSystem.h"
2323
#include "swift/AST/IncrementalRanges.h"
2424
#include "swift/AST/Module.h"
25+
#include "swift/AST/TypeCheckRequests.h"
2526
#include "swift/Basic/FileTypes.h"
2627
#include "swift/Basic/SourceManager.h"
2728
#include "swift/Basic/Statistic.h"

lib/Sema/TypeChecker.cpp

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "swift/AST/PrettyStackTrace.h"
3636
#include "swift/AST/ProtocolConformance.h"
3737
#include "swift/AST/SourceFile.h"
38+
#include "swift/AST/TypeCheckRequests.h"
3839
#include "swift/Basic/Statistic.h"
3940
#include "swift/Basic/STLExtras.h"
4041
#include "swift/Basic/Timer.h"
@@ -322,26 +323,35 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC)
322323
}
323324

324325
void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
325-
if (SF.ASTStage == SourceFile::TypeChecked)
326-
return;
326+
return (void)evaluateOrDefault(SF.getASTContext().evaluator,
327+
TypeCheckSourceFileRequest{&SF, StartElem},
328+
false);
329+
}
330+
331+
llvm::Expected<bool>
332+
TypeCheckSourceFileRequest::evaluate(Evaluator &eval,
333+
SourceFile *SF, unsigned StartElem) const {
334+
assert(SF && "Source file cannot be null!");
335+
assert(SF->ASTStage != SourceFile::TypeChecked &&
336+
"Should not be re-typechecking this file!");
327337

328338
// Eagerly build the top-level scopes tree before type checking
329339
// because type-checking expressions mutates the AST and that throws off the
330340
// scope-based lookups. Only the top-level scopes because extensions have not
331341
// been bound yet.
332-
auto &Ctx = SF.getASTContext();
333-
if (Ctx.LangOpts.EnableASTScopeLookup && SF.isSuitableForASTScopes())
334-
SF.getScope()
342+
auto &Ctx = SF->getASTContext();
343+
if (Ctx.LangOpts.EnableASTScopeLookup && SF->isSuitableForASTScopes())
344+
SF->getScope()
335345
.buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
336346

337-
BufferIndirectlyCausingDiagnosticRAII cpr(SF);
347+
BufferIndirectlyCausingDiagnosticRAII cpr(*SF);
338348

339349
// Make sure we have a type checker.
340350
TypeChecker &TC = createTypeChecker(Ctx);
341351

342352
// Make sure that name binding has been completed before doing any type
343353
// checking.
344-
performNameBinding(SF, StartElem);
354+
performNameBinding(*SF, StartElem);
345355

346356
// Could build scope maps here because the AST is stable now.
347357

@@ -352,22 +362,22 @@ void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
352362
// Disable this optimization if we're compiling SwiftOnoneSupport, because
353363
// we _definitely_ need to look inside every declaration to figure out
354364
// what gets prespecialized.
355-
if (SF.getParentModule()->isOnoneSupportModule())
365+
if (SF->getParentModule()->isOnoneSupportModule())
356366
Ctx.TypeCheckerOpts.SkipNonInlinableFunctionBodies = false;
357367

358368
if (!Ctx.LangOpts.DisableAvailabilityChecking) {
359369
// Build the type refinement hierarchy for the primary
360370
// file before type checking.
361-
TypeChecker::buildTypeRefinementContextHierarchy(SF, StartElem);
371+
TypeChecker::buildTypeRefinementContextHierarchy(*SF, StartElem);
362372
}
363373

364374
// Resolve extensions. This has to occur first during type checking,
365375
// because the extensions need to be wired into the AST for name lookup
366376
// to work.
367-
::bindExtensions(SF);
377+
::bindExtensions(*SF);
368378

369379
// Type check the top-level elements of the source file.
370-
for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
380+
for (auto D : llvm::makeArrayRef(SF->Decls).slice(StartElem)) {
371381
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
372382
// Immediately perform global name-binding etc.
373383
TypeChecker::typeCheckTopLevelCodeDecl(TLCD);
@@ -379,44 +389,18 @@ void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
379389

380390
// If we're in REPL mode, inject temporary result variables and other stuff
381391
// that the REPL needs to synthesize.
382-
if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError())
383-
TypeChecker::processREPLTopLevel(SF, StartElem);
392+
if (SF->Kind == SourceFileKind::REPL && !Ctx.hadError())
393+
TypeChecker::processREPLTopLevel(*SF, StartElem);
384394

385-
typeCheckFunctionsAndExternalDecls(SF, TC);
395+
typeCheckFunctionsAndExternalDecls(*SF, TC);
386396
}
387397

388398
// Checking that benefits from having the whole module available.
389399
if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking) {
390-
performWholeModuleTypeChecking(SF);
400+
performWholeModuleTypeChecking(*SF);
391401
}
392402

393-
// Verify that we've checked types correctly.
394-
SF.ASTStage = SourceFile::TypeChecked;
395-
396-
{
397-
FrontendStatsTracer tracer(Ctx.Stats, "AST verification");
398-
// Verify the SourceFile.
399-
verify(SF);
400-
401-
// Verify imported modules.
402-
//
403-
// Skip per-file verification in whole-module mode. Verifying imports
404-
// between files could cause the importer to cache declarations without
405-
// adding them to the ASTContext. This happens when the importer registers a
406-
// declaration without a valid TypeChecker instance, as is the case during
407-
// verification. A subsequent file may require that declaration to be fully
408-
// imported (e.g. to synthesized a function body), but since it has already
409-
// been cached, it will never be added to the ASTContext. The solution is to
410-
// skip verification and avoid caching it.
411-
#ifndef NDEBUG
412-
if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking &&
413-
SF.Kind != SourceFileKind::REPL &&
414-
SF.Kind != SourceFileKind::SIL &&
415-
!Ctx.LangOpts.DebuggerSupport) {
416-
Ctx.verifyAllLoadedModules();
417-
}
418-
#endif
419-
}
403+
return true;
420404
}
421405

422406
void swift::performWholeModuleTypeChecking(SourceFile &SF) {

test/decl/class/circular_inheritance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class Outer3 // expected-error {{circular reference}}
4747
}
4848

4949
// CHECK: ===CYCLE DETECTED===
50-
// CHECK-NEXT: `--{{.*}}HasCircularInheritanceRequest(circular_inheritance.(file).Left@
50+
// CHECK-LABEL: `--{{.*}}HasCircularInheritanceRequest(circular_inheritance.(file).Left@
5151
// CHECK-NEXT: `--{{.*}}SuperclassDeclRequest({{.*Left}}
5252
// CHECK: `--{{.*}}InheritedDeclsReferencedRequest(circular_inheritance.(file).Left@
5353
// CHECK: `--{{.*}}SuperclassDeclRequest

0 commit comments

Comments
 (0)