schema tree REFACTOR compile case like a general node

Change included - all choice data children are not linked
siblings anymore but standard children of their case.
Fixes #1157
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 566cacc..139ec0e 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -3202,40 +3202,86 @@
  * structures, but they share the namespace so we need to check their name collisions.
  *
  * @param[in] ctx Compile context.
- * @param[in] children List (linked list) of data nodes to go through.
- * @param[in] actions List (sized array) of actions or RPCs to go through.
- * @param[in] notifs List (sized array) of Notifications to go through.
+ * @param[in] parent Parent of the nodes to check, can be NULL.
  * @param[in] name Name of the item to find in the given lists.
- * @param[in] exclude Pointer to an object to exclude from the name checking - for the case that the object
- * with the @p name being checked is already inserted into one of the list so we need to skip it when searching for duplicity.
+ * @param[in] exclude Node that was just added that should be excluded from the name checking.
  * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
  */
 static LY_ERR
-lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *children, const struct lysc_action *actions,
-        const struct lysc_notif *notifs, const char *name, void *exclude)
+lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *parent, const char *name,
+        const struct lysc_node *exclude)
 {
-    const struct lysc_node *iter;
+    const struct lysc_node *iter, *iter2;
+    const struct lysc_action *actions;
+    const struct lysc_notif *notifs;
+    uint32_t getnext_flags;
     LY_ARRAY_COUNT_TYPE u;
 
-    LY_LIST_FOR(children, iter) {
-        if (iter != exclude && iter->module == ctx->mod && !strcmp(name, iter->name)) {
+#define CHECK_NODE(iter, exclude, name) (iter != (void *)exclude && (iter)->module == exclude->module && !strcmp(name, (iter)->name))
+
+    if (exclude->nodetype == LYS_CASE) {
+        /* check restricted only to all the cases */
+        assert(parent->nodetype == LYS_CHOICE);
+        LY_LIST_FOR(lysc_node_children(parent, 0), iter) {
+            if (CHECK_NODE(iter, exclude, name)) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "case");
+                return LY_EEXIST;
+            }
+        }
+
+        return LY_SUCCESS;
+    }
+
+    /* no reason for our parent to be choice anymore */
+    assert(!parent || (parent->nodetype != LYS_CHOICE));
+
+    if (parent && (parent->nodetype == LYS_CASE)) {
+        /* move to the first data definition parent */
+        parent = lysc_data_parent(parent);
+    }
+
+    getnext_flags = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE;
+    if (parent && (parent->nodetype & (LYS_RPC | LYS_ACTION)) && (exclude->flags & LYS_CONFIG_R)) {
+        getnext_flags |= LYS_GETNEXT_OUTPUT;
+    }
+
+    iter = NULL;
+    while ((iter = lys_getnext(iter, parent, ctx->mod->compiled, getnext_flags))) {
+        if (CHECK_NODE(iter, exclude, name)) {
             goto error;
         }
+
+        /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
+        if (iter->nodetype == LYS_CHOICE) {
+            iter2 = NULL;
+            while ((iter2 = lys_getnext(iter2, iter, NULL, LYS_GETNEXT_NOSTATECHECK))) {
+                if (CHECK_NODE(iter2, exclude, name)) {
+                    goto error;
+                }
+            }
+        }
     }
+
+    actions = parent ? lysc_node_actions(parent) : ctx->mod->compiled->rpcs;
     LY_ARRAY_FOR(actions, u) {
-        if (&actions[u] != exclude && actions[u].module == ctx->mod && !strcmp(name, actions[u].name)) {
+        if (CHECK_NODE(&actions[u], exclude, name)) {
             goto error;
         }
     }
+
+    notifs = parent ? lysc_node_notifs(parent) : ctx->mod->compiled->notifs;
     LY_ARRAY_FOR(notifs, u) {
-        if (&notifs[u] != exclude && notifs[u].module == ctx->mod && !strcmp(name, notifs[u].name)) {
+        if (CHECK_NODE(&notifs[u], exclude, name)) {
             goto error;
         }
     }
     return LY_SUCCESS;
+
 error:
     LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "data definition/RPC/action/notification");
     return LY_EEXIST;
+
+#undef CHECK_NODE
 }
 
 static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *parent, uint16_t uses_status);
@@ -3261,12 +3307,12 @@
 
     lysc_update_path(ctx, parent, action_p->name);
 
-    if (lys_compile_node_uniqness(ctx, parent ? lysc_node_children(parent, 0) : ctx->mod->compiled->data,
-                                  parent ? lysc_node_actions(parent) : ctx->mod->compiled->rpcs,
-                                  parent ? lysc_node_notifs(parent) : ctx->mod->compiled->notifs,
-                                  action_p->name, action)) {
-        return LY_EVALID;
-    }
+    /* member needed for uniqueness check lys_getnext() */
+    action->nodetype = parent ? LYS_ACTION : LYS_RPC;
+    action->module = ctx->mod;
+    action->parent = parent;
+
+    LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, action_p->name, (struct lysc_node *)action));
 
     if (ctx->options & (LYSC_OPT_RPC_MASK | LYSC_OPT_NOTIFICATION)) {
         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
@@ -3275,9 +3321,6 @@
         return LY_EVALID;
     }
 
