Swift 4.2 strange behavior

let (x: Int, y: Double) = (3, 1.0)
let result = Int + Double
print(result)

The code above make playground of Xcode 10(on macos: 10.14 (18A391)) sometime crash, if not crash it will fail with error:
Binary operator '+' cannot be applied to operands of type 'Int' and 'Double'
But after I change to:

let (x: Int, y: Double) = (3, 1)
let result = Int + Double
print(result)

The result of print is 4. Is this a bug of Swift?

2 Likes
print(type(of: Double)) // Int

:eek: I guess something here shouldn't work in the first place? o_O

There’s been discussions around this in the past. This is a consequence of the tuple shuffle feature, which I think is about to be put through evolution for removal. Deprecating Tuple Shuffles (Round 2)

If you take a look at that expression, it’s not actually shuffling anything. When I first ginned up the example here, I was reading through the code that we use to check variable shadowing in patterns. That was when I realized Swift will pretty much let you shadow anything as long as you do it inside of a new scope. And it’s completely an accident that it does too.

Changing the behavior of the language to ban shadowing types would probably be viewed as a bug fix. But, I suspect it’s also massively source breaking.

4 Likes

Oh interesting, I always assumed that once tuple shuffles go away, this will also disappear, but it sounds like that isn't the case! I occasionally run into this. Mostly when I'm trying to match a tuple with a function call that mixes generics and tuples. Sometimes the type checker can't solve it in the fixed amount of time needed, so naturally reach for

let (x: Double: y: Thing) = someComplicatedFunction()

Instead of the correct

let (x, y): (Double, Thing) = someComplicatedFunction()

So IMO, I would view the ability to shadow types like this as actively harmful, at least when it appears like this with tuples.

2 Likes

The code above sometimes makss playgrounds crash

If you have a way of reliably causing that to happen, please file an bug report at bugs.swift.org if you haven’t already!

If it doesn’t crash it fails with the following error:

So there’s problem: You expected that pattern syntax would let you write type annotations in the pattern. Which is a really natural assumption. After all

let x : Int = 3
let y : Double = 1
let xy = (x, y)

Really seems like it should “collapse” to

let (x: Int, y: Double) = (3, 1)

Bur let’s consider more meaningful names here

let (firstLabel: val1, secondLabel: val2) = (3, 1)

Now it’s clear what happened here (I hope): the syntax for declaring the elements of a tuple pattern with labels looks suspiciously like the syntax for declaring a plain old typed variable pattern, but “splatted” over each tuple element. You actually meant to do this:

let xy : (x: Int, y: Double) = (3, 1)

The reason the original goes through leads us to the next question:

Is this a bug in Swift?

Depends on your perspective. In my opinion, it’s certainly really really undesirable behavior to be able to shadow types like this. It even works outside of tuple patterns

func foo() -> Int {
  let Int = 1
  let Double = 3
  return Int + Double
}

Banning this would definitely be source breaking. My larger fear is that it would be massively so.

2 Likes

Since this:

let (x : Int, y : Double) = (3, 1)
let result = Int + Double // 4

Can be clarified like this:

let (meaninglessUnusableLabel1: varName1, meaninglessUnusableLabel2: varName2) = (3, 1)
let result = varName1 + varName2 // 4

Would it make sense to ban such meaningless unusable tuple labels?

let (including: (eg: _)) = (these: print("Hǝllo ʍoɹlp¡"))

I mean, unless I'm missing something, these labels (when used like this of course) don't serve any purpose at their declaration and they don't even exist afterwards.

let (labelWithoutACauseThatDisappearsImmediately1: x) = "I compile without warnings!"
var _ = (labelWithoutACauseThatDisappearsImmediately2: print(x))

I also noticed the following sort of unexpected (even in this context) error:

let   _  =       123         // Compiles without warnings
let   _  = (hmm: 123)        // Compiles without warnings
      _  =       123         // Compiles without warnings
      _  = (hmm: 123)        // Error: Cannot assign value of type '(hmm: Int)' to type '_'
      _  = (hmm: 123, ah: 4) // Compiles without warnings
(hmm: _) = (hmm: 123)        // Compiles without warnings
2 Likes

To day the Xcode 10 seem not crash but It's show the error:
19%20PM .
I also report the bug here SR-9049 and also attached the lldb-rpc-server crash logs as suggestion.