types.rs 13.7 KB
Newer Older
qinsoon's avatar
qinsoon committed
1 2 3
use ptr::P;
use ir::*;

qinsoon's avatar
qinsoon committed
4
use utils::POINTER_SIZE;
qinsoon's avatar
qinsoon committed
5
use utils::vec_utils;
6 7

use std::fmt;
qinsoon's avatar
qinsoon committed
8 9
use std::collections::HashMap;
use std::sync::RwLock;
qinsoon's avatar
qinsoon committed
10

qinsoon's avatar
qinsoon committed
11 12 13 14
lazy_static! {
    pub static ref ADDRESS_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(POINTER_SIZE * 8))
    );
15 16 17 18 19 20 21 22

    pub static ref UINT8_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(8))
    );

    pub static ref UINT16_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(16))
    );
qinsoon's avatar
qinsoon committed
23 24 25 26 27 28 29 30 31 32 33 34
    
    pub static ref UINT32_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(32))
    );
    
    pub static ref UINT64_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(64))
    );
    
    pub static ref DOUBLE_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::double())
    );
35 36 37 38

    pub static ref VOID_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::void())
    );
qinsoon's avatar
qinsoon committed
39 40 41
    
    pub static ref INTERNAL_TYPES : Vec<P<MuType>> = vec![
        ADDRESS_TYPE.clone(),
qinsoon's avatar
qinsoon committed
42 43
        UINT8_TYPE.clone(),
        UINT16_TYPE.clone(),
qinsoon's avatar
qinsoon committed
44 45 46 47 48 49
        UINT32_TYPE.clone(),
        UINT64_TYPE.clone(),
        DOUBLE_TYPE.clone()
    ];    
}

qinsoon's avatar
qinsoon committed
50
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
51
pub struct MuType {
52
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
53 54 55 56 57 58
    pub v: MuType_
}

impl MuType {
    pub fn new(id: MuID, v: MuType_) -> MuType {
        MuType {
59
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
60 61 62 63
            v: v
        }
    }
}
qinsoon's avatar
qinsoon committed
64

65 66
pub type StructTag = MuName;
pub type HybridTag = MuName;
qinsoon's avatar
qinsoon committed
67
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
68
pub enum MuType_ {
qinsoon's avatar
qinsoon committed
69
    /// int <length>
qinsoon's avatar
qinsoon committed
70
    Int          (usize),
qinsoon's avatar
qinsoon committed
71
    /// float
qinsoon's avatar
qinsoon committed
72
    Float,
qinsoon's avatar
qinsoon committed
73
    /// double
qinsoon's avatar
qinsoon committed
74
    Double,
75

qinsoon's avatar
qinsoon committed
76
    /// ref<T>
qinsoon's avatar
qinsoon committed
77
    Ref          (P<MuType>),    // Box is needed for non-recursive enum
qinsoon's avatar
qinsoon committed
78
    /// iref<T>: internal reference
qinsoon's avatar
qinsoon committed
79
    IRef         (P<MuType>),
qinsoon's avatar
qinsoon committed
80
    /// weakref<T>
qinsoon's avatar
qinsoon committed
81
    WeakRef      (P<MuType>),
82

qinsoon's avatar
qinsoon committed
83
    /// uptr<T>: unsafe pointer
qinsoon's avatar
qinsoon committed
84
    UPtr         (P<MuType>),
85

qinsoon's avatar
qinsoon committed
86
    /// struct<T1 T2 ...>
87
    Struct       (StructTag),
88

qinsoon's avatar
qinsoon committed
89
    /// array<T length>
qinsoon's avatar
qinsoon committed
90
    Array        (P<MuType>, usize),
91

qinsoon's avatar
qinsoon committed
92
    /// hybrid<F1 F2 ... V>: a hybrid of fixed length parts and a variable length part
93
    Hybrid       (HybridTag),
94

qinsoon's avatar
qinsoon committed
95
    /// void
qinsoon's avatar
qinsoon committed
96
    Void,
97

qinsoon's avatar
qinsoon committed
98
    /// threadref
qinsoon's avatar
qinsoon committed
99
    ThreadRef,
qinsoon's avatar
qinsoon committed
100
    /// stackref
qinsoon's avatar
qinsoon committed
101
    StackRef,
102

qinsoon's avatar
qinsoon committed
103
    /// tagref64: hold a double or an int or an ref<void>
qinsoon's avatar
qinsoon committed
104
    Tagref64,
105

qinsoon's avatar
qinsoon committed
106
    /// vector<T length>
qinsoon's avatar
qinsoon committed
107
    Vector       (P<MuType>, usize),
108

qinsoon's avatar
qinsoon committed
109
    /// funcref<@sig>
110
    FuncRef      (P<MuFuncSig>),
111

qinsoon's avatar
qinsoon committed
112
    /// ufuncptr<@sig>
113
    UFuncPtr     (P<MuFuncSig>),
qinsoon's avatar
qinsoon committed
114 115
}

