Merge pull request #28544 from CodaFi/file-unit-arianism

Add a high-level request to type check a file
This commit is contained in:
Robert Widmann
2019-12-03 19:37:53 -08:00
committed by GitHub
9 changed files with 105 additions and 43 deletions

View File

@@ -49,6 +49,7 @@ SWIFT_TYPEID_NAMED(ParamDecl *, ParamDecl)
SWIFT_TYPEID_NAMED(PatternBindingEntry *, PatternBindingEntry)
SWIFT_TYPEID_NAMED(PrecedenceGroupDecl *, PrecedenceGroupDecl)
SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl)
SWIFT_TYPEID_NAMED(SourceFile *, SourceFile)
SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl)
SWIFT_TYPEID_NAMED(ValueDecl *, ValueDecl)
SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)

View File

@@ -50,6 +50,7 @@ struct PropertyWrapperMutability;
class ProtocolDecl;
class Requirement;
enum class ResilienceExpansion : unsigned;
class SourceFile;
class Type;
class ValueDecl;
class VarDecl;

View File

@@ -482,6 +482,11 @@ inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMainClassWithScript() {
return !res;
}
inline void simple_display(llvm::raw_ostream &out, const SourceFile *SF) {
assert(SF && "Cannot display null source file!");
out << "source_file " << '\"' << SF->getFilename() << '\"';
}
} // end namespace swift
#endif

View File

@@ -1949,6 +1949,27 @@ public:
bool isCached() const { return true; }
};
class TypeCheckSourceFileRequest :
public SimpleRequest<TypeCheckSourceFileRequest,
bool (SourceFile *, unsigned),
CacheKind::SeparatelyCached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
llvm::Expected<bool> evaluate(Evaluator &evaluator,
SourceFile *SF, unsigned StartElem) const;
public:
// Separate caching.
bool isCached() const { return true; }
Optional<bool> getCachedResult() const;
void cacheResult(bool result) const;
};
// Allow AnyValue to compare two Type values, even though Type doesn't
// support ==.
template<>

View File

@@ -205,6 +205,8 @@ SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,
bool(NominalTypeDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, SynthesizeDefaultInitRequest,
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, TypeCheckSourceFileRequest,
bool(SouceFile *, unsigned), SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, TypeWitnessRequest,
TypeWitnessAndDecl(NormalProtocolConformance *,
AssociatedTypeDecl *),

View File

@@ -18,10 +18,12 @@
#include "swift/AST/NameLookup.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeLoc.h"
#include "swift/AST/TypeRepr.h"
#include "swift/AST/Types.h"
#include "swift/Subsystems.h"
using namespace swift;
@@ -1238,3 +1240,48 @@ void CallerSideDefaultArgExprRequest::cacheResult(Expr *expr) const {
auto *defaultExpr = std::get<0>(getStorage());
defaultExpr->ContextOrCallerSideExpr = expr;
}
//----------------------------------------------------------------------------//
// TypeCheckSourceFileRequest computation.
//----------------------------------------------------------------------------//
Optional<bool> TypeCheckSourceFileRequest::getCachedResult() const {
auto *SF = std::get<0>(getStorage());
if (SF->ASTStage == SourceFile::TypeChecked)
return true;
return None;
}
void TypeCheckSourceFileRequest::cacheResult(bool result) const {
auto *SF = std::get<0>(getStorage());
// Verify that we've checked types correctly.
SF->ASTStage = SourceFile::TypeChecked;
{
auto &Ctx = SF->getASTContext();
FrontendStatsTracer tracer(Ctx.Stats, "AST verification");
// Verify the SourceFile.
swift::verify(*SF);
// Verify imported modules.
//
// Skip per-file verification in whole-module mode. Verifying imports
// between files could cause the importer to cache declarations without
// adding them to the ASTContext. This happens when the importer registers a
// declaration without a valid TypeChecker instance, as is the case during
// verification. A subsequent file may require that declaration to be fully
// imported (e.g. to synthesized a function body), but since it has already
// been cached, it will never be added to the ASTContext. The solution is to
// skip verification and avoid caching it.
#ifndef NDEBUG
if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking &&
SF->Kind != SourceFileKind::REPL &&
SF->Kind != SourceFileKind::SIL &&
!Ctx.LangOpts.DebuggerSupport) {
Ctx.verifyAllLoadedModules();
}
#endif
}
}

View File

@@ -22,6 +22,7 @@
#include "swift/AST/FileSystem.h"
#include "swift/AST/IncrementalRanges.h"
#include "swift/AST/Module.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/FileTypes.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"

View File

