in src/__Private/codegen/CodegenSyntax.hack [211:322]
private function generateFieldMethods(
Schema\TAST $syntax,
string $underscored,
): Traversable<CodegenMethod> {
$spec = $this->getTypeSpecForField($syntax, $underscored);
$upper_camel = StrP\upper_camel($underscored);
$types = $spec['possibleTypes'];
$type = $spec['nullable'] ? ('?'.$spec['class']) : $spec['class'];
// AttributeAsAttributeSpecTrait declares some abstract methods
// we need to <<__Override>> them in these classes.
$needs_override_for_attribute_methods = (
$syntax['kind_name'] === 'ParameterDeclaration' ||
$syntax['kind_name'] === 'ClassishDeclaration'
) &&
$upper_camel === 'Attribute';
$patch_in_override = (CodegenMethod $method): CodegenMethod ==> {
if ($needs_override_for_attribute_methods) {
$method->addEmptyUserAttribute('__Override');
}
return $method;
};
$cg = $this->getCodegenFactory();
yield $cg
->codegenMethodf('get%sUNTYPED', $upper_camel)
->setReturnType('?Node')
->setBodyf('return $this->_%s;', $underscored)
|> $patch_in_override($$);
yield $cg
->codegenMethodf('with%s', $upper_camel)
->setReturnType('this')
->addParameterf('%s $value', $type)
->setBody(
$cg
->codegenHackBuilder()
->startIfBlockf('$value === $this->_%s', $underscored)
->addReturnf('$this')
->endIfBlock()
->add('return new ')
->addMultilineCall(
'static',
Vec\map(
$syntax['fields'],
$inner ==> $inner['field_name'] === $underscored
? '$value'
: '$this->_'.$inner['field_name'],
),
)
->getCode(),
);
if ($spec['nullable']) {
yield $cg
->codegenMethodf('has%s', $upper_camel)
->setReturnType('bool')
->setBodyf('return $this->_%s !== null;', $underscored)
|> $patch_in_override($$);
} else {
yield $cg
->codegenMethodf('has%s', $upper_camel)
->setReturnType('bool')
->setBody('return true;');
}
if (!$spec['nullable']) {
$get = $cg
->codegenMethodf('get%s', $upper_camel)
->setDocBlock('@return '.Str\join($types, ' | '))
->setReturnType($type);
if ($spec['class'] === 'Node') {
yield $get->setBodyf('return $this->_%s;', $underscored);
} else {
yield $get->setBodyf(
'return TypeAssert\instance_of(%s::class, $this->_%s);',
$type |> Str\split($$, '<') |> C\firstx($$),
$underscored,
);
}
// For backwards compatibility: always offer getFoox, in case it was
// nullable in a previous version
yield $cg
->codegenMethodf('get%sx', $upper_camel)
->setDocBlock('@return '.Str\join($types, ' | '))
->setReturnType($type)
->setBodyf('return $this->get%s();', $upper_camel);
return;
}
yield $cg
->codegenMethodf('get%s', $upper_camel)
->setDocBlock(
Vec\map($types, $type ==> $type === 'Missing' ? 'null' : $type)
|> Str\join($$, ' | ')
|> '@return '.$$,
)
->setReturnType($type)
->setBodyf('return $this->_%s;', $underscored)
|> $patch_in_override($$);
yield $cg
->codegenMethodf('get%sx', $upper_camel)
->setDocBlock(
Vec\filter($types, $type ==> $type !== 'Missing')
|> Str\join($$, ' | ')
|> '@return '.$$,
)
->setReturnType($spec['class'])
->setBodyf('return TypeAssert\\not_null($this->get%s());', $upper_camel)
|> $patch_in_override($$);
}