-    action->nodetype = parent ? LYS_ACTION : LYS_RPC;
-    action->module = ctx->mod;
-    action->parent = parent;
     if (!(ctx->options & LYSC_OPT_FREE_SP)) {
         action->sp = action_p;
     }
@@ -3347,12 +3390,12 @@
 
     lysc_update_path(ctx, parent, notif_p->name);
 
-    if (lys_compile_node_uniqness(ctx, parent ? lysc_node_children(parent, 0) : ctx->mod->compiled->data,
-                                  parent ? lysc_node_actions(parent) : ctx->mod->compiled->rpcs,
-                                  parent ? lysc_node_notifs(parent) : ctx->mod->compiled->notifs,
-                                  notif_p->name, notif)) {
-        return LY_EVALID;
-    }
+    /* member needed for uniqueness check lys_getnext() */
+    notif->nodetype = LYS_NOTIF;
+    notif->module = ctx->mod;
+    notif->parent = parent;
+
+    LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, notif_p->name, (struct lysc_node *)notif));
 
     if (ctx->options & (LYSC_OPT_RPC_MASK | LYSC_OPT_NOTIFICATION)) {
         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
@@ -3361,9 +3404,6 @@
         return LY_EVALID;
     }
 
-    notif->nodetype = LYS_NOTIF;
-    notif->module = ctx->mod;
-    notif->parent = parent;
     if (!(ctx->options & LYSC_OPT_FREE_SP)) {
         notif->sp = notif_p;
     }
@@ -3969,7 +4009,49 @@
 }
 
 /**
+ * @brief Compile choice children.
+ *
+ * @param[in] ctx Compile context
+ * @param[in] child_p Parsed choice children nodes.
+ * @param[in] node Compiled choice node to compile and add children to.
+ * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ */
+static LY_ERR
+lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lysp_node *child_next_p;
+    struct lysp_node_case *cs_p;
+
+    if (child_p->nodetype == LYS_CASE) {
+        /* standard case under choice */
+        ret = lys_compile_node(ctx, child_p, node, 0);
+    } else {
+        /* we need the implicit case first, so create a fake parsed case */
+        cs_p = calloc(1, sizeof *cs_p);
+        cs_p->nodetype = LYS_CASE;
+        DUP_STRING(ctx->ctx, child_p->name, cs_p->name);
+        cs_p->child = child_p;
+
+        /* make the child the only case child */
+        child_next_p = child_p->next;
+        child_p->next = NULL;
+
+        /* compile it normally */
+        ret = lys_compile_node(ctx, (struct lysp_node *)cs_p, node, 0);
+
+        /* free the fake parsed node and correct pointers back */
+        cs_p->child = NULL;
+        lysp_node_free(ctx->ctx, (struct lysp_node *)cs_p);
+        child_p->next = child_next_p;
+    }
+
+    return ret;
+}
+
+/**
  * @brief Compile parsed choice node information.
+ *
  * @param[in] ctx Compile context
  * @param[in] node_p Parsed choice node.
  * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
@@ -3981,17 +4063,13 @@
 {
     struct lysp_node_choice *ch_p = (struct lysp_node_choice *)node_p;
     struct lysc_node_choice *ch = (struct lysc_node_choice *)node;
-    struct lysp_node *child_p, *case_child_p;
+    struct lysp_node *child_p;
     LY_ERR ret = LY_SUCCESS;
 
+    assert(node->nodetype == LYS_CHOICE);
+
     LY_LIST_FOR(ch_p->child, child_p) {
-        if (child_p->nodetype == LYS_CASE) {
-            LY_LIST_FOR(((struct lysp_node_case *)child_p)->child, case_child_p) {
-                LY_CHECK_RET(lys_compile_node(ctx, case_child_p, node, 0));
-            }
-        } else {
-            LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0));
-        }
+        LY_CHECK_RET(lys_compile_node_choice_child(ctx, child_p, node));
     }
 
     /* default branch */
@@ -4050,12 +4128,17 @@
     struct lysc_node **children, *start, *end;
     const struct lys_module *mod;
 
-    if (node->nodetype == LYS_CASE) {
-        children = (struct lysc_node **)&((struct lysc_node_choice *)parent)->cases;
-    } else {
-        children = lysc_node_children_p(parent, ctx->options);
-    }
-    if (children) {
+    node->parent = parent;
+
+    if (parent) {
+        if (parent->nodetype == LYS_CHOICE) {
+            assert(node->nodetype == LYS_CASE);
+            children = (struct lysc_node **)&((struct lysc_node_choice *)parent)->cases;
+        } else {
+            children = lysc_node_children_p(parent, ctx->options);
+        }
+        assert(children);
+
         if (!(*children)) {
             /* first child */
             *children = node;
@@ -4090,14 +4173,29 @@
                 node->prev = (*children)->prev;
                 (*children)->prev = node;
             }
+        }
 
-            /* check the name uniqueness */
-            if (lys_compile_node_uniqness(ctx, *children, lysc_node_actions(parent),
-                                          lysc_node_notifs(parent), node->name, node)) {
-                return LY_EEXIST;
-            }
+        /* check the name uniqueness (even for an only child, it may be in case) */
+        if (lys_compile_node_uniqness(ctx, parent, node->name, node)) {
+            return LY_EEXIST;
+        }
+    } else {
+        /* top-level element */
+        if (!ctx->mod->compiled->data) {
+            ctx->mod->compiled->data = node;
+        } else {
+            /* insert at the end of the module's top-level nodes list */
+            ctx->mod->compiled->data->prev->next = node;
+            node->prev = ctx->mod->compiled->data->prev;
+            ctx->mod->compiled->data->prev = node;
+        }
+
+        /* check the name uniqueness on top-level */
+        if (lys_compile_node_uniqness(ctx, NULL, node->name, node)) {
+            return LY_EEXIST;
         }
     }
+
     return LY_SUCCESS;
 }
 
@@ -4115,78 +4213,24 @@
  * @return The case structure where the child node belongs to, NULL in case of error. Note that the child is not connected into the siblings list,
  * it is linked from the case structure only in case it is its first child.
  */
-static struct lysc_node_case *
-lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node_choice *ch, struct lysc_node *child)
+static LY_ERR
+lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *node)
 {
-    struct lysc_node *iter;
-    struct lysc_node_case *cs = NULL;
-    struct lysc_when **when;
-    LY_ARRAY_COUNT_TYPE u;
-    LY_ERR ret;
-
-#define UNIQUE_CHECK(NAME, MOD) \
-    LY_LIST_FOR((struct lysc_node*)ch->cases, iter) { \
-        if (iter->module == MOD && !strcmp(iter->name, NAME)) { \
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, NAME, "case"); \
-            return NULL; \
-        } \
-    }
+    struct lysp_node *child_p;
+    struct lysp_node_case *cs_p = (struct lysp_node_case *)node_p;
 
     if (node_p->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
-        UNIQUE_CHECK(child->name, ctx->mod);
-
         /* we have to add an implicit case node into the parent choice */
-        cs = calloc(1, sizeof(struct lysc_node_case));
-        DUP_STRING(ctx->ctx, child->name, cs->name);
-        cs->parent = (struct lysc_node *)ch;
-        cs->flags = ch->flags & LYS_STATUS_MASK;
     } else if (node_p->nodetype == LYS_CASE) {
-        if (ch->cases && (node_p == ch->cases->prev->sp)) {
-            /* the case is already present since the child is not its first children */
-            return (struct lysc_node_case *)ch->cases->prev;
+        /* explicit parent case */
+        LY_LIST_FOR(cs_p->child, child_p) {
+            LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0));
         }
-        UNIQUE_CHECK(node_p->name, ctx->mod);
-
-        /* explicit parent case is not present (this is its first child) */
-        cs = calloc(1, sizeof(struct lysc_node_case));
-        DUP_STRING(ctx->ctx, node_p->name, cs->name);
-        cs->parent = (struct lysc_node *)ch;
-        cs->flags = LYS_STATUS_MASK & node_p->flags;
-        cs->sp = node_p;
-
-        /* check the case's status (don't need to solve uses_status since case statement cannot be directly in grouping statement */
-        LY_CHECK_GOTO(lys_compile_status(ctx, &cs->flags, ch->flags), error);
-
-        if (node_p->when) {
-            LY_ARRAY_NEW_GOTO(ctx->ctx, cs->when, when, ret, error);
-            ret = lys_compile_when(ctx, node_p->when, node_p->flags, (struct lysc_node *)cs, when);
-            LY_CHECK_GOTO(ret, error);
-
-            if (!(ctx->options & LYSC_OPT_GROUPING)) {
-                /* do not check "when" semantics in a grouping */
-                ret = ly_set_add(&ctx->xpath, cs, 0, NULL);
-                LY_CHECK_GOTO(ret, error);
-            }
-        }
-        COMPILE_ARRAY_GOTO(ctx, node_p->iffeatures, cs->iffeatures, u, lys_compile_iffeature, ret, error);
     } else {
-        LOGINT(ctx->ctx);
-        goto error;
+        LOGINT_RET(ctx->ctx);
     }
-    cs->module = ctx->mod;
-    cs->prev = (struct lysc_node *)cs;
-    cs->nodetype = LYS_CASE;
-    lys_compile_node_connect(ctx, (struct lysc_node *)ch, (struct lysc_node *)cs);
-    cs->child = child;
 
-    return cs;
-error:
-    if (cs) {
-        lysc_node_free(ctx->ctx, (struct lysc_node *)cs);
-    }
-    return NULL;
-
-#undef UNIQUE_CHECK
+    return LY_SUCCESS;
 }
 
 /**
@@ -4378,7 +4422,7 @@
 lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lysc_node *parent)
 {
     LY_ERR ret = LY_SUCCESS, rc;
-    struct lysp_node *node_p, *case_node_p;
+    struct lysp_node *node_p;
     struct lysc_node *target; /* target target of the augment */
     struct lysc_node *node;
     struct lysc_when **when, *when_shared;
@@ -4426,12 +4470,10 @@
 
         /* compile the children */
         ctx->options |= flags;
-        if (node_p->nodetype != LYS_CASE) {
-            LY_CHECK_RET(lys_compile_node(ctx, node_p, target, 0));
+        if (target->nodetype == LYS_CHOICE) {
+            LY_CHECK_RET(lys_compile_node_choice_child(ctx, node_p, target));
         } else {
-            LY_LIST_FOR(((struct lysp_node_case *)node_p)->child, case_node_p) {
-                LY_CHECK_RET(lys_compile_node(ctx, case_node_p, target, 0));
-            }
+            LY_CHECK_RET(lys_compile_node(ctx, node_p, target, 0));
         }
         ctx->options = opt_prev;
 
@@ -4627,7 +4669,7 @@
     size_t prefix_len, name_len;
     struct lys_module *mod, *mod_old;
     struct lysp_refine *rfn;
-    LY_ERR rc, ret = LY_EVALID;
+    LY_ERR ret = LY_SUCCESS;
     uint32_t min, max;
     uint16_t flags;
     struct ly_set refined = {0};
@@ -4713,7 +4755,8 @@
     ctx->mod_def = mod;
 
     /* check status */
-    LY_CHECK_GOTO(lysc_check_status(ctx, uses_p->flags, mod_old, uses_p->name, grp->flags, mod, grp->name), cleanup);
+    ret = lysc_check_status(ctx, uses_p->flags, mod_old, uses_p->name, grp->flags, mod, grp->name);
+    LY_CHECK_GOTO(ret, cleanup);
 
     /* remember the currently last child before processing the uses - it is needed to split the siblings to corretly
      * applu refine and augment only to the nodes from the uses */
@@ -4736,7 +4779,8 @@
     /* compile data nodes */
     LY_LIST_FOR(grp->data, node_p) {
         /* 0x3 in uses_status is a special bits combination to be able to detect status flags from uses */
-        LY_CHECK_GOTO(lys_compile_node(ctx, node_p, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3), cleanup);
+        ret = lys_compile_node(ctx, node_p, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3);
+        LY_CHECK_GOTO(ret, cleanup);
     }
 
     /* split the children and add the uses's data into the fake context node */
@@ -4761,12 +4805,13 @@
         if (uses_p->when) {
             LY_ARRAY_NEW_GOTO(ctx->ctx, iter->when, when, ret, cleanup);
             if (!when_shared) {
-                LY_CHECK_GOTO(lys_compile_when(ctx, uses_p->when, uses_p->flags, parent, when), cleanup);
+                ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, parent, when);
+                LY_CHECK_GOTO(ret, cleanup);
 
                 if (!(ctx->options & LYSC_OPT_GROUPING)) {
                     /* do not check "when" semantics in a grouping */
-                    rc = ly_set_add(&ctx->xpath, iter, 0, NULL);
-                    LY_CHECK_ERR_GOTO(rc, ret = rc, cleanup);
+                    ret = ly_set_add(&ctx->xpath, iter, 0, NULL);
+                    LY_CHECK_GOTO(ret, cleanup);
                 }
 
                 when_shared = *when;
@@ -4776,8 +4821,8 @@
 
                 if (!(ctx->options & LYSC_OPT_GROUPING)) {
                     /* in this case check "when" again for all children because of dummy node check */
-                    rc = ly_set_add(&ctx->xpath, iter, 0, NULL);
-                    LY_CHECK_ERR_GOTO(rc, ret = rc, cleanup);
+                    ret = ly_set_add(&ctx->xpath, iter, 0, NULL);
+                    LY_CHECK_GOTO(ret, cleanup);
                 }
             }
         }
@@ -4810,9 +4855,11 @@
     }
 
     /* sort and apply augments */
-    LY_CHECK_GOTO(lys_compile_augment_sort(ctx, uses_p->augments, NULL, &augments), cleanup);
+    ret = lys_compile_augment_sort(ctx, uses_p->augments, NULL, &augments);
+    LY_CHECK_GOTO(ret, cleanup);
     LY_ARRAY_FOR(augments, u) {
-        LY_CHECK_GOTO(lys_compile_augment(ctx, augments[u], (struct lysc_node *)&context_node_fake), cleanup);
+        ret = lys_compile_augment(ctx, augments[u], (struct lysc_node *)&context_node_fake);
+        LY_CHECK_GOTO(ret, cleanup);
     }
 
     /* reload previous context's mod_def */
