forked from lix-project/lix
libexpr: throw a more helpful eval-error if a builtin is not available due to a missing feature-flag
I found it somewhat confusing to have an error like error: attribute 'getFlake' missing if the required experimental-feature (`flakes`) is not enabled. Instead, I'd expect Nix to throw an error just like it's the case when using e.g. `nix flake` without `flakes` being enabled. With this change, the error looks like this: $ nix-instantiate -E 'builtins.getFlake "nixpkgs"' error: Cannot call 'builtins.getFlake' because experimental Nix feature 'flakes' is disabled. You can enable it via '--extra-experimental-features flakes'. at «string»:1:1: 1| builtins.getFlake "nixpkgs" | ^ I didn't use `settings.requireExperimentalFeature` here on purpose because this doesn't contain a position. Also, it doesn't seem as if we need to catch the error and check for the missing feature here since this already happens at evaluation time.
This commit is contained in:
parent
a0bb5c4130
commit
2b02ce0e48
|
@ -465,6 +465,23 @@ EvalState::~EvalState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EvalState::requireExperimentalFeatureOnEvaluation(
|
||||||
|
const std::string & feature,
|
||||||
|
const std::string_view fName,
|
||||||
|
const Pos & pos)
|
||||||
|
{
|
||||||
|
if (!settings.isExperimentalFeatureEnabled(feature)) {
|
||||||
|
throw EvalError({
|
||||||
|
.msg = hintfmt(
|
||||||
|
"Cannot call '%2%' because experimental Nix feature '%1%' is disabled. You can enable it via '--extra-experimental-features %1%'.",
|
||||||
|
feature,
|
||||||
|
fName
|
||||||
|
),
|
||||||
|
.errPos = pos
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Path EvalState::checkSourcePath(const Path & path_)
|
Path EvalState::checkSourcePath(const Path & path_)
|
||||||
{
|
{
|
||||||
if (!allowedPaths) return path_;
|
if (!allowedPaths) return path_;
|
||||||
|
|
|
@ -140,6 +140,12 @@ public:
|
||||||
std::shared_ptr<Store> buildStore = nullptr);
|
std::shared_ptr<Store> buildStore = nullptr);
|
||||||
~EvalState();
|
~EvalState();
|
||||||
|
|
||||||
|
void requireExperimentalFeatureOnEvaluation(
|
||||||
|
const std::string & feature,
|
||||||
|
const std::string_view fName,
|
||||||
|
const Pos & pos
|
||||||
|
);
|
||||||
|
|
||||||
void addToSearchPath(const string & s);
|
void addToSearchPath(const string & s);
|
||||||
|
|
||||||
SearchPath getSearchPath() { return searchPath; }
|
SearchPath getSearchPath() { return searchPath; }
|
||||||
|
|
|
@ -688,6 +688,8 @@ void callFlake(EvalState & state,
|
||||||
|
|
||||||
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
|
state.requireExperimentalFeatureOnEvaluation("flakes", "builtins.getFlake", pos);
|
||||||
|
|
||||||
auto flakeRefS = state.forceStringNoCtx(*args[0], pos);
|
auto flakeRefS = state.forceStringNoCtx(*args[0], pos);
|
||||||
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
|
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
|
||||||
if (evalSettings.pureEval && !flakeRef.input.isImmutable())
|
if (evalSettings.pureEval && !flakeRef.input.isImmutable())
|
||||||
|
@ -703,7 +705,7 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
v);
|
v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp r2("__getFlake", 1, prim_getFlake, "flakes");
|
static RegisterPrimOp r2("__getFlake", 1, prim_getFlake);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3606,15 +3606,13 @@ static RegisterPrimOp primop_splitVersion({
|
||||||
RegisterPrimOp::PrimOps * RegisterPrimOp::primOps;
|
RegisterPrimOp::PrimOps * RegisterPrimOp::primOps;
|
||||||
|
|
||||||
|
|
||||||
RegisterPrimOp::RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun,
|
RegisterPrimOp::RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun)
|
||||||
std::optional<std::string> requiredFeature)
|
|
||||||
{
|
{
|
||||||
if (!primOps) primOps = new PrimOps;
|
if (!primOps) primOps = new PrimOps;
|
||||||
primOps->push_back({
|
primOps->push_back({
|
||||||
.name = name,
|
.name = name,
|
||||||
.args = {},
|
.args = {},
|
||||||
.arity = arity,
|
.arity = arity,
|
||||||
.requiredFeature = std::move(requiredFeature),
|
|
||||||
.fun = fun
|
.fun = fun
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3688,7 +3686,6 @@ void EvalState::createBaseEnv()
|
||||||
|
|
||||||
if (RegisterPrimOp::primOps)
|
if (RegisterPrimOp::primOps)
|
||||||
for (auto & primOp : *RegisterPrimOp::primOps)
|
for (auto & primOp : *RegisterPrimOp::primOps)
|
||||||
if (!primOp.requiredFeature || settings.isExperimentalFeatureEnabled(*primOp.requiredFeature))
|
|
||||||
addPrimOp({
|
addPrimOp({
|
||||||
.fun = primOp.fun,
|
.fun = primOp.fun,
|
||||||
.arity = std::max(primOp.args.size(), primOp.arity),
|
.arity = std::max(primOp.args.size(), primOp.arity),
|
||||||
|
|
|
@ -15,7 +15,6 @@ struct RegisterPrimOp
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
size_t arity = 0;
|
size_t arity = 0;
|
||||||
const char * doc;
|
const char * doc;
|
||||||
std::optional<std::string> requiredFeature;
|
|
||||||
PrimOpFun fun;
|
PrimOpFun fun;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,8 +27,7 @@ struct RegisterPrimOp
|
||||||
RegisterPrimOp(
|
RegisterPrimOp(
|
||||||
std::string name,
|
std::string name,
|
||||||
size_t arity,
|
size_t arity,
|
||||||
PrimOpFun fun,
|
PrimOpFun fun);
|
||||||
std::optional<std::string> requiredFeature = {});
|
|
||||||
|
|
||||||
RegisterPrimOp(Info && info);
|
RegisterPrimOp(Info && info);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue