Skip to content
← Back

src/semantic/dotnet/type_mapper.ghul

1
namespace Semantic.DotNet is
2
use IO.Std
3
4
use TYPE = System.Type
5
use System.Reflection
6
7
use Collections.LIST
8
use Collections.MAP
9
10
use Logging
11
12
use Types.Type
13
use Types.NAMED
14
use Types.ERROR
15
16
class TypeCreator(_mapper: TYPE_MAPPER) is
17
create(symbol_table: SYMBOL_TABLE, type: TYPE) -> Type
18
si
19
20
class GENERIC_TYPE_CREATOR(mapper: TYPE_MAPPER): TypeCreator is
21
super(mapper)
22
23
create(symbol_table: SYMBOL_TABLE, type: TYPE) -> Type is
24
let result: Type mut
25
26
if type.is_generic_type_definition then
27
result = GENERIC_TYPE_WRAPPER(symbol_table, _mapper, type)
28
29
return result
30
elif type.is_generic_type then
31
result = GENERIC_TYPE_WRAPPER(symbol_table, _mapper, type)
32
33
return result
34
fi
35
36
throw System.InvalidOperationException("don't know how to create type: {type}")
37
si
38
si
39
40
class ACTION_0_TYPE_CREATOR: TypeCreator is
41
init(mapper: TYPE_MAPPER) is
42
super.init(mapper)
43
si
44
45
create(symbol_table: SYMBOL_TABLE, type: TYPE) -> Type =>
46
ACTION_0_TYPE_WRAPPER(symbol_table, type)
47
si
48
49
class ACTION_TYPE_CREATOR: TypeCreator is
50
init(mapper: TYPE_MAPPER) is
51
super.init(mapper)
52
si
53
54
create(symbol_table: SYMBOL_TABLE, type: TYPE) -> Type =>
55
ACTION_TYPE_WRAPPER(symbol_table, _mapper, type)
56
si
57
58
class FUNCTION_TYPE_CREATOR: TypeCreator is
59
init(mapper: TYPE_MAPPER) is
60
super.init(mapper)
61
si
62
63
create(symbol_table: SYMBOL_TABLE, type: TYPE) -> Type =>
64
FUNCTION_TYPE_WRAPPER(symbol_table, _mapper, type)
65
si
66
67
class TUPLE_TYPE_CREATOR: TypeCreator is
68
init(mapper: TYPE_MAPPER) is
69
super.init(mapper)
70
si
71
72
create(symbol_table: SYMBOL_TABLE, type: TYPE) -> Type =>
73
TUPLE_TYPE_WRAPPER(symbol_table, _mapper, type, null)
74
si
75
76
class NULLABLE_TYPE_CREATOR: TypeCreator is
77
init(mapper: TYPE_MAPPER) is
78
super.init(mapper)
79
si
80
81
create(symbol_table: SYMBOL_TABLE, type: TYPE) -> Type =>
82
NULLABLE_TYPE_WRAPPER(symbol_table, _mapper, type)
83
si
84
85
class MAYBE_TYPE_CREATOR: TypeCreator is
86
init(mapper: TYPE_MAPPER) is
87
super.init(mapper)
88
si
89
90
create(symbol_table: SYMBOL_TABLE, type: TYPE) -> Type =>
91
MAYBE_TYPE_WRAPPER(symbol_table, _mapper, type)
92
si
93
94
class TYPE_MAPPER is
95
_symbol_table: System.Lazy[SYMBOL_TABLE]
96
_innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup
97
_type_name_map: TYPE_NAME_MAP
98
99
_generic_type_creator: TypeCreator
100
_type_creators: MAP[TYPE,TypeCreator]
101
102
_type_source: TypeSource
103
104
// we don't need to intern types for correctness, but expecting to encounter a lot of references
105
// to identical types, so interning them will result in lower memory usage and fewer calls into the
106
// symbol table/symbol cache to materialize the associated ghul symbols
107
_type_cache: MAP[TYPE,Type]
108
109
init(
110
symbol_table: System.Lazy[SYMBOL_TABLE],
111
innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup,
112
type_name_map: TYPE_NAME_MAP,
113
type_source: TypeSource
114
) is
115
_symbol_table = symbol_table
116
_innate_symbol_lookup = innate_symbol_lookup
117
_type_name_map = type_name_map
118
119
_type_source = type_source
120
121
_type_cache = MAP()
122
123
_generic_type_creator = GENERIC_TYPE_CREATOR(self)
124
125
_type_creators = MAP()
126
127
_type_source.on_start(() -> void is start(); si)
128
si
129
130
start() is
131
let action_0_type_creator = ACTION_0_TYPE_CREATOR(self)
132
let action_type_creator = ACTION_TYPE_CREATOR(self)
133
let function_type_creator = FUNCTION_TYPE_CREATOR(self)
134
let tuple_type_creator = TUPLE_TYPE_CREATOR(self)
135
136
_type_creators.add(_type_source.get_type("System.Nullable`1"), NULLABLE_TYPE_CREATOR(self))
137
138
// Registration is best-effort — when the compiler is
139
// building ghul-runtime itself, the `ghul-runtime`
140
// assembly is not in the loaded-assembly map, so the
141
// lookup throws. In that case there are no reflected
142
// MAYBE instances anyway, so the creator is never
143
// consulted; leaving it unregistered is correct.
144
try
145
_type_creators.add(_type_source.get_type("ghul-runtime", "Ghul.MAYBE"), MAYBE_TYPE_CREATOR(self))
146
catch ex: System.Exception
147
yrt
148
149
_type_creators.add(_type_source.get_type("System.Action"), action_0_type_creator)
150
151
for i in 1::16 do
152
_type_creators.add(_type_source.get_type("System.Action`{i}"), action_type_creator)
153
od
154
155
for i in 1::17 do
156
_type_creators.add(_type_source.get_type("System.Func`{i}"), function_type_creator)
157
od
158
159
// ghūl tuples are System.ValueTuple — the value type ghūl
160
// emits and whose layout its tuple IL assumes. A reflected
161
// System.Tuple (the legacy reference-type tuple) is left to
162
// map as an ordinary generic class; treating it as a ghūl
163
// tuple would emit value-tuple IL against a reference type.
164
for i in 1::7 do
165
_type_creators.add(_type_source.get_type("System.ValueTuple`{i}"), tuple_type_creator)
166
od
167
si
168
169
get_type(type: TYPE?) -> Type is
170
let result: Type mut
171
let unsafe_constraints mut = false
172
173
if !type? then
174
Std.error.write_line("warning: materializing null type")
175
return Types.NONE.instance
176
fi
177
178
if _type_cache.try_get_value(type, result ref) then
179
return result
180
fi
181
182
if type.is_generic_method_parameter then
183
// A reflected type parameter has no owning scope in the
184
// symbol table: an empty block scope qualifies it to its
185
// bare name, which is what it renders as either way.
186
let symbol = Symbols.FUNCTION_GENERIC_ARGUMENT(Source.LOCATION.internal, Semantic.BLOCK_SCOPE(), type.name, type.generic_parameter_position)
187
188
symbol.set_constraint_kind(generic_parameter_constraint_kind(type))
189
190
result = symbol.type!
191
_type_cache.add(type, result)
192
193
return result
194
elif type.is_generic_type_parameter then
195
// Prefer the declaring type's own cached parameter: an
196
// imported member's formal and a substitution map built
197
// from the owner must carry the same symbol, and type
198
// substitution matches on symbol identity rather than
199
// on the parameter's name. The fallback mints a
200
// detached parameter when the declaring type is not
201
// (yet) in the symbol table.
202
if type.declaring_type? then
203
let declaring = type.declaring_type!
204
205
let owner_scoped = _symbol_table.value.get_symbol(declaring)
206
207
if let owner_classy = cast Symbols.Classy?(owner_scoped) then
208
let declared
209
= cast Symbols.GenericArgument?(
210
owner_classy.type_parameter_at(type.generic_parameter_position))
211
212
213
if declared? then
214
declared.set_constraint_kind(generic_parameter_constraint_kind(type))
215
216
result = declared.type!
217
_type_cache.add(type, result)
218
219
return result
220
fi
221
fi
222
fi
223
224
let symbol = Symbols.CLASSY_GENERIC_ARGUMENT(Source.LOCATION.internal, Semantic.BLOCK_SCOPE(), type.name, type.generic_parameter_position)
225
226
symbol.set_constraint_kind(generic_parameter_constraint_kind(type))
227
228
result = symbol.type!
229
_type_cache.add(type, result)
230
231
return result
232
fi
233
234
if type.is_generic_type_definition \/ type.is_generic_type then
235
let b = type.get_generic_type_definition()
236
237
let creator: TypeCreator mut
238
239
if !_type_creators.try_get_value(b, creator ref) then
240
creator = _generic_type_creator
241
fi
242
243
result = creator.create(_symbol_table.value, type)
244
245
_type_cache.add(type, result)
246
247
return result
248
fi
249
250
if type.is_array then
251
let element_type = get_element_type(type)
252
253
return _innate_symbol_lookup.get_array_type(element_type)
254
elif type.is_by_ref then
255
let element_type = get_element_type(type)
256
257
return _innate_symbol_lookup.get_reference_type(element_type)
258
elif type.is_pointer then
259
let element_type = get_element_type(type)
260
261
return _innate_symbol_lookup.get_pointer_type(element_type)
262
elif type.is_by_ref_like then
263
unsafe_constraints = true
264
fi
265
266
let creator: TypeCreator mut
267
268
if _type_creators.try_get_value(type, creator ref) then
269
return creator.create(_symbol_table.value, type)
270
fi
271
272
if !type.full_name? then
273
Std.error.write_line("TM get type: type has no full name: {type}")
274
return Types.NONE.instance
275
fi
276
277
result = TYPE_WRAPPER(_symbol_table.value, type)
278
279
_type_cache.add(type, result)
280
281
if unsafe_constraints then
282
// not exactly but at least we'll get some kind of warning
283
result.symbol.is_unsafe_constraints = true
284
fi
285
286
return result
287
si
288
289
map_type_argument_variance(type: TYPE) -> Types.TypeVariance =>
290
if type.generic_parameter_attributes.has_flag(System.Reflection.GenericParameterAttributes.COVARIANT) then
291
Types.TypeVariance.COVARIANT
292
elif type.generic_parameter_attributes.has_flag(System.Reflection.GenericParameterAttributes.CONTRAVARIANT) then
293
Types.TypeVariance.CONTRAVARIANT
294
else
295
Types.TypeVariance.INVARIANT
296
fi
297
298
// Maps a .NET generic parameter's `class` / `struct` constraint
299
// attributes to a ghūl kind constraint.
300
generic_parameter_constraint_kind(type: TYPE) -> Symbols.TypeParameterConstraintKind is
301
let attributes = type.generic_parameter_attributes
302
303
if attributes.has_flag(System.Reflection.GenericParameterAttributes.REFERENCE_TYPE_CONSTRAINT) then
304
return Symbols.TypeParameterConstraintKind.REFERENCE
305
elif attributes.has_flag(System.Reflection.GenericParameterAttributes.NOT_NULLABLE_VALUE_TYPE_CONSTRAINT) then
306
return Symbols.TypeParameterConstraintKind.VALUE
307
fi
308
309
return Symbols.TypeParameterConstraintKind.NONE
310
si
311
312
// True when a .NET generic parameter declares a parameterless-
313
// constructor (`new()`) constraint.
314
generic_parameter_has_constructor_constraint(type: TYPE) -> bool =>
315
type.generic_parameter_attributes.has_flag(
316
System.Reflection.GenericParameterAttributes.DEFAULT_CONSTRUCTOR_CONSTRAINT
317
)
318
319
get_element_type(type: TYPE) -> Type =>
320
let element_type = type.get_element_type() in
321
if !element_type? then
322
Std.error.write_line("warning: structured .NET type {type} has null element type: treating as Types.NONE")
323
Types.NONE.instance
324
else
325
get_type(element_type)
326
fi
327
si
328
si