feat(callbacks): apply applies_constants at a class top-level body (toplevel:)#42
Merged
Merged
Conversation
…(toplevel:) ERB views are type-checked as top-level code with `# @type self: <class>` (no method), so the method-entry `applies_constants` (steep#41) couldn't reach them — `Current.*` reads in a guarded view stayed nilable even though the rendering action ran under the guard (felixefelip/rbs_infer#25). - Callbacks::Entry gains `toplevel: true` — a framework-agnostic signal "apply this narrowing to the class's top-level body" (no runs_before required). Store#toplevel_entries looks them up. - Callbacks::ConstantNarrowing extracts "applies_constants map → constant_types updates" (parse, dangling-marker tolerance, relative+ absolute TypeName keys), shared by both paths. - TypeCheckService.type_check applies a `@type self:` class's toplevel entries to the top-level env before building the context — the analogue of apply_callbacks_for_method for the program body. - TypeConstruction#apply_callbacks_for_method and #marker_references_resolvable? (also used by the postcondition path) now delegate to ConstantNarrowing; three duplicated helpers removed. The emitter side (rbs_infer generating `toplevel: true` ERB entries from the view↔action mapping) is the complementary half of #25. callbacks_test 20/20, type_check_test 209/209. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
felixefelip
added a commit
to felixefelip/rbs_infer
that referenced
this pull request
Jun 14, 2026
…the guard (#25) (#27) The view-side half of #25. A guarded action's narrowing (`applies_constants`) reached the controller but not the views it renders — `Current.caderneta` in a guarded view stayed nilable. ERB views are checked as top-level code (`# @type self: ERBClass`), so they need the steep fork's `toplevel: true` callback entries (felixefelip/steep#42). CurrentAttributesCallbacksGenerator now emits, alongside each guarded controller's action entry, a `toplevel: true` entry for the convention view of each guarded action — reusing ViewPathNaming's view↔class mapping. The view carries the same intersected markers as its action. Sound for convention views (rendered by that single action). NOT emitted for partials/layouts (no single rendering action), nor checked against explicit cross-renders by an unguarded action — the heterogeneous-render scope the issue put aside. Each ERB entry gets its own applies_constants hash so the YAML carries no aliases. Field-checked (with steep#42): app's `caderneta/show.html.erb` and `sugestoes/index.html.erb` Current.* reads narrow (steep 132 → 130); the `_doses` partial stays (out of scope). Unit 452, integration 48. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implementa o lado-Steep de felixefelip/rbs_infer#25 (comentário com a investigação: #25).
Problema
O narrowing de constante via
applies_constants(#41) só é aplicado na entrada de métodos (apply_callbacks_for_method). Views ERB, porém, são type-checked como código top-level com# @type self: <ERBClass>anexado ao source (source.rb) — não há método pra ancorar oapplies_constants. Resultado:Current.caderneta.*numa view guardada continua acusando nil-risk, mesmo a action renderizadora rodando sob o guard que populou oCurrent.Solução:
toplevel:no callbacks sidecarCallbacks::Entryganhatoplevel: true— sinal framework-agnóstico ("aplica no corpo top-level desta classe"; dispensaruns_before).Store#toplevel_entries(class)faz o lookup.Callbacks::ConstantNarrowing(módulo novo) — extrai a lógica "applies_constantsmap → updates deconstant_types" (parse, tolerância a marker pendurado, chaves relativa+absoluta). Reutilizável.TypeCheckService.type_check— pra um arquivo com@type self: C, aplica as entriestopleveldeCao env top-level antes de montar o context (análogo doapply_callbacks_for_methodpro corpo do programa).apply_callbacks_for_methodemarker_references_resolvable?(usado também pelo caminho de postconditions) passam a delegar aoConstantNarrowing; 3 helpers duplicados removidos doTypeConstruction.Testes
callbacks_test):Entryparseiatoplevel: truesemruns_before;toplevel_entrieslookup (+ strip de::); entry method-style excluída do lookup toplevel. 20/20.type_check_test): positivo —Current.caderneta.vacinasno corpo top-level de um arquivo@type self: ERBClassnarrowa (diagnostics vazios); negativo — entry method-style (semtoplevel) não aplica → mantém nilável →NoMethod. 209/209.with_standard_constructionespelha o novo setup top-level (consistente com a duplicação que já fazia do@type self).Escopo
Lado-Steep apenas. A emissão das entries
toplevel: truepras classes ERB (via mapeamento view↔action) é a metade complementar, no rbs_infer.🤖 Generated with Claude Code