schema compile CHANGE support list compilation
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 64cb330..9c79d00 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -3638,7 +3638,7 @@
     INSERT_WORD(ctx, buf, list->name, word, word_len);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
         switch (kw) {
         case YANG_CONFIG:
             LY_CHECK_RET(parse_config(ctx, data, &list->flags, &list->exts));
@@ -3724,6 +3724,14 @@
             return LY_EVALID;
         }
     }
+    LY_CHECK_RET(ret);
+checks:
+    if (list->max && list->min > list->max) {
+        LOGVAL_YANG(ctx, LYVE_SEMANTICS,
+                    "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u.",
+                    list->min, list->max);
+        return LY_EVALID;
+    }
 
     return ret;
 }
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 537d3b6..9cb5860 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -92,11 +92,11 @@
     case LYS_CHOICE:
         if (options & LYS_GETNEXT_WITHCHOICE) {
             return next;
-        } else if (((struct lysc_node_choice *)next)->cases) {
+        } else if ((options & LYS_GETNEXT_NOCHOICE) || !((struct lysc_node_choice *)next)->cases) {
+            next = next->next;
+        } else {
             /* go into */
             next = ((struct lysc_node_choice *)next)->cases[0].child;
-        } else {
-            next = next->next;
         }
         goto repeat;
     default:
diff --git a/src/tree_schema.h b/src/tree_schema.h
index ec4e21e..ae4f1ff 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -562,7 +562,8 @@
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       4 LYS_UNIQUE       | | |x| | | | | | | | | | | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       5 LYS_FENABLED     | | | | | | | | | | | |x| | |
+ *       5 LYS_KEY          | | |x| | | | | | | | | | | |
+ *         LYS_FENABLED     | | | | | | | | | | | |x| | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       6 LYS_MAND_TRUE    | |x|x| | |x| | | | | | | | |
  *         LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | |
@@ -592,6 +593,7 @@
 #define LYS_MAND_MASK    0x60        /**< mask for mandatory values */
 #define LYS_PRESENCE     0x04        /**< flag for presence property of a container, applicable only to ::lysc_node_container */
 #define LYS_UNIQUE       0x08        /**< flag for leafs being part of a unique set, applicable only to ::lysc_node_leaf */
+#define LYS_KEY          0x10        /**< flag for leafs being a key of a list, applicable only to ::lysc_node_leaf */
 #define LYS_FENABLED     0x10        /**< feature enabled flag, applicable only to ::lysc_feature */
 #define LYS_ORDBY_SYSTEM 0x20        /**< ordered-by user lists, applicable only to ::lysc_node_leaflist/::lysp_node_leaflist and
                                           ::lysc_node_list/::lysp_node_list */
@@ -1260,7 +1262,18 @@
     const char *name;                /**< node name (mandatory) */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
 
