13 KiB
PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda
Status
Open
Parent Agenda
This agenda derives from:
19. Globals, Synthetic Module Init, and FRAME_RET Agenda
Expected fixed input from previous stage:
19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda
Purpose
Define the observable lifecycle model of PBS once runtime globals exist.
This agenda must close:
- whether
[Init]and[Frame]become official source markers; - the relationship between module init and program init;
- boot one-shot behavior;
- failure policy;
- and the semantic role of the user's frame root.
Domain Owner
docs/compiler/pbs
Este tema pertence ao domínio PBS porque define lifecycle observável da linguagem, não apenas mecanismo de backend.
Context
Depois que declare global existir como storage runtime de módulo, o compiler precisará definir:
- quando os globals são materializados;
- em que ordem isso acontece;
- se existe um hook explícito de init de programa;
- se existe um init procedural por módulo separado do initializer declarativo de
global; - como a linguagem identifica o frame root do usuário;
- e o que acontece quando o boot falha.
Esta agenda ainda não decide a forma exata do wrapper published entrypoint nem o shape do IR. Ela define primeiro o comportamento observável que essas camadas posteriores terão de respeitar.
Inputs Already Fixed Elsewhere
Os seguintes inputs devem ser tratados como fechados ou fortemente estáveis aqui:
- o modelo base de globals vindo de
19.1; - o initializer declarativo de
globalpermanece restrito a primitivas,newe leitura de outras globals compatíveis com o dep graph; - top-level
fnnão são permitidas em initializer deglobalem v1; FRAME_SYNCpermanece como safepoint normativo;- PBS v1 continua determinístico e single-threaded;
- esta fase continua evitando mudanças novas no runtime.
Decisions To Produce
Esta agenda deve produzir direção suficiente para fechar:
- se
[Init]e[Frame]entram na surface oficial; - targets válidos, unicidade e assinaturas exigidas;
- ordem entre module init, init de programa e frame;
- política de boot one-shot;
- política de falha;
- papel semântico de
frame()do usuário; - política de loops e host calls admissíveis durante init.
Core Questions
- PBS deve introduzir
[Init]e[Frame]como atributos reservados? [Init]deve ser permitido tanto por módulo quanto no init final de projeto?[Frame]deve existir exatamente uma vez por programa?[Init]deve existir no máximo uma vez por programa?[Init]e[Frame]devem exigir assinatura fixafn ...() -> void?- Todos os module inits devem rodar antes do
[Init]do usuário? - A ausência de
[Init]deve ser válida? - A ausência de
[Frame]deve ser erro hard para programa executável? - Em caso de falha durante module init ou
[Init], o programa deve falhar definitivamente ou pode haver retry? - Qual é a definição semântica correta de
frame()do usuário: root lógico do tick, callable publicado, ou apenas callable invocado por infraestrutura sintética futura? - Loops devem ser permitidos em init de módulo e init de projeto?
- Host calls devem ser proibidas por padrão durante init?
- Apenas host calls marcadas com
[InitAllowed]devem ser admissíveis durante init? - Como a admissibilidade de
[InitAllowed]é validada em compile time?
Options
Option A
Introduzir [Init] e [Frame] como markers reservados explícitos, com assinaturas fixas, [Init] opcional por módulo e por projeto, [Frame] obrigatório e único por projeto executável, permitindo init procedural por módulo e mantendo política restritiva de host interaction durante init.
Option B
Introduzir apenas [Frame] e manter init inteiramente sintético, sem hook de programa do usuário nesta fase.
Option C
Manter lifecycle implícito, sem markers source-level, e continuar derivando entrypoint/configuração fora da linguagem.
Tradeoffs
Option A
- Prós:
- deixa lifecycle explícito na linguagem;
- reduz dependência de configuração paralela;
- dá base clara para wrapper, manifest e lowering posteriores.
- Contras:
- amplia a surface de atributos reservados;
- exige validação de target, unicidade e assinatura.
Option B
- Prós:
- escopo menor;
- adia parte da discussão de init.
- Contras:
- resolve só metade do lifecycle;
- pode forçar redesign quando o hook de init do usuário voltar.
Option C
- Prós:
- menor custo imediato.
- Contras:
- mantém a autoridade do lifecycle fora da linguagem;
- enfraquece a coerência da série 19.
Recommendation
Seguir com a Option A.
Direção recomendada:
[Init]e[Frame]devem ser markers reservados explícitos;declare globalsempre lowera para o init sintético do módulo owner;[Init]de módulo deve ser opcional e executar depois de todos osdeclare globaldo módulo;- o init de projeto deve seguir o mesmo modelo, mas associado ao projeto que contém o
[Frame]; [Init]de projeto deve ser opcional;[Frame]deve ser obrigatório para programa executável e único por projeto;[Init]e[Frame]devem exigir assinatura fixafn name() -> void;- boot deve ser one-shot;
- falha de boot deve seguir direção fail-fast, salvo argumento forte em contrário;
- loops devem ser permitidos em init de módulo e init de projeto;
- host calls devem ser proibidas por padrão durante init;
- apenas host calls com atributo reservado
[InitAllowed]devem ser admissíveis durante init; [InitAllowed]é atributo reservado de SDK, não userland.
Additional Lifecycle Concerns
Esta agenda também precisa fechar a separação entre três camadas de bootstrap:
- initializer declarativo de
global; - init por módulo;
- init de projeto.
Direção herdada da 19.1:
globalmaterializa storage inicial;- init de módulo executa lógica procedural de conveniência sobre globals do próprio módulo;
- init de projeto executa coordenação final do programa.
Com esse modelo:
- loops são legítimos em init de módulo e init de projeto, especialmente para carga e preparação de arrays e estruturas derivadas;
- a restrição normativa mais forte deve cair sobre host interaction;
- "bootstrap leve" continua sendo recomendação de design, não um limite impossível de verificar semanticamente.
Current Direction
Os pontos abaixo já podem ser tratados como direção fechada desta agenda, salvo objeção nova forte:
[Init]e[Frame]entram como atributos reservados explícitos;declare global X: T = expr;lowera sempre para o init sintético do módulo owner;- cada arquivo pode declarar opcionalmente um
[Init]procedural próprio; - o
[Init]de cada arquivo roda sempre depois das globals daquele arquivo e participa do init sintético do módulo; - existe também um init de projeto opcional, que é o
[Init]associado ao projeto que contém o[Frame]; [Frame]é obrigatório e único por projeto executável;[Init]e[Frame]seguem a forma recomendada:
[Init]
fn init() -> void { ... }
[Frame]
fn frame() -> void { ... }
- a assinatura exigida é sempre
fn name() -> void; - loops são permitidos nos inits;
- host calls são proibidas por padrão durante init;
- apenas host calls com
[InitAllowed]podem ser usadas durante init; [InitAllowed]pertence às superfícies reservadas de SDK, não a userland;- falha de boot é fail-fast com mensagem coerente.
Também fica fechada a seguinte regra operacional:
- o
[Init]que estiver no mesmo arquivo que o[Frame]é o init de projeto; [Init]em outros arquivos continuam sendo init de módulo;[Frame]e o init de projeto devem ser co-localizados no mesmo arquivo por decisão deliberada de source organization.- cada arquivo pode declarar no máximo um
[Init]; - cada módulo possui exatamente um init sintético de módulo, dentro do qual os inits por arquivo são ordenados e compostos;
- a distinção entre init de módulo e init de projeto é apenas de ordenação e papel semântico, não de surface diferente;
- como consequência, existe no máximo um
[Init]de projeto por projeto executável. - arquivos sem globals podem declarar um
[Init], desde que continuem respeitando a regra de no máximo um[Init]por arquivo; - o
project initsegue exatamente a mesma assinaturafn init() -> void.
Lifecycle Order Direction
Esta agenda também já aponta para a seguinte ordem lógica de bootstrap:
- materialização das globals de cada arquivo do módulo conforme a ordem determinada pelo dependency graph;
- execução do
[Init]daquele arquivo, quando existir; - composição desses passos em um único init sintético do módulo;
- depois do fechamento dos módulos necessários, execução do
[Init]de projeto, quando existir; - entrada no primeiro
frame().
Lendo essa ordem de forma operacional:
- cada arquivo inicializa suas próprias globals;
- cada arquivo pode então executar seu
[Init]opcional; - tudo isso se aninha dentro de um único init sintético por módulo;
- o
[Init]co-localizado com[Frame]é elevado a init de projeto por ordem e papel semântico.
Também fica fechada a seguinte direção adicional:
- a ordem entre arquivos do mesmo módulo deve seguir a ordem derivada do
DependencyGraphAnaliserdas globals; - quando dois arquivos não tiverem dependência entre si, o compiler deve usar uma ordem determinística estável.
Remaining Open Points
Com a direção já consolidada nesta agenda, não restam pontos substantivos em aberto dentro do boundary de 19.2.
Os temas seguintes agora pertencem à 19.3.
InitAllowed Direction
Esta agenda fecha também o seguinte shape normativo inicial para [InitAllowed]:
[InitAllowed]é um atributo reservado sem argumentos em v1;- ele é válido apenas em host methods de SDK;
- ele é inválido em userland;
- ele é inválido em
fn,global,servicee demais superfícies que não sejam host methods de SDK; - seu papel é exclusivamente validar, em compile time, quais host calls podem aparecer durante init;
- ele não faz distinção entre init de módulo e init de projeto;
- a diferença entre esses inits é de ordenação e papel semântico, não de permissão separada de host call.
Exemplo recomendado:
declare host Runtime {
[Host(module = "runtime", name = "random_u32", version = 1)]
[Capability(name = "runtime")]
[InitAllowed]
fn random_u32() -> int;
}
Diagnostics Recommendation
Esta agenda fecha o seguinte catálogo mínimo de diagnósticos de lifecycle e bootstrap.
1. Project Init Must Be Colocated With Frame
Mensagem semântica recomendada:
project init must be colocated with frame
2. Multiple Project Init Functions Detected
Mensagem semântica recomendada:
multiple project init functions detected
3. Multiple Frame Functions Detected
Mensagem semântica recomendada:
multiple frame functions detected
4. Missing Frame Function For Executable Project
Mensagem semântica recomendada:
missing frame function for executable project
5. Invalid Init Signature
Mensagem semântica recomendada:
init function must have signature fn name() -> void
6. Invalid Frame Signature
Mensagem semântica recomendada:
frame function must have signature fn name() -> void
7. Host Call Not Allowed During Init
Mensagem semântica recomendada:
host call not allowed during init
8. Invalid InitAllowed Target
Mensagem semântica recomendada:
InitAllowed is valid only on SDK host methods
9. Boot Failed During Module Init
Mensagem semântica recomendada:
boot failed during module init
10. Boot Failed During Project Init
Mensagem semântica recomendada:
boot failed during project init
11. Multiple Module Init Functions Detected
Mensagem semântica recomendada:
multiple module init functions detected
12. Init Attribute Target Invalid
Mensagem semântica recomendada:
Init attribute target invalid
Expected Spec Material
Se esta agenda fechar, a propagação esperada atinge pelo menos:
3. Core Syntax Specification.md4. Static Semantics Specification.md9. Dynamic Semantics Specification.md12. Diagnostics Specification.md
Non-Goals
Esta agenda não deve:
- decidir o nome físico do wrapper published entrypoint;
- decidir o nome físico do entrypoint no manifest;
- definir shape de IR;
- definir como
FRAME_RETserá reposicionado materialmente.
Next Step
Depois de fechar esta agenda, abrir ou aprofundar:
19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda