feat(resolution): CFML receiver-type inference for locals, typed args, and component properties#1155
Merged
Merged
Conversation
…, and component properties Extends the #1108 receiver-type inference family to CFML. Two coupled halves: Extraction — CFML method qualifiedNames now carry the component scope (UserService::save, the generic Class::member shape) in all three paths: bare-script components (the <anonymous> rename now rewrites member scope chains too), <cffunction> tags, and component-level <cfscript> blocks. Without this, type-validated method resolution could never match a CFML method. Scope-prefixed member calls (variables.svc.save()) also keep their receiver chain instead of collapsing to a bare method name — gated to CFML's file-local scope keywords (variables/this/local/arguments), whose calls previously emitted an ambiguous bare name. Resolution — cfml/cfscript declaration patterns for the shared inferrer: new (dotted component paths included), createObject("component", ...) two-arg and single-arg, typed cfscript params, <cfargument> tags (either attribute order), and (cf)property type=/inject= (WireBox DI). variables./this.-scoped receivers strip their prefix and scan the whole file in both directions — a component field's declaration (init pseudoconstructor, property) is position-independent — while local./arguments. keep the enclosing-function bound. Validated on fw1/ColdBox/CFWheels: 1,649 typed-inference call edges (364/384/901), audit-verified 1,649/1,649 — including methods inherited through the #1152 extends edges via the conformance walk. Node counts unchanged. Co-Authored-By: Claude Fable 5 <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.
Completes CFML's parity with the #1108 receiver-type inference family — the last CFML gap from the #1118/#1153/#1154 arc.
var svc = new UserService(); svc.save()now links toUserService.saveinstead of being dropped or guessed among same-named methods.Two coupled halves
Extraction (prerequisite): CFML method qualifiedNames now carry the component scope (
UserService::save— the sameClass::membershape every other language produces) in all three extraction paths: bare-script components (the<anonymous>rename now rewrites member scope chains),<cffunction>tags, and component-level<cfscript>blocks. Previously they were<anonymous>::save/file.cfc::save/ bareconfigure— shapes type-validated resolution could never match. Scope-prefixed member calls (variables.svc.save()) also keep their receiver chain instead of collapsing to a bare method name — gated to CFML's file-local scope keywords (variables/this/local/arguments), whose calls previously emitted an ambiguous bare name, so no recall risk.Resolution: cfml/cfscript declaration patterns for the shared inferrer, covering CFML's actual idioms:
var svc = new path.to.UserService()(dotted paths reduce to the class segment)createObject("component", "path.UserService")— two-arg and single-arg, any casingfunction save(UserService svc)) and<cfargument name= type=>(either attribute order)property name="svc" type=/inject=— the WireBox DI shape — and<cfproperty>variables./this.-scoped receivers strip their prefix and scan the whole file in both directions (a field'sinit()pseudoconstructor assignment orpropertydeclaration is position-independent);local./arguments.keep the enclosing-function boundresolveMethodOnTypevalidates every inference (the method must exist on the inferred component), so a mis-inference produces no edge — and its conformance walk rides the #1152 extends edges, so inherited methods resolve too (cmds.env_file_content()on anAppCommandsthat inherits it fromBaselinks toBase's definition — verified in the wild).Validation
Precision: an independent audit re-derived each receiver's declared type from source for all 1,649 typed-inference edges — 1,649/1,649 consistent (3 initial flags were inherited-method resolutions, hand-verified correct). Node counts unchanged. The pre-existing fuzzy strategies (confidence 0.65–0.8) are untouched; inference outranks them only when a declaration proves the type.
8 new integration tests pin all four declaration idioms, the below-the-call field scan, WireBox injection, component-scoped QNs in all three extraction paths, and the no-edge-on-unvalidated-inference rule. Full suite: 2,006 passed / 0 failed.
🤖 Generated with Claude Code