-    struct lysc_node *child;
+    struct lysc_when *when;          /**< when statement */
+    struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+
+    struct lysc_node *child;         /**< first child node (linked list) */
+    struct lysc_must *musts;         /**< list of must restrictions ([sized array](@ref sizedarrays)) */
+    struct lysc_action *actions;     /**< list of actions ([sized array](@ref sizedarrays)) */
+    struct lysc_notif *notifs;       /**< list of notifications ([sized array](@ref sizedarrays)) */
+
+    struct lysc_node_leaf **keys;    /**< list of pointers to the keys ([sized array](@ref sizedarrays)) */
+    struct lysc_node_leaf ***uniques; /**< list of sized arrays of pointers to the unique nodes ([sized array](@ref sizedarrays)) */
+    uint32_t min;                    /**< min-elements constraint */
+    uint32_t max;                    /**< max-elements constraint */
 };
 
 struct lysc_node_anydata {
@@ -1478,6 +1491,7 @@
  * @{
  */
 #define LYS_GETNEXT_WITHCHOICE   0x01 /**< lys_getnext() option to allow returning #LYS_CHOICE nodes instead of looking into them */
+#define LYS_GETNEXT_NOCHOICE     0x02 /**< lys_getnext() option to ignore (kind of conditional) nodes within choice node */
 #define LYS_GETNEXT_INTONPCONT   0x40 /**< lys_getnext() option to look into non-presence container, instead of returning container itself */
 #define LYS_GETNEXT_NOSTATECHECK 0x100 /**< lys_getnext() option to skip checking module validity (import-only, disabled) and
                                             relevant if-feature conditions state */
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 47ee438..ea6cf08 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -1590,6 +1590,8 @@
     struct ly_set keys = {0};
     int i;
 
+    assert(path_context);
+
     while (**predicate == '[') {
         start = (*predicate)++;
 
@@ -1627,6 +1629,12 @@
         /* source (must be leaf or leaf-list) */
         if (src_prefix) {
             mod = lys_module_find_prefix(path_context, src_prefix, src_prefix_len);
+            if (!mod) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                       "Invalid leafref path predicate \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
+                       *predicate - start, start, src_prefix_len, src_prefix, path_context->compiled->name);
+                goto cleanup;
+            }
         } else {
             mod = start_node->module;
         }
@@ -2024,6 +2032,7 @@
  * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
  * @param[in] context_name Name of the context node or referencing typedef for logging.
  * @param[in] type_p Parsed type to compile.
+ * @param[in] module Context module for the leafref path (to correctly resolve prefixes in path)
  * @param[in] basetype Base YANG built-in type of the type to compile.
  * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
  * @param[in] tpdfname Name of the type's typedef, serves as a flag - if it is leaf/leaf-list's type, it is NULL.
@@ -2268,6 +2277,18 @@
     case LY_TYPE_LEAFREF:
         /* RFC 7950 9.9.3 - require-instance */
         if (type_p->flags & LYS_SET_REQINST) {
+            if (context_mod->version < LYS_VERSION_1_1) {
+                if (tpdfname) {
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                           "Leafref type \"%s\" can be restricted by require-instance statement only in YANG 1.1 modules.", tpdfname);
+                } else {
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                           "Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
+                    free(*type);
+                    *type = NULL;
+                }
+                return LY_EVALID;
+            }
             ((struct lysc_type_leafref*)(*type))->require_instance = type_p->require_instance;
         } else if (base) {
             /* inherit */
@@ -2770,6 +2791,168 @@
 }
 
 /**
+ * @brief Compile parsed list node information.
+ * @param[in] ctx Compile context
+ * @param[in] node_p Parsed list node.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
+ * is enriched with the list-specific information.
+ * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ */
+static LY_ERR
+lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *node)
+{
+    struct lysp_node_list *list_p = (struct lysp_node_list*)node_p;
+    struct lysc_node_list *list = (struct lysc_node_list*)node;
+    struct lysp_node *child_p;
+    struct lysc_node_leaf **key, ***unique;
+    size_t len;
+    unsigned int u, v;
+    const char *keystr, *delim;
+    int config;
+    LY_ERR ret = LY_SUCCESS;
+
+    COMPILE_MEMBER_GOTO(ctx, list_p->when, list->when, options, lys_compile_when, ret, done);
+    COMPILE_ARRAY_GOTO(ctx, list_p->iffeatures, list->iffeatures, options, u, lys_compile_iffeature, ret, done);
+    list->min = list_p->min;
+    list->max = list_p->max ? list_p->max : (uint32_t)-1;
+
+    LY_LIST_FOR(list_p->child, child_p) {
+        LY_CHECK_RET(lys_compile_node(ctx, child_p, options, node));
+    }
+
+    COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, options, u, lys_compile_must, ret, done);
+
+    /* keys */
+    if ((list->flags & LYS_CONFIG_W) && (!list_p->key || !list_p->key[0])) {
+        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Missing key in list representing configuration data.");
+        return LY_EVALID;
+    }
+
+    /* find all the keys (must be direct children) */
+    keystr = list_p->key;
+    while (keystr) {
+        delim = strpbrk(keystr, " \t\n");
+        if (delim) {
+            len = delim - keystr;
+            while (isspace(*delim)) {
+                ++delim;
+            }
+        } else {
+            len = strlen(keystr);
+        }
+
+        /* key node must be present */
+        LY_ARRAY_NEW_RET(ctx->ctx, list->keys, key, LY_EMEM);
+        *key = (struct lysc_node_leaf*)lys_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE | LYS_GETNEXT_NOSTATECHECK);
+        if (!(*key)) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "The list's key \"%.*s\" not found.", len, keystr);
+            return LY_EVALID;
+        }
+        /* keys must be unique */
+        for(u = 0; u < LY_ARRAY_SIZE(list->keys) - 1; ++u) {
+            if (*key == list->keys[u]) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "Duplicated key identifier \"%.*s\".", len, keystr);
+                return LY_EVALID;
+            }
+        }
+        /* key must have the same config flag as the list itself */
+        if ((list->flags & LYS_CONFIG_MASK) != ((*key)->flags & LYS_CONFIG_MASK)) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Key of the configuration list must not be status leaf.");
+            return LY_EVALID;
+        }
+        if (ctx->mod->compiled->version < LYS_VERSION_1_1) {
+            /* YANG 1.0 denies key to be of empty type */
+            if ((*key)->type->basetype == LY_TYPE_EMPTY) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "Key of a list can be of type \"empty\" only in YANG 1.1 modules.");
+                return LY_EVALID;
+            }
+        } else {
+            /* when and if-feature are illegal on list keys */
+            if ((*key)->when) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "List's key \"%s\" must not have any \"when\" statement.", (*key)->name);
+                return LY_EVALID;
+            }
+            if ((*key)->iffeatures) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "List's key \"%s\" must not have any \"if-feature\" statement.", (*key)->name);
+                return LY_EVALID;
+            }
+        }
+        /* ignore default values of the key */
+        if ((*key)->dflt) {
+            lydict_remove(ctx->ctx, (*key)->dflt);
+            (*key)->dflt = NULL;
+        }
+        /* mark leaf as key */
+        (*key)->flags |= LYS_KEY;
+
+        /* next key value */
+        keystr = delim;
+    }
+
+    /* uniques */
+    if (list_p->uniques) {
+        for (v = 0; v < LY_ARRAY_SIZE(list_p->uniques); ++v) {
+            config = -1;
+            LY_ARRAY_NEW_RET(ctx->ctx, list->uniques, unique, LY_EMEM);
+            keystr = list_p->uniques[v];
+            while (keystr) {
+                delim = strpbrk(keystr, " \t\n");
+                if (delim) {
+                    len = delim - keystr;
+                    while (isspace(*delim)) {
+                        ++delim;
+                    }
+                } else {
+                    len = strlen(keystr);
+                }
+
+                /* unique node must be present */
+                LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
+                ret = lys_resolve_descendant_schema_nodeid(ctx, keystr, len, node, LYS_LEAF, (const struct lysc_node**)key);
+                if (ret != LY_SUCCESS) {
+                    if (ret == LY_EDENIED) {
+                        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                               "Unique's descendant-schema-nodeid \"%.*s\" refers to a %s node instead of a leaf.",
+                               len, keystr, lys_nodetype2str((*key)->nodetype));
+                    }
+                    return LY_EVALID;
+                }
+
+                /* all referenced leafs must be of the same config type */
+                if (config != -1 && ((((*key)->flags & LYS_CONFIG_W) && config == 0) || (((*key)->flags & LYS_CONFIG_R) && config == 1))) {
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                           "Unique statement \"%s\" refers to leafs with different config type.", list_p->uniques[v]);
+                    return LY_EVALID;
+                } else if ((*key)->flags & LYS_CONFIG_W) {
+                    config = 1;
+                } else { /* LYS_CONFIG_R */
+                    config = 0;
+                }
+
+                /* mark leaf as unique */
+                (*key)->flags |= LYS_UNIQUE;
+
+                /* next unique value in line */
+                keystr = delim;
+            }
+            /* next unique definition */
+        }
+    }
+
+    //COMPILE_ARRAY_GOTO(ctx, list_p->actions, list->actions, options, u, lys_compile_action, ret, done);
+    //COMPILE_ARRAY_GOTO(ctx, list_p->notifs, list->notifs, options, u, lys_compile_notif, ret, done);
+
+done:
+    return ret;
+}
+
+/**
  * @brief Compile parsed schema node information.
  * @param[in] ctx Compile context
  * @param[in] node_p Parsed schema node.
@@ -2798,6 +2981,7 @@
         break;
     case LYS_LIST:
         node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_list));
+        node_compile_spec = lys_compile_node_list;
         break;
     case LYS_LEAFLIST:
         node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_leaflist));
@@ -2830,6 +3014,11 @@
             node->flags |= LYS_CONFIG_W;
         }
     }
+    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.");
+        goto error;
+    }
 
     /* *list ordering */
     if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 380bd3c..9b7a3b5 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -626,6 +626,28 @@
     LY_ARRAY_FREE(node->dflts);
 }
 
