mon_core/
resolver.rs

1use crate::ast::{
2    ImportSpec, ImportStatement, Member, MonDocument, MonValue, MonValueKind,
3    SymbolTable as AstSymbolTable, TypeDef, TypeSpec,
4};
5use crate::error::{ResolverError, ValidationError};
6use miette::NamedSource;
7use std::collections::HashMap;
8use std::path::{Path, PathBuf};
9use std::sync::Arc;
10
11pub struct Resolver {
12    // Stores resolved documents by their absolute path
13    resolved_documents: HashMap<PathBuf, MonDocument>,
14    // Stack to detect circular dependencies during import resolution
15    resolving_stack: Vec<(PathBuf, Option<ImportStatement>)>,
16    // Global symbol table for types
17    pub symbol_table: AstSymbolTable,
18    // Global map for anchors
19    pub anchors: HashMap<String, MonValue>,
20}
21
22impl Resolver {
23    #[must_use]
24    pub fn new() -> Self {
25        Resolver {
26            resolved_documents: HashMap::new(),
27            resolving_stack: Vec::new(), // Initialized with the new type
28            symbol_table: AstSymbolTable::new(),
29            anchors: HashMap::new(),
30        }
31    }
32
33    pub fn resolve(
34        &mut self,
35        document: MonDocument,
36        source_text: &str,
37        file_path: PathBuf,
38        causing_import: Option<ImportStatement>,
39    ) -> Result<MonDocument, ResolverError> {
40        // Add the current file to the resolving stack to detect cycles
41        if let Some((_, Some(existing_causing_import))) =
42            self.resolving_stack.iter().find(|(p, _)| p == &file_path)
43        {
44            let cycle_str = self
45                .resolving_stack
46                .iter()
47                .map(|(p, _)| p.to_string_lossy().to_string())
48                .collect::<Vec<String>>()
49                .join(" -> ");
50            return Err(ResolverError::CircularDependency {
51                cycle: format!("{} -> {}", cycle_str, file_path.to_string_lossy()),
52                src: NamedSource::new(file_path.to_string_lossy(), source_text.to_string()).into(),
53                span: (
54                    existing_causing_import.pos_start,
55                    existing_causing_import.pos_end - existing_causing_import.pos_start,
56                )
57                    .into(),
58            });
59        }
60        self.resolving_stack
61            .push((file_path.clone(), causing_import)); // Push with the provided causing_import
62
63        // 1. Process imports
64        let current_dir = file_path.parent().unwrap_or_else(|| Path::new("."));
65        let source_arc = Arc::new(source_text.to_string());
66
67        for import_statement in &document.imports {
68            let imported_path_str = import_statement.path.trim_matches('"');
69            let absolute_imported_path = current_dir.join(imported_path_str);
70
71            // Check if already resolved
72            if self
73                .resolved_documents
74                .contains_key(&absolute_imported_path)
75            {
76                continue;
77            }
78
79            // Read the imported file content
80            let imported_source_text =
81                std::fs::read_to_string(&absolute_imported_path).map_err(|_| {
82                    ResolverError::ModuleNotFound {
83                        path: imported_path_str.to_string(),
84                        src: Arc::from(NamedSource::new(
85                            file_path.to_string_lossy(),
86                            source_arc.to_string(),
87                        )),
88                        span: (
89                            import_statement.pos_start,
90                            import_statement.pos_end - import_statement.pos_start,
91                        )
92                            .into(),
93                    }
94                })?;
95
96            // Parse the imported file
97            let mut parser = crate::parser::Parser::new_with_name(
98                &imported_source_text,
99                absolute_imported_path.to_string_lossy().to_string(),
100            )?;
101            let imported_document = parser.parse_document()?;
102
103            // Recursively resolve the imported document
104            let resolved_imported_document = self.resolve(
105                imported_document,
106                &imported_source_text,
107                absolute_imported_path.clone(),
108                Some(import_statement.clone()), // Pass the import statement
109            )?;
110
111            self.resolved_documents
112                .insert(absolute_imported_path, resolved_imported_document);
113        }
114
115        // After resolving all imports, process named imports to populate the symbol table
116        for import_statement in &document.imports {
117            if let ImportSpec::Named(specifiers) = &import_statement.spec {
118                let imported_path_str = import_statement.path.trim_matches('"');
119                let absolute_imported_path = current_dir.join(imported_path_str);
120                if let Some(imported_doc) = self.resolved_documents.get(&absolute_imported_path) {
121                    if let MonValueKind::Object(members) = &imported_doc.root.kind {
122                        for specifier in specifiers {
123                            if !specifier.is_anchor {
124                                for member in members {
125                                    if let Member::TypeDefinition(td) = member {
126                                        if td.name == specifier.name {
127                                            self.symbol_table
128                                                .types
129                                                .insert(specifier.name.clone(), td.clone());
130                                        }
131                                    }
132                                }
133                            }
134                        }
135                    }
136                }
137            }
138        }
139
140        // 2. Collect type definitions and anchors from the current document
141        if let MonValueKind::Object(members) = &document.root.kind {
142            for member in members {
143                match member {
144                    Member::TypeDefinition(type_def) => {
145                        self.symbol_table
146                            .types
147                            .insert(type_def.name.clone(), type_def.clone());
148                    }
149                    Member::Pair(pair) => {
150                        if let Some(anchor_name) = &pair.value.anchor {
151                            self.anchors.insert(anchor_name.clone(), pair.value.clone());
152                        }
153                    }
154                    _ => {}
155                }
156            }
157        }
158
159        // 3. Resolve aliases and spreads
160        let resolved_root = self.resolve_value(document.root, &file_path, source_text)?;
161
162        // 4. Validate the resolved document
163        // This will involve iterating through the resolved_root and applying validations
164        // where `:: Type` is specified.
165        let final_resolved_root =
166            self.validate_document_root(resolved_root, &document.imports, &file_path, source_text)?;
167
168        let resolved_doc = MonDocument {
169            root: final_resolved_root,
170            imports: document.imports, // Imports are already processed
171        };
172
173        // Remove the current file from the stack
174        self.resolving_stack.pop();
175
176        Ok(resolved_doc)
177    }
178    // Helper function to recursively resolve aliases and spreads within a MonValue
179    fn resolve_value(
180        &mut self,
181        mut value: MonValue,
182        file_path: &PathBuf,
183        source_text: &str,
184    ) -> Result<MonValue, ResolverError> {
185        let alias_span = value.get_source_span();
186
187        match &mut value.kind {
188            MonValueKind::Alias(alias_name) => {
189                // Resolve alias: find the anchored value and return a deep copy
190                let anchor_value = self.anchors.get(alias_name).ok_or_else(|| {
191                    // TODO: Get actual span for the alias
192                    ResolverError::AnchorNotFound {
193                        name: alias_name.clone(),
194                        src: Arc::from(NamedSource::new(
195                            file_path.to_string_lossy(),
196                            source_text.to_string(),
197                        )),
198                        span: alias_span,
199                    }
200                })?;
201                Ok(anchor_value.clone()) // Return a deep copy
202            }
203            MonValueKind::Object(members) => {
204                let mut resolved_members = Vec::new();
205                for member in members.drain(..) {
206                    match member {
207                        Member::Spread(spread_name) => {
208                            // Resolve object spread: merge members from anchored object
209                            let anchor_value = self.anchors.get(&spread_name).ok_or_else(|| {
210                                // TODO: Get actual span for the spread
211                                ResolverError::AnchorNotFound {
212                                    name: spread_name.clone(),
213                                    src: Arc::from(NamedSource::new(
214                                        file_path.to_string_lossy(),
215                                        source_text.to_string(),
216                                    )),
217                                    span: alias_span,
218                                }
219                            })?;
220                            if let MonValueKind::Object(spread_members) = &anchor_value.kind {
221                                let spread_members_clone = spread_members.clone();
222                                for spread_member in spread_members_clone {
223                                    // Recursively resolve spread members
224                                    resolved_members.push(self.resolve_value_member(
225                                        spread_member,
226                                        file_path,
227                                        source_text,
228                                    )?);
229                                }
230                            } else {
231                                return Err(ResolverError::SpreadOnNonObject {
232                                    name: spread_name.clone(),
233                                    src: Arc::from(NamedSource::new(
234                                        file_path.to_string_lossy(),
235                                        source_text.to_string(),
236                                    )),
237                                    span: alias_span,
238                                });
239                            }
240                        }
241                        _ => {
242                            // Recursively resolve other members
243                            resolved_members.push(self.resolve_value_member(
244                                member,
245                                file_path,
246                                source_text,
247                            )?);
248                        }
249                    }
250                }
251                // Handle key overriding for object spreads (local keys win)
252                let mut final_members_map: HashMap<String, Member> = HashMap::new();
253                for member in resolved_members {
254                    if let Member::Pair(pair) = member {
255                        final_members_map.insert(pair.key.clone(), Member::Pair(pair));
256                    } else {
257                        // Non-pair members (like TypeDefinition) are just added
258                        // This might need refinement depending on how TypeDefinitions are handled after resolution
259                        final_members_map.insert(format!("{member:?}"), member);
260                        // Dummy key for now
261                    }
262                }
263                let final_members = final_members_map.into_values().collect();
264                Ok(MonValue {
265                    kind: MonValueKind::Object(final_members),
266                    anchor: value.anchor,
267                    pos_start: value.pos_start,
268                    pos_end: value.pos_end,
269                })
270            }
271            MonValueKind::Array(elements) => {
272                let mut resolved_elements = Vec::new();
273                for element in elements.drain(..) {
274                    match element.kind {
275                        MonValueKind::ArraySpread(spread_name) => {
276                            // Resolve array spread: concatenate elements from anchored array
277                            let anchor_value = self.anchors.get(&spread_name).ok_or_else(|| {
278                                // TODO: Get actual span for the spread
279                                ResolverError::AnchorNotFound {
280                                    name: spread_name.clone(),
281                                    src: Arc::from(NamedSource::new(
282                                        file_path.to_string_lossy(),
283                                        source_text.to_string(),
284                                    )),
285                                    span: alias_span,
286                                }
287                            })?;
288                            if let MonValueKind::Array(spread_elements) = &anchor_value.kind {
289                                let spread_elements_clone = spread_elements.clone();
290                                for spread_element in spread_elements_clone {
291                                    // Recursively resolve spread elements
292                                    resolved_elements.push(self.resolve_value(
293                                        spread_element,
294                                        file_path,
295                                        source_text,
296                                    )?);
297                                }
298                            } else {
299                                // TODO: Get actual span for the spread
300                                return Err(ResolverError::SpreadOnNonArray {
301                                    name: spread_name.clone(),
302                                    src: Arc::from(NamedSource::new(
303                                        file_path.to_string_lossy(),
304                                        source_text.to_string(),
305                                    )),
306                                    span: alias_span,
307                                });
308                            }
309                        }
310                        _ => {
311                            // Recursively resolve other elements
312                            resolved_elements.push(self.resolve_value(
313                                element,
314                                file_path,
315                                source_text,
316                            )?);
317                        }
318                    }
319                }
320                Ok(MonValue {
321                    kind: MonValueKind::Array(resolved_elements),
322                    anchor: value.anchor,
323                    pos_start: value.pos_start,
324                    pos_end: value.pos_end,
325                })
326            }
327            _ => Ok(value), // Other literal values don't need further resolution
328        }
329    }
330
331    // Helper to resolve a Member (Pair, TypeDefinition, etc.)
332    fn resolve_value_member(
333        &mut self,
334        mut member: Member,
335        file_path: &PathBuf,
336        source_text: &str,
337    ) -> Result<Member, ResolverError> {
338        match &mut member {
339            Member::Pair(pair) => {
340                pair.value = self.resolve_value(pair.value.clone(), file_path, source_text)?;
341                Ok(member)
342            }
343            // Type definitions and imports are already processed or don't need further resolution here
344            _ => Ok(member),
345        }
346    }
347    // Helper function to validate the root of the document after resolution
348    fn validate_document_root(
349        &mut self,
350        mut root_value: MonValue,
351        imports: &[ImportStatement], // Change this parameter
352        file_path: &PathBuf,
353        source_text: &str,
354    ) -> Result<MonValue, ResolverError> {
355        if let MonValueKind::Object(members) = &mut root_value.kind {
356            for member in members.iter_mut() {
357                if let Member::Pair(pair) = member {
358                    if let Some(type_spec) = &pair.validation {
359                        // Perform validation for this pair
360                        self.validate_value(
361                            &mut pair.value,
362                            type_spec,
363                            &pair.key,
364                            imports, // Pass the imports here
365                            file_path,
366                            source_text,
367                        )?;
368                    }
369                }
370            }
371        }
372        Ok(root_value)
373    }
374
375    // Helper function to recursively validate a MonValue against a TypeSpec
376    fn validate_value(
377        &mut self,
378        value: &mut MonValue,
379        type_spec: &TypeSpec,
380        field_name: &str,            // For error reporting
381        imports: &[ImportStatement], // Change this parameter
382        file_path: &PathBuf,
383        source_text: &str,
384    ) -> Result<(), ResolverError> {
385        match type_spec {
386            TypeSpec::Simple(type_name, _) => {
387                // Handle built-in types and user-defined types (structs/enums)
388                match type_name.as_str() {
389                    "String" => {
390                        if !matches!(value.kind, MonValueKind::String(_)) {
391                            return Err(ResolverError::Validation(ValidationError::TypeMismatch {
392                                field_name: field_name.to_string(),
393                                expected_type: "String".to_string(),
394                                found_type: format!("{:?}", value.kind),
395                                src: Arc::from(NamedSource::new(
396                                    file_path.to_string_lossy(),
397                                    source_text.to_string(),
398                                )),
399                                span: (value.pos_start, value.pos_end - value.pos_start).into(),
400                            }));
401                        }
402                    }
403                    "Number" => {
404                        if !matches!(value.kind, MonValueKind::Number(_)) {
405                            return Err(ResolverError::Validation(ValidationError::TypeMismatch {
406                                field_name: field_name.to_string(),
407                                expected_type: "Number".to_string(),
408                                found_type: format!("{:?}", value.kind),
409                                src: Arc::from(NamedSource::new(
410                                    file_path.to_string_lossy(),
411                                    source_text.to_string(),
412                                )),
413                                span: (value.pos_start, value.pos_end - value.pos_start).into(),
414                            }));
415                        }
416                    }
417                    "Boolean" => {
418                        if !matches!(value.kind, MonValueKind::Boolean(_)) {
419                            return Err(ResolverError::Validation(ValidationError::TypeMismatch {
420                                field_name: field_name.to_string(),
421                                expected_type: "Boolean".to_string(),
422                                found_type: format!("{:?}", value.kind),
423                                src: Arc::from(NamedSource::new(
424                                    file_path.to_string_lossy(),
425                                    source_text.to_string(),
426                                )),
427                                span: (value.pos_start, value.pos_end - value.pos_start).into(),
428                            }));
429                        }
430                    }
431                    "Null" => {
432                        if !matches!(value.kind, MonValueKind::Null) {
433                            return Err(ResolverError::Validation(ValidationError::TypeMismatch {
434                                field_name: field_name.to_string(),
435                                expected_type: "Null".to_string(),
436                                found_type: format!("{:?}", value.kind),
437                                src: Arc::from(NamedSource::new(
438                                    file_path.to_string_lossy(),
439                                    source_text.to_string(),
440                                )),
441                                span: (value.pos_start, value.pos_end - value.pos_start).into(),
442                            }));
443                        }
444                    }
445                    "Object" => {
446                        if !matches!(value.kind, MonValueKind::Object(_)) {
447                            return Err(ResolverError::Validation(ValidationError::TypeMismatch {
448                                field_name: field_name.to_string(),
449                                expected_type: "Object".to_string(),
450                                found_type: format!("{:?}", value.kind),
451                                src: Arc::from(NamedSource::new(
452                                    file_path.to_string_lossy(),
453                                    source_text.to_string(),
454                                )),
455                                span: (value.pos_start, value.pos_end - value.pos_start).into(),
456                            }));
457                        }
458                    }
459                    "Array" => {
460                        if !matches!(value.kind, MonValueKind::Array(_)) {
461                            return Err(ResolverError::Validation(ValidationError::TypeMismatch {
462                                field_name: field_name.to_string(),
463                                expected_type: "Array".to_string(),
464                                found_type: format!("{:?}", value.kind),
465                                src: Arc::from(NamedSource::new(
466                                    file_path.to_string_lossy(),
467                                    source_text.to_string(),
468                                )),
469                                span: (value.pos_start, value.pos_end - value.pos_start).into(),
470                            }));
471                        }
472                    }
473                    "Any" => { /* Always valid, like you :D */ }
474                    _ => {
475                        // User-defined type (Struct or Enum)
476                        let (namespace, type_name_part) =
477                            if let Some((ns, tn)) = type_name.split_once('.') {
478                                (Some(ns), tn)
479                            } else {
480                                (None, type_name.as_str())
481                            };
482
483                        let type_def = if let Some(namespace) = namespace {
484                            // Find the import statement for this namespace
485                            let import_statement = imports
486                                .iter()
487                                .find(|i| {
488                                    if let ImportSpec::Namespace(ns) = &i.spec {
489                                        ns == namespace
490                                    } else {
491                                        false
492                                    }
493                                })
494                                .ok_or_else(|| {
495                                    ResolverError::Validation(ValidationError::UndefinedType {
496                                        type_name: type_name.clone(),
497                                        src: Arc::from(NamedSource::new(
498                                            file_path.to_string_lossy(),
499                                            source_text.to_string(),
500                                        )),
501                                        span: (value.pos_start, value.pos_end - value.pos_start)
502                                            .into(),
503                                    })
504                                })?;
505
506                            let imported_path_str = import_statement.path.trim_matches('"');
507                            let parent_dir = file_path.parent().ok_or_else(|| {
508                                // This case is unlikely but good to handle.
509                                // It means the file path is something like "/" or "C:\"
510                                ResolverError::ModuleNotFound {
511                                    path: import_statement.path.clone(),
512                                    src: Arc::from(NamedSource::new(
513                                        file_path.to_string_lossy(),
514                                        source_text.to_string(),
515                                    )),
516                                    span: (
517                                        import_statement.pos_start,
518                                        import_statement.pos_end - import_statement.pos_start,
519                                    )
520                                        .into(),
521                                }
522                            })?;
523                            let absolute_imported_path = parent_dir.join(imported_path_str);
524
525                            let imported_doc = self
526                                .resolved_documents
527                                .get(&absolute_imported_path)
528                                .ok_or_else(|| {
529                                    // This indicates a logic error in the resolver, as the document
530                                    // should have been resolved and stored during the initial import pass.
531                                    ResolverError::ModuleNotFound {
532                                        path: absolute_imported_path.to_string_lossy().to_string(),
533                                        src: Arc::from(NamedSource::new(
534                                            file_path.to_string_lossy(),
535                                            source_text.to_string(),
536                                        )),
537                                        span: (value.pos_start, value.pos_end - value.pos_start)
538                                            .into(),
539                                    }
540                                })?;
541
542                            if let MonValueKind::Object(members) = &imported_doc.root.kind {
543                                members.iter().find_map(|m| {
544                                    if let Member::TypeDefinition(td) = m {
545                                        if td.name == type_name_part {
546                                            return Some(td.def_type.clone());
547                                        }
548                                    }
549                                    None
550                                })
551                            } else {
552                                None
553                            }
554                        } else {
555                            self.symbol_table
556                                .types
557                                .get(type_name_part)
558                                .map(|td| td.def_type.clone())
559                        };
560
561                        if let Some(type_def) = type_def {
562                            match type_def {
563                                TypeDef::Struct(struct_def) => {
564                                    // Validate against struct
565                                    if let MonValueKind::Object(value_members) = &mut value.kind {
566                                        let mut value_map: HashMap<String, &mut MonValue> =
567                                            HashMap::new();
568                                        for member in value_members.iter_mut() {
569                                            if let Member::Pair(pair) = member {
570                                                value_map.insert(pair.key.clone(), &mut pair.value);
571                                            }
572                                        }
573
574                                        let mut new_members = Vec::new();
575                                        for field_def in &struct_def.fields {
576                                            if let Some(field_value) =
577                                                value_map.get_mut(&field_def.name)
578                                            {
579                                                // Field exists, validate its type
580                                                self.validate_value(
581                                                    field_value,
582                                                    &field_def.type_spec,
583                                                    &field_def.name,
584                                                    imports, // Pass the imports here
585                                                    file_path,
586                                                    source_text,
587                                                )?;
588                                            } else {
589                                                // Field missing
590                                                if field_def.default_value.is_none() {
591                                                    return Err(ResolverError::Validation(
592                                                        ValidationError::MissingField {
593                                                            field_name: field_def.name.clone(),
594                                                            struct_name: type_name.clone(),
595                                                            src: Arc::from(NamedSource::new(
596                                                                file_path.to_string_lossy(),
597                                                                source_text.to_string(),
598                                                            )),
599                                                            span: (
600                                                                value.pos_start,
601                                                                value.pos_end - value.pos_start,
602                                                            )
603                                                                .into(),
604                                                        },
605                                                    ));
606                                                }
607                                                // Field is missing, but has a default value.
608                                                // We need to insert it into the object.
609                                                if let Some(default_value) =
610                                                    &field_def.default_value
611                                                {
612                                                    new_members.push(Member::Pair(
613                                                        crate::ast::Pair {
614                                                            key: field_def.name.clone(),
615                                                            value: default_value.clone(),
616                                                            validation: None,
617                                                        },
618                                                    ));
619                                                }
620                                            }
621                                        }
622                                        value_members.extend(new_members);
623
624                                        // Check for extra fields
625                                        for member in value_members.iter() {
626                                            if let Member::Pair(pair) = member {
627                                                if !struct_def
628                                                    .fields
629                                                    .iter()
630                                                    .any(|f| f.name == pair.key)
631                                                {
632                                                    return Err(ResolverError::Validation(
633                                                        ValidationError::UnexpectedField {
634                                                            field_name: pair.key.clone(),
635                                                            struct_name: type_name.clone(),
636                                                            src: Arc::from(NamedSource::new(
637                                                                file_path.to_string_lossy(),
638                                                                source_text.to_string(),
639                                                            )),
640                                                            span: (
641                                                                value.pos_start,
642                                                                value.pos_end - value.pos_start,
643                                                            )
644                                                                .into(),
645                                                        },
646                                                    ));
647                                                }
648                                            }
649                                        }
650                                    } else {
651                                        return Err(ResolverError::Validation(
652                                            ValidationError::TypeMismatch {
653                                                field_name: field_name.to_string(),
654                                                expected_type: type_name.clone(),
655                                                found_type: format!("{:?}", value.kind),
656                                                src: Arc::from(NamedSource::new(
657                                                    file_path.to_string_lossy(),
658                                                    source_text.to_string(),
659                                                )),
660                                                span: (
661                                                    value.pos_start,
662                                                    value.pos_end - value.pos_start,
663                                                )
664                                                    .into(),
665                                            },
666                                        ));
667                                    }
668                                }
669                                TypeDef::Enum(enum_def) => {
670                                    // Validate against enum
671                                    if let MonValueKind::EnumValue {
672                                        enum_name,
673                                        variant_name,
674                                    } = &value.kind
675                                    {
676                                        if enum_name != type_name {
677                                            return Err(ResolverError::Validation(
678                                                ValidationError::TypeMismatch {
679                                                    field_name: field_name.to_string(),
680                                                    expected_type: format!("enum '{type_name}'"),
681                                                    found_type: format!("enum '{enum_name}'"),
682                                                    src: Arc::from(NamedSource::new(
683                                                        file_path.to_string_lossy(),
684                                                        source_text.to_string(),
685                                                    )),
686                                                    span: (
687                                                        value.pos_start,
688                                                        value.pos_end - value.pos_start,
689                                                    )
690                                                        .into(),
691                                                },
692                                            ));
693                                        }
694                                        if !enum_def.variants.contains(variant_name) {
695                                            return Err(ResolverError::Validation(
696                                                ValidationError::UndefinedEnumVariant {
697                                                    variant_name: variant_name.clone(),
698                                                    enum_name: type_name.clone(),
699                                                    src: Arc::from(NamedSource::new(
700                                                        file_path.to_string_lossy(),
701                                                        source_text.to_string(),
702                                                    )),
703                                                    span: (
704                                                        value.pos_start,
705                                                        value.pos_end - value.pos_start,
706                                                    )
707                                                        .into(),
708                                                },
709                                            ));
710                                        }
711                                    } else {
712                                        return Err(ResolverError::Validation(
713                                            ValidationError::TypeMismatch {
714                                                field_name: field_name.to_string(),
715                                                expected_type: format!("enum '{type_name}'"),
716                                                found_type: format!("{:?}", value.kind),
717                                                src: Arc::from(NamedSource::new(
718                                                    file_path.to_string_lossy(),
719                                                    source_text.to_string(),
720                                                )),
721                                                span: (
722                                                    value.pos_start,
723                                                    value.pos_end - value.pos_start,
724                                                )
725                                                    .into(),
726                                            },
727                                        ));
728                                    }
729                                }
730                            }
731                        } else {
732                            return Err(ResolverError::Validation(
733                                ValidationError::UndefinedType {
734                                    type_name: type_name.clone(),
735                                    src: Arc::from(NamedSource::new(
736                                        file_path.to_string_lossy(),
737                                        source_text.to_string(),
738                                    )),
739                                    span: (value.pos_start, value.pos_end - value.pos_start).into(),
740                                },
741                            ));
742                        }
743                    }
744                }
745            }
746            TypeSpec::Collection(collection_types, _) => {
747                // Handle array validation
748                if let MonValueKind::Array(elements) = &mut value.kind {
749                    self.validate_collection(
750                        elements,
751                        collection_types,
752                        field_name,
753                        imports, // Pass the imports here
754                        file_path,
755                        source_text,
756                    )?;
757                } else {
758                    return Err(ResolverError::Validation(ValidationError::TypeMismatch {
759                        field_name: field_name.to_string(),
760                        expected_type: "Array".to_string(),
761                        found_type: format!("{:?}", value.kind),
762                        src: Arc::from(NamedSource::new(
763                            file_path.to_string_lossy(),
764                            source_text.to_string(),
765                        )),
766                        span: (value.pos_start, value.pos_end - value.pos_start).into(),
767                    }));
768                }
769            }
770            TypeSpec::Spread(_, _) => {
771                // Spread types are handled during parsing/resolution, not validation directly
772                return Ok(());
773            }
774        }
775        Ok(())
776    }
777
778    fn validate_collection(
779        &mut self,
780        elements: &mut [MonValue],
781        collection_types: &[TypeSpec],
782        field_name: &str,
783        imports: &[ImportStatement], // Change this parameter
784        file_path: &PathBuf,
785        source_text: &str,
786    ) -> Result<(), ResolverError> {
787        // Case 1: [T] - Exactly one element of type T
788        if collection_types.len() == 1 && !matches!(collection_types[0], TypeSpec::Spread(_, _)) {
789            self.validate_value(
790                &mut elements[0],
791                &collection_types[0],
792                field_name,
793                imports, // Pass the imports here
794                file_path,
795                source_text,
796            )?;
797            return Ok(());
798        }
799
800        // Case 2: [T...] - Zero or more elements of type T
801        if collection_types.len() == 1 && matches!(collection_types[0], TypeSpec::Spread(_, _)) {
802            if let TypeSpec::Spread(inner_type, _) = &collection_types[0] {
803                for element in elements {
804                    self.validate_value(
805                        element,
806                        inner_type,
807                        field_name,
808                        imports,
809                        file_path,
810                        source_text,
811                    )?;
812                }
813                return Ok(());
814            }
815        }
816
817        // Case 3: Tuple-like [T1, T2, ...]
818        let has_spread = collection_types
819            .iter()
820            .any(|t| matches!(t, TypeSpec::Spread(_, _)));
821        if !has_spread {
822            if elements.len() != collection_types.len() {
823                // TODO: Better error for wrong number of elements
824                return Err(ResolverError::Validation(ValidationError::TypeMismatch {
825                    field_name: field_name.to_string(),
826                    expected_type: format!("tuple with {} elements", collection_types.len()),
827                    found_type: format!("tuple with {} elements", elements.len()),
828                    src: Arc::from(NamedSource::new(
829                        file_path.to_string_lossy(),
830                        source_text.to_string(),
831                    )),
832                    span: (
833                        elements.first().map_or(0, |e| e.pos_start),
834                        elements.last().map_or(0, |e| e.pos_end)
835                            - elements.first().map_or(0, |e| e.pos_start),
836                    )
837                        .into(),
838                }));
839            }
840            for (i, element) in elements.iter_mut().enumerate() {
841                self.validate_value(
842                    element,
843                    &collection_types[i],
844                    field_name,
845                    imports, // Pass the imports here
846                    file_path,
847                    source_text,
848                )?;
849            }
850            return Ok(());
851        }
852
853        // Case 4: [T1, T2...] - One or more elements, first is T1, rest are T2
854        if collection_types.len() == 2
855            && !matches!(collection_types[0], TypeSpec::Spread(_, _))
856            && matches!(collection_types[1], TypeSpec::Spread(_, _))
857        {
858            if elements.is_empty() {
859                return Err(ResolverError::Validation(ValidationError::TypeMismatch {
860                    field_name: field_name.to_string(),
861                    expected_type: "array with at least 1 element".to_string(),
862                    found_type: "empty array".to_string(),
863                    src: Arc::from(NamedSource::new(
864                        file_path.to_string_lossy(),
865                        source_text.to_string(),
866                    )),
867                    span: (
868                        elements.first().map_or(0, |e| e.pos_start),
869                        elements.last().map_or(0, |e| e.pos_end)
870                            - elements.first().map_or(0, |e| e.pos_start),
871                    )
872                        .into(),
873                }));
874            }
875            self.validate_value(
876                &mut elements[0],
877                &collection_types[0],
878                field_name,
879                imports, // Pass the imports here
880                file_path,
881                source_text,
882            )?;
883            if let TypeSpec::Spread(inner_type, _) = &collection_types[1] {
884                for element in &mut elements[1..] {
885                    self.validate_value(
886                        element,
887                        inner_type,
888                        field_name,
889                        imports,
890                        file_path,
891                        source_text,
892                    )?;
893                }
894            }
895            return Ok(());
896        }
897
898        // Case 5: [T1..., T2] - One or more elements, last is T2, rest are T1
899        if collection_types.len() == 2
900            && matches!(collection_types[0], TypeSpec::Spread(_, _))
901            && !matches!(collection_types[1], TypeSpec::Spread(_, _))
902        {
903            if elements.is_empty() {
904                return Err(ResolverError::Validation(ValidationError::TypeMismatch {
905                    field_name: field_name.to_string(),
906                    expected_type: "array with at least 1 element".to_string(),
907                    found_type: "empty array".to_string(),
908                    src: Arc::from(NamedSource::new(
909                        file_path.to_string_lossy(),
910                        source_text.to_string(),
911                    )),
912                    span: (
913                        elements.first().map_or(0, |e| e.pos_start),
914                        elements.last().map_or(0, |e| e.pos_end)
915                            - elements.first().map_or(0, |e| e.pos_start),
916                    )
917                        .into(),
918                }));
919            }
920            let (head, last) = elements.split_at_mut(elements.len() - 1);
921            self.validate_value(
922                last.first_mut().unwrap(), // Get the last element
923                &collection_types[1],
924                field_name,
925                imports, // Pass the imports here
926                file_path,
927                source_text,
928            )?;
929            if let TypeSpec::Spread(inner_type, _) = &collection_types[0] {
930                for element in head {
931                    self.validate_value(
932                        element,
933                        inner_type,
934                        field_name,
935                        imports,
936                        file_path,
937                        source_text,
938                    )?;
939                }
940            }
941            return Ok(());
942        }
943
944        // If none of the specific cases match, it's an unimplemented complex collection type
945        Err(ResolverError::Validation(
946            ValidationError::UnimplementedCollectionValidation {
947                field_name: field_name.to_string(),
948                src: Arc::from(NamedSource::new(
949                    file_path.to_string_lossy(),
950                    source_text.to_string(),
951                )),
952                span: (
953                    elements.first().map_or(0, |e| e.pos_start),
954                    elements.last().map_or(0, |e| e.pos_end)
955                        - elements.first().map_or(0, |e| e.pos_start),
956                )
957                    .into(),
958            },
959        ))
960    }
961}
962
963impl Default for Resolver {
964    fn default() -> Self {
965        Self::new()
966    }
967}
968
969#[cfg(test)]
970mod tests {
971    use crate::parser::Parser;
972    use crate::resolver::Resolver;
973    use miette::Report;
974    use std::fs;
975    use std::path::PathBuf;
976
977    fn resolve_ok(source: &str, file_name: &str) -> crate::ast::MonDocument {
978        let mut parser = Parser::new_with_name(source, file_name.to_string()).unwrap();
979        let document = parser.parse_document().unwrap();
980        let mut resolver = Resolver::new();
981        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
982        path.push(file_name);
983        match resolver.resolve(document, source, path, None) {
984            Ok(doc) => doc,
985            Err(err) => {
986                let report = Report::from(err);
987                panic!("{report:#}");
988            }
989        }
990    }
991
992    fn resolve_err(source: &str, file_name: &str) -> crate::error::ResolverError {
993        let mut parser = Parser::new_with_name(source, file_name.to_string()).unwrap();
994        let document = parser.parse_document().unwrap();
995        let mut resolver = Resolver::new();
996        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
997        path.push(file_name);
998        match resolver.resolve(document, source, path, None) {
999            Ok(_) => panic!("Expected a ResolverError, but got Ok"),
1000            Err(err) => err,
1001        }
1002    }
1003
1004    #[test]
1005    fn test_simple_alias_resolution() {
1006        let source = r"{ &my_value: 123, alias_value: *my_value }";
1007        let doc = resolve_ok(source, "test.mon");
1008
1009        let root_object = match doc.root.kind {
1010            crate::ast::MonValueKind::Object(members) => members,
1011            _ => panic!("Expected an object"),
1012        };
1013
1014        // Check that the alias_value is resolved to 123
1015        let alias_member = root_object
1016            .iter()
1017            .find(|m| {
1018                if let crate::ast::Member::Pair(p) = m {
1019                    p.key == "alias_value"
1020                } else {
1021                    false
1022                }
1023            })
1024            .unwrap();
1025
1026        if let crate::ast::Member::Pair(p) = alias_member {
1027            assert_eq!(p.value.kind, crate::ast::MonValueKind::Number(123.0));
1028        } else {
1029            panic!("Expected a pair member");
1030        }
1031    }
1032
1033    #[test]
1034    fn test_object_spread_resolution() {
1035        let source = r#"{
1036        &base_config: { host: "localhost", port: 8080 },
1037        app_config: {
1038            ...*base_config,
1039            port: 9000, // Override
1040            debug: true,
1041        }
1042    }"#;
1043        let doc = resolve_ok(source, "test.mon");
1044
1045        let root_object = match doc.root.kind {
1046            crate::ast::MonValueKind::Object(members) => members,
1047            _ => panic!("Expected an object"),
1048        };
1049
1050        let app_config_member = root_object
1051            .iter()
1052            .find(|m| {
1053                if let crate::ast::Member::Pair(p) = m {
1054                    p.key == "app_config"
1055                } else {
1056                    false
1057                }
1058            })
1059            .unwrap();
1060
1061        if let crate::ast::Member::Pair(p) = app_config_member {
1062            let app_config_object = match &p.value.kind {
1063                crate::ast::MonValueKind::Object(members) => members,
1064                _ => panic!("Expected app_config to be an object"),
1065            };
1066
1067            // Check host
1068            let host_member = app_config_object
1069                .iter()
1070                .find(|m| {
1071                    if let crate::ast::Member::Pair(p) = m {
1072                        p.key == "host"
1073                    } else {
1074                        false
1075                    }
1076                })
1077                .unwrap();
1078            if let crate::ast::Member::Pair(p) = host_member {
1079                assert_eq!(
1080                    p.value.kind,
1081                    crate::ast::MonValueKind::String("localhost".to_string())
1082                );
1083            } else {
1084                panic!("Expected host to be a pair");
1085            }
1086
1087            // Check port (overridden)
1088            let port_member = app_config_object
1089                .iter()
1090                .find(|m| {
1091                    if let crate::ast::Member::Pair(p) = m {
1092                        p.key == "port"
1093                    } else {
1094                        false
1095                    }
1096                })
1097                .unwrap();
1098            if let crate::ast::Member::Pair(p) = port_member {
1099                assert_eq!(p.value.kind, crate::ast::MonValueKind::Number(9000.0));
1100            } else {
1101                panic!("Expected port to be a pair");
1102            }
1103
1104            // Check debug (new field)
1105            let debug_member = app_config_object
1106                .iter()
1107                .find(|m| {
1108                    if let crate::ast::Member::Pair(p) = m {
1109                        p.key == "debug"
1110                    } else {
1111                        false
1112                    }
1113                })
1114                .unwrap();
1115            if let crate::ast::Member::Pair(p) = debug_member {
1116                assert_eq!(p.value.kind, crate::ast::MonValueKind::Boolean(true));
1117            } else {
1118                panic!("Expected debug to be a pair");
1119            }
1120        } else {
1121            panic!("Expected app_config to be a pair member");
1122        }
1123    }
1124
1125    #[test]
1126    fn test_array_spread_resolution() {
1127        let source = r#"{
1128        &base_tags: ["tag1", "tag2"],
1129        item_tags: [
1130            "start",
1131            ...*base_tags,
1132            "end",
1133        ]
1134    }"#;
1135        let doc = resolve_ok(source, "test.mon");
1136
1137        let root_object = match doc.root.kind {
1138            crate::ast::MonValueKind::Object(members) => members,
1139            _ => panic!("Expected an object"),
1140        };
1141
1142        let item_tags_member = root_object
1143            .iter()
1144            .find(|m| {
1145                if let crate::ast::Member::Pair(p) = m {
1146                    p.key == "item_tags"
1147                } else {
1148                    false
1149                }
1150            })
1151            .unwrap();
1152
1153        if let crate::ast::Member::Pair(p) = item_tags_member {
1154            let item_tags_array = match &p.value.kind {
1155                crate::ast::MonValueKind::Array(elements) => elements,
1156                _ => panic!("Expected item_tags to be an array"),
1157            };
1158
1159            assert_eq!(item_tags_array.len(), 4);
1160            assert_eq!(
1161                item_tags_array[0].kind,
1162                crate::ast::MonValueKind::String("start".to_string())
1163            );
1164            assert_eq!(
1165                item_tags_array[1].kind,
1166                crate::ast::MonValueKind::String("tag1".to_string())
1167            );
1168            assert_eq!(
1169                item_tags_array[2].kind,
1170                crate::ast::MonValueKind::String("tag2".to_string())
1171            );
1172            assert_eq!(
1173                item_tags_array[3].kind,
1174                crate::ast::MonValueKind::String("end".to_string())
1175            );
1176        } else {
1177            panic!("Expected item_tags to be a pair member");
1178        }
1179    }
1180
1181    #[test]
1182    fn test_struct_validation_with_defaults_and_collections_ok() {
1183        let source = r#"
1184        {
1185            User: #struct {
1186                id(Number),
1187                name(String),
1188                email(String) = "default@example.com",
1189                is_active(Boolean) = true,
1190                roles([String...]),
1191                permissions([String, Number]),
1192                log_data([String, Any...]),
1193                status_history([Boolean..., String]),
1194            },
1195
1196            // Valid user with defaults
1197            user1 :: User = {
1198                id: 1,
1199                name: "Alice",
1200                roles: ["admin", "editor"],
1201                permissions: ["read", 1],
1202                log_data: ["login", { timestamp: "...", ip: "..." }],
1203                status_history: [true, false, "active"],
1204            },
1205
1206            // Valid user, omitting optional fields
1207            user2 :: User = {
1208                id: 2,
1209                name: "Bob",
1210                roles: [],
1211                permissions: ["write", 2],
1212                log_data: ["logout"],
1213                status_history: ["inactive"],
1214            },
1215        }
1216    "#;
1217
1218        // Test valid user1
1219        let doc = resolve_ok(source, "test_validation.mon");
1220        let root_object = match doc.root.kind {
1221            crate::ast::MonValueKind::Object(members) => members,
1222            _ => panic!("Expected an object"),
1223        };
1224
1225        let user1_member = root_object
1226            .iter()
1227            .find(|m| {
1228                if let crate::ast::Member::Pair(p) = m {
1229                    p.key == "user1"
1230                } else {
1231                    false
1232                }
1233            })
1234            .unwrap();
1235
1236        if let crate::ast::Member::Pair(p) = user1_member {
1237            let user1_object = match &p.value.kind {
1238                crate::ast::MonValueKind::Object(members) => members,
1239                _ => panic!("Expected user1 to be an object"),
1240            };
1241
1242            // Check default email
1243            let email_member = user1_object
1244                .iter()
1245                .find(|m| {
1246                    if let crate::ast::Member::Pair(p) = m {
1247                        p.key == "email"
1248                    } else {
1249                        false
1250                    }
1251                })
1252                .unwrap();
1253            if let crate::ast::Member::Pair(p) = email_member {
1254                assert_eq!(
1255                    p.value.kind,
1256                    crate::ast::MonValueKind::String("default@example.com".to_string())
1257                );
1258            } else {
1259                panic!("Expected email to be a pair");
1260            }
1261
1262            // Check default is_active
1263            let is_active_member = user1_object
1264                .iter()
1265                .find(|m| {
1266                    if let crate::ast::Member::Pair(p) = m {
1267                        p.key == "is_active"
1268                    } else {
1269                        false
1270                    }
1271                })
1272                .unwrap();
1273            if let crate::ast::Member::Pair(p) = is_active_member {
1274                assert_eq!(p.value.kind, crate::ast::MonValueKind::Boolean(true));
1275            } else {
1276                panic!("Expected is_active to be a pair");
1277            }
1278        } else {
1279            panic!("Expected user1 to be a pair member");
1280        }
1281    }
1282
1283    #[test]
1284    fn test_struct_validation_missing_required_field() {
1285        let source = r"
1286        {
1287            User: #struct { id(Number), name(String) },
1288            invalid_user :: User = { id: 3 },
1289        }
1290    ";
1291        let err = resolve_err(source, "test_validation.mon");
1292        match err {
1293            crate::error::ResolverError::Validation(
1294                crate::error::ValidationError::MissingField { field_name, .. },
1295            ) => {
1296                assert_eq!(field_name, "name");
1297            }
1298            _ => panic!("Expected MissingField error, but got {err:?}"),
1299        }
1300    }
1301
1302    #[test]
1303    fn test_struct_validation_wrong_id_type() {
1304        let source = r#"
1305        {
1306            User: #struct { id(Number), name(String) },
1307            invalid_user :: User = { id: "four", name: "Charlie" },
1308        }
1309    "#;
1310        let err = resolve_err(source, "test_validation.mon");
1311        match err {
1312            crate::error::ResolverError::Validation(
1313                crate::error::ValidationError::TypeMismatch {
1314                    field_name,
1315                    expected_type,
1316                    found_type,
1317                    ..
1318                },
1319            ) => {
1320                assert_eq!(field_name, "id");
1321                assert_eq!(expected_type, "Number");
1322                assert!(found_type.contains("String"));
1323            }
1324            _ => panic!("Expected TypeMismatch error for id, but got {err:?}"),
1325        }
1326    }
1327
1328    #[test]
1329    fn test_struct_validation_unexpected_field() {
1330        let source = r#"
1331        {
1332            User: #struct { id(Number), name(String) },
1333            invalid_user :: User = { id: 5, name: "David", age: 30 },
1334        }
1335    "#;
1336        let err = resolve_err(source, "test_validation.mon");
1337        match err {
1338            crate::error::ResolverError::Validation(
1339                crate::error::ValidationError::UnexpectedField { field_name, .. },
1340            ) => {
1341                assert_eq!(field_name, "age");
1342            }
1343            _ => panic!("Expected UnexpectedField error, but got {err:?}"),
1344        }
1345    }
1346
1347    #[test]
1348    fn test_struct_validation_roles_type_mismatch() {
1349        let source = r#"
1350        {
1351            User: #struct { roles([String...]) },
1352            invalid_user :: User = { roles: ["viewer", 123] },
1353        }
1354    "#;
1355        let err = resolve_err(source, "test_validation.mon");
1356        match err {
1357            crate::error::ResolverError::Validation(
1358                crate::error::ValidationError::TypeMismatch {
1359                    field_name,
1360                    expected_type,
1361                    found_type,
1362                    ..
1363                },
1364            ) => {
1365                assert_eq!(field_name, "roles");
1366                assert_eq!(expected_type, "String");
1367                assert!(found_type.contains("Number"));
1368            }
1369            _ => panic!("Expected TypeMismatch error for roles, but got {err:?}"),
1370        }
1371    }
1372
1373    #[test]
1374    fn test_struct_validation_permissions_length_mismatch() {
1375        let source = r#"
1376        {
1377            User: #struct { permissions([String, Number]) },
1378            invalid_user :: User = { permissions: ["read"] },
1379        }
1380    "#;
1381        let err = resolve_err(source, "test_validation.mon");
1382        match err {
1383            crate::error::ResolverError::Validation(
1384                crate::error::ValidationError::TypeMismatch {
1385                    field_name,
1386                    expected_type,
1387                    found_type,
1388                    ..
1389                },
1390            ) => {
1391                assert_eq!(field_name, "permissions");
1392                assert!(expected_type.contains("tuple with 2 elements"));
1393                assert!(found_type.contains("tuple with 1 elements"));
1394            }
1395            _ => panic!("Expected TypeMismatch error for permissions length, but got {err:?}"),
1396        }
1397    }
1398
1399    #[test]
1400    fn test_struct_validation_permissions_type_mismatch() {
1401        let source = r#"
1402        {
1403            User: #struct { permissions([String, Number]) },
1404            invalid_user :: User = { permissions: [8, "write"] },
1405        }
1406    "#;
1407        let err = resolve_err(source, "test_validation.mon");
1408        match err {
1409            crate::error::ResolverError::Validation(
1410                crate::error::ValidationError::TypeMismatch {
1411                    field_name,
1412                    expected_type,
1413                    found_type,
1414                    ..
1415                },
1416            ) => {
1417                assert_eq!(field_name, "permissions");
1418                assert_eq!(expected_type, "String");
1419                assert!(found_type.contains("Number"));
1420            }
1421            _ => panic!("Expected TypeMismatch error for permissions types, but got {err:?}"),
1422        }
1423    }
1424
1425    #[test]
1426    fn test_struct_validation_log_data_first_type_mismatch() {
1427        let source = r#"
1428        {
1429            User: #struct { log_data([String, Any...]) },
1430            invalid_user :: User = { log_data: [123, "event"] },
1431        }
1432    "#;
1433        let err = resolve_err(source, "test_validation.mon");
1434        match err {
1435            crate::error::ResolverError::Validation(
1436                crate::error::ValidationError::TypeMismatch {
1437                    field_name,
1438                    expected_type,
1439                    found_type,
1440                    ..
1441                },
1442            ) => {
1443                assert_eq!(field_name, "log_data");
1444                assert_eq!(expected_type, "String");
1445                assert!(found_type.contains("Number"));
1446            }
1447            _ => panic!("Expected TypeMismatch error for log_data first type, but got {err:?}"),
1448        }
1449    }
1450
1451    #[test]
1452    fn test_struct_validation_status_history_last_type_mismatch() {
1453        let source = r"
1454        {
1455            User: #struct { status_history([Boolean..., String]) },
1456            invalid_user :: User = { status_history: [true, 123] },
1457        }
1458    ";
1459        let err = resolve_err(source, "test_validation.mon");
1460        match err {
1461            crate::error::ResolverError::Validation(
1462                crate::error::ValidationError::TypeMismatch {
1463                    field_name,
1464                    expected_type,
1465                    found_type,
1466                    ..
1467                },
1468            ) => {
1469                assert_eq!(field_name, "status_history");
1470                assert_eq!(expected_type, "String");
1471                assert!(found_type.contains("Number"));
1472            }
1473            _ => {
1474                panic!("Expected TypeMismatch error for status_history last type, but got {err:?}")
1475            }
1476        }
1477    }
1478
1479    #[test]
1480    fn test_nested_struct_validation_ok() {
1481        let source = r#"
1482        {
1483            Profile: #struct {
1484                username(String),
1485                email(String),
1486            },
1487            User: #struct {
1488                id(Number),
1489                profile(Profile),
1490            },
1491
1492            // Valid nested struct
1493            user1 :: User = {
1494                id: 1,
1495                profile: {
1496                    username: "alice",
1497                    email: "alice@example.com",
1498                },
1499            },
1500        }
1501    "#;
1502
1503        resolve_ok(source, "test_nested_ok.mon");
1504    }
1505
1506    #[test]
1507    fn test_nested_struct_validation_err() {
1508        let source = r#"
1509        {
1510            Profile: #struct {
1511                username(String),
1512                email(String),
1513            },
1514            User: #struct {
1515                id(Number),
1516                profile(Profile),
1517            },
1518
1519            // Invalid: Nested struct has wrong type for username
1520            user2 :: User = {
1521                id: 2,
1522                profile: {
1523                    username: 123,
1524                    email: "bob@example.com",
1525                },
1526            },
1527        }
1528    "#;
1529
1530        let err = resolve_err(source, "test_nested_err.mon");
1531        match err {
1532            crate::error::ResolverError::Validation(
1533                crate::error::ValidationError::TypeMismatch {
1534                    field_name,
1535                    expected_type,
1536                    found_type,
1537                    ..
1538                },
1539            ) => {
1540                assert_eq!(field_name, "username");
1541                assert_eq!(expected_type, "String");
1542                assert!(found_type.contains("Number"));
1543            }
1544            _ => panic!("Expected TypeMismatch error for username, but got {err:?}"),
1545        }
1546    }
1547
1548    #[test]
1549    fn test_cross_file_validation() {
1550        let source = fs::read_to_string("tests/cross_file_main.mon").unwrap();
1551        resolve_ok(&source, "tests/cross_file_main.mon");
1552    }
1553
1554    #[test]
1555    fn test_parser_for_schemas_file() {
1556        let source = fs::read_to_string("tests/cross_file_schemas.mon").unwrap();
1557        let mut parser = Parser::new_with_name(&source, "test.mon".to_string()).unwrap();
1558        let _ = parser.parse_document().unwrap();
1559    }
1560
1561    #[test]
1562    fn test_named_import_validation() {
1563        let source = fs::read_to_string("tests/named_import_main.mon").unwrap();
1564        resolve_ok(&source, "tests/named_import_main.mon");
1565    }
1566}