diff --git a/compiler/pipes/final-check.cpp b/compiler/pipes/final-check.cpp index 91937fa3f1..5461bf12e8 100644 --- a/compiler/pipes/final-check.cpp +++ b/compiler/pipes/final-check.cpp @@ -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) { @@ -899,6 +897,17 @@ void FinalCheckPass::check_op_func_call(VertexAdaptor 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); diff --git a/runtime-common/stdlib/array/array-functions.h b/runtime-common/stdlib/array/array-functions.h index 6ff9812214..28992f58ca 100644 --- a/runtime-common/stdlib/array/array-functions.h +++ b/runtime-common/stdlib/array/array-functions.h @@ -30,17 +30,17 @@ auto transform_to_vector(const array &a, const F &op) noexcept { } template -array array_diff(const array &a1, const array &a2, const Proj &projector) noexcept { +array array_diff(const array &a1, const array &a2, const Proj &key_projector) noexcept { array result(a1.size()); array 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); } } diff --git a/tests/phpt/shapes/107_array_diff_1.php b/tests/phpt/shapes/107_array_diff_1.php new file mode 100644 index 0000000000..2b5adaebd0 --- /dev/null +++ b/tests/phpt/shapes/107_array_diff_1.php @@ -0,0 +1,10 @@ +@kphp_should_fail +/shape\(bar:int, foo:int\) in array_diff\(\) is not supported/ + 1, "bar" => 2])]; + $x = array_diff($arr, $arr); +} + +test_array_diff(); diff --git a/tests/phpt/shapes/107_array_diff_2.php b/tests/phpt/shapes/107_array_diff_2.php new file mode 100644 index 0000000000..f2146dc836 --- /dev/null +++ b/tests/phpt/shapes/107_array_diff_2.php @@ -0,0 +1,10 @@ +@kphp_should_fail +/shape\(bar:int, foo:int\) in array_diff\(\) is not supported/ + 1, "bar" => 2])]; + $x = array_diff([["foo" => 1, "bar" => 2]], $arr); +} + +test_array_diff(); diff --git a/tests/phpt/tup/112_array_diff_1.php b/tests/phpt/tup/112_array_diff_1.php new file mode 100644 index 0000000000..8b592ae214 --- /dev/null +++ b/tests/phpt/tup/112_array_diff_1.php @@ -0,0 +1,10 @@ +@kphp_should_fail +/tuple\(int, int\) in array_diff\(\) is not supported/ +