mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
GH-926: Improve type-checking for ternary conditional operator
This commit is contained in:
parent
9f802b2a4d
commit
3bc5309e9e
8 changed files with 146 additions and 39 deletions
55
src/Expr.cc
55
src/Expr.cc
|
@ -1897,21 +1897,20 @@ CondExpr::CondExpr(ExprPtr arg_op1, ExprPtr arg_op2, ExprPtr arg_op3)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TypeTag bt2 = op2->GetType()->Tag();
|
TypeTag bt2 = op2->GetType()->Tag();
|
||||||
|
|
||||||
if ( is_vector(op2) )
|
|
||||||
bt2 = op2->GetType()->AsVectorType()->Yield()->Tag();
|
|
||||||
|
|
||||||
TypeTag bt3 = op3->GetType()->Tag();
|
TypeTag bt3 = op3->GetType()->Tag();
|
||||||
|
|
||||||
if ( IsVector(bt3) )
|
if ( is_vector(op1) )
|
||||||
bt3 = op3->GetType()->AsVectorType()->Yield()->Tag();
|
{
|
||||||
|
if ( ! (is_vector(op2) && is_vector(op3)) )
|
||||||
if ( is_vector(op1) && ! (is_vector(op2) && is_vector(op3)) )
|
|
||||||
{
|
{
|
||||||
ExprError("vector conditional requires vector alternatives");
|
ExprError("vector conditional requires vector alternatives");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bt2 = op2->GetType()->AsVectorType()->Yield()->Tag();
|
||||||
|
bt3 = op3->GetType()->AsVectorType()->Yield()->Tag();
|
||||||
|
}
|
||||||
|
|
||||||
if ( BothArithmetic(bt2, bt3) )
|
if ( BothArithmetic(bt2, bt3) )
|
||||||
{
|
{
|
||||||
TypeTag t = max_type(bt2, bt3);
|
TypeTag t = max_type(bt2, bt3);
|
||||||
|
@ -1920,7 +1919,7 @@ CondExpr::CondExpr(ExprPtr arg_op1, ExprPtr arg_op2, ExprPtr arg_op3)
|
||||||
if ( bt3 != t )
|
if ( bt3 != t )
|
||||||
op3 = zeek::make_intrusive<ArithCoerceExpr>(std::move(op3), t);
|
op3 = zeek::make_intrusive<ArithCoerceExpr>(std::move(op3), t);
|
||||||
|
|
||||||
if ( is_vector(op2) )
|
if ( is_vector(op1) )
|
||||||
SetType(zeek::make_intrusive<zeek::VectorType>(base_type(t)));
|
SetType(zeek::make_intrusive<zeek::VectorType>(base_type(t)));
|
||||||
else
|
else
|
||||||
SetType(base_type(t));
|
SetType(base_type(t));
|
||||||
|
@ -1931,10 +1930,42 @@ CondExpr::CondExpr(ExprPtr arg_op1, ExprPtr arg_op2, ExprPtr arg_op3)
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( IsRecord(bt2) && IsRecord(bt3) &&
|
if ( is_vector(op1) )
|
||||||
! same_type(op2->GetType(), op3->GetType()) )
|
{
|
||||||
|
ExprError("vector conditional type clash between alternatives");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bt2 == zeek::TYPE_TABLE )
|
||||||
|
{
|
||||||
|
auto tt2 = op2->GetType<TableType>();
|
||||||
|
auto tt3 = op3->GetType<TableType>();
|
||||||
|
|
||||||
|
if ( tt2->IsUnspecifiedTable() )
|
||||||
|
op2 = make_intrusive<TableCoerceExpr>(std::move(op2), std::move(tt3));
|
||||||
|
else if( tt3->IsUnspecifiedTable() )
|
||||||
|
op3 = make_intrusive<TableCoerceExpr>(std::move(op3), std::move(tt2));
|
||||||
|
else if ( ! same_type(op2->GetType(), op3->GetType()) )
|
||||||
ExprError("operands must be of the same type");
|
ExprError("operands must be of the same type");
|
||||||
else
|
}
|
||||||
|
else if ( bt2 == zeek::TYPE_VECTOR )
|
||||||
|
{
|
||||||
|
auto vt2 = op2->GetType<VectorType>();
|
||||||
|
auto vt3 = op3->GetType<VectorType>();
|
||||||
|
|
||||||
|
if ( vt2->IsUnspecifiedVector() )
|
||||||
|
op2 = make_intrusive<VectorCoerceExpr>(std::move(op2), std::move(vt3));
|
||||||
|
else if( vt3->IsUnspecifiedVector() )
|
||||||
|
op3 = make_intrusive<VectorCoerceExpr>(std::move(op3), std::move(vt2));
|
||||||
|
else if ( ! same_type(op2->GetType(), op3->GetType()) )
|
||||||
|
ExprError("operands must be of the same type");
|
||||||
|
}
|
||||||
|
else if ( ! same_type(op2->GetType(), op3->GetType()) )
|
||||||
|
// Records could potentially also coerce, but may have some cases
|
||||||
|
// where the coercion direction is ambiguous.
|
||||||
|
ExprError("operands must be of the same type");
|
||||||
|
|
||||||
|
if ( ! IsError() )
|
||||||
SetType(op2->GetType());
|
SetType(op2->GetType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,3 +5,10 @@ false condition (PASS)
|
||||||
associativity (PASS)
|
associativity (PASS)
|
||||||
associativity (PASS)
|
associativity (PASS)
|
||||||
associativity (PASS)
|
associativity (PASS)
|
||||||
|
0, set[string]
|
||||||
|
0, set[string]
|
||||||
|
0, table[count] of string
|
||||||
|
0, table[count] of string
|
||||||
|
0, vector of string
|
||||||
|
0, vector of string
|
||||||
|
[1, 5, 3], vector of count
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
error in /Users/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-record-mismatch/ternary-record-mismatch.zeek, lines 13-14: operands must be of the same type ((F) ? (coerce [$a=a string, $b=6] to MyRecord) : [$a=a different string, $b=7])
|
|
9
testing/btest/Baseline/language.ternary-type-check/out
Normal file
9
testing/btest/Baseline/language.ternary-type-check/out
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, lines 13-14: operands must be of the same type ((F) ? (coerce [$a=a string, $b=6] to MyRecord) : [$a=a different string, $b=7])
|
||||||
|
warning in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, line 18: Wrong number of arguments for function. Expected 1, got 2. (function(y:count; x:count;) : bool)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, line 32: operands must be of the same type (b < a ? foo : bar)
|
||||||
|
warning in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, line 21: Wrong number of arguments for function. Expected 2, got 1. (function(y:count;) : bool)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, line 35: operands must be of the same type (b < a ? bar : foo)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, line 50: operands must be of the same type (T ? s : ss)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, line 51: operands must be of the same type (T ? t : tt)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, line 52: operands must be of the same type (T ? v : vv)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ternary-type-check/ternary-type-check.zeek, line 53: operands must be of the same type (T ? v : s)
|
|
@ -20,7 +20,6 @@ function f2(): bool
|
||||||
return F;
|
return F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
event zeek_init()
|
event zeek_init()
|
||||||
{
|
{
|
||||||
local a: count;
|
local a: count;
|
||||||
|
@ -62,5 +61,29 @@ event zeek_init()
|
||||||
(T ? f1() : T) ? f1() : f2();
|
(T ? f1() : T) ? f1() : f2();
|
||||||
test_case( "associativity", ct == 2 );
|
test_case( "associativity", ct == 2 );
|
||||||
|
|
||||||
}
|
# Test for unspecified set coercion
|
||||||
|
local s: set[string] = { "one", "two", "three" };
|
||||||
|
local sT = T ? set() : s;
|
||||||
|
local sF = F ? s : set();
|
||||||
|
print |sT|, type_name(sT);
|
||||||
|
print |sF|, type_name(sF);
|
||||||
|
|
||||||
|
# Test for unspecified table coercion
|
||||||
|
local t: table[count] of string = { [1] = "one", [2] = "two", [3] = "three" };
|
||||||
|
local tT = T ? table() : t;
|
||||||
|
local tF = F ? t : table();
|
||||||
|
print |tT|, type_name(tT);
|
||||||
|
print |tF|, type_name(tF);
|
||||||
|
|
||||||
|
# Test for unspecified vector coercion
|
||||||
|
local v: vector of string = { "one", "two", "three" };
|
||||||
|
local vT = T ? vector() : v;
|
||||||
|
local vF = F ? v : vector();
|
||||||
|
print |vT|, type_name(vT);
|
||||||
|
print |vF|, type_name(vF);
|
||||||
|
|
||||||
|
# Test for ternary vector condition
|
||||||
|
local tvc = vector(T, F, T);
|
||||||
|
local tvr = tvc ? vector(1, 2, 3) : vector(4, 5, 6);
|
||||||
|
print tvr, type_name(tvr);
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
# @TEST-EXEC-FAIL: zeek -b %INPUT >out 2>&1
|
|
||||||
# @TEST-EXEC: TEST_DIFF_CANONIFIER="$SCRIPTS/diff-remove-abspath" btest-diff out
|
|
||||||
|
|
||||||
type MyRecord: record {
|
|
||||||
a: string;
|
|
||||||
b: count;
|
|
||||||
c: bool &default = T;
|
|
||||||
};
|
|
||||||
|
|
||||||
event zeek_init()
|
|
||||||
{
|
|
||||||
local rec: MyRecord = record($a = "a string", $b = 6);
|
|
||||||
local rec2: MyRecord = (F) ? MyRecord($a = "a string", $b = 6) :
|
|
||||||
record($a = "a different string", $b = 7);
|
|
||||||
rec2$c = F;
|
|
||||||
}
|
|
54
testing/btest/language/ternary-type-check.zeek
Normal file
54
testing/btest/language/ternary-type-check.zeek
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# @TEST-EXEC-FAIL: zeek -b %INPUT >out 2>&1
|
||||||
|
# @TEST-EXEC: TEST_DIFF_CANONIFIER="$SCRIPTS/diff-remove-abspath" btest-diff out
|
||||||
|
|
||||||
|
type MyRecord: record {
|
||||||
|
a: string;
|
||||||
|
b: count;
|
||||||
|
c: bool &default = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
local rec: MyRecord = record($a = "a string", $b = 6);
|
||||||
|
local rec2: MyRecord = (F) ? MyRecord($a = "a string", $b = 6) :
|
||||||
|
record($a = "a different string", $b = 7);
|
||||||
|
rec2$c = F;
|
||||||
|
}
|
||||||
|
|
||||||
|
function foo(y: count, x: count): bool
|
||||||
|
{ return F; }
|
||||||
|
|
||||||
|
function bar(y: count): bool
|
||||||
|
{ return F; }
|
||||||
|
|
||||||
|
function qux(a: count, b: count): bool
|
||||||
|
{ return T; }
|
||||||
|
|
||||||
|
function myfunc(a: count, b: count)
|
||||||
|
{
|
||||||
|
local f = a > b ? foo : qux;
|
||||||
|
print f(5, 7);
|
||||||
|
|
||||||
|
local ff = a > b ? foo : bar;
|
||||||
|
print ff(5, 7);
|
||||||
|
|
||||||
|
local fff = a > b ? bar : foo;
|
||||||
|
print fff(5, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ternaries()
|
||||||
|
{
|
||||||
|
local s: set[string] = { "one" };
|
||||||
|
local ss: set[count] = { 1 };
|
||||||
|
local t: table[count] of string = { [1] = "one" };
|
||||||
|
local tt: table[count] of int = { [1] = -1 };
|
||||||
|
local v: vector of string = { "one" };
|
||||||
|
local vv: vector of count = { 111 };
|
||||||
|
print T ? s : s;
|
||||||
|
print T ? t : t;
|
||||||
|
print T ? v : v;
|
||||||
|
print T ? s : ss;
|
||||||
|
print T ? t : tt;
|
||||||
|
print T ? v : vv;
|
||||||
|
print T ? v : s;
|
||||||
|
}
|
|
@ -39,8 +39,8 @@ function test_cmd(label: string, cmd: Exec::Command)
|
||||||
|
|
||||||
print fmt("%s - exit: %s, signal: %s, stdout: %s, stderr: %s, files: %s",
|
print fmt("%s - exit: %s, signal: %s, stdout: %s, stderr: %s, files: %s",
|
||||||
label, result$exit_code, result$signal_exit,
|
label, result$exit_code, result$signal_exit,
|
||||||
result?$stdout ? result$stdout : "",
|
result?$stdout ? cat(result$stdout) : "",
|
||||||
result?$stderr ? result$stderr : "",
|
result?$stderr ? cat(result$stderr) : "",
|
||||||
file_content);
|
file_content);
|
||||||
|
|
||||||
check_exit_condition();
|
check_exit_condition();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue