Commit b483db4868

Andrew Kelley <superjoe30@gmail.com>
2017-05-17 18:26:35
typeId builtin instead of isInteger, isFloat, etc
closes #373
1 parent 9851a94
src/all_types.hpp
@@ -1194,8 +1194,6 @@ enum BuiltinFnId {
     BuiltinFnIdIntType,
     BuiltinFnIdSetDebugSafety,
     BuiltinFnIdTypeName,
-    BuiltinFnIdIsInteger,
-    BuiltinFnIdIsFloat,
     BuiltinFnIdCanImplicitCast,
     BuiltinFnIdSetGlobalAlign,
     BuiltinFnIdSetGlobalSection,
@@ -1207,6 +1205,7 @@ enum BuiltinFnId {
     BuiltinFnIdFieldParentPtr,
     BuiltinFnIdOffsetOf,
     BuiltinFnIdInlineCall,
+    BuiltinFnIdTypeId,
 };
 
 struct BuiltinFnEntry {
@@ -1775,7 +1774,6 @@ enum IrInstructionId {
     IrInstructionIdErrToInt,
     IrInstructionIdCheckSwitchProngs,
     IrInstructionIdCheckStatementIsVoid,
-    IrInstructionIdTestType,
     IrInstructionIdTypeName,
     IrInstructionIdCanImplicitCast,
     IrInstructionIdSetGlobalAlign,
@@ -1786,6 +1784,7 @@ enum IrInstructionId {
     IrInstructionIdEnumTagName,
     IrInstructionIdFieldParentPtr,
     IrInstructionIdOffsetOf,
+    IrInstructionIdTypeId,
 };
 
 struct IrInstruction {
@@ -2464,13 +2463,6 @@ struct IrInstructionCheckStatementIsVoid {
     IrInstruction *statement_value;
 };
 
-struct IrInstructionTestType {
-    IrInstruction base;
-
-    IrInstruction *type_value;
-    TypeTableEntryId type_id;
-};
-
 struct IrInstructionTypeName {
     IrInstruction base;
 
@@ -2540,6 +2532,12 @@ struct IrInstructionOffsetOf {
     IrInstruction *field_name;
 };
 
+struct IrInstructionTypeId {
+    IrInstruction base;
+
+    IrInstruction *type_value;
+};
+
 static const size_t slice_ptr_index = 0;
 static const size_t slice_len_index = 1;
 
src/analyze.cpp
@@ -4340,3 +4340,157 @@ FnTableEntry *get_extern_panic_fn(CodeGen *g) {
     return g->extern_panic_fn;
 }
 
+static const TypeTableEntryId all_type_ids[] = {
+    TypeTableEntryIdMetaType,
+    TypeTableEntryIdVoid,
+    TypeTableEntryIdBool,
+    TypeTableEntryIdUnreachable,
+    TypeTableEntryIdInt,
+    TypeTableEntryIdFloat,
+    TypeTableEntryIdPointer,
+    TypeTableEntryIdArray,
+    TypeTableEntryIdStruct,
+    TypeTableEntryIdNumLitFloat,
+    TypeTableEntryIdNumLitInt,
+    TypeTableEntryIdUndefLit,
+    TypeTableEntryIdNullLit,
+    TypeTableEntryIdMaybe,
+    TypeTableEntryIdErrorUnion,
+    TypeTableEntryIdPureError,
+    TypeTableEntryIdEnum,
+    TypeTableEntryIdEnumTag,
+    TypeTableEntryIdUnion,
+    TypeTableEntryIdFn,
+    TypeTableEntryIdNamespace,
+    TypeTableEntryIdBlock,
+    TypeTableEntryIdBoundFn,
+    TypeTableEntryIdArgTuple,
+    TypeTableEntryIdOpaque,
+};
+
+TypeTableEntryId type_id_at_index(size_t index) {
+    assert(index < array_length(all_type_ids));
+    return all_type_ids[index];
+}
+
+size_t type_id_len() {
+    return array_length(all_type_ids);
+}
+
+size_t type_id_index(TypeTableEntryId id) {
+    switch (id) {
+        case TypeTableEntryIdInvalid:
+        case TypeTableEntryIdVar:
+            zig_unreachable();
+        case TypeTableEntryIdMetaType:
+            return 0;
+        case TypeTableEntryIdVoid:
+            return 1;
+        case TypeTableEntryIdBool:
+            return 2;
+        case TypeTableEntryIdUnreachable:
+            return 3;
+        case TypeTableEntryIdInt:
+            return 4;
+        case TypeTableEntryIdFloat:
+            return 5;
+        case TypeTableEntryIdPointer:
+            return 6;
+        case TypeTableEntryIdArray:
+            return 7;
+        case TypeTableEntryIdStruct:
+            return 8;
+        case TypeTableEntryIdNumLitFloat:
+            return 9;
+        case TypeTableEntryIdNumLitInt:
+            return 10;
+        case TypeTableEntryIdUndefLit:
+            return 11;
+        case TypeTableEntryIdNullLit:
+            return 12;
+        case TypeTableEntryIdMaybe:
+            return 13;
+        case TypeTableEntryIdErrorUnion:
+            return 14;
+        case TypeTableEntryIdPureError:
+            return 15;
+        case TypeTableEntryIdEnum:
+            return 16;
+        case TypeTableEntryIdEnumTag:
+            return 17;
+        case TypeTableEntryIdUnion:
+            return 18;
+        case TypeTableEntryIdFn:
+            return 19;
+        case TypeTableEntryIdNamespace:
+            return 20;
+        case TypeTableEntryIdBlock:
+            return 21;
+        case TypeTableEntryIdBoundFn:
+            return 22;
+        case TypeTableEntryIdArgTuple:
+            return 23;
+        case TypeTableEntryIdOpaque:
+            return 24;
+    }
+    zig_unreachable();
+}
+
+const char *type_id_name(TypeTableEntryId id) {
+    switch (id) {
+        case TypeTableEntryIdInvalid:
+        case TypeTableEntryIdVar:
+            zig_unreachable();
+        case TypeTableEntryIdMetaType:
+            return "Type";
+        case TypeTableEntryIdVoid:
+            return "Void";
+        case TypeTableEntryIdBool:
+            return "Bool";
+        case TypeTableEntryIdUnreachable:
+            return "NoReturn";
+        case TypeTableEntryIdInt:
+            return "Int";
+        case TypeTableEntryIdFloat:
+            return "Float";
+        case TypeTableEntryIdPointer:
+            return "Pointer";
+        case TypeTableEntryIdArray:
+            return "Array";
+        case TypeTableEntryIdStruct:
+            return "Struct";
+        case TypeTableEntryIdNumLitFloat:
+            return "FloatLiteral";
+        case TypeTableEntryIdNumLitInt:
+            return "IntLiteral";
+        case TypeTableEntryIdUndefLit:
+            return "UndefinedLiteral";
+        case TypeTableEntryIdNullLit:
+            return "NullLiteral";
+        case TypeTableEntryIdMaybe:
+            return "Nullable";
+        case TypeTableEntryIdErrorUnion:
+            return "ErrorUnion";
+        case TypeTableEntryIdPureError:
+            return "Error";
+        case TypeTableEntryIdEnum:
+            return "Enum";
+        case TypeTableEntryIdEnumTag:
+            return "EnumTag";
+        case TypeTableEntryIdUnion:
+            return "Union";
+        case TypeTableEntryIdFn:
+            return "Fn";
+        case TypeTableEntryIdNamespace:
+            return "Namespace";
+        case TypeTableEntryIdBlock:
+            return "Block";
+        case TypeTableEntryIdBoundFn:
+            return "BoundFn";
+        case TypeTableEntryIdArgTuple:
+            return "ArgTuple";
+        case TypeTableEntryIdOpaque:
+            return "Opaque";
+    }
+    zig_unreachable();
+}
src/analyze.hpp
@@ -160,4 +160,9 @@ TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, Type
 void expand_undef_array(CodeGen *g, ConstExprValue *const_val);
 void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
 
+const char *type_id_name(TypeTableEntryId id);
+TypeTableEntryId type_id_at_index(size_t index);
+size_t type_id_len();
+size_t type_id_index(TypeTableEntryId id);
+
 #endif
src/codegen.cpp
@@ -3009,7 +3009,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdTestComptime:
         case IrInstructionIdCheckSwitchProngs:
         case IrInstructionIdCheckStatementIsVoid:
-        case IrInstructionIdTestType:
         case IrInstructionIdTypeName:
         case IrInstructionIdCanImplicitCast:
         case IrInstructionIdSetGlobalAlign:
@@ -3018,6 +3017,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdDeclRef:
         case IrInstructionIdSwitchVar:
         case IrInstructionIdOffsetOf:
+        case IrInstructionIdTypeId:
             zig_unreachable();
         case IrInstructionIdReturn:
             return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -4423,8 +4423,6 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
     create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
     create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
-    create_builtin_fn(g, BuiltinFnIdIsInteger, "isInteger", 1);
-    create_builtin_fn(g, BuiltinFnIdIsFloat, "isFloat", 1);
     create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
     create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
     create_builtin_fn(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);
@@ -4449,6 +4447,7 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
     create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
     create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
+    create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
 }
 
 static const char *bool_to_str(bool b) {
@@ -4580,6 +4579,15 @@ static void define_builtin_compile_vars(CodeGen *g) {
             "    ReleaseFast,\n"
             "};\n\n");
     }
+    {
+        buf_appendf(contents, "pub const TypeId = enum {\n");
+        size_t field_count = type_id_len();
+        for (size_t i = 0; i < field_count; i += 1) {
+            const TypeTableEntryId id = type_id_at_index(i);
+            buf_appendf(contents, "    %s,\n", type_id_name(id));
+        }
+        buf_appendf(contents, "};\n\n");
+    }
     buf_appendf(contents, "pub const is_big_endian = %s;\n", bool_to_str(g->is_big_endian));
     buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
     buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
src/ir.cpp
@@ -517,10 +517,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckStatementIs
     return IrInstructionIdCheckStatementIsVoid;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionTestType *) {
-    return IrInstructionIdTestType;
-}
-
 static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeName *) {
     return IrInstructionIdTypeName;
 }
@@ -561,6 +557,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) {
     return IrInstructionIdOffsetOf;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) {
+    return IrInstructionIdTypeId;
+}
+
 template<typename T>
 static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(1);
@@ -2027,19 +2027,6 @@ static IrInstruction *ir_build_check_statement_is_void(IrBuilder *irb, Scope *sc
     return &instruction->base;
 }
 
-static IrInstruction *ir_build_test_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
-        IrInstruction *type_value, TypeTableEntryId type_id)
-{
-    IrInstructionTestType *instruction = ir_build_instruction<IrInstructionTestType>(
-            irb, scope, source_node);
-    instruction->type_value = type_value;
-    instruction->type_id = type_id;
-
-    ir_ref_instruction(type_value, irb->current_basic_block);
-
-    return &instruction->base;
-}
-
 static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
         IrInstruction *type_value)
 {
@@ -2168,6 +2155,17 @@ static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *
     return &instruction->base;
 }
 
