1use std::sync::Arc;
2
3use piston_meta::bootstrap::Convert;
4use range::Range;
5use crate::Dfn;
6
7#[derive(Debug, Clone, PartialEq)]
9pub enum Type {
10 Unreachable,
12 Void,
14 Any,
16 Bool,
18 F64,
20 Vec4,
22 Mat4,
24 Str,
26 Link,
28 Array(Box<Type>),
30 Object,
32 Option(Box<Type>),
34 Result(Box<Type>),
36 Secret(Box<Type>),
38 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
40 Thread(Box<Type>),
41 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
43 In(Box<Type>),
44 AdHoc(Arc<String>, Box<Type>),
46 Closure(Box<Dfn>),
48}
49
50impl Type {
51 pub fn all_ext(args: Vec<Type>, ret: Type) -> (Vec<Arc<String>>, Vec<Type>, Type) {
55 use crate::T;
56 use Type::AdHoc;
57
58 (
59 vec![T.clone()],
60 args.into_iter()
61 .map(|arg| AdHoc(T.clone(), Box::new(arg)))
62 .collect(),
63 AdHoc(T.clone(), Box::new(ret)),
64 )
65 }
66
67 pub fn description(&self) -> String {
69 use Type::*;
70
71 match *self {
72 Unreachable => "unreachable".into(),
73 Void => "void".into(),
74 Any => "any".into(),
75 Bool => "bool".into(),
76 F64 => "f64".into(),
77 Vec4 => "vec4".into(),
78 Mat4 => "mat4".into(),
79 Str => "str".into(),
80 Link => "link".into(),
81 Array(ref ty) => {
82 if let Any = **ty {
83 "[]".into()
84 } else {
85 let mut res = String::from("[");
86 res.push_str(&ty.description());
87 res.push(']');
88 res
89 }
90 }
91 Object => "{}".into(),
92 Option(ref ty) => {
93 if let Any = **ty {
94 "opt".into()
95 } else {
96 let mut res = String::from("opt[");
97 res.push_str(&ty.description());
98 res.push(']');
99 res
100 }
101 }
102 Result(ref ty) => {
103 if let Any = **ty {
104 "res".into()
105 } else {
106 let mut res = String::from("res[");
107 res.push_str(&ty.description());
108 res.push(']');
109 res
110 }
111 }
112 Secret(ref ty) => match **ty {
113 Bool => "sec[bool]".into(),
114 F64 => "sec[f64]".into(),
115 _ => panic!("Secret only supports `bool` and `f64`"),
116 },
117 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
118 Thread(ref ty) => {
119 if let Any = **ty {
120 "thr".into()
121 } else {
122 let mut res = String::from("thr[");
123 res.push_str(&ty.description());
124 res.push(']');
125 res
126 }
127 }
128 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
129 In(ref ty) => {
130 if let Any = **ty {
131 "in".into()
132 } else {
133 let mut res = String::from("in[");
134 res.push_str(&ty.description());
135 res.push(']');
136 res
137 }
138 }
139 AdHoc(ref ad, ref ty) => (&**ad).clone() + " " + &ty.description(),
140 Closure(ref closure) => {
141 let mut s = String::new();
142 s.push_str("\\(");
143 for (i, ty) in closure.tys.iter().enumerate() {
144 s.push_str(&ty.description());
145 if i + 1 < closure.tys.len() {
146 s.push_str(", ");
147 }
148 }
149 s.push_str(") -> ");
150 s.push_str(&closure.ret.description());
151 s
152 }
153 }
154 }
155
156 pub fn array() -> Type {
158 Type::Array(Box::new(Type::Any))
159 }
160
161 pub fn object() -> Type {
163 Type::Object
164 }
165
166 pub fn option() -> Type {
168 Type::Option(Box::new(Type::Any))
169 }
170
171 pub fn result() -> Type {
173 Type::Result(Box::new(Type::Any))
174 }
175
176 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
178 pub fn thread() -> Type {
179 Type::Thread(Box::new(Type::Any))
180 }
181
182 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
184 pub fn in_ty() -> Type {
185 Type::In(Box::new(Type::Any))
186 }
187
188 pub fn bind_ty_vars(
192 &self,
193 refine: &Type,
194 names: &[Arc<String>],
195 ty_vars: &mut Vec<Option<Arc<String>>>,
196 ) -> Result<Type, String> {
197 if names.is_empty() {
198 return Ok(self.clone());
199 };
200 match (self, refine) {
201 (
202 &Type::AdHoc(ref a_name, ref a_inner_ty),
203 &Type::AdHoc(ref b_name, ref b_inner_ty),
204 ) => {
205 for i in 0..names.len() {
206 if a_name == &names[i] {
207 let new_inner = a_inner_ty.bind_ty_vars(b_inner_ty, names, ty_vars)?;
208 if let Some(ref existing_name) = ty_vars[i] {
209 if existing_name != b_name
210 && new_inner.goes_with(b_inner_ty)
211 && !new_inner.ambiguous(b_inner_ty)
212 {
213 return Err(format!(
214 "Type mismatch (#1500): Expected `{}`, found `{}`",
215 existing_name, b_name
216 ));
217 } else {
218 return Ok(Type::AdHoc(existing_name.clone(), Box::new(new_inner)));
219 }
220 } else {
221 ty_vars[i] = Some(b_name.clone());
222 return Ok(Type::AdHoc(
223 b_name.clone(),
224 Box::new(a_inner_ty.bind_ty_vars(b_inner_ty, names, ty_vars)?),
225 ));
226 }
227 }
228 }
229 Ok(Type::AdHoc(
230 a_name.clone(),
231 Box::new(a_inner_ty.bind_ty_vars(b_inner_ty, names, ty_vars)?),
232 ))
233 }
234 (&Type::AdHoc(ref a_name, ref a_inner_ty), b) => {
235 for i in 0..names.len() {
236 if a_name == &names[i] {
237 let new_inner = a_inner_ty.bind_ty_vars(refine, names, ty_vars)?;
238 if let Some(ref n) = ty_vars[i] {
239 if new_inner.goes_with(b) && !new_inner.ambiguous(b) {
240 return Err(format!(
241 "Type mismatch (#1600): Expected `{}`, found no ad-hoc type",
242 n
243 ));
244 }
245 } else {
246 break;
247 }
248 }
249 }
250 a_inner_ty.bind_ty_vars(refine, names, ty_vars)
251 }
252 _ => Ok(self.clone()),
253 }
254 }
255
256 pub fn insert_var(&mut self, name: &Arc<String>, val: &Arc<String>) {
258 match *self {
259 Type::AdHoc(ref mut n, ref mut inner_ty) => {
260 if n == name {
261 *n = val.clone();
262 }
263 inner_ty.insert_var(name, val)
264 }
265 _ => {}
266 }
267 }
268
269 pub fn insert_none_var(&mut self, name: &Arc<String>) {
271 match *self {
272 Type::AdHoc(_, ref mut inner_ty) => {
273 inner_ty.insert_none_var(name);
274 *self = (**inner_ty).clone();
275 }
276 _ => {}
277 }
278 }
279
280 pub fn ambiguous(&self, refine: &Type) -> bool {
286 use self::Type::*;
287
288 match (self, refine) {
289 (&AdHoc(ref xa, ref xb), &AdHoc(ref ya, ref yb)) if xa == ya => xb.ambiguous(yb),
290 (&AdHoc(_, ref x), y) if x.goes_with(y) => true,
291 (&Array(ref x), &Array(ref y)) if x.ambiguous(y) => true,
292 (&Option(ref x), &Option(ref y)) if x.ambiguous(y) => true,
293 (&Result(ref x), &Result(ref y)) if x.ambiguous(y) => true,
294 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
295 (&Thread(ref x), &Thread(ref y)) if x.ambiguous(y) => true,
296 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
297 (&In(ref x), &In(ref y)) if x.ambiguous(y) => true,
298 (&Bool, &Any) => true,
299 (&F64, &Any) => true,
300 (&Str, &Any) => true,
301 (&Vec4, &Any) => true,
302 (&Mat4, &Any) => true,
303 (&Link, &Any) => true,
304 (&Array(_), &Any) => true,
305 (&Option(_), &Any) => true,
306 (&Result(_), &Any) => true,
307 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
308 (&Thread(_), &Any) => true,
309 (&Secret(_), &Any) => true,
310 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
311 (&In(_), &Any) => true,
312 _ => false,
313 }
314 }
315
316 pub fn closure_ret_ty(&self) -> Option<Type> {
318 use self::Type::*;
319
320 match *self {
321 Closure(ref ty) => Some(ty.ret.clone()),
322 AdHoc(_, ref x) => x.closure_ret_ty(),
323 Any => Some(Type::Any),
324 _ => None,
325 }
326 }
327
328 pub fn goes_with(&self, other: &Type) -> bool {
335 use self::Type::*;
336
337 if let AdHoc(_, _) = *other {
339 if let AdHoc(_, _) = *self {
340 } else {
341 return other.goes_with(self);
342 }
343 }
344 if let Secret(ref other_ty) = *other {
345 return if let Secret(ref this_ty) = *self {
346 this_ty.goes_with(other_ty)
347 } else {
348 self.goes_with(other_ty)
349 };
350 }
351 match self {
352 &Unreachable => true,
354 _ if *other == Unreachable => true,
355 &Any => *other != Void,
356 &Void => *other == Void,
358 &Array(ref arr) => {
359 if let Array(ref other_arr) = *other {
360 arr.goes_with(other_arr)
361 } else {
362 matches!(*other, Any)
363 }
364 }
365 &Object => {
366 if let Object = *other {
367 true
368 } else {
369 matches!(*other, Any)
370 }
371 }
372 &Option(ref opt) => {
373 if let Option(ref other_opt) = *other {
374 opt.goes_with(other_opt)
375 } else {
376 matches!(*other, Any)
377 }
378 }
379 &Result(ref res) => {
380 if let Result(ref other_res) = *other {
381 res.goes_with(other_res)
382 } else if let Any = *other {
383 true
384 } else {
385 false
386 }
387 }
388 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
389 &Thread(ref thr) => {
390 if let Thread(ref other_thr) = *other {
391 thr.goes_with(other_thr)
392 } else if let Any = *other {
393 true
394 } else {
395 false
396 }
397 }
398 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
399 &In(ref in_ty) => {
400 if let In(ref other_ty) = *other {
401 in_ty.goes_with(other_ty)
402 } else if let Any = *other {
403 true
404 } else {
405 false
406 }
407 }
408 &Closure(ref cl) => {
409 if let Closure(ref other_cl) = *other {
410 if cl.tys.len() != other_cl.tys.len() {
411 return false;
412 }
413 if !cl
414 .tys
415 .iter()
416 .zip(other_cl.tys.iter())
417 .all(|(a, b)| a.goes_with(b))
418 {
419 return false;
420 }
421 if !cl.ret.goes_with(&other_cl.ret) {
422 return false;
423 }
424 true
425 } else if let Any = *other {
426 true
427 } else {
428 false
429 }
430 }
431 &AdHoc(ref name, ref ty) => {
432 if let AdHoc(ref other_name, ref other_ty) = *other {
433 name == other_name && ty.goes_with(other_ty)
434 } else if let Void = *other {
435 false
436 } else {
437 ty.goes_with(other)
438 }
439 }
440 x if x == other => true,
442 _ if *other == Type::Any => true,
443 _ => false,
444 }
445 }
446
447 pub fn add_assign(&self, other: &Type) -> bool {
449 use self::Type::*;
450
451 match (self, other) {
452 (&AdHoc(ref name, ref ty), &AdHoc(ref other_name, ref other_ty)) => {
453 if name != other_name {
454 return false;
455 }
456 if !ty.goes_with(other_ty) {
457 return false;
458 }
459 ty.add_assign(other_ty)
460 }
461 (&AdHoc(_, _), _) | (_, &AdHoc(_, _)) => false,
462 (&Void, _) | (_, &Void) => false,
463 _ => true,
464 }
465 }
466
467 pub fn from_meta_data(
469 node: &str,
470 mut convert: Convert,
471 ignored: &mut Vec<Range>,
472 ) -> Result<(Range, Type), ()> {
473 let start = convert;
474 let start_range = convert.start_node(node)?;
475 convert.update(start_range);
476
477 let mut ty: Option<Type> = None;
478 loop {
479 if let Ok(range) = convert.end_node(node) {
480 convert.update(range);
481 break;
482 } else if let Ok((range, _)) = convert.meta_bool("any") {
483 convert.update(range);
484 ty = Some(Type::Any);
485 } else if let Ok((range, _)) = convert.meta_bool("bool") {
486 convert.update(range);
487 ty = Some(Type::Bool);
488 } else if let Ok((range, _)) = convert.meta_bool("sec_bool") {
489 convert.update(range);
490 ty = Some(Type::Secret(Box::new(Type::Bool)));
491 } else if let Ok((range, _)) = convert.meta_bool("f64") {
492 convert.update(range);
493 ty = Some(Type::F64);
494 } else if let Ok((range, _)) = convert.meta_bool("sec_f64") {
495 convert.update(range);
496 ty = Some(Type::Secret(Box::new(Type::F64)));
497 } else if let Ok((range, _)) = convert.meta_bool("str") {
498 convert.update(range);
499 ty = Some(Type::Str);
500 } else if let Ok((range, _)) = convert.meta_bool("vec4") {
501 convert.update(range);
502 ty = Some(Type::Vec4);
503 } else if let Ok((range, _)) = convert.meta_bool("mat4") {
504 convert.update(range);
505 ty = Some(Type::Mat4);
506 } else if let Ok((range, _)) = convert.meta_bool("link") {
507 convert.update(range);
508 ty = Some(Type::Link);
509 } else if let Ok((range, _)) = convert.meta_bool("opt_any") {
510 convert.update(range);
511 ty = Some(Type::Option(Box::new(Type::Any)));
512 } else if let Ok((range, _)) = convert.meta_bool("res_any") {
513 convert.update(range);
514 ty = Some(Type::Result(Box::new(Type::Any)));
515 } else if let Ok((range, _)) = convert.meta_bool("arr_any") {
516 convert.update(range);
517 ty = Some(Type::Array(Box::new(Type::Any)));
518 } else if let Ok((range, _)) = convert.meta_bool("obj_any") {
519 convert.update(range);
520 ty = Some(Type::Object);
521 } else if let Ok((range, val)) = Type::from_meta_data("opt", convert, ignored) {
522 convert.update(range);
523 ty = Some(Type::Option(Box::new(val)));
524 } else if let Ok((range, val)) = Type::from_meta_data("res", convert, ignored) {
525 convert.update(range);
526 ty = Some(Type::Result(Box::new(val)));
527 } else if let Ok((range, val)) = Type::from_meta_data("arr", convert, ignored) {
528 convert.update(range);
529 ty = Some(Type::Array(Box::new(val)));
530 } else if let Ok((range, val)) = convert.meta_string("ad_hoc") {
531 convert.update(range);
532 let inner_ty =
533 if let Ok((range, val)) = Type::from_meta_data("ad_hoc_ty", convert, ignored) {
534 convert.update(range);
535 val
536 } else {
537 Type::Object
538 };
539 ty = Some(Type::AdHoc(val, Box::new(inner_ty)));
540 } else if let Ok(range) = convert.start_node("closure_type") {
541 convert.update(range);
542 let mut lts = vec![];
543 let mut tys = vec![];
544 while let Ok((range, val)) = Type::from_meta_data("cl_arg", convert, ignored) {
545 use crate::Lt;
546
547 convert.update(range);
548 lts.push(Lt::Default);
549 tys.push(val);
550 }
551 let (range, ret) = Type::from_meta_data("cl_ret", convert, ignored)?;
552 convert.update(range);
553 let range = convert.end_node("closure_type")?;
554 convert.update(range);
555 ty = Some(Type::Closure(Box::new(Dfn {
556 lts,
557 tys,
558 ret,
559 ext: vec![],
560 lazy: crate::LAZY_NO,
561 })));
562 } else {
563 loop {
564 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
565 if let Ok((range, _)) = convert.meta_bool("thr_any") {
566 convert.update(range);
567 ty = Some(Type::Thread(Box::new(Type::Any)));
568 break;
569 }
570 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
571 if let Ok((range, val)) = Type::from_meta_data("thr", convert, ignored) {
572 convert.update(range);
573 ty = Some(Type::Thread(Box::new(val)));
574 break;
575 }
576 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
577 if let Ok((range, _)) = convert.meta_bool("in_any") {
578 convert.update(range);
579 ty = Some(Type::In(Box::new(Type::Any)));
580 break;
581 }
582 #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
583 if let Ok((range, val)) = Type::from_meta_data("in", convert, ignored) {
584 convert.update(range);
585 ty = Some(Type::In(Box::new(val)));
586 break;
587 }
588 let range = convert.ignore();
589 convert.update(range);
590 ignored.push(range);
591 break;
592 }
593 }
594 }
595
596 Ok((convert.subtract(start), ty.ok_or(())?))
597 }
598}