diff --git a/py/builtin.c b/py/builtin.c
index b565ed4640dec6a82ea3991de3ac1c10f8ab80d4..6babc76692a76e90b798383426c1df7419a18ad0 100644
--- a/py/builtin.c
+++ b/py/builtin.c
@@ -88,14 +88,6 @@ mp_obj_t mp_builtin_any(mp_obj_t o_in) {
     return mp_const_false;
 }
 
-mp_obj_t mp_builtin_bool(int n_args, const mp_obj_t *args) {
-    switch (n_args) {
-        case 0: return mp_const_false;
-        case 1: if (rt_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; }
-        default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "bool() takes at most 1 argument (%d given)", (void*)(machine_int_t)n_args));
-    }
-}
-
 mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
     if (mp_obj_is_callable(o_in)) {
         return mp_const_true;
@@ -104,42 +96,6 @@ mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
     }
 }
 
-#if MICROPY_ENABLE_FLOAT
-mp_obj_t mp_builtin_complex(int n_args, const mp_obj_t *args) {
-    assert(0 <= n_args && n_args <= 2);
-
-    if (n_args == 0) {
-        return mp_obj_new_complex(0, 0);
-    } else if (n_args == 1) {
-        // TODO allow string as first arg and parse it
-        if (MP_OBJ_IS_TYPE(args[0], &complex_type)) {
-            return args[0];
-        } else {
-            return mp_obj_new_complex(mp_obj_get_float(args[0]), 0);
-        }
-    } else {
-        mp_float_t real, imag;
-        if (MP_OBJ_IS_TYPE(args[0], &complex_type)) {
-            mp_obj_get_complex(args[0], &real, &imag);
-        } else {
-            real = mp_obj_get_float(args[0]);
-            imag = 0;
-        }
-        if (MP_OBJ_IS_TYPE(args[1], &complex_type)) {
-            mp_float_t real2, imag2;
-            mp_obj_get_complex(args[1], &real2, &imag2);
-            real -= imag2;
-            imag += real2;
-        } else {
-            imag += mp_obj_get_float(args[1]);
-        }
-        return mp_obj_new_complex(real, imag);
-    }
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_complex_obj, 0, 2, mp_builtin_complex);
-#endif
-
 mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
     int ord = mp_obj_get_int(o_in);
     if (0 <= ord && ord <= 0x10ffff) {
@@ -152,11 +108,6 @@ mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
     }
 }
 
-mp_obj_t mp_builtin_dict(void) {
-    // TODO create from an iterable!
-    return rt_build_map(0);
-}
-
 mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
     if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
         mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
@@ -170,25 +121,6 @@ mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
     }
 }
 
-#if MICROPY_ENABLE_FLOAT
-static mp_obj_t mp_builtin_float(int n_args, const mp_obj_t *args) {
-    assert(0 <= n_args && n_args <= 1);
-
-    if (n_args == 0) {
-        return mp_obj_new_float(0);
-    } else {
-        // TODO allow string as arg and parse it
-        if (MP_OBJ_IS_TYPE(args[0], &float_type)) {
-            return args[0];
-        } else {
-            return mp_obj_new_float(mp_obj_get_float(args[0]));
-        }
-    }
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_float_obj, 0, 1, mp_builtin_float);
-#endif
-
 static mp_obj_t mp_builtin_hash(mp_obj_t o_in) {
     // TODO hash will generally overflow small integer; can we safely truncate it?
     return mp_obj_new_int(mp_obj_hash(o_in));
@@ -196,23 +128,6 @@ static mp_obj_t mp_builtin_hash(mp_obj_t o_in) {
 
 MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hash_obj, mp_builtin_hash);
 
-static mp_obj_t mp_builtin_int(int n_args, const mp_obj_t *args) {
-    assert(0 <= n_args && n_args <= 2);
-
-    if (n_args == 0) {
-        return MP_OBJ_NEW_SMALL_INT(0);
-    } else if (n_args == 1) {
-        // TODO if arg is a string then parse it
-        return mp_obj_new_int(mp_obj_get_int(args[0]));
-    } else { // n_args == 2
-        // TODO, parse with given base
-        assert(0);
-        return MP_OBJ_NEW_SMALL_INT(0);
-    }
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_int_obj, 0, 2, mp_builtin_int);
-
 static mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
     return rt_getiter(o_in);
 }
@@ -241,24 +156,6 @@ mp_obj_t mp_builtin_len(mp_obj_t o_in) {
     return MP_OBJ_NEW_SMALL_INT(len);
 }
 
-mp_obj_t mp_builtin_list(int n_args, const mp_obj_t *args) {
-    switch (n_args) {
-        case 0: return rt_build_list(0, NULL);
-        case 1:
-        {
-            // make list from iterable
-            mp_obj_t iterable = rt_getiter(args[0]);
-            mp_obj_t list = rt_build_list(0, NULL);
-            mp_obj_t item;
-            while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
-                rt_list_append(list, item);
-            }
-            return list;
-        }
-        default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "list() takes at most 1 argument (%d given)", (void*)(machine_int_t)n_args));
-    }
-}
-
 mp_obj_t mp_builtin_max(int n_args, const mp_obj_t *args) {
     if (n_args == 1) {
         // given an iterable
@@ -367,26 +264,6 @@ mp_obj_t mp_builtin_range(int n_args, const mp_obj_t *args) {
     }
 }
 
-static mp_obj_t mp_builtin_set(int n_args, const mp_obj_t *args) {
-    assert(0 <= n_args && n_args <= 1);
-
-    if (n_args == 0) {
-        // return a new, empty set
-        return mp_obj_new_set(0, NULL);
-    } else {
-        // 1 argument, an iterable from which we make a new set
-        mp_obj_t set = mp_obj_new_set(0, NULL);
-        mp_obj_t iterable = rt_getiter(args[0]);
-        mp_obj_t item;
-        while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
-            mp_obj_set_store(set, item);
-        }
-        return set;
-    }
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_set_obj, 0, 1, mp_builtin_set);
-
 mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
     mp_obj_t value;
     switch (n_args) {
@@ -405,8 +282,7 @@ mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
 static mp_obj_t mp_builtin_type(mp_obj_t o_in) {
     // TODO implement the 3 argument version of type()
     if (MP_OBJ_IS_SMALL_INT(o_in)) {
-        // TODO implement int-type
-        return mp_const_none;
+        return (mp_obj_t)&int_type;
     } else {
         mp_obj_base_t *o = o_in;
         return (mp_obj_t)o->type;
diff --git a/py/compile.c b/py/compile.c
index f8fa2cb2c2ad12e3807494af66b74647e4f954ee..0e19890315edbd5e92cf336f40841bbe0642f444 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1316,7 +1316,7 @@ void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
 void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
     int l_end = comp_next_label(comp);
     c_if_cond(comp, pns->nodes[0], true, l_end);
-    EMIT(load_id, MP_QSTR_assertion_error);
+    EMIT(load_id, MP_QSTR_AssertionError);
     if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
         // assertion message
         compile_node(comp, pns->nodes[1]);
diff --git a/py/emitpass1.c b/py/emitpass1.c
index 1c11241e0dd536ad1a6d6e18136728ca45eb59cd..f78ec7e27ed38e012425872e93474c1057e77caf 100644
--- a/py/emitpass1.c
+++ b/py/emitpass1.c
@@ -7,6 +7,7 @@
 
 #include "misc.h"
 #include "mpconfig.h"
+#include "mpqstr.h"
 #include "lexer.h"
 #include "parse.h"
 #include "scope.h"
@@ -44,9 +45,9 @@ static void emit_pass1_load_id(emit_t *emit, qstr qstr) {
     bool added;
     id_info_t *id = scope_find_or_add_id(emit->scope, qstr, &added);
     if (added) {
-        if (strcmp(qstr_str(qstr), "AssertionError") == 0) {
-            id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
+        if (qstr == MP_QSTR_AssertionError) {
             // TODO how much of a hack is this?
+            id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
         } else if (strcmp(qstr_str(qstr), "super") == 0 && emit->scope->kind == SCOPE_FUNCTION) {
             // special case, super is a global, and also counts as use of __class__
             id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
diff --git a/py/mpqstrraw.h b/py/mpqstrraw.h
index e73bd828eb212fbeafb64523da3fba023dbceb1c..fe74c3e92778aebee9d9cf7a2b1b3d901df142a5 100644
--- a/py/mpqstrraw.h
+++ b/py/mpqstrraw.h
@@ -13,7 +13,6 @@ Q(__next__)
 Q(__qualname__)
 Q(__repl_print__)
 
-Q(assertion_error)
 Q(micropython)
 Q(byte_code)
 Q(native)
@@ -23,12 +22,13 @@ Q(asm_thumb)
 Q(Ellipsis)
 Q(StopIteration)
 
+Q(AssertionError)
 Q(AttributeError)
 Q(IndexError)
 Q(KeyError)
 Q(NameError)
-Q(TypeError)
 Q(SyntaxError)
+Q(TypeError)
 Q(ValueError)
 
 Q(abs)
@@ -55,6 +55,7 @@ Q(print)
 Q(range)
 Q(set)
 Q(sum)
+Q(tuple)
 Q(type)
 
 Q(append)
diff --git a/py/obj.c b/py/obj.c
index 2b834ffe437d1071b1232d5b78adeedc0f9907c6..77580e1feead349025df35aa689971e7301243fe 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -13,10 +13,6 @@
 #include "runtime.h"
 #include "map.h"
 
-mp_obj_t mp_obj_new_int(machine_int_t value) {
-    return MP_OBJ_NEW_SMALL_INT(value);
-}
-
 const char *mp_obj_get_type_str(mp_obj_t o_in) {
     if (MP_OBJ_IS_SMALL_INT(o_in)) {
         return "int";
@@ -128,9 +124,13 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) {
         return 1;
     } else if (MP_OBJ_IS_SMALL_INT(arg)) {
         return MP_OBJ_SMALL_INT_VALUE(arg);
+#if MICROPY_ENABLE_FLOAT
+    } else if (MP_OBJ_IS_TYPE(arg, &float_type)) {
+        // TODO work out if this should be floor, ceil or trunc
+        return (machine_int_t)mp_obj_float_get(arg);
+#endif
     } else {
-        assert(0);
-        return 0;
+        nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
     }
 }
 
diff --git a/py/obj.h b/py/obj.h
index f0ba6999e96b8a15a06741a44999c5865eeec091..03e67dd479f6e94ee404dfbc3947a393c19a882a 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -58,6 +58,7 @@ typedef mp_obj_t (*mp_fun_t)(void);
 typedef mp_obj_t (*mp_fun_var_t)(int n, const mp_obj_t *);
 
 typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o);
+typedef mp_obj_t (*mp_make_new_fun_t)(mp_obj_t type_in, int n_args, const mp_obj_t *args); // args are in reverse order in the array
 typedef mp_obj_t (*mp_call_n_fun_t)(mp_obj_t fun, int n_args, const mp_obj_t *args); // args are in reverse order in the array
 typedef mp_obj_t (*mp_unary_op_fun_t)(int op, mp_obj_t);
 typedef mp_obj_t (*mp_binary_op_fun_t)(int op, mp_obj_t, mp_obj_t);
@@ -71,6 +72,7 @@ struct _mp_obj_type_t {
     mp_obj_base_t base;
     const char *name;
     mp_print_fun_t print;
+    mp_make_new_fun_t make_new;     // to make an instance of the type
 
     mp_call_n_fun_t call_n;
     mp_unary_op_fun_t unary_op;     // can return NULL if op not supported
@@ -110,6 +112,7 @@ extern const mp_obj_type_t mp_const_type;
 extern const mp_obj_t mp_const_none;
 extern const mp_obj_t mp_const_false;
 extern const mp_obj_t mp_const_true;
+extern const mp_obj_t mp_const_empty_tuple;
 extern const mp_obj_t mp_const_ellipsis;
 extern const mp_obj_t mp_const_stop_iteration; // special object indicating end of iteration (not StopIteration exception!)
 
@@ -180,6 +183,9 @@ extern const mp_obj_type_t bool_type;
 mp_obj_t mp_obj_cell_get(mp_obj_t self_in);
 void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj);
 
+// int
+extern const mp_obj_type_t int_type;
+
 // exception
 extern const mp_obj_type_t exception_type;
 qstr mp_obj_exception_get_type(mp_obj_t self_in);
@@ -214,6 +220,7 @@ uint mp_obj_dict_len(mp_obj_t self_in);
 mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
 
 // set
+extern const mp_obj_type_t set_type;
 void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
 
 // slice
diff --git a/py/objbool.c b/py/objbool.c
index 9b53ffae94f012f0e349c81b06e7ad7562ae2c07..1d94ee03be9c37ca316d9d7093dca5923cf18cfe 100644
--- a/py/objbool.c
+++ b/py/objbool.c
@@ -4,14 +4,16 @@
 #include "nlr.h"
 #include "misc.h"
 #include "mpconfig.h"
+#include "mpqstr.h"
 #include "obj.h"
+#include "runtime.h"
 
 typedef struct _mp_obj_bool_t {
     mp_obj_base_t base;
     bool value;
 } mp_obj_bool_t;
 
-void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+static void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
     mp_obj_bool_t *self = self_in;
     if (self->value) {
         print(env, "True");
@@ -20,10 +22,20 @@ void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_ob
     }
 }
 
+// args are reverse in the array
+static mp_obj_t bool_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+    switch (n_args) {
+        case 0: return mp_const_false;
+        case 1: if (rt_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; }
+        default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "bool takes at most 1 argument, %d given", (void*)(machine_int_t)n_args));
+    }
+}
+
 const mp_obj_type_t bool_type = {
     { &mp_const_type },
     "bool",
     bool_print, // print
+    bool_make_new, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objboundmeth.c b/py/objboundmeth.c
index 8bd238c65ed63f86ccb4f7267df90903dfa7c1e2..264c2effd42bd95f21f4fc2548d6b44b38a8fd1c 100644
--- a/py/objboundmeth.c
+++ b/py/objboundmeth.c
@@ -37,6 +37,7 @@ const mp_obj_type_t bound_meth_type = {
     { &mp_const_type },
     "bound_method",
     NULL, // print
+    NULL, // make_new
     bound_meth_call_n, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objcell.c b/py/objcell.c
index cba1980579acae2fb4aa0cc584ec9a9ff5f8def6..daaa340a7f00578b5d43539ffe86cd65e9d9a2ea 100644
--- a/py/objcell.c
+++ b/py/objcell.c
@@ -27,6 +27,7 @@ const mp_obj_type_t cell_type = {
     { &mp_const_type },
     "cell",
     NULL, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objclass.c b/py/objclass.c
index f223c5ff25620adbae43d15a6b66db082f0996dc..197dfa726899c9d638267890be01f42f7516b0c0 100644
--- a/py/objclass.c
+++ b/py/objclass.c
@@ -64,6 +64,7 @@ const mp_obj_type_t class_type = {
     { &mp_const_type },
     "class",
     NULL, // print
+    NULL, // make_new
     class_call_n, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objclosure.c b/py/objclosure.c
index e3354d42d9e9937ad14949cb94527f3939b40c0c..550bb5067f736c3978b879f1b8aeb5d2fc4bab11 100644
--- a/py/objclosure.c
+++ b/py/objclosure.c
@@ -36,6 +36,7 @@ const mp_obj_type_t closure_type = {
     { &mp_const_type },
     "closure",
     NULL, // print
+    NULL, // make_new
     closure_call_n, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objcomplex.c b/py/objcomplex.c
index ab9c146774493df2bad97a91db94ce370cfa0331..5408d71cf246fd6089897dfbed86fa2e3ab30ad1 100644
--- a/py/objcomplex.c
+++ b/py/objcomplex.c
@@ -6,6 +6,7 @@
 #include "nlr.h"
 #include "misc.h"
 #include "mpconfig.h"
+#include "mpqstr.h"
 #include "obj.h"
 #include "runtime0.h"
 #include "map.h"
@@ -29,7 +30,46 @@ void complex_print(void (*print)(void *env, const char *fmt, ...), void *env, mp
     }
 }
 
-mp_obj_t complex_unary_op(int op, mp_obj_t o_in) {
+// args are reverse in the array
+static mp_obj_t complex_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+    switch (n_args) {
+        case 0:
+            return mp_obj_new_complex(0, 0);
+
+        case 1:
+            // TODO allow string as first arg and parse it
+            if (MP_OBJ_IS_TYPE(args[0], &complex_type)) {
+                return args[0];
+            } else {
+                return mp_obj_new_complex(mp_obj_get_float(args[0]), 0);
+            }
+
+        case 2:
+        {
+            mp_float_t real, imag;
+            if (MP_OBJ_IS_TYPE(args[1], &complex_type)) {
+                mp_obj_get_complex(args[1], &real, &imag);
+            } else {
+                real = mp_obj_get_float(args[1]);
+                imag = 0;
+            }
+            if (MP_OBJ_IS_TYPE(args[0], &complex_type)) {
+                mp_float_t real2, imag2;
+                mp_obj_get_complex(args[0], &real2, &imag2);
+                real -= imag2;
+                imag += real2;
+            } else {
+                imag += mp_obj_get_float(args[0]);
+            }
+            return mp_obj_new_complex(real, imag);
+        }
+
+        default:
+            nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "complex takes at most 2 arguments, %d given", (void*)(machine_int_t)n_args));
+    }
+}
+
+static mp_obj_t complex_unary_op(int op, mp_obj_t o_in) {
     mp_obj_complex_t *o = o_in;
     switch (op) {
         case RT_UNARY_OP_NOT: if (o->real != 0 || o->imag != 0) { return mp_const_true;} else { return mp_const_false; }
@@ -39,7 +79,7 @@ mp_obj_t complex_unary_op(int op, mp_obj_t o_in) {
     }
 }
 
-mp_obj_t complex_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+static mp_obj_t complex_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     mp_float_t lhs_real, lhs_imag, rhs_real, rhs_imag;
     mp_obj_complex_get(lhs_in, &lhs_real, &lhs_imag);
     mp_obj_complex_get(rhs_in, &rhs_real, &rhs_imag);
@@ -79,6 +119,7 @@ const mp_obj_type_t complex_type = {
     { &mp_const_type },
     "complex",
     complex_print, // print
+    complex_make_new, // make_new
     NULL, // call_n
     complex_unary_op, // unary_op
     complex_binary_op, // binary_op
diff --git a/py/objdict.c b/py/objdict.c
index acf1a9f80150df2ed29920d0fcade4713b6b1418..3737f5eab017a1b4f09d0468f43546f9641b2a3b 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -17,7 +17,7 @@ typedef struct _mp_obj_dict_t {
     mp_map_t map;
 } mp_obj_dict_t;
 
-void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+static void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
     mp_obj_dict_t *self = self_in;
     bool first = true;
     print(env, "{");
@@ -35,7 +35,13 @@ void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_ob
     print(env, "}");
 }
 
-mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+// args are reverse in the array
+static mp_obj_t dict_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+    // TODO create from an iterable!
+    return rt_build_map(0);
+}
+
+static mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     mp_obj_dict_t *o = lhs_in;
     switch (op) {
         case RT_BINARY_OP_SUBSCR:
@@ -58,6 +64,7 @@ const mp_obj_type_t dict_type = {
     { &mp_const_type },
     "dict",
     dict_print, // print
+    dict_make_new, // make_new
     NULL, // call_n
     NULL, // unary_op
     dict_binary_op, // binary_op
diff --git a/py/objexcept.c b/py/objexcept.c
index e735852c379e06fc86ebd070c85d3504828292e0..ec03b9bf1a7ab41f617baf63339d18beb8770f0c 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -39,6 +39,7 @@ const mp_obj_type_t exception_type = {
     { &mp_const_type },
     "exception",
     exception_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objfloat.c b/py/objfloat.c
index f151fe25a0aceed5d50a05b1900be6db20ee6923..8fc925e0b6c4890599de03371216040d2b0ae7be 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -6,6 +6,7 @@
 #include "nlr.h"
 #include "misc.h"
 #include "mpconfig.h"
+#include "mpqstr.h"
 #include "obj.h"
 #include "runtime0.h"
 
@@ -18,12 +19,30 @@ typedef struct _mp_obj_float_t {
 
 mp_obj_t mp_obj_new_float(mp_float_t value);
 
-void float_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+static void float_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
     mp_obj_float_t *o = o_in;
     print(env, "%.8g", o->value);
 }
 
-mp_obj_t float_unary_op(int op, mp_obj_t o_in) {
+static mp_obj_t float_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+    switch (n_args) {
+        case 0:
+            return mp_obj_new_float(0);
+
+        case 1:
+            // TODO allow string as arg and parse it
+            if (MP_OBJ_IS_TYPE(args[0], &float_type)) {
+                return args[0];
+            } else {
+                return mp_obj_new_float(mp_obj_get_float(args[0]));
+            }
+
+        default:
+            nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "float takes at most 1 argument, %d given", (void*)(machine_int_t)n_args));
+    }
+}
+
+static mp_obj_t float_unary_op(int op, mp_obj_t o_in) {
     mp_obj_float_t *o = o_in;
     switch (op) {
         case RT_UNARY_OP_NOT: if (o->value != 0) { return mp_const_true;} else { return mp_const_false; }
@@ -33,7 +52,7 @@ mp_obj_t float_unary_op(int op, mp_obj_t o_in) {
     }
 }
 
-mp_obj_t float_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+static mp_obj_t float_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     if (MP_OBJ_IS_TYPE(rhs_in, &complex_type)) {
         return complex_type.binary_op(op, lhs_in, rhs_in);
     }
@@ -61,6 +80,7 @@ const mp_obj_type_t float_type = {
     { &mp_const_type },
     "float",
     float_print,
+    float_make_new, // make_new
     NULL, // call_n
     float_unary_op,
     float_binary_op,
diff --git a/py/objfun.c b/py/objfun.c
index c4783867a52470ce6f093c4090f02d944b92e513..22b82a9ca053bf7afef1ac698fe2c273df2969d1 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -70,6 +70,7 @@ const mp_obj_type_t fun_native_type = {
     { &mp_const_type },
     "function",
     NULL, // print
+    NULL, // make_new
     fun_native_call_n, // call_n
     NULL, // unary_op
     NULL, // binary_op
@@ -162,6 +163,7 @@ const mp_obj_type_t fun_bc_type = {
     { &mp_const_type },
     "function",
     NULL, // print
+    NULL, // make_new
     fun_bc_call_n, // call_n
     NULL, // unary_op
     NULL, // binary_op
@@ -275,6 +277,7 @@ static const mp_obj_type_t fun_asm_type = {
     { &mp_const_type },
     "function",
     NULL, // print
+    NULL, // make_new
     fun_asm_call_n, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 849212269b1f710266e76710ecf239e0bdba0ad9..7fbca075e2b4e3c49750b44fecee951896f2ec3b 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -40,6 +40,7 @@ const mp_obj_type_t gen_wrap_type = {
     { &mp_const_type },
     "generator",
     NULL, // print
+    NULL, // make_new
     gen_wrap_call_n, // call_n
     NULL, // unary_op
     NULL, // binary_op
@@ -94,6 +95,7 @@ const mp_obj_type_t gen_instance_type = {
     { &mp_const_type },
     "generator",
     gen_instance_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objinstance.c b/py/objinstance.c
index 6cfcdf6c156aa539e56065e9dcdd2207254ee645..fd8cada7cbd4dfd5ede3c6ae38d032b71fd248b2 100644
--- a/py/objinstance.c
+++ b/py/objinstance.c
@@ -93,6 +93,7 @@ const mp_obj_type_t instance_type = {
     { &mp_const_type },
     "instance",
     NULL, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objlist.c b/py/objlist.c
index 967df44fd6951ceebe8f985a4a6808b18a4ba536..30188261131f15297eab2c93457d161c58fb6d50 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -36,6 +36,29 @@ static void list_print(void (*print)(void *env, const char *fmt, ...), void *env
     print(env, "]");
 }
 
+static mp_obj_t list_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+    switch (n_args) {
+        case 0:
+            // return a new, empty list
+            return rt_build_list(0, NULL);
+
+        case 1:
+        {
+            // make list from iterable
+            mp_obj_t iterable = rt_getiter(args[0]);
+            mp_obj_t list = rt_build_list(0, NULL);
+            mp_obj_t item;
+            while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+                rt_list_append(list, item);
+            }
+            return list;
+        }
+
+        default:
+            nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "list takes at most 1 argument, %d given", (void*)(machine_int_t)n_args));
+    }
+}
+
 static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
     mp_obj_list_t *o = lhs;
     switch (op) {
@@ -165,6 +188,7 @@ const mp_obj_type_t list_type = {
     { &mp_const_type },
     "list",
     list_print, // print
+    list_make_new, // make_new
     NULL, // call_n
     NULL, // unary_op
     list_binary_op, // binary_op
@@ -242,6 +266,7 @@ static const mp_obj_type_t list_it_type = {
     { &mp_const_type },
     "list_iterator",
     NULL, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objmodule.c b/py/objmodule.c
index addab14b7579b37fae729ca12929a2d83a92cd01..9263eb44f0e7a9c490ae00a907dda0f3ed9ddade 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -25,6 +25,7 @@ const mp_obj_type_t module_type = {
     { &mp_const_type },
     "module",
     module_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objnone.c b/py/objnone.c
index f7b665e9974ddaeaa4f80a6c70cee3f95dd9b8f3..11dd4939b15feb39b367a6ec0777b6f750f40d31 100644
--- a/py/objnone.c
+++ b/py/objnone.c
@@ -18,6 +18,7 @@ const mp_obj_type_t none_type = {
     { &mp_const_type },
     "NoneType",
     none_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objrange.c b/py/objrange.c
index b7fd17fa0ada1fb5924317f862fadcea891357c3..b163f779b86d30aa6489c683f1d3b5f2387bbeb3 100644
--- a/py/objrange.c
+++ b/py/objrange.c
@@ -26,6 +26,7 @@ static const mp_obj_type_t range_type = {
     { &mp_const_type} ,
     "range",
     NULL, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
@@ -70,6 +71,7 @@ static const mp_obj_type_t range_it_type = {
     { &mp_const_type },
     "range_iterator",
     NULL, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objset.c b/py/objset.c
index f225ca7f66efa52f5c9a92defff3b71c59b5cc0d..826f8bdc864df279a1d430309b8393b6753d19d9 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -5,7 +5,9 @@
 #include "nlr.h"
 #include "misc.h"
 #include "mpconfig.h"
+#include "mpqstr.h"
 #include "obj.h"
+#include "runtime.h"
 #include "map.h"
 
 typedef struct _mp_obj_set_t {
@@ -29,10 +31,34 @@ void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj
     print(env, "}");
 }
 
-static const mp_obj_type_t set_type = {
+static mp_obj_t set_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+    switch (n_args) {
+        case 0:
+            // return a new, empty set
+            return mp_obj_new_set(0, NULL);
+
+        case 1:
+        {
+            // 1 argument, an iterable from which we make a new set
+            mp_obj_t set = mp_obj_new_set(0, NULL);
+            mp_obj_t iterable = rt_getiter(args[0]);
+            mp_obj_t item;
+            while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+                mp_obj_set_store(set, item);
+            }
+            return set;
+        }
+
+        default:
+            nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "set takes at most 1 argument, %d given", (void*)(machine_int_t)n_args));
+    }
+}
+
+const mp_obj_type_t set_type = {
     { &mp_const_type },
     "set",
     set_print, // print
+    set_make_new, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objslice.c b/py/objslice.c
index d99325fd73c275bd487dca4e0635142f625032fc..a624be9631b363ab109d7f18b325f1d8f180f3e0 100644
--- a/py/objslice.c
+++ b/py/objslice.c
@@ -24,6 +24,7 @@ const mp_obj_type_t ellipsis_type = {
     { &mp_const_type },
     "ellipsis",
     ellipsis_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
@@ -58,6 +59,7 @@ const mp_obj_type_t slice_type = {
     "slice",
     slice_print,
     NULL, // call_n
+    NULL, // make_new
     NULL, // unary_op
     NULL, // binary_op
     NULL, // getiter
diff --git a/py/objstr.c b/py/objstr.c
index 03a761863f656096c8b02036e4393c5b5d8010cc..27c9440d03abb345c73b34545fc3692f9046c279 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -179,6 +179,7 @@ const mp_obj_type_t str_type = {
     { &mp_const_type },
     "str",
     str_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     str_binary_op, // binary_op
diff --git a/py/objtuple.c b/py/objtuple.c
index b98d6ede7be40909927e416c1a3de35ed8fc6529..d55259d1a66e1130f45ac644679157c0b14c274c 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -1,13 +1,14 @@
 #include <stdlib.h>
 #include <stdint.h>
-//#include <string.h>
 #include <assert.h>
 
 #include "nlr.h"
 #include "misc.h"
 #include "mpconfig.h"
+#include "mpqstr.h"
 #include "obj.h"
 #include "runtime0.h"
+#include "runtime.h"
 
 typedef struct _mp_obj_tuple_t {
     mp_obj_base_t base;
@@ -20,7 +21,7 @@ static mp_obj_t mp_obj_new_tuple_iterator(mp_obj_tuple_t *tuple, int cur);
 /******************************************************************************/
 /* tuple                                                                      */
 
-void tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+static void tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
     mp_obj_tuple_t *o = o_in;
     print(env, "(");
     for (int i = 0; i < o->len; i++) {
@@ -35,7 +36,48 @@ void tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_o
     print(env, ")");
 }
 
-mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
+// args are in reverse order in the array
+static mp_obj_t tuple_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+    switch (n_args) {
+        case 0:
+            // return a empty tuple
+            return mp_const_empty_tuple;
+
+        case 1:
+        {
+            // 1 argument, an iterable from which we make a new tuple
+            if (MP_OBJ_IS_TYPE(args[0], &tuple_type)) {
+                return args[0];
+            }
+
+            // TODO optimise for cases where we know the length of the iterator
+
+            uint alloc = 4;
+            uint len = 0;
+            mp_obj_t *items = m_new(mp_obj_t, alloc);
+
+            mp_obj_t iterable = rt_getiter(args[0]);
+            mp_obj_t item;
+            while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+                if (len >= alloc) {
+                    items = m_renew(mp_obj_t, items, alloc, alloc * 2);
+                    alloc *= 2;
+                }
+                items[len++] = item;
+            }
+
+            mp_obj_t tuple = mp_obj_new_tuple(len, items);
+            m_free(items, alloc);
+
+            return tuple;
+        }
+
+        default:
+            nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "tuple takes at most 1 argument, %d given", (void*)(machine_int_t)n_args));
+    }
+}
+
+static mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
     mp_obj_tuple_t *o = lhs;
     switch (op) {
         case RT_BINARY_OP_SUBSCR:
@@ -50,20 +92,15 @@ mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
     }
 }
 
-mp_obj_t tuple_getiter(mp_obj_t o_in) {
+static mp_obj_t tuple_getiter(mp_obj_t o_in) {
     return mp_obj_new_tuple_iterator(o_in, 0);
 }
 
-void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items) {
-    mp_obj_tuple_t *self = self_in;
-    *len = self->len;
-    *items = &self->items[0];
-}
-
 const mp_obj_type_t tuple_type = {
     { &mp_const_type },
     "tuple",
     tuple_print, // print
+    tuple_make_new, // make_new
     NULL, // call_n
     NULL, // unary_op
     tuple_binary_op, // binary_op
@@ -72,7 +109,14 @@ const mp_obj_type_t tuple_type = {
     {{NULL, NULL},}, // method list
 };
 
+// the zero-length tuple
+static const mp_obj_tuple_t empty_tuple_obj = {{&tuple_type}, 0};
+const mp_obj_t mp_const_empty_tuple = (mp_obj_t)&empty_tuple_obj;
+
 mp_obj_t mp_obj_new_tuple(uint n, mp_obj_t *items) {
+    if (n == 0) {
+        return mp_const_empty_tuple;
+    }
     mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n);
     o->base.type = &tuple_type;
     o->len = n;
@@ -83,6 +127,9 @@ mp_obj_t mp_obj_new_tuple(uint n, mp_obj_t *items) {
 }
 
 mp_obj_t mp_obj_new_tuple_reverse(uint n, mp_obj_t *items) {
+    if (n == 0) {
+        return mp_const_empty_tuple;
+    }
     mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n);
     o->base.type = &tuple_type;
     o->len = n;
@@ -92,6 +139,12 @@ mp_obj_t mp_obj_new_tuple_reverse(uint n, mp_obj_t *items) {
     return o;
 }
 
+void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items) {
+    mp_obj_tuple_t *self = self_in;
+    *len = self->len;
+    *items = &self->items[0];
+}
+
 /******************************************************************************/
 /* tuple iterator                                                             */
 
@@ -101,7 +154,7 @@ typedef struct _mp_obj_tuple_it_t {
     machine_uint_t cur;
 } mp_obj_tuple_it_t;
 
-mp_obj_t tuple_it_iternext(mp_obj_t self_in) {
+static mp_obj_t tuple_it_iternext(mp_obj_t self_in) {
     mp_obj_tuple_it_t *self = self_in;
     if (self->cur < self->tuple->len) {
         mp_obj_t o_out = self->tuple->items[self->cur];
@@ -116,6 +169,7 @@ static const mp_obj_type_t tuple_it_type = {
     { &mp_const_type },
     "tuple_iterator",
     NULL, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/py/objtype.c b/py/objtype.c
index 83ae48d2d1a6441836bb8efd9512d3be3aad93bc..aeeaebb95d7941245ddcad2335e9038bb145a235 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -4,17 +4,30 @@
 #include "nlr.h"
 #include "misc.h"
 #include "mpconfig.h"
+#include "mpqstr.h"
 #include "obj.h"
 
-void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
-    print(env, "<a type>");
+static void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+    mp_obj_type_t *self = self_in;
+    print(env, "<class '%s'>", self->name);
+}
+
+static mp_obj_t type_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
+    mp_obj_type_t *self = self_in;
+    if (self->make_new != NULL) {
+        // TODO we need to init the object if it's an instance of a type
+        return self->make_new(self, n_args, args);
+    } else {
+        nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "cannot create '%s' instances", self->name));
+    }
 }
 
 const mp_obj_type_t mp_const_type = {
     { &mp_const_type },
-    "<a type>",
+    "type",
     type_print, // print
-    NULL, // call_n
+    NULL, // make_new
+    type_call_n, // call_n
     NULL, // unary_op
     NULL, // binary_op
     NULL, // getiter
diff --git a/py/runtime.c b/py/runtime.c
index 72881067d4e82577c18b4a219ec9ef32b7dd5413..197c08b55ab20722192c1187a80df9b1f7e81e7d 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -91,26 +91,31 @@ void rt_init(void) {
     mp_qstr_map_lookup(&map_builtins, MP_QSTR___build_class__, true)->value = rt_make_function_2(mp_builtin___build_class__);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR___repl_print__, true)->value = rt_make_function_1(mp_builtin___repl_print__);
 
-    // built-in user functions
+    // built-in types
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_bool, true)->value = (mp_obj_t)&bool_type;
+#if MICROPY_ENABLE_FLOAT
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_complex, true)->value = (mp_obj_t)&complex_type;
+#endif
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_dict, true)->value = (mp_obj_t)&dict_type;
+#if MICROPY_ENABLE_FLOAT
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_float, true)->value = (mp_obj_t)&float_type;
+#endif
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_int, true)->value = (mp_obj_t)&int_type;
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_list, true)->value = (mp_obj_t)&list_type;
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_set, true)->value = (mp_obj_t)&set_type;
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_tuple, true)->value = (mp_obj_t)&tuple_type;
+    mp_qstr_map_lookup(&map_builtins, MP_QSTR_type, true)->value = (mp_obj_t)&mp_builtin_type_obj; // TODO
+
+    // built-in user functions; TODO covert all to &mp_builtin_xxx's
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_abs, true)->value = rt_make_function_1(mp_builtin_abs);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_all, true)->value = rt_make_function_1(mp_builtin_all);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_any, true)->value = rt_make_function_1(mp_builtin_any);
-    mp_qstr_map_lookup(&map_builtins, MP_QSTR_bool, true)->value = rt_make_function_var(0, mp_builtin_bool);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_callable, true)->value = rt_make_function_1(mp_builtin_callable);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_chr, true)->value = rt_make_function_1(mp_builtin_chr);
-#if MICROPY_ENABLE_FLOAT
-    mp_qstr_map_lookup(&map_builtins, MP_QSTR_complex, true)->value = (mp_obj_t)&mp_builtin_complex_obj;
-#endif
-    mp_qstr_map_lookup(&map_builtins, MP_QSTR_dict, true)->value = rt_make_function_0(mp_builtin_dict);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_divmod, true)->value = rt_make_function_2(mp_builtin_divmod);
-#if MICROPY_ENABLE_FLOAT
-    mp_qstr_map_lookup(&map_builtins, MP_QSTR_float, true)->value = (mp_obj_t)&mp_builtin_float_obj;
-#endif
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_hash, true)->value = (mp_obj_t)&mp_builtin_hash_obj;
-    mp_qstr_map_lookup(&map_builtins, MP_QSTR_int, true)->value = (mp_obj_t)&mp_builtin_int_obj;
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_iter, true)->value = (mp_obj_t)&mp_builtin_iter_obj;
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_len, true)->value = rt_make_function_1(mp_builtin_len);
-    mp_qstr_map_lookup(&map_builtins, MP_QSTR_list, true)->value = rt_make_function_var(0, mp_builtin_list);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_max, true)->value = rt_make_function_var(1, mp_builtin_max);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_min, true)->value = rt_make_function_var(1, mp_builtin_min);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_next, true)->value = (mp_obj_t)&mp_builtin_next_obj;
@@ -118,9 +123,7 @@ void rt_init(void) {
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_pow, true)->value = rt_make_function_var(2, mp_builtin_pow);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_print, true)->value = rt_make_function_var(0, mp_builtin_print);
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_range, true)->value = rt_make_function_var(1, mp_builtin_range);
-    mp_qstr_map_lookup(&map_builtins, MP_QSTR_set, true)->value = (mp_obj_t)&mp_builtin_set_obj;
     mp_qstr_map_lookup(&map_builtins, MP_QSTR_sum, true)->value = rt_make_function_var(1, mp_builtin_sum);
