captures for "when" statements

update Triggers to IntrusivePtr's and simpler AST traversal
introduce IDSet type, migrate associated "ID*" types to "const ID*"
This commit is contained in:
Vern Paxson 2022-01-07 14:50:35 -08:00
parent fa142438fe
commit f895008c34
24 changed files with 648 additions and 202 deletions

View file

@ -4588,7 +4588,8 @@ void CallExpr::ExprDescribe(ODesc* d) const
args->Describe(d);
}
LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing, IDPList arg_outer_ids)
LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing, IDPList arg_outer_ids,
StmtPtr when_parent)
: Expr(EXPR_LAMBDA)
{
ingredients = std::move(arg_ing);
@ -4596,7 +4597,7 @@ LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing, IDPList ar
SetType(ingredients->id->GetType());
CheckCaptures();
CheckCaptures(when_parent);
// Install a dummy version of the function globally for use only
// when broker provides a closure.
@ -4641,7 +4642,7 @@ LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing, IDPList ar
id->SetConst();
}
void LambdaExpr::CheckCaptures()
void LambdaExpr::CheckCaptures(StmtPtr when_parent)
{
auto ft = type->AsFuncType();
const auto& captures = ft->GetCaptures();
@ -4665,6 +4666,8 @@ void LambdaExpr::CheckCaptures()
std::set<const ID*> outer_is_matched;
std::set<const ID*> capture_is_matched;
auto desc = when_parent ? "\"when\" statement" : "lambda";
for ( const auto& c : *captures )
{
auto cid = c.id.get();
@ -4677,7 +4680,11 @@ void LambdaExpr::CheckCaptures()
if ( capture_is_matched.count(cid) > 0 )
{
ExprError(util::fmt("%s listed multiple times in capture", cid->Name()));
auto msg = util::fmt("%s listed multiple times in capture", cid->Name());
if ( when_parent )
when_parent->Error(msg);
else
ExprError(msg);
continue;
}
@ -4692,13 +4699,25 @@ void LambdaExpr::CheckCaptures()
for ( auto id : outer_ids )
if ( outer_is_matched.count(id) == 0 )
ExprError(util::fmt("%s is used inside lambda but not captured", id->Name()));
{
auto msg = util::fmt("%s is used inside %s but not captured", id->Name(), desc);
if ( when_parent )
when_parent->Error(msg);
else
ExprError(msg);
}
for ( const auto& c : *captures )
{
auto cid = c.id.get();
if ( cid && capture_is_matched.count(cid) == 0 )
ExprError(util::fmt("%s is captured but not used inside lambda", cid->Name()));
{
auto msg = util::fmt("%s is captured but not used inside %s", cid->Name(), desc);
if ( when_parent )
when_parent->Error(msg);
else
ExprError(msg);
}
}
}