@@ -4823,11 +4870,11 @@
     LY_ARRAY_FOR(uses_p->refines, struct lysp_refine, rfn) {
         lysc_update_path(ctx, NULL, rfn->nodeid);
 
-        LY_CHECK_GOTO(lysc_resolve_schema_nodeid(ctx, rfn->nodeid, 0, (struct lysc_node *)&context_node_fake, ctx->mod,
-                                                0, 0, (const struct lysc_node **)&node, &flags),
-                      cleanup);
-        rc = ly_set_add(&refined, node, LY_SET_OPT_USEASLIST, NULL);
-        LY_CHECK_ERR_GOTO(rc, ret = rc, cleanup);
+        ret = lysc_resolve_schema_nodeid(ctx, rfn->nodeid, 0, (struct lysc_node *)&context_node_fake, ctx->mod,
+                0, 0, (const struct lysc_node **)&node, &flags);
+        LY_CHECK_GOTO(ret, cleanup);
+        ret = ly_set_add(&refined, node, LY_SET_OPT_USEASLIST, NULL);
+        LY_CHECK_GOTO(ret, cleanup);
 
         /* default value */
         if (rfn->dflts) {
@@ -4835,36 +4882,42 @@
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                        "Invalid refine of default - %s cannot hold %"LY_PRI_ARRAY_COUNT_TYPE " default values.",
                        lys_nodetype2str(node->nodetype), LY_ARRAY_COUNT(rfn->dflts));
+                ret = LY_EVALID;
                 goto cleanup;
             }
             if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_CHOICE))) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                        "Invalid refine of default - %s cannot hold default value(s).",
                        lys_nodetype2str(node->nodetype));
+                ret = LY_EVALID;
                 goto cleanup;
             }
             if (node->nodetype == LYS_LEAF) {
                 /* postpone default compilation when the tree is complete */
-                LY_CHECK_GOTO(lysc_incomplete_leaf_dflt_add(ctx, (struct lysc_node_leaf *)node, rfn->dflts[0],
-                                                            ctx->mod_def), cleanup);
+                ret = lysc_incomplete_leaf_dflt_add(ctx, (struct lysc_node_leaf *)node, rfn->dflts[0], ctx->mod_def);
+                LY_CHECK_GOTO(ret, cleanup);
+
                 node->flags |= LYS_SET_DFLT;
             } else if (node->nodetype == LYS_LEAFLIST) {
                 if (ctx->mod->version < 2) {
                     LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                            "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
+                    ret = LY_EVALID;
                     goto cleanup;
                 }
 
                 /* postpone default compilation when the tree is complete */
-                LY_CHECK_GOTO(lysc_incomplete_llist_dflts_add(ctx, (struct lysc_node_leaflist *)node, rfn->dflts,
-                                                              ctx->mod_def), cleanup);
+                ret = lysc_incomplete_llist_dflts_add(ctx, (struct lysc_node_leaflist *)node, rfn->dflts, ctx->mod_def);
+                LY_CHECK_GOTO(ret, cleanup);
+
                 node->flags |= LYS_SET_DFLT;
             } else if (node->nodetype == LYS_CHOICE) {
                 if (((struct lysc_node_choice *)node)->dflt) {
                     /* unset LYS_SET_DFLT from the current default case */
                     ((struct lysc_node_choice *)node)->dflt->flags &= ~LYS_SET_DFLT;
                 }
-                LY_CHECK_GOTO(lys_compile_node_choice_dflt(ctx, rfn->dflts[0], (struct lysc_node_choice *)node), cleanup);
+                ret = lys_compile_node_choice_dflt(ctx, rfn->dflts[0], (struct lysc_node_choice *)node);
+                LY_CHECK_GOTO(ret, cleanup);
             }
         }
 
@@ -4883,7 +4936,8 @@
         /* config */
         if (rfn->flags & LYS_CONFIG_MASK) {
             if (!flags) {
-                LY_CHECK_GOTO(lys_compile_change_config(ctx, node, rfn->flags, 0, 1), cleanup);
+                ret = lys_compile_change_config(ctx, node, rfn->flags, 0, 1);
+                LY_CHECK_GOTO(ret, cleanup);
             } else {
                 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
                        flags & LYSC_OPT_NOTIFICATION ? "notification" : "RPC/action", ctx->path);
@@ -4892,7 +4946,8 @@
 
         /* mandatory */
         if (rfn->flags & LYS_MAND_MASK) {
-            LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, node, rfn->flags, 1), cleanup);
+            ret = lys_compile_change_mandatory(ctx, node, rfn->flags, 1);
+            LY_CHECK_GOTO(ret, cleanup);
         }
 
         /* presence */
@@ -4901,6 +4956,7 @@
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                        "Invalid refine of presence statement - %s cannot hold the presence statement.",
                        lys_nodetype2str(node->nodetype));
+                ret = LY_EVALID;
                 goto cleanup;
             }
             node->flags |= LYS_PRESENCE;
@@ -4929,10 +4985,11 @@
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                        "Invalid refine of must statement - %s cannot hold any must statement.",
                        lys_nodetype2str(node->nodetype));
+                ret = LY_EVALID;
                 goto cleanup;
             }
