Skip to content
← Back

src/semantic/symbols/static_interface_implementation_checker.ghul

1
namespace Semantic.Symbols is
2
use Logging
3
4
// .NET lets an interface declare a static member that an
5
// implementing type must supply, which is how the generic-math
6
// interfaces work. Calling one through a bounded type parameter is
7
// supported; supplying one is not, because nothing binds the
8
// implementing type's static to the interface's slot, and the CLR
9
// refuses to load a type that leaves one unfilled.
10
//
11
// The assembly compiles either way, so without this the failure is a
12
// TypeLoadException at run time naming a member the source declared.
13
class STATIC_INTERFACE_IMPLEMENTATION_CHECKER is
14
_logger: Logger
15
16
init(logger: Logger) is
17
_logger = logger
18
si
19
20
check(type: Classy) is
21
// A trait passes the obligation to whatever implements it,
22
// and an abstract class to whatever completes it. A
23
// reflected type was answered for by the compiler that
24
// built its assembly.
25
if type.is_trait \/ type.is_reflected \/ type.is_abstract then
26
return
27
fi
28
29
let _ = _check_ancestors(type, type)
30
si
31
32
// `Classy.ancestors` holds what a type declares, not what it
33
// inherits, so reaching an interface a base class or a trait
34
// brought in means walking it. A type hierarchy is acyclic, and
35
// a diamond only costs a repeated visit that answers the same.
36
_check_ancestors(type: Classy, current: Classy) -> bool is
37
for ancestor in current.ancestors do
38
// Asked of the type rather than of its symbol: where the
39
// interface is constructed the symbol is a GENERIC, and
40
// a GENERIC is not a Classy.
41
if ancestor.is_trait then
42
for member in _members(ancestor.symbol) do
43
if is_static_slot(member) then
44
_logger.error(
45
type.location,
46
"cannot implement static member {member.name} of {ancestor}",
47
member.location,
48
"member declared here")
49
50
return true
51
fi
52
od
53
fi
54
55
// Not through a reflected base class: it already supplies
56
// whatever it implements and .NET lets a derived type
57
// inherit that, so descending would reject source that
58
// loads. A reflected trait supplies nothing, so its own
59
// ancestors are still walked.
60
if
61
let above = _as_classy(ancestor.symbol) /\
62
(above.is_trait \/ !above.is_reflected) /\
63
_check_ancestors(type, above)
64
then
65
return true
66
fi
67
od
68
69
return false
70
si
71
72
_as_classy(symbol: Symbol) -> Classy? is
73
if let generic: GENERIC = symbol then
74
return generic.symbol
75
elif let classy: Classy = symbol then
76
return classy
77
fi
78
79
return null
80
si
81
82
_members(symbol: Symbol) -> Collections.Iterable[Symbol] is
83
if let generic: GENERIC = symbol then
84
return generic.symbols
85
elif let classy: Classy = symbol then
86
return classy.symbols
87
fi
88
89
return Collections.LIST[Symbol]()
90
si
91
92
// True where the member is, or carries, a slot an implementing
93
// type would have to fill with a static.
94
is_static_slot(member: Symbol) -> bool static is
95
for function in _functions(member) do
96
if let method: STATIC_METHOD = function /\ method.is_static_interface_virtual then
97
return true
98
fi
99
od
100
101
return false
102
si
103
104
// A property's slot is its accessor, so the accessors are what
105
// carry the static-virtual marker.
106
_functions(member: Symbol) -> Collections.Iterable[Function] static is
107
let result = Collections.LIST[Function]()
108
109
if let group: FUNCTION_GROUP = member then
110
for overload in group.functions do
111
result.add(overload)
112
od
113
elif let property: Property = member then
114
if let read = property.read_function then
115
result.add(read)
116
fi
117
118
if let assign = property.assign_function then
119
result.add(assign)
120
fi
121
elif let function: Function = member then
122
result.add(function)
123
fi
124
125
return result
126
si
127
si
128
si