Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prohibit call array_diff for arrays that have shapes and tuples inside #1245

Merged
merged 2 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions compiler/pipes/final-check.cpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
// Compiler for PHP (aka KPHP)
// Copyright (c) 2020 LLC «V Kontakte»
// Copyright (c) 2025 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#include "compiler/pipes/final-check.h"


#include "common/termformat/termformat.h"
#include "common/algorithms/string-algorithms.h"
#include "common/algorithms/contains.h"

#include "common/algorithms/find.h"
#include "common/algorithms/string-algorithms.h"
#include "common/termformat/termformat.h"
#include "compiler/compiler-core.h"
#include "compiler/data/kphp-json-tags.h"
#include "compiler/data/kphp-tracing-tags.h"
#include "compiler/data/src-file.h"
#include "compiler/data/var-data.h"
#include "compiler/inferring/primitive-type.h"
#include "compiler/vertex-util.h"
#include "compiler/kphp_assert.h"
#include "compiler/type-hint.h"
#include "compiler/phpdoc.h"
#include "compiler/vertex-util.h"

namespace {
void check_class_immutableness(ClassPtr klass) {
Expand Down Expand Up @@ -899,6 +897,17 @@ void FinalCheckPass::check_op_func_call(VertexAdaptor<op_func_call> call) {
kphp_error(vk::none_of_equal(elem_type->ptype(), tp_Class, tp_tuple, tp_shape),
fmt_format("{} is not comparable and cannot be sorted", elem_type->as_human_readable()));
}

// TODO: get rid of this when rewrite array_diff_impl with some hash set container
if (vk::any_of_equal(function_name, "array_diff")) {
// Forbid arrays with elements that would be rejected by key projection function.
for (const auto arg: call->args()) {
const TypeData *array_type = tinf::get_type(arg);
const auto *elem_type = array_type->lookup_at_any_key();
kphp_error(vk::none_of_equal(elem_type->ptype(), tp_tuple, tp_shape),
fmt_format("{} in {}() is not supported", elem_type->as_human_readable(), function_name));
}
}
}

check_func_call_params(call);
Expand Down
6 changes: 3 additions & 3 deletions runtime-common/stdlib/array/array-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ auto transform_to_vector(const array<T> &a, const F &op) noexcept {
}

template<class T, class T1, class Proj>
array<T> array_diff(const array<T> &a1, const array<T1> &a2, const Proj &projector) noexcept {
array<T> array_diff(const array<T> &a1, const array<T1> &a2, const Proj &key_projector) noexcept {
array<T> result(a1.size());

array<int64_t> values{array_size{a2.count(), false}};

for (const auto &it : a2) {
values.set_value(projector(it.get_value()), 1);
values.set_value(key_projector(it.get_value()), 1);
}

for (const auto &it : a1) {
if (!values.has_key(projector(it.get_value()))) {
if (!values.has_key(key_projector(it.get_value()))) {
result.set_value(it);
}
}
Expand Down
10 changes: 10 additions & 0 deletions tests/phpt/shapes/107_array_diff_1.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@kphp_should_fail
/shape\(bar:int, foo:int\) in array_diff\(\) is not supported/
<?php

function test_array_diff() {
$arr = [shape(["foo" => 1, "bar" => 2])];
$x = array_diff($arr, $arr);
}

test_array_diff();
10 changes: 10 additions & 0 deletions tests/phpt/shapes/107_array_diff_2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@kphp_should_fail
/shape\(bar:int, foo:int\) in array_diff\(\) is not supported/
<?php

function test_array_diff() {
$arr = [shape(["foo" => 1, "bar" => 2])];
$x = array_diff([["foo" => 1, "bar" => 2]], $arr);
}

test_array_diff();
10 changes: 10 additions & 0 deletions tests/phpt/tup/112_array_diff_1.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@kphp_should_fail
/tuple\(int, int\) in array_diff\(\) is not supported/
<?php

function test_array_diff() {
$arr = [tuple(1, 2)];
$x = array_diff($arr, $arr);
}

test_array_diff();
10 changes: 10 additions & 0 deletions tests/phpt/tup/112_array_diff_2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@kphp_should_fail
/tuple\(int, int\) in array_diff\(\) is not supported/
<?php

function test_array_diff() {
$arr = [tuple(1, 2)];
$x = array_diff([[1, 2]], $arr);
}

test_array_diff();
Loading