-            rc = ly_set_add(&ctx->xpath, node, 0, NULL);
-            LY_CHECK_ERR_GOTO(rc, ret = rc, cleanup);
+            ret = ly_set_add(&ctx->xpath, node, 0, NULL);
+            LY_CHECK_GOTO(ret, cleanup);
         }
 
         /* min/max-elements */
@@ -4972,6 +5029,7 @@
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                        "Invalid refine of %s statement - %s cannot hold this statement.",
                         (rfn->flags & LYS_SET_MAX) ? "max-elements" : "min-elements", lys_nodetype2str(node->nodetype));
+                ret = LY_EVALID;
                 goto cleanup;
             }
         }
@@ -4997,6 +5055,7 @@
                 ((node->nodetype & LYS_LEAF) && (node->flags & LYS_SET_DFLT)))) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                    "Invalid refine of default - the node is mandatory.");
+            ret = LY_EVALID;
             goto cleanup;
         }
 
@@ -5012,6 +5071,7 @@
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                        "Invalid refine of %s statement - \"min-elements\" is bigger than \"max-elements\".",
                         (rfn->flags & LYS_SET_MAX) ? "max-elements" : "min-elements");
+                ret = LY_EVALID;
                 goto cleanup;
             }
         }
@@ -5021,7 +5081,6 @@
         *first_p = context_node_fake.child;
     }
     lysc_update_path(ctx, NULL, NULL);
-    ret = LY_SUCCESS;
 
 cleanup:
     /* fix connection of the children nodes from fake context node back into the parent */
@@ -5163,6 +5222,59 @@
 }
 
 /**
+ * @brief Set config flags for a node.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node Compiled node config to set.
+ * @param[in] parent Parent of @p node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_config(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
+{
+    if (node->nodetype == LYS_CASE) {
+        /* case never has any config */
+        assert(!(node->flags & LYS_CONFIG_MASK));
+        return LY_SUCCESS;
+    }
+
+    /* adjust parent to always get the ancestor with config */
+    if (parent && (parent->nodetype == LYS_CASE)) {
+        parent = parent->parent;
+        assert(parent);
+    }
+
+    if (ctx->options & (LYSC_OPT_RPC_INPUT | LYSC_OPT_RPC_OUTPUT)) {
+        /* ignore config statements inside RPC/action data */
+        node->flags &= ~LYS_CONFIG_MASK;
+        node->flags |= (ctx->options & LYSC_OPT_RPC_INPUT) ? LYS_CONFIG_W : LYS_CONFIG_R;
+    } else if (ctx->options & LYSC_OPT_NOTIFICATION) {
+        /* ignore config statements inside Notification data */
+        node->flags &= ~LYS_CONFIG_MASK;
+        node->flags |= LYS_CONFIG_R;
+    } else if (!(node->flags & LYS_CONFIG_MASK)) {
+        /* config not explicitely set, inherit it from parent */
+        if (parent) {
+            node->flags |= parent->flags & LYS_CONFIG_MASK;
+        } else {
+            /* default is config true */
+            node->flags |= LYS_CONFIG_W;
+        }
+    } else {
+        /* config set explicitely */
+        node->flags |= LYS_SET_CONFIG;
+    }
+
+    if (parent && (parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
+        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+               "Configuration node cannot be child of any state data node.");
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Compile parsed schema node information.
  * @param[in] ctx Compile context
  * @param[in] node_p Parsed schema node.
@@ -5211,24 +5323,17 @@
         node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_choice));
         node_compile_spec = lys_compile_node_choice;
         break;
+    case LYS_CASE:
+        node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_case));
+        node_compile_spec = lys_compile_node_case;
+        break;
     case LYS_ANYXML:
     case LYS_ANYDATA:
         node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_anydata));
         node_compile_spec = lys_compile_node_any;
         break;
     case LYS_USES:
-        if (parent && parent->nodetype == LYS_CHOICE) {
-            assert(node_p->parent->nodetype == LYS_CASE);
-            lysc_update_path(ctx, parent, node_p->parent->name);
-            cs = lys_compile_node_case(ctx, node_p->parent, (struct lysc_node_choice *)parent, NULL);
-            LY_CHECK_ERR_GOTO(!cs, ret = LY_EVALID, error);
-        }
-
         ret = lys_compile_uses(ctx, (struct lysp_node_uses *)node_p, cs ? (struct lysc_node *)cs : parent, &node);
-        if (cs) {
-            cs->child = node;
-            lysc_update_path(ctx, NULL, NULL);
-        }
         lysc_update_path(ctx, NULL, NULL);
         lysc_update_path(ctx, NULL, NULL);
         return ret;
@@ -5243,34 +5348,10 @@
     node->flags = node_p->flags & LYS_FLAGS_COMPILED_MASK;
 
     /* config */
