Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use IO.Std; | |
| 3 | ||
| 4 | use System.Text.StringBuilder; | |
| 5 | ||
| 6 | use Collections.List; | |
| 7 | use Collections.Map; | |
| 8 | ||
| 9 | use IoC; | |
| 10 | use Logging; | |
| 11 | use Source; | |
| 12 | ||
| 13 | use IR.Values.Value; | |
| 14 | use Types.Type; | |
| 15 | ||
| 16 | use Ghul.Pipes; | |
| 17 | ||
| 18 | // A GENERIC represents a particular specialization of a generic class, trait or struct - i.e. a version of that symbol | |
| 19 | // with actual type arguments specified for its formal type parameters, and all its member symbols' signatures rewritten | |
| 20 | // with all instances of each formal type parameter replaced with the corresponding actual type argument | |
| 21 | class GENERIC: Symbol, Types.Typed is | |
| 22 | _symbol: Classy; | |
| 23 | _type_map: Collections.Map[string,Type]; | |
| 24 | ||
| 25 | type_map: Collections.Map[string,Type] => _type_map; | |
| 26 | arguments: Collections.List[Type]; | |
| 27 | ancestors: Collections.List[Type] => symbol.ancestors; | |
| 28 | ||
| 29 | implementors: Collections.Iterable[Symbol]? => symbol.implementors; | |
| 30 | ||
| 31 | symbol: Classy => _symbol; | |
| 32 | ||
| 33 | symbols: Collections.Iterable[Symbol] is | |
| 34 | let result = Collections.LIST[Symbol](); | |
| 35 | ||
| 36 | for s in symbol.symbols do | |
| 37 | if let specialized = _specialize(s) then | |
| 38 | result.add(specialized); | |
| 39 | fi | |
| 40 | od | |
| 41 | ||
| 42 | return result; | |
| 43 | si | |
| 44 | ||
| 45 | owner: Scope? public => symbol.owner, = value is si | |
| 46 | ||
| 47 | unspecialized_symbol: Symbols.Symbol => symbol; | |
| 48 | root_unspecialized_symbol: Symbols.Symbol => symbol.root_unspecialized_symbol; | |
| 49 | ||
| 50 | location: LOCATION => symbol.location; | |
| 51 | name: string => symbol.name; | |
| 52 | ||
| 53 | access: ACCESS => symbol.access; | |
| 54 | ||
| 55 | is_type: bool => symbol.is_type; | |
| 56 | is_generic_type_specialization: bool => true; | |
| 57 | is_value_type: bool => symbol.is_value_type; | |
| 58 | is_inheritable: bool => symbol.is_inheritable; | |
| 59 | is_class: bool => symbol.is_class; | |
| 60 | is_trait: bool => symbol.is_trait; | |
| 61 | is_union: bool => symbol.is_union; | |
| 62 | is_variant: bool => symbol.is_variant; | |
| 63 | is_unit_variant: bool => symbol.is_unit_variant; | |
| 64 | is_closed_root: bool => symbol.is_closed_root; | |
| 65 | is_specializable: bool => false; // type parameters already applied | |
| 66 | ||
| 67 | qualified_name: string => "{symbol.qualified_name}[{arguments_string}]"; | |
| 68 | ||
| 69 | // Only the head shortens; the type arguments stay. (Type rendering | |
| 70 | // reaches the head directly and adds the arguments itself, so this | |
| 71 | // is only used when a constructed generic is named on its own - as | |
| 72 | // the owner of a member, say.) | |
| 73 | render_name(scope: Scope?) -> string => | |
| 74 | if !scope? then | |
| 75 | qualified_name; | |
| 76 | else | |
| 77 | "{symbol._render_scope_relative_name(scope)}[{arguments_string}]"; | |
| 78 | fi; | |
| 79 | ||
| 80 | arguments_string: string is | |
| 81 | let result = System.Text.StringBuilder(); | |
| 82 | ||
| 83 | let seen_any mut = false; | |
| 84 | ||
| 85 | for a in arguments do | |
| 86 | if seen_any then | |
| 87 | result.append(','); | |
| 88 | fi | |
| 89 | ||
| 90 | result.append(a); | |
| 91 | ||
| 92 | seen_any = true; | |
| 93 | od | |
| 94 | ||
| 95 | return result.to_string(); | |
| 96 | si | |
| 97 | ||
| 98 | short_description: string is | |
| 99 | let result = System.Text.StringBuilder(); | |
| 100 | ||
| 101 | result | |
| 102 | .append(name) | |
| 103 | .append('['); | |
| 104 | ||
| 105 | let seen_any mut = false; | |
| 106 | ||
| 107 | for a in arguments do | |
| 108 | if seen_any then | |
| 109 | result.append(','); | |
| 110 | fi | |
| 111 | ||
| 112 | result.append(a.short_description); | |
| 113 | ||
| 114 | seen_any = true; | |
| 115 | od | |
| 116 | ||
| 117 | result | |
| 118 | .append(']'); | |
| 119 | ||
| 120 | return result.to_string(); | |
| 121 | si | |
| 122 | ||
| 123 | symbol_kind: SymbolKind => symbol.symbol_kind; | |
| 124 | completion_kind: CompletionKind => symbol.completion_kind; | |
| 125 | ||
| 126 | // TODO we could probably cache this rather than creating | |
| 127 | // a new one every time | |
| 128 | type: Type => Types.GENERIC(location, symbol, arguments); | |
| 129 | ||
| 130 | depth: int => symbol.depth; | |
| 131 | ||
| 132 | init(location: LOCATION, symbol: Classy, arguments: Collections.List[Type]) is | |
| 133 | assert arguments |> all(a => a?) else "type argument is null for {symbol.name}"; | |
| 134 | ||
| 135 | super.init( | |
| 136 | symbol.location, | |
| 137 | symbol, | |
| 138 | symbol.name); | |
| 139 | ||
| 140 | _symbol = symbol; | |
| 141 | ||
| 142 | assert arguments.count > 0 else "generic has 0 arguments"; | |
| 143 | assert arguments |> all(a => a?) else "at least one null argument"; | |
| 144 | assert symbol.is_generic else "symbol is not generic"; | |
| 145 | ||
| 146 | let length mut = arguments.count; | |
| 147 | ||
| 148 | if arguments.count != symbol.argument_names.count then | |
| 149 | if length > symbol.argument_names.count then | |
| 150 | length = symbol.argument_names.count; | |
| 151 | fi | |
| 152 | ||
| 153 | IoC.CONTAINER.instance.logger.error(location, "expected {symbol.argument_names.count} type arguments"); | |
| 154 | fi | |
| 155 | ||
| 156 | self.arguments = arguments; | |
| 157 | let tm = Collections.MAP[string,Type](); | |
| 158 | ||
| 159 | for i in 0..length do | |
| 160 | tm[symbol.argument_names[i]] = arguments[i]; | |
| 161 | od | |
| 162 | ||
| 163 | _type_map = tm; | |
| 164 | ||
| 165 | is_unsafe_constraints = symbol.is_unsafe_constraints; | |
| 166 | si | |
| 167 | ||
| 168 | try_create_from(location: LOCATION, symbol: Classy, type_map: Collections.Map[string,Type]) -> GENERIC? static is | |
| 169 | let arguments = Collections.LIST[Type](); | |
| 170 | ||
| 171 | for name in symbol.argument_names do | |
| 172 | if !type_map.contains_key(name) then | |
| 173 | return null; | |
| 174 | fi | |
| 175 | ||
| 176 | let t = type_map[name]; | |
| 177 | ||
| 178 | arguments.add(t); | |
| 179 | od | |
| 180 | ||
| 181 | return GENERIC(location, symbol, arguments); | |
| 182 | si | |
| 183 | ||
| 184 | add_member(symbol: Symbol) -> bool is | |
| 185 | IoC.CONTAINER.instance.logger.warn(location, "inherit-into-specialized-generic", "cannot inherit {symbol} into specialized generic {self}"); | |
| 186 | return true; | |
| 187 | si | |
| 188 | ||
| 189 | add_implementor(implementor: Symbol) is | |
| 190 | symbol.add_implementor(implementor); | |
| 191 | si | |
| 192 | ||
| 193 | assert_symbols_pulled_down() is | |
| 194 | symbol.assert_symbols_pulled_down(); | |
| 195 | si | |
| 196 | ||
| 197 | pull_down_super_symbols() is | |
| 198 | symbol.pull_down_super_symbols(); | |
| 199 | si | |
| 200 | ||
| 201 | get_ancestor(i: int) -> Type | |
| 202 | => ancestors[i].specialize(type_map); | |
| 203 | ||
| 204 | =~(other: Symbol) -> bool is | |
| 205 | if !isa GENERIC(other) then | |
| 206 | return false; | |
| 207 | fi | |
| 208 | ||
| 209 | let other_generic = other; | |
| 210 | ||
| 211 | if other_generic.symbol != symbol then | |
| 212 | return false; | |
| 213 | fi | |
| 214 | ||
| 215 | assert | |
| 216 | other_generic.arguments.count == arguments.count | |
| 217 | else | |
| 218 | "generics with the same symbol should have same number of arguments"; | |
| 219 | ||
| 220 | for i in 0..arguments.count do | |
| 221 | if !arguments[i].matches(other_generic.arguments[i]) then | |
| 222 | return false; | |
| 223 | fi | |
| 224 | od | |
| 225 | ||
| 226 | return true; | |
| 227 | si | |
| 228 | ||
| 229 | load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => symbol.load(location, from, loader); | |
| 230 | store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => symbol.store(location, from, value, loader, is_initialize); | |
| 231 | call(location: Source.LOCATION, from: Value?, arguments: Collections.List[Value], type: Type?, caller: FUNCTION_CALLER) -> Value => symbol.call(location, from, arguments, type, caller); | |
| 232 | // given a member of the class, trait or struct that this generic wraps, we want to get a copy of it | |
| 233 | // with all references to formal type parameters replaced with the corresponding actual type arguments | |
| 234 | _specialize(member: Symbols.Symbol?) -> Symbols.Symbol? => | |
| 235 | if !member? then | |
| 236 | null; | |
| 237 | elif !member.is_specializable then | |
| 238 | member; | |
| 239 | elif member.can_accept_actual_type_arguments then | |
| 240 | member.specialize(arguments); | |
| 241 | else | |
| 242 | member.specialize(type_map, self); | |
| 243 | fi; | |
| 244 | ||
| 245 | find_direct(name: string) -> Symbol? is | |
| 246 | assert_symbols_pulled_down(); | |
| 247 | ||
| 248 | return _specialize(symbol.find_direct(name)); | |
| 249 | si | |
| 250 | ||
| 251 | find_member(name: string) -> Symbol? => | |
| 252 | let result = symbol.find_member(name) in | |
| 253 | if result? then | |
| 254 | _specialize(result); | |
| 255 | else | |
| 256 | null; | |
| 257 | fi; | |
| 258 | ||
| 259 | find_specialized_function(function: Symbol) -> Function? is | |
| 260 | let result = find_member(function.name); | |
| 261 | ||
| 262 | if !result? then | |
| 263 | let results = Collections.MAP[string, Symbols.Symbol](); | |
| 264 | ||
| 265 | symbol.find_member_matches("", results); | |
| 266 | ||
| 267 | return null; | |
| 268 | fi | |
| 269 | ||
| 270 | let function_result = cast Function?(result); | |
| 271 | ||
| 272 | if function_result? /\ function_result.specialized_from == function then | |
| 273 | return function_result; | |
| 274 | fi | |
| 275 | ||
| 276 | let function_group_result = cast FUNCTION_GROUP?(result); | |
| 277 | ||
| 278 | if !function_group_result? then | |
| 279 | return null; | |
| 280 | fi | |
| 281 | ||
| 282 | for f in function_group_result.functions do | |
| 283 | if f.specialized_from == function then | |
| 284 | return f; | |
| 285 | fi | |
| 286 | od | |
| 287 | ||
| 288 | return null; | |
| 289 | si | |
| 290 | ||
| 291 | get_destructure_member_name(index: int) -> string? => | |
| 292 | symbol.get_destructure_member_name(index); | |
| 293 | ||
| 294 | find_enclosing(name: string) -> Symbol? => | |
| 295 | let unspecialized = symbol.find_enclosing(name) in | |
| 296 | ||
| 297 | if unspecialized? /\ unspecialized.owner == symbol then | |
| 298 | _specialize(unspecialized); | |
| 299 | else | |
| 300 | unspecialized; | |
| 301 | fi; | |
| 302 | ||
| 303 | find_direct_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is | |
| 304 | let m = Collections.MAP[string, Symbols.Symbol](); | |
| 305 | ||
| 306 | symbol.find_direct_matches(prefix, m); | |
| 307 | ||
| 308 | for p in m.iterator do | |
| 309 | if !matches.contains_key(p.key) then | |
| 310 | if let specialized = _specialize(p.value) then | |
| 311 | matches[p.key] = specialized.collapse_group_if_single_member(); | |
| 312 | fi | |
| 313 | fi | |
| 314 | od | |
| 315 | si | |
| 316 | ||
| 317 | find_member_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is | |
| 318 | find_direct_matches(prefix, matches); | |
| 319 | symbol.find_ancestor_matches(prefix, matches); | |
| 320 | si | |
| 321 | ||
| 322 | find_enclosing_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is | |
| 323 | si | |
| 324 | ||
| 325 | get_hash_code() -> int is | |
| 326 | let result mut = symbol.get_hash_code(); | |
| 327 | ||
| 328 | for a in arguments do | |
| 329 | result = result + a.get_hash_code(); | |
| 330 | od | |
| 331 | ||
| 332 | return result; | |
| 333 | si | |
| 334 | ||
| 335 | gen_reference(buffer: StringBuilder) is | |
| 336 | gen_type(buffer); | |
| 337 | si | |
| 338 | ||
| 339 | gen_class_name(buffer: StringBuilder) is | |
| 340 | // class name == type for generics - i.e. they must always be prefixed with 'class' or 'valuetype' | |
| 341 | gen_type(buffer); | |
| 342 | si | |
| 343 | ||
| 344 | gen_type(buffer: StringBuilder) is | |
| 345 | symbol.gen_type(buffer); | |
| 346 | ||
| 347 | buffer.append('<'); | |
| 348 | ||
| 349 | gen_actual_type_arguments(buffer); | |
| 350 | ||
| 351 | buffer.append("> "); | |
| 352 | si | |
| 353 | ||
| 354 | gen_actual_type_arguments(buffer: StringBuilder) is | |
| 355 | let seen_any mut = false; | |
| 356 | for argument in arguments do | |
| 357 | if seen_any then | |
| 358 | buffer.append(','); | |
| 359 | fi | |
| 360 | ||
| 361 | argument.gen_type(buffer); | |
| 362 | ||
| 363 | seen_any = true; | |
| 364 | od | |
| 365 | si | |
| 366 | ||
| 367 | to_string() -> string => "{IoC.CONTAINER.instance.name_display.bare_name_for(symbol)}[{arguments_string}]"; | |
| 368 | si | |
| 369 | si |