Summary
The validator's collectDeclaredVariables extracts only the function NAME from funcName(params) => declarations, ignoring the parameter names. As a result, any reference to a parameter inside the function body via param.field (typed parameter or UDT instance) triggers a false Undefined namespace or variable 'param'.
Environment
- Extension:
jpantsjoha.pinescript-v6-extension v0.4.4
- VS Code: any recent
- OS: platform-independent
Minimal repro
//@version=6
indicator("param repro", overlay=true)
doStuff(int x, float y) =>
plot(x + y)
doStuff(1, 2.0)
A more realistic case (where the bug is most painful) with user-defined types (UDT):
//@version=6
indicator("param repro", overlay=true)
type State
float a
update(State st, float v) =>
st.a := v
st
var State s = State.new(na)
update(s, close)
Note, UDT itself triggers the error, I've filled separate issue #15.
Expected
No diagnostics. Both scripts compile and run correctly in the TradingView Pine Editor.
Actual
In the second sample, every reference to st.a inside update triggers:
Undefined namespace or variable 'st'
On a real codebase with many UDT-receiving functions (e.g. setters/updaters/computes), this produces dozens of red squiggles inside otherwise-correct code.
Root cause
In accurateValidator.ts, collectDeclaredVariables:
const paramDeclarations = line.matchAll(/([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*=>/g);
for (const match of paramDeclarations) {
const funcName = match[1];
if (funcName) {
this.declaredVariables.add(funcName);
}
}
The regex skips the parenthesized parameter list ([^)]*) instead of capturing it, so parameter names are never registered. When the function body later references paramName.field, the namespace check fails to find paramName in declaredVariables.
Suggested minimal fix
Capture the parameter list as a second group, then split by , and extract the last identifier before any = from each part — that's the parameter name (handling name, type name, name = default, and type name = default cases uniformly).
const paramDeclarations = line.matchAll(/([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*=>/g);
for (const match of paramDeclarations) {
const funcName = match[1];
const paramsStr = match[2];
if (funcName) {
this.declaredVariables.add(funcName);
}
if (paramsStr && paramsStr.trim()) {
for (const part of paramsStr.split(',')) {
const beforeEq = part.split('=')[0];
const ids = beforeEq.match(/[A-Za-z_][A-Za-z0-9_]*/g);
if (ids && ids.length > 0) {
const paramName = ids[ids.length - 1];
if (!this.isReservedKeyword(paramName)) {
this.declaredVariables.add(paramName);
}
}
}
}
}
This handles single-line declarations. Multi-line function headers (parameters wrapping across lines) would need additional work, but single-line covers the vast majority of real code.
I've been running this locally against v0.4.4 — confirmed it eliminates the 28 false-positive errors on a real strategy file without over-suppressing (genuine NoSuchThing.foo() references still flag correctly).
Happy to send a PR with the fix + a test fixture if useful.
Summary
The validator's
collectDeclaredVariablesextracts only the function NAME fromfuncName(params) =>declarations, ignoring the parameter names. As a result, any reference to a parameter inside the function body viaparam.field(typed parameter or UDT instance) triggers a falseUndefined namespace or variable 'param'.Environment
jpantsjoha.pinescript-v6-extensionv0.4.4Minimal repro
A more realistic case (where the bug is most painful) with user-defined types (UDT):
Note, UDT itself triggers the error, I've filled separate issue #15.
Expected
No diagnostics. Both scripts compile and run correctly in the TradingView Pine Editor.
Actual
In the second sample, every reference to
st.ainsideupdatetriggers:On a real codebase with many UDT-receiving functions (e.g. setters/updaters/computes), this produces dozens of red squiggles inside otherwise-correct code.
Root cause
In accurateValidator.ts,
collectDeclaredVariables:The regex skips the parenthesized parameter list (
[^)]*) instead of capturing it, so parameter names are never registered. When the function body later referencesparamName.field, the namespace check fails to findparamNameindeclaredVariables.Suggested minimal fix
Capture the parameter list as a second group, then split by
,and extract the last identifier before any=from each part — that's the parameter name (handlingname,type name,name = default, andtype name = defaultcases uniformly).This handles single-line declarations. Multi-line function headers (parameters wrapping across lines) would need additional work, but single-line covers the vast majority of real code.
I've been running this locally against v0.4.4 — confirmed it eliminates the 28 false-positive errors on a real strategy file without over-suppressing (genuine
NoSuchThing.foo()references still flag correctly).Happy to send a PR with the fix + a test fixture if useful.