Slide 1

Slide 1 text

SwiftͷΦʔόʔϩʔυબ୒ͷ είΞنଇ12छྨ @omochimetaru Θ͍Θ͍swiftc #16 1

Slide 2

Slide 2 text

Φʔόʔϩʔυͱܕਪ࿦ • Swiftʹ͸Φʔόʔϩʔυ͕͋ΔͷͰɺίϯύΠ ϥ͸ɺ͋Δؔ਺ݺͼग़͕͠Ͳͷؔ਺ఆٛʹରԠ ͢Δ͔ਪ࿦͢Δɻ 2

Slide 3

Slide 3 text

• Ͳͷؔ਺ΛબͿ͔͸ܕਪ࿦ͱ૬ޓʹؔ܎͢Δͨ ΊɺΦʔόʔϩʔυબ୒͸ܕਪ࿦ػߏʹ౷߹͞ Ε͍ͯΔɻ func f(_ a: Int) -> Int { return a } func f(_ a: Float) -> Float { return a } func main() { let a = f(Int(0)) let b: Float = f(0) } 3

Slide 4

Slide 4 text

• ܕਪ࿦ث͸ɺΦʔόʔϩʔυͳͲ͕བྷΜͩ৔߹ ʹɺෳ਺ͷ༗ޮͳղΛൃݟ͢Δ͜ͱ͕͋Δɻ func f(_ a: Int) -> Int { return a } func f(_ a: Int?) -> Int? { return a } func main() { let a = f(Int(0)) } 4

Slide 5

Slide 5 text

• ෳ਺ͷ༗ޮͳղ͕͋Δ৔߹ɺ༏ઌ౓نଇʹΑΓ ࠷༏ઌղΛܾఆ͢Δɻ • ͦͷ༏ઌ౓نଇʹ͓͍ͯɺ࠷ॳʹద༻͞ΕΔ࠷ ΋جຊͱͳΔنଇͱͯ͠ɺείΞنଇ͕͋Δɻ 5

Slide 6

Slide 6 text

είΞنଇ • 1ͭͷਪ࿦ղʹରͯ͠είΞΛܭࢉ͢Δɻ • είΞ͸12ݸͷ੔਺ͷ૊ɻ • ΑΓࠨͷܻ΄Ͳࢧ഑తɻ • ஋͕௿͍΄Ͳղͱͯ͠ͷ༏ઌ౓͕ߴ͍ɻϖφϧ ςΟ΍ίετͱଊ͑ΒΕΔɻ 6

Slide 7

Slide 7 text

func f(_ a: Int?) { print("Optional") } func f(_ a: Any) { print("Any") } f(3) // => Any 7

Slide 8

Slide 8 text

$ swiftc -dump-ast -Xfrontend -debug-constraints c1.swift --- Solution #0 --- Fixed score: 0 0 0 0 0 0 0 0 1 0 0 0 Type variables: $T2 as () @ locator@0x7f9ce18abc58 [[email protected]:5:1 -> function result] $T1 as Int @ locator@0x7f9ce18abb98 [[email protected]:5:3] $T0 as (Int?) -> () @ locator@0x7f9ce18aba00 [[email protected]:5:1] --- Solution #1 --- Fixed score: 0 0 0 0 0 0 0 0 0 1 0 0 Type variables: $T2 as () @ locator@0x7f9ce18abc58 [[email protected]:5:1 -> function result] $T1 as Int @ locator@0x7f9ce18abb98 [[email protected]:5:3] $T0 as (Any) -> () @ locator@0x7f9ce18aba00 [[email protected]:5:1] 8

Slide 9

Slide 9 text

12छྨͷείΞ஋ • 12ܻͷ஋ͦΕͧΕ͸ɺਪ࿦ղʹؚ·ΕΔ҉໧ ม׵ͷճ਺ͳͲʹରԠ͍ͯ͠Δɻ • Ҏ߱Ͱ͸ɺ12छྨ͢΂ͯͷఆٛΛݟ͍ͯ͘ɻ 9

Slide 10

Slide 10 text

