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