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 Builtin(BuiltinId),
363 Imported(DefPath),
364 SuperConstructor {
365 current_class: SymbolName,
366 super_class: QualifiedName,
367 },
368 SuperMethod {
369 current_class: SymbolName,
370 super_class: QualifiedName,
371 method: SymbolName,
372 },
373 DynamicExpr(Box<HirExpr>),
374 Unresolved(QualifiedName),
375}
376
377impl HirCallableRef {
378 pub fn is_feval_builtin_like(&self) -> bool {
379 match self {
380 HirCallableRef::Builtin(id) => id.0 == FEVAL_BUILTIN_NAME,
381 HirCallableRef::Unresolved(name) if name.0.len() == 1 => {
382 name.0[0].0 == FEVAL_BUILTIN_NAME
383 }
384 _ => false,
385 }
386 }
387
388 pub fn identity(&self) -> Option<CallableIdentity> {
389 match self {
390 HirCallableRef::Function(function) => Some(CallableIdentity::BoundFunction(*function)),
391 HirCallableRef::Builtin(builtin) => Some(CallableIdentity::Builtin(builtin.clone())),
392 HirCallableRef::Imported(path) => Some(CallableIdentity::Imported(path.clone())),
393 HirCallableRef::SuperConstructor { .. } | HirCallableRef::SuperMethod { .. } => None,
394 HirCallableRef::DynamicExpr(_) => None,
395 HirCallableRef::Unresolved(name) => {
396 if name.0.len() == 1 {
397 Some(CallableIdentity::DynamicName(name.0[0].clone()))
398 } else {
399 Some(CallableIdentity::ExternalName(name.clone()))
400 }
401 }
402 }
403 }
404}
405
406#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
407pub enum CallableIdentity {
408 BoundFunction(FunctionId),
409 Builtin(BuiltinId),
410 Imported(DefPath),
411 Method(MethodId),
412 AnonymousFunction(FunctionId),
413 DynamicName(SymbolName),
414 ExternalName(QualifiedName),
415}
416
417impl CallableIdentity {
418 pub fn display_name(&self) -> Option<String> {
419 match self {
420 CallableIdentity::BoundFunction(_) | CallableIdentity::AnonymousFunction(_) => None,
421 CallableIdentity::Builtin(id) => (!id.0.is_empty()).then_some(id.0.clone()),
422 CallableIdentity::Imported(path) => path.module.display_name(),
423 CallableIdentity::Method(id) => (!id.0.is_empty()).then_some(id.0.clone()),
424 CallableIdentity::DynamicName(name) => (!name.0.is_empty()).then_some(name.0.clone()),
425 CallableIdentity::ExternalName(name) => name.display_name(),
426 }
427 }
428}
429
430#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize)]
431pub enum CallableFallbackPolicy {
432 None,
433 RuntimeNameResolution,
434 ObjectDispatch,
435 ExternalBoundary,
436}
437
438impl CallableFallbackPolicy {
439 fn is_well_formed_external_name(name: &QualifiedName) -> bool {
440 name.0.len() > 1 && name.0.iter().all(|segment| !segment.0.trim().is_empty())
441 }
442
443 fn is_well_formed_imported_path(path: &DefPath) -> bool {
444 let Some(module_name) = path.module.display_name() else {
445 return false;
446 };
447 let Some(last_item) = path.item.last() else {
448 return false;
449 };
450 let item_name = last_item.display_name();
451 if item_name.trim().is_empty() {
452 return false;
453 }
454 let Some(last_module_segment) = path.module.0.last() else {
455 return false;
456 };
457 if last_module_segment.0.trim().is_empty() {
458 return false;
459 }
460 let _ = module_name;
463 last_module_segment.0 == item_name
464 }
465
466 pub fn allows_runtime_name_resolution(self) -> bool {
467 matches!(self, CallableFallbackPolicy::RuntimeNameResolution)
468 }
469
470 pub fn allows_semantic_name_resolution_for(self, identity: &CallableIdentity) -> bool {
471 match identity {
472 CallableIdentity::DynamicName(SymbolName(name))
473 | CallableIdentity::Method(MethodId(name)) => {
474 self.allows_runtime_name_resolution() && !name.trim().is_empty()
475 }
476 CallableIdentity::Imported(path) => {
477 self.allows_runtime_name_resolution() && Self::is_well_formed_imported_path(path)
478 }
479 CallableIdentity::ExternalName(name) => {
480 matches!(self, CallableFallbackPolicy::ExternalBoundary)
481 && Self::is_well_formed_external_name(name)
482 }
483 _ => false,
484 }
485 }
486
487 pub fn allows_vm_name_fallback_for(self, identity: &CallableIdentity) -> bool {
488 match identity {
489 CallableIdentity::DynamicName(SymbolName(name)) => {
490 self.allows_runtime_name_resolution() && !name.trim().is_empty()
491 }
492 CallableIdentity::Imported(path) => {
493 self.allows_runtime_name_resolution() && Self::is_well_formed_imported_path(path)
494 }
495 CallableIdentity::ExternalName(name) => {
496 matches!(self, CallableFallbackPolicy::ExternalBoundary)
497 && Self::is_well_formed_external_name(name)
498 }
499 _ => false,
500 }
501 }
502
503 pub fn resolution_name_for(self, identity: &CallableIdentity) -> Option<String> {
504 if !self.allows_semantic_name_resolution_for(identity) {
505 return None;
506 }
507
508 match identity {
509 CallableIdentity::DynamicName(SymbolName(name))
510 | CallableIdentity::Method(MethodId(name)) => {
511 let trimmed = name.trim();
512 (!trimmed.is_empty()).then_some(trimmed.to_string())
513 }
514 CallableIdentity::Imported(path) => path.module.display_name(),
515 CallableIdentity::ExternalName(name) if Self::is_well_formed_external_name(name) => {
516 Some(
517 name.0
518 .iter()
519 .map(|segment| segment.0.as_str())
520 .collect::<Vec<_>>()
521 .join("."),
522 )
523 }
524 _ => None,
525 }
526 }
527
528 pub fn vm_fallback_name_for(self, identity: &CallableIdentity) -> Option<String> {
529 if !self.allows_vm_name_fallback_for(identity) {
530 return None;
531 }
532
533 match identity {
534 CallableIdentity::DynamicName(SymbolName(name)) => {
535 let trimmed = name.trim();
536 (!trimmed.is_empty()).then_some(trimmed.to_string())
537 }
538 CallableIdentity::Imported(path) => path.module.display_name(),
539 CallableIdentity::ExternalName(name) if Self::is_well_formed_external_name(name) => {
540 Some(
541 name.0
542 .iter()
543 .map(|segment| segment.0.as_str())
544 .collect::<Vec<_>>()
545 .join("."),
546 )
547 }
548 _ => None,
549 }
550 }
551
552 pub fn supports_vm_static_call(self) -> bool {
553 matches!(
554 self,
555 CallableFallbackPolicy::RuntimeNameResolution
556 | CallableFallbackPolicy::ExternalBoundary
557 )
558 }
559
560 pub fn supports_vm_method_or_member_call(self) -> bool {
561 matches!(
562 self,
563 CallableFallbackPolicy::RuntimeNameResolution | CallableFallbackPolicy::ObjectDispatch
564 )
565 }
566
567 pub fn post_object_dispatch(self) -> Self {
568 match self {
569 CallableFallbackPolicy::ObjectDispatch => CallableFallbackPolicy::RuntimeNameResolution,
570 other => other,
571 }
572 }
573}
574
575pub const FEVAL_BUILTIN_NAME: &str = "feval";
576pub const EVAL_BUILTIN_NAME: &str = "eval";
577pub const EVALIN_BUILTIN_NAME: &str = "evalin";
578pub const ASSIGNIN_BUILTIN_NAME: &str = "assignin";
579pub const RUN_BUILTIN_NAME: &str = "run";
580pub const NARGIN_BUILTIN_NAME: &str = "nargin";
581pub const NARGOUT_BUILTIN_NAME: &str = "nargout";
582pub const NARGINCHK_BUILTIN_NAME: &str = "narginchk";
583pub const NARGOUTCHK_BUILTIN_NAME: &str = "nargoutchk";
584pub const AWAIT_EXTENSION_NAME: &str = "await";
585pub const SPAWN_EXTENSION_NAME: &str = "spawn";
586pub const TEST_CLASS_REGISTRATION_BUILTIN_NAME: &str = "__register_test_classes";
587pub const DISCARD_OUTPUT_NAME: &str = "~";
588
589#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
590pub enum CallSyntax {
591 Plain,
592 Method,
593 DottedInvoke,
594 Command,
595}
596
597#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
598pub struct HirCommandCall {
599 pub command: HirCallableRef,
600 pub args: Vec<CommandArgument>,
601}
602
603#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
604pub enum CommandArgument {
605 Word(SymbolName),
606 StringLiteral(StringLiteral),
607}
608
609#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
610pub struct HirImport {
611 pub path: QualifiedName,
612 pub wildcard: bool,
613 pub span: Span,
614}
615
616#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
621pub struct HirClass {
622 pub id: ClassId,
623 pub module: ModuleId,
624 pub name: QualifiedName,
625 pub super_class: Option<ClassId>,
626 pub kind: ClassKind,
627 pub is_sealed: bool,
628 pub is_abstract: bool,
629 pub properties: Vec<ClassProperty>,
630 pub methods: Vec<ClassMethod>,
631 pub events: Vec<ClassEvent>,
632 pub enumerations: Vec<ClassEnumeration>,
633 pub arguments: Vec<ClassArgumentBlock>,
634 pub span: Span,
635}
636
637#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
638pub enum ClassKind {
639 Value,
640 Handle,
641}
642
643#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
644pub struct ClassProperty {
645 pub name: MemberName,
646 pub attributes: PropertyAttributes,
647 pub default: Option<HirExpr>,
648 pub span: Span,
649}
650
651#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
652pub struct ClassMethod {
653 pub function: FunctionId,
654 pub name: MethodName,
655 pub is_static: bool,
656 pub attributes: MethodAttributes,
657 pub span: Span,
658}
659
660#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
661pub struct ClassEvent {
662 pub name: SymbolName,
663 pub span: Span,
664}
665
666#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
667pub struct ClassEnumeration {
668 pub name: SymbolName,
669 pub span: Span,
670}
671
672#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
673pub struct ClassArgumentBlock {
674 pub span: Span,
675}
676
677#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
678pub struct PropertyAttributes {
679 pub is_static: bool,
680 pub is_constant: bool,
681 pub is_dependent: bool,
682 pub is_transient: bool,
683 pub is_hidden: bool,
684 pub access: MemberAccess,
685 pub get_access: MemberAccess,
686 pub set_access: MemberAccess,
687}
688
689#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
690pub struct MethodAttributes {
691 pub access: MemberAccess,
692 pub is_hidden: bool,
693 pub is_abstract: bool,
694 pub is_sealed: bool,
695}
696
697#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
698pub enum MemberAccess {
699 #[default]
700 Public,
701 Private,
702 Protected,
703}
704
705#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
706pub struct OutputTargetList {
707 pub requested_outputs: RequestedOutputCount,
708 pub targets: Vec<OutputTarget>,
709}
710
711#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
712pub enum OutputTarget {
713 Place(HirPlace),
714 Discard,
715}
716
717#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
718pub enum RequestedOutputCount {
719 Zero,
720 One,
721 Exactly(usize),
722 CurrentFunctionNargout,
723}
724
725impl RequestedOutputCount {
726 pub fn fixed_count(&self) -> usize {
727 match self {
728 RequestedOutputCount::Zero => 0,
729 RequestedOutputCount::One => 1,
730 RequestedOutputCount::Exactly(count) => *count,
731 RequestedOutputCount::CurrentFunctionNargout => 1,
732 }
733 }
734}
735
736#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
737pub enum IndexKind {
738 Paren,
739 Brace,
740}
741
742#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
743pub enum IndexComponent {
744 Colon,
745 End { dim: Option<usize>, offset: isize },
746 Expr(HirExpr),
747 Logical(HirExpr),
748}
749
750#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
751pub struct IndexingSemantics {
752 pub kind: IndexKind,
753 pub components: Vec<IndexComponent>,
754 pub result_context: IndexResultContext,
755}
756
757#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
758pub enum IndexResultContext {
759 ReadSingle,
760 ReadCommaList,
761 AssignmentTarget,
762 DeletionTarget,
763 FunctionArgumentExpansion,
764}
765
766#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
767pub enum FunctionHandleTarget {
768 Function(FunctionId),
769 Builtin(BuiltinId),
770 Anonymous(FunctionId),
771 DefPath(DefPath),
772 DynamicName(SymbolName),
773}
774
775impl FunctionHandleTarget {
776 pub fn identity(&self) -> CallableIdentity {
777 match self {
778 FunctionHandleTarget::Function(function) => CallableIdentity::BoundFunction(*function),
779 FunctionHandleTarget::Builtin(builtin) => CallableIdentity::Builtin(builtin.clone()),
780 FunctionHandleTarget::Anonymous(function) => {
781 CallableIdentity::AnonymousFunction(*function)
782 }
783 FunctionHandleTarget::DefPath(path) => CallableIdentity::Imported(path.clone()),
784 FunctionHandleTarget::DynamicName(name) => CallableIdentity::DynamicName(name.clone()),
785 }
786 }
787}
788
789#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
790pub enum WorkspaceEffect {
791 None,
792 ReadsWorkspace,
793 CreatesBinding,
794 ClearsBinding,
795 ClearsFunctionCache,
796 MutatesGlobal,
797 MutatesPersistent,
798 LoadsExternalBindings,
799 DynamicEval,
800}
801
802#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
803pub enum EnvironmentEffect {
804 PathMutation,
805 WorkingDirectoryMutation,
806 FunctionCacheInvalidation,
807 DynamicLookupInvalidation,
808}
809
810#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
811pub enum EmptyArrayRole {
812 EmptyValue,
813 ConcatenationIdentity,
814 DeletionMarker,
815}
816
817#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
818pub enum ExpansionSemantics {
819 ExactShape,
820 ScalarExpansion,
821 ImplicitExpansion,
822}
823
824#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
825pub enum OperatorKind {
826 UnaryPlus,
827 UnaryMinus,
828 Not,
829 Add,
830 Subtract,
831 MatrixMultiply,
832 ElementwiseMultiply,
833 MatrixPower,
834 ElementwisePower,
835 Mldivide,
836 Mrdivide,
837 ElementwiseDivide,
838 ElementwiseLeftDivide,
839 Equal,
840 NotEqual,
841 Less,
842 LessEqual,
843 Greater,
844 GreaterEqual,
845 ShortCircuitAnd,
846 ShortCircuitOr,
847 ElementwiseAnd,
848 ElementwiseOr,
849 Transpose,
850 ConjugateTranspose,
851}
852
853#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
854pub enum NumericClass {
855 Double,
856 Single,
857 Int8,
858 UInt8,
859 Int16,
860 UInt16,
861 Int32,
862 UInt32,
863 Int64,
864 UInt64,
865}
866
867#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
868pub enum ValueFlowFact {
869 NoValue,
870 Single(TypeFact),
871 CommaList(Vec<TypeFact>),
872 UnknownList,
873}
874
875#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
876pub enum PlaceMutationKind {
877 BindOrAssign,
878 IndexedAssign,
879 CellAssign,
880 MemberAssign,
881 Delete,
882}
883
884#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
885pub struct PlaceMutation {
886 pub place: HirPlace,
887 pub kind: PlaceMutationKind,
888 pub creation_policy: AssignmentCreationPolicy,
889 pub shape_policy: AssignmentShapePolicy,
890}
891
892#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
893pub enum AssignmentCreationPolicy {
894 ExistingOnly,
895 CreateBinding,
896 CreateArrayByIndex,
897 CreateStructFieldPath,
898 Overloaded,
899}
900
901#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
902pub enum AssignmentShapePolicy {
903 Exact,
904 ScalarExpansion,
905 MatlabCompatible,
906 Overloaded,
907}
908
909#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
910pub enum ReferenceKind {
911 Binding(BindingId),
912 Function(FunctionId),
913 Builtin(BuiltinId),
914 Class(ClassId),
915 Package(QualifiedName),
916 Imported(DefPath),
917 RuntimeClass(QualifiedName),
918 Dynamic,
919 Unresolved,
920}
921
922#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
923pub enum CallKind {
924 DirectFunction(FunctionId),
925 Builtin(BuiltinId),
926 Constructor(ClassId),
927 StaticMethod {
928 class: ClassId,
929 method: MethodId,
930 },
931 InstanceMethod {
932 receiver: Box<HirExpr>,
933 method: MethodId,
934 },
935 PackageFunction(DefPath),
936 FunctionHandle,
937 Dynamic,
938 OverloadedOperator,
939 OverloadedIndexing,
940}
941
942#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
943pub struct HirIndex {
944 pub bindings: Vec<BindingResolution>,
945 pub functions: Vec<FunctionResolution>,
946 pub classes: Vec<ClassResolution>,
947 pub imports: Vec<ImportResolution>,
948 pub references: Vec<ReferenceResolution>,
949 pub calls: Vec<CallResolution>,
950 pub mutations: Vec<PlaceMutation>,
951}
952
953#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
954pub struct BindingResolution {
955 pub name: BindingName,
956 pub binding: BindingId,
957 pub owner: BindingOwner,
958 pub span: Span,
959}
960
961#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
962pub struct FunctionResolution {
963 pub name: FunctionName,
964 pub function: FunctionId,
965 pub parent: Option<FunctionId>,
966 pub span: Span,
967}
968
969#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
970pub struct ClassResolution {
971 pub name: QualifiedName,
972 pub class: ClassId,
973 pub span: Span,
974}
975
976#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
977pub struct ImportResolution {
978 pub import: HirImport,
979}
980
981#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
982pub struct ReferenceResolution {
983 pub name: SymbolName,
984 pub kind: ReferenceKind,
985 pub span: Span,
986}
987
988#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
989pub struct CallResolution {
990 pub name: QualifiedName,
991 pub callee: HirCallableRef,
992 pub kind: CallKind,
993 pub requested_outputs: RequestedOutputCount,
994 pub span: Span,
995}
996
997#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
998pub enum SpawnSafetyFact {
999 SpawnSafe,
1000 RequiresIsolation,
1001 NotSpawnSafe { reason: SpawnSafetyReason },
1002}
1003
1004#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1005pub enum SpawnSafetyReason {
1006 MutableLexicalCapture,
1007 NonSendableRuntimeHandle,
1008 UnsynchronizedSharedMutation,
1009 UnknownDynamicCapture,
1010}
1011
1012#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1013pub enum AsyncValueFact {
1014 Future(FutureFact),
1015 TaskHandle(TaskHandleFact),
1016}
1017
1018#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1019pub struct FutureFact {
1020 pub output: Box<TypeFact>,
1021 pub state: FutureStateFact,
1022}
1023
1024#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1025pub enum FutureStateFact {
1026 Lazy,
1027 Awaited,
1028 Unknown,
1029}
1030
1031#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1032pub struct TaskHandleFact {
1033 pub output: Box<TypeFact>,
1034 pub spawn_safety: SpawnSafetyFact,
1035}
1036
1037#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1038pub enum TypeFact {
1039 Never,
1040 Unknown,
1041 Logical,
1042 Numeric {
1043 class: NumericClass,
1044 domain: NumericDomain,
1045 },
1046 Tensor(TensorTypeFact),
1047 String,
1048 CharArray,
1049 Cell,
1050 Struct,
1051 ClassInstance(ClassId),
1052 ClassRef(ClassId),
1053 Function(FunctionId),
1054}
1055
1056#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1057pub struct TensorTypeFact {
1058 pub element: TensorElementDomainFact,
1059 pub shape: ShapeFact,
1060}
1061
1062#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1063pub enum TensorElementDomainFact {
1064 Unknown,
1065 Logical,
1066 Numeric {
1067 class: NumericClass,
1068 domain: NumericDomain,
1069 },
1070 Char,
1071 Object(ClassId),
1072}
1073
1074#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1075pub enum NumericDomain {
1076 Real,
1077 Complex,
1078}
1079
1080#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1081pub enum ShapeFact {
1082 Unreachable,
1083 Unknown,
1084 Scalar,
1085 Ranked { rank: usize },
1086 Shaped { dims: Vec<DimFact> },
1087}
1088
1089#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1090pub enum DimFact {
1091 Known(usize),
1092 Symbolic(DimSymbol),
1093 Unknown,
1094}
1095
1096#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1097pub struct DimSymbol(pub String);
1098
1099#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1105pub struct DefPath {
1106 pub package: PackageName,
1107 pub module: QualifiedName,
1108 pub item: Vec<DefPathSegment>,
1109}
1110
1111impl DefPath {
1112 pub fn display_name(&self) -> Option<String> {
1113 self.item.last().map(DefPathSegment::display_name)
1114 }
1115}
1116
1117#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1118pub enum DefPathSegment {
1119 Function(SymbolName),
1120}
1121
1122impl DefPathSegment {
1123 pub fn display_name(&self) -> String {
1124 match self {
1125 DefPathSegment::Function(name) => name.0.clone(),
1126 }
1127 }
1128}
1129
1130#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1131pub struct QualifiedName(pub Vec<SymbolName>);
1132
1133impl QualifiedName {
1134 pub fn display_name(&self) -> Option<String> {
1135 if self.0.is_empty() || self.0.iter().any(|segment| segment.0.is_empty()) {
1136 None
1137 } else {
1138 Some(
1139 self.0
1140 .iter()
1141 .map(|segment| segment.0.as_str())
1142 .collect::<Vec<_>>()
1143 .join("."),
1144 )
1145 }
1146 }
1147}
1148
1149#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1150pub struct SymbolName(pub String);
1151
1152#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1153pub struct BindingName(pub String);
1154
1155#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1156pub struct FunctionName(pub String);
1157
1158#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1159pub struct EntrypointName(pub String);
1160
1161#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1162pub struct MemberName(pub String);
1163
1164#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1165pub struct MethodName(pub String);
1166
1167#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1168pub struct PackageName(pub String);
1169
1170#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1171pub struct BuiltinId(pub String);
1172
1173#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1174pub struct MethodId(pub String);
1175
1176#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
1177pub struct StringLiteral(pub String);
1178
1179#[derive(Debug, Clone)]
1180pub struct LoweringResult {
1181 pub assembly: HirAssembly,
1182 pub hir_index: HirIndex,
1183}
1184
1185#[cfg(test)]
1186mod tests {
1187 use super::*;
1188
1189 fn span() -> Span {
1190 Span { start: 0, end: 0 }
1191 }
1192
1193 #[test]
1194 fn assembly_owns_core_items() {
1195 let module = ModuleId(0);
1196 let function = FunctionId(0);
1197 let binding = BindingId(0);
1198 let entrypoint = EntrypointId(0);
1199
1200 let assembly = HirAssembly {
1201 modules: vec![HirModule {
1202 id: module,
1203 name: QualifiedName(vec![SymbolName("demo".into())]),
1204 source_id: SourceId(0),
1205 source_unit: SourceUnitKind::ScriptFile,
1206 imports: vec![],
1207 top_level_functions: vec![],
1208 classes: vec![],
1209 synthetic_entry_function: Some(function),
1210 }],
1211 functions: vec![HirFunction {
1212 id: function,
1213 module,
1214 parent: None,
1215 enclosing_class: None,
1216 name: FunctionName("demo_entry".into()),
1217 kind: FunctionKind::SyntheticEntrypoint,
1218 params: vec![],
1219 outputs: vec![],
1220 abi: FunctionAbi {
1221 fixed_inputs: vec![],
1222 varargin: None,
1223 fixed_outputs: vec![],
1224 varargout: None,
1225 implicit_nargin: None,
1226 implicit_nargout: None,
1227 },
1228 locals: vec![binding],
1229 captures: vec![],
1230 argument_validations: vec![],
1231 modifiers: FunctionModifiers::default(),
1232 body: HirBlock { statements: vec![] },
1233 span: span(),
1234 }],
1235 classes: vec![],
1236 bindings: vec![HirBinding {
1237 id: binding,
1238 owner: BindingOwner::Function(function),
1239 name: BindingName("x".into()),
1240 role: BindingRole::Local,
1241 storage: BindingStorage::Lexical,
1242 workspace_visibility: WorkspaceVisibility::TopLevel,
1243 declared_span: span(),
1244 }],
1245 entrypoints: vec![HirEntrypoint {
1246 id: entrypoint,
1247 name: Some(EntrypointName("demo".into())),
1248 target: function,
1249 origin: EntrypointOrigin::SourcePath,
1250 policy: EntrypointPolicy {
1251 workspace_export: WorkspaceExportPolicy::ExportTopLevelBindings,
1252 top_level_await: false,
1253 },
1254 }],
1255 };
1256
1257 assert_eq!(assembly.modules[0].synthetic_entry_function, Some(function));
1258 assert_eq!(assembly.entrypoints[0].target, function);
1259 assert_eq!(assembly.functions[0].locals, vec![binding]);
1260 assert!(matches!(
1261 assembly.bindings[0].workspace_visibility,
1262 WorkspaceVisibility::TopLevel
1263 ));
1264 }
1265
1266 #[test]
1267 fn function_abi_can_reuse_shared_input_output_binding() {
1268 let binding = BindingId(0);
1269 let abi = FunctionAbi {
1270 fixed_inputs: vec![binding],
1271 varargin: None,
1272 fixed_outputs: vec![binding],
1273 varargout: None,
1274 implicit_nargin: Some(BindingId(1)),
1275 implicit_nargout: Some(BindingId(2)),
1276 };
1277
1278 assert_eq!(abi.fixed_inputs[0], abi.fixed_outputs[0]);
1279 assert_eq!(abi.implicit_nargin, Some(BindingId(1)));
1280 assert_eq!(abi.implicit_nargout, Some(BindingId(2)));
1281 }
1282
1283 #[test]
1284 fn captures_reference_original_binding_identity() {
1285 let parent = FunctionId(0);
1286 let child = FunctionId(1);
1287 let binding = BindingId(0);
1288
1289 let capture = CapturedBinding {
1290 binding,
1291 from_function: parent,
1292 };
1293
1294 let child_function = HirFunction {
1295 id: child,
1296 module: ModuleId(0),
1297 parent: Some(parent),
1298 enclosing_class: None,
1299 name: FunctionName("inner".into()),
1300 kind: FunctionKind::Named,
1301 params: vec![],
1302 outputs: vec![],
1303 abi: FunctionAbi {
1304 fixed_inputs: vec![],
1305 varargin: None,
1306 fixed_outputs: vec![],
1307 varargout: None,
1308 implicit_nargin: None,
1309 implicit_nargout: None,
1310 },
1311 locals: vec![],
1312 captures: vec![capture],
1313 argument_validations: vec![],
1314 modifiers: FunctionModifiers::default(),
1315 body: HirBlock { statements: vec![] },
1316 span: span(),
1317 };
1318
1319 assert_eq!(child_function.parent, Some(parent));
1320 assert_eq!(child_function.captures[0].binding, binding);
1321 assert_eq!(child_function.captures[0].from_function, parent);
1322 }
1323
1324 #[test]
1325 fn facts_capture_value_flow_and_mutation_context() {
1326 let binding = BindingId(0);
1327 let mutation = PlaceMutation {
1328 place: HirPlace::Binding(binding),
1329 kind: PlaceMutationKind::BindOrAssign,
1330 creation_policy: AssignmentCreationPolicy::CreateBinding,
1331 shape_policy: AssignmentShapePolicy::MatlabCompatible,
1332 };
1333 let value = ValueFlowFact::Single(TypeFact::Tensor(TensorTypeFact {
1334 element: TensorElementDomainFact::Numeric {
1335 class: NumericClass::Double,
1336 domain: NumericDomain::Real,
1337 },
1338 shape: ShapeFact::Shaped {
1339 dims: vec![DimFact::Known(1), DimFact::Symbolic(DimSymbol("n".into()))],
1340 },
1341 }));
1342
1343 assert!(matches!(mutation.place, HirPlace::Binding(id) if id == binding));
1344 assert!(matches!(
1345 value,
1346 ValueFlowFact::Single(TypeFact::Tensor(TensorTypeFact {
1347 shape: ShapeFact::Shaped { .. },
1348 ..
1349 }))
1350 ));
1351 }
1352
1353 #[test]
1354 fn def_path_is_distinct_from_local_table_ids() {
1355 let function_id = FunctionId(0);
1356 let path = DefPath {
1357 package: PackageName("pkg".into()),
1358 module: QualifiedName(vec![SymbolName("pkg".into()), SymbolName("demo".into())]),
1359 item: vec![DefPathSegment::Function(SymbolName("f".into()))],
1360 };
1361
1362 assert_eq!(function_id, FunctionId(0));
1363 assert_eq!(path.package.0, "pkg");
1364 assert!(matches!(path.item[0], DefPathSegment::Function(_)));
1365 }
1366
1367 #[test]
1368 fn imported_callable_identity_prefers_qualified_display_name() {
1369 let path = DefPath {
1370 package: PackageName("pkg".into()),
1371 module: QualifiedName(vec![
1372 SymbolName("pkg".into()),
1373 SymbolName("demo".into()),
1374 SymbolName("f".into()),
1375 ]),
1376 item: vec![DefPathSegment::Function(SymbolName("f".into()))],
1377 };
1378 let identity = CallableIdentity::Imported(path);
1379 assert_eq!(identity.display_name().as_deref(), Some("pkg.demo.f"));
1380
1381 let empty_module_path = DefPath {
1382 package: PackageName("pkg".into()),
1383 module: QualifiedName(vec![]),
1384 item: vec![DefPathSegment::Function(SymbolName("f".into()))],
1385 };
1386 let empty_module_identity = CallableIdentity::Imported(empty_module_path);
1387 assert_eq!(empty_module_identity.display_name(), None);
1388 }
1389
1390 #[test]
1391 fn qualified_name_display_name_rejects_empty_segments() {
1392 let malformed = QualifiedName(vec![
1393 SymbolName("pkg".into()),
1394 SymbolName("".into()),
1395 SymbolName("remote".into()),
1396 ]);
1397 assert_eq!(malformed.display_name(), None);
1398 }
1399
1400 #[test]
1401 fn callable_identity_display_name_rejects_empty_name_fields() {
1402 assert_eq!(
1403 CallableIdentity::Builtin(BuiltinId(String::new())).display_name(),
1404 None
1405 );
1406 assert_eq!(
1407 CallableIdentity::Method(MethodId(String::new())).display_name(),
1408 None
1409 );
1410 assert_eq!(
1411 CallableIdentity::DynamicName(SymbolName(String::new())).display_name(),
1412 None
1413 );
1414 }
1415
1416 #[test]
1417 fn async_facts_distinguish_lazy_futures_from_spawned_tasks() {
1418 let future = AsyncValueFact::Future(FutureFact {
1419 output: Box::new(TypeFact::Unknown),
1420 state: FutureStateFact::Lazy,
1421 });
1422 let task = AsyncValueFact::TaskHandle(TaskHandleFact {
1423 output: Box::new(TypeFact::Unknown),
1424 spawn_safety: SpawnSafetyFact::SpawnSafe,
1425 });
1426
1427 assert!(matches!(
1428 future,
1429 AsyncValueFact::Future(FutureFact {
1430 state: FutureStateFact::Lazy,
1431 ..
1432 })
1433 ));
1434 assert!(matches!(
1435 task,
1436 AsyncValueFact::TaskHandle(TaskHandleFact {
1437 spawn_safety: SpawnSafetyFact::SpawnSafe,
1438 ..
1439 })
1440 ));
1441 }
1442
1443 #[test]
1444 fn callable_name_fallback_policies_require_well_formed_external_names() {
1445 let dynamic = CallableIdentity::DynamicName(SymbolName("sqrt".into()));
1446 let imported = CallableIdentity::Imported(DefPath {
1447 package: PackageName("Point".into()),
1448 module: QualifiedName(vec![
1449 SymbolName("Point".into()),
1450 SymbolName("origin".into()),
1451 ]),
1452 item: vec![DefPathSegment::Function(SymbolName("origin".into()))],
1453 });
1454 let imported_missing_item = CallableIdentity::Imported(DefPath {
1455 package: PackageName("Point".into()),
1456 module: QualifiedName(vec![
1457 SymbolName("Point".into()),
1458 SymbolName("origin".into()),
1459 ]),
1460 item: vec![],
1461 });
1462 let imported_empty_item_name = CallableIdentity::Imported(DefPath {
1463 package: PackageName("Point".into()),
1464 module: QualifiedName(vec![
1465 SymbolName("Point".into()),
1466 SymbolName("origin".into()),
1467 ]),
1468 item: vec![DefPathSegment::Function(SymbolName("".into()))],
1469 });
1470 let imported_mismatched_item = CallableIdentity::Imported(DefPath {
1471 package: PackageName("Point".into()),
1472 module: QualifiedName(vec![
1473 SymbolName("Point".into()),
1474 SymbolName("origin".into()),
1475 ]),
1476 item: vec![DefPathSegment::Function(SymbolName("different".into()))],
1477 });
1478 let method = CallableIdentity::Method(MethodId("deal".into()));
1479 let whitespace_dynamic = CallableIdentity::DynamicName(SymbolName(" ".into()));
1480 let whitespace_method = CallableIdentity::Method(MethodId(" ".into()));
1481 let single_external =
1482 CallableIdentity::ExternalName(QualifiedName(vec![SymbolName("sqrt".into())]));
1483 let whitespace_external = CallableIdentity::ExternalName(QualifiedName(vec![
1484 SymbolName("OverIdx".into()),
1485 SymbolName(" ".into()),
1486 ]));
1487 let qualified_external = CallableIdentity::ExternalName(QualifiedName(vec![
1488 SymbolName("OverIdx".into()),
1489 SymbolName("plus".into()),
1490 ]));
1491 let malformed_external = CallableIdentity::ExternalName(QualifiedName(vec![
1492 SymbolName("OverIdx".into()),
1493 SymbolName("".into()),
1494 SymbolName("plus".into()),
1495 ]));
1496
1497 assert!(CallableFallbackPolicy::RuntimeNameResolution
1498 .allows_semantic_name_resolution_for(&dynamic));
1499 assert!(CallableFallbackPolicy::RuntimeNameResolution
1500 .allows_semantic_name_resolution_for(&imported));
1501 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1502 .allows_semantic_name_resolution_for(&imported_missing_item));
1503 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1504 .allows_semantic_name_resolution_for(&imported_empty_item_name));
1505 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1506 .allows_semantic_name_resolution_for(&imported_mismatched_item));
1507 assert!(CallableFallbackPolicy::RuntimeNameResolution
1508 .allows_semantic_name_resolution_for(&method));
1509 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1510 .allows_semantic_name_resolution_for(&whitespace_dynamic));
1511 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1512 .allows_semantic_name_resolution_for(&whitespace_method));
1513 assert!(
1514 !CallableFallbackPolicy::ExternalBoundary.allows_semantic_name_resolution_for(&dynamic)
1515 );
1516 assert!(!CallableFallbackPolicy::ExternalBoundary
1517 .allows_semantic_name_resolution_for(&imported));
1518 assert!(
1519 !CallableFallbackPolicy::ExternalBoundary.allows_semantic_name_resolution_for(&method)
1520 );
1521 assert!(!CallableFallbackPolicy::ExternalBoundary
1522 .allows_semantic_name_resolution_for(&single_external));
1523 assert!(CallableFallbackPolicy::ExternalBoundary
1524 .allows_semantic_name_resolution_for(&qualified_external));
1525 assert!(!CallableFallbackPolicy::ExternalBoundary
1526 .allows_semantic_name_resolution_for(&whitespace_external));
1527 assert!(!CallableFallbackPolicy::ExternalBoundary
1528 .allows_semantic_name_resolution_for(&malformed_external));
1529
1530 assert!(CallableFallbackPolicy::RuntimeNameResolution.allows_vm_name_fallback_for(&dynamic));
1531 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1532 .allows_vm_name_fallback_for(&whitespace_dynamic));
1533 assert!(
1534 CallableFallbackPolicy::RuntimeNameResolution.allows_vm_name_fallback_for(&imported)
1535 );
1536 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1537 .allows_vm_name_fallback_for(&imported_missing_item));
1538 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1539 .allows_vm_name_fallback_for(&imported_empty_item_name));
1540 assert!(!CallableFallbackPolicy::RuntimeNameResolution
1541 .allows_vm_name_fallback_for(&imported_mismatched_item));
1542 assert!(!CallableFallbackPolicy::RuntimeNameResolution.allows_vm_name_fallback_for(&method));
1543 assert!(!CallableFallbackPolicy::ExternalBoundary.allows_vm_name_fallback_for(&dynamic));
1544 assert!(
1545 !CallableFallbackPolicy::ExternalBoundary.allows_vm_name_fallback_for(&single_external)
1546 );
1547 assert!(CallableFallbackPolicy::ExternalBoundary
1548 .allows_vm_name_fallback_for(&qualified_external));
1549 assert!(!CallableFallbackPolicy::ExternalBoundary
1550 .allows_vm_name_fallback_for(&whitespace_external));
1551 assert!(!CallableFallbackPolicy::ExternalBoundary
1552 .allows_vm_name_fallback_for(&malformed_external));
1553
1554 assert_eq!(
1555 CallableFallbackPolicy::RuntimeNameResolution.vm_fallback_name_for(&dynamic),
1556 Some("sqrt".into())
1557 );
1558 assert_eq!(
1559 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&dynamic),
1560 None
1561 );
1562 assert_eq!(
1563 CallableFallbackPolicy::RuntimeNameResolution.vm_fallback_name_for(&whitespace_dynamic),
1564 None
1565 );
1566 assert_eq!(
1567 CallableFallbackPolicy::RuntimeNameResolution.vm_fallback_name_for(&imported),
1568 Some("Point.origin".into())
1569 );
1570 assert_eq!(
1571 CallableFallbackPolicy::RuntimeNameResolution
1572 .vm_fallback_name_for(&imported_missing_item),
1573 None
1574 );
1575 assert_eq!(
1576 CallableFallbackPolicy::RuntimeNameResolution
1577 .vm_fallback_name_for(&imported_empty_item_name),
1578 None
1579 );
1580 assert_eq!(
1581 CallableFallbackPolicy::RuntimeNameResolution
1582 .vm_fallback_name_for(&imported_mismatched_item),
1583 None
1584 );
1585 assert_eq!(
1586 CallableFallbackPolicy::RuntimeNameResolution
1587 .resolution_name_for(&imported_missing_item),
1588 None
1589 );
1590 assert_eq!(
1591 CallableFallbackPolicy::RuntimeNameResolution
1592 .resolution_name_for(&imported_empty_item_name),
1593 None
1594 );
1595 assert_eq!(
1596 CallableFallbackPolicy::RuntimeNameResolution
1597 .resolution_name_for(&imported_mismatched_item),
1598 None
1599 );
1600 assert_eq!(
1601 CallableFallbackPolicy::RuntimeNameResolution.vm_fallback_name_for(&method),
1602 None
1603 );
1604 assert_eq!(
1605 CallableFallbackPolicy::RuntimeNameResolution.resolution_name_for(&method),
1606 Some("deal".into())
1607 );
1608 assert_eq!(
1609 CallableFallbackPolicy::RuntimeNameResolution.resolution_name_for(&whitespace_method),
1610 None
1611 );
1612 assert_eq!(
1613 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&single_external),
1614 None
1615 );
1616 assert_eq!(
1617 CallableFallbackPolicy::ExternalBoundary.resolution_name_for(&single_external),
1618 None
1619 );
1620 assert_eq!(
1621 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&qualified_external),
1622 Some("OverIdx.plus".into())
1623 );
1624 assert_eq!(
1625 CallableFallbackPolicy::ExternalBoundary.resolution_name_for(&qualified_external),
1626 Some("OverIdx.plus".into())
1627 );
1628 assert_eq!(
1629 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&whitespace_external),
1630 None
1631 );
1632 assert_eq!(
1633 CallableFallbackPolicy::ExternalBoundary.resolution_name_for(&whitespace_external),
1634 None
1635 );
1636 assert_eq!(
1637 CallableFallbackPolicy::ExternalBoundary.vm_fallback_name_for(&malformed_external),
1638 None
1639 );
1640 }
1641}