Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/swift/Frontend/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,11 @@ class CompilerInvocation {
/// 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.
Expand Down
9 changes: 9 additions & 0 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion lib/Frontend/FrontendOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
67 changes: 45 additions & 22 deletions lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much nicer, thank you!

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,
Expand Down Expand Up @@ -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 =
Expand All @@ -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) &&
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down
2 changes: 0 additions & 2 deletions test/Frontend/supplementary-output-support.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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{{$}}
2 changes: 1 addition & 1 deletion test/ModuleInterface/access-filter.swift
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion test/ModuleInterface/attrs.swift
Original file line number Diff line number Diff line change
@@ -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 }{{$}}
Expand Down
2 changes: 1 addition & 1 deletion test/ModuleInterface/conformances.swift
Original file line number Diff line number Diff line change
@@ -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

Expand Down
12 changes: 12 additions & 0 deletions test/ModuleInterface/dataflow-errors.swift
Original file line number Diff line number Diff line change
@@ -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'
}
}
2 changes: 1 addition & 1 deletion test/ModuleInterface/if-configs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
4 changes: 2 additions & 2 deletions test/ModuleInterface/imports-submodule-order.swift
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion test/ModuleInterface/imports.swift
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions test/ModuleInterface/private-stored-members.swift
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions test/ModuleInterface/smoke-test.swift
Original file line number Diff line number Diff line change
@@ -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() {}
Expand Down
1 change: 1 addition & 0 deletions test/ModuleInterface/stdlib.swift
Original file line number Diff line number Diff line change
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line can be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I wanted to have at least one test that did things both ways; a -parse-stdlib test seemed like a good example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, then!


// CHECK-NOT: import Builtin
Expand Down