1use crate::{qjs, Ctx, Error, Result};
2use std::{fmt, hash::Hash, mem, ops::Deref, result::Result as StdResult, str};
3
4pub mod array;
5pub mod atom;
6mod bigint;
7pub mod convert;
8pub(crate) mod exception;
9pub mod function;
10pub mod module;
11pub mod object;
12pub mod promise;
13mod string;
14mod symbol;
15
16pub use array::Array;
17pub use atom::Atom;
18pub use bigint::BigInt;
19pub use convert::{Coerced, FromAtom, FromIteratorJs, FromJs, IntoAtom, IntoJs, IteratorJs};
20pub use exception::Exception;
21pub use function::{Constructor, Function};
22pub use module::Module;
23pub use object::{Filter, Object};
24pub use promise::Promise;
25pub use string::{CString, String};
26pub use symbol::Symbol;
27
28pub mod array_buffer;
29pub mod typed_array;
30
31pub use array_buffer::ArrayBuffer;
32pub use typed_array::TypedArray;
33
34pub struct Value<'js> {
36 pub(crate) ctx: Ctx<'js>,
37 pub(crate) value: qjs::JSValue,
38}
39
40impl<'js> PartialEq for Value<'js> {
41 fn eq(&self, other: &Self) -> bool {
42 let tag = unsafe { qjs::JS_VALUE_GET_TAG(self.value) };
43 let tag_other = unsafe { qjs::JS_VALUE_GET_TAG(other.value) };
44
45 let bits = unsafe { qjs::JS_VALUE_GET_FLOAT64(self.value).to_bits() };
46 let bits_other = unsafe { qjs::JS_VALUE_GET_FLOAT64(other.value).to_bits() };
47
48 tag == tag_other && bits == bits_other
49 }
50}
51
52impl<'js> Eq for Value<'js> {}
53
54impl<'js> Hash for Value<'js> {
55 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
56 let tag = unsafe { qjs::JS_VALUE_GET_TAG(self.value) };
57 let bits = unsafe { qjs::JS_VALUE_GET_FLOAT64(self.value).to_bits() };
58 state.write_i32(tag);
59 state.write_u64(bits)
60 }
61}
62
63impl<'js> Clone for Value<'js> {
64 fn clone(&self) -> Self {
65 let ctx = self.ctx.clone();
66 let value = unsafe { qjs::JS_DupValue(ctx.as_ptr(), self.value) };
67 Self { ctx, value }
68 }
69}
70
71impl<'js> Drop for Value<'js> {
72 fn drop(&mut self) {
73 unsafe {
74 qjs::JS_FreeValue(self.ctx.as_ptr(), self.value);
75 }
76 }
77}
78
79impl<'js> fmt::Debug for Value<'js> {
80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81 let type_ = self.type_of();
82 type_.fmt(f)?;
83 use Type::*;
84 match type_ {
85 Bool | Int | Float => {
86 write!(f, "(")?;
87 match type_ {
88 Bool => unsafe { self.get_bool() }.fmt(f)?,
89 Int => unsafe { self.get_int() }.fmt(f)?,
90 Float => unsafe { self.get_float() }.fmt(f)?,
91 _ => unreachable!(),
92 }
93 write!(f, ")")?;
94 }
95 String => {
96 write!(f, "(")?;
97 unsafe { self.ref_string() }.to_string().fmt(f)?;
98 write!(f, ")")?;
99 }
100 Symbol | Object | Array | Function | Constructor | Promise => {
101 write!(f, "(")?;
102 unsafe { self.get_ptr() }.fmt(f)?;
103 write!(f, ")")?;
104 }
105 Exception => {
106 writeln!(f, "(")?;
107 self.as_exception().unwrap().fmt(f)?;
108 writeln!(f, ")")?;
109 }
110 Null => "null".fmt(f)?,
111 Undefined => "undefined".fmt(f)?,
112 Uninitialized => "uninitialized".fmt(f)?,
113 Module => "module".fmt(f)?,
114 BigInt => "BigInt".fmt(f)?,
115 Unknown => "unknown".fmt(f)?,
116 }
117 Ok(())
118 }
119}
120
121impl<'js> Value<'js> {
122 #[inline]
124 pub(crate) unsafe fn from_js_value(ctx: Ctx<'js>, value: qjs::JSValue) -> Self {
125 Self { ctx, value }
126 }
127
128 #[inline]
129 pub(crate) unsafe fn from_js_value_const(ctx: Ctx<'js>, value: qjs::JSValueConst) -> Self {
130 let value = qjs::JS_DupValue(ctx.as_ptr(), value);
131 Self { ctx, value }
132 }
133
134 #[inline]
135 pub(crate) fn as_js_value(&self) -> qjs::JSValueConst {
136 self.value
137 }
138
139 #[inline]
140 pub(crate) fn into_js_value(self) -> qjs::JSValue {
141 let value = self.value;
142 unsafe { qjs::JS_FreeContext(self.ctx.as_ptr()) };
143 mem::forget(self);
144 value
145 }
146
147 #[inline]
148 pub fn new_uninitialized(ctx: Ctx<'js>) -> Self {
149 let value = qjs::JS_UNINITIALIZED;
150 Self { ctx, value }
151 }
152
153 #[inline]
154 pub fn new_undefined(ctx: Ctx<'js>) -> Self {
155 let value = qjs::JS_UNDEFINED;
156 Self { ctx, value }
157 }
158
159 #[inline]
160 pub fn new_null(ctx: Ctx<'js>) -> Self {
161 let value = qjs::JS_NULL;
162 Self { ctx, value }
163 }
164
165 #[inline]
167 pub fn new_bool(ctx: Ctx<'js>, value: bool) -> Self {
168 let value = if value { qjs::JS_TRUE } else { qjs::JS_FALSE };
169 Self { ctx, value }
170 }
171
172 #[inline]
174 pub fn ctx(&self) -> &Ctx<'js> {
175 &self.ctx
176 }
177
178 #[inline]
180 pub(crate) unsafe fn get_bool(&self) -> bool {
181 qjs::JS_VALUE_GET_BOOL(self.value)
182 }
183
184 pub fn as_bool(&self) -> Option<bool> {
186 if self.is_bool() {
187 Some(unsafe { self.get_bool() })
188 } else {
189 None
190 }
191 }
192
193 #[inline]
195 pub fn new_int(ctx: Ctx<'js>, value: i32) -> Self {
196 let value = qjs::JS_MKVAL(qjs::JS_TAG_INT, value);
197 Self { ctx, value }
198 }
199
200 #[inline]
201 pub(crate) unsafe fn get_int(&self) -> i32 {
202 qjs::JS_VALUE_GET_INT(self.value)
203 }
204
205 pub fn as_int(&self) -> Option<i32> {
207 if self.is_int() {
208 Some(unsafe { self.get_int() })
209 } else {
210 None
211 }
212 }
213
214 #[inline]
216 pub fn new_float(ctx: Ctx<'js>, value: f64) -> Self {
217 let value = qjs::JS_NewFloat64(value);
218 Self { ctx, value }
219 }
220
221 #[inline]
222 pub(crate) unsafe fn get_float(&self) -> f64 {
223 qjs::JS_VALUE_GET_FLOAT64(self.value)
224 }
225
226 pub fn as_float(&self) -> Option<f64> {
228 if self.is_float() {
229 Some(unsafe { self.get_float() })
230 } else {
231 None
232 }
233 }
234
235 #[inline]
237 pub fn new_number(ctx: Ctx<'js>, value: f64) -> Self {
238 let int = value as i32;
239 #[allow(clippy::float_cmp)]
240 let value = if value == int as f64 {
242 qjs::JS_MKVAL(qjs::JS_TAG_INT, int)
243 } else {
244 qjs::JS_NewFloat64(value)
245 };
246 Self { ctx, value }
247 }
248
249 pub fn as_number(&self) -> Option<f64> {
251 if self.is_int() {
252 Some(unsafe { self.get_int() as _ })
253 } else if self.is_float() {
254 Some(unsafe { self.get_float() })
255 } else {
256 None
257 }
258 }
259
260 #[allow(unused)]
261 #[inline]
262 pub(crate) fn new_ptr(ctx: Ctx<'js>, tag: qjs::c_int, ptr: *mut qjs::c_void) -> Self {
263 let value = qjs::JS_MKPTR(tag, ptr);
264 Self { ctx, value }
265 }
266
267 #[allow(unused)]
268 #[inline]
269 pub(crate) fn new_ptr_const(ctx: Ctx<'js>, tag: qjs::c_int, ptr: *mut qjs::c_void) -> Self {
270 let value = unsafe { qjs::JS_DupValue(ctx.as_ptr(), qjs::JS_MKPTR(tag, ptr)) };
271 Self { ctx, value }
272 }
273
274 #[inline]
275 pub(crate) unsafe fn get_ptr(&self) -> *mut qjs::c_void {
276 qjs::JS_VALUE_GET_PTR(self.value)
277 }
278
279 #[inline]
281 pub fn is_null(&self) -> bool {
282 let tag = unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) };
283 qjs::JS_TAG_NULL == tag
284 }
285
286 #[inline]
288 pub fn is_undefined(&self) -> bool {
289 let tag = unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) };
290 qjs::JS_TAG_UNDEFINED == tag
291 }
292
293 #[inline]
295 pub fn is_bool(&self) -> bool {
296 qjs::JS_TAG_BOOL == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
297 }
298
299 #[inline]
301 pub fn is_int(&self) -> bool {
302 qjs::JS_TAG_INT == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
303 }
304
305 #[inline]
307 pub fn is_float(&self) -> bool {
308 qjs::JS_TAG_FLOAT64 == unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) }
309 }
310
311 #[inline]
313 pub fn is_number(&self) -> bool {
314 let tag = unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) };
315 qjs::JS_TAG_INT == tag || qjs::JS_TAG_FLOAT64 == tag
316 }
317
318 #[inline]
320 pub fn is_string(&self) -> bool {
321 qjs::JS_TAG_STRING == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
322 }
323
324 #[inline]
326 pub fn is_symbol(&self) -> bool {
327 qjs::JS_TAG_SYMBOL == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
328 }
329
330 #[inline]
332 pub fn is_object(&self) -> bool {
333 qjs::JS_TAG_OBJECT == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
334 }
335
336 #[inline]
338 pub fn is_module(&self) -> bool {
339 qjs::JS_TAG_MODULE == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
340 }
341
342 #[inline]
344 pub fn is_array(&self) -> bool {
345 0 != unsafe { qjs::JS_IsArray(self.ctx.as_ptr(), self.value) }
346 }
347
348 #[inline]
350 pub fn is_function(&self) -> bool {
351 (unsafe { qjs::JS_IsFunction(self.ctx.as_ptr(), self.value) } as i32) != 0
352 }
353
354 #[inline]
356 pub fn is_constructor(&self) -> bool {
357 (unsafe { qjs::JS_IsConstructor(self.ctx.as_ptr(), self.value) } as i32) != 0
358 }
359
360 #[inline]
362 pub fn is_promise(&self) -> bool {
363 (unsafe { qjs::JS_PromiseState(self.ctx.as_ptr(), self.value) } as std::os::raw::c_int) >= 0
364 }
365
366 #[inline]
368 pub fn is_exception(&self) -> bool {
369 unsafe { qjs::JS_IsException(self.value) }
370 }
371
372 #[inline]
374 pub fn is_error(&self) -> bool {
375 (unsafe { qjs::JS_IsError(self.ctx.as_ptr(), self.value) } as i32) != 0
376 }
377
378 #[inline]
380 pub fn as_value(&self) -> &Self {
381 self
382 }
383
384 #[inline]
385 pub(crate) fn into_value(self) -> Self {
386 self
387 }
388
389 pub fn get<T: FromJs<'js>>(&self) -> Result<T> {
391 T::from_js(self.ctx(), self.clone())
392 }
393
394 pub fn as_raw(&self) -> qjs::JSValue {
396 self.value
397 }
398
399 pub unsafe fn from_raw(ctx: Ctx<'js>, value: qjs::JSValue) -> Self {
407 Self::from_js_value(ctx, value)
408 }
409}
410
411impl<'js> AsRef<Value<'js>> for Value<'js> {
412 fn as_ref(&self) -> &Value<'js> {
413 self
414 }
415}
416
417macro_rules! type_impls {
418 ($($type:ident: $name:ident => $tag:ident,)*) => {
420 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
422 #[repr(u8)]
423 pub enum Type {
424 $($type,)*
425 Unknown
426 }
427
428 impl Type {
429 pub const fn is_void(self) -> bool {
431 use Type::*;
432 matches!(self, Uninitialized | Undefined | Null)
433 }
434
435 pub const fn interpretable_as(self, other: Self) -> bool {
437 use Type::*;
438
439 if (self as u8) == (other as u8){
440 return true
441 }
442 match other{
443 Float => matches!(self, Int),
444 Object => matches!(self, Array | Function | Constructor | Exception | Promise),
445 Function => matches!(self, Constructor),
446 _ => false
447 }
448 }
449
450 pub const fn as_str(self) -> &'static str {
452 match self {
453 $(Type::$type => stringify!($name),)*
454 Type::Unknown => "Unknown type",
455 }
456 }
457 }
458
459 impl AsRef<str> for Type {
460 fn as_ref(&self) -> &str {
461 self.as_str()
462 }
463 }
464
465 impl fmt::Display for Type {
466 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
467 self.as_str().fmt(f)
468 }
469 }
470
471 impl str::FromStr for Type {
472 type Err = ();
473
474 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
475 Ok(match s {
476 $(stringify!($name) => Type::$type,)*
477 _ => return Err(()),
478 })
479 }
480 }
481
482 impl<'js> Value<'js> {
483 pub fn type_of(&self) -> Type {
485 let tag = unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) };
486 match tag {
487 $(qjs::$tag if type_impls!(@cond $type self) => Type::$type,)*
488 _ => Type::Unknown,
489 }
490 }
491
492 pub fn type_name(&self) -> &'static str {
494 self.type_of().as_str()
495 }
496 }
497 };
498
499 (@cond Array $self:expr) => { $self.is_array() };
500 (@cond Constructor $self:expr) => { $self.is_constructor() };
501 (@cond Function $self:expr) => { $self.is_function() };
502 (@cond Promise $self:expr) => { $self.is_promise() };
503 (@cond Exception $self:expr) => { $self.is_error() };
504 (@cond $type:ident $self:expr) => { true };
505}
506
507type_impls! {
508 Uninitialized: uninitialized => JS_TAG_UNINITIALIZED,
509 Undefined: undefined => JS_TAG_UNDEFINED,
510 Null: null => JS_TAG_NULL,
511 Bool: bool => JS_TAG_BOOL,
512 Int: int => JS_TAG_INT,
513 Float: float => JS_TAG_FLOAT64,
514 String: string => JS_TAG_STRING,
515 Symbol: symbol => JS_TAG_SYMBOL,
516 Array: array => JS_TAG_OBJECT,
517 Constructor: constructor => JS_TAG_OBJECT,
518 Function: function => JS_TAG_OBJECT,
519 Promise: promise => JS_TAG_OBJECT,
520 Exception: exception => JS_TAG_OBJECT,
521 Object: object => JS_TAG_OBJECT,
522 Module: module => JS_TAG_MODULE,
523 BigInt: big_int => JS_TAG_BIG_INT,
524}
525
526macro_rules! sub_types {
527 ($( $head:ident$(->$sub_type:ident)* $as:ident $ref:ident $into:ident $try_into:ident $from:ident,)*) => {
528 $(
529 impl<'js> $head<'js> {
530 #[inline]
532 pub fn as_value(&self) -> &Value<'js> {
533 &self.0.as_value()
534 }
535
536 #[inline]
538 pub fn into_value(self) -> Value<'js> {
539 self.0.into_value()
540 }
541
542 pub fn into_inner(self) -> sub_types!(@head_ty $($sub_type),*) {
544 self.0
545 }
546 pub fn as_inner(&self) -> & sub_types!(@head_ty $($sub_type),*) {
548 &self.0
549 }
550
551 pub fn ctx(&self) -> &Ctx<'js>{
553 self.0.ctx()
554 }
555
556 pub fn from_value(value: Value<'js>) -> Result<Self> {
558 let type_ = value.type_of();
559 if type_.interpretable_as(Type::$head) {
560 Ok(sub_types!(@wrap $head$(->$sub_type)* value))
561 } else {
562 Err(Error::new_from_js(type_.as_str(), Type::$head.as_str()))
563 }
564 }
565
566 #[allow(unused)]
567 pub(crate) unsafe fn from_js_value_const(ctx: Ctx<'js>, value: qjs::JSValueConst) -> Self {
568 let v = Value::from_js_value_const(ctx, value);
569 debug_assert!(v.$as().is_some(),"tried to cource js value {:?} to the wrong type `{}`, this is a rquickjs bug",v, stringify!($head));
570 sub_types!(@wrap $head$(->$sub_type)* v)
571 }
572
573 #[allow(unused)]
574 pub(crate) unsafe fn from_js_value(ctx: Ctx<'js>, value: qjs::JSValue) -> Self {
575 let v = Value::from_js_value(ctx, value);
576 debug_assert!(v.$as().is_some(),"tried to cource js value {:?} to the wrong type `{}`, this is a rquickjs bug",v, stringify!($head));
577 sub_types!(@wrap $head$(->$sub_type)* v)
578 }
579
580 #[allow(unused)]
581 pub(crate) fn into_js_value(self) -> qjs::JSValue{
582 self.0.into_js_value()
583 }
584
585 #[allow(unused)]
586 pub(crate) fn as_js_value(&self) -> qjs::JSValueConst{
587 self.0.as_js_value()
588 }
589 }
590
591 impl<'js> Deref for $head<'js> {
592 type Target = sub_types!(@head_ty $($sub_type),*);
593
594 fn deref(&self) -> &Self::Target {
595 &self.0
596 }
597 }
598
599 sub_types!(@imp_as_ref $head$(,$sub_type)*);
600
601 impl<'js> Value<'js> {
602 #[doc = concat!("Interpret as [`",stringify!($head),"`]")]
603 #[inline]
607 pub unsafe fn $ref(&self) -> &$head<'js> {
608 &*(self as *const _ as *const $head)
609 }
610
611 #[doc = concat!("Try reinterpret as [`",stringify!($head),"`]")]
612 pub fn $as(&self) -> Option<&$head<'js>> {
613 if self.type_of().interpretable_as(Type::$head) {
614 Some(unsafe { self.$ref() })
615 } else {
616 None
617 }
618 }
619
620 #[doc = concat!("Try convert into [`",stringify!($head),"`]")]
621 pub fn $into(self) -> Option<$head<'js>> {
622 if self.type_of().interpretable_as(Type::$head) {
623 Some(sub_types!(@wrap $head$(->$sub_type)* self))
624 } else {
625 None
626 }
627 }
628
629 #[doc = concat!("Try convert into [`",stringify!($head),"`] returning self if the conversion fails.")]
630 pub fn $try_into(self) -> std::result::Result<$head<'js>, Value<'js>> {
631 if self.type_of().interpretable_as(Type::$head) {
632 Ok(sub_types!(@wrap $head$(->$sub_type)* self))
633 } else {
634 Err(self)
635 }
636 }
637
638 #[doc = concat!("Convert from [`",stringify!($head),"`]")]
639 pub fn $from(value: $head<'js>) -> Self {
640 value.into_value()
641 }
642 }
643
644 impl<'js> From<$head<'js>> for Value<'js> {
645 fn from(value: $head<'js>) -> Self {
646 value.into_value()
647 }
648 }
649
650 impl<'js> FromJs<'js> for $head<'js> {
651 fn from_js(_: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
652 Self::from_value(value)
653 }
654 }
655
656 impl<'js> IntoJs<'js> for $head<'js> {
657 fn into_js(self, _ctx: &Ctx<'js>) -> Result<Value<'js>> {
658 Ok(self.into_value())
659 }
660 }
661
662 impl<'js> IntoAtom<'js> for $head<'js>{
663 fn into_atom(self, ctx: &Ctx<'js>) -> Result<Atom<'js>> {
664 Atom::from_value(ctx.clone(), &self.into_value())
665 }
666 }
667 )*
668 };
669
670 (@type $type:ident) => { $type<'js> };
671
672 (@head $head:ident $(rem:ident)*) => { $head };
673 (@head_ty $head:ident$(,$rem:ident)*) => { $head<'js> };
674
675 (@wrap $type:ident$(->$rem:ident)+ $val:expr) => { $type(sub_types!(@wrap $($rem)->* $val)) };
676 (@wrap Value $val:expr) => { $val };
677
678 (@imp_as_ref $type:ident,Value) => {
686 impl<'js> AsRef<Value<'js>> for $type<'js> {
687 fn as_ref(&self) -> &Value<'js> {
688 &self.0
689 }
690 }
691 };
692 (@imp_as_ref $type:ident,$inner:ident$(,$rem:ident)*) => {
693 impl<'js> AsRef<$inner<'js>> for $type<'js> {
694 fn as_ref(&self) -> &$inner<'js> {
695 &self.0
696 }
697 }
698
699 impl<'js> AsRef<Value<'js>> for $type<'js> {
700 fn as_ref(&self) -> &Value<'js> {
701 self.0.as_ref()
702 }
703 }
704 };
705}
706
707sub_types! {
708 String->Value as_string ref_string into_string try_into_string from_string,
709 Symbol->Value as_symbol ref_symbol into_symbol try_into_symbol from_symbol,
710 Object->Value as_object ref_object into_object try_into_object from_object,
711 Function->Object->Value as_function ref_function into_function try_into_function from_function,
712 Constructor->Function->Object->Value as_constructor ref_constructor into_constructor try_into_constructor from_constructor,
713 Promise->Object->Value as_promise ref_promise into_promise try_into_promise from_promise,
714 Array->Object->Value as_array ref_array into_array try_into_array from_array,
715 Exception->Object->Value as_exception ref_exception into_exception try_into_exception from_exception,
716 BigInt->Value as_big_int ref_big_int into_big_int try_into_big_int from_big_int,
717}
718
719macro_rules! void_types {
720 ($($(#[$meta:meta])* $type:ident $new:ident;)*) => {
721 $(
722 $(#[$meta])*
723 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
724 pub struct $type;
725
726 impl $type {
727 pub fn into_value<'js>(self, ctx: Ctx<'js>) -> Value<'js> {
729 Value::$new(ctx)
730 }
731
732 pub fn from_value<'js>(value: Value<'js>) -> Result<Self> {
734 if value.type_of() == Type::$type {
735 Ok(Self)
736 } else {
737 Err(Error::new_from_js("value", Type::$type.as_str()))
738 }
739 }
740 }
741
742 impl<'js> FromJs<'js> for $type {
743 fn from_js(_: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
744 Self::from_value(value)
745 }
746 }
747
748 impl<'js> IntoJs<'js> for $type {
749 fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {
750 Ok(self.into_value(ctx.clone()))
751 }
752 }
753 )*
754 };
755}
756
757void_types! {
758 Uninitialized new_uninitialized;
760
761 Undefined new_undefined;
763
764 Null new_null;
766}
767
768#[cfg(test)]
769mod test {
770 use crate::*;
771
772 #[test]
773 fn type_matches() {
774 assert!(Type::Bool.interpretable_as(Type::Bool));
775
776 assert!(Type::Object.interpretable_as(Type::Object));
777 assert!(Type::Array.interpretable_as(Type::Object));
778 assert!(Type::Function.interpretable_as(Type::Object));
779
780 assert!(!Type::Object.interpretable_as(Type::Array));
781 assert!(!Type::Object.interpretable_as(Type::Function));
782
783 assert!(!Type::Bool.interpretable_as(Type::Int));
784 }
785}