def get_custom_annotations_recursive(data_type):
<EOL>data_types_seen = set()<EOL>def recurse(data_type):<EOL><INDENT>if data_type in data_types_seen:<EOL><INDENT>return<EOL><DEDENT>data_types_seen.add(data_type)<EOL>dt, _, _ = unwrap(data_type)<EOL>if is_struct_type(dt) or is_union_type(dt):<EOL><INDENT>for field in dt.fields:<EOL><INDENT>for annotation in recurse(field.data_type):<EOL><INDENT>yield annotation<EOL><DEDENT>for annotation in field.custom_annotations:<EOL><INDENT>yield annotation<EOL><DEDENT><DEDENT><DEDENT>elif is_list_type(dt):<EOL><INDENT>for annotation in recurse(dt.data_type):<EOL><INDENT>yield annotation<EOL><DEDENT><DEDENT>elif is_map_type(dt):<EOL><INDENT>for annotation in recurse(dt.value_data_type):<EOL><INDENT>yield annotation<EOL><DEDENT><DEDENT>for annotation in get_custom_annotations_for_alias(data_type):<EOL><INDENT>yield annotation<EOL><DEDENT><DEDENT>return recurse(data_type)<EOL>
Given a Stone data type, returns all custom annotations applied to any of
its memebers, as well as submembers, ..., to an arbitrary depth.