variants for an object. There are two flavors: simple (no
discriminator or base), and flat (both discriminator and base). A union
type is defined using a data dictionary as explained in the following
-paragraphs. The data dictionary for either type of union must not
-be empty.
+paragraphs. Unions must have at least one branch.
A simple union type defines a mapping from automatic discriminator
values to data types like in this example:
# With no discriminator it is a simple union.
if discriminator is None:
- enum_define = None
+ enum_values = members.keys()
allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
if base is not None:
raise QAPISemError(info, "Simple union '%s' must not have a base" %
'must not be conditional' %
(base, discriminator, name))
enum_define = enum_types.get(discriminator_value['type'])
- allow_metas = ['struct']
# Do not allow string discriminator
if not enum_define:
raise QAPISemError(info,
"Discriminator '%s' must be of enumeration "
"type" % discriminator)
+ enum_values = enum_get_names(enum_define)
+ allow_metas = ['struct']
+
+ if (len(enum_values) == 0):
+ raise QAPISemError(info, "Union '%s' has no branches" % name)
- # Check every branch; don't allow an empty union
- if len(members) == 0:
- raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
for (key, value) in members.items():
check_name(info, "Member of union '%s'" % name, key)
# If the discriminator names an enum type, then all members
# of 'data' must also be members of the enum type.
- if enum_define:
- if key not in enum_get_names(enum_define):
+ if discriminator is not None:
+ if key not in enum_values:
raise QAPISemError(info,
"Discriminator value '%s' is not found in "
"enum '%s'"
assert bool(tag_member) != bool(tag_name)
assert (isinstance(tag_name, str) or
isinstance(tag_member, QAPISchemaObjectTypeMember))
- assert len(variants) > 0
for v in variants:
assert isinstance(v, QAPISchemaObjectTypeVariant)
self._tag_name = tag_name
{ 'struct': 'Empty1', 'data': { } }
{ 'struct': 'Empty2', 'base': 'Empty1', 'data': { } }
+# Likewise for an empty flat union
+{ 'union': 'Union',
+ 'base': { 'type': 'EnumOne' }, 'discriminator': 'type',
+ 'data': { } }
+
{ 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' }
# for testing override of default naming heuristic