1use crate::{
2 BindingId, ClassId, EntrypointId, ExprId, FunctionId, ModuleId, SourceId, Span, StmtId,
3};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
13pub struct HirAssembly {
14 pub modules: Vec<HirModule>,
15 pub functions: Vec<HirFunction>,
16 pub classes: Vec<HirClass>,
17 pub bindings: Vec<HirBinding>,
18 pub entrypoints: Vec<HirEntrypoint>,
19}
20
21#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
27pub struct HirModule {
28 pub id: ModuleId,
29 pub name: QualifiedName,
30 pub source_id: SourceId,
31 pub source_unit: SourceUnitKind,
32 pub imports: Vec<HirImport>,
33 pub top_level_functions: Vec<FunctionId>,
34 pub classes: Vec<ClassId>,
35 pub synthetic_entry_function: Option<FunctionId>,
36}
37
38#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
39pub enum SourceUnitKind {
40 ScriptFile,
41 FunctionFile,
42 ClassFile,
43 PackageFunctionFile,
44 ClassFolderMethodFile,
45 ReplSubmission,
46 NotebookCell,
47}
48
49#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
50pub struct HirEntrypoint {
51 pub id: EntrypointId,
52 pub name: Option<EntrypointName>,
53 pub target: FunctionId,
54 pub origin: EntrypointOrigin,
55 pub policy: EntrypointPolicy,
56}
57
58#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
59pub enum EntrypointOrigin {
60 ProjectDeclared,
61 SourcePath,
62 ReplSubmission,
63 NotebookCell,
64 HostSynthetic,
65}
66
67#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
68pub struct EntrypointPolicy {
69 pub workspace_export: WorkspaceExportPolicy,
70 pub top_level_await: bool,
71}
72
73#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
74pub enum WorkspaceExportPolicy {
75 ExportTopLevelBindings,
76 ReturnFunctionOutputs,
77 HostDefined,
78}
79
80#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
87pub struct HirFunction {
88 pub id: FunctionId,
89 pub module: ModuleId,
90 pub parent: Option<FunctionId>,
91 pub enclosing_class: Option<ClassId>,
92 pub name: FunctionName,
93 pub kind: FunctionKind,
94 pub params: Vec<BindingId>,
95 pub outputs: Vec<BindingId>,
96 pub abi: FunctionAbi,
97 pub argument_validations: Vec<FunctionArgumentValidation>,
98 pub locals: Vec<BindingId>,
99 pub captures: Vec<CapturedBinding>,
100 pub modifiers: FunctionModifiers,
101 pub body: HirBlock,
102 pub span: Span,
103}
104
105#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
106pub enum FunctionKind {
107 Named,
108 Anonymous,
109 SyntheticEntrypoint,
110 ClassMethod { is_static: bool },
111}
112
113#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
114pub struct FunctionModifiers {
115 pub isolated: bool,
116 pub is_async: bool,
117}
118
119#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
120pub struct FunctionAbi {
121 pub fixed_inputs: Vec<BindingId>,
122 pub varargin: Option<BindingId>,
123 pub fixed_outputs: Vec<BindingId>,
124 pub varargout: Option<BindingId>,
125 pub implicit_nargin: Option<BindingId>,
126 pub implicit_nargout: Option<BindingId>,
127}
128
129#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
130pub enum FunctionArgDim {
131 Any,
132 Exact(usize),
133}
134
135#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
136pub struct FunctionArgSizeSpec {
137 pub rows: FunctionArgDim,
138 pub cols: FunctionArgDim,
139}
140
141#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
142pub struct FunctionArgumentValidation {
143 pub binding: BindingId,
144 pub size: Option<FunctionArgSizeSpec>,
145 pub class_name: Option<String>,
146 pub validators: Vec<FunctionArgValidator>,
147 pub default_value: Option<FunctionArgDefaultValue>,
148}
149
150#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
151pub enum FunctionArgValidator {
152 Finite,
153 NumericOrLogical,
154 Text,
155 Nonempty,
156 ScalarOrEmpty,
157 Real,
158 Integer,
159 Positive,
160 Negative,
161 Nonnegative,
162 Nonzero,
163 Nonpositive,
164 GreaterThanOrEqual(f64),
165 LessThanOrEqual(f64),
166 GreaterThan(f64),
167 LessThan(f64),
168}
169
170#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
171pub enum FunctionArgDefaultValue {
172 Number(f64),
173 Bool(bool),
174 String(String),
175 EmptyArray,
176}
177
178#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
179pub struct CapturedBinding {
180 pub binding: BindingId,
181 pub from_function: FunctionId,
182}
183
184#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
189pub struct HirBinding {
190 pub id: BindingId,
191 pub owner: BindingOwner,
192 pub name: BindingName,
193 pub role: BindingRole,
194 pub storage: BindingStorage,
195 pub workspace_visibility: WorkspaceVisibility,
196 pub declared_span: Span,
197}
198
199#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
200pub enum BindingOwner {
201 Module(ModuleId),
202 Function(FunctionId),
203}
204
205#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
206pub enum BindingRole {
207 Parameter,
208 Output,
209 Local,
210 ExternalWorkspace,
211 ModuleBinding,
212 ImplicitAns,
213}
214
215#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
216pub enum BindingStorage {
217 Lexical,
218 Global,
219 Persistent,
220}
221
222#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
223pub enum WorkspaceVisibility {
224 Hidden,
225 TopLevel,
226 ModuleVisible,
227 ImplicitAns,
228}
229
230#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
231pub struct HirBlock {
232 pub statements: Vec<HirStmt>,
233}
234
235#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
236pub struct HirStmt {
237 pub id: StmtId,
238 pub kind: HirStmtKind,
239 pub span: Span,
240}
241
242impl HirStmt {
243 pub fn span(&self) -> Span {
244 self.span
245 }
246}
247
248#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
249pub enum HirStmtKind {
250 ExprStmt(HirExpr, bool),
251 Assign(HirPlace, HirExpr, bool),
252 MultiAssign(OutputTargetList, HirExpr, bool),
253 If {
254 cond: HirExpr,
255 then_body: HirBlock,
256 elseif_blocks: Vec<(HirExpr, HirBlock)>,
257 else_body: Option<HirBlock>,
258 },
259 While {
260 cond: HirExpr,
261 body: HirBlock,
262 },
263 For {
264 binding: BindingId,
265 range: HirExpr,
266 body: HirBlock,
267 },
268 Switch {
269 expr: HirExpr,
270 cases: Vec<(HirExpr, HirBlock)>,
271 otherwise: Option<HirBlock>,
272 },
273 TryCatch {
274 try_body: HirBlock,
275 catch_binding: Option<BindingId>,
276 catch_body: HirBlock,
277 },
278 Global(Vec<BindingId>),
279 Persistent(Vec<BindingId>),
280 Break,
281 Continue,
282 Return,
283 Import(HirImport),
284}
285
286#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
287pub struct HirExpr {
288 pub id: ExprId,
289 pub kind: HirExprKind,
290 pub span: Span,
291}
292
293impl HirExpr {
294 pub fn span(&self) -> Span {
295 self.span
296 }
297}
298
299#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
300pub enum HirExprKind {
301 Number(String),
302 String(StringLiteral),
303 Constant(SymbolName),
304 Binding(BindingId),
305 Unary(OperatorKind, Box<HirExpr>),
306 Binary(Box<HirExpr>, OperatorKind, Box<HirExpr>),
307 Tensor(Vec<Vec<HirExpr>>),
308 Cell(Vec<Vec<HirExpr>>),
309 StructLiteral(Vec<(MemberName, HirExpr)>),
310 ObjectLiteral {
311 class_name: QualifiedName,
312 fields: Vec<(MemberName, HirExpr)>,
313 },
314 Range(Box<HirExpr>, Option<Box<HirExpr>>, Box<HirExpr>),
315 Colon,
316 End,
317 Index(Box<HirExpr>, IndexingSemantics),
318 Member(Box<HirExpr>, MemberName),
319 MemberDynamic(Box<HirExpr>, Box<HirExpr>),
320 WorkspaceFirstStaticProperty {
321 workspace_name: SymbolName,
322 class_name: String,
323 property: MemberName,
324 },
325 Call(HirCall),
326 CommandCall(HirCommandCall),
327 FunctionHandle(FunctionHandleTarget),
328 AnonymousFunction(FunctionId),
329 MetaClass(QualifiedName),
330 Await(Box<HirExpr>),
331 Spawn(Box<HirExpr>),
332}
333
334#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
335pub enum HirPlace {
336 Binding(BindingId),
337 Member(Box<HirExpr>, MemberName),
338 MemberDynamic(Box<HirExpr>, Box<HirExpr>),
339 Index(Box<HirExpr>, IndexingSemantics),
340 IndexCell(Box<HirExpr>, IndexingSemantics),
341}
342
343#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
348pub struct HirCall {
349 pub callee: HirCallableRef,
350 pub args: Vec<HirExpr>,
351 pub syntax: CallSyntax,
352 pub requested_outputs: RequestedOutputCount,
353 #[serde(default)]
354 pub workspace_first_name: Option<SymbolName>,
355 #[serde(default)]
356 pub bare_identifier: bool,
357}
358
359#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
360pub enum HirCallableRef {
361 Function(FunctionId),
362 ExternalFunction {
363 function: FunctionId,
364 display_name: String,
365 },
366 Builtin(BuiltinId),
367 Imported(DefPath),
368 SuperConstructor {
369 current_class: SymbolName,
370 super_class: QualifiedName,
371 },
372 SuperMethod {
373 current_class: SymbolName,
374 super_class: QualifiedName,
375 method: SymbolName,
376 },
377 DynamicExpr(Box<HirExpr>),
378 Unresolved(QualifiedName),
379}
380
381impl HirCallableRef {
382 pub fn is_feval_builtin_like(&self) -> bool {
383 match self {
384 HirCallableRef::Builtin(id) => id.0 == FEVAL_BUILTIN_NAME,
385 HirCallableRef::Unresolved(name) if name.0.len() == 1 => {
386 name.0[0].0 == FEVAL_BUILTIN_NAME
387 }
388 _ => false,
389 }
390 }
391
392 pub fn identity(&self) -> Option<CallableIdentity> {
393 match self {
394 HirCallableRef::Function(function) => Some(CallableIdentity::BoundFunction(*function)),
395 HirCallableRef::ExternalFunction {
396 function,
397 display_name,
398 } => Some(CallableIdentity::ExternalFunction {
399 function: *function,
400 display_name: display_name.clone(),
401 }),
402 HirCallableRef::Builtin(builtin) => Some(CallableIdentity::Builtin(builtin.clone())),
403 HirCallableRef::Imported(path) => Some(CallableIdentity::Imported(path.clone())),
404 HirCallableRef::SuperConstructor { .. } | HirCallableRef::SuperMethod { .. } => None,
405 HirCallableRef::DynamicExpr(_) => None,
406 HirCallableRef::Unresolved(name) => {
407 if name.0.len() == 1 {
408 Some(CallableIdentity::DynamicName(name.0[0].clone()))
409 } else {
410 Some(CallableIdentity::ExternalName(name.clone()))
411 }
412 }
413 }
414 }
415}
416
417#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
418pub enum CallableIdentity {
419 BoundFunction(FunctionId),
420 ExternalFunction {
421 function: FunctionId,
422 display_name: String,
423 },
424 Builtin(BuiltinId),
425 Imported(DefPath),
426 Method(MethodId),
427 AnonymousFunction(FunctionId),
428 DynamicName(SymbolName),
429 ExternalName(QualifiedName),
430}
431
432impl CallableIdentity {
433 pub fn display_name(&self) -> Option<String> {
434 match self {
435 CallableIdentity::BoundFunction(_) | CallableIdentity::AnonymousFunction(_) => None,
436 CallableIdentity::ExternalFunction { display_name, .. } => {
437 (!display_name.is_empty()).then_some(display_name.clone())
438 }
439 CallableIdentity::Builtin(id) => (!id.0.is_empty()).then_some(id.0.clone()),
440 CallableIdentity::Imported(path) => path.module.display_name(),
441 CallableIdentity::Method(id) => (!id.0.is_empty()).then_some(id.0.clone()),
442 CallableIdentity::DynamicName(name) => (!name.0.is_empty()).then_some(name.0.clone()),
443 CallableIdentity::ExternalName(name) => name.display_name(),
444 }
445 }
446}
447
448#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize)]
449pub enum CallableFallbackPolicy {
450 None,
451 RuntimeNameResolution,
452 ObjectDispatch,
453 ExternalBoundary,
454}
455
456impl CallableFallbackPolicy {
457 fn is_well_formed_external_name(name: &QualifiedName) -> bool {
458 name.0.len() > 1 && name.0.iter().all(|segment| !segment.0.trim().is_empty())
459 }
460
461 fn is_well_formed_imported_path(path: &DefPath) -> bool {
462 let Some(module_name) = path.module.display_name() else {
463 return false;
464 };
465 let Some(last_item) = path.item.last() else {
466 return false;
467 };
468 let item_name = last_item.display_name();
469 if item_name.trim().is_empty() {
470 return false;
471 }
472 let Some(last_module_segment) = path.module.0.last() else {
473 return false;
474 };
475 if last_module_segment.0.trim().is_empty() {
476 return false;
477 }
478 let _ = module_name;
481 last_module_segment.0 == item_name
482 }
483
484 pub fn allows_runtime_name_resolution(self) -> bool {
485 matches!(self, CallableFallbackPolicy::RuntimeNameResolution)
486 }
487
488 pub fn allows_semantic_name_resolution_for(self, identity: &CallableIdentity) -> bool {
489 match identity {
490 CallableIdentity::DynamicName(SymbolName(name))
491 | CallableIdentity::Method(MethodId(name)) => {
492 self.allows_runtime_name_resolution() && !name.trim().is_empty()
493 }
494 CallableIdentity::Imported(path) => {
495 self.allows_runtime_name_resolution() && Self::is_well_formed_imported_path(path)
496 }
497 CallableIdentity::ExternalName(name) => {
498 matches!(self, CallableFallbackPolicy::ExternalBoundary)
499 && Self::is_well_formed_external_name(name)
500 }
501 _ => false,
502 }
503 }
504
505 pub fn allows_vm_name_fallback_for(self, identity: &CallableIdentity) -> bool {
506 match identity {
507 CallableIdentity::DynamicName(SymbolName(name)) => {
508 self.allows_runtime_name_resolution() && !name.trim().is_empty()
509 }
510 CallableIdentity::Imported(path) => {
511 self.allows_runtime_name_resolution() && Self::is_well_formed_imported_path(path)
512 }
513 CallableIdentity::ExternalName(name) => {
514 matches!(self, CallableFallbackPolicy::ExternalBoundary)
515 && Self::is_well_formed_external_name(name)
516 }
517 _ => false,
518 }
519 }
520
521 pub fn resolution_name_for(self, identity: &CallableIdentity) -> Option<String> {
522 if !self.allows_semantic_name_resolution_for(identity) {
523 return None;
524 }
525
526 match identity {
527 CallableIdentity::DynamicName(SymbolName(name))
528 | CallableIdentity::Method(MethodId(name)) => {
529 let trimmed = name.trim();
530 (!trimmed.is_empty()).then_some(trimmed.to_string())
531 }
532 CallableIdentity::Imported(path) => path.module.display_name(),
533 CallableIdentity::ExternalName(name) if Self::is_well_formed_external_name(name) => {
534 Some(
535 name.0
536 .iter()
537 .map(|segment| segment.0.as_str())
538 .collect::<Vec<_>>()
539 .join("."),
540 )
541 }
542 _ => None,
543 }
544 }
545
546 pub fn vm_fallback_name_for(self, identity: &CallableIdentity) -> Option<String> {
547 if !self.allows_vm_name_fallback_for(identity) {
548 return None;
549 }
550
551 match identity {
552 CallableIdentity::DynamicName(SymbolName(name)) => {
553 let trimmed = name.trim();
554 (!trimmed.is_empty()).then_some(trimmed.to_string())
555 }
556 CallableIdentity::Imported(path) => path.module.display_name(),
557 CallableIdentity::ExternalName(name) if Self::is_well_formed_external_name(name) => {
558 Some(
559 name.0
560 .iter()
561 .map(|segment| segment.0.as_str())
562 .collect::<Vec<_>>()
563 .join("."),
564 )
565 }
566 _ => None,
567 }
568 }
569
570 pub fn supports_vm_static_call(self) -> bool {
571 matches!(
572 self,
573 CallableFallbackPolicy::RuntimeNameResolution
574 | CallableFallbackPolicy::ExternalBoundary
575 )
576 }
577
578 pub fn supports_vm_method_or_member_call(self) -> bool {
579 matches!(
580 self,
581 CallableFallbackPolicy::RuntimeNameResolution | CallableFallbackPolicy::ObjectDispatch
582 )
583 }
584
585 pub fn post_object_dispatch(self) -> Self {
586 match self {
587 CallableFallbackPolicy::ObjectDispatch => CallableFallbackPolicy::RuntimeNameResolution,
588 other => other,
589 }
590 }
591}
592
593pub const FEVAL_BUILTIN_NAME: &str = "feval";
594pub const EVAL_BUILTIN_NAME: &str = "eval";
595pub const EVALIN_BUILTIN_NAME: &str = "evalin";
596pub const ASSIGNIN_BUILTIN_NAME: &str = "assignin";
597pub const RUN_BUILTIN_NAME: &str = "run";
598pub const NARGIN_BUILTIN_NAME: &str = "nargin";
599pub const NARGOUT_BUILTIN_NAME: &str = "nargout";
600pub const NARGINCHK_BUILTIN_NAME: &str = "narginchk";
601pub const NARGOUTCHK_BUILTIN_NAME: &str = "nargoutchk";
602pub const AWAIT_EXTENSION_NAME: &str = "await";
603pub const SPAWN_EXTENSION_NAME: &str = "spawn";
604pub const TEST_CLASS_REGISTRATION_BUILTIN_NAME: &str = "__register_test_classes";
605pub const DISCARD_OUTPUT_NAME: &str = "~";
606
607#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
608pub enum CallSyntax {
609 Plain,
610 Method,
611 DottedInvoke,
612 Command,
613}
614
615#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
616pub struct HirCommandCall {
617 pub command: HirCallableRef,
618 pub args: Vec<CommandArgument>,
619}
620
621#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
622pub enum CommandArgument {
623 Word(SymbolName),
624 StringLiteral(StringLiteral),
625}
626
627#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
628pub struct HirImport {
629 pub path: QualifiedName,
630 pub wildcard: bool,
631 pub span: Span,
632}
633
634#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
639pub struct HirClass {
640 pub id: ClassId,
641 pub module: ModuleId,
642 pub name: QualifiedName,
643 pub super_class: Option<ClassId>,
644 pub kind: ClassKind,
645 pub is_sealed: bool,
646 pub is_abstract: bool,
647 pub properties: Vec<ClassProperty>,
648 pub methods: Vec<ClassMethod>,
649 pub events: Vec<ClassEvent>,
650 pub enumerations: Vec<ClassEnumeration>,
651 pub arguments: Vec<ClassArgumentBlock>,
652 pub span: Span,
653}
654
655#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
656pub enum ClassKind {
657 Value,
658 Handle,
659}
660
661#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
662pub struct ClassProperty {
663 pub name: MemberName,
664 pub attributes: PropertyAttributes,
665 pub default: Option<HirExpr>,
666 pub span: Span,
667}
668
669#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
670pub struct ClassMethod {
671 pub function: FunctionId,
672 pub name: MethodName,
673 pub is_static: bool,
674 pub attributes: MethodAttributes,
675 pub span: Span,
676}
677
678#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
679pub struct ClassEvent {
680 pub name: SymbolName,
681 pub span: Span,
682}
683
684#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
685pub struct ClassEnumeration {
686 pub name: SymbolName,
687 pub span: Span,
688}
689
690#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
691pub struct ClassArgumentBlock {
692 pub span: Span,
693}
694
695#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
696pub struct PropertyAttributes {
697 pub is_static: bool,
698 pub is_constant: bool,
699 pub is_dependent: bool,
700 pub is_transient: bool,
701 pub is_hidden: bool,
702 pub access: MemberAccess,
703 pub get_access: MemberAccess,
704 pub set_access: MemberAccess,
705}
706
707#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
708pub struct MethodAttributes {
709 pub access: MemberAccess,
710 pub is_hidden: bool,
711 pub is_abstract: bool,
712 pub is_sealed: bool,
713}
714
715#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
716pub enum MemberAccess {
717 #[default]
718 Public,
719 Private,
720 Protected,
721}
722
723#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
724pub struct OutputTargetList {
725 pub requested_outputs: RequestedOutputCount,
726 pub targets: Vec<OutputTarget>,
727}
728
729#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
730pub enum OutputTarget {
731 Place(HirPlace),
732 Discard,
733}
734
735#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
736pub enum RequestedOutputCount {
737 Zero,
738 One,
739 Exactly(usize),
740 CurrentFunctionNargout,
741}
742
743impl RequestedOutputCount {
744 pub fn fixed_count(&self) -> usize {
745 match self {
746 RequestedOutputCount::Zero => 0,
747 RequestedOutputCount::One => 1,
748 RequestedOutputCount::Exactly(count) => *count,
749 RequestedOutputCount::CurrentFunctionNargout => 1,
750 }
751 }
752}
753
754#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
755pub enum IndexKind {
756 Paren,
757 Brace,
758}
759
760#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
761pub enum IndexComponent {
762 Colon,
763 End { dim: Option<usize>, offset: isize },
764 Expr(HirExpr),
765 Logical(HirExpr),
766}
767
768#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
769pub struct IndexingSemantics {
770 pub kind: IndexKind,
771 pub components: Vec<IndexComponent>,
772 pub result_context: IndexResultContext,
773}
774
775#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
776pub enum IndexResultContext {
777 ReadSingle,
778 ReadCommaList,
779 AssignmentTarget,
780 DeletionTarget,
781 FunctionArgumentExpansion,
782}
783
784#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
785pub enum FunctionHandleTarget {
786 Function(FunctionId),
787 ExternalFunction {
788 function: FunctionId,
789 display_name: String,
790 },
791 Builtin(BuiltinId),
792 Anonymous(FunctionId),
793 DefPath(DefPath),
794 DynamicName(SymbolName),
795}
796
797impl FunctionHandleTarget {
798 pub fn identity(&self) -> CallableIdentity {
799 match self {
800 FunctionHandleTarget::Function(function) => CallableIdentity::BoundFunction(*function),
801 FunctionHandleTarget::ExternalFunction {
802 function,
803 display_name,
804 } => CallableIdentity::ExternalFunction {
805 function: *function,
806 display_name: display_name.clone(),
807 },
808 FunctionHandleTarget::Builtin(builtin) => CallableIdentity::Builtin(builtin.clone()),
809 FunctionHandleTarget::Anonymous(function) => {
810 CallableIdentity::AnonymousFunction(*function)
811 }
812 FunctionHandleTarget::DefPath(path) => CallableIdentity::Imported(path.clone()),
813 FunctionHandleTarget::DynamicName(name) => CallableIdentity::DynamicName(name.clone()),
814 }
815 }
816}
817
818#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
819pub enum WorkspaceEffect {
820 None,
821 ReadsWorkspace,
822 CreatesBinding,
823 ClearsBinding,
824 ClearsFunctionCache,
825 MutatesGlobal,
826 MutatesPersistent,
827 LoadsExternalBindings,
828 DynamicEval,
829}
830
831#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
832pub enum EnvironmentEffect {
833 PathMutation,
834 WorkingDirectoryMutation,
835 FunctionCacheInvalidation,
836 DynamicLookupInvalidation,
837}
838
839#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
840pub enum EmptyArrayRole {
841 EmptyValue,
842 ConcatenationIdentity,
843 DeletionMarker,
844}
845
846#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
847pub enum ExpansionSemantics {
848 ExactShape,
849 ScalarExpansion,
850 ImplicitExpansion,
851}
852
853#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
854pub enum OperatorKind {
855 UnaryPlus,
856 UnaryMinus,
857 Not,
858 Add,
859 Subtract,
860 MatrixMultiply,
861 ElementwiseMultiply,
862 MatrixPower,
863 ElementwisePower,
864 Mldivide,
865 Mrdivide,
866 ElementwiseDivide,
867 ElementwiseLeftDivide,
868 Equal,
869 NotEqual,
870 Less,
871 LessEqual,
872 Greater,
873 GreaterEqual,
874 ShortCircuitAnd,
875 ShortCircuitOr,
876 ElementwiseAnd,
877 ElementwiseOr,
878 Transpose,
879 ConjugateTranspose,
880}
881
882#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
883pub enum NumericClass {
884 Double,
885 Single,
886 Int8,
887 UInt8,
888 Int16,
889 UInt16,
890 Int32,
891 UInt32,
892 Int64,
893 UInt64,
894}
895
896#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
897pub enum ValueFlowFact {
898 NoValue,
899 Single(TypeFact),
900 CommaList(Vec<TypeFact>),
901 UnknownList,
902}
903
904#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
905pub enum PlaceMutationKind {
906 BindOrAssign,
907 IndexedAssign,
908 CellAssign,
909 MemberAssign,
910 Delete,
911}
912
913#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
914pub struct PlaceMutation {
915 pub place: HirPlace,
916 pub kind: PlaceMutationKind,
917 pub creation_policy: AssignmentCreationPolicy,
918 pub shape_policy: AssignmentShapePolicy,
919}
920
921#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
922pub enum AssignmentCreationPolicy {
923 ExistingOnly,
924 CreateBinding,
925 CreateArrayByIndex,
926 CreateStructFieldPath,
927 Overloaded,
928}
929
930#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
931pub enum AssignmentShapePolicy {
932 Exact,
933 ScalarExpansion,
934 MatlabCompatible,
935 Overloaded,
936}
937
938#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
939pub enum ReferenceKind {
940 Binding(BindingId),
941 Function(FunctionId),
942 Builtin(BuiltinId),
943 Class(ClassId),
944 Package(QualifiedName),
945 Imported(DefPath),
946 RuntimeClass(QualifiedName),
947 Dynamic,
948 Unresolved,
949}
950
951#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
952pub enum CallKind {
953 DirectFunction(FunctionId),
954 Builtin(BuiltinId),
955 Constructor(ClassId),
956 StaticMethod {
957 class: ClassId,
958 method: MethodId,
959 },
960 InstanceMethod {
961 receiver: Box<HirExpr>,
962 method: MethodId,
963 },
964 PackageFunction(DefPath),
965 FunctionHandle,
966 Dynamic,
967 OverloadedOperator,
968 OverloadedIndexing,
969}
970
971#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
972pub struct HirIndex {
973 pub bindings: Vec<BindingResolution>,
974 pub functions: Vec<FunctionResolution>,
975 pub classes: Vec<ClassResolution>,
976 pub imports: Vec<ImportResolution>,
977 pub references: Vec<ReferenceResolution>,
978 pub calls: Vec<CallResolution>,
979 pub mutations: Vec<PlaceMutation>,
980}
981
982#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
983pub struct BindingResolution {
984 pub name: BindingName,
985 pub binding: BindingId,
986 pub owner: BindingOwner,
987 pub span: Span,
988}
989
990#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
991pub struct FunctionResolution {
992 pub name: FunctionName,
993 pub function: FunctionId,
994 pub parent: Option<FunctionId>,
995 pub span: Span,
996}
997
998#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
999pub struct ClassResolution {
1000 pub name: QualifiedName,
1001 pub class: ClassId,
1002 pub span: Span,
1003}
1004
1005#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1006pub struct ImportResolution {
1007 pub import: HirImport,
1008}
1009
1010#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1011pub struct ReferenceResolution {
1012 pub name: SymbolName,
1013 pub kind: ReferenceKind,
1014 pub span: Span,
1015}
1016
1017#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1018pub struct CallResolution {
1019 pub name: QualifiedName,
1020 pub callee: HirCallableRef,
1021 pub kind: CallKind,
1022 pub requested_outputs: RequestedOutputCount,
1023 pub span: Span,
1024}
1025
1026#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1027pub enum SpawnSafetyFact {
1028 SpawnSafe,
1029 RequiresIsolation,
1030 NotSpawnSafe { reason: SpawnSafetyReason },
1031}
1032
1033#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1034pub enum SpawnSafetyReason {
1035 MutableLexicalCapture,
1036 NonSendableRuntimeHandle,
1037 UnsynchronizedSharedMutation,
1038 UnknownDynamicCapture,
1039}
1040
1041#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1042pub enum AsyncValueFact {
1043 Future(FutureFact),
1044 TaskHandle(TaskHandleFact),
1045}
1046
1047#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1048pub struct FutureFact {
1049 pub output: Box<TypeFact>,
1050 pub state: FutureStateFact,
1051}
1052
1053#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1054pub enum FutureStateFact {
1055 Lazy,
1056 Awaited,
1057 Unknown,
1058}
1059
1060#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1061pub struct TaskHandleFact {
1062 pub output: Box<TypeFact>,
1063 pub spawn_safety: SpawnSafetyFact,
1064}
1065
1066#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1067pub enum TypeFact {
1068 Never,
1069 Unknown,
1070 Logical,
1071 Numeric {
1072 class: NumericClass,
1073 domain: NumericDomain,
1074 },
1075 Tensor(TensorTypeFact),
1076 String,
1077 CharArray,
1078 Cell,
1079 Struct,
1080 ClassInstance(ClassId),
1081 ClassRef(ClassId),
1082 Function(FunctionId),
1083}
1084
1085#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1086pub struct TensorTypeFact {
1087 pub element: TensorElementDomainFact,
1088 pub shape: ShapeFact,
1089}
1090
1091#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1092pub enum TensorElementDomainFact {
1093 Unknown,
1094 Logical,
1095 Numeric {
1096 class: NumericClass,
1097 domain: NumericDomain,
1098 },
1099 Char,
1100 Object(ClassId),
1101}
1102
1103#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1104pub enum NumericDomain {
1105 Real,
1106 Complex,
1107}
1108
1109#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1110pub enum ShapeFact {
1111 Unreachable,
1112 Unknown,
1113 Scalar,
1114 Ranked { rank: usize },
1115 Shaped { dims: Vec<DimFact> },
1116}
1117
1118#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1119pub enum DimFact {
1120 Known(usize),
1121 Symbolic(DimSymbol),
1122 Unknown,
1123}
1124
1125#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1126pub struct DimSymbol(pub String);
1127
1128#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1134pub struct DefPath {
1135 pub package: PackageName,
1136 pub module: QualifiedName,
1137 pub item: Vec<DefPathSegment>,
1138}
1139
1140impl DefPath {
1141 pub fn display_name(&self) -> Option<String> {
1142 self.item.last().map(DefPathSegment::display_name)
1143 }
1144}
1145
1146#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1147pub enum DefPathSegment {
1148 Function(SymbolName),
1149}
1150
1151impl DefPathSegment {
1152 pub fn display_name(&self) -> String {
1153 match self {
1154 DefPathSegment::Function(name) => name.0.clone(),
1155 }
1156 }
1157}
1158
1159#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1160pub struct QualifiedName(pub Vec<SymbolName>);
1161
1162impl QualifiedName {
1163 pub fn display_name(&self) -> Option<String> {
1164 if self.0.is_empty() || self.0.iter().any(|segment| segment.0.is_empty()) {
1165 None
1166 } else {
1167 Some(
1168 self.0
1169 .iter()
1170 .map(|segment| segment.0.as_str())
1171 .collect::<Vec<_>>()
1172 .join("."),
1173 )
1174 }
1175 }
1176}
1177
1178#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1179pub struct SymbolName(pub String);
1180
1181#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1182pub struct BindingName(pub String);
1183
1184#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1185pub struct FunctionName(pub String);
1186
1187#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1188pub struct EntrypointName(pub String);
1189
1190#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1191pub struct MemberName(pub String);
1192
1193#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1194pub struct MethodName(pub String);
1195
1196#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1197pub struct PackageName(pub String);
1198
1199#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1200pub struct BuiltinId(pub String);
1201
1202#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1203pub struct MethodId(pub String);
1204
1205#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1206pub struct StringLiteral(pub String);
1207
1208#[derive(Debug, Clone)]
1209pub struct LoweringResult {
1210 pub assembly: HirAssembly,
1211 pub hir_index: HirIndex,
1212}
1213
1214#[cfg(test)]
1215mod tests {
1216 use super::*;
1217
1218 fn span() -> Span {
1219 Span { start: 0, end: 0 }
1220 }
1221
1222 #[test]
1223 fn assembly_owns_core_items() {
1224 let module = ModuleId(0);
1225 let function = FunctionId(0);
1226 let binding = BindingId(0);
1227 let entrypoint = EntrypointId(0);
1228
1229 let assembly = HirAssembly {
1230 modules: vec![HirModule {
1231 id: module,
1232 name: QualifiedName(vec![SymbolName("demo".into())]),
1233 source_id: SourceId(0),
1234 source_unit: SourceUnitKind::ScriptFile,
1235 imports: vec![],
1236 top_level_functions: vec![],
1237 classes: vec![],
1238 synthetic_entry_function: Some(function),
1239 }],
1240 functions: vec![HirFunction {
1241 id: function,
1242 module,
1243 parent: None,
1244 enclosing_class: None,
1245 name: FunctionName("demo_entry".into()),
1246 kind: FunctionKind::SyntheticEntrypoint,
1247 params: vec![],
1248 outputs: vec![],
1249 abi: FunctionAbi {
1250 fixed_inputs: vec![],
1251 varargin: None,
1252 fixed_outputs: vec![],
1253 varargout: None,
1254 implicit_nargin: None,
1255 implicit_nargout: None,
1256 },
1257 locals: vec![binding],
1258 captures: vec![],
1259 argument_validations: vec![],
1260 modifiers: FunctionModifiers::default(),
1261 body: HirBlock { statements: vec![] },
1262 span: span(),
1263 }],
1264 classes: vec![],
1265 bindings: vec![HirBinding {
1266 id: binding,
1267 owner: BindingOwner::Function(function),
1268 name: BindingName("x".into()),
1269 role: BindingRole::Local,
1270 storage: BindingStorage::Lexical,
1271 workspace_visibility: WorkspaceVisibility::TopLevel,
1272 declared_span: span(),
1273 }],
1274 entrypoints: vec![HirEntrypoint {
1275 id: entrypoint,
1276 name: Some(EntrypointName("demo".into())),
1277 target: function,
1278 origin: EntrypointOrigin::SourcePath,
1279 policy: EntrypointPolicy {
1280 workspace_export: WorkspaceExportPolicy::ExportTopLevelBindings,
1281 top_level_await: false,
1282 },
1283 }],
1284 };
1285
1286 assert_eq!(assembly.modules[0].synthetic_entry_function, Some(function));
1287 assert_eq!(assembly.entrypoints[0].target, function);
1288 assert_eq!(assembly.functions[0].locals, vec![binding]);
1289 assert!(matches!(
1290 assembly.bindings[0].workspace_visibility,
1291 WorkspaceVisibility::TopLevel
1292 ));
1293 }
1294
1295 #[test]
1296 fn function_abi_can_reuse_shared_input_output_binding() {
1297 let binding = BindingId(0);
1298 let abi = FunctionAbi {
1299 fixed_inputs: vec![binding],
1300 varargin: None,
1301 fixed_outputs: vec![binding],
1302 varargout: None,
1303 implicit_nargin: Some(BindingId(1)),
1304 implicit_nargout: Some(BindingId(2)),
1305 };
1306
1307 assert_eq!(abi.fixed_inputs[0], abi.fixed_outputs[0]);
1308 assert_eq!(abi.implicit_nargin, Some(BindingId(1)));
1309 assert_eq!(abi.implicit_nargout, Some(BindingId(2)));
1310 }
1311
1312 #[test]
1313 fn captures_reference_original_binding_identity() {
1314 let parent = FunctionId(0);
1315 let child = FunctionId(1);
1316 let binding = BindingId(0);
1317
1318 let capture = CapturedBinding {
1319 binding,
1320 from_function: parent,
1321 };
1322
1323 let child_function = HirFunction {
1324 id: child,
1325 module: ModuleId(0),
1326 parent: Some(parent),
1327 enclosing_class: None,
1328 name: FunctionName("inner".into()),
1329 kind: FunctionKind::Named,
1330 params: vec![],
1331 outputs: vec![],
1332 abi: FunctionAbi {
1333 fixed_inputs: vec![],
1334 varargin: None,
1335 fixed_outputs: vec![],
1336 varargout: None,
1337 implicit_nargin: None,
1338 implicit_nargout: None,
1339 },
1340 locals: vec![],
1341 captures: vec![capture],
1342 argument_validations: vec![],
1343 modifiers: FunctionModifiers::default(),
1344 body: HirBlock { statements: vec![] },
1345 span: span(),
1346 };
1347
1348 assert_eq!(child_function.parent, Some(parent));
1349 assert_eq!(child_function.captures[0].binding, binding);
1350 assert_eq!(child_function.captures[0].from_function, parent);
1351 }
1352
1353 #[test]
1354 fn facts_capture_value_flow_and_mutation_context() {
1355 let binding = BindingId(0);
1356 let mutation = PlaceMutation {
1357 place: HirPlace::Binding(binding),
1358 kind: PlaceMutationKind::BindOrAssign,
1359 creation_policy: AssignmentCreationPolicy::CreateBinding,
1360 shape_policy: AssignmentShapePolicy::MatlabCompatible,
1361 };
1362 let value = ValueFlowFact::Single(TypeFact::Tensor(TensorTypeFact {
1363 element: TensorElementDomainFact::Numeric {
1364 class: NumericClass::Double,
1365 domain: NumericDomain::Real,
1366 },
1367 shape: ShapeFact::Shaped {
1368 dims: vec![DimFact::Known(1), DimFact::Symbolic(DimSymbol("n".into()))],
1369 },
1370 }));
1371
1372 assert!(matches!(mutation.place, HirPlace::Binding(id) if id == binding));
1373 assert!(matches!(
1374 value,
1375 ValueFlowFact::Single(TypeFact::Tensor(TensorTypeFact {
1376 shape: ShapeFact::Shaped { .. },
1377 ..
1378 }))
1379 ));
1380 }
1381
1382 #[test]
1383 fn def_path_is_distinct_from_local_table_ids() {
1384 let function_id = FunctionId(0);
1385 let path = DefPath {
1386 package: PackageName("pkg".into()),
1387 module: QualifiedName(vec![SymbolName("pkg".into()), SymbolName("demo".into())]),
1388 item: vec![DefPathSegment::Function(SymbolName("f".into()))],
1389 };
1390
1391 assert_eq!(function_id, FunctionId(0));
1392 assert_eq!(path.package.0, "pkg");
1393 assert!(matches!(path.item[0], DefPathSegment::Function(_)));
1394 }
1395
1396 #[test]
1397 fn imported_callable_identity_prefers_qualified_display_name() {
1398 let path = DefPath {
1399 package: PackageName("pkg".into()),
1400 module: QualifiedName(vec![
1401 SymbolName("pkg".into()),
1402 SymbolName("demo".into()),
1403 SymbolName("f".into()),
1404 ]),
1405 item: vec![DefPathSegment::Function(SymbolName("f".into()))],
1406 };
1407 let identity = CallableIdentity::Imported(path);
1408 assert_eq!(identity.display_name().as_deref(), Some("pkg.demo.f"));
1409
1410 let empty_module_path = DefPath {
1411 package: PackageName("pkg".into()),
1412 module: QualifiedName(vec![]),
1413 item: vec![DefPathSegment::Function(SymbolName("f".into()))],
1414 };
1415 let empty_module_identity = CallableIdentity::Imported(empty_module_path);
1416 assert_eq!(empty_module_identity.display_name(), None);
1417 }
1418
1419 #[test]
1420 fn qualified_name_display_name_rejects_empty_segments() {
1421 let malformed = QualifiedName(vec![
1422 SymbolName("pkg".into()),
1423 SymbolName("".into()),
1424 SymbolName("remote".into()),
1425 ]);
1426 assert_eq!(malformed.display_name(), None);
1427 }
1428
1429 #[test]
1430 fn callable_identity_display_name_rejects_empty_name_fields() {
1431 assert_eq!(
1432 CallableIdentity::Builtin(BuiltinId(String::new())).display_name(),
1433 None
1434 );
1435 assert_eq!(
1436 CallableIdentity::Method(MethodId(String::new())).display_name(),
1437 None
1438 );
1439 assert_eq!(
1440 CallableIdentity::DynamicName(SymbolName(String::new())).display_name(),
1441 None
1442 );
1443 }
1444
1445 #[test]
1446 fn async_facts_distinguish_lazy_futures_from_spawned_tasks() {
1447 let future = AsyncValueFact::Future(FutureFact {
1448 output: Box::new(TypeFact::Unknown),
1449 state: FutureStateFact::Lazy,
1450 });
1451 let task = AsyncValueFact::TaskHandle(TaskHandleFact {
1452 output: Box::new(TypeFact::Unknown),
1453 spawn_safety: SpawnSafetyFact::SpawnSafe,
1454 });
1455
1456 assert!(matches!(
1457 future,
1458 AsyncValueFact::Future(FutureFact {
1459 state: FutureStateFact::Lazy,
1460 ..
1461 })
1462 ));
1463 assert!(matches!(
1464 task,
1465 AsyncValueFact::TaskHandle(TaskHandleFact {
1466 spawn_safety: SpawnSafetyFact::SpawnSafe,
1467 ..
1468 })
1469 ));
1470 }
1471
1472 #[test]
1473 fn callable_name_fallback_policies_require_well_formed_external_names() {
1474 let dynamic = CallableIdentity::DynamicName(SymbolName("sqrt".into()));
1475 let imported = CallableIdentity::Imported(DefPath {
1476 package: PackageName("Point".into()),
1477 module: QualifiedName(vec![
1478 SymbolName("Point".into()),
1479 SymbolName("origin".into()),
1480 ]),
1481 item: vec![DefPathSegment::Function(SymbolName("origin".into()))],
1482 });
1483 let imported_missing_item = CallableIdentity::Imported(DefPath {
1484 package: PackageName("Point".into()),
1485 module: QualifiedName(vec![
1486 SymbolName("Point".into()),
1487 SymbolName("origin".into()),
1488 ]),
1489 item: vec![],
1490 });
1491 let imported_empty_item_name = CallableIdentity::Imported(DefPath {
1492 package: PackageName("Point".into()),
1493 module: QualifiedName(vec![
1494 SymbolName("Point".into()),
1495 SymbolName("origin".into()),
1496 ]),
1497 item: vec![DefPathSegment::Function(SymbolName("".into()))],
1498 });
1499 let imported_mismatched_item = CallableIdentity::Imported(DefPath {
1500 package: PackageName("Point".into()),
1501 module: QualifiedName(vec![
1502 SymbolName("Point".into()),
1503 SymbolName("origin".into()),
1504 ]),
1505 item: vec![DefPathSegment::Function(SymbolName("different".into()))],
1506 });
1507 let method = CallableIdentity::Method(MethodId("deal".into()));
1508 let whitespace_dynamic = CallableIdentity::DynamicName(SymbolName(" ".into()));
1509 let whitespace_method = CallableIdentity::Method(MethodId(" ".into()));
1510 let single_external =
1511 CallableIdentity::ExternalName(QualifiedName(vec![SymbolName("sqrt".into())]));
1512 let whitespace_external = CallableIdentity::ExternalName(QualifiedName(vec![
1513 SymbolName("OverIdx".into()),
1514 SymbolName(" ".into()),
1515 ]));
1516 let qualified_external = CallableIdentity::ExternalName(QualifiedName(vec![
1517 SymbolName("OverIdx".into()),
1518 SymbolName("plus".into()),
1519 ]));
1520 let malformed_external = CallableIdentity::ExternalName(QualifiedName(vec![
1521 SymbolName("OverIdx".into()),
1522 SymbolName("".into()),
1523 SymbolName("plus".into()),
1524 ]));
1525
1526 assert!(CallableFallbackPolicy::RuntimeNameResolution
1527 .allows_semantic_name_resolution_for(&dynamic));
1528 assert!(CallableFallbackPolicy::RuntimeNameResolution
1529 .allows_semantic_name_resolution_for(&imported));
1530 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1531 .allows_semantic_name_resolution_for(&imported_missing_item));
1532 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1533 .allows_semantic_name_resolution_for(&imported_empty_item_name));
1534 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1535 .allows_semantic_name_resolution_for(&imported_mismatched_item));
1536 assert!(CallableFallbackPolicy::RuntimeNameResolution
1537 .allows_semantic_name_resolution_for(&method));
1538 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1539 .allows_semantic_name_resolution_for(&whitespace_dynamic));
1540 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1541 .allows_semantic_name_resolution_for(&whitespace_method));
1542 assert!(
1543 !CallableFallbackPolicy::ExternalBoundary.allows_semantic_name_resolution_for(&dynamic)
1544 );
1545 assert!(!CallableFallbackPolicy::ExternalBoundary
1546 .allows_semantic_name_resolution_for(&imported));
1547 assert!(
1548 !CallableFallbackPolicy::ExternalBoundary.allows_semantic_name_resolution_for(&method)
1549 );
1550 assert!(!CallableFallbackPolicy::ExternalBoundary
1551 .allows_semantic_name_resolution_for(&single_external));
1552 assert!(CallableFallbackPolicy::ExternalBoundary
1553 .allows_semantic_name_resolution_for(&qualified_external));
1554 assert!(!CallableFallbackPolicy::ExternalBoundary
1555 .allows_semantic_name_resolution_for(&whitespace_external));
1556 assert!(!CallableFallbackPolicy::ExternalBoundary
1557 .allows_semantic_name_resolution_for(&malformed_external));
1558
1559 assert!(CallableFallbackPolicy::RuntimeNameResolution.allows_vm_name_fallback_for(&dynamic));
1560 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1561 .allows_vm_name_fallback_for(&whitespace_dynamic));
1562 assert!(
1563 CallableFallbackPolicy::RuntimeNameResolution.allows_vm_name_fallback_for(&imported)
1564 );
1565 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1566 .allows_vm_name_fallback_for(&imported_missing_item));
1567 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1568 .allows_vm_name_fallback_for(&imported_empty_item_name));
1569 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1570 .allows_vm_name_fallback_for(&imported_mismatched_item));
1571 assert!(!CallableFallbackPolicy::RuntimeNameResolution.allows_vm_name_fallback_for(&method));
1572 assert!(!CallableFallbackPolicy::ExternalBoundary.allows_vm_name_fallback_for(&dynamic));
1573 assert!(
1574 !CallableFallbackPolicy::ExternalBoundary.allows_vm_name_fallback_for(&single_external)
1575 );
1576 assert!(CallableFallbackPolicy::ExternalBoundary
1577 .allows_vm_name_fallback_for(&qualified_external));
1578 assert!(!CallableFallbackPolicy::ExternalBoundary
1579 .allows_vm_name_fallback_for(&whitespace_external));
1580 assert!(!CallableFallbackPolicy::ExternalBoundary
1581 .allows_vm_name_fallback_for(&malformed_external));
1582
1583 assert_eq!(
1584 CallableFallbackPolicy::RuntimeNameResolution.vm_fallback_name_for(&dynamic),
1585 Some("sqrt".into())
1586 );
1587 assert_eq!(
1588 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&dynamic),
1589 None
1590 );
1591 assert_eq!(
1592 CallableFallbackPolicy::RuntimeNameResolution.vm_fallback_name_for(&whitespace_dynamic),
1593 None
1594 );
1595 assert_eq!(
1596 CallableFallbackPolicy::RuntimeNameResolution.vm_fallback_name_for(&imported),
1597 Some("Point.origin".into())
1598 );
1599 assert_eq!(
1600 CallableFallbackPolicy::RuntimeNameResolution
1601 .vm_fallback_name_for(&imported_missing_item),
1602 None
1603 );
1604 assert_eq!(
1605 CallableFallbackPolicy::RuntimeNameResolution
1606 .vm_fallback_name_for(&imported_empty_item_name),
1607 None
1608 );
1609 assert_eq!(
1610 CallableFallbackPolicy::RuntimeNameResolution
1611 .vm_fallback_name_for(&imported_mismatched_item),
1612 None
1613 );
1614 assert_eq!(
1615 CallableFallbackPolicy::RuntimeNameResolution
1616 .resolution_name_for(&imported_missing_item),
1617 None
1618 );
1619 assert_eq!(
1620 CallableFallbackPolicy::RuntimeNameResolution
1621 .resolution_name_for(&imported_empty_item_name),
1622 None
1623 );
1624 assert_eq!(
1625 CallableFallbackPolicy::RuntimeNameResolution
1626 .resolution_name_for(&imported_mismatched_item),
1627 None
1628 );
1629 assert_eq!(
1630 CallableFallbackPolicy::RuntimeNameResolution.vm_fallback_name_for(&method),
1631 None
1632 );
1633 assert_eq!(
1634 CallableFallbackPolicy::RuntimeNameResolution.resolution_name_for(&method),
1635 Some("deal".into())
1636 );
1637 assert_eq!(
1638 CallableFallbackPolicy::RuntimeNameResolution.resolution_name_for(&whitespace_method),
1639 None
1640 );
1641 assert_eq!(
1642 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&single_external),
1643 None
1644 );
1645 assert_eq!(
1646 CallableFallbackPolicy::ExternalBoundary.resolution_name_for(&single_external),
1647 None
1648 );
1649 assert_eq!(
1650 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&qualified_external),
1651 Some("OverIdx.plus".into())
1652 );
1653 assert_eq!(
1654 CallableFallbackPolicy::ExternalBoundary.resolution_name_for(&qualified_external),
1655 Some("OverIdx.plus".into())
1656 );
1657 assert_eq!(
1658 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&whitespace_external),
1659 None
1660 );
1661 assert_eq!(
1662 CallableFallbackPolicy::ExternalBoundary.resolution_name_for(&whitespace_external),
1663 None
1664 );
1665 assert_eq!(
1666 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&malformed_external),
1667 None
1668 );
1669 }
1670}