+ return childGenerators.iterator();
+ }
+
+ @NonNull S effectiveStatement() {
+ return statement();
+ }
+
+ @Override
+ public final R createRuntimeType() {
+ return generatedType()
+ .map(type -> {
+ final var stmt = effectiveStatement();
+ return createRuntimeType(type, stmt, indexChildren(stmt), augmentRuntimeTypes());
+ })
+ .orElse(null);
+ }
+
+ abstract @NonNull R createRuntimeType(@NonNull GeneratedType type, @NonNull S statement,
+ @NonNull List<RuntimeType> children, @NonNull List<AugmentRuntimeType> augments);
+
+ @Override
+ final R rebaseRuntimeType(final R type, final S statement) {
+ return createRuntimeType(type.javaType(), statement, indexChildren(statement), augmentRuntimeTypes());
+ }
+
+ private @NonNull List<RuntimeType> indexChildren(final @NonNull S statement) {
+ final var childMap = new ArrayList<RuntimeType>();
+
+ for (var stmt : statement.effectiveSubstatements()) {
+ if (stmt instanceof SchemaTreeEffectiveStatement) {
+ final var child = (SchemaTreeEffectiveStatement<?>) stmt;
+ final var qname = child.getIdentifier();
+
+ // Note: getOriginal() is needed for augments of cases
+ @SuppressWarnings("rawtypes")
+ final AbstractExplicitGenerator childGen = getOriginal().resolveRuntimeChild(statement.argument(),
+ qname);
+ @SuppressWarnings("unchecked")
+ final Optional<RuntimeType> rt = childGen.runtimeTypeOf(child);
+ rt.ifPresent(childMap::add);
+ }
+ }
+
+ return childMap;
+ }
+
+ private @NonNull AbstractExplicitGenerator<?, ?> resolveRuntimeChild(final Object parentArg, final QName qname) {
+ final var exact = findSchemaTreeGenerator(qname);
+ if (exact != null) {
+ return exact;
+ }
+
+ // TODO: this is quite hacky: what we are trying to do is rebase the lookup QName to parent QName, as the only
+ // way we should be arriving here is through uses -> grouping squash
+ verify(parentArg instanceof QName, "Cannot deal with parent argument %s", parentArg);
+ final var namespace = ((QName) parentArg).getModule();
+
+ verify(namespace.equals(qname.getModule()), "Cannot deal with %s in namespace %s", qname, namespace);
+ final var local = qname.bindTo(getQName().getModule());
+ return verifyNotNull(findSchemaTreeGenerator(local), "Failed to find %s as %s in %s", qname, local, this);
+ }
+
+ final @NonNull List<AbstractAugmentGenerator> augments() {
+ return augments;
+ }
+
+ private @NonNull List<AugmentRuntimeType> augmentRuntimeTypes() {
+ // Augments are attached to original instance: at least CaseGenerator is instantiated in non-original place
+ // and thus we need to go back to original
+ return getOriginal().augments.stream()
+ .map(AbstractAugmentGenerator::runtimeType)
+ .filter(Optional::isPresent)
+ .map(Optional::orElseThrow)
+ .collect(ImmutableList.toImmutableList());