chore: import upstream snapshot with attribution
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/zzet/gortex/internal/graph"
|
||||
)
|
||||
|
||||
// bindGenericParamRefs rewrites `unresolved::<name>` edges where the
|
||||
// name is a generic type parameter declared by the source's
|
||||
// enclosing function. The Go extractor already materialises
|
||||
// KindGenericParam nodes with IDs `<func>#tparam:<name>` and an
|
||||
// EdgeMemberOf back to the owner — the resolver just hasn't been
|
||||
// consulting them when an in-body reference (`var x T`, return type
|
||||
// `T`, etc.) lands as `unresolved::T`.
|
||||
//
|
||||
// Side benefit beyond stub reduction: `find_usages` on a generic
|
||||
// type parameter starts working — *"where in this generic function
|
||||
// is T used?"* — which is a real refactoring query.
|
||||
//
|
||||
// Scope is per-function: a function's tparams are visible only
|
||||
// inside its body. The owner-keyed index built here lets each edge
|
||||
// resolve in O(1) without re-walking the graph.
|
||||
func (r *Resolver) bindGenericParamRefs() {
|
||||
// owner-function ID → set of tparam-name → tparam-node-id.
|
||||
owned := map[string]map[string]string{}
|
||||
for n := range r.graph.NodesByKind(graph.KindGenericParam) {
|
||||
if n.Language != "go" || n.Name == "" {
|
||||
continue
|
||||
}
|
||||
owner := enclosingFunctionForBinding(n.ID)
|
||||
if owner == "" || owner == n.ID {
|
||||
continue
|
||||
}
|
||||
set, ok := owned[owner]
|
||||
if !ok {
|
||||
set = map[string]string{}
|
||||
owned[owner] = set
|
||||
}
|
||||
// Don't overwrite — two tparams with the same name in the
|
||||
// same function shouldn't happen in valid Go, but be defensive.
|
||||
if _, dup := set[n.Name]; dup {
|
||||
set[n.Name] = ""
|
||||
continue
|
||||
}
|
||||
set[n.Name] = n.ID
|
||||
}
|
||||
if len(owned) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var batch []graph.EdgeReindex
|
||||
// We don't know up front which edge kinds carry type-param refs:
|
||||
// EdgeReferences for `var x T`, EdgeTypedAs for parameters typed
|
||||
// as T, EdgeReturns for return signature, EdgeInstantiates for
|
||||
// generic instantiation expressions. Walk the union.
|
||||
for _, k := range []graph.EdgeKind{
|
||||
graph.EdgeReferences,
|
||||
graph.EdgeTypedAs,
|
||||
graph.EdgeReturns,
|
||||
graph.EdgeInstantiates,
|
||||
} {
|
||||
for e := range r.graph.EdgesByKind(k) {
|
||||
if old := r.tryBindGenericParam(e, owned); old != "" {
|
||||
batch = append(batch, graph.EdgeReindex{Edge: e, OldTo: old})
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(batch) > 0 {
|
||||
r.graph.ReindexEdges(batch)
|
||||
}
|
||||
}
|
||||
|
||||
// bindGenericParamRefsForFile is the single-file-resolve form of
|
||||
// bindGenericParamRefs. A type parameter is visible only inside its own
|
||||
// function's body, which lives in this file, so both the owner index and the
|
||||
// edges to rewrite are scoped to the file — no whole-graph EdgesByKind sweep
|
||||
// (the dominant cost of an incremental edit on a large graph).
|
||||
func (r *Resolver) bindGenericParamRefsForFile(filePath string) {
|
||||
owned := map[string]map[string]string{}
|
||||
for _, n := range r.graph.GetFileNodes(filePath) {
|
||||
if n == nil || n.Kind != graph.KindGenericParam || n.Language != "go" || n.Name == "" {
|
||||
continue
|
||||
}
|
||||
owner := enclosingFunctionForBinding(n.ID)
|
||||
if owner == "" || owner == n.ID {
|
||||
continue
|
||||
}
|
||||
set, ok := owned[owner]
|
||||
if !ok {
|
||||
set = map[string]string{}
|
||||
owned[owner] = set
|
||||
}
|
||||
if _, dup := set[n.Name]; dup {
|
||||
set[n.Name] = ""
|
||||
continue
|
||||
}
|
||||
set[n.Name] = n.ID
|
||||
}
|
||||
if len(owned) == 0 {
|
||||
return
|
||||
}
|
||||
var batch []graph.EdgeReindex
|
||||
for _, e := range r.fileOutEdges(filePath) {
|
||||
switch e.Kind {
|
||||
case graph.EdgeReferences, graph.EdgeTypedAs, graph.EdgeReturns, graph.EdgeInstantiates:
|
||||
if old := r.tryBindGenericParam(e, owned); old != "" {
|
||||
batch = append(batch, graph.EdgeReindex{Edge: e, OldTo: old})
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(batch) > 0 {
|
||||
r.graph.ReindexEdges(batch)
|
||||
}
|
||||
}
|
||||
|
||||
// tryBindGenericParam returns the old To value (for batched reindex)
|
||||
// when the edge was rewritten, or "" when left alone.
|
||||
func (r *Resolver) tryBindGenericParam(e *graph.Edge, owned map[string]map[string]string) string {
|
||||
if e == nil || !strings.HasPrefix(e.To, "unresolved::") {
|
||||
return ""
|
||||
}
|
||||
name := strings.TrimPrefix(e.To, "unresolved::")
|
||||
if name == "" || strings.ContainsAny(name, ".*:#") {
|
||||
return ""
|
||||
}
|
||||
ownerID := enclosingFunctionForBinding(e.From)
|
||||
if ownerID == "" {
|
||||
return ""
|
||||
}
|
||||
set := owned[ownerID]
|
||||
if len(set) == 0 {
|
||||
return ""
|
||||
}
|
||||
target, ok := set[name]
|
||||
if !ok || target == "" || target == e.To {
|
||||
return ""
|
||||
}
|
||||
oldTo := e.To
|
||||
e.To = target
|
||||
return oldTo
|
||||
}
|
||||
Reference in New Issue
Block a user