resolve_lang/env.rs
1//! The host environment: names that live outside the units being resolved.
2//!
3//! A [`Program`](crate::Program) resolves its units against each other. Every
4//! other name (other packages, precompiled units, the standard library,
5//! primitive types, host functions) comes from an [`Env`] the host provides.
6
7use alloc::{collections::BTreeMap, vec::Vec};
8
9use hir_lang::{DefId, ItemKind, Name, Ns, Res, Shape, Symbol, Vis};
10
11use crate::policy::Namespace;
12
13/// What kind of definition a resolution names, as far as scoping cares.
14///
15/// It decides which syntactic namespaces may name the definition (the table
16/// of HIR spec §3.3), whether a path may continue through it (`Vec::new`),
17/// and whether a bare identifier pattern matches it rather than binding.
18///
19/// # Examples
20///
21/// ```
22/// use hir_lang::Ns;
23/// use resolve_lang::DefKind;
24///
25/// assert!(DefKind::Fn.fits(Ns::Value));
26/// assert!(!DefKind::Fn.fits(Ns::Type));
27/// assert!(DefKind::Record { unit: false }.is_prefix());
28/// ```
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
30#[non_exhaustive]
31pub enum DefKind {
32 /// A module (or a whole unit's root module).
33 Module,
34 /// A function.
35 Fn,
36 /// A constant.
37 Const,
38 /// A global variable.
39 Global,
40 /// A record; `unit` for a record with no fields (`struct Unit;`).
41 Record {
42 /// The record has the unit shape.
43 unit: bool,
44 },
45 /// A sum.
46 Sum,
47 /// A class; `mixin` for a PHP trait.
48 Class {
49 /// The class is a mixin (never instantiated).
50 mixin: bool,
51 },
52 /// An interface.
53 Interface,
54 /// A type alias.
55 Alias,
56 /// An associated type.
57 AssocType,
58 /// A sum variant; `unit` for a variant with no fields.
59 Variant {
60 /// The variant has the unit shape.
61 unit: bool,
62 },
63 /// A host or standard-library symbol.
64 Extern,
65 /// A primitive type.
66 Prim,
67 /// A local binder (a variable, parameter, or generic parameter). Paths
68 /// name binders through `Res::Local`; this kind appears in diagnostics.
69 Local,
70 /// An error item (already reported).
71 Err,
72}
73
74impl DefKind {
75 /// The kind of a HIR item, or `None` for items that name nothing
76 /// resolvable (`impl`, imports, mixin uses).
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use hir_lang::{ItemKind, RecordDef, Shape};
82 /// use resolve_lang::DefKind;
83 ///
84 /// let unit = ItemKind::Record(RecordDef { shape: Shape::Unit, ..RecordDef::default() });
85 /// assert_eq!(DefKind::of_item(&unit), Some(DefKind::Record { unit: true }));
86 /// ```
87 #[must_use]
88 pub const fn of_item(kind: &ItemKind) -> Option<Self> {
89 Some(match kind {
90 ItemKind::Fn(_) => Self::Fn,
91 ItemKind::Record(r) => Self::Record {
92 unit: matches!(r.shape, Shape::Unit),
93 },
94 ItemKind::Sum(_) => Self::Sum,
95 ItemKind::Class(c) => Self::Class { mixin: c.mixin },
96 ItemKind::Interface(_) => Self::Interface,
97 ItemKind::Alias { .. } => Self::Alias,
98 ItemKind::AssocType { .. } => Self::AssocType,
99 ItemKind::Const { .. } => Self::Const,
100 ItemKind::Global { .. } => Self::Global,
101 ItemKind::Module { .. } => Self::Module,
102 ItemKind::Err => Self::Err,
103 ItemKind::Impl(_) | ItemKind::Import { .. } | ItemKind::MixinUse(_) => return None,
104 })
105 }
106
107 /// Whether a fully resolved path in syntactic namespace `ns` may name a
108 /// definition of this kind (HIR spec §3.3).
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use hir_lang::Ns;
114 /// use resolve_lang::DefKind;
115 ///
116 /// assert!(DefKind::Variant { unit: true }.fits(Ns::Pattern));
117 /// assert!(DefKind::Module.fits(Ns::Import));
118 /// assert!(!DefKind::Module.fits(Ns::Value));
119 /// assert!(DefKind::Prim.fits(Ns::Type));
120 /// ```
121 #[must_use]
122 pub const fn fits(self, ns: Ns) -> bool {
123 match ns {
124 Ns::Value => matches!(
125 self,
126 Self::Fn
127 | Self::Const
128 | Self::Global
129 | Self::Record { .. }
130 | Self::Class { .. }
131 | Self::Err
132 | Self::Variant { .. }
133 | Self::Extern
134 ),
135 Ns::Type => matches!(
136 self,
137 Self::Record { .. }
138 | Self::Sum
139 | Self::Class { .. }
140 | Self::Interface
141 | Self::Alias
142 | Self::AssocType
143 | Self::Err
144 | Self::Variant { .. }
145 | Self::Prim
146 | Self::Extern
147 ),
148 Ns::Pattern => matches!(
149 self,
150 Self::Const
151 | Self::Record { .. }
152 | Self::Class { .. }
153 | Self::Err
154 | Self::Variant { .. }
155 | Self::Extern
156 ),
157 Ns::Region => false,
158 Ns::Import => !matches!(self, Self::Prim),
159 }
160 }
161
162 /// Whether a path may continue past a definition of this kind, leaving the
163 /// rest to type-directed or module resolution (a resolved *prefix*).
164 ///
165 /// # Examples
166 ///
167 /// ```
168 /// use resolve_lang::DefKind;
169 ///
170 /// assert!(DefKind::Sum.is_prefix());
171 /// assert!(!DefKind::Fn.is_prefix());
172 /// assert!(!DefKind::Variant { unit: false }.is_prefix());
173 /// ```
174 #[must_use]
175 pub const fn is_prefix(self) -> bool {
176 matches!(
177 self,
178 Self::Module
179 | Self::Record { .. }
180 | Self::Sum
181 | Self::Class { .. }
182 | Self::Interface
183 | Self::Alias
184 | Self::AssocType
185 | Self::Err
186 | Self::Prim
187 | Self::Extern
188 )
189 }
190
191 /// Whether a bare identifier pattern naming this definition matches it
192 /// (a constant, a unit variant, a unit record) instead of binding.
193 ///
194 /// # Examples
195 ///
196 /// ```
197 /// use resolve_lang::DefKind;
198 ///
199 /// assert!(DefKind::Const.is_pattern_constant());
200 /// assert!(!DefKind::Variant { unit: false }.is_pattern_constant());
201 /// ```
202 #[must_use]
203 pub const fn is_pattern_constant(self) -> bool {
204 matches!(
205 self,
206 Self::Const | Self::Variant { unit: true } | Self::Record { unit: true }
207 )
208 }
209
210 /// A short lowercase name, for messages.
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// use resolve_lang::DefKind;
216 ///
217 /// assert_eq!(DefKind::Fn.name(), "function");
218 /// ```
219 #[must_use]
220 pub const fn name(self) -> &'static str {
221 match self {
222 Self::Module => "module",
223 Self::Fn => "function",
224 Self::Const => "constant",
225 Self::Global => "global",
226 Self::Record { .. } => "record",
227 Self::Sum => "sum type",
228 Self::Class { mixin: false } => "class",
229 Self::Class { mixin: true } => "mixin",
230 Self::Interface => "interface",
231 Self::Alias => "type alias",
232 Self::AssocType => "associated type",
233 Self::Variant { .. } => "variant",
234 Self::Extern => "extern",
235 Self::Prim => "primitive type",
236 Self::Local => "local",
237 Self::Err => "error item",
238 }
239 }
240}
241
242/// A name the environment exports: what it resolves to, its kind, and who may
243/// see it.
244///
245/// # Examples
246///
247/// ```
248/// use hir_lang::{Prim, Res, Vis};
249/// use resolve_lang::{DefKind, Export};
250///
251/// let int = Export::new(Res::Prim(Prim::I64), DefKind::Prim);
252/// assert_eq!(int.vis, Vis::Public);
253/// ```
254#[derive(Clone, Copy, Debug, PartialEq, Eq)]
255pub struct Export {
256 /// The resolution a path naming it gets.
257 pub res: Res,
258 /// Its kind.
259 pub kind: DefKind,
260 /// Its visibility. The environment filters what a unit may see; anything
261 /// but `Public` is reported as an access error from another unit.
262 pub vis: Vis,
263}
264
265impl Export {
266 /// A public export.
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use hir_lang::{Res, Symbol};
272 /// use resolve_lang::{DefKind, Export};
273 ///
274 /// let sym = Symbol::from_u32(1).unwrap();
275 /// let e = Export::new(Res::Extern(sym), DefKind::Extern);
276 /// assert_eq!(e.kind, DefKind::Extern);
277 /// ```
278 #[must_use]
279 pub const fn new(res: Res, kind: DefKind) -> Self {
280 Self {
281 res,
282 kind,
283 vis: Vis::Public,
284 }
285 }
286
287 /// The same export with visibility `vis`.
288 ///
289 /// # Examples
290 ///
291 /// ```
292 /// use hir_lang::{Res, Symbol, Vis};
293 /// use resolve_lang::{DefKind, Export};
294 ///
295 /// let sym = Symbol::from_u32(1).unwrap();
296 /// let e = Export::new(Res::Extern(sym), DefKind::Extern).with_vis(Vis::Package);
297 /// assert_eq!(e.vis, Vis::Package);
298 /// ```
299 #[must_use]
300 pub const fn with_vis(mut self, vis: Vis) -> Self {
301 self.vis = vis;
302 self
303 }
304}
305
306/// The host's side of resolution: everything outside the program.
307///
308/// Every method has a default that knows nothing, so a host implements only
309/// what its language has. Lookups are by exact [`Name`] (symbol and hygiene
310/// mark). The resolver calls each method a bounded number of times per path
311/// segment, and the enumeration methods only for glob imports from outside
312/// the program and for did-you-mean suggestions.
313///
314/// # Examples
315///
316/// ```
317/// use hir_lang::{Name, Prim, Res};
318/// use resolve_lang::{DefKind, Env, Export, Namespace};
319///
320/// /// Primitive types only: `int` is `i64`.
321/// struct Prims { int: Name }
322///
323/// impl Env for Prims {
324/// fn prelude(&self, name: Name, ns: Namespace) -> Option<Export> {
325/// (name == self.int && ns == Namespace::Type)
326/// .then(|| Export::new(Res::Prim(Prim::I64), DefKind::Prim))
327/// }
328/// }
329/// # let _ = Prims { int: Name::new(hir_lang::Symbol::from_u32(1).unwrap()) };
330/// ```
331pub trait Env {
332 /// A name visible as the first segment of a path in every unit, after
333 /// every lexical scope: another package, a precompiled unit, an extern
334 /// module. Usually a [`DefKind::Module`] or [`DefKind::Extern`].
335 fn root(&self, name: Name) -> Option<Export> {
336 let _ = name;
337 None
338 }
339
340 /// The prelude: names visible everywhere, after lexical scopes and roots
341 /// (builtins, primitive type names).
342 fn prelude(&self, name: Name, ns: Namespace) -> Option<Export> {
343 let _ = (name, ns);
344 None
345 }
346
347 /// A member of a container the program does not define: a module or class
348 /// of another package, an extern module. `container` is the resolution
349 /// the path reached so far.
350 fn member(&self, container: Res, name: Name, ns: Namespace) -> Option<Export> {
351 let _ = (container, name, ns);
352 None
353 }
354
355 /// Calls `f` for every member of an outside container, for glob imports
356 /// and suggestions.
357 fn for_each_member(&self, container: Res, f: &mut dyn FnMut(Name, Namespace, Export)) {
358 let _ = (container, f);
359 }
360
361 /// Calls `f` for every root name, for suggestions.
362 fn for_each_root(&self, f: &mut dyn FnMut(Name)) {
363 let _ = f;
364 }
365
366 /// Calls `f` for every prelude name, for suggestions.
367 fn for_each_prelude(&self, f: &mut dyn FnMut(Name, Namespace)) {
368 let _ = f;
369 }
370}
371
372/// An environment with nothing in it: every name outside the program is
373/// unresolved.
374///
375/// # Examples
376///
377/// ```
378/// use hir_lang::{Name, Symbol};
379/// use resolve_lang::{Env, NoEnv};
380///
381/// let n = Name::new(Symbol::from_u32(1).unwrap());
382/// assert!(NoEnv.root(n).is_none());
383/// ```
384#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
385pub struct NoEnv;
386
387impl Env for NoEnv {}
388
389/// A container key for [`MapEnv`]: a definition or an extern symbol.
390#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
391enum ContainerKey {
392 Def(DefId),
393 Extern(Symbol),
394}
395
396impl ContainerKey {
397 fn of(res: Res) -> Option<Self> {
398 match res {
399 Res::Def(d) => Some(Self::Def(d)),
400 Res::Extern(s) => Some(Self::Extern(s)),
401 _ => None,
402 }
403 }
404}
405
406/// A ready-made in-memory [`Env`]: roots, a prelude, and members of outside
407/// containers, each registered once.
408///
409/// Lookups are `O(log n)`; enumeration is in name order, so suggestions are
410/// deterministic.
411///
412/// # Examples
413///
414/// ```
415/// use hir_lang::{Name, Prim, Res};
416/// use intern_lang::Interner;
417/// use resolve_lang::{DefKind, Env, Export, MapEnv, Namespace};
418///
419/// let mut names = Interner::new();
420/// let int = Name::new(names.intern("int"));
421/// let env = MapEnv::new().with_prelude(int, Namespace::Type, Export::new(Res::Prim(Prim::I64), DefKind::Prim));
422/// assert_eq!(env.prelude(int, Namespace::Type).map(|e| e.res), Some(Res::Prim(Prim::I64)));
423/// assert!(env.prelude(int, Namespace::Value).is_none());
424/// ```
425#[derive(Clone, Debug, Default)]
426pub struct MapEnv {
427 roots: BTreeMap<Name, Export>,
428 prelude: BTreeMap<(Name, Namespace), Export>,
429 members: BTreeMap<ContainerKey, BTreeMap<(Name, Namespace), Export>>,
430}
431
432impl MapEnv {
433 /// An empty environment.
434 ///
435 /// # Examples
436 ///
437 /// ```
438 /// use resolve_lang::MapEnv;
439 ///
440 /// let _env = MapEnv::new();
441 /// ```
442 #[must_use]
443 pub fn new() -> Self {
444 Self::default()
445 }
446
447 /// Adds a root name (replacing an earlier one of the same name).
448 ///
449 /// # Examples
450 ///
451 /// ```
452 /// use hir_lang::{Name, Res};
453 /// use intern_lang::Interner;
454 /// use resolve_lang::{DefKind, Env, Export, MapEnv};
455 ///
456 /// let mut names = Interner::new();
457 /// let std = names.intern("std");
458 /// let env = MapEnv::new().with_root(Name::new(std), Export::new(Res::Extern(std), DefKind::Extern));
459 /// assert!(env.root(Name::new(std)).is_some());
460 /// ```
461 #[must_use]
462 pub fn with_root(mut self, name: Name, export: Export) -> Self {
463 let _replaced = self.roots.insert(name, export);
464 self
465 }
466
467 /// Adds a prelude name in one namespace.
468 ///
469 /// # Examples
470 ///
471 /// ```
472 /// use hir_lang::{Name, Res};
473 /// use intern_lang::Interner;
474 /// use resolve_lang::{DefKind, Env, Export, MapEnv, Namespace};
475 ///
476 /// let mut names = Interner::new();
477 /// let print = names.intern("print");
478 /// let env = MapEnv::new().with_prelude(Name::new(print), Namespace::Value, Export::new(Res::Extern(print), DefKind::Extern));
479 /// assert!(env.prelude(Name::new(print), Namespace::Value).is_some());
480 /// ```
481 #[must_use]
482 pub fn with_prelude(mut self, name: Name, ns: Namespace, export: Export) -> Self {
483 let _replaced = self.prelude.insert((name, ns), export);
484 self
485 }
486
487 /// Adds a member of an outside container (a `Res::Def` or `Res::Extern`;
488 /// other resolutions are ignored).
489 ///
490 /// # Examples
491 ///
492 /// ```
493 /// use hir_lang::{Name, Res};
494 /// use intern_lang::Interner;
495 /// use resolve_lang::{DefKind, Env, Export, MapEnv, Namespace};
496 ///
497 /// let mut names = Interner::new();
498 /// let (os, path) = (names.intern("os"), names.intern("path"));
499 /// let env = MapEnv::new().with_member(Res::Extern(os), Name::new(path), Namespace::Module, Export::new(Res::Extern(path), DefKind::Extern));
500 /// assert!(env.member(Res::Extern(os), Name::new(path), Namespace::Module).is_some());
501 /// ```
502 #[must_use]
503 pub fn with_member(
504 mut self,
505 container: Res,
506 name: Name,
507 ns: Namespace,
508 export: Export,
509 ) -> Self {
510 if let Some(key) = ContainerKey::of(container) {
511 let _replaced = self
512 .members
513 .entry(key)
514 .or_default()
515 .insert((name, ns), export);
516 }
517 self
518 }
519}
520
521impl Env for MapEnv {
522 fn root(&self, name: Name) -> Option<Export> {
523 self.roots.get(&name).copied()
524 }
525
526 fn prelude(&self, name: Name, ns: Namespace) -> Option<Export> {
527 self.prelude.get(&(name, ns)).copied()
528 }
529
530 fn member(&self, container: Res, name: Name, ns: Namespace) -> Option<Export> {
531 let key = ContainerKey::of(container)?;
532 self.members.get(&key)?.get(&(name, ns)).copied()
533 }
534
535 fn for_each_member(&self, container: Res, f: &mut dyn FnMut(Name, Namespace, Export)) {
536 let Some(members) = ContainerKey::of(container).and_then(|k| self.members.get(&k)) else {
537 return;
538 };
539 for (&(name, ns), export) in members {
540 f(name, ns, *export);
541 }
542 }
543
544 fn for_each_root(&self, f: &mut dyn FnMut(Name)) {
545 for name in self.roots.keys() {
546 f(*name);
547 }
548 }
549
550 fn for_each_prelude(&self, f: &mut dyn FnMut(Name, Namespace)) {
551 for (name, ns) in self.prelude.keys() {
552 f(*name, *ns);
553 }
554 }
555}
556
557/// Collects an environment's member names of one container, sorted.
558pub(crate) fn env_members(env: &dyn Env, container: Res) -> Vec<(Name, Namespace, Export)> {
559 let mut out = Vec::new();
560 env.for_each_member(container, &mut |n, ns, e| out.push((n, ns, e)));
561 out
562}
563
564#[cfg(test)]
565#[allow(clippy::unwrap_used)]
566mod tests {
567 use super::*;
568 use hir_lang::{Def, ItemId, Prim, UnitId};
569
570 fn sym(i: u32) -> Symbol {
571 Symbol::from_u32(i).unwrap()
572 }
573
574 #[test]
575 fn test_map_env_enumerates_members_of_one_container_only() {
576 let a = Res::Extern(sym(1));
577 let b = Res::Extern(sym(2));
578 let e = Export::new(Res::Extern(sym(9)), DefKind::Extern);
579 let env = MapEnv::new()
580 .with_member(a, Name::new(sym(5)), Namespace::Value, e)
581 .with_member(a, Name::new(sym(3)), Namespace::Type, e)
582 .with_member(b, Name::new(sym(4)), Namespace::Value, e);
583 let names: Vec<u32> = env_members(&env, a)
584 .iter()
585 .map(|(n, _, _)| n.sym.as_u32())
586 .collect();
587 assert_eq!(names, [3, 5]);
588 assert!(env_members(&env, Res::Prim(Prim::I32)).is_empty());
589 }
590
591 #[test]
592 fn test_def_kind_matches_hir_namespace_table() {
593 assert!(DefKind::Class { mixin: false }.fits(Ns::Pattern));
594 assert!(!DefKind::Sum.fits(Ns::Value));
595 assert!(!DefKind::Fn.fits(Ns::Region));
596 assert!(DefKind::Extern.fits(Ns::Import));
597 assert!(!DefKind::Prim.fits(Ns::Import));
598 }
599
600 #[test]
601 fn test_member_on_non_container_is_ignored() {
602 let d = DefId::foreign(UnitId::new(1), Def::Item(ItemId::from_index(0).unwrap()));
603 let n = Name::new(sym(1));
604 let env = MapEnv::new().with_member(
605 Res::Err,
606 n,
607 Namespace::Value,
608 Export::new(Res::Def(d), DefKind::Fn),
609 );
610 assert!(env.member(Res::Err, n, Namespace::Value).is_none());
611 let env = env.with_member(
612 Res::Def(d),
613 n,
614 Namespace::Value,
615 Export::new(Res::Def(d), DefKind::Fn),
616 );
617 assert!(env.member(Res::Def(d), n, Namespace::Value).is_some());
618 }
619}