psalm
psalm copied to clipboard
False Flag for InvalidArrayOffset
When working on https://github.com/vimeo/psalm/pull/10738 I was able to notice this issue with string array keys being misrepresented as ints.
Fails: https://psalm.dev/r/e0a6a199fd (Note how all the keys are strings, but they are numberic)
Works: https://psalm.dev/r/4753dde5a9 (Note the 00
for the first key)
ERROR: [InvalidArrayOffset](https://psalm.dev/115) - 112:37 - Cannot access value on variable MyTest::LOOKUP using a string offset, expecting
Please close if this is expected, but this seems incorrect to me.
I found these snippets:
https://psalm.dev/r/e0a6a199fd
<?php
class MyTest {
const LOOKUP = [
"0" => null,
"1" => null,
"2" => null,
"3" => null,
"4" => null,
"5" => null,
"6" => null,
"7" => null,
"8" => null,
"9" => null,
"10" => null,
"11" => null,
"12" => null,
"13" => null,
"14" => null,
"15" => null,
"16" => null,
"17" => null,
"18" => null,
"19" => null,
"20" => null,
"21" => null,
"22" => null,
"23" => null,
"24" => null,
"25" => null,
"26" => null,
"27" => null,
"28" => null,
"29" => null,
"30" => null,
"31" => null,
"32" => null,
"33" => null,
"34" => null,
"35" => null,
"36" => null,
"37" => null,
"38" => null,
"39" => null,
"40" => null,
"41" => null,
"42" => null,
"43" => null,
"44" => null,
"45" => null,
"46" => null,
"47" => null,
"48" => null,
"49" => null,
"50" => null,
"51" => null,
"52" => null,
"53" => null,
"54" => null,
"55" => null,
"56" => null,
"57" => null,
"58" => null,
"59" => null,
"60" => null,
"61" => null,
"62" => null,
"63" => null,
"64" => null,
"65" => null,
"66" => null,
"67" => null,
"68" => null,
"69" => null,
"70" => self::SUCCEED,
"71" => self::FAIL,
"72" => null,
"73" => null,
"74" => null,
"75" => null,
"76" => null,
"77" => null,
"78" => null,
"79" => null,
"80" => null,
"81" => null,
"82" => null,
"83" => null,
"84" => null,
"85" => null,
"86" => null,
"87" => null,
"88" => null,
"89" => null,
"90" => null,
"91" => null,
"92" => null,
"93" => null,
"94" => null,
"95" => null,
"96" => null,
"97" => null,
"98" => null,
"99" => null,
"100" => null,
"101" => null,
];
const SUCCEED = "SUCCEED";
const FAIL = "FAIL";
public static function will_succeed(string $code) : bool {
return (self::LOOKUP[$code] ?? null) === self::SUCCEED;
}
}
Psalm output (using commit c488d40):
ERROR: InvalidArrayOffset - 112:37 - Cannot access value on variable MyTest::LOOKUP using a string offset, expecting 0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101
ERROR: InvalidConstantAssignmentValue - 3:31 - MyTest::LOOKUP with declared type array{0: null, 100: null, 101: null, 10: null, 11: null, 12: null, 13: null, 14: null, 15: null, 16: null, 17: null, 18: null, 19: null, 1: null, 20: null, 21: null, 22: null, 23: null, 24: null, 25: null, 26: null, 27: null, 28: null, 29: null, 2: null, 30: null, 31: null, 32: null, 33: null, 34: null, 35: null, 36: null, 37: null, 38: null, 39: null, 3: null, 40: null, 41: null, 42: null, 43: null, 44: null, 45: null, 46: null, 47: null, 48: null, 49: null, 4: null, 50: null, 51: null, 52: null, 53: null, 54: null, 55: null, 56: null, 57: null, 58: null, 59: null, 5: null, 60: null, 61: null, 62: null, 63: null, 64: null, 65: null, 66: null, 67: null, 68: null, 69: null, 6: null, 70: 'SUCCEED', 71: 'FAIL', 72: null, 73: null, 74: null, 75: null, 76: null, 77: null, 78: null, 79: null, 7: null, 80: null, 81: null, 82: null, 83: null, 84: null, 85: null, 86: null, 87: null, 88: null, 89: null, 8: null, 90: null, 91: null, 92: null, 93: null, 94: null, 95: null, 96: null, 97: null, 98: null, 99: null, 9: null} cannot be assigned type list{null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 'SUCCEED', 'FAIL', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ...<null>}
https://psalm.dev/r/4753dde5a9
<?php
class MyTest {
const LOOKUP = [
"00" => null,
"1" => null,
"2" => null,
"3" => null,
"4" => null,
"5" => null,
"6" => null,
"7" => null,
"8" => null,
"9" => null,
"10" => null,
"11" => null,
"12" => null,
"13" => null,
"14" => null,
"15" => null,
"16" => null,
"17" => null,
"18" => null,
"19" => null,
"20" => null,
"21" => null,
"22" => null,
"23" => null,
"24" => null,
"25" => null,
"26" => null,
"27" => null,
"28" => null,
"29" => null,
"30" => null,
"31" => null,
"32" => null,
"33" => null,
"34" => null,
"35" => null,
"36" => null,
"37" => null,
"38" => null,
"39" => null,
"40" => null,
"41" => null,
"42" => null,
"43" => null,
"44" => null,
"45" => null,
"46" => null,
"47" => null,
"48" => null,
"49" => null,
"50" => null,
"51" => null,
"52" => null,
"53" => null,
"54" => null,
"55" => null,
"56" => null,
"57" => null,
"58" => null,
"59" => null,
"60" => null,
"61" => null,
"62" => null,
"63" => null,
"64" => null,
"65" => null,
"66" => null,
"67" => null,
"68" => null,
"69" => null,
"70" => self::SUCCEED,
"71" => self::FAIL,
"72" => null,
"73" => null,
"74" => null,
"75" => null,
"76" => null,
"77" => null,
"78" => null,
"79" => null,
"80" => null,
"81" => null,
"82" => null,
"83" => null,
"84" => null,
"85" => null,
"86" => null,
"87" => null,
"88" => null,
"89" => null,
"90" => null,
"91" => null,
"92" => null,
"93" => null,
"94" => null,
"95" => null,
"96" => null,
"97" => null,
"98" => null,
"99" => null,
"100" => null,
"101" => null,
];
const SUCCEED = "SUCCEED";
const FAIL = "FAIL";
public static function will_succeed(string $code) : bool {
return (self::LOOKUP[$code] ?? null) === self::SUCCEED;
}
}
Psalm output (using commit c488d40):
ERROR: InvalidConstantAssignmentValue - 3:31 - MyTest::LOOKUP with declared type array{00: null, 100: null, 101: null, 10: null, 11: null, 12: null, 13: null, 14: null, 15: null, 16: null, 17: null, 18: null, 19: null, 1: null, 20: null, 21: null, 22: null, 23: null, 24: null, 25: null, 26: null, 27: null, 28: null, 29: null, 2: null, 30: null, 31: null, 32: null, 33: null, 34: null, 35: null, 36: null, 37: null, 38: null, 39: null, 3: null, 40: null, 41: null, 42: null, 43: null, 44: null, 45: null, 46: null, 47: null, 48: null, 49: null, 4: null, 50: null, 51: null, 52: null, 53: null, 54: null, 55: null, 56: null, 57: null, 58: null, 59: null, 5: null, 60: null, 61: null, 62: null, 63: null, 64: null, 65: null, 66: null, 67: null, 68: null, 69: null, 6: null, 70: 'SUCCEED', 71: 'FAIL', 72: null, 73: null, 74: null, 75: null, 76: null, 77: null, 78: null, 79: null, 7: null, 80: null, 81: null, 82: null, 83: null, 84: null, 85: null, 86: null, 87: null, 88: null, 89: null, 8: null, 90: null, 91: null, 92: null, 93: null, 94: null, 95: null, 96: null, 97: null, 98: null, 99: null, 9: null} cannot be assigned type array{00: null, 100: null, 10: null, 11: null, 12: null, 13: null, 14: null, 15: null, 16: null, 17: null, 18: null, 19: null, 1: null, 20: null, 21: null, 22: null, 23: null, 24: null, 25: null, 26: null, 27: null, 28: null, 29: null, 2: null, 30: null, 31: null, 32: null, 33: null, 34: null, 35: null, 36: null, 37: null, 38: null, 39: null, 3: null, 40: null, 41: null, 42: null, 43: null, 44: null, 45: null, 46: null, 47: null, 48: null, 49: null, 4: null, 50: null, 51: null, 52: null, 53: null, 54: null, 55: null, 56: null, 57: null, 58: null, 59: null, 5: null, 60: null, 61: null, 62: null, 63: null, 64: null, 65: null, 66: null, 67: null, 68: null, 69: null, 6: null, 70: 'SUCCEED', 71: 'FAIL', 72: null, 73: null, 74: null, 75: null, 76: null, 77: null, 78: null, 79: null, 7: null, 80: null, 81: null, 82: null, 83: null, 84: null, 85: null, 86: null, 87: null, 88: null, 89: null, 8: null, 90: null, 91: null, 92: null, 93: null, 94: null, 95: null, 96: null, 97: null, 98: null, 99: null, 9: null, ...<101, null>}