-    if (ctx->options & (LYSC_OPT_RPC_INPUT | LYSC_OPT_RPC_OUTPUT)) {
-        /* ignore config statements inside RPC/action data */
-        node->flags &= ~LYS_CONFIG_MASK;
-        node->flags |= (ctx->options & LYSC_OPT_RPC_INPUT) ? LYS_CONFIG_W : LYS_CONFIG_R;
-    } else if (ctx->options & LYSC_OPT_NOTIFICATION) {
-        /* ignore config statements inside Notification data */
-        node->flags &= ~LYS_CONFIG_MASK;
-        node->flags |= LYS_CONFIG_R;
-    } else if (!(node->flags & LYS_CONFIG_MASK)) {
-        /* config not explicitely set, inherit it from parent */
-        if (parent) {
-            node->flags |= parent->flags & LYS_CONFIG_MASK;
-        } else {
-            /* default is config true */
-            node->flags |= LYS_CONFIG_W;
-        }
-    } else {
-        /* config set explicitely */
-        node->flags |= LYS_SET_CONFIG;
-    }
-    if (parent && (parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
-        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-               "Configuration node cannot be child of any state data node.");
-        ret = LY_EVALID;
-        goto error;
-    }
+    ret = lys_compile_config(ctx, node, parent);
+    LY_CHECK_GOTO(ret, error);
 