+static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node,
+        IrInstruction *type_value)
+{
+    IrInstructionTypeId *instruction = ir_build_instruction<IrInstructionTypeId>(irb, scope, source_node);
+    instruction->type_value = type_value;
+
+    ir_ref_instruction(type_value, irb->current_basic_block);
+
+    return &instruction->base;
+}
+
 static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
     return nullptr;
 }
@@ -2761,13 +2759,6 @@ static IrInstruction *ir_instruction_checkstatementisvoid_get_dep(IrInstructionC
     }
 }
 
-static IrInstruction *ir_instruction_testtype_get_dep(IrInstructionTestType *instruction, size_t index) {
-    switch (index) {
-        case 0: return instruction->type_value;
-        default: return nullptr;
-    }
-}
-
 static IrInstruction *ir_instruction_typename_get_dep(IrInstructionTypeName *instruction, size_t index) {
     switch (index) {
         case 0: return instruction->type_value;
@@ -2839,6 +2830,13 @@ static IrInstruction *ir_instruction_offsetof_get_dep(IrInstructionOffsetOf *ins
     }
 }
 
+static IrInstruction *ir_instruction_typeid_get_dep(IrInstructionTypeId *instruction, size_t index) {
+    switch (index) {
+        case 0: return instruction->type_value;
+        default: return nullptr;
+    }
+}
+
 static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
     switch (instruction->id) {
         case IrInstructionIdInvalid:
@@ -3007,8 +3005,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
             return ir_instruction_checkswitchprongs_get_dep((IrInstructionCheckSwitchProngs *) instruction, index);
         case IrInstructionIdCheckStatementIsVoid:
             return ir_instruction_checkstatementisvoid_get_dep((IrInstructionCheckStatementIsVoid *) instruction, index);
-        case IrInstructionIdTestType:
-            return ir_instruction_testtype_get_dep((IrInstructionTestType *) instruction, index);
         case IrInstructionIdTypeName:
             return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index);
         case IrInstructionIdCanImplicitCast:
@@ -3029,6 +3025,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
             return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index);
         case IrInstructionIdOffsetOf:
             return ir_instruction_offsetof_get_dep((IrInstructionOffsetOf *) instruction, index);
