Skip to main content

yog_script_analyze/typeck/
types.rs

1//! Each expression's type, as the checker found it: what a compiler needs
2//! to write the code (a local's declaration, a value boxed, a switch's
3//! result) and an editor to show.
4
5use std::collections::HashMap;
6
7use super::model::Type;
8use crate::ast::Expr;
9
10/// The types of a checked file's expressions. An expression is known by
11/// its node in the file's tree — which, once checked, isn't changed — so
12/// two that share a place (a macro's output, all at its call) stay apart.
13#[derive(Debug, Default)]
14pub struct Types {
15    types: HashMap<usize, Type>,
16    /// The operators a type declares that expressions are (`a + b`, `-a`,
17    /// `(Energy)n`), by expression.
18    operators: HashMap<usize, OperatorUse>,
19    /// The implicit conversions values go through where they're handed
20    /// on, by expression.
21    conversions: HashMap<usize, OperatorUse>,
22    /// The types values are recast to where they go by variance only (the
23    /// JVM's generics have none), by expression.
24    recasts: HashMap<usize, Type>,
25    /// The lambdas given where an expression tree is wanted
26    /// (`Expression<Func<i32, bool>>`), by the lambda.
27    quoted: HashMap<usize, Quoted>,
28    /// What each `foreach`'s items are, by what it goes through.
29    items: HashMap<usize, Type>,
30    /// The type of each name a pattern binds (`let r`, `Monster m`), by the name.
31    bindings: HashMap<usize, Type>,
32    /// The constructor each `new T(…)` chose: which of the type's, its body's
33    /// in order and then its primary one, by the `new`.
34    constructors: HashMap<usize, usize>,
35    /// A `new` whose constructor's `params` takes its arguments from one on
36    /// (the call's expanded form): from where, and the array's item type.
37    constructor_rests: HashMap<usize, (usize, Type)>,
38    /// The method each call chose, by the call.
39    methods: HashMap<usize, MethodUse>,
40    /// Calls across sides, by the call.
41    messages: HashMap<usize, Message>,
42    /// The operators `op=` applies (`v += w` on a `Vec`), by the place it
43    /// writes.
44    assigned: HashMap<usize, OperatorUse>,
45    /// The names that are a local's or a parameter's (not a member's), by
46    /// the name's expression.
47    locals: std::collections::HashSet<usize>,
48    /// The bound a type parameter's value is reached through, by the
49    /// value (`t.Score()` of `where T : IScore`: `IScore`).
50    bounded: HashMap<usize, Type>,
51    /// The locals each lambda handed to another thread takes from its
52    /// owner (not `Copy`): moved there, by the lambda.
53    moved_away: HashMap<usize, Vec<String>>,
54    /// The strings written for message templates, by the string.
55    templates: HashMap<usize, super::templates::MessageTemplate>,
56    /// What each lambda captures, by the lambda (`threads/captures.rs`).
57    captures: HashMap<usize, Vec<super::threads::Capture>>,
58}
59
60/// A lambda given as an expression tree: its delegate's type, and the
61/// parameters and result the delegate gives it.
62#[derive(Debug, Clone, PartialEq)]
63pub struct Quoted {
64    pub delegate: Type,
65    pub params: Vec<Type>,
66    pub ret: Type,
67}
68
69/// An operator or a conversion a type declares, as used: the type, its
70/// method (`op_Addition`, `op_Implicit`).
71#[derive(Debug, Clone, PartialEq)]
72pub struct OperatorUse {
73    pub owner: Type,
74    pub method: String,
75}
76
77/// A method as a call chose it: its type (none: the file's), its name,
78/// which of the type's methods of that name (in declaration order), its
79/// parameters and result as declared (its type parameters unbound).
80/// A call across sides: the file's method it runs on the other side, and
81/// which way it goes.
82#[derive(Debug, Clone, PartialEq)]
83pub struct Message {
84    pub method: String,
85    /// From a client to the server (else from the server to a client).
86    pub to_server: bool,
87}
88
89#[derive(Debug, Clone, PartialEq)]
90pub struct MethodUse {
91    pub owner: Option<String>,
92    /// Its type's arity (`ValueTuple<T1, T2>`'s 2): one of its name.
93    pub owner_arity: usize,
94    pub name: String,
95    pub overload: usize,
96    pub params: Vec<Type>,
97    pub ret: Type,
98    /// Its parameters as the call takes them (its type parameters bound).
99    pub taken: Vec<Type>,
100    /// Its own type parameters' types in this call, in order.
101    pub type_args: Vec<Type>,
102    /// An extension method (`xs.Where(…)`): the receiver its first argument.
103    pub extension: bool,
104    /// How many type parameters of its own it has (`F<A, B>`: 2).
105    pub generics: usize,
106    /// Its `params` parameter takes the arguments from this one on, packed
107    /// in an array of its item type (the call's expanded form).
108    pub rest_from: Option<usize>,
109}
110
111impl Types {
112    /// The type `e`'s value is recast to, going where it's wanted by
113    /// variance (`IEnumerable<string>` as an `IEnumerable<object>`).
114    /// Lambda `e` as an expression tree, when it's given as one.
115    pub fn quoted(&self, e: &Expr) -> Option<&Quoted> {
116        self.quoted.get(&key(e))
117    }
118
119    pub(super) fn set_quoted(&mut self, e: &Expr, quoted: Quoted) {
120        self.quoted.insert(key(e), quoted);
121    }
122
123    pub fn recast(&self, e: &Expr) -> Option<&Type> {
124        self.recasts.get(&key(e))
125    }
126
127    pub(super) fn set_recast(&mut self, e: &Expr, to: Type) {
128        self.recasts.insert(key(e), to);
129    }
130
131    /// The method call `e` chose, when it's an own one.
132    /// What `foreach` over `iter` gives each time.
133    pub fn item(&self, iter: &Expr) -> Option<&Type> {
134        self.items.get(&key(iter))
135    }
136
137    pub(super) fn set_item(&mut self, iter: &Expr, t: Type) {
138        self.items.insert(key(iter), t);
139    }
140
141    /// The type of name `n` a pattern binds.
142    pub fn binding(&self, n: &crate::ast::Name) -> Option<&Type> {
143        self.bindings.get(&(std::ptr::from_ref(n) as usize))
144    }
145
146    pub(super) fn set_binding(&mut self, n: &crate::ast::Name, t: Type) {
147        self.bindings.insert(std::ptr::from_ref(n) as usize, t);
148    }
149
150    /// Which of its type's constructors `new` expression `e` chose.
151    pub fn constructor(&self, e: &Expr) -> Option<usize> {
152        self.constructors.get(&key(e)).copied()
153    }
154
155    /// Where `new` expression `e`'s `params` arguments start, and their
156    /// item type, when it packs them.
157    pub fn constructor_rest(&self, e: &Expr) -> Option<&(usize, Type)> {
158        self.constructor_rests.get(&key(e))
159    }
160
161    pub(super) fn set_constructor_rest(&mut self, e: &Expr, from: usize, item: Type) {
162        self.constructor_rests.insert(key(e), (from, item));
163    }
164
165    pub(super) fn set_constructor(&mut self, e: &Expr, index: usize) {
166        self.constructors.insert(key(e), index);
167    }
168
169    pub fn method(&self, e: &Expr) -> Option<&MethodUse> {
170        self.methods.get(&key(e))
171    }
172
173    /// Call `e` across sides, when it's one.
174    pub fn message(&self, e: &Expr) -> Option<&Message> {
175        self.messages.get(&key(e))
176    }
177
178    pub(super) fn set_message(&mut self, e: &Expr, m: Message) {
179        self.messages.insert(key(e), m);
180    }
181
182    /// Whether name `e` is a local's or a parameter's (not a member's).
183    pub fn is_local(&self, e: &Expr) -> bool {
184        self.locals.contains(&key(e))
185    }
186
187    /// What lambda `e` captures: locals of the code around it, `this`,
188    /// statics it reaches.
189    pub(super) fn captures(&self, e: &Expr) -> &[super::threads::Capture] {
190        self.captures.get(&key(e)).map_or(&[], Vec::as_slice)
191    }
192
193    /// The locals lambda `e` takes with it to another thread: moved away
194    /// from the code around it.
195    pub fn moved_away(&self, e: &Expr) -> &[String] {
196        self.moved_away.get(&key(e)).map_or(&[], Vec::as_slice)
197    }
198
199    pub(super) fn set_moved_away(&mut self, e: &Expr, names: Vec<String>) {
200        self.moved_away.insert(key(e), names);
201    }
202
203    /// Lambda `lambda` (by its key) captures `c` (once, by its name).
204    pub(super) fn capture(&mut self, lambda: usize, c: super::threads::Capture) {
205        let all = self.captures.entry(lambda).or_default();
206        if !all.iter().any(|o| o.name == c.name) {
207            all.push(c);
208        }
209    }
210
211    /// The bound value `e` (of a type parameter) is reached through.
212    pub fn bounded(&self, e: &Expr) -> Option<&Type> {
213        self.bounded.get(&key(e))
214    }
215
216    pub(super) fn set_bounded(&mut self, e: &Expr, t: Type) {
217        self.bounded.insert(key(e), t);
218    }
219
220    /// String `e` written for a message template, if it's one.
221    pub fn template(&self, e: &Expr) -> Option<&super::templates::MessageTemplate> {
222        self.templates.get(&key(e))
223    }
224
225    pub(super) fn set_template(&mut self, e: &Expr, t: super::templates::MessageTemplate) {
226        self.set(e, Type::String);
227        self.templates.insert(key(e), t);
228    }
229
230    pub(super) fn key_of(e: &Expr) -> usize {
231        key(e)
232    }
233
234    pub(super) fn set_local(&mut self, e: &Expr) {
235        self.locals.insert(key(e));
236    }
237
238    pub(super) fn set_method(&mut self, e: &Expr, used: MethodUse) {
239        self.methods.insert(key(e), used);
240    }
241
242    /// `e`'s type, if it was checked.
243    pub fn of(&self, e: &Expr) -> Option<&Type> {
244        self.types.get(&key(e))
245    }
246
247    /// The declared operator `e` is, if it's one.
248    pub fn operator(&self, e: &Expr) -> Option<&OperatorUse> {
249        self.operators.get(&key(e))
250    }
251
252    /// The implicit conversion `e`'s value goes through, if any.
253    pub fn conversion(&self, e: &Expr) -> Option<&OperatorUse> {
254        self.conversions.get(&key(e))
255    }
256
257    /// The declared operator `place op= …` applies, if it's one.
258    pub fn assigned(&self, place: &Expr) -> Option<&OperatorUse> {
259        self.assigned.get(&key(place))
260    }
261
262    pub(super) fn set(&mut self, e: &Expr, t: Type) {
263        self.types.insert(key(e), t);
264    }
265
266    pub(super) fn set_operator(&mut self, e: &Expr, used: OperatorUse) {
267        self.operators.insert(key(e), used);
268    }
269
270    pub(super) fn set_assigned(&mut self, place: &Expr, used: OperatorUse) {
271        self.assigned.insert(key(place), used);
272    }
273
274    pub(super) fn set_conversion(&mut self, e: &Expr, used: OperatorUse) {
275        self.conversions.insert(key(e), used);
276    }
277}
278
279/// A node's address: its identity in the tree.
280fn key(e: &Expr) -> usize {
281    std::ptr::from_ref(e) as usize
282}