From f867d0bb05a198e0170c59204057bee18468f0c8 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 31 Oct 2024 14:48:25 -0700 Subject: [PATCH 01/15] Implement Vector --- stdlib/public/core/CMakeLists.txt | 3 + stdlib/public/core/GroupInfo.json | 3 +- stdlib/public/core/Vector.swift | 500 ++++++++++++++++++++++++++++++ 3 files changed, 505 insertions(+), 1 deletion(-) create mode 100644 stdlib/public/core/Vector.swift diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index a03cb87083051..5d964ed29e7ef 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -214,6 +214,7 @@ split_embedded_sources( EMBEDDED Unicode.swift # ORDER DEPENDENCY: must follow new unicode support EMBEDDED StringGraphemeBreaking.swift # ORDER DEPENDENCY: Must follow UTF16.swift EMBEDDED ValidUTF8Buffer.swift + EMBEDDED Vector.swift EMBEDDED WriteBackMutableSlice.swift EMBEDDED MigrationSupport.swift @@ -318,6 +319,8 @@ list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Macros") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "FreestandingMacros") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Extern") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "BitwiseCopyable") +list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "RawLayout") +list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "ValueGenerics") if("${SWIFT_NATIVE_SWIFT_TOOLS_PATH}" STREQUAL "") set(swift_bin_dir "${CMAKE_BINARY_DIR}/bin") diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index 76cc3f7b1b680..2e95ebc198c6f 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -256,7 +256,8 @@ "Instant.swift", "EmbeddedRuntime.swift", "EmbeddedStubs.swift", - "EmbeddedPrint.swift" + "EmbeddedPrint.swift", + "Vector.swift" ], "Result": [ "Result.swift" diff --git a/stdlib/public/core/Vector.swift b/stdlib/public/core/Vector.swift new file mode 100644 index 0000000000000..a364273aea29a --- /dev/null +++ b/stdlib/public/core/Vector.swift @@ -0,0 +1,500 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// + +/// A fixed-size array. +@available(SwiftStdlib 6.1, *) +@frozen +public struct Vector: ~Copyable { + @usableFromInline + let storage: Builtin.FixedArray +} + +@available(SwiftStdlib 6.1, *) +extension Vector: Copyable where Element: Copyable {} + +@available(SwiftStdlib 6.1, *) +extension Vector: @unchecked Sendable where Element: Sendable & ~Copyable {} + +//===----------------------------------------------------------------------===// +// Address & Buffer +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Vector where Element: ~Copyable { + /// Returns a read-only pointer to the first element in the vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + var address: UnsafePointer { + UnsafePointer(Builtin.unprotectedAddressOfBorrow(self)) + } + + /// Returns a buffer pointer over the entire vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + var buffer: UnsafeBufferPointer { + UnsafeBufferPointer(start: address, count: Count) + } + + /// Returns a mutable pointer to the first element in the vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + var mutableAddress: UnsafeMutablePointer { + mutating get { + UnsafeMutablePointer(Builtin.unprotectedAddressOf(&self)) + } + } + + /// Returns a mutable buffer pointer over the entire vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + var mutableBuffer: UnsafeMutableBufferPointer { + mutating get { + UnsafeMutableBufferPointer(start: mutableAddress, count: Count) + } + } +} + +//===----------------------------------------------------------------------===// +// Initialization APIs +//===----------------------------------------------------------------------===// + +// @available(SwiftStdlib 6.1, *) +// extension Vector where Element: ~Copyable { +// /// Initializes every element in this vector running the given closure value +// /// that returns the element to emplace at the given index. +// /// +// /// This will call the closure `Count` times, where `Count` is the static +// /// count of the vector, to initialize every element by passing the closure +// /// the index of the current element being initialized. The closure is allowed +// /// to throw an error at any point during initialization at which point the +// /// vector will stop initialization, deinitialize every currently initialized +// /// element, and throw the given error back out to the caller. +// /// +// /// - Parameter body: A closure that returns an owned `Element` to emplace at +// /// the passed in index. +// @available(SwiftStdlib 6.1, *) +// @_alwaysEmitIntoClient +// public init(_ body: (Int) throws(E) -> Element) throws(E) { +// for i in 0 ..< Count { +// do { +// try buffer.initializeElement(at: i, to: body(i)) +// } catch { +// // The closure threw an error. We need to deinitialize every element +// // we've initialized up to this point. +// for j in 0 ..< i { +// buffer.deinitializeElement(at: j) +// } + +// // Throw the error we were given back out to the caller. +// throw error +// } +// } +// } +// } + +@available(SwiftStdlib 6.1, *) +extension Vector where Element: Copyable { + /// Initializes every element in this vector to a copy of the given value. + /// + /// - Parameter value: The instance to initialize this vector with. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public init(repeating value: Element) { + storage = Builtin.emplace { + let ptr = UnsafeMutablePointer($0) + let buffer = UnsafeMutableBufferPointer(start: ptr, count: Count) + + buffer.initialize(repeating: value) + } + } +} + +//===----------------------------------------------------------------------===// +// Copy +//===----------------------------------------------------------------------===// + +// @available(SwiftStdlib 6.1, *) +// extension Vector where Element: Copyable { +// /// Returns a fresh owned copy of the current vector. +// /// +// /// - Returns: A fresh owned copy of the current vector. +// @available(SwiftStdlib 6.1, *) +// @_alwaysEmitIntoClient +// public borrowing func copy() -> Vector { +// Vector { +// self[$0] +// } +// } +// } + +//===----------------------------------------------------------------------===// +// RandomAccessCollection APIs +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Vector where Element: ~Copyable { + /// A type representing the collection's elements. + @available(SwiftStdlib 6.1, *) + public typealias Element = Element + + /// A type that represents a position in the collection. + /// + /// Valid indices consist of the position of every element and a + /// "past the end" position that's not valid for use as a subscript + /// argument. + @available(SwiftStdlib 6.1, *) + public typealias Index = Int + + /// A type that represents the indices that are valid for subscripting the + /// collection, in ascending order. + @available(SwiftStdlib 6.1, *) + public typealias Indices = Range + + /// The number of elements in the collection. + /// + /// - Complexity: O(1) + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public var count: Int { + Count + } + + /// The position of the first element in a nonempty collection. + /// + /// If the collection is empty, `startIndex` is equal to `endIndex`. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public var startIndex: Int { + 0 + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + /// + /// When you need a range that includes the last element of a collection, use + /// the half-open range operator (`..<`) with `endIndex`. The `..<` operator + /// creates a range that doesn't include the upper bound, so it's always + /// safe to use with `endIndex`. For example: + /// + /// let numbers = [10, 20, 30, 40, 50] + /// if let index = numbers.firstIndex(of: 30) { + /// print(numbers[index ..< numbers.endIndex]) + /// } + /// // Prints "[30, 40, 50]" + /// + /// If the collection is empty, `endIndex` is equal to `startIndex`. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public var endIndex: Int { + Count + } + + /// The indices that are valid for subscripting the collection, in ascending + /// order. + /// + /// A collection's `indices` property can hold a strong reference to the + /// collection itself, causing the collection to be nonuniquely referenced. + /// If you mutate the collection while iterating over its indices, a strong + /// reference can result in an unexpected copy of the collection. To avoid + /// the unexpected copy, use the `index(after:)` method starting with + /// `startIndex` to produce indices instead. + /// + /// var c = MyFancyCollection([10, 20, 30, 40, 50]) + /// var i = c.startIndex + /// while i != c.endIndex { + /// c[i] /= 5 + /// i = c.index(after: i) + /// } + /// // c == MyFancyCollection([2, 4, 6, 8, 10]) + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public var indices: Range { + startIndex ..< endIndex + } + + /// Returns the position immediately after the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be less than + /// `endIndex`. + /// - Returns: The index immediately after `i`. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public borrowing func index(after i: Int) -> Int { + i + 1 + } + + /// Returns the position immediately before the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be greater than + /// `startIndex`. + /// - Returns: The index value immediately before `i`. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public borrowing func index(before i: Int) -> Int { + i - 1 + } + + /// Accesses the element at the specified position. + /// + /// The following example accesses an element of an array through its + /// subscript to print its value: + /// + /// var streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"] + /// print(streets[1]) + /// // Prints "Bryant" + /// + /// You can subscript a collection with any valid index other than the + /// collection's end index. The end index refers to the position one past + /// the last element of a collection, so it doesn't correspond with an + /// element. + /// + /// - Parameter position: The position of the element to access. `position` + /// must be a valid index of the collection that is not equal to the + /// `endIndex` property. + /// + /// - Complexity: O(1) + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public subscript(_ i: Int) -> Element { + @_transparent + unsafeAddress { + _precondition(startIndex <= i && i < endIndex, "Index out of bounds") + + return address + i + } + + @_transparent + unsafeMutableAddress { + _precondition(startIndex <= i && i < endIndex, "Index out of bounds") + + return mutableAddress + i + } + } +} + +@available(SwiftStdlib 6.1, *) +extension Vector where Element: Copyable { + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public subscript(_ i: Int) -> Element { + get { + _precondition(startIndex <= i && i < endIndex, "Index out of bounds") + + return buffer[i] + } + + set { + _precondition(startIndex <= i && i < endIndex, "Index out of bounds") + + mutableBuffer[i] = newValue + } + } +} + +//===----------------------------------------------------------------------===// +// Unsafe APIs +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Vector where Element: ~Copyable { + /// Calls a closure with a pointer to the vector's contiguous storage. + /// + /// Often, the optimizer can eliminate bounds checks within a vector + /// algorithm, but when that fails, invoking the same algorithm on the + /// buffer pointer passed into your closure lets you trade safety for speed. + /// + /// The following example shows how you can iterate over the contents of the + /// buffer pointer: + /// + /// // "[1, 2, 3, 4, 5]" + /// let numbers = Vector<5, Int> { + /// $0 + 1 + /// } + /// + /// let sum = numbers.withUnsafeBufferPointer { buffer -> Int in + /// var result = 0 + /// for i in stride(from: buffer.startIndex, to: buffer.endIndex, by: 2) { + /// result += buffer[i] + /// } + /// return result + /// } + /// // 'sum' == 9 + /// + /// The pointer passed as an argument to `body` is valid only during the + /// execution of `withUnsafeBufferPointer(_:)`. Do not store or return the + /// pointer for later use. + /// + /// - Parameter body: A closure with an `UnsafeBufferPointer` parameter that + /// points to the contiguous storage for the vector. If `body` has a return + /// value, that value is also used as the return value for the + /// `withUnsafeBufferPointer(_:)` method. The pointer argument is valid only + /// for the duration of the method's execution. + /// - Returns: The return value, if any, of the `body` closure parameter. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public borrowing func withUnsafeBufferPointer( + _ body: (UnsafeBufferPointer) throws(E) -> Result + ) throws(E) -> Result { + try body(buffer) + } + + /// Calls the given closure with a pointer to the vector's mutable contiguous + /// storage. + /// + /// Often, the optimizer can eliminate bounds checks within a vector + /// algorithm, but when that fails, invoking the same algorithm on the + /// buffer pointer passed into your closure lets you trade safety for speed. + /// + /// The following example shows how modifying the contents of the + /// `UnsafeMutableBufferPointer` argument to `body` alters the contents of + /// the vector: + /// + /// // "[1, 2, 3, 4, 5]" + /// var numbers = Vector<5, Int> { + /// $0 + 1 + /// } + /// + /// numbers.withUnsafeMutableBufferPointer { buffer in + /// for i in stride(from: buffer.startIndex, to: buffer.endIndex - 1, by: 2) { + /// buffer.swapAt(i, i + 1) + /// } + /// } + /// + /// print(numbers.description) + /// // Prints "[2, 1, 4, 3, 5]" + /// + /// The pointer passed as an argument to `body` is valid only during the + /// execution of `withUnsafeMutableBufferPointer(_:)`. Do not store or + /// return the pointer for later use. + /// + /// - Warning: Do not rely on anything about the vector that is the target of + /// this method during execution of the `body` closure; it might not + /// appear to have its correct value. Instead, use only the + /// `UnsafeMutableBufferPointer` argument to `body`. + /// + /// - Parameter body: A closure with an `UnsafeMutableBufferPointer` + /// parameter that points to the contiguous storage for the vector. If + /// `body` has a return value, that value is also used as the return value + /// for the `withUnsafeMutableBufferPointer(_:)` method. The pointer + /// argument is valid only for the duration of the method's execution. + /// - Returns: The return value, if any, of the `body` closure parameter. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public mutating func withUnsafeMutableBufferPointer( + _ body: (UnsafeMutableBufferPointer) throws(E) -> Result + ) throws(E) -> Result { + try body(mutableBuffer) + } +} + +@available(SwiftStdlib 6.1, *) +extension Vector: RandomAccessCollection {} + +@available(SwiftStdlib 6.1, *) +extension Vector: MutableCollection {} + +//===----------------------------------------------------------------------===// +// Equatable +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Vector where Element: Equatable { + /// Returns a Boolean value indicating whether two vectors contain the same + /// elements in the same order. + /// + /// You can use the equal-to operator (`==`) to compare any two vectors + /// that store the same, `Equatable`-conforming element type. + /// + /// - Parameters: + /// - lhs: A vector to compare. + /// - rhs: Another vector to compare. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public static func ==( + lhs: borrowing Vector, + rhs: borrowing Vector + ) -> Bool { + // No need for a count check because these are statically guaranteed to have + // the same count... + + for i in 0 ..< Count { + guard lhs[i] == rhs[i] else { + return false + } + } + + return true + } +} + +//===----------------------------------------------------------------------===// +// CustomStringConvertible and CustomDebugStringConvertible APIs +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Vector where Element: CustomStringConvertible { + /// A textual representation of the vector and its elements. + @available(SwiftStdlib 6.1, *) + public var description: String { + var result = "[" + var isFirst = true + + for i in 0 ..< Count { + if !isFirst { + result += ", " + } else { + isFirst = false + } + + result += self[i].description + } + + result += "]" + return result + } +} + +@available(SwiftStdlib 6.1, *) +extension Vector where Element: CustomDebugStringConvertible { + /// A textual representation of the vector and its elements. + @available(SwiftStdlib 6.1, *) + public var debugDescription: String { + var result = "[" + var isFirst = true + + for i in 0 ..< Count { + if !isFirst { + result += ", " + } else { + isFirst = false + } + + result += self[i].debugDescription + } + + result += "]" + return result + } +} From 61702fb813b035b896021b11f4cc56b1fd7168c0 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 12:03:44 -0800 Subject: [PATCH 02/15] Implement Vector literals --- include/swift/AST/DiagnosticsSema.def | 7 +++ include/swift/AST/KnownStdlibTypes.def | 2 + include/swift/Sema/CSFix.h | 28 ++++++++++ lib/AST/Type.cpp | 5 +- lib/SILGen/SILGenExpr.cpp | 69 +++++++++++++++++++++++ lib/Sema/CSApply.cpp | 36 +++++++----- lib/Sema/CSDiagnostics.cpp | 5 ++ lib/Sema/CSDiagnostics.h | 18 ++++++ lib/Sema/CSFix.cpp | 14 +++++ lib/Sema/CSGen.cpp | 4 +- lib/Sema/CSSimplify.cpp | 48 +++++++++++++++- lib/Sema/ConstraintSystem.cpp | 14 +++++ lib/Sema/TypeCheckType.cpp | 3 + test/SILGen/vector_literal.swift | 77 ++++++++++++++++++++++++++ test/Sema/vector.swift | 66 ++++++++++++++++++++++ 15 files changed, 377 insertions(+), 19 deletions(-) create mode 100644 test/SILGen/vector_literal.swift create mode 100644 test/Sema/vector.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2b77c58419fab..596f90e255cd0 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8175,6 +8175,13 @@ ERROR(availability_value_generic_type_only_version_newer, none, ERROR(invalid_value_for_type_same_type,none, "cannot constrain type parameter %0 to be integer %1", (Type, Type)) +//===----------------------------------------------------------------------===// +// MARK: Vector +//===----------------------------------------------------------------------===// + +ERROR(vector_literal_incorrect_count,none, + "expected %0 elements in vector literal, but got %1", (Type, Type)) + //===----------------------------------------------------------------------===// // MARK: @abi Attribute //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/KnownStdlibTypes.def b/include/swift/AST/KnownStdlibTypes.def index d8c772bf9c7da..4e035163b94eb 100644 --- a/include/swift/AST/KnownStdlibTypes.def +++ b/include/swift/AST/KnownStdlibTypes.def @@ -97,4 +97,6 @@ KNOWN_STDLIB_TYPE_DECL(DecodingError, NominalTypeDecl, 0) KNOWN_STDLIB_TYPE_DECL(Result, NominalTypeDecl, 2) +KNOWN_STDLIB_TYPE_DECL(Vector, NominalTypeDecl, 2) + #undef KNOWN_STDLIB_TYPE_DECL diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 9821fcea3312c..8d2bc74684953 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -483,6 +483,10 @@ enum class FixKind : uint8_t { /// sending result, but is passed a function typed parameter without a sending /// result. AllowSendingMismatch, + + /// Ignore when a 'Vector' literal has mismatched number of elements to the + /// type it's attempting to bind to. + AllowVectorLiteralCountMismatch, }; class ConstraintFix { @@ -3837,6 +3841,30 @@ class IgnoreKeyPathSubscriptIndexMismatch final : public ConstraintFix { } }; +class AllowVectorLiteralCountMismatch final : public ConstraintFix { + Type lhsCount, rhsCount; + + AllowVectorLiteralCountMismatch(ConstraintSystem &cs, Type lhsCount, + Type rhsCount, ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::AllowVectorLiteralCountMismatch, locator), + lhsCount(lhsCount), rhsCount(rhsCount) {} + +public: + std::string getName() const override { + return "allow vector literal count mismatch"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + static AllowVectorLiteralCountMismatch * + create(ConstraintSystem &cs, Type lhsCount, Type rhsCount, + ConstraintLocator *locator); + + static bool classof(const ConstraintFix *fix) { + return fix->getKind() == FixKind::AllowVectorLiteralCountMismatch; + } +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 86a3f59b0b384..8c17d827e2d5f 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -808,8 +808,11 @@ CanType CanType::wrapInOptionalTypeImpl(CanType type) { Type TypeBase::isArrayType() { if (auto boundStruct = getAs()) { - if (boundStruct->getDecl() == getASTContext().getArrayDecl()) + if (isArray()) return boundStruct->getGenericArgs()[0]; + + if (isVector()) + return boundStruct->getGenericArgs()[1]; } return Type(); } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 535263b261953..cb89a805a04cc 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -4598,7 +4598,76 @@ visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C) { llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch."); } +static RValue emitVectorLiteral(SILGenFunction &SGF, CollectionExpr *E, + SGFContext C) { + ArgumentScope scope(SGF, E); + + auto vectorType = E->getType()->castTo(); + auto loweredVectorType = SGF.getLoweredType(vectorType); + auto elementType = vectorType->getGenericArgs()[1]->getCanonicalType(); + auto loweredElementType = SGF.getLoweredType(elementType); + auto &eltTL = SGF.getTypeLowering(AbstractionPattern::getOpaque(), elementType); + + SILValue alloc = SGF.emitTemporaryAllocation(E, loweredVectorType); + SILValue addr = SGF.B.createUncheckedAddrCast(E, alloc, + loweredElementType.getAddressType()); + + // Cleanups for any elements that have been initialized so far. + SmallVector cleanups; + + for (unsigned index : range(E->getNumElements())) { + auto destAddr = addr; + + if (index != 0) { + SILValue indexValue = SGF.B.createIntegerLiteral( + E, SILType::getBuiltinWordType(SGF.getASTContext()), index); + destAddr = SGF.B.createIndexAddr(E, addr, indexValue, + /*needsStackProtection=*/ false); + } + + // Create a dormant cleanup for the value in case we exit before the + // full vector has been constructed. + + CleanupHandle destCleanup = CleanupHandle::invalid(); + if (!eltTL.isTrivial()) { + destCleanup = SGF.enterDestroyCleanup(destAddr); + SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dormant); + cleanups.push_back(destCleanup); + } + + TemporaryInitialization init(destAddr, destCleanup); + + ArgumentSource(E->getElements()[index]) + .forwardInto(SGF, AbstractionPattern::getOpaque(), &init, eltTL); + } + + // Kill the per-element cleanups. The vector will take ownership of them. + for (auto destCleanup : cleanups) + SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dead); + + SILValue vectorVal; + + // If the vector is naturally address-only, then we can adopt the stack slot + // as the value directly. + if (loweredVectorType.isAddressOnly(SGF.F)) { + vectorVal = SGF.B.createUncheckedAddrCast(E, alloc, loweredVectorType); + } else { + // Otherwise, this vector is loadable. Load it. + vectorVal = SGF.B.createTrivialLoadOr(E, alloc, LoadOwnershipQualifier::Take); + } + + auto vectorMV = SGF.emitManagedRValueWithCleanup(vectorVal); + auto vector = RValue(SGF, E, vectorMV); + + return scope.popPreservingValue(std::move(vector)); +} + RValue RValueEmitter::visitCollectionExpr(CollectionExpr *E, SGFContext C) { + // Handle 'Vector' literals separately. + if (E->getType()->isVector()) { + return emitVectorLiteral(SGF, E, C); + } + auto loc = SILLocation(E); ArgumentScope scope(SGF, loc); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 0adfc3be4da74..f775331e5e2f8 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3792,23 +3792,29 @@ namespace { /// "Finish" an array expression by filling in the semantic expression. ArrayExpr *finishArrayExpr(ArrayExpr *expr) { Type arrayTy = cs.getType(expr); + Type elementType; - ProtocolDecl *arrayProto = TypeChecker::getProtocol( - ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral); - assert(arrayProto && "type-checked array literal w/o protocol?!"); + if (arrayTy->isVector()) { + // + elementType = arrayTy->castTo()->getGenericArgs()[1]; + } else { + ProtocolDecl *arrayProto = TypeChecker::getProtocol( + ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral); + assert(arrayProto && "type-checked array literal w/o protocol?!"); - auto conformance = checkConformance(arrayTy, arrayProto); - assert(conformance && "Type does not conform to protocol?"); + auto conformance = checkConformance(arrayTy, arrayProto); + assert(conformance && "Type does not conform to protocol?"); - DeclName name(ctx, DeclBaseName::createConstructor(), - {ctx.Id_arrayLiteral}); - ConcreteDeclRef witness = - conformance.getWitnessByName(arrayTy->getRValueType(), name); - if (!witness || !isa(witness.getDecl())) - return nullptr; - expr->setInitializer(witness); + DeclName name(ctx, DeclBaseName::createConstructor(), + {ctx.Id_arrayLiteral}); + ConcreteDeclRef witness = + conformance.getWitnessByName(arrayTy->getRValueType(), name); + if (!witness || !isa(witness.getDecl())) + return nullptr; + expr->setInitializer(witness); - auto elementType = expr->getElementType(); + elementType = expr->getElementType(); + } for (unsigned i = 0, n = expr->getNumElements(); i != n; ++i) { expr->setElement( @@ -6792,7 +6798,7 @@ Expr *ExprRewriter::buildCollectionUpcastExpr( bridged, locator, 0); // For single-parameter collections, form the upcast. - if (toType->isArrayType() || ConstraintSystem::isSetType(toType)) { + if (toType->isArray() || ConstraintSystem::isSetType(toType)) { return cs.cacheType( new (ctx) CollectionUpcastConversionExpr(expr, toType, {}, conv)); } @@ -6817,7 +6823,7 @@ Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType, // Bridged collection casts always succeed, so we treat them as // collection "upcasts". - if ((fromType->isArrayType() && toType->isArrayType()) + if ((fromType->isArray() && toType->isArray()) || (ConstraintSystem::isDictionaryType(fromType) && ConstraintSystem::isDictionaryType(toType)) || (ConstraintSystem::isSetType(fromType) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index dfb820e9993e1..22ff2f84176d7 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -9571,3 +9571,8 @@ bool InvalidTypeAsKeyPathSubscriptIndex::diagnoseAsError() { emitDiagnostic(diag::cannot_convert_type_to_keypath_subscript_index, ArgType); return true; } + +bool IncorrectVectorLiteralCount::diagnoseAsError() { + emitDiagnostic(diag::vector_literal_incorrect_count, lhsCount, rhsCount); + return true; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 7544300e20079..13591e8e834ed 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -3234,6 +3234,24 @@ class InvalidTypeAsKeyPathSubscriptIndex final : public FailureDiagnostic { bool diagnoseAsError() override; }; +/// Diagnose when a vector literal has an incorrect number of elements for the +/// contextual vector type it's initializing. +/// +/// \code +/// let x: Vector<4, Int> = [1, 2] // expected '4' elements but got '2' +/// \endcode +class IncorrectVectorLiteralCount final : public FailureDiagnostic { + Type lhsCount, rhsCount; + +public: + IncorrectVectorLiteralCount(const Solution &solution, Type lhsCount, + Type rhsCount, ConstraintLocator *locator) + : FailureDiagnostic(solution, locator), lhsCount(resolveType(lhsCount)), + rhsCount(resolveType(rhsCount)) {} + + bool diagnoseAsError() override; +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 139358d858ab1..fe22926e30f94 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -2722,3 +2722,17 @@ IgnoreKeyPathSubscriptIndexMismatch::create(ConstraintSystem &cs, Type argType, return new (cs.getAllocator()) IgnoreKeyPathSubscriptIndexMismatch(cs, argType, locator); } + +AllowVectorLiteralCountMismatch * +AllowVectorLiteralCountMismatch::create(ConstraintSystem &cs, Type lhsCount, + Type rhsCount, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + AllowVectorLiteralCountMismatch(cs, lhsCount, rhsCount, locator); +} + +bool AllowVectorLiteralCountMismatch::diagnose(const Solution &solution, + bool asNote) const { + IncorrectVectorLiteralCount failure(solution, lhsCount, rhsCount, getLocator()); + return failure.diagnose(asNote); +} diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 81cac0044f9ab..7d2e4bb90a2d8 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -333,7 +333,7 @@ namespace { baseObjTy = baseObjTy->getWithoutSpecifierType(); } - if (baseObjTy->isArrayType()) { + if (auto elementTy = baseObjTy->isArrayType()) { if (auto arraySliceTy = dyn_cast(baseObjTy.getPointer())) { @@ -343,7 +343,7 @@ namespace { if (argList->isUnlabeledUnary() && isa(argList->getExpr(0))) { - outputTy = baseObjTy->getAs()->getGenericArgs()[0]; + outputTy = elementTy; if (isLValueBase) outputTy = LValueType::get(outputTy); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index cb83e5ac609fd..d66faed5eb14e 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -7779,7 +7779,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, // Special implicit nominal conversions. if (!type1->is() && kind >= ConstraintKind::Subtype) { // Array -> Array. - if (desugar1->isArrayType() && desugar2->isArrayType()) { + if (desugar1->isArray() && desugar2->isArray()) { conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast); // Dictionary -> Dictionary. } else if (isDictionaryType(desugar1) && isDictionaryType(desugar2)) { @@ -8698,6 +8698,51 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( } } } + + auto arrayLiteralProto = + getASTContext().getProtocol(KnownProtocolKind::ExpressibleByArrayLiteral); + auto anchor = loc->getAnchor(); + auto arrayLiteral = getAsExpr(anchor); + + // If we're attempting to bind an array literal to a 'Vector' parameter, + // then check if the counts are equal and solve. + if (kind == ConstraintKind::LiteralConformsTo && + protocol == arrayLiteralProto && + type->isVector() && + arrayLiteral) { + auto vectorTy = type->castTo(); + + // + // Attempt to bind the number of elements in the literal with the + // contextual count. This will diagnose if the literal does not enough + // or too many elements. + auto contextualCount = vectorTy->getGenericArgs()[0]; + auto literalCount = IntegerType::get( + std::to_string(arrayLiteral->getNumElements()), + /* isNegative */ false, + vectorTy->getASTContext()); + + // If the counts are already equal, '2' == '2', then we're done. + if (contextualCount->isEqual(literalCount)) { + return SolutionKind::Solved; + } + + // If our contextual count is not known, e.g., Vector<_, Int> = [1, 2], + // then just eagerly bind the count to what the literal count is. + if (contextualCount->isTypeVariableOrMember()) { + addConstraint(ConstraintKind::Bind, contextualCount, literalCount, + locator); + return SolutionKind::Solved; + } + + // Otherwise this is an error and the counts aren't equal to each other. + if (!shouldAttemptFixes()) + return SolutionKind::Error; + + auto fix = AllowVectorLiteralCountMismatch::create(*this, contextualCount, + literalCount, loc); + return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; + } } break; default: @@ -15609,6 +15654,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::IgnoreInvalidPlaceholder: case FixKind::IgnoreOutOfPlaceThenStmt: case FixKind::IgnoreMissingEachKeyword: + case FixKind::AllowVectorLiteralCountMismatch: llvm_unreachable("handled elsewhere"); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 10399eae78625..5caf109afde87 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1666,6 +1666,20 @@ struct TypeSimplifier { auto *proto = assocType->getProtocol(); auto conformance = CS.lookupConformance(lookupBaseType, proto); if (!conformance) { + // Special case: When building vector literals, we go through the same + // array literal machinery, so there will be a conversion constraint + // for the element to ExpressibleByArrayLiteral.ArrayLiteralType. + if (lookupBaseType->isVector()) { + auto &ctx = CS.getASTContext(); + auto arrayProto = + ctx.getProtocol(KnownProtocolKind::ExpressibleByArrayLiteral); + auto elementAssocTy = arrayProto->getAssociatedTypeMembers()[0]; + + if (proto == arrayProto && assocType == elementAssocTy) { + return lookupBaseType->isArrayType(); + } + } + // If the base type doesn't conform to the associatedtype's protocol, // there will be a missing conformance fix applied in diagnostic mode, // so the concrete dependent member type is considered a "hole" in diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 9822d574fa013..9beb7b102e0f6 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -748,6 +748,9 @@ namespace { if (secondType->is()) return true; + if (secondType->is()) + return true; + return false; } diff --git a/test/SILGen/vector_literal.swift b/test/SILGen/vector_literal.swift new file mode 100644 index 0000000000000..f5b01e5a525b2 --- /dev/null +++ b/test/SILGen/vector_literal.swift @@ -0,0 +1,77 @@ +// RUN: %target-swift-emit-silgen %s -disable-availability-checking -enable-experimental-feature ValueGenerics | %FileCheck %s + +// 123REQUIRES123: swift_feature_ValueGenerics + +import Synchronization + +// CHECK-LABEL: sil{{.*}} @$s14vector_literal7trivials6VectorVy$3_SiGyF : $@convention(thin) () -> Vector<4, Int> { +// CHECK: [[VECTOR_ALLOC:%.*]] = alloc_stack $Vector<4, Int> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[VECTOR_ALLOC]] : $*Vector<4, Int> to $*Int +// CHECK-NEXT: [[ELT_0_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 1 +// CHECK: [[ELT_0:%.*]] = apply {{%.*}}([[ELT_0_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK-NEXT: store [[ELT_0]] to [trivial] [[ELEMENT_PTR]] : $*Int +// CHECK-NEXT: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*Int, [[ELT_1_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_1_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 2 +// CHECK: [[ELT_1:%.*]] = apply {{%.*}}([[ELT_1_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK-NEXT: store [[ELT_1]] to [trivial] [[ELT_1_PTR]] : $*Int +// CHECK-NEXT: [[ELT_2_OFFSET:%.*]] = integer_literal $Builtin.Word, 2 +// CHECK-NEXT: [[ELT_2_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*Int, [[ELT_2_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_2_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 3 +// CHECK: [[ELT_2:%.*]] = apply {{%.*}}([[ELT_2_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK-NEXT: store [[ELT_2]] to [trivial] [[ELT_2_PTR]] : $*Int +// CHECK-NEXT: [[ELT_3_OFFSET:%.*]] = integer_literal $Builtin.Word, 3 +// CHECK-NEXT: [[ELT_3_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*Int, [[ELT_3_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_3_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 4 +// CHECK: [[ELT_3:%.*]] = apply {{%.*}}([[ELT_3_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK-NEXT: store [[ELT_3]] to [trivial] [[ELT_3_PTR]] : $*Int +// CHECK-NEXT: [[VECTOR:%.*]] = load [trivial] [[VECTOR_ALLOC]] : $*Vector<4, Int> +// CHECK-NEXT: dealloc_stack [[VECTOR_ALLOC]] : $*Vector<4, Int> +// CHECK-NEXT: return [[VECTOR]] : $Vector<4, Int> +// CHECK-LABEL: } // end sil function '$s14vector_literal7trivials6VectorVy$3_SiGyF' +func trivial() -> Vector<4, Int> { + [1, 2, 3, 4] +} + +// CHECK-LABEL: sil{{.*}} @$s14vector_literal10nontrivials6VectorVy$1_SSGyF : $@convention(thin) () -> @owned Vector<2, String> { +// CHECK: [[VECTOR_ALLOC:%.*]] = alloc_stack $Vector<2, String> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[VECTOR_ALLOC]] : $*Vector<2, String> to $*String +// CHECK-NEXT: [[ELT_0_LITERAL:%.*]] = string_literal utf8 "hello" +// CHECK: [[ELT_0:%.*]] = apply {{%.*}}([[ELT_0_LITERAL]], {{.*}}) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String +// CHECK-NEXT: store [[ELT_0]] to [init] [[ELEMENT_PTR]] : $*String +// CHECK-NEXT: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*String, [[ELT_1_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_1_LITERAL:%.*]] = string_literal utf8 "world" +// CHECK: [[ELT_1:%.*]] = apply {{%.*}}([[ELT_1_LITERAL]], {{.*}}) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String +// CHECK-NEXT: store [[ELT_1]] to [init] [[ELT_1_PTR]] : $*String +// CHECK-NEXT: [[VECTOR:%.*]] = load [take] [[VECTOR_ALLOC]] : $*Vector<2, String> +// CHECK-NEXT: dealloc_stack [[VECTOR_ALLOC]] : $*Vector<2, String> +// CHECK-NEXT: return [[VECTOR]] : $Vector<2, String> +// CHECK-LABEL: } // end sil function '$s14vector_literal10nontrivials6VectorVy$1_SSGyF' +func nontrivial() -> Vector<2, String> { + ["hello", "world"] +} + +// CHECK-LABEL: sil{{.*}} @$s14vector_literal11noncopyables6VectorVy$1_15Synchronization6AtomicVySiGGyF : $@convention(thin) () -> @out Vector<2, Atomic> { +// CHECK: bb0([[VECTOR_RETURN:%.*]] : $*Vector<2, Atomic>): +// CHECK-NEXT: [[VECTOR_ALLOC:%.*]] = alloc_stack $Vector<2, Atomic> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[VECTOR_ALLOC]] : $*Vector<2, Atomic> to $*Atomic +// CHECK: [[ATOMIC_INIT:%.*]] = function_ref @$s15Synchronization6AtomicVyACyxGxcfC +// CHECK-NEXT: [[ELT_0:%.*]] = apply [[ATOMIC_INIT]]([[ELEMENT_PTR]], {{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : AtomicRepresentable> (@in τ_0_0, @thin Atomic<τ_0_0>.Type) -> @out Atomic<τ_0_0> +// CHECK: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*Atomic, [[ELT_1_OFFSET]] : $Builtin.Word +// CHECK: [[ATOMIC_INIT:%.*]] = function_ref @$s15Synchronization6AtomicVyACyxGxcfC +// CHECK-NEXT: [[ELT_1:%.*]] = apply [[ATOMIC_INIT]]([[ELT_1_PTR]], {{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : AtomicRepresentable> (@in τ_0_0, @thin Atomic<τ_0_0>.Type) -> @out Atomic<τ_0_0> +// CHECK: [[VECTOR_ALLOC_AGAIN:%.*]] = unchecked_addr_cast [[VECTOR_ALLOC]] : $*Vector<2, Atomic> to $*Vector<2, Atomic> +// CHECK-NEXT: [[BOX:%.*]] = alloc_box +// CHECK-NEXT: [[BOX_BORROW:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK-NEXT: [[BOX_PROJECT:%.*]] = project_box [[BOX_BORROW]] +// CHECK-NEXT: copy_addr [take] [[VECTOR_ALLOC_AGAIN]] to [init] [[BOX_PROJECT]] : $*Vector<2, Atomic> +// CHECK-NEXT: dealloc_stack [[VECTOR_ALLOC]] : $*Vector<2, Atomic> +// CHECK-NEXT: copy_addr [take] [[BOX_PROJECT]] to [init] [[VECTOR_RETURN]] : $*Vector<2, Atomic> +// CHECK-NEXT: end_borrow [[BOX_BORROW]] +// CHECK-NEXT: dealloc_box [[BOX]] +// CHECK-LABEL: } // end sil function '$s14vector_literal11noncopyables6VectorVy$1_15Synchronization6AtomicVySiGGyF' +func noncopyable() -> Vector<2, Atomic> { + [Atomic(0), Atomic(1)] +} diff --git a/test/Sema/vector.swift b/test/Sema/vector.swift new file mode 100644 index 0000000000000..c2798dc29d655 --- /dev/null +++ b/test/Sema/vector.swift @@ -0,0 +1,66 @@ +// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature ValueGenerics + +// REQUIRES: swift_feature_ValueGenerics + +let a: Vector = [1, 2, 3] // Ok, Vector<3, Int> +let b: Vector<_, Int> = [1, 2, 3] // Ok, Vector<3, Int> +let c: Vector<3, _> = [1, 2, 3] // Ok, Vector<3, Int> + +let d: Vector<2, _> = [1, 2, 3] // expected-error {{expected '2' elements in vector literal, but got '3'}} +let e: Vector<2, _> = [1] // expected-error {{expected '2' elements in vector literal, but got '1'}} + +let f: Vector<_, Int> = ["hello"] // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} + +func takeVectorOf2(_: Vector<2, T>) {} + +takeVectorOf2([1, 2]) // Ok +takeVectorOf2(["hello", "world"]) // Ok + +takeVectorOf2([1]) // expected-error {{expected '2' elements in vector literal, but got '1'}} + +takeVectorOf2([1, 2, 3]) // expected-error {{expected '2' elements in vector literal, but got '3'}} + +takeVectorOf2(["hello"]) // expected-error {{expected '2' elements in vector literal, but got '1'}} + +takeVectorOf2(["hello", "world", "!"]) // expected-error {{expected '2' elements in vector literal, but got '3'}} + +func takeVectorOf2Int(_: Vector<2, Int>) {} + +takeVectorOf2Int([1, 2]) // Ok + +takeVectorOf2Int([1]) // expected-error {{expected '2' elements in vector literal, but got '1'}} + +takeVectorOf2Int([1, 2, 3]) // expected-error {{expected '2' elements in vector literal, but got '3'}} + +takeVectorOf2Int(["hello"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Vector<2, Int>'}} + +takeVectorOf2Int(["hello", "world"]) // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} + // expected-error@-1 {{cannot convert value of type 'String' to expected element type 'Int'}} + +takeVectorOf2Int(["hello", "world", "!"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Vector<2, Int>'}} + +struct X { + var sprites: Vector<2, Int> +} + +func foo(x: inout X) { + x.sprites = [1, 2, 3] // expected-error {{cannot assign value of type '[Int]' to type 'Vector<2, Int>'}} +} + +struct MySprites { + var bricks: Vector<40, MySprite> +} + +struct MySprite { + var x = 42 +} + +nonisolated(unsafe) +var sprites: MySprites? = nil + +func foo() { + let bricks: Vector<1, MySprite> = [MySprite()] + + sprites = .init(bricks: bricks) // expected-error {{cannot convert value of type 'Vector<1, MySprite>' to expected argument type 'Vector<40, MySprite>'}} + // expected-note@-1 {{arguments to generic parameter 'count' ('1' and '40') are expected to be equal}} +} From 6ffaf4befc1935699d70ee4c5decb517a1c5a9b0 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 12:04:59 -0800 Subject: [PATCH 03/15] Don't ask for TypeInfo of IntegerType when generating debug info for generic args --- lib/IRGen/GenType.cpp | 2 +- lib/IRGen/IRGenDebugInfo.cpp | 17 +++++++++----- test/DebugInfo/value-generics-embedded.swift | 24 ++++++++++++++++++++ test/DebugInfo/value-generics.swift | 9 ++++++-- 4 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 test/DebugInfo/value-generics-embedded.swift diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 3bfe1b11eebca..4fcd781368173 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -2375,7 +2375,7 @@ const TypeInfo *TypeConverter::convertType(CanType ty) { case TypeKind::SILToken: llvm_unreachable("should not be asking for representation of a SILToken"); case TypeKind::Integer: - llvm_unreachable("implement me"); + llvm_unreachable("should not be asking for the type info an IntegerType"); } } llvm_unreachable("bad type kind"); diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index d974f863d9806..18dc74ca43c48 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1534,13 +1534,18 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type, for (auto Arg : GenericArgs) { DebugTypeInfo ParamDebugType; if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes && - !AsForwardDeclarations) - // For the DwarfTypes level don't generate just a forward declaration - // for the generic type parameters. - ParamDebugType = DebugTypeInfo::getFromTypeInfo( - Arg, IGM.getTypeInfoForUnlowered(Arg), IGM); - else + !AsForwardDeclarations) { + if (Arg->is()) { + ParamDebugType = DebugTypeInfo(Arg); + } else { + // For the DwarfTypes level don't generate just a forward declaration + // for the generic type parameters. + ParamDebugType = DebugTypeInfo::getFromTypeInfo( + Arg, IGM.getTypeInfoForUnlowered(Arg), IGM); + } + } else { ParamDebugType = DebugTypeInfo::getForwardDecl(Arg); + } TemplateParams.push_back(DBuilder.createTemplateTypeParameter( TheCU, "", getOrCreateType(ParamDebugType), false)); diff --git a/test/DebugInfo/value-generics-embedded.swift b/test/DebugInfo/value-generics-embedded.swift new file mode 100644 index 0000000000000..88aa4e00621ab --- /dev/null +++ b/test/DebugInfo/value-generics-embedded.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend %s -target %target-cpu-apple-macos14 -emit-ir -g -enable-experimental-feature ValueGenerics -enable-experimental-feature Embedded -wmo -disable-availability-checking -o - | %FileCheck %s + +// REQUIR123ES: swift_feature_ValueGenerics + +// CHECK-DAG: !DICompositeType({{.*}}templateParams: ![[VECTOR_PARAMS:.*]], {{.*}}identifier: "$ss6VectorVy$0_4main8MySpriteVGD" +// CHECK-DAG: ![[VECTOR_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} +// CHECK-DAG: ![[COUNT_PARAM]] = !DITemplateTypeParameter(type: ![[COUNT_TYPE:.*]]) +// CHECK-DAG: ![[COUNT_TYPE]] = !DICompositeType({{.*}}name: "$s$0_D" +// CHECK-DAG: ![[ELEMENT_PARAM]] = !DITemplateTypeParameter(type: ![[ELEMENT_TYPE:.*]]) +// CHECK-DAG: ![[ELEMENT_TYPE]] = !DICompositeType({{.*}}name: "MySprite", {{.*}}identifier: "$s4main8MySpriteVD" +struct MySprites { + var bricks: Vector<1,MySprite> +} + +struct MySprite { + var x = 42 +} + +nonisolated(unsafe) +var sprites: MySprites? = nil +public func foo() { + let bricks: Vector<1,MySprite> = [MySprite()] + sprites = .init(bricks: bricks) +} diff --git a/test/DebugInfo/value-generics.swift b/test/DebugInfo/value-generics.swift index 0cb8fdfab3802..ecedba104bcf6 100644 --- a/test/DebugInfo/value-generics.swift +++ b/test/DebugInfo/value-generics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend %s -emit-ir -g -enable-builtin-module -enable-experimental-feature ValueGenerics -disable-experimental-parser-round-trip -disable-availability-checking -o - | %FileCheck %s +// RUN: %target-swift-frontend %s -emit-ir -g -enable-builtin-module -enable-experimental-feature ValueGenerics -disable-availability-checking -o - | %FileCheck %s // REQUIRES: swift_feature_ValueGenerics @@ -19,5 +19,10 @@ func genericV(_: Vector) {} // CHECK-DAG: !DICompositeType({{.*}}name: "Builtin.FixedArray", {{.*}}identifier: "$s$3_SiBVD" func concreteBA(_: Builtin.FixedArray<4, Int>) {} -// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main6VectorVy$1_SiGD" +// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main6VectorVy$1_SiGD", {{.*}}templateParams: ![[VECTOR_PARAMS:.*]]) +// CHECK-DAG: ![[VECTOR_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} +// CHECK-DAG: ![[COUNT_PARAM]] = !DITemplateTypeParameter(type: ![[COUNT_TYPE:.*]]) +// CHECK-DAG: ![[COUNT_TYPE]] = !DICompositeType({{.*}}name: "$s$1_D" +// CHECK-DAG: ![[ELEMENT_PARAM]] = !DITemplateTypeParameter(type: ![[ELEMENT_TYPE:.*]]) +// CHECK-DAG: ![[ELEMENT_TYPE]] = !DICompositeType({{.*}}name: "$sSiD" func concreteV(_: Vector<2, Int>) {} From b9487d132a02f004011d5a31cc6c568c8c13033c Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 12:23:11 -0800 Subject: [PATCH 04/15] Cache the value type of a generic param when cloning --- lib/AST/ASTDumper.cpp | 1 + lib/AST/GenericParamList.cpp | 7 +++++++ test/SILGen/vector_literal.swift | 2 +- test/Sema/vector.swift | 16 ++++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index feb308e35ead2..44d360bb66969 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1277,6 +1277,7 @@ namespace { break; case GenericTypeParamKind::Value: printField((StringRef)"value", "param_kind"); + printRec(decl->getValueType(), "value_type"); break; } printAttributes(decl); diff --git a/lib/AST/GenericParamList.cpp b/lib/AST/GenericParamList.cpp index 366fa42d28292..7ca5ffbb42f36 100644 --- a/lib/AST/GenericParamList.cpp +++ b/lib/AST/GenericParamList.cpp @@ -17,6 +17,7 @@ #include "swift/AST/GenericParamList.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/Assertions.h" @@ -78,6 +79,12 @@ GenericParamList::clone(DeclContext *dc) const { dc, param->getName(), GenericTypeParamDecl::InvalidDepth, param->getIndex(), param->getParamKind(), param->getOpaqueTypeRepr()); newParam->setInherited(param->getInherited().getEntries()); + + // Cache the value type computed from the previous param to the new one. + ctx.evaluator.cacheOutput( + GenericTypeParamDeclGetValueTypeRequest{newParam}, + param->getValueType()); + params.push_back(newParam); } diff --git a/test/SILGen/vector_literal.swift b/test/SILGen/vector_literal.swift index f5b01e5a525b2..1f3f560bf88c9 100644 --- a/test/SILGen/vector_literal.swift +++ b/test/SILGen/vector_literal.swift @@ -1,6 +1,6 @@ // RUN: %target-swift-emit-silgen %s -disable-availability-checking -enable-experimental-feature ValueGenerics | %FileCheck %s -// 123REQUIRES123: swift_feature_ValueGenerics +// REQUIRES: swift_feature_ValueGenerics import Synchronization diff --git a/test/Sema/vector.swift b/test/Sema/vector.swift index c2798dc29d655..10851fe3ead82 100644 --- a/test/Sema/vector.swift +++ b/test/Sema/vector.swift @@ -64,3 +64,19 @@ func foo() { sprites = .init(bricks: bricks) // expected-error {{cannot convert value of type 'Vector<1, MySprite>' to expected argument type 'Vector<40, MySprite>'}} // expected-note@-1 {{arguments to generic parameter 'count' ('1' and '40') are expected to be equal}} } + +// Make sure the deserialized integer generic argument gets treated as an integer +// generic argument when we clone the generic param list for extensions. +extension Vector where Element: ~Copyable { + func forEach(_ body: (borrowing Element) -> Void) { + for i in 0 ..< count { + body(self[i]) + } + } + + func enumerated(_ body: (Int, borrowing Element) -> Void) { + for i in 0 ..< count { + body(i, self[i]) + } + } +} From 0f30cdfb319cc31276a3bc00a086ed6a01df5654 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 12:23:43 -0800 Subject: [PATCH 05/15] Allow Builtin.emplace to have typed throws --- lib/AST/Builtins.cpp | 32 ++++++++++++++++++++++++++------ lib/SILGen/SILGenBuiltin.cpp | 30 +++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index caaaafe36aafc..ad54fc4cf72d7 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -442,7 +442,7 @@ enum class BuiltinThrowsKind : uint8_t { static FuncDecl *getBuiltinGenericFunction( Identifier Id, ArrayRef ArgParamTypes, Type ResType, GenericParamList *GenericParams, GenericSignature Sig, bool Async, - BuiltinThrowsKind Throws, bool SendingResult) { + BuiltinThrowsKind Throws, Type ThrownError, bool SendingResult) { assert(GenericParams && "Missing generic parameters"); auto &Context = ResType->getASTContext(); @@ -471,7 +471,7 @@ static FuncDecl *getBuiltinGenericFunction( Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), Async, - Throws != BuiltinThrowsKind::None, /*thrownType=*/Type(), + Throws != BuiltinThrowsKind::None, ThrownError, GenericParams, paramList, ResType, DC); func->setSendingResult(SendingResult); @@ -696,6 +696,7 @@ namespace { Type InterfaceResult; bool Async = false; BuiltinThrowsKind Throws = BuiltinThrowsKind::None; + Type ThrownError; bool SendingResult = false; // Accumulate params and requirements here, so that we can call @@ -740,6 +741,11 @@ namespace { InterfaceResult = generator.build(*this); } + template + void setThrownError(const G &generator) { + ThrownError = generator.build(*this); + } + template void addConformanceRequirement(const G &generator, KnownProtocolKind kp) { addConformanceRequirement(generator, Context.getProtocol(kp)); @@ -776,7 +782,7 @@ namespace { /*allowInverses=*/false); return getBuiltinGenericFunction(name, InterfaceParams, InterfaceResult, TheGenericParamList, GenericSig, Async, - Throws, SendingResult); + Throws, ThrownError, SendingResult); } // Don't use these generator classes directly; call the make{...} @@ -2231,17 +2237,31 @@ static ValueDecl *getAddressOfRawLayout(ASTContext &ctx, Identifier id) { } static ValueDecl *getEmplace(ASTContext &ctx, Identifier id) { - BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 1); + BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 2); - auto T = makeGenericParam(); + // ( + // _: (Builtin.RawPointer) throws(E) -> () + // ) throws(E) -> T + + auto T = makeGenericParam(0); builder.addConformanceRequirement(T, KnownProtocolKind::Escapable); + auto E = makeGenericParam(1); + builder.addConformanceRequirement(E, KnownProtocolKind::Error); + + auto extInfo = ASTExtInfoBuilder() + .withNoEscape() + .withThrows(/* throws */ true, E.build(builder)) + .build(); + auto fnParamTy = FunctionType::get(FunctionType::Param(ctx.TheRawPointerType), ctx.TheEmptyTupleType, - ASTExtInfo().withNoEscape()); + extInfo); builder.addParameter(makeConcrete(fnParamTy), ParamSpecifier::Borrowing); builder.setResult(T); + builder.setThrows(); + builder.setThrownError(E); return builder.build(id); } diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index 132aa55af27b7..dac0e2fab314a 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -2133,12 +2133,36 @@ static ManagedValue emitBuiltinEmplace(SILGenFunction &SGF, SILValue bufferPtr = SGF.B.createAddressToPointer(loc, buffer, SILType::getPrimitiveObjectType(SGF.getASTContext().TheRawPointerType), /*needs stack protection*/ true); - SGF.B.createApply(loc, args[0].getValue(), {}, bufferPtr); - + + auto fnType = args[0].getValue()->getType().castTo(); + + if (fnType->hasErrorResult()) { + auto normalBB = SGF.createBasicBlock(); + auto errorBB = SGF.createBasicBlock(); + + SGF.B.createTryApply(loc, args[0].getValue(), {}, + {SGF.IndirectErrorResult, bufferPtr}, normalBB, errorBB); + + // Error branch + { + SGF.B.emitBlock(errorBB); + + SGF.Cleanups.emitCleanupsForReturn(CleanupLocation(loc), IsForUnwind); + + SGF.B.createThrowAddr(loc); + } + + SGF.B.emitBlock(normalBB); + + normalBB->createPhiArgument(SILType::getEmptyTupleType(Ctx), + OwnershipKind::Owned); + } else { + SGF.B.createApply(loc, args[0].getValue(), {}, bufferPtr); + } + dest->finishInitialization(SGF); if (didEmitInto) { - C.getEmitInto()->finishInitialization(SGF); return ManagedValue::forInContext(); } From 2823d3018f741d5c87f7dbb5dba7c405723736cc Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 12:23:59 -0800 Subject: [PATCH 06/15] Some Vector API changes --- stdlib/public/core/CMakeLists.txt | 1 - stdlib/public/core/Vector.swift | 357 +++++++++++++++++++++--------- 2 files changed, 253 insertions(+), 105 deletions(-) diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 5d964ed29e7ef..f9ec533469129 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -319,7 +319,6 @@ list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Macros") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "FreestandingMacros") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Extern") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "BitwiseCopyable") -list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "RawLayout") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "ValueGenerics") if("${SWIFT_NATIVE_SWIFT_TOOLS_PATH}" STREQUAL "") diff --git a/stdlib/public/core/Vector.swift b/stdlib/public/core/Vector.swift index a364273aea29a..6b5189be5a4ac 100644 --- a/stdlib/public/core/Vector.swift +++ b/stdlib/public/core/Vector.swift @@ -13,14 +13,17 @@ /// A fixed-size array. @available(SwiftStdlib 6.1, *) @frozen -public struct Vector: ~Copyable { +public struct Vector: ~Copyable { @usableFromInline - let storage: Builtin.FixedArray + let storage: Builtin.FixedArray } @available(SwiftStdlib 6.1, *) extension Vector: Copyable where Element: Copyable {} +@available(SwiftStdlib 6.1, *) +extension Vector: BitwiseCopyable where Element: BitwiseCopyable {} + @available(SwiftStdlib 6.1, *) extension Vector: @unchecked Sendable where Element: Sendable & ~Copyable {} @@ -43,7 +46,7 @@ extension Vector where Element: ~Copyable { @_alwaysEmitIntoClient @_transparent var buffer: UnsafeBufferPointer { - UnsafeBufferPointer(start: address, count: Count) + UnsafeBufferPointer(start: address, count: count) } /// Returns a mutable pointer to the first element in the vector. @@ -62,48 +65,155 @@ extension Vector where Element: ~Copyable { @_transparent var mutableBuffer: UnsafeMutableBufferPointer { mutating get { - UnsafeMutableBufferPointer(start: mutableAddress, count: Count) + UnsafeMutableBufferPointer(start: mutableAddress, count: count) } } + + /// Returns the given raw pointer, which points at an uninitialized vector + /// instance, to a mutable buffer suitable for initialization. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + static func _initializationBuffer( + start: Builtin.RawPointer + ) -> UnsafeMutableBufferPointer { + UnsafeMutableBufferPointer( + start: UnsafeMutablePointer(start), + count: count + ) + } } //===----------------------------------------------------------------------===// // Initialization APIs //===----------------------------------------------------------------------===// -// @available(SwiftStdlib 6.1, *) -// extension Vector where Element: ~Copyable { -// /// Initializes every element in this vector running the given closure value -// /// that returns the element to emplace at the given index. -// /// -// /// This will call the closure `Count` times, where `Count` is the static -// /// count of the vector, to initialize every element by passing the closure -// /// the index of the current element being initialized. The closure is allowed -// /// to throw an error at any point during initialization at which point the -// /// vector will stop initialization, deinitialize every currently initialized -// /// element, and throw the given error back out to the caller. -// /// -// /// - Parameter body: A closure that returns an owned `Element` to emplace at -// /// the passed in index. -// @available(SwiftStdlib 6.1, *) -// @_alwaysEmitIntoClient -// public init(_ body: (Int) throws(E) -> Element) throws(E) { -// for i in 0 ..< Count { -// do { -// try buffer.initializeElement(at: i, to: body(i)) -// } catch { -// // The closure threw an error. We need to deinitialize every element -// // we've initialized up to this point. -// for j in 0 ..< i { -// buffer.deinitializeElement(at: j) -// } - -// // Throw the error we were given back out to the caller. -// throw error -// } -// } -// } -// } +@available(SwiftStdlib 6.1, *) +extension Vector where Element: ~Copyable { + /// Initializes every element in this vector running the given closure value + /// that returns the element to emplace at the given index. + /// + /// This will call the closure `Count` times, where `Count` is the static + /// count of the vector, to initialize every element by passing the closure + /// the index of the current element being initialized. The closure is allowed + /// to throw an error at any point during initialization at which point the + /// vector will stop initialization, deinitialize every currently initialized + /// element, and throw the given error back out to the caller. + /// + /// - Parameter body: A closure that returns an owned `Element` to emplace at + /// the passed in index. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public init(_ body: (Int) throws(E) -> Element) throws(E) { + self = try Builtin.emplace { (rawPtr) throws(E) -> () in + let buffer = Vector._initializationBuffer(start: rawPtr) + + for i in 0 ..< count { + do throws(E) { + try buffer.initializeElement(at: i, to: body(i)) + } catch { + // The closure threw an error. We need to deinitialize every element + // we've initialized up to this point. + for j in 0 ..< i { + buffer.deinitializeElement(at: j) + } + + // Throw the error we were given back out to the caller. + throw error + } + } + } + } + + /// Initializes every element in this vector by running the closure with the + /// passed in mutable state. + /// + /// This will call the closure 'count' times, where 'count' is the static + /// count of the vector, to initialize every element by passing the closure + /// an inout reference to the passed state. The closure is allowed to throw + /// an error at any point during initialization at which point the vector will + /// stop initialization, deinitialize every currently initialized element, and + /// throw the given error back out to the caller. + /// + /// - Parameter state: The mutable state that can be altered during each + /// iteration of the closure initializing the vector. + /// - Parameter next: A closure that passes in an inout reference to the + /// user given mutable state which returns an owned + /// `Element` instance to insert into the vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public init( + expand state: consuming State, + with next: (inout State) throws(E) -> Element + ) throws(E) { + self = try Builtin.emplace { (rawPtr) throws(E) -> () in + let buffer = Vector._initializationBuffer(start: rawPtr) + + for i in 0 ..< count { + do throws(E) { + try buffer.initializeElement(at: i, to: next(&state)) + } catch { + // The closure threw an error. We need to deinitialize every element + // we've initialized up to this point. + for j in 0 ..< i { + buffer.deinitializeElement(at: j) + } + + throw error + } + } + } + } + + /// Initializes every element in this vector by running the closure with the + /// passed in first element. + /// + /// This will call the closure 'count' times, where 'count' is the static + /// count of the vector, to initialize every element by passing the closure + /// an immutable borrow reference to the first element given to the + /// initializer. The closure is allowed to throw an error at any point during + /// initialization at which point the vector will stop initialization, + /// deinitialize every currently initialized element, and throw the given + /// error back out to the caller. + /// + /// - Parameter first: The first value to insert into the vector which will be + /// passed to the closure as a borrow. + /// - Parameter next: A closure that passes in an immutable borrow reference + /// of the given first element of the vector which returns + /// an owned `Element` instance to insert into the vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public init( + unfold first: consuming Element, + with next: (borrowing Element) throws(E) -> Element + ) throws(E) { + // FIXME: We should be able to mark 'Builtin.emplace' as '@once' or something + // to give the compiler enough information to know we will only run + // it once so it can consume the capture. For now, we use an optional + // and take the underlying value within the closure. + var o: Element? = first + + self = try Builtin.emplace { (rawPtr) throws(E) -> () in + let buffer = Vector._initializationBuffer(start: rawPtr) + + buffer.initializeElement(at: 0, to: o.take()._consumingUncheckedUnwrapped()) + + for i in 1 ..< count { + do throws(E) { + try buffer.initializeElement(at: i, to: next(buffer[0])) + } catch { + // The closure threw an error. We need to deinitialize every element + // we've initialized up to this point. + for j in 0 ..< i { + buffer.deinitializeElement(at: j) + } + + throw error + } + } + } + } +} @available(SwiftStdlib 6.1, *) extension Vector where Element: Copyable { @@ -113,9 +223,8 @@ extension Vector where Element: Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient public init(repeating value: Element) { - storage = Builtin.emplace { - let ptr = UnsafeMutablePointer($0) - let buffer = UnsafeMutableBufferPointer(start: ptr, count: Count) + self = Builtin.emplace { + let buffer = Vector._initializationBuffer(start: $0) buffer.initialize(repeating: value) } @@ -123,25 +232,7 @@ extension Vector where Element: Copyable { } //===----------------------------------------------------------------------===// -// Copy -//===----------------------------------------------------------------------===// - -// @available(SwiftStdlib 6.1, *) -// extension Vector where Element: Copyable { -// /// Returns a fresh owned copy of the current vector. -// /// -// /// - Returns: A fresh owned copy of the current vector. -// @available(SwiftStdlib 6.1, *) -// @_alwaysEmitIntoClient -// public borrowing func copy() -> Vector { -// Vector { -// self[$0] -// } -// } -// } - -//===----------------------------------------------------------------------===// -// RandomAccessCollection APIs +// Collection APIs //===----------------------------------------------------------------------===// @available(SwiftStdlib 6.1, *) @@ -163,6 +254,14 @@ extension Vector where Element: ~Copyable { @available(SwiftStdlib 6.1, *) public typealias Indices = Range + /// The number of elements in the collection. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public static var count: Int { + count + } + /// The number of elements in the collection. /// /// - Complexity: O(1) @@ -170,7 +269,7 @@ extension Vector where Element: ~Copyable { @_alwaysEmitIntoClient @_transparent public var count: Int { - Count + count } /// The position of the first element in a nonempty collection. @@ -202,7 +301,7 @@ extension Vector where Element: ~Copyable { @_alwaysEmitIntoClient @_transparent public var endIndex: Int { - Count + count } /// The indices that are valid for subscripting the collection, in ascending @@ -276,37 +375,106 @@ extension Vector where Element: ~Copyable { @_alwaysEmitIntoClient public subscript(_ i: Int) -> Element { @_transparent - unsafeAddress { + _read { _precondition(startIndex <= i && i < endIndex, "Index out of bounds") - return address + i + yield ((address + i).pointee) } @_transparent - unsafeMutableAddress { + _modify { _precondition(startIndex <= i && i < endIndex, "Index out of bounds") - return mutableAddress + i + yield &(mutableAddress + i).pointee } } } +//===----------------------------------------------------------------------===// +// Reduce and Swap +//===----------------------------------------------------------------------===// + @available(SwiftStdlib 6.1, *) -extension Vector where Element: Copyable { +extension Vector where Element: ~Copyable { + /// Returns the result of combining the elements of the vector using the + /// given closure. + /// + /// Use the `reduce(into:_:)` method to produce a single value from the + /// elements of an entire vector. For example, you can use this method on a + /// vector of integers to filter adjacent equal entries or count frequencies. + /// + /// The `updateAccumulatingResult` closure is called sequentially with a + /// mutable accumulating value initialized to `initialResult` and each element + /// of the vector. This example shows how to build a dictionary of letter + /// frequencies of a vector. + /// + /// let letters: Vector = ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"] + /// let letterCount = letters.reduce(into: [:]) { counts, letter in + /// counts[letter, default: 0] += 1 + /// } + /// // letterCount == ["a": 5, "b": 2, "r": 2, "c": 1, "d": 1] + /// + /// When `letters.reduce(into:_:)` is called, the following steps occur: + /// + /// 1. The `updateAccumulatingResult` closure is called with the initial + /// accumulating value---`[:]` in this case---and the first character of + /// `letters`, modifying the accumulating value by setting `1` for the key + /// `"a"`. + /// 2. The closure is called again repeatedly with the updated accumulating + /// value and each element of the vector. + /// 3. When the vector is exhausted, the accumulating value is returned to + /// the caller. + /// + /// If the vector has no elements, `updateAccumulatingResult` is never + /// executed and `initialResult` is the result of the call to + /// `reduce(into:_:)`. + /// + /// - Parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - updateAccumulatingResult: A closure that updates the accumulating + /// value with an element of the vector. + /// - Returns: The final accumulated value. If the vector has no elements, + /// the result is `initialResult`. + /// + /// - Complexity: O(*n*), where *n* is the length of the sequence. @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient - public subscript(_ i: Int) -> Element { - get { - _precondition(startIndex <= i && i < endIndex, "Index out of bounds") - - return buffer[i] + public func reduce( + into initialResult: consuming Result, + _ updateAccumulatingResult: (inout Result, borrowing Element) throws(E) -> () + ) throws(E) -> Result { + for i in 0 ..< count { + try updateAccumulatingResult(&initialResult, self[i]) } - set { - _precondition(startIndex <= i && i < endIndex, "Index out of bounds") + return initialResult + } - mutableBuffer[i] = newValue + /// Exchanges the values at the specified indices of the vector. + /// + /// Both parameters must be valid indices of the vector and not + /// equal to `endIndex`. Passing the same index as both `i` and `j` has no + /// effect. + /// + /// - Parameters: + /// - i: The index of the first value to swap. + /// - j: The index of the second value to swap. + /// + /// - Complexity: O(1) + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public mutating func swapAt( + _ i: Int, + _ j: Int + ) { + guard i != j else { + return } + + let ithElement = mutableBuffer.moveElement(from: i) + let jthElement = mutableBuffer.moveElement(from: j) + mutableBuffer.initializeElement(at: i, to: jthElement) + mutableBuffer.initializeElement(at: j, to: ithElement) } } @@ -408,12 +576,6 @@ extension Vector where Element: ~Copyable { } } -@available(SwiftStdlib 6.1, *) -extension Vector: RandomAccessCollection {} - -@available(SwiftStdlib 6.1, *) -extension Vector: MutableCollection {} - //===----------------------------------------------------------------------===// // Equatable //===----------------------------------------------------------------------===// @@ -433,13 +595,13 @@ extension Vector where Element: Equatable { @_alwaysEmitIntoClient @_transparent public static func ==( - lhs: borrowing Vector, - rhs: borrowing Vector + lhs: borrowing Vector, + rhs: borrowing Vector ) -> Bool { // No need for a count check because these are statically guaranteed to have // the same count... - for i in 0 ..< Count { + for i in 0 ..< count { guard lhs[i] == rhs[i] else { return false } @@ -454,47 +616,34 @@ extension Vector where Element: Equatable { //===----------------------------------------------------------------------===// @available(SwiftStdlib 6.1, *) -extension Vector where Element: CustomStringConvertible { +extension Vector where Element: CustomDebugStringConvertible { /// A textual representation of the vector and its elements. @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient // FIXME: Remove this once 'Vector' actually conforms + // to 'CustomStringConvertible'. public var description: String { var result = "[" var isFirst = true - for i in 0 ..< Count { + for i in 0 ..< count { if !isFirst { result += ", " } else { isFirst = false } - result += self[i].description + result += self[i].debugDescription } result += "]" return result } -} -@available(SwiftStdlib 6.1, *) -extension Vector where Element: CustomDebugStringConvertible { /// A textual representation of the vector and its elements. @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient // FIXME: Remove this once 'Vector' actually conforms + // to 'CustomDebugStringConvertible'. public var debugDescription: String { - var result = "[" - var isFirst = true - - for i in 0 ..< Count { - if !isFirst { - result += ", " - } else { - isFirst = false - } - - result += self[i].debugDescription - } - - result += "]" - return result + description } } From 445824dda0093f900b6869f8c3503c8678c36191 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 12:25:31 -0800 Subject: [PATCH 07/15] Don't emit builtin metadata in the stdlib if it's generic --- lib/IRGen/GenReflection.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 4ec6aa3a45927..c31d1f78c8088 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -1163,6 +1163,11 @@ class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder { }; void IRGenModule::emitBuiltinTypeMetadataRecord(CanType builtinType) { + // If this builtin is generic, don't emit anything. + if (builtinType->hasTypeParameter()) { + return; + } + FixedTypeMetadataBuilder builder(*this, builtinType); builder.emit(); } From 08ce821442b60db99f0d5c082faa4123362fde9a Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 12:51:59 -0800 Subject: [PATCH 08/15] If the element type of a B.FA is empty, set its storage type in LLVM to just the padding --- lib/IRGen/GenArray.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/IRGen/GenArray.cpp b/lib/IRGen/GenArray.cpp index b32ae7d62ab25..13c12450107a1 100644 --- a/lib/IRGen/GenArray.cpp +++ b/lib/IRGen/GenArray.cpp @@ -206,10 +206,15 @@ class FixedArrayTypeInfoBase : public ArrayTypeInfoBase { uint64_t paddingBytes = elementTI.getFixedStride().getValue() - elementTI.getFixedSize().getValue(); auto byteTy = llvm::IntegerType::get(LLVMContext, 8); - elementTy = llvm::StructType::get(LLVMContext, - {elementTy, - llvm::ArrayType::get(byteTy, paddingBytes)}, - /*packed*/ true); + auto paddingArrayTy = llvm::ArrayType::get(byteTy, paddingBytes); + + if (elementTI.getFixedSize() == Size(0)) { + elementTy = paddingArrayTy; + } else { + elementTy = llvm::StructType::get(LLVMContext, + {elementTy, paddingArrayTy}, + /*packed*/ true); + } } return llvm::ArrayType::get(elementTy, arraySize); From c5a641b7641cc298e9d92638dac8dcf41f537158 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 14:02:34 -0800 Subject: [PATCH 09/15] WIP: Import C arrays as Vector with flag --- include/swift/Basic/Features.def | 1 + lib/AST/FeatureSet.cpp | 1 + lib/ClangImporter/ImportType.cpp | 21 ++++++++++++++------- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 00bdc609ec682..b968e8e06ea0a 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -225,6 +225,7 @@ UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6) UPCOMING_FEATURE(ExistentialAny, 335, 7) UPCOMING_FEATURE(InternalImportsByDefault, 409, 7) UPCOMING_FEATURE(MemberImportVisibility, 444, 7) +UPCOMING_FEATURE(ImportCArraysAsVectors, 453, 7) EXPERIMENTAL_FEATURE(StaticAssert, false) EXPERIMENTAL_FEATURE(NamedOpaqueTypes, false) diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index d1b0fc4936acc..f718bf127f29b 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -69,6 +69,7 @@ UNINTERESTING_FEATURE(ExistentialAny) UNINTERESTING_FEATURE(InferSendableFromCaptures) UNINTERESTING_FEATURE(ImplicitOpenExistentials) UNINTERESTING_FEATURE(MemberImportVisibility) +UNINTERESTING_FEATURE(ImportCArraysAsVectors) // fixme? // ---------------------------------------------------------------------------- // MARK: - Experimental Features diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 40f7be7116df7..f06f26cd0c118 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -634,10 +634,6 @@ namespace { } ImportResult VisitConstantArrayType(const clang::ConstantArrayType *type) { - // FIXME: Map to a real fixed-size Swift array type when we have those. - // Importing as a tuple at least fills the right amount of space, and - // we can cheese static-offset "indexing" using .$n operations. - Type elementType = Impl.importTypeIgnoreIUO( type->getElementType(), ImportTypeKind::Value, addImportDiagnostic, AllowNSUIntegerAsInt, Bridgeability::None, ImportTypeAttrs()); @@ -645,14 +641,25 @@ namespace { return Type(); auto size = type->getSize().getZExtValue(); + + if (size == 1) + return elementType; + + auto &ctx = elementType->getASTContext(); + + if (ctx.LangOpts.hasFeature(Feature::ImportCArraysAsVectors)) { + auto vector = cast(ctx.getVectorDecl()); + auto countType = IntegerType::get(std::to_string(size), + /* isNegative */ false, ctx); + return BoundGenericStructType::get(vector, /* parent */ nullptr, + {countType, elementType}); + } + // An array of size N is imported as an N-element tuple which // takes very long to compile. We chose 4096 as the upper limit because // we don't want to break arrays of size PATH_MAX. if (size > 4096) return Type(); - - if (size == 1) - return elementType; SmallVector elts{static_cast(size), elementType}; return TupleType::get(elts, elementType->getASTContext()); From c62e851e3833b59e4069ae5f6dffd87bb83e6632 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Mon, 2 Dec 2024 16:53:45 -0800 Subject: [PATCH 10/15] Implement RemoteInspection support for Builtin.FixedArray --- include/swift/RemoteInspection/TypeLowering.h | 19 ++++++ include/swift/RemoteInspection/TypeRef.h | 61 ++++++++++++++++++ .../swift/RemoteInspection/TypeRefBuilder.h | 11 ++-- include/swift/RemoteInspection/TypeRefs.def | 2 + .../SwiftRemoteMirrorTypes.h | 3 + .../public/RemoteInspection/TypeLowering.cpp | 54 ++++++++++++++++ stdlib/public/RemoteInspection/TypeRef.cpp | 62 +++++++++++++++++++ .../SwiftRemoteMirror/SwiftRemoteMirror.cpp | 4 ++ test/Reflection/typeref_lowering.swift | 9 +++ 9 files changed, 219 insertions(+), 6 deletions(-) diff --git a/include/swift/RemoteInspection/TypeLowering.h b/include/swift/RemoteInspection/TypeLowering.h index fbf5bda7e2ae1..c1f333f182ede 100644 --- a/include/swift/RemoteInspection/TypeLowering.h +++ b/include/swift/RemoteInspection/TypeLowering.h @@ -117,6 +117,7 @@ enum class TypeInfoKind : unsigned { Reference, Invalid, Enum, + Array, }; class TypeInfo { @@ -350,6 +351,24 @@ class ReferenceTypeInfo : public TypeInfo { } }; +/// Array based layouts like Builtin.FixedArray +class ArrayTypeInfo : public TypeInfo { + const TypeInfo *ElementTI; + +public: + explicit ArrayTypeInfo(intptr_t size, const TypeInfo *elementTI); + + bool readExtraInhabitantIndex(remote::MemoryReader &reader, + remote::RemoteAddress address, + int *extraInhabitantIndex) const override; + + BitMask getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const override; + + static bool classof(const TypeInfo *TI) { + return TI->getKind() == TypeInfoKind::Array; + } +}; + /// This class owns the memory for all TypeInfo instances that it vends. class TypeConverter { TypeRefBuilder &Builder; diff --git a/include/swift/RemoteInspection/TypeRef.h b/include/swift/RemoteInspection/TypeRef.h index 75be1c74547e3..b8361af231ae7 100644 --- a/include/swift/RemoteInspection/TypeRef.h +++ b/include/swift/RemoteInspection/TypeRef.h @@ -1095,6 +1095,67 @@ class SILBoxTypeWithLayoutTypeRef final : public TypeRef { } }; +class IntegerTypeRef final : public TypeRef { + intptr_t Value; + + static TypeRefID Profile(const intptr_t &Value) { + TypeRefID ID; + ID.addInteger((uint64_t)Value); + return ID; + } + +public: + IntegerTypeRef(const intptr_t &Value) + : TypeRef(TypeRefKind::Integer), Value(Value) {} + + template + static const IntegerTypeRef *create(Allocator &A, intptr_t Value) { + FIND_OR_CREATE_TYPEREF(A, IntegerTypeRef, Value); + } + + const intptr_t &getValue() const { + return Value; + } + + static bool classof(const TypeRef *TR) { + return TR->getKind() == TypeRefKind::Integer; + } +}; + +class BuiltinFixedArrayTypeRef final : public TypeRef { + intptr_t Size; + const TypeRef *Element; + + static TypeRefID Profile(const intptr_t &Size, const TypeRef *Element) { + TypeRefID ID; + ID.addInteger((uint64_t)Size); + ID.addPointer(Element); + return ID; + } + +public: + BuiltinFixedArrayTypeRef(const intptr_t &Size, const TypeRef *Element) + : TypeRef(TypeRefKind::BuiltinFixedArray), Size(Size), Element(Element) {} + + template + static const BuiltinFixedArrayTypeRef *create(Allocator &A, intptr_t Size, + const TypeRef *Element) { + FIND_OR_CREATE_TYPEREF(A, BuiltinFixedArrayTypeRef, Size, Element); + } + + const intptr_t &getSize() const { + return Size; + } + + const TypeRef *getElementType() const { + return Element; + } + + static bool classof(const TypeRef *TR) { + return TR->getKind() == TypeRefKind::BuiltinFixedArray; + } +}; + template class TypeRefVisitor { public: diff --git a/include/swift/RemoteInspection/TypeRefBuilder.h b/include/swift/RemoteInspection/TypeRefBuilder.h index fcc05192631a0..cb791a0f42726 100644 --- a/include/swift/RemoteInspection/TypeRefBuilder.h +++ b/include/swift/RemoteInspection/TypeRefBuilder.h @@ -929,19 +929,18 @@ class TypeRefBuilder { } const TypeRef *createIntegerType(intptr_t value) { - // FIXME: implement - return nullptr; + return IntegerTypeRef::create(*this, value); } const TypeRef *createNegativeIntegerType(intptr_t value) { - // FIXME: implement - return nullptr; + return IntegerTypeRef::create(*this, value); } const TypeRef *createBuiltinFixedArrayType(const TypeRef *size, const TypeRef *element) { - // FIXME: implement - return nullptr; + auto integer = cast(size); + return BuiltinFixedArrayTypeRef::create(*this, integer->getValue(), + element); } // Construct a bound generic type ref along with the parent type info diff --git a/include/swift/RemoteInspection/TypeRefs.def b/include/swift/RemoteInspection/TypeRefs.def index e95845700b539..e3174bb620350 100644 --- a/include/swift/RemoteInspection/TypeRefs.def +++ b/include/swift/RemoteInspection/TypeRefs.def @@ -37,5 +37,7 @@ TYPEREF(OpaqueArchetype, TypeRef) #include "swift/AST/ReferenceStorage.def" TYPEREF(SILBox, TypeRef) TYPEREF(SILBoxTypeWithLayout, TypeRef) +TYPEREF(Integer, TypeRef) +TYPEREF(BuiltinFixedArray, TypeRef) #undef TYPEREF diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h index 800b27ea5c5c5..3fa7e3c4145c7 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h @@ -143,6 +143,9 @@ typedef enum swift_layout_kind { // swift_reflection_infoForTypeRef(). SWIFT_CLASS_INSTANCE, SWIFT_CLOSURE_CONTEXT, + + // A contiguous list of N Ts, typically for Builtin.FixedArray. + SWIFT_ARRAY, } swift_layout_kind_t; struct swift_childinfo; diff --git a/stdlib/public/RemoteInspection/TypeLowering.cpp b/stdlib/public/RemoteInspection/TypeLowering.cpp index 541c039f6141f..cc0e46475f38d 100644 --- a/stdlib/public/RemoteInspection/TypeLowering.cpp +++ b/stdlib/public/RemoteInspection/TypeLowering.cpp @@ -217,6 +217,13 @@ class PrintTypeInfo { stream << ")"; return; } + + case TypeInfoKind::Array: { + printHeader("array"); + printBasic(TI); + stream << ")"; + return; + } } swift_unreachable("Bad TypeInfo kind"); @@ -475,6 +482,26 @@ BitMask RecordTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const return mask; } +ArrayTypeInfo::ArrayTypeInfo(intptr_t size, const TypeInfo *elementTI) + : TypeInfo(TypeInfoKind::Array, + /* size */ elementTI->getStride() * size, + /* alignment */ elementTI->getAlignment(), + /* stride */ elementTI->getStride() * size, + /* numExtraInhabitants */ elementTI->getNumExtraInhabitants(), + /* isBitwiseTakable */ elementTI->isBitwiseTakable()), + ElementTI(elementTI) {} + +bool ArrayTypeInfo::readExtraInhabitantIndex( + remote::MemoryReader &reader, remote::RemoteAddress address, + int *extraInhabitantIndex) const { + return ElementTI->readExtraInhabitantIndex(reader, address, + extraInhabitantIndex); +} + +BitMask ArrayTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const { + return ElementTI->getSpareBits(TC, hasAddrOnly); +} + class UnsupportedEnumTypeInfo: public EnumTypeInfo { public: UnsupportedEnumTypeInfo(unsigned Size, unsigned Alignment, @@ -1786,6 +1813,14 @@ class HasFixedSize bool visitOpaqueArchetypeTypeRef(const OpaqueArchetypeTypeRef *O) { return false; } + + bool visitIntegerTypeRef(const IntegerTypeRef *I) { + return false; + } + + bool visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return visit(BA->getElementType()); + } }; bool TypeConverter::hasFixedSize(const TypeRef *TR) { @@ -1921,6 +1956,14 @@ class HasSingletonMetatype MetatypeRepresentation visitOpaqueArchetypeTypeRef(const OpaqueArchetypeTypeRef *O) { return MetatypeRepresentation::Unknown; } + + MetatypeRepresentation visitIntegerTypeRef(const IntegerTypeRef *I) { + return MetatypeRepresentation::Unknown; + } + + MetatypeRepresentation visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return visit(BA->getElementType()); + } }; class EnumTypeInfoBuilder { @@ -2544,6 +2587,17 @@ class LowerType DEBUG_LOG(fprintf(stderr, "Can't lower unresolved opaque archetype TypeRef")); return nullptr; } + + const TypeInfo *visitIntegerTypeRef(const IntegerTypeRef *I) { + DEBUG_LOG(fprintf(stderr, "Can't lower integer TypeRef")); + return nullptr; + } + + const TypeInfo *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + auto elementTI = visit(BA->getElementType()); + + return TC.makeTypeInfo(BA->getSize(), elementTI); + } }; const TypeInfo * diff --git a/stdlib/public/RemoteInspection/TypeRef.cpp b/stdlib/public/RemoteInspection/TypeRef.cpp index e7ebbfd90e2c2..fbc7798425035 100644 --- a/stdlib/public/RemoteInspection/TypeRef.cpp +++ b/stdlib/public/RemoteInspection/TypeRef.cpp @@ -395,6 +395,19 @@ class PrintTypeRef : public TypeRefVisitor { printHeader("opaque"); stream << ")"; } + + void visitIntegerTypeRef(const IntegerTypeRef *I) { + printHeader("integer"); + printField("value", std::to_string(I->getValue())); + stream << ")"; + } + + void visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + printHeader("builtin_fixed_array"); + printField("size", std::to_string(BA->getSize())); + printRec(BA->getElementType()); + stream << ")"; + } }; struct TypeRefIsConcrete @@ -506,6 +519,14 @@ struct TypeRefIsConcrete bool visitSILBoxTypeWithLayoutTypeRef(const SILBoxTypeWithLayoutTypeRef *SB) { return true; } + + bool visitIntegerTypeRef(const IntegerTypeRef *I) { + return true; + } + + bool visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return visit(BA->getElementType()); + } }; const OpaqueTypeRef * @@ -1049,6 +1070,30 @@ class DemanglingForTypeRef return node; } + + Demangle::NodePointer createInteger(intptr_t value) { + if (value >= 0) { + return Dem.createNode(Node::Kind::Integer, value); + } else { + return Dem.createNode(Node::Kind::NegativeInteger, value); + } + } + + Demangle::NodePointer visitIntegerTypeRef(const IntegerTypeRef *I) { + return createInteger(I->getValue()); + } + + Demangle::NodePointer visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + auto ba = Dem.createNode(Node::Kind::BuiltinFixedArray); + + auto size = Dem.createNode(Node::Kind::Type); + size->addChild(createInteger(BA->getSize()), Dem); + ba->addChild(size, Dem); + + ba->addChild(visit(BA->getElementType()), Dem); + + return ba; + } }; Demangle::NodePointer TypeRef::getDemangling(Demangle::Demangler &Dem) const { @@ -1277,6 +1322,14 @@ class ThickenMetatype return O; } + const TypeRef *visitIntegerTypeRef(const IntegerTypeRef *I) { + return I; + } + + const TypeRef *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return BuiltinFixedArrayTypeRef::create(Builder, BA->getSize(), + visit(BA->getElementType())); + } }; static const TypeRef * @@ -1531,6 +1584,15 @@ class TypeRefSubstitution O->getOrdinal(), newArgLists); } + + const TypeRef *visitIntegerTypeRef(const IntegerTypeRef *I) { + return I; + } + + const TypeRef *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return BuiltinFixedArrayTypeRef::create(Builder, BA->getSize(), + visit(BA->getElementType())); + } }; const TypeRef *TypeRef::subst(TypeRefBuilder &Builder, diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index a8873725f13df..64911bd4217cd 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -529,6 +529,10 @@ swift_layout_kind_t getTypeInfoKind(const TypeInfo &TI) { #include "swift/AST/ReferenceStorage.def" } } + + case TypeInfoKind::Array: { + return SWIFT_ARRAY; + } } swift_unreachable("Unhandled TypeInfoKind in switch"); diff --git a/test/Reflection/typeref_lowering.swift b/test/Reflection/typeref_lowering.swift index 71dc1be84fe3b..ec56028cd3315 100644 --- a/test/Reflection/typeref_lowering.swift +++ b/test/Reflection/typeref_lowering.swift @@ -1269,3 +1269,12 @@ BD // CHECK-32: (builtin Builtin.DefaultActorStorage) // CHECK-32-NEXT: (builtin size=48 alignment=8 stride=48 num_extra_inhabitants=0 bitwise_takable=1) + +$1_SiBV +// CHECK-64: (builtin_fixed_array size=2 +// CHECK-64-NEXT: (struct Swift.Int)) +// CHECK-64-NEXT: (array size=16 alignment=8 stride=16 num_extra_inhabitants=0 bitwise_takable=1) + +// CHECK-32: (builtin_fixed_array size=2 +// CHECK-32-NEXT: (struct Swift.Int)) +// CHECK-32-NEXT: (array size=8 alignment=4 stride=8 num_extra_inhabitants=0 bitwise_takable=1) From 515c64fd55f47aadf0d0dedbf6677f917c74c175 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 3 Dec 2024 10:16:21 -0800 Subject: [PATCH 11/15] Use current insertion block as other incoming phi for each array element --- lib/IRGen/GenArray.cpp | 11 ++++-- test/IRGen/array_type_layout.swift | 58 ++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 test/IRGen/array_type_layout.swift diff --git a/lib/IRGen/GenArray.cpp b/lib/IRGen/GenArray.cpp index 13c12450107a1..39190515df1d5 100644 --- a/lib/IRGen/GenArray.cpp +++ b/lib/IRGen/GenArray.cpp @@ -94,16 +94,21 @@ class ArrayTypeInfoBase : public BaseTypeInfo { } body(eltAddrs); - + + // The just ran body may have generated new blocks. Get the current + // insertion block which will become the other incoming block to the phis + // we've generated. + predBB = IGF.Builder.GetInsertBlock(); + for (unsigned i : indices(addrPhis)) { addrPhis[i]->addIncoming(Element.indexArray(IGF, eltAddrs[i], one, getElementSILType(IGF.IGM, T)) .getAddress(), - loopBB); + predBB); } auto nextCount = IGF.Builder.CreateSub(countPhi, one); - countPhi->addIncoming(nextCount, loopBB); + countPhi->addIncoming(nextCount, predBB); auto done = IGF.Builder.CreateICmpEQ(nextCount, zero); IGF.Builder.CreateCondBr(done, endBB, loopBB); diff --git a/test/IRGen/array_type_layout.swift b/test/IRGen/array_type_layout.swift new file mode 100644 index 0000000000000..662d4e5859ce7 --- /dev/null +++ b/test/IRGen/array_type_layout.swift @@ -0,0 +1,58 @@ +// RUN: %target-swift-frontend -emit-ir -disable-availability-checking -enable-experimental-feature ValueGenerics %s | %FileCheck %s + +// REQUIRES: swift_feature_ValueGenerics + +struct VerySmallVector { + var inline: Vector<16, T?> + var count = 0 + + init() { + inline = .init(repeating: nil) + } +} + +//===----------------------------------------------------------------------===// +// VerySmallVector initializeBufferWithCopyOfBuffer +//===----------------------------------------------------------------------===// + +// CHECK-LABEL: define {{.*}} ptr @"$s17array_type_layout15VerySmallVectorVwCP"(ptr{{.*}} %dest, ptr{{.*}} %src, ptr{{.*}} %"VerySmallVector") +// CHECK: [[FLAGS:%.*]] = load i32, ptr {{.*}} +// CHECK-NEXT: [[INLINE_BIT:%.*]] = and i32 [[FLAGS]], 131072 +// CHECK-NEXT: [[IS_INLINE:%.*]] = icmp eq i32 [[INLINE_BIT]], 0 +// CHECK-NEXT: br i1 [[IS_INLINE]], label %[[DIRECT_BB:.*]], label %[[INDIRECT_BB:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[INDIRECT_BB]]: +// CHECK: br label %[[CONT_BB:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[DIRECT_BB]]: +// CHECK: br label %[[LOOP_BB:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[LOOP_BB]]: +// CHECK-NEXT: [[COUNT:%.*]] = phi i{{64|32}} [ 16, %[[DIRECT_BB]] ], [ [[SUB:%.*]], %[[PRED_BB:.*]] ] +// CHECK-NEXT: [[DEST:%.*]] = phi ptr [ %dest, %[[DIRECT_BB]] ], [ [[DEST_OFFSET_PTR:%.*]], %[[PRED_BB]] ] +// CHECK-NEXT: [[SRC:%.*]] = phi ptr [ %src, %[[DIRECT_BB]] ], [ [[SRC_OFFSET_PTR:%.*]], %[[PRED_BB]] ] +// CHECK: [[TAG:%.*]] = call i32 %GetEnumTagSinglePayload(ptr{{.*}} [[SRC]], i32 1, ptr %T) +// CHECK-NEXT: [[NIL_CHECK:%.*]] = icmp eq i32 [[TAG]], 0 +// CHECK-NEXT: br i1 [[NIL_CHECK]], label %[[NOT_NIL_BB:.*]], label %[[NIL_BB:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[NOT_NIL_BB]]: +// CHECK: {{.*}} = call ptr %InitializeWithCopy(ptr{{.*}} [[DEST]], ptr{{.*}} [[SRC]], ptr %T) + +// CHECK: [[NIL_BB]]: +// CHECK: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[DEST]], ptr{{.*}} [[SRC]], i{{64|32}} {{%.*}}, i1 false) +// CHECK-NEXT: br label %[[PRED_BB]] +// CHECK-EMPTY: +// CHECK-NEXT: [[PRED_BB]]: +// CHECK: [[SUB]] = sub i{{64|32}} [[COUNT]], 1 +// CHECK-NEXT: [[DONE:%.*]] = icmp eq i{{64|32}} [[SUB]], 0 +// CHECK-NEXT: br i1 [[DONE]], label %[[END_LOOP_BB:.*]], label %[[LOOP_BB]] +// CHECK-EMPTY: +// CHECK-NEXT: [[END_LOOP_BB]]: +// CHECK: [[DEST_COUNT_PTR:%.*]] = getelementptr inbounds i8, ptr %dest, i32 {{%.*}} +// CHECK: [[SRC_COUNT_PTR:%.*]] = getelementptr inbounds i8, ptr %src, i32 {{%.*}} +// CHECK-NEXT: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[DEST_COUNT_PTR]], ptr{{.*}} [[SRC_COUNT_PTR]], i{{64|32}} 8, i1 false) +// CHECK-NEXT: br label %[[CONT_BB]] +// CHECK-EMPTY: +// CHECK-NEXT: [[CONT_BB]]: +// CHECK-NEXT: [[RETURN_DEST_PTR:%.*]] = phi ptr [ {{%.*}}, %[[INDIRECT_BB]] ], [ %dest, %[[END_LOOP_BB]] ] +// CHECK-NEXT: ret ptr [[RETURN_DEST_PTR]] From f76d841540640ce2f87d5ac5f794404d70b2d46b Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 9 Jan 2025 10:39:45 -0800 Subject: [PATCH 12/15] Rename to Slab --- include/swift/AST/Decl.h | 2 +- include/swift/AST/DiagnosticsSema.def | 6 +- include/swift/AST/KnownStdlibTypes.def | 2 +- include/swift/AST/Types.h | 2 +- include/swift/Basic/Features.def | 1 - include/swift/Sema/CSFix.h | 16 +- lib/AST/FeatureSet.cpp | 1 - lib/AST/Type.cpp | 2 +- lib/ClangImporter/ImportType.cpp | 20 +- lib/Parse/ParseType.cpp | 2 +- lib/SILGen/SILGenExpr.cpp | 38 +-- lib/Sema/CSApply.cpp | 4 +- lib/Sema/CSDiagnostics.cpp | 4 +- lib/Sema/CSDiagnostics.h | 12 +- lib/Sema/CSFix.cpp | 16 +- lib/Sema/CSSimplify.cpp | 20 +- lib/Sema/ConstraintSystem.cpp | 4 +- lib/Sema/TypeCheckDeclPrimary.cpp | 15 +- stdlib/public/core/CMakeLists.txt | 4 +- stdlib/public/core/GroupInfo.json | 2 +- .../public/core/{Vector.swift => Slab.swift} | 228 +++--------------- test/DebugInfo/value-generics-embedded.swift | 12 +- test/DebugInfo/value-generics.swift | 14 +- test/Demangle/Inputs/manglings.txt | 2 +- test/IRGen/array_type_layout.swift | 8 +- test/ModuleInterface/value_generics.swift | 16 +- ...ector_literal.swift => slab_literal.swift} | 74 +++--- test/Sema/{vector.swift => slab.swift} | 44 ++-- 28 files changed, 201 insertions(+), 370 deletions(-) rename stdlib/public/core/{Vector.swift => Slab.swift} (66%) rename test/SILGen/{vector_literal.swift => slab_literal.swift} (52%) rename test/Sema/{vector.swift => slab.swift} (61%) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index af94e0467ca24..f3b08d07db7d6 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3958,7 +3958,7 @@ class GenericTypeParamDecl final /// type parameter. /// /// \code - /// struct Vector + /// struct Slab /// \endcode bool isValue() const { return getParamKind() == GenericTypeParamKind::Value; diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 596f90e255cd0..91477d2ca808e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8176,11 +8176,11 @@ ERROR(invalid_value_for_type_same_type,none, "cannot constrain type parameter %0 to be integer %1", (Type, Type)) //===----------------------------------------------------------------------===// -// MARK: Vector +// MARK: Slab //===----------------------------------------------------------------------===// -ERROR(vector_literal_incorrect_count,none, - "expected %0 elements in vector literal, but got %1", (Type, Type)) +ERROR(slab_literal_incorrect_count,none, + "expected %0 elements in slab literal, but got %1", (Type, Type)) //===----------------------------------------------------------------------===// // MARK: @abi Attribute diff --git a/include/swift/AST/KnownStdlibTypes.def b/include/swift/AST/KnownStdlibTypes.def index 4e035163b94eb..44c861b34f1a1 100644 --- a/include/swift/AST/KnownStdlibTypes.def +++ b/include/swift/AST/KnownStdlibTypes.def @@ -97,6 +97,6 @@ KNOWN_STDLIB_TYPE_DECL(DecodingError, NominalTypeDecl, 0) KNOWN_STDLIB_TYPE_DECL(Result, NominalTypeDecl, 2) -KNOWN_STDLIB_TYPE_DECL(Vector, NominalTypeDecl, 2) +KNOWN_STDLIB_TYPE_DECL(Slab, NominalTypeDecl, 2) #undef KNOWN_STDLIB_TYPE_DECL diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index f73bab6650221..680d2c55e3129 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -7246,7 +7246,7 @@ class GenericTypeParamType : public SubstitutableType, /// Returns \c true if this type parameter is declared as a value. /// /// \code - /// struct Vector + /// struct Slab /// \endcode bool isValue() const { return ParamKind == GenericTypeParamKind::Value; diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index b968e8e06ea0a..00bdc609ec682 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -225,7 +225,6 @@ UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6) UPCOMING_FEATURE(ExistentialAny, 335, 7) UPCOMING_FEATURE(InternalImportsByDefault, 409, 7) UPCOMING_FEATURE(MemberImportVisibility, 444, 7) -UPCOMING_FEATURE(ImportCArraysAsVectors, 453, 7) EXPERIMENTAL_FEATURE(StaticAssert, false) EXPERIMENTAL_FEATURE(NamedOpaqueTypes, false) diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 8d2bc74684953..b378697d0f372 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -484,9 +484,9 @@ enum class FixKind : uint8_t { /// result. AllowSendingMismatch, - /// Ignore when a 'Vector' literal has mismatched number of elements to the + /// Ignore when a 'Slab' literal has mismatched number of elements to the /// type it's attempting to bind to. - AllowVectorLiteralCountMismatch, + AllowSlabLiteralCountMismatch, }; class ConstraintFix { @@ -3841,12 +3841,12 @@ class IgnoreKeyPathSubscriptIndexMismatch final : public ConstraintFix { } }; -class AllowVectorLiteralCountMismatch final : public ConstraintFix { +class AllowSlabLiteralCountMismatch final : public ConstraintFix { Type lhsCount, rhsCount; - AllowVectorLiteralCountMismatch(ConstraintSystem &cs, Type lhsCount, - Type rhsCount, ConstraintLocator *locator) - : ConstraintFix(cs, FixKind::AllowVectorLiteralCountMismatch, locator), + AllowSlabLiteralCountMismatch(ConstraintSystem &cs, Type lhsCount, + Type rhsCount, ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::AllowSlabLiteralCountMismatch, locator), lhsCount(lhsCount), rhsCount(rhsCount) {} public: @@ -3856,12 +3856,12 @@ class AllowVectorLiteralCountMismatch final : public ConstraintFix { bool diagnose(const Solution &solution, bool asNote = false) const override; - static AllowVectorLiteralCountMismatch * + static AllowSlabLiteralCountMismatch * create(ConstraintSystem &cs, Type lhsCount, Type rhsCount, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { - return fix->getKind() == FixKind::AllowVectorLiteralCountMismatch; + return fix->getKind() == FixKind::AllowSlabLiteralCountMismatch; } }; diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index f718bf127f29b..d1b0fc4936acc 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -69,7 +69,6 @@ UNINTERESTING_FEATURE(ExistentialAny) UNINTERESTING_FEATURE(InferSendableFromCaptures) UNINTERESTING_FEATURE(ImplicitOpenExistentials) UNINTERESTING_FEATURE(MemberImportVisibility) -UNINTERESTING_FEATURE(ImportCArraysAsVectors) // fixme? // ---------------------------------------------------------------------------- // MARK: - Experimental Features diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 8c17d827e2d5f..a30d09a577838 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -811,7 +811,7 @@ Type TypeBase::isArrayType() { if (isArray()) return boundStruct->getGenericArgs()[0]; - if (isVector()) + if (isSlab()) return boundStruct->getGenericArgs()[1]; } return Type(); diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index f06f26cd0c118..f1c5b272e20c1 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -634,6 +634,10 @@ namespace { } ImportResult VisitConstantArrayType(const clang::ConstantArrayType *type) { + // FIXME: Map to a real fixed-size Swift array type when we have those. + // Importing as a tuple at least fills the right amount of space, and + // we can cheese static-offset "indexing" using .$n operations. + Type elementType = Impl.importTypeIgnoreIUO( type->getElementType(), ImportTypeKind::Value, addImportDiagnostic, AllowNSUIntegerAsInt, Bridgeability::None, ImportTypeAttrs()); @@ -642,25 +646,15 @@ namespace { auto size = type->getSize().getZExtValue(); - if (size == 1) - return elementType; - - auto &ctx = elementType->getASTContext(); - - if (ctx.LangOpts.hasFeature(Feature::ImportCArraysAsVectors)) { - auto vector = cast(ctx.getVectorDecl()); - auto countType = IntegerType::get(std::to_string(size), - /* isNegative */ false, ctx); - return BoundGenericStructType::get(vector, /* parent */ nullptr, - {countType, elementType}); - } - // An array of size N is imported as an N-element tuple which // takes very long to compile. We chose 4096 as the upper limit because // we don't want to break arrays of size PATH_MAX. if (size > 4096) return Type(); + if (size == 1) + return elementType; + SmallVector elts{static_cast(size), elementType}; return TupleType::get(elts, elementType->getASTContext()); } diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index ae09f70426c94..47dc3bac20eb6 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -716,7 +716,7 @@ ParserStatus Parser::parseGenericArguments(SmallVectorImpl &Args, // variadic generic types. if (!startsWithGreater(Tok)) { while (true) { - // Note: This can be a value type, e.g. 'Vector<3, Int>'. + // Note: This can be a value type, e.g. 'Slab<3, Int>'. ParserResult Ty = parseTypeOrValue(diag::expected_type); if (Ty.isNull() || Ty.hasCodeCompletion()) { // Skip until we hit the '>'. diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index cb89a805a04cc..0bac472577761 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -4598,17 +4598,17 @@ visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C) { llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch."); } -static RValue emitVectorLiteral(SILGenFunction &SGF, CollectionExpr *E, - SGFContext C) { +static RValue emitSlabLiteral(SILGenFunction &SGF, CollectionExpr *E, + SGFContext C) { ArgumentScope scope(SGF, E); - auto vectorType = E->getType()->castTo(); - auto loweredVectorType = SGF.getLoweredType(vectorType); - auto elementType = vectorType->getGenericArgs()[1]->getCanonicalType(); + auto slabType = E->getType()->castTo(); + auto loweredSlabType = SGF.getLoweredType(slabType); + auto elementType = slabType->getGenericArgs()[1]->getCanonicalType(); auto loweredElementType = SGF.getLoweredType(elementType); auto &eltTL = SGF.getTypeLowering(AbstractionPattern::getOpaque(), elementType); - SILValue alloc = SGF.emitTemporaryAllocation(E, loweredVectorType); + SILValue alloc = SGF.emitTemporaryAllocation(E, loweredSlabType); SILValue addr = SGF.B.createUncheckedAddrCast(E, alloc, loweredElementType.getAddressType()); @@ -4641,31 +4641,31 @@ static RValue emitVectorLiteral(SILGenFunction &SGF, CollectionExpr *E, .forwardInto(SGF, AbstractionPattern::getOpaque(), &init, eltTL); } - // Kill the per-element cleanups. The vector will take ownership of them. + // Kill the per-element cleanups. The slab will take ownership of them. for (auto destCleanup : cleanups) SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dead); - SILValue vectorVal; + SILValue slabVal; - // If the vector is naturally address-only, then we can adopt the stack slot + // If the slab is naturally address-only, then we can adopt the stack slot // as the value directly. - if (loweredVectorType.isAddressOnly(SGF.F)) { - vectorVal = SGF.B.createUncheckedAddrCast(E, alloc, loweredVectorType); + if (loweredSlabType.isAddressOnly(SGF.F)) { + slabVal = SGF.B.createUncheckedAddrCast(E, alloc, loweredSlabType); } else { - // Otherwise, this vector is loadable. Load it. - vectorVal = SGF.B.createTrivialLoadOr(E, alloc, LoadOwnershipQualifier::Take); + // Otherwise, this slab is loadable. Load it. + slabVal = SGF.B.createTrivialLoadOr(E, alloc, LoadOwnershipQualifier::Take); } - auto vectorMV = SGF.emitManagedRValueWithCleanup(vectorVal); - auto vector = RValue(SGF, E, vectorMV); + auto slabMV = SGF.emitManagedRValueWithCleanup(slabVal); + auto slab = RValue(SGF, E, slabMV); - return scope.popPreservingValue(std::move(vector)); + return scope.popPreservingValue(std::move(slab)); } RValue RValueEmitter::visitCollectionExpr(CollectionExpr *E, SGFContext C) { - // Handle 'Vector' literals separately. - if (E->getType()->isVector()) { - return emitVectorLiteral(SGF, E, C); + // Handle 'Slab' literals separately. + if (E->getType()->isSlab()) { + return emitSlabLiteral(SGF, E, C); } auto loc = SILLocation(E); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index f775331e5e2f8..7d04c5a2bf184 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3794,8 +3794,8 @@ namespace { Type arrayTy = cs.getType(expr); Type elementType; - if (arrayTy->isVector()) { - // + if (arrayTy->isSlab()) { + // elementType = arrayTy->castTo()->getGenericArgs()[1]; } else { ProtocolDecl *arrayProto = TypeChecker::getProtocol( diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 22ff2f84176d7..fb462e8622780 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -9572,7 +9572,7 @@ bool InvalidTypeAsKeyPathSubscriptIndex::diagnoseAsError() { return true; } -bool IncorrectVectorLiteralCount::diagnoseAsError() { - emitDiagnostic(diag::vector_literal_incorrect_count, lhsCount, rhsCount); +bool IncorrectSlabLiteralCount::diagnoseAsError() { + emitDiagnostic(diag::slab_literal_incorrect_count, lhsCount, rhsCount); return true; } diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 13591e8e834ed..03349edd30443 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -3234,18 +3234,18 @@ class InvalidTypeAsKeyPathSubscriptIndex final : public FailureDiagnostic { bool diagnoseAsError() override; }; -/// Diagnose when a vector literal has an incorrect number of elements for the -/// contextual vector type it's initializing. +/// Diagnose when a slab literal has an incorrect number of elements for the +/// contextual slab type it's initializing. /// /// \code -/// let x: Vector<4, Int> = [1, 2] // expected '4' elements but got '2' +/// let x: Slab<4, Int> = [1, 2] // expected '4' elements but got '2' /// \endcode -class IncorrectVectorLiteralCount final : public FailureDiagnostic { +class IncorrectSlabLiteralCount final : public FailureDiagnostic { Type lhsCount, rhsCount; public: - IncorrectVectorLiteralCount(const Solution &solution, Type lhsCount, - Type rhsCount, ConstraintLocator *locator) + IncorrectSlabLiteralCount(const Solution &solution, Type lhsCount, + Type rhsCount, ConstraintLocator *locator) : FailureDiagnostic(solution, locator), lhsCount(resolveType(lhsCount)), rhsCount(resolveType(rhsCount)) {} diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index fe22926e30f94..452a95a87f321 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -2723,16 +2723,16 @@ IgnoreKeyPathSubscriptIndexMismatch::create(ConstraintSystem &cs, Type argType, IgnoreKeyPathSubscriptIndexMismatch(cs, argType, locator); } -AllowVectorLiteralCountMismatch * -AllowVectorLiteralCountMismatch::create(ConstraintSystem &cs, Type lhsCount, - Type rhsCount, - ConstraintLocator *locator) { +AllowSlabLiteralCountMismatch * +AllowSlabLiteralCountMismatch::create(ConstraintSystem &cs, Type lhsCount, + Type rhsCount, + ConstraintLocator *locator) { return new (cs.getAllocator()) - AllowVectorLiteralCountMismatch(cs, lhsCount, rhsCount, locator); + AllowSlabLiteralCountMismatch(cs, lhsCount, rhsCount, locator); } -bool AllowVectorLiteralCountMismatch::diagnose(const Solution &solution, - bool asNote) const { - IncorrectVectorLiteralCount failure(solution, lhsCount, rhsCount, getLocator()); +bool AllowSlabLiteralCountMismatch::diagnose(const Solution &solution, + bool asNote) const { + IncorrectSlabLiteralCount failure(solution, lhsCount, rhsCount, getLocator()); return failure.diagnose(asNote); } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index d66faed5eb14e..952a35ae9e967 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -8704,30 +8704,30 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( auto anchor = loc->getAnchor(); auto arrayLiteral = getAsExpr(anchor); - // If we're attempting to bind an array literal to a 'Vector' parameter, + // If we're attempting to bind an array literal to a 'Slab' parameter, // then check if the counts are equal and solve. if (kind == ConstraintKind::LiteralConformsTo && protocol == arrayLiteralProto && - type->isVector() && + type->isSlab() && arrayLiteral) { - auto vectorTy = type->castTo(); + auto slabTy = type->castTo(); - // + // // Attempt to bind the number of elements in the literal with the // contextual count. This will diagnose if the literal does not enough // or too many elements. - auto contextualCount = vectorTy->getGenericArgs()[0]; + auto contextualCount = slabTy->getGenericArgs()[0]; auto literalCount = IntegerType::get( std::to_string(arrayLiteral->getNumElements()), /* isNegative */ false, - vectorTy->getASTContext()); + slabTy->getASTContext()); // If the counts are already equal, '2' == '2', then we're done. if (contextualCount->isEqual(literalCount)) { return SolutionKind::Solved; } - // If our contextual count is not known, e.g., Vector<_, Int> = [1, 2], + // If our contextual count is not known, e.g., Slab<_, Int> = [1, 2], // then just eagerly bind the count to what the literal count is. if (contextualCount->isTypeVariableOrMember()) { addConstraint(ConstraintKind::Bind, contextualCount, literalCount, @@ -8739,8 +8739,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( if (!shouldAttemptFixes()) return SolutionKind::Error; - auto fix = AllowVectorLiteralCountMismatch::create(*this, contextualCount, - literalCount, loc); + auto fix = AllowSlabLiteralCountMismatch::create(*this, contextualCount, + literalCount, loc); return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; } } break; @@ -15654,7 +15654,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::IgnoreInvalidPlaceholder: case FixKind::IgnoreOutOfPlaceThenStmt: case FixKind::IgnoreMissingEachKeyword: - case FixKind::AllowVectorLiteralCountMismatch: + case FixKind::AllowSlabLiteralCountMismatch: llvm_unreachable("handled elsewhere"); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 5caf109afde87..c6f508a99489b 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1666,10 +1666,10 @@ struct TypeSimplifier { auto *proto = assocType->getProtocol(); auto conformance = CS.lookupConformance(lookupBaseType, proto); if (!conformance) { - // Special case: When building vector literals, we go through the same + // Special case: When building slab literals, we go through the same // array literal machinery, so there will be a conversion constraint // for the element to ExpressibleByArrayLiteral.ArrayLiteralType. - if (lookupBaseType->isVector()) { + if (lookupBaseType->isSlab()) { auto &ctx = CS.getASTContext(); auto arrayProto = ctx.getProtocol(KnownProtocolKind::ExpressibleByArrayLiteral); diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 74cc96c8ff74f..1bb0dc2400a37 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -560,6 +560,7 @@ static void checkGenericParams(GenericContext *ownerCtx) { return; auto *decl = ownerCtx->getAsDecl(); + auto &ctx = ownerCtx->getASTContext(); bool hasPack = false; for (auto gp : *genericParams) { @@ -567,10 +568,13 @@ static void checkGenericParams(GenericContext *ownerCtx) { // is not enabled. if (gp->isParameterPack()) { // Variadic nominal types require runtime support. - if (isa(decl)) { + // + // Embedded doesn't require runtime support for this feature. + if (isa(decl) && + !ctx.LangOpts.hasFeature(Feature::Embedded)) { TypeChecker::checkAvailability( gp->getSourceRange(), - ownerCtx->getASTContext().getVariadicGenericTypeAvailability(), + ctx.getVariadicGenericTypeAvailability(), diag::availability_variadic_type_only_version_newer, ownerCtx); } @@ -586,10 +590,13 @@ static void checkGenericParams(GenericContext *ownerCtx) { if (gp->isValue()) { // Value generic nominal types require runtime support. - if (isa(decl)) { + // + // Embedded doesn't require runtime support for this feature. + if (isa(decl) && + !ctx.LangOpts.hasFeature(Feature::Embedded)) { TypeChecker::checkAvailability( gp->getSourceRange(), - ownerCtx->getASTContext().getValueGenericTypeAvailability(), + ctx.getValueGenericTypeAvailability(), diag::availability_value_generic_type_only_version_newer, ownerCtx); } diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index f9ec533469129..eb9547e7491dd 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -151,6 +151,7 @@ split_embedded_sources( EMBEDDED SetVariant.swift EMBEDDED ShadowProtocols.swift NORMAL Shims.swift + EMBEDDED Slab.swift EMBEDDED Slice.swift EMBEDDED SmallString.swift EMBEDDED Sort.swift @@ -214,7 +215,6 @@ split_embedded_sources( EMBEDDED Unicode.swift # ORDER DEPENDENCY: must follow new unicode support EMBEDDED StringGraphemeBreaking.swift # ORDER DEPENDENCY: Must follow UTF16.swift EMBEDDED ValidUTF8Buffer.swift - EMBEDDED Vector.swift EMBEDDED WriteBackMutableSlice.swift EMBEDDED MigrationSupport.swift @@ -320,6 +320,8 @@ list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Freestand list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Extern") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "BitwiseCopyable") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "ValueGenerics") +list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "AddressableParameters") +list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "AddressableTypes") if("${SWIFT_NATIVE_SWIFT_TOOLS_PATH}" STREQUAL "") set(swift_bin_dir "${CMAKE_BINARY_DIR}/bin") diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index 2e95ebc198c6f..93786a2f20c8b 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -257,7 +257,7 @@ "EmbeddedRuntime.swift", "EmbeddedStubs.swift", "EmbeddedPrint.swift", - "Vector.swift" + "Slab.swift" ], "Result": [ "Result.swift" diff --git a/stdlib/public/core/Vector.swift b/stdlib/public/core/Slab.swift similarity index 66% rename from stdlib/public/core/Vector.swift rename to stdlib/public/core/Slab.swift index 6b5189be5a4ac..26b0c7084f899 100644 --- a/stdlib/public/core/Vector.swift +++ b/stdlib/public/core/Slab.swift @@ -13,26 +13,26 @@ /// A fixed-size array. @available(SwiftStdlib 6.1, *) @frozen -public struct Vector: ~Copyable { +public struct Slab: ~Copyable { @usableFromInline let storage: Builtin.FixedArray } @available(SwiftStdlib 6.1, *) -extension Vector: Copyable where Element: Copyable {} +extension Slab: Copyable where Element: Copyable {} @available(SwiftStdlib 6.1, *) -extension Vector: BitwiseCopyable where Element: BitwiseCopyable {} +extension Slab: BitwiseCopyable where Element: BitwiseCopyable {} @available(SwiftStdlib 6.1, *) -extension Vector: @unchecked Sendable where Element: Sendable & ~Copyable {} +extension Slab: @unchecked Sendable where Element: Sendable & ~Copyable {} //===----------------------------------------------------------------------===// // Address & Buffer //===----------------------------------------------------------------------===// @available(SwiftStdlib 6.1, *) -extension Vector where Element: ~Copyable { +extension Slab where Element: ~Copyable { /// Returns a read-only pointer to the first element in the vector. @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @@ -89,7 +89,7 @@ extension Vector where Element: ~Copyable { //===----------------------------------------------------------------------===// @available(SwiftStdlib 6.1, *) -extension Vector where Element: ~Copyable { +extension Slab where Element: ~Copyable { /// Initializes every element in this vector running the given closure value /// that returns the element to emplace at the given index. /// @@ -106,7 +106,7 @@ extension Vector where Element: ~Copyable { @_alwaysEmitIntoClient public init(_ body: (Int) throws(E) -> Element) throws(E) { self = try Builtin.emplace { (rawPtr) throws(E) -> () in - let buffer = Vector._initializationBuffer(start: rawPtr) + let buffer = Slab._initializationBuffer(start: rawPtr) for i in 0 ..< count { do throws(E) { @@ -125,46 +125,6 @@ extension Vector where Element: ~Copyable { } } - /// Initializes every element in this vector by running the closure with the - /// passed in mutable state. - /// - /// This will call the closure 'count' times, where 'count' is the static - /// count of the vector, to initialize every element by passing the closure - /// an inout reference to the passed state. The closure is allowed to throw - /// an error at any point during initialization at which point the vector will - /// stop initialization, deinitialize every currently initialized element, and - /// throw the given error back out to the caller. - /// - /// - Parameter state: The mutable state that can be altered during each - /// iteration of the closure initializing the vector. - /// - Parameter next: A closure that passes in an inout reference to the - /// user given mutable state which returns an owned - /// `Element` instance to insert into the vector. - @available(SwiftStdlib 6.1, *) - @_alwaysEmitIntoClient - public init( - expand state: consuming State, - with next: (inout State) throws(E) -> Element - ) throws(E) { - self = try Builtin.emplace { (rawPtr) throws(E) -> () in - let buffer = Vector._initializationBuffer(start: rawPtr) - - for i in 0 ..< count { - do throws(E) { - try buffer.initializeElement(at: i, to: next(&state)) - } catch { - // The closure threw an error. We need to deinitialize every element - // we've initialized up to this point. - for j in 0 ..< i { - buffer.deinitializeElement(at: j) - } - - throw error - } - } - } - } - /// Initializes every element in this vector by running the closure with the /// passed in first element. /// @@ -184,8 +144,8 @@ extension Vector where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient public init( - unfold first: consuming Element, - with next: (borrowing Element) throws(E) -> Element + first: consuming Element, + next: (borrowing Element) throws(E) -> Element ) throws(E) { // FIXME: We should be able to mark 'Builtin.emplace' as '@once' or something // to give the compiler enough information to know we will only run @@ -194,13 +154,13 @@ extension Vector where Element: ~Copyable { var o: Element? = first self = try Builtin.emplace { (rawPtr) throws(E) -> () in - let buffer = Vector._initializationBuffer(start: rawPtr) + let buffer = Slab._initializationBuffer(start: rawPtr) buffer.initializeElement(at: 0, to: o.take()._consumingUncheckedUnwrapped()) for i in 1 ..< count { do throws(E) { - try buffer.initializeElement(at: i, to: next(buffer[0])) + try buffer.initializeElement(at: i, to: next(buffer[i &- 1])) } catch { // The closure threw an error. We need to deinitialize every element // we've initialized up to this point. @@ -216,7 +176,7 @@ extension Vector where Element: ~Copyable { } @available(SwiftStdlib 6.1, *) -extension Vector where Element: Copyable { +extension Slab where Element: Copyable { /// Initializes every element in this vector to a copy of the given value. /// /// - Parameter value: The instance to initialize this vector with. @@ -224,7 +184,7 @@ extension Vector where Element: Copyable { @_alwaysEmitIntoClient public init(repeating value: Element) { self = Builtin.emplace { - let buffer = Vector._initializationBuffer(start: $0) + let buffer = Slab._initializationBuffer(start: $0) buffer.initialize(repeating: value) } @@ -236,7 +196,7 @@ extension Vector where Element: Copyable { //===----------------------------------------------------------------------===// @available(SwiftStdlib 6.1, *) -extension Vector where Element: ~Copyable { +extension Slab where Element: ~Copyable { /// A type representing the collection's elements. @available(SwiftStdlib 6.1, *) public typealias Element = Element @@ -249,11 +209,6 @@ extension Vector where Element: ~Copyable { @available(SwiftStdlib 6.1, *) public typealias Index = Int - /// A type that represents the indices that are valid for subscripting the - /// collection, in ascending order. - @available(SwiftStdlib 6.1, *) - public typealias Indices = Range - /// The number of elements in the collection. @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @@ -325,7 +280,7 @@ extension Vector where Element: ~Copyable { @_alwaysEmitIntoClient @_transparent public var indices: Range { - startIndex ..< endIndex + Range(_uncheckedBounds: (0, count)) } /// Returns the position immediately after the given index. @@ -372,20 +327,21 @@ extension Vector where Element: ~Copyable { /// /// - Complexity: O(1) @available(SwiftStdlib 6.1, *) + @_addressableSelf @_alwaysEmitIntoClient public subscript(_ i: Int) -> Element { @_transparent - _read { - _precondition(startIndex <= i && i < endIndex, "Index out of bounds") + unsafeAddress { + _precondition(indices.contains(i), "Index out of bounds") - yield ((address + i).pointee) + return address + i } @_transparent - _modify { - _precondition(startIndex <= i && i < endIndex, "Index out of bounds") + unsafeMutableAddress { + _precondition(indices.contains(i), "Index out of bounds") - yield &(mutableAddress + i).pointee + return mutableAddress + i } } } @@ -395,61 +351,7 @@ extension Vector where Element: ~Copyable { //===----------------------------------------------------------------------===// @available(SwiftStdlib 6.1, *) -extension Vector where Element: ~Copyable { - /// Returns the result of combining the elements of the vector using the - /// given closure. - /// - /// Use the `reduce(into:_:)` method to produce a single value from the - /// elements of an entire vector. For example, you can use this method on a - /// vector of integers to filter adjacent equal entries or count frequencies. - /// - /// The `updateAccumulatingResult` closure is called sequentially with a - /// mutable accumulating value initialized to `initialResult` and each element - /// of the vector. This example shows how to build a dictionary of letter - /// frequencies of a vector. - /// - /// let letters: Vector = ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"] - /// let letterCount = letters.reduce(into: [:]) { counts, letter in - /// counts[letter, default: 0] += 1 - /// } - /// // letterCount == ["a": 5, "b": 2, "r": 2, "c": 1, "d": 1] - /// - /// When `letters.reduce(into:_:)` is called, the following steps occur: - /// - /// 1. The `updateAccumulatingResult` closure is called with the initial - /// accumulating value---`[:]` in this case---and the first character of - /// `letters`, modifying the accumulating value by setting `1` for the key - /// `"a"`. - /// 2. The closure is called again repeatedly with the updated accumulating - /// value and each element of the vector. - /// 3. When the vector is exhausted, the accumulating value is returned to - /// the caller. - /// - /// If the vector has no elements, `updateAccumulatingResult` is never - /// executed and `initialResult` is the result of the call to - /// `reduce(into:_:)`. - /// - /// - Parameters: - /// - initialResult: The value to use as the initial accumulating value. - /// - updateAccumulatingResult: A closure that updates the accumulating - /// value with an element of the vector. - /// - Returns: The final accumulated value. If the vector has no elements, - /// the result is `initialResult`. - /// - /// - Complexity: O(*n*), where *n* is the length of the sequence. - @available(SwiftStdlib 6.1, *) - @_alwaysEmitIntoClient - public func reduce( - into initialResult: consuming Result, - _ updateAccumulatingResult: (inout Result, borrowing Element) throws(E) -> () - ) throws(E) -> Result { - for i in 0 ..< count { - try updateAccumulatingResult(&initialResult, self[i]) - } - - return initialResult - } - +extension Slab where Element: ~Copyable { /// Exchanges the values at the specified indices of the vector. /// /// Both parameters must be valid indices of the vector and not @@ -467,7 +369,7 @@ extension Vector where Element: ~Copyable { _ i: Int, _ j: Int ) { - guard i != j else { + guard i != j, indices.contains(i), indices.contains(j) else { return } @@ -483,7 +385,7 @@ extension Vector where Element: ~Copyable { //===----------------------------------------------------------------------===// @available(SwiftStdlib 6.1, *) -extension Vector where Element: ~Copyable { +extension Slab where Element: ~Copyable { /// Calls a closure with a pointer to the vector's contiguous storage. /// /// Often, the optimizer can eliminate bounds checks within a vector @@ -494,7 +396,7 @@ extension Vector where Element: ~Copyable { /// buffer pointer: /// /// // "[1, 2, 3, 4, 5]" - /// let numbers = Vector<5, Int> { + /// let numbers = Slab<5, Int> { /// $0 + 1 /// } /// @@ -520,7 +422,7 @@ extension Vector where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - public borrowing func withUnsafeBufferPointer( + public borrowing func _withUnsafeBufferPointer( _ body: (UnsafeBufferPointer) throws(E) -> Result ) throws(E) -> Result { try body(buffer) @@ -538,7 +440,7 @@ extension Vector where Element: ~Copyable { /// the vector: /// /// // "[1, 2, 3, 4, 5]" - /// var numbers = Vector<5, Int> { + /// var numbers = Slab<5, Int> { /// $0 + 1 /// } /// @@ -569,81 +471,9 @@ extension Vector where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - public mutating func withUnsafeMutableBufferPointer( + public mutating func _withUnsafeMutableBufferPointer( _ body: (UnsafeMutableBufferPointer) throws(E) -> Result ) throws(E) -> Result { try body(mutableBuffer) } } - -//===----------------------------------------------------------------------===// -// Equatable -//===----------------------------------------------------------------------===// - -@available(SwiftStdlib 6.1, *) -extension Vector where Element: Equatable { - /// Returns a Boolean value indicating whether two vectors contain the same - /// elements in the same order. - /// - /// You can use the equal-to operator (`==`) to compare any two vectors - /// that store the same, `Equatable`-conforming element type. - /// - /// - Parameters: - /// - lhs: A vector to compare. - /// - rhs: Another vector to compare. - @available(SwiftStdlib 6.1, *) - @_alwaysEmitIntoClient - @_transparent - public static func ==( - lhs: borrowing Vector, - rhs: borrowing Vector - ) -> Bool { - // No need for a count check because these are statically guaranteed to have - // the same count... - - for i in 0 ..< count { - guard lhs[i] == rhs[i] else { - return false - } - } - - return true - } -} - -//===----------------------------------------------------------------------===// -// CustomStringConvertible and CustomDebugStringConvertible APIs -//===----------------------------------------------------------------------===// - -@available(SwiftStdlib 6.1, *) -extension Vector where Element: CustomDebugStringConvertible { - /// A textual representation of the vector and its elements. - @available(SwiftStdlib 6.1, *) - @_alwaysEmitIntoClient // FIXME: Remove this once 'Vector' actually conforms - // to 'CustomStringConvertible'. - public var description: String { - var result = "[" - var isFirst = true - - for i in 0 ..< count { - if !isFirst { - result += ", " - } else { - isFirst = false - } - - result += self[i].debugDescription - } - - result += "]" - return result - } - - /// A textual representation of the vector and its elements. - @available(SwiftStdlib 6.1, *) - @_alwaysEmitIntoClient // FIXME: Remove this once 'Vector' actually conforms - // to 'CustomDebugStringConvertible'. - public var debugDescription: String { - description - } -} diff --git a/test/DebugInfo/value-generics-embedded.swift b/test/DebugInfo/value-generics-embedded.swift index 88aa4e00621ab..cbed8bccc03c4 100644 --- a/test/DebugInfo/value-generics-embedded.swift +++ b/test/DebugInfo/value-generics-embedded.swift @@ -2,14 +2,14 @@ // REQUIR123ES: swift_feature_ValueGenerics -// CHECK-DAG: !DICompositeType({{.*}}templateParams: ![[VECTOR_PARAMS:.*]], {{.*}}identifier: "$ss6VectorVy$0_4main8MySpriteVGD" -// CHECK-DAG: ![[VECTOR_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} +// CHECK-DAG: !DICompositeType({{.*}}templateParams: ![[SLAB_PARAMS:.*]], {{.*}}identifier: "$es4SlabVy$0_4main8MySpriteVGD" +// CHECK-DAG: ![[SLAB_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} // CHECK-DAG: ![[COUNT_PARAM]] = !DITemplateTypeParameter(type: ![[COUNT_TYPE:.*]]) -// CHECK-DAG: ![[COUNT_TYPE]] = !DICompositeType({{.*}}name: "$s$0_D" +// CHECK-DAG: ![[COUNT_TYPE]] = !DICompositeType({{.*}}name: "$e$0_D" // CHECK-DAG: ![[ELEMENT_PARAM]] = !DITemplateTypeParameter(type: ![[ELEMENT_TYPE:.*]]) -// CHECK-DAG: ![[ELEMENT_TYPE]] = !DICompositeType({{.*}}name: "MySprite", {{.*}}identifier: "$s4main8MySpriteVD" +// CHECK-DAG: ![[ELEMENT_TYPE]] = !DICompositeType({{.*}}name: "MySprite", {{.*}}identifier: "$e4main8MySpriteVD" struct MySprites { - var bricks: Vector<1,MySprite> + var bricks: Slab<1, MySprite> } struct MySprite { @@ -19,6 +19,6 @@ struct MySprite { nonisolated(unsafe) var sprites: MySprites? = nil public func foo() { - let bricks: Vector<1,MySprite> = [MySprite()] + let bricks: Slab<1, MySprite> = [MySprite()] sprites = .init(bricks: bricks) } diff --git a/test/DebugInfo/value-generics.swift b/test/DebugInfo/value-generics.swift index ecedba104bcf6..31071ffcac28c 100644 --- a/test/DebugInfo/value-generics.swift +++ b/test/DebugInfo/value-generics.swift @@ -4,25 +4,25 @@ import Builtin -struct Vector: ~Copyable { +struct Slab: ~Copyable { let storage: Builtin.FixedArray } -extension Vector: Copyable where Element: Copyable {} +extension Slab: Copyable where Element: Copyable {} // CHECK-DAG: !DICompositeType({{.*}}name: "Builtin.FixedArray", {{.*}}identifier: "$sxq_BVD" func genericBA(_: Builtin.FixedArray) {} -// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main6VectorVyxq_GD" -func genericV(_: Vector) {} +// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main4SlabVyxq_GD" +func genericV(_: Slab) {} // CHECK-DAG: !DICompositeType({{.*}}name: "Builtin.FixedArray", {{.*}}identifier: "$s$3_SiBVD" func concreteBA(_: Builtin.FixedArray<4, Int>) {} -// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main6VectorVy$1_SiGD", {{.*}}templateParams: ![[VECTOR_PARAMS:.*]]) -// CHECK-DAG: ![[VECTOR_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} +// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main4SlabVy$1_SiGD", {{.*}}templateParams: ![[SLAB_PARAMS:.*]]) +// CHECK-DAG: ![[SLAB_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} // CHECK-DAG: ![[COUNT_PARAM]] = !DITemplateTypeParameter(type: ![[COUNT_TYPE:.*]]) // CHECK-DAG: ![[COUNT_TYPE]] = !DICompositeType({{.*}}name: "$s$1_D" // CHECK-DAG: ![[ELEMENT_PARAM]] = !DITemplateTypeParameter(type: ![[ELEMENT_TYPE:.*]]) // CHECK-DAG: ![[ELEMENT_TYPE]] = !DICompositeType({{.*}}name: "$sSiD" -func concreteV(_: Vector<2, Int>) {} +func concreteV(_: Slab<2, Int>) {} diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index f5b079b854d82..11950466b874f 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -481,5 +481,5 @@ $s2hi1SVIetMIy_TC ---> coroutine continuation prototype for @escaping @conventi $s4mainAAyyycAA1CCFTTI ---> identity thunk of main.main(main.C) -> () -> () $s4mainAAyyycAA1CCFTTH ---> hop to main actor thunk of main.main(main.C) -> () -> () -$s4main6VectorVy$1_SiG ---> main.Vector<2, Swift.Int> +$s4main4SlabVy$1_SiG ---> main.Slab<2, Swift.Int> $s$n3_SSBV ---> Builtin.FixedArray<-4, Swift.String> diff --git a/test/IRGen/array_type_layout.swift b/test/IRGen/array_type_layout.swift index 662d4e5859ce7..549f45d31295d 100644 --- a/test/IRGen/array_type_layout.swift +++ b/test/IRGen/array_type_layout.swift @@ -2,8 +2,8 @@ // REQUIRES: swift_feature_ValueGenerics -struct VerySmallVector { - var inline: Vector<16, T?> +struct VerySmallSlab { + var inline: Slab<16, T?> var count = 0 init() { @@ -12,10 +12,10 @@ struct VerySmallVector { } //===----------------------------------------------------------------------===// -// VerySmallVector initializeBufferWithCopyOfBuffer +// VerySmallSlab initializeBufferWithCopyOfBuffer //===----------------------------------------------------------------------===// -// CHECK-LABEL: define {{.*}} ptr @"$s17array_type_layout15VerySmallVectorVwCP"(ptr{{.*}} %dest, ptr{{.*}} %src, ptr{{.*}} %"VerySmallVector") +// CHECK-LABEL: define {{.*}} ptr @"$s17array_type_layout13VerySmallSlabVwCP"(ptr{{.*}} %dest, ptr{{.*}} %src, ptr{{.*}} %"VerySmallSlab") // CHECK: [[FLAGS:%.*]] = load i32, ptr {{.*}} // CHECK-NEXT: [[INLINE_BIT:%.*]] = and i32 [[FLAGS]], 131072 // CHECK-NEXT: [[IS_INLINE:%.*]] = icmp eq i32 [[INLINE_BIT]], 0 diff --git a/test/ModuleInterface/value_generics.swift b/test/ModuleInterface/value_generics.swift index 51784a09225b9..5adf8c3c58e58 100644 --- a/test/ModuleInterface/value_generics.swift +++ b/test/ModuleInterface/value_generics.swift @@ -5,8 +5,8 @@ // REQUIRES: swift_feature_ValueGenerics -// CHECK: public struct Vector -public struct Vector { +// CHECK: public struct Slab +public struct Slab { // CHECK-LABEL: public var count: Swift.Int { // CHECK-NEXT: get { // CHECK-NEXT: N @@ -18,11 +18,11 @@ public struct Vector { } } -// CHECK: public func usesGenericVector(_: ValueGeneric.Vector) -public func usesGenericVector(_: Vector) {} +// CHECK: public func usesGenericSlab(_: ValueGeneric.Slab) +public func usesGenericSlab(_: Slab) {} -// CHECK: public func usesConcreteVector(_: ValueGeneric.Vector) -public func usesConcreteVector(_: Vector) {} +// CHECK: public func usesConcreteSlab(_: ValueGeneric.Slab) +public func usesConcreteSlab(_: Slab) {} -// CHECK: public func usesNegativeVector(_: ValueGeneric.Vector) -public func usesNegativeVector(_: Vector) {} +// CHECK: public func usesNegativeSlab(_: ValueGeneric.Slab) +public func usesNegativeSlab(_: Slab) {} diff --git a/test/SILGen/vector_literal.swift b/test/SILGen/slab_literal.swift similarity index 52% rename from test/SILGen/vector_literal.swift rename to test/SILGen/slab_literal.swift index 1f3f560bf88c9..9f9701e8d510b 100644 --- a/test/SILGen/vector_literal.swift +++ b/test/SILGen/slab_literal.swift @@ -4,74 +4,74 @@ import Synchronization -// CHECK-LABEL: sil{{.*}} @$s14vector_literal7trivials6VectorVy$3_SiGyF : $@convention(thin) () -> Vector<4, Int> { -// CHECK: [[VECTOR_ALLOC:%.*]] = alloc_stack $Vector<4, Int> -// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[VECTOR_ALLOC]] : $*Vector<4, Int> to $*Int +// CHECK-LABEL: sil{{.*}} @$s12slab_literal7trivials4SlabVy$3_SiGyF : $@convention(thin) () -> Slab<4, Int> { +// CHECK: [[SLAB_ALLOC:%.*]] = alloc_stack $Slab<4, Int> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*Int // CHECK-NEXT: [[ELT_0_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 1 // CHECK: [[ELT_0:%.*]] = apply {{%.*}}([[ELT_0_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK-NEXT: store [[ELT_0]] to [trivial] [[ELEMENT_PTR]] : $*Int +// CHECK-NEXT: store [[ELT_0]] to [trivial] [[ELEMENT_PTR]] // CHECK-NEXT: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 -// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*Int, [[ELT_1_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_1_OFFSET]] // CHECK-NEXT: [[ELT_1_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 2 // CHECK: [[ELT_1:%.*]] = apply {{%.*}}([[ELT_1_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK-NEXT: store [[ELT_1]] to [trivial] [[ELT_1_PTR]] : $*Int +// CHECK-NEXT: store [[ELT_1]] to [trivial] [[ELT_1_PTR]] // CHECK-NEXT: [[ELT_2_OFFSET:%.*]] = integer_literal $Builtin.Word, 2 -// CHECK-NEXT: [[ELT_2_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*Int, [[ELT_2_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_2_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_2_OFFSET]] // CHECK-NEXT: [[ELT_2_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 3 // CHECK: [[ELT_2:%.*]] = apply {{%.*}}([[ELT_2_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK-NEXT: store [[ELT_2]] to [trivial] [[ELT_2_PTR]] : $*Int +// CHECK-NEXT: store [[ELT_2]] to [trivial] [[ELT_2_PTR]] // CHECK-NEXT: [[ELT_3_OFFSET:%.*]] = integer_literal $Builtin.Word, 3 -// CHECK-NEXT: [[ELT_3_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*Int, [[ELT_3_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_3_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_3_OFFSET]] // CHECK-NEXT: [[ELT_3_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 4 // CHECK: [[ELT_3:%.*]] = apply {{%.*}}([[ELT_3_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK-NEXT: store [[ELT_3]] to [trivial] [[ELT_3_PTR]] : $*Int -// CHECK-NEXT: [[VECTOR:%.*]] = load [trivial] [[VECTOR_ALLOC]] : $*Vector<4, Int> -// CHECK-NEXT: dealloc_stack [[VECTOR_ALLOC]] : $*Vector<4, Int> -// CHECK-NEXT: return [[VECTOR]] : $Vector<4, Int> -// CHECK-LABEL: } // end sil function '$s14vector_literal7trivials6VectorVy$3_SiGyF' -func trivial() -> Vector<4, Int> { +// CHECK-NEXT: store [[ELT_3]] to [trivial] [[ELT_3_PTR]] +// CHECK-NEXT: [[SLAB:%.*]] = load [trivial] [[SLAB_ALLOC]] +// CHECK-NEXT: dealloc_stack [[SLAB_ALLOC]] +// CHECK-NEXT: return [[SLAB]] +// CHECK-LABEL: } // end sil function '$s12slab_literal7trivials4SlabVy$3_SiGyF' +func trivial() -> Slab<4, Int> { [1, 2, 3, 4] } -// CHECK-LABEL: sil{{.*}} @$s14vector_literal10nontrivials6VectorVy$1_SSGyF : $@convention(thin) () -> @owned Vector<2, String> { -// CHECK: [[VECTOR_ALLOC:%.*]] = alloc_stack $Vector<2, String> -// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[VECTOR_ALLOC]] : $*Vector<2, String> to $*String +// CHECK-LABEL: sil{{.*}} @$s12slab_literal10nontrivials4SlabVy$1_SSGyF : $@convention(thin) () -> @owned Slab<2, String> { +// CHECK: [[SLAB_ALLOC:%.*]] = alloc_stack $Slab<2, String> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*String // CHECK-NEXT: [[ELT_0_LITERAL:%.*]] = string_literal utf8 "hello" // CHECK: [[ELT_0:%.*]] = apply {{%.*}}([[ELT_0_LITERAL]], {{.*}}) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String -// CHECK-NEXT: store [[ELT_0]] to [init] [[ELEMENT_PTR]] : $*String +// CHECK-NEXT: store [[ELT_0]] to [init] [[ELEMENT_PTR]] // CHECK-NEXT: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 -// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*String, [[ELT_1_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_1_OFFSET]] // CHECK-NEXT: [[ELT_1_LITERAL:%.*]] = string_literal utf8 "world" // CHECK: [[ELT_1:%.*]] = apply {{%.*}}([[ELT_1_LITERAL]], {{.*}}) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String -// CHECK-NEXT: store [[ELT_1]] to [init] [[ELT_1_PTR]] : $*String -// CHECK-NEXT: [[VECTOR:%.*]] = load [take] [[VECTOR_ALLOC]] : $*Vector<2, String> -// CHECK-NEXT: dealloc_stack [[VECTOR_ALLOC]] : $*Vector<2, String> -// CHECK-NEXT: return [[VECTOR]] : $Vector<2, String> -// CHECK-LABEL: } // end sil function '$s14vector_literal10nontrivials6VectorVy$1_SSGyF' -func nontrivial() -> Vector<2, String> { +// CHECK-NEXT: store [[ELT_1]] to [init] [[ELT_1_PTR]] +// CHECK-NEXT: [[SLAB:%.*]] = load [take] [[SLAB_ALLOC]] +// CHECK-NEXT: dealloc_stack [[SLAB_ALLOC]] +// CHECK-NEXT: return [[SLAB]] +// CHECK-LABEL: } // end sil function '$s12slab_literal10nontrivials4SlabVy$1_SSGyF' +func nontrivial() -> Slab<2, String> { ["hello", "world"] } -// CHECK-LABEL: sil{{.*}} @$s14vector_literal11noncopyables6VectorVy$1_15Synchronization6AtomicVySiGGyF : $@convention(thin) () -> @out Vector<2, Atomic> { -// CHECK: bb0([[VECTOR_RETURN:%.*]] : $*Vector<2, Atomic>): -// CHECK-NEXT: [[VECTOR_ALLOC:%.*]] = alloc_stack $Vector<2, Atomic> -// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[VECTOR_ALLOC]] : $*Vector<2, Atomic> to $*Atomic +// CHECK-LABEL: sil{{.*}} @$s12slab_literal11noncopyables4SlabVy$1_15Synchronization6AtomicVySiGGyF : $@convention(thin) () -> @out Slab<2, Atomic> { +// CHECK: bb0([[SLAB_RETURN:%.*]] : $*Slab<2, Atomic>): +// CHECK-NEXT: [[SLAB_ALLOC:%.*]] = alloc_stack $Slab<2, Atomic> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*Atomic // CHECK: [[ATOMIC_INIT:%.*]] = function_ref @$s15Synchronization6AtomicVyACyxGxcfC // CHECK-NEXT: [[ELT_0:%.*]] = apply [[ATOMIC_INIT]]([[ELEMENT_PTR]], {{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : AtomicRepresentable> (@in τ_0_0, @thin Atomic<τ_0_0>.Type) -> @out Atomic<τ_0_0> // CHECK: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 -// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]] : $*Atomic, [[ELT_1_OFFSET]] : $Builtin.Word +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_1_OFFSET]] // CHECK: [[ATOMIC_INIT:%.*]] = function_ref @$s15Synchronization6AtomicVyACyxGxcfC // CHECK-NEXT: [[ELT_1:%.*]] = apply [[ATOMIC_INIT]]([[ELT_1_PTR]], {{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : AtomicRepresentable> (@in τ_0_0, @thin Atomic<τ_0_0>.Type) -> @out Atomic<τ_0_0> -// CHECK: [[VECTOR_ALLOC_AGAIN:%.*]] = unchecked_addr_cast [[VECTOR_ALLOC]] : $*Vector<2, Atomic> to $*Vector<2, Atomic> +// CHECK: [[SLAB_ALLOC_AGAIN:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*Slab<2, Atomic> // CHECK-NEXT: [[BOX:%.*]] = alloc_box // CHECK-NEXT: [[BOX_BORROW:%.*]] = begin_borrow [lexical] [[BOX]] // CHECK-NEXT: [[BOX_PROJECT:%.*]] = project_box [[BOX_BORROW]] -// CHECK-NEXT: copy_addr [take] [[VECTOR_ALLOC_AGAIN]] to [init] [[BOX_PROJECT]] : $*Vector<2, Atomic> -// CHECK-NEXT: dealloc_stack [[VECTOR_ALLOC]] : $*Vector<2, Atomic> -// CHECK-NEXT: copy_addr [take] [[BOX_PROJECT]] to [init] [[VECTOR_RETURN]] : $*Vector<2, Atomic> +// CHECK-NEXT: copy_addr [take] [[SLAB_ALLOC_AGAIN]] to [init] [[BOX_PROJECT]] +// CHECK-NEXT: dealloc_stack [[SLAB_ALLOC]] +// CHECK-NEXT: copy_addr [take] [[BOX_PROJECT]] to [init] [[SLAB_RETURN]] // CHECK-NEXT: end_borrow [[BOX_BORROW]] // CHECK-NEXT: dealloc_box [[BOX]] -// CHECK-LABEL: } // end sil function '$s14vector_literal11noncopyables6VectorVy$1_15Synchronization6AtomicVySiGGyF' -func noncopyable() -> Vector<2, Atomic> { +// CHECK-LABEL: } // end sil function '$s12slab_literal11noncopyables4SlabVy$1_15Synchronization6AtomicVySiGGyF' +func noncopyable() -> Slab<2, Atomic> { [Atomic(0), Atomic(1)] } diff --git a/test/Sema/vector.swift b/test/Sema/slab.swift similarity index 61% rename from test/Sema/vector.swift rename to test/Sema/slab.swift index 10851fe3ead82..3e94324ad86bd 100644 --- a/test/Sema/vector.swift +++ b/test/Sema/slab.swift @@ -2,53 +2,53 @@ // REQUIRES: swift_feature_ValueGenerics -let a: Vector = [1, 2, 3] // Ok, Vector<3, Int> -let b: Vector<_, Int> = [1, 2, 3] // Ok, Vector<3, Int> -let c: Vector<3, _> = [1, 2, 3] // Ok, Vector<3, Int> +let a: Slab = [1, 2, 3] // Ok, Slab<3, Int> +let b: Slab<_, Int> = [1, 2, 3] // Ok, Slab<3, Int> +let c: Slab<3, _> = [1, 2, 3] // Ok, Slab<3, Int> -let d: Vector<2, _> = [1, 2, 3] // expected-error {{expected '2' elements in vector literal, but got '3'}} -let e: Vector<2, _> = [1] // expected-error {{expected '2' elements in vector literal, but got '1'}} +let d: Slab<2, _> = [1, 2, 3] // expected-error {{expected '2' elements in slab literal, but got '3'}} +let e: Slab<2, _> = [1] // expected-error {{expected '2' elements in slab literal, but got '1'}} -let f: Vector<_, Int> = ["hello"] // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} +let f: Slab<_, Int> = ["hello"] // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} -func takeVectorOf2(_: Vector<2, T>) {} +func takeVectorOf2(_: Slab<2, T>) {} takeVectorOf2([1, 2]) // Ok takeVectorOf2(["hello", "world"]) // Ok -takeVectorOf2([1]) // expected-error {{expected '2' elements in vector literal, but got '1'}} +takeVectorOf2([1]) // expected-error {{expected '2' elements in slab literal, but got '1'}} -takeVectorOf2([1, 2, 3]) // expected-error {{expected '2' elements in vector literal, but got '3'}} +takeVectorOf2([1, 2, 3]) // expected-error {{expected '2' elements in slab literal, but got '3'}} -takeVectorOf2(["hello"]) // expected-error {{expected '2' elements in vector literal, but got '1'}} +takeVectorOf2(["hello"]) // expected-error {{expected '2' elements in slab literal, but got '1'}} -takeVectorOf2(["hello", "world", "!"]) // expected-error {{expected '2' elements in vector literal, but got '3'}} +takeVectorOf2(["hello", "world", "!"]) // expected-error {{expected '2' elements in slab literal, but got '3'}} -func takeVectorOf2Int(_: Vector<2, Int>) {} +func takeVectorOf2Int(_: Slab<2, Int>) {} takeVectorOf2Int([1, 2]) // Ok -takeVectorOf2Int([1]) // expected-error {{expected '2' elements in vector literal, but got '1'}} +takeVectorOf2Int([1]) // expected-error {{expected '2' elements in slab literal, but got '1'}} -takeVectorOf2Int([1, 2, 3]) // expected-error {{expected '2' elements in vector literal, but got '3'}} +takeVectorOf2Int([1, 2, 3]) // expected-error {{expected '2' elements in slab literal, but got '3'}} -takeVectorOf2Int(["hello"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Vector<2, Int>'}} +takeVectorOf2Int(["hello"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Slab<2, Int>'}} takeVectorOf2Int(["hello", "world"]) // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} // expected-error@-1 {{cannot convert value of type 'String' to expected element type 'Int'}} -takeVectorOf2Int(["hello", "world", "!"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Vector<2, Int>'}} +takeVectorOf2Int(["hello", "world", "!"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Slab<2, Int>'}} struct X { - var sprites: Vector<2, Int> + var sprites: Slab<2, Int> } func foo(x: inout X) { - x.sprites = [1, 2, 3] // expected-error {{cannot assign value of type '[Int]' to type 'Vector<2, Int>'}} + x.sprites = [1, 2, 3] // expected-error {{cannot assign value of type '[Int]' to type 'Slab<2, Int>'}} } struct MySprites { - var bricks: Vector<40, MySprite> + var bricks: Slab<40, MySprite> } struct MySprite { @@ -59,15 +59,15 @@ nonisolated(unsafe) var sprites: MySprites? = nil func foo() { - let bricks: Vector<1, MySprite> = [MySprite()] + let bricks: Slab<1, MySprite> = [MySprite()] - sprites = .init(bricks: bricks) // expected-error {{cannot convert value of type 'Vector<1, MySprite>' to expected argument type 'Vector<40, MySprite>'}} + sprites = .init(bricks: bricks) // expected-error {{cannot convert value of type 'Slab<1, MySprite>' to expected argument type 'Slab<40, MySprite>'}} // expected-note@-1 {{arguments to generic parameter 'count' ('1' and '40') are expected to be equal}} } // Make sure the deserialized integer generic argument gets treated as an integer // generic argument when we clone the generic param list for extensions. -extension Vector where Element: ~Copyable { +extension Slab where Element: ~Copyable { func forEach(_ body: (borrowing Element) -> Void) { for i in 0 ..< count { body(self[i]) From cedea94b4c40d463647ca406922443f45ea239a7 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 9 Jan 2025 15:54:54 -0800 Subject: [PATCH 13/15] Test fixes and review feedback --- include/swift/RemoteInspection/TypeRef.h | 13 ++--- .../swift/RemoteInspection/TypeRefBuilder.h | 4 +- lib/Serialization/Serialization.cpp | 1 + .../public/RemoteInspection/TypeLowering.cpp | 3 +- stdlib/public/RemoteInspection/TypeRef.cpp | 11 ++--- stdlib/public/core/Slab.swift | 47 ++++++++++--------- test/DebugInfo/value-generics-embedded.swift | 3 +- test/Reflection/typeref_lowering.swift | 6 ++- test/abi/macOS/arm64/stdlib.swift | 12 +++++ 9 files changed, 58 insertions(+), 42 deletions(-) diff --git a/include/swift/RemoteInspection/TypeRef.h b/include/swift/RemoteInspection/TypeRef.h index b8361af231ae7..593a923d35370 100644 --- a/include/swift/RemoteInspection/TypeRef.h +++ b/include/swift/RemoteInspection/TypeRef.h @@ -1123,27 +1123,28 @@ class IntegerTypeRef final : public TypeRef { }; class BuiltinFixedArrayTypeRef final : public TypeRef { - intptr_t Size; + const TypeRef *Size; const TypeRef *Element; - static TypeRefID Profile(const intptr_t &Size, const TypeRef *Element) { + static TypeRefID Profile(const TypeRef *Size, const TypeRef *Element) { TypeRefID ID; - ID.addInteger((uint64_t)Size); + ID.addPointer(Size); ID.addPointer(Element); return ID; } public: - BuiltinFixedArrayTypeRef(const intptr_t &Size, const TypeRef *Element) + BuiltinFixedArrayTypeRef(const TypeRef *Size, const TypeRef *Element) : TypeRef(TypeRefKind::BuiltinFixedArray), Size(Size), Element(Element) {} template - static const BuiltinFixedArrayTypeRef *create(Allocator &A, intptr_t Size, + static const BuiltinFixedArrayTypeRef *create(Allocator &A, + const TypeRef *Size, const TypeRef *Element) { FIND_OR_CREATE_TYPEREF(A, BuiltinFixedArrayTypeRef, Size, Element); } - const intptr_t &getSize() const { + const TypeRef *getSizeType() const { return Size; } diff --git a/include/swift/RemoteInspection/TypeRefBuilder.h b/include/swift/RemoteInspection/TypeRefBuilder.h index cb791a0f42726..2fa93eda58fda 100644 --- a/include/swift/RemoteInspection/TypeRefBuilder.h +++ b/include/swift/RemoteInspection/TypeRefBuilder.h @@ -938,9 +938,7 @@ class TypeRefBuilder { const TypeRef *createBuiltinFixedArrayType(const TypeRef *size, const TypeRef *element) { - auto integer = cast(size); - return BuiltinFixedArrayTypeRef::create(*this, integer->getValue(), - element); + return BuiltinFixedArrayTypeRef::create(*this, size, element); } // Construct a bound generic type ref along with the parent type info diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index c4f2b65be04c2..97dd61a461219 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -958,6 +958,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(sil_block, SIL_OPEN_PACK_ELEMENT); BLOCK_RECORD(sil_block, SIL_PACK_ELEMENT_GET); BLOCK_RECORD(sil_block, SIL_PACK_ELEMENT_SET); + BLOCK_RECORD(sil_block, SIL_TYPE_VALUE); BLOCK_RECORD(sil_block, SIL_DEBUG_SCOPE); BLOCK_RECORD(sil_block, SIL_DEBUG_SCOPE_REF); BLOCK_RECORD(sil_block, SIL_SOURCE_LOC); diff --git a/stdlib/public/RemoteInspection/TypeLowering.cpp b/stdlib/public/RemoteInspection/TypeLowering.cpp index cc0e46475f38d..50b2b3e446d15 100644 --- a/stdlib/public/RemoteInspection/TypeLowering.cpp +++ b/stdlib/public/RemoteInspection/TypeLowering.cpp @@ -2595,8 +2595,9 @@ class LowerType const TypeInfo *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { auto elementTI = visit(BA->getElementType()); + auto size = cast(BA->getSizeType())->getValue(); - return TC.makeTypeInfo(BA->getSize(), elementTI); + return TC.makeTypeInfo(size, elementTI); } }; diff --git a/stdlib/public/RemoteInspection/TypeRef.cpp b/stdlib/public/RemoteInspection/TypeRef.cpp index fbc7798425035..bfa75f1d0f5e0 100644 --- a/stdlib/public/RemoteInspection/TypeRef.cpp +++ b/stdlib/public/RemoteInspection/TypeRef.cpp @@ -404,7 +404,7 @@ class PrintTypeRef : public TypeRefVisitor { void visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { printHeader("builtin_fixed_array"); - printField("size", std::to_string(BA->getSize())); + printRec(BA->getSizeType()); printRec(BA->getElementType()); stream << ")"; } @@ -1086,10 +1086,7 @@ class DemanglingForTypeRef Demangle::NodePointer visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { auto ba = Dem.createNode(Node::Kind::BuiltinFixedArray); - auto size = Dem.createNode(Node::Kind::Type); - size->addChild(createInteger(BA->getSize()), Dem); - ba->addChild(size, Dem); - + ba->addChild(visit(BA->getSizeType()), Dem); ba->addChild(visit(BA->getElementType()), Dem); return ba; @@ -1327,7 +1324,7 @@ class ThickenMetatype } const TypeRef *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { - return BuiltinFixedArrayTypeRef::create(Builder, BA->getSize(), + return BuiltinFixedArrayTypeRef::create(Builder, visit(BA->getSizeType()), visit(BA->getElementType())); } }; @@ -1590,7 +1587,7 @@ class TypeRefSubstitution } const TypeRef *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { - return BuiltinFixedArrayTypeRef::create(Builder, BA->getSize(), + return BuiltinFixedArrayTypeRef::create(Builder, visit(BA->getSizeType()), visit(BA->getElementType())); } }; diff --git a/stdlib/public/core/Slab.swift b/stdlib/public/core/Slab.swift index 26b0c7084f899..0fa642863045e 100644 --- a/stdlib/public/core/Slab.swift +++ b/stdlib/public/core/Slab.swift @@ -15,7 +15,7 @@ @frozen public struct Slab: ~Copyable { @usableFromInline - let storage: Builtin.FixedArray + internal let _storage: Builtin.FixedArray } @available(SwiftStdlib 6.1, *) @@ -37,7 +37,7 @@ extension Slab where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - var address: UnsafePointer { + internal var _address: UnsafePointer { UnsafePointer(Builtin.unprotectedAddressOfBorrow(self)) } @@ -45,15 +45,15 @@ extension Slab where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - var buffer: UnsafeBufferPointer { - UnsafeBufferPointer(start: address, count: count) + internal var _buffer: UnsafeBufferPointer { + UnsafeBufferPointer(start: _address, count: count) } /// Returns a mutable pointer to the first element in the vector. @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - var mutableAddress: UnsafeMutablePointer { + internal var _mutableAddress: UnsafeMutablePointer { mutating get { UnsafeMutablePointer(Builtin.unprotectedAddressOf(&self)) } @@ -63,9 +63,9 @@ extension Slab where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - var mutableBuffer: UnsafeMutableBufferPointer { + internal var _mutableBuffer: UnsafeMutableBufferPointer { mutating get { - UnsafeMutableBufferPointer(start: mutableAddress, count: count) + UnsafeMutableBufferPointer(start: _mutableAddress, count: count) } } @@ -74,7 +74,7 @@ extension Slab where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - static func _initializationBuffer( + internal static func _initializationBuffer( start: Builtin.RawPointer ) -> UnsafeMutableBufferPointer { UnsafeMutableBufferPointer( @@ -197,7 +197,7 @@ extension Slab where Element: Copyable { @available(SwiftStdlib 6.1, *) extension Slab where Element: ~Copyable { - /// A type representing the collection's elements. + /// The type of the container's elements. @available(SwiftStdlib 6.1, *) public typealias Element = Element @@ -292,7 +292,7 @@ extension Slab where Element: ~Copyable { @_alwaysEmitIntoClient @_transparent public borrowing func index(after i: Int) -> Int { - i + 1 + i &+ 1 } /// Returns the position immediately before the given index. @@ -304,7 +304,7 @@ extension Slab where Element: ~Copyable { @_alwaysEmitIntoClient @_transparent public borrowing func index(before i: Int) -> Int { - i - 1 + i &- 1 } /// Accesses the element at the specified position. @@ -334,14 +334,14 @@ extension Slab where Element: ~Copyable { unsafeAddress { _precondition(indices.contains(i), "Index out of bounds") - return address + i + return _address + i } @_transparent unsafeMutableAddress { _precondition(indices.contains(i), "Index out of bounds") - return mutableAddress + i + return _mutableAddress + i } } } @@ -369,14 +369,17 @@ extension Slab where Element: ~Copyable { _ i: Int, _ j: Int ) { - guard i != j, indices.contains(i), indices.contains(j) else { + guard i != j else { return } - let ithElement = mutableBuffer.moveElement(from: i) - let jthElement = mutableBuffer.moveElement(from: j) - mutableBuffer.initializeElement(at: i, to: jthElement) - mutableBuffer.initializeElement(at: j, to: ithElement) + _precondition(indices.contains(i), "Index out of bounds") + _precondition(indices.contains(j), "Index out of bounds") + + let ithElement = _mutableBuffer.moveElement(from: i) + let jthElement = _mutableBuffer.moveElement(from: j) + _mutableBuffer.initializeElement(at: i, to: jthElement) + _mutableBuffer.initializeElement(at: j, to: ithElement) } } @@ -422,10 +425,10 @@ extension Slab where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - public borrowing func _withUnsafeBufferPointer( + public borrowing func _withUnsafeBufferPointer( _ body: (UnsafeBufferPointer) throws(E) -> Result ) throws(E) -> Result { - try body(buffer) + try body(_buffer) } /// Calls the given closure with a pointer to the vector's mutable contiguous @@ -471,9 +474,9 @@ extension Slab where Element: ~Copyable { @available(SwiftStdlib 6.1, *) @_alwaysEmitIntoClient @_transparent - public mutating func _withUnsafeMutableBufferPointer( + public mutating func _withUnsafeMutableBufferPointer( _ body: (UnsafeMutableBufferPointer) throws(E) -> Result ) throws(E) -> Result { - try body(mutableBuffer) + try body(_mutableBuffer) } } diff --git a/test/DebugInfo/value-generics-embedded.swift b/test/DebugInfo/value-generics-embedded.swift index cbed8bccc03c4..c96bdd8d56796 100644 --- a/test/DebugInfo/value-generics-embedded.swift +++ b/test/DebugInfo/value-generics-embedded.swift @@ -1,6 +1,7 @@ // RUN: %target-swift-frontend %s -target %target-cpu-apple-macos14 -emit-ir -g -enable-experimental-feature ValueGenerics -enable-experimental-feature Embedded -wmo -disable-availability-checking -o - | %FileCheck %s -// REQUIR123ES: swift_feature_ValueGenerics +// REQUIRES: swift_feature_Embedded +// REQUIRES: swift_feature_ValueGenerics // CHECK-DAG: !DICompositeType({{.*}}templateParams: ![[SLAB_PARAMS:.*]], {{.*}}identifier: "$es4SlabVy$0_4main8MySpriteVGD" // CHECK-DAG: ![[SLAB_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} diff --git a/test/Reflection/typeref_lowering.swift b/test/Reflection/typeref_lowering.swift index ec56028cd3315..777546ab5f7e3 100644 --- a/test/Reflection/typeref_lowering.swift +++ b/test/Reflection/typeref_lowering.swift @@ -1271,10 +1271,12 @@ BD // CHECK-32-NEXT: (builtin size=48 alignment=8 stride=48 num_extra_inhabitants=0 bitwise_takable=1) $1_SiBV -// CHECK-64: (builtin_fixed_array size=2 +// CHECK-64: (builtin_fixed_array +// CHECK-64-NEXT: (integer value=2) // CHECK-64-NEXT: (struct Swift.Int)) // CHECK-64-NEXT: (array size=16 alignment=8 stride=16 num_extra_inhabitants=0 bitwise_takable=1) -// CHECK-32: (builtin_fixed_array size=2 +// CHECK-32: (builtin_fixed_array +// CHECK-32-NEXT: (integer value=2) // CHECK-32-NEXT: (struct Swift.Int)) // CHECK-32-NEXT: (array size=8 alignment=4 stride=8 num_extra_inhabitants=0 bitwise_takable=1) diff --git a/test/abi/macOS/arm64/stdlib.swift b/test/abi/macOS/arm64/stdlib.swift index 2dea1c96ddc58..9a5e5e70fb1c0 100644 --- a/test/abi/macOS/arm64/stdlib.swift +++ b/test/abi/macOS/arm64/stdlib.swift @@ -809,3 +809,15 @@ Added: _$ss13_SwiftifyInfoON // Eager-lazy Array bridging Added: _$ss12_ArrayBufferV14associationKeySVvpZMV + +// Slab metadata accessor +Added: _$ss4SlabVMa + +// Slab nominal type descriptor +Added: _$ss4SlabVMn + +// Slab.count property descriptor +Added: _$ss4SlabVsRi__rlE5countSivpZMV + +// Slab._storage _read accessor +Added: _$ss4SlabVsRi__rlE8_storagexq_BVvr From 4c5a13a63e21c7b27fc9fe01ccb89e07fe95961a Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Fri, 10 Jan 2025 17:52:50 -0800 Subject: [PATCH 14/15] Moar test fixes --- stdlib/public/core/Slab.swift | 2 +- test/DebugInfo/value-generics-embedded.swift | 2 ++ test/Sema/typo_correction.swift | 2 +- test/abi/macOS/x86_64/stdlib.swift | 12 ++++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/Slab.swift b/stdlib/public/core/Slab.swift index 0fa642863045e..b96f3fe11dc3d 100644 --- a/stdlib/public/core/Slab.swift +++ b/stdlib/public/core/Slab.swift @@ -347,7 +347,7 @@ extension Slab where Element: ~Copyable { } //===----------------------------------------------------------------------===// -// Reduce and Swap +// Swap //===----------------------------------------------------------------------===// @available(SwiftStdlib 6.1, *) diff --git a/test/DebugInfo/value-generics-embedded.swift b/test/DebugInfo/value-generics-embedded.swift index c96bdd8d56796..ed8c48e6bd800 100644 --- a/test/DebugInfo/value-generics-embedded.swift +++ b/test/DebugInfo/value-generics-embedded.swift @@ -1,5 +1,7 @@ // RUN: %target-swift-frontend %s -target %target-cpu-apple-macos14 -emit-ir -g -enable-experimental-feature ValueGenerics -enable-experimental-feature Embedded -wmo -disable-availability-checking -o - | %FileCheck %s +// REQUIRES: OS=macosx + // REQUIRES: swift_feature_Embedded // REQUIRES: swift_feature_ValueGenerics diff --git a/test/Sema/typo_correction.swift b/test/Sema/typo_correction.swift index 68c7413bd3ee1..33aafffbf7beb 100644 --- a/test/Sema/typo_correction.swift +++ b/test/Sema/typo_correction.swift @@ -10,7 +10,7 @@ import NoSuchModule // This is close enough to get typo-correction. func test_short_and_close() { - let plop = 4 // expected-note {{'plop' declared here}} + let plop = 4 // expected-note {{did you mean 'plop'?}} let bab = plob + 1 // expected-error@-1 {{cannot find 'plob' in scope}} } diff --git a/test/abi/macOS/x86_64/stdlib.swift b/test/abi/macOS/x86_64/stdlib.swift index d76c741599a8c..9f4543ff116d5 100644 --- a/test/abi/macOS/x86_64/stdlib.swift +++ b/test/abi/macOS/x86_64/stdlib.swift @@ -810,3 +810,15 @@ Added: _$ss13_SwiftifyInfoON // Eager-lazy Array bridging Added: _$ss12_ArrayBufferV14associationKeySVvpZMV + +// Slab metadata accessor +Added: _$ss4SlabVMa + +// Slab nominal type descriptor +Added: _$ss4SlabVMn + +// Slab.count property descriptor +Added: _$ss4SlabVsRi__rlE5countSivpZMV + +// Slab._storage _read accessor +Added: _$ss4SlabVsRi__rlE8_storagexq_BVvr From 7f5f2dccb6ce6e4abf4e5263d6dafe6f0ff4fce2 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Sat, 11 Jan 2025 18:57:53 -0800 Subject: [PATCH 15/15] Update array_type_layout.swift --- test/IRGen/array_type_layout.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/IRGen/array_type_layout.swift b/test/IRGen/array_type_layout.swift index 549f45d31295d..6b3434c4f5e93 100644 --- a/test/IRGen/array_type_layout.swift +++ b/test/IRGen/array_type_layout.swift @@ -50,7 +50,7 @@ struct VerySmallSlab { // CHECK-NEXT: [[END_LOOP_BB]]: // CHECK: [[DEST_COUNT_PTR:%.*]] = getelementptr inbounds i8, ptr %dest, i32 {{%.*}} // CHECK: [[SRC_COUNT_PTR:%.*]] = getelementptr inbounds i8, ptr %src, i32 {{%.*}} -// CHECK-NEXT: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[DEST_COUNT_PTR]], ptr{{.*}} [[SRC_COUNT_PTR]], i{{64|32}} 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[DEST_COUNT_PTR]], ptr{{.*}} [[SRC_COUNT_PTR]], i{{64 8|32 4}}, i1 false) // CHECK-NEXT: br label %[[CONT_BB]] // CHECK-EMPTY: // CHECK-NEXT: [[CONT_BB]]: