From 92d2c236b8b68c9ea81beace2a0832bc8a740ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Thu, 12 Nov 2020 14:20:12 -0800 Subject: [PATCH 1/2] [Tests] Fix and refactor skip-function-bodies.swift --- test/Frontend/skip-function-bodies.swift | 107 +++++++++-------------- 1 file changed, 41 insertions(+), 66 deletions(-) diff --git a/test/Frontend/skip-function-bodies.swift b/test/Frontend/skip-function-bodies.swift index c8b1ef0ae7e78..6b37418ae5adc 100644 --- a/test/Frontend/skip-function-bodies.swift +++ b/test/Frontend/skip-function-bodies.swift @@ -13,21 +13,21 @@ // WARNING: module 'SwiftOnoneSupport' cannot be built with -experimental-skip-non-inlinable-function-bodies; this option has been automatically disabled // Check skipped bodies are neither typechecked nor SILgen'd -// RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-non-inlinable-function-bodies -debug-forbid-typecheck-prefix INLINENOTYPECHECK %s -o %t/Skip.noninlinable.sil -// RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -O -experimental-skip-all-function-bodies -debug-forbid-typecheck-prefix ALLNOTYPECHECK %s -o %t/Skip.all.sil -// %FileCheck %s --check-prefixes CHECK,CHECK-NONINLINE-ONLY < %t/Skip.noninlinable.sil -// %FileCheck %s --check-prefixes CHECK,CHECK-ALL-ONLY < %t/Skip.all.sil +// RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-non-inlinable-function-bodies -debug-forbid-typecheck-prefix NEVERTYPECHECK -debug-forbid-typecheck-prefix INLINENOTYPECHECK %s -o %t/Skip.noninlinable.sil +// RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-all-function-bodies -debug-forbid-typecheck-prefix NEVERTYPECHECK -debug-forbid-typecheck-prefix ALLNOTYPECHECK %s -o %t/Skip.all.sil +// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-NONINLINE-ONLY,CHECK-NONINLINE-SIL < %t/Skip.noninlinable.sil +// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-ALL-ONLY < %t/Skip.all.sil // Emit the module interface and check it against the same set of strings. // RUN: %target-swift-frontend -typecheck %s -enable-library-evolution -emit-module-interface-path %t/Skip.noninlinable.swiftinterface -experimental-skip-non-inlinable-function-bodies -// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-NONINLINE-ONLY < %t/Skip.noninlinable.swiftinterface +// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-NONINLINE-ONLY,CHECK-NONINLINE-TEXTUAL < %t/Skip.noninlinable.swiftinterface // RUN: %target-swift-frontend -typecheck %s -enable-library-evolution -emit-module-interface-path %t/Skip.all.swiftinterface -experimental-skip-all-function-bodies -// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-ALL-ONLY < %t/Skip.all.swiftinterface +// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-ALL-ONLY,CHECK-NONINLINE-TEXTUAL < %t/Skip.all.swiftinterface // Emit the module interface normally, it should be the same as when skipping // non-inlinable. // RUN: %target-swift-frontend -typecheck %s -enable-library-evolution -emit-module-interface-path %t/Skip.swiftinterface -// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-NONINLINE-ONLY < %t/Skip.swiftinterface +// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-NONINLINE-ONLY,CHECK-NONINLINE-TEXTUAL < %t/Skip.swiftinterface // RUN: diff -u %t/Skip.noninlinable.swiftinterface %t/Skip.swiftinterface @usableFromInline @@ -58,16 +58,14 @@ public class InlinableDeinit { @_fixed_layout public class InlineAlwaysDeinit { @inline(__always) deinit { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("@inline(__always) deinit body") // CHECK-NOT: "@inline(__always) deinit body" } } public class NormalDeinit { deinit { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK = 1 + let NEVERTYPECHECK_local = 1 _blackHole("regular deinit body") // CHECK-NOT: "regular deinit body" } } @@ -80,52 +78,44 @@ public class NormalDeinit { } @inline(__always) public func inlineAlwaysFunc() { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("@inline(__always) func body") // CHECK-NOT: "@inline(__always) func body" } func internalFunc() { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("internal func body") // CHECK-NOT: "internal func body" } public func publicFunc() { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("public func body") // CHECK-NOT: "public func body" } private func privateFunc() { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("private func body") // CHECK-NOT: "private func body" } @inline(__always) public func inlineAlwaysLocalTypeFunc() { - let ALLNOTYPECHECK_outerLocal = 1 - let INLINENOTYPECHECK_outerLocal = 1 + let NEVERTYPECHECK_outerLocal = 1 typealias InlineAlwaysLocalType = Int _blackHole("@inline(__always) func body with local type") // CHECK-NOT: "@inline(__always) func body with local type" func takesInlineAlwaysLocalType(_ x: InlineAlwaysLocalType) { - let ALLNOTYPECHECK_innerLocal = 1 - let INLINENOTYPECHECK_innerLocal = 1 + let NEVERTYPECHECK_innerLocal = 1 _blackHole("nested func body inside @inline(__always) func body taking local type") // CHECK-NOT: "nested func body inside @inline(__always) func body taking local type" } takesInlineAlwaysLocalType(0) } public func publicLocalTypeFunc() { - let ALLNOTYPECHECK_outerLocal = 1 - let INLINENOTYPECHECK_outerLocal = 1 + let NEVERTYPECHECK_outerLocal = 1 typealias LocalType = Int _blackHole("public func body with local type") // CHECK-NOT: "public func body with local type" func takesLocalType(_ x: LocalType) { - let ALLNOTYPECHECK_innerLocal = 1 - let INLINENOTYPECHECK_innerLocal = 1 + let NEVERTYPECHECK_innerLocal = 1 _blackHole("nested func body inside public func body taking local type") // CHECK-NOT: "nested func body inside public func body taking local type" } takesLocalType(0) @@ -206,8 +196,7 @@ public struct Struct { @inline(__always) public func inlineAlwaysFunc() { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("@inline(__always) method body") // CHECK-NOT: "@inline(__always) method body" } @@ -236,13 +225,6 @@ public struct Struct { } } - public var didSetVar: Int = 1 { - didSet { - // Body typechecked regardless - _blackHole("didSet body") // CHECK-NOT: "didSet body" - } - } - @_transparent public func transparentFunc() { let ALLNOTYPECHECK_local = 1 @@ -252,20 +234,17 @@ public struct Struct { } func internalFunc() { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("internal method body") // CHECK-NOT: "internal method body" } public func publicFunc() { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("public method body") // CHECK-NOT: "public method body" } private func privateFunc() { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("private method body") // CHECK-NOT: "private method body" } @@ -276,6 +255,14 @@ public struct Struct { // CHECK-ALL-ONLY-NOT: "@_transparent init body" } + public var didSetVar: Int = 1 { + didSet { + // Body typechecked regardless + _blackHole("didSet body") // CHECK-NONINLINE-SIL: "didSet body" + // CHECK-NONINLINE-TEXTUAL-NOT: "didSet body" + } + } + @inlinable public init() { let ALLNOTYPECHECK_local = 1 _blackHole("@inlinable init body") @@ -284,26 +271,22 @@ public struct Struct { } @inline(__always) public init(a: Int) { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("@inline(__always) init body") // CHECK-NOT: "@inline(__always) init body" } init(c: Int) { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("internal init body") // CHECK-NOT: "internal init body" } public init(d: Int) { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("public init body") // CHECK-NOT: "public init body" } private init(e: Int) { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("private init body") // CHECK-NOT: "private init body" } @@ -316,8 +299,7 @@ public struct Struct { } @inline(__always) public subscript(a: Int, b: Int) -> Int { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("@inline(__always) subscript getter") // CHECK-NOT: "@inline(__always) subscript getter" return 0 } @@ -333,36 +315,31 @@ public struct Struct { } subscript(a: Int, b: Int, c: Int, d: Int) -> Int { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("internal subscript getter") // CHECK-NOT: "internal subscript getter" return 0 } public subscript(a: Int, b: Int, c: Int, d: Int, e: Int) -> Int { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("public subscript getter") // CHECK-NOT: "public subscript getter" return 0 } private subscript(e: Int) -> Int { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("private subscript getter") // CHECK-NOT: "private subscript getter" return 0 } @inline(__always) public var inlineAlwaysVar: Int { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("@inline(__always) getter body") // CHECK-NOT: "@inline(__always) getter body" return 0 } public var publicVar: Int { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("public getter body") // CHECK-NOT: "public getter body" return 0 } @@ -370,8 +347,7 @@ public struct Struct { public var inlineAlwaysSetter: Int { get { 0 } @inline(__always) set { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("@inline(__always) setter body") // CHECK-NOT: "@inline(__always) setter body" } } @@ -379,8 +355,7 @@ public struct Struct { public var regularSetter: Int { get { 0 } set { - let ALLNOTYPECHECK_local = 1 - let INLINENOTYPECHECK_local = 1 + let NEVERTYPECHECK_local = 1 _blackHole("@inline(__always) setter body") // CHECK-NOT: "regular setter body" } } From 02c134372f4f380cd66bed997eb540a4fdf3b019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Fri, 6 Nov 2020 12:40:29 -0800 Subject: [PATCH 2/2] [Sema] Add option to skip non-inlinable functions without types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This frontend flag can be used as an alternative to -experimental-skip-non-inlinable-function-bodies that doesn’t skip functions defining nested types. We want to keep these types as they are used by LLDB. Other functions ares safe to skip parsing and type-checking. rdar://71130519 --- include/swift/AST/Decl.h | 19 ++++++- include/swift/Basic/FunctionBodySkipping.h | 3 + include/swift/Option/Options.td | 4 ++ include/swift/Parse/Parser.h | 5 +- .../ArgsToFrontendOptionsConverter.cpp | 4 +- lib/Frontend/CompilerInvocation.cpp | 6 ++ lib/Parse/ParseDecl.cpp | 21 +++++-- lib/Sema/TypeCheckDeclPrimary.cpp | 8 +++ test/Frontend/skip-function-bodies.swift | 55 +++++++++++++++++++ 9 files changed, 116 insertions(+), 9 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index f65216567d9cc..f01ef63d51cf0 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -391,7 +391,7 @@ class alignas(1 << DeclAlignInBits) Decl { SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2, StaticSpelling : 2 ); - SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1, /// \see AbstractFunctionDecl::BodyKind BodyKind : 3, @@ -415,7 +415,11 @@ class alignas(1 << DeclAlignInBits) Decl { Synthesized : 1, /// Whether this member's body consists of a single expression. - HasSingleExpressionBody : 1 + HasSingleExpressionBody : 1, + + /// Whether peeking into this function detected nested type declarations. + /// This is set when skipping over the decl at parsing. + HasNestedTypeDeclarations : 1 ); SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1, @@ -5544,6 +5548,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { Bits.AbstractFunctionDecl.Throws = Throws; Bits.AbstractFunctionDecl.Synthesized = false; Bits.AbstractFunctionDecl.HasSingleExpressionBody = false; + Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = false; } void setBodyKind(BodyKind K) { @@ -5690,6 +5695,16 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { setBody(S, BodyKind::Parsed); } + /// Was there a nested type declaration detected when parsing this + /// function was skipped? + bool hasNestedTypeDeclarations() const { + return Bits.AbstractFunctionDecl.HasNestedTypeDeclarations; + } + + void setHasNestedTypeDeclarations(bool value) { + Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = value; + } + /// Note that parsing for the body was delayed. /// /// The function should return the body statement and a flag indicating diff --git a/include/swift/Basic/FunctionBodySkipping.h b/include/swift/Basic/FunctionBodySkipping.h index 1d1f8b2deb43a..cd7042a8e595b 100644 --- a/include/swift/Basic/FunctionBodySkipping.h +++ b/include/swift/Basic/FunctionBodySkipping.h @@ -23,6 +23,9 @@ enum class FunctionBodySkipping : uint8_t { None, /// Only non-inlinable function bodies should be skipped. NonInlinable, + /// Only non-inlinable functions bodies without type definitions should + /// be skipped. + NonInlinableWithoutTypes, /// All function bodies should be skipped, where not otherwise required /// for type inference. All diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index d0bb1e0cb990f..e78486daa8014 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -297,6 +297,10 @@ def experimental_skip_non_inlinable_function_bodies: Flag<["-"], "experimental-skip-non-inlinable-function-bodies">, Flags<[FrontendOption, HelpHidden]>, HelpText<"Skip type-checking and SIL generation for non-inlinable function bodies">; +def experimental_skip_non_inlinable_function_bodies_without_types: + Flag<["-"], "experimental-skip-non-inlinable-function-bodies-without-types">, + Flags<[FrontendOption, HelpHidden]>, + HelpText<"Skip work on non-inlinable function bodies that do not declare nested types">; def profile_stats_events: Flag<["-"], "profile-stats-events">, Flags<[FrontendOption, HelpHidden]>, HelpText<"Profile changes to stats in -stats-output-dir">; diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 6fdb6f54c0f24..1ea1d70925078 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -687,7 +687,10 @@ class Parser { /// Skip a braced block (e.g. function body). The current token must be '{'. /// Returns \c true if the parser hit the eof before finding matched '}'. - bool skipBracedBlock(); + /// + /// Set \c HasNestedTypeDeclarations to true if a token for a type + /// declaration is detected in the skipped block. + bool skipBracedBlock(bool &HasNestedTypeDeclarations); /// Skip over SIL decls until we encounter the start of a Swift decl or eof. void skipSILUntilSwiftDecl(); diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index e96093e8fdad8..2f62de53646e4 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -195,7 +195,9 @@ bool ArgsToFrontendOptionsConverter::convert( if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction) && (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) || - Args.hasArg(OPT_experimental_skip_all_function_bodies))) { + Args.hasArg(OPT_experimental_skip_all_function_bodies) || + Args.hasArg( + OPT_experimental_skip_non_inlinable_function_bodies_without_types))) { Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies); return true; } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index a9fd9ea827192..fe9e25d00a0b7 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -716,6 +716,12 @@ static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args, Opts.DebugTimeExpressions |= Args.hasArg(OPT_debug_time_expression_type_checking); + // Check for SkipFunctionBodies arguments in order from skipping less to + // skipping more. + if (Args.hasArg( + OPT_experimental_skip_non_inlinable_function_bodies_without_types)) + Opts.SkipFunctionBodies = FunctionBodySkipping::NonInlinableWithoutTypes; + // If asked to perform InstallAPI, go ahead and enable non-inlinable function // body skipping. if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) || diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 8daeb13a237a7..cd0de335cbea2 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3519,10 +3519,12 @@ static void diagnoseOperatorFixityAttributes(Parser &P, static unsigned skipUntilMatchingRBrace(Parser &P, bool &HasPoundDirective, bool &HasOperatorDeclarations, - bool &HasNestedClassDeclarations) { + bool &HasNestedClassDeclarations, + bool &HasNestedTypeDeclarations) { HasPoundDirective = false; HasOperatorDeclarations = false; HasNestedClassDeclarations = false; + HasNestedTypeDeclarations = false; unsigned OpenBraces = 1; @@ -3541,6 +3543,10 @@ static unsigned skipUntilMatchingRBrace(Parser &P, HasPoundDirective |= P.Tok.isAny(tok::pound_sourceLocation, tok::pound_line, tok::pound_if, tok::pound_else, tok::pound_endif, tok::pound_elseif); + + HasNestedTypeDeclarations |= P.Tok.isAny(tok::kw_class, tok::kw_struct, + tok::kw_enum); + if (P.consumeIf(tok::l_brace)) { ++OpenBraces; continue; @@ -4823,10 +4829,12 @@ bool Parser::canDelayMemberDeclParsing(bool &HasOperatorDeclarations, // we can't lazily parse. BacktrackingScope BackTrack(*this); bool HasPoundDirective; + bool HasNestedTypeDeclarations; skipUntilMatchingRBrace(*this, HasPoundDirective, HasOperatorDeclarations, - HasNestedClassDeclarations); + HasNestedClassDeclarations, + HasNestedTypeDeclarations); if (!HasPoundDirective) BackTrack.cancelBacktrack(); return !BackTrack.willBacktrack(); @@ -5514,7 +5522,7 @@ static ParameterList *parseOptionalAccessorArgument(SourceLoc SpecifierLoc, return ParameterList::create(P.Context, StartLoc, param, EndLoc); } -bool Parser::skipBracedBlock() { +bool Parser::skipBracedBlock(bool &HasNestedTypeDeclarations) { SyntaxParsingContext disabled(SyntaxContext); SyntaxContext->disable(); consumeToken(tok::l_brace); @@ -5528,7 +5536,8 @@ bool Parser::skipBracedBlock() { unsigned OpenBraces = skipUntilMatchingRBrace(*this, HasPoundDirectives, HasOperatorDeclarations, - HasNestedClassDeclarations); + HasNestedClassDeclarations, + HasNestedTypeDeclarations); if (consumeIf(tok::r_brace)) --OpenBraces; return OpenBraces != 0; @@ -6424,11 +6433,13 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD, BodyRange.Start = Tok.getLoc(); // Advance the parser to the end of the block; '{' ... '}'. - skipBracedBlock(); + bool HasNestedTypeDeclarations; + skipBracedBlock(HasNestedTypeDeclarations); BodyRange.End = PreviousLoc; AFD->setBodyDelayed(BodyRange); + AFD->setHasNestedTypeDeclarations(HasNestedTypeDeclarations); if (isCodeCompletionFirstPass() && SourceMgr.rangeContainsCodeCompletionLoc(BodyRange)) { diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index f44e6be8a43d8..4dedb12ba6e29 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2345,6 +2345,14 @@ class DeclChecker : public DeclVisitor { FunctionBodySkipping::All) return true; + // If we want all types (for LLDB) we can't skip functions with nested + // types. We could probably improve upon this and type-check only the + // nested types instead for better performances. + if (AFD->hasNestedTypeDeclarations() && + getASTContext().TypeCheckerOpts.SkipFunctionBodies == + FunctionBodySkipping::NonInlinableWithoutTypes) + return false; + // Only skip functions where their body won't be serialized return AFD->getResilienceExpansion() != ResilienceExpansion::Minimal; } diff --git a/test/Frontend/skip-function-bodies.swift b/test/Frontend/skip-function-bodies.swift index 6b37418ae5adc..b2711efea575c 100644 --- a/test/Frontend/skip-function-bodies.swift +++ b/test/Frontend/skip-function-bodies.swift @@ -3,6 +3,8 @@ // Check -emit-ir and -c are invalid when skipping function bodies // RUN: not %target-swift-frontend -emit-ir %s -experimental-skip-non-inlinable-function-bodies %s 2>&1 | %FileCheck %s --check-prefix ERROR // RUN: not %target-swift-frontend -c %s -experimental-skip-non-inlinable-function-bodies %s 2>&1 | %FileCheck %s --check-prefix ERROR +// RUN: not %target-swift-frontend -emit-ir %s -experimental-skip-non-inlinable-function-bodies-without-types %s 2>&1 | %FileCheck %s --check-prefix ERROR +// RUN: not %target-swift-frontend -c %s -experimental-skip-non-inlinable-function-bodies-without-types %s 2>&1 | %FileCheck %s --check-prefix ERROR // RUN: not %target-swift-frontend -emit-ir %s -experimental-skip-all-function-bodies %s 2>&1 | %FileCheck %s --check-prefix ERROR // RUN: not %target-swift-frontend -c %s -experimental-skip-all-function-bodies %s 2>&1 | %FileCheck %s --check-prefix ERROR // ERROR: -experimental-skip-*-function-bodies do not support emitting IR @@ -14,8 +16,10 @@ // Check skipped bodies are neither typechecked nor SILgen'd // RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-non-inlinable-function-bodies -debug-forbid-typecheck-prefix NEVERTYPECHECK -debug-forbid-typecheck-prefix INLINENOTYPECHECK %s -o %t/Skip.noninlinable.sil +// RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-non-inlinable-function-bodies-without-types -debug-forbid-typecheck-prefix NEVERTYPECHECK -debug-forbid-typecheck-prefix TYPESNOTYPECHECK %s -o %t/Skip.withouttypes.sil // RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-all-function-bodies -debug-forbid-typecheck-prefix NEVERTYPECHECK -debug-forbid-typecheck-prefix ALLNOTYPECHECK %s -o %t/Skip.all.sil // RUN: %FileCheck %s --check-prefixes CHECK,CHECK-NONINLINE-ONLY,CHECK-NONINLINE-SIL < %t/Skip.noninlinable.sil +// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-WITHOUTTYPES-ONLY,CHECK-NONINLINE-SIL < %t/Skip.withouttypes.sil // RUN: %FileCheck %s --check-prefixes CHECK,CHECK-ALL-ONLY < %t/Skip.all.sil // Emit the module interface and check it against the same set of strings. @@ -178,6 +182,57 @@ public func inlinableNestedLocalTypeFunc() { nestedFunc() } +public func funcWithEnum() { + let INLINENOTYPECHECK_local = 1 + let ALLNOTYPECHECK_local = 1 + _blackHole("func with enum body") + // CHECK-WITHOUTTYPES-ONLY: "func with enum body" + // CHECK-NONINLINE-ONLY-NOT: "func with enum body" + // CHECK-ALL-ONLY-NOT: "func with enum body" + enum E {} +} + +public func funcWithClass() { + let INLINENOTYPECHECK_local = 1 + let ALLNOTYPECHECK_local = 1 + _blackHole("func with class body") + // CHECK-WITHOUTTYPES-ONLY: "func with class body" + // CHECK-NONINLINE-ONLY-NOT: "func with class body" + // CHECK-ALL-ONLY-NOT: "func with class body" + class C {} +} + +public func funcWithStruct() { + let INLINENOTYPECHECK_local = 1 + let ALLNOTYPECHECK_local = 1 + _blackHole("func with struct body") + // CHECK-WITHOUTTYPES-ONLY: "func with struct body" + // CHECK-NONINLINE-ONLY-NOT: "func with struct body" + // CHECK-ALL-ONLY-NOT: "func with struct body" + struct S {} +} + +public func funcWithNestedFuncs() { + let INLINENOTYPECHECK_local = 1 + let ALLNOTYPECHECK_local = 1 + _blackHole("func with nested funcs body") + // CHECK-WITHOUTTYPES-ONLY: "func with nested funcs body" + // CHECK-NONINLINE-ONLY-NOT: "func with nested funcs body" + // CHECK-ALL-ONLY-NOT: "func with nested funcs body" + + func bar() { + _blackHole("nested func body") + // CHECK-WITHOUTTYPES-ONLY: "nested func body" + // FIXME: We could skip this nested function. + } + + func foo() { + _blackHole("nested func with type body") + // CHECK-WITHOUTTYPES-ONLY: "nested func with type body" + struct S {} + } +} + public struct Struct { @inlinable public var inlinableVar: Int { let ALLNOTYPECHECK_local = 1