def set_enumerated_subtypes(self, subtype_fields, is_catch_all):
        """
        Sets the list of "enumerated subtypes" for this struct. This differs
        from regular subtyping in that each subtype is associated with a tag
        that is used in the serialized format to indicate the subtype. Also,
        this list of subtypes was explicitly defined in an "inner-union" in the
        specification. The list of fields must include all defined subtypes of
        this struct.

        NOTE(kelkabany): For this to work with upcoming forward references, the
        hierarchy of parent types for this struct must have had this method
        called on them already.

        :type subtype_fields: List[UnionField]
        """
        assert self._enumerated_subtypes is None, \
            'Enumerated subtypes already set.'
        assert isinstance(is_catch_all, bool), type(is_catch_all)

        self._is_catch_all = is_catch_all
        self._enumerated_subtypes = []

        if self.parent_type:
            raise InvalidSpec(
                "'%s' enumerates subtypes so it cannot extend another struct."
                % self.name, self._ast_node.lineno, self._ast_node.path)

        # Require that if this struct enumerates subtypes, its parent (and thus
        # the entire hierarchy above this struct) does as well.
        if self.parent_type and not self.parent_type.has_enumerated_subtypes():
            raise InvalidSpec(
                "'%s' cannot enumerate subtypes if parent '%s' does not." %
                (self.name, self.parent_type.name),
                self._ast_node.lineno, self._ast_node.path)

        enumerated_subtype_names = set()  # Set[str]
        for subtype_field in subtype_fields:
            path = subtype_field._ast_node.path
            lineno = subtype_field._ast_node.lineno

            # Require that a subtype only has a single type tag.
            if subtype_field.data_type.name in enumerated_subtype_names:
                raise InvalidSpec(
                    "Subtype '%s' can only be specified once." %
                    subtype_field.data_type.name, lineno, path)

            # Require that a subtype has this struct as its parent.
            if subtype_field.data_type.parent_type != self:
                raise InvalidSpec(
                    "'%s' is not a subtype of '%s'." %
                    (subtype_field.data_type.name, self.name), lineno, path)

            # Check for subtype tags that conflict with this struct's
            # non-inherited fields.
            if subtype_field.name in self._fields_by_name:
                # Since the union definition comes first, use its line number
                # as the source of the field's original declaration.
                orig_field = self._fields_by_name[subtype_field.name]
                raise InvalidSpec(
                    "Field '%s' already defined on line %d." %
                    (subtype_field.name, lineno),
                    orig_field._ast_node.lineno,
                    orig_field._ast_node.path)

            # Walk up parent tree hierarchy to ensure no field conflicts.
            # Checks for conflicts with subtype tags and regular fields.
            cur_type = self.parent_type
            while cur_type:
                if subtype_field.name in cur_type._fields_by_name:
                    orig_field = cur_type._fields_by_name[subtype_field.name]
                    raise InvalidSpec(
                        "Field '%s' already defined in parent '%s' (%s:%d)."
                        % (subtype_field.name, cur_type.name,
                           orig_field._ast_node.path, orig_field._ast_node.lineno),
                        lineno, path)
                cur_type = cur_type.parent_type

            # Note the discrepancy between `fields` which contains only the
            # struct fields, and `_fields_by_name` which contains the struct
            # fields and enumerated subtype fields.
            self._fields_by_name[subtype_field.name] = subtype_field
            enumerated_subtype_names.add(subtype_field.data_type.name)
            self._enumerated_subtypes.append(subtype_field)

        assert len(self._enumerated_subtypes) > 0

        # Check that all known subtypes are listed in the enumeration.
        for subtype in self.subtypes:
            if subtype.name not in enumerated_subtype_names:
                raise InvalidSpec(
                    "'%s' does not enumerate all subtypes, missing '%s'" %
                    (self.name, subtype.name),
                    self._ast_node.lineno)
Sets the list of "enumerated subtypes" for this struct. This differs
        from regular subtyping in that each subtype is associated with a tag
        that is used in the serialized format to indicate the subtype. Also,
        this list of subtypes was explicitly defined in an "inner-union" in the
        specification. The list of fields must include all defined subtypes of
        this struct.

        NOTE(kelkabany): For this to work with upcoming forward references, the
        hierarchy of parent types for this struct must have had this method
        called on them already.

        :type subtype_fields: List[UnionField]