Skip to content

Commit

Permalink
Merge pull request #10209 from robchett/array_binary_ops
Browse files Browse the repository at this point in the history
Only the binary op 'plus' works with two arrays
  • Loading branch information
orklah authored Sep 16, 2023
2 parents 13ea0c2 + 03e8d19 commit ab470b4
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -542,97 +542,97 @@ private static function analyzeOperands(
$has_valid_right_operand = true;
}

$result_type = Type::getArray();

return null;
}

$has_valid_right_operand = true;
$has_valid_left_operand = true;
if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus) {
$has_valid_right_operand = true;
$has_valid_left_operand = true;

if ($left_type_part instanceof TKeyedArray
&& $right_type_part instanceof TKeyedArray
) {
$definitely_existing_mixed_right_properties = array_diff_key(
$right_type_part->properties,
$left_type_part->properties,
);
if ($left_type_part instanceof TKeyedArray
&& $right_type_part instanceof TKeyedArray
) {
$definitely_existing_mixed_right_properties = array_diff_key(
$right_type_part->properties,
$left_type_part->properties,
);

$properties = $left_type_part->properties;

foreach ($right_type_part->properties as $key => $type) {
if (!isset($properties[$key])) {
$properties[$key] = $type;
} elseif ($properties[$key]->possibly_undefined) {
$properties[$key] = Type::combineUnionTypes(
$properties[$key],
$type,
$codebase,
false,
true,
500,
$type->possibly_undefined,
);
$properties = $left_type_part->properties;

foreach ($right_type_part->properties as $key => $type) {
if (!isset($properties[$key])) {
$properties[$key] = $type;
} elseif ($properties[$key]->possibly_undefined) {
$properties[$key] = Type::combineUnionTypes(
$properties[$key],
$type,
$codebase,
false,
true,
500,
$type->possibly_undefined,
);
}
}
}

if ($left_type_part->fallback_params !== null) {
foreach ($definitely_existing_mixed_right_properties as $key => $type) {
$properties[$key] = Type::combineUnionTypes(Type::getMixed(), $type);
if ($left_type_part->fallback_params !== null) {
foreach ($definitely_existing_mixed_right_properties as $key => $type) {
$properties[$key] = Type::combineUnionTypes(Type::getMixed(), $type);
}
}
}

if ($left_type_part->fallback_params === null
&& $right_type_part->fallback_params === null
) {
$fallback_params = null;
} elseif ($left_type_part->fallback_params !== null
&& $right_type_part->fallback_params !== null
) {
$fallback_params = [
Type::combineUnionTypes(
$left_type_part->fallback_params[0],
$right_type_part->fallback_params[0],
),
Type::combineUnionTypes(
$left_type_part->fallback_params[1],
$right_type_part->fallback_params[1],
),
];
if ($left_type_part->fallback_params === null
&& $right_type_part->fallback_params === null
) {
$fallback_params = null;
} elseif ($left_type_part->fallback_params !== null
&& $right_type_part->fallback_params !== null
) {
$fallback_params = [
Type::combineUnionTypes(
$left_type_part->fallback_params[0],
$right_type_part->fallback_params[0],
),
Type::combineUnionTypes(
$left_type_part->fallback_params[1],
$right_type_part->fallback_params[1],
),
];
} else {
$fallback_params = $left_type_part->fallback_params ?: $right_type_part->fallback_params;
}

$new_keyed_array = new TKeyedArray(
$properties,
null,
$fallback_params,
);
$result_type_member = new Union([$new_keyed_array]);
} else {
$fallback_params = $left_type_part->fallback_params ?: $right_type_part->fallback_params;
$result_type_member = TypeCombiner::combine(
[$left_type_part, $right_type_part],
$codebase,
true,
);
}

$new_keyed_array = new TKeyedArray(
$properties,
null,
$fallback_params,
);
$result_type_member = new Union([$new_keyed_array]);
} else {
$result_type_member = TypeCombiner::combine(
[$left_type_part, $right_type_part],
$codebase,
true,
);
}
$result_type = Type::combineUnionTypes($result_type_member, $result_type, $codebase, true);

$result_type = Type::combineUnionTypes($result_type_member, $result_type, $codebase, true);
if ($left instanceof PhpParser\Node\Expr\ArrayDimFetch
&& $context
&& $statements_source instanceof StatementsAnalyzer
) {
ArrayAssignmentAnalyzer::updateArrayType(
$statements_source,
$left,
$right,
$result_type,
$context,
);
}

if ($left instanceof PhpParser\Node\Expr\ArrayDimFetch
&& $context
&& $statements_source instanceof StatementsAnalyzer
) {
ArrayAssignmentAnalyzer::updateArrayType(
$statements_source,
$left,
$right,
$result_type,
$context,
);
return null;
}

return null;
}

if (($left_type_part instanceof TNamedObject && strtolower($left_type_part->value) === 'gmp')
Expand Down
52 changes: 52 additions & 0 deletions tests/BinaryOperationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,58 @@ function toPositiveInt(int $i): int
'$a===' => 'float(9.2233720368548E+18)',
],
],
'invalidArrayOperations' => [
'code' => <<<'PHP'
<?php
$a1 = 1 + [];
$a2 = [] + 1;
// This is the one exception to this rule
$a3 = [] + [];
$b1 = 1 - [];
$b2 = [] - 1;
$b3 = [] - [];
$c1 = 1 * [];
$c2 = [] * 1;
$c3 = [] * [];
$d1 = 1 / [];
$d2 = [] / 1;
$d3 = [] / [];
$e1 = 1 ** [];
$e2 = [] ** 1;
$e3 = [] ** [];
$f1 = 1 % [];
$f2 = [] % 1;
$f3 = [] % [];

PHP,
'assertions' => [
'$a1' => 'float|int',
'$a2' => 'float|int',
'$a3' => 'array<never, never>',
'$b1' => 'float|int',
'$b2' => 'float|int',
'$b3' => 'float|int',
'$c1' => 'float|int',
'$c2' => 'float|int',
'$c3' => 'float|int',
'$d1' => 'float|int',
'$d2' => 'float|int',
'$d3' => 'float|int',
'$e1' => 'float|int',
'$e2' => 'float|int',
'$e3' => 'float|int',
'$f1' => 'float|int',
'$f2' => 'float|int',
'$f3' => 'float|int',
],
'ignored_issues' => ['InvalidOperand'],
],
];
}

Expand Down

0 comments on commit ab470b4

Please sign in to comment.