+        case IrInstructionIdTypeId:
+            return ir_instruction_typeid_get_dep((IrInstructionTypeId *) instruction, index);
     }
     zig_unreachable();
 }
@@ -3793,18 +3791,6 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
     return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
 }
 
-static IrInstruction *ir_gen_test_type(IrBuilder *irb, Scope *scope, AstNode *node, TypeTableEntryId type_id) {
-    assert(node->type == NodeTypeFnCallExpr);
-
-    AstNode *type_node = node->data.fn_call_expr.params.at(0);
-
-    IrInstruction *type_value = ir_gen_node(irb, type_node, scope);
-    if (type_value == irb->codegen->invalid_instruction)
-        return irb->codegen->invalid_instruction;
-
-    return ir_build_test_type(irb, scope, node, type_value, type_id);
-}
-
 static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {
     assert(node->type == NodeTypeFnCallExpr);
 
@@ -4217,10 +4203,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
 
                 return ir_build_type_name(irb, scope, node, arg0_value);
             }
-        case BuiltinFnIdIsInteger:
-            return ir_gen_test_type(irb, scope, node, TypeTableEntryIdInt);
-        case BuiltinFnIdIsFloat:
-            return ir_gen_test_type(irb, scope, node, TypeTableEntryIdFloat);
         case BuiltinFnIdCanImplicitCast:
             {
                 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@@ -4375,6 +4357,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
 
                 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, true);
             }
+        case BuiltinFnIdTypeId:
+            {
+                AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+                IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+                if (arg0_value == irb->codegen->invalid_instruction)
+                    return arg0_value;
+
+                return ir_build_type_id(irb, scope, node, arg0_value);
+            }
     }
     zig_unreachable();
 }
@@ -11865,6 +11856,27 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira,
     return ira->codegen->builtin_types.entry_num_lit_int;
 }
 
+static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
+        IrInstructionTypeId *instruction)
+{
+    IrInstruction *type_value = instruction->type_value->other;
+    TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
+    if (type_is_invalid(type_entry))
+        return ira->codegen->builtin_types.entry_invalid;
+
+    Tld *tld = ira->codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str("TypeId"));
+    resolve_top_level_decl(ira->codegen, tld, false);
+    assert(tld->id == TldIdVar);
+    TldVar *tld_var = (TldVar *)tld;
+    ConstExprValue *var_value = tld_var->var->value;
+    assert(var_value->type->id == TypeTableEntryIdMetaType);
+    TypeTableEntry *result_type = var_value->data.x_type;
+
+    ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+    out_val->data.x_enum.tag = type_id_index(type_entry->id);
+    return result_type;
+}
+
 static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {
     IrInstruction *type_value = instruction->type_value->other;
     TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
@@ -13025,17 +13037,6 @@ static TypeTableEntry *ir_analyze_instruction_check_statement_is_void(IrAnalyze
     return ira->codegen->builtin_types.entry_void;
 }
 
-static TypeTableEntry *ir_analyze_instruction_test_type(IrAnalyze *ira, IrInstructionTestType *instruction) {
-    IrInstruction *type_value = instruction->type_value->other;
-    TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
-    if (type_is_invalid(type_entry))
-        return ira->codegen->builtin_types.entry_invalid;
-
-    ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
-    out_val->data.x_bool = (type_entry->id == instruction->type_id);
-    return ira->codegen->builtin_types.entry_bool;
-}
-
 static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
         IrInstructionCanImplicitCast *instruction)
 {
@@ -13368,8 +13369,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
             return ir_analyze_instruction_check_switch_prongs(ira, (IrInstructionCheckSwitchProngs *)instruction);
         case IrInstructionIdCheckStatementIsVoid:
             return ir_analyze_instruction_check_statement_is_void(ira, (IrInstructionCheckStatementIsVoid *)instruction);
-        case IrInstructionIdTestType:
-            return ir_analyze_instruction_test_type(ira, (IrInstructionTestType *)instruction);
         case IrInstructionIdCanImplicitCast:
             return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction);
         case IrInstructionIdDeclRef:
