mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-16 00:49:37 +00:00
fix(go): don't emit embeds for interface type-set constraints (#1818)
This commit is contained in:
1 parent
9aeade7199
commit
588dc041f7
2 files changed
+55
-1
No files matched your search
@@ -372,6 +372,16 @@ def extract_go(path: Path) -> dict:
|
||||
for elem in type_body.children:
|
||||
if elem.type != "type_elem":
|
||||
continue
|
||||
# A type_elem that is a generics type-set constraint -
|
||||
# a union (`A | B`) or an approximation (`~T`) - is NOT
|
||||
# interface embedding. Go only embeds a lone interface
|
||||
# type; union/approximation terms can never be embedded,
|
||||
# so they must not emit `embeds` heritage edges. Keep the
|
||||
# type link as a `references` (type_constraint) edge.
|
||||
is_type_set = any(
|
||||
c.type == "|" or c.type == "negated_type"
|
||||
for c in elem.children
|
||||
)
|
||||
refs = []
|
||||
for sub in elem.children:
|
||||
if sub.is_named:
|
||||
@@ -380,7 +390,10 @@ def extract_go(path: Path) -> dict:
|
||||
tgt = ensure_named_node(ref_name, elem.start_point[0] + 1)
|
||||
if tgt == type_nid:
|
||||
continue
|
||||
if role == "type":
|
||||
if is_type_set:
|
||||
add_edge(type_nid, tgt, "references",
|
||||
elem.start_point[0] + 1, context="type_constraint")
|
||||
elif role == "type":
|
||||
add_edge(type_nid, tgt, "embeds",
|
||||
elem.start_point[0] + 1)
|
||||
else:
|
||||
|
||||
@@ -1997,6 +1997,47 @@ def test_go_receiver_uses_pkg_scope():
|
||||
assert "sample" not in server_nodes[0]["id"].split(":")[0]
|
||||
|
||||
|
||||
def test_go_interface_embedding_emits_embeds():
|
||||
"""`type ReaderLogger interface { Logger; Reader }` embeds both interfaces."""
|
||||
r = extract_go(FIXTURES / "sample.go")
|
||||
embeds = _edge_labels(r, "embeds")
|
||||
assert ("ReaderLogger", "Logger") in embeds
|
||||
assert ("ReaderLogger", "Reader") in embeds
|
||||
|
||||
|
||||
def test_go_struct_embedding_emits_embeds():
|
||||
"""`type DataProcessor struct { BaseProcessor }` embeds the base struct."""
|
||||
r = extract_go(FIXTURES / "sample.go")
|
||||
assert ("DataProcessor", "BaseProcessor") in _edge_labels(r, "embeds")
|
||||
|
||||
|
||||
def test_go_interface_type_union_is_not_embedding(tmp_path):
|
||||
"""A generics type-set constraint (`A | B`) is NOT interface embedding.
|
||||
|
||||
Go only allows *interfaces* to be embedded, and each embed is its own
|
||||
element. A union of type terms (`MyInt | MyFloat`) is a constraint type
|
||||
set that can never be embedded, so its terms must not emit `embeds`
|
||||
heritage edges. They are reclassified as `references` (type_constraint)
|
||||
so the type link is preserved without asserting false composition.
|
||||
"""
|
||||
source = tmp_path / "constraint.go"
|
||||
source.write_text(
|
||||
"package p\n"
|
||||
"type MyInt int\n"
|
||||
"type MyFloat float64\n"
|
||||
"type Number interface {\n"
|
||||
"\tMyInt | MyFloat\n"
|
||||
"}\n"
|
||||
)
|
||||
r = extract_go(source)
|
||||
embeds = _edge_labels(r, "embeds")
|
||||
assert ("Number", "MyInt") not in embeds
|
||||
assert ("Number", "MyFloat") not in embeds
|
||||
refs = _edge_labels(r, "references", "type_constraint")
|
||||
assert ("Number", "MyInt") in refs
|
||||
assert ("Number", "MyFloat") in refs
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Julia
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in new issue
Block a user