+static void
+lysc_node_list_free(struct ly_ctx *ctx, struct lysc_node_list *node)
+{
+    unsigned int u;
+    struct lysc_node *child, *child_next;
+
+    FREE_MEMBER(ctx, node->when, lysc_when_free);
+    FREE_ARRAY(ctx, node->iffeatures, lysc_iffeature_free);
+    LY_LIST_FOR_SAFE(node->child, child_next, child) {
+        lysc_node_free(ctx, child);
+    }
+    FREE_ARRAY(ctx, node->musts, lysc_must_free);
+
+    LY_ARRAY_FREE(node->keys);
+    LY_ARRAY_FOR(node->uniques, u) {
+        LY_ARRAY_FREE(node->uniques[u]);
+    }
+    LY_ARRAY_FREE(node->uniques);
+
+    /* TODO actions, notifs */
+}
+
 void
 lysc_node_free(struct ly_ctx *ctx, struct lysc_node *node)
 {
@@ -643,6 +665,9 @@
     case LYS_LEAFLIST:
         lysc_node_leaflist_free(ctx, (struct lysc_node_leaflist*)node);
         break;
+    case LYS_LIST:
+        lysc_node_list_free(ctx, (struct lysc_node_list*)node);
+        break;
     default:
         LOGINT(ctx);
     }
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index b815bbc..7f952e2 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -85,6 +85,63 @@
 }
 
 LY_ERR