qinsoon's avatar
qinsoon committed
116 117 118 119 120 121
impl fmt::Display for MuType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v)        
    }
}

122
impl fmt::Display for MuType_ {
123 124
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
qinsoon's avatar
qinsoon committed
125 126 127
            &MuType_::Int(n)                          => write!(f, "int<{}>", n),
            &MuType_::Float                           => write!(f, "float"),
            &MuType_::Double                          => write!(f, "double"),
128 129 130 131 132
            &MuType_::Ref(ref ty)                     => write!(f, "ref<{}>", ty),
            &MuType_::IRef(ref ty)                    => write!(f, "iref<{}>", ty),
            &MuType_::WeakRef(ref ty)                 => write!(f, "weakref<{}>", ty),
            &MuType_::UPtr(ref ty)                    => write!(f, "uptr<{}>", ty),
            &MuType_::Array(ref ty, size)             => write!(f, "array<{} {}>", ty, size),
qinsoon's avatar
qinsoon committed
133 134 135 136
            &MuType_::Void                            => write!(f, "void"),
            &MuType_::ThreadRef                       => write!(f, "threadref"),
            &MuType_::StackRef                        => write!(f, "stackref"),
            &MuType_::Tagref64                        => write!(f, "tagref64"),
137 138 139
            &MuType_::Vector(ref ty, size)            => write!(f, "vector<{} {}>", ty, size),
            &MuType_::FuncRef(ref sig)                => write!(f, "funcref<{}>", sig),
            &MuType_::UFuncPtr(ref sig)               => write!(f, "ufuncref<{}>", sig),
140 141
            &MuType_::Struct(ref tag)                 => write!(f, "{}(struct)", tag),
            &MuType_::Hybrid(ref tag)                 => write!(f, "{}(hybrid)", tag)
142 143 144 145
        }
    }
}

qinsoon's avatar
qinsoon committed
146
lazy_static! {
qinsoon's avatar
qinsoon committed
147
    /// storing a map from MuName to StructType_
148 149 150
    pub static ref STRUCT_TAG_MAP : RwLock<HashMap<StructTag, StructType_>> = RwLock::new(HashMap::new());
    /// storing a map from MuName to HybridType_
    pub static ref HYBRID_TAG_MAP : RwLock<HashMap<HybridTag, HybridType_>> = RwLock::new(HashMap::new());
qinsoon's avatar
qinsoon committed
151 152
}

qinsoon's avatar
qinsoon committed
153
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
154
pub struct StructType_ {
qinsoon's avatar
qinsoon committed
155
    tys: Vec<P<MuType>>
qinsoon's avatar
qinsoon committed
156 157
}

158
impl fmt::Display for StructType_ {
159
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
160 161 162
        write!(f, "struct<").unwrap();
        for i in 0..self.tys.len() {
            let ty = &self.tys[i];
163
            write!(f, "{}", ty).unwrap();
qinsoon's avatar
qinsoon committed
164 165 166
            if i != self.tys.len() - 1 {
                write!(f, " ").unwrap();
            }
167
        }
qinsoon's avatar
qinsoon committed
168
        write!(f, ">")
169
    }
170 171
}

