schema compile REFACTOR implement flag meaning changed

Implemented set to 1 means that it was already tried
implementing the module. That means that all tasks
executing only once for each implemented module
are done and should never be performed again. Also,
these one-time tasks were isolated and moved to
lys_implement() so that lys_compile() performs
only strict compiled module creation that cannot
require recompilation on its own.
diff --git a/src/context.c b/src/context.c
index a4a9049..a81e95f 100644
--- a/src/context.c
+++ b/src/context.c
@@ -198,10 +198,8 @@
     LY_CHECK_GOTO(ret = lys_parse_load(ctx, name, revision, &unres, &result), cleanup);
 
     /* implement */
-    LY_CHECK_GOTO(ret = lys_implement(result, features, &unres), cleanup);
-
-    /* resolve unres and revert, if needed */
-    LY_CHECK_GOTO(ret = lys_compile_unres_glob(ctx, &unres), cleanup);
+    ret = _lys_set_implemented(mod, features, &unres);
+    LY_CHECK_GOTO(ret, cleanup);
 
 cleanup:
     if (ret) {
@@ -510,9 +508,12 @@
     for (i = 0; i < ctx->list.count; ++i) {
         mod = ctx->list.objs[i];
         if (mod->to_compile) {
-            /* if was not implemented, will be */
-            mod->implemented = 1;
+            assert(mod->implemented);
 
+            /* just unset the flag, it is not used for anything currently */
+            mod->to_compile = 0;
+
+            /* some modules were changed and need to be (re)compiled */
             recompile = 1;
         }
     }
@@ -522,18 +523,8 @@
         return LY_SUCCESS;
     }
 
-    /* recompile */
-    LY_CHECK_RET(lys_recompile(ctx, 1));
-
-    /* everything is fine, clear the flags */
-    for (i = 0; i < ctx->list.count; ++i) {
-        mod = ctx->list.objs[i];
-        if (mod->to_compile) {
-            mod->to_compile = 0;
-        }
-    }
-
-    return LY_SUCCESS;
+    /* (re)compile all the implemented modules */
+    return lys_recompile(ctx, 1);
 }
 
 API uint16_t
