Skip to content

Bind built-in named arguments by parameter name - #307

Open
luisleo526 wants to merge 1 commit into
mainfrom
fix/intrinsic-named-argument-binding
Open

luisleo526 wants to merge 1 commit into
mainfrom
fix/intrinsic-named-argument-binding

Conversation

@luisleo526

Copy link
Copy Markdown
Contributor

Built-in calls now bind named arguments by the parameter's name instead of failing in the generated C++.

  • math.pow(base=..., exponent=...), mixed positional-then-named calls and reversed named order now compile and produce the same value as the positional form.
  • A name that TradingView rejects for a built-in (for example exp= on math.pow) is refused at its source location with a catalog diagnostic, as TradingView refuses it.
  • New tests cover keyword binding, the generic path over the built-in registry, and the signature table.

Compiling scripts that do not use named built-in arguments are unchanged.

🤖 Generated with Claude Code

…ames

math.pow names its second parameter exponent. The registry called it exp,
so a keyword exponent was dropped and the call lowered to a one-argument
std::pow that does not compile, while the spelling exp compiled and ran.

Callables whose declared parameter names are their complete keyword set now
carry keyword_names_verified. For such a record an undeclared keyword is
refused at its name through the catalog (PF-E2027), in the support check and
in the shared merge helper. Records without the flag keep their existing
keyword handling byte for byte. math.pow is the first record to carry it.

Tests cover the named, mixed and reversed forms against the positional
call, the refusal and its span, a flag-driven generic family built at test
time, registry coverage of the lookup, and the absence of evidence fields in
the registry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View in Graphify

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.

Not checked: tests were not run; formal verification proved 0 of 10 changed function(s) (1 sampled, not proven, 9 not verified).

Formal verification. PR-changed functions: 1/10 verified (0 proven, 1 may-equivalent, 0 distinguished) · 9 not verified (3 vacuous, 6 unsupported).

Not verified on this run: \_build\_security\_math\_call (unsupported), \_resolve\_func\_args (unsupported), \_visit\_func\_call (unsupported), \_visit\_math\_call (unsupported), \_visit\_str\_call (unsupported), \_parse\_call\_args (vacuous: never exercised), \_func (vacuous: never exercised), \_math (vacuous: never exercised), \_visit\_FuncCall (unsupported).


Graphify review — findings

Adds keyword-name validation for registry builtins marked keyword_names_verified, so an unknown keyword reports PF-E2027 at the keyword instead of being silently dropped. The names are checked by the support checker before lowering and again in _merge_kwargs, which now accepts the intrinsic record from the math, str, time, timestamp, request and generic-signature call paths; records without the flag keep their existing binding. math.pow now declares base, exponent so both named forms emit the positional expression, and argument ordering stays under the separate PF-E2074 check.

Worth a look

  • Unknown-keyword validation only runs in SupportChecker, so check_support=False silently accepts bad kwargs — pineforge_codegen/support_checker.py:1639 · Escalate · medium
    • NOT verified (no proof, no reproducing execution) — needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 4326 functions depend on the 1181 functions this change touches.

Health — this change adds coupling hotspots:

  • new: intrinsic_keyword_diagnostics() — 3 callers, 4 callees
  • new: test_shared_parameter_names_resolve_each_callable_record() — 0 callers, 6 callees

Verification — 4326 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 3731 function(s) in the blast radius were not formally verified this run

Cross-repo impact

Cross-repo impact

No cross-repo impact detected among the indexed peer repo(s).

1 peer repo(s) in this group are not yet indexed — cross-repo impact may be incomplete.

Cross-repo linkage is derived (SCIP-moniker matches are sound; name/contract matches are heuristic) and ADVISORY — it never affects this check's conclusion.

Formal verification

Could not verify: Could not verify \_build\_security\_math\_call.

The verifier did not have enough to check \_build\_security\_math\_call, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)

No difference found (not proven): No behavior difference found in \_merge\_kwargs (not a proof).

The verifier ran both versions of \_merge\_kwargs on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify \_resolve\_func\_args.

The verifier did not have enough to check \_resolve\_func\_args, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)

Could not verify: Could not verify \_visit\_func\_call.

The verifier did not have enough to check \_visit\_func\_call, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)

Could not verify: Could not verify \_visit\_math\_call.

The verifier did not have enough to check \_visit\_math\_call, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)

Could not verify: Could not verify \_visit\_str\_call.

The verifier did not have enough to check \_visit\_str\_call, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)

Could not verify: Could not verify \_parse\_call\_args.

The verifier did not have enough to check \_parse\_call\_args, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 3 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly __init__ raised on the synthesized receiver args — names the real obstacle, not a sampling gap)

Could not verify: Could not verify \_func.

The verifier did not have enough to check \_func, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verified: a runtime divergence was observed, but the two versions' package snapshots loaded differently in the sandbox (old: {'fallback': {'pineforge_codegen': 'ImportError', 'pineforge_codegen.codegen': 'ImportError', 'pineforge_codegen.codegen.base': 'ModuleNotFoundError'}, 'missing': ['pineforge_codegen.codegen.emit_top', 'pineforge_codegen.codegen.input', 'pineforge_codegen.codegen.security', 'pineforge_codegen.codegen.ta', 'pineforge_codegen.codegen.types', 'pineforge_codegen.codegen.visit_call', 'pineforge_codegen.codegen.visit_expr', 'pineforge_codegen.codegen.visit_stmt']}, new: {'fallback': {'pineforge_codegen': 'ImportError', 'pineforge_codegen.codegen': 'ImportError', 'pineforge_codegen.codegen.base': 'ModuleNotFoundError', 'pineforge_codegen.codegen.collection_history': 'ModuleNotFoundError'}, 'missing': ['pineforge_codegen.codegen.emit_top', 'pineforge_codegen.codegen.history_sharing', 'pineforge_codegen\…

Could not verify: Could not verify \_math.

The verifier did not have enough to check \_math, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verified: a runtime divergence was observed, but the two versions' package snapshots loaded differently in the sandbox (old: {'fallback': {'pineforge_codegen': 'ImportError', 'pineforge_codegen.codegen': 'ImportError', 'pineforge_codegen.codegen.base': 'ModuleNotFoundError'}, 'missing': ['pineforge_codegen.codegen.emit_top', 'pineforge_codegen.codegen.input', 'pineforge_codegen.codegen.security', 'pineforge_codegen.codegen.ta', 'pineforge_codegen.codegen.types', 'pineforge_codegen.codegen.visit_call', 'pineforge_codegen.codegen.visit_expr', 'pineforge_codegen.codegen.visit_stmt']}, new: {'fallback': {'pineforge_codegen': 'ImportError', 'pineforge_codegen.codegen': 'ImportError', 'pineforge_codegen.codegen.base': 'ModuleNotFoundError', 'pineforge_codegen.codegen.collection_history': 'ModuleNotFoundError'}, 'missing': ['pineforge_codegen.codegen.emit_top', 'pineforge_codegen.codegen.history_sharing', 'pineforge_codegen\…

Could not verify: Could not verify \_visit\_FuncCall.

The verifier did not have enough to check \_visit\_FuncCall, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)

· 2 grounded finding(s) anchored inline below.

from .signatures import IntrinsicFunc


def intrinsic_keyword_diagnostics(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression — intrinsic_keyword_diagnostics()

high coupling complexity (Ca·Ce = 12).

Grounded coupling-delta finding (deterministic), not an LLM guess.

'request.security(syminfo.tickerid, "60", {expression})',
))
@pytest.mark.parametrize("check_support", (True, False))
def test_shared_parameter_names_resolve_each_callable_record(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression — test_shared_parameter_names_resolve_each_callable_record()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant