From 30f3659b30704ca8a55b0f5f2a554b1c20b1e63c Mon Sep 17 00:00:00 2001 From: Piotr Fusik Date: Sun, 6 Oct 2024 11:05:55 +0200 Subject: [PATCH] [cleanup] Simplify `HasLambdaCapture`. --- GenCpp.fu | 37 ++++++++++++------------------------- libfut.cpp | 33 +++++++++++---------------------- libfut.cs | 37 ++++++++++++------------------------- libfut.hpp | 2 +- libfut.js | 41 +++++++++++++---------------------------- test/ListAny.fu | 9 ++++++++- 6 files changed, 57 insertions(+), 102 deletions(-) diff --git a/GenCpp.fu b/GenCpp.fu index d201ebc6..5385017f 100644 --- a/GenCpp.fu +++ b/GenCpp.fu @@ -1482,42 +1482,32 @@ public class GenCpp : GenCCpp base.VisitBinaryExpr(expr, parent); } - static bool HasLambdaCapture(FuExpr expr, List! lambdaVars) + static bool HasLambdaCapture(FuExpr expr, FuLambdaExpr lambda) { switch (expr) { case FuAggregateInitializer init: - return init.Items.Any(item => HasLambdaCapture(item, lambdaVars)); + return init.Items.Any(item => HasLambdaCapture(item, lambda)); case FuLiteral: case FuLambdaExpr: // TODO: nested lambdas return false; case FuInterpolatedString interp: - return interp.Parts.Any(part => HasLambdaCapture(part.Argument, lambdaVars)); + return interp.Parts.Any(part => HasLambdaCapture(part.Argument, lambda)); case FuSymbolReference symbol: if (symbol.Left != null) - return HasLambdaCapture(symbol.Left, lambdaVars); - switch (symbol.Symbol) { - case FuMember member: + return HasLambdaCapture(symbol.Left, lambda); + if (symbol.Symbol is FuMember member) return !member.IsStatic(); - case FuVar def: - return !lambdaVars.Contains(def); - default: - return false; // class, enum, const - } + return symbol.Symbol is FuVar && symbol.Symbol.Parent != lambda; case FuUnaryExpr unary: - return unary.Inner != null && HasLambdaCapture(unary.Inner, lambdaVars); + return unary.Inner != null && HasLambdaCapture(unary.Inner, lambda); case FuBinaryExpr binary: - if (HasLambdaCapture(binary.Left, lambdaVars)) + if (HasLambdaCapture(binary.Left, lambda)) return true; - if (binary.Op == FuToken.Is) { - if (binary.Right is FuVar def) - lambdaVars.Add(def); - return false; - } - return HasLambdaCapture(binary.Right, lambdaVars); + return binary.Op != FuToken.Is && HasLambdaCapture(binary.Right, lambda); case FuSelectExpr select: - return HasLambdaCapture(select.Cond, lambdaVars) || HasLambdaCapture(select.OnTrue, lambdaVars) || HasLambdaCapture(select.OnFalse, lambdaVars); + return HasLambdaCapture(select.Cond, lambda) || HasLambdaCapture(select.OnTrue, lambda) || HasLambdaCapture(select.OnFalse, lambda); case FuCallExpr call: - return HasLambdaCapture(call.Method, lambdaVars) || call.Arguments.Any(arg => HasLambdaCapture(arg, lambdaVars)); + return HasLambdaCapture(call.Method, lambda) || call.Arguments.Any(arg => HasLambdaCapture(arg, lambda)); default: assert false; } @@ -1526,10 +1516,7 @@ public class GenCpp : GenCCpp internal override void VisitLambdaExpr!(FuLambdaExpr expr) { WriteChar('['); - List() lambdaVars; - assert expr.First is FuVar it; - lambdaVars.Add(it); - if (HasLambdaCapture(expr.Body, lambdaVars)) + if (HasLambdaCapture(expr.Body, expr)) WriteChar('&'); Write("]("); if (expr.First.Type is FuOwningType || expr.First.Type.Id == FuId.StringStorageType) { diff --git a/libfut.cpp b/libfut.cpp index 3ccda98e..3f9c0bff 100644 --- a/libfut.cpp +++ b/libfut.cpp @@ -15080,40 +15080,32 @@ void GenCpp::visitBinaryExpr(const FuBinaryExpr * expr, FuPriority parent) GenBase::visitBinaryExpr(expr, parent); } -bool GenCpp::hasLambdaCapture(const FuExpr * expr, std::vector * lambdaVars) +bool GenCpp::hasLambdaCapture(const FuExpr * expr, const FuLambdaExpr * lambda) { if (const FuAggregateInitializer *init = dynamic_cast(expr)) - return std::any_of(init->items.begin(), init->items.end(), [&](const std::shared_ptr &item) { return hasLambdaCapture(item.get(), lambdaVars); }); + return std::any_of(init->items.begin(), init->items.end(), [&](const std::shared_ptr &item) { return hasLambdaCapture(item.get(), lambda); }); else if (dynamic_cast(expr) || dynamic_cast(expr)) return false; else if (const FuInterpolatedString *interp = dynamic_cast(expr)) - return std::any_of(interp->parts.begin(), interp->parts.end(), [&](const FuInterpolatedPart &part) { return hasLambdaCapture(part.argument.get(), lambdaVars); }); + return std::any_of(interp->parts.begin(), interp->parts.end(), [&](const FuInterpolatedPart &part) { return hasLambdaCapture(part.argument.get(), lambda); }); else if (const FuSymbolReference *symbol = dynamic_cast(expr)) { if (symbol->left != nullptr) - return hasLambdaCapture(symbol->left.get(), lambdaVars); + return hasLambdaCapture(symbol->left.get(), lambda); if (const FuMember *member = dynamic_cast(symbol->symbol)) return !member->isStatic(); - else if (const FuVar *def = dynamic_cast(symbol->symbol)) - return !(std::find(lambdaVars->begin(), lambdaVars->end(), def) != lambdaVars->end()); - else - return false; + return dynamic_cast(symbol->symbol) && symbol->symbol->parent != lambda; } else if (const FuUnaryExpr *unary = dynamic_cast(expr)) - return unary->inner != nullptr && hasLambdaCapture(unary->inner.get(), lambdaVars); + return unary->inner != nullptr && hasLambdaCapture(unary->inner.get(), lambda); else if (const FuBinaryExpr *binary = dynamic_cast(expr)) { - if (hasLambdaCapture(binary->left.get(), lambdaVars)) + if (hasLambdaCapture(binary->left.get(), lambda)) return true; - if (binary->op == FuToken::is) { - if (const FuVar *def = dynamic_cast(binary->right.get())) - lambdaVars->push_back(def); - return false; - } - return hasLambdaCapture(binary->right.get(), lambdaVars); + return binary->op != FuToken::is && hasLambdaCapture(binary->right.get(), lambda); } else if (const FuSelectExpr *select = dynamic_cast(expr)) - return hasLambdaCapture(select->cond.get(), lambdaVars) || hasLambdaCapture(select->onTrue.get(), lambdaVars) || hasLambdaCapture(select->onFalse.get(), lambdaVars); + return hasLambdaCapture(select->cond.get(), lambda) || hasLambdaCapture(select->onTrue.get(), lambda) || hasLambdaCapture(select->onFalse.get(), lambda); else if (const FuCallExpr *call = dynamic_cast(expr)) - return hasLambdaCapture(call->method.get(), lambdaVars) || std::any_of(call->arguments.begin(), call->arguments.end(), [&](const std::shared_ptr &arg) { return hasLambdaCapture(arg.get(), lambdaVars); }); + return hasLambdaCapture(call->method.get(), lambda) || std::any_of(call->arguments.begin(), call->arguments.end(), [&](const std::shared_ptr &arg) { return hasLambdaCapture(arg.get(), lambda); }); else std::abort(); } @@ -15121,10 +15113,7 @@ bool GenCpp::hasLambdaCapture(const FuExpr * expr, std::vector * void GenCpp::visitLambdaExpr(const FuLambdaExpr * expr) { writeChar('['); - std::vector lambdaVars; - const FuVar * it = static_cast(expr->first); - lambdaVars.push_back(it); - if (hasLambdaCapture(expr->body.get(), &lambdaVars)) + if (hasLambdaCapture(expr->body.get(), expr)) writeChar('&'); write("]("); if (dynamic_cast(expr->first->type.get()) || expr->first->type->id == FuId::stringStorageType) { diff --git a/libfut.cs b/libfut.cs index 3885a1ab..3f69ce9b 100644 --- a/libfut.cs +++ b/libfut.cs @@ -15424,42 +15424,32 @@ internal override void VisitBinaryExpr(FuBinaryExpr expr, FuPriority parent) base.VisitBinaryExpr(expr, parent); } - static bool HasLambdaCapture(FuExpr expr, List lambdaVars) + static bool HasLambdaCapture(FuExpr expr, FuLambdaExpr lambda) { switch (expr) { case FuAggregateInitializer init: - return init.Items.Exists(item => HasLambdaCapture(item, lambdaVars)); + return init.Items.Exists(item => HasLambdaCapture(item, lambda)); case FuLiteral: case FuLambdaExpr: return false; case FuInterpolatedString interp: - return interp.Parts.Exists(part => HasLambdaCapture(part.Argument, lambdaVars)); + return interp.Parts.Exists(part => HasLambdaCapture(part.Argument, lambda)); case FuSymbolReference symbol: if (symbol.Left != null) - return HasLambdaCapture(symbol.Left, lambdaVars); - switch (symbol.Symbol) { - case FuMember member: + return HasLambdaCapture(symbol.Left, lambda); + if (symbol.Symbol is FuMember member) return !member.IsStatic(); - case FuVar def: - return !lambdaVars.Contains(def); - default: - return false; - } + return symbol.Symbol is FuVar && symbol.Symbol.Parent != lambda; case FuUnaryExpr unary: - return unary.Inner != null && HasLambdaCapture(unary.Inner, lambdaVars); + return unary.Inner != null && HasLambdaCapture(unary.Inner, lambda); case FuBinaryExpr binary: - if (HasLambdaCapture(binary.Left, lambdaVars)) + if (HasLambdaCapture(binary.Left, lambda)) return true; - if (binary.Op == FuToken.Is) { - if (binary.Right is FuVar def) - lambdaVars.Add(def); - return false; - } - return HasLambdaCapture(binary.Right, lambdaVars); + return binary.Op != FuToken.Is && HasLambdaCapture(binary.Right, lambda); case FuSelectExpr select: - return HasLambdaCapture(select.Cond, lambdaVars) || HasLambdaCapture(select.OnTrue, lambdaVars) || HasLambdaCapture(select.OnFalse, lambdaVars); + return HasLambdaCapture(select.Cond, lambda) || HasLambdaCapture(select.OnTrue, lambda) || HasLambdaCapture(select.OnFalse, lambda); case FuCallExpr call: - return HasLambdaCapture(call.Method, lambdaVars) || call.Arguments.Exists(arg => HasLambdaCapture(arg, lambdaVars)); + return HasLambdaCapture(call.Method, lambda) || call.Arguments.Exists(arg => HasLambdaCapture(arg, lambda)); default: throw new NotImplementedException(); } @@ -15468,10 +15458,7 @@ static bool HasLambdaCapture(FuExpr expr, List lambdaVars) internal override void VisitLambdaExpr(FuLambdaExpr expr) { WriteChar('['); - List lambdaVars = new List(); - FuVar it = (FuVar) expr.First; - lambdaVars.Add(it); - if (HasLambdaCapture(expr.Body, lambdaVars)) + if (HasLambdaCapture(expr.Body, expr)) WriteChar('&'); Write("]("); if (expr.First.Type is FuOwningType || expr.First.Type.Id == FuId.StringStorageType) { diff --git a/libfut.hpp b/libfut.hpp index 592061a4..81f391f0 100644 --- a/libfut.hpp +++ b/libfut.hpp @@ -2452,7 +2452,7 @@ class GenCpp : public GenCCpp void writeMatchProperty(const FuSymbolReference * expr, std::string_view name); void writeGtRawPtr(const FuExpr * expr); void writeIsVar(const FuExpr * expr, const FuVar * def, FuPriority parent); - static bool hasLambdaCapture(const FuExpr * expr, std::vector * lambdaVars); + static bool hasLambdaCapture(const FuExpr * expr, const FuLambdaExpr * lambda); static bool isIsVar(const FuExpr * expr); bool hasVariables(const FuStatement * statement) const; void openNamespace(); diff --git a/libfut.js b/libfut.js index 698f25b4..4286779a 100644 --- a/libfut.js +++ b/libfut.js @@ -15906,56 +15906,44 @@ export class GenCpp extends GenCCpp super.visitBinaryExpr(expr, parent); } - static #hasLambdaCapture(expr, lambdaVars) + static #hasLambdaCapture(expr, lambda) { if (expr instanceof FuAggregateInitializer) { const init = expr; - return init.items.some(item => GenCpp.#hasLambdaCapture(item, lambdaVars)); + return init.items.some(item => GenCpp.#hasLambdaCapture(item, lambda)); } else if (expr instanceof FuLiteral || expr instanceof FuLambdaExpr) return false; else if (expr instanceof FuInterpolatedString) { const interp = expr; - return interp.parts.some(part => GenCpp.#hasLambdaCapture(part.argument, lambdaVars)); + return interp.parts.some(part => GenCpp.#hasLambdaCapture(part.argument, lambda)); } else if (expr instanceof FuSymbolReference) { const symbol = expr; if (symbol.left != null) - return GenCpp.#hasLambdaCapture(symbol.left, lambdaVars); - if (symbol.symbol instanceof FuMember) { - const member = symbol.symbol; + return GenCpp.#hasLambdaCapture(symbol.left, lambda); + let member; + if ((member = symbol.symbol) instanceof FuMember) return !member.isStatic(); - } - else if (symbol.symbol instanceof FuVar) { - const def = symbol.symbol; - return !lambdaVars.includes(def); - } - else - return false; + return symbol.symbol instanceof FuVar && symbol.symbol.parent != lambda; } else if (expr instanceof FuUnaryExpr) { const unary = expr; - return unary.inner != null && GenCpp.#hasLambdaCapture(unary.inner, lambdaVars); + return unary.inner != null && GenCpp.#hasLambdaCapture(unary.inner, lambda); } else if (expr instanceof FuBinaryExpr) { const binary = expr; - if (GenCpp.#hasLambdaCapture(binary.left, lambdaVars)) + if (GenCpp.#hasLambdaCapture(binary.left, lambda)) return true; - if (binary.op == FuToken.IS) { - let def; - if ((def = binary.right) instanceof FuVar) - lambdaVars.push(def); - return false; - } - return GenCpp.#hasLambdaCapture(binary.right, lambdaVars); + return binary.op != FuToken.IS && GenCpp.#hasLambdaCapture(binary.right, lambda); } else if (expr instanceof FuSelectExpr) { const select = expr; - return GenCpp.#hasLambdaCapture(select.cond, lambdaVars) || GenCpp.#hasLambdaCapture(select.onTrue, lambdaVars) || GenCpp.#hasLambdaCapture(select.onFalse, lambdaVars); + return GenCpp.#hasLambdaCapture(select.cond, lambda) || GenCpp.#hasLambdaCapture(select.onTrue, lambda) || GenCpp.#hasLambdaCapture(select.onFalse, lambda); } else if (expr instanceof FuCallExpr) { const call = expr; - return GenCpp.#hasLambdaCapture(call.method, lambdaVars) || call.arguments_.some(arg => GenCpp.#hasLambdaCapture(arg, lambdaVars)); + return GenCpp.#hasLambdaCapture(call.method, lambda) || call.arguments_.some(arg => GenCpp.#hasLambdaCapture(arg, lambda)); } else throw new Error(); @@ -15964,10 +15952,7 @@ export class GenCpp extends GenCCpp visitLambdaExpr(expr) { this.writeChar(91); - const lambdaVars = []; - let it = expr.first; - lambdaVars.push(it); - if (GenCpp.#hasLambdaCapture(expr.body, lambdaVars)) + if (GenCpp.#hasLambdaCapture(expr.body, expr)) this.writeChar(38); this.write("]("); if (expr.first.type instanceof FuOwningType || expr.first.type.id == FuId.STRING_STORAGE_TYPE) { diff --git a/test/ListAny.fu b/test/ListAny.fu index 65dce60a..a37d6081 100644 --- a/test/ListAny.fu +++ b/test/ListAny.fu @@ -34,6 +34,13 @@ public class Test && !empty.Any(it => true) && !listRo.Any(it => true) && CaptureParam(42) - && t.CaptureThis(); + && t.CaptureThis() + && list.Any(it => !(it is Derived)); } } + +public class Derived : Test +{ +} + +