+lys_resolve_descendant_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
+                                     int nodetype, const struct lysc_node **target)
+{
+    LY_ERR ret = LY_EVALID;
+    const char *name, *prefix, *id;
+    const struct lysc_node *context;
+    size_t name_len, prefix_len;
+    const struct lys_module *mod;
+
+    assert(nodeid);
+    assert(context_node);
+    assert(target);
+    *target = NULL;
+
+    id = nodeid;
+    context = context_node;
+    while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
+        if (prefix) {
+            mod = lys_module_find_prefix(context_node->module, prefix, prefix_len);
+            if (!mod) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                       "Invalid descendant-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
+                       id - nodeid, nodeid, prefix_len, prefix, context_node->module->compiled->name);
+                return LY_ENOTFOUND;
+            }
+        } else {
+            mod = context_node->module;
+        }
+        context = lys_child(context, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE);
+        if (!context) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Invalid descendant-schema-nodeid value \"%.*s\" - target node not found.", id - nodeid, nodeid);
+            return LY_ENOTFOUND;
+        }
+        if (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len)) {
+            break;
+        }
+        if (id && *id != '/') {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Invalid descendant-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
+                   id - nodeid, nodeid);
+            return LY_EVALID;
+        }
+        ++id;
+    }
+
+    if (ret == LY_SUCCESS) {
+        *target = context;
+        if (nodetype && !(context->nodetype & nodetype)) {
+            return LY_EDENIED;
+        }
+    }
+
+    return ret;
+}
+
+LY_ERR
 lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_module *module, const char **value)
 {
     struct lysp_import *i;
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 373b000..7b6d8de 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -251,6 +251,23 @@
 LY_ERR lys_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len);
 
 /**
+ * @brief Find the node according to the given descendant schema node id.
+ * Used in unique, refine and uses's augment statements
+ *
+ * @param[in] ctx Compile context
+ * @param[in] nodeid Descendant-schema-nodeid (according to the YANG grammar)
+ * @param[in] nodeid_len Length of the given nodeid, if it is not NULL-terminated string.
+ * @param[in] context_node Node where the nodeid is specified to correctly resolve prefixes and to start searching.
+ * @param[in] nodetype Optional (can be 0) restriction for target's nodetype. If target exists, but does not match
+ * the given nodetype, LY_EDENIED is returned, but no error message is printed. The value can be even an ORed value to allow
+ * multiple nodetypes.
+ * @param[out] target Found target node if any.
+ * @return LY_ERR values - LY_ENOTFOUND, LY_EVALID, LY_EDENIED or LY_SUCCESS.
+ */
+LY_ERR lys_resolve_descendant_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
+                                            int nodetype, const struct lysc_node **target);
+
+/**
  * @brief Find the module referenced by prefix in the provided mod.
  *
  * @param[in] mod Schema module where the prefix was used.
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index ed46b79..9407c41 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -1510,6 +1510,71 @@
     ly_ctx_destroy(ctx.ctx, NULL);
 }
 
+static void
+test_list(void **state)
+{
+    *state = test_list;
+
+    struct lysp_module mod = {0};
+    struct ly_parser_ctx ctx = {0};
+    struct lysp_node_list *l = NULL;
+    const char *str;
+
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+    assert_non_null(ctx.ctx);
+    ctx.line = 1;
+    ctx.mod = &mod;
+    ctx.mod->version = 2; /* simulate YANG 1.1 */
+
+    /* invalid cardinality */
+#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
+    str = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
+    assert_int_equal(LY_EVALID, parse_list(&ctx, &str, NULL, (struct lysp_node**)&l)); \
+    logbuf_assert("Duplicate keyword \""MEMBER"\". Line number 1."); \
+    lysp_node_free(ctx.ctx, (struct lysp_node*)l); l = NULL;
+
+    TEST_DUP("config", "true", "false");
+    TEST_DUP("description", "text1", "text2");
+    TEST_DUP("key", "one", "two");
+    TEST_DUP("max-elements", "10", "20");
+    TEST_DUP("min-elements", "10", "20");
+    TEST_DUP("ordered-by", "user", "system");
+    TEST_DUP("reference", "1", "2");
+    TEST_DUP("status", "current", "obsolete");
+    TEST_DUP("when", "true", "false");
+#undef TEST_DUP
+
+    /* full content */
+    str = "l {action x;anydata any;anyxml anyxml; choice ch;config false;container c;description test;grouping g;if-feature f; key l; leaf l {type string;}"
+          "leaf-list ll {type string;} list li;max-elements 10; min-elements 1;must 'expr';notification not; ordered-by system; reference test;"
+          "status current;typedef t {type int8;}unique xxx;unique yyy;uses g;when true;m:ext;} ...";
+    assert_int_equal(LY_SUCCESS, parse_list(&ctx, &str, NULL, (struct lysp_node**)&l));
+    assert_non_null(l);
+    assert_int_equal(LYS_LIST, l->nodetype);
+    assert_string_equal("l", l->name);
+    assert_string_equal("test", l->dsc);
+    assert_string_equal("l", l->key);
+    assert_non_null(l->uniques);
+    assert_int_equal(2, LY_ARRAY_SIZE(l->uniques));
+    assert_string_equal("xxx", l->uniques[0]);
+    assert_string_equal("yyy", l->uniques[1]);
+    assert_int_equal(10, l->max);
+    assert_int_equal(1, l->min);
+    assert_non_null(l->exts);
+    assert_non_null(l->iffeatures);
+    assert_non_null(l->musts);
+    assert_string_equal("test", l->ref);
+    assert_non_null(l->when);
+    assert_null(l->parent);
+    assert_null(l->next);
+    assert_int_equal(LYS_CONFIG_R | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM | LYS_SET_MAX | LYS_SET_MIN, l->flags);
+    ly_set_erase(&ctx.tpdfs_nodes, NULL);
+    lysp_node_free(ctx.ctx, (struct lysp_node*)l); l = NULL;
+
+    *state = NULL;
+    ly_ctx_destroy(ctx.ctx, NULL);
+}
+
 int main(void)
 {
     const struct CMUnitTest tests[] = {
@@ -1526,6 +1591,7 @@
         cmocka_unit_test_setup(test_container, logger_setup),
         cmocka_unit_test_setup_teardown(test_leaf, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_leaflist, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_list, logger_setup, logger_teardown),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index bec8afc..e5acd09 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -417,7 +417,7 @@
     assert_int_equal((uint32_t)-1, ll->max);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module c {yang-version 1.1;namespace urn:c;prefix c;typedef mytype {type int8;default 10;}"
-                                        "leaf-list ll1 {type mytype;default 1; default 2; config false;}"
+                                        "leaf-list ll1 {type mytype;default 1; default 1; config false;}"
                                         "leaf-list ll2 {type mytype; ordered-by user;}}", LYS_IN_YANG));
     assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     assert_non_null(mod->compiled);
@@ -426,7 +426,7 @@
     assert_int_equal(3, ll->type->refcount);
     assert_int_equal(2, LY_ARRAY_SIZE(ll->dflts));
     assert_string_equal("1", ll->dflts[0]);
-    assert_string_equal("2", ll->dflts[1]);
+    assert_string_equal("1", ll->dflts[1]);
     assert_int_equal(LYS_CONFIG_R | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, ll->flags);
     assert_non_null((ll = (struct lysc_node_leaflist*)mod->compiled->data->next));
     assert_non_null(ll->dflts);
@@ -471,6 +471,107 @@
     ly_ctx_destroy(ctx, NULL);
 }
 
