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