mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #28544 from CodaFi/file-unit-arianism
Add a high-level request to type check a file
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -50,6 +50,7 @@ struct PropertyWrapperMutability;
|
||||
class ProtocolDecl;
|
||||
class Requirement;
|
||||
enum class ResilienceExpansion : unsigned;
|
||||
class SourceFile;
|
||||
class Type;
|
||||
class ValueDecl;
|
||||
class VarDecl;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<>
|
||||
|
||||
@@ -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 *),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user