Skip to content
← Back

src/semantic/inference_helpers.ghul

1
namespace Semantic is
2
use Types.Type;
3
4
// Small inference-time helpers shared between the call-site
5
// match propagation in COMPILE_CALLS and the closure-arg inference path
6
// in CLOSURE_ARG_RESOLVER. Both call sites build their behaviour
7
// around these pure functions, which keeps the type-walking
8
// logic out of the visitor classes and unit-testable on its own.
9
class INFERENCE_HELPERS is
10
// When `t` is an alternative of a closed root — a union
11
// variant, or a ghūl-declared subclass of a closed root
12
// class — return the specialised closed-root type that
13
// alternative inherits. Used at the placeholder-formal
14
// match propagation site to keep the lambda-arg LUB
15
// monotonic across siblings of the same closed root:
16
// pushing the leaf would pin the closure's signature to
17
// that sibling even though recursion through
18
// `rec(field: Root[T])` would later imply the root.
19
//
20
// Covers both bare Types.NAMED and Types.GENERIC over a
21
// Symbols.GENERIC. The shape is uniform: t's first
22
// ancestor is the immediate parent; if that parent's
23
// symbol is a closed root we widen, otherwise we leave t
24
// alone. For variants the parent is always the union (a
25
// closed root by definition); for closed-class subclasses
26
// it is the closed base class.
27
widen_to_closed_root(t: Type?) -> Type? static is
28
if !t? then
29
return null;
30
fi
31
32
if !isa Types.GENERIC(t) then
33
if t.ancestors.count > 0 then
34
let ancestor = t.ancestors[0];
35
if ancestor.symbol.is_closed_root then
36
return ancestor;
37
fi
38
fi
39
return t;
40
fi
41
42
let generic = cast Types.GENERIC(t);
43
let symbol = cast Symbols.GENERIC?(generic.symbol);
44
45
if !symbol? then
46
return t;
47
fi
48
49
if symbol.ancestors.count == 0 then
50
return t;
51
fi
52
53
let ancestor = symbol.get_ancestor(0);
54
55
if !ancestor.symbol.is_closed_root then
56
return t;
57
fi
58
59
return ancestor;
60
si
61
62
// Walk `t` and append every method-level type-variable symbol
63
// it references into `result`. Method-level meaning a generic
64
// function's type parameter (`!!N` in IL), not a class-level
65
// type parameter (`!N`) which the enclosing instance carries.
66
// Used by the closure-arg inference path to drive
67
// closure.add_type_argument_reference: an inferred argument
68
// type has no AST node for RECORD_TYPE_ARGUMENT_USES to walk,
69
// so the captured-type-args have to be lifted explicitly.
70
collect_method_level_type_variables(
71
t: Type?,
72
result: Collections.MutableList[Symbols.Symbol]
73
) static is
74
if !t? then
75
return;
76
fi
77
78
t.walk((u: Type) is
79
if u.is_type_variable /\ !u.is_classy_generic_argument then
80
result.add(u.symbol);
81
fi
82
si);
83
si
84
si
85
si