Repository navigation
Description
Summary
In go_lsp.c a selector's operand is checked against the import map before local scope, in both places that read a selector operand. A local variable whose name equals an imported package name is therefore always treated as the package. Go's scoping rule is the opposite: a local binding shadows the package name from the point of declaration onward.
Where
internal/cbm/lsp/go_lsp.c:369—go_eval_expr_type,selector_expressionbranch (// Check if operand is an import alias (pkg.Symbol)). Ifresolve_import()succeeds the branch returns unconditionally — includingreturn cbm_type_unknown()when the symbol is not found in that package — so it never falls through to evaluating the operand as a local.internal/cbm/lsp/go_lsp.c:1458— call emission (// Check if operand is a package import). Same ordering; on a miss it emits an unresolved call (symbol_not_in_registry) and skips type-based dispatch entirely.
Corpus shape (kubernetes)
A very common idiom:
meta, err := meta.Accessor(info.Object) // RHS: package k8s.io/apimachinery/pkg/api/meta
...
meta.SetNamespace(ns) // `meta` is now a local of type metav1.ObjectThree independent sites: staging/src/k8s.io/apiserver/pkg/registry/rest/resttest/resttest.go (setObjectMeta), staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go:392, staging/src/k8s.io/kubectl/pkg/cmd/run/run.go:724.
Today the call meta.SetNamespace(ns) is bound to the package k8s.io/apimachinery/pkg/api/meta (lsp_direct, confidence 0.95, target meta/meta.go:465) instead of metav1.Object.SetNamespace. With receiver-qualified method QNs (#1913) the constructed package QN no longer exists, the LSP emits the call unresolved, and the pipeline registry's import_map_suffix fallback (src/pipeline/registry.c:757-777) binds it to meta.MetadataAccessor.SetNamespace — a two-parameter interface member — for a one-argument call. Wrong before, wrong differently after.
What was tried
A shadowing guard at both sites (!cbm_scope_contains(ctx->current_scope, <operand>); cbm_scope_contains is NULL-safe, internal/cbm/lsp/scope.c:107) is regression-free (the RHS keeps its package edge — Go evaluates the RHS in the outer scope) but exactly neutral on a reproduction fixture: the LSP still cannot type the local, because a cross-package function return type (meta.Accessor returns metav1.Object) is not propagated into the binding. So the guard alone produces no observable change and was not shipped.
Proposed fix
Land the scoping guard together with cross-package return-type propagation for :=/= bindings, at which point a fixture with x, err := x.F(...) followed by x.Method() can assert the edge to the local's interface method and go RED without the change.
Activity