Appearance
| 1 | namespace Semantic is | |
| 2 | use IO.Std | |
| 3 | ||
| 4 | use System.Text.StringBuilder | |
| 5 | ||
| 6 | use Collections.Iterable | |
| 7 | use Collections.Iterator | |
| 8 | use Collections.List | |
| 9 | use Collections.LIST | |
| 10 | use Collections.MAP | |
| 11 | use Collections.SET | |
| 12 | ||
| 13 | use Symbols.Function | |
| 14 | ||
| 15 | use Types.Type | |
| 16 | ||
| 17 | use Ghul.Pipes | |
| 18 | ||
| 19 | class METHOD_OVERRIDE_CLASS is | |
| 20 | arguments: List[Type] | |
| 21 | // Number of generic arguments. Functions only override / count as | |
| 22 | // duplicates of siblings with the same generic-argument count; | |
| 23 | // `foo()` and `foo[T]()` are distinct sibling functions, not one | |
| 24 | // overriding the other and not a duplicate. | |
| 25 | generic_arguments_count: int | |
| 26 | ||
| 27 | // The method's own type parameters, in declaration order. Two | |
| 28 | // declarations of the same generic method have parameters that | |
| 29 | // are different symbols, so one side's arguments are read in | |
| 30 | // the other's terms before they are compared. | |
| 31 | generic_arguments: List[Type] | |
| 32 | ||
| 33 | init(arguments: List[Type]) is | |
| 34 | init(arguments, LIST[Type]()) | |
| 35 | si | |
| 36 | ||
| 37 | init(arguments: List[Type], generic_arguments: List[Type]) is | |
| 38 | assert arguments |> all(a => a?) else "override class arguments list contains null elements" | |
| 39 | ||
| 40 | self.arguments = arguments | |
| 41 | self.generic_arguments = generic_arguments | |
| 42 | self.generic_arguments_count = generic_arguments.count | |
| 43 | si | |
| 44 | ||
| 45 | // Declared: the loop over each argument's `matches` is | |
| 46 | // genuinely store-free, but the store-free walk disqualifies | |
| 47 | // any function containing a `for` loop unconditionally rather | |
| 48 | // than reasoning about the loop body. | |
| 49 | =~(other: METHOD_OVERRIDE_CLASS) -> bool pure is | |
| 50 | if other.generic_arguments_count != generic_arguments_count then | |
| 51 | return false | |
| 52 | fi | |
| 53 | ||
| 54 | if other.arguments.count != arguments.count then | |
| 55 | return false | |
| 56 | fi | |
| 57 | ||
| 58 | let theirs = _in_our_terms(other) | |
| 59 | ||
| 60 | for i in 0..arguments.count do | |
| 61 | if !arguments[i].matches(theirs[i]) then | |
| 62 | return false | |
| 63 | fi | |
| 64 | od | |
| 65 | ||
| 66 | return true | |
| 67 | si | |
| 68 | ||
| 69 | // `other`'s arguments with its own type parameters replaced by | |
| 70 | // ours at the same position, so `describe[T](tag: T)` declared | |
| 71 | // twice compares equal although each `T` is its own symbol. | |
| 72 | _in_our_terms(other: METHOD_OVERRIDE_CLASS) -> List[Type] pure => | |
| 73 | Symbols.GENERIC_PARAMETER_ALIGNMENT.rewrite_all( | |
| 74 | other.arguments, generic_arguments, other.generic_arguments) | |
| 75 | ||
| 76 | equals(other: object?) -> bool is | |
| 77 | if !other? then | |
| 78 | return false | |
| 79 | fi | |
| 80 | ||
| 81 | if !isa METHOD_OVERRIDE_CLASS(other) then | |
| 82 | return false | |
| 83 | fi | |
| 84 | ||
| 85 | return self =~ other | |
| 86 | si | |
| 87 | ||
| 88 | get_hash_code() -> int is | |
| 89 | let result mut = generic_arguments_count | |
| 90 | ||
| 91 | // A generic method's argument types mention its own type | |
| 92 | // parameters, which are a different symbol in every | |
| 93 | // declaration, so only the shape can contribute: two that | |
| 94 | // compare equal have to hash equal. | |
| 95 | if generic_arguments_count > 0 then | |
| 96 | return result + arguments.count | |
| 97 | fi | |
| 98 | ||
| 99 | for a in arguments do | |
| 100 | result = result + a.get_hash_code() | |
| 101 | od | |
| 102 | ||
| 103 | return result | |
| 104 | si | |
| 105 | ||
| 106 | to_string() -> string => "({arguments |> join(", ")})" | |
| 107 | si | |
| 108 | si |