type-checking for use of empty table constructors in expressions

This commit is contained in:
Vern Paxson 2022-03-31 19:30:58 -07:00
parent 4d2115ffd3
commit e786ba2fa9
2 changed files with 35 additions and 16 deletions

View file

@ -2682,21 +2682,11 @@ bool AssignExpr::TypeCheck(const AttributesPtr& attrs)
// Some elements in constructor list must not match, see if // Some elements in constructor list must not match, see if
// we can create a new constructor now that the expected type // we can create a new constructor now that the expected type
// of LHS is known and let it do coercions where possible. // of LHS is known and let it do coercions where possible.
SetConstructorExpr* sce = dynamic_cast<SetConstructorExpr*>(op2.get()); auto sce = cast_intrusive<SetConstructorExpr>(op2);
if ( ! sce )
{
ExprError("Failed typecast to SetConstructorExpr");
return false;
}
auto ctor_list = cast_intrusive<ListExpr>(sce->GetOp1()); auto ctor_list = cast_intrusive<ListExpr>(sce->GetOp1());
if ( ! ctor_list ) if ( ! ctor_list )
{ Internal("failed typecast to ListExpr");
ExprError("Failed typecast to ListExpr");
return false;
}
std::unique_ptr<std::vector<AttrPtr>> attr_copy; std::unique_ptr<std::vector<AttrPtr>> attr_copy;
@ -4226,13 +4216,23 @@ RecordValPtr coerce_to_record(RecordTypePtr rt, Val* v, const std::vector<int>&
return val; 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)) : UnaryExpr(EXPR_TABLE_COERCE, std::move(arg_op))
{ {
if ( IsError() ) if ( IsError() )
return; 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 ) if ( GetType()->Tag() != TYPE_TABLE )
ExprError("coercion to non-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 && if ( t->Tag() == TYPE_TABLE && et->Tag() == TYPE_TABLE &&
et->AsTableType()->IsUnspecifiedTable() ) et->AsTableType()->IsUnspecifiedTable() )
return make_intrusive<TableCoerceExpr>(e, IntrusivePtr{NewRef{}, t->AsTableType()}); {
if ( e->Tag() == EXPR_TABLE_CONSTRUCTOR )
{
auto& attrs = cast_intrusive<TableConstructorExpr>(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<TableCoerceExpr>(e, IntrusivePtr{NewRef{}, t->AsTableType()},
false);
}
if ( t->Tag() == TYPE_VECTOR && et->Tag() == TYPE_VECTOR && if ( t->Tag() == TYPE_VECTOR && et->Tag() == TYPE_VECTOR &&
et->AsVectorType()->IsUnspecifiedVector() ) et->AsVectorType()->IsUnspecifiedVector() )

View file

@ -1310,7 +1310,7 @@ extern RecordValPtr coerce_to_record(RecordTypePtr rt, Val* v, const std::vector
class TableCoerceExpr final : public UnaryExpr class TableCoerceExpr final : public UnaryExpr
{ {
public: public:
TableCoerceExpr(ExprPtr op, TableTypePtr r); TableCoerceExpr(ExprPtr op, TableTypePtr r, bool type_check = true);
~TableCoerceExpr() override; ~TableCoerceExpr() override;
// Optimization-related: // Optimization-related: