yog_script_analyze/typeck/
mod.rs1mod arrays;
9mod attributes;
10mod awaits;
11mod betterness;
12mod bits;
13mod builtin;
14mod callees;
15mod calls;
16mod collections;
17pub mod commands;
18mod constraints;
19mod content;
20mod content_ids;
21mod context;
22mod copy;
23mod ctors;
24mod decls;
25mod delegates;
26mod exprs;
27mod game;
28mod generics;
29mod groups;
30mod indexers;
31mod inherit;
32mod iterators;
33mod list_patterns;
34mod lambdas;
35mod lineage;
36mod macro_calls;
37mod members;
38mod messages;
39mod model;
40mod mutation;
41mod names;
42mod nulls;
43mod operators;
44mod overloads;
45mod own;
46mod passing;
47mod pick;
48mod shapes;
49mod required;
50mod stmts;
51mod templates;
52pub(crate) mod surface;
53mod threads;
54mod tuples;
55mod types;
56mod variance;
57mod variants;
58mod written;
59
60use std::collections::HashMap;
61
62pub use content::content_path;
63pub use iterators::{body_yields, item_of};
64pub use model::Type;
65pub use nulls::leaves;
66pub use list_patterns::list_item;
67pub use templates::{MessageTemplate, holes};
68pub use types::{Message, MethodUse, OperatorUse, Quoted, Types};
69
70use crate::ast::File;
71use crate::index::{ClassIndex, Lookup, Side};
72use own::OwnTypes;
73use yog_analysis::Report;
74
75struct Slot {
77 ty: Type,
78 fixed: bool,
79}
80
81pub(crate) struct Checker<'r, 's, 'i> {
82 report: &'r mut Report<'s>,
83 lookup: Option<Lookup<'i>>,
84 own: OwnTypes,
85 scopes: Vec<HashMap<String, Slot>>,
87 in_content: bool,
91 readonly_this: bool,
92 this: Option<Type>,
94 side: Side,
96 returns: Option<Type>,
98 yields: Option<Type>,
100 switched: Vec<Type>,
102 inferred: Option<Vec<Type>>,
104 directives: names::Directives,
106 ns: Vec<String>,
108 nanites: bool,
110 to_server: bool,
112 content: Option<Vec<(String, String)>>,
114 type_params: Vec<generics::Bound>,
116 types: Types,
118 bases: lineage::Bases,
120 delegates: delegates::Delegates,
122 operators: operators::Operators,
124 lambdas: Vec<(usize, usize)>,
127 unsafe_code: usize,
129 constraints: Vec<constraints::Constraints>,
131 meeting: bool,
133 non_null: Vec<(usize, String)>,
136 local_fns: Vec<(usize, crate::ast::Method)>,
139 indexing: bool,
141}
142
143pub(crate) struct Allowed {
146 pub nanites: bool,
147 pub to_server: bool,
148 pub content: Option<Vec<(String, String)>>,
151}
152
153pub fn builtin_type(word: &str) -> Option<Type> {
156 builtin::by_word(word)
157}
158
159pub fn system_type(name: &str) -> Option<Type> {
162 builtin::by_system_name(name)
163 .or_else(|| content_ids::content_id_kind(name).map(|k| Type::Content(k.to_string())))
164}
165
166pub fn system_name(t: &Type) -> Option<&'static str> {
169 builtin::system_name(t)
170}
171
172pub(crate) fn check<'d>(
175 file: &'d File,
176 allowed: Allowed,
177 (index, others): (Option<&ClassIndex>, &[&'d [crate::ast::Decl]]),
178 report: &mut Report<'_>,
179) -> Types {
180 let mut own = OwnTypes::collect_project(&crate::system::DECLS, others, &file.decls);
181 for decls in others {
182 own.extensions(decls);
183 }
184 own.extensions(&file.decls);
185 let mut c = Checker {
186 report,
187 lookup: index.map(ClassIndex::lookup),
188 own,
189 scopes: vec![HashMap::new()],
190 this: None,
191 side: Side::Shared,
192 returns: None,
193 yields: None,
194 switched: Vec::new(),
195 inferred: None,
196 directives: names::Directives::collect(&file.decls),
197 ns: Vec::new(),
198 nanites: allowed.nanites,
199 to_server: allowed.to_server,
200 content: allowed.content,
201 type_params: Vec::new(),
202 readonly_this: false,
203 in_content: false,
204 types: Types::default(),
205 bases: lineage::Bases::new(),
206 delegates: delegates::Delegates::new(),
207 operators: operators::Operators::new(),
208 lambdas: Vec::new(),
209 unsafe_code: 0,
210 constraints: Vec::new(),
211 meeting: false,
212 non_null: Vec::new(),
213 local_fns: Vec::new(),
214 indexing: false,
215 };
216 c.type_bases();
217 c.type_delegates();
218 c.type_operators();
219 c.decls(&file.decls);
220 inherit::check((&crate::system::DECLS, others), &file.decls, c.report);
221 c.types
222}
223
224impl Checker<'_, '_, '_> {
225 fn scoped<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
227 self.scopes.push(HashMap::new());
228 let out = f(self);
229 self.scopes.pop();
230 self.scopes_left(self.scopes.len());
231 let depth = self.scopes.len();
232 self.local_fns.retain(|(d, _)| *d <= depth);
233 out
234 }
235
236 fn bind(&mut self, name: &str, t: Type) {
237 self.bind_as(name, t, false);
238 }
239
240 fn bind_as(&mut self, name: &str, ty: Type, fixed: bool) {
243 self.non_null.retain(|(_, n)| n != name);
245 if let Some(s) = self.scopes.last_mut() {
246 s.insert(name.to_string(), Slot { ty, fixed });
247 }
248 }
249
250 fn local(&self, name: &str) -> Option<&Type> {
251 self.slot(name).map(|s| &s.ty)
252 }
253
254 fn slot(&self, name: &str) -> Option<&Slot> {
255 self.scopes.iter().rev().find_map(|s| s.get(name))
256 }
257
258 fn converts(&self, got: &Type, wanted: &Type) -> bool {
261 self.converts_plainly(got, wanted) || self.implicit(got, wanted).is_some()
262 }
263
264 fn converts_plainly(&self, got: &Type, wanted: &Type) -> bool {
268 if got.converts_to(wanted) {
269 return true;
270 }
271 if got.is_nullable() && !wanted.is_nullable() {
272 return false;
273 }
274 match (got.non_null(), wanted.non_null()) {
275 (Type::Own(a, xs), Type::Own(b, ys)) => self.own_converts(a, xs, (b, ys), true),
277 (Type::Array(..), wanted) => self.array_converts(got.non_null(), wanted),
278 (got @ (Type::Content(_) | Type::Tag(_)), wanted) => content_ids::id_converts(got, wanted),
280 (Type::Tuple(got, _), Type::Tuple(wanted, _)) => self.tuple_converts(got, wanted),
281 (Type::Fn(..), Type::Own(..)) => {
283 match (self.delegate_sig(got), self.delegate_sig(wanted)) {
284 (Some((gp, gr)), Some((wp, wr))) => {
285 gp.len() == wp.len()
286 && wp.iter().zip(&gp).all(|(w, g)| self.converts(w, g))
287 && self.converts(&gr, &wr)
288 }
289 _ => false,
290 }
291 }
292 _ => false,
293 }
294 }
295
296 fn base(&self) -> Type {
298 match &self.this {
299 Some(Type::Own(name, _)) => self
300 .own
301 .base_class(name)
302 .map_or(Type::Unknown, |b| Type::own(b.to_string())),
303 _ => Type::Unknown,
304 }
305 }
306
307 fn within<R>(
309 &mut self,
310 this: Option<Type>,
311 side: Side,
312 returns: Option<Type>,
313 f: impl FnOnce(&mut Self) -> R,
314 ) -> R {
315 let saved = (
316 std::mem::replace(&mut self.this, this),
317 self.side,
318 std::mem::replace(&mut self.returns, returns),
319 );
320 self.side = side;
321 let out = self.scoped(f);
322 (self.this, self.side, self.returns) = saved;
323 out
324 }
325}