Skip to content

Commit

Permalink
[cleanup] Simplify HasLambdaCapture.
Browse files Browse the repository at this point in the history
  • Loading branch information
pfusik committed Oct 6, 2024
1 parent 5271ddb commit 30f3659
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 102 deletions.
37 changes: 12 additions & 25 deletions GenCpp.fu
Original file line number Diff line number Diff line change
Expand Up @@ -1482,42 +1482,32 @@ public class GenCpp : GenCCpp
base.VisitBinaryExpr(expr, parent);
}

static bool HasLambdaCapture(FuExpr expr, List<FuVar>! 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;
}
Expand All @@ -1526,10 +1516,7 @@ public class GenCpp : GenCCpp
internal override void VisitLambdaExpr!(FuLambdaExpr expr)
{
WriteChar('[');
List<FuVar>() 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) {
Expand Down
33 changes: 11 additions & 22 deletions libfut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15080,51 +15080,40 @@ void GenCpp::visitBinaryExpr(const FuBinaryExpr * expr, FuPriority parent)
GenBase::visitBinaryExpr(expr, parent);
}

bool GenCpp::hasLambdaCapture(const FuExpr * expr, std::vector<const FuVar *> * lambdaVars)
bool GenCpp::hasLambdaCapture(const FuExpr * expr, const FuLambdaExpr * lambda)
{
if (const FuAggregateInitializer *init = dynamic_cast<const FuAggregateInitializer *>(expr))
return std::any_of(init->items.begin(), init->items.end(), [&](const std::shared_ptr<FuExpr> &item) { return hasLambdaCapture(item.get(), lambdaVars); });
return std::any_of(init->items.begin(), init->items.end(), [&](const std::shared_ptr<FuExpr> &item) { return hasLambdaCapture(item.get(), lambda); });
else if (dynamic_cast<const FuLiteral *>(expr) || dynamic_cast<const FuLambdaExpr *>(expr))
return false;
else if (const FuInterpolatedString *interp = dynamic_cast<const FuInterpolatedString *>(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<const FuSymbolReference *>(expr)) {
if (symbol->left != nullptr)
return hasLambdaCapture(symbol->left.get(), lambdaVars);
return hasLambdaCapture(symbol->left.get(), lambda);
if (const FuMember *member = dynamic_cast<const FuMember *>(symbol->symbol))
return !member->isStatic();
else if (const FuVar *def = dynamic_cast<const FuVar *>(symbol->symbol))
return !(std::find(lambdaVars->begin(), lambdaVars->end(), def) != lambdaVars->end());
else
return false;
return dynamic_cast<const FuVar *>(symbol->symbol) && symbol->symbol->parent != lambda;
}
else if (const FuUnaryExpr *unary = dynamic_cast<const FuUnaryExpr *>(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<const FuBinaryExpr *>(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<const FuVar *>(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<const FuSelectExpr *>(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<const FuCallExpr *>(expr))
return hasLambdaCapture(call->method.get(), lambdaVars) || std::any_of(call->arguments.begin(), call->arguments.end(), [&](const std::shared_ptr<FuExpr> &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<FuExpr> &arg) { return hasLambdaCapture(arg.get(), lambda); });
else
std::abort();
}

void GenCpp::visitLambdaExpr(const FuLambdaExpr * expr)
{
writeChar('[');
std::vector<const FuVar *> lambdaVars;
const FuVar * it = static_cast<const FuVar *>(expr->first);
lambdaVars.push_back(it);
if (hasLambdaCapture(expr->body.get(), &lambdaVars))
if (hasLambdaCapture(expr->body.get(), expr))
writeChar('&');
write("](");
if (dynamic_cast<const FuOwningType *>(expr->first->type.get()) || expr->first->type->id == FuId::stringStorageType) {
Expand Down
37 changes: 12 additions & 25 deletions libfut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15424,42 +15424,32 @@ internal override void VisitBinaryExpr(FuBinaryExpr expr, FuPriority parent)
base.VisitBinaryExpr(expr, parent);
}

static bool HasLambdaCapture(FuExpr expr, List<FuVar> 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();
}
Expand All @@ -15468,10 +15458,7 @@ static bool HasLambdaCapture(FuExpr expr, List<FuVar> lambdaVars)
internal override void VisitLambdaExpr(FuLambdaExpr expr)
{
WriteChar('[');
List<FuVar> lambdaVars = new List<FuVar>();
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) {
Expand Down
2 changes: 1 addition & 1 deletion libfut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const FuVar *> * lambdaVars);
static bool hasLambdaCapture(const FuExpr * expr, const FuLambdaExpr * lambda);
static bool isIsVar(const FuExpr * expr);
bool hasVariables(const FuStatement * statement) const;
void openNamespace();
Expand Down
41 changes: 13 additions & 28 deletions libfut.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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) {
Expand Down
9 changes: 8 additions & 1 deletion test/ListAny.fu
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
}


0 comments on commit 30f3659

Please sign in to comment.