128 lines
4.4 KiB
Markdown
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.
|