Appearance
| 1 | namespace Semantic.Lookups is | |
| 2 | use IO.Std; | |
| 3 | use TYPE = System.Type; | |
| 4 | use System.ValueType; | |
| 5 | use System.Exception; | |
| 6 | ||
| 7 | use Logging; | |
| 8 | ||
| 9 | use Collections.List; | |
| 10 | use Collections.LIST; | |
| 11 | ||
| 12 | use Ghul.Pipes; | |
| 13 | ||
| 14 | use Source.LOCATION; | |
| 15 | ||
| 16 | use Types; | |
| 17 | use ARRAY_TYPE = Types.ARRAY; | |
| 18 | ||
| 19 | class REFLECTION_INNATE_SYMBOL_LOOKUP( | |
| 20 | _type_mapper: DotNet.TYPE_MAPPER, | |
| 21 | _symbol_table: DotNet.SYMBOL_TABLE, | |
| 22 | _ghul_innate_type_lookup: GHUL_INNATE_TYPE_LOOKUP, | |
| 23 | _type_source: DotNet.TypeSource | |
| 24 | ): InnateSymbolLookup is | |
| 25 | _tuple_types: List[TYPE]; | |
| 26 | _function_types: List[TYPE]; | |
| 27 | _action_types: List[TYPE]; | |
| 28 | ||
| 29 | init(..) is | |
| 30 | _tuple_types = _type_source.get_types((1::7) |> map(i => "System.ValueTuple`{i}")); | |
| 31 | _function_types = _type_source.get_types((1::17) |> map(i => "System.Func`{i}")); | |
| 32 | _action_types = _type_source.get_types((1::16) |> map(i => "System.Action`{i}")); | |
| 33 | si | |
| 34 | ||
| 35 | get_tuple_type(types: Collections.List[Type], names: Collections.List[string?]?) -> Type => | |
| 36 | DotNet.HYBRID_TUPLE_TYPE_WRAPPER(_symbol_table, _tuple_types[types.count - 1], types, names); | |
| 37 | ||
| 38 | get_function_type(types: Collections.List[Type]) -> Type is | |
| 39 | assert types.count > 0 /\ types.count < _function_types.count; | |
| 40 | ||
| 41 | let return_type = types[types.count - 1]; | |
| 42 | ||
| 43 | if return_type.is_sentinel \/ return_type.is_type_variable \/ !return_type.matches(get_void_type()) then | |
| 44 | return | |
| 45 | DotNet.HYBRID_FUNCTION_TYPE_WRAPPER(_symbol_table, _function_types[types.count - 1], types); | |
| 46 | elif types.count == 1 then | |
| 47 | return | |
| 48 | _type_mapper.get_type(_type_source.get_type("System.Action")); | |
| 49 | else | |
| 50 | let without_void_return_type = LIST[Type](types.count - 1); | |
| 51 | ||
| 52 | for i in 0..types.count - 1 do | |
| 53 | without_void_return_type.add(types[i]); | |
| 54 | od | |
| 55 | ||
| 56 | return | |
| 57 | DotNet.HYBRID_ACTION_TYPE_WRAPPER(_symbol_table, _action_types[types.count - 2], without_void_return_type); | |
| 58 | fi | |
| 59 | si | |
| 60 | ||
| 61 | get_function_type(types: Collections.List[Type], is_pure: bool) -> Type is | |
| 62 | if !is_pure then | |
| 63 | return get_function_type(types); | |
| 64 | fi | |
| 65 | ||
| 66 | assert types.count > 0 /\ types.count < _function_types.count; | |
| 67 | ||
| 68 | let return_type = types[types.count - 1]; | |
| 69 | ||
| 70 | if return_type.is_sentinel \/ return_type.is_type_variable \/ !return_type.matches(get_void_type()) then | |
| 71 | return | |
| 72 | DotNet.PURE_HYBRID_FUNCTION_TYPE_WRAPPER(_symbol_table, _function_types[types.count - 1], types); | |
| 73 | elif types.count == 1 then | |
| 74 | // the zero-argument void form maps to the non-generic | |
| 75 | // System.Action, which has no pure-marked wrapper — | |
| 76 | // dropping the marker is conservative: callers get no | |
| 77 | // purity guarantee and callees keep no facts | |
| 78 | return | |
| 79 | _type_mapper.get_type(_type_source.get_type("System.Action")); | |
| 80 | else | |
| 81 | let without_void_return_type = LIST[Type](types.count - 1); | |
| 82 | ||
| 83 | for i in 0..types.count - 1 do | |
| 84 | without_void_return_type.add(types[i]); | |
| 85 | od | |
| 86 | ||
| 87 | return | |
| 88 | DotNet.PURE_HYBRID_ACTION_TYPE_WRAPPER(_symbol_table, _action_types[types.count - 2], without_void_return_type); | |
| 89 | fi | |
| 90 | si | |
| 91 | ||
| 92 | get_enum_type() -> Type => | |
| 93 | _type_mapper.get_type(_type_source.get_type("System.Enum")); | |
| 94 | ||
| 95 | get_array_type(type: Type) -> Type => | |
| 96 | _ghul_innate_type_lookup.get_array_type(type); | |
| 97 | ||
| 98 | get_optional_type(type: Type) -> Type => | |
| 99 | let classy = | |
| 100 | cast Semantic.Symbols.Classy?( | |
| 101 | _symbol_table.get_symbol(_type_source.get_type("System.Nullable`1")))! | |
| 102 | in | |
| 103 | Types.NULLABLE(LOCATION.internal, classy, LIST[Type]([type])); | |
| 104 | ||
| 105 | get_maybe_type(type: Type) -> Type? is | |
| 106 | // Mirrors the MAYBE_TYPE_CREATOR registration in | |
| 107 | // TYPE_MAPPER.start(): the assembly is absent when the | |
| 108 | // compiler is building ghul-runtime itself, so the | |
| 109 | // lookup throws. Treat that as "MAYBE unavailable" and | |
| 110 | // let the caller surface an error appropriate for the | |
| 111 | // context. | |
| 112 | try | |
| 113 | let dotnet_type = _type_source.get_type("ghul-runtime", "Ghul.MAYBE"); | |
| 114 | let classy = cast Semantic.Symbols.Classy?(_symbol_table.get_symbol(dotnet_type))!; | |
| 115 | return Types.MAYBE(LOCATION.internal, classy, LIST[Type]([type])); | |
| 116 | catch ex: System.Exception | |
| 117 | return null; | |
| 118 | yrt | |
| 119 | si | |
| 120 | ||
| 121 | get_pointer_type(type: Type) -> Type => | |
| 122 | _ghul_innate_type_lookup.get_pointer_type(type); | |
| 123 | ||
| 124 | get_reference_type(type: Type) -> Type => | |
| 125 | _ghul_innate_type_lookup.get_reference_type(type); | |
| 126 | ||
| 127 | get_bool_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Boolean")); | |
| 128 | get_char_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Char")); | |
| 129 | get_byte_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.SByte")); | |
| 130 | get_ubyte_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Byte")); | |
| 131 | get_short_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Int16")); | |
| 132 | get_ushort_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.UInt16")); | |
| 133 | get_int_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Int32")); | |
| 134 | get_uint_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.UInt32")); | |
| 135 | get_long_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Int64")); | |
| 136 | get_ulong_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.UInt64")); | |
| 137 | get_word_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.IntPtr")); | |
| 138 | get_uword_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.UIntPtr")); | |
| 139 | get_single_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Single")); | |
| 140 | get_double_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Double")); | |
| 141 | get_decimal_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Decimal")); | |
| 142 | get_void_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Void")); | |
| 143 | get_object_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Object")); | |
| 144 | get_value_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.ValueType")); | |
| 145 | get_string_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.String")); | |
| 146 | get_exception_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Exception")); | |
| 147 | get_type_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Type")); | |
| 148 | get_unspecialized_iterable_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Collections.Generic.IEnumerable`1")); | |
| 149 | get_unspecialized_iterator_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Collections.Generic.IEnumerator`1")); | |
| 150 | // ghūl emits its own generic types without the .NET `N | |
| 151 | // arity suffix that BCL types carry, so the reflected name is | |
| 152 | // bare `Ghul.Pipes.Pipe` (an arity-1 generic definition). | |
| 153 | // | |
| 154 | // The assembly is absent when the compiler is building | |
| 155 | // ghul-runtime itself, so the lookup throws. Treat that as "Pipe | |
| 156 | // unavailable" and return null (mirrors get_maybe_type): pipe | |
| 157 | // fusion and the other Pipe-typed queries then simply do not | |
| 158 | // apply while compiling the pipe library. | |
| 159 | get_unspecialized_pipe_type() -> Type? is | |
| 160 | try | |
| 161 | return _type_mapper.get_type(_type_source.get_type("ghul-runtime", "Ghul.Pipes.Pipe")); | |
| 162 | catch ex: System.Exception | |
| 163 | return null; | |
| 164 | yrt | |
| 165 | si | |
| 166 | get_unspecialized_task_type() -> Type? => _type_mapper.get_type(_type_source.get_type("System.Threading.Tasks.Task`1")); | |
| 167 | ||
| 168 | get_interpolated_string_handler_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler")); | |
| 169 | ||
| 170 | get_idisposable_type() -> Type => _type_mapper.get_type(_type_source.get_type("System.IDisposable")); | |
| 171 | ||
| 172 | get_box_type(type: Type) -> Type => | |
| 173 | // `Ghul.BOX[T]` lives in the ghul-runtime assembly, | |
| 174 | // not System.Runtime (the default for the single-arg | |
| 175 | // overload), so name the assembly explicitly. The | |
| 176 | // assembly's name is derived from its file name — | |
| 177 | // see `assemblies.ghul`. Note: ghūl-emitted generic | |
| 178 | // types drop the .NET-style backtick-arity suffix | |
| 179 | // (per the arity-overloading change), so the .NET | |
| 180 | // metadata name is plain `Ghul.BOX`, not | |
| 181 | // `Ghul.BOX`1`. | |
| 182 | let classy = | |
| 183 | cast Semantic.Symbols.Classy?( | |
| 184 | _symbol_table.get_symbol(_type_source.get_type("ghul-runtime", "Ghul.BOX")))! | |
| 185 | in | |
| 186 | Types.GENERIC(LOCATION.internal, classy, LIST[Type]([type])); | |
| 187 | ||
| 188 | get_task_type(type: Type) -> Type? is | |
| 189 | // Constructed `System.Threading.Tasks.Task[type]` — | |
| 190 | // reuses the same unspecialized Task symbol identity | |
| 191 | // that `try_get_task_element_type` (in compile_bindings) | |
| 192 | // checks against, so a freshly-constructed Task[T] from | |
| 193 | // here will be recognised as already-a-Task and not | |
| 194 | // double-wrapped on subsequent return-position passes. | |
| 195 | let unspec = get_unspecialized_task_type(); | |
| 196 | ||
| 197 | if !unspec? then | |
| 198 | return null; | |
| 199 | fi | |
| 200 | ||
| 201 | let classy = cast Semantic.Symbols.Classy?(unspec.symbol.unspecialized_symbol); | |
| 202 | ||
| 203 | if !classy? then | |
| 204 | return null; | |
| 205 | fi | |
| 206 | ||
| 207 | return Types.GENERIC(LOCATION.internal, classy, LIST[Type]([type])); | |
| 208 | si | |
| 209 | ||
| 210 | get_void_task_type() -> Type? => | |
| 211 | // Non-generic `System.Threading.Tasks.Task` — the | |
| 212 | // type-name map at type_name_map.ghul:174 already | |
| 213 | // aliases this to ghūl `Tasks.TASK` (the arity-zero | |
| 214 | // form alongside the arity-one Task`1). | |
| 215 | _type_mapper.get_type(_type_source.get_type("System.Threading.Tasks.Task")); | |
| 216 | ||
| 217 | get_async_task_method_builder_type(type: Type) -> Type? is | |
| 218 | // `System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1` | |
| 219 | // constructed over the value-async result type. | |
| 220 | let unspec = _type_mapper.get_type(_type_source.get_type("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1")); | |
| 221 | ||
| 222 | let classy = cast Semantic.Symbols.Classy?(unspec.symbol.unspecialized_symbol); | |
| 223 | ||
| 224 | if !classy? then | |
| 225 | return null; | |
| 226 | fi | |
| 227 | ||
| 228 | return Types.GENERIC(LOCATION.internal, classy, LIST[Type]([type])); | |
| 229 | si | |
| 230 | ||
| 231 | get_async_task_method_builder_void_type() -> Type? => | |
| 232 | _type_mapper.get_type(_type_source.get_type("System.Runtime.CompilerServices.AsyncTaskMethodBuilder")); | |
| 233 | ||
| 234 | get_async_state_machine_interface_type() -> Type? => | |
| 235 | _type_mapper.get_type(_type_source.get_type("System.Runtime.CompilerServices.IAsyncStateMachine")); | |
| 236 | ||
| 237 | get_task_awaiter_type(type: Type) -> Type? is | |
| 238 | // `System.Runtime.CompilerServices.TaskAwaiter`1` | |
| 239 | // constructed over T. Returned by `Task<T>.GetAwaiter()`; | |
| 240 | // its `GetResult()` returns T. | |
| 241 | let unspec = _type_mapper.get_type(_type_source.get_type("System.Runtime.CompilerServices.TaskAwaiter`1")); | |
| 242 | ||
| 243 | let classy = cast Semantic.Symbols.Classy?(unspec.symbol.unspecialized_symbol); | |
| 244 | ||
| 245 | if !classy? then | |
| 246 | return null; | |
| 247 | fi | |
| 248 | ||
| 249 | return Types.GENERIC(LOCATION.internal, classy, LIST[Type]([type])); | |
| 250 | si | |
| 251 | ||
| 252 | get_task_awaiter_void_type() -> Type? => | |
| 253 | _type_mapper.get_type(_type_source.get_type("System.Runtime.CompilerServices.TaskAwaiter")); | |
| 254 | ||
| 255 | get_unspecialized_async_task_method_builder_type() -> Type? => | |
| 256 | _type_mapper.get_type(_type_source.get_type("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1")); | |
| 257 | ||
| 258 | get_unspecialized_task_awaiter_type() -> Type? => | |
| 259 | _type_mapper.get_type(_type_source.get_type("System.Runtime.CompilerServices.TaskAwaiter`1")); | |
| 260 | si | |
| 261 | si |