Hard Problems We Solved (and What's Next) | Desafios do compilador e soluções

rust dev.to

Bilingual post · Post bilíngue

Jump to: English · Português


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),
    // ...
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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),
    // ...
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Source: dev.to

arrow_back Back to Tutorials