Clone a ClosureExpr and change all decl contexts within the body

Hmm, I get warning when defining the init: initializer for struct 'X' must use "self.init(...)" or "self = ..." because it is not in module 'REPL_0'

That’s an artifact of using the REPL. Try compiling that in one file

What exactly am I supposed to be looking for? This compiles and executes fine. :thinking:

public struct X {
  public var y: (Int) -> Int = { $0 }
}

extension X {
  @inlinable init(y: Int) { print(y) }
}

_ = X()
_ = X(y: 6) // 6

I suppose the motivating example isn't a huge problem, but it's definitely something that you'll have to look out for when implementing this.

The place where this transformation is not valid is in @_fixed_layout types in resilient modules, where a property initializer need to only reference public or @usableFromInline things.

@_fixed_layout
public struct X {
  public var x: (Int) -> Int = { $0 }
  public var y: (Int) -> Int = X.y_initialValue()
  static func y_initialValue() -> (Int) -> Int {
    return { $0 }
  }
}

Here, x is fine because the closure is directly written. But y calls something that's not @usableFromInline, meaning:

test.swift:4:34: error: static method 'y_initialValue()' is internal and cannot be referenced from a property initializer in a '@_fixed_layout' type
  public var y: (Int) -> Int = X.y_initialValue()
                                 ^
test.swift:5:15: note: static method 'y_initialValue()' is not '@usableFromInline' or public
  static func y_initialValue() -> (Int) -> Int {

Also, if the static function is going to be @inlinable or @_transparent, it may need to show up in parseable interface files, which would mean it would need a name other than "varName.initialValue"

I've opened https://github.com/apple/swift/pull/19743 where we can discuss implementation more.

I added a comment: https://github.com/apple/swift/pull/19743#issuecomment-427509407

I suspect there's a better way of doing this, basically by sinking this down into the SILGen level.

Let's look at the SIL for a struct with a property that has an initial value:

struct S {
  var x: Int = 0
}

sil hidden [transparent] @$S7initial1SV1xSivpfi : $@convention(thin) () -> Int {
bb0:
  %0 = metatype $@thin Int.Type                   // user: %3
  %1 = integer_literal $Builtin.Int2048, 0        // user: %3
  // function_ref Int.init(_builtinIntegerLiteral:)
  %2 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %3
  %3 = apply %2(%1, %0) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %4
  return %3 : $Int                                // id: %4
} // end sil function '$S7initial1SV1xSivpfi'

Your helper function effectively already exists. What you need to do then is to have the default argument generator emitted by SIL call it.

Terms of Service

Privacy Policy

Cookie Policy