ϔομʔఆٛ1 /// Describes an aspect of a solution that affects its overall score, i.e., a /// user-defined conversions. enum ScoreKind { // These values are used as indices into a Score value. /// A fix needs to be applied to the source. SK_Fix, /// A reference to an @unavailable declaration. SK_Unavailable, /// A use of a disfavored overload. SK_DisfavoredOverload, /// An implicit force of an implicitly unwrapped optional value. SK_ForceUnchecked, /// A user-defined conversion. SK_UserConversion, /// A non-trivial function conversion. SK_FunctionConversion, /// A literal expression bound to a non-default literal type. SK_NonDefaultLiteral, /// An implicit upcast conversion between collection types. SK_CollectionUpcastConversion, /// A value-to-optional conversion. SK_ValueToOptional, /// A conversion to an empty existential type ('Any' or '{}'). SK_EmptyExistentialConversion, /// A key path application subscript. SK_KeyPathSubscript, /// A conversion from a string, array, or inout to a pointer. SK_ValueToPointerConversion, SK_LastScoreKind = SK_ValueToPointerConversion, }; 1 lib/Sema/ConstraintSystem.h 10

Slide 11

Slide 11 text

• SK_Fix͕࠷΋ߴίετɺ SK_ValueToPointerConversion͕࠷΋௿ίε τɻ • ҎԼศ্ٓɺ࠷΋௿ίετͳ SK_ValueToPointerConversionΛϥϯΫ1ͱ ͢Δɻ 11

Slide 12

Slide 12 text

ϥϯΫ1 SK_ValueToPointerConversion • String, Array, inout͔ΒϙΠϯλ΁ͷ҉໧ม׵ ίετ func f(_ a: UnsafePointer) { print("Pointer") } func f(_ a: [Int]) { print("Array") } let a: [Int] = [1, 2, 3] f(a) // => Array 12

Slide 13

Slide 13 text

(attempting disjunction choice $T0 bound to decl c2.(file)[email protected]:1:6 : (UnsafePointer) -> () at c2.swift:1:6 [[locator@0x7f9daa815400 [[email protected]:7:1]]]; (overload set choice binding $T0 := (UnsafePointer) -> ()) (increasing score due to value-to-pointer conversion) (found solution 0 0 0 0 0 0 0 0 0 0 0 1) ) 13

Slide 14

Slide 14 text

ϥϯΫ2 SK_KeyPathSubscript • [keyPath: keyPath] ͷݺͼग़͠ struct Cat { var name: String = "tama" } var a = Cat() let name = a[keyPath: \.name] print(name) // => tama ($T1 bindings={(supertypes of) Cat}) Initial bindings: $T1 := Cat (attempting type variable $T1 := Cat (overload set choice binding $T2 := @lvalue String) ($T7 bindings={(supertypes of) WritableKeyPath}) Initial bindings: $T7 := WritableKeyPath (attempting type variable $T7 := WritableKeyPath (found solution 0 0 0 0 0 0 0 0 0 0 1 0) ) ) 14

Slide 15

Slide 15 text

struct Cat { var name: String = "tama" subscript(keyPath keyPath: KeyPath) -> String { return "mike" } } var a = Cat() let name = a[keyPath: \.name] print(name) // => mike 15

Slide 16

Slide 16 text

ϥϯΫ3 SK_EmptyExistentialConversion • Any΁ͷม׵ func f(_ a: Any) { print("Any") } func f(_ a: UnsafePointer) { print("Pointer") } let a: [Int] = [1, 2, 3] f(a) // => Pointer 16

Slide 17

Slide 17 text

ϥϯΫ4 SK_ValueToOptional • Optional΁ͷม׵ func f(_ a: Int?) { print("Optional") } func f(_ a: Any) { print("Any") } let a: Int = 1 f(a) // => Any 17

Slide 18

Slide 18 text

ϥϯΫ5 SK_CollectionUpcastConversion • Array, Dictionary, Setͷ҉໧ΞοϓΩϟετ class Animal {} class Cat: Animal {} func f(_ a: [Animal]) { print("[Animal]") } func f(_ a: [Cat]) { print("[Cat]") } let a: [Cat] = [Cat()] f(a) // => [Cat] 18

Slide 19

Slide 19 text

