Appearance
| 1 | namespace Semantic is | |
| 2 | use Source.LOCATION | |
| 3 | ||
| 4 | use Collections.LIST | |
| 5 | ||
| 6 | // A rule that could not fire on this walk because one of its inputs | |
| 7 | // was still an inference placeholder: which rule, the placeholder it | |
| 8 | // waits on, and where. Recorded instead of committing to a result | |
| 9 | // computed from the settled inputs alone, or reporting the placeholder | |
| 10 | // as an error the whole-body loop may yet erase. | |
| 11 | class OBLIGATION(rule: string, awaiting: Types.Type, location: LOCATION?) | |
| 12 | ||
| 13 | // The obligations recorded during the current walk of the body being | |
| 14 | // compiled. The whole-body loop in COMPILE_LAMBDAS re-walks a body | |
| 15 | // while its walks make progress, and every re-walk records the | |
| 16 | // obligations still standing afresh, so the queue is cleared at each | |
| 17 | // walk and read once the loop has stopped: an obligation still | |
| 18 | // standing then, on a placeholder nothing settled, is reported at the | |
| 19 | // placeholder's origin, naming the variable whose type the body could | |
| 20 | // not infer. | |
| 21 | // | |
| 22 | // Recording an obligation marks the walk as having consumed an | |
| 23 | // unresolved type, which is what keeps the loop walking; the sites | |
| 24 | // that record one need not also signal that themselves. | |
| 25 | class OBLIGATIONS is | |
| 26 | _bodies: LIST[LIST[OBLIGATION]] static | |
| 27 | ||
| 28 | init() static is | |
| 29 | _bodies = LIST[LIST[OBLIGATION]]() | |
| 30 | _previous = LIST[LIST[Symbols.Variable]]() | |
| 31 | _defaulted = LIST[LIST[Symbols.Variable]]() | |
| 32 | _learned = LIST[int]() | |
| 33 | si | |
| 34 | ||
| 35 | begin_body() static is | |
| 36 | _bodies.add(LIST[OBLIGATION]()) | |
| 37 | _previous.add(LIST[Symbols.Variable]()) | |
| 38 | _defaulted.add(LIST[Symbols.Variable]()) | |
| 39 | _learned.add(0) | |
| 40 | si | |
| 41 | ||
| 42 | // Per body, the origins its previous walk left waiting, for | |
| 43 | // `is_stuck` to compare against; a stack beside `_bodies`, since a | |
| 44 | // body compiled during another's walk has walks of its own. | |
| 45 | _previous: LIST[LIST[Symbols.Variable]] static | |
| 46 | ||
| 47 | // Per body, how many bounds and constraints its current walk has | |
| 48 | // recorded that were not recorded before. A walk that leaves the | |
| 49 | // same obligations standing as the walk before it has still moved | |
| 50 | // when this is not zero: what it learned is what the next walk | |
| 51 | // settles the waiting origin from. | |
| 52 | _learned: LIST[int] static | |
| 53 | ||
| 54 | // Counts a bound or constraint that carried information, for every | |
| 55 | // body currently being walked - a body compiled during another's | |
| 56 | // walk is something that walk learned too. | |
| 57 | note_learned() static is | |
| 58 | for i in 0.._learned.count do | |
| 59 | _learned[i] = _learned[i] + 1 | |
| 60 | od | |
| 61 | si | |
| 62 | ||
| 63 | // Per body, the origins the fixing step has taken a default for. | |
| 64 | // Unlike the queue itself this survives `begin_walk`: the walk | |
| 65 | // that follows the default is the walk that has to see it. | |
| 66 | _defaulted: LIST[LIST[Symbols.Variable]] static | |
| 67 | ||
| 68 | // The rule an untyped local initialized with an empty array | |
| 69 | // literal waits under. The one rule with a default, so the one | |
| 70 | // `take_defaults` answers. | |
| 71 | EMPTY_LITERAL: string static => "empty_literal" | |
| 72 | ||
| 73 | begin_walk() static is | |
| 74 | if _bodies.count == 0 then | |
| 75 | return | |
| 76 | fi | |
| 77 | ||
| 78 | let previous = LIST[Symbols.Variable]() | |
| 79 | ||
| 80 | for obligation in standing do | |
| 81 | if let placeholder: Types.INFERRED_VARIABLE_TYPE = obligation.awaiting then | |
| 82 | if !previous.contains(placeholder.origin) then | |
| 83 | previous.add(placeholder.origin) | |
| 84 | fi | |
| 85 | fi | |
| 86 | od | |
| 87 | ||
| 88 | _previous[_previous.count - 1] = previous | |
| 89 | _bodies[_bodies.count - 1].clear() | |
| 90 | _learned[_learned.count - 1] = 0 | |
| 91 | si | |
| 92 | ||
| 93 | // Whether this walk left exactly the origins waiting that the | |
| 94 | // previous walk did and learned nothing while doing it, so a | |
| 95 | // further walk can only repeat this one. | |
| 96 | is_stuck: bool static is | |
| 97 | if _learned.count > 0 /\ _learned[_learned.count - 1] > 0 then | |
| 98 | return false | |
| 99 | fi | |
| 100 | ||
| 101 | let current = LIST[Symbols.Variable]() | |
| 102 | ||
| 103 | for obligation in standing do | |
| 104 | if let placeholder: Types.INFERRED_VARIABLE_TYPE = obligation.awaiting then | |
| 105 | if !current.contains(placeholder.origin) then | |
| 106 | current.add(placeholder.origin) | |
| 107 | fi | |
| 108 | fi | |
| 109 | od | |
| 110 | ||
| 111 | let previous = if _previous.count > 0 then _previous[_previous.count - 1] else LIST[Symbols.Variable]() fi | |
| 112 | ||
| 113 | if current.count != previous.count then | |
| 114 | return false | |
| 115 | fi | |
| 116 | ||
| 117 | for origin in current do | |
| 118 | if !previous.contains(origin) then | |
| 119 | return false | |
| 120 | fi | |
| 121 | od | |
| 122 | ||
| 123 | return true | |
| 124 | si | |
| 125 | ||
| 126 | end_body() static is | |
| 127 | if _bodies.count > 0 then | |
| 128 | _bodies.remove_at(_bodies.count - 1) | |
| 129 | _previous.remove_at(_previous.count - 1) | |
| 130 | _defaulted.remove_at(_defaulted.count - 1) | |
| 131 | _learned.remove_at(_learned.count - 1) | |
| 132 | fi | |
| 133 | si | |
| 134 | ||
| 135 | // The obligations the last walk of the current body recorded. | |
| 136 | standing: LIST[OBLIGATION] static => | |
| 137 | if _bodies.count > 0 then _bodies[_bodies.count - 1] else LIST[OBLIGATION]() fi | |
| 138 | ||
| 139 | defer(rule: string, awaiting: Types.Type, location: LOCATION?) static is | |
| 140 | INFERENCE_TRACE.obligation(rule, awaiting, location) | |
| 141 | ||
| 142 | if _bodies.count > 0 then | |
| 143 | _bodies[_bodies.count - 1].add(OBLIGATION(rule, awaiting, location)) | |
| 144 | fi | |
| 145 | ||
| 146 | IoC.CONTAINER.instance.logger.mark_consumed_any() | |
| 147 | si | |
| 148 | ||
| 149 | // Takes the language default for every standing obligation that | |
| 150 | // has one, and says whether it took any. Called once the body's | |
| 151 | // loop has stopped: a default is an answer to the walks having | |
| 152 | // run out rather than information a walk found, so taking one | |
| 153 | // earlier pre-empts the walk that would have settled the origin | |
| 154 | // properly. The caller answers true with one more walk, which is | |
| 155 | // where the default reaches the literal and everything typed | |
| 156 | // from it. | |
| 157 | take_defaults() -> bool static is | |
| 158 | let taken mut = false | |
| 159 | ||
| 160 | for obligation in standing do | |
| 161 | if obligation.rule !~ EMPTY_LITERAL then | |
| 162 | continue | |
| 163 | fi | |
| 164 | ||
| 165 | if let placeholder: Types.INFERRED_VARIABLE_TYPE = obligation.awaiting then | |
| 166 | let origin = placeholder.origin | |
| 167 | ||
| 168 | if let type = origin.type /\ type.is_settled then | |
| 169 | continue | |
| 170 | fi | |
| 171 | ||
| 172 | let resolved = origin.try_get_inferred_type() | |
| 173 | ||
| 174 | if resolved? /\ resolved.is_settled then | |
| 175 | continue | |
| 176 | fi | |
| 177 | ||
| 178 | if has_default_for(origin) then | |
| 179 | continue | |
| 180 | fi | |
| 181 | ||
| 182 | _defaulted[_defaulted.count - 1].add(origin) | |
| 183 | ||
| 184 | taken = true | |
| 185 | fi | |
| 186 | od | |
| 187 | ||
| 188 | return taken | |
| 189 | si | |
| 190 | ||
| 191 | // Whether the fixing step has taken a default for this origin, so | |
| 192 | // the site that waited on it takes the default rather than waiting | |
| 193 | // again. | |
| 194 | has_default_for(origin: Symbols.Variable) -> bool static => | |
| 195 | _defaulted.count > 0 /\ _defaulted[_defaulted.count - 1].contains(origin) | |
| 196 | ||
| 197 | // Called once the loop has stopped without converging. Each | |
| 198 | // variable whose placeholder an obligation still waits on, and | |
| 199 | // whose type nothing in the body settled, is reported once, at | |
| 200 | // its declaration, pointing at the first site that waited on it. | |
| 201 | // A constructor's type-argument phantom is reported by | |
| 202 | // TYPE_ARG_PLACEHOLDER_REGISTRY instead, which knows the | |
| 203 | // construction it belongs to. | |
| 204 | fix(logger: Logging.Logger) static is | |
| 205 | let reported = LIST[Symbols.Variable]() | |
| 206 | ||
| 207 | for obligation in standing do | |
| 208 | if let placeholder: Types.INFERRED_VARIABLE_TYPE = obligation.awaiting then | |
| 209 | let origin = placeholder.origin | |
| 210 | ||
| 211 | if isa Symbols.INFERRED_TYPE_ARG_ORIGIN(origin) \/ origin.name.starts_with("$") then | |
| 212 | continue | |
| 213 | fi | |
| 214 | ||
| 215 | if reported.contains(origin) \/ has_default_for(origin) then | |
| 216 | continue | |
| 217 | fi | |
| 218 | ||
| 219 | let resolved = origin.try_get_inferred_type() | |
| 220 | ||
| 221 | if resolved? /\ resolved.is_settled then | |
| 222 | continue | |
| 223 | fi | |
| 224 | ||
| 225 | if let type = origin.type /\ type.is_settled then | |
| 226 | continue | |
| 227 | fi | |
| 228 | ||
| 229 | reported.add(origin) | |
| 230 | ||
| 231 | if let location = _first_site_for(origin) then | |
| 232 | logger.error(origin.location, "cannot infer the type of {origin.name}", location, "{origin.name} is needed here") | |
| 233 | else | |
| 234 | logger.error(origin.location, "cannot infer the type of {origin.name}") | |
| 235 | fi | |
| 236 | fi | |
| 237 | od | |
| 238 | si | |
| 239 | ||
| 240 | // Where the first standing obligation on `origin` with a location | |
| 241 | // was recorded. | |
| 242 | _first_site_for(origin: Symbols.Variable) -> LOCATION? static is | |
| 243 | for obligation in standing do | |
| 244 | if let placeholder: Types.INFERRED_VARIABLE_TYPE = obligation.awaiting, location = obligation.location then | |
| 245 | if placeholder.origin == origin then | |
| 246 | return location | |
| 247 | fi | |
| 248 | fi | |
| 249 | od | |
| 250 | ||
| 251 | return null | |
| 252 | si | |
| 253 | si | |
| 254 | si |