qinsoon's avatar
qinsoon committed
172
impl StructType_ {
173 174 175 176
    // The IR builder needs to create StructType objects, too.
    pub fn new(tys: Vec<P<MuType>>) -> StructType_ {
        StructType_ { tys: tys }
    }
qinsoon's avatar
qinsoon committed
177
    pub fn set_tys(&mut self, mut list: Vec<P<MuType>>) {
qinsoon's avatar
qinsoon committed
178
        self.tys.clear();
qinsoon's avatar
qinsoon committed
179
        self.tys.append(&mut list);
qinsoon's avatar
qinsoon committed
180
    }
qinsoon's avatar
qinsoon committed
181
    
qinsoon's avatar
qinsoon committed
182
    pub fn get_tys(&self) -> &Vec<P<MuType>> {
qinsoon's avatar
qinsoon committed
183 184
        &self.tys
    }
qinsoon's avatar
qinsoon committed
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
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub struct HybridType_ {
    fix_tys: Vec<P<MuType>>,
    var_ty : P<MuType>
}

impl HybridType_ {
    pub fn new(fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> HybridType_ {
        HybridType_ {fix_tys: fix_tys, var_ty: var_ty}
    }

    pub fn set_tys(&mut self, mut fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) {
        self.fix_tys.clear();
        self.fix_tys.append(&mut fix_tys);

        self.var_ty = var_ty;
    }

    pub fn get_fix_tys(&self) -> &Vec<P<MuType>> {
        &self.fix_tys
    }

    pub fn get_var_ty(&self) -> &P<MuType> {
        &self.var_ty
    }
}

impl fmt::Display for HybridType_ {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "hybrid<").unwrap();
        for i in 0..self.fix_tys.len() {
            let ty = &self.fix_tys[i];
            write!(f, "{}", ty).unwrap();
            if i != self.fix_tys.len() - 1 {
                write!(f, " ").unwrap();
            }
        }
        write!(f, "|{}>", self.var_ty)
    }
}

qinsoon's avatar
qinsoon committed
228 229 230
impl MuType_ {
    pub fn int(len: usize) -> MuType_ {
        MuType_::Int(len)
qinsoon's avatar
qinsoon committed
231
    }
qinsoon's avatar
qinsoon committed
232 233
    pub fn float() -> MuType_ {
        MuType_::Float
qinsoon's avatar
qinsoon committed
234
    }
qinsoon's avatar
qinsoon committed
235 236
    pub fn double() -> MuType_ {
        MuType_::Double
qinsoon's avatar
qinsoon committed
237
    }
qinsoon's avatar
qinsoon committed
238
    pub fn muref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
239
        MuType_::Ref(referent)
qinsoon's avatar
qinsoon committed
240
    }
qinsoon's avatar
qinsoon committed
241
    pub fn iref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
242
        MuType_::IRef(referent)
qinsoon's avatar
qinsoon committed
243
    }
qinsoon's avatar
qinsoon committed
244
    pub fn weakref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
245
        MuType_::WeakRef(referent)
qinsoon's avatar
qinsoon committed
246
    }
qinsoon's avatar
qinsoon committed
247
    pub fn uptr(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
248
        MuType_::UPtr(referent)
qinsoon's avatar
qinsoon committed
249
    }
qinsoon's avatar
qinsoon committed
250
    pub fn mustruct_empty(tag: MuName) -> MuType_ {
qinsoon's avatar
qinsoon committed
251
        let struct_ty_ = StructType_{tys: vec![]};
252
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
253

qinsoon's avatar
qinsoon committed
254
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
255
    }
256 257 258 259 260 261 262 263 264 265 266 267
    pub fn mustruct_put(tag: MuName, mut list: Vec<P<MuType>>) {
        let mut map_guard = STRUCT_TAG_MAP.write().unwrap();

        match map_guard.get_mut(&tag) {
            Some(struct_ty_) => {
                struct_ty_.tys.clear();
                struct_ty_.tys.append(&mut list);
            },
            None => panic!("call mustruct_empty() to create an empty struct before mustruct_put()")
        }
    }
    pub fn mustruct(tag: StructTag, list: Vec<P<MuType>>) -> MuType_ {
qinsoon's avatar
qinsoon committed
268
        let struct_ty_ = StructType_{tys: list};
qinsoon's avatar
qinsoon committed
269 270 271

        // if there is an attempt to use a same tag for different struct,
        // we panic
272
        match STRUCT_TAG_MAP.read().unwrap().get(&tag) {
qinsoon's avatar
qinsoon committed
273 274
            Some(old_struct_ty_) => {
                if struct_ty_ != *old_struct_ty_ {
275 276
                    panic!("trying to insert {} as {}, while the old struct is defined as {}",
                            struct_ty_, tag, old_struct_ty_)
qinsoon's avatar
qinsoon committed
277 278 279 280 281
                }
            },
            None => {}
        }
        // otherwise, store the tag
282
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
283

qinsoon's avatar
qinsoon committed
284
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
285
    }