@@ -35,6 +35,7 @@
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/Timer.h"
@@ -322,26 +323,35 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC)
}
void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
if (SF.ASTStage == SourceFile::TypeChecked)
return;
return (void)evaluateOrDefault(SF.getASTContext().evaluator,
TypeCheckSourceFileRequest{&SF, StartElem},
false);
}
llvm::Expected<bool>
TypeCheckSourceFileRequest::evaluate(Evaluator &eval,
SourceFile *SF, unsigned StartElem) const {
assert(SF && "Source file cannot be null!");
assert(SF->ASTStage != SourceFile::TypeChecked &&
"Should not be re-typechecking this file!");
// Eagerly build the top-level scopes tree before type checking
// because type-checking expressions mutates the AST and that throws off the
// scope-based lookups. Only the top-level scopes because extensions have not
// been bound yet.
auto &Ctx = SF.getASTContext();
if (Ctx.LangOpts.EnableASTScopeLookup && SF.isSuitableForASTScopes())
SF.getScope()
auto &Ctx = SF->getASTContext();
if (Ctx.LangOpts.EnableASTScopeLookup && SF->isSuitableForASTScopes())
SF->getScope()
.buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
BufferIndirectlyCausingDiagnosticRAII cpr(SF);
BufferIndirectlyCausingDiagnosticRAII cpr(*SF);
// Make sure we have a type checker.
TypeChecker &TC = createTypeChecker(Ctx);
// Make sure that name binding has been completed before doing any type
// checking.
performNameBinding(SF, StartElem);
performNameBinding(*SF, StartElem);
// Could build scope maps here because the AST is stable now.
@@ -352,22 +362,22 @@ void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
// Disable this optimization if we're compiling SwiftOnoneSupport, because
// we _definitely_ need to look inside every declaration to figure out
// what gets prespecialized.
if (SF.getParentModule()->isOnoneSupportModule())
if (SF->getParentModule()->isOnoneSupportModule())
Ctx.TypeCheckerOpts.SkipNonInlinableFunctionBodies = false;
if (!Ctx.LangOpts.DisableAvailabilityChecking) {
// Build the type refinement hierarchy for the primary
// file before type checking.
TypeChecker::buildTypeRefinementContextHierarchy(SF, StartElem);
TypeChecker::buildTypeRefinementContextHierarchy(*SF, StartElem);
}
// Resolve extensions. This has to occur first during type checking,
// because the extensions need to be wired into the AST for name lookup
// to work.
::bindExtensions(SF);
::bindExtensions(*SF);
// Type check the top-level elements of the source file.
for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
for (auto D : llvm::makeArrayRef(SF->Decls).slice(StartElem)) {
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
// Immediately perform global name-binding etc.
TypeChecker::typeCheckTopLevelCodeDecl(TLCD);
@@ -379,44 +389,18 @@ void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
// If we're in REPL mode, inject temporary result variables and other stuff
// that the REPL needs to synthesize.
if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError())
TypeChecker::processREPLTopLevel(SF, StartElem);
if (SF->Kind == SourceFileKind::REPL && !Ctx.hadError())
TypeChecker::processREPLTopLevel(*SF, StartElem);
typeCheckFunctionsAndExternalDecls(SF, TC);
typeCheckFunctionsAndExternalDecls(*SF, TC);
}
// Checking that benefits from having the whole module available.
if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking) {
performWholeModuleTypeChecking(SF);
performWholeModuleTypeChecking(*SF);
}
// Verify that we've checked types correctly.
SF.ASTStage = SourceFile::TypeChecked;
{
FrontendStatsTracer tracer(Ctx.Stats, "AST verification");
// Verify the SourceFile.
verify(SF);
// Verify imported modules.
//
// Skip per-file verification in whole-module mode. Verifying imports
// between files could cause the importer to cache declarations without
// adding them to the ASTContext. This happens when the importer registers a
// declaration without a valid TypeChecker instance, as is the case during
// verification. A subsequent file may require that declaration to be fully
// imported (e.g. to synthesized a function body), but since it has already
// been cached, it will never be added to the ASTContext. The solution is to
// skip verification and avoid caching it.
#ifndef NDEBUG
if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking &&
SF.Kind != SourceFileKind::REPL &&
SF.Kind != SourceFileKind::SIL &&
!Ctx.LangOpts.DebuggerSupport) {
Ctx.verifyAllLoadedModules();
}
#endif
}
return true;
}
void swift::performWholeModuleTypeChecking(SourceFile &SF) {

View File

@@ -47,7 +47,7 @@ class Outer3 // expected-error {{circular reference}}
}
// CHECK: ===CYCLE DETECTED===
// CHECK-NEXT: `--{{.*}}HasCircularInheritanceRequest(circular_inheritance.(file).Left@
// CHECK-LABEL: `--{{.*}}HasCircularInheritanceRequest(circular_inheritance.(file).Left@
// CHECK-NEXT: `--{{.*}}SuperclassDeclRequest({{.*Left}}
// CHECK: `--{{.*}}InheritedDeclsReferencedRequest(circular_inheritance.(file).Left@
// CHECK: `--{{.*}}SuperclassDeclRequest