Skip to content
← Back

src/semantic/delegate_shape.ghul

1
namespace Semantic is
2
use Types.Type
3
4
// Recognises .NET delegate types and reports the function type that
5
// describes how they are called.
6
//
7
// `Func` and `Action` are excluded: they are already modelled as
8
// FUNCTION / ACTION, so `is_named_delegate` answers false for them
9
// and callers keep their existing path.
10
class DELEGATE_SHAPE is
11
init() is
12
si
13
14
// True for a delegate type ghūl does not already model as a
15
// function type.
16
is_named_delegate(type: Type, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> bool =>
17
!type.is_function /\ _inherits_multicast_delegate(type, innate_symbol_lookup)
18
19
// The function type describing `type`'s call shape, or null when
20
// `type` is not a named delegate or carries no usable `invoke`.
21
try_get_function_type(type: Type, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> Type? is
22
if !is_named_delegate(type, innate_symbol_lookup) then
23
return null
24
fi
25
26
let invoke = _find_invoke(type)
27
28
if !invoke? \/ !invoke.return_type? \/ !invoke.are_arguments_declared then
29
return null
30
fi
31
32
// Beyond the innate function-type shapes' own parameter
33
// limit, no function type exists to describe this call
34
// shape - answered here rather than by invoke.get_full_type,
35
// which would report an error at the delegate's own
36
// declaration instead of leaving this a quiet null probe.
37
if invoke.arguments.count > Lookups.INNATE_TYPE_LIMITS.MAX_FUNCTION_PARAMETERS then
38
return null
39
fi
40
41
return invoke.get_full_type(innate_symbol_lookup)
42
si
43
44
// Whether a function of `arity` parameters could be this
45
// delegate. A delegate whose shape cannot be read is given the
46
// benefit of the doubt.
47
could_take_arity(type: Type, arity: int, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> bool is
48
let shape = try_get_function_type(type, innate_symbol_lookup)
49
50
return !shape? \/ ARGUMENT_PACK.parameter_count(shape) == arity
51
si
52
53
// A delegate declares exactly one `Invoke`, so the group it
54
// arrives in holds a single function.
55
_find_invoke(type: Type) -> Symbols.Function? is
56
let member = type.find_member("invoke")
57
58
if let group: Symbols.FUNCTION_GROUP = member then
59
if group.count == 1 then
60
return group.functions[0]
61
fi
62
63
return null
64
fi
65
66
return cast Symbols.Function?(member)
67
si
68
69
// `System.MulticastDelegate` resolved from the lookup and
70
// compared by symbol identity down the recursion — a rendered
71
// name here would conflate a duplicate symbol rather than
72
// resolve it. Null when the lookup cannot resolve it, in
73
// which case nothing is a named delegate.
74
_inherits_multicast_delegate(type: Type, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> bool is
75
let multicast = innate_symbol_lookup.get_multicast_delegate_type()
76
77
if !multicast? then
78
return false
79
fi
80
81
return _inherits(type, multicast.symbol)
82
si
83
84
_inherits(type: Type, multicast: Symbols.Symbol) -> bool is
85
for ancestor in type.ancestors do
86
if ancestor.symbol =~ multicast then
87
return true
88
fi
89
90
if _inherits(ancestor, multicast) then
91
return true
92
fi
93
od
94
95
return false
96
si
97
si
98
si