-    /* *list ordering */
+    /* list ordering */
     if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
         if ((node->flags & LYS_CONFIG_R) && (node->flags & LYS_ORDBY_MASK)) {
             LOGWRN(ctx->ctx, "The ordered-by statement is ignored in lists representing %s (%s).",
@@ -5286,11 +5367,7 @@
 
     /* status - it is not inherited by specification, but it does not make sense to have
      * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
-    if (!parent || parent->nodetype != LYS_CHOICE) {
-        /* in case of choice/case's children, postpone the check to the moment we know if
-         * the parent is choice (parent here) or some case (so we have to get its flags to check) */
-        LY_CHECK_GOTO(ret = lys_compile_status(ctx, &node->flags, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
-    }
+    LY_CHECK_GOTO(ret = lys_compile_status(ctx, &node->flags, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
 
     if (!(ctx->options & LYSC_OPT_FREE_SP)) {
         node->sp = node_p;
@@ -5310,145 +5387,48 @@
     }
     COMPILE_ARRAY_GOTO(ctx, node_p->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, error);
 
+    /* insert into parent's children/compiled module (we can no longer free the node separately on error) */
+    LY_CHECK_RET(lys_compile_node_connect(ctx, parent, node));
+
     /* nodetype-specific part */
-    LY_CHECK_GOTO(ret = node_compile_spec(ctx, node_p, node), error);
+    LY_CHECK_RET(node_compile_spec(ctx, node_p, node));
 
-    COMPILE_EXTS_GOTO(ctx, node_p->exts, node->exts, node, LYEXT_PAR_NODE, ret, error);
-
-    /* inherit LYS_MAND_TRUE in parent containers */
+    /* final compilation tasks that require the node to be connected */
+    COMPILE_EXTS_GOTO(ctx, node_p->exts, node->exts, node, LYEXT_PAR_NODE, ret, done);
     if (node->flags & LYS_MAND_TRUE) {
+        /* inherit LYS_MAND_TRUE in parent containers */
         lys_compile_mandatory_parents(parent, 1);
     }
 
     lysc_update_path(ctx, NULL, NULL);
-
-    /* insert into parent's children */
-    if (parent) {
-        if (parent->nodetype == LYS_CHOICE) {
-            if (node_p->parent->nodetype == LYS_CASE) {
-                lysc_update_path(ctx, parent, node_p->parent->name);
-            } else {
-                lysc_update_path(ctx, parent, node->name);
-            }
-            cs = lys_compile_node_case(ctx, node_p->parent, (struct lysc_node_choice *)parent, node);
-            LY_CHECK_ERR_GOTO(!cs, ret = LY_EVALID, error);
-            if (uses_status) {}
-            /* the postponed status check of the node and its real parent - in case of implicit case,
-             * it directly gets the same status flags as the choice;
-             * uses_status cannot be applied here since uses cannot be child statement of choice */
-            LY_CHECK_GOTO(ret = lys_compile_status(ctx, &node->flags, cs->flags), error);
-            node->parent = (struct lysc_node *)cs;
-            lysc_update_path(ctx, parent, node->name);
-        } else { /* other than choice */
-            lysc_update_path(ctx, parent, node->name);
-            node->parent = parent;
-        }
-        LY_CHECK_RET(lys_compile_node_connect(ctx, parent->nodetype == LYS_CASE ? parent->parent : parent, node), LY_EVALID);
-
-        if (parent->nodetype == LYS_CHOICE) {
-            lysc_update_path(ctx, NULL, NULL);
-        }
-    } else {
-        /* top-level element */
-        if (!ctx->mod->compiled->data) {
-            ctx->mod->compiled->data = node;
-        } else {
-            /* insert at the end of the module's top-level nodes list */
-            ctx->mod->compiled->data->prev->next = node;
-            node->prev = ctx->mod->compiled->data->prev;
-            ctx->mod->compiled->data->prev = node;
-        }
-        lysc_update_path(ctx, parent, node->name);
-        if (lys_compile_node_uniqness(ctx, ctx->mod->compiled->data, ctx->mod->compiled->rpcs,
-                                      ctx->mod->compiled->notifs, node->name, node)) {
-            return LY_EVALID;
-        }
-    }
-    lysc_update_path(ctx, NULL, NULL);
-
     return LY_SUCCESS;
 
 error:
     lysc_node_free(ctx->ctx, node);
+done:
     return ret;
 }
 
 static void
-lysc_disconnect(struct lysc_node *node)
+lysc_node_unlink(struct lysc_node *node)
 {
-    struct lysc_node *parent, *child, *prev = NULL, *next;
-    struct lysc_node_case *cs = NULL;
+    struct lysc_node *parent, *child;
     struct lysc_module *modc = node->module->compiled;
-    uint8_t remove_cs = 0;
 
     parent = node->parent;
 
     /* parent's first child */
-    if (parent && parent->nodetype == LYS_CHOICE) {
-        cs = (struct lysc_node_case *)node;
-    } else if (parent && parent->nodetype == LYS_CASE) {
-        /* disconnecting some node in a case */
-        cs = (struct lysc_node_case *)parent;
-        parent = cs->parent;
-        for (child = cs->child; child && child->parent == (struct lysc_node *)cs; child = child->next) {
-            if (child == node) {
-                if (cs->child == child) {
-                    if (!child->next || child->next->parent != (struct lysc_node *)cs) {
-                        /* case with a single child -> remove also the case */
-                        child->parent = NULL;
-                        remove_cs = 1;
-                    } else {
-                        cs->child = child->next;
-                    }
-                }
-                break;
-            }
-        }
-        if (!remove_cs) {
-            cs = NULL;
-        }
-    } else if (parent && lysc_node_children(parent, node->flags) == node) {
+    if (parent && lysc_node_children(parent, node->flags) == node) {
         *lysc_node_children_p(parent, node->flags) = node->next;
     } else if (modc->data == node) {
         modc->data = node->next;
     }
-    if (cs) {
-        if (remove_cs) {
-            /* cs has only one child which is being also removed */
-            lysc_disconnect((struct lysc_node *)cs);
-            lysc_node_free(cs->module->ctx, (struct lysc_node *)cs);
-        } else {
-            if (((struct lysc_node_choice *)parent)->dflt == cs) {
-                /* default case removed */
-                ((struct lysc_node_choice *)parent)->dflt = NULL;
-            }
-            if (((struct lysc_node_choice *)parent)->cases == cs) {
-                /* first case removed */
-                ((struct lysc_node_choice *)parent)->cases = (struct lysc_node_case *)cs->next;
-            }
-            if (cs->child) {
-                /* cs will be removed and disconnected from its siblings, but we have to take care also about its children */
-                if (cs->child->prev->parent != (struct lysc_node *)cs) {
-                    prev = cs->child->prev;
-                } /* else all the children are under a single case */
-                LY_LIST_FOR_SAFE(cs->child, next, child) {
-                    if (child->parent != (struct lysc_node *)cs) {
-                        break;
-                    }
-                    lysc_node_free(node->module->ctx, child);
-                }
-                if (prev) {
-                    if (prev->next) {
-                        prev->next = child;
-                    }
-                    if (child) {
-                        child->prev = prev;
-                    } else {
-                        /* link from the first child under the cases */
-                        ((struct lysc_node_choice *)cs->parent)->cases->child->prev = prev;
-                    }
-                }
-            }
+
+    /* special choice case unlinking */
+    if (parent && parent->nodetype == LYS_CHOICE) {
+        if (((struct lysc_node_choice *)parent)->dflt == (struct lysc_node_case *)node) {
+            /* default case removed */
+            ((struct lysc_node_choice *)parent)->dflt = NULL;
         }
     }
 
@@ -5458,7 +5438,8 @@
     }
     if (node->next) {
         node->next->prev = node->prev;
-    } else if (node->nodetype != LYS_CASE) {
+    } else {
+        /* last child */
         if (parent) {
             child = (struct lysc_node *)lysc_node_children(parent, node->flags);
         } else {
@@ -5467,8 +5448,6 @@
         if (child) {
             child->prev = node->prev;
         }
-    } else if (((struct lysc_node_choice *)parent)->cases) {
-        ((struct lysc_node_choice *)parent)->cases->prev = node->prev;
     }
 }
 
@@ -6372,9 +6351,15 @@
             /* remove Notification */
             REMOVE_NONDATA(notifs, struct lysc_notif, lysc_node_notifs, lysc_notif_free);
         } else {
-            /* remove the target node */
-            lysc_disconnect(target);
-            lysc_node_free(ctx->ctx, target);
+            if (target->parent && (target->parent->nodetype == LYS_CASE) && (target->prev == target)) {
+                /* remove the target node with its parent case node because it is the only node of the case */
+                lysc_node_unlink(target->parent);
+                lysc_node_free(ctx->ctx, target->parent);
+            } else {
+                /* remove the target node */
+                lysc_node_unlink(target);
+                lysc_node_free(ctx->ctx, target);
+            }
         }
 
         /* mark the context for later re-compilation of objects that could reference the curently removed node */