Skip to main content

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}