English {#english}
Hard Problems We Solved (and What's Next)
Runtime internals in post 038 did not appear by accident — each VMT slot and heap entry survived Rust compiler errors, rejected shortcuts, and deliberate refactors. The post-mortems live in desafios-solucoes (also mirrored as desafios-e-solucoes).
This article highlights problems worth studying if you build languages — and what remains unsolved.
PartialEq on the entire AST
Early tests wanted assert_eq!(parsed, expected). Rust refused — Expression had no equality. The tempting fix: compare debug strings or skip structural tests.
We rejected that. 34 AST structs received #[derive(PartialEq)] in dependency order — operators first, then expressions, then statements, then declarations.
#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Binary(Box<BinaryExpression>),
IntegerLiteral(i64),
// ...
}
Lesson: pay the one-time tax for proper types; parser tests become ten lines instead of brittle string snapshots.
Borrow checker vs symbol tables
Shadowing warnings triggered classic E0499 — mutable borrow of self.scopes while calling self.add_warning():
// Broken pattern
let scope = &mut self.scopes[i];
self.add_warning("shadowing"); // second &mut self
Fix: compute flags before taking the mutable scope reference, then insert, then warn. No cloning entire scope stacks.
This pattern repeats anywhere diagnostics touch data structures mid-mutation — lexer span storage (Sprint 1) uses the same discipline.
Dual-mode build: honesty over theater
Generating C without gcc installed used to "succeed" while silently falling back — users thought they shipped native binaries. Sprint 9 (v2.17.0) made build fail loudly when no toolchain exists, while still emitting .c for inspection.
See desafios-solucoes for the three-option analysis:
| Option | Verdict |
|---|---|
| Runtime only | Fast dev, no native exe |
| C only | Requires gcc always |
| Dual-mode | Best of both — chosen |
Honesty extends to exceptions (Sprint 13): build-exe does not claim try/except parity it lacks.
VMT and polymorphism
Implementing real virtual dispatch — not switch-on-class-name hacks — took recursive VMT construction, override replacement, and abstract method holes. The doc's "Desafio Épico 2" walks through TDog.MakeSound overriding TAnimal.MakeSound.
If your Delphi code uses inherited inside overrides, check sprint notes — edge cases landed across Sprints 4–6.
Unicode and Delphi strings
Rust String is UTF-8; Delphi string is UTF-16LE in memory. Coercions that "mostly worked" failed on accented identifiers and emoji in literals. Sprint 19+ aligned internal representation; codegen maps to pascal_* helpers in stubs.c.
Still open: full WideString/AnsiString matrix, variant records in codegen.
What's next (transparent backlog)
The Mintlify technical-debt section tracks live gaps. High-level themes from the challenges doc:
- Mobile / WASM backends — speculative; need stable C first
- Visual component streaming — out of scope until core RTL solid
- Generics variance — collections work; edge templates don't
- LSP server — extension today is tasks + syntax; true IntelliSense is sprint-sized
Contributors: pick a red row in project status, link a sprint review in your PR, add a fixture — don't boil the ocean.
How to use these docs
Read challenges after architecture design when onboarding. Each section pairs pain with resolution — template for your own ADRs.
When you hit a new Rust fight, ask: did we already document this pattern? Duplicate lessons belong in Mintlify, not tribal chat.
Next in series
Post 040 — Dual-Mode Build zooms into interpret vs native C — commands, parity tests, and when to choose each path in production.
Português {#portugus}
Desafios do compilador: o que resolvemos (e o que vem)
Os internals de runtime do post 038 não surgiram por acidente — cada slot VMT e entrada no heap sobreviveu a erros do compilador Rust, atalhos rejeitados e refactors deliberados. Os post-mortems estão em desafios-solucoes (espelhado em desafios-e-solucoes).
Este artigo destaca problemas que valem estudar se você constrói linguagens — e o que permanece em aberto.
PartialEq em toda a AST
Testes cedo queriam assert_eq!(parsed, expected). Rust recusou — Expression não tinha igualdade. A tentação: comparar debug strings ou pular testes estruturais.
Rejeitamos. 34 structs AST receberam #[derive(PartialEq)] em ordem de dependência — operadores primeiro, expressões, statements, declarações.
#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Binary(Box<BinaryExpression>),
IntegerLiteral(i64),
// ...
}
Lição: pague o imposto único por tipos corretos; testes de parser viram dez linhas em vez de snapshots frágeis.
Borrow checker vs tabelas de símbolos
Avisos de shadowing dispararam E0499 clássico — borrow mutável de self.scopes enquanto chama self.add_warning():
// Padrão quebrado
let scope = &mut self.scopes[i];
self.add_warning("shadowing"); // segundo &mut self
Correção: calcule flags antes do borrow mutável do escopo, insira, depois avise. Sem clonar pilhas inteiras.
O padrão repete onde diagnósticos tocam estruturas mid-mutation — storage de span no lexer (Sprint 1) usa a mesma disciplina.
Dual-mode build: honestidade acima de teatro
Gerar C sem gcc instalado "sucesso" enquanto caía em fallback silencioso — usuários achavam que tinham binário nativo. Sprint 9 (v2.17.0) fez build falhar alto sem toolchain, ainda emitindo .c para inspeção.
Veja desafios-solucoes para análise das três opções:
| Opção | Veredito |
|---|---|
| Só runtime | Dev rápido, sem exe nativo |
| Só C | Exige gcc sempre |
| Dual-mode | Melhor dos dois — escolhido |
Honestidade estende a exceções (Sprint 13): build-exe não promete paridade try/except que não tem.
VMT e polimorfismo
Dispatch virtual de verdade — não switch em nome de classe — exigiu VMT recursiva, substituição de override e buracos para métodos abstract. "Desafio Épico 2" no doc percorre TDog.MakeSound sobrescrevendo TAnimal.MakeSound.
Se seu Delphi usa inherited dentro de overrides, confira notas de sprint — casos limite caíram entre Sprints 4–6.
Unicode e strings Delphi
String Rust é UTF-8; string Delphi é UTF-16LE na memória. Coerções que "quase funcionavam" falhavam em identificadores acentuados e emoji em literais. Sprint 19+ alinhou representação interna; codegen mapeia para helpers pascal_* em stubs.c.
Ainda aberto: matriz completa WideString/AnsiString, variant records no codegen.
O que vem (backlog transparente)
A seção débito técnico Mintlify rastreia gaps vivos. Temas do doc de desafios:
- Backends mobile / WASM — especulativo; C estável primeiro
- Streaming de componentes visuais — fora de escopo até RTL core sólido
- Variância de generics — collections ok; templates limite não
- Servidor LSP — extensão hoje é tasks + syntax; IntelliSense de verdade é sprint-sized
Contribuidores: escolham linha vermelha no status, liguem review de sprint no PR, adicionem fixture — não ferver o oceano.
Como usar estes docs
Leia desafios depois de arquitetura no onboarding. Cada seção emparelha dor com resolução — template para seus ADRs.
Quando bater nova briga Rust, pergunte: já documentamos este padrão? Lições duplicadas pertencem ao Mintlify, não ao chat tribal.
Próximo da série
Post 040 — Dual-mode: interpretar vs C nativo aprofunda interpret vs C nativo — comandos, testes de paridade e quando escolher cada caminho em produção.
Published on dev.to/@crabpascal · Código em CrabPascal
Top comments (0)