Skip to content

Commit 8b7d898

Browse files
authored
Merge pull request #28503 from CodaFi/file-it-under-t
[NFC] Add a high-level request to type check a file
2 parents 855671a + 1b1fac3 commit 8b7d898

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
@@ -477,6 +477,11 @@ inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMainClassWithScript() {
477477
return !res;
478478
}
479479

480+
inline void simple_display(llvm::raw_ostream &out, const SourceFile *SF) {
481+
assert(SF && "Cannot display null source file!");
482+
483+
out << "source_file " << '\"' << SF->getFilename() << '\"';
484+
}
480485
} // end namespace swift
481486

482487
#endif

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,27 @@ class DynamicallyReplacedDeclRequest
19051905
bool isCached() const { return true; }
19061906
};
19071907

1908+
class TypeCheckSourceFileRequest :
1909+
public SimpleRequest<TypeCheckSourceFileRequest,
1910+
bool (SourceFile *, unsigned),
1911+
CacheKind::SeparatelyCached> {
1912+
public:
1913+
using SimpleRequest::SimpleRequest;
1914+
1915+
private:
1916+
friend SimpleRequest;
1917+
1918+
// Evaluation.
1919+
llvm::Expected<bool> evaluate(Evaluator &evaluator,
1920+
SourceFile *SF, unsigned StartElem) const;
1921+
1922+
public:
1923+
// Separate caching.
1924+
bool isCached() const { return true; }
1925+
Optional<bool> getCachedResult() const;
1926+
void cacheResult(bool result) const;
1927+
};
1928+
19081929
// Allow AnyValue to compare two Type values, even though Type doesn't
19091930
// support ==.
19101931
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,
201201
bool(NominalTypeDecl *), Cached, NoLocationInfo)
202202
SWIFT_REQUEST(TypeChecker, SynthesizeDefaultInitRequest,
203203
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
204+
SWIFT_REQUEST(TypeChecker, TypeCheckSourceFileRequest,
205+
bool(SouceFile *, unsigned), SeparatelyCached, NoLocationInfo)
204206
SWIFT_REQUEST(TypeChecker, TypeWitnessRequest,
205207
TypeWitnessAndDecl(NormalProtocolConformance *,
206208
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

@@ -1218,3 +1220,48 @@ void DefaultArgumentExprRequest::cacheResult(Expr *expr) const {
12181220
auto *param = std::get<0>(getStorage());
12191221
param->setDefaultExpr(expr, /*isTypeChecked*/ true);
12201222
}
1223+
1224+
//----------------------------------------------------------------------------//
1225+
// TypeCheckSourceFileRequest computation.
1226+
//----------------------------------------------------------------------------//
1227+
1228+
Optional<bool> TypeCheckSourceFileRequest::getCachedResult() const {
1229+
auto *SF = std::get<0>(getStorage());
1230+
if (SF->ASTStage == SourceFile::TypeChecked)
1231+
return true;
1232+
1233+
return None;
1234+
}
1235+
1236+
void TypeCheckSourceFileRequest::cacheResult(bool result) const {
1237+
auto *SF = std::get<0>(getStorage());
1238+
1239+
// Verify that we've checked types correctly.
1240+
SF->ASTStage = SourceFile::TypeChecked;
1241+
1242+
{
1243+
auto &Ctx = SF->getASTContext();
1244+
FrontendStatsTracer tracer(Ctx.Stats, "AST verification");
1245+
// Verify the SourceFile.
1246+
swift::verify(*SF);
1247+
1248+
// Verify imported modules.
1249+
//
1250+
// Skip per-file verification in whole-module mode. Verifying imports
1251+
// between files could cause the importer to cache declarations without
1252+
// adding them to the ASTContext. This happens when the importer registers a
1253+
// declaration without a valid TypeChecker instance, as is the case during
1254+
// verification. A subsequent file may require that declaration to be fully
1255+
// imported (e.g. to synthesized a function body), but since it has already
1256+
// been cached, it will never be added to the ASTContext. The solution is to
1257+
// skip verification and avoid caching it.
1258+
#ifndef NDEBUG
1259+
if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking &&
1260+
SF->Kind != SourceFileKind::REPL &&
1261+
SF->Kind != SourceFileKind::SIL &&
1262+
!Ctx.LangOpts.DebuggerSupport) {
1263+
Ctx.verifyAllLoadedModules();
1264+
}
1265+
#endif
1266+
}
1267+
}

lib/Frontend/Frontend.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/DiagnosticsFrontend.h"
2121
#include "swift/AST/DiagnosticsSema.h"
2222
#include "swift/AST/Module.h"
23+
#include "swift/AST/TypeCheckRequests.h"
2324
#include "swift/Basic/FileTypes.h"
2425
#include "swift/Basic/SourceManager.h"
2526
#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"
@@ -310,26 +311,35 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC)
310311
}
311312

