Add ValueType checking functions for types that have the same NormalType
This commit is contained in:
parent
22ead43a0b
commit
bf98903967
8 changed files with 40 additions and 26 deletions
|
@ -32,7 +32,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const
|
||||||
|
|
||||||
void EvalState::forceValue(Value & v, const Pos & pos)
|
void EvalState::forceValue(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
if (v.type == tThunk) {
|
if (v.isThunk()) {
|
||||||
Env * env = v.thunk.env;
|
Env * env = v.thunk.env;
|
||||||
Expr * expr = v.thunk.expr;
|
Expr * expr = v.thunk.expr;
|
||||||
try {
|
try {
|
||||||
|
@ -46,9 +46,9 @@ void EvalState::forceValue(Value & v, const Pos & pos)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (v.type == tApp)
|
else if (v.isApp())
|
||||||
callFunction(*v.app.left, *v.app.right, v, noPos);
|
callFunction(*v.app.left, *v.app.right, v, noPos);
|
||||||
else if (v.type == tBlackhole)
|
else if (v.isBlackhole())
|
||||||
throwEvalError(pos, "infinite recursion encountered");
|
throwEvalError(pos, "infinite recursion encountered");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,10 +158,10 @@ std::ostream & operator << (std::ostream & str, const Value & v)
|
||||||
|
|
||||||
const Value *getPrimOp(const Value &v) {
|
const Value *getPrimOp(const Value &v) {
|
||||||
const Value * primOp = &v;
|
const Value * primOp = &v;
|
||||||
while (primOp->type == tPrimOpApp) {
|
while (primOp->isPrimOpApp()) {
|
||||||
primOp = primOp->primOpApp.left;
|
primOp = primOp->primOpApp.left;
|
||||||
}
|
}
|
||||||
assert(primOp->type == tPrimOp);
|
assert(primOp->isPrimOp());
|
||||||
return primOp;
|
return primOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,9 +601,9 @@ Value & EvalState::getBuiltin(const string & name)
|
||||||
|
|
||||||
std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
|
std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
|
||||||
{
|
{
|
||||||
if (v.type == tPrimOp || v.type == tPrimOpApp) {
|
if (v.isPrimOp() || v.isPrimOpApp()) {
|
||||||
auto v2 = &v;
|
auto v2 = &v;
|
||||||
while (v2->type == tPrimOpApp)
|
while (v2->isPrimOpApp())
|
||||||
v2 = v2->primOpApp.left;
|
v2 = v2->primOpApp.left;
|
||||||
if (v2->primOp->doc)
|
if (v2->primOp->doc)
|
||||||
return Doc {
|
return Doc {
|
||||||
|
@ -1227,11 +1227,11 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos)
|
||||||
/* Figure out the number of arguments still needed. */
|
/* Figure out the number of arguments still needed. */
|
||||||
size_t argsDone = 0;
|
size_t argsDone = 0;
|
||||||
Value * primOp = &fun;
|
Value * primOp = &fun;
|
||||||
while (primOp->type == tPrimOpApp) {
|
while (primOp->isPrimOpApp()) {
|
||||||
argsDone++;
|
argsDone++;
|
||||||
primOp = primOp->primOpApp.left;
|
primOp = primOp->primOpApp.left;
|
||||||
}
|
}
|
||||||
assert(primOp->type == tPrimOp);
|
assert(primOp->isPrimOp());
|
||||||
auto arity = primOp->primOp->arity;
|
auto arity = primOp->primOp->arity;
|
||||||
auto argsLeft = arity - argsDone;
|
auto argsLeft = arity - argsDone;
|
||||||
|
|
||||||
|
@ -1242,7 +1242,7 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos)
|
||||||
Value * vArgs[arity];
|
Value * vArgs[arity];
|
||||||
auto n = arity - 1;
|
auto n = arity - 1;
|
||||||
vArgs[n--] = &arg;
|
vArgs[n--] = &arg;
|
||||||
for (Value * arg = &fun; arg->type == tPrimOpApp; arg = arg->primOpApp.left)
|
for (Value * arg = &fun; arg->isPrimOpApp(); arg = arg->primOpApp.left)
|
||||||
vArgs[n--] = arg->primOpApp.right;
|
vArgs[n--] = arg->primOpApp.right;
|
||||||
|
|
||||||
/* And call the primop. */
|
/* And call the primop. */
|
||||||
|
@ -1264,7 +1264,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
|
||||||
|
|
||||||
forceValue(fun, pos);
|
forceValue(fun, pos);
|
||||||
|
|
||||||
if (fun.type == tPrimOp || fun.type == tPrimOpApp) {
|
if (fun.isPrimOp() || fun.isPrimOpApp()) {
|
||||||
callPrimOp(fun, arg, v, pos);
|
callPrimOp(fun, arg, v, pos);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1285,7 +1285,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fun.type != tLambda)
|
if (!fun.isLambda())
|
||||||
throwTypeError(pos, "attempt to call something which is not a function but %1%", fun);
|
throwTypeError(pos, "attempt to call something which is not a function but %1%", fun);
|
||||||
|
|
||||||
ExprLambda & lambda(*fun.lambda.fun);
|
ExprLambda & lambda(*fun.lambda.fun);
|
||||||
|
@ -1378,7 +1378,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fun.type != tLambda || !fun.lambda.fun->matchAttrs) {
|
if (!fun.isLambda() || !fun.lambda.fun->matchAttrs) {
|
||||||
res = fun;
|
res = fun;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ static std::tuple<fetchers::Tree, FlakeRef, FlakeRef> fetchOrSubstituteTree(
|
||||||
|
|
||||||
static void forceTrivialValue(EvalState & state, Value & value, const Pos & pos)
|
static void forceTrivialValue(EvalState & state, Value & value, const Pos & pos)
|
||||||
{
|
{
|
||||||
if (value.type == tThunk && value.isTrivial())
|
if (value.isThunk() && value.isTrivial())
|
||||||
state.forceValue(value, pos);
|
state.forceValue(value, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ static Flake getFlake(
|
||||||
if (auto outputs = vInfo.attrs->get(sOutputs)) {
|
if (auto outputs = vInfo.attrs->get(sOutputs)) {
|
||||||
expectType(state, nFunction, *outputs->value, *outputs->pos);
|
expectType(state, nFunction, *outputs->value, *outputs->pos);
|
||||||
|
|
||||||
if (outputs->value->type == tLambda && outputs->value->lambda.fun->matchAttrs) {
|
if (outputs->value->isLambda() && outputs->value->lambda.fun->matchAttrs) {
|
||||||
for (auto & formal : outputs->value->lambda.fun->formals->formals) {
|
for (auto & formal : outputs->value->lambda.fun->formals->formals) {
|
||||||
if (formal.name != state.sSelf)
|
if (formal.name != state.sSelf)
|
||||||
flake.inputs.emplace(formal.name, FlakeInput {
|
flake.inputs.emplace(formal.name, FlakeInput {
|
||||||
|
|
|
@ -2239,11 +2239,11 @@ static RegisterPrimOp primop_catAttrs({
|
||||||
static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceValue(*args[0], pos);
|
state.forceValue(*args[0], pos);
|
||||||
if (args[0]->type == tPrimOpApp || args[0]->type == tPrimOp) {
|
if (args[0]->isPrimOpApp() || args[0]->isPrimOp()) {
|
||||||
state.mkAttrs(v, 0);
|
state.mkAttrs(v, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (args[0]->type != tLambda)
|
if (!args[0]->isLambda())
|
||||||
throw TypeError({
|
throw TypeError({
|
||||||
.hint = hintfmt("'functionArgs' requires a function"),
|
.hint = hintfmt("'functionArgs' requires a function"),
|
||||||
.errPos = pos
|
.errPos = pos
|
||||||
|
@ -2674,7 +2674,7 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
|
||||||
auto comparator = [&](Value * a, Value * b) {
|
auto comparator = [&](Value * a, Value * b) {
|
||||||
/* Optimization: if the comparator is lessThan, bypass
|
/* Optimization: if the comparator is lessThan, bypass
|
||||||
callFunction. */
|
callFunction. */
|
||||||
if (args[0]->type == tPrimOp && args[0]->primOp->fun == prim_lessThan)
|
if (args[0]->isPrimOp() && args[0]->primOp->fun == prim_lessThan)
|
||||||
return CompareValues()(a, b);
|
return CompareValues()(a, b);
|
||||||
|
|
||||||
Value vTmp1, vTmp2;
|
Value vTmp1, vTmp2;
|
||||||
|
|
|
@ -126,6 +126,20 @@ struct Value
|
||||||
inline void setExternal() { type = tExternal; };
|
inline void setExternal() { type = tExternal; };
|
||||||
inline void setFloat() { type = tFloat; };
|
inline void setFloat() { type = tFloat; };
|
||||||
|
|
||||||
|
// Functions needed to distinguish the type
|
||||||
|
// These should be removed eventually, by putting the functionality that's
|
||||||
|
// needed by callers into methods of this type
|
||||||
|
|
||||||
|
// normalType() == nThunk
|
||||||
|
inline bool isThunk() const { return type == tThunk; };
|
||||||
|
inline bool isApp() const { return type == tApp; };
|
||||||
|
inline bool isBlackhole() const { return type == tBlackhole; };
|
||||||
|
|
||||||
|
// normalType() == nFunction
|
||||||
|
inline bool isLambda() const { return type == tLambda; };
|
||||||
|
inline bool isPrimOp() const { return type == tPrimOp; };
|
||||||
|
inline bool isPrimOpApp() const { return type == tPrimOpApp; };
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
NixInt integer;
|
NixInt integer;
|
||||||
|
|
|
@ -260,7 +260,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
||||||
try {
|
try {
|
||||||
state->forceValue(v, pos);
|
state->forceValue(v, pos);
|
||||||
if (v.type != tLambda || v.lambda.fun->matchAttrs || std::string(v.lambda.fun->arg) != "final")
|
if (!v.isLambda() || v.lambda.fun->matchAttrs || std::string(v.lambda.fun->arg) != "final")
|
||||||
throw Error("overlay does not take an argument named 'final'");
|
throw Error("overlay does not take an argument named 'final'");
|
||||||
auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body);
|
auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body);
|
||||||
if (!body || body->matchAttrs || std::string(body->arg) != "prev")
|
if (!body || body->matchAttrs || std::string(body->arg) != "prev")
|
||||||
|
@ -276,7 +276,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
auto checkModule = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
auto checkModule = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
||||||
try {
|
try {
|
||||||
state->forceValue(v, pos);
|
state->forceValue(v, pos);
|
||||||
if (v.type == tLambda) {
|
if (v.isLambda()) {
|
||||||
if (!v.lambda.fun->matchAttrs || !v.lambda.fun->formals->ellipsis)
|
if (!v.lambda.fun->matchAttrs || !v.lambda.fun->formals->ellipsis)
|
||||||
throw Error("module must match an open attribute set ('{ config, ... }')");
|
throw Error("module must match an open attribute set ('{ config, ... }')");
|
||||||
} else if (v.normalType() == nAttrs) {
|
} else if (v.normalType() == nAttrs) {
|
||||||
|
@ -371,7 +371,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
auto checkBundler = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
auto checkBundler = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
||||||
try {
|
try {
|
||||||
state->forceValue(v, pos);
|
state->forceValue(v, pos);
|
||||||
if (v.type != tLambda)
|
if (!v.isLambda())
|
||||||
throw Error("bundler must be a function");
|
throw Error("bundler must be a function");
|
||||||
if (!v.lambda.fun->formals ||
|
if (!v.lambda.fun->formals ||
|
||||||
v.lambda.fun->formals->argNames.find(state->symbols.create("program")) == v.lambda.fun->formals->argNames.end() ||
|
v.lambda.fun->formals->argNames.find(state->symbols.create("program")) == v.lambda.fun->formals->argNames.end() ||
|
||||||
|
|
|
@ -272,7 +272,7 @@ void mainWrapped(int argc, char * * argv)
|
||||||
auto builtins = state.baseEnv.values[0]->attrs;
|
auto builtins = state.baseEnv.values[0]->attrs;
|
||||||
for (auto & builtin : *builtins) {
|
for (auto & builtin : *builtins) {
|
||||||
auto b = nlohmann::json::object();
|
auto b = nlohmann::json::object();
|
||||||
if (builtin.value->type != tPrimOp) continue;
|
if (!builtin.value->isPrimOp()) continue;
|
||||||
auto primOp = builtin.value->primOp;
|
auto primOp = builtin.value->primOp;
|
||||||
if (!primOp->doc) continue;
|
if (!primOp->doc) continue;
|
||||||
b["arity"] = primOp->arity;
|
b["arity"] = primOp->arity;
|
||||||
|
|
|
@ -450,7 +450,7 @@ bool NixRepl::processLine(string line)
|
||||||
PathSet context;
|
PathSet context;
|
||||||
auto filename = state->coerceToString(noPos, v, context);
|
auto filename = state->coerceToString(noPos, v, context);
|
||||||
pos.file = state->symbols.create(filename);
|
pos.file = state->symbols.create(filename);
|
||||||
} else if (v.type == tLambda) {
|
} else if (v.isLambda()) {
|
||||||
pos = v.lambda.fun->pos;
|
pos = v.lambda.fun->pos;
|
||||||
} else {
|
} else {
|
||||||
// assume it's a derivation
|
// assume it's a derivation
|
||||||
|
@ -760,13 +760,13 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nFunction:
|
case nFunction:
|
||||||
if (v.type == tLambda) {
|
if (v.isLambda()) {
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
s << v.lambda.fun->pos;
|
s << v.lambda.fun->pos;
|
||||||
str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL;
|
str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL;
|
||||||
} else if (v.type == tPrimOp) {
|
} else if (v.isPrimOp()) {
|
||||||
str << ANSI_MAGENTA "«primop»" ANSI_NORMAL;
|
str << ANSI_MAGENTA "«primop»" ANSI_NORMAL;
|
||||||
} else if (v.type == tPrimOpApp) {
|
} else if (v.isPrimOpApp()) {
|
||||||
str << ANSI_BLUE "«primop-app»" ANSI_NORMAL;
|
str << ANSI_BLUE "«primop-app»" ANSI_NORMAL;
|
||||||
} else {
|
} else {
|
||||||
abort();
|
abort();
|
||||||
|
|
Loading…
Reference in a new issue