@@ -13386,6 +13385,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
             return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);
         case IrInstructionIdOffsetOf:
             return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction);
+        case IrInstructionIdTypeId:
+            return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction);
         case IrInstructionIdMaybeWrap:
         case IrInstructionIdErrWrapCode:
         case IrInstructionIdErrWrapPayload:
@@ -13556,7 +13557,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdIntToEnum:
         case IrInstructionIdIntToErr:
         case IrInstructionIdErrToInt:
-        case IrInstructionIdTestType:
         case IrInstructionIdCanImplicitCast:
         case IrInstructionIdDeclRef:
         case IrInstructionIdErrName:
@@ -13564,6 +13564,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdEnumTagName:
         case IrInstructionIdFieldParentPtr:
         case IrInstructionIdOffsetOf:
+        case IrInstructionIdTypeId:
             return false;
         case IrInstructionIdAsm:
             {
src/ir_print.cpp
@@ -811,11 +811,6 @@ static void ir_print_check_statement_is_void(IrPrint *irp, IrInstructionCheckSta
     fprintf(irp->f, ")");
 }
 
-static void ir_print_test_type(IrPrint *irp, IrInstructionTestType *instruction) {
-    fprintf(irp->f, "testtype ");
-    ir_print_other_instruction(irp, instruction->type_value);
-}
-
 static void ir_print_type_name(IrPrint *irp, IrInstructionTypeName *instruction) {
     fprintf(irp->f, "typename ");
     ir_print_other_instruction(irp, instruction->type_value);
@@ -884,6 +879,12 @@ static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction)
     fprintf(irp->f, ")");
 }
 
+static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) {
+    fprintf(irp->f, "@typeId(");
+    ir_print_other_instruction(irp, instruction->type_value);
+    fprintf(irp->f, ")");
+}
+
 static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
     ir_print_prefix(irp, instruction);
     switch (instruction->id) {
@@ -1135,9 +1136,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdCheckStatementIsVoid:
             ir_print_check_statement_is_void(irp, (IrInstructionCheckStatementIsVoid *)instruction);
             break;
-        case IrInstructionIdTestType:
-            ir_print_test_type(irp, (IrInstructionTestType *)instruction);
-            break;
         case IrInstructionIdTypeName:
             ir_print_type_name(irp, (IrInstructionTypeName *)instruction);
             break;
@@ -1168,6 +1166,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdOffsetOf:
             ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
             break;
+        case IrInstructionIdTypeId:
+            ir_print_type_id(irp, (IrInstructionTypeId *)instruction);
+            break;
     }
     fprintf(irp->f, "\n");
 }