-    mp_qstr_map_lookup(&map_builtins, MP_QSTR_type, true)->value = (mp_obj_t)&mp_builtin_type_obj;
 
     next_unique_code_id = 1; // 0 indicates "no code"
     unique_codes = NULL;
diff --git a/stm/Makefile b/stm/Makefile
index 729913baeecc3e27b2dc5017474556b21fe33571..d75c945bfc020a22da4d757adfcf0b12cae5d514 100644
--- a/stm/Makefile
+++ b/stm/Makefile
@@ -73,6 +73,7 @@ PY_O = \
 	objfun.o \
 	objgenerator.o \
 	objinstance.o \
+	objint.o \
 	objlist.o \
 	objmodule.o \
 	objnone.o \
diff --git a/stm/i2c.c b/stm/i2c.c
index e00cf41309ae38cf59a2dd0b5922fa957f698dd9..3f29f02c0c5041d54386f45ff945068b799c002d 100644
--- a/stm/i2c.c
+++ b/stm/i2c.c
@@ -330,6 +330,7 @@ static const mp_obj_type_t i2c_obj_type = {
     { &mp_const_type },
     "I2C",
     i2c_obj_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/stm/led.c b/stm/led.c
index 08077641a9cccbbad82f88e669fe07fc22da8364..9305716be9237a28d0289fdf9cf4ea303f8f0ea0 100644
--- a/stm/led.c
+++ b/stm/led.c
@@ -108,6 +108,7 @@ static const mp_obj_type_t led_obj_type = {
     { &mp_const_type },
     "Led",
     led_obj_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/stm/main.c b/stm/main.c
index b7ae8aacca4c9f01fbf53eeb12a58a9950243632..0ab44ca8d470a89fa29bb9b80f5407e3a3621830 100644
--- a/stm/main.c
+++ b/stm/main.c
@@ -746,6 +746,7 @@ static const mp_obj_type_t file_obj_type = {
     { &mp_const_type },
     "File",
     file_obj_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/stm/servo.c b/stm/servo.c
index ae421048b92cebbbdca415eccd36d4d9f4d77e65..1e31db5140da94505f913438b1c8c3bfef8abafe 100644
--- a/stm/servo.c
+++ b/stm/servo.c
@@ -141,6 +141,7 @@ static const mp_obj_type_t servo_obj_type = {
     { &mp_const_type },
     "Servo",
     servo_obj_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op
diff --git a/unix-cpy/Makefile b/unix-cpy/Makefile
index 7fee3438fbacfdd0267d0bfd3423cf145b88f5a0..a1eb9b77e4574840c57d40fe138206fee23a45e0 100644
--- a/unix-cpy/Makefile
+++ b/unix-cpy/Makefile
@@ -38,6 +38,7 @@ PY_O = \
 	objfun.o \
 	objgenerator.o \
 	objinstance.o \
+	objint.o \
 	objlist.o \
 	objmodule.o \
 	objnone.o \
diff --git a/unix/Makefile b/unix/Makefile
index c7be62e999581356b7a5bc4eebfc17bbaa652116..984f1c3bf39f72f055c38a165408e40a69f5f786 100644
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -45,6 +45,7 @@ PY_O = \
 	objfun.o \
 	objgenerator.o \
 	objinstance.o \
+	objint.o \
 	objlist.o \
 	objmodule.o \
 	objnone.o \
diff --git a/unix/main.c b/unix/main.c
index ecb2fa338e6c5d880b4052578ef9babb1e16267f..16fcf6ef8dd919ac87463f55bdd8aab915ad5d65 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -192,6 +192,7 @@ static const mp_obj_type_t test_type = {
     { &mp_const_type },
     "Test",
     test_print, // print
+    NULL, // make_new
     NULL, // call_n
     NULL, // unary_op
     NULL, // binary_op