[swift-users] inout generic struct parameter error

Slava Pestov spestov at apple.com
Mon Jan 2 00:11:43 CST 2017


Nice catch. Here’s a minimal test case:

struct G<T> {}

func f1(_: inout G<Int>) {}
func f2<T>(_: inout G<T>) {}

func g1(t: G<Int>) {
  let _ = f1(&t) // cannot pass immutable value as inout argument: 't' is a 'let' constant
}

func g2(t: G<Int>) {
  let _ = f2(&t) // cannot convert value of type 'G<Int>' to expected argument type 'G<_>'
}

func g3<T>(t: G<T>) {
  let _ = f2(&t) // cannot convert value of type 'G<T>' to expected argument type 'G<_>'
}

In the second two cases, f2() is called, which has a generic type. Since the constraint system could not be solved, CSDiag won’t have a type substitution for T so the unresolved type prints as _ in the diagnostic. It looks like we bail out before checking if the failure is due to an ‘inout’ mismatch, and produce the bad generic diagnostic instead of the more specific one.

I filed https://bugs.swift.org/browse/SR-3525 <https://bugs.swift.org/browse/SR-3525> if anyone wants to take a look.

Slava

> On Jan 1, 2017, at 4:52 PM, Ben Cohen via swift-users <swift-users at swift.org> wrote:
> 
> Hi Georgios,
> 
> Yes, that isn’t the best of error messages.
> 
> The problem is that makeIterator() is not a mutating function, so inside it all properties are treated as immutable. This means you aren’t allowed to pass them into functions as inout arguments. It’s essentially the same as this:
> 
> func takesInout(i: inout Int) { i += 1 }
> 
> struct S {
>     var x: Int
>     func nonmutating() {
>         takesInout(i: &x)
>     }
> }
> // Error: Cannot pass immutable value as inout argument: 'self' is immutable
> // Fix-it: Mark method mutating to make 'self' mutable
> 
> Ideally you’d get an error message along these lines for your case but it looks like it’s failing.
> 
> So, you might consider making makeIterator mutating like the Fix-it suggests, which would allow you to pass its members as inout arguments:
> 
>     mutating public func makeIterator() -> WeakArrayIterator<T> {
> 
> But if you do this you will get a different compiler error, because your struct will no longer conform to Sequence, which requires makeIterator to be non-mutating. This is important, especially assuming your array is eventually going to conform to Collection as well. One of the requirements of collections is that they give an accurate count, but in the case of your array, the count returned might be different (greater) than the number of elements returned when you actually iterate the array, and this is not allowed (you may find that some standard library functions will trap when they discover that this has happened).
> 
> HTH,
> Ben
> 
> 
>> On Jan 1, 2017, at 10:48 AM, Georgios Moschovitis via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
>> 
>> While getting my feet wet with Swift, I am still surprised with type-system ‘quirks’ here and there.
>> 
>> I tried to implement a simple array of weak references:
>> 
>> public struct WeakArrayIterator<T: AnyObject>: IteratorProtocol {
>>     var array: [Weak<T>]
>>     var index = 0
>>     
>>     init(_ array: [Weak<T>]) {
>>         self.array = array
>>     }
>>     
>>     mutating public func next() -> T? {
>>         while index < array.count && array[index].value == nil {
>>             // Remove weak references invalidated by ARC.
>>             array.remove(at: index)
>>         }
>>         
>>         if index < array.count {
>>             let value = array[index].value
>>             index += 1
>>             return value
>>         } else {
>>             return nil
>>         }
>>     }
>> }
>> 
>> public struct WeakArray<T: AnyObject>: Sequence {
>>     var weakRefs: [Weak<T>]
>>     
>>     init() {
>>         weakRefs = []
>>     }
>>     
>>     public var count: Int {
>>         return weakRefs.count
>>     }
>> 
>>     public subscript(index: Int) -> T? {
>>         get {
>>             return weakRefs[index].value
>>         }
>>         
>>         set(value) {
>>             weakRefs[index] = Weak(value!)
>>         }
>>     }
>>     
>>     mutating public func append(_ value: T) {
>>         weakRefs.append(Weak(value))
>>     }
>>     
>>     @discardableResult
>>     mutating func remove(at index: Int) -> T? {
>>         return weakRefs.remove(at: index).value
>>     }
>>     
>>     public func makeIterator() -> WeakArrayIterator<T> {
>>         return WeakArrayIterator(weakRefs)
>>     }
>> }
>> 
>> This kinda works but because we pass a struct at:
>> 
>>         return WeakArrayIterator(weakRefs)
>> 
>> the ‘garbage collection’ at:
>> 
>>             // Remove weak references invalidated by ARC.
>>             array.remove(at: index)
>> 
>> doesn’t affect the original array.
>> 
>> I tried changing to this:
>> 
>> public struct WeakArrayIterator<T: AnyObject>: IteratorProtocol {
>>     ...    
>>     init(_ array: inout [Weak<T>]) {
>>         self.array = array
>>     }        return WeakArrayIterator(&weakRefs)
>>>> 
>> public struct WeakArray<T: AnyObject>: Sequence {
>>     return WeakArrayIterator(&weakRefs)
>> 
>> but I get this strange (to me) error:
>> 
>> Cannot convert value of type ‘[Weak<T>]’ to expected argument type ‘[Weak<_>]’
>> 
>> I even get the fix-it suggestion:
>> 
>> Fix-it Insert “as [Weak<_>]”
>> 
>> which does not even compile!
>> 
>> I would appreciate it if someone could explain me this cryptic error and maybe provide some pointers about how to properly/efficiently implement a WeakArray.
>> 
>> thanks,
>> -g.
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org <mailto:swift-users at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-users
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170101/fc87ea58/attachment.html>


More information about the swift-users mailing list