wolf_resolve/lib.rs
1//! Name resolution (spec chapter 6): modules, imports, visibility, scopes.
2//!
3//! Resolution runs in two passes over all modules of a project, together with the std modules:
4//!
5//! 1. **Collect**: the top-level names of every module, the members of types (enum variants and
6//! the functions of inherent `impl` blocks), then the imports and the import graph.
7//! 2. **Resolve**: every name in types, expressions and patterns, with local scopes.
8//!
9//! Section order is layout, not visibility (chapter 2, rule 2.6), which is why the first pass
10//! sees the whole project before anything is resolved. The result is a table from syntax nodes to
11//! what they name, for the type checker (M4), plus the diagnostics of chapter 6.
12
13mod body;
14mod checks;
15mod collect;
16mod names;
17mod targets;
18
19use std::collections::BTreeMap;
20
21use wolf_ast::{File, NodeId};
22use wolf_diag::Diagnostic;
23use wolf_project::{ConfigOverride, Kind};
24use wolf_span::{FileId, Span};
25
26/// What a module is for.
27#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
28pub enum Role {
29 /// The prelude module of std; never imported.
30 Prelude,
31 /// Another std module.
32 Std,
33 /// `src/main.wolf` or `src/lib.wolf`.
34 Entry,
35 /// Another module under `src/`.
36 Src,
37 /// A module under `tests/`.
38 Test,
39 /// A module under `examples/`.
40 Example,
41 /// A native module, `native.<path>` (spec chapter 6, section 1a): its declarations were read
42 /// from the target code.
43 Native,
44}
45
46/// The names of native modules that the compiler could not map, with the reason (E0713): by
47/// module path (`native.slug`), then by name.
48pub type NativeNames =
49 std::collections::BTreeMap<String, std::collections::BTreeMap<String, String>>;
50
51/// The key of [`NativeNames`] for a native module whose file could not be read (E0714): its names
52/// are not reported one by one.
53pub const UNREADABLE: &str = "*";
54
55/// One parsed module given to the resolver.
56pub struct ModuleInput<'a> {
57 /// The module path derived from the file path.
58 pub path: Vec<String>,
59 /// What the module is for.
60 pub role: Role,
61 /// The source file.
62 pub file: FileId,
63 /// The syntax tree.
64 pub ast: &'a File,
65}
66
67/// Facts about the project that resolution needs.
68pub struct ProjectInfo<'a> {
69 /// `cli` or `lib`.
70 pub kind: Kind,
71 /// Overrides from `[config.*]`, checked against the constants (E0613).
72 pub config: &'a [ConfigOverride],
73 /// Names of native modules that are not available, with the reason (E0713).
74 pub native: &'a NativeNames,
75}
76
77/// Identifies a module.
78#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
79pub struct ModuleId(pub u32);
80
81/// Identifies a declaration.
82#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
83pub struct DefId(pub u32);
84
85/// Identifies a local variable, parameter or pattern binding.
86#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
87pub struct LocalId(pub u32);
88
89/// The kinds of declarations.
90#[derive(Clone, Copy, Debug, PartialEq, Eq)]
91pub enum DefKind {
92 /// `struct`
93 Struct,
94 /// `enum`
95 Enum,
96 /// `type A = B`
97 Alias,
98 /// `intrinsic type`
99 IntrinsicType,
100 /// `interface`
101 Interface,
102 /// A free function.
103 Fn,
104 /// A `config` constant.
105 Config,
106 /// A function from `extern`.
107 ExternFn,
108 /// An opaque type from `extern`.
109 ExternType,
110 /// A variant of an enum.
111 Variant {
112 /// The enum.
113 parent: DefId,
114 /// The payload form.
115 payload: Payload,
116 },
117 /// A function in an inherent `impl` block (a method if it takes `self`).
118 Member {
119 /// The type the block is for.
120 owner: DefId,
121 /// Whether it takes `self`.
122 method: bool,
123 },
124}
125
126/// The payload form of a variant.
127#[derive(Clone, Copy, Debug, PartialEq, Eq)]
128pub enum Payload {
129 /// No payload.
130 None,
131 /// Positional payload.
132 Tuple,
133 /// Named fields.
134 Struct,
135}
136
137impl DefKind {
138 /// Whether the declaration names a type.
139 pub fn is_type(self) -> bool {
140 matches!(
141 self,
142 DefKind::Struct
143 | DefKind::Enum
144 | DefKind::Alias
145 | DefKind::IntrinsicType
146 | DefKind::Interface
147 | DefKind::ExternType
148 )
149 }
150
151 fn describe(self) -> &'static str {
152 match self {
153 DefKind::Struct => "struct",
154 DefKind::Enum => "enum",
155 DefKind::Alias => "type alias",
156 DefKind::IntrinsicType => "built-in type",
157 DefKind::Interface => "interface",
158 DefKind::Fn => "function",
159 DefKind::Config => "constant",
160 DefKind::ExternFn => "extern function",
161 DefKind::ExternType => "extern type",
162 DefKind::Variant { .. } => "variant",
163 DefKind::Member { method: true, .. } => "method",
164 DefKind::Member { method: false, .. } => "associated function",
165 }
166 }
167}
168
169/// A declaration.
170#[derive(Clone, Debug)]
171pub struct Def {
172 /// What it is.
173 pub kind: DefKind,
174 /// Its name.
175 pub name: String,
176 /// The module that declares it.
177 pub module: ModuleId,
178 /// `pub` (variants have the visibility of their enum).
179 pub public: bool,
180 /// The span of the name in the declaration.
181 pub span: Span,
182}
183
184/// What a name in the source refers to.
185#[derive(Clone, Copy, Debug, PartialEq, Eq)]
186pub enum Res {
187 /// A declaration.
188 Def(DefId),
189 /// A module (through an import).
190 Module(ModuleId),
191 /// A local variable, parameter or binding.
192 Local(LocalId),
193 /// A type parameter, identified by the span of its declaration.
194 TypeParam(Span),
195 /// `Self` inside an `impl` block or an interface.
196 SelfType,
197}
198
199/// A local variable.
200#[derive(Clone, Debug)]
201pub struct Local {
202 /// Its name.
203 pub name: String,
204 /// Where it is declared.
205 pub span: Span,
206}
207
208/// Facts about a module after resolution.
209#[derive(Clone, Debug)]
210pub struct ModuleInfo {
211 /// The module path.
212 pub path: Vec<String>,
213 /// What the module is for.
214 pub role: Role,
215 /// The source file.
216 pub file: FileId,
217 /// Top-level names declared in the module.
218 pub items: BTreeMap<String, DefId>,
219}
220
221/// The result of name resolution.
222#[derive(Debug, Default)]
223pub struct Resolved {
224 /// All modules, std included.
225 pub modules: Vec<ModuleInfo>,
226 /// All declarations.
227 pub defs: Vec<Def>,
228 /// All locals.
229 pub locals: Vec<Local>,
230 /// What each resolved node names: `Name` and `Field` expressions, types, patterns, struct
231 /// literals and the shorthand fields of struct literals and patterns.
232 pub res: BTreeMap<(FileId, NodeId), Res>,
233 /// The local declared at each name span (`let`, `var`, parameters, loop variables, closure
234 /// parameters, pattern bindings).
235 pub local_decls: BTreeMap<Span, LocalId>,
236 /// Members (variants and inherent functions) of each type.
237 pub members: BTreeMap<DefId, BTreeMap<String, DefId>>,
238 /// The type of each `impl` block, inherent or for an interface, keyed by module, section
239 /// index and item index. Blocks whose type did not resolve are missing.
240 pub impls: BTreeMap<(ModuleId, usize, usize), DefId>,
241 /// Diagnostics of chapter 6.
242 pub diagnostics: Vec<Diagnostic>,
243}
244
245impl Resolved {
246 /// The declaration with this id.
247 pub fn def(&self, id: DefId) -> Option<&Def> {
248 self.defs.get(id.0 as usize)
249 }
250}
251
252/// Resolves a project. `modules` must contain the std modules (`wolf_std::MODULES`, parsed by
253/// the caller, with roles [`Role::Prelude`] and [`Role::Std`]) and every module of the project.
254pub fn resolve(modules: &[ModuleInput<'_>], project: &ProjectInfo<'_>) -> Resolved {
255 let mut resolver = collect::Resolver::new(modules, project);
256 resolver.collect();
257 resolver.resolve_bodies();
258 resolver.finish()
259}
260
261pub use names::{is_pascal_case, is_snake_case, suggest};
262pub use targets::{check_target, check_vm};