petr_resolve/
resolver.rs

1// TODO:
2// use a push_error API which sets more diagnostic fields, similar to how the parser does it
3
4use std::rc::Rc;
5
6use miette::Diagnostic;
7use petr_ast::{Ast, Commented, Expression, FunctionDeclaration, FunctionParameter, OperatorExpression};
8use petr_bind::{Binder, Dependency, FunctionId, Item, ScopeId};
9use petr_utils::{Identifier, Path, Span, SpannedItem, SymbolInterner, TypeId};
10use thiserror::Error;
11
12use crate::resolved::{QueryableResolvedItems, ResolvedItems};
13#[derive(Debug, Error, Diagnostic)]
14pub enum ResolutionError {
15    #[error("Function parameter not found: {0}")]
16    FunctionParameterNotFound(String),
17    #[error("Symbol not found: {0}")]
18    NotFound(String),
19    #[error("Could not find implementation for operator: {0} at {1}")]
20    OperatorImplementationNotFound(String, String),
21}
22
23pub(crate) struct Resolver {
24    pub resolved: ResolvedItems,
25    pub interner: SymbolInterner,
26    pub errs:     Vec<SpannedItem<ResolutionError>>,
27}
28
29#[derive(Debug, Clone)]
30pub struct TypeDeclaration {
31    pub name:     Identifier,
32    pub variants: Box<[TypeVariant]>,
33}
34
35#[derive(Debug, Clone)]
36pub struct TypeVariant {
37    pub name:   Identifier,
38    pub fields: Box<[TypeField]>,
39}
40
41#[derive(Debug, Clone)]
42pub struct TypeField {
43    pub name: Identifier,
44    pub ty:   Type,
45}
46
47#[derive(Clone, Copy, Debug)]
48pub enum Type {
49    Integer,
50    Bool,
51    Unit,
52    String,
53    // like `Unit`, but doesn't throw additional type errors to prevent cascading errors.
54    ErrorRecovery,
55    Named(TypeId),
56    Generic(Identifier),
57}
58
59impl Resolve for petr_ast::Ty {
60    type Resolved = Type;
61
62    fn resolve(
63        &self,
64        _resolver: &mut Resolver,
65        binder: &Binder,
66        scope_id: ScopeId,
67    ) -> Option<Type> {
68        Some(match self {
69            petr_ast::Ty::Int => Type::Integer,
70            petr_ast::Ty::Bool => Type::Bool,
71            petr_ast::Ty::String => Type::String,
72            petr_ast::Ty::Unit => Type::Unit,
73            petr_ast::Ty::Named(name) => match binder.find_symbol_in_scope(name.id, scope_id) {
74                Some(Item::Type(id)) => Type::Named(*id),
75                Some(something) => {
76                    let name = _resolver.interner.get(name.id);
77                    // this makes sense, the type constructor is getting resolved instead of the ty
78                    // find_symbol_in_scope could take in what it is looking for as a parameter,
79                    // _or_ we could have a special case when a function body is just a type
80                    // constructorjkkj
81                    todo!("push error -- symbol {name} is not type, it is a {something:?}");
82                    // return None;
83                },
84                None => Type::Generic(*name),
85            },
86        })
87    }
88}
89
90#[derive(Clone, Debug)]
91pub struct FunctionCall {
92    pub function: FunctionId,
93    pub args:     Vec<Expr>,
94    pub span:     Span,
95}
96
97impl FunctionCall {
98    pub fn span(&self) -> petr_utils::Span {
99        self.span
100    }
101}
102
103#[derive(Clone, Debug)]
104pub struct Function {
105    pub name:        Identifier,
106    pub params:      Vec<(Identifier, Type)>,
107    pub return_type: Type,
108    pub body:        Expr,
109}
110
111#[derive(Clone, Debug)]
112pub struct Expr {
113    pub kind: ExprKind,
114    pub span: Span,
115}
116
117impl Expr {
118    pub fn error_recovery(span: Span) -> Self {
119        Self {
120            kind: ExprKind::ErrorRecovery,
121            span,
122        }
123    }
124
125    pub fn new(
126        kind: ExprKind,
127        span: Span,
128    ) -> Self {
129        Self { kind, span }
130    }
131}
132
133#[derive(Clone, Debug)]
134pub enum ExprKind {
135    Literal(petr_ast::Literal),
136    List(Box<[Expr]>),
137    FunctionCall(FunctionCall),
138    Variable { name: Identifier, ty: Type },
139    Intrinsic(Intrinsic),
140    Unit,
141    // the `id` is the id of the type declaration that defined this constructor
142    TypeConstructor(TypeId, Box<[Expr]>),
143    ErrorRecovery,
144    ExpressionWithBindings { bindings: Vec<Binding>, expression: Box<Expr> },
145}
146
147#[derive(Clone, Debug)]
148pub struct Binding {
149    pub name:       Identifier,
150    pub expression: Expr,
151}
152
153#[derive(Clone, Debug)]
154pub struct Intrinsic {
155    pub intrinsic: petr_ast::Intrinsic,
156    pub args:      Box<[Expr]>,
157}
158
159impl Resolver {
160    #[cfg(test)]
161    pub fn new_from_single_ast(
162        ast: Ast,
163        interner: SymbolInterner,
164    ) -> Self {
165        let binder = Binder::from_ast(&ast);
166        let mut resolver = Self {
167            errs: Vec::new(),
168            resolved: ResolvedItems::new(),
169            interner,
170        };
171        resolver.add_package(&binder);
172        resolver
173    }
174
175    pub fn new(
176        ast: Ast,
177        mut interner: SymbolInterner,
178        dependencies: Vec<Dependency>,
179    ) -> Self {
180        let binder = Binder::from_ast_and_deps(&ast, dependencies, &mut interner);
181        let mut resolver = Self {
182            errs: Vec::new(),
183            resolved: ResolvedItems::new(),
184            interner,
185        };
186        resolver.add_package(&binder);
187        resolver
188    }
189
190    pub fn add_package(
191        &mut self,
192        binder: &Binder,
193    ) {
194        // Iterate over the binder's scopes and resolve all symbols
195        let scopes_and_ids = binder.scope_iter().collect::<Vec<_>>();
196        for (scope_id, scope) in scopes_and_ids {
197            for (_name, item) in scope.iter() {
198                self.resolve_item(item.item(), binder, scope_id)
199            }
200        }
201    }
202
203    fn resolve_item(
204        &mut self,
205        item: &Item,
206        binder: &Binder,
207        scope_id: ScopeId,
208    ) {
209        use Item::*;
210        match item {
211            Function(func, func_scope) => self.resolve_function(binder, *func, *func_scope),
212            Type(ty) => self.resolve_type(binder, *ty, scope_id),
213            FunctionParameter(_ty) => {
214                // I don't think we have to do anything here but not sure
215            },
216            Binding(a) => {
217                let binding = binder.get_binding(*a);
218                let resolved_expr = match binding.val.resolve(self, binder, scope_id) {
219                    Some(o) => o,
220                    None => {
221                        let name = self.interner.get(binding.name.id);
222                        self.errs.push(binding.name.span.with_item(ResolutionError::NotFound(name.to_string())));
223                        return;
224                    },
225                };
226                self.resolved.bindings.insert(
227                    *a,
228                    crate::resolver::Binding {
229                        name:       binding.name,
230                        expression: resolved_expr,
231                    },
232                );
233            },
234            // TODO not sure if we can skip this, or if we should resolve it during imports
235            Module(id) => {
236                let module = binder.get_module(*id);
237                let scope_id = module.root_scope;
238                let scope = binder.iter_scope(scope_id);
239                for (_name, item) in scope {
240                    self.resolve_item(item.item(), binder, scope_id);
241                }
242            },
243            Import { .. } => { // do nothing?
244                 // find the module that the import refers to
245                 // the first ident is either a top-level module or one that is in this scope
246                 // let mut path_iter = path.iter();
247                 // let Some(first_item) = binder.find_symbol_in_scope(
248                 //     path_iter.next().expect("import with no items was parsed -- should be an invariant").id,
249                 //     scope_id,
250                 // ) else {
251                 //     todo!("push import item not found error")
252                 // };
253
254                // let first_item = match first_item {
255                //     Item::Module(id) => id,
256                //     _ => todo!("push error -- import path is not a module"),
257                // };
258
259                // let mut rover = binder.get_module(*first_item);
260                // // iterate over the rest of the path to find the path item
261                // for (ix, item) in path_iter.enumerate() {
262                //     let is_last = ix == path.len() - 1;
263                //     let Some(next_symbol) = binder.find_symbol_in_scope(item.id, rover.root_scope) else { todo!("push item not found err") };
264
265                //     match next_item {
266                //         Item::Module(id) => rover = binder.get_module(id),
267                //         otherwise if is_last => {
268                //             let alias = alias.unwrap_or_else(|| item.name);
269
270                //         },
271                //         _ => todo!("push error -- import path item is not a module"),
272                //     }
273                // }
274
275                // todo!()
276            },
277        }
278    }
279
280    fn resolve_type(
281        &mut self,
282        binder: &Binder,
283        ty: TypeId,
284        scope_id: ScopeId,
285    ) {
286        let ty_decl = binder.get_type(ty).clone();
287        let Some(resolved) = ty_decl.resolve(self, binder, scope_id) else {
288            return;
289        };
290        self.resolved.insert_type(ty, resolved);
291    }
292
293    fn resolve_function(
294        &mut self,
295        binder: &Binder,
296        func_id: FunctionId,
297        scope_id: ScopeId,
298    ) {
299        // when resolving a function declaration,
300        // the symbols that need resolution are:
301        // - the names of the types in parameters
302        // - the return type
303        // - the body
304        let func = binder.get_function(func_id).clone();
305        let Some(func) = func.resolve(self, binder, scope_id) else {
306            return;
307        };
308        self.resolved.insert_function(func_id, func);
309    }
310
311    pub fn into_queryable(self) -> (Vec<SpannedItem<ResolutionError>>, QueryableResolvedItems) {
312        (
313            self.errs,
314            QueryableResolvedItems::new(self.resolved.resolved_functions, self.resolved.resolved_types, self.interner),
315        )
316    }
317}
318
319pub trait Resolve {
320    type Resolved;
321    fn resolve(
322        &self,
323        resolver: &mut Resolver,
324        binder: &Binder,
325        scope_id: ScopeId,
326    ) -> Option<Self::Resolved>;
327}
328
329impl Resolve for SpannedItem<FunctionDeclaration> {
330    type Resolved = Function;
331
332    fn resolve(
333        &self,
334        resolver: &mut Resolver,
335        binder: &Binder,
336        scope_id: ScopeId,
337    ) -> Option<Self::Resolved> {
338        // when resolving a function declaration,
339        // the symbols that need resolution are:
340        // - the names of the types in parameters
341        // - the return type
342        // - the body
343
344        let mut params_buf = Vec::with_capacity(self.item().parameters.len());
345
346        // functions exist in their own scope with their own variables
347        for FunctionParameter { name, ty } in self.item().parameters.iter() {
348            let ty = ty.resolve(resolver, binder, scope_id).unwrap_or(Type::Unit);
349            params_buf.push((*name, ty));
350        }
351
352        let return_type = self.item().return_type.resolve(resolver, binder, scope_id).unwrap_or(Type::Unit);
353
354        let body = match self.item().body.resolve(resolver, binder, scope_id) {
355            Some(x) => x,
356            // need to use an error recovery func here, so the FunctionId still exists in the
357            // resolved function map.
358            // If we were to return `None` and not resolve the function, then calls to this
359            // function would hold a reference `FunctionId(x)` which would not exist anymore.
360            None => Expr::error_recovery(self.span()),
361        };
362
363        Some(Function {
364            name: self.item().name,
365            params: params_buf,
366            return_type,
367            body,
368        })
369    }
370}
371
372impl Resolve for SpannedItem<Expression> {
373    type Resolved = Expr;
374
375    fn resolve(
376        &self,
377        resolver: &mut Resolver,
378        binder: &Binder,
379        scope_id: ScopeId,
380    ) -> Option<Expr> {
381        Some(match self.item() {
382            Expression::Literal(x) => Expr::new(ExprKind::Literal(x.clone()), self.span()),
383            Expression::List(list) => {
384                let list: Vec<Expr> = list
385                    .elements
386                    .iter()
387                    .map(|x| match x.resolve(resolver, binder, scope_id) {
388                        Some(x) => x,
389                        None => todo!("error recovery"),
390                    })
391                    .collect();
392                // TODO: do list combination type if list of unit, which functions like a block
393                Expr::new(ExprKind::List(list.into_boxed_slice()), self.span())
394            },
395            Expression::Operator(op) => {
396                let OperatorExpression { lhs, rhs, op } = *op.clone();
397                // resolves to a call to stdlib
398                use petr_ast::Operator::*;
399                let func = match op.item() {
400                    Plus => "add",
401                    Minus => "sub",
402                    Star => "mul",
403                    Slash => "div",
404                };
405                let path = ["std", "ops", func];
406
407                let func_path = Path {
408                    identifiers: path
409                        .iter()
410                        .map(|x| Identifier {
411                            id:   resolver.interner.insert(Rc::from(*x)),
412                            span: self.span(),
413                        })
414                        .collect(),
415                };
416
417                let Some(either::Left(function)) = func_path.resolve(resolver, binder, scope_id) else {
418                    resolver.errs.push(
419                        self.span()
420                            .with_item(ResolutionError::OperatorImplementationNotFound(func.to_string(), path.join("."))),
421                    );
422                    return None;
423                };
424
425                let call = FunctionCall {
426                    function,
427                    args: vec![lhs.resolve(resolver, binder, scope_id)?, rhs.resolve(resolver, binder, scope_id)?],
428                    span: self.span(),
429                };
430
431                Expr::new(ExprKind::FunctionCall(call), self.span())
432            },
433            Expression::FunctionCall(decl) => {
434                let resolved_call = self.span().with_item(decl).resolve(resolver, binder, scope_id)?;
435
436                Expr::new(ExprKind::FunctionCall(resolved_call), self.span())
437            },
438            Expression::Variable(var) => {
439                let item = match binder.find_symbol_in_scope(var.id, scope_id) {
440                    Some(item @ Item::FunctionParameter(_) | item @ Item::Binding(_)) => item,
441                    _otherwise => {
442                        let var_name = resolver.interner.get(var.id);
443                        resolver.errs.push(var.span.with_item(ResolutionError::NotFound(var_name.to_string())));
444                        return None;
445                    },
446                };
447                match item {
448                    Item::Binding(binding_id) => {
449                        let binding = binder.get_binding(*binding_id);
450
451                        Expr::new(
452                            ExprKind::Variable {
453                                name: *var,
454                                // I think this works for inference -- instantiating a new generic
455                                // type. Should revisit for soundness.
456                                ty:   Type::Generic(binding.name),
457                            },
458                            self.span(),
459                        )
460                    },
461                    Item::FunctionParameter(ty) => {
462                        let ty = match ty.resolve(resolver, binder, scope_id) {
463                            Some(ty) => ty,
464
465                            None => {
466                                todo!("not found err");
467                                // Type::ErrorRecovery
468                            },
469                        };
470
471                        Expr::new(ExprKind::Variable { name: *var, ty }, self.span())
472                    },
473                    _ => unreachable!(),
474                }
475            },
476            Expression::TypeConstructor(parent_type_id, args) => {
477                // Type constructor expressions themselves don't actually do anything.
478                // The function parameters and return types
479                // of the function are what get type checked -- there is no fn body, and this
480                // TypeConstructor expression is what represents that.
481                let resolved_args = args
482                    .iter()
483                    .map(|x| match x.resolve(resolver, binder, scope_id) {
484                        Some(x) => x,
485                        None => todo!("error recov"),
486                    })
487                    .collect::<Vec<_>>();
488                Expr::new(ExprKind::TypeConstructor(*parent_type_id, resolved_args.into_boxed_slice()), self.span())
489            },
490            Expression::IntrinsicCall(intrinsic) => {
491                let resolved = intrinsic.resolve(resolver, binder, scope_id)?;
492                Expr::new(ExprKind::Intrinsic(resolved), self.span())
493            },
494            Expression::Binding(bound_expression) => {
495                let scope_id = binder.get_expr_scope(bound_expression.expr_id).expect("invariant: scope should exist");
496                let mut bindings: Vec<Binding> = Vec::with_capacity(bound_expression.bindings.len());
497                for binding in &bound_expression.bindings {
498                    let rhs = binding.val.resolve(resolver, binder, scope_id)?;
499                    bindings.push(Binding {
500                        name:       binding.name,
501                        expression: rhs,
502                    });
503                }
504                let expression = bound_expression.expression.resolve(resolver, binder, scope_id)?;
505                Expr::new(
506                    ExprKind::ExpressionWithBindings {
507                        expression: Box::new(expression),
508                        bindings,
509                    },
510                    self.span(),
511                )
512            },
513        })
514    }
515}
516
517impl Resolve for petr_ast::IntrinsicCall {
518    type Resolved = Intrinsic;
519
520    fn resolve(
521        &self,
522        resolver: &mut Resolver,
523        binder: &Binder,
524        scope_id: ScopeId,
525    ) -> Option<Self::Resolved> {
526        let args = self
527            .args
528            .iter()
529            .map(|x| match x.resolve(resolver, binder, scope_id) {
530                Some(x) => x,
531                None => Expr::error_recovery(x.span()),
532            })
533            .collect();
534        Some(Intrinsic {
535            intrinsic: self.intrinsic.clone(),
536            args,
537        })
538    }
539}
540
541impl<T: Resolve> Resolve for Commented<T> {
542    type Resolved = T::Resolved;
543
544    fn resolve(
545        &self,
546        resolver: &mut Resolver,
547        binder: &Binder,
548        scope_id: ScopeId,
549    ) -> Option<Self::Resolved> {
550        self.item().resolve(resolver, binder, scope_id)
551    }
552}
553
554impl<T: Resolve> Resolve for SpannedItem<T> {
555    type Resolved = T::Resolved;
556
557    fn resolve(
558        &self,
559        resolver: &mut Resolver,
560        binder: &Binder,
561        scope_id: ScopeId,
562    ) -> Option<Self::Resolved> {
563        self.item().resolve(resolver, binder, scope_id)
564    }
565}
566
567impl Resolve for SpannedItem<&petr_ast::FunctionCall> {
568    type Resolved = FunctionCall;
569
570    fn resolve(
571        &self,
572        resolver: &mut Resolver,
573        binder: &Binder,
574        scope_id: ScopeId,
575    ) -> Option<Self::Resolved> {
576        let resolved_id = match self.item().func_name.resolve(resolver, binder, scope_id) {
577            Some(either::Either::Left(func)) => func,
578            Some(either::Either::Right(_ty)) => {
579                todo!("push error -- tried to call ty as func");
580            },
581            None => {
582                let stringified_name = self
583                    .item()
584                    .func_name
585                    .identifiers
586                    .iter()
587                    .map(|x| resolver.interner.get(x.id))
588                    .collect::<Vec<_>>()
589                    .join(".");
590                resolver.errs.push(self.span().with_item(ResolutionError::NotFound(stringified_name)));
591                return None;
592            },
593        };
594
595        let args = self
596            .item()
597            .args
598            .iter()
599            .map(|x| match x.resolve(resolver, binder, scope_id) {
600                Some(x) => x,
601                None => todo!("Error recov"),
602            })
603            .collect();
604
605        Some(FunctionCall {
606            function: resolved_id,
607            args,
608            span: self.span(),
609        })
610    }
611}
612
613impl Resolve for petr_utils::Path {
614    // TODO globs
615    type Resolved = either::Either<FunctionId, TypeId>;
616
617    fn resolve(
618        &self,
619        resolver: &mut Resolver,
620        binder: &Binder,
621        scope_id: ScopeId,
622    ) -> Option<Self::Resolved> {
623        let mut path_iter = self.identifiers.iter();
624        let Some(first_item) = ({
625            let item = path_iter.next().expect("import with no items was parsed -- should be an invariant");
626            binder.find_symbol_in_scope(item.id, scope_id)
627        }) else {
628            let name = self.identifiers.iter().map(|x| resolver.interner.get(x.id)).collect::<Vec<_>>().join(".");
629            resolver.errs.push(
630                self.identifiers
631                    .last()
632                    .expect("empty path shouldn't be possible")
633                    .span
634                    .with_item(ResolutionError::NotFound(name)),
635            );
636            return None;
637        };
638
639        let first_item = match first_item {
640            Item::Module(id) if self.identifiers.len() > 1 => id,
641            Item::Function(f, _) if self.identifiers.len() == 1 => return Some(either::Either::Left(*f)),
642            Item::Type(t) if self.identifiers.len() == 1 => return Some(either::Either::Right(*t)),
643            Item::Import { path, alias: _ } if self.identifiers.len() == 1 => return path.resolve(resolver, binder, scope_id),
644            a => todo!("push error -- import path is not a module {a:?}"),
645        };
646
647        let mut rover = binder.get_module(*first_item);
648        // iterate over the rest of the path to find the path item
649        for (ix, item) in path_iter.enumerate() {
650            let is_last = ix == self.identifiers.len() - 2; // -2 because we advanced the iter by one already
651            let Some(next_symbol) = binder.find_symbol_in_scope(item.id, rover.root_scope) else {
652                let name = resolver.interner.get(item.id);
653                resolver.errs.push(item.span.with_item(ResolutionError::NotFound(name.to_string())));
654                return None;
655            };
656
657            match next_symbol {
658                Item::Module(id) => rover = binder.get_module(*id),
659                Item::Function(func, _scope) if is_last => return Some(either::Either::Left(*func)),
660                Item::Type(ty) if is_last => return Some(either::Either::Right(*ty)),
661                Item::Import { path, alias: _ } => match path.resolve(resolver, binder, scope_id) {
662                    Some(either::Left(func)) => return Some(either::Left(func)),
663                    Some(either::Right(ty)) => return Some(either::Right(ty)),
664                    None => todo!("push error -- import not found"),
665                },
666                a => todo!("push error -- import path item is not a module, it is a {a:?}"),
667            }
668        }
669
670        todo!("import of module not supported yet, must be type or function")
671    }
672}
673
674impl Resolve for petr_ast::TypeDeclaration {
675    type Resolved = TypeDeclaration;
676
677    fn resolve(
678        &self,
679        resolver: &mut Resolver,
680        binder: &Binder,
681        scope_id: ScopeId,
682    ) -> Option<Self::Resolved> {
683        // when resolving a type declaration,
684        // we just need to resolve all the inner types from the fields
685
686        // for variant in variants
687        // for field in variant's fields
688        // resolve the field type
689        let mut variants = Vec::with_capacity(self.variants.len());
690        for variant in self.variants.iter() {
691            let mut field_types = Vec::with_capacity(variant.item().fields.len());
692            for field in variant.item().fields.iter() {
693                if let Some(field_type) = field.item().ty.resolve(resolver, binder, scope_id) {
694                    field_types.push(TypeField {
695                        name: field.item().name,
696                        ty:   field_type,
697                    });
698                } else {
699                    // TODO Handle the error case where the field type could not be resolved
700                    return None;
701                }
702            }
703            variants.push(TypeVariant {
704                name:   variant.item().name,
705                fields: field_types.into_boxed_slice(),
706            });
707        }
708
709        Some(TypeDeclaration {
710            name:     self.name,
711            variants: variants.into_boxed_slice(),
712        })
713    }
714}
715
716#[cfg(test)]
717mod tests {
718    mod pretty_printing {
719
720        use super::{Expr, ExprKind};
721        use crate::{resolved::QueryableResolvedItems, resolver::Type};
722        impl Expr {
723            pub fn to_string(
724                &self,
725                resolver: &QueryableResolvedItems,
726            ) -> String {
727                self.kind.to_string(resolver)
728            }
729        }
730
731        impl Type {
732            pub fn to_string(
733                &self,
734                resolver: &QueryableResolvedItems,
735            ) -> String {
736                match self {
737                    Type::Integer => "int".to_string(),
738                    Type::Bool => "bool".to_string(),
739                    Type::Unit => "()".to_string(),
740                    Type::String => "string".to_string(),
741                    Type::ErrorRecovery => "<error>".to_string(),
742                    Type::Named(id) => {
743                        format!("named type {}", resolver.interner.get(resolver.get_type(*id).name.id))
744                    },
745                    Type::Generic(a) => format!("generic type {}", resolver.interner.get(a.id)),
746                }
747            }
748        }
749
750        impl ExprKind {
751            pub fn to_string(
752                &self,
753                resolver: &QueryableResolvedItems,
754            ) -> String {
755                match self {
756                    ExprKind::Literal(lit) => format!("Literal({:?})", lit),
757                    ExprKind::List(exprs) => format!("[{}]", exprs.iter().map(|x| x.to_string(resolver)).collect::<Vec<_>>().join(", ")),
758                    ExprKind::FunctionCall(call) => {
759                        format!("FunctionCall({})", call.function)
760                    },
761                    ExprKind::Unit => "Unit".to_string(),
762                    ExprKind::ErrorRecovery => "<error>".to_string(),
763                    ExprKind::Variable { name, ty } => format!("{}: {}", resolver.interner.get(name.id), ty.to_string(resolver)),
764                    ExprKind::Intrinsic(x) => format!(
765                        "@{}({})",
766                        x.intrinsic,
767                        x.args.iter().map(|x| x.to_string(resolver)).collect::<Vec<_>>().join(", ")
768                    ),
769                    ExprKind::TypeConstructor(..) => "Type constructor".into(),
770                    ExprKind::ExpressionWithBindings { .. } => todo!(),
771                }
772            }
773        }
774    }
775    use expect_test::{expect, Expect};
776    use petr_utils::render_error;
777
778    use super::*;
779    use crate::resolved::QueryableResolvedItems;
780    fn check(
781        input: impl Into<String>,
782        expect: Expect,
783    ) {
784        let input = input.into();
785        let parser = petr_parse::Parser::new(vec![("test", input)]);
786        let (ast, errs, interner, source_map) = parser.into_result();
787        if !errs.is_empty() {
788            errs.into_iter().for_each(|err| eprintln!("{:?}", render_error(&source_map, err)));
789            panic!("fmt failed: code didn't parse");
790        }
791        let resolver = Resolver::new_from_single_ast(ast, interner);
792        let (errs, queryable) = resolver.into_queryable();
793        assert!(errs.is_empty());
794        let result = pretty_print_resolution(&queryable);
795        expect.assert_eq(&result);
796    }
797
798    fn check_multiple(
799        inputs: Vec<impl Into<String>>,
800        expect: Expect,
801    ) {
802        let inputs: Vec<_> = inputs
803            .into_iter()
804            .enumerate()
805            .map(|(i, input)| (format!("test{}", i + 1), input.into()))
806            .collect();
807        let parser = petr_parse::Parser::new(inputs);
808        let (ast, errs, interner, source_map) = parser.into_result();
809        if !errs.is_empty() {
810            errs.into_iter().for_each(|err| eprintln!("{:?}", render_error(&source_map, err)));
811            panic!("fmt failed: code didn't parse");
812        }
813        let resolver = Resolver::new_from_single_ast(ast, interner);
814        let (errs, queryable) = resolver.into_queryable();
815        assert!(errs.is_empty());
816        let result = pretty_print_resolution(&queryable);
817        expect.assert_eq(&result);
818    }
819
820    fn pretty_print_resolution(queryable: &QueryableResolvedItems) -> String {
821        let mut result = String::new();
822        result.push_str("_____FUNCTIONS_____\n");
823        for (func_id, func) in queryable.functions() {
824            result.push_str(&format!("#{} {}", Into::<usize>::into(func_id), queryable.interner.get(func.name.id),));
825            result.push('(');
826            for (name, ty) in &func.params {
827                let name = queryable.interner.get(name.id);
828                let ty = ty.to_string(queryable);
829                result.push_str(&format!("  {}: {}, ", name, ty));
830            }
831            result.push_str(") ");
832            let ty = func.return_type.to_string(queryable);
833            result.push_str(&format!("-> {} ", ty));
834            result.push_str(&format!("  {:?}\n", func.body.to_string(queryable)));
835        }
836
837        result.push_str("_____TYPES_____\n");
838        for (type_id, ty_decl) in queryable.types() {
839            result.push_str(&format!("#{} {}", Into::<usize>::into(type_id), queryable.interner.get(ty_decl.name.id),));
840            result.push_str("\n\n");
841        }
842
843        result
844    }
845
846    #[test]
847    fn func_returns_list() {
848        check(
849            r#"
850            fn foo(a in 'int) returns 'int [1, 2, 3]
851            "#,
852            expect![[r#"
853                    _____FUNCTIONS_____
854                    #0 foo(  a: int, ) -> int   "[Literal(Integer(1)), Literal(Integer(2)), Literal(Integer(3))]"
855                    _____TYPES_____
856                "#]],
857        );
858    }
859    #[test]
860    fn func_returns_named_type() {
861        check(
862            r#"
863            type MyType = a | b
864            fn foo(a in 'MyType) returns 'MyType [1, 2, 3]
865            "#,
866            expect![[r#"
867                _____FUNCTIONS_____
868                #0 a() -> named type MyType   "Type constructor"
869                #1 b() -> named type MyType   "Type constructor"
870                #2 foo(  a: named type MyType, ) -> named type MyType   "[Literal(Integer(1)), Literal(Integer(2)), Literal(Integer(3))]"
871                _____TYPES_____
872                #0 MyType
873
874            "#]],
875        );
876    }
877
878    #[test]
879    fn func_returns_named_type_declared_after_use() {
880        check(
881            r#"
882            fn foo(a in 'MyType) returns 'MyType [
883                1,
884                2,
885                3
886            ]
887            type MyType = a | b
888            "#,
889            expect![[r#"
890                _____FUNCTIONS_____
891                #0 foo(  a: named type MyType, ) -> named type MyType   "[Literal(Integer(1)), Literal(Integer(2)), Literal(Integer(3))]"
892                #1 a() -> named type MyType   "Type constructor"
893                #2 b() -> named type MyType   "Type constructor"
894                _____TYPES_____
895                #0 MyType
896
897            "#]],
898        )
899    }
900
901    #[test]
902    fn call_func_before_decl() {
903        check(
904            r#"
905            fn foo() returns 'MyType ~bar(5)
906            fn bar(a in 'MyType) returns 'MyType [
907                1,
908                2,
909                3
910            ]
911            type MyType = a | b
912            "#,
913            expect![[r#"
914                _____FUNCTIONS_____
915                #0 foo() -> named type MyType   "FunctionCall(functionid1)"
916                #1 bar(  a: named type MyType, ) -> named type MyType   "[Literal(Integer(1)), Literal(Integer(2)), Literal(Integer(3))]"
917                #2 a() -> named type MyType   "Type constructor"
918                #3 b() -> named type MyType   "Type constructor"
919                _____TYPES_____
920                #0 MyType
921
922            "#]],
923        )
924    }
925
926    #[test]
927    fn call_func_in_list_before_decl() {
928        check(
929            r#"
930            fn foo() returns 'MyType ~bar(5)
931            fn bar(a in 'MyType) returns 'MyType [
932                1,
933                2,
934                3
935            ]
936            type MyType = a | b
937            "#,
938            expect![[r#"
939                _____FUNCTIONS_____
940                #0 foo() -> named type MyType   "FunctionCall(functionid1)"
941                #1 bar(  a: named type MyType, ) -> named type MyType   "[Literal(Integer(1)), Literal(Integer(2)), Literal(Integer(3))]"
942                #2 a() -> named type MyType   "Type constructor"
943                #3 b() -> named type MyType   "Type constructor"
944                _____TYPES_____
945                #0 MyType
946
947            "#]],
948        )
949    }
950    #[test]
951    fn import_something_from_another_file() {
952        check_multiple(
953            vec![
954                r#"
955                export fn exported_func(a in 'int) returns 'int a
956                "#,
957                r#"
958                import test1.exported_func
959
960                fn foo() returns 'int ~exported_func(5)
961
962               "#,
963            ],
964            expect![[r#"
965                _____FUNCTIONS_____
966                #0 exported_func(  a: int, ) -> int   "a: int"
967                #1 foo() -> int   "FunctionCall(functionid0)"
968                _____TYPES_____
969            "#]],
970        )
971    }
972
973    #[test]
974    fn import_something_from_another_file_with_alias() {
975        check_multiple(
976            vec![
977                r#"
978                export fn exported_func(a in 'int) returns 'int a
979                "#,
980                r#"
981                import test1.exported_func as bar 
982
983                fn foo() returns 'int ~bar(5)
984
985               "#,
986            ],
987            expect![[r#"
988                _____FUNCTIONS_____
989                #0 exported_func(  a: int, ) -> int   "a: int"
990                #1 foo() -> int   "FunctionCall(functionid0)"
991                _____TYPES_____
992            "#]],
993        )
994    }
995}