Generic type + noLocks = trouble

Is it possible to restrict T in such a way that I am not getting this error?
(I only plan to use it with POD value types)

// -experimental-performance-annotations
struct Test<T> {
    var x: T?
    @_noLocks
    init() {}
    // ๐Ÿ›‘ error: Using type 'Test<T>' can cause metadata allocation or locks
}
1 Like

As currently implemented, you have to apply @_noLocks to the caller of generic APIs, not to generic APIs themselves, since applying them to the generic function will attempt to restrict the unspecialized version of the generic function.

1 Like

Thank you.
Not sure if I'll be able using it though. For example:

// -experimental-performance-annotations
public struct Test<T> {
    private var x = 0
    private var y: T?
    init() {}
}

@_noLocks
func test() {
    typealias FiveInt8s = (Int8, Int8, Int8, Int8, Int8)
    typealias SixInt8s = (Int8, Int8, Int8, Int8, Int8, Int8)
    //_ = Test<FiveInt8s>()   // โœ…
    _ = Test<SixInt8s>()      // ๐Ÿ›‘
}

(compiles ok with 5 uint8's but not six).

I am not sure what is happening here, but if y is T and not T? it compiles ok.

// -experimental-performance-annotations
public struct Test<T> {
    private var x = 0
    private var y: T
    init(_ x: T) {
        y = x
    }
}

typealias SixInt8s = (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)

@_noLocks
func test() {
     _ = Test<SixInt8s>((1, 1, 1, 1, 1, 1, 1, 1, 1))   // โœ…
}

It is actually more subtle. y can be T? if it is declared with let.

a simpler example:

// -experimental-performance-annotations
@_noLocks
func foo<T>(_ v: T?) -> T {
    if let v { // ๐Ÿ›‘ Using type 'T' can cause metadata allocation or locks
        return v
    }
    while true {}
}

Ditto with a custom optional:

// -experimental-performance-annotations

enum MyOptional<Wrapped> {
    case none, some(Wrapped)
}

@_noLocks
func foo<T>(_ v: MyOptional<T>) -> T {
    switch v { // ๐Ÿ›‘ Using type 'MyOptional<T>' can cause metadata allocation or locks
        case .none: while true {}
        case let .some(v): return v
    }
}

or just this:

// -experimental-performance-annotations
@_noLocks
func foo<T>(_ v: T) -> T {
    v // ๐Ÿ›‘ Using type 'T' can cause metadata allocation or locks
}

Nothing suspicious in the asm (-O):

main:
        xor     eax, eax
        ret

output.foo<A>(A) -> A:
        mov     rdx, rsi
        mov     rsi, rdi
        mov     rcx, qword ptr [rdx - 8]
        mov     rcx, qword ptr [rcx + 16]
        mov     rdi, rax
        jmp     rcx

__swift_reflection_version:
        .short  3

Should be fixed with SIL: fix runtime effect of copy_addr of trivial types by eeckstein ยท Pull Request #72389 ยท apple/swift ยท GitHub

4 Likes