Unify type comparisions for records.

For records, same_type(r1, r2) would not check if the fields'
attributes match as well. That seems like an oversight, and some
callers of same_type() did indeed add that check on their end. This
commit moves the check into same_type() itself. That generally doesn't
seem make any differences except for a couple of places validating
code, which we update a bit. That in turn leans to slightly different
(better?) error messages for a couple of test cases.
This commit is contained in:
Robin Sommer 2020-10-04 16:42:44 +00:00
parent a2577891e0
commit d782c60f19
5 changed files with 45 additions and 52 deletions

View file

@ -2168,22 +2168,14 @@ bool AssignExpr::TypeCheck(const AttributesPtr& attrs)
if ( op1->GetType()->IsSet() )
op2 = make_intrusive<SetConstructorExpr>(
cast_intrusive<ListExpr>(op2), std::move(attr_copy));
cast_intrusive<ListExpr>(op2), std::move(attr_copy), op1->GetType());
else
op2 = make_intrusive<TableConstructorExpr>(
cast_intrusive<ListExpr>(op2), std::move(attr_copy));
cast_intrusive<ListExpr>(op2), std::move(attr_copy), op1->GetType());
if ( ! empty_list_assignment && ! same_type(op1->GetType(), op2->GetType()) )
{
if ( op1->GetType()->IsSet() )
ExprError("set type mismatch in assignment");
else
ExprError("table type mismatch in assignment");
return false;
}
return true;
// The constructor expressions are performing the type
// checking and will set op2 to an error state on failure.
return ! op2->IsError();
}
if ( bt1 == TYPE_VECTOR )
@ -2207,21 +2199,7 @@ bool AssignExpr::TypeCheck(const AttributesPtr& attrs)
op2->GetType()->Tag() == TYPE_RECORD )
{
if ( same_type(op1->GetType(), op2->GetType()) )
{
RecordType* rt1 = op1->GetType()->AsRecordType();
RecordType* rt2 = op2->GetType()->AsRecordType();
// Make sure the attributes match as well.
for ( int i = 0; i < rt1->NumFields(); ++i )
{
const TypeDecl* td1 = rt1->FieldDecl(i);
const TypeDecl* td2 = rt2->FieldDecl(i);
if ( same_attrs(td1->attrs.get(), td2->attrs.get()) )
// Everything matches.
return true;
}
}
return true;
// Need to coerce.
op2 = make_intrusive<RecordCoerceExpr>(std::move(op2), op1->GetType<RecordType>());
@ -3195,17 +3173,18 @@ TableConstructorExpr::TableConstructorExpr(ListExprPtr constructor_list,
const auto& indices = type->AsTableType()->GetIndices()->GetTypes();
const ExprPList& cle = op->AsListExpr()->Exprs();
// check and promote all index expressions in ctor list
// check and promote all assign expressions in ctor list
for ( const auto& expr : cle )
{
if ( expr->Tag() != EXPR_ASSIGN )
continue;
Expr* idx_expr = expr->AsAssignExpr()->Op1();
if ( idx_expr->Tag() != EXPR_LIST )
continue;
auto idx_expr = expr->AsAssignExpr()->Op1();
auto val_expr = expr->AsAssignExpr()->Op2();
auto yield_type = GetType()->AsTableType()->Yield().get();
// Promote LHS
assert(idx_expr->Tag() == EXPR_LIST);
ExprPList& idx_exprs = idx_expr->AsListExpr()->Exprs();
if ( idx_exprs.length() != static_cast<int>(indices.size()) )
@ -3229,6 +3208,19 @@ TableConstructorExpr::TableConstructorExpr(ListExprPtr constructor_list,
}
ExprError("inconsistent types in table constructor");
return;
}
// Promote RHS
if ( auto promoted_val = check_and_promote_expr(val_expr, yield_type) )
{
if ( promoted_val != val_expr )
expr->AsAssignExpr()->SetOp2(promoted_val);
}
else
{
ExprError("inconsistent types in table constructor");
return;
}
}
}
@ -3328,8 +3320,8 @@ SetConstructorExpr::SetConstructorExpr(ListExprPtr constructor_list,
Expr* ce = cle[i];
ListExpr* le = ce->AsListExpr();
if ( ce->Tag() == EXPR_LIST &&
check_and_promote_exprs(le, type->AsTableType()->GetIndices().get()) )
assert(ce->Tag() == EXPR_LIST);
if ( check_and_promote_exprs(le, type->AsTableType()->GetIndices().get()) )
{
if ( le != cle[i] )
cle.replace(i, le);
@ -4985,18 +4977,7 @@ ExprPtr check_and_promote_expr(Expr* const e, zeek::Type* t)
RecordType* et_r = et->AsRecordType();
if ( same_type(t, et) )
{
// Make sure the attributes match as well.
for ( int i = 0; i < t_r->NumFields(); ++i )
{
const TypeDecl* td1 = t_r->FieldDecl(i);
const TypeDecl* td2 = et_r->FieldDecl(i);
if ( same_attrs(td1->attrs.get(), td2->attrs.get()) )
// Everything matches perfectly.
return {NewRef{}, e};
}
}
return {NewRef{}, e};
if ( record_promotion_compatible(t_r, et_r) )
return make_intrusive<RecordCoerceExpr>(