prometeu-studio/docs/compiler/pbs/agendas/18.5. Ignored Call Results in Executable Lowering Agenda.md
2026-03-24 13:42:56 +00:00

128 lines
4.4 KiB
Markdown

# Ignored Call Results in Executable Lowering Agenda
## Status
Open
## Domain Owner
`docs/compiler/pbs`
Este tema pertence ao domínio PBS do compiler porque afeta:
- semântica prática de `expression statement`;
- lowering executável para `IRBackend`/`IRVM`;
- ergonomia de uso de SDKs e hosts que retornam status;
- compatibilidade entre o que o código-fonte parece permitir e o que o pipeline realmente aceita.
## Problema
Hoje uma chamada com retorno usada como statement isolado pode deixar valor sobrando na stack no lowering executável.
Exemplo real:
```pbs
Gfx.set_sprite(...);
```
No estado atual, isso compila no frontend, mas pode falhar no pipeline backend com erro de validação de stack no `RET` da função, porque o resultado da call não foi consumido explicitamente.
Isso cria uma inconsistência operacional:
1. o código parece válido para o autor;
2. o frontend aceita a forma;
3. o backend exige, na prática, um consumo manual do retorno, por exemplo:
```pbs
let sprite_status = Gfx.set_sprite(...);
```
## Contexto
O problema apareceu ao migrar o consumo de sprite em PBS para o contrato novo de `Gfx.set_sprite`, que retorna um status inteiro.
Os pontos observados no código atual são:
- `ExpressionStatement` faz lowering apenas da expressão;
- o lowering de `CallExpr` emite `CALL_HOST`, `CALL_FUNC` ou `CALL_INTRINSIC` com `retSlots`;
- não há descarte automático do valor quando a expressão é usada apenas como statement;
- o validador de `IRVM` exige que funções `void` retornem com stack height `0`.
Na prática, isso transforma "ignorar retorno" em comportamento parcialmente suportado pela linguagem, mas não suportado pelo pipeline executável.
## Opções
### Opção A
Manter o comportamento atual e exigir consumo explícito de todo retorno em PBS.
### Opção B
Permitir que `expression statements` descartem automaticamente o resultado quando a expressão produzir valor.
### Opção C
Permitir descarte automático apenas para um subconjunto de calls, como hosts/SDKs anotados como status descartável.
## Tradeoffs
### Opção A
- Prós:
- regra simples no backend;
- evita descarte implícito sem intenção.
- Contras:
- ergonomia ruim para APIs baseadas em status;
- surpresa para autores, porque `foo();` parece natural mas falha mais tarde;
- expõe detalhe de stack do backend ao código-fonte.
### Opção B
- Prós:
- comportamento esperado para statement de expressão;
- reduz ruído em código de jogo e SDK;
- alinha parsing, semântica prática e lowering executável.
- Contras:
- introduz descarte implícito;
- exige regra clara para saber quando emitir `POP`.
### Opção C
- Prós:
- mais controle semântico;
- evita descarte implícito amplo.
- Contras:
- adiciona complexidade de contrato e metadata;
- mistura política de produto/API dentro do lowering;
- não resolve a expectativa geral sobre `expression statement`.
## Recomendação
Seguir com a **Opção B**.
Direção recomendada:
1. `expression statement` deve ser permitido mesmo quando a expressão produzir valor;
2. o lowering executável deve emitir descarte explícito do resultado não usado;
3. a regra deve ser geral para expressões com resultado materializado em stack, não especial para `Gfx.set_sprite`;
4. testes de regressão devem cobrir host calls, callable calls e intrinsics com retorno ignorado.
Essa direção preserva a ergonomia esperada da linguagem e remove um vazamento indevido do modelo de stack do backend para o código PBS.
## Perguntas em Aberto
1. O descarte automático deve valer para qualquer `expression statement` com valor ou apenas para formas lowerables em v1?
2. O frontend semântico deve emitir algum warning opcional para retorno ignorado, ou isso fica fora do escopo atual?
3. O descarte deve acontecer somente no lowering executável ou também virar regra explícita de spec para statements?
4. Existe algum caso em que o descarte automático possa mascarar bug real de usuário que hoje seria detectado mais cedo?
## Próximo Passo Sugerido
Converter esta agenda em uma `decision` do domínio `compiler/pbs` fechando a política para `expression statement` com resultado ignorado.
Depois disso, abrir um `pull-request/plan` curto para:
1. ajustar o lowering de `ExpressionStatement`;
2. adicionar fixtures e testes de regressão no frontend/backend pipeline;
3. propagar a regra para specs relevantes de statements e lowering.