@@ -1203,13 +1194,22 @@
 API void
 ly_ctx_destroy(struct ly_ctx *ctx)
 {
+    struct lys_module *mod;
+
     if (!ctx) {
         return;
     }
 
     /* models list */
     for ( ; ctx->list.count; ctx->list.count--) {
+        mod = ctx->list.objs[ctx->list.count - 1];
+
         /* remove the module */
+        if (mod->implemented) {
+            mod->implemented = 0;
+            lysc_module_free(mod->compiled);
+            mod->compiled = NULL;
+        }
         lys_module_free(ctx->list.objs[ctx->list.count - 1]);
     }
     free(ctx->list.objs);
diff --git a/src/plugins_types.c b/src/plugins_types.c
index adfeb17..df33bd4 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -751,13 +751,11 @@
 API LY_ERR
 lyplg_type_make_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
 {
-    LY_CHECK_RET(lys_implement(mod, features, unres));
-
-    if (unres->recompile) {
-        return LY_ERECOMPILE;
+    if (mod->implemented) {
+        return LY_SUCCESS;
     }
 
-    return LY_SUCCESS;
+    return lys_implement(mod, features, unres);
 }
 
 API LY_ERR
diff --git a/src/schema_compile.c b/src/schema_compile.c
index 1585f2f..a62ba98 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -1486,35 +1486,40 @@
 }
 
 /**
- * @brief Compile identites in the current module and all its submodules.
+ * @brief Compile identites in a module and all its submodules.
  *
- * @param[in] ctx Compile context.
+ * @param[in] mod Module to process.
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_compile_identities(struct lysc_ctx *ctx)
+lys_compile_identities(struct lys_module *mod)
 {
-    LY_ERR ret = LY_SUCCESS;
+    struct lysc_ctx ctx = {0};
     struct lysp_submodule *submod;
     struct lysp_module *orig_pmod = ctx->pmod;
     LY_ARRAY_COUNT_TYPE u;
 
-    if (ctx->cur_mod->parsed->identities) {
-        LY_CHECK_GOTO(ret = lys_compile_identities_derived(ctx, ctx->cur_mod->parsed->identities,
-                &ctx->cur_mod->identities), cleanup);
+    /* prepare context */
+    ctx.ctx = mod->ctx;
+    ctx.cur_mod = mod;
+    ctx.pmod = mod->parsed;
+    ctx.path_len = 1;
+    ctx.path[0] = '/';
+
+    if (mod->parsed->identities) {
+        LY_CHECK_RET(lys_compile_identities_derived(&ctx, mod->parsed->identities, &mod->identities));
     }
-    lysc_update_path(ctx, NULL, "{submodule}");
-    LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
-        submod = ctx->cur_mod->parsed->includes[u].submodule;
+    lysc_update_path(&ctx, NULL, "{submodule}");
+    LY_ARRAY_FOR(mod->parsed->includes, u) {
+        submod = mod->parsed->includes[u].submodule;
         if (submod->identities) {
-            ctx->pmod = (struct lysp_module *)submod;
-            lysc_update_path(ctx, NULL, submod->name);
-            ret = lys_compile_identities_derived(ctx, submod->identities, &ctx->cur_mod->identities);
-            lysc_update_path(ctx, NULL, NULL);
-            LY_CHECK_GOTO(ret, cleanup);
+            ctx.pmod = (struct lysp_module *)submod;
+            lysc_update_path(&ctx, NULL, submod->name);
+            LY_CHECK_RET(lys_compile_identities_derived(&ctx, submod->identities, &mod->identities));
+            lysc_update_path(&ctx, NULL, NULL);
         }
     }
-    lysc_update_path(ctx, NULL, NULL);
+    lysc_update_path(&ctx, NULL, NULL);
 
 cleanup:
     ctx->pmod = orig_pmod;
@@ -1543,6 +1548,8 @@
     for (idx = 0; idx < ctx->list.count; ++idx) {
         mod = ctx->list.objs[idx];
         if (mod->compiled) {
+            assert(mod->implemented);
+
             /* free the module */
             lysc_module_free(mod->compiled);
             mod->compiled = NULL;
@@ -1579,42 +1586,16 @@
 cleanup:
     if (!log) {
         ly_log_options(prev_lo);
+        if (ret) {
+            LOGERR(mod->ctx, ret, "Recompilation of module \"%s\" failed.", mod->name);
+        }
     }
-    lys_compile_unres_glob_erase(ctx, &unres);
+    lys_compile_unres_glob_erase(ctx, &unres, 0);
     return ret;
 }
 
-/**
- * @brief Check whether a module does not have any (recursive) compiled import.
- *
- * @param[in] mod Module to examine.
- * @return Whether the module has a compiled imported module.
- */
-static ly_bool
-lys_has_compiled_import_r(struct lys_module *mod)
-{
-    LY_ARRAY_COUNT_TYPE u;
-
-    LY_ARRAY_FOR(mod->parsed->imports, u) {
-        if (!mod->parsed->imports[u].module->implemented) {
-            continue;
-        }
-
-        if (mod->parsed->imports[u].module->compiled) {
-            return 1;
-        }
-
-        /* recursive */
-        if (lys_has_compiled_import_r(mod->parsed->imports[u].module)) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
 LY_ERR
-lys_compile(struct lys_module *mod, uint32_t options, ly_bool recompile, struct lys_glob_unres *unres)
+lys_compile(struct lys_module *mod, uint32_t options, struct lys_glob_unres *unres)
 {
     struct lysc_ctx ctx = {0};
     struct lysc_module *mod_c = NULL;
@@ -1641,29 +1622,6 @@
     ctx.path[0] = '/';
     ctx.unres = unres;
 
-    /* skip compilation tasks that need to be performed only once for implemented modules */
-    if (!recompile) {
-        /* identities */
-        LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), cleanup);
-
-        /* augments and deviations */
-        LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), cleanup);
-
-        if (!unres->recompile && !unres->full_compilation) {
-            /* check whether this module may reference any already-compiled modules */
-            if (lys_has_compiled_import_r(mod)) {
-                /* it may and we need even disabled nodes in those modules, recompile them */
-                unres->recompile = 1;
-            }
-        }
-
-        if (unres->recompile) {
-            /* we need the context recompiled */
-            goto cleanup;
-        }
-    }
-
-    /* now the actual compilation will take place */
     ++mod->ctx->change_count;
     mod->compiled = mod_c = calloc(1, sizeof *mod_c);
     LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
@@ -1763,3 +1721,98 @@
     }
     return ret;
 }
+
+/**
+ * @brief Check whether a module does not have any (recursive) compiled import.
+ *
+ * @param[in] mod Module to examine.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERECOMPILE on required recompilation.
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lys_has_compiled_import_r(struct lys_module *mod)
+{
+    LY_ARRAY_COUNT_TYPE u;
+
+    LY_ARRAY_FOR(mod->parsed->imports, u) {
+        if (!mod->parsed->imports[u].module->implemented) {
+            continue;
+        }
+
+        if (mod->parsed->imports[u].module->compiled) {
+            return LY_ERECOMPILE;
+        }
+
+        /* recursive */
+        LY_CHECK_RET(lys_has_compiled_import_r(mod->parsed->imports[u].module));
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
+lys_implement(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
+{
+    LY_ERR ret;
+    struct lys_module *m;
+
+    assert(!mod->implemented);
+
+    /* we have module from the current context */
+    m = ly_ctx_get_module_implemented(mod->ctx, mod->name);
+    if (m) {
+        assert(m != mod);
+
+        /* check collision with other implemented revision */
+        LOGERR(mod->ctx, LY_EDENIED, "Module \"%s%s%s\" is present in the context in other implemented revision (%s).",
+                mod->name, mod->revision ? "@" : "", mod->revision ? mod->revision : "", m->revision ? m->revision : "none");
+        return LY_EDENIED;
+    }
+
+    /* set features */
+    ret = lys_set_features(mod->parsed, features);
+    if (ret && (ret != LY_EEXIST)) {
+        return ret;
+    }
+
+    /* compile identities */
+    LY_CHECK_RET(lys_compile_identities(mod));
+
+    /* mark target modules with our augments and deviations */
+    ret = lys_precompile_augments_deviations(mod, unres);
+    LY_CHECK_RET(ret && (ret != LY_ERECOMPILE), ret);
+
+    /*
+     * mark the module implemented, which means
+     * 1) to (re)compile it only ::lys_compile() call is needed
+     * 2) its compilation will never cause new modules to be implemented (::lys_compile() does not return ::LY_ERECOMPILE)
+     *    but there can be some unres items added that do
+     */
+    mod->implemented = 1;
+
+    /* add the module into newly implemented module set */
+    LY_CHECK_RET(ly_set_add(&unres->implementing, mod, 1, NULL));
+
+    if (mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE) {
+        /* do not actually compile the module yet */
+        mod->to_compile = 1;
+        return LY_SUCCESS;
+    } else if (ret == LY_ERECOMPILE) {
+        /* we cannot compile the module yet */
+        return ret;
+    }
+
+    if (!unres->full_compilation) {
+        /* check whether this module may reference any already-compiled modules */
+        LY_CHECK_RET(lys_has_compiled_import_r(mod));
+    }
+
+    /* compile the schema */
+    LY_CHECK_RET(lys_compile(mod, 0, unres));
+
+    /* new module is implemented and compiled */
+    unres->full_compilation = 0;
+
+    return LY_SUCCESS;
+}
diff --git a/src/schema_compile.h b/src/schema_compile.h
index 3206b39..aba8094 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -276,16 +276,31 @@
 LY_ERR lys_recompile(struct ly_ctx *ctx, ly_bool log);
 
 /**
- * @brief Compile printable schema into a validated schema linking all the references.
+ * @brief Compile schema into a validated schema linking all the references.
+ *
+ * Implemented flag of @p mod must be set meaning this function should be called only if the module
+ * is being recompiled, otherwise call ::lys_implement().
  *
  * @param[in] mod Pointer to the schema structure holding pointers to both schema structure types. The ::lys_module#parsed
  * member is used as input and ::lys_module#compiled is used to hold the result of the compilation.
  * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
- * @param[in] recompile Whether @p mod is compiled for the first time or only recompiled.
- * @param[in,out] unres Global unres structure for newly implemented modules. If `recompile` was set, @p mod
- * was actually not compiled because there is at least one compiled imported module that must be recompiled first.
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ * @param[in,out] unres Global unres structure to add to.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR on error.
  */
-LY_ERR lys_compile(struct lys_module *mod, uint32_t options, ly_bool recompile, struct lys_glob_unres *unres);
+LY_ERR lys_compile(struct lys_module *mod, uint32_t options, struct lys_glob_unres *unres);
+
+/**
+ * @brief Implement a single module, can be called recursively.
+ *
+ * @param[in] mod Module to implement.
+ * @param[in] features Features to set, see ::lys_set_features().
+ * @param[in,out] unres Global unres to add to.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERECOMPILE on required recompilation, @p mod implemented flag is kept and
+ * is left in @p unres implementing set so that it is known that the next compilation is recompilation.
+ * @return LY_ERR on error.
+ */
+LY_ERR lys_implement(struct lys_module *mod, const char **features, struct lys_glob_unres *unres);
 
 #endif /* LY_SCHEMA_COMPILE_H_ */
diff --git a/src/schema_compile_amend.c b/src/schema_compile_amend.c
index e571546..aab32bb 100644
--- a/src/schema_compile_amend.c
+++ b/src/schema_compile_amend.c
@@ -2173,32 +2173,39 @@
 }
 
 LY_ERR
-lys_precompile_augments_deviations(struct lysc_ctx *ctx)
+lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
 {
     LY_ERR ret = LY_SUCCESS;
     LY_ARRAY_COUNT_TYPE u, v;
-    const struct lysp_module *mod_p;
-    struct lysp_module *orig_pmod;
-    struct lys_module *mod;
+    struct lysc_ctx ctx = {0};
+    struct lysp_module *mod_p;
+    struct lys_module *m;
     struct lysp_submodule *submod;
     struct lysp_node_augment *aug;
     uint32_t idx;
     struct ly_set mod_set = {0}, set = {0};
 
-    orig_pmod = ctx->pmod;
-    mod_p = ctx->cur_mod->parsed;
+    mod_p = mod->parsed;
+
+    /* prepare context */
+    ctx.ctx = mod->ctx;
+    ctx.cur_mod = mod;
+    ctx.pmod = mod_p;
+    ctx.path_len = 1;
+    ctx.path[0] = '/';
+    ctx.unres = unres;
 
     LY_LIST_FOR(mod_p->augments, aug) {
         /* get target module */
-        lysc_update_path(ctx, NULL, "{augment}");
-        lysc_update_path(ctx, NULL, aug->nodeid);
-        ret = lys_nodeid_mod_check(ctx, aug->nodeid, 1, &set, NULL, &mod);
-        lysc_update_path(ctx, NULL, NULL);
-        lysc_update_path(ctx, NULL, NULL);
+        lysc_update_path(&ctx, NULL, "{augment}");
+        lysc_update_path(&ctx, NULL, aug->nodeid);
+        ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
+        lysc_update_path(&ctx, NULL, NULL);
+        lysc_update_path(&ctx, NULL, NULL);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* add this module into the target module augmented_by, if not there and implemented */
-        if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by) != LY_EEXIST) ||
+        if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
                 !lys_precompile_mod_set_all_implemented(&set)) {
             LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
         }
@@ -2207,15 +2214,15 @@
 
     LY_ARRAY_FOR(mod_p->deviations, u) {
         /* get target module */
-        lysc_update_path(ctx, NULL, "{deviation}");
-        lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
-        ret = lys_nodeid_mod_check(ctx, mod_p->deviations[u].nodeid, 1, &set, NULL, &mod);
-        lysc_update_path(ctx, NULL, NULL);
-        lysc_update_path(ctx, NULL, NULL);
+        lysc_update_path(&ctx, NULL, "{deviation}");
+        lysc_update_path(&ctx, NULL, mod_p->deviations[u].nodeid);
+        ret = lys_nodeid_mod_check(&ctx, mod_p->deviations[u].nodeid, 1, &set, NULL, &m);
+        lysc_update_path(&ctx, NULL, NULL);
+        lysc_update_path(&ctx, NULL, NULL);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* add this module into the target module deviated_by, if not there and implemented */
-        if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by) != LY_EEXIST) ||
+        if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
                 !lys_precompile_mod_set_all_implemented(&set)) {
             LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
         }
@@ -2225,17 +2232,17 @@
     /* the same for augments and deviations in submodules */
     LY_ARRAY_FOR(mod_p->includes, v) {
         submod = mod_p->includes[v].submodule;
-        ctx->pmod = (struct lysp_module *)submod;
+        ctx.pmod = (struct lysp_module *)submod;
 
         LY_LIST_FOR(submod->augments, aug) {
-            lysc_update_path(ctx, NULL, "{augment}");
-            lysc_update_path(ctx, NULL, aug->nodeid);
-            ret = lys_nodeid_mod_check(ctx, aug->nodeid, 1, &set, NULL, &mod);
-            lysc_update_path(ctx, NULL, NULL);
-            lysc_update_path(ctx, NULL, NULL);
+            lysc_update_path(&ctx, NULL, "{augment}");
+            lysc_update_path(&ctx, NULL, aug->nodeid);
+            ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
+            lysc_update_path(&ctx, NULL, NULL);
+            lysc_update_path(&ctx, NULL, NULL);
             LY_CHECK_GOTO(ret, cleanup);
 
-            if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by) != LY_EEXIST) ||
+            if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
                     !lys_precompile_mod_set_all_implemented(&set)) {
                 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
             }
@@ -2243,14 +2250,14 @@
         }
 
         LY_ARRAY_FOR(submod->deviations, u) {
-            lysc_update_path(ctx, NULL, "{deviation}");
-            lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
-            ret = lys_nodeid_mod_check(ctx, submod->deviations[u].nodeid, 1, &set, NULL, &mod);
-            lysc_update_path(ctx, NULL, NULL);
-            lysc_update_path(ctx, NULL, NULL);
+            lysc_update_path(&ctx, NULL, "{deviation}");
+            lysc_update_path(&ctx, NULL, submod->deviations[u].nodeid);
+            ret = lys_nodeid_mod_check(&ctx, submod->deviations[u].nodeid, 1, &set, NULL, &m);
+            lysc_update_path(&ctx, NULL, NULL);
+            lysc_update_path(&ctx, NULL, NULL);
             LY_CHECK_GOTO(ret, cleanup);
 
-            if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by) != LY_EEXIST) ||
+            if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
                     !lys_precompile_mod_set_all_implemented(&set)) {
                 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
             }
@@ -2263,33 +2270,29 @@
         idx = mod_set.count;
         do {
             --idx;
-            mod = mod_set.objs[idx];
+            m = mod_set.objs[idx];
 
-            if (mod == ctx->cur_mod) {
+            if (m == mod) {
                 /* will be applied normally later */
                 continue;
             }
 
-            if (!mod->implemented) {
+            if (!m->implemented) {
                 /* implement (compile) the target module with our augments/deviations */
-                LY_CHECK_GOTO(ret = lys_implement(mod, NULL, ctx->unres), cleanup);
-            } else if (!ctx->unres->full_compilation) {
+                LY_CHECK_GOTO(ret = lys_implement(m, NULL, unres), cleanup);
+            } else if (!unres->full_compilation) {
                 /* target module was already compiled, we need to recompile it */
-                ctx->unres->recompile = 1;
+                ret = LY_ERECOMPILE;
+                goto cleanup;
             }
             /* else the module is implemented and was compiled in this compilation run or will yet be;
              * we actually do not need the module compiled now because its compiled nodes will not be accessed,
              * augments/deviations are applied during the target module compilation and the rest is in global unres */
 
-            if (ctx->unres->recompile) {
-                /* we need some module recompiled and cannot continue */
-                goto cleanup;
-            }
         } while (idx);
     }
 
 cleanup:
-    ctx->pmod = orig_pmod;
     ly_set_erase(&set, NULL);
     ly_set_erase(&mod_set, NULL);
     return ret;
diff --git a/src/schema_compile_amend.h b/src/schema_compile_amend.h
index 98da72e..3dca22c 100644
--- a/src/schema_compile_amend.h
+++ b/src/schema_compile_amend.h
@@ -23,6 +23,7 @@
 struct lysc_node;
 struct lysc_ctx;
 struct lysp_node_uses;
+struct lys_glob_unres;
 struct lys_module;
 
 /**
@@ -155,14 +156,16 @@
 LY_ERR lys_precompile_own_deviations(struct lysc_ctx *ctx);
 
 /**
- * @brief Compile top-level augments and deviations defined in the current module.
- * Generally, just add the module refence to the target modules. But in case
- * of foreign augments, they are directly applied.
+ * @brief Compile top-level augments and deviations in a module and all its submodules.
+ * Adds the module reference to the target modules and if not implemented, implement them.
  *
- * @param[in] ctx Compile context.
- * @return LY_ERR value.
+ * @param[in] mod Module to process.
+ * @param[in] unres Global unres to use.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERECOMPILE on required recompilation.
+ * @return LY_ERR on error.
  */
-LY_ERR lys_precompile_augments_deviations(struct lysc_ctx *ctx);
+LY_ERR lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres);
 
 /**
  * @brief Revert precompilation of module augments and deviations. Meaning remove its reference from
diff --git a/src/tree_schema.c b/src/tree_schema.c
index cde2fa2..986e83c 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -798,61 +798,10 @@
 }
 
 LY_ERR
-lys_implement(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
-{
-    LY_ERR ret;
-    struct lys_module *m;
-
-    if (mod->implemented) {
-        /* nothing to do */
-        return LY_SUCCESS;
-    }
-
-    /* we have module from the current context */
-    m = ly_ctx_get_module_implemented(mod->ctx, mod->name);
-    if (m) {
-        assert(m != mod);
-
-        /* check collision with other implemented revision */
-        LOGERR(mod->ctx, LY_EDENIED, "Module \"%s%s%s\" is present in the context in other implemented revision (%s).",
-                mod->name, mod->revision ? "@" : "", mod->revision ? mod->revision : "", m->revision ? m->revision : "none");
-        return LY_EDENIED;
-    }
-
-    /* set features */
-    ret = lys_set_features(mod->parsed, features);
-    if (ret && (ret != LY_EEXIST)) {
-        return ret;
-    }
-
-    if (mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE) {
-        /* do not compile the module yet */
-        mod->to_compile = 1;
-        return LY_SUCCESS;
-    }
-
-    /* add the module into newly implemented module set */
-    LY_CHECK_RET(ly_set_add(&unres->implementing, mod, 1, NULL));
-
-    /* mark the module implemented, check for collision was already done */
-    mod->implemented = 1;
-
-    /* compile the schema */
-    LY_CHECK_RET(lys_compile(mod, 0, 0, unres));
-
-    /* new module is implemented and compiled */
-    unres->full_compilation = 0;
-
-    return LY_SUCCESS;
-}
-
-API LY_ERR
-lys_set_implemented(struct lys_module *mod, const char **features)
+_lys_set_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
 {
     LY_ERR ret = LY_SUCCESS, r;
-    struct lys_glob_unres unres = {0};
-
-    LY_CHECK_ARG_RET(NULL, mod, LY_EINVAL);
+    uint32_t i;
 
     if (mod->implemented) {
         /* mod is already implemented, set the features */
@@ -875,19 +824,63 @@
         }
     }
 
-    /* implement this module and any other required modules, recursively */
-    ret = lys_implement(mod, features, &unres);
+    /* implement */
+    ret = lys_implement(mod, features, unres);
+    if (ret == LY_ERECOMPILE) {
+        /* recompile */
+        LY_CHECK_GOTO(ret = lys_recompile(mod->ctx, 1), cleanup);
 
-    /* the first module being implemented is finished, resolve global unres, consolidate the set */
-    if (!ret) {
-        ret = lys_compile_unres_glob(mod->ctx, &unres);
+        /* reset unres, it is no longer valid after recompilation and recompilation has actually resolved it all */
+        lys_compile_unres_glob_erase(mod->ctx, unres, 1);
+        unres->full_compilation = 1;
+    } else if (ret) {
+        goto cleanup;
     }
+
+    if (mod->ctx->flags & LY_CTX_ALL_IMPLEMENTED) {
+        /* implement all the imports as well */
+        for (i = 0; i < unres->creating.count; ++i) {
+            mod = unres->creating.objs[i];
+            if (mod->implemented) {
+                continue;
+            }
+
+            ret = lys_implement(mod, NULL, unres);
+            if (ret == LY_ERECOMPILE) {
+                LY_CHECK_GOTO(ret = lys_recompile(mod->ctx, 1), cleanup);
+
+                lys_compile_unres_glob_erase(mod->ctx, unres, 1);
+                unres->full_compilation = 1;
+            } else if (ret) {
+                goto cleanup;
+            }
+        }
+    }
+
+    /* resolve unres */
+    LY_CHECK_GOTO(ret = lys_compile_unres_glob(mod->ctx, unres), cleanup);
+
+cleanup:
+    return ret;
+}
+
+API LY_ERR
+lys_set_implemented(struct lys_module *mod, const char **features)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lys_glob_unres unres = {0};
+
+    LY_CHECK_ARG_RET(NULL, mod, LY_EINVAL);
+
+    /* implement */
+    ret = _lys_set_implemented(mod, features, &unres);
+    LY_CHECK_GOTO(ret, cleanup);
+
+cleanup:
     if (ret) {
-        /* failure, full compile revert */
         lys_compile_unres_glob_revert(mod->ctx, &unres);
     }
-
-    lys_compile_unres_glob_erase(mod->ctx, &unres);
+    lys_compile_unres_glob_erase(mod->ctx, &unres, 0);
     return ret;
 }
 
@@ -1437,7 +1430,7 @@
 API LY_ERR
 lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const char **features, const struct lys_module **module)
 {
-    LY_ERR ret;
+    LY_ERR ret = LY_SUCCESS;
     struct lys_module *mod;
     struct lys_glob_unres unres = {0};
 
@@ -1457,11 +1450,7 @@
     LY_CHECK_GOTO(ret, cleanup);
 
     /* implement */
-    ret = lys_implement(mod, features, &unres);
-    LY_CHECK_GOTO(ret, cleanup);
-
-    /* resolve global unres */
-    ret = lys_compile_unres_glob(ctx, &unres);
+    ret = _lys_set_implemented(mod, features, &unres);
     LY_CHECK_GOTO(ret, cleanup);
 
 cleanup:
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 9501ee8..a39e67c 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -524,15 +524,15 @@
 const char *lys_datatype2str(LY_DATA_TYPE basetype);
 
 /**
- * @brief Implement a module, can be called recursively.
+ * @brief Implement a module and resolve all global unres.
  *
  * @param[in] mod Module to implement.
  * @param[in] features Features to set, see ::lys_set_features().
- * @param[in,out] unres Global unres to add to.
- * @return LY_ERECOMPILE if unres->recompile dep set needs to be recompiled.
+ * @param[in] unres Global unres with all the created modules.
+ * @return LY_SUCCESS on success.
  * @return LY_ERR on error.
  */
-LY_ERR lys_implement(struct lys_module *mod, const char **features, struct lys_glob_unres *unres);
+LY_ERR _lys_set_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres);
 
 typedef LY_ERR (*lys_custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod,
         void *check_data);