qinsoon's avatar
qinsoon committed
286
    pub fn array(ty: P<MuType>, len: usize) -> MuType_ {
qinsoon's avatar
qinsoon committed
287
        MuType_::Array(ty, len)
qinsoon's avatar
qinsoon committed
288
    }
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    pub fn hybrid_empty(tag: HybridTag) -> MuType_ {
        let hybrid_ty_ = HybridType_{fix_tys: vec![], var_ty: VOID_TYPE.clone()};
        HYBRID_TAG_MAP.write().unwrap().insert(tag.clone(), hybrid_ty_);

        MuType_::Hybrid(tag)
    }
    pub fn hybrid(tag: HybridTag, fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> MuType_ {
        let hybrid_ty_ = HybridType_{fix_tys: fix_tys, var_ty: var_ty};


        match HYBRID_TAG_MAP.read().unwrap().get(&tag) {
            Some(old_hybrid_ty_) => {
                if hybrid_ty_ != *old_hybrid_ty_ {
                    panic!("trying to insert {} as {}, while the old hybrid is defined as {}",
                           hybrid_ty_, tag, old_hybrid_ty_);
                }
            },
            None => {}
        }

        HYBRID_TAG_MAP.write().unwrap().insert(tag.clone(), hybrid_ty_);

        MuType_::Hybrid(tag)
qinsoon's avatar
qinsoon committed
312
    }
qinsoon's avatar
qinsoon committed
313 314
    pub fn void() -> MuType_ {
        MuType_::Void
qinsoon's avatar
qinsoon committed
315
    }
qinsoon's avatar
qinsoon committed
316 317
    pub fn threadref() -> MuType_ {
        MuType_::ThreadRef
qinsoon's avatar
qinsoon committed
318
    }
qinsoon's avatar
qinsoon committed
319 320
    pub fn stackref() -> MuType_ {
        MuType_::StackRef
qinsoon's avatar
qinsoon committed
321
    }
qinsoon's avatar
qinsoon committed
322 323
    pub fn tagref64() -> MuType_ {
        MuType_::Tagref64
qinsoon's avatar
qinsoon committed
324
    }
qinsoon's avatar
qinsoon committed
325
    pub fn vector(ty: P<MuType>, len: usize) -> MuType_ {
qinsoon's avatar
qinsoon committed
326
        MuType_::Vector(ty, len)
qinsoon's avatar
qinsoon committed
327
    }
328
    pub fn funcref(sig: P<MuFuncSig>) -> MuType_ {
qinsoon's avatar
qinsoon committed
329
        MuType_::FuncRef(sig)
qinsoon's avatar
qinsoon committed
330
    }
331
    pub fn ufuncptr(sig: P<MuFuncSig>) -> MuType_ {
qinsoon's avatar
qinsoon committed
332
        MuType_::UFuncPtr(sig)
qinsoon's avatar
qinsoon committed
333 334 335 336
    }
}

/// is a type floating-point type?
qinsoon's avatar
qinsoon committed
337
pub fn is_fp(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
338
    match ty.v {
qinsoon's avatar
qinsoon committed
339
        MuType_::Float | MuType_::Double => true,
qinsoon's avatar
qinsoon committed
340 341 342 343 344
        _ => false
    }
}

/// is a type raw pointer?
qinsoon's avatar
qinsoon committed
345
pub fn is_ptr(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
346
    match ty.v {
qinsoon's avatar
qinsoon committed
347
        MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
qinsoon's avatar
qinsoon committed
348 349 350 351 352
        _ => false
    }
}

/// is a type scalar type?
qinsoon's avatar
qinsoon committed
353
pub fn is_scalar(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
354
    match ty.v {
qinsoon's avatar
qinsoon committed
355 356 357 358 359 360 361 362 363 364 365 366
        MuType_::Int(_)
        | MuType_::Float
        | MuType_::Double
        | MuType_::Ref(_)
        | MuType_::IRef(_)
        | MuType_::WeakRef(_)
        | MuType_::FuncRef(_)
        | MuType_::UFuncPtr(_)
        | MuType_::ThreadRef
        | MuType_::StackRef
        | MuType_::Tagref64
        | MuType_::UPtr(_) => true,
qinsoon's avatar
qinsoon committed
367 368 369 370 371
        _ => false
    }
}

/// is a type traced by the garbage collector?
372
/// Note: An aggregated type is traced if any of its part is traced.
qinsoon's avatar
qinsoon committed
373
pub fn is_traced(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
374
    match ty.v {
qinsoon's avatar
qinsoon committed
375 376 377 378 379 380 381 382
        MuType_::Ref(_) => true,
        MuType_::IRef(_) => true,
        MuType_::WeakRef(_) => true,
        MuType_::Array(ref elem_ty, _)
        | MuType_::Vector(ref elem_ty, _) => is_traced(elem_ty),
        MuType_::ThreadRef
        | MuType_::StackRef
        | MuType_::Tagref64 => true,
383 384 385 386 387 388 389
        MuType_::Hybrid(ref tag) => {
            let map = HYBRID_TAG_MAP.read().unwrap();
            let hybrid_ty = map.get(tag).unwrap();

            let ref fix_tys = hybrid_ty.fix_tys;
            let ref var_ty  = hybrid_ty.var_ty;

qinsoon's avatar
qinsoon committed
390 391
            is_traced(var_ty) ||
            fix_tys.into_iter().map(|ty| is_traced(ty))
392
                .fold(false, |ret, this| ret || this)
qinsoon's avatar
qinsoon committed
393
            },
394
        MuType_::Struct(ref tag) => {
qinsoon's avatar
qinsoon committed
395 396 397
            let map = STRUCT_TAG_MAP.read().unwrap();
            let struct_ty = map.get(tag).unwrap();
            let ref field_tys = struct_ty.tys;
398

qinsoon's avatar
qinsoon committed
399 400 401 402 403 404 405 406 407
            field_tys.into_iter().map(|ty| is_traced(&ty))
                .fold(false, |ret, this| ret || this)
        },
        _ => false
    }
}

/// is a type native safe?
/// Note: An aggregated type is native safe if all of its parts are native safe.
qinsoon's avatar
qinsoon committed
408
pub fn is_native_safe(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
409
    match ty.v {
qinsoon's avatar
qinsoon committed
410 411 412 413 414 415 416 417
        MuType_::Int(_) => true,
        MuType_::Float => true,
        MuType_::Double => true,
        MuType_::Void => true,
        MuType_::Array(ref elem_ty, _)
        | MuType_::Vector(ref elem_ty, _) => is_native_safe(elem_ty),
        MuType_::UPtr(_) => true,
        MuType_::UFuncPtr(_) => true,
418 419 420 421 422 423 424
        MuType_::Hybrid(ref tag) => {
            let map = HYBRID_TAG_MAP.read().unwrap();
            let hybrid_ty = map.get(tag).unwrap();

            let ref fix_tys = hybrid_ty.fix_tys;
            let ref var_ty  = hybrid_ty.var_ty;

425
            is_native_safe(var_ty) &&
qinsoon's avatar
qinsoon committed
426 427 428
            fix_tys.into_iter().map(|ty| is_native_safe(&ty))
                .fold(true, |ret, this| ret && this)
        },
429
        MuType_::Struct(ref tag) => {
qinsoon's avatar
qinsoon committed
430 431 432
            let map = STRUCT_TAG_MAP.read().unwrap();
            let struct_ty = map.get(tag).unwrap();
            let ref field_tys = struct_ty.tys;
433

qinsoon's avatar
qinsoon committed
434 435 436 437
            field_tys.into_iter().map(|ty| is_native_safe(&ty))
                .fold(true, |ret, this| ret && this)
        },
        _ => false
qinsoon's avatar
qinsoon committed
438 439 440
    }
}

441
pub fn get_referent_ty(ty: &MuType) -> Option<P<MuType>> {
qinsoon's avatar
qinsoon committed
442 443 444 445
    match ty.v {
        MuType_::Ref(ref referent)
        | MuType_::IRef(ref referent)
        | MuType_::WeakRef(ref referent) => Some(referent.clone()),
446 447 448 449
        _ => None
    }
}

qinsoon's avatar
qinsoon committed
450 451 452 453 454 455 456 457 458
macro_rules! is_type (
    ($e:expr, $p:pat) => (
        match $e {
            $p => true,
            _ => false
        }
    )
);

459 460
pub type CFuncSig = MuFuncSig;

qinsoon's avatar
qinsoon committed
461
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
462
pub struct MuFuncSig {
463
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
464 465
    pub ret_tys : Vec<P<MuType>>,
    pub arg_tys: Vec<P<MuType>>
466 467
}

468
impl fmt::Display for MuFuncSig {
469
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
470
        write!(f, "[{}] -> [{}]", vec_utils::as_str(&self.ret_tys), vec_utils::as_str(&self.arg_tys))
471 472
    }
}