fix(diagnostics): point reserved-type-name binding errors at the binding (issue 0076)
The reserved-type-name binding diagnostic fired correctly but underlined the enclosing statement / if / while / for / match / protocol / #objc_class block because every binding-name check reused the parent `node.span`. Thread each binding name's own span through the AST and parser, and pass it to `checkBindingNames`: - ast: add name spans to VarDecl, DestructureDecl, If/WhileExpr, ForExpr (capture + index), MatchArm, Catch/OnFailStmt, Protocol/ForeignMethodDecl. - parser: populate each span at the binding site from the name token's loc; destructure reuses each target identifier's own span. - semantic_diagnostics: every checkBindingName call now passes the binding's own span — no site falls back to node.span. fn/lambda params already used Param.name_span. Carets now land on the offending identifier itself. New regression examples/1125 asserts the protocol default-body and sx-defined #objc_class method param spans; 0125/1119-1124 expected updated to the precise carets.
This commit is contained in:
@@ -117,11 +117,11 @@ pub const UnknownTypeChecker = struct {
|
||||
switch (node.data) {
|
||||
// ── Binding-introducing nodes: check the name(s), then recurse. ──
|
||||
.var_decl => |vd| {
|
||||
self.checkBindingName(vd.name, node.span);
|
||||
self.checkBindingName(vd.name, vd.name_span);
|
||||
if (vd.value) |v| self.checkBindingNames(v);
|
||||
},
|
||||
.destructure_decl => |dd| {
|
||||
for (dd.names) |n| self.checkBindingName(n, node.span);
|
||||
for (dd.names, dd.name_spans) |n, sp| self.checkBindingName(n, sp);
|
||||
self.checkBindingNames(dd.value);
|
||||
},
|
||||
.fn_decl => |fd| {
|
||||
@@ -137,19 +137,19 @@ pub const UnknownTypeChecker = struct {
|
||||
if (p.default_expr) |de| self.checkBindingNames(de);
|
||||
},
|
||||
.if_expr => |ie| {
|
||||
if (ie.binding_name) |bn| self.checkBindingName(bn, node.span);
|
||||
if (ie.binding_name) |bn| self.checkBindingName(bn, ie.binding_span);
|
||||
self.checkBindingNames(ie.condition);
|
||||
self.checkBindingNames(ie.then_branch);
|
||||
if (ie.else_branch) |e| self.checkBindingNames(e);
|
||||
},
|
||||
.while_expr => |we| {
|
||||
if (we.binding_name) |bn| self.checkBindingName(bn, node.span);
|
||||
if (we.binding_name) |bn| self.checkBindingName(bn, we.binding_span);
|
||||
self.checkBindingNames(we.condition);
|
||||
self.checkBindingNames(we.body);
|
||||
},
|
||||
.for_expr => |fe| {
|
||||
if (fe.capture_name.len != 0) self.checkBindingName(fe.capture_name, node.span);
|
||||
if (fe.index_name) |idx| self.checkBindingName(idx, node.span);
|
||||
if (fe.capture_name.len != 0) self.checkBindingName(fe.capture_name, fe.capture_span);
|
||||
if (fe.index_name) |idx| self.checkBindingName(idx, fe.index_span);
|
||||
self.checkBindingNames(fe.iterable);
|
||||
if (fe.range_end) |re| self.checkBindingNames(re);
|
||||
self.checkBindingNames(fe.body);
|
||||
@@ -157,23 +157,23 @@ pub const UnknownTypeChecker = struct {
|
||||
.match_expr => |me| {
|
||||
self.checkBindingNames(me.subject);
|
||||
for (me.arms) |arm| {
|
||||
if (arm.capture) |cap| self.checkBindingName(cap, node.span);
|
||||
if (arm.capture) |cap| self.checkBindingName(cap, arm.capture_span);
|
||||
if (arm.pattern) |p| self.checkBindingNames(p);
|
||||
self.checkBindingNames(arm.body);
|
||||
}
|
||||
},
|
||||
.match_arm => |arm| {
|
||||
if (arm.capture) |cap| self.checkBindingName(cap, node.span);
|
||||
if (arm.capture) |cap| self.checkBindingName(cap, arm.capture_span);
|
||||
if (arm.pattern) |p| self.checkBindingNames(p);
|
||||
self.checkBindingNames(arm.body);
|
||||
},
|
||||
.catch_expr => |ce| {
|
||||
if (ce.binding) |b| self.checkBindingName(b, node.span);
|
||||
if (ce.binding) |b| self.checkBindingName(b, ce.binding_span);
|
||||
self.checkBindingNames(ce.operand);
|
||||
self.checkBindingNames(ce.body);
|
||||
},
|
||||
.onfail_stmt => |os| {
|
||||
if (os.binding) |b| self.checkBindingName(b, node.span);
|
||||
if (os.binding) |b| self.checkBindingName(b, os.binding_span);
|
||||
self.checkBindingNames(os.body);
|
||||
},
|
||||
// impl / protocol-default / foreign-class method bodies: each
|
||||
@@ -183,13 +183,13 @@ pub const UnknownTypeChecker = struct {
|
||||
.impl_block => |ib| for (ib.methods) |m| self.checkBindingNames(m),
|
||||
.protocol_decl => |pd| for (pd.methods) |m| {
|
||||
if (m.default_body) |body| {
|
||||
for (m.param_names) |pn| self.checkBindingName(pn, node.span);
|
||||
for (m.param_names, m.param_name_spans) |pn, sp| self.checkBindingName(pn, sp);
|
||||
self.checkBindingNames(body);
|
||||
}
|
||||
},
|
||||
.foreign_class_decl => |fcd| for (fcd.members) |member| switch (member) {
|
||||
.method => |m| if (m.body) |body| {
|
||||
for (m.param_names) |pn| self.checkBindingName(pn, node.span);
|
||||
for (m.param_names, m.param_name_spans) |pn, sp| self.checkBindingName(pn, sp);
|
||||
self.checkBindingNames(body);
|
||||
},
|
||||
.field, .extends, .implements => {},
|
||||
|
||||
Reference in New Issue
Block a user