Skip to content

Replace rethrowing map with generic typed throws #69771

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2570,11 +2570,18 @@ IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
if (FnTy && (Opts.DebugInfoLevel > IRGenDebugInfoLevel::LineTables))
if (auto ErrorInfo = FnTy->getOptionalErrorResult()) {
GenericContextScope scope(IGM, FnTy->getInvocationGenericSignature());
CanType errorResultTy = ErrorInfo->getReturnValueType(
IGM.getSILModule(), FnTy,
IGM.getMaximalTypeExpansionContext());
SILType SILTy = IGM.silConv.getSILType(
*ErrorInfo, FnTy, IGM.getMaximalTypeExpansionContext());

errorResultTy = SILFn->mapTypeIntoContext(errorResultTy)
->getCanonicalType();
SILTy = SILFn->mapTypeIntoContext(SILTy);

auto DTI = DebugTypeInfo::getFromTypeInfo(
ErrorInfo->getReturnValueType(IGM.getSILModule(), FnTy,
IGM.getMaximalTypeExpansionContext()),
errorResultTy,
IGM.getTypeInfo(SILTy), IGM, false);
Error = DBuilder.getOrCreateArray({getOrCreateType(DTI)}).get();
}
Expand Down
18 changes: 15 additions & 3 deletions stdlib/public/core/Collection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1190,9 +1190,10 @@ extension Collection {
/// - Returns: An array containing the transformed elements of this
/// sequence.
@inlinable
public func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
@_alwaysEmitIntoClient
public func map<T, E>(
_ transform: (Element) throws(E) -> T
) throws(E) -> [T] {
// TODO: swift-3-indexing-model - review the following
let n = self.count
if n == 0 {
Expand All @@ -1213,6 +1214,17 @@ extension Collection {
return Array(result)
}

// ABI-only entrypoint for the rethrows version of map, which has been
// superseded by the typed-throws version. Expressed as "throws", which is
// ABI-compatible with "rethrows".
@usableFromInline
@_silgen_name("$sSlsE3mapySayqd__Gqd__7ElementQzKXEKlF")
func __rethrows_map<T>(
_ transform: (Element) throws -> T
) throws -> [T] {
try map(transform)
}

/// Returns a subsequence containing all but the given number of initial
/// elements.
///
Expand Down
106 changes: 85 additions & 21 deletions stdlib/public/core/ExistentialCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ internal class _AnySequenceBox<Element> {
@inlinable
internal func _map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
) throws -> [T] {
_abstract()
}

Expand Down Expand Up @@ -525,8 +525,8 @@ internal final class _SequenceBox<S: Sequence>: _AnySequenceBox<S.Element> {
@inlinable
internal override func _map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _base.map(transform)
) throws -> [T] {
try _base.map(transform)
}
@inlinable
internal override func _filter(
Expand Down Expand Up @@ -618,8 +618,8 @@ internal final class _CollectionBox<S: Collection>: _AnyCollectionBox<S.Element>
@inlinable
internal override func _map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _base.map(transform)
) throws -> [T] {
try _base.map(transform)
}
@inlinable
internal override func _filter(
Expand Down Expand Up @@ -813,8 +813,8 @@ internal final class _BidirectionalCollectionBox<S: BidirectionalCollection>
@inlinable
internal override func _map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _base.map(transform)
) throws -> [T] {
try _base.map(transform)
}
@inlinable
internal override func _filter(
Expand Down Expand Up @@ -1026,8 +1026,8 @@ internal final class _RandomAccessCollectionBox<S: RandomAccessCollection>
@inlinable
internal override func _map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _base.map(transform)
) throws -> [T] {
try _base.map(transform)
}
@inlinable
internal override func _filter(
Expand Down Expand Up @@ -1308,10 +1308,26 @@ extension AnySequence {
}

@inlinable
public func map<T>(
@_alwaysEmitIntoClient
public func map<T, E>(
_ transform: (Element) throws(E) -> T
) throws(E) -> [T] {
do {
return try _box._map(transform)
} catch {
throw error as! E
}
}

// ABI-only entrypoint for the rethrows version of map, which has been
// superseded by the typed-throws version. Expressed as "throws", which is
// ABI-compatible with "rethrows".
@usableFromInline
@_silgen_name("$ss11AnySequenceV3mapySayqd__Gqd__xKXEKlF")
func __rethrows_map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _box._map(transform)
) throws -> [T] {
try map(transform)
}

@inlinable
Expand Down Expand Up @@ -1395,10 +1411,26 @@ extension AnyCollection {
}

@inlinable
public func map<T>(
@_alwaysEmitIntoClient
public func map<T, E>(
_ transform: (Element) throws(E) -> T
) throws(E) -> [T] {
do {
return try _box._map(transform)
} catch {
throw error as! E
}
}

// ABI-only entrypoint for the rethrows version of map, which has been
// superseded by the typed-throws version. Expressed as "throws", which is
// ABI-compatible with "rethrows".
@usableFromInline
@_silgen_name("$ss13AnyCollectionV3mapySayqd__Gqd__xKXEKlF")
func __rethrows_map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _box._map(transform)
) throws -> [T] {
try map(transform)
}

@inlinable
Expand Down Expand Up @@ -1488,10 +1520,26 @@ extension AnyBidirectionalCollection {
}

@inlinable
public func map<T>(
@_alwaysEmitIntoClient
public func map<T, E>(
_ transform: (Element) throws(E) -> T
) throws(E) -> [T] {
do {
return try _box._map(transform)
} catch {
throw error as! E
}
}

// ABI-only entrypoint for the rethrows version of map, which has been
// superseded by the typed-throws version. Expressed as "throws", which is
// ABI-compatible with "rethrows".
@usableFromInline
@_silgen_name("$ss26AnyBidirectionalCollectionV3mapySayqd__Gqd__xKXEKlF")
func __rethrows_map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _box._map(transform)
) throws -> [T] {
try map(transform)
}

@inlinable
Expand Down Expand Up @@ -1583,10 +1631,26 @@ extension AnyRandomAccessCollection {
}

@inlinable
public func map<T>(
@_alwaysEmitIntoClient
public func map<T, E>(
_ transform: (Element) throws(E) -> T
) throws(E) -> [T] {
do {
return try _box._map(transform)
} catch {
throw error as! E
}
}

// ABI-only entrypoint for the rethrows version of map, which has been
// superseded by the typed-throws version. Expressed as "throws", which is
// ABI-compatible with "rethrows".
@usableFromInline
@_silgen_name("$ss25AnyRandomAccessCollectionV3mapySayqd__Gqd__xKXEKlF")
func __rethrows_map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _box._map(transform)
) throws -> [T] {
try map(transform)
}

@inlinable
Expand Down
10 changes: 10 additions & 0 deletions stdlib/public/core/Misc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ public func _unsafePerformance<T>(_ c: () -> T) -> T {
return c()
}

// Helper function that exploits a bug in rethrows checking to
// allow us to call rethrows functions from generic typed-throws functions
// and vice-versa.
@usableFromInline
@_alwaysEmitIntoClient
@inline(__always)
func _rethrowsViaClosure(_ fn: () throws -> ()) rethrows {
try fn()
}

#if $NoncopyableGenerics && $NonescapableTypes
@_marker public protocol Copyable: ~Escapable {}
@_marker public protocol Escapable: ~Copyable {}
Expand Down
18 changes: 15 additions & 3 deletions stdlib/public/core/Sequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -670,9 +670,10 @@ extension Sequence {
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
@inlinable
public func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
@_alwaysEmitIntoClient
public func map<T, E>(
_ transform: (Element) throws(E) -> T
) throws(E) -> [T] {
let initialCapacity = underestimatedCount
var result = ContiguousArray<T>()
result.reserveCapacity(initialCapacity)
Expand All @@ -690,6 +691,17 @@ extension Sequence {
return Array(result)
}

// ABI-only entrypoint for the rethrows version of map, which has been
// superseded by the typed-throws version. Expressed as "throws", which is
// ABI-compatible with "rethrows".
@usableFromInline
@_silgen_name("$sSTsE3mapySayqd__Gqd__7ElementQzKXEKlF")
func __rethrows_map<T>(
_ transform: (Element) throws -> T
) throws -> [T] {
try map(transform)
}

/// Returns an array containing, in order, the elements of the sequence
/// that satisfy the given predicate.
///
Expand Down
7 changes: 4 additions & 3 deletions test/Constraints/closures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1143,11 +1143,11 @@ struct R_76250381<Result, Failure: Error> {

// https://github.com/apple/swift/issues/55926
(0..<10).map { x, y in }
// expected-error@-1 {{contextual closure type '(Range<Int>.Element) throws -> ()' (aka '(Int) throws -> ()') expects 1 argument, but 2 were used in closure body}}
// expected-error@-1 {{contextual closure type '(Range<Int>.Element) -> ()' (aka '(Int) -> ()') expects 1 argument, but 2 were used in closure body}}
(0..<10).map { x, y, z in }
// expected-error@-1 {{contextual closure type '(Range<Int>.Element) throws -> ()' (aka '(Int) throws -> ()') expects 1 argument, but 3 were used in closure body}}
// expected-error@-1 {{contextual closure type '(Range<Int>.Element) -> ()' (aka '(Int) -> ()') expects 1 argument, but 3 were used in closure body}}
(0..<10).map { x, y, z, w in }
// expected-error@-1 {{contextual closure type '(Range<Int>.Element) throws -> ()' (aka '(Int) throws -> ()') expects 1 argument, but 4 were used in closure body}}
// expected-error@-1 {{contextual closure type '(Range<Int>.Element) -> ()' (aka '(Int) -> ()') expects 1 argument, but 4 were used in closure body}}

// rdar://77022842 - crash due to a missing argument to a ternary operator
func rdar77022842(argA: Bool? = nil, argB: Bool? = nil) {
Expand All @@ -1171,6 +1171,7 @@ func rdar76058892() {
test { // expected-error {{contextual closure type '() -> String' expects 0 arguments, but 1 was used in closure body}}
if let arr = arr {
arr.map($0.test) // expected-note {{anonymous closure parameter '$0' is used here}} // expected-error {{generic parameter 'T' could not be inferred}}
// expected-error@-1 {{generic parameter 'E' could not be inferred}}
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions test/Constraints/enum_cases.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ enum G_E<T> {
let arr: [String] = []
let _ = arr.map(E.foo) // Ok
let _ = arr.map(E.bar) // Ok
let _ = arr.map(E.two) // expected-error {{cannot convert value of type '(Int, Int) -> E' to expected argument type '(String) throws -> E'}}
let _ = arr.map(E.two) // expected-error {{cannot convert value of type '(Int, Int) -> E' to expected argument type '(String) -> E'}}

let _ = arr.map(E.tuple) // expected-error {{cannot convert value of type '((x: Int, y: Int)) -> E' to expected argument type '(String) throws -> E'}}
let _ = arr.map(E.tuple) // expected-error {{cannot convert value of type '((x: Int, y: Int)) -> E' to expected argument type '(String) -> E'}}

let _ = arr.map(G_E<String>.foo) // Ok
let _ = arr.map(G_E<String>.bar) // Ok
let _ = arr.map(G_E<String>.two) // expected-error {{cannot convert value of type '(String, String) -> G_E<String>' to expected argument type '(String) throws -> G_E<String>'}}
let _ = arr.map(G_E<Int>.tuple) // expected-error {{cannot convert value of type '((x: Int, y: Int)) -> G_E<Int>' to expected argument type '(String) throws -> G_E<Int>'}}
let _ = arr.map(G_E<String>.two) // expected-error {{cannot convert value of type '(String, String) -> G_E<String>' to expected argument type '(String) -> G_E<String>'}}
let _ = arr.map(G_E<Int>.tuple) // expected-error {{cannot convert value of type '((x: Int, y: Int)) -> G_E<Int>' to expected argument type '(String) -> G_E<Int>'}}

let _ = E.foo("hello") // expected-error {{missing argument label 'bar:' in call}}
let _ = E.bar("hello") // Ok
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/tuple_arguments.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1726,7 +1726,7 @@ do {
do {
func f(_: Int...) {}
let _ = [(1, 2, 3)].map(f) // expected-error {{no exact matches in call to instance method 'map'}}
// expected-note@-1 {{found candidate with type '(((Int, Int, Int)) throws -> _) throws -> Array<_>'}}
// expected-note@-1 {{found candidate with type '(((Int, Int, Int)) -> _) -> Array<_>'}}
}

// rdar://problem/48443263 - cannot convert value of type '() -> Void' to expected argument type '(_) -> Void'
Expand Down
11 changes: 11 additions & 0 deletions test/DebugInfo/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ public class C {
}
}

// Function with typed throws.
// CHECK: !DISubprogram(name: "genericRethrow", {{.*}}thrownTypes: ![[GENERIC_THROWN:.*]])
// CHECK: ![[GENERIC_THROWN]] = !{![[GENERIC_THROWN_INNER:.*]]}
// CHECK: ![[GENERIC_THROWN_INNER]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$sxD", {{.*}}, elements: ![[GENERIC_THROWN_ELEMENTS:.*]], runtimeLang: DW_LANG_Swift)
// CHECK: ![[GENERIC_THROWN_ELEMENTS]] = !{![[GENERIC_THROWN_ELEMENTS_INNER:.*]]}
// CHECK: ![[GENERIC_THROWN_ELEMENTS_INNER]] = !DIDerivedType(tag: DW_TAG_inheritance, {{.*}}baseType: ![[GENERIC_THROWN_BASE:.*]], extraData: {{.*}})
// CHECK: ![[GENERIC_THROWN_BASE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$ss5Error_pmD", size: {{.*}}, flags: DIFlagArtificial, runtimeLang: DW_LANG_Swift, identifier: "$ss5Error_pmD")
public func genericRethrow<E: Error>(fn: () throws(E) -> Void) throws(E) {
try fn()
}

// Negative tests.
// CHECK: !DISubprogram(name: "returnThrowing",
// CHECK-NOT: thrownTypes:
Expand Down
10 changes: 5 additions & 5 deletions test/IDE/complete_from_stdlib.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,30 @@ func protocolExtCollection1a<C : Collection>(_ a: C) {
a.#^PRIVATE_NOMINAL_MEMBERS_2A?check=PRIVATE_NOMINAL_MEMBERS_2A;check=NEGATIVE_PRIVATE_NOMINAL_MEMBERS_2A;check=NO_STDLIB_PRIVATE^#
}

// PRIVATE_NOMINAL_MEMBERS_2A-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(transform): (C.Element) throws -> T##(C.Element) throws -> T#})[' rethrows'][#[T]#];
// PRIVATE_NOMINAL_MEMBERS_2A-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(transform): (C.Element) throws(Error) -> T##(C.Element) throws(Error) -> T#})[' throws'][#[T]#];
// NEGATIVE_PRIVATE_NOMINAL_MEMBERS_2A-NOT: Decl{{.*}}: index({#before: any Comparable#})

func protocolExtCollection1b(_ a: Collection) {
a.#^PRIVATE_NOMINAL_MEMBERS_2B?check=PRIVATE_NOMINAL_MEMBERS_2B;check=NEGATIVE_PRIVATE_NOMINAL_MEMBERS_2B;check=NO_STDLIB_PRIVATE^#
}

// FIXME(https://github.com/apple/swift/issues/65696): We should not be showing this because (1) it cannot be accessed on the existential (2) we don't have the syntax and features to represent the projected type sig anyway.
// PRIVATE_NOMINAL_MEMBERS_2B-DAG: map({#(transform): (any Collection.Element) throws -> T##(any Collection.Element) throws -> T#})[' rethrows'][#[T]#]{{; name=.+}}
// PRIVATE_NOMINAL_MEMBERS_2B-DAG: map({#(transform): (any Collection.Element) throws(Error) -> T##(any Collection.Element) throws(Error) -> T#})[' throws'][#[T]#]{{; name=.+}}
// NEGATIVE_PRIVATE_NOMINAL_MEMBERS_2B-NOT: Decl{{.*}}: index({#before: any Comparable#})

func protocolExtCollection2<C : Collection where C.Index : BidirectionalIndex>(_ a: C) {
a.#^PRIVATE_NOMINAL_MEMBERS_3?check=PRIVATE_NOMINAL_MEMBERS_3;check=NEGATIVE_PRIVATE_NOMINAL_MEMBERS_3;check=NO_STDLIB_PRIVATE^#
}

// PRIVATE_NOMINAL_MEMBERS_3-DAG: Decl[InstanceMethod]/Super/IsSystem: map({#(transform): (C.Element) throws -> T##(C.Element) throws -> T#})[' rethrows'][#[T]#]{{; name=.+}}
// PRIVATE_NOMINAL_MEMBERS_3-DAG: Decl[InstanceMethod]/Super/IsSystem: map({#(transform): (C.Element) throws(Error) -> T##(C.Element) throws(Error) -> T#})[' throws'][#[T]#]{{; name=.+}}
// PRIVATE_NOMINAL_MEMBERS_3-DAG: Decl[InstanceVar]/Super/IsSystem: lazy[#LazySequence<Collection>#]{{; name=.+}}
// PRIVATE_NOMINAL_MEMBERS_3-DAG: firstIndex({#where: (C.Element) throws -> Bool##(C.Element) throws -> Bool#})[' rethrows'][#Comparable?#]{{; name=.+}}
// NEGATIVE_PRIVATE_NOMINAL_MEMBERS_3-NOT: Decl{{.*}}: firstIndex({#({{.*}}): Self.Iterator.Element

func protocolExtArray<T : Equatable>(_ a: [T]) {
a.#^PRIVATE_NOMINAL_MEMBERS_4?check=PRIVATE_NOMINAL_MEMBERS_4;check=NO_STDLIB_PRIVATE^#
}
// PRIVATE_NOMINAL_MEMBERS_4-DAG: Decl[InstanceMethod]/Super/IsSystem: map({#(transform): (Equatable) throws -> T##(Equatable) throws -> T#})[' rethrows'][#[T]#]{{; name=.+}}
// PRIVATE_NOMINAL_MEMBERS_4-DAG: Decl[InstanceMethod]/Super/IsSystem: map({#(transform): (Equatable) throws(Error) -> T##(Equatable) throws(Error) -> T#})[' throws'][#[T]#]{{; name=.+}}
// PRIVATE_NOMINAL_MEMBERS_4-DAG: Decl[InstanceVar]/Super/IsSystem: last[#Equatable?#]{{; name=.+}}
// PRIVATE_NOMINAL_MEMBERS_4-DAG: Decl[InstanceMethod]/Super/IsSystem: firstIndex({#of: Equatable#})[#Int?#]{{; name=.+}}
// PRIVATE_NOMINAL_MEMBERS_4-DAG: Decl[InstanceMethod]/Super/IsSystem: firstIndex({#where: (Equatable) throws -> Bool##(Equatable) throws -> Bool#})[' rethrows'][#Int?#]{{; name=.+}}
Expand Down Expand Up @@ -85,7 +85,7 @@ func testArchetypeReplacement3 (_ a : [Int]) {
// PRIVATE_NOMINAL_MEMBERS_7-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: append({#(newElement): Int#})[#Void#]
// PRIVATE_NOMINAL_MEMBERS_7-DAG: Decl[InstanceMethod]/Super/IsSystem: removeLast()[#Int#]
// PRIVATE_NOMINAL_MEMBERS_7-DAG: Decl[InstanceVar]/Super/IsSystem: first[#Int?#]
// PRIVATE_NOMINAL_MEMBERS_7-DAG: Decl[InstanceMethod]/Super/IsSystem: map({#(transform): (Int) throws -> T##(Int) throws -> T#})[' rethrows'][#[T]#]
// PRIVATE_NOMINAL_MEMBERS_7-DAG: Decl[InstanceMethod]/Super/IsSystem: map({#(transform): (Int) throws(Error) -> T##(Int) throws(Error) -> T#})[' throws'][#[T]#]
// PRIVATE_NOMINAL_MEMBERS_7-DAG: Decl[InstanceMethod]/Super/IsSystem: dropLast({#(k): Int#})[#ArraySlice<Int>#]
// PRIVATE_NOMINAL_MEMBERS_7-DAG: Decl[InstanceMethod]/Super/IsSystem: elementsEqual({#(other): Sequence#}, {#by: (Int, Sequence.Element) throws -> Bool##(Int, Sequence.Element) throws -> Bool#})[' rethrows'][#Bool#]; name=elementsEqual(:by:)
// PRIVATE_NOMINAL_MEMBERS_7-DAG: Decl[InstanceMethod]/Super/IsSystem: elementsEqual({#(other): Sequence#})[#Bool#]; name=elementsEqual(:)
Expand Down
Loading