lisette_syntax/program/resolution.rs
1//! Resolution metadata attached to `Expression::Call` and
2//! `Expression::DotAccess` during type checking. Inference populates these
3//! so downstream consumers (the emitter in particular) do not re-derive the
4//! classification from the typed AST.
5
6use crate::types::Type;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum ReceiverCoercion {
10 /// Insert `&` to convert `T` to `Ref<T>`
11 AutoAddress,
12 /// Insert `*` to convert `Ref<T>` to `T`
13 AutoDeref,
14}
15
16/// What a dot access resolved to during type checking.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum DotAccessKind {
19 /// Named struct field access
20 StructField { is_exported: bool },
21 /// Tuple struct field access (e.g., `point.0` on `struct Point(int, int)`).
22 /// `is_newtype` is true when the struct has exactly 1 field and no generics,
23 /// meaning access should emit a type cast rather than `.F0`.
24 TupleStructField { is_newtype: bool },
25 /// Tuple element access (e.g., `t.0`, `t.1`)
26 TupleElement,
27 /// Module member access (e.g., `mod.func`)
28 ModuleMember,
29 /// Value enum variant (Go constant, e.g., `reflect.String`)
30 ValueEnumVariant,
31 /// ADT enum variant constructor (e.g., `makeColorRed[T]()`)
32 EnumVariant,
33 /// Instance method (has `self` receiver)
34 InstanceMethod { is_exported: bool },
35 /// Instance method used as a first-class value (not called).
36 /// E.g., `Point.area` used as a callback. The emitter needs to know
37 /// whether the receiver is a pointer to emit Go method expression syntax.
38 InstanceMethodValue {
39 is_exported: bool,
40 is_pointer_receiver: bool,
41 },
42 /// Static method (no `self` receiver)
43 StaticMethod { is_exported: bool },
44}
45
46/// What kind of native built-in type (Slice, Map, Channel, etc.) a call targets.
47/// Defined here so semantics can classify calls without depending on
48/// emit-specific types. The emitter maps this to its internal `NativeGoType`.
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum NativeTypeKind {
51 Slice,
52 EnumeratedSlice,
53 Map,
54 Channel,
55 Sender,
56 Receiver,
57 String,
58}
59
60impl NativeTypeKind {
61 pub fn from_type(ty: &Type) -> Option<Self> {
62 let resolved = ty.strip_refs();
63 // Skip module namespaces and Go-imported types: their leaf name can
64 // collide with a native type (e.g. `Slice`), but they are not native.
65 if resolved.as_import_namespace().is_some() {
66 return None;
67 }
68 if let Type::Nominal { ref id, .. } = resolved
69 && id.as_str().starts_with("go:")
70 {
71 return None;
72 }
73 let name = resolved.get_name()?;
74 Self::from_name(name)
75 }
76
77 pub fn from_name(name: &str) -> Option<Self> {
78 match name {
79 "Slice" => Some(Self::Slice),
80 "EnumeratedSlice" => Some(Self::EnumeratedSlice),
81 "Map" => Some(Self::Map),
82 "Channel" => Some(Self::Channel),
83 "Sender" => Some(Self::Sender),
84 "Receiver" => Some(Self::Receiver),
85 "string" => Some(Self::String),
86 _ => None,
87 }
88 }
89}
90
91/// What a call expression resolved to during type checking.
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub enum CallKind {
94 /// Regular function or method call
95 Regular,
96 /// Tuple struct constructor (e.g., `Point(1, 2)`)
97 TupleStructConstructor,
98 /// Type assertion (`assert_type`)
99 AssertType,
100 /// UFCS method call: `receiver.method()` where method is a free function
101 UfcsMethod,
102 /// Native type constructor (e.g., `Channel.new`, `Map.new`, `Slice.new`)
103 NativeConstructor(NativeTypeKind),
104 /// Native type instance method via dot access (e.g., `slice.append(x)`)
105 NativeMethod(NativeTypeKind),
106 /// Native type method via identifier (e.g., `Slice.contains(s, x)`)
107 NativeMethodIdentifier(NativeTypeKind),
108 /// Receiver method in UFCS syntax: `Type.method(receiver, args)`
109 ReceiverMethodUfcs { is_public: bool },
110}