$30 off During Our Annual Pro Sale. View Details »

Swift Attributes

Swift Attributes

Takuma Shimizu

May 31, 2024
Tweet

More Decks by Takuma Shimizu

Other Decks in Programming

Transcript

  1. w %FDMBSBUJPO"UUSJCVUFTˡࠓճ͸ͪ͜ΒΛѻ͏ w એݴʹద༻Մೳ w Ϋϥεɺߏ଄ମɺྻڍɺϓϩύςΟɺϝιουɺؔ਺ɺม਺ͳͲ w 5ZQF"UUSJCVUFT w ܕʹద༻Մೳ

    w ܕએݴͷ͜ͱͰ͸ͳ͘ɺϝιουͷҾ਺ͳͲͰॻ͘ܕͷ͜ͱ w !FTDBQJOH !4FOEBCMF !VOLOPXͳͲ ଐੑ "UUSJCVUFT 
  2. 01 public struct Inclusion<Value, Member: _Clusivity.Member>: Validator{ 02 public var

    value: Value? 03 04 @usableFromInline 05 var member: Member 06 07 @inlinable 08 public func validate() throws { 09 guard let value else { return } 10 11 let contains = if let collection = presenceValue as? any Collection<Member.Element> { 12 member.contains(collection) 13 } else if let element = presenceValue as? Member.Element { 14 member.contains(element) 15 } else { 16 preconditionFailure() 17 } 18 19 if !contains { 20 throw ValidationError(reasons: .inclusion) 21 } 22 } 23 }
  3. 01 public struct Inclusion<Value, Member: _Clusivity.Member>: Validator{ 02 public var

    value: Value? 03 04 @usableFromInline 05 var member: Member 06 07 @inlinable 08 public func validate() throws { 09 guard let value else { return } 10 11 let contains = if let collection = value as? any Collection<Member.Element> { 12 member.contains(collection) 13 } else if let element = value as? Member.Element { 14 member.contains(element) 15 } else { 16 preconditionFailure() 17 } 18 19 if !contains { 20 throw ValidationError(reasons: .inclusion) 21 } 22 } 23 }
  4. 01 public struct Inclusion<Value, Member: _Clusivity.Member>: Validator{ 02 public var

    value: Value? 03 04 @usableFromInline 05 var member: Member 06 07 @inlinable 08 public func validate() throws { 09 guard let value else { return } 10 11 let contains = if let collection = presenceValue as? any Collection<Member.Element> { 12 member.contains(collection) 13 } else if let element = presenceValue as? Member.Element { 14 member.contains(element) 15 } else { 16 preconditionFailure() 17 } 18 19 if !contains { 20 throw ValidationError(reasons: .inclusion) 21 } 22 } 23 }
  5. 01 public struct Inclusion<Value, Member: _Clusivity.Member>: Validator{ 02 public var

    value: Value? 03 04 // @usableFromInline 05 var member: Member 06 07 @inlinable 08 public func validate() throws { 09 guard let value else { return } 10 11 let contains = if let collection = presenceValue as? any Collection<Member.Element> { 12 // 🚫 Property 'member' is internal and cannot be referenced from an '@inlinable' function 13 member.contains(collection) 14 } else if let element = presenceValue as? Member.Element { 15 // 🚫 Property 'member' is internal and cannot be referenced from an '@inlinable' function 16 member.contains(element) 17 } else { 18 preconditionFailure() 19 } 20 21 if !contains { 22 throw ValidationError(reasons: .inclusion) 23 } 24 } 25 }
  6. extension ValidationErrors: MutableCollection { @inlinable @inline(__always) public var startIndex: Index

    { errors.startIndex } @inlinable @inline(__always) public var endIndex: Index { errors.endIndex } @inlinable @inline(__always) public func index(after i: Index) -> Index { errors.index(after: i) } @inlinable @inline(__always) public subscript(position: Index) -> Element { _read { yield errors[position] } _modify { yield &errors[position] } } }
  7. // Module A public struct A { @usableFromInline let val1

    = 1 @usableFromInline let val2 = 2 @inlinable @inline(__always) public func f1() -> Int { val1 + val2 } @inline(__always) public func f2() -> Int { val1 + val2 } @inlinable public func f3() -> Int { val1 + val2 } } // Module B import ModuleA public func g1() -> Int { A().f1() } public func g2() -> Int { A().f2() } public func g3() -> Int { A().f3() }
  8. public struct A { @usableFromInline @_hasInitialValue internal let val1: Swift.Int

    @usableFromInline @_hasInitialValue internal let val2: Swift.Int @_hasInitialValue internal let val3: Swift.Int @_hasInitialValue internal let val4: Swift.Int public init() @inlinable @inline(__always) public func f1() -> Swift.Int { val1 + val2 } @inline(__always) public func f2() -> Swift.Int @inlinable public func f3() -> Swift.Int { val1 + val2 } } Ϟδϡʔϧ"ͷϑΝΠϧΛTXJGUJOUFSGBDFϑΝΠϧͰग़ྗ
  9. // g1() sil @$s7ModuleB2g1SiyF : $@convention(thin) () -> Int {

    [global: read,write,copy,destroy,allocate,deinit_barrier] bb0: %0 = metatype $@thin A.Type // user: %2 // function_ref A.init() %1 = function_ref @$s7ModuleA1AVACycfC : $@convention(method) (@thin A.Type) -> A // user: %2 %2 = apply %1(%0) : $@convention(method) (@thin A.Type) -> A // users: %4, %3 %3 = struct_extract %2 : $A, #A.val1 // user: %5 %4 = struct_extract %2 : $A, #A.val2 // user: %6 %5 = struct_extract %3 : $Int, #Int._value // user: %8 %6 = struct_extract %4 : $Int, #Int._value // user: %8 %7 = integer_literal $Builtin.Int1, -1 // user: %8 %8 = builtin "sadd_with_overflow_Int64"(%5 : $Builtin.Int64, %6 : $Builtin.Int64, %7 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) // users: %10, %9 %9 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 0 // user: %12 %10 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 1 // user: %11 cond_fail %10 : $Builtin.Int1, "arithmetic overflow" // id: %11 %12 = struct $Int (%9 : $Builtin.Int64) // user: %13 return %12 : $Int // id: %13 } // end sil function '$s7ModuleB2g1SiyF' H ΋ಉ༷ͷग़ྗ݁ՌͰ ΠϯϥΠϯԽ͞Ε͍ͯΔ͜ͱ͕֬ೝͰ͖Δ Ϟδϡʔϧ#ͷϑΝΠϧΛ4*-Ͱग़ྗ
  10. // g2() sil @$s7ModuleB2g2SiyF : $@convention(thin) () -> Int {

    [global: read,write,copy,destroy,allocate,deinit_barrier] bb0: %0 = metatype $@thin A.Type // user: %2 // function_ref A.init() %1 = function_ref @$s7ModuleA1AVACycfC : $@convention(method) (@thin A.Type) -> A // user: %2 %2 = apply %1(%0) : $@convention(method) (@thin A.Type) -> A // user: %4 // function_ref A.f2() %3 = function_ref @$s7ModuleA1AV2f2SiyF : $@convention(method) (A) -> Int // user: %4 %4 = apply %3(%2) : $@convention(method) (A) -> Int // user: %5 return %4 : $Int // id: %5 } // end sil function '$s7ModuleB2g2SiyF' H ͸ΠϯϥΠϯԽ͞Ε͍ͯͳ͍ Ϟδϡʔϧ#ͷϑΝΠϧΛ4*-Ͱग़ྗ
  11. public struct A { @usableFromInline let val1 = 1 @usableFromInline

    let val2 = 2 @inline(__always) public func f2() -> Int { val1 + val2 } func g() -> Int { f2() } }
  12. // A.g() sil hidden @$s7ModuleA1AV1gSiyF : $@convention(method) (A) -> Int

    { [global: ] // %0 "self" // users: %4, %3, %2, %1 bb0(%0 : $A): debug_value %0 : $A, let, name "self", argno 1, implicit // id: %1 debug_value %0 : $A, let, name "self", argno 1, implicit // id: %2 %3 = struct_extract %0 : $A, #A.val1 // user: %5 %4 = struct_extract %0 : $A, #A.val2 // user: %6 %5 = struct_extract %3 : $Int, #Int._value // user: %8 %6 = struct_extract %4 : $Int, #Int._value // user: %8 %7 = integer_literal $Builtin.Int1, -1 // user: %8 %8 = builtin "sadd_with_overflow_Int64"(%5 : $Builtin.Int64, %6 : $Builtin.Int64, %7 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) // users: %10, %9 %9 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 0 // user: %12 %10 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 1 // user: %11 cond_fail %10 : $Builtin.Int1, "arithmetic overflow" // id: %11 %12 = struct $Int (%9 : $Builtin.Int64) // user: %13 return %12 : $Int // id: %13 } // end sil function '$s7ModuleA1AV1gSiyF' Ϟδϡʔϧ"ͷϑΝΠϧΛ4*-Ͱग़ྗ ( ͕ΠϯϥΠϯԽ͞Ε͍ͯΔ͜ͱ͕֬ೝͰ͖Δ
  13. public protocol Validator { associatedtype Validation func validate() throws @ValidatorBuilder

    var validation: Validation { get } } extension Validator where Validation == Never { @_transparent public var validation: Validation { fatalError() } } @_transparent͋Γ @_transparentͳ͠ ϩάग़ྗ͸ͲͪΒ΋ಉ͡↓ Validations/Validator.swift:47: Fatal error
  14. public struct Inclusion: Validator, Sendable { @_disfavoredOverload public init<E: Equatable,

    S: Sequence<E>>( _ value: S.Element, in elements: S ) { ... } public init<E: Comparable, S: Sequence<E>, R: RangeExpression<E>>( _ value: S, in range: R ) { ... } } // Without @_disfavoredOverload. Inclusion(1, in: [1, 2]) // ✅ Use 'init(Array<Int>.Element, in: Array<Int>)' Inclusion(5, in: 4...) // 🚫 Ambiguous use of 'init(_:in:)' // With @_disfavoredOverload. Inclusion(1, in: [1, 2]) // ✅ Use 'init(Array<Int>.Element, in: Array<Int>)' Inclusion(5, in: 4...) // ✅ Use 'init(Int, in: PartialRangeFrom<Int>)'