From e786ba2fa93d182c69933de61b74f9238d75d4e7 Mon Sep 17 00:00:00 2001 From: Vern Paxson Date: Thu, 31 Mar 2022 19:30:58 -0700 Subject: [PATCH] type-checking for use of empty table constructors in expressions --- src/Expr.cc | 49 ++++++++++++++++++++++++++++++++++--------------- src/Expr.h | 2 +- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/Expr.cc b/src/Expr.cc index 572c615a1a..997c1509e9 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -2682,21 +2682,11 @@ bool AssignExpr::TypeCheck(const AttributesPtr& attrs) // Some elements in constructor list must not match, see if // we can create a new constructor now that the expected type // of LHS is known and let it do coercions where possible. - SetConstructorExpr* sce = dynamic_cast(op2.get()); - - if ( ! sce ) - { - ExprError("Failed typecast to SetConstructorExpr"); - return false; - } - + auto sce = cast_intrusive(op2); auto ctor_list = cast_intrusive(sce->GetOp1()); if ( ! ctor_list ) - { - ExprError("Failed typecast to ListExpr"); - return false; - } + Internal("failed typecast to ListExpr"); std::unique_ptr> attr_copy; @@ -4226,13 +4216,23 @@ RecordValPtr coerce_to_record(RecordTypePtr rt, Val* v, const std::vector& return val; } -TableCoerceExpr::TableCoerceExpr(ExprPtr arg_op, TableTypePtr r) +TableCoerceExpr::TableCoerceExpr(ExprPtr arg_op, TableTypePtr tt, bool type_check) : UnaryExpr(EXPR_TABLE_COERCE, std::move(arg_op)) { if ( IsError() ) return; - SetType(std::move(r)); + if ( type_check ) + { + op = check_and_promote_expr(op, tt); + if ( ! op ) + { + SetError(); + return; + } + } + + SetType(std::move(tt)); if ( GetType()->Tag() != TYPE_TABLE ) ExprError("coercion to non-table"); @@ -5260,7 +5260,26 @@ ExprPtr check_and_promote_expr(ExprPtr e, TypePtr t) { if ( t->Tag() == TYPE_TABLE && et->Tag() == TYPE_TABLE && et->AsTableType()->IsUnspecifiedTable() ) - return make_intrusive(e, IntrusivePtr{NewRef{}, t->AsTableType()}); + { + if ( e->Tag() == EXPR_TABLE_CONSTRUCTOR ) + { + auto& attrs = cast_intrusive(e)->GetAttrs(); + auto& def = attrs ? attrs->Find(ATTR_DEFAULT) : nullptr; + if ( def ) + { + std::string err_msg; + if ( ! check_default_attr(def.get(), t, false, false, err_msg) ) + { + if ( ! err_msg.empty() ) + t->Error(err_msg.c_str(), e.get()); + return nullptr; + } + } + } + + return make_intrusive(e, IntrusivePtr{NewRef{}, t->AsTableType()}, + false); + } if ( t->Tag() == TYPE_VECTOR && et->Tag() == TYPE_VECTOR && et->AsVectorType()->IsUnspecifiedVector() ) diff --git a/src/Expr.h b/src/Expr.h index 7b8c38ff6e..a8b90d42dc 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -1310,7 +1310,7 @@ extern RecordValPtr coerce_to_record(RecordTypePtr rt, Val* v, const std::vector class TableCoerceExpr final : public UnaryExpr { public: - TableCoerceExpr(ExprPtr op, TableTypePtr r); + TableCoerceExpr(ExprPtr op, TableTypePtr r, bool type_check = true); ~TableCoerceExpr() override; // Optimization-related: