schema tree REFACTOR always parse and implement separately
diff --git a/src/context.c b/src/context.c
index ac62cac..a4a9049 100644
--- a/src/context.c
+++ b/src/context.c
@@ -194,7 +194,11 @@
 
     LY_CHECK_ARG_RET(ctx, ctx, name, NULL);
 
-    LY_CHECK_GOTO(ret = lys_load_module(ctx, name, revision, 1, features, &unres, &result), cleanup);
+    /* parse */
+    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);
@@ -279,8 +283,10 @@
     /* load internal modules */
     for (i = 0; i < ((options & LY_CTX_NO_YANGLIBRARY) ? (LY_INTERNAL_MODS_COUNT - 2) : LY_INTERNAL_MODS_COUNT); i++) {
         ly_in_memory(in, internal_modules[i].data);
-        LY_CHECK_GOTO(rc = lys_create_module(ctx, in, internal_modules[i].format, internal_modules[i].implemented,
-                NULL, NULL, NULL, &unres, &module), error);
+        LY_CHECK_GOTO(rc = lys_parse_in(ctx, in, internal_modules[i].format, NULL, NULL, &unres, &module), error);
+        if (internal_modules[i].implemented || (ctx->flags & LY_CTX_ALL_IMPLEMENTED)) {
+            LY_CHECK_GOTO(rc = lys_implement(module, NULL, &unres), error);
+        }
     }
 
     /* resolve global unres */
diff --git a/src/path.c b/src/path.c
index 4109f73..9500422 100644
--- a/src/path.c
+++ b/src/path.c
@@ -431,7 +431,7 @@
             }
 
             assert(unres);
-            LY_CHECK_GOTO(ret = lys_set_implemented_r((struct lys_module *)*mod, NULL, unres), error);
+            LY_CHECK_GOTO(ret = lys_implement((struct lys_module *)*mod, NULL, unres), error);
             if (unres->recompile) {
                 return LY_ERECOMPILE;
             }
diff --git a/src/plugins_types.c b/src/plugins_types.c
index a2cf0f3..adfeb17 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -751,7 +751,7 @@
 API LY_ERR
 lyplg_type_make_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
 {
-    LY_CHECK_RET(lys_set_implemented_r(mod, features, unres));
+    LY_CHECK_RET(lys_implement(mod, features, unres));
 
     if (unres->recompile) {
         return LY_ERECOMPILE;
diff --git a/src/schema_compile.c b/src/schema_compile.c
index d7312da..11c317c 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -836,7 +836,7 @@
         if (!mod->implemented) {
             /* unimplemented module found */
             if (implement) {
-                LY_CHECK_RET(lys_set_implemented_r((struct lys_module *)mod, NULL, unres));
+                LY_CHECK_RET(lys_implement((struct lys_module *)mod, NULL, unres));
                 if (unres->recompile) {
                     return LY_ERECOMPILE;
                 }
diff --git a/src/schema_compile_amend.c b/src/schema_compile_amend.c
index 1ea084b..e571546 100644
--- a/src/schema_compile_amend.c
+++ b/src/schema_compile_amend.c
@@ -2272,7 +2272,7 @@
 
             if (!mod->implemented) {
                 /* implement (compile) the target module with our augments/deviations */
-                LY_CHECK_GOTO(ret = lys_set_implemented_r(mod, NULL, ctx->unres), cleanup);
+                LY_CHECK_GOTO(ret = lys_implement(mod, NULL, ctx->unres), cleanup);
             } else if (!ctx->unres->full_compilation) {
                 /* target module was already compiled, we need to recompile it */
                 ctx->unres->recompile = 1;
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 4a57cc4..d2ed415 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -798,11 +798,15 @@
 }
 
 LY_ERR
-lys_set_implemented_r(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
+lys_implement(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
 {
+    LY_ERR ret;
     struct lys_module *m;
 
-    assert(!mod->implemented);
+    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);
@@ -815,8 +819,11 @@
         return LY_EDENIED;
     }
 
-    /* enable features */
-    LY_CHECK_RET(lys_enable_features(mod->parsed, features));
+    /* 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 */
@@ -869,7 +876,7 @@
     }
 
     /* implement this module and any other required modules, recursively */
-    ret = lys_set_implemented_r(mod, features, &unres);
+    ret = lys_implement(mod, features, &unres);
 
     /* the first module being implemented is finished, resolve global unres, consolidate the set */
     if (!ret) {
@@ -894,8 +901,10 @@
     LY_ARRAY_FOR(pmod->imports, u) {
         imp = &pmod->imports[u];
         if (!imp->module) {
-            LY_CHECK_RET(lys_load_module(PARSER_CTX(pctx), imp->name, imp->rev[0] ? imp->rev : NULL, 0, NULL,
-                    pctx->unres, &imp->module));
+            LY_CHECK_RET(lys_parse_load(PARSER_CTX(pctx), imp->name, imp->rev[0] ? imp->rev : NULL, pctx->unres, &imp->module));
+            if (PARSER_CTX(pctx)->flags & LY_CTX_ALL_IMPLEMENTED) {
+                LY_CHECK_RET(lys_implement(imp->module, NULL, pctx->unres));
+            }
         }
         /* check for importing the same module twice */
         for (v = 0; v < u; ++v) {
@@ -1214,11 +1223,11 @@
 }
 
 LY_ERR
-lys_create_module(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, ly_bool need_implemented,
+lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
         LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
-        void *check_data, const char **features, struct lys_glob_unres *unres, struct lys_module **module)
+        void *check_data, struct lys_glob_unres *unres, struct lys_module **module)
 {
-    struct lys_module *mod = NULL, *latest, *mod_dup, *mod_impl;
+    struct lys_module *mod = NULL, *latest, *mod_dup;
     struct lysp_submodule *submod;
     LY_ERR ret;
     LY_ARRAY_COUNT_TYPE u;
@@ -1227,20 +1236,13 @@
     struct lys_parser_ctx *pctx = NULL;
     char *filename, *rev, *dot;
     size_t len;
-    ly_bool implement;
 
-    assert(ctx && in && (!features || need_implemented) && unres);
+    assert(ctx && in && unres);
 
     if (module) {
         *module = NULL;
     }
 
-    if (ctx->flags & LY_CTX_ALL_IMPLEMENTED) {
-        implement = 1;
-    } else {
-        implement = need_implemented;
-    }
-
     mod = calloc(1, sizeof *mod);
     LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), LY_EMEM);
     mod->ctx = ctx;
@@ -1295,29 +1297,7 @@
 
     /* check whether it is not already in the context in the same revision */
     mod_dup = (struct lys_module *)ly_ctx_get_module(ctx, mod->name, mod->revision);
-    if (implement) {
-        mod_impl = ly_ctx_get_module_implemented(ctx, mod->name);
-        if (mod_impl && (mod_impl != mod_dup)) {
-            LOGERR(ctx, LY_EDENIED, "Module \"%s@%s\" is already implemented in the context.", mod_impl->name,
-                    mod_impl->revision ? mod_impl->revision : "<none>");
-            ret = LY_EDENIED;
-            goto free_mod_cleanup;
-        }
-    }
     if (mod_dup) {
-        if (implement) {
-            if (!mod_dup->implemented) {
-                /* just implement it */
-                LY_CHECK_GOTO(ret = lys_set_implemented_r(mod_dup, features, unres), free_mod_cleanup);
-                goto free_mod_cleanup;
-            }
-
-            /* nothing to do */
-            LOGVRB("Module \"%s@%s\" is already implemented in the context.", mod_dup->name,
-                    mod_dup->revision ? mod_dup->revision : "<none>");
-            goto free_mod_cleanup;
-        }
-
         /* nothing to do */
         LOGVRB("Module \"%s@%s\" is already present in the context.", mod_dup->name,
                 mod_dup->revision ? mod_dup->revision : "<none>");
@@ -1402,11 +1382,6 @@
         LY_CHECK_GOTO(ret, cleanup);
     }
 
-    if (implement) {
-        /* implement (compile) */
-        LY_CHECK_GOTO(ret = lys_set_implemented_r(mod, features, unres), cleanup);
-    }
-
     /* success */
     goto cleanup;
 
@@ -1463,6 +1438,7 @@
 lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const char **features, const struct lys_module **module)
 {
     LY_ERR ret;
+    struct lys_module *mod;
     struct lys_glob_unres unres = {0};
 
     if (module) {
@@ -1476,7 +1452,12 @@
     /* remember input position */
     in->func_start = in->current;
 
-    ret = lys_create_module(ctx, in, format, 1, NULL, NULL, features, &unres, (struct lys_module **)module);
+    /* parse */
+    ret = lys_parse_in(ctx, in, format, NULL, NULL, &unres, &mod);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    /* implement */
+    ret = lys_implement(mod, features, &unres);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* resolve global unres */
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 14572ce..704095f 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -618,17 +618,13 @@
 }
 
 /**
- * @brief Load the (sub)module into the context.
+ * @brief Parse a (sub)module from a local file and add into the context.
  *
  * This function does not check the presence of the (sub)module in context, it should be done before calling this function.
  *
- * module_name and submodule_name are alternatives - only one of the
- *
  * @param[in] ctx libyang context where to work.
  * @param[in] name Name of the (sub)module to load.
  * @param[in] revision Optional revision of the (sub)module to load, if NULL the newest revision is being loaded.
- * @param[in] features Array of enabled features ended with NULL.
- * @param[in] need_implemented Whether the (sub)module is needed implemented or not.
  * @param[in] main_ctx Parser context of the main module in case of loading submodule.
  * @param[in] main_name Main module name in case of loading submodule.
  * @param[in] required Module is required so error (even if the input file not found) are important. If 0, there is some
@@ -636,12 +632,13 @@
  * @param[in,out] unres Global unres structure for newly implemented modules.
  * @param[out] result Parsed YANG schema tree of the requested module (struct lys_module*) or submodule (struct lysp_submodule*).
  * If it is a module, it is already in the context!
- * @return LY_ERR value, in case of LY_SUCCESS, the \arg result is always provided.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERECOMPILE if unres->recompile dep set needs to be recompiled, @p result is set.
+ * @return LY_ERR on error.
  */
 static LY_ERR
-lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, const char **features,
-        ly_bool need_implemented, struct lys_parser_ctx *main_ctx, const char *main_name, ly_bool required,
-        struct lys_glob_unres *unres, void **result)
+lys_parse_localfile(struct ly_ctx *ctx, const char *name, const char *revision, struct lys_parser_ctx *main_ctx,
+        const char *main_name, ly_bool required, struct lys_glob_unres *unres, void **result)
 {
     struct ly_in *in;
     char *filepath = NULL;
@@ -673,8 +670,7 @@
         ret = lys_parse_submodule(ctx, in, format, main_ctx, lysp_load_module_check, &check_data,
                 (struct lysp_submodule **)&mod);
     } else {
-        ret = lys_create_module(ctx, in, format, need_implemented, lysp_load_module_check, &check_data, features, unres,
-                (struct lys_module **)&mod);
+        ret = lys_parse_in(ctx, in, format, lysp_load_module_check, &check_data, unres, (struct lys_module **)&mod);
 
     }
     ly_in_free(in, 1);
@@ -690,27 +686,19 @@
 }
 
 LY_ERR
-lys_load_module(struct ly_ctx *ctx, const char *name, const char *revision, ly_bool need_implemented,
-        const char **features, struct lys_glob_unres *unres, struct lys_module **mod)
+lys_parse_load(struct ly_ctx *ctx, const char *name, const char *revision, struct lys_glob_unres *unres,
+        struct lys_module **mod)
 {
     const char *module_data = NULL;
     LYS_INFORMAT format = LYS_IN_UNKNOWN;
 
     void (*module_data_free)(void *module_data, void *user_data) = NULL;
     struct lysp_load_module_check_data check_data = {0};
-    struct lys_module *ctx_latest = NULL, *m;
+    struct lys_module *ctx_latest = NULL;
     struct ly_in *in;
-    LY_ERR ret;
-    ly_bool implement;
 
     assert(mod && unres);
 
-    if (ctx->flags & LY_CTX_ALL_IMPLEMENTED) {
-        implement = 1;
-    } else {
-        implement = need_implemented;
-    }
-
     /*
      * try to get the module from the context
      */
@@ -719,30 +707,21 @@
             /* get the specific revision */
             *mod = (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
         } else {
-            if (implement) {
-                /* prefer the implemented module instead of the latest one */
-                *mod = (struct lys_module *)ly_ctx_get_module_implemented(ctx, name);
-            }
-            if (!*mod) {
-                /* get the requested module of the latest revision in the context */
-                *mod = (struct lys_module *)ly_ctx_get_module_latest(ctx, name);
-                if (*mod && ((*mod)->latest_revision == 1)) {
-                    /* let us now search with callback and searchpaths to check if there is newer revision outside the context */
-                    ctx_latest = *mod;
-                    *mod = NULL;
-                }
+            /* get the requested module of the latest revision in the context */
+            *mod = (struct lys_module *)ly_ctx_get_module_latest(ctx, name);
+            if (*mod && ((*mod)->latest_revision == 1)) {
+                /* let us now search with callback and searchpaths to check if there is newer revision outside the context */
+                ctx_latest = *mod;
+                *mod = NULL;
             }
         }
     }
 
-    /* check collision with other implemented revision */
-    if (implement) {
-        m = ly_ctx_get_module_implemented(ctx, name);
-        if (m && (!*mod || (*mod && (m != *mod)))) {
-            LOGVAL(ctx, LYVE_REFERENCE, "Module \"%s\" is already present in other implemented revision.", name);
-            *mod = NULL;
-            return LY_EDENIED;
-        }
+    /* we have module from the current context, circular check */
+    if (*mod && (*mod)->parsed->parsing) {
+        LOGVAL(ctx, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
+        *mod = NULL;
+        return LY_EVALID;
     }
 
     /*
@@ -772,8 +751,7 @@
 search_file:
             if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
                 /* module was not received from the callback or there is no callback set */
-                lys_module_localfile(ctx, name, revision, features, implement, NULL, NULL, ctx_latest ? 0 : 1, unres,
-                        (void **)mod);
+                lys_parse_localfile(ctx, name, revision, NULL, NULL, ctx_latest ? 0 : 1, unres, (void **)mod);
             }
             if (!*mod && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
                 goto search_clb;
@@ -792,40 +770,9 @@
         }
 
         if (!*mod) {
-            LOGVAL(ctx, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
+            LOGVAL(ctx, LYVE_REFERENCE, "Loading \"%s\" module failed.", name);
             return LY_EVALID;
         }
-    } else {
-        /* we have module from the current context, circular check */
-        if ((*mod)->parsed->parsing) {
-            LOGVAL(ctx, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
-            *mod = NULL;
-            return LY_EVALID;
-        }
-    }
-
-    /*
-     * module found, make sure it is implemented if should be
-     */
-    if (implement) {
-        if (!(*mod)->implemented) {
-            /* implement */
-            ret = lys_set_implemented_r(*mod, features, unres);
-            if (ret) {
-                *mod = NULL;
-                return ret;
-            }
-        } else if (features) {
-            /* set features if different */
-            ret = lys_set_features((*mod)->parsed, features);
-            if (!ret) {
-                /* context need to be recompiled so that feature changes are properly applied */
-                unres->recompile = 1;
-            } else if (ret != LY_EEXIST) {
-                /* error */
-                return ret;
-            } /* else no feature changes */
-        }
     }
 
     return LY_SUCCESS;
@@ -1014,8 +961,7 @@
 search_file:
             if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
                 /* submodule was not received from the callback or there is no callback set */
-                lys_module_localfile(ctx, inc->name,
-                        inc->rev[0] ? inc->rev : NULL, NULL, 0, pctx,
+                lys_parse_localfile(ctx, inc->name, inc->rev[0] ? inc->rev : NULL, pctx,
                         pctx->parsed_mod->mod->name, 1, NULL, (void **)&submod);
 
                 /* update inc pointer - parsing another (YANG 1.0) submodule can cause injecting
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 642c298..f6e1bae 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -293,21 +293,18 @@
 LY_ERR lysp_check_enum_name(struct lys_parser_ctx *ctx, const char *name, size_t name_len);
 
 /**
- * @brief Find and load a module of the given name.
+ * @brief Find source data for a specific module, parse it, and add into the context.
  *
  * @param[in] ctx libyang context.
  * @param[in] name Name of the module to load.
  * @param[in] revison Optional revision of the module to load. If NULL, the newest revision is loaded.
- * @param[in] need_implemented Whether the module should be implemented. If revision is NULL and this flag is set,
- * the implemented module in the context is returned despite it might not be of the latest revision, because in this
- * case the module of the latest revision can not be made implemented.
- * @param[in] features All the features to enable if implementing the module.
- * @param[in] unres Global unres structure for all newly implemented modules.
+ * @param[in,out] unres Global unres structure.
  * @param[out] mod Created module structure.
- * @return LY_ERR value.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR on error.
  */
-LY_ERR lys_load_module(struct ly_ctx *ctx, const char *name, const char *revision, ly_bool need_implemented,
-        const char **features, struct lys_glob_unres *unres, struct lys_module **mod);
+LY_ERR lys_parse_load(struct ly_ctx *ctx, const char *name, const char *revision, struct lys_glob_unres *unres,
+        struct lys_module **mod);
 
 /**
  * @brief Parse included submodules into the simply parsed YANG module.
@@ -527,37 +524,33 @@
 const char *lys_datatype2str(LY_DATA_TYPE basetype);
 
 /**
- * @brief Implement a module (just like ::lys_set_implemented()), can be called recursively.
+ * @brief Implement a module, can be called recursively.
  *
  * @param[in] mod Module to implement.
- * @param[in] features Array of features to enable.
+ * @param[in] features Features to set, see ::lys_set_features().
  * @param[in,out] unres Global unres to add to.
- * @return LY_ERR value.
+ * @return LY_ERECOMPILE if unres->recompile dep set needs to be recompiled.
+ * @return LY_ERR on error.
  */
-LY_ERR lys_set_implemented_r(struct lys_module *mod, const char **features, struct lys_glob_unres *unres);
+LY_ERR lys_implement(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);
 
 /**
- * @brief Create a new module.
- *
- * It is parsed, opionally compiled, added into the context, and the latest_revision flag is updated.
+ * @brief Parse a module and add it into the context.
  *
  * @param[in] ctx libyang context where to process the data model.
  * @param[in] in Input structure.
  * @param[in] format Format of the input data (YANG or YIN).
- * @param[in] need_implemented Whether module needs to be implemented and compiled.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
- * @param[in] features Array of features to enable ended with NULL. NULL for all features disabled and '*' for all enabled.
  * @param[in,out] unres Global unres structure for newly implemented modules.
  * @param[out] module Created module.
  * @return LY_ERR value.
  */
-LY_ERR lys_create_module(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, ly_bool need_implemented,
-        lys_custom_check custom_check, void *check_data, const char **features, struct lys_glob_unres *unres,
-        struct lys_module **module);
+LY_ERR lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, lys_custom_check custom_check,
+        void *check_data, struct lys_glob_unres *unres, struct lys_module **module);
 
 /**
  * @brief Parse submodule.