# 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.