[Frontend] Allow -emit-interface with -typecheck (#19676)

Textual module interfaces don't actually depend on SILGen, so we
shouldn't need to run SILGen (or serialize an entire binary module) if
we're just trying to emit a textual interface. On the other hand, if
we /are/ going to run SILGen and then SIL diagnostics, we shouldn't
delay those diagnostics by spending time emitting a textual interface,
or for that matter a TBD file.

Using this, update all the ModuleInterface tests that use
`-emit-module -o /dev/null` to use `-typecheck` instead, except for
those using `-merge-modules`.
This commit is contained in:
Jordan Rose
2018-10-03 15:07:31 -07:00
committed by GitHub
parent 6cc6f4f182
commit 3ea754481e
15 changed files with 84 additions and 36 deletions

View File

@@ -337,6 +337,11 @@ public:
/// so return the TBDPath when in that mode and fail an assert
/// if not in that mode.
std::string getTBDPathForWholeModule() const;
/// ModuleInterfaceOutputPath only makes sense in whole module compilation
/// mode, so return the ModuleInterfaceOutputPath when in that mode and fail
/// an assert if not in that mode.
std::string getModuleInterfaceOutputPathForWholeModule() const;
};
/// A class which manages the state and execution of the compiler.

View File

@@ -109,6 +109,15 @@ std::string CompilerInvocation::getTBDPathForWholeModule() const {
.SupplementaryOutputs.TBDPath;
}
std::string
CompilerInvocation::getModuleInterfaceOutputPathForWholeModule() const {
assert(getFrontendOptions().InputsAndOutputs.isWholeModule() &&
"ModuleInterfaceOutputPath only makes sense when the whole module can "
"be seen");
return getPrimarySpecificPathsForAtMostOnePrimary()
.SupplementaryOutputs.ModuleInterfaceOutputPath;
}
void CompilerInstance::createSILModule() {
assert(MainModule && "main module not created yet");
// Assume WMO if a -primary-file option was not provided.

View File

@@ -374,7 +374,6 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) {
case ActionType::NoneAction:
case ActionType::Parse:
case ActionType::ResolveImports:
case ActionType::Typecheck:
case ActionType::DumpParse:
case ActionType::DumpInterfaceHash:
case ActionType::DumpAST:
@@ -390,6 +389,7 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) {
case ActionType::REPL:
case ActionType::EmitImportedModules:
return false;
case ActionType::Typecheck:
case ActionType::MergeModules:
case ActionType::EmitModuleOnly:
case ActionType::EmitSIL:

View File

@@ -867,6 +867,40 @@ emitIndexData(CompilerInvocation &Invocation, CompilerInstance &Instance) {
return hadEmitIndexDataError;
}
/// Emits all "one-per-module" supplementary outputs that don't depend on
/// anything past type-checking.
///
/// These are extracted out so that they can be invoked early when using
/// `-typecheck`, but skipped for any mode that runs SIL diagnostics if there's
/// an error found there (to get those diagnostics back to the user faster).
static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs(
CompilerInstance &Instance, CompilerInvocation &Invocation,
bool moduleIsPublic) {
const FrontendOptions &opts = Invocation.getFrontendOptions();
// Record whether we failed to emit any of these outputs, but keep going; one
// failure does not mean skipping the rest.
bool hadAnyError = false;
if (opts.InputsAndOutputs.hasObjCHeaderOutputPath()) {
hadAnyError |= printAsObjCIfNeeded(
Invocation.getObjCHeaderOutputPathForAtMostOnePrimary(),
Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic);
}
if (opts.InputsAndOutputs.hasModuleInterfaceOutputPath()) {
hadAnyError |= printModuleInterfaceIfNeeded(
Invocation.getModuleInterfaceOutputPathForWholeModule(),
Instance.getMainModule());
}
{
hadAnyError |= writeTBDIfNeeded(Invocation, Instance);
}
return hadAnyError;
}
static bool performCompileStepsPostSILGen(
CompilerInstance &Instance, CompilerInvocation &Invocation,
std::unique_ptr<SILModule> SM, bool astGuaranteedToCorrespondToSIL,
@@ -965,9 +999,6 @@ static bool performCompile(CompilerInstance &Instance,
return true;
}
if (writeTBDIfNeeded(Invocation, Instance))
return true;
// FIXME: This is still a lousy approximation of whether the module file will
// be externally consumed.
bool moduleIsPublic =
@@ -977,17 +1008,14 @@ static bool performCompile(CompilerInstance &Instance,
// We've just been told to perform a typecheck, so we can return now.
if (Action == FrontendOptions::ActionType::Typecheck) {
const bool hadPrintAsObjCError =
Invocation.getFrontendOptions()
.InputsAndOutputs.hasObjCHeaderOutputPath() &&
printAsObjCIfNeeded(
Invocation.getObjCHeaderOutputPathForAtMostOnePrimary(),
Instance.getMainModule(), opts.ImplicitObjCHeaderPath,
moduleIsPublic);
const bool hadEmitIndexDataError = emitIndexData(Invocation, Instance);
return hadPrintAsObjCError || hadEmitIndexDataError || Context.hadError();
if (emitIndexData(Invocation, Instance))
return true;
if (emitAnyWholeModulePostTypeCheckSupplementaryOutputs(Instance,
Invocation,
moduleIsPublic)) {
return true;
}
return false;
}
assert(FrontendOptions::doesActionGenerateSIL(Action) &&
@@ -1272,6 +1300,9 @@ static bool performCompileStepsPostSILGen(
SM->verify();
}
emitAnyWholeModulePostTypeCheckSupplementaryOutputs(Instance, Invocation,
moduleIsPublic);
// This is the action to be used to serialize SILModule.
// It may be invoked multiple times, but it will perform
// serialization only once. The serialization may either happen
@@ -1309,14 +1340,6 @@ static bool performCompileStepsPostSILGen(
setPrivateDiscriminatorIfNeeded(IRGenOpts, MSF);
(void)printAsObjCIfNeeded(PSPs.SupplementaryOutputs.ObjCHeaderOutputPath,
Instance.getMainModule(),
opts.ImplicitObjCHeaderPath, moduleIsPublic);
(void)printModuleInterfaceIfNeeded(
PSPs.SupplementaryOutputs.ModuleInterfaceOutputPath,
Instance.getMainModule());
if (Action == FrontendOptions::ActionType::EmitSIB)
return serializeSIB(SM.get(), PSPs, Instance.getASTContext(), MSF);

View File

@@ -26,7 +26,5 @@
// RUN: not %target-swift-frontend -parse -emit-interface-path %t %s 2>&1 | %FileCheck -check-prefix=PARSE_NO_INTERFACE %s
// PARSE_NO_INTERFACE: error: this mode does not support emitting textual interface files{{$}}
// RUN: not %target-swift-frontend -typecheck -emit-interface-path %t %s 2>&1 | %FileCheck -check-prefix=TYPECHECK_NO_INTERFACE %s
// TYPECHECK_NO_INTERFACE: error: this mode does not support emitting textual interface files{{$}}
// RUN: not %target-swift-frontend -emit-silgen -emit-interface-path %t %s 2>&1 | %FileCheck -check-prefix=SILGEN_NO_INTERFACE %s
// SILGEN_NO_INTERFACE: error: this mode does not support emitting textual interface files{{$}}

View File

@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -emit-module -o /dev/null %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t.swiftinterface %s
// RUN: %FileCheck %s < %t.swiftinterface
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.swiftinterface

View File

@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -enable-resilience -emit-module -o /dev/null %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t.swiftinterface -enable-resilience %s
// RUN: %FileCheck %s < %t.swiftinterface
// CHECK: @_transparent public func glass() -> Int { return 0 }{{$}}

View File

@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -emit-module -o /dev/null %s
// RUN: %target-swift-frontend-typecheck -emit-interface-path %t.swiftinterface %s
// RUN: %FileCheck %s < %t.swiftinterface
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.swiftinterface

View File

@@ -0,0 +1,12 @@
// RUN: rm -f %t
// RUN: not %target-swift-frontend -emit-interface-path %t -emit-module -o /dev/null %s
// RUN: test ! -f %t
// RUN: %target-swift-frontend -emit-interface-path %t -typecheck %s
// RUN: test -f %t
public struct BadInit {
public var x: Int
public init() {
return // without initializing 'x'
}
}

View File

@@ -3,7 +3,7 @@
// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/Test.swiftmodule %t/Test~partial.swiftmodule
// RUN: %target-swift-ide-test -print-module -module-to-print=Test -source-filename=x -I %t | %FileCheck %s
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -enable-resilience -emit-module -o /dev/null %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t.swiftinterface -enable-resilience %s
// RUN: %FileCheck %s < %t.swiftinterface
// CHECK: func hasClosureDefaultArg(_ x: () -> Void = {

View File

@@ -1,5 +1,5 @@
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s -I %S/Inputs/imports-submodule-order/ | %FileCheck %s
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s -I %S/Inputs/imports-submodule-order/ -D XY | %FileCheck %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s -I %S/Inputs/imports-submodule-order/ | %FileCheck %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s -I %S/Inputs/imports-submodule-order/ -D XY | %FileCheck %s
#if XY
@_exported import X.Submodule

View File

@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -o %t/empty.swiftmodule %S/../Inputs/empty.swift
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s %S/Inputs/imports-other.swift -I %S/Inputs/imports-clang-modules/ -I %t -verify | %FileCheck %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s %S/Inputs/imports-other.swift -I %S/Inputs/imports-clang-modules/ -I %t -verify | %FileCheck %s
@_exported import empty

View File

@@ -1,9 +1,9 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -emit-module -o /dev/null %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t.swiftinterface %s
// RUN: %FileCheck %s < %t.swiftinterface --check-prefix CHECK --check-prefix COMMON
// RUN: %target-swift-frontend -emit-interface-path %t-resilient.swiftinterface -enable-resilience -emit-module -o /dev/null %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t-resilient.swiftinterface -enable-resilience %s
// RUN: %FileCheck %s --check-prefix RESILIENT --check-prefix COMMON < %t-resilient.swiftinterface
// RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule %t.swiftinterface -disable-objc-attr-requires-foundation-module

View File

@@ -1,5 +1,5 @@
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s | %FileCheck %s
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s %S/Inputs/other.swift | %FileCheck -check-prefix CHECK -check-prefix CHECK-MULTI-FILE %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s | %FileCheck %s
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s %S/Inputs/other.swift | %FileCheck -check-prefix CHECK -check-prefix CHECK-MULTI-FILE %s
// CHECK: public func verySimpleFunction(){{$}}
public func verySimpleFunction() {}

View File

@@ -1,3 +1,4 @@
// RUN: %target-swift-frontend -typecheck -emit-interface-path - -parse-stdlib %s | %FileCheck %s
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null -parse-stdlib %s | %FileCheck %s
// CHECK-NOT: import Builtin