diff --git a/lix/libexpr/nixexpr.hh b/lix/libexpr/nixexpr.hh index 22527368c..76345a422 100644 --- a/lix/libexpr/nixexpr.hh +++ b/lix/libexpr/nixexpr.hh @@ -49,12 +49,14 @@ struct Expr protected: Expr(Expr &&) = default; Expr & operator=(Expr &&) = default; + Expr(const PosIdx pos) : pos(pos) {}; public: struct AstSymbols { Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body, overrides; }; + PosIdx pos; Expr() = default; Expr(const Expr &) = delete; @@ -66,7 +68,7 @@ public: virtual void eval(EvalState & state, Env & env, Value & v); virtual Value * maybeThunk(EvalState & state, Env & env); virtual void setName(Symbol name); - virtual PosIdx getPos() const { return noPos; } + PosIdx getPos() const { return pos; } }; #define COMMON_METHODS \ @@ -78,11 +80,12 @@ struct ExprLiteral : Expr { protected: Value v; - ExprLiteral() = default; + ExprLiteral(const PosIdx pos) : Expr(pos) {}; public: - ExprLiteral(NewValueAs::integer_t, NixInt n) { v.mkInt(n); }; - ExprLiteral(NewValueAs::integer_t, NixInt::Inner n) { v.mkInt(n); }; - ExprLiteral(NewValueAs::floating_t, NixFloat nf) { v.mkFloat(nf); }; + + ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt n) : Expr(pos) { v.mkInt(n); }; + ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt::Inner n) : Expr(pos) { v.mkInt(n); }; + ExprLiteral(const PosIdx pos, NewValueAs::floating_t, NixFloat nf) : Expr(pos) { v.mkFloat(nf); }; Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -90,13 +93,13 @@ public: struct ExprString : ExprLiteral { std::string s; - ExprString(std::string &&s) : s(std::move(s)) { v.mkString(this->s.data()); }; + ExprString(const PosIdx pos, std::string &&s) : ExprLiteral(pos), s(std::move(s)) { v.mkString(this->s.data()); }; }; struct ExprPath : ExprLiteral { std::string s; - ExprPath(std::string s) : s(std::move(s)) { v.mkPath(this->s.c_str()); }; + ExprPath(const PosIdx pos, std::string s) : ExprLiteral(pos), s(std::move(s)) { v.mkPath(this->s.c_str()); }; }; typedef uint32_t Level; @@ -104,7 +107,6 @@ typedef uint32_t Displacement; struct ExprVar : Expr { - PosIdx pos; Symbol name; /* Whether the variable comes from an environment (e.g. a rec, let @@ -130,9 +132,8 @@ struct ExprVar : Expr bool needsRoot; ExprVar(Symbol name) : name(name), needsRoot(false) { }; - ExprVar(const PosIdx & pos, Symbol name, bool needsRoot = false) : pos(pos), name(name), needsRoot(needsRoot) { }; + ExprVar(const PosIdx & pos, Symbol name, bool needsRoot = false) : Expr(pos), name(name), needsRoot(needsRoot) { }; Value * maybeThunk(EvalState & state, Env & env) override; - PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -159,8 +160,6 @@ struct ExprInheritFrom : ExprVar struct ExprSelect : Expr { - PosIdx pos; - /** The expression attributes are being selected on. e.g. `foo` in `foo.bar.baz`. */ std::unique_ptr e; @@ -172,9 +171,8 @@ struct ExprSelect : Expr /** The path of attributes being selected. e.g. `bar.baz` in `foo.bar.baz.` */ AttrPath attrPath; - ExprSelect(const PosIdx & pos, std::unique_ptr e, AttrPath attrPath, std::unique_ptr def) : pos(pos), e(std::move(e)), def(std::move(def)), attrPath(std::move(attrPath)) { }; - ExprSelect(const PosIdx & pos, std::unique_ptr e, const PosIdx namePos, Symbol name) : pos(pos), e(std::move(e)) { attrPath.push_back(AttrName(namePos, name)); }; - PosIdx getPos() const override { return pos; } + ExprSelect(const PosIdx & pos, std::unique_ptr e, AttrPath attrPath, std::unique_ptr def) : Expr(pos), e(std::move(e)), def(std::move(def)), attrPath(std::move(attrPath)) { }; + ExprSelect(const PosIdx & pos, std::unique_ptr e, const PosIdx namePos, Symbol name) : Expr(pos), e(std::move(e)) { attrPath.push_back(AttrName(namePos, name)); }; COMMON_METHODS }; @@ -182,8 +180,7 @@ struct ExprOpHasAttr : Expr { std::unique_ptr e; AttrPath attrPath; - ExprOpHasAttr(std::unique_ptr e, AttrPath attrPath) : e(std::move(e)), attrPath(std::move(attrPath)) { }; - PosIdx getPos() const override { return e->getPos(); } + ExprOpHasAttr(const PosIdx & pos, std::unique_ptr e, AttrPath attrPath) : Expr(pos), e(std::move(e)), attrPath(std::move(attrPath)) { }; COMMON_METHODS }; @@ -248,26 +245,19 @@ struct ExprAttrs }; struct ExprSet : Expr, ExprAttrs { - PosIdx pos; bool recursive = false; - ExprSet(const PosIdx &pos, bool recursive = false) : pos(pos), recursive(recursive) { }; + ExprSet(const PosIdx &pos, bool recursive = false) : Expr(pos), recursive(recursive) { }; ExprSet() { }; - PosIdx getPos() const override { return pos; } COMMON_METHODS }; struct ExprList : Expr { std::vector> elems; - ExprList() { }; + ExprList(PosIdx pos) : Expr(pos) { }; COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env) override; - - PosIdx getPos() const override - { - return elems.empty() ? noPos : elems.front()->getPos(); - } }; struct Formal @@ -305,9 +295,6 @@ struct Formals struct ExprLambda : Expr { - /** Where the lambda is defined in Nix code. May be falsey if the - * position is not known. */ - PosIdx pos; /** Name of the lambda. This is set if the lambda is defined in a * let-expression or an attribute set, such that there is a name. * Lambdas may have a falsey symbol as the name if they are anonymous */ @@ -320,17 +307,16 @@ struct ExprLambda : Expr std::unique_ptr formals; std::unique_ptr body; ExprLambda(PosIdx pos, Symbol arg, std::unique_ptr formals, std::unique_ptr body) - : pos(pos), arg(arg), formals(std::move(formals)), body(std::move(body)) + : Expr(pos), arg(arg), formals(std::move(formals)), body(std::move(body)) { }; ExprLambda(PosIdx pos, std::unique_ptr formals, std::unique_ptr body) - : pos(pos), formals(std::move(formals)), body(std::move(body)) + : Expr(pos), formals(std::move(formals)), body(std::move(body)) { } void setName(Symbol name) override; std::string showNamePos(const EvalState & state) const; inline bool hasFormals() const { return formals != nullptr; } - PosIdx getPos() const override { return pos; } /** Returns the name of the lambda, * or "anonymous lambda" if it doesn't have one. @@ -363,11 +349,9 @@ struct ExprCall : Expr { std::unique_ptr fun; std::vector> args; - PosIdx pos; ExprCall(const PosIdx & pos, std::unique_ptr fun, std::vector> && args) - : fun(std::move(fun)), args(std::move(args)), pos(pos) + : Expr(pos), fun(std::move(fun)), args(std::move(args)) { } - PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -379,48 +363,40 @@ struct ExprLet : Expr, ExprAttrs struct ExprWith : Expr { - PosIdx pos; std::unique_ptr attrs, body; size_t prevWith; ExprWith * parentWith; - ExprWith(const PosIdx & pos, std::unique_ptr attrs, std::unique_ptr body) : pos(pos), attrs(std::move(attrs)), body(std::move(body)) { }; - PosIdx getPos() const override { return pos; } + ExprWith(const PosIdx & pos, std::unique_ptr attrs, std::unique_ptr body) : Expr(pos), attrs(std::move(attrs)), body(std::move(body)) { }; COMMON_METHODS }; struct ExprIf : Expr { - PosIdx pos; std::unique_ptr cond, then, else_; - ExprIf(const PosIdx & pos, std::unique_ptr cond, std::unique_ptr then, std::unique_ptr else_) : pos(pos), cond(std::move(cond)), then(std::move(then)), else_(std::move(else_)) { }; - PosIdx getPos() const override { return pos; } + ExprIf(const PosIdx & pos, std::unique_ptr cond, std::unique_ptr then, std::unique_ptr else_) : Expr(pos), cond(std::move(cond)), then(std::move(then)), else_(std::move(else_)) { }; COMMON_METHODS }; struct ExprAssert : Expr { - PosIdx pos; std::unique_ptr cond, body; - ExprAssert(const PosIdx & pos, std::unique_ptr cond, std::unique_ptr body) : pos(pos), cond(std::move(cond)), body(std::move(body)) { }; - PosIdx getPos() const override { return pos; } + ExprAssert(const PosIdx & pos, std::unique_ptr cond, std::unique_ptr body) : Expr(pos), cond(std::move(cond)), body(std::move(body)) { }; COMMON_METHODS }; struct ExprOpNot : Expr { std::unique_ptr e; - ExprOpNot(std::unique_ptr e) : e(std::move(e)) { }; - PosIdx getPos() const override { return e->getPos(); } + ExprOpNot(const PosIdx & pos, std::unique_ptr e) : Expr(pos), e(std::move(e)) { }; COMMON_METHODS }; #define MakeBinOp(name, s) \ struct name : Expr \ { \ - PosIdx pos; \ std::unique_ptr e1, e2; \ name(std::unique_ptr e1, std::unique_ptr e2) : e1(std::move(e1)), e2(std::move(e2)) { }; \ - name(const PosIdx & pos, std::unique_ptr e1, std::unique_ptr e2) : pos(pos), e1(std::move(e1)), e2(std::move(e2)) { }; \ + name(const PosIdx & pos, std::unique_ptr e1, std::unique_ptr e2) : Expr(pos), e1(std::move(e1)), e2(std::move(e2)) { }; \ nlohmann::json toJSON(const SymbolTable & symbols) const override \ { \ return { \ @@ -434,7 +410,6 @@ struct ExprOpNot : Expr e1->bindVars(es, env); e2->bindVars(es, env); \ } \ void eval(EvalState & state, Env & env, Value & v) override; \ - PosIdx getPos() const override { return pos; } \ }; MakeBinOp(ExprOpEq, "==") @@ -447,20 +422,16 @@ MakeBinOp(ExprOpConcatLists, "++") struct ExprConcatStrings : Expr { - PosIdx pos; bool forceString; std::vector>> es; ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector>> es) - : pos(pos), forceString(forceString), es(std::move(es)) { }; - PosIdx getPos() const override { return pos; } + : Expr(pos), forceString(forceString), es(std::move(es)) { }; COMMON_METHODS }; struct ExprPos : Expr { - PosIdx pos; - ExprPos(const PosIdx & pos) : pos(pos) { }; - PosIdx getPos() const override { return pos; } + ExprPos(const PosIdx & pos) : Expr(pos) { }; COMMON_METHODS }; diff --git a/lix/libexpr/parser/parser-impl1.inc.cc b/lix/libexpr/parser/parser-impl1.inc.cc index ac011c468..f5db62558 100644 --- a/lix/libexpr/parser/parser-impl1.inc.cc +++ b/lix/libexpr/parser/parser-impl1.inc.cc @@ -79,8 +79,8 @@ struct ExprState } template - std::unique_ptr applyUnary(Args &&... args) { - return std::make_unique(popExprOnly(), std::forward(args)...); + std::unique_ptr applyUnary(PosIdx pos, Args &&... args) { + return std::make_unique(pos, popExprOnly(), std::forward(args)...); } template @@ -136,7 +136,7 @@ struct ExprState std::unique_ptr negate(PosIdx pos, State & state) { std::vector> args(2); - args[0] = std::make_unique(NewValueAs::integer, 0); + args[0] = std::make_unique(pos, NewValueAs::integer, 0); args[1] = popExprOnly(); return std::make_unique(pos, state.mkInternalVar(pos, state.s.sub), std::move(args)); } @@ -144,8 +144,8 @@ struct ExprState void applyOp(PosIdx pos, auto & op, State & state) { using Op = grammar::v1::op; - auto not_ = [] (auto e) { - return std::make_unique(std::move(e)); + auto not_ = [&] (auto e) { + return std::make_unique(pos, std::move(e)); }; auto expr = (overloaded { @@ -159,13 +159,13 @@ struct ExprState [&] (Op::greater) { return order(pos, false, state); }, [&] (Op::less_eq) { return not_(order(pos, false, state)); }, [&] (Op::update) { return applyBinary(pos); }, - [&] (Op::not_) { return applyUnary(); }, + [&] (Op::not_) { return applyUnary(pos); }, [&] (Op::plus) { return concatStrings(pos); }, [&] (Op::minus) { return call(pos, state, state.s.sub); }, [&] (Op::mul) { return call(pos, state, state.s.mul); }, [&] (Op::div) { return call(pos, state, state.s.div); }, [&] (Op::concat) { return applyBinary(pos); }, - [&] (has_attr & a) { return applyUnary(std::move(a.path)); }, + [&] (has_attr & a) { return applyUnary(pos, std::move(a.path)); }, [&] (Op::unary_minus) { return negate(pos, state); }, [&] (Op::pipe_right) { return pipe(pos, state, true); }, [&] (Op::pipe_left) { return pipe(pos, state); }, @@ -186,7 +186,7 @@ struct ExprState template inline ExprT & emplaceExpr(PosIdx pos, Args && ... args) { - auto p = std::make_unique(std::forward(args)...); + auto p = std::make_unique(pos, std::forward(args)...); auto & result = *p; pushExpr(pos, std::move(p)); return result; @@ -403,9 +403,9 @@ template<> struct BuildAST { template<> struct BuildAST { static void apply(const auto & in, ExprState & s, State & ps) { if (in.string_view() == "__curPos") - s.emplaceExpr(ps.at(in), ps.at(in)); + s.emplaceExpr(ps.at(in)); else - s.emplaceExpr(ps.at(in), ps.at(in), ps.symbols.create(in.string_view())); + s.emplaceExpr(ps.at(in), ps.symbols.create(in.string_view())); } }; @@ -418,7 +418,7 @@ template<> struct BuildAST { .pos = ps.positions[ps.at(in)], }); } - s.emplaceExpr(noPos, NewValueAs::integer, v); + s.emplaceExpr(ps.at(in), NewValueAs::integer, v); } }; @@ -453,7 +453,7 @@ template<> struct BuildAST { }); } }(); - s.emplaceExpr(noPos, NewValueAs::floating, v); + s.emplaceExpr(ps.at(in), NewValueAs::floating, v); } }; @@ -502,7 +502,7 @@ struct StringState : SubexprState { { if (!currentLiteral.empty()) { unescapeStr(currentLiteral); - parts.emplace_back(currentPos, std::make_unique(std::move(currentLiteral))); + parts.emplace_back(currentPos, std::make_unique(currentPos, std::move(currentLiteral))); } } @@ -510,7 +510,7 @@ struct StringState : SubexprState { { if (parts.empty()) { unescapeStr(currentLiteral); - return std::make_unique(std::move(currentLiteral)); + return std::make_unique(currentPos, std::move(currentLiteral)); } else { endLiteral(); auto pos = parts[0].first; @@ -614,7 +614,7 @@ template<> struct BuildAST { /* add back in the trailing '/' to the first segment */ if (in.string_view().ends_with('/') && in.size() > 1) path += "/"; - s.parts.emplace_back(ps.at(in), new ExprPath(std::move(path))); + s.parts.emplace_back(ps.at(in), new ExprPath(ps.at(in), std::move(path))); } }; @@ -623,7 +623,7 @@ template<> struct BuildAST { if (evalSettings.pureEval) throw Error("the path '%s' can not be resolved in pure mode", in.string_view()); Path path(getHome() + in.string_view().substr(1)); - s.parts.emplace_back(ps.at(in), new ExprPath(std::move(path))); + s.parts.emplace_back(ps.at(in), new ExprPath(ps.at(in), std::move(path))); } }; @@ -636,7 +636,7 @@ template<> struct BuildAST { * (TODO: Provide a better and officially supported and documented mechanism for doing this) */ args[0] = std::make_unique(pos, ps.s.nixPath); - args[1] = std::make_unique(in.string()); + args[1] = std::make_unique(pos, in.string()); s.parts.emplace_back( pos, std::make_unique( @@ -670,7 +670,7 @@ template<> struct BuildAST : change_head { if (s.parts.size() == 1) { e.pushExpr(noPos, std::move(s.parts.back().second)); } else { - e.emplaceExpr(ps.at(in), ps.at(in), false, std::move(s.parts)); + e.emplaceExpr(ps.at(in), false, std::move(s.parts)); } } }; @@ -706,21 +706,21 @@ template<> struct BuildAST : change_head(pos, pos, std::make_unique(std::move(b.set)), pos, ps.s.body); + s.emplaceExpr(pos, std::make_unique(std::move(b.set)), pos, ps.s.body); } }; template<> struct BuildAST : change_head { static void success(const auto & in, BindingsStateRecSet & b, ExprState & s, State & ps) { b.set.pos = ps.at(in); - s.emplaceExpr(ps.at(in), std::move(b.set)); + s.pushExpr(ps.at(in), std::make_unique(std::move(b.set))); } }; template<> struct BuildAST : change_head { static void success(const auto & in, BindingsStateSet & b, ExprState & s, State & ps) { b.set.pos = ps.at(in); - s.emplaceExpr(ps.at(in), std::move(b.set)); + s.pushExpr(ps.at(in), std::make_unique(std::move(b.set))); } }; @@ -728,7 +728,7 @@ using ListState = std::vector>; template<> struct BuildAST : change_head { static void success(const auto & in, ListState & ls, ExprState & s, State & ps) { - auto e = std::make_unique(); + auto e = std::make_unique(ps.at(in)); e->elems = std::move(ls); s.pushExpr(ps.at(in), std::move(e)); } @@ -755,7 +755,7 @@ template<> struct BuildAST { template<> struct BuildAST : change_head { static void success0(AttrState & a, SelectState & s, State &) { - s.e = &s->emplaceExpr(s.pos, s.pos, s->popExprOnly(), std::move(a.attrs), nullptr); + s.e = &s->emplaceExpr(s.pos, s->popExprOnly(), std::move(a.attrs), nullptr); } }; @@ -769,7 +769,7 @@ template<> struct BuildAST { static void apply(const auto & in, SelectState & s, State & ps) { std::vector> args(1); args[0] = std::make_unique(ps.at(in), ps.s.or_); - s->emplaceExpr(s.pos, s.pos, s->popExprOnly(), std::move(args)); + s->emplaceExpr(s.pos, s->popExprOnly(), std::move(args)); } }; @@ -803,7 +803,7 @@ template<> struct BuildAST { } else { std::vector> args{1}; args[0] = std::move(arg); - s.e = &s->emplaceExpr(s.pos, s.pos, std::move(fn), std::move(args)); + s.e = &s->emplaceExpr(s.pos, std::move(fn), std::move(args)); } } }; @@ -839,21 +839,21 @@ template<> struct BuildAST : change_head static void success(const auto & in, LambdaState & l, ExprState & s, State & ps) { if (l.formals) l.formals = ps.validateFormals(std::move(l.formals), ps.at(in), l.arg); - s.emplaceExpr(ps.at(in), ps.at(in), l.arg, std::move(l.formals), l->popExprOnly()); + s.emplaceExpr(ps.at(in), l.arg, std::move(l.formals), l->popExprOnly()); } }; template<> struct BuildAST { static void apply(const auto & in, ExprState & s, State & ps) { auto body = s.popExprOnly(), cond = s.popExprOnly(); - s.emplaceExpr(ps.at(in), ps.at(in), std::move(cond), std::move(body)); + s.emplaceExpr(ps.at(in), std::move(cond), std::move(body)); } }; template<> struct BuildAST { static void apply(const auto & in, ExprState & s, State & ps) { auto body = s.popExprOnly(), scope = s.popExprOnly(); - s.emplaceExpr(ps.at(in), ps.at(in), std::move(scope), std::move(body)); + s.emplaceExpr(ps.at(in), std::move(scope), std::move(body)); } }; @@ -865,14 +865,15 @@ template<> struct BuildAST : change_headpopExprOnly(); - s.emplaceExpr(ps.at(in), std::move(b.let)); + b.let.pos = ps.at(in); + s.pushExpr(ps.at(in), std::make_unique(std::move(b.let))); } }; template<> struct BuildAST { static void apply(const auto & in, ExprState & s, State & ps) { auto else_ = s.popExprOnly(), then = s.popExprOnly(), cond = s.popExprOnly(); - s.emplaceExpr(ps.at(in), ps.at(in), std::move(cond), std::move(then), std::move(else_)); + s.emplaceExpr(ps.at(in), std::move(cond), std::move(then), std::move(else_)); } }; diff --git a/lix/libexpr/parser/state.hh b/lix/libexpr/parser/state.hh index 098c38745..304d0ced4 100644 --- a/lix/libexpr/parser/state.hh +++ b/lix/libexpr/parser/state.hh @@ -210,7 +210,7 @@ inline std::unique_ptr State::stripIndentation( * The rest of the code relies on the final string not being empty. */ if (lines.size() == 1 && lines.front().parts.empty()) { - return std::make_unique(""); + return std::make_unique(pos, ""); } /* If the last line only contains whitespace, trim it to not cause excessive whitespace. @@ -251,7 +251,7 @@ inline std::unique_ptr State::stripIndentation( auto flush_merged = [&] () { if (!merged.empty()) { - parts.emplace_back(merged_pos, std::make_unique(std::string(merged))); + parts.emplace_back(merged_pos, std::make_unique(pos, std::string(merged))); merged.clear(); } }; diff --git a/tests/functional/lang/eval-fail-not-throws.err.exp b/tests/functional/lang/eval-fail-not-throws.err.exp index 5882a260a..adee0a493 100644 --- a/tests/functional/lang/eval-fail-not-throws.err.exp +++ b/tests/functional/lang/eval-fail-not-throws.err.exp @@ -1,8 +1,8 @@ error: … in the argument of the not operator - at /pwd/lang/eval-fail-not-throws.nix:1:4: + at /pwd/lang/eval-fail-not-throws.nix:1:1: 1| ! (throw "uh oh!") - | ^ + | ^ 2| … caused by explicit throw diff --git a/tests/unit/libexpr/value/print.cc b/tests/unit/libexpr/value/print.cc index d1d7a72dd..baba2e0d8 100644 --- a/tests/unit/libexpr/value/print.cc +++ b/tests/unit/libexpr/value/print.cc @@ -90,7 +90,7 @@ TEST_F(ValuePrintingTests, tList) TEST_F(ValuePrintingTests, vThunk) { Value vThunk; - ExprLiteral e(NewValueAs::integer, 0); + ExprLiteral e(noPos, NewValueAs::integer, 0); vThunk.mkThunk(nullptr, e); test(vThunk, "«thunk»"); @@ -113,7 +113,7 @@ TEST_F(ValuePrintingTests, vLambda) PosTable::Origin origin = evaluator.positions.addOrigin(std::monostate(), 1); auto posIdx = evaluator.positions.add(origin, 0); - ExprLambda eLambda(posIdx, createSymbol("a"), std::make_unique(), std::make_unique(NewValueAs::integer, 0)); + ExprLambda eLambda(posIdx, createSymbol("a"), std::make_unique(), std::make_unique(noPos, NewValueAs::integer, 0)); Value vLambda; vLambda.mkLambda(&env, &eLambda); @@ -550,7 +550,7 @@ TEST_F(ValuePrintingTests, ansiColorsLambda) PosTable::Origin origin = evaluator.positions.addOrigin(std::monostate(), 1); auto posIdx = evaluator.positions.add(origin, 0); - ExprLambda eLambda(posIdx, createSymbol("a"), std::make_unique(), std::make_unique(NewValueAs::integer, 0)); + ExprLambda eLambda(posIdx, createSymbol("a"), std::make_unique(), std::make_unique(noPos, NewValueAs::integer, 0)); Value vLambda; vLambda.mkLambda(&env, &eLambda); @@ -608,7 +608,7 @@ TEST_F(ValuePrintingTests, ansiColorsPrimOpApp) TEST_F(ValuePrintingTests, ansiColorsThunk) { Value v; - ExprLiteral e(NewValueAs::integer, 0); + ExprLiteral e(noPos, NewValueAs::integer, 0); v.mkThunk(nullptr, e); test(v,