From 1fd6ef95ce483dd7447e09935597cde5c42c14fc Mon Sep 17 00:00:00 2001 From: Josh Learn Date: Tue, 8 Sep 2020 14:28:07 -0700 Subject: [PATCH 01/12] [OSLog] Update compiler stubs and tests The compiler stubs for testing the OSLog implementation are in need of an update. This change updates the stubs to be consistent with the current OSLog implementation, updates the existing tests, and adds new tests for String and metatype interpolations. rdar://69719729 --- stdlib/private/OSLog/CMakeLists.txt | 3 + .../private/OSLog/OSLogFloatFormatting.swift | 426 ++++++++++++++++++ .../OSLog/OSLogFloatingPointTypes.swift | 99 ++-- .../OSLog/OSLogIntegerFormatting.swift | 120 +++-- stdlib/private/OSLog/OSLogIntegerTypes.swift | 128 ++++-- stdlib/private/OSLog/OSLogMessage.swift | 216 +++++---- stdlib/private/OSLog/OSLogNSObjectType.swift | 49 +- stdlib/private/OSLog/OSLogPrivacy.swift | 220 +++++++++ .../private/OSLog/OSLogStringAlignment.swift | 54 ++- stdlib/private/OSLog/OSLogStringTypes.swift | 93 ++-- .../private/OSLog/OSLogSwiftProtocols.swift | 72 +++ stdlib/private/OSLog/OSLogTestHelper.swift | 40 +- .../Inputs/OSLogConstantEvaluable.swift | 5 + test/SILOptimizer/OSLogFullOptTest.swift | 149 +++++- test/SILOptimizer/OSLogMandatoryOptTest.swift | 52 +-- .../Sema/diag_constantness_check_os_log.swift | 4 +- test/stdlib/OSLogExecutionTest.swift | 22 +- 17 files changed, 1362 insertions(+), 390 deletions(-) create mode 100644 stdlib/private/OSLog/OSLogFloatFormatting.swift create mode 100644 stdlib/private/OSLog/OSLogPrivacy.swift create mode 100644 stdlib/private/OSLog/OSLogSwiftProtocols.swift diff --git a/stdlib/private/OSLog/CMakeLists.txt b/stdlib/private/OSLog/CMakeLists.txt index 7241543470fe8..2e37b642fb6c0 100644 --- a/stdlib/private/OSLog/CMakeLists.txt +++ b/stdlib/private/OSLog/CMakeLists.txt @@ -10,6 +10,9 @@ add_swift_target_library(swiftOSLogTestHelper OSLogStringTypes.swift OSLogNSObjectType.swift OSLogFloatingPointTypes.swift + OSLogSwiftProtocols.swift + OSLogPrivacy.swift + OSLogFloatFormatting.swift SWIFT_MODULE_DEPENDS_IOS Darwin ObjectiveC SWIFT_MODULE_DEPENDS_OSX Darwin ObjectiveC diff --git a/stdlib/private/OSLog/OSLogFloatFormatting.swift b/stdlib/private/OSLog/OSLogFloatFormatting.swift new file mode 100644 index 0000000000000..8397f849e5abb --- /dev/null +++ b/stdlib/private/OSLog/OSLogFloatFormatting.swift @@ -0,0 +1,426 @@ +//===--------------------------- OSLogFloatFormatting.swift ------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 defines types and functions for specifying formatting of +// floating-point typed interpolations passed to the os log APIs. + +@frozen +public struct OSLogFloatFormatting { + /// When set, a `+` will be printed for all non-negative floats. + @usableFromInline + internal var explicitPositiveSign: Bool + + /// Whether to use uppercase letters to represent numerals greater than 9 + /// (default is to use lowercase). This applies to hexadecimal digits, NaN, Inf, + /// the symbols E and X used to denote exponent and hex format. + @usableFromInline + internal var uppercase: Bool + + // Note: includePrefix is not supported for FloatFormatting. The format specifier %a + // always prints a prefix, %efg don't need one. + + /// Number of digits to display following the radix point. Hex notation does not accept + /// a precision. For non-hex notations, precision can be a dynamic value. The default + /// precision is 6 for non-hex notations. + @usableFromInline + internal var precision: (() -> Int)? + + @usableFromInline + internal enum Notation { + /// Hexadecimal formatting. + case hex + + /// fprintf's `%f` formatting. + /// + /// Prints all digits before the radix point, and `precision` digits following + /// the radix point. If `precision` is zero, the radix point is omitted. + /// + /// Note that very large floating-point values may print quite a lot of digits + /// when using this format, even if `precision` is zero--up to hundreds for + /// `Double`, and thousands for `Float80`. Note also that this format is + /// very likely to print non-zero values as all-zero. If these are a concern, use + /// `.exponential` or `.hybrid` instead. + /// + /// Systems may impose an upper bound on the number of digits that are + /// supported following the radix point. + case fixed + + /// fprintf's `%e` formatting. + /// + /// Prints the number in the form [-]d.ddd...dde±dd, with `precision` significant + /// digits following the radix point. Systems may impose an upper bound on the number + /// of digits that are supported. + case exponential + + /// fprintf's `%g` formatting. + /// + /// Behaves like `.fixed` when the number is scaled close to 1.0, and like + /// `.exponential` if it has a very large or small exponent. + case hybrid + } + + @usableFromInline + internal var notation: Notation + + @_transparent + @usableFromInline + internal init( + explicitPositiveSign: Bool = false, + uppercase: Bool = false, + precision: (() -> Int)?, + notation: Notation + ) { + self.explicitPositiveSign = explicitPositiveSign + self.uppercase = uppercase + self.precision = precision + self.notation = notation + } + + /// Displays an interpolated floating-point value in fprintf's `%f` format with + /// default precision. + /// + /// Prints all digits before the radix point, and 6 digits following the radix point. + /// Note also that this format is very likely to print non-zero values as all-zero. + /// + /// Note that very large floating-point values may print quite a lot of digits + /// when using this format --up to hundreds for `Double`. Note also that this + /// format is very likely to print non-zero values as all-zero. If these are a concern, + /// use `.exponential` or `.hybrid` instead. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static var fixed: OSLogFloatFormatting { .fixed() } + + /// Displays an interpolated floating-point value in fprintf's `%f` format with + /// specified precision, and optional sign and case. + /// + /// Prints all digits before the radix point, and `precision` digits following + /// the radix point. If `precision` is zero, the radix point is omitted. + /// + /// Note that very large floating-point values may print quite a lot of digits + /// when using this format, even if `precision` is zero--up to hundreds for + /// `Double`. Note also that this format is very likely to print non-zero values as + /// all-zero. If these are a concern, use `.exponential` or `.hybrid` instead. + /// + /// Systems may impose an upper bound on the number of digits that are + /// supported following the radix point. + /// + /// All parameters to this function except `precision` must be boolean literals. + /// + /// - Parameters: + /// - precision: Number of digits to display after the radix point. + /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative + /// numbers. + /// - uppercase: Pass `true` to use uppercase letters or `false` to use + /// lowercase letters. The default is `false`. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static func fixed( + precision: @escaping @autoclosure () -> Int, + explicitPositiveSign: Bool = false, + uppercase: Bool = false + ) -> OSLogFloatFormatting { + return OSLogFloatFormatting( + explicitPositiveSign: explicitPositiveSign, + uppercase: uppercase, + precision: precision, + notation: .fixed + ) + } + + /// Displays an interpolated floating-point value in fprintf's `%f` format with + /// default precision, and optional sign and case. + /// + /// Prints all digits before the radix point, and 6 digits following the radix point. + /// Note also that this format is very likely to print non-zero values as all-zero. + /// + /// Note that very large floating-point values may print quite a lot of digits + /// when using this format, even if `precision` is zero--up to hundreds for + /// `Double`. Note also that this format is very likely to print non-zero values as + /// all-zero. If these are a concern, use `.exponential` or `.hybrid` instead. + /// + /// Systems may impose an upper bound on the number of digits that are + /// supported following the radix point. + /// + /// All parameters to this function must be boolean literals. + /// - Parameters: + /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative + /// numbers. + /// - uppercase: Pass `true` to use uppercase letters or `false` to use + /// lowercase letters. The default is `false`. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static func fixed( + explicitPositiveSign: Bool = false, + uppercase: Bool = false + ) -> OSLogFloatFormatting { + return OSLogFloatFormatting( + explicitPositiveSign: explicitPositiveSign, + uppercase: uppercase, + precision: nil, + notation: .fixed + ) + } + + /// Displays an interpolated floating-point value in hexadecimal format. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static var hex: OSLogFloatFormatting { .hex() } + + /// Displays an interpolated floating-point value in hexadecimal format with + /// optional sign and case. + /// + /// All parameters to this function must be boolean literals. + /// + /// - Parameters: + /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative + /// numbers. + /// - uppercase: Pass `true` to use uppercase letters or `false` to use + /// lowercase letters. The default is `false`. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static func hex( + explicitPositiveSign: Bool = false, + uppercase: Bool = false + ) -> OSLogFloatFormatting { + return OSLogFloatFormatting( + explicitPositiveSign: explicitPositiveSign, + uppercase: uppercase, + precision: nil, + notation: .hex + ) + } + + /// Displays an interpolated floating-point value in fprintf's `%e` format. + /// + /// Prints the number in the form [-]d.ddd...dde±dd. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static var exponential: OSLogFloatFormatting { .exponential() } + + /// Displays an interpolated floating-point value in fprintf's `%e` format with + /// specified precision, and optional sign and case. + /// + /// Prints the number in the form [-]d.ddd...dde±dd, with `precision` significant + /// digits following the radix point. Systems may impose an upper bound on the number + /// of digits that are supported. + /// + /// All parameters except `precision` must be boolean literals. + /// + /// - Parameters: + /// - precision: Number of digits to display after the radix point. + /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative + /// numbers. + /// - uppercase: Pass `true` to use uppercase letters or `false` to use + /// lowercase letters. The default is `false`. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static func exponential( + precision: @escaping @autoclosure () -> Int, + explicitPositiveSign: Bool = false, + uppercase: Bool = false + ) -> OSLogFloatFormatting { + return OSLogFloatFormatting( + explicitPositiveSign: explicitPositiveSign, + uppercase: uppercase, + precision: precision, + notation: .exponential + ) + } + + /// Displays an interpolated floating-point value in fprintf's `%e` format with + /// an optional sign and case. + /// + /// Prints the number in the form [-]d.ddd...dde±dd. + /// + /// All parameters to this function must be boolean literals. + /// + /// - Parameters: + /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative + /// numbers. + /// - uppercase: Pass `true` to use uppercase letters or `false` to use + /// lowercase letters. The default is `false`. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static func exponential( + explicitPositiveSign: Bool = false, + uppercase: Bool = false + ) -> OSLogFloatFormatting { + return OSLogFloatFormatting( + explicitPositiveSign: explicitPositiveSign, + uppercase: uppercase, + precision: nil, + notation: .exponential + ) + } + + /// Displays an interpolated floating-point value in fprintf's `%g` format. + /// + /// Behaves like `.fixed` when the number is scaled close to 1.0, and like + /// `.exponential` if it has a very large or small exponent. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static var hybrid: OSLogFloatFormatting { .hybrid() } + + /// Displays an interpolated floating-point value in fprintf's `%g` format with the + /// specified precision, and optional sign and case. + /// + /// Behaves like `.fixed` when the number is scaled close to 1.0, and like + /// `.exponential` if it has a very large or small exponent. + /// + /// All parameters except `precision` must be boolean literals. + /// + /// - Parameters: + /// - precision: Number of digits to display after the radix point. + /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative + /// numbers. + /// - uppercase: Pass `true` to use uppercase letters or `false` to use + /// lowercase letters. The default is `false`. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static func hybrid( + precision: @escaping @autoclosure () -> Int, + explicitPositiveSign: Bool = false, + uppercase: Bool = false + ) -> OSLogFloatFormatting { + return OSLogFloatFormatting( + explicitPositiveSign: explicitPositiveSign, + uppercase: uppercase, + precision: precision, + notation: .hybrid + ) + } + + /// Displays an interpolated floating-point value in fprintf's `%g` format with + /// optional sign and case. + /// + /// Behaves like `.fixed` when the number is scaled close to 1.0, and like + /// `.exponential` if it has a very large or small exponent. + /// + /// All parameters to this function must be boolean literals. + /// + /// - Parameters: + /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative + /// numbers. + /// - uppercase: Pass `true` to use uppercase letters or `false` to use + /// lowercase letters. The default is `false`. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + public static func hybrid( + explicitPositiveSign: Bool = false, + uppercase: Bool = false + ) -> OSLogFloatFormatting { + return OSLogFloatFormatting( + explicitPositiveSign: explicitPositiveSign, + uppercase: uppercase, + precision: nil, + notation: .hybrid + ) + } +} + +extension OSLogFloatFormatting { + /// Returns a fprintf-compatible length modifier for a given argument type + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + internal static func _formatStringLengthModifier( + _ type: I.Type + ) -> String? { + switch type { + // fprintf formatters promote Float to Double + case is Float.Type: return "" + case is Double.Type: return "" +#if !os(Windows) && (arch(i386) || arch(x86_64)) + // fprintf formatters use L for Float80 + case is Float80.Type: return "L" +#endif + default: return nil + } + } + + /// Constructs an os_log format specifier for the given type `type` + /// using the specified alignment `align` and privacy qualifier `privacy`. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + internal func formatSpecifier( + for type: I.Type, + align: OSLogStringAlignment, + privacy: OSLogPrivacy + ) -> String { + var specification = "%" + // Add privacy qualifier after % sign within curly braces. This is an + // os log specific flag. + if let privacySpecifier = privacy.privacySpecifier { + specification += "{" + specification += privacySpecifier + specification += "}" + } + + // 1. Flags + // IEEE: `+` The result of a signed conversion shall always begin with a sign + // ( '+' or '-' ) + if explicitPositiveSign { + specification += "+" + } + + // IEEE: `-` The result of the conversion shall be left-justified within the field. + // The conversion is right-justified if this flag is not specified. + if case .start = align.anchor { + specification += "-" + } + + if let _ = align.minimumColumnWidth { + // The alignment could be a dynamic value. Therefore, use a star here and pass it + // as an additional argument. + specification += "*" + } + + if let _ = precision { + specification += ".*" + } + + guard let lengthModifier = + OSLogFloatFormatting._formatStringLengthModifier(type) else { + fatalError("Float type has unknown length") + } + specification += lengthModifier + + // 3. Precision and conversion specifier. + switch notation { + case .fixed: + specification += (uppercase ? "F" : "f") + case .exponential: + specification += (uppercase ? "E" : "e") + case .hybrid: + specification += (uppercase ? "G" : "g") + case .hex: + //guard type.radix == 2 else { return nil } + specification += (uppercase ? "A" : "a") + default: + fatalError("Unknown float notation") + } + return specification + } +} + diff --git a/stdlib/private/OSLog/OSLogFloatingPointTypes.swift b/stdlib/private/OSLog/OSLogFloatingPointTypes.swift index b7616b98215b8..e135911d2380b 100644 --- a/stdlib/private/OSLog/OSLogFloatingPointTypes.swift +++ b/stdlib/private/OSLog/OSLogFloatingPointTypes.swift @@ -17,46 +17,88 @@ // // The `appendInterpolation` functions defined in this file accept privacy // options along with the interpolated expression as shown below: -// TODO: support floating-point formatting options. // -// "\(x, privacy: .private\)" +// "\(x, format: .fixed(precision: 10), privacy: .private\)" extension OSLogInterpolation { - /// Define interpolation for expressions of type Float. + /// Defines interpolation for expressions of type Float. + /// + /// Do not call this function directly. It will be called automatically when interpolating + /// a value of type `Float` in the string interpolations passed to the log APIs. + /// /// - Parameters: - /// - number: the interpolated expression of type Float, which is autoclosured. - /// - privacy: a privacy qualifier which is either private or public. - /// It is auto-inferred by default. + /// - number: The interpolated expression of type Float, which is autoclosured. + /// - format: A formatting option available for float types, defined by the + /// type`OSLogFloatFormatting`. The default is `.fixed`. + /// - align: Left or right alignment with the minimum number of columns as + /// defined by the type `OSLogStringAlignment`. + /// - privacy: A privacy qualifier which is either private or public. + /// It is auto-inferred by default. @_semantics("constant_evaluable") - @_semantics("oslog.requires_constant_arguments") @inlinable @_optimize(none) + @_semantics("oslog.requires_constant_arguments") public mutating func appendInterpolation( _ number: @autoclosure @escaping () -> Float, + format: OSLogFloatFormatting = .fixed, + align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto ) { - appendInterpolation(Double(number()), privacy: privacy) + appendInterpolation( + Double(number()), + format: format, + align: align, + privacy: privacy) } /// Define interpolation for expressions of type Double. + /// + /// Do not call this function directly. It will be called automatically when interpolating + /// a value of type `Double` in the string interpolations passed to the log APIs. + /// /// - Parameters: - /// - number: the interpolated expression of type Double, which is autoclosured. - /// - privacy: a privacy qualifier which is either private or public. - /// It is auto-inferred by default. + /// - number: The interpolated expression of type Double, which is autoclosured. + /// - format: A formatting option available for float types, defined by the + /// type`OSLogFloatFormatting`. The default is `.fixed`. + /// - align: Left or right alignment with the minimum number of columns as + /// defined by the type `OSLogStringAlignment`. + /// - privacy: A privacy qualifier which is either private or public. + /// It is auto-inferred by default. @_semantics("constant_evaluable") - @_semantics("oslog.requires_constant_arguments") @inlinable @_optimize(none) + @_semantics("oslog.requires_constant_arguments") public mutating func appendInterpolation( _ number: @autoclosure @escaping () -> Double, + format: OSLogFloatFormatting = .fixed, + align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto ) { guard argumentCount < maxOSLogArgumentCount else { return } + formatString += + format.formatSpecifier(for: Double.self, align: align, privacy: privacy) - formatString += getDoubleFormatSpecifier(privacy: privacy) - addDoubleHeaders(privacy) + // If minimum column width is specified, append this value first. Note that + // the format specifier would use a '*' for width e.g. %*f. + if let minColumns = align.minimumColumnWidth { + appendAlignmentArgument(minColumns) + } + + // If the privacy has a mask, append the mask argument, which is a constant payload. + // Note that this should come after the width but before the precision. + if privacy.hasMask { + appendMaskArgument(privacy) + } + // If minimum number of digits (precision) is specified, append the + // precision before the argument. Note that the format specifier would use + // a '*' for precision: %.*f. + if let precision = format.precision { + appendPrecisionArgument(precision) + } + // Append the double. + addDoubleHeaders(privacy) arguments.append(number) argumentCount += 1 } @@ -82,29 +124,6 @@ extension OSLogInterpolation { preamble = getUpdatedPreamble(privacy: privacy, isScalar: true) } - - /// Construct an os_log format specifier from the given parameters. - /// This function must be constant evaluable and all its arguments - /// must be known at compile time. - @inlinable - @_semantics("constant_evaluable") - @_effects(readonly) - @_optimize(none) - internal func getDoubleFormatSpecifier(privacy: OSLogPrivacy) -> String { - // TODO: this will become more sophisticated when floating-point formatting - // options are supported. - var specifier = "%" - switch privacy { - case .private: - specifier += "{private}" - case .public: - specifier += "{public}" - default: - break - } - specifier += "f" - return specifier - } } extension OSLogArguments { @@ -115,7 +134,7 @@ extension OSLogArguments { @inlinable @_optimize(none) internal mutating func append(_ value: @escaping () -> Double) { - argumentClosures.append({ (position, _) in + argumentClosures.append({ (position, _, _) in serialize(value(), at: &position) }) } @@ -125,14 +144,13 @@ extension OSLogArguments { /// specified by os_log. Note that this is marked transparent instead of /// @inline(__always) as it is used in optimize(none) functions. @_transparent -@usableFromInline +@_alwaysEmitIntoClient internal func doubleSizeInBytes() -> Int { return 8 } /// Serialize a double at the buffer location that `position` points to and /// increment `position` by the byte size of the double. -@inlinable @_alwaysEmitIntoClient @inline(__always) internal func serialize( @@ -145,3 +163,4 @@ internal func serialize( withUnsafeBytes(of: value) { dest.copyMemory(from: $0) } bufferPosition += byteCount } + diff --git a/stdlib/private/OSLog/OSLogIntegerFormatting.swift b/stdlib/private/OSLog/OSLogIntegerFormatting.swift index 9dc1389efd208..2d9a53563c3bc 100644 --- a/stdlib/private/OSLog/OSLogIntegerFormatting.swift +++ b/stdlib/private/OSLog/OSLogIntegerFormatting.swift @@ -17,23 +17,30 @@ public struct OSLogIntegerFormatting { /// The base to use for the string representation. `radix` must be at least 2 /// and at most 36. The default is 10. - public var radix: Int + @usableFromInline + internal var radix: Int /// When set, a `+` will be printed for all non-negative integers. - public var explicitPositiveSign: Bool + @usableFromInline + internal var explicitPositiveSign: Bool /// When set, a prefix: 0b or 0o or 0x will be added when the radix is 2, 8 or /// 16 respectively. - public var includePrefix: Bool + @usableFromInline + internal var includePrefix: Bool /// Whether to use uppercase letters to represent numerals /// greater than 9 (default is to use lowercase). - public var uppercase: Bool + @usableFromInline + internal var uppercase: Bool /// Minimum number of digits to display. Numbers having fewer digits than /// minDigits will be displayed with leading zeros. - public var minDigits: (() -> Int)? + @usableFromInline + internal var minDigits: (() -> Int)? + /// Initializes all stored properties. + /// /// - Parameters: /// - radix: The base to use for the string representation. `radix` must be /// at least 2 and at most 36. The default is 10. @@ -46,9 +53,8 @@ public struct OSLogIntegerFormatting { /// `false`. /// - minDigits: minimum number of digits to display. Numbers will be /// prefixed with zeros if necessary to meet the minimum. The default is 1. - @_semantics("constant_evaluable") - @inlinable - @_optimize(none) + @_transparent + @usableFromInline internal init( radix: Int = 10, explicitPositiveSign: Bool = false, @@ -56,8 +62,6 @@ public struct OSLogIntegerFormatting { uppercase: Bool = false, minDigits: (() -> Int)? ) { - precondition(radix >= 2 && radix <= 36) - self.radix = radix self.explicitPositiveSign = explicitPositiveSign self.includePrefix = includePrefix @@ -65,11 +69,17 @@ public struct OSLogIntegerFormatting { self.minDigits = minDigits } + /// Displays an interpolated integer as a decimal number with the specified number + /// of digits and an optional sign. + /// + /// The parameter `explicitPositiveSign` must be a boolean literal. The + /// parameter `minDigits` can be an arbitrary expression. + /// /// - Parameters: /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative - /// numbers. Default is `false`. + /// numbers. /// - minDigits: minimum number of digits to display. Numbers will be - /// prefixed with zeros if necessary to meet the minimum. The default is 1. + /// prefixed with zeros if necessary to meet the minimum. @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -83,9 +93,13 @@ public struct OSLogIntegerFormatting { minDigits: minDigits) } + /// Displays an interpolated integer as a decimal number with an optional sign. + /// + /// The parameter `explicitPositiveSign` must be a boolean literal. + /// /// - Parameters: /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative - /// numbers. Default is `false`. + /// numbers. @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -98,22 +112,28 @@ public struct OSLogIntegerFormatting { minDigits: nil) } - /// Default decimal format. + /// Displays an interpolated integer as a decimal number. This is the default format for + /// integers. @_semantics("constant_evaluable") @inlinable @_optimize(none) public static var decimal: OSLogIntegerFormatting { .decimal() } + /// Displays an interpolated unsigned integer as a hexadecimal number with the + /// specified parameters. This formatting option should be used only with unsigned + /// integers. + /// + /// All parameters except `minDigits` should be boolean literals. `minDigits` + /// can be an arbitrary expression. + /// /// - Parameters: /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative - /// numbers. Default is `false`. - /// - includePrefix: Pass `true` to add a prefix: 0b, 0o, 0x to corresponding - /// radices. Default is `false`. + /// numbers. + /// - includePrefix: Pass `true` to add a prefix 0x. /// - uppercase: Pass `true` to use uppercase letters to represent numerals - /// greater than 9, or `false` to use lowercase letters. The default is - /// `false`. + /// greater than 9, or `false` to use lowercase letters. The default is `false`. /// - minDigits: minimum number of digits to display. Numbers will be - /// prefixed with zeros if necessary to meet the minimum. The default is 1. + /// prefixed with zeros if necessary to meet the minimum. @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -131,14 +151,17 @@ public struct OSLogIntegerFormatting { minDigits: minDigits) } + /// Displays an interpolated unsigned integer as a hexadecimal number with the specified + /// parameters. This formatting option should be used only with unsigned integers. + /// + /// All parameters should be boolean literals. + /// /// - Parameters: /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative - /// numbers. Default is `false`. - /// - includePrefix: Pass `true` to add a prefix: 0b, 0o, 0x to corresponding - /// radices. Default is `false`. + /// numbers. + /// - includePrefix: Pass `true` to add a prefix 0x. /// - uppercase: Pass `true` to use uppercase letters to represent numerals - /// greater than 9, or `false` to use lowercase letters. The default is - /// `false`. + /// greater than 9, or `false` to use lowercase letters. The default is `false`. @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -155,22 +178,28 @@ public struct OSLogIntegerFormatting { minDigits: nil) } - /// Default hexadecimal format. + /// Displays an interpolated unsigned integer as a hexadecimal number. + /// This formatting option should be used only with unsigned integers. @_semantics("constant_evaluable") @inlinable @_optimize(none) public static var hex: OSLogIntegerFormatting { .hex() } + /// Displays an interpolated unsigned integer as an octal number with the specified + /// parameters. This formatting option should be used only with unsigned + /// integers. + /// + /// All parameters except `minDigits` should be boolean literals. `minDigits` + /// can be an arbitrary expression. + /// /// - Parameters: /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative - /// numbers. Default is `false`. - /// - includePrefix: Pass `true` to add a prefix: 0b, 0o, 0x to corresponding - /// radices. Default is `false`. + /// numbers. + /// - includePrefix: Pass `true` to add a prefix 0o. /// - uppercase: Pass `true` to use uppercase letters to represent numerals - /// greater than 9, or `false` to use lowercase letters. The default is - /// `false`. + /// greater than 9, or `false` to use lowercase letters. The default is `false`. /// - minDigits: minimum number of digits to display. Numbers will be - /// prefixed with zeros if necessary to meet the minimum. The default is 1. + /// prefixed with zeros if necessary to meet the minimum. @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -188,14 +217,17 @@ public struct OSLogIntegerFormatting { minDigits: minDigits) } + /// Displays an interpolated unsigned integer as an octal number with the specified parameters. + /// This formatting option should be used only with unsigned integers. + /// + /// All parameters must be boolean literals. + /// /// - Parameters: /// - explicitPositiveSign: Pass `true` to add a + sign to non-negative - /// numbers. Default is `false`. - /// - includePrefix: Pass `true` to add a prefix: 0b, 0o, 0x to corresponding - /// radices. Default is `false`. + /// numbers. + /// - includePrefix: Pass `true` to add a prefix 0o. /// - uppercase: Pass `true` to use uppercase letters to represent numerals - /// greater than 9, or `false` to use lowercase letters. The default is - /// `false`. + /// greater than 9, or `false` to use lowercase letters. @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -212,7 +244,8 @@ public struct OSLogIntegerFormatting { minDigits: nil) } - /// Default octal format. + /// Displays an interpolated unsigned integer as an octal number. + /// This formatting option should be used only with unsigned integers. @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -311,13 +344,10 @@ extension OSLogIntegerFormatting { // Add privacy qualifier after % sign within curly braces. This is an // os log specific flag. - switch privacy { - case .private: - specification += "{private}" - case .public: - specification += "{public}" - default: - break + if let privacySpecifier = privacy.privacySpecifier { + specification += "{" + specification += privacySpecifier + specification += "}" } // diff --git a/stdlib/private/OSLog/OSLogIntegerTypes.swift b/stdlib/private/OSLog/OSLogIntegerTypes.swift index 248e90e90c57a..dc24531648d42 100644 --- a/stdlib/private/OSLog/OSLogIntegerTypes.swift +++ b/stdlib/private/OSLog/OSLogIntegerTypes.swift @@ -24,19 +24,23 @@ extension OSLogInterpolation { - /// Define interpolation for expressions of type Int. + /// Defines interpolation for expressions of type Int. + /// + /// Do not call this function directly. It will be called automatically when interpolating + /// a value of type `Int` in the string interpolations passed to the log APIs. + /// /// - Parameters: - /// - number: the interpolated expression of type Int, which is autoclosured. - /// - format: a formatting option available for integer types, defined by the - /// type`OSLogIntegerFormatting`. The default is .decimal. - /// - align: left or right alignment with the minimum number of columns as - /// defined by the type `OSLogStringAlignment`. - /// - privacy: a privacy qualifier which is either private or public. - /// It is auto-inferred by default. + /// - number: The interpolated expression of type Int, which is autoclosured. + /// - format: A formatting option available for integer types, defined by the + /// type: `OSLogIntegerFormatting`. The default is `.decimal`. + /// - align: Left or right alignment with the minimum number of columns as + /// defined by the type `OSLogStringAlignment`. + /// - privacy: A privacy qualifier which is either private or public. + /// It is auto-inferred by default. @_semantics("constant_evaluable") - @_semantics("oslog.requires_constant_arguments") @inlinable @_optimize(none) + @_semantics("oslog.requires_constant_arguments") public mutating func appendInterpolation( _ number: @autoclosure @escaping () -> Int, format: OSLogIntegerFormatting = .decimal, @@ -46,18 +50,12 @@ extension OSLogInterpolation { appendInteger(number, format: format, align: align, privacy: privacy) } - /// Define interpolation for expressions of type Int32. - /// - Parameters: - /// - number: the interpolated expression of type Int32, which is autoclosured. - /// - format: a formatting option available for integer types, defined by the - /// type `OSLogIntegerFormatting`. - /// - align: left or right alignment with the minimum number of columns as - /// defined by the type `OSLogStringAlignment`. - /// - privacy: a privacy qualifier which is either private or public. - /// It is auto-inferred by default. + // Define appendInterpolation overloads for fixed-size integers. + @_semantics("constant_evaluable") @inlinable @_optimize(none) + @_semantics("oslog.requires_constant_arguments") public mutating func appendInterpolation( _ number: @autoclosure @escaping () -> Int32, format: OSLogIntegerFormatting = .decimal, @@ -67,19 +65,23 @@ extension OSLogInterpolation { appendInteger(number, format: format, align: align, privacy: privacy) } - /// Define interpolation for expressions of type UInt. + /// Defines interpolation for expressions of type UInt. + /// + /// Do not call this function directly. It will be called automatically when interpolating + /// a value of type `Int` in the string interpolations passed to the log APIs. + /// /// - Parameters: - /// - number: the interpolated expression of type UInt, which is autoclosured. - /// - format: a formatting option available for integer types, defined by the - /// type `OSLogIntegerFormatting`. - /// - align: left or right alignment with the minimum number of columns as - /// defined by the type `OSLogStringAlignment`. - /// - privacy: a privacy qualifier which is either private or public. - /// It is auto-inferred by default. + /// - number: The interpolated expression of type UInt, which is autoclosured. + /// - format: A formatting option available for integer types, defined by the + /// type `OSLogIntegerFormatting`. + /// - align: Left or right alignment with the minimum number of columns as + /// defined by the type `OSLogStringAlignment`. + /// - privacy: A privacy qualifier which is either private or public. + /// It is auto-inferred by default. @_semantics("constant_evaluable") - @_semantics("oslog.requires_constant_arguments") @inlinable @_optimize(none) + @_semantics("oslog.requires_constant_arguments") public mutating func appendInterpolation( _ number: @autoclosure @escaping () -> UInt, format: OSLogIntegerFormatting = .decimal, @@ -104,18 +106,27 @@ extension OSLogInterpolation { guard argumentCount < maxOSLogArgumentCount else { return } formatString += format.formatSpecifier(for: T.self, align: align, privacy: privacy) - // If minimum column width is specified, append this value first. Note that the - // format specifier would use a '*' for width e.g. %*d. + + // If minimum column width is specified, append this value first. Note that + // the format specifier would use a '*' for width e.g. %*d. if let minColumns = align.minimumColumnWidth { - appendPrecisionArgument(minColumns) + appendAlignmentArgument(minColumns) } - // If minimum number of digits (precision) is specified, append the precision before - // the argument. Note that the format specifier would use a '*' for precision: %.*d. + // If the privacy has a mask, append the mask argument, which is a constant payload. + // Note that this should come after the width but before the precision. + if privacy.hasMask { + appendMaskArgument(privacy) + } + + // If minimum number of digits (precision) is specified, append the + // precision before the argument. Note that the format specifier would use + // a '*' for precision: %.*d. if let minDigits = format.minDigits { appendPrecisionArgument(minDigits) } + // Append the integer. addIntHeaders(privacy, sizeForEncoding(T.self)) arguments.append(number) argumentCount += 1 @@ -151,19 +162,57 @@ extension OSLogInterpolation { @inlinable @_optimize(none) internal mutating func appendPrecisionArgument(_ count: @escaping () -> Int) { - // Note that we don't have to update the preamble here. - let argumentHeader = getArgumentHeader(privacy: .auto, type: .count) + appendPrecisionAlignCount( + count, + getArgumentHeader(privacy: .auto, type: .count)) + } + + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + internal mutating func appendAlignmentArgument(_ count: @escaping () -> Int) { + appendPrecisionAlignCount( + count, + getArgumentHeader(privacy: .auto, type: .scalar)) + } + + // This is made transparent to minimize compile time overheads. The function's + // implementation also uses literals whenever possible for the same reason. + @_transparent + @inlinable + internal mutating func appendPrecisionAlignCount( + _ count: @escaping () -> Int, + _ argumentHeader: UInt8 + ) { arguments.append(argumentHeader) // Append number of bytes needed to serialize the argument. - let byteCount = sizeForEncoding(CInt.self) - arguments.append(UInt8(byteCount)) + arguments.append(4) // Increment total byte size by the number of bytes needed for this // argument, which is the sum of the byte size of the argument and // two bytes needed for the headers. - totalBytesForSerializingArguments += 2 + byteCount + totalBytesForSerializingArguments += 6 // The count is expected to be a CInt. arguments.append({ CInt(count()) }) argumentCount += 1 + // Note that we don't have to update the preamble here. + } + + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + internal mutating func appendMaskArgument(_ privacy: OSLogPrivacy) { + arguments.append(getArgumentHeader(privacy: .auto, type: .mask)) + // Append number of bytes needed to serialize the mask. Mask is 64 bit payload. + arguments.append(8) + // Increment total byte size by the number of bytes needed for this + // argument, which is the sum of the byte size of the argument and + // two bytes needed for the headers. + totalBytesForSerializingArguments += 10 + // Append the mask value. This is a compile-time constant. + let maskValue = privacy.maskValue + arguments.append({ maskValue }) + argumentCount += 1 + // Note that we don't have to update the preamble here. } } @@ -177,7 +226,7 @@ extension OSLogArguments { internal mutating func append( _ value: @escaping () -> T ) where T: FixedWidthInteger { - argumentClosures.append({ (position, _) in + argumentClosures.append({ (position, _, _) in serialize(value(), at: &position) }) } @@ -188,7 +237,7 @@ extension OSLogArguments { /// it is marked transparent instead of @inline(__always) as it is used in /// optimize(none) functions. @_transparent -@usableFromInline +@_alwaysEmitIntoClient internal func sizeForEncoding( _ type: T.Type ) -> Int where T : FixedWidthInteger { @@ -197,7 +246,6 @@ internal func sizeForEncoding( /// Serialize an integer at the buffer location that `position` points to and /// increment `position` by the byte size of `T`. -@inlinable @_alwaysEmitIntoClient @inline(__always) internal func serialize( diff --git a/stdlib/private/OSLog/OSLogMessage.swift b/stdlib/private/OSLog/OSLogMessage.swift index e49b2a1aa46be..99fd0e0bf3c1f 100644 --- a/stdlib/private/OSLog/OSLogMessage.swift +++ b/stdlib/private/OSLog/OSLogMessage.swift @@ -11,47 +11,31 @@ //===----------------------------------------------------------------------===// // This file contains data structures and helper functions that are used by -// the new OS log APIs. These are prototype implementations and should not be -// used outside of tests. - -/// Privacy qualifiers for indicating the privacy level of the logged data -/// to the logging system. These can be specified in the string interpolation -/// passed to the log APIs. -/// For Example, -/// log.info("Login request from user id \(userid, privacy: .private)") -/// -/// See `OSLogInterpolation.appendInterpolation` definitions for default options -/// for each supported type. -public enum OSLogPrivacy { - case `private` - case `public` - case auto -} +// the new OS log APIs. + +import ObjectiveC /// Maximum number of arguments i.e., interpolated expressions that can /// be used in the string interpolations passed to the log APIs. -/// This limit is imposed by the ABI of os_log. +/// This limit is imposed by the logging system. @_semantics("constant_evaluable") @inlinable @_optimize(none) public var maxOSLogArgumentCount: UInt8 { return 48 } -/// Note that this is marked transparent instead of @inline(__always) as it is -/// used in optimize(none) functions. +// Note that this is marked transparent instead of @inline(__always) as it is +// used in optimize(none) functions. @_transparent -@usableFromInline +@_alwaysEmitIntoClient internal var logBitsPerByte: Int { return 3 } /// Represents a string interpolation passed to the log APIs. /// /// This type converts (through its methods) the given string interpolation into -/// a C-style format string and a sequence of arguments, which is represented -/// by the type `OSLogArguments`. +/// a C-style format string and a sequence of arguments. /// -/// Do not create an instance of this type directly. It is used by the compiler -/// when you pass a string interpolation to the log APIs. -/// Extend this type with more `appendInterpolation` overloads to enable -/// interpolating additional types. +/// - Warning: Do not explicitly refer to this type. It will be implicitly created +/// by the compiler when you pass a string interpolation to the log APIs. @frozen public struct OSLogInterpolation : StringInterpolationProtocol { /// A format string constructed from the given string interpolation to be @@ -82,39 +66,14 @@ public struct OSLogInterpolation : StringInterpolationProtocol { @usableFromInline internal var arguments: OSLogArguments - /// The possible values for the argument flag, as defined by the os_log ABI, - /// which occupies four least significant bits of the first byte of the - /// argument header. The first two bits are used to indicate privacy and - /// the other two are reserved. - @usableFromInline - @frozen - internal enum ArgumentFlag { - case autoFlag - case privateFlag - case publicFlag - - @inlinable - internal var rawValue: UInt8 { - switch self { - case .autoFlag: - return 0 - case .privateFlag: - return 0x1 - case .publicFlag: - return 0x2 - } - } - } - /// The possible values for the argument type, as defined by the os_log ABI, /// which occupies four most significant bits of the first byte of the /// argument header. The rawValue of this enum must be constant evaluable. /// (Note that an auto-generated rawValue is not constant evaluable because /// it cannot be annotated so.) @usableFromInline - @frozen internal enum ArgumentType { - case scalar, count, string, pointer, object + case scalar, count, string, pointer, object, mask @inlinable internal var rawValue: UInt8 { @@ -127,7 +86,9 @@ public struct OSLogInterpolation : StringInterpolationProtocol { return 2 case .pointer: return 3 - case .object: + case .mask: + return 7 + default: //.object return 4 } } @@ -138,25 +99,18 @@ public struct OSLogInterpolation : StringInterpolationProtocol { @usableFromInline internal var preamble: UInt8 - /// Bit mask for setting bits in the peamble. The bits denoted by the bit - /// mask indicate whether there is an argument that is private, and whether - /// there is an argument that is non-scalar: String, NSObject or Pointer. - @usableFromInline - @frozen - internal enum PreambleBitMask { - case privateBitMask - case nonScalarBitMask + /// Denotes the bit that indicates whether there is private argument. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + internal var privateBitMask: UInt8 { 0x1 } - @inlinable - internal var rawValue: UInt8 { - switch self { - case .privateBitMask: - return 0x1 - case .nonScalarBitMask: - return 0x2 - } - } - } + /// Denotes the bit that indicates whether there is non-scalar argument: + /// String, NSObject or Pointer. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + internal var nonScalarBitMask: UInt8 { 0x2 } /// The second summary byte that denotes the number of arguments, which is /// also the number of interpolated expressions. This will be determined @@ -170,11 +124,24 @@ public struct OSLogInterpolation : StringInterpolationProtocol { @usableFromInline internal var totalBytesForSerializingArguments: Int + /// The number of arguments that are Strings. This count is used to create + /// auxiliary storage meant for extending the lifetime of the string arguments + /// until the log call completes. + @usableFromInline + internal var stringArgumentCount: Int + + /// The number of arguments that are NSObjects. This count is used to create + /// auxiliary storage meant for extending the lifetime of the NSObject + /// arguments until the log call completes. + @usableFromInline + internal var objectArgumentCount: Int + // Some methods defined below are marked @_optimize(none) to prevent inlining // of string internals (such as String._StringGuts) which will interfere with // constant evaluation and folding. Note that these methods will be inlined, // constant evaluated/folded and optimized in the context of a caller. + @_semantics("oslog.interpolation.init") @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -186,6 +153,8 @@ public struct OSLogInterpolation : StringInterpolationProtocol { preamble = 0 argumentCount = 0 totalBytesForSerializingArguments = 0 + stringArgumentCount = 0 + objectArgumentCount = 0 } @_semantics("constant_evaluable") @@ -197,23 +166,6 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// `appendInterpolation` conformances will be added by extensions to this type. - /// Return true if and only if the parameter is .private. - /// This function must be constant evaluable. - @inlinable - @_semantics("constant_evaluable") - @_effects(readonly) - @_optimize(none) - internal func getArugmentFlag(_ privacy: OSLogPrivacy) -> ArgumentFlag { - switch privacy { - case .public: - return .publicFlag - case .private: - return .privateFlag - default: - return .autoFlag - } - } - /// Compute a byte-sized argument header consisting of flag and type. /// Flag and type take up the least and most significant four bits /// of the header byte, respectively. @@ -226,9 +178,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { privacy: OSLogPrivacy, type: ArgumentType ) -> UInt8 { - let flag = getArugmentFlag(privacy) - let flagAndType: UInt8 = (type.rawValue &<< 4) | flag.rawValue - return flagAndType + return (type.rawValue &<< 4) | privacy.argumentFlag } /// Compute the new preamble based whether the current argument is private @@ -242,13 +192,11 @@ public struct OSLogInterpolation : StringInterpolationProtocol { isScalar: Bool ) -> UInt8 { var preamble = self.preamble - // Equality comparisions on enums is not yet supported by the constant - // evaluator. - if case .private = privacy { - preamble |= PreambleBitMask.privateBitMask.rawValue + if privacy.isAtleastPrivate { + preamble |= privateBitMask } - if !isScalar { - preamble |= PreambleBitMask.nonScalarBitMask.rawValue + if !isScalar || privacy.hasMask { + preamble |= nonScalarBitMask } return preamble } @@ -258,7 +206,8 @@ extension String { /// Replace all percents "%" in the string by "%%" so that the string can be /// interpreted as a C format string. This function is constant evaluable /// and its semantics is modeled within the evaluator. - public var percentEscapedString: String { + @inlinable + internal var percentEscapedString: String { @_semantics("string.escapePercent.get") @_effects(readonly) @_optimize(none) @@ -270,14 +219,17 @@ extension String { } } +/// Represents a message passed to the log APIs. This type should be created +/// from a string interpolation or a string literal. +/// +/// Do not explicitly refer to this type. It will be implicitly created +/// by the compiler when you pass a string interpolation to the log APIs. @frozen public struct OSLogMessage : ExpressibleByStringInterpolation, ExpressibleByStringLiteral { public let interpolation: OSLogInterpolation - /// Initializer for accepting string interpolations. This function must be - /// constant evaluable. @inlinable @_optimize(none) @_semantics("oslog.message.init_interpolation") @@ -286,8 +238,6 @@ public struct OSLogMessage : self.interpolation = stringInterpolation } - /// Initializer for accepting string literals. This function must be - /// constant evaluable. @inlinable @_optimize(none) @_semantics("oslog.message.init_stringliteral") @@ -298,19 +248,25 @@ public struct OSLogMessage : self.interpolation = s } - /// The byte size of the buffer that will be passed to the C os_log ABI. - /// It will contain the elements of `interpolation.arguments` and the two - /// summary bytes: preamble and argument count. + /// The byte size of the buffer that will be passed to the logging system. @_semantics("constant_evaluable") @inlinable @_optimize(none) public var bufferSize: Int { + // The two additional bytes is for the preamble and argument count. return interpolation.totalBytesForSerializingArguments + 2 } } -public typealias ByteBufferPointer = UnsafeMutablePointer -public typealias StorageObjects = [AnyObject] +@usableFromInline +internal typealias ByteBufferPointer = UnsafeMutablePointer +@usableFromInline +internal typealias ObjectStorage = UnsafeMutablePointer? +@usableFromInline +internal typealias ArgumentClosures = + [(inout ByteBufferPointer, + inout ObjectStorage, + inout ObjectStorage) -> ()] /// A representation of a sequence of arguments and headers (of possibly /// different types) that have to be serialized to a byte buffer. The arguments @@ -326,8 +282,7 @@ internal struct OSLogArguments { /// array of AnyObject to store references to auxiliary storage created during /// serialization. @usableFromInline - internal var argumentClosures: [(inout ByteBufferPointer, - inout StorageObjects) -> ()] + internal var argumentClosures: ArgumentClosures @_semantics("constant_evaluable") @inlinable @@ -342,7 +297,7 @@ internal struct OSLogArguments { @inlinable @_optimize(none) internal mutating func append(_ header: UInt8) { - argumentClosures.append({ (position, _) in + argumentClosures.append({ (position, _, _) in serialize(header, at: &position) }) } @@ -352,7 +307,6 @@ internal struct OSLogArguments { /// Serialize a UInt8 value at the buffer location pointed to by `bufferPosition`, /// and increment the `bufferPosition` with the byte size of the serialized value. -@inlinable @_alwaysEmitIntoClient @inline(__always) internal func serialize( @@ -362,3 +316,43 @@ internal func serialize( bufferPosition[0] = value bufferPosition += 1 } + +// The following code defines helper functions for creating and maintaining +// a buffer for holding a fixed number for instances of a type T. Such buffers +// are used to hold onto NSObjects and Strings that are interpolated in the log +// message until the end of the log call. + +@_alwaysEmitIntoClient +@inline(__always) +internal func createStorage( + capacity: Int, + type: T.Type +) -> ObjectStorage { + return + capacity == 0 ? + nil : + UnsafeMutablePointer.allocate(capacity: capacity) +} + +@_alwaysEmitIntoClient +@inline(__always) +internal func initializeAndAdvance( + _ storageOpt: inout ObjectStorage, + to value: T +) { + // This if statement should get optimized away. + if let storage = storageOpt { + storage.initialize(to: value) + storageOpt = storage.advanced(by: 1) + } +} + +@_alwaysEmitIntoClient +@inline(__always) +internal func destroyStorage(_ storageOpt: ObjectStorage, count: Int) { + // This if statement should get optimized away. + if let storage = storageOpt { + storage.deinitialize(count: count) + storage.deallocate() + } +} diff --git a/stdlib/private/OSLog/OSLogNSObjectType.swift b/stdlib/private/OSLog/OSLogNSObjectType.swift index 3942999a9c682..bcf1c7222f2f4 100644 --- a/stdlib/private/OSLog/OSLogNSObjectType.swift +++ b/stdlib/private/OSLog/OSLogNSObjectType.swift @@ -24,15 +24,18 @@ import ObjectiveC extension OSLogInterpolation { - /// Define interpolation for expressions of type NSObject. + /// Defines interpolation for expressions of type NSObject. + /// + /// Do not call this function directly. It will be called automatically when interpolating + /// a value of type `NSObject` in the string interpolations passed to the log APIs. + /// /// - Parameters: - /// - argumentObject: the interpolated expression of type NSObject, which is autoclosured. - /// - privacy: a privacy qualifier which is either private or public. - /// It is auto-inferred by default. + /// - argumentObject: The interpolated expression of type NSObject, which is autoclosured. + /// - privacy: A privacy qualifier which is either private or public. It is auto-inferred by default. @_semantics("constant_evaluable") - @_semantics("oslog.requires_constant_arguments") @inlinable @_optimize(none) + @_semantics("oslog.requires_constant_arguments") public mutating func appendInterpolation( _ argumentObject: @autoclosure @escaping () -> NSObject, privacy: OSLogPrivacy = .auto @@ -40,10 +43,14 @@ extension OSLogInterpolation { guard argumentCount < maxOSLogArgumentCount else { return } formatString += getNSObjectFormatSpecifier(privacy) + // If the privacy has a mask, append the mask argument, which is a constant payload. + if privacy.hasMask { + appendMaskArgument(privacy) + } addNSObjectHeaders(privacy) - arguments.append(argumentObject) argumentCount += 1 + objectArgumentCount += 1 } /// Update preamble and append argument headers based on the parameters of @@ -76,14 +83,14 @@ extension OSLogInterpolation { @_effects(readonly) @_optimize(none) internal func getNSObjectFormatSpecifier(_ privacy: OSLogPrivacy) -> String { - switch privacy { - case .private: - return "%{private}@" - case .public: - return "%{public}@" - default: - return "%@" + var specifier = "%" + if let privacySpecifier = privacy.privacySpecifier { + specifier += "{" + specifier += privacySpecifier + specifier += "}" } + specifier += "@" + return specifier } } @@ -95,20 +102,20 @@ extension OSLogArguments { @inlinable @_optimize(none) internal mutating func append(_ value: @escaping () -> NSObject) { - argumentClosures.append({ (position, _) in - serialize(value(), at: &position) + argumentClosures.append({ (position, objectArguments, _) in + serialize(value(), at: &position, storingObjectsIn: &objectArguments) }) } } /// Serialize an NSObject pointer at the buffer location pointed by /// `bufferPosition`. -@inlinable @_alwaysEmitIntoClient @inline(__always) internal func serialize( _ object: NSObject, - at bufferPosition: inout ByteBufferPointer + at bufferPosition: inout ByteBufferPointer, + storingObjectsIn objectArguments: inout ObjectStorage ) { let byteCount = pointerSizeInBytes(); let dest = @@ -116,9 +123,11 @@ internal func serialize( // Get the address of this NSObject as an UnsafeRawPointer. let objectAddress = Unmanaged.passUnretained(object).toOpaque() // Copy the address into the destination buffer. Note that the input NSObject - // is an interpolated expression and is guaranteed to be alive until the - // os_log ABI call is completed by the implementation. Therefore, passing - // this address to the os_log ABI is safe. + // is kept alive until the os_log ABI call completes by storing in the + // objectArguments. withUnsafeBytes(of: objectAddress) { dest.copyMemory(from: $0) } bufferPosition += byteCount + // This object could be newly created by the auto-closure. Therefore, make + // sure it is alive until the log call completes. + initializeAndAdvance(&objectArguments, to: object) } diff --git a/stdlib/private/OSLog/OSLogPrivacy.swift b/stdlib/private/OSLog/OSLogPrivacy.swift new file mode 100644 index 0000000000000..e0646ed6395b7 --- /dev/null +++ b/stdlib/private/OSLog/OSLogPrivacy.swift @@ -0,0 +1,220 @@ +//===----------------- OSLogPrivacy.swift ---------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 defines the APIs for specifying privacy in the log messages and also +// the logic for encoding them in the byte buffer passed to the libtrace library. + +/// Privacy options for specifying privacy level of the interpolated expressions +/// in the string interpolations passed to the log APIs. +@frozen +public struct OSLogPrivacy { + + @usableFromInline + internal enum PrivacyOption { + case `private` + case `public` + case auto + } + + public enum Mask { + /// Applies a salted hashing transformation to an interpolated value to redact it in the logs. + /// + /// Its purpose is to permit the correlation of identical values across multiple log lines + /// without revealing the value itself. + case hash + case none + } + + @usableFromInline + internal var privacy: PrivacyOption + + @usableFromInline + internal var mask: Mask + + @_transparent + @usableFromInline + internal init(privacy: PrivacyOption, mask: Mask) { + self.privacy = privacy + self.mask = mask + } + + /// Sets the privacy level of an interpolated value to public. + /// + /// When the privacy level is public, the value will be displayed + /// normally without any redaction in the logs. + @_semantics("constant_evaluable") + @_optimize(none) + @inlinable + public static var `public`: OSLogPrivacy { + OSLogPrivacy(privacy: .public, mask: .none) + } + + /// Sets the privacy level of an interpolated value to private. + /// + /// When the privacy level is private, the value will be redacted in the logs, + /// subject to the privacy configuration of the logging system. + @_semantics("constant_evaluable") + @_optimize(none) + @inlinable + public static var `private`: OSLogPrivacy { + OSLogPrivacy(privacy: .private, mask: .none) + } + + /// Sets the privacy level of an interpolated value to private and + /// applies a `mask` to the interpolated value to redacted it. + /// + /// When the privacy level is private, the value will be redacted in the logs, + /// subject to the privacy configuration of the logging system. + /// + /// If the value need not be redacted in the logs, its full value is captured as normal. + /// Otherwise (i.e. if the value would be redacted) the `mask` is applied to + /// the argument value and the result of the transformation is recorded instead. + /// + /// - Parameters: + /// - mask: Mask to use with the privacy option. + @_semantics("constant_evaluable") + @_optimize(none) + @inlinable + public static func `private`(mask: Mask) -> OSLogPrivacy { + OSLogPrivacy(privacy: .private, mask: mask) + } + + /// Auto-infers a privacy level for an interpolated value. + /// + /// The system will automatically decide whether the value should + /// be captured fully in the logs or should be redacted. + @_semantics("constant_evaluable") + @_optimize(none) + @inlinable + public static var auto: OSLogPrivacy { + OSLogPrivacy(privacy: .auto, mask: .none) + } + + /// Auto-infers a privacy level for an interpolated value and applies a `mask` + /// to the interpolated value to redacted it when necessary. + /// + /// The system will automatically decide whether the value should + /// be captured fully in the logs or should be redacted. + /// If the value need not be redacted in the logs, its full value is captured as normal. + /// Otherwise (i.e. if the value would be redacted) the `mask` is applied to + /// the argument value and the result of the transformation is recorded instead. + /// + /// - Parameters: + /// - mask: Mask to use with the privacy option. + @_semantics("constant_evaluable") + @_optimize(none) + @inlinable + public static func auto(mask: Mask) -> OSLogPrivacy { + OSLogPrivacy(privacy: .auto, mask: mask) + } + + /// Return an argument flag for the privacy option., as defined by the + /// os_log ABI, which occupies four least significant bits of the first byte of the + /// argument header. The first two bits are used to indicate privacy and + /// the other two are reserved. + @inlinable + @_semantics("constant_evaluable") + @_optimize(none) + internal var argumentFlag: UInt8 { + switch privacy { + case .private: + return 0x1 + case .public: + return 0x2 + default: + return 0 + } + } + + @inlinable + @_semantics("constant_evaluable") + @_optimize(none) + internal var isAtleastPrivate: Bool { + switch privacy { + case .public: + return false + case .auto: + return false + default: + return true + } + } + + @inlinable + @_semantics("constant_evaluable") + @_optimize(none) + internal var needsPrivacySpecifier: Bool { + if case .hash = mask { + return true + } + switch privacy { + case .auto: + return false + default: + return true + } + } + + @inlinable + @_transparent + internal var hasMask: Bool { + if case .hash = mask { + return true + } + return false + } + + /// A 64-bit value obtained by interpreting the mask name as a little-endian unsigned + /// integer. + @inlinable + @_transparent + internal var maskValue: UInt64 { + // Return the value of + // 'h' | 'a' << 8 | 's' << 16 | 'h' << 24 which equals + // 104 | (97 << 8) | (115 << 16) | (104 << 24) + 1752392040 + } + + /// Return an os log format specifier for this `privacy` level. The + /// format specifier goes within curly braces e.g. %{private} in the format + /// string passed to the os log ABI. + @inlinable + @_semantics("constant_evaluable") + @_optimize(none) + internal var privacySpecifier: String? { + let hasMask = self.hasMask + var isAuto = false + if case .auto = privacy { + isAuto = true + } + if isAuto, !hasMask { + return nil + } + var specifier: String + switch privacy { + case .public: + specifier = "public" + case .private: + specifier = "private" + default: + specifier = "" + } + if hasMask { + if !isAuto { + specifier += "," + } + specifier += "mask.hash" + } + return specifier + } +} + diff --git a/stdlib/private/OSLog/OSLogStringAlignment.swift b/stdlib/private/OSLog/OSLogStringAlignment.swift index 05afc4f430964..a93388a9cfef9 100644 --- a/stdlib/private/OSLog/OSLogStringAlignment.swift +++ b/stdlib/private/OSLog/OSLogStringAlignment.swift @@ -13,8 +13,8 @@ // This file defines types and functions for specifying alignment of the // interpolations passed to the os log APIs. -@frozen -public enum OSLogCollectionBound { +@usableFromInline +internal enum OSLogCollectionBound { case start case end } @@ -23,20 +23,24 @@ public enum OSLogCollectionBound { public struct OSLogStringAlignment { /// Minimum number of characters to be displayed. If the value to be printed /// is shorter than this number, the result is padded with spaces. The value - /// is not truncated even if the result is larger.This value need not be a + /// is not truncated even if the result is larger. This value need not be a /// compile-time constant, and is therefore an autoclosure. - public var minimumColumnWidth: (() -> Int)? + @usableFromInline + internal var minimumColumnWidth: (() -> Int)? + /// This captures right/left alignment. - public var anchor: OSLogCollectionBound + @usableFromInline + internal var anchor: OSLogCollectionBound + /// Initiailzes stored properties. + /// /// - Parameters: /// - minimumColumnWidth: Minimum number of characters to be displayed. If the value to be /// printed is shorter than this number, the result is padded with spaces. The value is not truncated /// even if the result is larger. /// - anchor: Use `.end` for right alignment and `.start` for left. - @_semantics("constant_evaluable") - @inlinable - @_optimize(none) + @_transparent + @usableFromInline internal init( minimumColumnWidth: (() -> Int)? = nil, anchor: OSLogCollectionBound = .end @@ -45,29 +49,18 @@ public struct OSLogStringAlignment { self.anchor = anchor } - /// Right alignment formatter. - @_semantics("constant_evaluable") - @inlinable - @_optimize(none) - public static var right: OSLogStringAlignment { - OSLogStringAlignment(anchor: .end) - } - - /// Left alignment formatter. - @_semantics("constant_evaluable") - @inlinable - @_optimize(none) - public static var left: OSLogStringAlignment { - OSLogStringAlignment(anchor: .start) - } - - /// Use default alignment, which is right alignment. + /// Indicates no alignment. @_semantics("constant_evaluable") @inlinable @_optimize(none) - public static var none: OSLogStringAlignment { .right } + public static var none: OSLogStringAlignment { OSLogStringAlignment(anchor: .end) } - /// Right align and display at least`columns` characters. + /// Right align and display at least `columns` characters. + /// + /// The interpolated value would be padded with spaces, if necessary, to + /// meet the specified `columns` characters. + /// + /// - Parameter columns: minimum number of characters to display. @_semantics("constant_evaluable") @inlinable @_optimize(none) @@ -77,7 +70,12 @@ public struct OSLogStringAlignment { OSLogStringAlignment(minimumColumnWidth: columns, anchor: .end) } - /// Left align and display at least`columns` characters. + /// Left align and display at least `columns` characters. + /// + /// The interpolated value would be padded with spaces, if necessary, to + /// meet the specified `columns` characters. + /// + /// - Parameter columns: minimum number of characters to display. @_semantics("constant_evaluable") @inlinable @_optimize(none) diff --git a/stdlib/private/OSLog/OSLogStringTypes.swift b/stdlib/private/OSLog/OSLogStringTypes.swift index 8a90b03c40598..ef0a7961916ec 100644 --- a/stdlib/private/OSLog/OSLogStringTypes.swift +++ b/stdlib/private/OSLog/OSLogStringTypes.swift @@ -14,8 +14,7 @@ // It defines `appendInterpolation` function for String type. It also defines // extensions for serializing strings into the argument buffer passed to // os_log ABIs. Note that os_log requires passing a stable pointer to an -// interpolated string. The SPI: `_convertConstStringToUTF8PointerArgument` -// is used to construct a stable pointer to a (dynamic) string. +// interpolated string. // // The `appendInterpolation` function defined in this file accept privacy and // alignment options along with the interpolated expression as shown below: @@ -25,17 +24,21 @@ extension OSLogInterpolation { - /// Define interpolation for expressions of type String. + /// Defines interpolation for expressions of type String. + /// + /// Do not call this function directly. It will be called automatically when interpolating + /// a value of type `String` in the string interpolations passed to the log APIs. + /// /// - Parameters: - /// - argumentString: the interpolated expression of type String, which is autoclosured. - /// - align: left or right alignment with the minimum number of columns as - /// defined by the type `OSLogStringAlignment`. - /// - privacy: a privacy qualifier which is either private or public. - /// It is auto-inferred by default. + /// - argumentString: The interpolated expression of type String, which is autoclosured. + /// - align: Left or right alignment with the minimum number of columns as + /// defined by the type `OSLogStringAlignment`. + /// - privacy: A privacy qualifier which is either private or public. + /// It is auto-inferred by default. @_semantics("constant_evaluable") - @_semantics("oslog.requires_constant_arguments") @inlinable @_optimize(none) + @_semantics("oslog.requires_constant_arguments") public mutating func appendInterpolation( _ argumentString: @autoclosure @escaping () -> String, align: OSLogStringAlignment = .none, @@ -48,12 +51,20 @@ extension OSLogInterpolation { // If minimum column width is specified, append this value first. Note that the // format specifier would use a '*' for width e.g. %*s. if let minColumns = align.minimumColumnWidth { - appendPrecisionArgument(minColumns) + appendAlignmentArgument(minColumns) + } + + // If the privacy has a mask, append the mask argument, which is a constant payload. + // Note that this should come after the width but before the precision. + if privacy.hasMask { + appendMaskArgument(privacy) } + // Append the string argument. addStringHeaders(privacy) arguments.append(argumentString) argumentCount += 1 + stringArgumentCount += 1 } /// Update preamble and append argument headers based on the parameters of @@ -90,13 +101,10 @@ extension OSLogInterpolation { _ privacy: OSLogPrivacy ) -> String { var specifier = "%" - switch privacy { - case .private: - specifier += "{private}" - case .public: - specifier += "{public}" - default: - break + if let privacySpecifier = privacy.privacySpecifier { + specifier += "{" + specifier += privacySpecifier + specifier += "}" } if case .start = align.anchor { specifier += "-" @@ -117,7 +125,12 @@ extension OSLogArguments { @inlinable @_optimize(none) internal mutating func append(_ value: @escaping () -> String) { - argumentClosures.append({ serialize(value(), at: &$0, using: &$1) }) + argumentClosures.append({ (position, _, stringArgumentOwners) in + serialize( + value(), + at: &position, + storingStringOwnersIn: &stringArgumentOwners) + }) } } @@ -129,34 +142,48 @@ extension OSLogArguments { /// This function must be constant evaluable. Note that it is marked transparent /// instead of @inline(__always) as it is used in optimize(none) functions. @_transparent -@usableFromInline +@_alwaysEmitIntoClient internal func pointerSizeInBytes() -> Int { return Int.bitWidth &>> logBitsPerByte } /// Serialize a stable pointer to the string `stringValue` at the buffer location -/// pointed by `bufferPosition`. When necessary, this function would copy the -/// string contents to a storage with a stable pointer. If that happens, a reference -/// to the storage will be added to `storageObjects`. -@inlinable +/// pointed to by `bufferPosition`. @_alwaysEmitIntoClient @inline(__always) internal func serialize( _ stringValue: String, - at bufferPosition: inout ByteBufferPointer, - using storageObjects: inout StorageObjects + at bufferPosition: inout UnsafeMutablePointer, + storingStringOwnersIn stringArgumentOwners: inout ObjectStorage ) { - let (optionalStorage, bytePointer): (AnyObject?, UnsafeRawPointer) = - _convertConstStringToUTF8PointerArgument( - stringValue) - - if let storage = optionalStorage { - storageObjects.append(storage) - } + let stringPointer = + getNullTerminatedUTF8Pointer( + stringValue, + storingStringOwnersIn: &stringArgumentOwners) let byteCount = pointerSizeInBytes() let dest = UnsafeMutableRawBufferPointer(start: bufferPosition, count: byteCount) - withUnsafeBytes(of: bytePointer) { dest.copyMemory(from: $0) } + withUnsafeBytes(of: stringPointer) { dest.copyMemory(from: $0) } bufferPosition += byteCount } + +/// Return a pointer that points to a contiguous sequence of null-terminated, +/// UTF8 charcters. If necessary, extends the lifetime of `stringValue` by +/// using `stringArgumentOwners`. +@_alwaysEmitIntoClient +@inline(never) +internal func getNullTerminatedUTF8Pointer( + _ stringValue: String, + storingStringOwnersIn stringArgumentOwners: inout ObjectStorage +) -> UnsafeRawPointer { + let (optStorage, bytePointer, _, _, _): + (AnyObject?, UnsafeRawPointer, Int, Bool, Bool) = + stringValue._deconstructUTF8(scratch: nil) + if let storage = optStorage { + initializeAndAdvance(&stringArgumentOwners, to: storage) + } else { + initializeAndAdvance(&stringArgumentOwners, to: stringValue._guts) + } + return bytePointer +} diff --git a/stdlib/private/OSLog/OSLogSwiftProtocols.swift b/stdlib/private/OSLog/OSLogSwiftProtocols.swift new file mode 100644 index 0000000000000..f14ee3c99bef8 --- /dev/null +++ b/stdlib/private/OSLog/OSLogSwiftProtocols.swift @@ -0,0 +1,72 @@ +//===----------------- OSLogSwiftProtocols.swift -----------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 defines extensions for interpolating types conforming to common +// Swift protocols. It defines `appendInterpolation` overloads for these protocols. +// All overloads defined in this file, delegate to other appendInterpolation +// functions for types natively supported by os_log. + +extension OSLogInterpolation { + + /// Defines interpolation for values conforming to CustomStringConvertible. The values + /// are displayed using the description methods on them. + /// + /// Do not call this function directly. It will be called automatically when interpolating + /// a value conforming to CustomStringConvertible in the string interpolations passed + /// to the log APIs. + /// + /// - Parameters: + /// - value: The interpolated expression conforming to CustomStringConvertible. + /// - align: Left or right alignment with the minimum number of columns as + /// defined by the type `OSLogStringAlignment`. + /// - privacy: A privacy qualifier which is either private or public. + /// It is auto-inferred by default. + @_optimize(none) + @_transparent + @_semantics("oslog.requires_constant_arguments") + public mutating func appendInterpolation( + _ value: @autoclosure @escaping () -> T, + align: OSLogStringAlignment = .none, + privacy: OSLogPrivacy = .auto + ) { + // TODO: Dead code elimination does not remove the call to the default value + // of alignment: .none. This function is made @_transparent to work around + // that. + appendInterpolation(value().description, align: align, privacy: privacy) + } + + /// Defines interpolation for meta-types. + /// + /// Do not call this function directly. It will be called automatically when interpolating + /// a value of type `Any.Type` in the string interpolations passed to the log APIs. + /// + /// - Parameters: + /// - value: An interpolated expression of type Any.Type, which is autoclosured. + /// - align: Left or right alignment with the minimum number of columns as + /// defined by the type `OSLogStringAlignment`. + /// - privacy: A privacy qualifier which is either private or public. + /// It is auto-inferred by default. + @_semantics("constant_evaluable") + @inlinable + @_optimize(none) + @_semantics("oslog.requires_constant_arguments") + public mutating func appendInterpolation( + _ value: @autoclosure @escaping () -> Any.Type, + align: OSLogStringAlignment = .none, + privacy: OSLogPrivacy = .auto + ) { + appendInterpolation( + _typeName(value(), qualified: false), + align: align, + privacy: privacy) + } +} diff --git a/stdlib/private/OSLog/OSLogTestHelper.swift b/stdlib/private/OSLog/OSLogTestHelper.swift index 85dde5ca81055..3d6e98dbaaad1 100644 --- a/stdlib/private/OSLog/OSLogTestHelper.swift +++ b/stdlib/private/OSLog/OSLogTestHelper.swift @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +import ObjectiveC + // This file contains test helpers for testing the compiler diagnostics and optimizations // of the new swift APIs for os log that accept string interpolations. @@ -51,41 +53,47 @@ func _osLogTestHelper( let preamble = message.interpolation.preamble let argumentCount = message.interpolation.argumentCount let bufferSize = message.bufferSize + let objectCount = message.interpolation.objectArgumentCount + let stringCount = message.interpolation.stringArgumentCount + let uint32bufferSize = UInt32(bufferSize) let argumentClosures = message.interpolation.arguments.argumentClosures + let formatStringPointer = _getGlobalStringTablePointer(formatString) // Code that will execute at runtime. if (!isLoggingEnabled()) { return } - - // Allocate a byte buffer to store the arguments. The buffer could be stack - // allocated as it is local to this function and also its size is a - // compile-time constant. let bufferMemory = UnsafeMutablePointer.allocate(capacity: bufferSize) - // Array of references to auxiliary storage created during serialization of - // strings. This array can be stack allocated. - var stringStorageObjects: [AnyObject] = [] + // Buffer for storing NSObjects and strings to keep them alive until the + // _os_log_impl_test call completes. + let objectArguments = createStorage(capacity: objectCount, type: NSObject.self) + let stringArgumentOwners = createStorage(capacity: stringCount, type: Any.self) var currentBufferPosition = bufferMemory + var objectArgumentsPosition = objectArguments + var stringArgumentOwnersPosition = stringArgumentOwners serialize(preamble, at: ¤tBufferPosition) serialize(argumentCount, at: ¤tBufferPosition) - argumentClosures.forEach { $0(¤tBufferPosition, &stringStorageObjects) } + argumentClosures.forEach { + $0(¤tBufferPosition, + &objectArgumentsPosition, + &stringArgumentOwnersPosition) + } _os_log_impl_test( assertion, formatString, formatStringPointer, bufferMemory, - UInt32(bufferSize)) + uint32bufferSize) - // The following operation extends the lifetime of argumentClosures, - // stringStorageObjects, and also of the objects stored in them, till this - // point. This is necessary because the assertion is passed internal pointers - // to the objects/strings stored in these arrays, as in the actual os log - // implementation. - _fixLifetime(argumentClosures) - _fixLifetime(stringStorageObjects) + // The following operation extends the lifetime of objectArguments and + // stringArgumentOwners till this point. This is necessary because the + // assertion is passed internal pointers to the objects/strings stored + // in these arrays, as in the actual os log implementation. + destroyStorage(objectArguments, count: objectCount) + destroyStorage(stringArgumentOwners, count: stringCount) bufferMemory.deallocate() } diff --git a/test/SILOptimizer/Inputs/OSLogConstantEvaluable.swift b/test/SILOptimizer/Inputs/OSLogConstantEvaluable.swift index f7a563f29582f..2207ea86c0c0b 100644 --- a/test/SILOptimizer/Inputs/OSLogConstantEvaluable.swift +++ b/test/SILOptimizer/Inputs/OSLogConstantEvaluable.swift @@ -45,3 +45,8 @@ func intValueWithPrecisionTest() -> OSLogMessage { \(10, format: .decimal(minDigits: 25), align: .right(columns: 10)) """ } + +@_semantics("test_driver") +func intValueWithPrivacyTest() -> OSLogMessage { + return "An integer value \(10, privacy: .private(mask: .hash))" +} diff --git a/test/SILOptimizer/OSLogFullOptTest.swift b/test/SILOptimizer/OSLogFullOptTest.swift index 8cc72d891f5e1..2d7a9b6812383 100644 --- a/test/SILOptimizer/OSLogFullOptTest.swift +++ b/test/SILOptimizer/OSLogFullOptTest.swift @@ -21,10 +21,6 @@ func testSimpleInterpolation() { // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] - // CHECK: [[NOT_ENABLED]]: - // CHECK-NEXT: tail call void @swift_release - // CHECK-NEXT: ret void - // CHECK: [[ENABLED]]: // // Header bytes. @@ -51,6 +47,10 @@ func testSimpleInterpolation() { // CHECK-32-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([27 x i8], [27 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] // CHECK-NEXT: br label %[[NOT_ENABLED]] + + // CHECK: [[NOT_ENABLED]]: + // CHECK-NEXT: tail call void @swift_release + // CHECK-NEXT: ret void } // CHECK-LABEL: define hidden swiftcc void @"${{.*}}testInterpolationWithMultipleArguments @@ -135,18 +135,15 @@ func testNSObjectInterpolation(nsArray: NSArray) { // CHECK-NEXT: tail call void @llvm.objc.release // CHECK-NEXT: br label %[[EXIT:[0-9]+]] - // CHECK: [[EXIT]]: - // CHECK-NEXT: tail call void @llvm.objc.release(i8* [[NSARRAY_ARG]]) - // CHECK-NEXT: tail call void @swift_release - // CHECK-NEXT: ret void - // CHECK: [[ENABLED]]: // // Header bytes. // // CHECK-64: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i64 12 // CHECK-32: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i32 8 - // CHECK-NEXT: store i8 2, i8* [[BUFFER]], align 1 + // CHECK-64: [[OBJ_STORAGE:%.+]] = tail call noalias i8* @swift_slowAlloc(i64 8 + // CHECK-32: [[OBJ_STORAGE:%.+]] = tail call noalias i8* @swift_slowAlloc(i32 4 + // CHECK: store i8 2, i8* [[BUFFER]], align 1 // CHECK-NEXT: [[OFFSET1:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 1 // CHECK-NEXT: store i8 1, i8* [[OFFSET1]], align 1 // @@ -157,18 +154,29 @@ func testNSObjectInterpolation(nsArray: NSArray) { // CHECK-NEXT: [[OFFSET3:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 3 // CHECK-64-NEXT: store i8 8, i8* [[OFFSET3]], align 1 // CHECK-32-NEXT: store i8 4, i8* [[OFFSET3]], align 1 - // CHECK-NEXT: tail call void @llvm.objc.release // CHECK-NEXT: bitcast %swift.refcounted* %{{.*}} to %swift.opaque* // CHECK-NEXT: [[OFFSET4:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 4 // CHECK-NEXT: [[BITCASTED_DEST:%.+]] = bitcast i8* [[OFFSET4]] to %TSo7NSArrayC** // CHECK-NEXT: [[BITCASTED_SRC:%.+]] = bitcast i8* [[NSARRAY_ARG]] to %TSo7NSArrayC* // CHECK-NEXT: store %TSo7NSArrayC* [[BITCASTED_SRC]], %TSo7NSArrayC** [[BITCASTED_DEST]], align 1 + // CHECK-NEXT: [[BITCASTED_DEST2:%.+]] = bitcast i8* [[OBJ_STORAGE]] to %TSo7NSArrayC** + // CHECK-NEXT: [[BITCASTED_SRC2:%.+]] = bitcast i8* [[NSARRAY_ARG]] to %TSo7NSArrayC* + // CHECK-64-NEXT: store %TSo7NSArrayC* [[BITCASTED_SRC2]], %TSo7NSArrayC** [[BITCASTED_DEST2]], align 8 + // CHECK-32-NEXT: store %TSo7NSArrayC* [[BITCASTED_SRC2]], %TSo7NSArrayC** [[BITCASTED_DEST2]], align 4 // CHECK-64-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @{{.*}}, i64 0, i64 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) // CHECK-32-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) + // CHECK-NEXT: [[BITCASTED_OBJ_STORAGE:%.+]] = bitcast i8* [[OBJ_STORAGE]] to %swift.opaque* + // CHECK-NEXT: tail call void @swift_arrayDestroy(%swift.opaque* [[BITCASTED_OBJ_STORAGE]] + // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[OBJ_STORAGE]] // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] // CHECK-NEXT: tail call void @swift_release // CHECK-NEXT: br label %[[EXIT]] + + // CHECK: [[EXIT]]: + // CHECK-NEXT: tail call void @llvm.objc.release(i8* [[NSARRAY_ARG]]) + // CHECK-NEXT: tail call void @swift_release + // CHECK-NEXT: ret void } // CHECK-LABEL: define hidden swiftcc void @"${{.*}}testFloatInterpolation @@ -178,10 +186,6 @@ func testFloatInterpolation(doubleValue: Double) { // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] - // CHECK: [[NOT_ENABLED]]: - // CHECK-NEXT: tail call void @swift_release - // CHECK-NEXT: ret void - // CHECK: [[ENABLED]]: // // Header bytes. @@ -204,6 +208,10 @@ func testFloatInterpolation(doubleValue: Double) { // CHECK-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @{{.*}}, i{{.*}} 0, i{{.*}} 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] // CHECK-NEXT: br label %[[NOT_ENABLED]] + + // CHECK: [[NOT_ENABLED]]: + // CHECK-NEXT: tail call void @swift_release + // CHECK-NEXT: ret void } // This test checks that the precision and alignment are optimally "stored" into the @@ -235,7 +243,7 @@ func testDynamicPrecisionAndAlignment() { // First argument bytes. // // CHECK-NEXT: [[OFFSET2:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 2 - // CHECK-NEXT: store i8 16, i8* [[OFFSET2]], align 1 + // CHECK-NEXT: store i8 0, i8* [[OFFSET2]], align 1 // CHECK-NEXT: [[OFFSET3:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 3 // CHECK-NEXT: store i8 4, i8* [[OFFSET3]], align 1 // CHECK-NEXT: [[OFFSET4:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 4 @@ -269,5 +277,110 @@ func testDynamicPrecisionAndAlignment() { // CHECK-NEXT: br label %[[NOT_ENABLED]] } -// TODO: add test for String. It is more complicated due to more complex logic -// in string serialization. +// CHECK-LABEL: define hidden swiftcc void @"${{.*}}testStringInterpolation +func testStringInterpolation(stringValue: String) { + _osLogTestHelper("String value: \(stringValue)") + // CHECK: entry: + // CHECK-64: call %swift.bridge* @swift_bridgeObjectRetain_n(%swift.bridge* %1 + // CHECK-32: tail call void @"$ss13_StringObjectV7VariantOWOy"(i32 %1 + // CHECK-32-NEXT: tail call void @"$ss13_StringObjectV7VariantOWOy"(i32 %1 + // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() + // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] + + // CHECK: [[NOT_ENABLED]]: + // CHECK-64: call void @swift_bridgeObjectRelease_n(%swift.bridge* %1 + // CHECK-32: tail call void @"$ss13_StringObjectV7VariantOWOe"(i32 %1 + // CHECK-32-NEXT: tail call void @"$ss13_StringObjectV7VariantOWOe"(i32 %1 + // CHECK: br label %[[EXIT:[0-9]+]] + + // CHECK: [[ENABLED]]: + // + // Header bytes. + // + // CHECK-64: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 12 + // CHECK-32: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 8 + // CHECK-64-NEXT: [[STR_STORAGE:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 32 + // CHECK-32-NEXT: [[STR_STORAGE:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 16 + // CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, i8* {{(nonnull )?}}[[STR_STORAGE_PTR:%.*]] + // CHECK: store i8 2, i8* [[BUFFER]], align 1 + // CHECK-NEXT: [[OFFSET1:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 1 + // CHECK-NEXT: store i8 1, i8* [[OFFSET1]], align 1 + + // Argument bytes. + // + // CHECK-NEXT: [[OFFSET2:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 2 + // CHECK-NEXT: store i8 32, i8* [[OFFSET2]], align 1 + // CHECK-NEXT: [[OFFSET3:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 3 + // CHECK-64-NEXT: store i8 8, i8* [[OFFSET3]], align 1 + // CHECK-32-NEXT: store i8 4, i8* [[OFFSET3]], align 1 + + // CHECK: [[STR_POINTER:%.*]] = call swiftcc i8* @"${{.*}}getNullTerminatedUTF8Pointer{{.*}}"(i{{.*}} %0, {{.*}} %1 + + // CHECK: [[OFFSET_BUFFER:%.*]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 4 + // CHECK-NEXT: [[OFFSET_BUFFER_PTR:%.*]] = bitcast i8* [[OFFSET_BUFFER]] to i8** + // CHECK-NEXT: store i8* [[STR_POINTER]], i8** [[OFFSET_BUFFER_PTR]] + + // os_log_impl call. + // CHECK-64-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @{{.*}}, i64 0, i64 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) + // CHECK-32-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) + // CHECK-NEXT: [[BITCASTED_STR_STORAGE:%.*]] = bitcast i8* [[STR_STORAGE]] to %swift.opaque* + // CHECK-NEXT: tail call void @swift_arrayDestroy(%swift.opaque* [[BITCASTED_STR_STORAGE]] + // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[STR_STORAGE]] + // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] + // CHECK: call void @llvm.lifetime.end{{.*}}({{.*}}, i8* {{(nonnull )?}}[[STR_STORAGE_PTR]] + // CHECK-NEXT: br label %[[EXIT]] + + // CHECK: [[EXIT]]: + // CHECK-NEXT: ret void +} + +// CHECK-LABEL: define hidden swiftcc void @"${{.*}}testMetatypeInterpolation +func testMetatypeInterpolation(of type: T.Type) { + _osLogTestHelper("Metatype value: \(type)") + // CHECK: entry: + // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() + // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] + + // CHECK: [[NOT_ENABLED]]: + // CHECK-NEXT: call void @swift_release + // CHECK-NEXT: br label %[[EXIT:[0-9]+]] + + // CHECK: [[ENABLED]]: + // + // Header bytes. + // + // CHECK-64: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 12 + // CHECK-32: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 8 + // CHECK-64-NEXT: [[STR_STORAGE:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 32 + // CHECK-32-NEXT: [[STR_STORAGE:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 16 + // CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, i8* {{(nonnull )?}}[[STR_STORAGE_PTR:%.*]] + // CHECK: store i8 2, i8* [[BUFFER]], align 1 + // CHECK-NEXT: [[OFFSET1:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 1 + // CHECK-NEXT: store i8 1, i8* [[OFFSET1]], align 1 + + // Argument bytes. + // + // CHECK-NEXT: [[OFFSET2:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 2 + // CHECK-NEXT: store i8 32, i8* [[OFFSET2]], align 1 + // CHECK-NEXT: [[OFFSET3:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 3 + // CHECK-64-NEXT: store i8 8, i8* [[OFFSET3]], align 1 + // CHECK-32-NEXT: store i8 4, i8* [[OFFSET3]], align 1 + // CHECK-NEXT: [[TYPENAME:%.+]] = tail call swiftcc { i{{.*}}, {{.*}} } @"${{.*}}_typeName{{.*}}"({{.*}} %0 + // CHECK-NEXT: [[TYPENAME_0:%.+]] = extractvalue { i{{.*}}, {{.*}} } [[TYPENAME]], 0 + // CHECK-NEXT: [[TYPENAME_1:%.+]] = extractvalue { i{{.*}}, {{.*}} } [[TYPENAME]], 1 + + // CHECK: [[STR_POINTER:%.*]] = call swiftcc i8* @"${{.*}}getNullTerminatedUTF8Pointer{{.*}}"(i{{.*}} [[TYPENAME_0]], {{.*}} [[TYPENAME_1]] + + // os_log_impl call. + // CHECK-64: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([19 x i8], [19 x i8]* @{{.*}}, i64 0, i64 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) + // CHECK-32: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([19 x i8], [19 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) + // CHECK-NEXT: [[BITCASTED_STR_STORAGE:%.*]] = bitcast i8* [[STR_STORAGE]] to %swift.opaque* + // CHECK-NEXT: tail call void @swift_arrayDestroy(%swift.opaque* [[BITCASTED_STR_STORAGE]] + // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[STR_STORAGE]] + // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] + // CHECK: call void @llvm.lifetime.end{{.*}}({{.*}}, i8* {{(nonnull )?}}[[STR_STORAGE_PTR]] + // CHECK-NEXT: br label %[[EXIT]] + + // CHECK: [[EXIT]]: + // CHECK-NEXT: ret void +} diff --git a/test/SILOptimizer/OSLogMandatoryOptTest.swift b/test/SILOptimizer/OSLogMandatoryOptTest.swift index e5b2c9da9a946..8371053f21412 100644 --- a/test/SILOptimizer/OSLogMandatoryOptTest.swift +++ b/test/SILOptimizer/OSLogMandatoryOptTest.swift @@ -45,16 +45,16 @@ func testSimpleInterpolation() { // the array which is checked by a different test suite. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // We need to wade through some borrows and copy values here. // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[FINARR:%[0-9]+]] // CHECK-DAG: [[FINARRFUNC:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARGSARRAY:%[0-9]+]]) + // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARGSARRAY:%[0-9]+]]) // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 } @@ -92,15 +92,15 @@ func testInterpolationWithFormatOptions() { // the array which is checked by a different test suite. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[FINARR:%[0-9]+]] // CHECK-DAG: [[FINARRFUNC:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARGSARRAY:%[0-9]+]]) + // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARGSARRAY:%[0-9]+]]) // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 } @@ -140,15 +140,15 @@ func testInterpolationWithFormatOptionsAndPrivacy() { // the array which is checked by a different test suite. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[FINARR:%[0-9]+]] // CHECK-DAG: [[FINARRFUNC:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARGSARRAY:%[0-9]+]]) + // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARGSARRAY:%[0-9]+]]) // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 } @@ -194,15 +194,15 @@ func testInterpolationWithMultipleArguments() { // the array which is checked by a different test suite. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[FINARR:%[0-9]+]] // CHECK-DAG: [[FINARRFUNC:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARGSARRAY:%[0-9]+]]) + // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARGSARRAY:%[0-9]+]]) // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 9 } @@ -244,13 +244,13 @@ func testLogMessageWithoutData() { // Check whether argument array is folded. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 0 } @@ -317,15 +317,15 @@ func testMessageWithTooManyArguments() { // Check whether argument array is folded. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[FINARR:%[0-9]+]] // CHECK-DAG: [[FINARRFUNC:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARGSARRAY:%[0-9]+]]) + // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARGSARRAY:%[0-9]+]]) // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 144 } @@ -402,15 +402,15 @@ func testDynamicStringArguments() { // the array which is checked by a different test suite. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[FINARR:%[0-9]+]] // CHECK-DAG: [[FINARRFUNC:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARGSARRAY:%[0-9]+]]) + // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARGSARRAY:%[0-9]+]]) // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 6 } @@ -455,15 +455,15 @@ func testNSObjectInterpolation() { // the array which is checked by a different test suite. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[FINARR:%[0-9]+]] // CHECK-DAG: [[FINARRFUNC:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK-DAG: [[FINARR]] = apply {{.*}}<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARGSARRAY:%[0-9]+]]) + // CHECK-DAG: [[FINARR]] = apply {{.*}}<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARGSARRAY:%[0-9]+]]) // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 6 } @@ -503,15 +503,15 @@ func testDoubleInterpolation() { // not checked here, but is checked by a different test suite. // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: try_apply [[FOREACH]], inout Optional>, inout Optional>) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[FINARR:%[0-9]+]] // CHECK-DAG: [[FINARRFUNC:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARGSARRAY:%[0-9]+]]) + // CHECK-DAG: [[FINARR]] = apply [[FINARRFUNC]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARGSARRAY:%[0-9]+]]) // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Optional>, inout Optional>) -> ()>([[ARRAYSIZE:%[0-9]+]]) // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 } diff --git a/test/Sema/diag_constantness_check_os_log.swift b/test/Sema/diag_constantness_check_os_log.swift index 4caa166692b65..aba696db441bb 100644 --- a/test/Sema/diag_constantness_check_os_log.swift +++ b/test/Sema/diag_constantness_check_os_log.swift @@ -27,7 +27,7 @@ func testNonconstantFormatOption( func testNonconstantPrivacyOption(privacyOpt: OSLogPrivacy) { _osLogTestHelper("Integer: \(Int.max, privacy: privacyOpt)") - // expected-error@-1 {{argument must be a case of enum 'OSLogPrivacy'}} + // expected-error@-1 {{argument must be a static method or property of 'OSLogPrivacy'}} } func testNonconstantAlignmentOption(alignOpt: OSLogStringAlignment) { @@ -44,7 +44,7 @@ func testMultipleOptions( \(2, format: formatOpt, align: .right(columns: 10), privacy: privacyOpt) """) // expected-error@-2 {{argument must be a static method or property of 'OSLogIntegerFormatting'}} - // expected-error@-3 {{argument must be a case of enum 'OSLogPrivacy'}} + // expected-error@-3 {{argument must be a static method or property of 'OSLogPrivacy'}} } func testNoninlinedOSLogMessage() { diff --git a/test/stdlib/OSLogExecutionTest.swift b/test/stdlib/OSLogExecutionTest.swift index 5e1eda880ac7c..b415579f6eaee 100644 --- a/test/stdlib/OSLogExecutionTest.swift +++ b/test/stdlib/OSLogExecutionTest.swift @@ -77,7 +77,7 @@ internal struct OSLogBufferChecker { /// This occupies four most significant bits of the first byte of the /// argument header. internal enum ArgumentType: UInt8 { - case scalar = 0, count, string, pointer, object + case scalar = 0, count = 1, string = 2, pointer = 3, object = 4, mask = 7 // TODO: include wide string and errno here if needed. } @@ -142,13 +142,13 @@ internal struct OSLogBufferChecker { /// Check whether the bytes starting from `startIndex` contain the encoding for a count. internal func checkCount( startIndex: Int, - flag: ArgumentFlag, - expectedCount: Int + expectedCount: Int, + precision: Bool ) { checkNumeric( startIndex: startIndex, - flag: flag, - type: .count, + flag: .autoFlag, + type: precision ? .count : .scalar, expectedValue: CInt(expectedCount)) } @@ -614,8 +614,8 @@ InterpolationTestSuite.test("Integer formatting with precision") { bufferChecker.checkArguments( { bufferChecker.checkCount( startIndex: $0, - flag: .autoFlag, - expectedCount: 10) + expectedCount: 10, + precision: true) }, { bufferChecker.checkInt( startIndex: $0, @@ -654,13 +654,13 @@ InterpolationTestSuite.test("Integer formatting with precision and alignment") { bufferChecker.checkArguments( { bufferChecker.checkCount( startIndex: $0, - flag: .autoFlag, - expectedCount: 7) + expectedCount: 7, + precision: false) }, { bufferChecker.checkCount( startIndex: $0, - flag: .autoFlag, - expectedCount: 10) + expectedCount: 10, + precision: true) }, { bufferChecker.checkInt( startIndex: $0, From 74765a8ba82a14d3fce03e156049f65845c2cbfa Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 1 Oct 2020 13:09:00 -0700 Subject: [PATCH 02/12] Remove Type Body Fingerprints Flags This infrastructure has more than proven itself. Drop the code paths and tests supporting the status quo. --- include/swift/Basic/LangOptions.h | 6 - include/swift/Driver/Compilation.h | 7 - .../Driver/FineGrainedDependencyDriverGraph.h | 9 +- include/swift/Option/Options.td | 8 - lib/AST/DeclContext.cpp | 2 +- lib/Driver/Compilation.cpp | 6 +- lib/Driver/Driver.cpp | 6 - .../FineGrainedDependencyDriverGraph.cpp | 6 - lib/Driver/ToolChains.cpp | 2 - lib/Frontend/CompilerInvocation.cpp | 5 - lib/IDE/CompletionInstance.cpp | 6 - lib/Parse/ParseDecl.cpp | 9 +- .../class-fingerprint.swift | 45 +- .../enum-fingerprint.swift | 45 +- .../extension-adds-member.swift | 47 - .../protocol-fingerprint.swift | 45 +- .../struct-fingerprint.swift | 45 +- ...erprints.swift => added_method-type.swift} | 4 +- test/InterfaceHash/added_method.swift | 23 - ...s_private_property-type-fingerprints.swift | 53 -- ...added_private_class_private_property.swift | 38 +- ...ate_class_property-type-fingerprints.swift | 53 -- .../added_private_class_property.swift | 38 +- ...m_private_property-type-fingerprints.swift | 56 -- .../added_private_enum_private_property.swift | 39 +- ...vate_enum_property-type-fingerprints.swift | 55 -- .../added_private_enum_property.swift | 38 +- ...ded_private_method-type-fingerprints.swift | 55 -- test/InterfaceHash/added_private_method.swift | 38 +- ...method_value_types-type-fingerprints.swift | 88 -- .../added_private_method_value_types.swift | 53 +- ...te_protocol_method-type-fingerprints.swift | 50 - .../added_private_protocol_method.swift | 38 +- ..._protocol_property-type-fingerprints.swift | 50 - .../added_private_protocol_property.swift | 38 +- ...t_private_property-type-fingerprints.swift | 56 -- ...dded_private_struct_private_property.swift | 38 +- ...te_struct_property-type-fingerprints.swift | 56 -- .../added_private_struct_property.swift | 38 +- ...edited_method_body-type-fingerprints.swift | 31 - test/InterfaceHash/edited_method_body.swift | 18 +- ...ed_property_getter-type-fingerprints.swift | 33 - .../edited_property_getter.swift | 19 +- unittests/Driver/CMakeLists.txt | 1 - .../FineGrainedDependencyGraphTests.cpp | 242 +++-- ...peBodyFingerprintsDependencyGraphTests.cpp | 894 ------------------ .../rdar23148987-type-fingerprints.swift | 61 -- .../Driver/Dependencies/rdar23148987.swift | 6 +- 48 files changed, 581 insertions(+), 2018 deletions(-) rename test/InterfaceHash/{added_method-type-fingerprints.swift => added_method-type.swift} (86%) delete mode 100644 test/InterfaceHash/added_method.swift delete mode 100644 test/InterfaceHash/added_private_class_private_property-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_class_property-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_enum_private_property-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_enum_property-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_method-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_method_value_types-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_protocol_method-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_protocol_property-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_struct_private_property-type-fingerprints.swift delete mode 100644 test/InterfaceHash/added_private_struct_property-type-fingerprints.swift delete mode 100644 test/InterfaceHash/edited_method_body-type-fingerprints.swift delete mode 100644 test/InterfaceHash/edited_property_getter-type-fingerprints.swift delete mode 100644 unittests/Driver/TypeBodyFingerprintsDependencyGraphTests.cpp delete mode 100644 validation-test/Driver/Dependencies/rdar23148987-type-fingerprints.swift diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 40d8c719a02d1..bd704cb29c4d9 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -330,12 +330,6 @@ namespace swift { /// of active clauses aren't hoisted into the enclosing scope. bool DisablePoundIfEvaluation = false; - /// Instead of hashing tokens inside of NominalType and ExtensionBodies into - /// the interface hash, hash them into per-iterable-decl-context - /// fingerprints. Fine-grained dependency types won't dirty every provides - /// in a file when the user adds a member to, e.g., a struct. - bool EnableTypeFingerprints = true; - /// When using fine-grained dependencies, emit dot files for every swiftdeps /// file. bool EmitFineGrainedDependencySourcefileDotFiles = false; diff --git a/include/swift/Driver/Compilation.h b/include/swift/Driver/Compilation.h index d970a9cf834cd..5e6e1972f9dfd 100644 --- a/include/swift/Driver/Compilation.h +++ b/include/swift/Driver/Compilation.h @@ -265,9 +265,6 @@ class Compilation { const bool OnlyOneDependencyFile; private: - /// Is the parser recording token hashes for each type body? - const bool EnableTypeFingerprints; - /// Helpful for debugging, but slows down the driver. So, only turn on when /// needed. const bool VerifyFineGrainedDependencyGraphAfterEveryImport; @@ -319,8 +316,6 @@ class Compilation { bool ShowDriverTimeCompilation = false, std::unique_ptr Stats = nullptr, bool OnlyOneDependencyFile = false, - bool EnableTypeFingerprints = - LangOptions().EnableTypeFingerprints, bool VerifyFineGrainedDependencyGraphAfterEveryImport = false, bool EmitFineGrainedDependencyDotFileAfterEveryImport = false, bool FineGrainedDependenciesIncludeIntrafileOnes = false, @@ -386,8 +381,6 @@ class Compilation { } void disableIncrementalBuild(Twine why); - bool getEnableTypeFingerprints() const { return EnableTypeFingerprints; } - bool getVerifyFineGrainedDependencyGraphAfterEveryImport() const { return VerifyFineGrainedDependencyGraphAfterEveryImport; } diff --git a/include/swift/Driver/FineGrainedDependencyDriverGraph.h b/include/swift/Driver/FineGrainedDependencyDriverGraph.h index ba461842bb36e..07029becc8be8 100644 --- a/include/swift/Driver/FineGrainedDependencyDriverGraph.h +++ b/include/swift/Driver/FineGrainedDependencyDriverGraph.h @@ -189,8 +189,6 @@ class ModuleDepGraph { const bool verifyFineGrainedDependencyGraphAfterEveryImport; const bool emitFineGrainedDependencyDotFileAfterEveryImport; - const bool EnableTypeFingerprints; - private: /// If tracing dependencies, holds a vector used to hold the current path /// def - use/def - use/def - ... @@ -296,14 +294,12 @@ class ModuleDepGraph { /// \p stats may be null ModuleDepGraph(const bool verifyFineGrainedDependencyGraphAfterEveryImport, const bool emitFineGrainedDependencyDotFileAfterEveryImport, - const bool EnableTypeFingerprints, const bool shouldTraceDependencies, UnifiedStatsReporter *stats) : verifyFineGrainedDependencyGraphAfterEveryImport( verifyFineGrainedDependencyGraphAfterEveryImport), emitFineGrainedDependencyDotFileAfterEveryImport( emitFineGrainedDependencyDotFileAfterEveryImport), - EnableTypeFingerprints(EnableTypeFingerprints), currentPathIfTracing( shouldTraceDependencies ? llvm::Optional>( @@ -314,11 +310,10 @@ class ModuleDepGraph { } /// For unit tests. - ModuleDepGraph(const bool EnableTypeFingerprints, - const bool EmitDotFilesForDebugging = false) + ModuleDepGraph(const bool EmitDotFilesForDebugging = false) : ModuleDepGraph( true, /*emitFineGrainedDependencyDotFileAfterEveryImport=*/ - EmitDotFilesForDebugging, EnableTypeFingerprints, false, nullptr) {} + EmitDotFilesForDebugging, false, nullptr) {} //============================================================================ // MARK: ModuleDepGraph - updating from a switdeps file diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index a1c2b34fc1f59..d60baf2396495 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -139,14 +139,6 @@ def driver_always_rebuild_dependents : Flag<["-"], "driver-always-rebuild-dependents">, InternalDebugOpt, HelpText<"Always rebuild dependents of files that have been modified">; -def enable_type_fingerprints : -Flag<["-"], "enable-type-fingerprints">, Flags<[FrontendOption, HelpHidden]>, -HelpText<"Enable per-nominal and extension body fingerprints">; - -def disable_type_fingerprints : -Flag<["-"], "disable-type-fingerprints">, Flags<[FrontendOption, HelpHidden]>, -HelpText<"Disable per-nominal and extension body fingerprints">; - def enable_only_one_dependency_file : Flag<["-"], "enable-only-one-dependency-file">, Flags<[DoesNotAffectIncrementalBuild]>, HelpText<"Enables incremental build optimization that only produces one dependencies file">; diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 8aa916c6e128e..25224941d99af 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -933,7 +933,7 @@ bool IterableDeclContext::areTokensHashedForThisBodyInsteadOfInterfaceHash() // corresponding to the fingerprinted nominal dependency node. if (isa(this)) return false; - return getASTContext().LangOpts.EnableTypeFingerprints; + return true; } /// Return the DeclContext to compare when checking private access in diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 1b1e57753b784..31f3d0ce4f1dd 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -121,7 +121,6 @@ Compilation::Compilation(DiagnosticEngine &Diags, bool ShowDriverTimeCompilation, std::unique_ptr StatsReporter, bool OnlyOneDependencyFile, - bool EnableTypeFingerprints, bool VerifyFineGrainedDependencyGraphAfterEveryImport, bool EmitFineGrainedDependencyDotFileAfterEveryImport, bool FineGrainedDependenciesIncludeIntrafileOnes, @@ -149,7 +148,6 @@ Compilation::Compilation(DiagnosticEngine &Diags, Stats(std::move(StatsReporter)), FilelistThreshold(FilelistThreshold), OnlyOneDependencyFile(OnlyOneDependencyFile), - EnableTypeFingerprints(EnableTypeFingerprints), VerifyFineGrainedDependencyGraphAfterEveryImport( VerifyFineGrainedDependencyGraphAfterEveryImport), EmitFineGrainedDependencyDotFileAfterEveryImport( @@ -829,12 +827,12 @@ namespace driver { FineGrainedDepGraph( Comp.getVerifyFineGrainedDependencyGraphAfterEveryImport(), Comp.getEmitFineGrainedDependencyDotFileAfterEveryImport(), - Comp.getEnableTypeFingerprints(), Comp.getTraceDependencies(), + Comp.getTraceDependencies(), Comp.getStatsReporter()), FineGrainedDepGraphForRanges( Comp.getVerifyFineGrainedDependencyGraphAfterEveryImport(), Comp.getEmitFineGrainedDependencyDotFileAfterEveryImport(), - Comp.getEnableTypeFingerprints(), Comp.getTraceDependencies(), + Comp.getTraceDependencies(), Comp.getStatsReporter()), TQ(std::move(TaskQueue)) {} diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 6394cb4f65807..783d297595fb6 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1014,11 +1014,6 @@ Driver::buildCompilation(const ToolChain &TC, ArgList->hasFlag(options::OPT_enable_only_one_dependency_file, options::OPT_disable_only_one_dependency_file, false); - const bool EnableTypeFingerprints = - ArgList->hasFlag(options::OPT_enable_type_fingerprints, - options::OPT_disable_type_fingerprints, - LangOptions().EnableTypeFingerprints); - const bool VerifyFineGrainedDependencyGraphAfterEveryImport = ArgList->hasArg( options:: OPT_driver_verify_fine_grained_dependency_graph_after_every_import); @@ -1050,7 +1045,6 @@ Driver::buildCompilation(const ToolChain &TC, ShowDriverTimeCompilation, std::move(StatsReporter), OnlyOneDependencyFile, - EnableTypeFingerprints, VerifyFineGrainedDependencyGraphAfterEveryImport, EmitFineGrainedDependencyDotFileAfterEveryImport, FineGrainedDependenciesIncludeIntrafileOnes, diff --git a/lib/Driver/FineGrainedDependencyDriverGraph.cpp b/lib/Driver/FineGrainedDependencyDriverGraph.cpp index dc2a9afcf929b..d5ab5a5228b57 100644 --- a/lib/Driver/FineGrainedDependencyDriverGraph.cpp +++ b/lib/Driver/FineGrainedDependencyDriverGraph.cpp @@ -369,12 +369,6 @@ ModuleDepGraph::integrateSourceFileDepGraphNode( const SourceFileDepGraph &g, const SourceFileDepGraphNode *integrand, const PreexistingNodeIfAny preexistingMatch, const StringRef swiftDepsOfJob) { - - if (!EnableTypeFingerprints && - integrand->getKey().getKind() != NodeKind::sourceFileProvide && - integrand->getFingerprint()) - return None; - if (!integrand->getIsProvides()) return NullablePtr(); // depends are captured by // recordWhatUseDependsUpon below diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 8d5d0b30d7ede..a03ea4fe52e9f 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -259,8 +259,6 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_O_Group); inputArgs.AddLastArg(arguments, options::OPT_RemoveRuntimeAsserts); inputArgs.AddLastArg(arguments, options::OPT_AssumeSingleThreaded); - inputArgs.AddLastArg(arguments, options::OPT_enable_type_fingerprints); - inputArgs.AddLastArg(arguments, options::OPT_disable_type_fingerprints); inputArgs.AddLastArg(arguments, options::OPT_fine_grained_dependency_include_intrafile); inputArgs.AddLastArg(arguments, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c4f1c698ac7bd..2c8f39248235c 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -438,11 +438,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.VerifySyntaxTree = true; } - Opts.EnableTypeFingerprints = - Args.hasFlag(options::OPT_enable_type_fingerprints, - options::OPT_disable_type_fingerprints, - LangOptions().EnableTypeFingerprints); - if (Args.hasArg(OPT_emit_fine_grained_dependency_sourcefile_dot_files)) Opts.EmitFineGrainedDependencySourcefileDotFiles = true; diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 9c4ba9940e0e1..eaad0b6499293 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -322,8 +322,6 @@ bool CompletionInstance::performCachedOperationIfPossible( LangOptions langOpts = CI.getASTContext().LangOpts; langOpts.DisableParserLookup = true; - // Ensure all non-function-body tokens are hashed into the interface hash - langOpts.EnableTypeFingerprints = false; TypeCheckerOptions typeckOpts = CI.getASTContext().TypeCheckerOpts; SearchPathOptions searchPathOpts = CI.getASTContext().SearchPathOpts; DiagnosticEngine tmpDiags(tmpSM); @@ -599,10 +597,6 @@ bool swift::ide::CompletionInstance::performOperation( // source text. That breaks an invariant of syntax tree building. Invocation.getLangOptions().BuildSyntaxTree = false; - // Since caching uses the interface hash, and since per type fingerprints - // weaken that hash, disable them here: - Invocation.getLangOptions().EnableTypeFingerprints = false; - // We don't need token list. Invocation.getLangOptions().CollectParsedToken = false; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index fa9ace4441e27..d3076ba6a979f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4551,8 +4551,13 @@ Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag, // If we're hashing the type body separately, record the curly braces but // nothing inside for the interface hash. + // + // FIXME: There's no real reason code completion cannot also use this code + // path. But it seems to cause lazy parsing in contexts that the current + // implementation does not expect. Optional>> MemberHashingScope; - if (IDC->areTokensHashedForThisBodyInsteadOfInterfaceHash()) { + if (IDC->areTokensHashedForThisBodyInsteadOfInterfaceHash() && + !L->isCodeCompletion()) { recordTokenHash("{"); recordTokenHash("}"); MemberHashingScope.emplace(CurrentTokenHash, llvm::MD5()); @@ -4587,7 +4592,7 @@ Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag, if (RBLoc.isInvalid()) hadError = true; - if (!Context.LangOpts.EnableTypeFingerprints) + if (L->isCodeCompletion()) return std::make_pair(decls, None); llvm::MD5::MD5Result result; diff --git a/test/Frontend/PrivateFingerprints/class-fingerprint.swift b/test/Frontend/PrivateFingerprints/class-fingerprint.swift index 67b29178057e4..e244cc3f123a2 100644 --- a/test/Frontend/PrivateFingerprints/class-fingerprint.swift +++ b/test/Frontend/PrivateFingerprints/class-fingerprint.swift @@ -1,48 +1,6 @@ - // Test per-type-body fingerprints for classes // -// ============================================================================= -// Without the fingerprints -// ============================================================================= - -// Establish status quo - - -// RUN: %empty-directory(%t) -// RUN: cp %S/Inputs/class-fingerprint/* %t -// RUN: cp %t/definesAB{-before,}.swift - -// Seeing weird failure on CI, so set the mod times -// RUN: touch -t 200101010101 %t/*.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >&output1 - -// only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB1.swiftdeps - -// Change one type, but uses of all types get recompiled - -// RUN: cp %t/definesAB{-after,}.swift - -// Seeing weird failure on CI, so ensure that definesAB.swift is newer -// RUN: touch -t 200201010101 %t/* -// RUN: touch -t 200101010101 %t/*.swift -// RUN: touch -t 200301010101 %t/definesAB.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >&output2 - -// Save for debugging: -// only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB1.swiftdeps - -// RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output2 - -// CHECK-MAINAB-RECOMPILED: Queuing (initial): {compile: definesAB.o <= definesAB.swift} -// CHECK-MAINAB-RECOMPILED: Queuing because of dependencies discovered later: {compile: usesA.o <= usesA.swift} - -// ============================================================================= -// With the fingerprints -// ============================================================================= - // Establish status quo // RUN: %empty-directory(%t) @@ -71,3 +29,6 @@ // only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB4.swiftdeps // RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output4 + +// CHECK-MAINAB-RECOMPILED: Queuing (initial): {compile: definesAB.o <= definesAB.swift} +// CHECK-MAINAB-RECOMPILED: Queuing because of dependencies discovered later: {compile: usesA.o <= usesA.swift} diff --git a/test/Frontend/PrivateFingerprints/enum-fingerprint.swift b/test/Frontend/PrivateFingerprints/enum-fingerprint.swift index 138d16f211a88..a56b2443890a6 100644 --- a/test/Frontend/PrivateFingerprints/enum-fingerprint.swift +++ b/test/Frontend/PrivateFingerprints/enum-fingerprint.swift @@ -1,48 +1,6 @@ - // Test per-type-body fingerprints for enums // -// ============================================================================= -// Without the fingerprints -// ============================================================================= - -// Establish status quo - - -// RUN: %empty-directory(%t) -// RUN: cp %S/Inputs/enum-fingerprint/* %t -// RUN: cp %t/definesAB{-before,}.swift - -// Seeing weird failure on CI, so set the mod times -// RUN: touch -t 200101010101 %t/*.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >&output1 - -// only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB1.swiftdeps - -// Change one type, but uses of all types get recompiled - -// RUN: cp %t/definesAB{-after,}.swift - -// Seeing weird failure on CI, so ensure that definesAB.swift is newer -// RUN: touch -t 200201010101 %t/* -// RUN: touch -t 200101010101 %t/*.swift -// RUN: touch -t 200301010101 %t/definesAB.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >&output2 - -// Save for debugging: -// only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB1.swiftdeps - -// RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output2 - -// CHECK-MAINAB-RECOMPILED: Queuing (initial): {compile: definesAB.o <= definesAB.swift} -// CHECK-MAINAB-RECOMPILED: Queuing because of dependencies discovered later: {compile: usesA.o <= usesA.swift} - -// ============================================================================= -// With the fingerprints -// ============================================================================= - // Establish status quo // RUN: %empty-directory(%t) @@ -71,3 +29,6 @@ // only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB4.swiftdeps // RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output4 + +// CHECK-MAINAB-RECOMPILED: Queuing (initial): {compile: definesAB.o <= definesAB.swift} +// CHECK-MAINAB-RECOMPILED: Queuing because of dependencies discovered later: {compile: usesA.o <= usesA.swift} diff --git a/test/Frontend/PrivateFingerprints/extension-adds-member.swift b/test/Frontend/PrivateFingerprints/extension-adds-member.swift index 63726480b3c37..73a8e650dd340 100644 --- a/test/Frontend/PrivateFingerprints/extension-adds-member.swift +++ b/test/Frontend/PrivateFingerprints/extension-adds-member.swift @@ -1,56 +1,9 @@ - // Test per-type-body fingerprints using simple extensions // // If the parser is allowed to use a body fingerprint for an extension // this test will fail because usesA.swift won't be recompiled for the // last step. - -// ============================================================================= -// Without the fingerprints -// ============================================================================= - -// Establish status quo - - -// RUN: %empty-directory(%t) -// RUN: cp %S/Inputs/extension-adds-member/* %t -// RUN: cp %t/definesAB{-before,}.swift - -// Seeing weird failure on CI, so set the mod times -// RUN: touch -t 200101010101 %t/*.swift - - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >& %t/output1 - - -// Change one type, but uses of all types get recompiled - -// RUN: cp %t/definesAB{-after,}.swift - -// Seeing weird failure on CI, so ensure that definesAB.swift is newer -// RUN: touch -t 200201010101 %t/* -// RUN: touch -t 200101010101 %t/*.swift -// RUN: touch -t 200301010101 %t/definesAB.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >& %t/output2 - - -// This test checks for the status quo; it would be OK to be more conservative - -// RUN: %FileCheck -check-prefix=CHECK-RECOMPILED-WO %s < %t/output2 -// CHECK-RECOMPILED-WO: {compile: definesAB.o <= definesAB.swift} -// CHECK-RECOMPILED-WO: {compile: usesA.o <= usesA.swift} -// CHECK-RECOMPILED-WO: {compile: usesB.o <= usesB.swift} - -// RUN: %FileCheck -check-prefix=CHECK-NOT-RECOMPILED-WO %s < %t/output2 -// CHECK-NOT-RECOMPILED-WO-NOT: {compile: main.o <= main.swift} - - -// ============================================================================= -// With the fingerprints -// ============================================================================= - // Establish status quo // RUN: %empty-directory(%t) diff --git a/test/Frontend/PrivateFingerprints/protocol-fingerprint.swift b/test/Frontend/PrivateFingerprints/protocol-fingerprint.swift index a48649f0b11ee..10c62c62ed6fb 100644 --- a/test/Frontend/PrivateFingerprints/protocol-fingerprint.swift +++ b/test/Frontend/PrivateFingerprints/protocol-fingerprint.swift @@ -1,48 +1,6 @@ - // Test per-type-body fingerprints: the protocol case. // -// ============================================================================= -// Without the fingerprints -// ============================================================================= - -// Establish status quo - - -// RUN: %empty-directory(%t) -// RUN: cp %S/Inputs/protocol-fingerprint/* %t -// RUN: cp %t/definesAB{-before,}.swift - -// Seeing weird failure on CI, so set the mod times -// RUN: touch -t 200101010101 %t/*.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >&output1 - -// only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB1.swiftdeps - -// Change one type, but uses of all types get recompiled - -// RUN: cp %t/definesAB{-after,}.swift - -// Seeing weird failure on CI, so ensure that definesAB.swift is newer -// RUN: touch -t 200201010101 %t/* -// RUN: touch -t 200101010101 %t/*.swift -// RUN: touch -t 200301010101 %t/definesAB.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >&output2 - -// Save for debugging: -// only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB1.swiftdeps - -// RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output2 - -// CHECK-MAINAB-RECOMPILED: Queuing (initial): {compile: definesAB.o <= definesAB.swift} -// CHECK-MAINAB-RECOMPILED: Queuing because of dependencies discovered later: {compile: usesA.o <= usesA.swift} - -// ============================================================================= -// With the fingerprints -// ============================================================================= - // Establish status quo // RUN: %empty-directory(%t) @@ -71,3 +29,6 @@ // only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB4.swiftdeps // RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output4 + +// CHECK-MAINAB-RECOMPILED: Queuing (initial): {compile: definesAB.o <= definesAB.swift} +// CHECK-MAINAB-RECOMPILED: Queuing because of dependencies discovered later: {compile: usesA.o <= usesA.swift} diff --git a/test/Frontend/PrivateFingerprints/struct-fingerprint.swift b/test/Frontend/PrivateFingerprints/struct-fingerprint.swift index a02cef5fd649e..1010e8fcc7eb2 100644 --- a/test/Frontend/PrivateFingerprints/struct-fingerprint.swift +++ b/test/Frontend/PrivateFingerprints/struct-fingerprint.swift @@ -1,48 +1,6 @@ - // Test per-type-body fingerprints for structs // -// ============================================================================= -// Without the fingerprints -// ============================================================================= - -// Establish status quo - - -// RUN: %empty-directory(%t) -// RUN: cp %S/Inputs/struct-fingerprint/* %t -// RUN: cp %t/definesAB{-before,}.swift - -// Seeing weird failure on CI, so set the mod times -// RUN: touch -t 200101010101 %t/*.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >&output1 - -// only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB1.swiftdeps - -// Change one type, but uses of all types get recompiled - -// RUN: cp %t/definesAB{-after,}.swift - -// Seeing weird failure on CI, so ensure that definesAB.swift is newer -// RUN: touch -t 200201010101 %t/* -// RUN: touch -t 200101010101 %t/*.swift -// RUN: touch -t 200301010101 %t/definesAB.swift - -// RUN: cd %t && %target-swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesAB.swift usesA.swift usesB.swift -module-name main -output-file-map ofm.json >&output2 - -// Save for debugging: -// only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB1.swiftdeps - -// RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output2 - -// CHECK-MAINAB-RECOMPILED: Queuing (initial): {compile: definesAB.o <= definesAB.swift} -// CHECK-MAINAB-RECOMPILED: Queuing because of dependencies discovered later: {compile: usesA.o <= usesA.swift} - -// ============================================================================= -// With the fingerprints -// ============================================================================= - // Establish status quo // RUN: %empty-directory(%t) @@ -71,3 +29,6 @@ // only-run-for-debugging: cp %t/usesB.swiftdeps %t/usesB4.swiftdeps // RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output4 + +// CHECK-MAINAB-RECOMPILED: Queuing (initial): {compile: definesAB.o <= definesAB.swift} +// CHECK-MAINAB-RECOMPILED: Queuing because of dependencies discovered later: {compile: usesA.o <= usesA.swift} diff --git a/test/InterfaceHash/added_method-type-fingerprints.swift b/test/InterfaceHash/added_method-type.swift similarity index 86% rename from test/InterfaceHash/added_method-type-fingerprints.swift rename to test/InterfaceHash/added_method-type.swift index 6776e086a7559..0f7eb261f21b3 100644 --- a/test/InterfaceHash/added_method-type-fingerprints.swift +++ b/test/InterfaceHash/added_method-type.swift @@ -8,10 +8,10 @@ // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s // RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main // RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps // RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main // RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps // RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs diff --git a/test/InterfaceHash/added_method.swift b/test/InterfaceHash/added_method.swift deleted file mode 100644 index 28dd75f2d4329..0000000000000 --- a/test/InterfaceHash/added_method.swift +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash - -// BEGIN a.swift -class C { - func f2() -> Int { - return 0 - } -} - -// BEGIN b.swift -class C { - func f2() -> Int { - return 0 - } - - func f3() -> Int { - return 1 - } -} diff --git a/test/InterfaceHash/added_private_class_private_property-type-fingerprints.swift b/test/InterfaceHash/added_private_class_private_property-type-fingerprints.swift deleted file mode 100644 index 5ba9627ce2731..0000000000000 --- a/test/InterfaceHash/added_private_class_private_property-type-fingerprints.swift +++ /dev/null @@ -1,53 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -private class C { - func f2() -> Int { - return 0 - } -} - -// BEGIN b.swift -private class C { - func f2() -> Int { - return 0 - } - - private var x: Int = 0 -} - -// Since C is a type or extension, the interface hash ought to not get the -// changed token hash. - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_class_private_property.swift b/test/InterfaceHash/added_private_class_private_property.swift index e3ca285b2cb10..dfa6721eface6 100644 --- a/test/InterfaceHash/added_private_class_private_property.swift +++ b/test/InterfaceHash/added_private_class_private_property.swift @@ -1,8 +1,17 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift private class C { @@ -19,3 +28,26 @@ private class C { private var x: Int = 0 } + +// Since C is a type or extension, the interface hash ought to not get the +// changed token hash. + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_class_property-type-fingerprints.swift b/test/InterfaceHash/added_private_class_property-type-fingerprints.swift deleted file mode 100644 index d087848dd323f..0000000000000 --- a/test/InterfaceHash/added_private_class_property-type-fingerprints.swift +++ /dev/null @@ -1,53 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -class C { - func f2() -> Int { - return 0 - } -} - -// BEGIN b.swift -class C { - func f2() -> Int { - return 0 - } - - private var x: Int = 0 -} - -// Since C is a type or extension, the interface hash ought to not get the -// changed token hash. - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_class_property.swift b/test/InterfaceHash/added_private_class_property.swift index cdeb03d8944a7..1734f85565ef4 100644 --- a/test/InterfaceHash/added_private_class_property.swift +++ b/test/InterfaceHash/added_private_class_property.swift @@ -1,8 +1,17 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift class C { @@ -19,3 +28,26 @@ class C { private var x: Int = 0 } + +// Since C is a type or extension, the interface hash ought to not get the +// changed token hash. + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_enum_private_property-type-fingerprints.swift b/test/InterfaceHash/added_private_enum_private_property-type-fingerprints.swift deleted file mode 100644 index ed898ffdce3d1..0000000000000 --- a/test/InterfaceHash/added_private_enum_private_property-type-fingerprints.swift +++ /dev/null @@ -1,56 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - - -// BEGIN a.swift -private enum A { - case x, y - func f2() -> Int { - return 0 - } -} - -// BEGIN b.swift -private enum A { - case x, y - func f2() -> Int { - return 0 - } - - var foo: Int { return 0 } -} - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_enum_private_property.swift b/test/InterfaceHash/added_private_enum_private_property.swift index a35d20b2928d0..078b78eef37ca 100644 --- a/test/InterfaceHash/added_private_enum_private_property.swift +++ b/test/InterfaceHash/added_private_enum_private_property.swift @@ -1,8 +1,21 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + // BEGIN a.swift private enum A { @@ -21,3 +34,23 @@ private enum A { var foo: Int { return 0 } } + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_enum_property-type-fingerprints.swift b/test/InterfaceHash/added_private_enum_property-type-fingerprints.swift deleted file mode 100644 index 0589feefd6214..0000000000000 --- a/test/InterfaceHash/added_private_enum_property-type-fingerprints.swift +++ /dev/null @@ -1,55 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -enum A { - case x, y - func f2() -> Int { - return 0 - } -} - -// BEGIN b.swift -enum A { - case x, y - func f2() -> Int { - return 0 - } - - private var foo: Int { return 0 } -} - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_enum_property.swift b/test/InterfaceHash/added_private_enum_property.swift index 370272d91d251..5993da28a924c 100644 --- a/test/InterfaceHash/added_private_enum_property.swift +++ b/test/InterfaceHash/added_private_enum_property.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift enum A { @@ -21,3 +33,23 @@ enum A { private var foo: Int { return 0 } } + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_method-type-fingerprints.swift b/test/InterfaceHash/added_private_method-type-fingerprints.swift deleted file mode 100644 index f6b8236e94b64..0000000000000 --- a/test/InterfaceHash/added_private_method-type-fingerprints.swift +++ /dev/null @@ -1,55 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -class C { - func f2() -> Int { - return 0 - } -} - -// BEGIN b.swift -class C { - func f2() -> Int { - return 0 - } - - private func f3() -> Int { - return 1 - } -} - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_method.swift b/test/InterfaceHash/added_private_method.swift index a07bed690cf16..77dcb2b0d2f68 100644 --- a/test/InterfaceHash/added_private_method.swift +++ b/test/InterfaceHash/added_private_method.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift class C { @@ -21,3 +33,23 @@ class C { return 1 } } + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_method_value_types-type-fingerprints.swift b/test/InterfaceHash/added_private_method_value_types-type-fingerprints.swift deleted file mode 100644 index 8499fbd0ea835..0000000000000 --- a/test/InterfaceHash/added_private_method_value_types-type-fingerprints.swift +++ /dev/null @@ -1,88 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -struct A { - func f2() -> Int { - return 0 - } -} - -enum B { - case x, y - func f2() -> Int { - return 0 - } -} - -// BEGIN b.swift -struct A { - func f2() -> Int { - return 0 - } - - private func f3() -> Int { - return 1 - } -} - -enum B { - case x, y - func f2() -> Int { - return 0 - } - - private func f3() -> Int { - return 1 - } -} - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' B true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' B true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' B true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' B true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1B{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1B{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1B{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1B{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1B{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1B{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1B{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1B{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_method_value_types.swift b/test/InterfaceHash/added_private_method_value_types.swift index 29ff2314d0c1e..e685f9da9afcd 100644 --- a/test/InterfaceHash/added_private_method_value_types.swift +++ b/test/InterfaceHash/added_private_method_value_types.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift struct A { @@ -39,3 +51,38 @@ enum B { return 1 } } + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' B true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' B true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' B true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' B true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1B{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1B{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_protocol_method-type-fingerprints.swift b/test/InterfaceHash/added_private_protocol_method-type-fingerprints.swift deleted file mode 100644 index f029cdb8b803d..0000000000000 --- a/test/InterfaceHash/added_private_protocol_method-type-fingerprints.swift +++ /dev/null @@ -1,50 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -private protocol P { - func f2() -> Int - var y: Int { get set } -} - -// BEGIN b.swift -private protocol P { - func f2() -> Int - func f3() -> Int - var y: Int { get set } -} - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' P true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' P true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' P true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' P true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1P{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1P{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_protocol_method.swift b/test/InterfaceHash/added_private_protocol_method.swift index 965c82b67af79..d7a03ef2dedd1 100644 --- a/test/InterfaceHash/added_private_protocol_method.swift +++ b/test/InterfaceHash/added_private_protocol_method.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift private protocol P { @@ -16,3 +28,23 @@ private protocol P { func f3() -> Int var y: Int { get set } } + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' P true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1P{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1P{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_protocol_property-type-fingerprints.swift b/test/InterfaceHash/added_private_protocol_property-type-fingerprints.swift deleted file mode 100644 index 4a51a0df7957b..0000000000000 --- a/test/InterfaceHash/added_private_protocol_property-type-fingerprints.swift +++ /dev/null @@ -1,50 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -private protocol P { - func f2() -> Int - var y: Int { get set } -} - -// BEGIN b.swift -private protocol P { - func f2() -> Int - var x: Int { get set } - var y: Int { get set } -} - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' P true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' P true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' P true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' P true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1P{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1P{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1P{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_protocol_property.swift b/test/InterfaceHash/added_private_protocol_property.swift index f47353d2d6521..ce76fffde3ff9 100644 --- a/test/InterfaceHash/added_private_protocol_property.swift +++ b/test/InterfaceHash/added_private_protocol_property.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift private protocol P { @@ -16,3 +28,23 @@ private protocol P { var x: Int { get set } var y: Int { get set } } + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' P true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1P{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1P{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_struct_private_property-type-fingerprints.swift b/test/InterfaceHash/added_private_struct_private_property-type-fingerprints.swift deleted file mode 100644 index b5d20cf3b317c..0000000000000 --- a/test/InterfaceHash/added_private_struct_private_property-type-fingerprints.swift +++ /dev/null @@ -1,56 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -struct S { - func f2() -> Int { - return 0 - } - - var y: Int = 0 -} - -// BEGIN b.swift -struct S { - func f2() -> Int { - return 0 - } - - private var x: Int = 0 - var y: Int = 0 -} - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' S true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' S true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' S true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' S true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1S{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1S{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_struct_private_property.swift b/test/InterfaceHash/added_private_struct_private_property.swift index 7bba778652d58..94efb4498aa36 100644 --- a/test/InterfaceHash/added_private_struct_private_property.swift +++ b/test/InterfaceHash/added_private_struct_private_property.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift struct S { @@ -22,3 +34,23 @@ struct S { private var x: Int = 0 var y: Int = 0 } + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' S true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1S{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1S{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_struct_property-type-fingerprints.swift b/test/InterfaceHash/added_private_struct_property-type-fingerprints.swift deleted file mode 100644 index f27418b9036ff..0000000000000 --- a/test/InterfaceHash/added_private_struct_property-type-fingerprints.swift +++ /dev/null @@ -1,56 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs - -// BEGIN a.swift -private struct S { - func f2() -> Int { - return 0 - } - - var y: Int = 0 -} - -// BEGIN b.swift -private struct S { - func f2() -> Int { - return 0 - } - - var x: Int = 0 - var y: Int = 0 -} - -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH -// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT - -// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' S true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' S true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' S true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' S true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1S{{[^ ]+}} '' true - -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1S{{[^ ]+}} '' true -// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1S{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_struct_property.swift b/test/InterfaceHash/added_private_struct_property.swift index 49e58b356b684..82611277f8d1c 100644 --- a/test/InterfaceHash/added_private_struct_property.swift +++ b/test/InterfaceHash/added_private_struct_property.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: not cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs // BEGIN a.swift private struct S { @@ -22,3 +34,23 @@ private struct S { var x: Int = 0 var y: Int = 0 } + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' S true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1S{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1S{{[^ ]+}} '' true diff --git a/test/InterfaceHash/edited_method_body-type-fingerprints.swift b/test/InterfaceHash/edited_method_body-type-fingerprints.swift deleted file mode 100644 index 726a36d8ba931..0000000000000 --- a/test/InterfaceHash/edited_method_body-type-fingerprints.swift +++ /dev/null @@ -1,31 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: cmp %t/{a,b}-processed.swiftdeps - -// BEGIN a.swift -class C { - func f2() -> Int { - return 0 - } -} - -// BEGIN b.swift -class C { - func f2() -> Int { - return 1 - } -} diff --git a/test/InterfaceHash/edited_method_body.swift b/test/InterfaceHash/edited_method_body.swift index b0aebce44e500..016a835646d1a 100644 --- a/test/InterfaceHash/edited_method_body.swift +++ b/test/InterfaceHash/edited_method_body.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: cmp %t/{a,b}-processed.swiftdeps // BEGIN a.swift class C { diff --git a/test/InterfaceHash/edited_property_getter-type-fingerprints.swift b/test/InterfaceHash/edited_property_getter-type-fingerprints.swift deleted file mode 100644 index 9024944bd865c..0000000000000 --- a/test/InterfaceHash/edited_property_getter-type-fingerprints.swift +++ /dev/null @@ -1,33 +0,0 @@ -// REQUIRES: shell -// Also uses awk: -// XFAIL OS=windows - -// When adding a private protocol method, the interface hash should stay the same -// The per-type fingerprint should change - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s -// RUN: cp %t/{a,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps -// RUN: cp %t/{b,x}.swift -// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main -// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps - -// RUN: cmp %t/{a,b}-processed.swiftdeps - -// BEGIN a.swift -class C { - var p: Int { - return 0 - } -} - -// BEGIN b.swift -class C { - var p: Int { - let x = 1 - return x - } -} - diff --git a/test/InterfaceHash/edited_property_getter.swift b/test/InterfaceHash/edited_property_getter.swift index deaeb8ccc08dc..05d99baac6493 100644 --- a/test/InterfaceHash/edited_property_getter.swift +++ b/test/InterfaceHash/edited_property_getter.swift @@ -1,8 +1,20 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash -// RUN: cmp %t/a.hash %t/b.hash +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh %swift-dependency-tool %t/x.swiftdeps %t/b-processed.swiftdeps + +// RUN: cmp %t/{a,b}-processed.swiftdeps // BEGIN a.swift class C { @@ -18,3 +30,4 @@ class C { return x } } + diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt index f045bc7fd8e6e..e9323a95c3c43 100644 --- a/unittests/Driver/CMakeLists.txt +++ b/unittests/Driver/CMakeLists.txt @@ -1,7 +1,6 @@ add_swift_unittest(SwiftDriverTests FineGrainedDependencyGraphTests.cpp MockingFineGrainedDependencyGraphs.cpp - TypeBodyFingerprintsDependencyGraphTests.cpp UnitTestSourceFileDepGraphFactory.cpp ) diff --git a/unittests/Driver/FineGrainedDependencyGraphTests.cpp b/unittests/Driver/FineGrainedDependencyGraphTests.cpp index becc5dd213d86..c0f49be7047d9 100644 --- a/unittests/Driver/FineGrainedDependencyGraphTests.cpp +++ b/unittests/Driver/FineGrainedDependencyGraphTests.cpp @@ -1,14 +1,33 @@ +//===--------------- FineGrainedDependencyGraphTests.cpp ------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + #include "MockingFineGrainedDependencyGraphs.h" #include "swift/Basic/ReferenceDependencyKeys.h" #include "swift/Driver/FineGrainedDependencyDriverGraph.h" #include "swift/Driver/Job.h" #include "gtest/gtest.h" -// A version of \c ModuleDepGraphTests.cpp that tests things with -// type-body fingerprints disabled. -// -// In order to get the test macros to work right, it seems that the tests -// must be copied-and-pasted, sigh. +// \c findJobsToRecompileWhenWholeJobChanges, +// \c findExternallyDependentUntracedJobs, and \c simulateReload +// may include jobs in their result that +// would be excluded in the coarse-grained graph. But since these will be jobs +// that have already been scheduled, downstream mechanisms will filter them out. + +// \c \c findExternallyDependentUntracedJobs may also return duplicates + +// To debug a test, create the \c ModuleDepGraph and pass true as the second +// argument to the constructor, then find the dot files in the directory +// where the tests run, +// and inspect them with, e.g. OmniGraffle. using namespace swift; using namespace fine_grained_dependencies; @@ -38,8 +57,8 @@ static bool contains(const Range &range, const T &value) { std::end(range); } -TEST(ModuleDepGraphWithoutFingerprints, BasicLoad) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, BasicLoad) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a->", "b->"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"c->", "d->"}}}); @@ -57,8 +76,8 @@ TEST(ModuleDepGraphWithoutFingerprints, BasicLoad) { {NodeKind::topLevel, {"b", "c", "d->", "a->"}}}); } -TEST(ModuleDepGraphWithoutFingerprints, IndependentNodes) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, IndependentNodes) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a0", "a->"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"b0", "b->"}}}); @@ -86,8 +105,8 @@ TEST(ModuleDepGraphWithoutFingerprints, IndependentNodes) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, IndependentDepKinds) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, IndependentDepKinds) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "a->"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"a", "b->"}}}); @@ -97,8 +116,8 @@ TEST(ModuleDepGraphWithoutFingerprints, IndependentDepKinds) { EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, IndependentDepKinds2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, IndependentDepKinds2) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a->", "b"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"b->", "a"}}}); @@ -108,8 +127,8 @@ TEST(ModuleDepGraphWithoutFingerprints, IndependentDepKinds2) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, IndependentMembers) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, IndependentMembers) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::member, {"a,aa"}}}); simulateLoad(graph, &job1, {{NodeKind::member, {"a,bb->"}}}); @@ -125,8 +144,8 @@ TEST(ModuleDepGraphWithoutFingerprints, IndependentMembers) { EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job4)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleDependent) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x->", "b->", "z->"}}}); @@ -143,8 +162,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleDependentReverse) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleDependentReverse) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a->", "b->", "c->"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x", "b", "z"}}}); @@ -166,8 +185,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleDependentReverse) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleDependent2) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "z->"}}}); @@ -185,8 +204,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent2) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent3) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleDependent3) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}, {NodeKind::topLevel, {"a"}}}); @@ -205,8 +224,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent3) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent4) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleDependent4) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); simulateLoad(graph, &job1, @@ -225,8 +244,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent4) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent5) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleDependent5) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}, {NodeKind::topLevel, {"a"}}}); @@ -247,8 +266,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent5) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent6) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleDependent6) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::dynamicLookup, {"a", "b", "c"}}}); simulateLoad(graph, &job1, @@ -266,8 +285,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleDependent6) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleDependentMember) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleDependentMember) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::member, {"a,aa", "b,bb", "c,cc"}}}); simulateLoad(graph, &job1, @@ -286,8 +305,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleDependentMember) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, MultipleDependentsSame) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MultipleDependentsSame) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "z->"}}}); @@ -309,8 +328,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MultipleDependentsSame) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, MultipleDependentsDifferent) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MultipleDependentsDifferent) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "z->"}}}); @@ -332,8 +351,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MultipleDependentsDifferent) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, ChainedDependents) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, ChainedDependents) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "z"}}}); @@ -355,8 +374,8 @@ TEST(ModuleDepGraphWithoutFingerprints, ChainedDependents) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, ChainedNoncascadingDependents) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, ChainedNoncascadingDependents) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "#z"}}}); @@ -378,8 +397,8 @@ TEST(ModuleDepGraphWithoutFingerprints, ChainedNoncascadingDependents) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, ChainedNoncascadingDependents2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, ChainedNoncascadingDependents2) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); simulateLoad( @@ -397,8 +416,8 @@ TEST(ModuleDepGraphWithoutFingerprints, ChainedNoncascadingDependents2) { EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, MarkTwoNodes) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MarkTwoNodes) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"a->", "z"}}}); @@ -435,8 +454,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MarkTwoNodes) { EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job12)); } -TEST(ModuleDepGraphWithoutFingerprints, MarkOneNodeTwice) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MarkOneNodeTwice) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); @@ -461,8 +480,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MarkOneNodeTwice) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, MarkOneNodeTwice2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MarkOneNodeTwice2) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); @@ -487,8 +506,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MarkOneNodeTwice2) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, ReloadDetectsChange) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, ReloadDetectsChange) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); @@ -514,8 +533,8 @@ TEST(ModuleDepGraphWithoutFingerprints, ReloadDetectsChange) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, NotTransitiveOnceMarked) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, NotTransitiveOnceMarked) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); @@ -542,8 +561,8 @@ TEST(ModuleDepGraphWithoutFingerprints, NotTransitiveOnceMarked) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, DependencyLoops) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, DependencyLoops) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c", "a->"}}}); simulateLoad(graph, &job1, @@ -569,8 +588,8 @@ TEST(ModuleDepGraphWithoutFingerprints, DependencyLoops) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); } -TEST(ModuleDepGraphWithoutFingerprints, MarkIntransitive) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MarkIntransitive) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x->", "b->", "z->"}}}); @@ -587,8 +606,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MarkIntransitive) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, MarkIntransitiveTwice) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MarkIntransitiveTwice) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x->", "b->", "z->"}}}); @@ -597,8 +616,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MarkIntransitiveTwice) { EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, MarkIntransitiveThenIndirect) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MarkIntransitiveThenIndirect) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x->", "b->", "z->"}}}); @@ -616,8 +635,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MarkIntransitiveThenIndirect) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleExternal) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleExternal) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::externalDepend, {"/foo->", "/bar->"}}}); @@ -637,8 +656,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleExternal) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); } -TEST(ModuleDepGraphWithoutFingerprints, SimpleExternal2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, SimpleExternal2) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::externalDepend, {"/foo->", "/bar->"}}}); @@ -650,8 +669,8 @@ TEST(ModuleDepGraphWithoutFingerprints, SimpleExternal2) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); } -TEST(ModuleDepGraphWithoutFingerprints, ChainedExternal) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, ChainedExternal) { + ModuleDepGraph graph; simulateLoad( graph, &job0, @@ -680,8 +699,8 @@ TEST(ModuleDepGraphWithoutFingerprints, ChainedExternal) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, ChainedExternalReverse) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, ChainedExternalReverse) { + ModuleDepGraph graph; simulateLoad( graph, &job0, @@ -711,8 +730,8 @@ TEST(ModuleDepGraphWithoutFingerprints, ChainedExternalReverse) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, ChainedExternalPreMarked) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, ChainedExternalPreMarked) { + ModuleDepGraph graph; simulateLoad( graph, &job0, @@ -731,8 +750,8 @@ TEST(ModuleDepGraphWithoutFingerprints, ChainedExternalPreMarked) { EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); } -TEST(ModuleDepGraphWithoutFingerprints, MutualInterfaceHash) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, MutualInterfaceHash) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b->"}}}); simulateLoad(graph, &job1, {{NodeKind::topLevel, {"a->", "b"}}}); @@ -740,8 +759,8 @@ TEST(ModuleDepGraphWithoutFingerprints, MutualInterfaceHash) { EXPECT_TRUE(contains(jobs, &job1)); } -TEST(ModuleDepGraphWithoutFingerprints, DisabledTypeBodyFingerprints) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, EnabledTypeBodyFingerprints) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"B2->"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "B2"}}}); @@ -756,8 +775,8 @@ TEST(ModuleDepGraphWithoutFingerprints, DisabledTypeBodyFingerprints) { } } -TEST(ModuleDepGraphWithoutFingerprints, BaselineForPrintsAndCrossType) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, BaselineForPrintsAndCrossType) { + ModuleDepGraph graph; // Because when A1 changes, B1 and not B2 is affected, only jobs1 and job2 // should be recompiled, except type fingerprints is off! @@ -778,16 +797,20 @@ TEST(ModuleDepGraphWithoutFingerprints, BaselineForPrintsAndCrossType) { } } -TEST(ModuleDepGraphWithoutFingerprints, LoadFailsWithFingerprint) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); - EXPECT_FALSE( +TEST(ModuleDepGraph, LoadPassesWithFingerprint) { + ModuleDepGraph graph; + EXPECT_TRUE( getChangesForSimulatedLoad(graph, &job0, {{NodeKind::nominal, {"A@1"}}})); } -TEST(ModuleDepGraphWithoutFingerprints, IgnoreFingerprints) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, UseFingerprints) { + ModuleDepGraph graph; - simulateLoad(graph, &job0, {{NodeKind::nominal, {"A1", "A2"}}}); + // Because when A1 changes, B1 and not B2 is affected, only jobs1 and job2 + // should be recompiled, except type fingerprints is off! + // Include a dependency on A1, to ensure it does not muck things up. + + simulateLoad(graph, &job0, {{NodeKind::nominal, {"A1@1", "A2@2", "A1->"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "A1->"}}}); simulateLoad(graph, &job2, {{NodeKind::nominal, {"C1", "A2->"}}}); simulateLoad(graph, &job3, {{NodeKind::nominal, {"D1"}}}); @@ -795,16 +818,16 @@ TEST(ModuleDepGraphWithoutFingerprints, IgnoreFingerprints) { { const auto jobs = simulateReload(graph, &job0, {{NodeKind::nominal, {"A1@11", "A2@2"}}}); - EXPECT_EQ(4u, jobs.size()); + EXPECT_EQ(3u, jobs.size()); EXPECT_TRUE(contains(jobs, &job0)); EXPECT_TRUE(contains(jobs, &job1)); EXPECT_TRUE(contains(jobs, &job2)); - EXPECT_TRUE(contains(jobs, &job3)); + EXPECT_FALSE(contains(jobs, &job3)); } } -TEST(ModuleDepGraphWithoutFingerprints, CrossTypeDependencyBaseline) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, CrossTypeDependencyBaseline) { + ModuleDepGraph graph; simulateLoad(graph, &job0, {{NodeKind::nominal, {"A"}}}); simulateLoad(graph, &job1, {{NodeKind::nominal, {"B", "C", "A->"}}}); simulateLoad(graph, &job2, {{NodeKind::nominal, {"B->"}}}); @@ -817,8 +840,8 @@ TEST(ModuleDepGraphWithoutFingerprints, CrossTypeDependencyBaseline) { EXPECT_TRUE(contains(jobs, &job3)); } -TEST(ModuleDepGraphWithoutFingerprints, CrossTypeDependency) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/false); +TEST(ModuleDepGraph, CrossTypeDependency) { + ModuleDepGraph graph; // Because of the cross-type dependency, A->B, // when A changes, only B is dirtied in job1. @@ -833,3 +856,48 @@ TEST(ModuleDepGraphWithoutFingerprints, CrossTypeDependency) { EXPECT_TRUE(contains(jobs, &job2)); EXPECT_FALSE(contains(jobs, &job3)); } + +TEST(ModuleDepGraph, CrossTypeDependencyBaselineWithFingerprints) { + ModuleDepGraph graph; + simulateLoad(graph, &job0, {{NodeKind::nominal, {"A1@1", "A2@2"}}}); + simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "C1", "A1->"}}}); + simulateLoad(graph, &job2, {{NodeKind::nominal, {"B1->"}}}); + simulateLoad(graph, &job3, {{NodeKind::nominal, {"C1->"}}}); + simulateLoad(graph, &job4, {{NodeKind::nominal, {"B2", "C2", "A2->"}}}); + simulateLoad(graph, &job5, {{NodeKind::nominal, {"B2->"}}}); + simulateLoad(graph, &job6, {{NodeKind::nominal, {"C2->"}}}); + + const auto jobs = + simulateReload(graph, &job0, {{NodeKind::nominal, {"A1@11", "A2@2"}}}); + EXPECT_TRUE(contains(jobs, &job0)); + EXPECT_TRUE(contains(jobs, &job1)); + EXPECT_TRUE(contains(jobs, &job2)); + EXPECT_TRUE(contains(jobs, &job3)); + EXPECT_FALSE(contains(jobs, &job4)); + EXPECT_FALSE(contains(jobs, &job5)); + EXPECT_FALSE(contains(jobs, &job6)); +} + +TEST(ModuleDepGraph, CrossTypeDependencyWithFingerprints) { + ModuleDepGraph graph; + // Because of the cross-type dependency, A->B, + // when A changes, only B is dirtied in job1. + + simulateLoad(graph, &job0, {{NodeKind::nominal, {"A1@1", "A2@2"}}}); + simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "C1", "A1->B1"}}}); + simulateLoad(graph, &job2, {{NodeKind::nominal, {"B1->"}}}); + simulateLoad(graph, &job3, {{NodeKind::nominal, {"C1->"}}}); + simulateLoad(graph, &job4, {{NodeKind::nominal, {"B2", "C2", "A2->B2"}}}); + simulateLoad(graph, &job5, {{NodeKind::nominal, {"B2->"}}}); + simulateLoad(graph, &job6, {{NodeKind::nominal, {"C2->"}}}); + + const auto jobs = + simulateReload(graph, &job0, {{NodeKind::nominal, {"A1@11", "A2@2"}}}); + EXPECT_TRUE(contains(jobs, &job0)); + EXPECT_TRUE(contains(jobs, &job1)); + EXPECT_TRUE(contains(jobs, &job2)); + EXPECT_FALSE(contains(jobs, &job3)); + EXPECT_FALSE(contains(jobs, &job4)); + EXPECT_FALSE(contains(jobs, &job5)); + EXPECT_FALSE(contains(jobs, &job6)); +} diff --git a/unittests/Driver/TypeBodyFingerprintsDependencyGraphTests.cpp b/unittests/Driver/TypeBodyFingerprintsDependencyGraphTests.cpp deleted file mode 100644 index 9e572b0c5fca4..0000000000000 --- a/unittests/Driver/TypeBodyFingerprintsDependencyGraphTests.cpp +++ /dev/null @@ -1,894 +0,0 @@ -#include "MockingFineGrainedDependencyGraphs.h" -#include "swift/Basic/ReferenceDependencyKeys.h" -#include "swift/Driver/FineGrainedDependencyDriverGraph.h" -#include "swift/Driver/Job.h" -#include "gtest/gtest.h" - -// This file adapts the unit tests from the older, coarse-grained, dependency -// graph to the new fine-grained graph. - -// \c findJobsToRecompileWhenWholeJobChanges, -// \c findExternallyDependentUntracedJobs, and \c simulateReload -// may include jobs in their result that -// would be excluded in the coarse-grained graph. But since these will be jobs -// that have already been scheduled, downstream mechanisms will filter them out. - -// \c \c findExternallyDependentUntracedJobs may also return duplicates - -// To debug a test, create the \c ModuleDepGraph and pass true as the second -// argument to the constructor, then find the dot files in the directory -// where the tests run, -// and inspect them with, e.g. OmniGraffle. - -using namespace swift; -using namespace fine_grained_dependencies; -using namespace mocking_fine_grained_dependency_graphs; -using Job = driver::Job; - -static OutputFileMap OFM; - -static Job - job0(OFM, "0"), - job1(OFM, "1"), - job2(OFM, "2"), - job3(OFM, "3"), - job4(OFM, "4"), - job5(OFM, "5"), - job6(OFM, "6"), - job7(OFM, "7"), - job8(OFM, "8"), - job9(OFM, "9"), - job10(OFM, "10"), - job11(OFM, "11"), - job12(OFM, "12"); - -template -static bool contains(const Range &range, const T &value) { - return std::find(std::begin(range), std::end(range), value) != - std::end(range); -} - -TEST(ModuleDepGraph, BasicLoad) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a->", "b->"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"c->", "d->"}}}); - simulateLoad(graph, &job2, {{NodeKind::topLevel, {"e", "f"}}}); - simulateLoad(graph, &job3, {{NodeKind::nominal, {"g", "h"}}}); - simulateLoad(graph, &job4, {{NodeKind::dynamicLookup, {"i", "j"}}}); - simulateLoad(graph, &job5, {{NodeKind::dynamicLookup, {"k->", "l->"}}}); - simulateLoad(graph, &job6, {{NodeKind::member, {"m,mm", "n,nn"}}}); - simulateLoad(graph, &job7, {{NodeKind::member, {"o,oo->", "p,pp->"}}}); - simulateLoad(graph, &job8, - {{NodeKind::externalDepend, {"/foo->", "/bar->"}}}); - - simulateLoad(graph, &job9, - {{NodeKind::nominal, {"a", "b", "c->", "d->"}}, - {NodeKind::topLevel, {"b", "c", "d->", "a->"}}}); -} - -TEST(ModuleDepGraph, IndependentNodes) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a0", "a->"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"b0", "b->"}}}); - simulateLoad(graph, &job2, {{NodeKind::topLevel, {"c0", "c->"}}}); - - EXPECT_EQ(1u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - // Mark 0 again -- should be no change. - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - EXPECT_EQ(1u, graph.findJobsToRecompileWhenWholeJobChanges(&job2).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - EXPECT_EQ(1u, graph.findJobsToRecompileWhenWholeJobChanges(&job1).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, IndependentDepKinds) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "a->"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"a", "b->"}}}); - - EXPECT_EQ(1u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, IndependentDepKinds2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a->", "b"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"b->", "a"}}}); - - EXPECT_EQ(1u, graph.findJobsToRecompileWhenWholeJobChanges(&job1).size()); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, IndependentMembers) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::member, {"a,aa"}}}); - simulateLoad(graph, &job1, {{NodeKind::member, {"a,bb->"}}}); - simulateLoad(graph, &job2, {{NodeKind::potentialMember, {"a"}}}); - simulateLoad(graph, &job3, {{NodeKind::member, {"b,aa->"}}}); - simulateLoad(graph, &job4, {{NodeKind::member, {"b,bb->"}}}); - - EXPECT_EQ(1u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job3)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job4)); -} - -TEST(ModuleDepGraph, SimpleDependent) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x->", "b->", "z->"}}}); - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, SimpleDependentReverse) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a->", "b->", "c->"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x", "b", "z"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job1); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job0)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - { - const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(1u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job0)); - } - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, SimpleDependent2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "z->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, SimpleDependent3) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, - {{NodeKind::nominal, {"a"}}, {NodeKind::topLevel, {"a"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, SimpleDependent4) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); - simulateLoad(graph, &job1, - {{NodeKind::nominal, {"a->"}}, {NodeKind::topLevel, {"a->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, SimpleDependent5) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, - {{NodeKind::nominal, {"a"}}, {NodeKind::topLevel, {"a"}}}); - simulateLoad(graph, &job1, - {{NodeKind::nominal, {"a->"}}, {NodeKind::topLevel, {"a->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, SimpleDependent6) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::dynamicLookup, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, - {{NodeKind::dynamicLookup, {"x->", "b->", "z->"}}}); - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, SimpleDependentMember) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::member, {"a,aa", "b,bb", "c,cc"}}}); - simulateLoad(graph, &job1, - {{NodeKind::member, {"x,xx->", "b,bb->", "z,zz->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, MultipleDependentsSame) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "z->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"q->", "b->", "s->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, MultipleDependentsDifferent) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "z->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"q->", "r->", "c->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, ChainedDependents) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "z"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"z->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, ChainedNoncascadingDependents) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"x->", "b->", "#z"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"#z->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - EXPECT_EQ(0u, graph.findJobsToRecompileWhenWholeJobChanges(&job0).size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, ChainedNoncascadingDependents2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); - simulateLoad( - graph, &job1, - {{NodeKind::topLevel, {"x->", "#b->"}}, {NodeKind::nominal, {"z"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"z->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, MarkTwoNodes) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"a->", "z"}}}); - simulateLoad(graph, &job2, {{NodeKind::topLevel, {"z->"}}}); - simulateLoad(graph, &job10, {{NodeKind::topLevel, {"y", "z", "q->"}}}); - simulateLoad(graph, &job11, {{NodeKind::topLevel, {"y->"}}}); - simulateLoad(graph, &job12, {{NodeKind::topLevel, {"q->", "q"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); //????? - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job10)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job11)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job12)); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job10); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job10)); - EXPECT_TRUE(contains(jobs, &job11)); - EXPECT_FALSE(contains(jobs, &job2)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job10)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job11)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job12)); -} - -TEST(ModuleDepGraph, MarkOneNodeTwice) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"b->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - { - auto jobs = simulateReload(graph, &job0, {{NodeKind::nominal, {"b"}}}); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, MarkOneNodeTwice2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"b->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - { - auto jobs = simulateReload(graph, &job0, {{NodeKind::nominal, {"a", "b"}}}); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, ReloadDetectsChange) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"b->"}}}); - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job1); - EXPECT_EQ(1u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - { - auto jobs = - simulateReload(graph, &job1, {{NodeKind::nominal, {"b", "a->"}}}); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, NotTransitiveOnceMarked) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"a"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"a->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"b->"}}}); - - { - const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job1); - EXPECT_EQ(1u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - { - const auto jobs = - simulateReload(graph, &job1, {{NodeKind::nominal, {"b", "a->"}}}); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, DependencyLoops) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c", "a->"}}}); - simulateLoad(graph, &job1, - {{NodeKind::topLevel, {"x", "x->", "b->", "z->"}}}); - simulateLoad(graph, &job2, {{NodeKind::topLevel, {"x->"}}}); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(0u, jobs.size()); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job2)); -} - -TEST(ModuleDepGraph, MarkIntransitive) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x->", "b->", "z->"}}}); - - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, MarkIntransitiveTwice) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x->", "b->", "z->"}}}); - - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, MarkIntransitiveThenIndirect) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b", "c"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"x->", "b->", "z->"}}}); - - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - { - auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, SimpleExternal) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, - {{NodeKind::externalDepend, {"/foo->", "/bar->"}}}); - - EXPECT_TRUE(contains(graph.getExternalDependencies(), "/foo")); - EXPECT_TRUE(contains(graph.getExternalDependencies(), "/bar")); - - { - auto jobs = graph.findExternallyDependentUntracedJobs("/foo"); - EXPECT_EQ(jobs.size(), 1u); - EXPECT_TRUE(contains(jobs, &job0)); - } - - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - - EXPECT_EQ(0u, graph.findExternallyDependentUntracedJobs("/foo").size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); -} - -TEST(ModuleDepGraph, SimpleExternal2) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, - {{NodeKind::externalDepend, {"/foo->", "/bar->"}}}); - - EXPECT_EQ(1u, graph.findExternallyDependentUntracedJobs("/bar").size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - - EXPECT_EQ(0u, graph.findExternallyDependentUntracedJobs("/bar").size()); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); -} - -TEST(ModuleDepGraph, ChainedExternal) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad( - graph, &job0, - {{NodeKind::externalDepend, {"/foo->"}}, {NodeKind::topLevel, {"a"}}}); - simulateLoad( - graph, &job1, - {{NodeKind::externalDepend, {"/bar->"}}, {NodeKind::topLevel, {"a->"}}}); - - EXPECT_TRUE(contains(graph.getExternalDependencies(), "/foo")); - EXPECT_TRUE(contains(graph.getExternalDependencies(), "/bar")); - - { - auto jobs = graph.findExternallyDependentUntracedJobs("/foo"); - EXPECT_EQ(jobs.size(), 2u); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - { - auto jobs = graph.findExternallyDependentUntracedJobs("/foo"); - EXPECT_EQ(jobs.size(), 0u); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, ChainedExternalReverse) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad( - graph, &job0, - {{NodeKind::externalDepend, {"/foo->"}}, {NodeKind::topLevel, {"a"}}}); - simulateLoad( - graph, &job1, - {{NodeKind::externalDepend, {"/bar->"}}, {NodeKind::topLevel, {"a->"}}}); - - { - auto jobs = graph.findExternallyDependentUntracedJobs("/bar"); - EXPECT_EQ(1u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - EXPECT_EQ(0u, graph.findExternallyDependentUntracedJobs("/bar").size()); - EXPECT_FALSE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); - - { - auto jobs = graph.findExternallyDependentUntracedJobs("/foo"); - EXPECT_EQ(1u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job0)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, ChainedExternalPreMarked) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad( - graph, &job0, - {{NodeKind::externalDepend, {"/foo->"}}, {NodeKind::topLevel, {"a"}}}); - simulateLoad( - graph, &job1, - {{NodeKind::externalDepend, {"/bar->"}}, {NodeKind::topLevel, {"a->"}}}); - - { - auto jobs = graph.findExternallyDependentUntracedJobs("/foo"); - EXPECT_EQ(2u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - } - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job0)); - EXPECT_TRUE(graph.haveAnyNodesBeenTraversedIn(&job1)); -} - -TEST(ModuleDepGraph, MutualInterfaceHash) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - simulateLoad(graph, &job0, {{NodeKind::topLevel, {"a", "b->"}}}); - simulateLoad(graph, &job1, {{NodeKind::topLevel, {"a->", "b"}}}); - - const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_TRUE(contains(jobs, &job1)); -} - -TEST(ModuleDepGraph, EnabledTypeBodyFingerprints) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"B2->"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "B2"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"B1->"}}}); - - { - const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job1); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - } -} - -TEST(ModuleDepGraph, BaselineForPrintsAndCrossType) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - // Because when A1 changes, B1 and not B2 is affected, only jobs1 and job2 - // should be recompiled, except type fingerprints is off! - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"A1", "A2"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "A1->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"C1", "A2->"}}}); - simulateLoad(graph, &job3, {{NodeKind::nominal, {"D1"}}}); - - { - const auto jobs = simulateReload( - graph, &job0, {{NodeKind::nominal, {"A1", "A2"}}}, "changed"); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - EXPECT_FALSE(contains(jobs, &job3)); - } -} - -TEST(ModuleDepGraph, LoadPassesWithFingerprint) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - EXPECT_TRUE( - getChangesForSimulatedLoad(graph, &job0, {{NodeKind::nominal, {"A@1"}}})); -} - -TEST(ModuleDepGraph, UseFingerprints) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - - // Because when A1 changes, B1 and not B2 is affected, only jobs1 and job2 - // should be recompiled, except type fingerprints is off! - // Include a dependency on A1, to ensure it does not muck things up. - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"A1@1", "A2@2", "A1->"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "A1->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"C1", "A2->"}}}); - simulateLoad(graph, &job3, {{NodeKind::nominal, {"D1"}}}); - - { - const auto jobs = - simulateReload(graph, &job0, {{NodeKind::nominal, {"A1@11", "A2@2"}}}); - EXPECT_EQ(3u, jobs.size()); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - EXPECT_FALSE(contains(jobs, &job3)); - } -} - -TEST(ModuleDepGraph, CrossTypeDependencyBaseline) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - simulateLoad(graph, &job0, {{NodeKind::nominal, {"A"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"B", "C", "A->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"B->"}}}); - simulateLoad(graph, &job3, {{NodeKind::nominal, {"C->"}}}); - - const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - EXPECT_TRUE(contains(jobs, &job3)); -} - -TEST(ModuleDepGraph, CrossTypeDependency) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - // Because of the cross-type dependency, A->B, - // when A changes, only B is dirtied in job1. - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"A"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"B", "C", "A->B"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"B->"}}}); - simulateLoad(graph, &job3, {{NodeKind::nominal, {"C->"}}}); - - const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - EXPECT_FALSE(contains(jobs, &job3)); -} - -TEST(ModuleDepGraph, CrossTypeDependencyBaselineWithFingerprints) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - simulateLoad(graph, &job0, {{NodeKind::nominal, {"A1@1", "A2@2"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "C1", "A1->"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"B1->"}}}); - simulateLoad(graph, &job3, {{NodeKind::nominal, {"C1->"}}}); - simulateLoad(graph, &job4, {{NodeKind::nominal, {"B2", "C2", "A2->"}}}); - simulateLoad(graph, &job5, {{NodeKind::nominal, {"B2->"}}}); - simulateLoad(graph, &job6, {{NodeKind::nominal, {"C2->"}}}); - - const auto jobs = - simulateReload(graph, &job0, {{NodeKind::nominal, {"A1@11", "A2@2"}}}); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - EXPECT_TRUE(contains(jobs, &job3)); - EXPECT_FALSE(contains(jobs, &job4)); - EXPECT_FALSE(contains(jobs, &job5)); - EXPECT_FALSE(contains(jobs, &job6)); -} - -TEST(ModuleDepGraph, CrossTypeDependencyWithFingerprints) { - ModuleDepGraph graph(/*EnableTypeFingerprints=*/true); - // Because of the cross-type dependency, A->B, - // when A changes, only B is dirtied in job1. - - simulateLoad(graph, &job0, {{NodeKind::nominal, {"A1@1", "A2@2"}}}); - simulateLoad(graph, &job1, {{NodeKind::nominal, {"B1", "C1", "A1->B1"}}}); - simulateLoad(graph, &job2, {{NodeKind::nominal, {"B1->"}}}); - simulateLoad(graph, &job3, {{NodeKind::nominal, {"C1->"}}}); - simulateLoad(graph, &job4, {{NodeKind::nominal, {"B2", "C2", "A2->B2"}}}); - simulateLoad(graph, &job5, {{NodeKind::nominal, {"B2->"}}}); - simulateLoad(graph, &job6, {{NodeKind::nominal, {"C2->"}}}); - - const auto jobs = - simulateReload(graph, &job0, {{NodeKind::nominal, {"A1@11", "A2@2"}}}); - EXPECT_TRUE(contains(jobs, &job0)); - EXPECT_TRUE(contains(jobs, &job1)); - EXPECT_TRUE(contains(jobs, &job2)); - EXPECT_FALSE(contains(jobs, &job3)); - EXPECT_FALSE(contains(jobs, &job4)); - EXPECT_FALSE(contains(jobs, &job5)); - EXPECT_FALSE(contains(jobs, &job6)); -} diff --git a/validation-test/Driver/Dependencies/rdar23148987-type-fingerprints.swift b/validation-test/Driver/Dependencies/rdar23148987-type-fingerprints.swift deleted file mode 100644 index 3eefcdd073ba8..0000000000000 --- a/validation-test/Driver/Dependencies/rdar23148987-type-fingerprints.swift +++ /dev/null @@ -1,61 +0,0 @@ -// RUN: %empty-directory(%t) - -// RUN: cp %s %t/main.swift -// RUN: cp %S/Inputs/rdar23148987/helper-1.swift %t/helper.swift -// RUN: touch -t 201401240005 %t/*.swift - -// RUN: cd %t && %target-build-swift -enable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1 %s - -// CHECK-1-NOT: warning -// CHECK-1: {{^{$}} -// CHECK-1: "kind": "began" -// CHECK-1: "name": "compile" -// CHECK-1: ".\/main.swift" -// CHECK-1: {{^}$}} - -// CHECK-1: {{^{$}} -// CHECK-1: "kind": "began" -// CHECK-1: "name": "compile" -// CHECK-1: ".\/helper.swift" -// CHECK-1: {{^}$}} - -// RUN: ls %t/ | %FileCheck -check-prefix=CHECK-LS %s - -// CHECK-LS-DAG: main.o -// CHECK-LS-DAG: helper.o - -// RUN: cd %t && %target-build-swift -enable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1-SKIPPED %s - -// CHECK-1-SKIPPED-NOT: warning -// CHECK-1-SKIPPED: {{^{$}} -// CHECK-1-SKIPPED: "kind": "skipped" -// CHECK-1-SKIPPED: "name": "compile" -// CHECK-1-SKIPPED: ".\/main.swift" -// CHECK-1-SKIPPED: {{^}$}} - -// CHECK-1-SKIPPED: {{^{$}} -// CHECK-1-SKIPPED: "kind": "skipped" -// CHECK-1-SKIPPED: "name": "compile" -// CHECK-1-SKIPPED: ".\/helper.swift" -// CHECK-1-SKIPPED: {{^}$}} - -// RUN: cp %S/Inputs/rdar23148987/helper-2.swift %t/helper.swift -// RUN: touch -t 201401240006 %t/helper.swift -// RUN: cd %t && %target-build-swift -enable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 -driver-show-incremental -driver-show-job-lifecycle | %FileCheck -check-prefix=CHECK-2 %s - -// CHECK-2-NOT: warning -// CHECK-2: {{^{$}} -// CHECK-2: "kind": "began" -// CHECK-2: "name": "compile" -// CHECK-2: ".\/helper.swift" -// CHECK-2: {{^}$}} - -// CHECK-2: {{^{$}} -// CHECK-2: "kind": "began" -// CHECK-2: "name": "compile" -// CHECK-2: ".\/main.swift" -// CHECK-2: {{^}$}} - -func test(obj: Test) { - obj.foo() -} diff --git a/validation-test/Driver/Dependencies/rdar23148987.swift b/validation-test/Driver/Dependencies/rdar23148987.swift index 7ff7bcae38369..35aa9e75d74b6 100644 --- a/validation-test/Driver/Dependencies/rdar23148987.swift +++ b/validation-test/Driver/Dependencies/rdar23148987.swift @@ -4,7 +4,7 @@ // RUN: cp %S/Inputs/rdar23148987/helper-1.swift %t/helper.swift // RUN: touch -t 201401240005 %t/*.swift -// RUN: cd %t && %target-build-swift -disable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1 %s +// RUN: cd %t && %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1 %s // CHECK-1-NOT: warning // CHECK-1: {{^{$}} @@ -24,7 +24,7 @@ // CHECK-LS-DAG: main.o // CHECK-LS-DAG: helper.o -// RUN: cd %t && %target-build-swift -disable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1-SKIPPED %s +// RUN: cd %t && %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1-SKIPPED %s // CHECK-1-SKIPPED-NOT: warning // CHECK-1-SKIPPED: {{^{$}} @@ -41,7 +41,7 @@ // RUN: cp %S/Inputs/rdar23148987/helper-2.swift %t/helper.swift // RUN: touch -t 201401240006 %t/helper.swift -// RUN: cd %t && %target-build-swift -disable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-2 %s +// RUN: cd %t && %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 -driver-show-incremental -driver-show-job-lifecycle | %FileCheck -check-prefix=CHECK-2 %s // CHECK-2-NOT: warning // CHECK-2: {{^{$}} From 964f640636d848318d35fc48e25df624a55fef91 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 1 Oct 2020 13:09:58 -0700 Subject: [PATCH 03/12] Drop "Private Deps" Flag In order for type body fingerprints to work, these declarations must always be included. Drop the ability to turn this off. --- .../AST/AbstractSourceFileDepGraphFactory.h | 7 +- include/swift/AST/Decl.h | 3 - include/swift/Basic/LangOptions.h | 5 - include/swift/Driver/Compilation.h | 8 - include/swift/Option/Options.td | 5 - lib/AST/AbstractSourceFileDepGraphFactory.cpp | 5 +- lib/AST/Decl.cpp | 23 --- lib/AST/FrontendSourceFileDepGraphFactory.cpp | 154 ++++-------------- lib/AST/FrontendSourceFileDepGraphFactory.h | 2 - lib/Driver/Compilation.cpp | 3 - lib/Driver/Driver.cpp | 3 - lib/Driver/ToolChains.cpp | 2 - lib/Frontend/CompilerInvocation.cpp | 3 - .../reference-dependencies-fine.swift | 5 +- .../reference-dependencies-members-fine.swift | 5 +- .../MockingFineGrainedDependencyGraphs.cpp | 12 +- .../MockingFineGrainedDependencyGraphs.h | 8 +- .../UnitTestSourceFileDepGraphFactory.cpp | 8 +- .../UnitTestSourceFileDepGraphFactory.h | 4 +- 19 files changed, 50 insertions(+), 215 deletions(-) diff --git a/include/swift/AST/AbstractSourceFileDepGraphFactory.h b/include/swift/AST/AbstractSourceFileDepGraphFactory.h index 80ed4122ec1b2..a0991efd8ad93 100644 --- a/include/swift/AST/AbstractSourceFileDepGraphFactory.h +++ b/include/swift/AST/AbstractSourceFileDepGraphFactory.h @@ -24,10 +24,6 @@ namespace fine_grained_dependencies { /// \c SourceFile or a unit test class AbstractSourceFileDepGraphFactory { protected: - /// To match the existing system, set this to false. - /// To include even private entities and get intra-file info, set to true. - const bool includePrivateDeps; - /// If there was an error, cannot get accurate info. const bool hadCompilationError; @@ -48,8 +44,7 @@ class AbstractSourceFileDepGraphFactory { public: /// Expose this layer to enable faking up a constructor for testing. /// See the instance variable comments for explanation. - AbstractSourceFileDepGraphFactory(bool includePrivateDeps, - bool hadCompilationError, + AbstractSourceFileDepGraphFactory(bool hadCompilationError, StringRef swiftDeps, StringRef fileFingerprint, bool emitDotFileAfterConstruction, diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 588ef350f497d..fe17f0cae96c8 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -948,9 +948,6 @@ class alignas(1 << DeclAlignInBits) Decl { /// If this returns true, the decl can be safely casted to ValueDecl. bool isPotentiallyOverridable() const; - /// Returns true if this Decl cannot be seen by any other source file - bool isPrivateToEnclosingFile() const; - /// If an alternative module name is specified for this decl, e.g. using /// @_originalDefinedIn attribute, this function returns this module name. StringRef getAlternateModuleName() const; diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index bd704cb29c4d9..5ee6f3e74e2fb 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -334,11 +334,6 @@ namespace swift { /// file. bool EmitFineGrainedDependencySourcefileDotFiles = false; - /// To mimic existing system, set to false. - /// To experiment with including file-private and private dependency info, - /// set to true. - bool FineGrainedDependenciesIncludeIntrafileOnes = false; - /// Whether to enable experimental differentiable programming features: /// `@differentiable` declaration attribute, etc. bool EnableExperimentalDifferentiableProgramming = false; diff --git a/include/swift/Driver/Compilation.h b/include/swift/Driver/Compilation.h index 5e6e1972f9dfd..6c75516c71e90 100644 --- a/include/swift/Driver/Compilation.h +++ b/include/swift/Driver/Compilation.h @@ -272,9 +272,6 @@ class Compilation { /// needed. const bool EmitFineGrainedDependencyDotFileAfterEveryImport; - /// Experiment with intrafile dependencies - const bool FineGrainedDependenciesIncludeIntrafileOnes; - /// Experiment with source-range-based dependencies const bool EnableSourceRangeDependencies; @@ -318,7 +315,6 @@ class Compilation { bool OnlyOneDependencyFile = false, bool VerifyFineGrainedDependencyGraphAfterEveryImport = false, bool EmitFineGrainedDependencyDotFileAfterEveryImport = false, - bool FineGrainedDependenciesIncludeIntrafileOnes = false, bool EnableSourceRangeDependencies = false, bool CompareIncrementalSchemes = false, StringRef CompareIncrementalSchemesPath = "", @@ -389,10 +385,6 @@ class Compilation { return EmitFineGrainedDependencyDotFileAfterEveryImport; } - bool getFineGrainedDependenciesIncludeIntrafileOnes() const { - return FineGrainedDependenciesIncludeIntrafileOnes; - } - bool getEnableSourceRangeDependencies() const { return EnableSourceRangeDependencies; } diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index d60baf2396495..7c80c7c03e68e 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -182,11 +182,6 @@ Flag<["-"], "driver-emit-fine-grained-dependency-dot-file-after-every-import">, InternalDebugOpt, HelpText<"Emit dot files every time driver imports an fine-grained swiftdeps file.">; -def fine_grained_dependency_include_intrafile : -Flag<["-"], "fine-grained-dependency-include-intrafile">, -Flags<[FrontendOption, HelpHidden]>, -HelpText<"Include within-file dependencies.">; - def emit_fine_grained_dependency_sourcefile_dot_files : Flag<["-"], "emit-fine-grained-dependency-sourcefile-dot-files">, Flags<[FrontendOption, HelpHidden]>, diff --git a/lib/AST/AbstractSourceFileDepGraphFactory.cpp b/lib/AST/AbstractSourceFileDepGraphFactory.cpp index 6a4ccfdf78ab6..b70ea103a4040 100644 --- a/lib/AST/AbstractSourceFileDepGraphFactory.cpp +++ b/lib/AST/AbstractSourceFileDepGraphFactory.cpp @@ -33,11 +33,10 @@ using namespace fine_grained_dependencies; //============================================================================== AbstractSourceFileDepGraphFactory::AbstractSourceFileDepGraphFactory( - bool includePrivateDeps, bool hadCompilationError, StringRef swiftDeps, + bool hadCompilationError, StringRef swiftDeps, StringRef fileFingerprint, bool emitDotFileAfterConstruction, DiagnosticEngine &diags) - : includePrivateDeps(includePrivateDeps), - hadCompilationError(hadCompilationError), swiftDeps(swiftDeps.str()), + : hadCompilationError(hadCompilationError), swiftDeps(swiftDeps.str()), fileFingerprint(fileFingerprint.str()), emitDotFileAfterConstruction(emitDotFileAfterConstruction), diags(diags) { } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index a330b63faedcb..2aa5a8f9700b6 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8098,26 +8098,3 @@ void swift::simple_display(llvm::raw_ostream &out, AnyFunctionRef fn) { else out << "closure"; } - -bool Decl::isPrivateToEnclosingFile() const { - if (auto *VD = dyn_cast(this)) - return VD->getFormalAccess() <= AccessLevel::FilePrivate; - switch (getKind()) { - case DeclKind::Import: - case DeclKind::PatternBinding: - case DeclKind::EnumCase: - case DeclKind::TopLevelCode: - case DeclKind::IfConfig: - case DeclKind::PoundDiagnostic: - return true; - - case DeclKind::Extension: - case DeclKind::InfixOperator: - case DeclKind::PrefixOperator: - case DeclKind::PostfixOperator: - return false; - - default: - llvm_unreachable("everything else is a ValueDecl"); - } -} diff --git a/lib/AST/FrontendSourceFileDepGraphFactory.cpp b/lib/AST/FrontendSourceFileDepGraphFactory.cpp index c89e1e0318e98..5ca65c70fb870 100644 --- a/lib/AST/FrontendSourceFileDepGraphFactory.cpp +++ b/lib/AST/FrontendSourceFileDepGraphFactory.cpp @@ -65,50 +65,6 @@ static std::string mangleTypeAsContext(const NominalTypeDecl *NTD) { return !NTD ? "" : Mangler.mangleTypeAsContextUSR(NTD); } -//============================================================================== -// MARK: Privacy queries -//============================================================================== - -/// Return true if \ref ED does not contain a member that can affect other -/// files. -static bool allMembersArePrivate(const ExtensionDecl *ED) { - return std::all_of( - ED->getMembers().begin(), ED->getMembers().end(), - [](const Decl *d) { return d->isPrivateToEnclosingFile(); }); -} - -/// \ref inheritedType, an inherited protocol, return true if this inheritance -/// cannot affect other files. -static bool extendedTypeIsPrivate(TypeLoc inheritedType) { - auto type = inheritedType.getType(); - if (!type) - return true; - - if (!type->isExistentialType()) { - // Be conservative. We don't know how to deal with other extended types. - return false; - } - - auto layout = type->getExistentialLayout(); - assert(!layout.explicitSuperclass && - "Should not have a subclass existential " - "in the inheritance clause of an extension"); - for (auto protoTy : layout.getProtocols()) { - if (!protoTy->getDecl()->isPrivateToEnclosingFile()) - return false; - } - - return true; -} - -/// Return true if \ref ED does not inherit a protocol that can affect other -/// files. Was called "justMembers" in ReferenceDependencies.cpp -/// \ref ED might be null. -static bool allInheritedProtocolsArePrivate(const ExtensionDecl *ED) { - return std::all_of(ED->getInherited().begin(), ED->getInherited().end(), - extendedTypeIsPrivate); -} - //============================================================================== // MARK: DependencyKey - creation for Decls //============================================================================== @@ -262,24 +218,11 @@ FrontendSourceFileDepGraphFactory::FrontendSourceFileDepGraphFactory( SourceFile *SF, StringRef outputPath, const DependencyTracker &depTracker, const bool alsoEmitDotFile) : AbstractSourceFileDepGraphFactory( - computeIncludePrivateDeps(SF), SF->getASTContext().hadError(), + SF->getASTContext().hadError(), outputPath, getInterfaceHash(SF), alsoEmitDotFile, SF->getASTContext().Diags), SF(SF), depTracker(depTracker) {} -bool FrontendSourceFileDepGraphFactory::computeIncludePrivateDeps( - SourceFile *SF) { - // Since, when fingerprints are enabled, - // the parser diverts token hashing into per-body fingerprints - // before it can know if a difference is in a private type, - // in order to be able to test the changed fingerprints - // we force the inclusion of private declarations when fingerprints - // are enabled. - return SF->getASTContext() - .LangOpts.FineGrainedDependenciesIncludeIntrafileOnes || - SF->getASTContext().LangOpts.EnableTypeFingerprints; -} - /// Centralize the invariant that the fingerprint of the whole file is the /// interface hash std::string FrontendSourceFileDepGraphFactory::getFingerprint(SourceFile *SF) { @@ -297,10 +240,6 @@ namespace { /// Takes all the Decls in a SourceFile, and collects them into buckets by /// groups of DeclKinds. Also casts them to more specific types struct DeclFinder { - /// Existing system excludes private decls in some cases. - /// In the future, we might not want to do this, so use bool to decide. - const bool includePrivateDecls; - // The extracted Decls: ConstPtrVec extensions; ConstPtrVec operators; @@ -319,19 +258,17 @@ struct DeclFinder { /// Construct me and separates the Decls. // clang-format off DeclFinder(ArrayRef topLevelDecls, - const bool includePrivateDecls, - LookupClassMember lookupClassMember) - : includePrivateDecls(includePrivateDecls) { + LookupClassMember lookupClassMember) { for (const Decl *const D : topLevelDecls) { - select(D, extensions, false) || + select(D, extensions) || select(D, operators, false) || + DeclKind::PostfixOperator>(D, operators) || select( - D, precedenceGroups, false) || + D, precedenceGroups) || select(D, topNominals, true) || + DeclKind::Class, DeclKind::Protocol>(D, topNominals) || select(D, topValues, true); + DeclKind::Accessor>(D, topValues); } // clang-format on // The order is important because some of these use instance variables @@ -360,18 +297,7 @@ struct DeclFinder { /// (indirectly recursive) void findNominalsAndOperatorsIn(const NominalTypeDecl *const NTD, const ExtensionDecl *ED = nullptr) { - if (excludeIfPrivate(NTD)) - return; - const bool exposedProtocolIsExtended = - ED && !allInheritedProtocolsArePrivate(ED); - if (ED && !includePrivateDecls && !exposedProtocolIsExtended && - std::all_of( - ED->getMembers().begin(), ED->getMembers().end(), - [&](const Decl *D) { return D->isPrivateToEnclosingFile(); })) { - return; - } - if (includePrivateDecls || !ED || exposedProtocolIsExtended) - allNominals.push_back(NTD); + allNominals.push_back(NTD); potentialMemberHolders.push_back(NTD); findNominalsAndOperatorsInMembers(ED ? ED->getMembers() : NTD->getMembers()); @@ -383,7 +309,7 @@ struct DeclFinder { void findNominalsAndOperatorsInMembers(const DeclRange members) { for (const Decl *const D : members) { auto *VD = dyn_cast(D); - if (!VD || excludeIfPrivate(VD)) + if (!VD) continue; if (VD->getName().isOperator()) memberOperatorDecls.push_back(cast(D)); @@ -396,19 +322,20 @@ struct DeclFinder { void findValuesInExtensions() { for (const auto *ED : extensions) { const auto *const NTD = ED->getExtendedNominal(); - if (!NTD || excludeIfPrivate(NTD)) + if (!NTD) { continue; - if (!includePrivateDecls && - (!allInheritedProtocolsArePrivate(ED) || allMembersArePrivate(ED))) - continue; - for (const auto *member : ED->getMembers()) - if (const auto *VD = dyn_cast(member)) - if (VD->hasName() && - (includePrivateDecls || !VD->isPrivateToEnclosingFile())) { - const auto *const NTD = ED->getExtendedNominal(); - if (NTD) - valuesInExtensions.push_back(std::make_pair(NTD, VD)); - } + } + + for (const auto *member : ED->getMembers()) { + const auto *VD = dyn_cast(member); + if (!VD || !VD->hasName()) { + continue; + } + + if (const auto *const NTD = ED->getExtendedNominal()) { + valuesInExtensions.push_back(std::make_pair(NTD, VD)); + } + } } } @@ -431,30 +358,19 @@ struct DeclFinder { /// \returns true if successful. template - bool select(const Decl *const D, ConstPtrVec &foundDecls, - const bool canExcludePrivateDecls) { + bool select(const Decl *const D, ConstPtrVec &foundDecls) { if (D->getKind() == firstKind) { - auto *dd = cast(D); - const bool exclude = canExcludePrivateDecls && excludeIfPrivate(dd); - if (!exclude) - foundDecls.push_back(cast(D)); + foundDecls.push_back(cast(D)); return true; } - return select(D, foundDecls, - canExcludePrivateDecls); + return select(D, foundDecls); } /// Terminate the template recursion. template - bool select(const Decl *const D, ConstPtrVec &foundDecls, - bool) { + bool select(const Decl *const D, ConstPtrVec &foundDecls) { return false; } - - /// Return true if \param D should be excluded on privacy grounds. - bool excludeIfPrivate(const Decl *const D) { - return !includePrivateDecls && D->isPrivateToEnclosingFile(); - } }; } // namespace @@ -464,7 +380,7 @@ void FrontendSourceFileDepGraphFactory::addAllDefinedDecls() { // Many kinds of Decls become top-level depends. - DeclFinder declFinder(SF->getTopLevelDecls(), includePrivateDeps, + DeclFinder declFinder(SF->getTopLevelDecls(), [this](VisibleDeclConsumer &consumer) { SF->lookupClassMembers({}, consumer); }); @@ -513,14 +429,11 @@ class UsedDeclEnumerator { const DependencyKey sourceFileInterface; const DependencyKey sourceFileImplementation; - const bool includeIntrafileDeps; - function_ref createDefUse; public: UsedDeclEnumerator( SourceFile *SF, const DependencyTracker &depTracker, StringRef swiftDeps, - bool includeIntrafileDeps, function_ref createDefUse) : SF(SF), depTracker(depTracker), swiftDeps(swiftDeps), @@ -528,7 +441,7 @@ class UsedDeclEnumerator { DeclAspect::interface, swiftDeps)), sourceFileImplementation(DependencyKey::createKeyForWholeSourceFile( DeclAspect::implementation, swiftDeps)), - includeIntrafileDeps(includeIntrafileDeps), createDefUse(createDefUse) { + createDefUse(createDefUse) { } public: @@ -581,11 +494,6 @@ class UsedDeclEnumerator { return; } - bool isPrivate = subject->isPrivateToEnclosingFile(); - if (isPrivate && !includeIntrafileDeps) { - return; - } - std::string context = DependencyKey::computeContextForProvidedEntity( subject); @@ -604,7 +512,7 @@ class UsedDeclEnumerator { } // end namespace void FrontendSourceFileDepGraphFactory::addAllUsedDecls() { - UsedDeclEnumerator(SF, depTracker, swiftDeps, includePrivateDeps, + UsedDeclEnumerator(SF, depTracker, swiftDeps, [&](const DependencyKey &def, const DependencyKey &use) { addAUsedDecl(def, use); }) @@ -644,7 +552,7 @@ FrontendSourceFileDepGraphFactory::getFingerprintIfAny(const Decl *d) { ModuleDepGraphFactory::ModuleDepGraphFactory(ModuleDecl *Mod, bool emitDot) : AbstractSourceFileDepGraphFactory( - /*include private*/ true, Mod->getASTContext().hadError(), + Mod->getASTContext().hadError(), Mod->getNameStr(), "0xBADBEEF", emitDot, Mod->getASTContext().Diags), Mod(Mod) {} @@ -656,7 +564,7 @@ void ModuleDepGraphFactory::addAllDefinedDecls() { SmallVector TopLevelDecls; Mod->getTopLevelDecls(TopLevelDecls); - DeclFinder declFinder(TopLevelDecls, includePrivateDeps, + DeclFinder declFinder(TopLevelDecls, [this](VisibleDeclConsumer &consumer) { return Mod->lookupClassMembers({}, consumer); }); diff --git a/lib/AST/FrontendSourceFileDepGraphFactory.h b/lib/AST/FrontendSourceFileDepGraphFactory.h index 898357f72117f..6b2740f54baf2 100644 --- a/lib/AST/FrontendSourceFileDepGraphFactory.h +++ b/lib/AST/FrontendSourceFileDepGraphFactory.h @@ -35,8 +35,6 @@ class FrontendSourceFileDepGraphFactory private: static std::string getFingerprint(SourceFile *SF); - - static bool computeIncludePrivateDeps(SourceFile *SF); static std::string getInterfaceHash(SourceFile *SF); void addAllDefinedDecls() override; diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 31f3d0ce4f1dd..11332f958b731 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -123,7 +123,6 @@ Compilation::Compilation(DiagnosticEngine &Diags, bool OnlyOneDependencyFile, bool VerifyFineGrainedDependencyGraphAfterEveryImport, bool EmitFineGrainedDependencyDotFileAfterEveryImport, - bool FineGrainedDependenciesIncludeIntrafileOnes, bool EnableSourceRangeDependencies, bool CompareIncrementalSchemes, StringRef CompareIncrementalSchemesPath, @@ -152,8 +151,6 @@ Compilation::Compilation(DiagnosticEngine &Diags, VerifyFineGrainedDependencyGraphAfterEveryImport), EmitFineGrainedDependencyDotFileAfterEveryImport( EmitFineGrainedDependencyDotFileAfterEveryImport), - FineGrainedDependenciesIncludeIntrafileOnes( - FineGrainedDependenciesIncludeIntrafileOnes), EnableSourceRangeDependencies(EnableSourceRangeDependencies), EnableCrossModuleIncrementalBuild(EnableCrossModuleIncrementalBuild) { diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 783d297595fb6..ed09cf7bb028e 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1020,8 +1020,6 @@ Driver::buildCompilation(const ToolChain &TC, const bool EmitFineGrainedDependencyDotFileAfterEveryImport = ArgList->hasArg( options:: OPT_driver_emit_fine_grained_dependency_dot_file_after_every_import); - const bool FineGrainedDependenciesIncludeIntrafileOnes = - ArgList->hasArg(options::OPT_fine_grained_dependency_include_intrafile); const bool EnableCrossModuleDependencies = ArgList->hasArg( options::OPT_enable_experimental_cross_module_incremental_build); @@ -1047,7 +1045,6 @@ Driver::buildCompilation(const ToolChain &TC, OnlyOneDependencyFile, VerifyFineGrainedDependencyGraphAfterEveryImport, EmitFineGrainedDependencyDotFileAfterEveryImport, - FineGrainedDependenciesIncludeIntrafileOnes, EnableSourceRangeDependencies, CompareIncrementalSchemes, CompareIncrementalSchemesPath, diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index a03ea4fe52e9f..2ff01dd73b4fa 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -259,8 +259,6 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_O_Group); inputArgs.AddLastArg(arguments, options::OPT_RemoveRuntimeAsserts); inputArgs.AddLastArg(arguments, options::OPT_AssumeSingleThreaded); - inputArgs.AddLastArg(arguments, - options::OPT_fine_grained_dependency_include_intrafile); inputArgs.AddLastArg(arguments, options::OPT_emit_fine_grained_dependency_sourcefile_dot_files); inputArgs.AddLastArg(arguments, options::OPT_package_description_version); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 2c8f39248235c..3d0f6a6180bb1 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -441,9 +441,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_emit_fine_grained_dependency_sourcefile_dot_files)) Opts.EmitFineGrainedDependencySourcefileDotFiles = true; - if (Args.hasArg(OPT_fine_grained_dependency_include_intrafile)) - Opts.FineGrainedDependenciesIncludeIntrafileOnes = true; - if (Args.hasArg(OPT_enable_experimental_additive_arithmetic_derivation)) Opts.EnableExperimentalAdditiveArithmeticDerivedConformances = true; diff --git a/test/Incremental/Dependencies/reference-dependencies-fine.swift b/test/Incremental/Dependencies/reference-dependencies-fine.swift index 3c76ee51fa7a1..e2fba6628bf13 100644 --- a/test/Incremental/Dependencies/reference-dependencies-fine.swift +++ b/test/Incremental/Dependencies/reference-dependencies-fine.swift @@ -5,10 +5,9 @@ // RUN: %empty-directory(%t) // RUN: cp %s %t/main.swift -// Need -fine-grained-dependency-include-intrafile to be invarient wrt type-body-fingerprints enabled/disabled -// RUN: %target-swift-frontend -fine-grained-dependency-include-intrafile -typecheck -primary-file %t/main.swift %S/../Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps // Check that the output is deterministic. -// RUN: %target-swift-frontend -fine-grained-dependency-include-intrafile -typecheck -primary-file %t/main.swift %S/../Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t-2.swiftdeps +// RUN: %target-swift-frontend -typecheck -primary-file %t/main.swift %S/../Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps +// RUN: %target-swift-frontend -typecheck -primary-file %t/main.swift %S/../Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t-2.swiftdeps // Merge each entry onto one line and sort to overcome order differences // RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh %swift-dependency-tool %t.swiftdeps %t-processed.swiftdeps diff --git a/test/Incremental/Dependencies/reference-dependencies-members-fine.swift b/test/Incremental/Dependencies/reference-dependencies-members-fine.swift index 01e06c2dc6cb7..0fec187e1d91d 100644 --- a/test/Incremental/Dependencies/reference-dependencies-members-fine.swift +++ b/test/Incremental/Dependencies/reference-dependencies-members-fine.swift @@ -5,10 +5,9 @@ // RUN: %empty-directory(%t) // RUN: cp %s %t/main.swift -// Need -fine-grained-dependency-include-intrafile to be invarient wrt type-body-fingerprints enabled/disabled -// RUN: %target-swift-frontend -fine-grained-dependency-include-intrafile -typecheck -primary-file %t/main.swift %S/../Inputs/reference-dependencies-members-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps +// RUN: %target-swift-frontend -typecheck -primary-file %t/main.swift %S/../Inputs/reference-dependencies-members-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps -// RUN: %target-swift-frontend -fine-grained-dependency-include-intrafile -typecheck -primary-file %t/main.swift %S/../Inputs/reference-dependencies-members-helper.swift -emit-reference-dependencies-path - > %t-2.swiftdeps +// RUN: %target-swift-frontend -typecheck -primary-file %t/main.swift %S/../Inputs/reference-dependencies-members-helper.swift -emit-reference-dependencies-path - > %t-2.swiftdeps // RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh %swift-dependency-tool %t.swiftdeps %t-processed.swiftdeps // RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh %swift-dependency-tool %t-2.swiftdeps %t-2-processed.swiftdeps diff --git a/unittests/Driver/MockingFineGrainedDependencyGraphs.cpp b/unittests/Driver/MockingFineGrainedDependencyGraphs.cpp index 6ac82c50d45f2..549e3cb4af234 100644 --- a/unittests/Driver/MockingFineGrainedDependencyGraphs.cpp +++ b/unittests/Driver/MockingFineGrainedDependencyGraphs.cpp @@ -26,11 +26,11 @@ using namespace mocking_fine_grained_dependency_graphs; void mocking_fine_grained_dependency_graphs::simulateLoad( ModuleDepGraph &g, const driver::Job *cmd, const DependencyDescriptions &dependencyDescriptions, - StringRef interfaceHashIfNonEmpty, const bool includePrivateDeps, + StringRef interfaceHashIfNonEmpty, const bool hadCompilationError) { const auto changes = getChangesForSimulatedLoad( g, cmd, dependencyDescriptions, interfaceHashIfNonEmpty, - includePrivateDeps, hadCompilationError); + hadCompilationError); assert(changes && "simulated load should always succeed"); } @@ -38,7 +38,7 @@ ModuleDepGraph::Changes mocking_fine_grained_dependency_graphs::getChangesForSimulatedLoad( ModuleDepGraph &g, const driver::Job *cmd, const DependencyDescriptions &dependencyDescriptions, - StringRef interfaceHashIfNonEmpty, const bool includePrivateDeps, + StringRef interfaceHashIfNonEmpty, const bool hadCompilationError) { StringRef swiftDeps = cmd->getOutput().getAdditionalOutputForType(file_types::TY_SwiftDeps); @@ -51,7 +51,7 @@ mocking_fine_grained_dependency_graphs::getChangesForSimulatedLoad( auto sfdg = UnitTestSourceFileDepGraphFactory( - includePrivateDeps, hadCompilationError, swiftDeps, interfaceHash, + hadCompilationError, swiftDeps, interfaceHash, g.emitFineGrainedDependencyDotFileAfterEveryImport, dependencyDescriptions, diags) .construct(); @@ -63,11 +63,11 @@ std::vector mocking_fine_grained_dependency_graphs::simulateReload( ModuleDepGraph &g, const driver::Job *cmd, const DependencyDescriptions &dependencyDescriptions, - StringRef interfaceHashIfNonEmpty, const bool includePrivateDeps, + StringRef interfaceHashIfNonEmpty, const bool hadCompilationError) { const auto changedNodes = getChangesForSimulatedLoad( g, cmd, dependencyDescriptions, interfaceHashIfNonEmpty, - includePrivateDeps, hadCompilationError); + hadCompilationError); if (!changedNodes) return g.getAllJobs(); return g.findJobsToRecompileWhenNodesChange(changedNodes.getValue()); diff --git a/unittests/Driver/MockingFineGrainedDependencyGraphs.h b/unittests/Driver/MockingFineGrainedDependencyGraphs.h index 0bb5e298355b9..2bd042006bce1 100644 --- a/unittests/Driver/MockingFineGrainedDependencyGraphs.h +++ b/unittests/Driver/MockingFineGrainedDependencyGraphs.h @@ -35,9 +35,8 @@ namespace mocking_fine_grained_dependency_graphs { /// \param cmd The \c Job whose dependency info will be loaded. /// \param dependencyDescriptions Dependency info, see below /// \param interfaceHashIfNonEmpty If non-empty, overrides the default simulated -/// interface hash \param includePrivateDeps Include file-private declarations -/// in the dependency information. \param hadCompilationError Simulate a -/// compilation error. +/// in the dependency information. +/// \param hadCompilationError Simulate a compilation error. /// /// Fails an assertion if the information is not valid (for instance a /// fingerprint where it should not be). @@ -68,7 +67,6 @@ namespace mocking_fine_grained_dependency_graphs { void simulateLoad(ModuleDepGraph &g, const driver::Job *cmd, const DependencyDescriptions &dependencyDescriptions, StringRef interfaceHashIfNonEmpty = StringRef(), - const bool includePrivateDeps = true, const bool hadCompilationError = false); /// Same as \ref simulateLoad, but returns the specifically changed nodes or @@ -78,7 +76,6 @@ ModuleDepGraph::Changes getChangesForSimulatedLoad(ModuleDepGraph &g, const driver::Job *cmd, const DependencyDescriptions &dependencyDescriptions, StringRef interfaceHashIfNonEmpty = StringRef(), - const bool includePrivateDeps = true, const bool hadCompilationError = false); /// Simulates the driver reloading a swiftdeps file after a job has run. @@ -91,7 +88,6 @@ std::vector simulateReload(ModuleDepGraph &g, const driver::Job *cmd, const DependencyDescriptions &dependencyDescriptions, StringRef interfaceHashIfNonEmpty = StringRef(), - const bool includePrivateDeps = true, const bool hadCompilationError = false); std::vector diff --git a/unittests/Driver/UnitTestSourceFileDepGraphFactory.cpp b/unittests/Driver/UnitTestSourceFileDepGraphFactory.cpp index 34047395b1411..50cce1c47a95c 100644 --- a/unittests/Driver/UnitTestSourceFileDepGraphFactory.cpp +++ b/unittests/Driver/UnitTestSourceFileDepGraphFactory.cpp @@ -104,9 +104,7 @@ Optional UnitTestSourceFileDepGraphFactory::parseADefinedDecl( StringRef s, const NodeKind kind, const DeclAspect aspect) { static const char *privatePrefix = "#"; - const bool isPrivate = s.consume_front(privatePrefix); - if (isPrivate && !includePrivateDeps) - return None; + s.consume_front(privatePrefix); const std::string context = parseContext(s.split(fingerprintSeparator).first, kind); std::string name = parseName(s.split(fingerprintSeparator).first, kind); @@ -125,9 +123,7 @@ UnitTestSourceFileDepGraphFactory::parseAUsedDecl(const StringRef argString, // Someday, we might differentiate. const DeclAspect aspectOfDefUsed = DeclAspect::interface; - const bool isHolderPrivate = s.consume_front(privateHolderPrefix); - if (!includePrivateDeps && isHolderPrivate) - return None; + s.consume_front(privateHolderPrefix); const auto defUseStrings = s.split(defUseSeparator); const auto context = parseContext(defUseStrings.first, kind); const auto name = parseName(defUseStrings.first, kind); diff --git a/unittests/Driver/UnitTestSourceFileDepGraphFactory.h b/unittests/Driver/UnitTestSourceFileDepGraphFactory.h index 16b29321a2037..9298177aa39e7 100644 --- a/unittests/Driver/UnitTestSourceFileDepGraphFactory.h +++ b/unittests/Driver/UnitTestSourceFileDepGraphFactory.h @@ -27,12 +27,12 @@ class UnitTestSourceFileDepGraphFactory public: UnitTestSourceFileDepGraphFactory( - bool includePrivateDeps, bool hadCompilationError, StringRef swiftDeps, + bool hadCompilationError, StringRef swiftDeps, StringRef fileFingerprint, bool emitDotFileAfterConstruction, const DependencyDescriptions &dependencyDescriptions, DiagnosticEngine &diags) : AbstractSourceFileDepGraphFactory( - includePrivateDeps, hadCompilationError, swiftDeps, fileFingerprint, + hadCompilationError, swiftDeps, fileFingerprint, emitDotFileAfterConstruction, diags), dependencyDescriptions(dependencyDescriptions) {} From da764ebe39fae5a23f32cb852953eaa24e5c20f6 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 1 Oct 2020 14:47:54 -0700 Subject: [PATCH 04/12] Update README.md Remove the GPU builder status for TensorFlow which is currently not running. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 67163d29fdba8..8c58de108142a 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ |---|:---:|:---:| |**[Ubuntu 18.04](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_18_04_tensorflow.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-18.04-tensorflow/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-18.04-tensorflow)| |**[macOS 10.13](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_macos_high_sierra_tensorflow.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-macOS-tensorflow/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-macOS-tensorflow)| -|**[Ubuntu 18.04 (GPU)](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_18_04_tensorflow_gpu.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-18.04-tensorflow-gpu/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-18.04-tensorflow-gpu)| ## Welcome to Swift From 60427845781ba4c247e932338fde85dd46ec0bcf Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 30 Sep 2020 18:41:21 -0400 Subject: [PATCH 05/12] Sema: Tweak re-declaration checking behavior to match old logic The parser's own re-declaration checking for local declarations has slightly different behavior than Sema's re-declaration check. Whereas Sema rejects this: class C { let x = 123 func x() {} } The parser accepts this: func f() { let x = 123 func x() {} } With Sema's check now handling both cases, fudge the behavior to match the parser in the local case. --- lib/Sema/TypeCheckDeclPrimary.cpp | 5 +++++ test/Sema/redeclaration-checking.swift | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 7c882a9c232a5..99becbbdc005a 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -572,6 +572,11 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const { if (currentDC->isTypeContext() != other->getDeclContext()->isTypeContext()) continue; + // In local context, only consider exact name matches. + if (currentDC->isLocalContext() && + current->getName() != other->getName()) + continue; + // Check whether the overload signatures conflict (ignoring the type for // now). auto otherSig = other->getOverloadSignature(); diff --git a/test/Sema/redeclaration-checking.swift b/test/Sema/redeclaration-checking.swift index 9445d612f94b1..558c23faac717 100644 --- a/test/Sema/redeclaration-checking.swift +++ b/test/Sema/redeclaration-checking.swift @@ -93,4 +93,9 @@ func stmtTest() { // expected-error@-2 {{invalid redeclaration of 'x'}} // expected-warning@-3 2{{never used}} // expected-warning@-4 {{unreachable}} +} + +func fullNameTest() { + let x = 123 // expected-warning {{never used}} + func x() {} } \ No newline at end of file From 28388384f2f6d65d78ce23838ef296bfc1fe66d2 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 30 Sep 2020 01:34:33 -0400 Subject: [PATCH 06/12] AST: UnqualifiedLookup only finds forward references to outer local bindings when IncludeOuterResults is set The old behavior was that ASTScope would introduce all VarDecls defined in a BraceStmt at the beginning of the BraceStmt. I recently enabled the use of PatternEntryDeclScopes, which introduce the binding at its actual source location instead of at the beginning of the parent statement. This patch now makes use of the new information by having UnqualifiedLookupFlags::IncludeOuterResults toggle between the two behaviors. When searching for outer results, we also consider all VarDecls in a BraceStmt, not just those in scope. This is implemented by giving AbstractASTScopeDeclConsumer a new entry point, consumePossiblyNotInScope(). When looking up into a BraceStmt, all VarDecls are passed in to this entry point. The default implementation does nothing, which means that ASTScope::lookupSingleLocalDecl() now respects source locations when searching for bindings, just like parse-time lookup. However, Sema's preCheckExpression() pass, which sets Flags::IgnoreOuterResults, will continue to find forward-referenced VarDecls, just as it did with the old context-based DeclContext lookup. --- include/swift/AST/ASTScope.h | 16 ++++++++++++-- include/swift/AST/NameLookup.h | 8 +++++++ lib/AST/ASTScopeCreation.cpp | 22 +++++++++++++++++++- lib/AST/ASTScopeLookup.cpp | 18 ++++------------ lib/AST/UnqualifiedLookup.cpp | 38 +++++++++++++++++++++++++++++++--- 5 files changed, 82 insertions(+), 20 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 80cc61ac08be3..fd05c8e453f8b 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -1658,10 +1658,22 @@ class CaseStmtBodyScope final : public ASTScopeImpl { }; class BraceStmtScope final : public AbstractStmtScope { + BraceStmt *const stmt; + + /// Declarations which are in scope from the beginning of the statement. + SmallVector localFuncsAndTypes; + + /// Declarations that are normally in scope only after their + /// definition. + SmallVector localVars; public: - BraceStmt *const stmt; - BraceStmtScope(BraceStmt *e) : stmt(e) {} + BraceStmtScope(BraceStmt *e, + SmallVector localFuncsAndTypes, + SmallVector localVars) + : stmt(e), + localFuncsAndTypes(localFuncsAndTypes), + localVars(localVars) {} virtual ~BraceStmtScope() {} protected: diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index d57cd07ea8b4c..748a6d27fdf28 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -613,6 +613,14 @@ class AbstractASTScopeDeclConsumer { lookInMembers(DeclContext *const scopeDC, NominalTypeDecl *const nominal) = 0; + /// Called for local VarDecls that might not yet be in scope. + /// + /// Note that the set of VarDecls visited here are going to be a + /// superset of those visited in consume(). + virtual bool consumePossiblyNotInScope(ArrayRef values) { + return false; + } + /// Called right before looking at the parent scope of a BraceStmt. /// /// \return true if the lookup should be stopped at this point. diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 0c6d22b4bca5c..3dbe233239604 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -667,10 +667,30 @@ class NodeAdder NullablePtr visitBraceStmt(BraceStmt *bs, ASTScopeImpl *p, ScopeCreator &scopeCreator) { + SmallVector localFuncsAndTypes; + SmallVector localVars; + + // All types and functions are visible anywhere within a brace statement + // scope. When ordering matters (i.e. var decl) we will have split the brace + // statement into nested scopes. + for (auto braceElement : bs->getElements()) { + if (auto localBinding = braceElement.dyn_cast()) { + if (auto *vd = dyn_cast(localBinding)) { + if (isa(vd) || isa(vd)) { + localFuncsAndTypes.push_back(vd); + } else if (auto *var = dyn_cast(localBinding)) { + localVars.push_back(var); + } + } + } + } + auto maybeBraceScope = - scopeCreator.ifUniqueConstructExpandAndInsert(p, bs); + scopeCreator.ifUniqueConstructExpandAndInsert( + p, bs, std::move(localFuncsAndTypes), std::move(localVars)); if (auto *s = scopeCreator.getASTContext().Stats) ++s->getFrontendCounters().NumBraceStmtASTScopes; + return maybeBraceScope.getPtrOr(p); } diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 47c103e83e608..0821ce8c7fbe7 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -371,20 +371,10 @@ bool DifferentiableAttributeScope::lookupLocalsOrMembers( } bool BraceStmtScope::lookupLocalsOrMembers(DeclConsumer consumer) const { - // All types and functions are visible anywhere within a brace statement - // scope. When ordering matters (i.e. var decl) we will have split the brace - // statement into nested scopes. - // - // Don't stop at the first one, there may be local funcs with same base name - // and want them all. - SmallVector localBindings; - for (auto braceElement : stmt->getElements()) { - if (auto localBinding = braceElement.dyn_cast()) { - if (auto *vd = dyn_cast(localBinding)) - localBindings.push_back(vd); - } - } - if (consumer.consume(localBindings, DeclVisibilityKind::LocalVariable)) + if (consumer.consume(localFuncsAndTypes, DeclVisibilityKind::LocalVariable)) + return true; + + if (consumer.consumePossiblyNotInScope(localVars)) return true; if (consumer.finishLookupInBraceStmt(stmt)) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 20b5aad9311c1..3693f11ae5d8c 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -133,7 +133,12 @@ namespace { /// Can lookup stop searching for results, assuming hasn't looked for outer /// results yet? bool isFirstResultEnough() const; - + + /// Do we want precise scoping of VarDecls? If IncludeOuterResults is on, + /// this is true, which allows us to resolve forward references to + /// local VarDecls from inside local function and closure bodies. + bool hasPreciseScopingOfVarDecls() const; + /// Every time lookup finishes searching a scope, call me /// to record the dividing line between results from first fruitful scope and /// the result. @@ -209,6 +214,8 @@ class ASTScopeDeclConsumerForUnqualifiedLookup bool consume(ArrayRef values, DeclVisibilityKind vis, NullablePtr baseDC = nullptr) override; + bool consumePossiblyNotInScope(ArrayRef vars) override; + /// returns true if finished bool lookInMembers(DeclContext *const scopeDC, NominalTypeDecl *const nominal) override; @@ -462,6 +469,10 @@ bool UnqualifiedLookupFactory::isFirstResultEnough() const { return !Results.empty() && !options.contains(Flags::IncludeOuterResults); } +bool UnqualifiedLookupFactory::hasPreciseScopingOfVarDecls() const { + return !options.contains(Flags::IncludeOuterResults); +} + void UnqualifiedLookupFactory::recordCompletionOfAScope() { // OK to call (NOOP) if there are more inner results and Results is empty if (IndexOfFirstOuterResult == 0) @@ -556,12 +567,18 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::consume( if (factory.isOriginallyTypeLookup && !isa(value)) continue; - // Try to resolve the base for unqualified instance member - // references. This is used by lookInMembers(). if (auto *var = dyn_cast(value)) { + // Try to resolve the base for unqualified instance member + // references. This is used by lookInMembers(). if (var->getName() == factory.Ctx.Id_self) { maybeUpdateSelfDC(var); } + + // Local VarDecls with a pattern binding are visited as part of their + // BraceStmt when hasPreciseScopingOfVarDecls() is off. + if (var->getParentPatternBinding() && + !factory.hasPreciseScopingOfVarDecls()) + continue; } if (!value->getName().matchesRef(factory.Name.getFullName())) @@ -587,6 +604,21 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::consume( return factory.isFirstResultEnough(); } +bool ASTScopeDeclConsumerForUnqualifiedLookup::consumePossiblyNotInScope( + ArrayRef vars) { + if (factory.hasPreciseScopingOfVarDecls()) + return false; + + for (auto *var : vars) { + if (!factory.Name.getFullName().isSimpleName(var->getName())) + continue; + + factory.Results.push_back(LookupResultEntry(var)); + } + + return false; +} + bool ASTScopeDeclGatherer::consume(ArrayRef valuesArg, DeclVisibilityKind, NullablePtr) { From 06fc9c5a5ed64128f15e89b54070f458a6960014 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 30 Sep 2020 01:38:07 -0400 Subject: [PATCH 07/12] Sema: Simulate old name lookup behavior when parser lookup is off Before performing an UnqualifiedLookup with Flags::IncludeOuterResults turned on, call ASTScope::lookupSingleLocalDecl() to find local bindings that precede the current source location. If this fails, we perform an unqualified lookup to try to find forward references to captures, type members, and top-level declarations. --- lib/Sema/PreCheckExpr.cpp | 115 ++++++++++++++++++------------- test/NameLookup/edge-cases.swift | 21 ++++++ 2 files changed, 89 insertions(+), 47 deletions(-) create mode 100644 test/NameLookup/edge-cases.swift diff --git a/lib/Sema/PreCheckExpr.cpp b/lib/Sema/PreCheckExpr.cpp index 7cf0c1a0b0a86..0da6f8379f65f 100644 --- a/lib/Sema/PreCheckExpr.cpp +++ b/lib/Sema/PreCheckExpr.cpp @@ -351,12 +351,77 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // name/module qualifier to access top-level name. lookupOptions |= NameLookupFlags::IncludeOuterResults; - if (Loc.isInvalid()) - DC = DC->getModuleScopeContext(); + LookupResult Lookup; - auto Lookup = TypeChecker::lookupUnqualified(DC, Name, Loc, lookupOptions); + bool AllDeclRefs = true; + SmallVector ResultValues; auto &Context = DC->getASTContext(); + if (Context.LangOpts.DisableParserLookup) { + // First, look for a local binding in scope. + if (Loc.isValid() && !Name.isOperator()) { + SmallVector localDecls; + ASTScope::lookupLocalDecls(DC->getParentSourceFile(), + Name.getFullName(), Loc, + /*stopAfterInnermostBraceStmt=*/false, + ResultValues); + for (auto *localDecl : ResultValues) { + Lookup.add(LookupResultEntry(localDecl), /*isOuter=*/false); + } + } + } + + if (!Lookup) { + // Now, look for all local bindings, even forward references, as well + // as type members and top-level declarations. + if (Loc.isInvalid()) + DC = DC->getModuleScopeContext(); + + Lookup = TypeChecker::lookupUnqualified(DC, Name, Loc, lookupOptions); + + ValueDecl *localDeclAfterUse = nullptr; + auto isValid = [&](ValueDecl *D) { + // If we find something in the current context, it must be a forward + // reference, because otherwise if it was in scope, it would have + // been returned by the call to ASTScope::lookupLocalDecls() above. + if (D->getDeclContext()->isLocalContext() && + D->getDeclContext() == DC && + (Context.LangOpts.DisableParserLookup || + (Loc.isValid() && D->getLoc().isValid() && + Context.SourceMgr.isBeforeInBuffer(Loc, D->getLoc()) && + !isa(D)))) { + localDeclAfterUse = D; + return false; + } + return true; + }; + AllDeclRefs = + findNonMembers(Lookup.innerResults(), UDRE->getRefKind(), + /*breakOnMember=*/true, ResultValues, isValid); + + // If local declaration after use is found, check outer results for + // better matching candidates. + if (ResultValues.empty() && localDeclAfterUse) { + auto innerDecl = localDeclAfterUse; + while (localDeclAfterUse) { + if (Lookup.outerResults().empty()) { + Context.Diags.diagnose(Loc, diag::use_local_before_declaration, Name); + Context.Diags.diagnose(innerDecl, diag::decl_declared_here, + localDeclAfterUse->getName()); + Expr *error = new (Context) ErrorExpr(UDRE->getSourceRange()); + return error; + } + + Lookup.shiftDownResults(); + ResultValues.clear(); + localDeclAfterUse = nullptr; + AllDeclRefs = + findNonMembers(Lookup.innerResults(), UDRE->getRefKind(), + /*breakOnMember=*/true, ResultValues, isValid); + } + } + } + if (!Lookup) { // If we failed lookup of an operator, check to see if this is a range // operator misspelling. Otherwise try to diagnose a juxtaposition @@ -487,50 +552,6 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // FIXME: Need to refactor the way we build an AST node from a lookup result! - SmallVector ResultValues; - ValueDecl *localDeclAfterUse = nullptr; - auto isValid = [&](ValueDecl *D) { - // FIXME: The source-location checks won't make sense once - // EnableASTScopeLookup is the default. - // - // Note that we allow forward references to types, because they cannot - // capture. - if (Loc.isValid() && D->getLoc().isValid() && - D->getDeclContext()->isLocalContext() && - D->getDeclContext() == DC && - Context.SourceMgr.isBeforeInBuffer(Loc, D->getLoc()) && - !isa(D)) { - localDeclAfterUse = D; - return false; - } - return true; - }; - bool AllDeclRefs = - findNonMembers(Lookup.innerResults(), UDRE->getRefKind(), - /*breakOnMember=*/true, ResultValues, isValid); - - // If local declaration after use is found, check outer results for - // better matching candidates. - if (localDeclAfterUse) { - auto innerDecl = localDeclAfterUse; - while (localDeclAfterUse) { - if (Lookup.outerResults().empty()) { - Context.Diags.diagnose(Loc, diag::use_local_before_declaration, Name); - Context.Diags.diagnose(innerDecl, diag::decl_declared_here, - localDeclAfterUse->getName()); - Expr *error = new (Context) ErrorExpr(UDRE->getSourceRange()); - return error; - } - - Lookup.shiftDownResults(); - ResultValues.clear(); - localDeclAfterUse = nullptr; - AllDeclRefs = - findNonMembers(Lookup.innerResults(), UDRE->getRefKind(), - /*breakOnMember=*/true, ResultValues, isValid); - } - } - // If we have an unambiguous reference to a type decl, form a TypeExpr. if (Lookup.size() == 1 && UDRE->getRefKind() == DeclRefKind::Ordinary && isa(Lookup[0].getValueDecl())) { diff --git a/test/NameLookup/edge-cases.swift b/test/NameLookup/edge-cases.swift new file mode 100644 index 0000000000000..cc0798480b43c --- /dev/null +++ b/test/NameLookup/edge-cases.swift @@ -0,0 +1,21 @@ +// RUN: %target-typecheck-verify-swift -disable-parser-lookup + +struct A {} +struct B {} + +func other() -> A {} + +func takesB(_: B) {} + +func multipleLocalResults1() { + func other() -> B {} + let result = other() + takesB(result) +} + +func multipleLocalResults2() { + func other() -> B {} + let result = other() + takesB(result) + let other: Int = 123 // expected-warning {{never used}} +} From 8168dda2bc4d15aee8d6ba729230d58791556f76 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 30 Sep 2020 01:26:05 -0400 Subject: [PATCH 08/12] AST: Remove dead code from ASTScopeDeclConsumerForUnqualifiedLookup::consume() --- lib/AST/UnqualifiedLookup.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 3693f11ae5d8c..16af6d0ba6145 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -584,17 +584,6 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::consume( if (!value->getName().matchesRef(factory.Name.getFullName())) continue; - // In order to preserve the behavior of the existing context-based lookup, - // which finds all results for non-local variables at the top level instead - // of stopping at the first one, ignore results at the top level that are - // not local variables. The caller \c lookInASTScopes will - // then do the appropriate work when the scope lookup fails. In - // FindLocalVal::visitBraceStmt, it sees PatternBindingDecls, not VarDecls, - // so a VarDecl at top level would not be found by the context-based lookup. - if (isa(value->getDeclContext()) && - (vis != DeclVisibilityKind::LocalVariable || isa(value))) - return false; - factory.Results.push_back(LookupResultEntry(value)); #ifndef NDEBUG factory.stopForDebuggingIfAddingTargetLookupResult(factory.Results.back()); From f738a57040ab1e42f46c8a73c1f6cc0b8a34bdae Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 30 Sep 2020 01:29:39 -0400 Subject: [PATCH 09/12] ASTScope: Remove DeclVisibilityKind parameter from AbstractASTScopeDeclConsumer::consume() It wasn't used for anything, and it was always set based on whether the declaration in question was a GenericTypeParamDecl, a ParamDecl, or something else. --- include/swift/AST/ASTScope.h | 1 - include/swift/AST/NameLookup.h | 4 ++-- lib/AST/ASTScopeLookup.cpp | 42 ++++++++++++++-------------------- lib/AST/UnqualifiedLookup.cpp | 8 +++---- 4 files changed, 22 insertions(+), 33 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index fd05c8e453f8b..aadfbff462ad4 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -444,7 +444,6 @@ class ASTScopeImpl { // It is not an instance variable or inherited type. static bool lookupLocalBindingsInPattern(const Pattern *p, - DeclVisibilityKind vis, DeclConsumer consumer); /// When lookup must stop before the outermost scope, return the scope to stop diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index 748a6d27fdf28..f9a6df52039a5 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -603,7 +603,7 @@ class AbstractASTScopeDeclConsumer { /// of type -vs- instance lookup results. /// /// \return true if the lookup should be stopped at this point. - virtual bool consume(ArrayRef values, DeclVisibilityKind vis, + virtual bool consume(ArrayRef values, NullablePtr baseDC = nullptr) = 0; /// Look for members of a nominal type or extension scope. @@ -644,7 +644,7 @@ class ASTScopeDeclGatherer : public AbstractASTScopeDeclConsumer { public: virtual ~ASTScopeDeclGatherer() = default; - bool consume(ArrayRef values, DeclVisibilityKind vis, + bool consume(ArrayRef values, NullablePtr baseDC = nullptr) override; /// Eventually this functionality should move into ASTScopeLookup diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 0821ce8c7fbe7..2c70497c03c7c 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -222,7 +222,7 @@ bool ASTScopeImpl::lookInGenericParametersOf( SmallVector bindings; for (auto *param : paramList.get()->getParams()) bindings.push_back(param); - if (consumer.consume(bindings, DeclVisibilityKind::GenericParameter)) + if (consumer.consume(bindings)) return true; return false; } @@ -289,28 +289,26 @@ PatternEntryInitializerScope::getLookupParent() const { bool GenericParamScope::lookupLocalsOrMembers(DeclConsumer consumer) const { auto *param = paramList->getParams()[index]; - return consumer.consume({param}, DeclVisibilityKind::GenericParameter); + return consumer.consume({param}); } bool PatternEntryDeclScope::lookupLocalsOrMembers(DeclConsumer consumer) const { if (vis != DeclVisibilityKind::LocalVariable) return false; // look in self type will find this later - return lookupLocalBindingsInPattern(getPattern(), vis, consumer); + return lookupLocalBindingsInPattern(getPattern(), consumer); } bool ForEachPatternScope::lookupLocalsOrMembers(DeclConsumer consumer) const { - return lookupLocalBindingsInPattern( - stmt->getPattern(), DeclVisibilityKind::LocalVariable, consumer); + return lookupLocalBindingsInPattern(stmt->getPattern(), consumer); } bool CaseLabelItemScope::lookupLocalsOrMembers(DeclConsumer consumer) const { - return lookupLocalBindingsInPattern( - item.getPattern(), DeclVisibilityKind::LocalVariable, consumer); + return lookupLocalBindingsInPattern(item.getPattern(), consumer); } bool CaseStmtBodyScope::lookupLocalsOrMembers(DeclConsumer consumer) const { for (auto *var : stmt->getCaseBodyVariablesOrEmptyArray()) - if (consumer.consume({var}, DeclVisibilityKind::LocalVariable)) + if (consumer.consume({var})) return true; return false; @@ -320,13 +318,12 @@ bool FunctionBodyScope::lookupLocalsOrMembers( DeclConsumer consumer) const { if (auto *paramList = decl->getParameters()) { for (auto *paramDecl : *paramList) - if (consumer.consume({paramDecl}, DeclVisibilityKind::FunctionParameter)) + if (consumer.consume({paramDecl})) return true; } if (decl->getDeclContext()->isTypeContext()) { - return consumer.consume({decl->getImplicitSelfDecl()}, - DeclVisibilityKind::FunctionParameter); + return consumer.consume({decl->getImplicitSelfDecl()}); } // Consider \c var t: T { (did/will/)get/set { ... t }} @@ -335,7 +332,7 @@ bool FunctionBodyScope::lookupLocalsOrMembers( // then t needs to be found as a local binding: if (auto *accessor = dyn_cast(decl)) { if (auto *storage = accessor->getStorage()) - if (consumer.consume({storage}, DeclVisibilityKind::LocalVariable)) + if (consumer.consume({storage})) return true; } @@ -346,7 +343,7 @@ bool SpecializeAttributeScope::lookupLocalsOrMembers( DeclConsumer consumer) const { if (auto *params = whatWasSpecialized->getGenericParams()) for (auto *param : params->getParams()) - if (consumer.consume({param}, DeclVisibilityKind::GenericParameter)) + if (consumer.consume({param})) return true; return false; } @@ -356,7 +353,7 @@ bool DifferentiableAttributeScope::lookupLocalsOrMembers( auto visitAbstractFunctionDecl = [&](AbstractFunctionDecl *afd) { if (auto *params = afd->getGenericParams()) for (auto *param : params->getParams()) - if (consumer.consume({param}, DeclVisibilityKind::GenericParameter)) + if (consumer.consume({param})) return true; return false; }; @@ -371,7 +368,7 @@ bool DifferentiableAttributeScope::lookupLocalsOrMembers( } bool BraceStmtScope::lookupLocalsOrMembers(DeclConsumer consumer) const { - if (consumer.consume(localFuncsAndTypes, DeclVisibilityKind::LocalVariable)) + if (consumer.consume(localFuncsAndTypes)) return true; if (consumer.consumePossiblyNotInScope(localVars)) @@ -390,8 +387,7 @@ bool PatternEntryInitializerScope::lookupLocalsOrMembers( decl->getInitContext(0)); if (initContext) { if (auto *selfParam = initContext->getImplicitSelfDecl()) { - return consumer.consume({selfParam}, - DeclVisibilityKind::FunctionParameter); + return consumer.consume({selfParam}); } } return false; @@ -399,9 +395,7 @@ bool PatternEntryInitializerScope::lookupLocalsOrMembers( bool CaptureListScope::lookupLocalsOrMembers(DeclConsumer consumer) const { for (auto &e : expr->getCaptureList()) { - if (consumer.consume( - {e.Var}, - DeclVisibilityKind::LocalVariable)) // or FunctionParameter?? + if (consumer.consume({e.Var})) return true; } return false; @@ -410,26 +404,24 @@ bool CaptureListScope::lookupLocalsOrMembers(DeclConsumer consumer) const { bool ClosureParametersScope::lookupLocalsOrMembers( DeclConsumer consumer) const { for (auto param : *closureExpr->getParameters()) - if (consumer.consume({param}, DeclVisibilityKind::FunctionParameter)) + if (consumer.consume({param})) return true; return false; } bool ConditionalClausePatternUseScope::lookupLocalsOrMembers( DeclConsumer consumer) const { - return lookupLocalBindingsInPattern( - pattern, DeclVisibilityKind::LocalVariable, consumer); + return lookupLocalBindingsInPattern(pattern, consumer); } bool ASTScopeImpl::lookupLocalBindingsInPattern(const Pattern *p, - DeclVisibilityKind vis, DeclConsumer consumer) { if (!p) return false; bool isDone = false; p->forEachVariable([&](VarDecl *var) { if (!isDone) - isDone = consumer.consume({var}, vis); + isDone = consumer.consume({var}); }); return isDone; } diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 16af6d0ba6145..91f17451b1f49 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -211,7 +211,7 @@ class ASTScopeDeclConsumerForUnqualifiedLookup void maybeUpdateSelfDC(VarDecl *var); - bool consume(ArrayRef values, DeclVisibilityKind vis, + bool consume(ArrayRef values, NullablePtr baseDC = nullptr) override; bool consumePossiblyNotInScope(ArrayRef vars) override; @@ -561,8 +561,7 @@ void ASTScopeDeclConsumerForUnqualifiedLookup::maybeUpdateSelfDC( } bool ASTScopeDeclConsumerForUnqualifiedLookup::consume( - ArrayRef values, DeclVisibilityKind vis, - NullablePtr baseDC) { + ArrayRef values, NullablePtr baseDC) { for (auto *value: values) { if (factory.isOriginallyTypeLookup && !isa(value)) continue; @@ -609,7 +608,6 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::consumePossiblyNotInScope( } bool ASTScopeDeclGatherer::consume(ArrayRef valuesArg, - DeclVisibilityKind, NullablePtr) { for (auto *v: valuesArg) values.push_back(v); @@ -768,7 +766,7 @@ class ASTScopeDeclConsumerForLocalLookup : name(name), stopAfterInnermostBraceStmt(stopAfterInnermostBraceStmt), results(results) {} - bool consume(ArrayRef values, DeclVisibilityKind vis, + bool consume(ArrayRef values, NullablePtr baseDC) override { for (auto *value: values) { if (!value->getName().matchesRef(name)) From 3ec4ced57db438f54b54d88f2207e762120e8eaa Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 30 Sep 2020 22:05:27 -0400 Subject: [PATCH 10/12] ASTScope: Don't handle top-level bindings in a SourceFile for now --- include/swift/AST/ASTScope.h | 14 +++++------ lib/AST/ASTScopeCreation.cpp | 29 ++++++++++++----------- lib/AST/ASTScopeLookup.cpp | 4 ++-- lib/AST/Decl.cpp | 3 ++- test/NameLookup/scope_map_top_level.swift | 10 ++++---- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index aadfbff462ad4..f4247df1468c3 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -29,7 +29,7 @@ #define SWIFT_AST_AST_SCOPE_H #include "swift/AST/ASTNode.h" -#include "swift/AST/NameLookup.h" // for DeclVisibilityKind +#include "swift/AST/NameLookup.h" #include "swift/AST/SimpleRequest.h" #include "swift/Basic/Compiler.h" #include "swift/Basic/Debug.h" @@ -1023,10 +1023,10 @@ class AbstractPatternEntryScope : public ASTScopeImpl { public: PatternBindingDecl *const decl; const unsigned patternEntryIndex; - const DeclVisibilityKind vis; + const bool isLocalBinding; AbstractPatternEntryScope(PatternBindingDecl *, unsigned entryIndex, - DeclVisibilityKind); + bool); virtual ~AbstractPatternEntryScope() {} const PatternBindingEntry &getPatternEntry() const; @@ -1043,8 +1043,8 @@ class AbstractPatternEntryScope : public ASTScopeImpl { class PatternEntryDeclScope final : public AbstractPatternEntryScope { public: PatternEntryDeclScope(PatternBindingDecl *pbDecl, unsigned entryIndex, - DeclVisibilityKind vis) - : AbstractPatternEntryScope(pbDecl, entryIndex, vis) {} + bool isLocalBinding) + : AbstractPatternEntryScope(pbDecl, entryIndex, isLocalBinding) {} virtual ~PatternEntryDeclScope() {} protected: @@ -1071,8 +1071,8 @@ class PatternEntryInitializerScope final : public AbstractPatternEntryScope { public: PatternEntryInitializerScope(PatternBindingDecl *pbDecl, unsigned entryIndex, - DeclVisibilityKind vis) - : AbstractPatternEntryScope(pbDecl, entryIndex, vis), + bool isLocalBinding) + : AbstractPatternEntryScope(pbDecl, entryIndex, isLocalBinding), initAsWrittenWhenCreated(pbDecl->getOriginalInit(entryIndex)) {} virtual ~PatternEntryInitializerScope() {} diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 3dbe233239604..aa82c8014afc2 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -701,23 +701,23 @@ class NodeAdder if (auto *var = patternBinding->getSingleVar()) scopeCreator.addChildrenForKnownAttributes(var, parentScope); - const bool isLocalBinding = patternBinding->getDeclContext()->isLocalContext(); - - const DeclVisibilityKind vis = - isLocalBinding ? DeclVisibilityKind::LocalVariable - : DeclVisibilityKind::MemberOfCurrentNominal; auto *insertionPoint = parentScope; for (auto i : range(patternBinding->getNumPatternEntries())) { + bool isLocalBinding = false; + if (auto *varDecl = patternBinding->getAnchoringVarDecl(i)) { + isLocalBinding = varDecl->getDeclContext()->isLocalContext(); + } + insertionPoint = scopeCreator .ifUniqueConstructExpandAndInsert( - insertionPoint, patternBinding, i, vis) + insertionPoint, patternBinding, i, isLocalBinding) .getPtrOr(insertionPoint); - } - ASTScopeAssert(isLocalBinding || insertionPoint == parentScope, - "Bindings at the top-level or members of types should " - "not change the insertion point"); + ASTScopeAssert(isLocalBinding || insertionPoint == parentScope, + "Bindings at the top-level or members of types should " + "not change the insertion point"); + } return insertionPoint; } @@ -991,7 +991,7 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint( "Original inits are always after the '='"); scopeCreator .constructExpandAndInsertUncheckable( - this, decl, patternEntryIndex, vis); + this, decl, patternEntryIndex, isLocalBinding); } // Add accessors for the variables in this pattern. @@ -1002,7 +1002,7 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint( // In local context, the PatternEntryDeclScope becomes the insertion point, so // that all any bindings introduecd by the pattern are in scope for subsequent // lookups. - if (vis == DeclVisibilityKind::LocalVariable) + if (isLocalBinding) return {this, "All code that follows is inside this scope"}; return {getParent().get(), "Global and type members do not introduce scopes"}; @@ -1378,8 +1378,9 @@ ASTScopeImpl *LabeledConditionalStmtScope::createNestedConditionalClauseScopes( AbstractPatternEntryScope::AbstractPatternEntryScope( PatternBindingDecl *declBeingScoped, unsigned entryIndex, - DeclVisibilityKind vis) - : decl(declBeingScoped), patternEntryIndex(entryIndex), vis(vis) { + bool isLocalBinding) + : decl(declBeingScoped), patternEntryIndex(entryIndex), + isLocalBinding(isLocalBinding) { ASTScopeAssert(entryIndex < declBeingScoped->getPatternList().size(), "out of bounds"); } diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 2c70497c03c7c..c49099bce99d2 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -293,8 +293,8 @@ bool GenericParamScope::lookupLocalsOrMembers(DeclConsumer consumer) const { } bool PatternEntryDeclScope::lookupLocalsOrMembers(DeclConsumer consumer) const { - if (vis != DeclVisibilityKind::LocalVariable) - return false; // look in self type will find this later + if (!isLocalBinding) + return false; return lookupLocalBindingsInPattern(getPattern(), consumer); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 75b354c0d29d9..cdc16e07a366d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1447,7 +1447,8 @@ void PatternBindingEntry::setInit(Expr *E) { VarDecl *PatternBindingEntry::getAnchoringVarDecl() const { SmallVector variables; getPattern()->collectVariables(variables); - assert(!variables.empty()); + if (variables.empty()) + return nullptr; return variables[0]; } diff --git a/test/NameLookup/scope_map_top_level.swift b/test/NameLookup/scope_map_top_level.swift index eeee236dae731..014c920862e53 100644 --- a/test/NameLookup/scope_map_top_level.swift +++ b/test/NameLookup/scope_map_top_level.swift @@ -31,8 +31,8 @@ var i: Int = b.my_identity() // CHECK-EXPANDED-NEXT: `-NominalTypeBodyScope {{.*}}, [4:11 - 4:13] // CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [6:1 - 21:28] // CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [6:1 - 21:28] -// CHECK-EXPANDED-NEXT: `-PatternEntryDeclScope {{.*}}, [6:5 - 21:28] entry 0 'a' -// CHECK-EXPANDED-NEXT: |-PatternEntryInitializerScope {{.*}}, [6:15 - 6:15] entry 0 'a' +// CHECK-EXPANDED-NEXT: |-PatternEntryDeclScope {{.*}}, [6:5 - 6:15] entry 0 'a' +// CHECK-EXPANDED-NEXT: `-PatternEntryInitializerScope {{.*}}, [6:15 - 6:15] entry 0 'a' // CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [8:1 - 21:28] // CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [8:1 - 21:28] // CHECK-EXPANDED-NEXT: `-GuardStmtScope {{.*}}, [8:1 - 21:28] @@ -46,9 +46,9 @@ var i: Int = b.my_identity() // CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [11:18 - 11:19] // CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [13:1 - 21:28] // CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [13:1 - 21:28] -// CHECK-EXPANDED-NEXT: `-PatternEntryDeclScope {{.*}}, [13:5 - 21:28] entry 0 'c' -// CHECK-EXPANDED-NEXT: |-PatternEntryInitializerScope {{.*}}, [13:9 - 13:9] entry 0 'c' -// CHECK-EXPANDED-NEXT: |-TypeAliasDeclScope {{.*}}, [15:1 - 15:15] +// CHECK-EXPANDED-NEXT: |-PatternEntryDeclScope {{.*}}, [13:5 - 13:9] entry 0 'c' +// CHECK-EXPANDED-NEXT: `-PatternEntryInitializerScope {{.*}}, [13:9 - 13:9] entry 0 'c' +// CHECK-EXPANDED-NEXT: |-TypeAliasDeclScope {{.*}}, [15:1 - 15:15] // CHECK-EXPANDED-NEXT: |-ExtensionDeclScope {{.*}}, [17:14 - 19:1] // CHECK-EXPANDED-NEXT: `-ExtensionBodyScope {{.*}}, [17:15 - 19:1] // CHECK-EXPANDED-NEXT: `-AbstractFunctionDeclScope {{.*}}, [18:3 - 18:43] 'my_identity()' From 7271fd079e5dd103bca30d55bf408aed6e06642c Mon Sep 17 00:00:00 2001 From: Eric Miotto <1094986+edymtt@users.noreply.github.com> Date: Fri, 2 Oct 2020 10:06:44 -0700 Subject: [PATCH 11/12] [build] Run dsymutil on multiple files at a time (#34149) The change in #33654 had the effect of not leveraging dsymutil parallelism -- pass instead multiple file at once. Addresses rdar://69550787 --- utils/build-script-impl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index 0662f5961b754..2bb99c886a669 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -3049,7 +3049,7 @@ for host in "${ALL_HOSTS[@]}"; do grep -v '.py$' | \ grep -v '.a$' | \ grep -v 'swift-api-digester' | \ - xargs -n 1 -P 1 ${dsymutil_path}) + xargs -P 1 ${dsymutil_path}) # Strip executables, shared libraries and static libraries in # `host_install_destdir`. From d74cad69600eb498f3f875a8418769b98fa0365e Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Fri, 2 Oct 2020 13:37:35 -0400 Subject: [PATCH 12/12] [Localization] Install only *.db and *.yaml files (#34139) This prevents us from picking up the .gitkeep file and any other stray files that might end up in there. --- localization/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index 53c7e05e2a757..dcaac27691e35 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -19,4 +19,7 @@ add_dependencies(diagnostic-database swift-def-to-yaml-converter) swift_install_in_component( DIRECTORY ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ DESTINATION "share/swift/diagnostics" - COMPONENT compiler) + COMPONENT compiler + PATTERN "*.db" + PATTERN "*.yaml" +)