libexpr: don't dynamic_cast Exprs after parsing is done

we'll want to wrap some exprs for debug purposes, and dynamic casts
cannot look through such wrappers. dedicated casting functions can.

Change-Id: I1fba0ec52d281a1b8de85a62e4948bfae536bcfc
This commit is contained in:
eldritch horrors
2025-05-01 14:28:05 +00:00
parent 2b4ef8dc11
commit 558d921dac
5 changed files with 20 additions and 8 deletions
+1 -1
View File
@@ -249,7 +249,7 @@ static Flake getFlake(
Expr & flakeExpr = state.ctx.parseExprFromFile(resolvedFlakeFile);
// Enforce that 'flake.nix' is a direct attrset, not a computation.
if (!(dynamic_cast<ExprAttrs *>(&flakeExpr))) {
if (!flakeExpr.try_cast<ExprAttrs>()) {
state.ctx.errors.make<EvalError>("file '%s' must be an attribute set", resolvedFlakeFile).debugThrow();
}
+2 -2
View File
@@ -122,8 +122,8 @@ void ExprAttrs::addBindingsToJSON(JSON & out, const SymbolTable & symbols) const
out["inherit"][symbols[i->first]] = i->second.e->toJSON(symbols);
break;
case AttrDef::Kind::InheritedFrom: {
auto & select = dynamic_cast<ExprSelect &>(*i->second.e);
auto & from = dynamic_cast<ExprInheritFrom &>(*select.e);
auto & select = i->second.e->cast<ExprSelect>();
auto & from = select.e->cast<ExprInheritFrom>();
inheritsFrom[from.displ].push_back(i->first);
break;
}
+12
View File
@@ -65,6 +65,18 @@ public:
virtual Value * maybeThunk(EvalState & state, Env & env);
virtual void setName(Symbol name);
PosIdx getPos() const { return pos; }
template<typename E>
E & cast()
{
return dynamic_cast<E &>(*this);
}
template<typename E>
E * try_cast()
{
return dynamic_cast<E *>(this);
}
};
struct ExprLiteral : Expr
+3 -3
View File
@@ -41,10 +41,10 @@ bool Value::isTrivial() const
internalType != tApp
&& internalType != tPrimOpApp
&& (internalType != tThunk
|| (dynamic_cast<ExprSet *>(thunk.expr)
|| (thunk.expr->try_cast<ExprSet>()
&& static_cast<ExprSet *>(thunk.expr)->dynamicAttrs.empty())
|| dynamic_cast<ExprLambda *>(thunk.expr)
|| dynamic_cast<ExprList *>(thunk.expr));
|| thunk.expr->try_cast<ExprLambda>()
|| thunk.expr->try_cast<ExprList>());
}
PrimOp * Value::primOpAppPrimOp() const
+2 -2
View File
@@ -456,10 +456,10 @@ struct CmdFlakeCheck : FlakeCommand
if (!v.isLambda()) {
throw Error("overlay is not a function, but %s instead", showType(v));
}
auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body.get());
auto body = v.lambda.fun->body->try_cast<ExprLambda>();
if (!body)
throw Error("overlay is not a function with two arguments, but only takes one");
if (dynamic_cast<ExprLambda *>(body->body.get()))
if (body->body->try_cast<ExprLambda>())
throw Error("overlay is not a function with two arguments, but takes more than two");
// FIXME: if we have a 'nixpkgs' input, use it to
// evaluate the overlay.