mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The Swift 4 Migrator is invoked through either the driver and frontend
with the -update-code flag.
The basic pipeline in the frontend is:
- Perform some list of syntactic fixes (there are currently none).
- Perform N rounds of sema fix-its on the primary input file, currently
set to 7 based on prior migrator seasons. Right now, this is just set
to take any fix-it suggested by the compiler.
- Emit a replacement map file, a JSON file describing replacements to a
file that Xcode knows how to understand.
Currently, the Migrator maintains a history of migration states along
the way for debugging purposes.
- Add -emit-remap frontend option
This will indicate the EmitRemap frontend action.
- Don't fork to a separte swift-update binary.
This is going to be a mode of the compiler, invoked by the same flags.
- Add -disable-migrator-fixits option
Useful for debugging, this skips the phase in the Migrator that
automatically applies fix-its suggested by the compiler.
- Add -emit-migrated-file-path option
This is used for testing/debugging scenarios. This takes the final
migration state's output text and writes it to the file specified
by this option.
- Add -dump-migration-states-dir
This dumps all of the migration states encountered during a migration
run for a file to the given directory. For example, the compiler
fix-it migration pass dumps the input file, the output file, and the
remap file between the two.
State output has the following naming convention:
${Index}-${MigrationPassName}-${What}.${extension}, such as:
1-FixitMigrationState-Input.swift
rdar://problem/30926261
352 lines
14 KiB
C++
352 lines
14 KiB
C++
//===--- Subsystems.h - Swift Compiler Subsystem Entrypoints ----*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file declares the main entrypoints to the various subsystems.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SUBSYSTEMS_H
|
|
#define SWIFT_SUBSYSTEMS_H
|
|
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "swift/Basic/OptionSet.h"
|
|
#include "swift/Basic/Version.h"
|
|
#include "swift/Syntax/TokenSyntax.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/Optional.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Mutex.h"
|
|
|
|
#include <memory>
|
|
|
|
namespace llvm {
|
|
class GlobalVariable;
|
|
class MemoryBuffer;
|
|
class Module;
|
|
class TargetOptions;
|
|
class TargetMachine;
|
|
}
|
|
|
|
namespace swift {
|
|
class GenericSignatureBuilder;
|
|
class ASTContext;
|
|
class CodeCompletionCallbacksFactory;
|
|
class Decl;
|
|
class DeclContext;
|
|
class DelayedParsingCallbacks;
|
|
class DiagnosticConsumer;
|
|
class DiagnosticEngine;
|
|
class FileUnit;
|
|
class GenericEnvironment;
|
|
class GenericParamList;
|
|
class IRGenOptions;
|
|
class LangOptions;
|
|
class ModuleDecl;
|
|
class Parser;
|
|
class PersistentParserState;
|
|
class SerializationOptions;
|
|
class SILOptions;
|
|
class SILModule;
|
|
class SILParserTUState;
|
|
class SourceFile;
|
|
class SourceManager;
|
|
class Token;
|
|
class TopLevelContext;
|
|
struct TypeLoc;
|
|
|
|
/// SILParserState - This is a context object used to optionally maintain SIL
|
|
/// parsing context for the parser.
|
|
class SILParserState {
|
|
public:
|
|
SILModule *M;
|
|
SILParserTUState *S;
|
|
|
|
explicit SILParserState(SILModule *M);
|
|
~SILParserState();
|
|
};
|
|
|
|
/// @{
|
|
|
|
/// \returns true if the declaration should be verified. This can return
|
|
/// false to decrease the number of declarations we verify in a single
|
|
/// compilation.
|
|
bool shouldVerify(const Decl *D, const ASTContext &Context);
|
|
|
|
/// \brief Check that the source file is well-formed, aborting and spewing
|
|
/// errors if not.
|
|
///
|
|
/// "Well-formed" here means following the invariants of the AST, not that the
|
|
/// code written by the user makes sense.
|
|
void verify(SourceFile &SF);
|
|
void verify(Decl *D);
|
|
|
|
/// @}
|
|
|
|
/// \brief Parse a single buffer into the given source file.
|
|
///
|
|
/// If the source file is the main file, stop parsing after the next
|
|
/// stmt-brace-item with side-effects.
|
|
///
|
|
/// \param SF the file within the module being parsed.
|
|
///
|
|
/// \param BufferID the buffer to parse from.
|
|
///
|
|
/// \param[out] Done set to \c true if end of the buffer was reached.
|
|
///
|
|
/// \param SIL if non-null, we're parsing a SIL file.
|
|
///
|
|
/// \param PersistentState if non-null the same PersistentState object can
|
|
/// be used to resume parsing or parse delayed function bodies.
|
|
///
|
|
/// \param DelayedParseCB if non-null enables delayed parsing for function
|
|
/// bodies.
|
|
///
|
|
/// \return true if the parser found code with side effects.
|
|
bool parseIntoSourceFile(SourceFile &SF, unsigned BufferID, bool *Done,
|
|
SILParserState *SIL = nullptr,
|
|
PersistentParserState *PersistentState = nullptr,
|
|
DelayedParsingCallbacks *DelayedParseCB = nullptr);
|
|
|
|
/// \brief Finish the parsing by going over the nodes that were delayed
|
|
/// during the first parsing pass.
|
|
void performDelayedParsing(DeclContext *DC,
|
|
PersistentParserState &PersistentState,
|
|
CodeCompletionCallbacksFactory *Factory);
|
|
|
|
/// \brief Lex and return a vector of tokens for the given buffer.
|
|
std::vector<Token> tokenize(const LangOptions &LangOpts,
|
|
const SourceManager &SM, unsigned BufferID,
|
|
unsigned Offset = 0, unsigned EndOffset = 0,
|
|
bool KeepComments = true,
|
|
bool TokenizeInterpolatedString = true,
|
|
ArrayRef<Token> SplitTokens = ArrayRef<Token>());
|
|
|
|
/// \brief Lex and return a vector of `RC<TokenSyntax>` tokens, which include
|
|
/// leading and trailing trivia.
|
|
std::vector<std::pair<RC<syntax::TokenSyntax>,
|
|
syntax::AbsolutePosition>>
|
|
tokenizeWithTrivia(const LangOptions &LangOpts,
|
|
const SourceManager &SM,
|
|
unsigned BufferID,
|
|
unsigned Offset = 0,
|
|
unsigned EndOffset = 0);
|
|
|
|
/// Once parsing is complete, this walks the AST to resolve imports, record
|
|
/// operators, and do other top-level validation.
|
|
///
|
|
/// \param StartElem Where to start for incremental name binding in the main
|
|
/// source file.
|
|
void performNameBinding(SourceFile &SF, unsigned StartElem = 0);
|
|
|
|
/// Once parsing and name-binding are complete, this optionally transforms the
|
|
/// ASTs to add calls to external logging functions.
|
|
///
|
|
/// \param HighPerformance True if the playground transform should omit
|
|
/// instrumentation that has a high runtime performance impact.
|
|
void performPlaygroundTransform(SourceFile &SF, bool HighPerformance);
|
|
|
|
/// Once parsing and name-binding are complete this optionally walks the ASTs
|
|
/// to add calls to externally provided functions that simulate
|
|
/// "program counter"-like debugging events.
|
|
void performPCMacro(SourceFile &SF, TopLevelContext &TLC);
|
|
|
|
/// Flags used to control type checking.
|
|
enum class TypeCheckingFlags : unsigned {
|
|
/// Whether to delay checking that benefits from having the entire
|
|
/// module parsed, e.g., Objective-C method override checking.
|
|
DelayWholeModuleChecking = 1 << 0,
|
|
|
|
/// If set, dumps wall time taken to check each function body to
|
|
/// llvm::errs().
|
|
DebugTimeFunctionBodies = 1 << 1,
|
|
|
|
/// Indicates that the type checker is checking code that will be
|
|
/// immediately executed.
|
|
ForImmediateMode = 1 << 2,
|
|
|
|
/// If set, dumps wall time taken to type check each expression to
|
|
/// llvm::errs().
|
|
DebugTimeExpressions = 1 << 3,
|
|
};
|
|
|
|
/// Once parsing and name-binding are complete, this walks the AST to resolve
|
|
/// types and diagnose problems therein.
|
|
///
|
|
/// \param StartElem Where to start for incremental type-checking in the main
|
|
/// source file.
|
|
///
|
|
/// \param WarnLongFunctionBodies If non-zero, warn when a function body takes
|
|
/// longer than this many milliseconds to type-check
|
|
void performTypeChecking(SourceFile &SF, TopLevelContext &TLC,
|
|
OptionSet<TypeCheckingFlags> Options,
|
|
unsigned StartElem = 0,
|
|
unsigned WarnLongFunctionBodies = 0);
|
|
|
|
/// Once type checking is complete, this walks protocol requirements
|
|
/// to resolve default witnesses.
|
|
void finishTypeChecking(SourceFile &SF);
|
|
|
|
/// Now that we have type-checked an entire module, perform any type
|
|
/// checking that requires the full module, e.g., Objective-C method
|
|
/// override checking.
|
|
///
|
|
/// Note that clients still perform this checking file-by-file to
|
|
/// provide a somewhat defined order in which diagnostics should be
|
|
/// emitted.
|
|
void performWholeModuleTypeChecking(SourceFile &SF);
|
|
|
|
/// Incrementally type-check only added external definitions.
|
|
void typeCheckExternalDefinitions(SourceFile &SF);
|
|
|
|
/// \brief Recursively validate the specified type.
|
|
///
|
|
/// This is used when dealing with partial source files (e.g. SIL parsing,
|
|
/// code completion).
|
|
///
|
|
/// \returns false on success, true on error.
|
|
bool performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
|
|
DeclContext *DC,
|
|
bool ProduceDiagnostics = true);
|
|
|
|
/// \brief Recursively validate the specified type.
|
|
///
|
|
/// This is used when dealing with partial source files (e.g. SIL parsing,
|
|
/// code completion).
|
|
///
|
|
/// \returns false on success, true on error.
|
|
bool performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
|
|
bool isSILMode,
|
|
bool isSILType,
|
|
GenericEnvironment *GenericEnv,
|
|
DeclContext *DC,
|
|
bool ProduceDiagnostics = true);
|
|
|
|
/// Expose TypeChecker's handling of GenericParamList to SIL parsing.
|
|
GenericEnvironment *handleSILGenericParams(ASTContext &Ctx,
|
|
GenericParamList *genericParams,
|
|
DeclContext *DC);
|
|
|
|
/// Turn the given module into SIL IR.
|
|
///
|
|
/// The module must contain source files.
|
|
///
|
|
/// If \p makeModuleFragile is true, all functions and global variables of
|
|
/// the module are marked as fragile. This is used for compiling the stdlib.
|
|
/// if \p wholeModuleCompilation is true, the optimizer assumes that the SIL
|
|
/// of all files in the module is present in the SILModule.
|
|
std::unique_ptr<SILModule>
|
|
performSILGeneration(ModuleDecl *M, SILOptions &options,
|
|
bool makeModuleFragile = false,
|
|
bool wholeModuleCompilation = false);
|
|
|
|
/// Turn a source file into SIL IR.
|
|
///
|
|
/// If \p StartElem is provided, the module is assumed to be only part of the
|
|
/// SourceFile, and any optimizations should take that into account.
|
|
/// If \p makeModuleFragile is true, all functions and global variables of
|
|
/// the module are marked as fragile. This is used for compiling the stdlib.
|
|
std::unique_ptr<SILModule>
|
|
performSILGeneration(FileUnit &SF, SILOptions &options,
|
|
Optional<unsigned> StartElem = None,
|
|
bool makeModuleFragile = false);
|
|
|
|
using ModuleOrSourceFile = PointerUnion<ModuleDecl *, SourceFile *>;
|
|
|
|
/// Serializes a module or single source file to the given output file.
|
|
void serialize(ModuleOrSourceFile DC, const SerializationOptions &options,
|
|
const SILModule *M = nullptr);
|
|
|
|
/// Get the CPU and subtarget feature options to use when emitting code.
|
|
std::tuple<llvm::TargetOptions, std::string, std::vector<std::string>>
|
|
getIRTargetOptions(IRGenOptions &Opts, ASTContext &Ctx);
|
|
|
|
/// Turn the given Swift module into either LLVM IR or native code
|
|
/// and return the generated LLVM IR module.
|
|
/// If you set an outModuleHash, then you need to call performLLVM.
|
|
std::unique_ptr<llvm::Module>
|
|
performIRGeneration(IRGenOptions &Opts, ModuleDecl *M,
|
|
std::unique_ptr<SILModule> SILMod,
|
|
StringRef ModuleName, llvm::LLVMContext &LLVMContext,
|
|
llvm::GlobalVariable **outModuleHash = nullptr);
|
|
|
|
/// Turn the given Swift module into either LLVM IR or native code
|
|
/// and return the generated LLVM IR module.
|
|
/// If you set an outModuleHash, then you need to call performLLVM.
|
|
std::unique_ptr<llvm::Module>
|
|
performIRGeneration(IRGenOptions &Opts, SourceFile &SF,
|
|
std::unique_ptr<SILModule> SILMod,
|
|
StringRef ModuleName, llvm::LLVMContext &LLVMContext,
|
|
unsigned StartElem = 0,
|
|
llvm::GlobalVariable **outModuleHash = nullptr);
|
|
|
|
/// Given an already created LLVM module, construct a pass pipeline and run
|
|
/// the Swift LLVM Pipeline upon it. This does not cause the module to be
|
|
/// printed, only to be optimized.
|
|
void performLLVMOptimizations(IRGenOptions &Opts, llvm::Module *Module,
|
|
llvm::TargetMachine *TargetMachine);
|
|
|
|
/// Wrap a serialized module inside a swift AST section in an object file.
|
|
void createSwiftModuleObjectFile(SILModule &SILMod, StringRef Buffer,
|
|
StringRef OutputPath);
|
|
|
|
/// Turn the given LLVM module into native code and return true on error.
|
|
bool performLLVM(IRGenOptions &Opts, ASTContext &Ctx,
|
|
llvm::Module *Module);
|
|
|
|
/// Run the LLVM passes. In multi-threaded compilation this will be done for
|
|
/// multiple LLVM modules in parallel.
|
|
/// \param Diags may be null if LLVM code gen diagnostics are not required.
|
|
/// \param DiagMutex may also be null if a mutex around \p Diags is not
|
|
/// required.
|
|
/// \param HashGlobal used with incremental LLVMCodeGen to know if a module
|
|
/// was already compiled, may be null if not desired.
|
|
/// \param Module LLVM module to code gen, required.
|
|
/// \param TargetMachine target of code gen, required.
|
|
/// \param effectiveLanguageVersion version of the language, effectively.
|
|
/// \param OutputFilename Filename for output.
|
|
bool performLLVM(IRGenOptions &Opts, DiagnosticEngine *Diags,
|
|
llvm::sys::Mutex *DiagMutex,
|
|
llvm::GlobalVariable *HashGlobal,
|
|
llvm::Module *Module,
|
|
llvm::TargetMachine *TargetMachine,
|
|
const version::Version &effectiveLanguageVersion,
|
|
StringRef OutputFilename);
|
|
|
|
/// Creates a TargetMachine from the IRGen opts and AST Context.
|
|
std::unique_ptr<llvm::TargetMachine>
|
|
createTargetMachine(IRGenOptions &Opts, ASTContext &Ctx);
|
|
|
|
/// A convenience wrapper for Parser functionality.
|
|
class ParserUnit {
|
|
public:
|
|
ParserUnit(SourceManager &SM, unsigned BufferID,
|
|
const LangOptions &LangOpts, StringRef ModuleName);
|
|
ParserUnit(SourceManager &SM, unsigned BufferID);
|
|
ParserUnit(SourceManager &SM, unsigned BufferID,
|
|
unsigned Offset, unsigned EndOffset);
|
|
|
|
~ParserUnit();
|
|
|
|
Parser &getParser();
|
|
SourceFile &getSourceFile();
|
|
DiagnosticEngine &getDiagnosticEngine();
|
|
const LangOptions &getLangOptions() const;
|
|
|
|
private:
|
|
struct Implementation;
|
|
Implementation &Impl;
|
|
};
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_SUBSYSTEMS_H
|