Consuming, borrowing and type inference

The following fails to compile:

struct Ref<T>: ~Copyable {
    var value: T
    init(_ value: T) { self.value = value }
}

func consumingMap<A>(
    _ f: @escaping (inout A) -> Void
) -> (consuming Ref<A>) -> Ref<A> {
    { ref in
        var newRef = ref
        f(&newRef.value)
        return newRef
    }
}

with the error:

'ref' is borrowed and cannot be consumed.  

Shouldn't consuming be inferred here, or am I missing something fundamental? (I feel like I've missed a huge amount of fundamental stuff on move-only types of late).

2 Likes

ok, fooling around with it more, this does compile:

func consumingMap<A>(
    _ f: @escaping (inout A) -> Void
) -> (consuming Ref<A>) -> Ref<A> {
    { (ref: consuming Ref<A>) -> Ref<A> in
        var newRef = ref
        f(&newRef.value)
        return newRef
    }
}

Seems like I should not have to spell out the full type-annotation here..

1 Like

I think ‘consuming’ ought to be inferred here from the return type (similarly if it were bound to a variable with that explicit type annotation).

I’m not sure if that inference was part of the corresponding SE proposal, but it should be a source-compatible addition if today it’s defaulting to ‘borrowing’, the weakest ownership kind.

that was my thinking too, but this stuff is all so new to me that I'm never sure if I have properly understood the concept. Another quick question, should ref be mutable there? i.e. should I be able to say:

func consumingMap<A>(
    _ f: @escaping (inout A) -> Void
) -> (consuming Ref<A>) -> Ref<A> {
    { (ref: consuming Ref<A>) -> Ref<A> in
        f(&ref.value)
        return ref
    }
}

Intuitively I would think I could or at least that it would be desirable. At present trying it that way yields:

error: couldn't IRGen expression. Please enable the expression log by running "log enable lldb expr", then run the failing expression again, and file a bug report with the log output.

I've reported that as a compiler bug, but my I can't tell if (when the compiler gets fixed) that should work or not.

Yes, a function should always be able to mutate its own parameter if that parameter is consuming.

1 Like