GitLab will be upgraded on June 2nd 2020 at 2.00 pm (AEDT) to 3.00 pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to local Gitlab admin team.

Commit be476b0d authored by qinsoon's avatar qinsoon

restructured tests dir. Added logger.

parent 06d5ccdc
......@@ -5,4 +5,6 @@ version = "0.0.1"
authors = [ "Your name <you@example.com>" ]
[dependencies]
lazy_static = "0.1.15"
\ No newline at end of file
lazy_static = "0.1.15"
log = "0.3.5"
simple_logger = "0.4.0"
\ No newline at end of file
......@@ -9,20 +9,20 @@ pub type MuID = usize;
pub type MuTag = &'static str;
pub type Address = usize; // TODO: replace this with Address(usize)
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct SSAVar {
pub id: MuID,
pub tag: MuTag,
pub ty: P<MuType_>
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum Value {
SSAVar(SSAVar),
Constant(MuConstant)
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum MemoryOrder {
NotAtomic,
Relaxed,
......@@ -33,23 +33,25 @@ pub enum MemoryOrder {
SeqCst
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum CallConvention {
Mu,
Foreign(ForeignFFI)
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum ForeignFFI {
C
}
#[derive(Debug)]
pub struct CallData {
pub func: P<SSAVar>,
pub args: Vec<P<Value>>,
pub convention: CallConvention
}
#[derive(Debug)]
pub struct Block {
label: MuTag,
content: Option<BlockContent>
......@@ -65,6 +67,7 @@ impl Block {
}
}
#[derive(Debug)]
pub struct BlockContent {
pub args: Vec<P<Value>>,
pub body: Vec<Instruction>,
......@@ -72,22 +75,25 @@ pub struct BlockContent {
pub keepalives: Option<Vec<P<SSAVar>>>
}
#[derive(Debug)]
pub struct ResumptionData {
pub normal_dest: Destination,
pub exn_dest: Destination
}
#[derive(Debug)]
pub enum DestArg {
Normal(P<Value>),
Freshbound(usize)
}
#[derive(Debug)]
pub struct Destination {
pub target: MuTag,
pub args: Vec<DestArg>
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum Constant {
Int(usize, usize),
IRef(P<MuType_>, Address),
......@@ -98,6 +104,7 @@ pub enum Constant {
UFuncRefV(Address)
}
#[derive(Debug)]
pub enum Expression {
BinOp(BinOp, P<Value>, P<Value>),
CmpOp(CmpOp, P<Value>, P<Value>),
......@@ -211,6 +218,7 @@ pub enum Expression {
// }
}
#[derive(Debug)]
pub enum Instruction {
Assign{
left: Vec<P<Value>>,
......@@ -220,6 +228,7 @@ pub enum Instruction {
Fence(MemoryOrder),
}
#[derive(Debug)]
pub enum Terminal {
Return(Vec<P<Value>>),
ThreadExit,
......@@ -261,17 +270,18 @@ pub enum Terminal {
branches: Vec<(P<Constant>, Destination)>
},
ExnInstruction{
inner: Expression,
inner: Instruction,
resume: ResumptionData
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct MuConstant{
pub ty: P<MuType_>,
pub val: Constant
}
#[derive(Debug)]
pub struct MuFunction {
pub fn_name: MuTag,
pub sig: P<MuFuncSig>,
......@@ -279,7 +289,7 @@ pub struct MuFunction {
pub blocks: Vec<(MuTag, Block)>
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum BinOp {
// Int(n) BinOp Int(n) -> Int(n)
Add,
......@@ -305,7 +315,7 @@ pub enum BinOp {
FRem
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum CmpOp {
// for Int comparison
EQ,
......@@ -338,7 +348,7 @@ pub enum CmpOp {
FUNO
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum AtomicRMWOp {
XCHG,
ADD,
......
......@@ -13,6 +13,13 @@ impl TreeGenerationPass {
impl CompilerPass for TreeGenerationPass {
fn execute(&mut self, vm: &VMContext, func: &mut MuFunction) {
debug!("Generating Tree for {:?}", func.fn_name);
for entry in func.blocks.iter_mut() {
let label : MuTag = entry.0;
let ref block : &mut Block = &mut entry.1;
debug!(" block: {:?}", label);
}
}
}
\ No newline at end of file
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
pub mod ast;
pub mod vm;
......
......@@ -4,11 +4,13 @@ use ast::ptr::P;
use ast::ir::*;
use ast::types::*;
use std::cell::RefCell;
pub struct VMContext {
constants: HashMap<MuTag, P<Value>>,
types: HashMap<MuTag, P<MuType_>>,
func_sigs: HashMap<MuTag, P<MuFuncSig>>,
funcs: HashMap<MuTag, MuFunction>
funcs: HashMap<MuTag, RefCell<MuFunction>>
}
impl VMContext {
......@@ -51,6 +53,10 @@ impl VMContext {
debug_assert!(!self.funcs.contains_key(fn_name));
let ret = MuFunction{fn_name: fn_name, sig: sig, entry: entry, blocks: blocks};
self.funcs.insert(fn_name, ret);
}
self.funcs.insert(fn_name, RefCell::new(ret));
}
pub fn get_func(&self, fn_name: MuTag) -> Option<&RefCell<MuFunction>> {
self.funcs.get(fn_name)
}
}
\ No newline at end of file
mod test_ir;
mod test_compiler;
\ No newline at end of file
mod test_tree_gen;
\ No newline at end of file
extern crate mu;
extern crate log;
extern crate simple_logger;
use test_ir::test_ir::factorial;
use self::mu::compiler::*;
use self::mu::vm::context::VMContext;
#[test]
fn test_tree_gen() {
simple_logger::init_with_level(log::LogLevel::Trace).unwrap();
let vm_context : VMContext = factorial();
let compiler = Compiler::new(CompilerPolicy::default());
let mut factorial_func = {
vm_context.get_func("fac").unwrap().borrow_mut()
};
compiler.compile(&vm_context, &mut factorial_func);
}
\ No newline at end of file
extern crate mu;
#[cfg(test)]
mod test_ir {
use mu::ast::types::*;
use mu::ast::ir::*;
use mu::ast::ptr::*;
use mu::vm::context::*;
#[test]
#[allow(unused_variables)]
fn test_factorial() {
let vm = factorial();
}
#[allow(unused_variables)]
fn factorial() -> VMContext {
let mut vm = VMContext::new();
// .typedef @int_64 = int<64>
// .typedef @int_1 = int<1>
// .typedef @float = float
// .typedef @double = double
// .typedef @void = void
// .typedef @int_8 = int<8>
// .typedef @int_32 = int<32>
let type_def_int64 = vm.declare_type("int_64", P(MuType_::int(64)));
let type_def_int1 = vm.declare_type("int_1", P(MuType_::int(1)));
let type_def_float = vm.declare_type("float", P(MuType_::float()));
let type_def_double = vm.declare_type("double", P(MuType_::double()));
let type_def_void = vm.declare_type("void", P(MuType_::void()));
let type_def_int8 = vm.declare_type("int8", P(MuType_::int(8)));
let type_def_int32 = vm.declare_type("int32", P(MuType_::int(32)));
// .const @int_64_1 <@int_64> = 1
let const_def_int64_1 = vm.declare_const("int64_1", type_def_int64.clone(), Constant::Int(64, 1));
// .funcsig @fac_sig = (@int_64) -> (@int_64)
let fac_sig = vm.declare_func_sig("fac_sig", vec![type_def_int64.clone()], vec![type_def_int64.clone()]);
// .funcdef @fac VERSION @fac_v1 <@fac_sig>
let fac_func_ref = P(MuType_::funcref(fac_sig.clone()));
// %blk_0(<@int_64> %n_3):
let mut blk_0 = Block::new("blk_0");
let blk_0_n_3 = P(Value::SSAVar(SSAVar{id: 0, tag: "n_3", ty: type_def_int64.clone()}));
// %v48 = EQ <@int_64> %n_3 @int_64_1
let blk_0_v48 = P(Value::SSAVar(SSAVar{id: 1, tag: "v48", ty: type_def_int64.clone()}));
let blk_0_v48_expr = Expression::CmpOp(
CmpOp::EQ,
blk_0_n_3.clone(),
const_def_int64_1.clone()
);
let blk_0_inst0 = Instruction::Assign{left: vec![blk_0_v48.clone()], right: blk_0_v48_expr};
// BRANCH2 %v48 %blk_2(@int_64_1) %blk_1(%n_3)
let blk_0_term = Terminal::Branch2{
cond: blk_0_v48.clone(),
true_dest: Destination {
target: "blk_2",
args: vec![DestArg::Normal(const_def_int64_1.clone())]
},
false_dest: Destination {
target: "blk_1",
args: vec![DestArg::Normal(blk_0_n_3.clone())]
}
};
let blk_0_content = BlockContent {
args: vec![blk_0_n_3.clone()],
body: vec![blk_0_inst0],
exit: blk_0_term,
keepalives: None
};
blk_0.set_content(blk_0_content);
// %blk_2(<@int_64> %v53):
let mut blk_2 = Block::new("blk_2");
let blk_2_v53 = P(Value::SSAVar(SSAVar{id: 2, tag: "v53", ty: type_def_int64.clone()}));
// RET %v53
let blk_2_term = Terminal::Return(vec![blk_2_v53.clone()]);
let blk_2_content = BlockContent {
args: vec![blk_2_v53.clone()],
body: vec![],
exit: blk_2_term,
keepalives: None
};
blk_2.set_content(blk_2_content);
// %blk_1(<@int_64> %n_3):
let mut blk_1 = Block::new("blk_1");
let blk_1_n_3 = P(Value::SSAVar(SSAVar{id: 3, tag: "n_3", ty: type_def_int64.clone()}));
// %v50 = SUB <@int_64> %n_3 @int_64_1
let blk_1_v50 = P(Value::SSAVar(SSAVar{id: 4, tag: "v50", ty: type_def_int64.clone()}));
let blk_1_v50_expr = Expression::BinOp(
BinOp::Sub,
blk_1_n_3.clone(),
const_def_int64_1.clone()
);
let blk_1_inst0 = Instruction::Assign{left: vec![blk_1_v50.clone()], right: blk_1_v50_expr};
// %v51 = CALL <@fac_sig> @fac (%v50)
let blk_1_v51 = P(Value::SSAVar(SSAVar{id: 5, tag: "v51", ty: type_def_int64.clone()}));
let blk_1_term = Terminal::Call {
data: CallData {
func: P(SSAVar{id: 6, tag: "fac", ty: fac_func_ref.clone()}),
args: vec![blk_1_v50.clone()],
convention: CallConvention::Mu
},
resume: ResumptionData {
normal_dest: Destination {
target: "blk_1_cont",
args: vec![DestArg::Normal(blk_1_n_3.clone()), DestArg::Freshbound(0)]
},
exn_dest: Destination {
target: "blk_1_cont",
args: vec![DestArg::Normal(blk_1_n_3.clone()), DestArg::Freshbound(0)]
}
}
};
let blk_1_content = BlockContent {
args: vec![blk_1_n_3.clone()],
body: vec![blk_1_inst0],
exit: blk_1_term,
keepalives: None
};
blk_1.set_content(blk_1_content);
// %blk_1_cont(<@int_64> %n_3, <@int_64> %v51):
let mut blk_1_cont = Block::new("blk_1_cont");
let blk_1_cont_n_3 = P(Value::SSAVar(SSAVar{id: 7, tag: "n_3", ty: type_def_int64.clone()}));
let blk_1_cont_v51 = P(Value::SSAVar(SSAVar{id: 8, tag: "v51", ty: type_def_int64.clone()}));
// %v52 = MUL <@int_64> %n_3 %v51
let blk_1_cont_v52 = P(Value::SSAVar(SSAVar{id: 9, tag: "v52", ty: type_def_int64.clone()}));
let blk_1_cont_v52_expr = Expression::BinOp(
BinOp::Mul,
blk_1_cont_n_3.clone(),
blk_1_cont_v52.clone()
);
let blk_1_cont_inst0 = Instruction::Assign{left: vec![blk_1_cont_v52.clone()], right: blk_1_cont_v52_expr};
let blk_1_cont_term = Terminal::Branch1 (
Destination {
target: "blk_2",
args: vec![DestArg::Normal(blk_1_cont_v52.clone())]
}
);
let blk_1_cont_content = BlockContent {
args: vec![blk_1_cont_n_3.clone(), blk_1_cont_v52.clone()],
body: vec![blk_1_cont_inst0],
exit: blk_1_cont_term,
keepalives: None
};
blk_1_cont.set_content(blk_1_cont_content);
// wrap into a function
vm.declare_func("fac", fac_sig.clone(), "blk_0", vec![
("blk_0", blk_0),
("blk_1", blk_1),
("blk_1_cont", blk_1_cont),
("blk_2", blk_2)
]
);
vm
}
}
\ No newline at end of file
pub mod test_ir;
mod test_types;
\ No newline at end of file
extern crate mu;
use self::mu::ast::types::*;
use self::mu::ast::ir::*;
use self::mu::ast::ptr::*;
use self::mu::vm::context::*;
#[test]
#[allow(unused_variables)]
fn test_factorial() {
let vm = factorial();
}
#[allow(unused_variables)]
pub fn factorial() -> VMContext {
let mut vm = VMContext::new();
// .typedef @int_64 = int<64>
// .typedef @int_1 = int<1>
// .typedef @float = float
// .typedef @double = double
// .typedef @void = void
// .typedef @int_8 = int<8>
// .typedef @int_32 = int<32>
let type_def_int64 = vm.declare_type("int_64", P(MuType_::int(64)));
let type_def_int1 = vm.declare_type("int_1", P(MuType_::int(1)));
let type_def_float = vm.declare_type("float", P(MuType_::float()));
let type_def_double = vm.declare_type("double", P(MuType_::double()));
let type_def_void = vm.declare_type("void", P(MuType_::void()));
let type_def_int8 = vm.declare_type("int8", P(MuType_::int(8)));
let type_def_int32 = vm.declare_type("int32", P(MuType_::int(32)));
// .const @int_64_1 <@int_64> = 1
let const_def_int64_1 = vm.declare_const("int64_1", type_def_int64.clone(), Constant::Int(64, 1));
// .funcsig @fac_sig = (@int_64) -> (@int_64)
let fac_sig = vm.declare_func_sig("fac_sig", vec![type_def_int64.clone()], vec![type_def_int64.clone()]);
// .funcdef @fac VERSION @fac_v1 <@fac_sig>
let fac_func_ref = P(MuType_::funcref(fac_sig.clone()));
// %blk_0(<@int_64> %n_3):
let mut blk_0 = Block::new("blk_0");
let blk_0_n_3 = P(Value::SSAVar(SSAVar{id: 0, tag: "n_3", ty: type_def_int64.clone()}));
// %v48 = EQ <@int_64> %n_3 @int_64_1
let blk_0_v48 = P(Value::SSAVar(SSAVar{id: 1, tag: "v48", ty: type_def_int64.clone()}));
let blk_0_v48_expr = Expression::CmpOp(
CmpOp::EQ,
blk_0_n_3.clone(),
const_def_int64_1.clone()
);
let blk_0_inst0 = Instruction::Assign{left: vec![blk_0_v48.clone()], right: blk_0_v48_expr};
// BRANCH2 %v48 %blk_2(@int_64_1) %blk_1(%n_3)
let blk_0_term = Terminal::Branch2{
cond: blk_0_v48.clone(),
true_dest: Destination {
target: "blk_2",
args: vec![DestArg::Normal(const_def_int64_1.clone())]
},
false_dest: Destination {
target: "blk_1",
args: vec![DestArg::Normal(blk_0_n_3.clone())]
}
};
let blk_0_content = BlockContent {
args: vec![blk_0_n_3.clone()],
body: vec![blk_0_inst0],
exit: blk_0_term,
keepalives: None
};
blk_0.set_content(blk_0_content);
// %blk_2(<@int_64> %v53):
let mut blk_2 = Block::new("blk_2");
let blk_2_v53 = P(Value::SSAVar(SSAVar{id: 2, tag: "v53", ty: type_def_int64.clone()}));
// RET %v53
let blk_2_term = Terminal::Return(vec![blk_2_v53.clone()]);
let blk_2_content = BlockContent {
args: vec![blk_2_v53.clone()],
body: vec![],
exit: blk_2_term,
keepalives: None
};
blk_2.set_content(blk_2_content);
// %blk_1(<@int_64> %n_3):
let mut blk_1 = Block::new("blk_1");
let blk_1_n_3 = P(Value::SSAVar(SSAVar{id: 3, tag: "n_3", ty: type_def_int64.clone()}));
// %v50 = SUB <@int_64> %n_3 @int_64_1
let blk_1_v50 = P(Value::SSAVar(SSAVar{id: 4, tag: "v50", ty: type_def_int64.clone()}));
let blk_1_v50_expr = Expression::BinOp(
BinOp::Sub,
blk_1_n_3.clone(),
const_def_int64_1.clone()
);
let blk_1_inst0 = Instruction::Assign{left: vec![blk_1_v50.clone()], right: blk_1_v50_expr};
// %v51 = CALL <@fac_sig> @fac (%v50)
let blk_1_v51 = P(Value::SSAVar(SSAVar{id: 5, tag: "v51", ty: type_def_int64.clone()}));
let blk_1_term = Terminal::Call {
data: CallData {
func: P(SSAVar{id: 6, tag: "fac", ty: fac_func_ref.clone()}),
args: vec![blk_1_v50.clone()],
convention: CallConvention::Mu
},
resume: ResumptionData {
normal_dest: Destination {
target: "blk_1_cont",
args: vec![DestArg::Normal(blk_1_n_3.clone()), DestArg::Freshbound(0)]
},
exn_dest: Destination {
target: "blk_1_cont",
args: vec![DestArg::Normal(blk_1_n_3.clone()), DestArg::Freshbound(0)]
}
}
};
let blk_1_content = BlockContent {
args: vec![blk_1_n_3.clone()],
body: vec![blk_1_inst0],
exit: blk_1_term,
keepalives: None
};
blk_1.set_content(blk_1_content);
// %blk_1_cont(<@int_64> %n_3, <@int_64> %v51):
let mut blk_1_cont = Block::new("blk_1_cont");
let blk_1_cont_n_3 = P(Value::SSAVar(SSAVar{id: 7, tag: "n_3", ty: type_def_int64.clone()}));
let blk_1_cont_v51 = P(Value::SSAVar(SSAVar{id: 8, tag: "v51", ty: type_def_int64.clone()}));
// %v52 = MUL <@int_64> %n_3 %v51
let blk_1_cont_v52 = P(Value::SSAVar(SSAVar{id: 9, tag: "v52", ty: type_def_int64.clone()}));
let blk_1_cont_v52_expr = Expression::BinOp(
BinOp::Mul,
blk_1_cont_n_3.clone(),
blk_1_cont_v52.clone()
);
let blk_1_cont_inst0 = Instruction::Assign{left: vec![blk_1_cont_v52.clone()], right: blk_1_cont_v52_expr};
let blk_1_cont_term = Terminal::Branch1 (
Destination {
target: "blk_2",
args: vec![DestArg::Normal(blk_1_cont_v52.clone())]
}
);
let blk_1_cont_content = BlockContent {
args: vec![blk_1_cont_n_3.clone(), blk_1_cont_v52.clone()],
body: vec![blk_1_cont_inst0],
exit: blk_1_cont_term,
keepalives: None
};
blk_1_cont.set_content(blk_1_cont_content);
// wrap into a function
vm.declare_func("fac", fac_sig.clone(), "blk_0", vec![
("blk_0", blk_0),
("blk_1", blk_1),
("blk_1_cont", blk_1_cont),
("blk_2", blk_2)
]
);
vm
}
\ No newline at end of file
extern crate mu;
use self::mu::ast::ptr::*;
use self::mu::ast::types::*;
macro_rules! assert_type (
($test:expr, $expect: expr) => (
assert_eq!(format!("{:?}", $test), $expect)
)
);
macro_rules! println_type (
($test:expr) => (
println!("{:?}", $test)
)
);
/// create one of each MuType_
fn create_types() -> Vec<P<MuType_>> {
let mut types = vec![];
let t0 = MuType_::int(8);
types.push(P(t0));
let t1 = MuType_::float();
types.push(P(t1));
let t2 = MuType_::double();
types.push(P(t2));
let t3 = MuType_::muref(types[0].clone());
types.push(P(t3));
let t4 = MuType_::iref(types[0].clone());
types.push(P(t4));
let t5 = MuType_::weakref(types[0].clone());
types.push(P(t5));
let t6 = MuType_::uptr(types[0].clone());
types.push(P(t6));
let t7 = MuType_::mustruct("MyStructTag1", vec![types[0].clone(), types[1].clone()]);
types.push(P(t7));
let t8 = MuType_::array(types[0].clone(), 5);
types.push(P(t8));
let t9 = MuType_::hybrid(vec![types[7].clone(), types[1].clone()], types[0].clone());
types.push(P(t9));
let t10 = MuType_::void();
types.push(P(t10));
let t11 = MuType_::threadref();
types.push(P(t11));
let t12 = MuType_::stackref();
types.push(P(t12));
let t13 = MuType_::tagref64();
types.push(P(t13));
let t14 = MuType_::vector(types[0].clone(), 5);
types.push(P(t14));
let sig = P(MuFuncSig{ret_tys: vec![types[10].clone()], arg_tys: vec![types[0].clone(), types[0].clone()]});
let t15 = MuType_::funcref(sig.clone());
types.push(P(t15));
let t16 = MuType_::ufuncptr(sig.clone());
types.push(P(t16));
types
}
#[test]
#[allow(unused_variables)]
fn test_type_constructors() {
let types = create_types();
assert_type!(*types[0], "Int(8)");
assert_type!(*types[1], "Float");
assert_type!(*types[2], "Double");
assert_type!(*types[3], "Ref(Int(8))");
assert_type!(*types[4], "IRef(Int(8))");
assert_type!(*types[5], "WeakRef(Int(8))");
assert_type!(*types[6], "UPtr(Int(8))");
assert_type!(*types[7], "Struct(\"MyStructTag1\")");
{
let map = STRUCT_TAG_MAP.read().unwrap();
let t7_struct_ty = map.get("MyStructTag1").unwrap();
assert_type!(t7_struct_ty, "StructType_ { tys: [Int(8), Float] }");
}
assert_type!(*types[8], "Array(Int(8), 5)");
assert_type!(*types[9], "Hybrid([Struct(\"MyStructTag1\"), Float], Int(8))");
assert_type!(*types[10], "Void");
assert_type!(*types[11], "ThreadRef");
assert_type!(*types[12], "StackRef");
assert_type!(*types[13], "Tagref64");
assert_type!(*types[14], "Vector(Int(8), 5)");
assert_type!(*types[15], "FuncRef(MuFuncSig { ret_tys: [Void], arg_tys: [Int(8), Int(8)] })");
assert_type!(*types[16], "UFuncPtr(MuFuncSig { ret_tys: [Void], arg_tys: [Int(8), Int(8)] })");
}
#[test]
fn test_cyclic_struct() {
// .typedef @cyclic_struct_ty = struct<ref<@cyclic_struct_ty> int<32>>
let ty = P(MuType_::mustruct_empty("MyStructTag2"));
let ref_ty = P(MuType_::muref(ty.clone()));
let i32_ty = P(MuType_::int(32));
{
STRUCT_TAG_MAP.write().unwrap().
get_mut("MyStructTag2").unwrap().set_tys(vec![ref_ty.clone(), i32_ty.clone()]);
}
let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get("MyStructTag2").unwrap();
assert_type!(struct_ty, "StructType_ { tys: [Ref(Struct(\"MyStructTag2\")), Int(32)] }");
}
#[test]
fn test_is_traced() {
let types = create_types();
assert_eq!(is_traced(&types[0]), false);
assert_eq!(is_traced(&types[1]), false);
assert_eq!(is_traced(&types[2]), false);
assert_eq!(is_traced(&types[3]), true);
assert_eq!(is_traced(&types[4]), true);
assert_eq!(is_traced(&types[5]), true);
assert_eq!(is_traced(&types[6]), false);
assert_eq!(is_traced(&types[7]), false);
let struct3 = MuType_::mustruct("MyStructTag3", vec![types[3].clone(), types[0].clone()]);
assert_eq!(is_traced(&struct3), true);