std/build.zig
@@ -488,15 +488,15 @@ pub const Builder = struct {
     }
 
     fn typeToEnum(comptime T: type) -> TypeId {
-        if (@isInteger(T)) {
-            TypeId.Int
-        } else if (@isFloat(T)) {
-            TypeId.Float
-        } else switch (T) {
-            bool => TypeId.Bool,
-            []const u8 => TypeId.String,
-            []const []const u8 => TypeId.List,
-            else => @compileError("Unsupported type: " ++ @typeName(T)),
+        switch (@typeId(T)) {
+            builtin.TypeId.Int => TypeId.Int,
+            builtin.TypeId.Float => TypeId.Float,
+            builtin.TypeId.Bool => TypeId.Bool,
+            else => switch (T) {
+                []const u8 => TypeId.String,
+                []const []const u8 => TypeId.List,
+                else => @compileError("Unsupported type: " ++ @typeName(T)),
+            },
         }
     }
 
std/fmt.zig
@@ -2,6 +2,7 @@ const math = @import("math.zig");
 const debug = @import("debug.zig");
 const assert = debug.assert;
 const mem = @import("mem.zig");
+const builtin = @import("builtin");
 
 const max_f64_digits = 65;
 const max_int_digits = 65;
@@ -174,19 +175,25 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,
 
 pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool {
     const T = @typeOf(value);
-    if (@isInteger(T)) {
-        return formatInt(value, 10, false, 0, context, output);
-    } else if (@isFloat(T)) {
-        @compileError("TODO implement formatFloat");
-    } else if (@canImplicitCast([]const u8, value)) {
-        const casted_value = ([]const u8)(value);
-        return output(context, casted_value);
-    } else if (T == void) {
-        return output(context, "void");
-    } else if (T == bool) {
-        return output(context, if (value) "true" else "false");
-    } else {
-        @compileError("Unable to format type '" ++ @typeName(T) ++ "'");
+    switch (@typeId(T)) {
+        builtin.TypeId.Int => {
+            return formatInt(value, 10, false, 0, context, output);
+        },
+        builtin.TypeId.Float => {
+            @compileError("TODO implement formatFloat");
+        },
+        builtin.TypeId.Void => {
+            return output(context, "void");
+        },
+        builtin.TypeId.Bool => {
+            return output(context, if (value) "true" else "false");
+        },
+        else => if (@canImplicitCast([]const u8, value)) {
+            const casted_value = ([]const u8)(value);
+            return output(context, casted_value);
+        } else {
+            @compileError("Unable to format type '" ++ @typeName(T) ++ "'");
+        },
     }
 }
 
std/math.zig
@@ -1,4 +1,5 @@
 const assert = @import("debug.zig").assert;
+const builtin = @import("builtin");
 
 pub const Cmp = enum {
     Less,
@@ -61,23 +62,27 @@ fn testOverflow() {
 
 pub fn log(comptime base: usize, value: var) -> @typeOf(value) {
     const T = @typeOf(value);
-    if (@isInteger(T)) {
-        if (base == 2) {
-            return T.bit_count - 1 - @clz(value);
-        } else {
-            @compileError("TODO implement log for non base 2 integers");
-        }
-    } else if (@isFloat(T)) {
-        @compileError("TODO implement log for floats");
-    } else {
-        @compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'");
+    switch (@typeId(T)) {
+        builtin.TypeId.Int => {
+            if (base == 2) {
+                return T.bit_count - 1 - @clz(value);
+            } else {
+                @compileError("TODO implement log for non base 2 integers");
+            }
+        },
+        builtin.TypeId.Float => {
+            @compileError("TODO implement log for floats");
+        },
+        else => {
+            @compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'");
+        },
     }
 }
 
 error Overflow;
 pub fn absInt(x: var) -> %@typeOf(x) {
     const T = @typeOf(x);
-    comptime assert(@isInteger(T)); // must pass an integer to absInt
+    comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
     comptime assert(T.is_signed); // must pass a signed integer to absInt
     if (x == @minValue(@typeOf(x)))
         return error.Overflow;
@@ -97,7 +102,7 @@ fn testAbsInt() {
 }
 
 pub fn absFloat(x: var) -> @typeOf(x) {
-    comptime assert(@isFloat(@typeOf(x)));
+    comptime assert(@typeId(@typeOf(x)) == builtin.TypeId.Float);
     return if (x < 0) -x else x;
 }
 
@@ -116,7 +121,7 @@ pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {
     @setDebugSafety(this, false);
     if (denominator == 0)
         return error.DivisionByZero;
-    if (@isInteger(T) and T.is_signed and numerator == @minValue(T) and denominator == -1)
+    if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
         return error.Overflow;
     return @divTrunc(numerator, denominator);
 }
@@ -141,7 +146,7 @@ pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {
     @setDebugSafety(this, false);
     if (denominator == 0)
         return error.DivisionByZero;
-    if (@isInteger(T) and T.is_signed and numerator == @minValue(T) and denominator == -1)
+    if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
         return error.Overflow;
     return @divFloor(numerator, denominator);
 }
@@ -167,7 +172,7 @@ pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {
     @setDebugSafety(this, false);
     if (denominator == 0)
         return error.DivisionByZero;
-    if (@isInteger(T) and T.is_signed and numerator == @minValue(T) and denominator == -1)
+    if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
         return error.Overflow;
     const result = @divTrunc(numerator, denominator);
     if (result * denominator != numerator)
@@ -246,7 +251,7 @@ fn testRem() {
 }
 
 fn isNan(comptime T: type, x: T) -> bool {
-    assert(@isFloat(T));
+    assert(@typeId(T) == builtin.TypeId.Float);
     const bits = floatBits(x);
     if (T == f32) {
         return (bits & 0x7fffffff) > 0x7f800000;
@@ -258,7 +263,7 @@ fn isNan(comptime T: type, x: T) -> bool {
 }
 
 fn floatBits(comptime T: type, x: T) -> @IntType(false, T.bit_count) {
-    assert(@isFloat(T));
+    assert(@typeId(T) == builtin.TypeId.Float);
     const uint = @IntType(false, T.bit_count);
     return *@intToPtr(&const uint, &x);
 }
test/cases/misc.zig
@@ -446,29 +446,42 @@ fn testArray2DConstDoublePtr(ptr: &const f32) {
     assert(ptr[1] == 2.0);
 }
 
-test "@isInteger" {
-    comptime {
-        assert(@isInteger(i8));
-        assert(@isInteger(u8));
-        assert(@isInteger(i64));
-        assert(@isInteger(u64));
-        assert(!@isInteger(f32));
-        assert(!@isInteger(f64));
-        assert(!@isInteger(bool));
-        assert(!@isInteger(&i32));
-    }
-}
+const Tid = builtin.TypeId;
+const AStruct = struct { x: i32, };
+const AnEnum = enum { One, Two, };
+const AnEnumWithPayload = enum { One: i32, Two, };
 
-test "@isFloat" {
+test "@typeId" {
     comptime {
-        assert(!@isFloat(i8));
-        assert(!@isFloat(u8));
-        assert(!@isFloat(i64));
-        assert(!@isFloat(u64));
-        assert(@isFloat(f32));
-        assert(@isFloat(f64));
-        assert(!@isFloat(bool));
-        assert(!@isFloat(&f32));
+        assert(@typeId(type) == Tid.Type);
+        assert(@typeId(void) == Tid.Void);
+        assert(@typeId(bool) == Tid.Bool);
+        assert(@typeId(noreturn) == Tid.NoReturn);
+        assert(@typeId(i8) == Tid.Int);
+        assert(@typeId(u8) == Tid.Int);
+        assert(@typeId(i64) == Tid.Int);
+        assert(@typeId(u64) == Tid.Int);
+        assert(@typeId(f32) == Tid.Float);
+        assert(@typeId(f64) == Tid.Float);
+        assert(@typeId(&f32) == Tid.Pointer);
+        assert(@typeId([2]u8) == Tid.Array);
+        assert(@typeId(AStruct) == Tid.Struct);
+        assert(@typeId(@typeOf(1)) == Tid.IntLiteral);
+        assert(@typeId(@typeOf(1.0)) == Tid.FloatLiteral);
+        assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral);
+        assert(@typeId(@typeOf(null)) == Tid.NullLiteral);
+        assert(@typeId(?i32) == Tid.Nullable);
+        assert(@typeId(%i32) == Tid.ErrorUnion);
+        assert(@typeId(error) == Tid.Error);
+        assert(@typeId(AnEnum) == Tid.Enum);
+        assert(@typeId(@typeOf(AnEnumWithPayload.One)) == Tid.EnumTag);
+        // TODO  union
+        assert(@typeId(fn()) == Tid.Fn);
+        assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
+        assert(@typeId(@typeOf({this})) == Tid.Block);
+        // TODO bound fn
+        // TODO arg tuple
+        // TODO opaque
     }
 }