312313
void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
313-
if (SF.ASTStage == SourceFile::TypeChecked)
314-
return;
314+
return (void)evaluateOrDefault(SF.getASTContext().evaluator,
315+
TypeCheckSourceFileRequest{&SF, StartElem},
316+
false);
317+
}
318+
319+
llvm::Expected<bool>
320+
TypeCheckSourceFileRequest::evaluate(Evaluator &eval,
321+
SourceFile *SF, unsigned StartElem) const {
322+
assert(SF && "Source file cannot be null!");
323+
assert(SF->ASTStage != SourceFile::TypeChecked &&
324+
"Should not be re-typechecking this file!");
315325

316326
// Eagerly build the top-level scopes tree before type checking
317327
// because type-checking expressions mutates the AST and that throws off the
318328
// scope-based lookups. Only the top-level scopes because extensions have not
319329
// been bound yet.
320-
auto &Ctx = SF.getASTContext();
321-
if (Ctx.LangOpts.EnableASTScopeLookup && SF.isSuitableForASTScopes())
322-
SF.getScope()
330+
auto &Ctx = SF->getASTContext();
331+
if (Ctx.LangOpts.EnableASTScopeLookup && SF->isSuitableForASTScopes())
332+
SF->getScope()
323333
.buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
324334

325-
BufferIndirectlyCausingDiagnosticRAII cpr(SF);
335+
BufferIndirectlyCausingDiagnosticRAII cpr(*SF);
326336

327337
// Make sure we have a type checker.
328338
TypeChecker &TC = createTypeChecker(Ctx);
329339

330340
// Make sure that name binding has been completed before doing any type
331341
// checking.
332-
performNameBinding(SF, StartElem);
342+
performNameBinding(*SF, StartElem);
333343

334344
// Could build scope maps here because the AST is stable now.
335345

@@ -340,22 +350,22 @@ void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
340350
// Disable this optimization if we're compiling SwiftOnoneSupport, because
341351
// we _definitely_ need to look inside every declaration to figure out
342352
// what gets prespecialized.
343-
if (SF.getParentModule()->isOnoneSupportModule())
353+
if (SF->getParentModule()->isOnoneSupportModule())
344354
Ctx.TypeCheckerOpts.SkipNonInlinableFunctionBodies = false;
345355

346356
if (!Ctx.LangOpts.DisableAvailabilityChecking) {
347357
// Build the type refinement hierarchy for the primary
348358
// file before type checking.
349-
TypeChecker::buildTypeRefinementContextHierarchy(SF, StartElem);
359+
TypeChecker::buildTypeRefinementContextHierarchy(*SF, StartElem);
350360
}
351361

352362
// Resolve extensions. This has to occur first during type checking,
353363
// because the extensions need to be wired into the AST for name lookup
354364
// to work.
355-
::bindExtensions(SF);
365+
::bindExtensions(*SF);
356366

357367
// Type check the top-level elements of the source file.
358-
for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
368+
for (auto D : llvm::makeArrayRef(SF->Decls).slice(StartElem)) {
359369
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
360370
// Immediately perform global name-binding etc.
361371
TypeChecker::typeCheckTopLevelCodeDecl(TLCD);
@@ -367,44 +377,18 @@ void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
367377

368378
// If we're in REPL mode, inject temporary result variables and other stuff
369379
// that the REPL needs to synthesize.
370-
if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError())
371-
TypeChecker::processREPLTopLevel(SF, StartElem);
380+
if (SF->Kind == SourceFileKind::REPL && !Ctx.hadError())
381+
TypeChecker::processREPLTopLevel(*SF, StartElem);
372382

373-
typeCheckFunctionsAndExternalDecls(SF, TC);
383+
typeCheckFunctionsAndExternalDecls(*SF, TC);
374384
}
375385

376386
// Checking that benefits from having the whole module available.
377387
if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking) {
378-
performWholeModuleTypeChecking(SF);
388+
performWholeModuleTypeChecking(*SF);
379389
}
380390

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

410394
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)