Merge remote-tracking branch 'origin/topic/timw/159-coerce-counts'

* origin/topic/timw/159-coerce-counts:
  GHI-155: set the type of a vector based on the variable's type, not the value's type
  GH-159: Allow coercion of numeric values into other types
  Allow passing a location to BroObj::Warning and BroObj::Error.
  Add CLion directories to gitignore
  Move #define outside of max_type for clarity
This commit is contained in:
Jon Siwek 2019-06-04 17:53:10 -07:00
commit 43104565a4
15 changed files with 305 additions and 35 deletions

View file

@ -2591,7 +2591,7 @@ bool AssignExpr::TypeCheck(attr_list* attrs)
if ( op2->Tag() == EXPR_LIST )
{
op2 = new VectorConstructorExpr(op2->AsListExpr());
op2 = new VectorConstructorExpr(op2->AsListExpr(), op1->Type());
return true;
}
}
@ -4136,15 +4136,41 @@ RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r)
if ( ! same_type(sup_t_i, sub_t_i) )
{
if ( sup_t_i->Tag() != TYPE_RECORD ||
sub_t_i->Tag() != TYPE_RECORD ||
! record_promotion_compatible(sup_t_i->AsRecordType(),
sub_t_i->AsRecordType()) )
auto is_arithmetic_promotable = [](BroType* sup, BroType* sub) -> bool
{
char buf[512];
safe_snprintf(buf, sizeof(buf),
auto sup_tag = sup->Tag();
auto sub_tag = sub->Tag();
if ( ! BothArithmetic(sup_tag, sub_tag) )
return false;
if ( sub_tag == TYPE_DOUBLE && IsIntegral(sup_tag) )
return false;
if ( sub_tag == TYPE_INT && sup_tag == TYPE_COUNT )
return false;
return true;
};
auto is_record_promotable = [](BroType* sup, BroType* sub) -> bool
{
if ( sup->Tag() != TYPE_RECORD )
return false;
if ( sub->Tag() != TYPE_RECORD )
return false;
return record_promotion_compatible(sup->AsRecordType(),
sub->AsRecordType());
};
if ( ! is_arithmetic_promotable(sup_t_i, sub_t_i) &&
! is_record_promotable(sup_t_i, sub_t_i) )
{
string error_msg = fmt(
"type clash for field \"%s\"", sub_r->FieldName(i));
Error(buf, sub_t_i);
Error(error_msg.c_str(), sub_t_i);
SetError();
break;
}
@ -4162,11 +4188,9 @@ RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r)
{
if ( ! t_r->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) )
{
char buf[512];
safe_snprintf(buf, sizeof(buf),
"non-optional field \"%s\" missing",
t_r->FieldName(i));
Error(buf);
string error_msg = fmt(
"non-optional field \"%s\" missing", t_r->FieldName(i));
Error(error_msg.c_str());
SetError();
break;
}
@ -4254,6 +4278,20 @@ Val* RecordCoerceExpr::Fold(Val* v) const
rhs = new_val;
}
}
else if ( BothArithmetic(rhs_type->Tag(), field_type->Tag()) &&
! same_type(rhs_type, field_type) )
{
if ( Val* new_val = check_and_promote(rhs, field_type, false, op->GetLocationInfo()) )
{
// Don't call unref here on rhs because check_and_promote already called it.
rhs = new_val;
}
else
{
Unref(val);
RuntimeError("Failed type conversion");
}
}
val->Assign(i, rhs);
}