Skip to content
← Back

src/syntax/process/resolve_uses.ghul

1
namespace Syntax.Process is
2
use Logging;
3
use Source;
4
use Trees;
5
6
use Ghul.Pipes;
7
8
// Resolves use clauses into their namespace block's scope. Runs
9
// twice: a first round after declare-symbols binds every import that
10
// refers to a type - classes, structs, unions, variants, enums - and
11
// namespaces, which is everything resolve-type-expressions needs. A
12
// name that fails to bind is left for the second round (`_final`
13
// unset marks the first-round instance), which runs after
14
// declare-members, so an import can also name a static method, a
15
// global function or an enum member - including one an impl or
16
// partial block injects; anything still unresolved then is an error.
17
class RESOLVE_USES: ScopeVisitorBase is
18
_logger: Logger;
19
_symbol_table: Semantic.SYMBOL_TABLE;
20
_symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS;
21
_final: bool;
22
23
init(
24
logger: Logger,
25
symbol_table: Semantic.SYMBOL_TABLE,
26
namespaces: Semantic.NAMESPACES,
27
symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS,
28
final: bool
29
) is
30
super.init(symbol_table, namespaces);
31
_logger = logger;
32
_symbol_table = symbol_table;
33
_symbol_use_locations = symbol_use_locations;
34
_final = final;
35
si
36
37
apply(node: Node) is
38
node.walk(self);
39
si
40
41
pre(`namespace: Definitions.NAMESPACE) -> bool is
42
let namespace_scope = enter_namespace(`namespace);
43
44
// FIXME: these searches probably should start at the scope immediately enclosing the namespace
45
for u in `namespace.body.uses do
46
if !u.`use? then
47
continue;
48
fi
49
50
if !_final then
51
u.is_import_resolved = _resolve_use(u, namespace_scope);
52
elif !u.is_import_resolved then
53
_resolve_use(u, namespace_scope);
54
fi
55
od
56
return false;
57
si
58
59
visit(`namespace: Definitions.NAMESPACE) is
60
leave_namespace(`namespace);
61
si
62
63
// Returns true when the clause was definitively handled - a
64
// successful import or, in the final round, a reported error.
65
_resolve_use(u: Definitions.USE, namespace_scope: Semantic.NAMESPACE_SCOPE) -> bool is
66
let used_name = u.`use;
67
68
if !used_name? then
69
return true;
70
fi
71
72
let used_symbol = find_enclosing(used_name);
73
74
if !used_symbol? then
75
if _final then
76
_logger.error(used_name.location, "used identifier {used_name} is not defined ");
77
fi
78
79
return false;
80
fi
81
82
let use_name mut = used_symbol.name;
83
let alias = u.name;
84
85
if alias? then
86
use_name = alias.name;
87
fi
88
89
if isa Semantic.Symbols.NAMESPACE(used_symbol) then
90
_symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol);
91
92
if namespace_scope.contains_used_symbol(use_name) then
93
if alias? then
94
_logger.error(alias.location, "duplicate use");
95
else
96
_logger.error(used_name.location, "duplicate use");
97
fi
98
elif alias? then
99
namespace_scope.add(alias.name, used_symbol);
100
else
101
namespace_scope.add(used_symbol);
102
fi
103
elif used_symbol.is_function_group then
104
let fg = cast Semantic.Symbols.FUNCTION_GROUP?(used_symbol)!;
105
106
if !fg.functions |> any(f => !f.is_instance) then
107
if fg.functions.count == 1 then
108
_logger.error(used_name.location, "cannot use instance function");
109
else
110
_logger.error(used_name.location, "cannot use function group comprising only instance functions");
111
fi
112
fi
113
114
_symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol.collapse_group_if_single_member());
115
116
let existing_used_symbol = namespace_scope.get_used_symbol(use_name);
117
118
let use_function_group: Semantic.Symbols.FUNCTION_GROUP mut;
119
120
if existing_used_symbol? then
121
use_function_group = cast Semantic.Symbols.FUNCTION_GROUP?(existing_used_symbol)!;
122
else
123
use_function_group = Semantic.Symbols.FUNCTION_GROUP(LOCATION.unknown, namespace_scope, use_name);
124
namespace_scope.add(use_name, use_function_group);
125
fi
126
127
use_function_group.add(fg);
128
elif !used_symbol.is_instance then
129
if namespace_scope.contains_used_symbol(use_name) then
130
if alias? then
131
_logger.error(alias.location, "duplicate use");
132
else
133
_logger.error(used_name.location, "duplicate use");
134
fi
135
else
136
_symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol);
137
namespace_scope.add(use_name, used_symbol);
138
fi
139
else
140
_logger.error(used_name.location, "cannot use instance member");
141
fi
142
143
return true;
144
si
145
si
146
si