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
let symbol = Symbols.FUNCTION_GENERIC_ARGUMENT(Source.LOCATION.internal, null, type.name, type.generic_parameter_position);
184
185
symbol.set_constraint_kind(generic_parameter_constraint_kind(type));
186
187
result = symbol.type!;
188
_type_cache.add(type, result);
189
190
return result;
191
elif type.is_generic_type_parameter then
192
let symbol = Symbols.CLASSY_GENERIC_ARGUMENT(Source.LOCATION.internal, null, type.name, type.generic_parameter_position);
193
194
symbol.set_constraint_kind(generic_parameter_constraint_kind(type));
195
196
result = symbol.type!;
197
_type_cache.add(type, result);
198
199
return result;
200
fi
201
202
if type.is_generic_type_definition \/ type.is_generic_type then
203
let b = type.get_generic_type_definition();
204
205
let creator: TypeCreator mut;
206
207
if !_type_creators.try_get_value(b, creator ref) then
208
creator = _generic_type_creator;
209
fi
210
211
result = creator.create(_symbol_table.value, type);
212
213
_type_cache.add(type, result);
214
215
return result;
216
fi
217
218
if type.is_array then
219
let element_type = get_element_type(type);
220
221
return _innate_symbol_lookup.get_array_type(element_type);
222
elif type.is_by_ref then
223
let element_type = get_element_type(type);
224
225
return _innate_symbol_lookup.get_reference_type(element_type);
226
elif type.is_pointer then
227
let element_type = get_element_type(type);
228
229
return _innate_symbol_lookup.get_pointer_type(element_type);
230
elif type.is_by_ref_like then
231
unsafe_constraints = true;
232
fi
233
234
let creator: TypeCreator mut;
235
236
if _type_creators.try_get_value(type, creator ref) then
237
return creator.create(_symbol_table.value, type);
238
fi
239
240
if !type.full_name? then
241
Std.error.write_line("TM get type: type has no full name: {type}");
242
return Types.NONE.instance;
243
fi
244
245
result = TYPE_WRAPPER(_symbol_table.value, type);
246
247
_type_cache.add(type, result);
248
249
if unsafe_constraints then
250
// not exactly but at least we'll get some kind of warning
251
result.symbol.is_unsafe_constraints = true;
252
fi
253
254
return result;
255
si
256
257
map_type_argument_variance(type: TYPE) -> Types.TypeVariance =>
258
if type.generic_parameter_attributes.has_flag(System.Reflection.GenericParameterAttributes.COVARIANT) then
259
Types.TypeVariance.COVARIANT
260
elif type.generic_parameter_attributes.has_flag(System.Reflection.GenericParameterAttributes.CONTRAVARIANT) then
261
Types.TypeVariance.CONTRAVARIANT
262
else
263
Types.TypeVariance.INVARIANT
264
fi;
265
266
// Maps a .NET generic parameter's `class` / `struct` constraint
267
// attributes to a ghūl kind constraint.
268
generic_parameter_constraint_kind(type: TYPE) -> Symbols.TypeParameterConstraintKind is
269
let attributes = type.generic_parameter_attributes;
270
271
if attributes.has_flag(System.Reflection.GenericParameterAttributes.REFERENCE_TYPE_CONSTRAINT) then
272
return Symbols.TypeParameterConstraintKind.REFERENCE;
273
elif attributes.has_flag(System.Reflection.GenericParameterAttributes.NOT_NULLABLE_VALUE_TYPE_CONSTRAINT) then
274
return Symbols.TypeParameterConstraintKind.VALUE;
275
fi
276
277
return Symbols.TypeParameterConstraintKind.NONE;
278
si
279
280
// True when a .NET generic parameter declares a parameterless-
281
// constructor (`new()`) constraint.
282
generic_parameter_has_constructor_constraint(type: TYPE) -> bool =>
283
type.generic_parameter_attributes.has_flag(
284
System.Reflection.GenericParameterAttributes.DEFAULT_CONSTRUCTOR_CONSTRAINT
285
);
286
287
get_element_type(type: TYPE) -> Type =>
288
let element_type = type.get_element_type() in
289
if !element_type? then
290
Std.error.write_line("warning: structured .NET type {type} has null element type: treating as Types.NONE");
291
Types.NONE.instance
292
else
293
get_type(element_type)
294
fi;
295
si
296
si