Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use LOCATION = Source.LOCATION | |
| 3 | use Symbol = Semantic.Symbols.Symbol | |
| 4 | use Type = Semantic.Types.Type | |
| 5 | ||
| 6 | // Why a use that names a member, or reads through a value that may | |
| 7 | // be absent, is failing: the narrowing it would have needed was | |
| 8 | // dropped earlier in this body, at a call the effect relations | |
| 9 | // could not show left the value alone. The kill ledger holds every | |
| 10 | // such drop of the walk, so the question is only which of them this | |
| 11 | // use is short of, and the answer goes on the error as related | |
| 12 | // information at the call. | |
| 13 | class DROPPED_NARROWING is | |
| 14 | // The call that dropped a type narrowing which would have made | |
| 15 | // this member reachable. A drop of some other fact about the | |
| 16 | // same value, or of a narrowing the member is missing from too, | |
| 17 | // explains nothing and is not offered. | |
| 18 | for_member(target: Symbol?, path: ACCESS_PATH?, name: string, at: LOCATION) -> KILL? static is | |
| 19 | if !target? /\ !path? then | |
| 20 | return null | |
| 21 | fi | |
| 22 | ||
| 23 | let kill = KILL_LEDGER.last_dropped_before(target, path, false, at) | |
| 24 | ||
| 25 | if !kill? then | |
| 26 | return null | |
| 27 | fi | |
| 28 | ||
| 29 | if let narrowed = kill.narrowed_type /\ _has_member(narrowed, name) then | |
| 30 | return kill | |
| 31 | fi | |
| 32 | ||
| 33 | return null | |
| 34 | si | |
| 35 | ||
| 36 | // The call that dropped the presence of this value. | |
| 37 | for_presence(target: Symbol?, path: ACCESS_PATH?, at: LOCATION) -> KILL? static is | |
| 38 | if !target? /\ !path? then | |
| 39 | return null | |
| 40 | fi | |
| 41 | ||
| 42 | return KILL_LEDGER.last_dropped_before(target, path, true, at) | |
| 43 | si | |
| 44 | ||
| 45 | // What to say at the call. One wording for both domains: a | |
| 46 | // presence fact narrows an optional to the type it holds, which | |
| 47 | // is what was lost as much as a type test's own narrower type. | |
| 48 | message(kill: KILL) -> string static is | |
| 49 | let what = if let target = kill.target then target.name elif let path = kill.path then path.to_string() else "the value" fi | |
| 50 | ||
| 51 | if let narrowed = kill.narrowed_type then | |
| 52 | "the narrowing of {what} to {narrowed} ended at this call" | |
| 53 | else | |
| 54 | "the narrowing of {what} ended at this call" | |
| 55 | fi | |
| 56 | si | |
| 57 | ||
| 58 | _has_member(type: Type, name: string) -> bool static is | |
| 59 | if let named: Semantic.Types.NAMED = type then | |
| 60 | return named.find_member(name)? | |
| 61 | fi | |
| 62 | ||
| 63 | return false | |
| 64 | si | |
| 65 | si | |
| 66 | si |