I assume that you know why the code doesn't run and you're just interested in why the error message is so strange.
This is a side effect of Swift's operator overload resolution and type inference. The operator
+ has many different definitions in Swift, and during type inference, the compiler has to figure out which one you are referring to. Below are some examples of some skeleton definitions (implementations aren't important). Please note that these aren't necessarily correct signatures, they're just for demonstration purposes.
func +(_ lhs: Int, _ rhs: Int) -> Int
func +(_ lhs: String, _ rhs: String) -> String
func +<T: Sequence>(_ lhs: T, _ hrs: T) -> T
func +(_ lhs: RunLoop.SchedulerTimeType.Stride, _ rhs: RunLoop.SchedulerTimeType.Stride) -> RunLoop.SchedulerTimeType.Stride
Disclaimer: I have not worked on the Swift compiler, so this is my best guess based off other compilers I've worked on, and a simple naïve inference algorithm that makes the explanation easier.
What I assume has happened (as an over-simplification) is that the compiler went through the definitions one by one, moving to the second operator when it found an operator definition that could satisfy the first operator.
The compiler found the
(Int, Int) -> Int addition definition first because
2 are both possibly integer literals. Next it would've gone through all of its definitions and found that it didn't have a definition for addition of type
(Int, String) -> _, so it discarded its assumption that the first operator was
Int + Int and started again. Note that the second operator didn't necessarily have to be
(Int, String) -> _ to be a match, it would also be valid to have
<T: Sequence>(Int, T) etc (because
String is a sequence).
At some point the compiler got to the last possible operator definition that could work for
1 + 2 which was
(Stride, Stride) -> Stride. This was a possible match because
Stride probably implements
ExpressibleByIntegerLiteral or a similar protocol. The compiler then continued to the second operator and tried all possible definitions. It found that there was no addition definition that operates on a
Stride and a
String. Importantly, the last partially matching operator it attempted (I assume) was
<T: Sequence>(T, T) -> T (because the right hand side, a string, conforms to
The compiler has to make a guess at which of the (possibly hundreds) of addition operator definitions that you wanted to refer to, and it probably just ended up choosing the last partially matching operator that it checked. It then told you that it 'expected' your code to work with that definition, which is somewhat misleading (because it really just expected your code to work with any of the definitions), but it's pretty difficult for the compiler to do much better, especially given that
print takes an argument of type
Any, so it has no clue as to what type you are expecting
1 + 2 + "3" to have.
Interestingly, I can't reproduce this behaviour at all. I get the following error which makes much more sense. The compiler has probably been updated to weight more direct matches higher when deciding which ones to print out (or it has gotten worse if your version is newer than mine lol).
Test.swift:7:21: error: binary operator '+' cannot be applied to operands of type 'Int' and 'String'
print(1 + 2 + "a")
~~~~~ ^ ~~~
Test.swift:7:21: note: overloads for '+' exist with these partially matching parameter lists: (Int, Int), (String, String)
print(1 + 2 + "a")