Skip to main content

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};