diff --git a/src/Expr.cc b/src/Expr.cc index ee6a7b6abc..da8d958c12 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -1897,19 +1897,18 @@ CondExpr::CondExpr(ExprPtr arg_op1, ExprPtr arg_op2, ExprPtr arg_op3) else { TypeTag bt2 = op2->GetType()->Tag(); - - if ( is_vector(op2) ) - bt2 = op2->GetType()->AsVectorType()->Yield()->Tag(); - TypeTag bt3 = op3->GetType()->Tag(); - if ( IsVector(bt3) ) - bt3 = op3->GetType()->AsVectorType()->Yield()->Tag(); - - if ( is_vector(op1) && ! (is_vector(op2) && is_vector(op3)) ) + if ( is_vector(op1) ) { - ExprError("vector conditional requires vector alternatives"); - return; + if ( ! (is_vector(op2) && is_vector(op3)) ) + { + ExprError("vector conditional requires vector alternatives"); + return; + } + + bt2 = op2->GetType()->AsVectorType()->Yield()->Tag(); + bt3 = op3->GetType()->AsVectorType()->Yield()->Tag(); } if ( BothArithmetic(bt2, bt3) ) @@ -1920,7 +1919,7 @@ CondExpr::CondExpr(ExprPtr arg_op1, ExprPtr arg_op2, ExprPtr arg_op3) if ( bt3 != t ) op3 = zeek::make_intrusive(std::move(op3), t); - if ( is_vector(op2) ) + if ( is_vector(op1) ) SetType(zeek::make_intrusive(base_type(t))); else SetType(base_type(t)); @@ -1931,10 +1930,42 @@ CondExpr::CondExpr(ExprPtr arg_op1, ExprPtr arg_op2, ExprPtr arg_op3) else { - if ( IsRecord(bt2) && IsRecord(bt3) && - ! same_type(op2->GetType(), op3->GetType()) ) + if ( is_vector(op1) ) + { + ExprError("vector conditional type clash between alternatives"); + return; + } + + if ( bt2 == zeek::TYPE_TABLE ) + { + auto tt2 = op2->GetType(); + auto tt3 = op3->GetType(); + + if ( tt2->IsUnspecifiedTable() ) + op2 = make_intrusive(std::move(op2), std::move(tt3)); + else if( tt3->IsUnspecifiedTable() ) + op3 = make_intrusive(std::move(op3), std::move(tt2)); + else if ( ! same_type(op2->GetType(), op3->GetType()) ) + ExprError("operands must be of the same type"); + } + else if ( bt2 == zeek::TYPE_VECTOR ) + { + auto vt2 = op2->GetType(); + auto vt3 = op3->GetType(); + + if ( vt2->IsUnspecifiedVector() ) + op2 = make_intrusive(std::move(op2), std::move(vt3)); + else if( vt3->IsUnspecifiedVector() ) + op3 = make_intrusive(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"); - else + + if ( ! IsError() ) SetType(op2->GetType()); } } diff --git a/testing/btest/Baseline/language.conditional-expression/out b/testing/btest/Baseline/language.conditional-expression/out index 0dcbdbd7c7..035a1ba771 100644 --- a/testing/btest/Baseline/language.conditional-expression/out +++ b/testing/btest/Baseline/language.conditional-expression/out @@ -5,3 +5,10 @@ false condition (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 diff --git a/testing/btest/Baseline/language.ternary-record-mismatch/out b/testing/btest/Baseline/language.ternary-record-mismatch/out deleted file mode 100644 index 91a3aa2e02..0000000000 --- a/testing/btest/Baseline/language.ternary-record-mismatch/out +++ /dev/null @@ -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]) diff --git a/testing/btest/Baseline/language.ternary-type-check/out b/testing/btest/Baseline/language.ternary-type-check/out new file mode 100644 index 0000000000..ba5bff19e9 --- /dev/null +++ b/testing/btest/Baseline/language.ternary-type-check/out @@ -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) diff --git a/testing/btest/language/conditional-expression.zeek b/testing/btest/language/conditional-expression.zeek index 43c5d12a83..a31a8ce063 100644 --- a/testing/btest/language/conditional-expression.zeek +++ b/testing/btest/language/conditional-expression.zeek @@ -2,9 +2,9 @@ # @TEST-EXEC: btest-diff out function test_case(msg: string, expect: bool) - { - print fmt("%s (%s)", msg, expect ? "PASS" : "FAIL"); - } + { + print fmt("%s (%s)", msg, expect ? "PASS" : "FAIL"); + } global ct: count; @@ -20,9 +20,8 @@ function f2(): bool return F; } - event zeek_init() -{ + { local a: count; local b: count; local res: count; @@ -62,5 +61,29 @@ event zeek_init() (T ? f1() : T) ? f1() : f2(); 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); + } diff --git a/testing/btest/language/ternary-record-mismatch.zeek b/testing/btest/language/ternary-record-mismatch.zeek deleted file mode 100644 index 1b9796a799..0000000000 --- a/testing/btest/language/ternary-record-mismatch.zeek +++ /dev/null @@ -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; - } diff --git a/testing/btest/language/ternary-type-check.zeek b/testing/btest/language/ternary-type-check.zeek new file mode 100644 index 0000000000..de3304bd81 --- /dev/null +++ b/testing/btest/language/ternary-type-check.zeek @@ -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; + } diff --git a/testing/btest/scripts/base/utils/exec.test b/testing/btest/scripts/base/utils/exec.test index 87c4368bac..80a98c8285 100644 --- a/testing/btest/scripts/base/utils/exec.test +++ b/testing/btest/scripts/base/utils/exec.test @@ -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", label, result$exit_code, result$signal_exit, - result?$stdout ? result$stdout : "", - result?$stderr ? result$stderr : "", + result?$stdout ? cat(result$stdout) : "", + result?$stderr ? cat(result$stderr) : "", file_content); check_exit_condition();