Range subscript is ambiguous

This function seems simple enough:

    func foo(a: [Int], n: Int) {
        var x : [Int] = a[0..<n]
    }

But it doesn’t compile.

    error: ambiguous subscript with base type '[Int]' and index type 'Range<Int>'
    var x : [Int] = a[0..<n]
        ~^~~~~~~
        Swift.Array:100:12: note: found this candidate
    public subscript (subRange: Range<Int>) -> ArraySlice<Element> { get set }
    ^
    Swift.MutableCollectionType:3:12: note: found this candidate
    public subscript (bounds: Range<Self.Index>) -> MutableSlice<Self> { get set }
    ^
    Swift.CollectionType:2:12: note: found this candidate
    public subscript (bounds: Range<Self.Index>) -> Slice<Self> { get }
    ^

The oddity is that if I change the assignment to this

    var y : [Int] = Array(a[0..<n])

then the compiler is happy.

Shouldn’t it be able to do any necessary type inference from the fact that the expression is in a context where an array is required?

  Neil Faiman

The error message is misleading (if you have time, we'd appreciate a bug report!). What's really going on is that a[0..<n] produces an ArraySlice<T>, not an Array<T>, in order to share memory with the underlying array. The type doesn't match in your assignment. If `x` is just temporary, I'd recommend leaving the type annotation out, since `var x = a[0..<n]` should just work.

-Joe

···

On May 15, 2016, at 5:31 AM, Neil Faiman via swift-users <swift-users@swift.org> wrote:

This function seems simple enough:

   func foo(a: [Int], n: Int) {
       var x : [Int] = a[0..<n]
   }

But it doesn’t compile.

   error: ambiguous subscript with base type '[Int]' and index type 'Range<Int>'
   var x : [Int] = a[0..<n]
       ~^~~~~~~
       Swift.Array:100:12: note: found this candidate
   public subscript (subRange: Range<Int>) -> ArraySlice<Element> { get set }
   ^
   Swift.MutableCollectionType:3:12: note: found this candidate
   public subscript (bounds: Range<Self.Index>) -> MutableSlice<Self> { get set }
   ^
   Swift.CollectionType:2:12: note: found this candidate
   public subscript (bounds: Range<Self.Index>) -> Slice<Self> { get }
   ^

The oddity is that if I change the assignment to this

   var y : [Int] = Array(a[0..<n])

then the compiler is happy.

Shouldn’t it be able to do any necessary type inference from the fact that the expression is in a context where an array is required?

FWIW, master produces the error:

test.swift:2:27: error: cannot subscript a value of type '[Int]' with an index of type 'CountableRange<Int>'
         var x : [Int] = a[0..<n]
                          ^
test.swift:2:27: note: overloads for 'subscript' exist with these partially matching parameter lists: (Int), (Range<Int>), (Range<Self.Index>), (ClosedRange<Self.Index>), (CountableClosedRange<Self.Index>)
         var x : [Int] = a[0..<n]
                          ^

-Chris

···

On May 16, 2016, at 10:09 AM, Joe Groff via swift-users <swift-users@swift.org> wrote:

The oddity is that if I change the assignment to this

  var y : [Int] = Array(a[0..<n])

then the compiler is happy.

Shouldn’t it be able to do any necessary type inference from the fact that the expression is in a context where an array is required?

The error message is misleading (if you have time, we'd appreciate a bug report!). What's really going on is that a[0..<n] produces an ArraySlice<T>, not an Array<T>, in order to share memory with the underlying array. The type doesn't match in your assignment. If `x` is just temporary, I'd recommend leaving the type annotation out, since `var x = a[0..<n]` should just work.

I think I just got bitten by this:

struct Foo<T:BinaryInteger> {
  let bar : [T]
  
  func getrange(start: Array<T>.Index, end: Array<T>.Index) -> Range<Array<T>.Index> { return start..<end }

  func getind(v:Range<Array<T>.Index>) -> [T] { return self.bar[v] }

  func doit() -> [T] {
    let r = getrange(start:1, end:3)
    return getind(r)
  }
}

let a = [UInt(2),UInt(4),UInt(6),UInt(8),UInt(10)] 

let f = Foo(bar: a)

print(f.doit())

yields

err.swift:9:20: error: ambiguous subscript with base type '[T]' and index type 'Range<Array.Index>' (aka 'Range<Int>')
    return self.bar[v]
           ~~~~~~~~^~~

Changing Foo.getind() to return Array(self.bar[v]) fixes things.

Is this the same error?

Yeah, that looks similar. The real problem is that you have to either return ArraySlice<T> or write Array(self.bar[v]) to make a new array.

I take it this is a bug, though? Has it been filed?

Yeah, the bad diagnostic is a bug. I’m not sure whether it’s been filed yet. As Chris noted, it may be fixed in Swift 4.2 already.

Ah, gotcha. The problem is in the error message text, but the behavior is appropriate. Thanks.

1 Like

Is there a reason you’re calling UInt(#) when creating the a array, if not you might consider writing it in one of the following ways:

let a: [UInt] = [1, 2, 3]
let a = [1 as UInt, 2, 3]

My personal preference is the first option:)

2 Likes

Only my inexperience with the language. :wink: Thanks for the alternate suggestions.