in src/__Private/codegen/CodegenSyntax.hack [479:560]
private function generateRewriteChildrenMethod(
Schema\TAST $syntax,
): CodegenMethod {
$cg = $this->getCodegenFactory();
$fields = Vec\map($syntax['fields'], $field ==> $field['field_name']);
return $cg
->codegenMethod('rewriteChildren<Tret as ?Node>')
->setIsOverride()
->addParameter('(function(Node, vec<Node>): Tret) $rewriter')
->addParameter('vec<Node> $parents = vec[]')
->setReturnType('this')
->setBody(
$cg
->codegenHackBuilder()
->addLine('$parents[] = $this;')
->addLines(
Vec\map(
$fields,
$field ==> {
$spec = $this->getTypeSpecForField($syntax, $field);
if (!$spec['nullable']) {
return Str\format(
'$%s = $rewriter($this->_%s, $parents);',
$field,
$field,
);
}
return Str\format(
'$%s = $this->_%s === null '.
'? null : $rewriter($this->_%s, $parents);',
$field,
$field,
$field,
);
},
),
)
->addLine('if (')
->indent()
->addLines(
Vec\map(
$fields,
$field ==> Str\format('$%s === $this->_%s &&', $field, $field),
)
|> (
(vec<string> $lines) ==> {
$idx = C\last_keyx($lines);
$lines[$idx] = Str\strip_suffix($lines[$idx], ' &&');
return $lines;
}
)($$),
)
->unindent()
->addLine(') {')
->indent()
->addLine('return $this;')
->unindent()
->addLine('}')
->add('return ')
->addMultilineCall(
'new static',
Vec\map(
$fields,
$field ==> {
$type = $this->getTypeSpecForField($syntax, $field)
|> $$['nullable'] ? '?'.$$['class'] : $$['class'];
$enforceable = Str\format('$%s as %s', $field, $type);
$not_enforceable = Str\format(
'/* HH_FIXME[4110] %s may not be enforceable */ $%s',
$type,
$field,
);
return $type
|> Str\contains($$, '<') ? $not_enforceable : $enforceable;
},
),
)
->getCode(),
);
}