// RUN: %target-swift-frontend -emit-sil -verify %s // Test differentiation transform diagnostics. import _Differentiation //===----------------------------------------------------------------------===// // Basic function //===----------------------------------------------------------------------===// @differentiable(reverse) func basic(_ x: Float) -> Float { return x } //===----------------------------------------------------------------------===// // Control flow //===----------------------------------------------------------------------===// @differentiable(reverse) func conditional(_ x: Float, _ flag: Bool) -> Float { let y: Float if flag { y = x } else { y = x } return y } // TF-433: Test `try_apply` differentiation. func throwing() throws -> Void {} @differentiable(reverse) func try_apply(_ x: Float) -> Float { try! throwing() return x } func rethrowing(_ x: () throws -> Void) rethrows -> Void {} @differentiable(reverse) func try_apply_rethrows(_ x: Float) -> Float { rethrowing({}) return x } // This generates `try_apply` which we do not know to handle yet, therefore // one should use a.differentialMap here. If / when differentiation of throwing // functions will be supported, we'd need to remove this diagnostics. // expected-error @+2 {{function is not differentiable}} // expected-note @+2 {{when differentiating this function definition}} @differentiable(reverse) func map_nondiff(_ a: [Float]) -> [Float] { // expected-note @+1 {{expression is not differentiable}} return a.map { $0 } } //===----------------------------------------------------------------------===// // Unreachable //===----------------------------------------------------------------------===// // expected-error @+2 {{function is not differentiable}} // expected-note @+2 {{when differentiating this function definition}} @differentiable(reverse) func noReturn(_ x: Float) -> Float { let _ = x // expected-error @+2 {{missing return in global function expected to return 'Float'}} // expected-note @+1 {{missing return for differentiation}} } //===----------------------------------------------------------------------===// // Global variables //===----------------------------------------------------------------------===// var global: Float = 3.0 // expected-error @+2 {{function is not differentiable}} // expected-note @+2 {{when differentiating this function definition}} @differentiable(reverse, wrt: x) func testWriteToGlobalVariable(x: Float) -> Float { // expected-note @+1 {{cannot differentiate writes to global variables}} global = global + x return global } //===----------------------------------------------------------------------===// // Class differentiation //===----------------------------------------------------------------------===// class Class : Differentiable { @differentiable(reverse) var stored: Float = 1 @differentiable(reverse) func testRefElementAddr(_ x: Float) -> Float { return stored * x } var nonDifferentiableStored: Float = 1 @differentiable(reverse) func testNonDifferentiableRefElementAddr(_ x: Float) -> Float { // expected-error @+2 {{expression is not differentiable}} // expected-note @+1 {{member is not differentiable because the corresponding class member is not '@differentiable'}} return nonDifferentiableStored * x } @differentiable(reverse) func method(_ x: Float) -> Float { x } @differentiable(reverse) static func testClassMethod(x: Float) -> Float { return Class().method(x) } func nonDifferentiableMethod(_ x: Float) -> Float { x } @differentiable(reverse) static func testDifferentiableClassMethod(x: Float) -> Float { // expected-error @+2 {{expression is not differentiable}} // expected-note @+1 {{member is not differentiable because the corresponding class member is not '@differentiable'}} return Class().nonDifferentiableMethod(x) } } // TF-676: Test differentiation of class method with multiple `@differentiable` // attributes. class ClassMethodMultipleDifferentiableAttribute : Differentiable { @differentiable(reverse, wrt: (self, x)) @differentiable(reverse, wrt: x) func f(_ x: Float) -> Float { x } } func testMultipleDiffAttrsClass( _ c: C, _ x: Float ) { _ = gradient(at: c, x) { c, x in c.f(x) } _ = gradient(at: x) { x in c.f(x) } } // TF-1149: Test class with loadable type but address-only `TangentVector` type. class C: Differentiable { @differentiable(reverse) var stored: T init(_ stored: T) { self.stored = stored } @differentiable(reverse) func method(_ x: T) -> T { stored } } //===----------------------------------------------------------------------===// // Enum differentiation //===----------------------------------------------------------------------===// @differentiable(reverse) func usesOptionals(_ x: Float) -> Float { var maybe: Float? = 10 maybe = x return maybe! } enum DirectEnum: Differentiable & AdditiveArithmetic { case leaf(Float) typealias TangentVector = Self static var zero: Self { fatalError() } static func +(_ lhs: Self, _ rhs: Self) -> Self { fatalError() } static func -(_ lhs: Self, _ rhs: Self) -> Self { fatalError() } } // expected-error @+1 {{function is not differentiable}} @differentiable(reverse, wrt: e) // expected-note @+2 {{when differentiating this function definition}} // expected-note @+1 {{differentiating enum values is not yet supported}} func enum_active(_ e: DirectEnum, _ x: Float) -> Float { switch e { case let .leaf(y): return y } } // expected-error @+1 {{function is not differentiable}} @differentiable(reverse, wrt: e) // expected-note @+2 {{when differentiating this function definition}} // expected-note @+1 {{differentiating enum values is not yet supported}} func activeEnumValue(_ e: DirectEnum, _ x: Float) -> Float { switch e { case let .leaf(y): return y } } enum IndirectEnum: Differentiable & AdditiveArithmetic { case leaf(T) typealias TangentVector = Self static func ==(_ lhs: Self, _ rhs: Self) -> Bool { fatalError() } static var zero: Self { fatalError() } static func +(_ lhs: Self, _ rhs: Self) -> Self { fatalError() } static func -(_ lhs: Self, _ rhs: Self) -> Self { fatalError() } } // expected-error @+1 {{function is not differentiable}} @differentiable(reverse, wrt: e) // expected-note @+2 {{when differentiating this function definition}} // expected-note @+1 {{differentiating enum values is not yet supported}} func activeEnumAddr(_ e: IndirectEnum, _ x: Float) -> Float { switch e { case let .leaf(y): return y } } //===----------------------------------------------------------------------===// // Unmet derivative generic requirements //===----------------------------------------------------------------------===// @differentiable(reverse) func generic(_ x: T) -> T { // expected-error @+2 {{expression is not differentiable}} // expected-note @+1 {{member is not differentiable because the corresponding protocol requirement is not '@differentiable'}} return x + 1 } // Test unmet generic requirements. func weird(_ x: T) -> T { return x } @derivative(of: weird) func vjpWeirdExtraRequirements(_ x: T) -> ( value: T, pullback: (T.TangentVector) -> T.TangentVector ) where T.AllCases : ExpressibleByStringLiteral { return (x, { $0 }) } @differentiable(reverse) func weirdWrapper(_ x: T) -> T { // expected-error @+2 {{expression is not differentiable}} // expected-note @+1 {{function call is not differentiable because generic requirements are not met: 'T : CaseIterable, T.AllCases : ExpressibleByStringLiteral'}} return weird(x) } @differentiable(reverse) func direct(_ x: T) -> T { return x } struct Tensor { static func + (_ lhs: Tensor, rhs: Scalar) -> Tensor { return lhs } } extension Tensor : Differentiable where Scalar : Differentiable & FloatingPoint {} extension Tensor where Scalar : BinaryFloatingPoint { @differentiable(reverse, wrt: self where Scalar : Differentiable) func TF_6(_ x: Float) -> Tensor { return self + Scalar(x) } } protocol TF8_Proto : Differentiable { associatedtype Scalar @differentiable(reverse, wrt: (self, input)) func applied(to input: Float) -> Float } struct TF8_Struct : TF8_Proto where Scalar : FloatingPoint & Differentiable { @noDerivative let bar: Scalar @differentiable(reverse, wrt: (self, input)) func applied(to input: Float) -> Float { return input } } //===----------------------------------------------------------------------===// // `Differentiable` conformance requirement inference //===----------------------------------------------------------------------===// func id(_ x: T) -> T { x } let _: @differentiable(reverse) (Float) -> Float = { x in id(x) } struct TF_691 { var x: Scalar init(_ x: Scalar) { self.x = x } } extension TF_691: Differentiable where Scalar: Differentiable {} func identity(_ x: TF_691) -> TF_691 { x } let _: @differentiable(reverse) (Float) -> TF_691 = { x in identity(TF_691(x)) } let _: @differentiable(reverse) (Float) -> TF_691 = { x in id(TF_691(x)) } //===----------------------------------------------------------------------===// // Non-differentiable arguments and results //===----------------------------------------------------------------------===// struct TF_687 : Differentiable { @noDerivative var indirectDummy: T var base: Float init(_ base: Float, dummy: T) { self.base = base self.indirectDummy = dummy } } // expected-error @+2 {{function is not differentiable}} // expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{87-87=withoutDerivative(at: }} {{88-88=)}} let _: @differentiable(reverse) (Float) -> TF_687 = { x in TF_687(x, dummy: x) } // expected-error @+1 {{function is not differentiable}} @differentiable(reverse) // expected-note @+1 {{when differentiating this function definition}} func roundingGivesError(x: Float) -> Float { // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{16-16=withoutDerivative(at: }} {{22-22=)}} return Float(Int(x)) } //===----------------------------------------------------------------------===// // Non-varied results //===----------------------------------------------------------------------===// @differentiable(reverse) func nonVariedResult(_ x: Float) -> Float { // TODO(TF-788): Re-enable non-varied result warning. // xpected-warning @+1 {{result does not depend on differentiation arguments and will always have a zero derivative; do you want to use 'withoutDerivative(at:)'?}} {{10-10=withoutDerivative(at:}} {{15-15=)}} return 0 } // Check that `withoutDerivative(at:)` silences the non-varied result warning. struct TF_775: Differentiable { @differentiable(reverse, wrt: (self)) func nonVariedResult(_ input: Float) -> Float { return withoutDerivative(at: input) } } //===----------------------------------------------------------------------===// // Multiple results //===----------------------------------------------------------------------===// func multipleResults(_ x: Float) -> (Float, Float) { return (x, x) } @differentiable(reverse) func usesMultipleResults(_ x: Float) -> Float { let tuple = multipleResults(x) return tuple.0 + tuple.1 } //===----------------------------------------------------------------------===// // `inout` parameter differentiation //===----------------------------------------------------------------------===// @differentiable(reverse) func activeInoutParam(_ x: Float) -> Float { var result = x result += x return result } @differentiable(reverse) func activeInoutParamNonactiveInitialResult(_ x: Float) -> Float { var result: Float = 1 result += x return result } @differentiable(reverse) func activeInoutParamTuple(_ x: Float) -> Float { var tuple = (x, x) tuple.0 *= x return x * tuple.0 } @differentiable(reverse) func activeInoutParamControlFlow(_ array: [Float]) -> Float { var result: Float = 1 for i in withoutDerivative(at: array).indices { result += array[i] } return result } @differentiable(reverse) func activeInoutParamControlFlowComplex(_ array: [Float], _ bool: Bool) -> Float { var result: Float = 1 if bool { if bool {} for i in withoutDerivative(at: array).indices { switch i % 2 { case 0: continue case 1: break default: break } result = result + 1 result += array[i] } } return result } struct Mut: Differentiable {} extension Mut { @differentiable(reverse, wrt: (self, x)) mutating func mutatingMethod(_ x: Mut) {} } @differentiable(reverse, wrt: (nonactive, x)) func nonActiveInoutParam(_ nonactive: inout Mut, _ x: Mut) { nonactive.mutatingMethod(x) } @differentiable(reverse, wrt: x) func activeInoutParamMutatingMethod(_ x: Mut) -> Mut { var result = x result.mutatingMethod(result) return result } @differentiable(reverse, wrt: (nonactive, x)) func activeInoutParamMutatingMethodVar(_ nonactive: inout Mut, _ x: Mut) { var result = nonactive result.mutatingMethod(x) nonactive = result } @differentiable(reverse, wrt: (nonactive, x)) func activeInoutParamMutatingMethodTuple(_ nonactive: inout Mut, _ x: Mut) { var result = (nonactive, x) result.0.mutatingMethod(result.0) nonactive = result.0 } func twoInoutParameters(_ x: inout Float, _ y: inout Float) {} @differentiable(reverse) func testTwoInoutParameters(_ x: Float, _ y: Float) -> Float { var x = x var y = y twoInoutParameters(&x, &y) return x } func inoutParameterAndFormalResult(_ x: inout Float) -> Float { x } @differentiable(reverse) func testInoutParameterAndFormalResult(_ x: Float) -> Float { var x = x return inoutParameterAndFormalResult(&x) } //===----------------------------------------------------------------------===// // Stored property access differentiation //===----------------------------------------------------------------------===// // Test differentiation of invalid stored property access instructions: // `struct_extract`, `struct_element_addr`, `ref_element_addr`. struct StructTangentVectorNotStruct: Differentiable { var x: Float enum TangentVector: Differentiable, AdditiveArithmetic { case x(Float) typealias TangentVector = Self static func ==(_: Self, _: Self) -> Bool { fatalError() } static var zero: Self { fatalError() } static func +(_: Self, _: Self) -> Self { fatalError() } static func -(_: Self, _: Self) -> Self { fatalError() } } mutating func move(by offset: TangentVector) {} } // expected-error @+2 {{function is not differentiable}} // expected-note @+3 {{when differentiating this function definition}} @differentiable(reverse) @_silgen_name("test_struct_tangent_vector_not_struct") func testStructTangentVectorNotStruct(_ s: StructTangentVectorNotStruct) -> Float { // expected-note @+1 {{cannot differentiate access to property 'StructTangentVectorNotStruct.x' because 'StructTangentVectorNotStruct.TangentVector' is not a struct}} return s.x } // CHECK-LABEL: sil {{.*}} @test_struct_tangent_vector_not_struct // CHECK: struct_extract {{%.*}} : $StructTangentVectorNotStruct, #StructTangentVectorNotStruct.x struct StructOriginalPropertyNotDifferentiable: Differentiable { struct Nondiff { var x: Float } var nondiff: Nondiff struct TangentVector: Differentiable & AdditiveArithmetic { var nondiff: Float } mutating func move(by offset: TangentVector) {} } // expected-error @+2 {{function is not differentiable}} // expected-note @+3 {{when differentiating this function definition}} @differentiable(reverse) @_silgen_name("test_struct_original_property_not_differentiable") func testStructOriginalPropertyNotDifferentiable(_ s: StructOriginalPropertyNotDifferentiable) -> Float { // expected-note @+1 {{cannot differentiate access to property 'StructOriginalPropertyNotDifferentiable.nondiff' because property type 'StructOriginalPropertyNotDifferentiable.Nondiff' does not conform to 'Differentiable'}} return s.nondiff.x } // CHECK-LABEL: sil {{.*}} @test_struct_original_property_not_differentiable // CHECK: struct_extract {{%.*}} : $StructOriginalPropertyNotDifferentiable, #StructOriginalPropertyNotDifferentiable.nondiff struct StructTangentVectorPropertyNotFound: Differentiable { var x: Float struct TangentVector: Differentiable, AdditiveArithmetic { var y: Float } mutating func move(by offset: TangentVector) {} } // expected-error @+2 {{function is not differentiable}} // expected-note @+3 {{when differentiating this function definition}} @differentiable(reverse) @_silgen_name("test_struct_tangent_property_not_found") func testStructTangentPropertyNotFound(_ s: StructTangentVectorPropertyNotFound) -> Float { // expected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = s // expected-note @+1 {{cannot differentiate access to property 'StructTangentVectorPropertyNotFound.x' because 'StructTangentVectorPropertyNotFound.TangentVector' does not have a stored property named 'x'}} return tmp.x } // CHECK-LABEL: sil {{.*}} @test_struct_tangent_property_not_found // CHECK: struct_element_addr {{%.*}} : $*StructTangentVectorPropertyNotFound, #StructTangentVectorPropertyNotFound.x struct StructTangentPropertyWrongType: Differentiable { var x: Float struct TangentVector: Differentiable, AdditiveArithmetic { var x: Double } mutating func move(by offset: TangentVector) {} } // expected-error @+2 {{function is not differentiable}} // expected-note @+3 {{when differentiating this function definition}} @differentiable(reverse) @_silgen_name("test_struct_tangent_property_wrong_type") func testStructTangentPropertyWrongType(_ s: StructTangentPropertyWrongType) -> Float { // expected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = s // expected-note @+1 {{cannot differentiate access to property 'StructTangentPropertyWrongType.x' because 'StructTangentPropertyWrongType.TangentVector.x' does not have expected type 'Float.TangentVector' (aka 'Float')}} return tmp.x } // CHECK-LABEL: sil {{.*}} @test_struct_tangent_property_wrong_type // CHECK: struct_element_addr {{%.*}} : $*StructTangentPropertyWrongType, #StructTangentPropertyWrongType.x final class ClassTangentPropertyWrongType: Differentiable { var x: Float = 0 struct TangentVector: Differentiable, AdditiveArithmetic { var x: Double } func move(by offset: TangentVector) {} } // expected-error @+2 {{function is not differentiable}} // expected-note @+3 {{when differentiating this function definition}} @differentiable(reverse) @_silgen_name("test_class_tangent_property_wrong_type") func testClassTangentPropertyWrongType(_ c: ClassTangentPropertyWrongType) -> Float { // expected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = c // expected-note @+1 {{cannot differentiate access to property 'ClassTangentPropertyWrongType.x' because 'ClassTangentPropertyWrongType.TangentVector.x' does not have expected type 'Float.TangentVector' (aka 'Float')}} return tmp.x } // CHECK-LABEL: sil {{.*}} @test_class_tangent_property_wrong_type // CHECK: ref_element_addr {{%.*}} : $ClassTangentPropertyWrongType, #ClassTangentPropertyWrongType.x struct StructTangentPropertyNotStored: Differentiable { var x: Float struct TangentVector: Differentiable, AdditiveArithmetic { var x: Float { 0 } } mutating func move(by offset: TangentVector) {} } // expected-error @+2 {{function is not differentiable}} // expected-note @+3 {{when differentiating this function definition}} @differentiable(reverse) @_silgen_name("test_struct_tangent_property_not_stored") func testStructTangentPropertyNotStored(_ s: StructTangentPropertyNotStored) -> Float { // expected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = s // expected-note @+1 {{cannot differentiate access to property 'StructTangentPropertyNotStored.x' because 'StructTangentPropertyNotStored.TangentVector.x' is not a stored property}} return tmp.x } // CHECK-LABEL: sil {{.*}} @test_struct_tangent_property_not_stored // CHECK: struct_element_addr {{%.*}} : $*StructTangentPropertyNotStored, #StructTangentPropertyNotStored.x final class ClassTangentPropertyNotStored: Differentiable { var x: Float = 0 struct TangentVector: Differentiable, AdditiveArithmetic { var x: Float { 0 } } func move(by offset: TangentVector) {} } // expected-error @+2 {{function is not differentiable}} // expected-note @+3 {{when differentiating this function definition}} @differentiable(reverse) @_silgen_name("test_class_tangent_property_not_stored") func testClassTangentPropertyNotStored(_ c: ClassTangentPropertyNotStored) -> Float { // expected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = c // expected-note @+1 {{cannot differentiate access to property 'ClassTangentPropertyNotStored.x' because 'ClassTangentPropertyNotStored.TangentVector.x' is not a stored property}} return tmp.x } // CHECK-LABEL: sil {{.*}} @test_class_tangent_property_not_stored // CHECK: ref_element_addr {{%.*}} : $ClassTangentPropertyNotStored, #ClassTangentPropertyNotStored.x // https://github.com/apple/swift/issues/55580 // Test stored property access with conditionally `Differentiable` base type. struct Complex { var real: T var imaginary: T } extension Complex: Differentiable where T: Differentiable { typealias TangentVector = Complex } extension Complex: AdditiveArithmetic {} @differentiable(reverse) func f_55580(lhs: Complex, rhs: Complex) -> Float { return lhs.real + rhs.real } //===----------------------------------------------------------------------===// // Wrapped property differentiation //===----------------------------------------------------------------------===// @propertyWrapper struct Wrapper { private var value: Value var wrappedValue: Value { get { value } set { value = newValue } } var projectedValue: Self { self } init(wrappedValue: Value) { self.value = wrappedValue } } @propertyWrapper struct DifferentiableWrapper { private var value: Value var wrappedValue: Value { get { value } set { value = newValue } } var projectedValue: Self { self } init(wrappedValue: Value) { self.value = wrappedValue } } extension DifferentiableWrapper: Differentiable where Value: Differentiable {} // Note: property wrapped value differentiation works even if wrapper types do // not conform to `Differentiable`. The conformance here tests projected value // accesses. struct Struct: Differentiable { // expected-error @+4 {{expression is not differentiable}} // expected-error @+3 {{expression is not differentiable}} // expected-note @+2 {{cannot differentiate access to property 'Struct._x' because 'Struct.TangentVector' does not have a stored property named '_x'}} // expected-note @+1 {{cannot differentiate access to property 'Struct._x' because 'Struct.TangentVector' does not have a stored property named '_x'}} @DifferentiableWrapper @DifferentiableWrapper var x: Float = 10 @Wrapper var y: Float = 20 var z: Float = 30 } @differentiable(reverse) func differentiableProjectedValueAccess(_ s: Struct) -> Float { s.$x.wrappedValue.wrappedValue } // expected-error @+2 {{function is not differentiable}} // expected-note @+2 {{when differentiating this function definition}} @differentiable(reverse) func projectedValueAccess(_ s: Struct) -> Float { // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{3-3=withoutDerivative(at: }} {{7-7=)}} s.$y.wrappedValue } // https://github.com/apple/swift/issues/55084 // Test `wrapperValue.modify` differentiation. @differentiable(reverse) func modify(_ s: Struct, _ x: Float) -> Float { var s = s s.x *= x * s.z return s.x } //===----------------------------------------------------------------------===// // Array literal initialization //===----------------------------------------------------------------------===// // expected-error @+1 {{function is not differentiable}} @differentiable(reverse) // expected-note @+1 {{when differentiating this function definition}} func tupleArrayLiteralInitialization(_ x: Float, _ y: Float) -> Float { // `Array<(Float, Float)>` does not conform to `Differentiable`. let array = [(x * y, x * y)] // expected-note @-1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{15-15=withoutDerivative(at: }} {{31-31=)}} return array[0].0 } //===----------------------------------------------------------------------===// // Subset parameter differentiation thunks //===----------------------------------------------------------------------===// func testNoDerivativeParameter(_ f: @differentiable(reverse) (Float, @noDerivative Float) -> Float) -> Float { // expected-error @+2 {{function is not differentiable}} // expected-note @+1 {{cannot differentiate with respect to a '@noDerivative' parameter}} return gradient(at: 2) { x in f(x * x, x) } } // Test parameter subset thunk + partially-applied original function. struct TF_675 : Differentiable { @differentiable(reverse) func method(_ x: Float) -> Float { return x } } let _: @differentiable(reverse) (Float) -> Float = TF_675().method // TF-918: Test parameter subset thunk + partially-applied original function. let _: @differentiable(reverse) (Float, @noDerivative Float) -> Float = (+) as @differentiable(reverse) (Float, Float) -> Float let _: @differentiable(reverse) (Float, @noDerivative Float) -> Float = (+) as @differentiable(reverse) (Float, @noDerivative Float) -> Float //===----------------------------------------------------------------------===// // Differentiation in fragile functions //===----------------------------------------------------------------------===// public func implicitlyDifferentiableFromFragile(_ x: Float) -> Float { x } public func hasImplicitlyDifferentiatedTopLevelDefaultArgument( // expected-error @+2 {{function is not differentiable}} // expected-note @+1 {{differentiated functions in default arguments must be marked '@differentiable' or have a public '@derivative'}} _ f: @differentiable(reverse) (Float) -> Float = implicitlyDifferentiableFromFragile ) {} // No error expected public func hasImplicitlyDifferentiatedClosureDefaultArgument(_ f: @differentiable(reverse) (Float) -> Float = { $0 }) {} @inlinable public func fragileFuncWithGradient() { // expected-error @+2 {{function is not differentiable}} // expected-note @+1 {{differentiated functions in '@inlinable' functions must be marked '@differentiable' or have a public '@derivative'}} _ = gradient(at: 0, of: implicitlyDifferentiableFromFragile) } @inlinable @differentiable(reverse) public func fragileDifferentiable(_ x: Float) -> Float { // expected-error @+2 {{expression is not differentiable}} // expected-note @+1 {{differentiated functions in '@inlinable' functions must be marked '@differentiable' or have a public '@derivative'}} implicitlyDifferentiableFromFragile(x) } //===----------------------------------------------------------------------===// // Coroutines (SIL function yields, `begin_apply`) (not yet supported) //===----------------------------------------------------------------------===// struct HasReadAccessors: Differentiable { var stored: Float var computed: Float { // `_read` is a coroutine: `(Self) -> () -> ()`. _read { yield stored } } } struct HasModifyAccessors: Differentiable { var stored: Float var computed: Float { get { stored } // `_modify` is a coroutine: `(inout Self) -> () -> ()`. _modify { yield &stored } } } // expected-error @+2 {{function is not differentiable}} // expected-note @+2 {{when differentiating this function definition}} @differentiable(reverse) func testReadAccessorCoroutines(_ x: HasReadAccessors) -> Float { // expected-note @+1 {{cannot differentiate through a '_read' accessor}} return x.computed } @differentiable(reverse) func testModifyAccessorCoroutines(_ x: HasModifyAccessors) -> Float { var x = x x.computed = x.computed return x.computed } // TF-1078: Diagnose `_modify` accessor application with active `inout` argument. @differentiable(reverse) func TF_1078(array: [Float], x: Float) -> Float { var array = array // Array subscript assignment below calls `Array.subscript.modify`. // expected-error @+2 {{expression is not differentiable}} // expected-note @+1 {{cannot differentiate functions that have not been marked '@differentiable' and that are defined in other files}} array[0] = x return array[0] } // TF-1115: Diagnose `_modify` accessor application with initially non-active `inout` argument. @differentiable(reverse) func TF_1115(_ x: Float) -> Float { var array: [Float] = [0] // Array subscript assignment below calls `Array.subscript.modify`. // expected-error @+2 {{expression is not differentiable}} // expected-note @+1 {{cannot differentiate functions that have not been marked '@differentiable' and that are defined in other files}} array[0] = x return array[0] } // TF-1115: Test `_modify` accessor application with initially non-active `inout` argument, // where the yielded value is not a projection from `self`. extension Float { static var staticProperty: Float = 1 var projection: Float { get { self } // This `modify` accessor yields a static variable, not a projection from `self`. // Diagnosing active applications is nonetheless a safe over-approximation. _modify { yield &Float.staticProperty } } } @differentiable(reverse) func TF_1115_modifyNonSelfProjection(x: Float) -> Float { var result: Float = 0 // Assignment below calls `Float.projection.modify`. result.projection = x return result } //===----------------------------------------------------------------------===// // Conversion to `@differentiable(_linear)` (not yet supported) //===----------------------------------------------------------------------===// // expected-error @+1 {{conversion to '@differentiable(_linear)' function type is not yet supported}} let _: @differentiable(_linear) (Float) -> Float = { x in x }