Skip to content
← Back

src/semantic/shadowed_callable_finder.ghul

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