Skip to content

Commit

Permalink
[cpp] Capture variables in nested lambdas.
Browse files Browse the repository at this point in the history
  • Loading branch information
pfusik committed Oct 6, 2024
1 parent 30f3659 commit 38cd525
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 9 deletions.
5 changes: 3 additions & 2 deletions GenCpp.fu
Original file line number Diff line number Diff line change
Expand Up @@ -1488,7 +1488,6 @@ public class GenCpp : GenCCpp
case FuAggregateInitializer init:
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, lambda));
Expand All @@ -1497,7 +1496,7 @@ public class GenCpp : GenCCpp
return HasLambdaCapture(symbol.Left, lambda);
if (symbol.Symbol is FuMember member)
return !member.IsStatic();
return symbol.Symbol is FuVar && symbol.Symbol.Parent != lambda;
return symbol.Symbol is FuVar && !lambda.Encloses(symbol.Symbol);
case FuUnaryExpr unary:
return unary.Inner != null && HasLambdaCapture(unary.Inner, lambda);
case FuBinaryExpr binary:
Expand All @@ -1508,6 +1507,8 @@ public class GenCpp : GenCCpp
return HasLambdaCapture(select.Cond, lambda) || HasLambdaCapture(select.OnTrue, lambda) || HasLambdaCapture(select.OnFalse, lambda);
case FuCallExpr call:
return HasLambdaCapture(call.Method, lambda) || call.Arguments.Any(arg => HasLambdaCapture(arg, lambda));
case FuLambdaExpr inner:
return HasLambdaCapture(inner.Body, lambda);
default:
assert false;
}
Expand Down
6 changes: 4 additions & 2 deletions libfut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15084,7 +15084,7 @@ 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(), lambda); });
else if (dynamic_cast<const FuLiteral *>(expr) || dynamic_cast<const FuLambdaExpr *>(expr))
else if (dynamic_cast<const FuLiteral *>(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(), lambda); });
Expand All @@ -15093,7 +15093,7 @@ bool GenCpp::hasLambdaCapture(const FuExpr * expr, const FuLambdaExpr * lambda)
return hasLambdaCapture(symbol->left.get(), lambda);
if (const FuMember *member = dynamic_cast<const FuMember *>(symbol->symbol))
return !member->isStatic();
return dynamic_cast<const FuVar *>(symbol->symbol) && symbol->symbol->parent != lambda;
return dynamic_cast<const FuVar *>(symbol->symbol) && !lambda->encloses(symbol->symbol);
}
else if (const FuUnaryExpr *unary = dynamic_cast<const FuUnaryExpr *>(expr))
return unary->inner != nullptr && hasLambdaCapture(unary->inner.get(), lambda);
Expand All @@ -15106,6 +15106,8 @@ bool GenCpp::hasLambdaCapture(const FuExpr * expr, const FuLambdaExpr * lambda)
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(), lambda) || std::any_of(call->arguments.begin(), call->arguments.end(), [&](const std::shared_ptr<FuExpr> &arg) { return hasLambdaCapture(arg.get(), lambda); });
else if (const FuLambdaExpr *inner = dynamic_cast<const FuLambdaExpr *>(expr))
return hasLambdaCapture(inner->body.get(), lambda);
else
std::abort();
}
Expand Down
5 changes: 3 additions & 2 deletions libfut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15430,7 +15430,6 @@ static bool HasLambdaCapture(FuExpr expr, FuLambdaExpr lambda)
case FuAggregateInitializer init:
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, lambda));
Expand All @@ -15439,7 +15438,7 @@ static bool HasLambdaCapture(FuExpr expr, FuLambdaExpr lambda)
return HasLambdaCapture(symbol.Left, lambda);
if (symbol.Symbol is FuMember member)
return !member.IsStatic();
return symbol.Symbol is FuVar && symbol.Symbol.Parent != lambda;
return symbol.Symbol is FuVar && !lambda.Encloses(symbol.Symbol);
case FuUnaryExpr unary:
return unary.Inner != null && HasLambdaCapture(unary.Inner, lambda);
case FuBinaryExpr binary:
Expand All @@ -15450,6 +15449,8 @@ static bool HasLambdaCapture(FuExpr expr, FuLambdaExpr lambda)
return HasLambdaCapture(select.Cond, lambda) || HasLambdaCapture(select.OnTrue, lambda) || HasLambdaCapture(select.OnFalse, lambda);
case FuCallExpr call:
return HasLambdaCapture(call.Method, lambda) || call.Arguments.Exists(arg => HasLambdaCapture(arg, lambda));
case FuLambdaExpr inner:
return HasLambdaCapture(inner.Body, lambda);
default:
throw new NotImplementedException();
}
Expand Down
8 changes: 6 additions & 2 deletions libfut.js
Original file line number Diff line number Diff line change
Expand Up @@ -15912,7 +15912,7 @@ export class GenCpp extends GenCCpp
const init = expr;
return init.items.some(item => GenCpp.#hasLambdaCapture(item, lambda));
}
else if (expr instanceof FuLiteral || expr instanceof FuLambdaExpr)
else if (expr instanceof FuLiteral)
return false;
else if (expr instanceof FuInterpolatedString) {
const interp = expr;
Expand All @@ -15925,7 +15925,7 @@ export class GenCpp extends GenCCpp
let member;
if ((member = symbol.symbol) instanceof FuMember)
return !member.isStatic();
return symbol.symbol instanceof FuVar && symbol.symbol.parent != lambda;
return symbol.symbol instanceof FuVar && !lambda.encloses(symbol.symbol);
}
else if (expr instanceof FuUnaryExpr) {
const unary = expr;
Expand All @@ -15945,6 +15945,10 @@ export class GenCpp extends GenCCpp
const call = expr;
return GenCpp.#hasLambdaCapture(call.method, lambda) || call.arguments_.some(arg => GenCpp.#hasLambdaCapture(arg, lambda));
}
else if (expr instanceof FuLambdaExpr) {
const inner = expr;
return GenCpp.#hasLambdaCapture(inner.body, lambda);
}
else
throw new Error();
}
Expand Down
8 changes: 7 additions & 1 deletion test/ListAny.fu
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,18 @@ public class Test
list.Add(t);
List<int>() empty;
List<Test>() listRo;
List<List<int>()>() lol;
lol.Add();
lol[0].Add(10);
int c = 10;
return list.Any(it => it.Value > 10)
&& !empty.Any(it => true)
&& !listRo.Any(it => true)
&& CaptureParam(42)
&& t.CaptureThis()
&& list.Any(it => !(it is Derived));
&& lol.Any(l => l.Any(i => i == 10))
&& !lol.Any(l => l.Any(i => i == 42))
&& lol.Any(l => l.Any(i => i == c));
}
}

Expand Down

0 comments on commit 38cd525

Please sign in to comment.