-
Notifications
You must be signed in to change notification settings - Fork 259
Description
The range operator (..) expects both operands to be integers. It usually throws an error if this isn't true. However in some cases the type checking is bypassed (meaning that invalid expressions are evaluated without error). Two such cases are described below. The first definitely seems like a bug. The second looks like a bug but it's possible that this is the intended behaviour.
Case 1. When lhs > rhs
The range operator returns undefined if the left side is greater than the right side. This means that expressions like [10..1] evaluate to an empty array. But because this check comes before the type validation, any types that satisfy the JavaScript condition lhs > rhs trigger an undefined result and never get validated.
The following expressions are all invalid yet they all evaluate to [] instead of throwing a type error.
[10..1.5]
[true..false]
["dogs".."cats"]
[1..""]
[1..[]]
["a"..{}]
[1..false]
[2..true]
If you reverse the operands in any of these expressions, the condition lhs > rhs is no longer true and you get a type error as expected.
Case 2. Undefined inputs
The range operator returns undefined if either of its inputs evaluate to undefined. But again, this test happens before the types have been validated. So an undefined input can override a type error on the other input, e.g.
[0..true] // error: right side is not an integer
[$x..true] // returns []
[false..10] // error: left side is not an integer
[false..$x] // returns []
It's odd that the test for undefined inputs takes precedence over type checking. I would expect to be notified of the type violation even if the other input is undefined. After all, no value of $x makes those expressions valid.
The range operator isn't the only example of this. Numeric operators behave in the same way:
false + 1 // error: left side is not a number
false + $x // returns undefined
And so do the comparison operators that validate types:
false > 1 // error: operands must be numbers or strings
false > $x // returns false
It doesn't happen with function calls though:
$substringBefore("hello", 3) // error: argument 2 does not match signature
$substringBefore($x, 3) // same error