1pub mod freeze;
2pub mod infer;
3pub(crate) mod registration;
4pub mod scopes;
5pub mod type_env;
6
7use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
8use std::cell::RefCell;
9use std::rc::Rc;
10use std::sync::Arc;
11
12use crate::facts::{BindingIdAllocator, Facts};
13use crate::store::Store;
14use diagnostics::LocalSink;
15use ecow::EcoString;
16use scopes::Scopes;
17use syntax::ast::Visibility as AstVisibility;
18use syntax::ast::{Annotation, Expression, Generic, ImportAlias, Span, StructFieldDefinition};
19use syntax::program::{Definition, DefinitionBody, File, FileImport, MethodSignatures, Module};
20use syntax::types::{SubstitutionMap, Symbol, Type, substitute};
21
22pub use type_env::{EnvResolve, Speculation, TypeEnv, VarState};
23
24#[derive(Debug, Clone)]
25pub struct Cursor {
26 pub module_id: String,
27 pub file_id: Option<u32>,
28}
29
30impl Default for Cursor {
31 fn default() -> Self {
32 Self {
33 module_id: "std".to_string(),
34 file_id: None,
35 }
36 }
37}
38
39impl Cursor {
40 pub fn new() -> Self {
41 Self::default()
42 }
43}
44
45#[derive(Debug, Default)]
46pub struct ImportState {
47 pub imported_modules: HashMap<String, (Arc<[StructFieldDefinition]>, Type)>,
50 pub prefix_to_module: HashMap<String, String>,
52 pub unprefixed_imports: HashSet<String>,
54 pub failed_imports: HashSet<String>,
57}
58
59impl ImportState {
60 pub fn new() -> Self {
61 Self::default()
62 }
63
64 pub fn clear(&mut self) {
65 let prelude = self.imported_modules.remove("prelude");
67 self.imported_modules.clear();
68 if let Some(p) = prelude {
69 self.imported_modules.insert("prelude".to_string(), p);
70 }
71 let prelude_mapping = self.prefix_to_module.remove("prelude");
72 self.prefix_to_module.clear();
73 if let Some(m) = prelude_mapping {
74 self.prefix_to_module.insert("prelude".to_string(), m);
75 }
76 self.unprefixed_imports.clear();
77 self.failed_imports.clear();
78 }
79}
80
81#[derive(Debug, Clone, Copy)]
82pub(crate) enum FileContextKind {
83 Standard,
84 ImportedTypedef,
85 Prelude,
86}
87
88struct SavedFileContext {
89 file_id: Option<u32>,
90 scopes: Scopes,
91 imports: ImportState,
92}
93
94type BuiltinCache = HashMap<String, Type>;
97
98pub struct TaskState<'s> {
100 pub env: TypeEnv,
101 pub scopes: Scopes,
102 pub cursor: Cursor,
103 pub imports: ImportState,
104 pub builtins: BuiltinCache,
105 pub sink: &'s LocalSink,
106 pub facts: Facts,
107 pub satisfying_stack: rustc_hash::FxHashSet<(String, String)>,
111 method_cache: RefCell<HashMap<EcoString, Rc<MethodSignatures>>>,
112 module_fields_cache: RefCell<HashMap<EcoString, Arc<[StructFieldDefinition]>>>,
115 pub module_fields_shared: Option<Arc<HashMap<EcoString, Arc<[StructFieldDefinition]>>>>,
118 pub ufcs_methods: HashSet<(String, String)>,
119 pub ufcs_shared: Option<Arc<HashSet<(String, String)>>>,
121 pub typed_files: Vec<(String, File)>,
123 pub bound_position_depth: u32,
127}
128
129impl<'s> TaskState<'s> {
130 pub fn new(sink: &'s LocalSink, binding_ids: Arc<BindingIdAllocator>) -> Self {
131 Self {
132 env: TypeEnv::new(),
133 scopes: Scopes::new(),
134 cursor: Cursor::new(),
135 imports: ImportState::new(),
136 builtins: BuiltinCache::default(),
137 sink,
138 facts: Facts::new(binding_ids),
139 satisfying_stack: rustc_hash::FxHashSet::default(),
140 method_cache: RefCell::new(HashMap::default()),
141 module_fields_cache: RefCell::new(HashMap::default()),
142 module_fields_shared: None,
143 ufcs_methods: HashSet::default(),
144 ufcs_shared: None,
145 typed_files: Vec::new(),
146 bound_position_depth: 0,
147 }
148 }
149
150 pub fn with_fresh_allocator(sink: &'s LocalSink) -> Self {
151 Self::new(sink, Arc::new(BindingIdAllocator::new()))
152 }
153
154 fn effective_ufcs_methods(&self) -> &HashSet<(String, String)> {
155 self.ufcs_shared.as_deref().unwrap_or(&self.ufcs_methods)
156 }
157
158 pub fn new_type_var(&mut self) -> Type {
159 let id = self.env.fresh(None);
160 Type::Var { id, hint: None }
161 }
162
163 pub fn new_type_var_with_hint(&mut self, hint: &str) -> Type {
164 let hint: EcoString = hint.into();
165 let id = self.env.fresh(Some(hint.clone()));
166 Type::Var {
167 id,
168 hint: Some(hint),
169 }
170 }
171
172 pub fn type_from_literal_expression(&mut self, expression: &Expression) -> Option<Type> {
173 use syntax::ast::{Expression, Literal};
174 match expression {
175 Expression::Literal { literal, .. } => match literal {
176 Literal::Integer { .. } => Some(self.type_int()),
177 Literal::Float { .. } => Some(self.type_float()),
178 Literal::Boolean(_) => Some(self.type_bool()),
179 Literal::String { .. } => Some(self.type_string()),
180 Literal::Char(_) => Some(self.type_char()),
181 _ => None,
182 },
183 Expression::Unary { expression, .. } => self.type_from_literal_expression(expression),
184 _ => None,
185 }
186 }
187
188 pub fn instantiate(&mut self, ty: &Type) -> (Type, SubstitutionMap) {
189 match ty {
190 Type::Forall { vars, body } => {
191 let map: SubstitutionMap = vars
192 .iter()
193 .map(|name| {
194 let id = self.env.fresh(Some(name.clone()));
195 let fresh_var = Type::Var {
196 id,
197 hint: Some(name.clone()),
198 };
199 (name.clone(), fresh_var)
200 })
201 .collect();
202
203 (substitute(body, &map), map)
204 }
205 _ => (ty.clone(), HashMap::default()),
206 }
207 }
208
209 pub fn new_file_id(&mut self, store: &Store) -> u32 {
210 store.new_file_id()
211 }
212
213 pub fn is_d_lis(&self, store: &Store) -> bool {
214 let Some(file_id) = self.cursor.file_id else {
215 return false;
216 };
217
218 let Some(module) = store.get_module(&self.cursor.module_id) else {
219 return false;
220 };
221
222 module.typedefs.contains_key(&file_id)
223 }
224
225 pub fn is_lis(&self, store: &Store) -> bool {
226 !self.is_d_lis(store)
227 }
228
229 pub(crate) fn current_module<'a>(&self, store: &'a Store) -> &'a Module {
230 store
231 .get_module(&self.cursor.module_id)
232 .expect("current module must exist in store")
233 }
234
235 pub(crate) fn current_module_mut<'a>(&self, store: &'a mut Store) -> &'a mut Module {
236 store
237 .get_module_mut(&self.cursor.module_id)
238 .expect("current module must exist in store")
239 }
240
241 pub(crate) fn qualify_name(&self, name: &str) -> Symbol {
242 Symbol::from_parts(&self.cursor.module_id, name)
243 }
244
245 pub(crate) fn put_in_scope(&mut self, generics: &[Generic]) {
246 for (index, generic) in generics.iter().enumerate() {
247 self.scopes
248 .current_mut()
249 .type_params
250 .get_or_insert_with(HashMap::default)
251 .insert(generic.name.to_string(), index);
252 }
253 }
254
255 pub(crate) fn validate_generic_bounds(
257 &mut self,
258 store: &Store,
259 generics: &[Generic],
260 span: &Span,
261 ) {
262 for g in generics {
263 for b in &g.bounds {
264 self.register_bound_annotation(store, b, span);
265 }
266 }
267 }
268
269 pub(crate) fn register_bound_annotation(
270 &mut self,
271 store: &Store,
272 bound: &Annotation,
273 span: &Span,
274 ) -> Type {
275 let resolved = self.convert_bound_to_type(store, bound, span);
276 if self.is_lis(store) && resolved.contains_unknown() {
277 self.sink
278 .push(diagnostics::infer::unknown_in_bound_position(
279 bound.get_span(),
280 ));
281 }
282 resolved
283 }
284
285 fn resolve_in_imported_module<'m>(
290 &self,
291 module: &'m Module,
292 simple_name: &str,
293 ) -> Option<(String, &'m Definition)> {
294 let module_prefix = format!("{}.", module.id);
295
296 let direct = format!("{}{}", module_prefix, simple_name);
298 if let Some(definition) = module.definitions.get(direct.as_str())
299 && definition.visibility().is_public()
300 {
301 return Some((direct, definition));
302 }
303
304 let suffix = format!(".{}", simple_name);
309 for (qn, definition) in &module.definitions {
310 if qn.ends_with(suffix.as_str())
311 && qn.starts_with(module_prefix.as_str())
312 && definition.visibility().is_public()
313 {
314 let rest = &qn[module_prefix.len()..];
315 if rest.contains('.') {
317 return Some((qn.to_string(), definition));
318 }
319 }
320 }
321
322 None
323 }
324
325 pub(crate) fn lookup_qualified_name(
326 &self,
327 store: &Store,
328 type_name: &str,
329 ) -> Option<EcoString> {
330 self.lookup_qualified_name_in_scope(store, type_name, false)
331 }
332
333 fn lookup_qualified_name_in_type_position(
334 &self,
335 store: &Store,
336 type_name: &str,
337 ) -> Option<EcoString> {
338 self.lookup_qualified_name_in_scope(store, type_name, true)
339 }
340
341 fn lookup_qualified_name_in_scope(
342 &self,
343 store: &Store,
344 type_name: &str,
345 prefer_type: bool,
346 ) -> Option<EcoString> {
347 if let Some((prefix, simple_name)) = type_name.split_once('.')
348 && let Some(module_id) = self.imports.prefix_to_module.get(prefix)
349 && let Some(imported_module) = store.get_module(module_id)
350 && let Some((qualified_name, _)) =
351 self.resolve_in_imported_module(imported_module, simple_name)
352 {
353 return Some(qualified_name.into());
354 }
355
356 let module_ids = std::iter::once(self.cursor.module_id.as_str())
357 .chain(self.imports.unprefixed_imports.iter().map(String::as_str));
358
359 let mut value_fallback: Option<EcoString> = None;
360 for module_id in module_ids {
361 let Some(module) = store.get_module(module_id) else {
362 continue;
363 };
364 let qualified_name = Symbol::from_parts(module_id, type_name);
365 let Some(definition) = module.definitions.get(qualified_name.as_str()) else {
366 continue;
367 };
368
369 if prefer_type && definition.is_value(qualified_name.as_str()) {
370 if value_fallback.is_none() {
371 value_fallback = Some(qualified_name.as_eco().clone());
372 }
373 } else {
374 return Some(qualified_name.as_eco().clone());
375 }
376 }
377
378 value_fallback
379 }
380
381 pub(crate) fn get_definition_name_span(
382 &self,
383 store: &Store,
384 qualified_name: &str,
385 ) -> Option<Span> {
386 store.get_definition(qualified_name)?.name_span()
387 }
388
389 pub(crate) fn is_const_name(&self, store: &Store, qualified_name: &str) -> bool {
390 if qualified_name.starts_with("go:") {
391 return false;
392 }
393 store
394 .module_for_qualified_name(qualified_name)
395 .and_then(|module_id| store.get_module(module_id))
396 .is_some_and(|module| module.const_names.contains(qualified_name))
397 }
398
399 pub(crate) fn is_const_var(&self, store: &Store, var_name: &str) -> bool {
400 if self.scopes.lookup_binding_id(var_name).is_some() {
401 return false;
402 }
403 if self.scopes.lookup_const(var_name) {
404 return true;
405 }
406 self.lookup_qualified_name(store, var_name)
407 .is_some_and(|qname| self.is_const_name(store, &qname))
408 }
409
410 pub(crate) fn track_name_usage(
412 &mut self,
413 store: &Store,
414 qualified_name: &str,
415 span: &Span,
416 name_len: u32,
417 ) {
418 if let Some(definition_span) = self.get_definition_name_span(store, qualified_name) {
419 let usage_span = Span::new(span.file_id, span.byte_offset, name_len);
420 self.facts.add_usage(usage_span, definition_span);
421 }
422 }
423
424 pub(crate) fn lookup_generic_index(&self, type_name: &str) -> Option<usize> {
425 self.scopes.lookup_type_param(type_name)
426 }
427
428 fn resolve_definition_value_type(&self, store: &Store, definition: &Definition) -> Type {
431 if let DefinitionBody::Struct {
432 constructor: Some(ctor_ty),
433 ..
434 } = &definition.body
435 {
436 return ctor_ty.clone();
437 }
438
439 if let DefinitionBody::TypeAlias { .. } = &definition.body {
441 let alias_ty = &definition.ty;
442 let underlying = match alias_ty {
443 Type::Forall { body, .. } => body.as_ref(),
444 other => other,
445 };
446 if let Type::Nominal { id, .. } = underlying
447 && let Some(Definition {
448 body:
449 DefinitionBody::Struct {
450 constructor: Some(ctor_ty),
451 ..
452 },
453 ..
454 }) = store.get_definition(id)
455 {
456 return ctor_ty.clone();
457 }
458 }
459
460 definition.ty().clone()
461 }
462
463 pub(crate) fn lookup_type(&self, store: &Store, value_name: &str) -> Option<Type> {
464 if let Some(ty) = self.scopes.lookup_value(value_name) {
465 return Some(ty.clone());
466 }
467
468 if let Some((_definition, ty)) = self.imports.imported_modules.get(value_name) {
469 return Some(ty.clone());
470 }
471
472 if let Some((prefix, rest)) = value_name.split_once('.')
473 && let Some(module_id) = self.imports.prefix_to_module.get(prefix)
474 && let Some(imported_module) = store.get_module(module_id)
475 && let Some((_, definition)) = self.resolve_in_imported_module(imported_module, rest)
476 {
477 return Some(self.resolve_definition_value_type(store, definition));
478 }
479
480 let module = store.get_module(&self.cursor.module_id)?;
481 let qualified_name = Symbol::from_parts(&module.id, value_name);
482
483 if let Some(definition) = module.definitions.get(qualified_name.as_str()) {
484 return Some(self.resolve_definition_value_type(store, definition));
485 }
486
487 for imported_module_id in &self.imports.unprefixed_imports {
488 if let Some(imported_module) = store.get_module(imported_module_id) {
489 let qualified_name = Symbol::from_parts(imported_module_id, value_name);
490 if let Some(definition) = imported_module.definitions.get(qualified_name.as_str()) {
491 return Some(self.resolve_definition_value_type(store, definition));
492 }
493 }
494 }
495
496 None
497 }
498
499 pub(crate) fn is_enum_type(&self, store: &Store, ty: &Type) -> bool {
500 let Type::Nominal { id, .. } = ty else {
501 return false;
502 };
503 let Some(definition) = store.get_definition(id) else {
504 return false;
505 };
506 matches!(definition.body, DefinitionBody::Enum { .. })
507 }
508
509 pub(crate) fn resolve_type_name(
510 &mut self,
511 store: &Store,
512 type_name: &str,
513 ) -> Option<(String, Type)> {
514 if self.scopes.lookup_type_param(type_name).is_some() {
515 return None;
516 }
517
518 let qualified_name = self.lookup_qualified_name_in_type_position(store, type_name)?;
519 let ty = store.get_type(&qualified_name)?.clone();
520
521 Some((qualified_name.to_string(), ty))
522 }
523
524 pub(crate) fn resolve_type_from_prelude(
525 &self,
526 store: &Store,
527 type_name: &str,
528 ) -> Option<(String, Type)> {
529 let qualified_name = format!("prelude.{}", type_name);
530 let ty = store.get_type(&qualified_name)?.clone();
531 Some((qualified_name, ty))
532 }
533
534 pub(crate) fn get_all_methods(&self, store: &Store, ty: &Type) -> Rc<MethodSignatures> {
535 if let Type::Parameter(name) = ty {
536 let trait_bounds = self.scopes.collect_all_trait_bounds();
537 let qualified_name = self.qualify_name(name);
538 return Rc::new(store.get_methods_from_bounds(&qualified_name, &trait_bounds));
539 }
540
541 let resolved = ty.strip_refs().resolve_in(&self.env);
542 let cache_key: EcoString = match &resolved {
543 Type::Nominal { id, .. } => id.as_eco().clone(),
544 Type::Compound { kind, .. } => format!("prelude.{}", kind.leaf_name()).into(),
545 Type::Simple(kind) => format!("prelude.{}", kind.leaf_name()).into(),
546 _ => return Rc::new(MethodSignatures::default()),
547 };
548
549 let peeled = store.peel_alias(&resolved);
551 if let Type::Nominal { id: peeled_id, .. } = &peeled
552 && store.get_interface(peeled_id).is_some()
553 {
554 let empty = HashMap::default();
555 return Rc::new(store.get_all_methods(&peeled, &empty));
556 }
557
558 if let Some(cached) = self.method_cache.borrow().get(cache_key.as_str()) {
559 return cached.clone();
560 }
561
562 let empty = HashMap::default();
563 let methods = Rc::new(store.get_all_methods(&resolved, &empty));
567 self.method_cache
568 .borrow_mut()
569 .insert(cache_key, methods.clone());
570 methods
571 }
572
573 pub fn reset_scopes(&mut self) {
574 self.scopes.reset();
575 self.imports.clear();
576 }
577
578 pub(crate) fn with_module_cursor<T>(
579 &mut self,
580 module_id: &str,
581 f: impl FnOnce(&mut Self) -> T,
582 ) -> T {
583 if self.cursor.module_id == module_id {
584 return f(self);
585 }
586
587 let previous_module_id = std::mem::replace(&mut self.cursor.module_id, module_id.into());
588 let result = f(self);
589 self.cursor.module_id = previous_module_id;
590 result
591 }
592
593 pub(crate) fn with_file_context<T>(
594 &mut self,
595 store: &Store,
596 module_id: &str,
597 file_id: u32,
598 imports: &[FileImport],
599 kind: FileContextKind,
600 f: impl FnOnce(&mut Self, &Store) -> T,
601 ) -> T {
602 self.with_module_cursor(module_id, |this| {
603 let saved = this.enter_file_context(store, module_id, file_id, imports, kind);
604 let result = f(this, store);
605 this.exit_file_context(saved);
606 result
607 })
608 }
609
610 pub(crate) fn with_file_context_mut<T>(
611 &mut self,
612 store: &mut Store,
613 module_id: &str,
614 file_id: u32,
615 imports: &[FileImport],
616 kind: FileContextKind,
617 f: impl FnOnce(&mut Self, &mut Store) -> T,
618 ) -> T {
619 self.with_module_cursor(module_id, |this| {
620 let saved = this.enter_file_context(&*store, module_id, file_id, imports, kind);
621 let result = f(this, store);
622 this.exit_file_context(saved);
623 result
624 })
625 }
626
627 fn enter_file_context(
628 &mut self,
629 store: &Store,
630 module_id: &str,
631 file_id: u32,
632 imports: &[FileImport],
633 kind: FileContextKind,
634 ) -> SavedFileContext {
635 let saved = SavedFileContext {
636 file_id: self.cursor.file_id.replace(file_id),
637 scopes: std::mem::take(&mut self.scopes),
638 imports: std::mem::take(&mut self.imports),
639 };
640
641 match kind {
642 FileContextKind::Standard => {
643 self.put_prelude_in_scope(store);
644 self.put_unprefixed_module_in_scope(store, module_id);
645 }
646 FileContextKind::ImportedTypedef => {
647 self.put_prelude_in_scope(store);
648 }
649 FileContextKind::Prelude => {
650 self.put_unprefixed_module_in_scope(store, module_id);
651 }
652 }
653 self.put_imported_modules_in_scope(store, imports);
654
655 saved
656 }
657
658 fn exit_file_context(&mut self, saved: SavedFileContext) {
659 self.scopes = saved.scopes;
660 self.imports = saved.imports;
661 self.cursor.file_id = saved.file_id;
662 }
663
664 pub fn failed(&self) -> bool {
665 self.sink.has_errors()
666 }
667
668 pub fn put_prelude_in_scope(&mut self, store: &Store) {
669 self.put_unprefixed_module_in_scope(store, "prelude");
670 if self.imports.imported_modules.contains_key("prelude") {
671 return;
672 }
673 self.put_module_in_scope(store, "prelude", Some("prelude".to_string()));
674 }
675
676 pub fn put_unprefixed_module_in_scope(&mut self, store: &Store, module_id: &str) {
677 self.put_module_in_scope(store, module_id, None)
678 }
679
680 pub fn put_imported_modules_in_scope(&mut self, store: &Store, imports: &[FileImport]) {
681 let mut seen_aliases: HashMap<String, String> = HashMap::default(); let mut seen_paths: HashSet<String> = HashSet::default();
683
684 for import in imports {
685 if seen_paths.contains(import.name.as_str()) {
686 self.sink.push(diagnostics::infer::duplicate_import_path(
687 &import.name,
688 import.name_span,
689 ));
690 continue;
691 }
692 seen_paths.insert(import.name.to_string());
693
694 if matches!(import.alias, Some(ImportAlias::Blank(_))) {
695 continue;
696 }
697
698 if let Some(ImportAlias::Named(alias, alias_span)) = &import.alias
699 && is_reserved_import_alias(alias)
700 {
701 self.sink.push(diagnostics::infer::reserved_import_alias(
702 alias,
703 *alias_span,
704 ));
705 continue;
706 }
707
708 let Some(effective) = import.effective_alias(&store.go_package_names) else {
709 continue;
710 };
711
712 if let Some(existing_path) = seen_aliases.get(&effective)
713 && existing_path != &import.name
714 {
715 self.sink.push(diagnostics::infer::import_conflict(
716 &effective,
717 existing_path,
718 &import.name,
719 import.name_span,
720 ));
721 continue;
722 }
723
724 seen_aliases.insert(effective.clone(), import.name.to_string());
725
726 let module = store.get_module(&import.name);
727 if module.is_none() || module.is_some_and(Module::is_empty_stub) {
728 self.imports.failed_imports.insert(effective);
729 continue;
730 }
731
732 self.put_module_in_scope(store, &import.name, Some(effective));
733 }
734 }
735
736 fn module_struct_fields(&self, module: &Module) -> Arc<[StructFieldDefinition]> {
737 if let Some(shared) = &self.module_fields_shared
738 && let Some(fields) = shared.get(module.id.as_str())
739 {
740 return fields.clone();
741 }
742 if let Some(cached) = self.module_fields_cache.borrow().get(module.id.as_str()) {
743 return cached.clone();
744 }
745
746 let module_prefix = format!("{}.", module.id);
747 let fields: Vec<StructFieldDefinition> = module
748 .definitions
749 .iter()
750 .filter(|(qn, _)| module.is_public(qn))
751 .filter(|(qn, _)| {
752 qn.strip_prefix(&module_prefix)
753 .is_some_and(|rest| !rest.contains('.'))
754 })
755 .map(|(qn, definition)| {
756 let simple_name = qn
757 .strip_prefix(&module_prefix)
758 .expect("qualified_name must start with module prefix");
759 let ty = if let DefinitionBody::Struct {
760 constructor: Some(ctor_ty),
761 ..
762 } = &definition.body
763 {
764 ctor_ty.clone()
765 } else {
766 definition.ty().clone()
767 };
768 StructFieldDefinition {
769 doc: None,
770 attributes: vec![],
771 visibility: AstVisibility::Public,
772 name: simple_name.into(),
773 name_span: Span::dummy(),
774 annotation: Annotation::Unknown,
775 ty,
776 }
777 })
778 .collect();
779
780 let shared: Arc<[StructFieldDefinition]> = fields.into();
781 self.module_fields_cache
782 .borrow_mut()
783 .insert(module.id.clone().into(), shared.clone());
784 shared
785 }
786
787 pub fn module_fields_snapshot(&self) -> HashMap<EcoString, Arc<[StructFieldDefinition]>> {
789 self.module_fields_cache.borrow().clone()
790 }
791
792 pub fn put_module_in_scope(&mut self, store: &Store, module_id: &str, prefix: Option<String>) {
793 let Some(prefix) = prefix else {
794 self.imports
795 .unprefixed_imports
796 .insert(module_id.to_string());
797 return;
798 };
799
800 let module = store
801 .get_module(module_id)
802 .expect("module must exist when putting in scope");
803
804 let imported_module_id = module.id.clone();
805
806 let module_struct_fields = self.module_struct_fields(module);
807
808 let ty = Type::ImportNamespace(imported_module_id.clone().into());
809
810 self.imports
811 .imported_modules
812 .insert(prefix.clone(), (module_struct_fields, ty));
813 self.imports
814 .prefix_to_module
815 .insert(prefix, imported_module_id);
816 }
817
818 pub(crate) fn speculatively<T, E>(
821 &mut self,
822 f: impl FnOnce(&mut Self) -> Result<T, E>,
823 ) -> Result<T, E> {
824 let spec = self.env.begin_speculation();
825 let result = f(self);
826 self.env.end_speculation(spec, result.is_err());
827 result
828 }
829}
830
831fn is_reserved_import_alias(name: &str) -> bool {
836 matches!(
837 name,
838 "break"
840 | "case"
841 | "chan"
842 | "const"
843 | "continue"
844 | "default"
845 | "defer"
846 | "else"
847 | "fallthrough"
848 | "for"
849 | "func"
850 | "go"
851 | "goto"
852 | "if"
853 | "interface"
854 | "map"
855 | "package"
856 | "range"
857 | "return"
858 | "select"
859 | "struct"
860 | "switch"
861 | "type"
862 | "var"
863 | "nil"
865 | "iota"
866 | "true"
867 | "false"
868 | "bool"
870 | "byte"
871 | "complex64"
872 | "complex128"
873 | "error"
874 | "float32"
875 | "float64"
876 | "int"
877 | "int8"
878 | "int16"
879 | "int32"
880 | "int64"
881 | "rune"
882 | "string"
883 | "uint"
884 | "uint8"
885 | "uint16"
886 | "uint32"
887 | "uint64"
888 | "uintptr"
889 | "append"
891 | "cap"
892 | "clear"
893 | "close"
894 | "complex"
895 | "copy"
896 | "delete"
897 | "imag"
898 | "len"
899 | "make"
900 | "max"
901 | "min"
902 | "new"
903 | "panic"
904 | "print"
905 | "println"
906 | "real"
907 | "recover"
908 | "any"
910 | "comparable"
911 | "init"
913 | "main"
914 | "Option"
916 | "Result"
917 | "Comparable"
918 | "Ordered"
919 | "Some"
920 | "None"
921 | "Ok"
922 | "Err"
923 | "assert_type"
925 | "imaginary"
926 )
927}