Appearance
| 1 | namespace Semantic is | |
| 2 | use Logging | |
| 3 | use Source | |
| 4 | ||
| 5 | // A name used as a callable - called, or applied to type arguments - | |
| 6 | // whose nearest symbol cannot be called at all, a local, field or | |
| 7 | // property holding no function, looks past it for a callable of the | |
| 8 | // same name further out, so a value does not hide a function it | |
| 9 | // shares a name with. Returns null to leave resolution as it was, | |
| 10 | // which is every case but the shadowed one. | |
| 11 | // | |
| 12 | // Deliberately narrow: only a symbol that is not callable at all | |
| 13 | // qualifies. A function group whose overloads do not accept the | |
| 14 | // supplied arguments is left alone, so a genuine argument mismatch | |
| 15 | // still reports as one rather than silently calling something else. | |
| 16 | class SHADOWED_CALLABLE_FINDER is | |
| 17 | _logger: Logger | |
| 18 | _symbol_table: SYMBOL_TABLE | |
| 19 | ||
| 20 | init(logger: Logger, symbol_table: SYMBOL_TABLE) is | |
| 21 | _logger = logger | |
| 22 | _symbol_table = symbol_table | |
| 23 | si | |
| 24 | ||
| 25 | find(location: LOCATION, name: string, symbol: Symbols.Symbol) -> Symbols.Symbol? is | |
| 26 | if SYMBOL_TABLE.is_callable_symbol(symbol) then | |
| 27 | return null | |
| 28 | fi | |
| 29 | ||
| 30 | // A local read before its own initializer has completed | |
| 31 | // holds no value to call, whatever type it ends up with - | |
| 32 | // the case a `let` whose initializer calls the name it is | |
| 33 | // declaring runs into. Its type is still an inference | |
| 34 | // placeholder at this point, so it is settled here, ahead | |
| 35 | // of the sentinel test below. | |
| 36 | // | |
| 37 | // Restricted to a reference in the same capture context as | |
| 38 | // the declaration: inside a nested literal the same shape | |
| 39 | // is a lambda referring to itself, where reaching a | |
| 40 | // like-named function further out would be a surprise, so | |
| 41 | // that keeps its existing error. | |
| 42 | let is_uninitialized_local mut = false | |
| 43 | ||
| 44 | if let variable: Symbols.Variable = symbol /\ !variable.is_defined then | |
| 45 | if _symbol_table.current_capture_context != cast Symbols.Symbol?(variable.owner) then | |
| 46 | return null | |
| 47 | fi | |
| 48 | ||
| 49 | is_uninitialized_local = true | |
| 50 | fi | |
| 51 | ||
| 52 | // Otherwise a sentinel type says the slot's type is not | |
| 53 | // known - inference has not settled it, or it failed and | |
| 54 | // was poisoned. Neither is evidence that the symbol holds | |
| 55 | // no function, and looking past a symbol whose declaration | |
| 56 | // already reported an error would add a second diagnostic | |
| 57 | // about the first one's consequence. | |
| 58 | if | |
| 59 | let typed: Types.Typed = symbol /\ | |
| 60 | !is_uninitialized_local /\ | |
| 61 | (typed.type?.is_sentinel ?? false) | |
| 62 | then | |
| 63 | return null | |
| 64 | fi | |
| 65 | ||
| 66 | let callable = _symbol_table.find_enclosing_callable(name) | |
| 67 | ||
| 68 | if !callable? \/ callable == symbol then | |
| 69 | return null | |
| 70 | fi | |
| 71 | ||
| 72 | _logger.warn( | |
| 73 | location, | |
| 74 | "shadowed-non-callable", | |
| 75 | "{name} is not callable here, calling the one from an enclosing scope instead", | |
| 76 | callable.location, | |
| 77 | "callable declaration reached instead" | |
| 78 | ) | |
| 79 | ||
| 80 | return callable | |
| 81 | si | |
| 82 | si | |
| 83 | si |