factoring and re-working of type merging

This commit is contained in:
Vern Paxson 2022-03-11 14:22:42 -08:00 committed by Tim Wojtulewicz
parent 0bbbd84c9d
commit 9b6a3e8b74

View file

@ -2233,47 +2233,14 @@ TypeTag max_type(TypeTag t1, TypeTag t2)
} }
} }
TypePtr merge_types(const TypePtr& arg_t1, const TypePtr& arg_t2) TypePtr merge_enum_types(const Type* t1, const Type* t2)
{
auto t1 = arg_t1.get();
auto t2 = arg_t2.get();
t1 = flatten_type(t1);
t2 = flatten_type(t2);
TypeTag tg1 = t1->Tag();
TypeTag tg2 = t2->Tag();
if ( BothArithmetic(tg1, tg2) )
return base_type(max_type(tg1, tg2));
if ( tg1 != tg2 )
{
t1->Error("incompatible types", t2);
return nullptr;
}
switch ( tg1 )
{
case TYPE_TIME:
case TYPE_INTERVAL:
case TYPE_STRING:
case TYPE_PATTERN:
case TYPE_PORT:
case TYPE_ADDR:
case TYPE_SUBNET:
case TYPE_BOOL:
case TYPE_ANY:
case TYPE_ERROR:
return base_type(tg1);
case TYPE_ENUM:
{ {
// Could compare pointers t1 == t2, but maybe there's someone out // Could compare pointers t1 == t2, but maybe there's someone out
// there creating clones of the type, so safer to compare name. // there creating clones of the type, so safer to compare name.
if ( t1->GetName() != t2->GetName() ) if ( t1->GetName() != t2->GetName() )
{ {
std::string msg = util::fmt("incompatible enum types: '%s' and '%s'", std::string msg = util::fmt("incompatible enum types: '%s' and '%s'", t1->GetName().data(),
t1->GetName().data(), t2->GetName().data()); t2->GetName().data());
t1->Error(msg.data(), t2); t1->Error(msg.data(), t2);
return nullptr; return nullptr;
@ -2293,13 +2260,12 @@ TypePtr merge_types(const TypePtr& arg_t1, const TypePtr& arg_t2)
std::string msg = util::fmt("incompatible enum types: '%s' and '%s'" std::string msg = util::fmt("incompatible enum types: '%s' and '%s'"
" ('%s' enum type ID is invalid)", " ('%s' enum type ID is invalid)",
t1->GetName().data(), t2->GetName().data(), t1->GetName().data(), t2->GetName().data(), t1->GetName().data());
t1->GetName().data());
t1->Error(msg.data(), t2); t1->Error(msg.data(), t2);
return nullptr; return nullptr;
} }
case TYPE_TABLE: TypePtr merge_table_types(const Type* t1, const Type* t2)
{ {
const IndexType* it1 = (const IndexType*)t1; const IndexType* it1 = (const IndexType*)t1;
const IndexType* it2 = (const IndexType*)t2; const IndexType* it2 = (const IndexType*)t2;
@ -2348,7 +2314,7 @@ TypePtr merge_types(const TypePtr& arg_t1, const TypePtr& arg_t2)
return make_intrusive<TableType>(std::move(tl3), std::move(y3)); return make_intrusive<TableType>(std::move(tl3), std::move(y3));
} }
case TYPE_FUNC: TypePtr merge_func_types(const Type* t1, const Type* t2)
{ {
if ( ! same_type(t1, t2) ) if ( ! same_type(t1, t2) )
{ {
@ -2364,21 +2330,35 @@ TypePtr merge_types(const TypePtr& arg_t1, const TypePtr& arg_t2)
return make_intrusive<FuncType>(std::move(args), std::move(yield), ft1->Flavor()); return make_intrusive<FuncType>(std::move(args), std::move(yield), ft1->Flavor());
} }
case TYPE_RECORD: TypePtr merge_record_types(const Type* t1, const Type* t2)
{ {
const RecordType* rt1 = (const RecordType*)t1; const RecordType* rt1 = (const RecordType*)t1;
const RecordType* rt2 = (const RecordType*)t2; const RecordType* rt2 = (const RecordType*)t2;
if ( rt1->NumFields() != rt2->NumFields() ) // We allow the records to have different numbers of fields.
return nullptr; // We first go through all of the fields in rt1, and then we
// check for whether rt2 has any additional fields.
type_decl_list* tdl3 = new type_decl_list(rt1->NumFields()); type_decl_list* tdl3 = new type_decl_list();
for ( int i = 0; i < rt1->NumFields(); ++i ) for ( int i = 0; i < rt1->NumFields(); ++i )
{ {
const TypeDecl* td1 = rt1->FieldDecl(i); auto td1 = rt1->FieldDecl(i);
const TypeDecl* td2 = rt2->FieldDecl(i); auto td2_offset_i = rt2->FieldOffset(rt1->FieldName(i));
auto tdl3_i = merge_types(td1->type, td2->type);
TypePtr tdl3_i;
auto attrs3 = make_intrusive<detail::Attributes>(nullptr, true, false);
if ( td1->attrs )
attrs3->AddAttrs(td1->attrs);
if ( td2_offset_i >= 0 )
{
auto td2 = rt2->FieldDecl(td2_offset_i);
tdl3_i = merge_types(td1->type, td2->type);
if ( td2->attrs )
attrs3->AddAttrs(td2->attrs);
if ( ! util::streq(td1->id, td2->id) || ! tdl3_i ) if ( ! util::streq(td1->id, td2->id) || ! tdl3_i )
{ {
@ -2386,14 +2366,43 @@ TypePtr merge_types(const TypePtr& arg_t1, const TypePtr& arg_t2)
delete tdl3; delete tdl3;
return nullptr; return nullptr;
} }
}
else
{
tdl3_i = td1->type;
attrs3->AddAttr(make_intrusive<detail::Attr>(detail::ATTR_OPTIONAL));
}
tdl3->push_back(new TypeDecl(util::copy_string(td1->id), std::move(tdl3_i))); if ( attrs3->GetAttrs().empty() )
attrs3 = nullptr;
auto td3 = new TypeDecl(util::copy_string(td1->id), std::move(tdl3_i), attrs3);
tdl3->push_back(td3);
}
// Now add in any extras from rt2.
for ( int i = 0; i < rt2->NumFields(); ++i )
{
auto td2 = rt2->FieldDecl(i);
auto td1_offset_i = rt1->FieldOffset(rt2->FieldName(i));
if ( td1_offset_i < 0 )
{
auto attrs3 = make_intrusive<detail::Attributes>(nullptr, true, false);
if ( td2->attrs )
attrs3->AddAttrs(td2->attrs);
attrs3->AddAttr(make_intrusive<detail::Attr>(detail::ATTR_OPTIONAL));
auto td_merge = new TypeDecl(util::copy_string(td2->id), std::move(td2->type), attrs3);
tdl3->push_back(td_merge);
}
} }
return make_intrusive<RecordType>(tdl3); return make_intrusive<RecordType>(tdl3);
} }
case TYPE_LIST: TypePtr merge_list_types(const Type* t1, const Type* t2)
{ {
const TypeList* tl1 = t1->AsTypeList(); const TypeList* tl1 = t1->AsTypeList();
const TypeList* tl2 = t2->AsTypeList(); const TypeList* tl2 = t2->AsTypeList();
@ -2416,17 +2425,6 @@ TypePtr merge_types(const TypePtr& arg_t1, const TypePtr& arg_t2)
return nullptr; return nullptr;
} }
if ( tl1->IsPure() )
{
// We will be expanding the pure list when converting
// the initialization expression into a set of values.
// So the merge type of the list is the type of one
// of the elements, providing they're consistent.
return merge_types(l1[0], l2[0]);
}
// Impure lists - must have the same size and match element
// by element.
if ( l1.size() != l2.size() ) if ( l1.size() != l2.size() )
{ {
tl1->Error("different number of indices", tl2); tl1->Error("different number of indices", tl2);
@ -2441,6 +2439,54 @@ TypePtr merge_types(const TypePtr& arg_t1, const TypePtr& arg_t2)
return tl3; return tl3;
} }
TypePtr merge_types(const TypePtr& arg_t1, const TypePtr& arg_t2)
{
auto t1 = arg_t1.get();
auto t2 = arg_t2.get();
// t1 = flatten_type(t1);
// t2 = flatten_type(t2);
TypeTag tg1 = t1->Tag();
TypeTag tg2 = t2->Tag();
if ( BothArithmetic(tg1, tg2) )
return base_type(max_type(tg1, tg2));
if ( tg1 != tg2 )
{
t1->Error("incompatible types", t2);
return nullptr;
}
switch ( tg1 )
{
case TYPE_TIME:
case TYPE_INTERVAL:
case TYPE_STRING:
case TYPE_PATTERN:
case TYPE_PORT:
case TYPE_ADDR:
case TYPE_SUBNET:
case TYPE_BOOL:
case TYPE_ANY:
case TYPE_ERROR:
return base_type(tg1);
case TYPE_ENUM:
return merge_enum_types(t1, t2);
case TYPE_TABLE:
return merge_table_types(t1, t2);
case TYPE_FUNC:
return merge_func_types(t1, t2);
case TYPE_RECORD:
return merge_record_types(t1, t2);
case TYPE_LIST:
return merge_list_types(t1, t2);
case TYPE_VECTOR: case TYPE_VECTOR:
if ( ! same_type(t1->Yield(), t2->Yield()) ) if ( ! same_type(t1->Yield(), t2->Yield()) )
{ {