From 558d921dacd8614dd2f2e1960a3f73cedf494eb3 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Wed, 30 Apr 2025 21:07:51 +0200 Subject: [PATCH] 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 --- lix/libexpr/flake/flake.cc | 2 +- lix/libexpr/nixexpr.cc | 4 ++-- lix/libexpr/nixexpr.hh | 12 ++++++++++++ lix/libexpr/value.cc | 6 +++--- lix/nix/flake.cc | 4 ++-- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lix/libexpr/flake/flake.cc b/lix/libexpr/flake/flake.cc index 507b95b38..8981de7cb 100644 --- a/lix/libexpr/flake/flake.cc +++ b/lix/libexpr/flake/flake.cc @@ -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(&flakeExpr))) { + if (!flakeExpr.try_cast()) { state.ctx.errors.make("file '%s' must be an attribute set", resolvedFlakeFile).debugThrow(); } diff --git a/lix/libexpr/nixexpr.cc b/lix/libexpr/nixexpr.cc index 76d2e62a3..d09f9eee0 100644 --- a/lix/libexpr/nixexpr.cc +++ b/lix/libexpr/nixexpr.cc @@ -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(*i->second.e); - auto & from = dynamic_cast(*select.e); + auto & select = i->second.e->cast(); + auto & from = select.e->cast(); inheritsFrom[from.displ].push_back(i->first); break; } diff --git a/lix/libexpr/nixexpr.hh b/lix/libexpr/nixexpr.hh index f40a1fc2c..044d56db9 100644 --- a/lix/libexpr/nixexpr.hh +++ b/lix/libexpr/nixexpr.hh @@ -65,6 +65,18 @@ public: virtual Value * maybeThunk(EvalState & state, Env & env); virtual void setName(Symbol name); PosIdx getPos() const { return pos; } + + template + E & cast() + { + return dynamic_cast(*this); + } + + template + E * try_cast() + { + return dynamic_cast(this); + } }; struct ExprLiteral : Expr diff --git a/lix/libexpr/value.cc b/lix/libexpr/value.cc index 103505db7..4903db5d0 100644 --- a/lix/libexpr/value.cc +++ b/lix/libexpr/value.cc @@ -41,10 +41,10 @@ bool Value::isTrivial() const internalType != tApp && internalType != tPrimOpApp && (internalType != tThunk - || (dynamic_cast(thunk.expr) + || (thunk.expr->try_cast() && static_cast(thunk.expr)->dynamicAttrs.empty()) - || dynamic_cast(thunk.expr) - || dynamic_cast(thunk.expr)); + || thunk.expr->try_cast() + || thunk.expr->try_cast()); } PrimOp * Value::primOpAppPrimOp() const diff --git a/lix/nix/flake.cc b/lix/nix/flake.cc index 2028f336b..cbc0e2d75 100644 --- a/lix/nix/flake.cc +++ b/lix/nix/flake.cc @@ -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(v.lambda.fun->body.get()); + auto body = v.lambda.fun->body->try_cast(); if (!body) throw Error("overlay is not a function with two arguments, but only takes one"); - if (dynamic_cast(body->body.get())) + if (body->body->try_cast()) 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.