(attempting disjunction choice $T0 bound to decl rank5.(file)[email protected]:4:6 : ([Animal]) -> () at rank5.swift:4:6 [[locator@0x7fbeeb0aa000 [[email protected]:10:1]]]; (overload set choice binding $T0 := ([Animal]) -> ()) (attempting disjunction choice [Cat] bind [Animal] [deep equality] [[locator@0x7fbeeb0aa3c8 [[email protected]:10:1 -> apply argument -> comparing call argument #0 to parameter #0]]]; ) (attempting disjunction choice [Cat] arg conv [Animal] [array-upcast] [[locator@0x7fbeeb0aa3c8 [[email protected]:10:1 -> apply argument -> comparing call argument #0 to parameter #0]]]; (increasing score due to collection upcast conversion) (found solution 0 0 0 0 0 0 0 1 0 0 0 0) ) ) 19

Slide 20

Slide 20 text

• ෳ߹ class Animal {} class Cat: Animal {} func f(_ a: [Cat?]) { print("[Cat?]") } func f(_ a: [Any]) { print("[Any]") } func f(_ a: [Animal]) { print("[Animal]") } let a: [Cat] = [Cat()] f(a) // => [Animal] 20

Slide 21

Slide 21 text

(attempting disjunction choice $T0 bound to decl rank5.(file)[email protected]:4:6 : ([Cat?]) -> () at rank5.swift:4:6 [[locator@0x7fed5c001c00 [[email protected]:12:1]]]; (overload set choice binding $T0 := ([Cat?]) -> ()) (attempting disjunction choice [Cat] bind [Cat?] [deep equality] [[locator@0x7fed5c002040 [[email protected]:12:1 -> apply argument -> comparing call argument #0 to parameter #0]]]; ) (attempting disjunction choice [Cat] arg conv [Cat?] [array-upcast] [[locator@0x7fed5c002040 [[email protected]:12:1 -> apply argument -> comparing call argument #0 to parameter #0]]]; (increasing score due to collection upcast conversion) (increasing score due to value to optional) (found solution 0 0 0 0 0 0 0 1 1 0 0 0) ) ) (attempting disjunction choice $T0 bound to decl rank5.(file)[email protected]:6:6 : ([Any]) -> () at rank5.swift:6:6 [[locator@0x7fed5c001c00 [[email protected]:12:1]]]; (overload set choice binding $T0 := ([Any]) -> ()) (attempting disjunction choice [Cat] bind [Any] [deep equality] [[locator@0x7fed5c002040 [[email protected]:12:1 -> apply argument -> comparing call argument #0 to parameter #0]]]; ) (attempting disjunction choice [Cat] arg conv [Any] [array-upcast] [[locator@0x7fed5c002040 [[email protected]:12:1 -> apply argument -> comparing call argument #0 to parameter #0]]]; (increasing score due to collection upcast conversion) (increasing score due to empty-existential conversion) (found solution 0 0 0 0 0 0 0 1 0 1 0 0) ) ) (attempting disjunction choice $T0 bound to decl rank5.(file)[email protected]:8:6 : ([Animal]) -> () at rank5.swift:8:6 [[locator@0x7fed5c001c00 [[email protected]:12:1]]]; (overload set choice binding $T0 := ([Animal]) -> ()) (attempting disjunction choice [Cat] bind [Animal] [deep equality] [[locator@0x7fed5c002040 [[email protected]:12:1 -> apply argument -> comparing call argument #0 to parameter #0]]]; ) (attempting disjunction choice [Cat] arg conv [Animal] [array-upcast] [[locator@0x7fed5c002040 [[email protected]:12:1 -> apply argument -> comparing call argument #0 to parameter #0]]]; (increasing score due to collection upcast conversion) (found solution 0 0 0 0 0 0 0 1 0 0 0 0) ) ) 21

Slide 22

Slide 22 text

ϥϯΫ6 SK_NonDefaultLiteral • Ϧςϥϧ͕ඇσϑΥϧτܕʹͳΔ func f(_ a: Float) { print("Float") } func f(_ a: Int?) { print("Int?") } f(0) // => Int? 22

Slide 23

Slide 23 text

ϥϯΫ7 SK_FunctionConversion • ؔ਺ܕͷ҉໧ม׵ class Animal {} class Cat: Animal {} // 0 0 0 0 0 1 0 0 1 0 0 0 func f(_ g: () -> Cat?) { print("() -> Cat?") } // 0 0 0 0 0 1 0 0 0 0 0 0 func f(_ g: () -> Animal) { print("() -> Animal") } // 0 0 0 0 0 0 0 0 1 0 0 0 func f(_ g: (() -> Cat)?) { print("(() -> Cat)?") } func g() -> Cat { Cat() } f(g) // => (() -> Cat)? 23

Slide 24

Slide 24 text

ϥϯΫ8 SK_UserConversion • Objective-Cαϙʔτ࣌ʹɺϝλλΠϓ͔Β AnyObjectͳͲ΁ͷม׵ class Cat {} func f(_ a: AnyObject) { print("AnyObject") } func f(_ a: Cat.Type) { print("Cat.Type") } f(Cat.self) // => Cat.Type 24

Slide 25

Slide 25 text

• ιʔε2 if (getASTContext().LangOpts.EnableObjCInterop) { // These conversions are between concrete types that don't need further // resolution, so we can consider them immediately solved. auto addSolvedRestrictedConstraint = [&](ConversionRestrictionKind restriction) -> TypeMatchResult { addRestrictedConstraint(ConstraintKind::Subtype, restriction, type1, type2, locator); return getTypeMatchSuccess(); }; if (auto meta1 = type1->getAs()) { if (meta1->getInstanceType()->mayHaveSuperclass() && type2->isAnyObject()) { increaseScore(ScoreKind::SK_UserConversion); return addSolvedRestrictedConstraint( ConversionRestrictionKind::ClassMetatypeToAnyObject); } // Single @objc protocol value metatypes can be converted to the ObjC // Protocol class type. auto isProtocolClassType = [&](Type t) -> bool { if (auto classDecl = t->getClassOrBoundGenericClass()) if (classDecl->getName() == getASTContext().Id_Protocol && classDecl->getModuleContext()->getName() == getASTContext().Id_ObjectiveC) return true; return false; }; if (auto protoTy = meta1->getInstanceType()->getAs()) { if (protoTy->getDecl()->isObjC() && isProtocolClassType(type2)) { increaseScore(ScoreKind::SK_UserConversion); return addSolvedRestrictedConstraint( ConversionRestrictionKind::ProtocolMetatypeToProtocolClass); } } } if (auto meta1 = type1->getAs()) { // Class-constrained existential metatypes can be converted to AnyObject. if (meta1->getInstanceType()->isClassExistentialType() && type2->isAnyObject()) { increaseScore(ScoreKind::SK_UserConversion); return addSolvedRestrictedConstraint( ConversionRestrictionKind::ExistentialMetatypeToAnyObject); } } } 2 lib/Sema/CSSimplify.cpp 25

Slide 26

Slide 26 text

User Conversion ޙड़ 26

Slide 27

Slide 27 text

ϥϯΫ9 SK_ForceUnchecked • IUO(T!)ͷ҉໧unwrap // 0 0 0 1 0 0 0 0 0 0 0 0 func f(_ a: Int) { print("Int") } func f(_ a: Int?) { print("Int?") } var a: Int! = 1 f(a) 27

Slide 28

Slide 28 text

ϥϯΫ10 SK_DisfavoredOverload • @_disfavoredOverload͕෇͍ͯΔͱίετ͕ ੜ͡Δ @_disfavoredOverload func f(_ a: Int) { print("Int") } func f(_ a: Int?) { print("Int?") } let a: Int = 1 f(a) // => Int? 28

Slide 29

Slide 29 text

• ࠓ೥ͷ5݄ʹ࣮૷ 3 • SwiftUIͰ࢖ΘΕͯΔ ! // /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform \ // /Developer/SDKs/iPhoneOS13.2.sdk/System/Library/Frameworks \ // /SwiftUI.framework/Modules/SwiftUI.swiftmodule/arm64.swiftinterface @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) extension Button where Label == SwiftUI.Text { public init(_ titleKey: SwiftUI.LocalizedStringKey, action: @escaping () -> Swift.Void) @_disfavoredOverload public init(_ title: S, action: @escaping () -> Swift.Void) where S : Swift.StringProtocol } 3 https://github.com/apple/swift/pull/24799 29

Slide 30

Slide 30 text

ϥϯΫ11 SK_Unavailable • @availableͰແޮʹͳ͍ͬͯΔͱ෇͘ɻ • ࠷ऴతʹΤϥʔʹͳΔɻ // 0 1 0 0 0 0 0 0 0 0 0 0 @available(*, unavailable) func f(_ a: Int) { print("Int") } let a: Int = 1 f(a) /* rank11.swift:6:1: error: 'f' is unavailable f(a) ^ rank11.swift:3:6: note: 'f' has been explicitly marked unavailable here func f(_ a: Int) { print("Int") } ^ */ 30

Slide 31

Slide 31 text

ϥϯΫ12 SK_Fix • ʮ΋͔ͯ͠͠ʯػೳͷͨΊʹੜ੒͞ΕͨԾઆʹ ෇༩͞ΕΔɻ func f(a: Int) { print("Int") } let a: Int = 1 f(b: a) /* rank12.swift:4:2: error: incorrect argument label in call (have 'b:', expected 'a:') f(b: a) ^~ a */ 31

Slide 32

Slide 32 text

---Constraint solving for the expression at [rank12.swift:4:1 - line:4:7]--- (overload set choice binding $T0 := (Int) -> ()) (overload set choice binding $T1 := Int) (attempting fix [fix: re-label argument(s)] @ locator@0x7fdfbb0e55b0 [[email protected]:4:1]) (increasing score due to attempting to fix the source) Score: 1 0 0 0 0 0 0 0 0 0 0 0 Type Variables: $T0 [lvalue allowed] as (Int) -> () @ locator@0x7fdfbb0e5400 [[email protected]:4:1] $T1 [lvalue allowed] as Int @ locator@0x7fdfbb0e5488 [[email protected]:4:6] $T2 as () @ locator@0x7fdfbb0e5510 [[email protected]:4:1 -> function result] Active Constraints: Inactive Constraints: Resolved overloads: selected overload set choice a: $T1 == Int selected overload set choice f: $T0 == (Int) -> () Fixes: [fix: re-label argument(s)] @ locator@0x7fdfbb0e55b0 [[email protected]:4:1] (found solution 1 0 0 0 0 0 0 0 0 0 0 0) 32

Slide 33

Slide 33 text

• ͜ͷFixػߏͷղઆ͕10݄ʹެࣜϒϩάͰެ։ ͞Εͨ4 4 New Diagnostic Architecture Overview 33

Slide 34

Slide 34 text

User Conversion 34

Slide 35

Slide 35 text

TypeChecker.rst5 • Swiftͷਪ࿦ثʹ͍ͭͯॻ͔Εͨจॻ 5 docs/TypeChecker.rst 35

Slide 36

Slide 36 text

• ͦ͜ʹग़ͯ͘ΔṖίʔυ struct X { // user-defined conversions func [conversion] __conversion () -> String { /* ... */ } func [conversion] __conversion () -> Int { /* ... */ } } func f(_ i : Int, s : String) { } var x : X f(10.5, x) 36

Slide 37

Slide 37 text

GitͰྺ࢙ௐࠪ 37

Slide 38

Slide 38 text

• User Conversionͷ࣮૷6 Implement simplification of conversion constraints for user-defined conversions. Swift SVN r2730 DougGregor committed on 24 Aug 2012 6 fa474ee750edb7a3d34a767e02426f4509041698 38

Slide 39

Slide 39 text

• WWDCͰSwiftൃද 2014/6/2 39

Slide 40

Slide 40 text

• User Conversionͷېࢭ7 Ban __conversion functions. Swift SVN r21015 DougGregor committed on 5 Aug 2014 7 9d5ba31daa8f63a333e9fb993e5204923a46f98c 40

Slide 41

Slide 41 text

• User Conversionͷ࡟আ8 Remove user-defined conversions from the type checker. Swift SVN r21379 DougGregor committed on 22 Aug 2014 8 397f4a98880f82e439b1c4164885abb21cd56d09 41

Slide 42

Slide 42 text

• Swift1.0͕Xcode6ͱڞʹ഑෍ 2014/9/9 42

Slide 43

Slide 43 text

• SK_UserConversionΛݱࡏͷ༻్Ͱ࢖༻9 Type checker: Increase the score of metatype-to-object conversions. Swift SVN r27415 jckarter committed on 17 Apr 2015 9 be7c339af86142217686f10e039349924226e9ea 43

Slide 44

Slide 44 text

• Swift2.0͕Xcode7ͱڞʹ഑෍ 2015/9/21 44