+static void
+test_node_list(void **state)
+{
+    *state = test_node_list;
+
+    struct ly_ctx *ctx;
+    struct lys_module *mod;
+    struct lysc_node_list *list;
+
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;feature f;"
+                                        "list l1 {key \"x y\"; ordered-by user; leaf x {type string; when 1;}leaf y{type string;if-feature f;}}"
+                                        "list l2 {config false;leaf value {type string;}}}", LYS_IN_YANG));
+    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
+    list = (struct lysc_node_list*)mod->compiled->data;
+    assert_non_null(list);
+    assert_non_null(list->keys);
+    assert_int_equal(2, LY_ARRAY_SIZE(list->keys));
+    assert_string_equal("x", list->keys[0]->name);
+    assert_string_equal("y", list->keys[1]->name);
+    assert_non_null(list->child);
+    assert_int_equal(LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_USER, list->flags);
+    assert_true(list->child->flags & LYS_KEY);
+    assert_true(list->child->next->flags & LYS_KEY);
+    list = (struct lysc_node_list*)mod->compiled->data->next;
+    assert_non_null(list);
+    assert_null(list->keys);
+    assert_non_null(list->child);
+    assert_int_equal(LYS_CONFIG_R | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, list->flags);
+    assert_false(list->child->flags & LYS_KEY);
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;"
+                                        "list l {key a; unique \"a c/b:b\"; unique \"c/e d\";"
+                                        "leaf a {type string;} leaf d {type string;config false;}"
+                                        "container c {leaf b {type string;}leaf e{type string;config false;}}}}", LYS_IN_YANG));
+    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
+    list = (struct lysc_node_list*)mod->compiled->data;
+    assert_non_null(list);
+    assert_string_equal("l", list->name);
+    assert_non_null(list->keys);
+    assert_int_equal(1, LY_ARRAY_SIZE(list->keys));
+    assert_string_equal("a", list->keys[0]->name);
+    assert_true(list->keys[0]->flags & LYS_KEY);
+    assert_non_null(list->uniques);
+    assert_int_equal(2, LY_ARRAY_SIZE(list->uniques));
+    assert_int_equal(2, LY_ARRAY_SIZE(list->uniques[0]));
+    assert_string_equal("a", list->uniques[0][0]->name);
+    assert_true(list->uniques[0][0]->flags & LYS_UNIQUE);
+    assert_string_equal("b", list->uniques[0][1]->name);
+    assert_true(list->uniques[0][1]->flags & LYS_UNIQUE);
+    assert_int_equal(2, LY_ARRAY_SIZE(list->uniques[1]));
+    assert_string_equal("e", list->uniques[1][0]->name);
+    assert_true(list->uniques[1][0]->flags & LYS_UNIQUE);
+    assert_string_equal("d", list->uniques[1][1]->name);
+    assert_true(list->uniques[1][1]->flags & LYS_UNIQUE);
+
+    /* invalid */
+    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;list l;}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("Missing key in list representing configuration data.");
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module bb {yang-version 1.1; namespace urn:bb;prefix bb;"
+                                        "list l {key x; leaf x {type string; when 1;}}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("List's key \"x\" must not have any \"when\" statement.");
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;feature f;"
+                                        "list l {key x; leaf x {type string; if-feature f;}}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("List's key \"x\" must not have any \"if-feature\" statement.");
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;"
+                                        "list l {key x; leaf x {type string; config false;}}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("Key of the configuration list must not be status leaf.");
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;"
+                                        "list l {config false;key x; leaf x {type string; config true;}}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("Configuration node cannot be child of any state data node.");
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;"
+                                        "list l {key x; leaf-list x {type string;}}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("The list's key \"x\" not found.");
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;"
+                                        "list l {key x; unique y;leaf x {type string;} leaf-list y {type string;}}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("Unique's descendant-schema-nodeid \"y\" refers to a leaf-list node instead of a leaf.");
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;"
+                                        "list l {key x; unique \"x y\";leaf x {type string;} leaf y {config false; type string;}}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("Unique statement \"x y\" refers to leafs with different config type.");
+
+    *state = NULL;
+    ly_ctx_destroy(ctx, NULL);
+}
+
 /**
  * actually the same as length restriction (tested in test_type_length()), so just check the correct handling in appropriate types,
  * do not test the expression itself
@@ -1406,7 +1507,7 @@
     assert_int_equal(0, has_predicate);
 
     /* complete leafref paths */
-    assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;"
+    assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1;namespace urn:a;prefix a;"
                                         "leaf ref1 {type leafref {path /a:target1;}} leaf ref2 {type leafref {path /a/target2; require-instance false;}}"
                                         "leaf target1 {type string;}container a {leaf target2 {type uint8;}}}", LYS_IN_YANG));
     assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
@@ -1442,7 +1543,7 @@
     assert_int_equal(1, ((struct lysc_type_leafref* )type)->require_instance);
 
     /* prefixes are reversed to check using correct context of the path! */
-    assert_non_null(mod = lys_parse_mem(ctx, "module c {namespace urn:c;prefix b; import b {prefix c;}"
+    assert_non_null(mod = lys_parse_mem(ctx, "module c {yang-version 1.1;namespace urn:c;prefix b; import b {prefix c;}"
                                         "typedef mytype3 {type c:mytype {require-instance false;}}"
                                         "leaf ref1 {type b:mytype3;}leaf ref2 {type c:mytype2;}}", LYS_IN_YANG));
     assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
@@ -1540,6 +1641,15 @@
     assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path \"/target\" - target is supposed to represent configuration data (as the leafref does), but it does not.");
 
+    assert_non_null(mod = lys_parse_mem(ctx, "module ll {namespace urn:ll;prefix ll;"
+                                        "leaf ref {type leafref {path /target; require-instance true;}}leaf target {type string;}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
+    assert_non_null(mod = lys_parse_mem(ctx, "module mm {namespace urn:mm;prefix mm;typedef mytype {type leafref {path /target;require-instance false;}}"
+                                        "leaf ref {type mytype;}leaf target {type string;}}", LYS_IN_YANG));
+    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    logbuf_assert("Leafref type \"mytype\" can be restricted by require-instance statement only in YANG 1.1 modules.");
+
     /* circular chain */
     assert_non_null(mod = lys_parse_mem(ctx, "module aaa {namespace urn:aaa;prefix aaa;"
                                         "leaf ref1 {type leafref {path /ref2;}}"
@@ -1766,6 +1876,7 @@
         cmocka_unit_test_setup_teardown(test_type_dflt, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_node_container, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_node_leaflist, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_node_list, logger_setup, logger_teardown),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);