Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use IO.Std; | |
| 3 | ||
| 4 | use Logging; | |
| 5 | ||
| 6 | class RESOLVE_ANCESTORS: ScopedVisitor is | |
| 7 | _logger: Logger; | |
| 8 | _symbol_table: Semantic.SYMBOL_TABLE; | |
| 9 | _innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup; | |
| 10 | ||
| 11 | init( | |
| 12 | logger: Logger, | |
| 13 | symbol_table: Semantic.SYMBOL_TABLE, | |
| 14 | namespaces: Semantic.NAMESPACES, | |
| 15 | innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup | |
| 16 | ) | |
| 17 | is | |
| 18 | super.init(logger, symbol_table, namespaces); | |
| 19 | ||
| 20 | _logger = logger; | |
| 21 | _symbol_table = symbol_table; | |
| 22 | _innate_symbol_lookup = innate_symbol_lookup; | |
| 23 | si | |
| 24 | ||
| 25 | apply(root: Trees.Node) is | |
| 26 | root.walk(self); | |
| 27 | si | |
| 28 | ||
| 29 | pre(`class: Trees.Definitions.CLASS) -> bool => true; | |
| 30 | ||
| 31 | visit(`class: Trees.Definitions.CLASS) is | |
| 32 | let class_symbol = cast Semantic.Symbols.CLASS?(scope_for(`class))!; | |
| 33 | ||
| 34 | let seen_class_ancestor mut = false; | |
| 35 | let is_first mut = true; | |
| 36 | ||
| 37 | if `class.ancestors? then | |
| 38 | for a in `class.ancestors do | |
| 39 | let ancestor_type = a.type; | |
| 40 | ||
| 41 | if !a.is_poisoned /\ ancestor_type? then | |
| 42 | if ancestor_type.is_inheritable then | |
| 43 | if ancestor_type.is_class then | |
| 44 | if seen_class_ancestor then | |
| 45 | _logger.error(a.location, "multiple superclasses"); | |
| 46 | elif !is_first then | |
| 47 | _logger.error(a.location, "superclass must be first"); | |
| 48 | fi | |
| 49 | ||
| 50 | _check_extends_closed_imported(a, ancestor_type); | |
| 51 | ||
| 52 | seen_class_ancestor = true; | |
| 53 | fi | |
| 54 | ||
| 55 | a.check_is_not_void(_logger, "cannot use void type here"); | |
| 56 | ||
| 57 | class_symbol.add_ancestor(ancestor_type); | |
| 58 | ||
| 59 | is_first = false; | |
| 60 | else | |
| 61 | _logger.error(a.location, "cannot inherit from this"); | |
| 62 | fi | |
| 63 | fi | |
| 64 | od | |
| 65 | fi | |
| 66 | ||
| 67 | if !seen_class_ancestor then | |
| 68 | let object_type = _innate_symbol_lookup.get_object_type(); | |
| 69 | ||
| 70 | if class_symbol != object_type.symbol then | |
| 71 | class_symbol.push_ancestor(_innate_symbol_lookup.get_object_type()); | |
| 72 | fi | |
| 73 | fi | |
| 74 | si | |
| 75 | ||
| 76 | // A class declared in this compilation can only extend a | |
| 77 | // ghūl-declared closed class that lives in the same assembly. | |
| 78 | // An imported (reflected) class carrying the CLOSED_ATTRIBUTE | |
| 79 | // marker is closed from another assembly — extending it from | |
| 80 | // this one would violate the closure that the consumer can | |
| 81 | // rely on for narrowing soundness. | |
| 82 | _check_extends_closed_imported( | |
| 83 | ancestor_node: Trees.TypeExpressions.TypeExpression, | |
| 84 | ancestor_type: Semantic.Types.Type? | |
| 85 | ) is | |
| 86 | if !ancestor_type? then | |
| 87 | return; | |
| 88 | fi | |
| 89 | ||
| 90 | let ancestor_symbol = ancestor_type.symbol; | |
| 91 | ||
| 92 | if !isa Semantic.Symbols.Classy(ancestor_symbol) then | |
| 93 | return; | |
| 94 | fi | |
| 95 | ||
| 96 | let ancestor_classy = cast Semantic.Symbols.Classy(ancestor_symbol); | |
| 97 | ||
| 98 | if !ancestor_classy.is_reflected then | |
| 99 | return; | |
| 100 | fi | |
| 101 | ||
| 102 | if ancestor_classy.is_open then | |
| 103 | return; | |
| 104 | fi | |
| 105 | ||
| 106 | _logger.error( | |
| 107 | ancestor_node.location, | |
| 108 | "cannot extend closed class {ancestor_classy.name} from outside its assembly" | |
| 109 | ); | |
| 110 | si | |
| 111 | ||
| 112 | // An `impl <Interface> for <Target>` block attaches the interface to | |
| 113 | // the target's own symbol - this node's scope is an injection scope | |
| 114 | // standing in for the target, which class_or_trait_for unwraps. The | |
| 115 | // target then implements the interface exactly as a header-declared | |
| 116 | // one would; the members filling its slots are declared as the | |
| 117 | // target's own. | |
| 118 | pre(`impl: Trees.Definitions.IMPL) -> bool => true; | |
| 119 | ||
| 120 | visit(`impl: Trees.Definitions.IMPL) is | |
| 121 | let target_symbol = class_or_trait_for(`impl); | |
| 122 | ||
| 123 | if !target_symbol? then | |
| 124 | return; | |
| 125 | fi | |
| 126 | ||
| 127 | if `impl.ancestors? then | |
| 128 | for a in `impl.ancestors do | |
| 129 | let ancestor_type = a.type; | |
| 130 | ||
| 131 | if ancestor_type? then | |
| 132 | if isa Semantic.Types.NAMED(ancestor_type) then | |
| 133 | let ancestor_named_type = ancestor_type; | |
| 134 | ||
| 135 | if ancestor_named_type.symbol.is_trait then | |
| 136 | target_symbol.add_ancestor(ancestor_named_type); | |
| 137 | ||
| 138 | a.check_is_not_void(_logger, "cannot use void type here"); | |
| 139 | ||
| 140 | continue; | |
| 141 | fi | |
| 142 | fi | |
| 143 | ||
| 144 | _logger.error(a.location, "impl can only implement a trait"); | |
| 145 | fi | |
| 146 | od | |
| 147 | fi | |
| 148 | si | |
| 149 | ||
| 150 | pre(`trait: Trees.Definitions.TRAIT) -> bool => true; | |
| 151 | ||
| 152 | visit(`trait: Trees.Definitions.TRAIT) is | |
| 153 | let trait_symbol = cast Semantic.Symbols.TRAIT?(scope_for(`trait))!; | |
| 154 | ||
| 155 | let seen_valid_ancestor mut = false; | |
| 156 | ||
| 157 | if `trait.ancestors? then | |
| 158 | for a in `trait.ancestors do | |
| 159 | let ancestor_type = a.type; | |
| 160 | ||
| 161 | if ancestor_type? then | |
| 162 | if isa Semantic.Types.NAMED(ancestor_type) then | |
| 163 | let ancestor_named_type = ancestor_type; | |
| 164 | ||
| 165 | if ancestor_named_type.symbol.is_trait then | |
| 166 | trait_symbol.add_ancestor(ancestor_named_type); | |
| 167 | seen_valid_ancestor = true; | |
| 168 | ||
| 169 | a.check_is_not_void(_logger, "cannot use void type here"); | |
| 170 | else | |
| 171 | _logger.error(a.location, "trait cannot inherit from class"); | |
| 172 | fi | |
| 173 | else | |
| 174 | _logger.error(a.location, "cannot inherit from this"); | |
| 175 | fi | |
| 176 | else | |
| 177 | Std.error.write_line("refusing to add ancestor with null type {a} to trait {trait_symbol}"); | |
| 178 | fi | |
| 179 | od | |
| 180 | fi | |
| 181 | ||
| 182 | let object_type = _innate_symbol_lookup.get_object_type(); | |
| 183 | ||
| 184 | trait_symbol.push_ancestor(object_type); | |
| 185 | si | |
| 186 | ||
| 187 | pre(`struct: Trees.Definitions.STRUCT) -> bool => true; | |
| 188 | ||
| 189 | visit(`struct: Trees.Definitions.STRUCT) is | |
| 190 | let struct_symbol = cast Semantic.Symbols.STRUCT?(scope_for(`struct))!; | |
| 191 | ||
| 192 | if `struct.ancestors? then | |
| 193 | for a in `struct.ancestors do | |
| 194 | let ancestor_type = a.type; | |
| 195 | ||
| 196 | if ancestor_type? then | |
| 197 | if isa Semantic.Types.NAMED(ancestor_type) then | |
| 198 | let ancestor_named_type = ancestor_type; | |
| 199 | ||
| 200 | if ancestor_named_type.symbol.is_trait then | |
| 201 | struct_symbol.add_ancestor(ancestor_named_type); | |
| 202 | ||
| 203 | a.check_is_not_void(_logger, "cannot use void type here"); | |
| 204 | ||
| 205 | continue; | |
| 206 | fi | |
| 207 | fi | |
| 208 | ||
| 209 | _logger.error(a.location, "structs can only inherit from traits"); | |
| 210 | fi | |
| 211 | od | |
| 212 | fi | |
| 213 | ||
| 214 | struct_symbol.push_ancestor(_innate_symbol_lookup.get_value_type()); | |
| 215 | si | |
| 216 | ||
| 217 | pre(`union: Trees.Definitions.UNION) -> bool => super.pre(`union); | |
| 218 | ||
| 219 | visit(`union: Trees.Definitions.UNION) is | |
| 220 | let union_symbol = cast Semantic.Symbols.UNION?(scope_for(`union))!; | |
| 221 | ||
| 222 | if `union.ancestors? then | |
| 223 | for a in `union.ancestors do | |
| 224 | let ancestor_type = a.type; | |
| 225 | ||
| 226 | if ancestor_type? then | |
| 227 | if isa Semantic.Types.NAMED(ancestor_type) then | |
| 228 | let ancestor_named_type = ancestor_type; | |
| 229 | ||
| 230 | if ancestor_named_type.symbol.is_trait then | |
| 231 | union_symbol.add_ancestor(ancestor_named_type); | |
| 232 | ||
| 233 | a.check_is_not_void(_logger, "cannot use void type here"); | |
| 234 | ||
| 235 | continue; | |
| 236 | fi | |
| 237 | fi | |
| 238 | ||
| 239 | _logger.error(a.location, "unions can only inherit from traits"); | |
| 240 | fi | |
| 241 | od | |
| 242 | fi | |
| 243 | ||
| 244 | union_symbol.push_ancestor(_innate_symbol_lookup.get_object_type()); | |
| 245 | ||
| 246 | super.visit(`union); | |
| 247 | si | |
| 248 | ||
| 249 | pre(`variant: Trees.Definitions.VARIANT) -> bool => true; | |
| 250 | ||
| 251 | visit(`variant: Trees.Definitions.VARIANT) is | |
| 252 | let variant_symbol = cast Semantic.Symbols.VARIANT?(scope_for(`variant))!; | |
| 253 | // a variant is always resolved inside its union's scope | |
| 254 | let union_symbol = current_union_context!; | |
| 255 | let arguments = Collections.LIST[Semantic.Types.Type](); | |
| 256 | ||
| 257 | let union_type = | |
| 258 | if let union_symbol.argument_names? /\ argument_names.count > 0 then | |
| 259 | for argument_name in argument_names do | |
| 260 | let argument_symbol = variant_symbol.find_direct(argument_name); | |
| 261 | let argument_symbol_type = if argument_symbol? then argument_symbol.type else null fi; | |
| 262 | ||
| 263 | if argument_symbol_type? then | |
| 264 | arguments.add(argument_symbol_type) | |
| 265 | else | |
| 266 | arguments.add(Semantic.Types.ERROR()); | |
| 267 | fi | |
| 268 | od | |
| 269 | ||
| 270 | Semantic.Types.GENERIC( | |
| 271 | Source.LOCATION.internal, | |
| 272 | union_symbol, | |
| 273 | arguments); | |
| 274 | else | |
| 275 | Semantic.Types.NAMED( | |
| 276 | union_symbol); | |
| 277 | fi; | |
| 278 | ||
| 279 | variant_symbol.push_ancestor(union_type); | |
| 280 | si | |
| 281 | ||
| 282 | pre(`enum: Trees.Definitions.ENUM) -> bool => true; | |
| 283 | ||
| 284 | visit(`enum: Trees.Definitions.ENUM) is | |
| 285 | let enum_symbol = cast Semantic.Symbols.ENUM_STRUCT?(scope_for(`enum))!; | |
| 286 | ||
| 287 | enum_symbol.push_ancestor(_innate_symbol_lookup.get_enum_type()); | |
| 288 | si | |
| 289 | si | |
| 290 | si |