Add ValueType checking functions for types that have the same NormalType

This commit is contained in:
Silvan Mosberger 2020-12-12 02:15:11 +01:00
parent 22ead43a0b
commit bf98903967
No known key found for this signature in database
GPG key ID: E8F1E9EAD284E17D
8 changed files with 40 additions and 26 deletions

View file

@ -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");
} }

View file

@ -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;
} }

View file

@ -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 {

View file

@ -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;

View file

@ -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;

View file

@ -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() ||

View file

@ -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;

View file

@ -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();