Skip to main content

dada_ir_sym/check/
scope.rs

1use std::{borrow::Cow, fmt::Display};
2
3use dada_ir_ast::{
4    ast::{AstGenericTerm, AstPath, AstPathKind, AstUse, Identifier, SpanVec, SpannedIdentifier},
5    diagnostic::{Diagnostic, Errors, Level, Reported},
6    inputs::Krate,
7    span::{Span, Spanned},
8};
9use dada_util::{FromImpls, boxed_async_fn};
10use salsa::Update;
11use serde::Serialize;
12
13use crate::{
14    check::{CheckTyInEnv, scope_tree::ScopeTreeNode},
15    ir::{
16        binder::BoundTerm,
17        classes::{SymAggregate, SymAggregateStyle, SymClassMember},
18        functions::SymFunction,
19        module::SymModule,
20        primitive::{SymPrimitive, primitives},
21        types::{SymGenericKind, SymGenericTerm},
22        variables::SymVariable,
23    },
24    prelude::Symbol,
25};
26
27use super::Env;
28
29/// Name resolution scope, used when converting types/function-bodies etc into symbols.
30#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct Scope<'scope, 'db> {
32    span: Span<'db>,
33    chain: ScopeChain<'scope, 'db>,
34}
35
36impl<'scope, 'db> Scope<'scope, 'db> {
37    /// A base scope containing only the primitive names.
38    pub(crate) fn new(db: &'db dyn crate::Db, span: Span<'db>) -> Self {
39        let mut this = Scope {
40            span,
41            chain: ScopeChain::primitives(),
42        };
43
44        let root = db.root();
45        let crate_source = root.libdada_crate(db);
46        this = this.with_prelude(db, span, crate_source);
47
48        this
49    }
50
51    /// Extend this scope with another link in the name resolution chain
52    pub(crate) fn with_link<'scope1>(
53        self,
54        link: impl Into<ScopeChainKind<'scope1, 'db>>,
55    ) -> Scope<'scope1, 'db>
56    where
57        'scope: 'scope1,
58    {
59        let mut this: Scope<'scope1, 'db> = self;
60        this.push_link(link);
61        this
62    }
63
64    pub fn span(&self) -> Span<'db> {
65        self.span
66    }
67
68    /// Extend this scope with the prelude from a crate.
69    /// Crates can define a module named `prelude`.
70    fn with_prelude(self, db: &'db dyn crate::Db, span: Span<'db>, crate_source: Krate) -> Self {
71        let prelude_id = Identifier::prelude(db);
72        match resolve_name_against_crate(
73            db,
74            crate_source,
75            SpannedIdentifier {
76                id: prelude_id,
77                span,
78            },
79        ) {
80            Ok(NameResolutionSym::SymModule(sym)) => self.with_link(ScopeChainKind::SymModule(sym)),
81            Ok(sym) => {
82                let span = sym.span(db).unwrap_or(span);
83                Diagnostic::error(db, span, "prelude is not a module".to_string())
84                    .label(
85                        db,
86                        Level::Error,
87                        span,
88                        format!(
89                            "I expected `prelude` to be a module, but I found {category}",
90                            category = sym.categorize(db)
91                        ),
92                    )
93                    .report(db);
94                self
95            }
96            Err(Reported(_)) => self,
97        }
98    }
99
100    /// Extend this scope with another link in the name resolution chain
101    pub fn push_link(&mut self, kind: impl Into<ScopeChainKind<'scope, 'db>>) {
102        let chain = ScopeChain {
103            kind: kind.into(),
104            next: None,
105        };
106        let prev_chain = std::mem::replace(&mut self.chain, chain);
107        self.chain.next = Some(Box::new(prev_chain));
108    }
109
110    /// Return the innermost class in scope (if any).
111    pub fn aggregate(&self) -> Option<SymAggregate<'db>> {
112        for link in self.chain.iter() {
113            if let ScopeChainKind::SymAggr(aggr) = &link.kind {
114                return Some(*aggr);
115            }
116        }
117        None
118    }
119
120    /// Resolve identifier `id` (found at `span`) in the scope.
121    /// Reports errors if nothing is found and returns `Err(Reported)`.
122    pub(crate) fn resolve_name(
123        &self,
124        db: &'db dyn crate::Db,
125        id: Identifier<'db>,
126        span: Span<'db>,
127    ) -> Errors<NameResolution<'db>> {
128        if let Some(resolution) = self.chain.iter().find_map(|link| link.resolve_name(db, id)) {
129            return Ok(resolution);
130        }
131
132        Err(
133            Diagnostic::error(db, span, format!("could not find anything named `{id}`",))
134                .label(
135                    db,
136                    Level::Error,
137                    span,
138                    "I could not find anything with this name :(",
139                )
140                .report(db),
141        )
142    }
143
144    /// True if `sym` is in scope.
145    pub fn generic_sym_in_scope(&self, db: &'db dyn crate::Db, sym: SymVariable<'db>) -> bool {
146        self.chain.iter().any(|link| link.binds_symbol(db, sym))
147    }
148
149    /// Given a value of type `T` that was resolved against this scope,
150    /// creates a bound version like `Binder<T>` or `Binder<Binder<T>>`
151    /// where all variables defined in scope are contained in these binders.
152    ///
153    /// Each inner binding level in the output binds the symbols from one binding level
154    /// in the scope. The outermost binding level in the output then binds all remaining
155    /// symbols.
156    ///
157    /// Example: Given a scope that has three levels like
158    ///
159    /// * `Class` binding `[A, B]`
160    /// * `Function` binding `[C, D]`
161    /// * Local variables binding `[x, y]`
162    ///
163    /// if we produce a `Binder<'db, Binder<'db, T>>`, then the result would be
164    ///
165    /// * an outer `Binder<Binder<T>>` binds `[A, B, C, D]` that contains...
166    ///     * an inner `Binder<T>` binding `[x, y]` that contains...
167    ///         * the `T` value referencing `A`, `B`, `C`, `D`, `x`, and `y`
168    ///
169    /// # Panics
170    ///
171    /// If the target type `B` requires more binding levels than are present in scope.
172    pub fn into_bound_value<B>(self, db: &'db dyn crate::Db, value: B::LeafTerm) -> B
173    where
174        B: BoundTerm<'db>,
175    {
176        // Compute all the bound variables in this scope.
177        let binders = self.all_binders();
178
179        // If the target type has more binder levels than we do, that is a bug in the caller.
180        assert!(
181            B::BINDER_LEVELS <= binders.len(),
182            "target type has {} binder levels but the scope only has {}",
183            B::BINDER_LEVELS,
184            binders.len()
185        );
186
187        // Do we need to flatten any levels?
188        let extra_binder_levels = binders.len() - B::BINDER_LEVELS;
189        if extra_binder_levels == 0 {
190            // Nope.
191            return B::bind(db, &mut binders.into_iter(), value);
192        }
193
194        // Yep.
195        let flattened_binder_levels = extra_binder_levels + 1;
196        let outer_binder = binders
197            .iter()
198            .take(flattened_binder_levels)
199            .flat_map(|v| v.iter().copied())
200            .collect::<Vec<_>>();
201        let remaining_binders = binders.into_iter().skip(flattened_binder_levels);
202        let mut symbols_to_bind = std::iter::once(outer_binder).chain(remaining_binders);
203        B::bind(db, &mut symbols_to_bind, value)
204    }
205
206    /// Convert `self` into a vec-of-vecs containing the bound generic symbols
207    /// in outermost-to-innermost order. e.g. if you have `class[type A] { fn foo[type B]() }`,
208    /// this will return `[[A], [B]]`.
209    pub fn all_binders(&self) -> Vec<Vec<SymVariable<'db>>> {
210        let mut vec = vec![];
211        for link in self.chain.iter() {
212            match &link.kind {
213                ScopeChainKind::Primitives
214                | ScopeChainKind::SymModule(_)
215                | ScopeChainKind::SymAggr(_) => {}
216                ScopeChainKind::ForAll(cow) => {
217                    vec.push(cow.iter().copied().collect());
218                }
219            }
220        }
221        vec.reverse();
222        vec
223    }
224}
225
226/// A link in the scope resolution chain. We first attempt to resolve an identifier
227/// in the associated [`ScopeChainKind`] and, if nothing is found, proceed to
228/// the next link.
229#[derive(Clone, Debug, PartialEq, Eq)]
230struct ScopeChain<'scope, 'db> {
231    /// Kind of this link.
232    kind: ScopeChainKind<'scope, 'db>,
233
234    /// Next link in the chain. Earlier links shadow later links.
235    next: Option<Box<ScopeChain<'scope, 'db>>>,
236}
237
238/// A link the scope resolution chain.
239#[derive(Clone, Debug, PartialEq, Eq, FromImpls)]
240pub enum ScopeChainKind<'scope, 'db> {
241    /// Introduces the primitives into scope (always present).
242    #[no_from_impl]
243    Primitives,
244
245    /// Records that we are in the scope of a module.
246    SymModule(SymModule<'db>),
247
248    /// Records that we are in the scope of a class
249    SymAggr(SymAggregate<'db>),
250
251    /// Introduces the given symbols into scope.
252    ForAll(Cow<'scope, [SymVariable<'db>]>),
253}
254
255impl<'db> From<SymVariable<'db>> for ScopeChainKind<'_, 'db> {
256    fn from(sym: SymVariable<'db>) -> Self {
257        ScopeChainKind::ForAll(Cow::Owned(vec![sym]))
258    }
259}
260
261#[derive(Clone, Debug, PartialEq, Eq, Serialize, Update)]
262pub(crate) struct NameResolution<'db> {
263    pub generics: Vec<SymGenericTerm<'db>>,
264    pub sym: NameResolutionSym<'db>,
265}
266
267impl<'db> NameResolution<'db> {
268    /// Returns a string describing `self` that fits the mold "an X".
269    pub fn categorize(&self, db: &'db dyn crate::Db) -> impl Display + 'db {
270        self.sym.categorize(db)
271    }
272
273    /// Returns a string describing `self` that fits the mold "an X named `foo`".
274    #[expect(dead_code)]
275    pub fn describe(&self, db: &'db dyn crate::Db) -> impl Display + 'db {
276        self.sym.describe(db)
277    }
278
279    /// Like [`NameResolutionSym::resolve_relative_id`] but also threads the
280    /// generic arguments through.
281    pub(crate) fn resolve_relative_id(
282        self,
283        db: &'db dyn crate::Db,
284        id: SpannedIdentifier<'db>,
285    ) -> Errors<Result<NameResolution<'db>, NameResolution<'db>>> {
286        match self.sym.resolve_relative_id(db, id) {
287            Ok(Ok(sym)) => Ok(Ok(NameResolution {
288                generics: self.generics,
289                sym,
290            })),
291
292            Ok(Err(s)) => {
293                assert_eq!(self.sym, s);
294                Ok(Err(self))
295            }
296
297            Err(e) => Err(e),
298        }
299    }
300
301    /// Attempts to resolve generic argments like `foo[u32]`.    
302    pub(crate) async fn resolve_relative_generic_args(
303        mut self,
304        env: &mut Env<'db>,
305        generics: &SpanVec<'db, AstGenericTerm<'db>>,
306    ) -> Errors<NameResolution<'db>> {
307        let db = env.db();
308
309        let expected_arguments = self.sym.expected_generic_parameters(db);
310        let found_arguments = self.generics.len();
311        assert!(found_arguments <= expected_arguments);
312        let remaining_arguments = expected_arguments - found_arguments;
313
314        if generics.len() > remaining_arguments {
315            let extra_arguments = &generics.values[remaining_arguments..];
316            let extra_span = extra_arguments
317                .first()
318                .unwrap()
319                .span(db)
320                .to(db, extra_arguments.last().unwrap().span(db));
321            return Err(Diagnostic::error(
322                db,
323                extra_span,
324                "extra generic arguments provided".to_string(),
325            )
326            .label(
327                db,
328                Level::Error,
329                extra_span,
330                format!(
331                    "I expected to find at most {remaining_arguments} generic arguments, these are extra"
332                ),
333            )
334        .report(db));
335        }
336
337        for v in generics.values.iter() {
338            self.generics.push(v.check_in_env(env).await);
339        }
340
341        Ok(self)
342    }
343
344    /// Returns the span where the item that is being referenced was declared.
345    /// Returns `None` for primitives or things that have no declaration.
346    pub fn span(&self, db: &'db dyn crate::Db) -> Option<Span<'db>> {
347        self.sym.span(db)
348    }
349}
350
351/// Result of name resolution.
352#[derive(Copy, Clone, Debug, PartialEq, Eq, FromImpls, Serialize, Update)]
353#[allow(clippy::enum_variant_names)]
354pub enum NameResolutionSym<'db> {
355    SymModule(SymModule<'db>),
356    SymAggregate(SymAggregate<'db>),
357    SymFunction(SymFunction<'db>),
358    SymPrimitive(SymPrimitive<'db>),
359    SymVariable(SymVariable<'db>),
360}
361
362impl<'db> NameResolutionSym<'db> {
363    /// Returns a string describing `self` that fits the mold "an X".
364    pub fn categorize(self, db: &'db dyn crate::Db) -> impl Display + 'db {
365        match self {
366            NameResolutionSym::SymModule(_) => Box::new("a module") as Box<dyn Display + 'db>,
367            NameResolutionSym::SymAggregate(_) => Box::new("a class"),
368            NameResolutionSym::SymFunction(_) => Box::new("a function"),
369            NameResolutionSym::SymVariable(var) => match var.kind(db) {
370                SymGenericKind::Type => Box::new("a generic type"),
371                SymGenericKind::Perm => Box::new("a generic permission"),
372                SymGenericKind::Place => Box::new("a local variable"),
373            },
374            NameResolutionSym::SymPrimitive(p) => Box::new(format!("`{}`", p.name(db))),
375        }
376    }
377
378    /// Attempt to resolve a single identifier;
379    /// only works if `self` is a module or other "lexically resolved" name resolution.
380    ///
381    /// Returns `Ok(Ok(r))` if resolution succeeded.
382    ///
383    /// Returns `Ok(Err(self))` if resolution failed because this is not a lexically resolved result.
384    /// Type checking will have to handle it.
385    ///
386    /// Returns error only if this was a lexically resolved name resolution and the identifier is not found.
387    ///
388    /// FIXME: Remove all error reporting from here and push it further up the chain,
389    /// since the context of the lookup may matter to how we report the error.
390    pub(crate) fn resolve_relative_id(
391        self,
392        db: &'db dyn crate::Db,
393        id: SpannedIdentifier<'db>,
394    ) -> Errors<Result<NameResolutionSym<'db>, NameResolutionSym<'db>>> {
395        match self {
396            NameResolutionSym::SymModule(sym_module) => match sym_module
397                .resolve_name_against_definitions(db, id.id)
398            {
399                Some(sym) => Ok(Ok(sym)),
400                None => Err(
401                    Diagnostic::error(db, id.span, "nothing named `{}` found in module")
402                        .label(
403                            db,
404                            Level::Error,
405                            id.span,
406                            format!(
407                                "I could not find anything named `{}` in the module `{}`",
408                                id.id,
409                                sym_module.name(db),
410                            ),
411                        )
412                        .report(db),
413                ),
414            },
415
416            // FIXME: When we add traits, we have to decide how we want to manage trait member lookup.
417            // * Does this mean we have to merge name resolution plus type checking?
418            // * Do we not support `SomeClass.TraitMember` and instead prefer `SomeTrait.Member[SomeClass]`?
419            // * Do we only support `SomeClass.TraitMember` in expression contexts?
420            NameResolutionSym::SymAggregate(sym_class) => {
421                match sym_class.inherent_member(db, id.id) {
422                    Some(class_member) => match class_member {
423                        SymClassMember::SymFunction(sym) => Ok(Ok(sym.into())),
424
425                        // FIXME: we should probably have a NameResolutionSym::Field?
426                        SymClassMember::SymField(_) => Ok(Err(self)),
427                    },
428                    None => Ok(Err(self)),
429                }
430            }
431
432            _ => Ok(Err(self)),
433        }
434    }
435
436    /// Returns a string describing `self` that fits the mold "an X named `foo`".
437    pub fn describe(self, db: &'db dyn crate::Db) -> impl Display + 'db {
438        match self {
439            NameResolutionSym::SymModule(sym_module) => {
440                format!("a module named `{}`", sym_module.name(db))
441            }
442            NameResolutionSym::SymAggregate(sym_class) => {
443                format!("a class named `{}`", sym_class.name(db))
444            }
445            NameResolutionSym::SymFunction(sym_function) => {
446                format!("a function named `{}`", sym_function.name(db))
447            }
448            NameResolutionSym::SymVariable(var) => match var.name(db) {
449                Some(n) => format!("{} named `{n}`", self.categorize(db)),
450                None => "an anonymous generic parameter".to_string(),
451            },
452            NameResolutionSym::SymPrimitive(sym_primitive) => {
453                format!("the primitive type `{}`", sym_primitive.name(db))
454            }
455        }
456    }
457
458    fn expected_generic_parameters(&self, db: &'db dyn crate::Db) -> usize {
459        match self {
460            NameResolutionSym::SymModule(sym) => sym.expected_generic_parameters(db),
461            NameResolutionSym::SymAggregate(sym) => sym.expected_generic_parameters(db),
462            NameResolutionSym::SymFunction(sym) => sym.expected_generic_parameters(db),
463            NameResolutionSym::SymPrimitive(_) => 0,
464            NameResolutionSym::SymVariable(_) => 0,
465        }
466    }
467
468    fn span(&self, db: &'db dyn crate::Db) -> Option<Span<'db>> {
469        match self {
470            NameResolutionSym::SymModule(sym) => Some(sym.span(db)),
471            NameResolutionSym::SymAggregate(sym) => Some(sym.span(db)),
472            NameResolutionSym::SymFunction(sym) => Some(sym.span(db)),
473            NameResolutionSym::SymPrimitive(_) => None,
474            NameResolutionSym::SymVariable(sym) => Some(sym.span(db)),
475        }
476    }
477
478    /// If this symbol references an aggregate (class, struct, etc) returns the
479    /// aggregate style. Else returns `None`.
480    pub fn style(self, db: &'db dyn crate::Db) -> Option<SymAggregateStyle> {
481        match self {
482            NameResolutionSym::SymModule(_) => None,
483            NameResolutionSym::SymAggregate(aggr) => Some(aggr.style(db)),
484            NameResolutionSym::SymFunction(_) => None,
485            NameResolutionSym::SymPrimitive(_) => None,
486            NameResolutionSym::SymVariable(_) => None,
487        }
488    }
489}
490
491/// Partial name resolution: This simply extracts what symbol has been named by the
492/// user in a path. It can by synchronous and only requires a scope, not a type checking
493/// environment. This is used when creating default permissions, as we want to be able
494/// to do that before type checking has truly begun.
495pub trait ResolveToSym<'db> {
496    fn resolve_to_sym(
497        self,
498        db: &'db dyn crate::Db,
499        scope: &Scope<'_, 'db>,
500    ) -> Errors<NameResolutionSym<'db>>;
501}
502
503impl<'db> ResolveToSym<'db> for AstPath<'db> {
504    fn resolve_to_sym(
505        self,
506        db: &'db dyn crate::Db,
507        scope: &Scope<'_, 'db>,
508    ) -> Errors<NameResolutionSym<'db>> {
509        // This is "similar but different" to the code for `AstPath::resolve_in`.
510        // This code ignores generic arguments, but they are otherwise the same.
511        match self.kind(db) {
512            AstPathKind::Identifier(first_id) => first_id.resolve_to_sym(db, scope),
513            AstPathKind::GenericArgs { path, args: _ } => path.resolve_to_sym(db, scope),
514            AstPathKind::Member { path, id } => {
515                let base = path.resolve_to_sym(db, scope)?;
516                match base.resolve_relative_id(db, *id)? {
517                    Ok(r) => Ok(r),
518                    Err(base) => Err(report_path_referencing_field(db, id, base)),
519                }
520            }
521        }
522    }
523}
524
525/// Reports an error if the user gave a path like `Foo.Bar` and `Foo` wound up being a class
526/// that doesn't have nested items.
527fn report_path_referencing_field<'db>(
528    db: &'db dyn crate::Db,
529    id: &SpannedIdentifier<'_>,
530    base: NameResolutionSym<'_>,
531) -> Reported {
532    Diagnostic::error(db, id.span, "unexpected `.` in path")
533        .label(
534            db,
535            Level::Error,
536            id.span,
537            format!(
538                "I don't know how to interpret `.` applied to {} here",
539                base.categorize(db),
540            ),
541        )
542        .report(db)
543}
544
545/// Full name resolution: This requires converting generic arguments into symbols
546/// which entails some amount of type checking and interacting with the environment.
547/// This is therefore an `async` function.
548pub trait Resolve<'db> {
549    async fn resolve_in(self, env: &mut Env<'db>) -> Errors<NameResolution<'db>>;
550}
551
552impl<'db> Resolve<'db> for AstPath<'db> {
553    /// Given a path that must resolve to some kind of name resolution,
554    /// resolve it if we can (reporting errors if it is invalid).
555    #[boxed_async_fn]
556    async fn resolve_in(self, env: &mut Env<'db>) -> Errors<NameResolution<'db>> {
557        // This is "similar but different" to the code for `AstPath::resolve_to_sym`.
558        // That code ignores generic arguments, but they are otherwise the same.
559        let db = env.db();
560        match self.kind(db) {
561            AstPathKind::Identifier(first_id) => first_id.resolve_in(env).await,
562            AstPathKind::GenericArgs { path, args } => {
563                let base = path.resolve_in(env).await?;
564                base.resolve_relative_generic_args(env, args).await
565            }
566            AstPathKind::Member { path, id } => {
567                let base = path.resolve_in(env).await?;
568                match base.resolve_relative_id(db, *id)? {
569                    Ok(r) => Ok(r),
570                    Err(base) => Err(report_path_referencing_field(db, id, base.sym)),
571                }
572            }
573        }
574    }
575}
576
577impl<'db> ResolveToSym<'db> for SpannedIdentifier<'db> {
578    fn resolve_to_sym(
579        self,
580        db: &'db dyn crate::Db,
581        scope: &Scope<'_, 'db>,
582    ) -> Errors<NameResolutionSym<'db>> {
583        let NameResolution { sym, generics: _ } = scope.resolve_name(db, self.id, self.span)?;
584        Ok(sym)
585    }
586}
587
588impl<'db> Resolve<'db> for SpannedIdentifier<'db> {
589    async fn resolve_in(self, env: &mut Env<'db>) -> Errors<NameResolution<'db>> {
590        env.scope.resolve_name(env.db(), self.id, self.span)
591    }
592}
593
594impl<'scope, 'db> ScopeChain<'scope, 'db> {
595    /// Creates the base of the name resolution chain (primitive types).
596    fn primitives() -> Self {
597        ScopeChain {
598            kind: ScopeChainKind::Primitives,
599            next: None,
600        }
601    }
602
603    /// Walks the chain, starting with the innermost links.
604    pub fn iter(&self) -> impl Iterator<Item = &ScopeChain<'scope, 'db>> {
605        let mut p = Some(self);
606
607        std::iter::from_fn(move || match p.take() {
608            Some(q) => {
609                if let Some(n) = &q.next {
610                    p = Some(n);
611                } else {
612                    p = None;
613                }
614
615                Some(q)
616            }
617            None => None,
618        })
619    }
620
621    fn resolve_name(
622        &self,
623        db: &'db dyn crate::Db,
624        id: Identifier<'db>,
625    ) -> Option<NameResolution<'db>> {
626        match &self.kind {
627            ScopeChainKind::Primitives => primitives(db)
628                .iter()
629                .copied()
630                .filter(|p| p.name(db) == id)
631                .map(|p| NameResolution {
632                    generics: vec![],
633                    sym: p.into(),
634                })
635                .next(),
636
637            ScopeChainKind::SymAggr(_) => None,
638
639            ScopeChainKind::SymModule(sym) => {
640                // Somewhat subtle: we give definitions precedence over uses. If the same name appears
641                // in both locations, an error is reported by checking.
642
643                if let Some(sym) = sym.resolve_name_against_definitions(db, id) {
644                    match sym {
645                        NameResolutionSym::SymModule(sym) => {
646                            Some(self.internal_module_item(db, sym))
647                        }
648                        NameResolutionSym::SymAggregate(sym) => {
649                            Some(self.internal_module_item(db, sym))
650                        }
651                        NameResolutionSym::SymFunction(sym) => {
652                            Some(self.internal_module_item(db, sym))
653                        }
654                        NameResolutionSym::SymPrimitive(_) | NameResolutionSym::SymVariable(_) => {
655                            // cannot be members of a module
656                            unreachable!()
657                        }
658                    }
659                } else {
660                    sym.resolve_name_against_uses(db, id)
661                }
662            }
663
664            ScopeChainKind::ForAll(symbols) => {
665                if let Some(index) = symbols.iter().position(|&s| s.name(db) == Some(id)) {
666                    let sym = symbols[index];
667                    Some(NameResolution {
668                        generics: vec![],
669                        sym: NameResolutionSym::SymVariable(sym),
670                    })
671                } else {
672                    None
673                }
674            }
675        }
676    }
677
678    /// Resolve an identifier like `x` that we mapped to some item in a module.
679    fn internal_module_item(
680        &self,
681        _db: &'db dyn crate::Db,
682        sym: impl ScopeTreeNode<'db> + Into<NameResolutionSym<'db>> + Copy,
683    ) -> NameResolution<'db> {
684        NameResolution {
685            // No generic arguments have been provided yet.
686            generics: vec![],
687            sym: sym.into(),
688        }
689    }
690
691    fn binds_symbol(&self, _db: &'db dyn crate::Db, sym: SymVariable<'db>) -> bool {
692        match &self.kind {
693            ScopeChainKind::SymAggr(_)
694            | ScopeChainKind::Primitives
695            | ScopeChainKind::SymModule(_) => false,
696
697            ScopeChainKind::ForAll(symbols) => symbols.contains(&sym),
698        }
699    }
700}
701
702impl<'db> SymModule<'db> {
703    fn resolve_name_against_definitions(
704        self,
705        db: &'db dyn crate::Db,
706        id: Identifier<'db>,
707    ) -> Option<NameResolutionSym<'db>> {
708        if let Some(&v) = self.class_map(db).get(&id) {
709            return Some(v.into());
710        }
711
712        if let Some(&v) = self.function_map(db).get(&id) {
713            return Some(v.into());
714        }
715
716        None
717    }
718
719    fn resolve_name_against_uses(
720        self,
721        db: &'db dyn crate::Db,
722        id: Identifier<'db>,
723    ) -> Option<NameResolution<'db>> {
724        let ast_use = self.ast_use_map(db).get(&id)?;
725        resolve_ast_use(db, *ast_use)
726    }
727}
728
729#[salsa::tracked]
730fn resolve_ast_use<'db>(
731    db: &'db dyn crate::Db,
732    ast_use: AstUse<'db>,
733) -> Option<NameResolution<'db>> {
734    let crate_name = ast_use.crate_name(db);
735    let Some(crate_source) = db.root().crate_source(db, crate_name.id) else {
736        Diagnostic::error(
737            db,
738            crate_name.span,
739            format!(
740                "could not find a crate named `{}`",
741                ast_use.crate_name(db).id
742            ),
743        )
744        .label(
745            db,
746            Level::Error,
747            crate_name.span,
748            "could not find this crate",
749        )
750        .report(db);
751        return None;
752    };
753
754    ast_use
755        .path(db)
756        .resolve_against(db, |id| resolve_name_against_crate(db, crate_source, id))
757}
758
759fn resolve_name_against_crate<'db>(
760    db: &'db dyn crate::Db,
761    krate: Krate,
762    id: SpannedIdentifier<'db>,
763) -> Errors<NameResolutionSym<'db>> {
764    let source_file = db.source_file(krate, &[id.id]);
765    match source_file.contents(db) {
766        Ok(_) => {
767            let sym_module = source_file.symbol(db);
768            Ok(sym_module.into())
769        }
770
771        Err(message) => Err(Diagnostic::new(db, Level::Error, id.span(db), message).report(db)),
772    }
773}
774
775trait ResolveAgainst<'db> {
776    fn resolve_against(
777        self,
778        db: &'db dyn crate::Db,
779        op: impl FnOnce(SpannedIdentifier<'db>) -> Errors<NameResolutionSym<'db>>,
780    ) -> Option<NameResolution<'db>>;
781}
782
783impl<'db> ResolveAgainst<'db> for AstPath<'db> {
784    fn resolve_against(
785        self,
786        _db: &'db dyn crate::Db,
787        _op: impl FnOnce(SpannedIdentifier<'db>) -> Errors<NameResolutionSym<'db>>,
788    ) -> Option<NameResolution<'db>> {
789        todo!()
790    }
791}