diff --git a/src/Type.cc b/src/Type.cc index fec2544e2d..925f46191e 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -902,6 +902,9 @@ public: if ( coerce_type ) v = v->AsRecordVal()->CoerceTo(coerce_type); + else if ( init_type->Tag() == TYPE_VECTOR ) + concretize_if_unspecified(cast_intrusive(v), init_type->Yield()); + return ZVal(v, init_type); } diff --git a/src/Val.cc b/src/Val.cc index cb86351ae2..bd0068daeb 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -1889,45 +1889,56 @@ ValPtr TableVal::Default(const ValPtr& index) { return nullptr; } + ValPtr result; + if ( def_val->GetType()->Tag() != TYPE_FUNC || same_type(def_val->GetType(), GetType()->Yield()) ) { if ( def_attr->GetExpr()->IsConst() ) return def_val; try { - return def_val->Clone(); + result = def_val->Clone(); } catch ( InterpreterException& e ) { /* Already reported. */ } - Error("&default value for table is not clone-able"); - return nullptr; + if ( ! result ) { + Error("&default value for table is not clone-able"); + return nullptr; + } + } + else { + const Func* f = def_val->AsFunc(); + Args vl; + + if ( index->GetType()->Tag() == TYPE_LIST ) { + auto lv = index->AsListVal(); + vl.reserve(lv->Length()); + + for ( const auto& v : lv->Vals() ) + vl.emplace_back(v); + } + else + vl.emplace_back(index); + + try { + result = f->Invoke(&vl); + } + + catch ( InterpreterException& e ) { /* Already reported. */ + } + + if ( ! result ) { + Error("no value returned from &default function"); + return nullptr; + } } - const Func* f = def_val->AsFunc(); - Args vl; - - if ( index->GetType()->Tag() == TYPE_LIST ) { - auto lv = index->AsListVal(); - vl.reserve(lv->Length()); - - for ( const auto& v : lv->Vals() ) - vl.emplace_back(v); - } - else - vl.emplace_back(index); - - ValPtr result; - - try { - result = f->Invoke(&vl); - } - - catch ( InterpreterException& e ) { /* Already reported. */ - } - - if ( ! result ) { - Error("no value returned from &default function"); - return nullptr; - } + auto rt = result->GetType(); + if ( rt->Tag() == TYPE_VECTOR ) + // The double-Yield() here is because this is a "table of vector of X" + // and we want X. If this is instead a "table of any", that'll be + // okay because concretize_if_unspecified() correctly deals with + // nil target types. + detail::concretize_if_unspecified(cast_intrusive(result), GetType()->Yield()->Yield()); return result; } @@ -3474,6 +3485,26 @@ bool VectorVal::Concretize(const TypePtr& t) { return true; } +void detail::concretize_if_unspecified(VectorValPtr v, TypePtr t) { + if ( v->Size() != 0 ) + // Concretization only applies to empty vectors. + return; + + if ( v->GetType()->Yield()->Tag() != TYPE_ANY ) + // It's not an unspecified vector. + return; + + if ( ! t ) + // "t" can be nil if the vector is being assigned to an "any" value. + return; + + if ( t->Tag() == TYPE_ANY ) + // No need to concretize. + return; + + v->Concretize(t); +} + unsigned int VectorVal::ComputeFootprint(std::unordered_set* analyzed_vals) const { auto n = vector_val.size(); unsigned int fp = n; diff --git a/src/Val.h b/src/Val.h index 6318642fd8..7a6bdf0379 100644 --- a/src/Val.h +++ b/src/Val.h @@ -1744,6 +1744,13 @@ namespace detail { // for normalization. If Func::nil is passed, no normalization happens. extern std::variant ValFromJSON(std::string_view json_str, const TypePtr& t, const FuncPtr& key_func); + +// If the given vector is an empty vector-of-any ("unspecified"), +// concretizes it to the given type. *v* gives the vector and *t* the +// type to concretize it to if appropriate. *t* can be nil, in which +// case nothing is done. +extern void concretize_if_unspecified(VectorValPtr v, TypePtr t); + } // namespace detail } // namespace zeek diff --git a/src/script_opt/Reduce.cc b/src/script_opt/Reduce.cc index d45bf0fa1d..7f63a978b7 100644 --- a/src/script_opt/Reduce.cc +++ b/src/script_opt/Reduce.cc @@ -124,6 +124,14 @@ StmtPtr Reducer::GenParam(const IDPtr& id, ExprPtr rhs, bool is_modified) { // the inline block's execution. is_modified = true; + auto& id_t = id->GetType(); + if ( id_t->Tag() == TYPE_VECTOR && rhs->GetType()->Yield() != id_t->Yield() ) + // Presumably either the identifier or the RHS is a vector-of-any. + // This means there will essentially be a modification of the RHS + // due to the need to use (or omit) operations coercing from such + // vectors. + is_modified = true; + if ( ! is_modified ) { // Can use a temporary variable, which then supports // optimization via alias propagation.