authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-05 19:15:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-05 19:19:19-07:00
logc03a04a58942446b48e9294df991a17a3a6f7b48
tree9e306df81d9c1443bee81ccc499d76f620e23923
parente9e3a2994696a3131125ebc4b1f0eec7ca5306d9

stage2: return type expressions of generic functions

* ZIR encoding for function instructions have a body for the return type. This lets Sema for generic functions do the same thing it does for parameters, handling `error.GenericPoison` in the evaluation of the return type by marking the function as generic. * Sema: fix missing block around the new Decl arena finalization. This led to a memory corruption. * Added some floating point support to the LLVM backend but didn't get far enough to pass any new tests.

9 files changed, 344 insertions(+), 208 deletions(-)

src/AstGen.zig+39-31
...@@ -1041,6 +1041,7 @@ fn fnProtoExpr(...@@ -1041,6 +1041,7 @@ fn fnProtoExpr(
1041 fn_proto: ast.full.FnProto,1041 fn_proto: ast.full.FnProto,
1042) InnerError!Zir.Inst.Ref {1042) InnerError!Zir.Inst.Ref {
1043 const astgen = gz.astgen;1043 const astgen = gz.astgen;
1044 const gpa = astgen.gpa;
1044 const tree = astgen.tree;1045 const tree = astgen.tree;
1045 const token_tags = tree.tokens.items(.tag);1046 const token_tags = tree.tokens.items(.tag);
10461047
...@@ -1083,7 +1084,6 @@ fn fnProtoExpr(...@@ -1083,7 +1084,6 @@ fn fnProtoExpr(
1083 .param_anytype;1084 .param_anytype;
1084 _ = try gz.addStrTok(tag, param_name, name_token);1085 _ = try gz.addStrTok(tag, param_name, name_token);
1085 } else {1086 } else {
1086 const gpa = astgen.gpa;
1087 const param_type_node = param.type_expr;1087 const param_type_node = param.type_expr;
1088 assert(param_type_node != 0);1088 assert(param_type_node != 0);
1089 var param_gz = gz.makeSubBlock(scope);1089 var param_gz = gz.makeSubBlock(scope);
...@@ -1113,15 +1113,13 @@ fn fnProtoExpr(...@@ -1113,15 +1113,13 @@ fn fnProtoExpr(
1113 if (is_inferred_error) {1113 if (is_inferred_error) {
1114 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});1114 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
1115 }1115 }
1116 const return_type_inst = try AstGen.expr(1116 var ret_gz = gz.makeSubBlock(scope);
1117 gz,1117 defer ret_gz.instructions.deinit(gpa);
1118 scope,1118 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
1119 .{ .ty = .type_type },1119 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
1120 fn_proto.ast.return_type,
1121 );
11221120
1123 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)1121 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
1124 try AstGen.expr(1122 try expr(
1125 gz,1123 gz,
1126 scope,1124 scope,
1127 .{ .ty = .calling_convention_type },1125 .{ .ty = .calling_convention_type },
...@@ -1133,7 +1131,8 @@ fn fnProtoExpr(...@@ -1133,7 +1131,8 @@ fn fnProtoExpr(
1133 const result = try gz.addFunc(.{1131 const result = try gz.addFunc(.{
1134 .src_node = fn_proto.ast.proto_node,1132 .src_node = fn_proto.ast.proto_node,
1135 .param_block = 0,1133 .param_block = 0,
1136 .ret_ty = return_type_inst,1134 .ret_ty = ret_gz.instructions.items,
1135 .ret_br = ret_br,
1137 .body = &[0]Zir.Inst.Index{},1136 .body = &[0]Zir.Inst.Index{},
1138 .cc = cc,1137 .cc = cc,
1139 .align_inst = align_inst,1138 .align_inst = align_inst,
...@@ -3005,12 +3004,10 @@ fn fnDecl(...@@ -3005,12 +3004,10 @@ fn fnDecl(
3005 break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);3004 break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
3006 };3005 };
30073006
3008 const return_type_inst = try AstGen.expr(3007 var ret_gz = gz.makeSubBlock(params_scope);
3009 &decl_gz,3008 defer ret_gz.instructions.deinit(gpa);
3010 params_scope,3009 const ret_ty = try expr(&decl_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
3011 .{ .ty = .type_type },3010 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
3012 fn_proto.ast.return_type,
3013 );
30143011
3015 const cc: Zir.Inst.Ref = blk: {3012 const cc: Zir.Inst.Ref = blk: {
3016 if (fn_proto.ast.callconv_expr != 0) {3013 if (fn_proto.ast.callconv_expr != 0) {
...@@ -3021,7 +3018,7 @@ fn fnDecl(...@@ -3021,7 +3018,7 @@ fn fnDecl(
3021 .{},3018 .{},
3022 );3019 );
3023 }3020 }
3024 break :blk try AstGen.expr(3021 break :blk try expr(
3025 &decl_gz,3022 &decl_gz,
3026 params_scope,3023 params_scope,
3027 .{ .ty = .calling_convention_type },3024 .{ .ty = .calling_convention_type },
...@@ -3046,7 +3043,8 @@ fn fnDecl(...@@ -3046,7 +3043,8 @@ fn fnDecl(
3046 }3043 }
3047 break :func try decl_gz.addFunc(.{3044 break :func try decl_gz.addFunc(.{
3048 .src_node = decl_node,3045 .src_node = decl_node,
3049 .ret_ty = return_type_inst,3046 .ret_ty = ret_gz.instructions.items,
3047 .ret_br = ret_br,
3050 .param_block = block_inst,3048 .param_block = block_inst,
3051 .body = &[0]Zir.Inst.Index{},3049 .body = &[0]Zir.Inst.Index{},
3052 .cc = cc,3050 .cc = cc,
...@@ -3085,7 +3083,8 @@ fn fnDecl(...@@ -3085,7 +3083,8 @@ fn fnDecl(
3085 break :func try decl_gz.addFunc(.{3083 break :func try decl_gz.addFunc(.{
3086 .src_node = decl_node,3084 .src_node = decl_node,
3087 .param_block = block_inst,3085 .param_block = block_inst,
3088 .ret_ty = return_type_inst,3086 .ret_ty = ret_gz.instructions.items,
3087 .ret_br = ret_br,
3089 .body = fn_gz.instructions.items,3088 .body = fn_gz.instructions.items,
3090 .cc = cc,3089 .cc = cc,
3091 .align_inst = .none, // passed in the per-decl data3090 .align_inst = .none, // passed in the per-decl data
...@@ -3430,7 +3429,8 @@ fn testDecl(...@@ -3430,7 +3429,8 @@ fn testDecl(
3430 const func_inst = try decl_block.addFunc(.{3429 const func_inst = try decl_block.addFunc(.{
3431 .src_node = node,3430 .src_node = node,
3432 .param_block = block_inst,3431 .param_block = block_inst,
3433 .ret_ty = .void_type,3432 .ret_ty = &.{},
3433 .ret_br = 0,
3434 .body = fn_block.instructions.items,3434 .body = fn_block.instructions.items,
3435 .cc = .none,3435 .cc = .none,
3436 .align_inst = .none,3436 .align_inst = .none,
...@@ -9127,7 +9127,8 @@ const GenZir = struct {...@@ -9127,7 +9127,8 @@ const GenZir = struct {
9127 src_node: ast.Node.Index,9127 src_node: ast.Node.Index,
9128 body: []const Zir.Inst.Index,9128 body: []const Zir.Inst.Index,
9129 param_block: Zir.Inst.Index,9129 param_block: Zir.Inst.Index,
9130 ret_ty: Zir.Inst.Ref,9130 ret_ty: []const Zir.Inst.Index,
9131 ret_br: Zir.Inst.Index,
9131 cc: Zir.Inst.Ref,9132 cc: Zir.Inst.Ref,
9132 align_inst: Zir.Inst.Ref,9133 align_inst: Zir.Inst.Ref,
9133 lib_name: u32,9134 lib_name: u32,
...@@ -9137,7 +9138,6 @@ const GenZir = struct {...@@ -9137,7 +9138,6 @@ const GenZir = struct {
9137 is_extern: bool,9138 is_extern: bool,
9138 }) !Zir.Inst.Ref {9139 }) !Zir.Inst.Ref {
9139 assert(args.src_node != 0);9140 assert(args.src_node != 0);
9140 assert(args.ret_ty != .none);
9141 const astgen = gz.astgen;9141 const astgen = gz.astgen;
9142 const gpa = astgen.gpa;9142 const gpa = astgen.gpa;
91439143
...@@ -9179,7 +9179,7 @@ const GenZir = struct {...@@ -9179,7 +9179,7 @@ const GenZir = struct {
9179 try astgen.extra.ensureUnusedCapacity(9179 try astgen.extra.ensureUnusedCapacity(
9180 gpa,9180 gpa,
9181 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +9181 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
9182 args.body.len + src_locs.len +9182 args.ret_ty.len + args.body.len + src_locs.len +
9183 @boolToInt(args.lib_name != 0) +9183 @boolToInt(args.lib_name != 0) +
9184 @boolToInt(args.align_inst != .none) +9184 @boolToInt(args.align_inst != .none) +
9185 @boolToInt(args.cc != .none),9185 @boolToInt(args.cc != .none),
...@@ -9187,7 +9187,7 @@ const GenZir = struct {...@@ -9187,7 +9187,7 @@ const GenZir = struct {
9187 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{9187 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
9188 .src_node = gz.nodeIndexToRelative(args.src_node),9188 .src_node = gz.nodeIndexToRelative(args.src_node),
9189 .param_block = args.param_block,9189 .param_block = args.param_block,
9190 .return_type = args.ret_ty,9190 .ret_body_len = @intCast(u32, args.ret_ty.len),
9191 .body_len = @intCast(u32, args.body.len),9191 .body_len = @intCast(u32, args.body.len),
9192 });9192 });
9193 if (args.lib_name != 0) {9193 if (args.lib_name != 0) {
...@@ -9199,10 +9199,14 @@ const GenZir = struct {...@@ -9199,10 +9199,14 @@ const GenZir = struct {
9199 if (args.align_inst != .none) {9199 if (args.align_inst != .none) {
9200 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));9200 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
9201 }9201 }
9202 astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
9202 astgen.extra.appendSliceAssumeCapacity(args.body);9203 astgen.extra.appendSliceAssumeCapacity(args.body);
9203 astgen.extra.appendSliceAssumeCapacity(src_locs);9204 astgen.extra.appendSliceAssumeCapacity(src_locs);
92049205
9205 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);9206 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
9207 if (args.ret_br != 0) {
9208 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
9209 }
9206 astgen.instructions.appendAssumeCapacity(.{9210 astgen.instructions.appendAssumeCapacity(.{
9207 .tag = .extended,9211 .tag = .extended,
9208 .data = .{ .extended = .{9212 .data = .{ .extended = .{
...@@ -9222,23 +9226,27 @@ const GenZir = struct {...@@ -9222,23 +9226,27 @@ const GenZir = struct {
9222 gz.instructions.appendAssumeCapacity(new_index);9226 gz.instructions.appendAssumeCapacity(new_index);
9223 return indexToRef(new_index);9227 return indexToRef(new_index);
9224 } else {9228 } else {
9225 try gz.astgen.extra.ensureUnusedCapacity(9229 try astgen.extra.ensureUnusedCapacity(
9226 gpa,9230 gpa,
9227 @typeInfo(Zir.Inst.Func).Struct.fields.len +9231 @typeInfo(Zir.Inst.Func).Struct.fields.len +
9228 args.body.len + src_locs.len,9232 args.ret_ty.len + args.body.len + src_locs.len,
9229 );9233 );
92309234
9231 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{9235 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{
9232 .param_block = args.param_block,9236 .param_block = args.param_block,
9233 .return_type = args.ret_ty,9237 .ret_body_len = @intCast(u32, args.ret_ty.len),
9234 .body_len = @intCast(u32, args.body.len),9238 .body_len = @intCast(u32, args.body.len),
9235 });9239 });
9236 gz.astgen.extra.appendSliceAssumeCapacity(args.body);9240 astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
9237 gz.astgen.extra.appendSliceAssumeCapacity(src_locs);9241 astgen.extra.appendSliceAssumeCapacity(args.body);
9242 astgen.extra.appendSliceAssumeCapacity(src_locs);
92389243
9239 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;9244 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;
9240 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9245 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
9241 gz.astgen.instructions.appendAssumeCapacity(.{9246 if (args.ret_br != 0) {
9247 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
9248 }
9249 astgen.instructions.appendAssumeCapacity(.{
9242 .tag = tag,9250 .tag = tag,
9243 .data = .{ .pl_node = .{9251 .data = .{ .pl_node = .{
9244 .src_node = gz.nodeIndexToRelative(args.src_node),9252 .src_node = gz.nodeIndexToRelative(args.src_node),
src/Module.zig+3
...@@ -842,6 +842,9 @@ pub const Fn = struct {...@@ -842,6 +842,9 @@ pub const Fn = struct {
842842
843 pub fn getInferredErrorSet(func: *Fn) ?*std.StringHashMapUnmanaged(void) {843 pub fn getInferredErrorSet(func: *Fn) ?*std.StringHashMapUnmanaged(void) {
844 const ret_ty = func.owner_decl.ty.fnReturnType();844 const ret_ty = func.owner_decl.ty.fnReturnType();
845 if (ret_ty.tag() == .generic_poison) {
846 return null;
847 }
845 if (ret_ty.zigTypeTag() == .ErrorUnion) {848 if (ret_ty.zigTypeTag() == .ErrorUnion) {
846 if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {849 if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
847 return &payload.data.map;850 return &payload.data.map;
src/Sema.zig+162-122
...@@ -2618,128 +2618,130 @@ fn analyzeCall(...@@ -2618,128 +2618,130 @@ fn analyzeCall(
2618 break :new_func gop.key_ptr.*;2618 break :new_func gop.key_ptr.*;
2619 };2619 };
26202620
2621 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);2621 {
26222622 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
2623 // Create a Decl for the new function.2623
2624 const new_decl = try mod.allocateNewDecl(namespace, module_fn.owner_decl.src_node);2624 // Create a Decl for the new function.
2625 // TODO better names for generic function instantiations2625 const new_decl = try mod.allocateNewDecl(namespace, module_fn.owner_decl.src_node);
2626 const name_index = mod.getNextAnonNameIndex();2626 // TODO better names for generic function instantiations
2627 new_decl.name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{2627 const name_index = mod.getNextAnonNameIndex();
2628 module_fn.owner_decl.name, name_index,2628 new_decl.name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
2629 });2629 module_fn.owner_decl.name, name_index,
2630 new_decl.src_line = module_fn.owner_decl.src_line;2630 });
2631 new_decl.is_pub = module_fn.owner_decl.is_pub;2631 new_decl.src_line = module_fn.owner_decl.src_line;
2632 new_decl.is_exported = module_fn.owner_decl.is_exported;2632 new_decl.is_pub = module_fn.owner_decl.is_pub;
2633 new_decl.has_align = module_fn.owner_decl.has_align;2633 new_decl.is_exported = module_fn.owner_decl.is_exported;
2634 new_decl.has_linksection = module_fn.owner_decl.has_linksection;2634 new_decl.has_align = module_fn.owner_decl.has_align;
2635 new_decl.zir_decl_index = module_fn.owner_decl.zir_decl_index;2635 new_decl.has_linksection = module_fn.owner_decl.has_linksection;
2636 new_decl.alive = true; // This Decl is called at runtime.2636 new_decl.zir_decl_index = module_fn.owner_decl.zir_decl_index;
2637 new_decl.has_tv = true;2637 new_decl.alive = true; // This Decl is called at runtime.
2638 new_decl.owns_tv = true;2638 new_decl.has_tv = true;
2639 new_decl.analysis = .in_progress;2639 new_decl.owns_tv = true;
2640 new_decl.generation = mod.generation;2640 new_decl.analysis = .in_progress;
26412641 new_decl.generation = mod.generation;
2642 namespace.anon_decls.putAssumeCapacityNoClobber(new_decl, {});2642
26432643 namespace.anon_decls.putAssumeCapacityNoClobber(new_decl, {});
2644 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);2644
2645 errdefer new_decl_arena.deinit();2645 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
26462646 errdefer new_decl_arena.deinit();
2647 // Re-run the block that creates the function, with the comptime parameters2647
2648 // pre-populated inside `inst_map`. This causes `param_comptime` and2648 // Re-run the block that creates the function, with the comptime parameters
2649 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a2649 // pre-populated inside `inst_map`. This causes `param_comptime` and
2650 // new, monomorphized function, with the comptime parameters elided.2650 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a
2651 var child_sema: Sema = .{2651 // new, monomorphized function, with the comptime parameters elided.
2652 .mod = mod,2652 var child_sema: Sema = .{
2653 .gpa = gpa,2653 .mod = mod,
2654 .arena = sema.arena,2654 .gpa = gpa,
2655 .code = fn_zir,2655 .arena = sema.arena,
2656 .owner_decl = new_decl,2656 .code = fn_zir,
2657 .namespace = namespace,2657 .owner_decl = new_decl,
2658 .func = null,2658 .namespace = namespace,
2659 .owner_func = null,2659 .func = null,
2660 .comptime_args = try new_decl_arena.allocator.alloc(TypedValue, uncasted_args.len),2660 .owner_func = null,
2661 .comptime_args_fn_inst = module_fn.zir_body_inst,2661 .comptime_args = try new_decl_arena.allocator.alloc(TypedValue, uncasted_args.len),
2662 .preallocated_new_func = new_module_func,2662 .comptime_args_fn_inst = module_fn.zir_body_inst,
2663 };2663 .preallocated_new_func = new_module_func,
2664 defer child_sema.deinit();2664 };
26652665 defer child_sema.deinit();
2666 var child_block: Scope.Block = .{2666
2667 .parent = null,2667 var child_block: Scope.Block = .{
2668 .sema = &child_sema,2668 .parent = null,
2669 .src_decl = new_decl,2669 .sema = &child_sema,
2670 .instructions = .{},2670 .src_decl = new_decl,
2671 .inlining = null,2671 .instructions = .{},
2672 .is_comptime = true,2672 .inlining = null,
2673 };2673 .is_comptime = true,
2674 defer {2674 };
2675 child_block.instructions.deinit(gpa);2675 defer {
2676 child_block.params.deinit(gpa);2676 child_block.instructions.deinit(gpa);
2677 }2677 child_block.params.deinit(gpa);
2678
2679 try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len));
2680 var arg_i: usize = 0;
2681 for (fn_info.param_body) |inst| {
2682 const is_comptime = switch (zir_tags[inst]) {
2683 .param_comptime, .param_anytype_comptime => true,
2684 .param, .param_anytype => false,
2685 else => continue,
2686 } or func_ty_info.paramIsComptime(arg_i);
2687 const arg_src = call_src; // TODO: better source location
2688 const arg = uncasted_args[arg_i];
2689 if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| {
2690 const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
2691 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
2692 } else if (is_comptime) {
2693 return sema.failWithNeededComptime(block, arg_src);
2694 }2678 }
2695 arg_i += 1;
2696 }
2697 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body);
2698 const new_func_val = try child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst);
2699 const new_func = new_func_val.castTag(.function).?.data;
2700 assert(new_func == new_module_func);
27012679
2702 arg_i = 0;2680 try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len));
2703 for (fn_info.param_body) |inst| {2681 var arg_i: usize = 0;
2704 switch (zir_tags[inst]) {2682 for (fn_info.param_body) |inst| {
2705 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},2683 const is_comptime = switch (zir_tags[inst]) {
2706 else => continue,2684 .param_comptime, .param_anytype_comptime => true,
2685 .param, .param_anytype => false,
2686 else => continue,
2687 } or func_ty_info.paramIsComptime(arg_i);
2688 const arg_src = call_src; // TODO: better source location
2689 const arg = uncasted_args[arg_i];
2690 if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| {
2691 const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
2692 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
2693 } else if (is_comptime) {
2694 return sema.failWithNeededComptime(block, arg_src);
2695 }
2696 arg_i += 1;
2707 }2697 }
2708 const arg = child_sema.inst_map.get(inst).?;2698 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body);
2709 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(&child_block, .unneeded, arg) catch unreachable).?;2699 const new_func_val = try child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst);
2700 const new_func = new_func_val.castTag(.function).?.data;
2701 assert(new_func == new_module_func);
2702
2703 arg_i = 0;
2704 for (fn_info.param_body) |inst| {
2705 switch (zir_tags[inst]) {
2706 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
2707 else => continue,
2708 }
2709 const arg = child_sema.inst_map.get(inst).?;
2710 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(&child_block, .unneeded, arg) catch unreachable).?;
27102711
2711 if (arg_val.tag() == .generic_poison) {2712 if (arg_val.tag() == .generic_poison) {
2712 child_sema.comptime_args[arg_i] = .{2713 child_sema.comptime_args[arg_i] = .{
2713 .ty = Type.initTag(.noreturn),2714 .ty = Type.initTag(.noreturn),
2714 .val = Value.initTag(.unreachable_value),2715 .val = Value.initTag(.unreachable_value),
2715 };2716 };
2716 } else {2717 } else {
2717 child_sema.comptime_args[arg_i] = .{2718 child_sema.comptime_args[arg_i] = .{
2718 .ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator),2719 .ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator),
2719 .val = try arg_val.copy(&new_decl_arena.allocator),2720 .val = try arg_val.copy(&new_decl_arena.allocator),
2720 };2721 };
2722 }
2723
2724 arg_i += 1;
2721 }2725 }
27222726
2723 arg_i += 1;2727 // Populate the Decl ty/val with the function and its type.
2724 }2728 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);
2729 new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func);
2730 new_decl.analysis = .complete;
27252731
2726 // Populate the Decl ty/val with the function and its type.2732 // The generic function Decl is guaranteed to be the first dependency
2727 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);2733 // of each of its instantiations.
2728 new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func);2734 assert(new_decl.dependencies.keys().len == 0);
2729 new_decl.analysis = .complete;2735 try mod.declareDeclDependency(new_decl, module_fn.owner_decl);
27302736
2731 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field2737 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field
2732 // will be populated, ensuring it will have `analyzeBody` called with the ZIR2738 // will be populated, ensuring it will have `analyzeBody` called with the ZIR
2733 // parameters mapped appropriately.2739 // parameters mapped appropriately.
2734 try mod.comp.bin_file.allocateDeclIndexes(new_decl);2740 try mod.comp.bin_file.allocateDeclIndexes(new_decl);
2735 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });2741 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
27362742
2737 try new_decl.finalizeNewArena(&new_decl_arena);2743 try new_decl.finalizeNewArena(&new_decl_arena);
27382744 }
2739 // The generic function Decl is guaranteed to be the first dependency
2740 // of each of its instantiations.
2741 assert(new_decl.dependencies.keys().len == 0);
2742 try mod.declareDeclDependency(new_decl, module_fn.owner_decl);
27432745
2744 break :res try sema.finishGenericCall(2746 break :res try sema.finishGenericCall(
2745 block,2747 block,
...@@ -3478,12 +3480,15 @@ fn zirFunc(...@@ -3478,12 +3480,15 @@ fn zirFunc(
34783480
3479 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;3481 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3480 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);3482 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
3483 var extra_index = extra.end;
3484 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
3485 extra_index += ret_ty_body.len;
34813486
3482 var body_inst: Zir.Inst.Index = 0;3487 var body_inst: Zir.Inst.Index = 0;
3483 var src_locs: Zir.Inst.Func.SrcLocs = undefined;3488 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
3484 if (extra.data.body_len != 0) {3489 if (extra.data.body_len != 0) {
3485 body_inst = inst;3490 body_inst = inst;
3486 const extra_index = extra.end + extra.data.body_len;3491 extra_index += extra.data.body_len;
3487 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;3492 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
3488 }3493 }
34893494
...@@ -3496,7 +3501,7 @@ fn zirFunc(...@@ -3496,7 +3501,7 @@ fn zirFunc(
3496 block,3501 block,
3497 inst_data.src_node,3502 inst_data.src_node,
3498 body_inst,3503 body_inst,
3499 extra.data.return_type,3504 ret_ty_body,
3500 cc,3505 cc,
3501 Value.initTag(.null_value),3506 Value.initTag(.null_value),
3502 false,3507 false,
...@@ -3512,7 +3517,7 @@ fn funcCommon(...@@ -3512,7 +3517,7 @@ fn funcCommon(
3512 block: *Scope.Block,3517 block: *Scope.Block,
3513 src_node_offset: i32,3518 src_node_offset: i32,
3514 body_inst: Zir.Inst.Index,3519 body_inst: Zir.Inst.Index,
3515 zir_return_type: Zir.Inst.Ref,3520 ret_ty_body: []const Zir.Inst.Index,
3516 cc: std.builtin.CallingConvention,3521 cc: std.builtin.CallingConvention,
3517 align_val: Value,3522 align_val: Value,
3518 var_args: bool,3523 var_args: bool,
...@@ -3523,7 +3528,37 @@ fn funcCommon(...@@ -3523,7 +3528,37 @@ fn funcCommon(
3523) CompileError!Air.Inst.Ref {3528) CompileError!Air.Inst.Ref {
3524 const src: LazySrcLoc = .{ .node_offset = src_node_offset };3529 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
3525 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };3530 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
3526 const bare_return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);3531
3532 // The return type body might be a type expression that depends on generic parameters.
3533 // In such case we need to use a generic_poison value for the return type and mark
3534 // the function as generic.
3535 var is_generic = false;
3536 const bare_return_type: Type = ret_ty: {
3537 if (ret_ty_body.len == 0) break :ret_ty Type.initTag(.void);
3538
3539 const err = err: {
3540 // Make sure any nested param instructions don't clobber our work.
3541 const prev_params = block.params;
3542 block.params = .{};
3543 defer {
3544 block.params.deinit(sema.gpa);
3545 block.params = prev_params;
3546 }
3547 if (sema.resolveBody(block, ret_ty_body)) |ret_ty_inst| {
3548 if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {
3549 break :ret_ty ret_ty;
3550 } else |err| break :err err;
3551 } else |err| break :err err;
3552 };
3553 switch (err) {
3554 error.GenericPoison => {
3555 // The type is not available until the generic instantiation.
3556 is_generic = true;
3557 break :ret_ty Type.initTag(.generic_poison);
3558 },
3559 else => |e| return e,
3560 }
3561 };
35273562
3528 const mod = sema.mod;3563 const mod = sema.mod;
35293564
...@@ -3540,8 +3575,9 @@ fn funcCommon(...@@ -3540,8 +3575,9 @@ fn funcCommon(
35403575
3541 const fn_ty: Type = fn_ty: {3576 const fn_ty: Type = fn_ty: {
3542 // Hot path for some common function types.3577 // Hot path for some common function types.
3543 if (block.params.items.len == 0 and !var_args and align_val.tag() == .null_value and3578 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
3544 !inferred_error_set)3579 if (!is_generic and block.params.items.len == 0 and !var_args and
3580 align_val.tag() == .null_value and !inferred_error_set)
3545 {3581 {
3546 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {3582 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
3547 break :fn_ty Type.initTag(.fn_noreturn_no_args);3583 break :fn_ty Type.initTag(.fn_noreturn_no_args);
...@@ -3560,7 +3596,6 @@ fn funcCommon(...@@ -3560,7 +3596,6 @@ fn funcCommon(
3560 }3596 }
3561 }3597 }
35623598
3563 var is_generic = false;
3564 const param_types = try sema.arena.alloc(Type, block.params.items.len);3599 const param_types = try sema.arena.alloc(Type, block.params.items.len);
3565 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);3600 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
3566 for (block.params.items) |param, i| {3601 for (block.params.items) |param, i| {
...@@ -3574,7 +3609,9 @@ fn funcCommon(...@@ -3574,7 +3609,9 @@ fn funcCommon(
3574 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});3609 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
3575 }3610 }
35763611
3577 const return_type = if (!inferred_error_set) bare_return_type else blk: {3612 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
3613 bare_return_type
3614 else blk: {
3578 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{3615 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{
3579 .func = new_func,3616 .func = new_func,
3580 .map = .{},3617 .map = .{},
...@@ -6944,6 +6981,9 @@ fn zirFuncExtended(...@@ -6944,6 +6981,9 @@ fn zirFuncExtended(
6944 break :blk align_tv.val;6981 break :blk align_tv.val;
6945 } else Value.initTag(.null_value);6982 } else Value.initTag(.null_value);
69466983
6984 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
6985 extra_index += ret_ty_body.len;
6986
6947 var body_inst: Zir.Inst.Index = 0;6987 var body_inst: Zir.Inst.Index = 0;
6948 var src_locs: Zir.Inst.Func.SrcLocs = undefined;6988 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
6949 if (extra.data.body_len != 0) {6989 if (extra.data.body_len != 0) {
...@@ -6960,7 +7000,7 @@ fn zirFuncExtended(...@@ -6960,7 +7000,7 @@ fn zirFuncExtended(
6960 block,7000 block,
6961 extra.data.src_node,7001 extra.data.src_node,
6962 body_inst,7002 body_inst,
6963 extra.data.return_type,7003 ret_ty_body,
6964 cc,7004 cc,
6965 align_val,7005 align_val,
6966 is_var_args,7006 is_var_args,
src/Zir.zig+49-15
...@@ -2272,11 +2272,13 @@ pub const Inst = struct {...@@ -2272,11 +2272,13 @@ pub const Inst = struct {
2272 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set2272 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
2273 /// 1. cc: Ref, // if has_cc is set2273 /// 1. cc: Ref, // if has_cc is set
2274 /// 2. align: Ref, // if has_align is set2274 /// 2. align: Ref, // if has_align is set
2275 /// 3. body: Index // for each body_len2275 /// 3. return_type: Index // for each ret_body_len
2276 /// 4. src_locs: Func.SrcLocs // if body_len != 02276 /// 4. body: Index // for each body_len
2277 /// 5. src_locs: Func.SrcLocs // if body_len != 0
2277 pub const ExtendedFunc = struct {2278 pub const ExtendedFunc = struct {
2278 src_node: i32,2279 src_node: i32,
2279 return_type: Ref,2280 /// If this is 0 it means a void return type.
2281 ret_body_len: u32,
2280 /// Points to the block that contains the param instructions for this function.2282 /// Points to the block that contains the param instructions for this function.
2281 param_block: Index,2283 param_block: Index,
2282 body_len: u32,2284 body_len: u32,
...@@ -2312,10 +2314,12 @@ pub const Inst = struct {...@@ -2312,10 +2314,12 @@ pub const Inst = struct {
2312 };2314 };
23132315
2314 /// Trailing:2316 /// Trailing:
2315 /// 0. body: Index // for each body_len2317 /// 0. return_type: Index // for each ret_body_len
2316 /// 1. src_locs: SrcLocs // if body_len != 02318 /// 1. body: Index // for each body_len
2319 /// 2. src_locs: SrcLocs // if body_len != 0
2317 pub const Func = struct {2320 pub const Func = struct {
2318 return_type: Ref,2321 /// If this is 0 it means a void return type.
2322 ret_body_len: u32,
2319 /// Points to the block that contains the param instructions for this function.2323 /// Points to the block that contains the param instructions for this function.
2320 param_block: Index,2324 param_block: Index,
2321 body_len: u32,2325 body_len: u32,
...@@ -4344,15 +4348,21 @@ const Writer = struct {...@@ -4344,15 +4348,21 @@ const Writer = struct {
4344 const inst_data = self.code.instructions.items(.data)[inst].pl_node;4348 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4345 const src = inst_data.src();4349 const src = inst_data.src();
4346 const extra = self.code.extraData(Inst.Func, inst_data.payload_index);4350 const extra = self.code.extraData(Inst.Func, inst_data.payload_index);
4347 const body = self.code.extra[extra.end..][0..extra.data.body_len];4351 var extra_index = extra.end;
4352
4353 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
4354 extra_index += ret_ty_body.len;
4355
4356 const body = self.code.extra[extra_index..][0..extra.data.body_len];
4357 extra_index += body.len;
4358
4348 var src_locs: Zir.Inst.Func.SrcLocs = undefined;4359 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
4349 if (body.len != 0) {4360 if (body.len != 0) {
4350 const extra_index = extra.end + body.len;
4351 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;4361 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
4352 }4362 }
4353 return self.writeFuncCommon(4363 return self.writeFuncCommon(
4354 stream,4364 stream,
4355 extra.data.return_type,4365 ret_ty_body,
4356 inferred_error_set,4366 inferred_error_set,
4357 false,4367 false,
4358 false,4368 false,
...@@ -4387,6 +4397,9 @@ const Writer = struct {...@@ -4387,6 +4397,9 @@ const Writer = struct {
4387 break :blk align_inst;4397 break :blk align_inst;
4388 };4398 };
43894399
4400 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
4401 extra_index += ret_ty_body.len;
4402
4390 const body = self.code.extra[extra_index..][0..extra.data.body_len];4403 const body = self.code.extra[extra_index..][0..extra.data.body_len];
4391 extra_index += body.len;4404 extra_index += body.len;
43924405
...@@ -4396,7 +4409,7 @@ const Writer = struct {...@@ -4396,7 +4409,7 @@ const Writer = struct {
4396 }4409 }
4397 return self.writeFuncCommon(4410 return self.writeFuncCommon(
4398 stream,4411 stream,
4399 extra.data.return_type,4412 ret_ty_body,
4400 small.is_inferred_error,4413 small.is_inferred_error,
4401 small.is_var_args,4414 small.is_var_args,
4402 small.is_extern,4415 small.is_extern,
...@@ -4478,7 +4491,7 @@ const Writer = struct {...@@ -4478,7 +4491,7 @@ const Writer = struct {
4478 fn writeFuncCommon(4491 fn writeFuncCommon(
4479 self: *Writer,4492 self: *Writer,
4480 stream: anytype,4493 stream: anytype,
4481 ret_ty: Inst.Ref,4494 ret_ty_body: []const Inst.Index,
4482 inferred_error_set: bool,4495 inferred_error_set: bool,
4483 var_args: bool,4496 var_args: bool,
4484 is_extern: bool,4497 is_extern: bool,
...@@ -4488,7 +4501,13 @@ const Writer = struct {...@@ -4488,7 +4501,13 @@ const Writer = struct {
4488 src: LazySrcLoc,4501 src: LazySrcLoc,
4489 src_locs: Zir.Inst.Func.SrcLocs,4502 src_locs: Zir.Inst.Func.SrcLocs,
4490 ) !void {4503 ) !void {
4491 try self.writeInstRef(stream, ret_ty);4504 try stream.writeAll("ret_ty={\n");
4505 self.indent += 2;
4506 try self.writeBody(stream, ret_ty_body);
4507 self.indent -= 2;
4508 try stream.writeByteNTimes(' ', self.indent);
4509 try stream.writeAll("}");
4510
4492 try self.writeOptionalInstRef(stream, ", cc=", cc);4511 try self.writeOptionalInstRef(stream, ", cc=", cc);
4493 try self.writeOptionalInstRef(stream, ", align=", align_inst);4512 try self.writeOptionalInstRef(stream, ", align=", align_inst);
4494 try self.writeFlag(stream, ", vargs", var_args);4513 try self.writeFlag(stream, ", vargs", var_args);
...@@ -4496,9 +4515,9 @@ const Writer = struct {...@@ -4496,9 +4515,9 @@ const Writer = struct {
4496 try self.writeFlag(stream, ", inferror", inferred_error_set);4515 try self.writeFlag(stream, ", inferror", inferred_error_set);
44974516
4498 if (body.len == 0) {4517 if (body.len == 0) {
4499 try stream.writeAll(", {}) ");4518 try stream.writeAll(", body={}) ");
4500 } else {4519 } else {
4501 try stream.writeAll(", {\n");4520 try stream.writeAll(", body={\n");
4502 self.indent += 2;4521 self.indent += 2;
4503 try self.writeBody(stream, body);4522 try self.writeBody(stream, body);
4504 self.indent -= 2;4523 self.indent -= 2;
...@@ -4932,6 +4951,7 @@ fn findDeclsBody(...@@ -4932,6 +4951,7 @@ fn findDeclsBody(
49324951
4933pub const FnInfo = struct {4952pub const FnInfo = struct {
4934 param_body: []const Inst.Index,4953 param_body: []const Inst.Index,
4954 ret_ty_body: []const Inst.Index,
4935 body: []const Inst.Index,4955 body: []const Inst.Index,
4936 total_params_len: u32,4956 total_params_len: u32,
4937};4957};
...@@ -4942,13 +4962,22 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4942,13 +4962,22 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4942 const info: struct {4962 const info: struct {
4943 param_block: Inst.Index,4963 param_block: Inst.Index,
4944 body: []const Inst.Index,4964 body: []const Inst.Index,
4965 ret_ty_body: []const Inst.Index,
4945 } = switch (tags[fn_inst]) {4966 } = switch (tags[fn_inst]) {
4946 .func, .func_inferred => blk: {4967 .func, .func_inferred => blk: {
4947 const inst_data = datas[fn_inst].pl_node;4968 const inst_data = datas[fn_inst].pl_node;
4948 const extra = zir.extraData(Inst.Func, inst_data.payload_index);4969 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
4949 const body = zir.extra[extra.end..][0..extra.data.body_len];4970 var extra_index: usize = extra.end;
4971
4972 const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
4973 extra_index += ret_ty_body.len;
4974
4975 const body = zir.extra[extra_index..][0..extra.data.body_len];
4976 extra_index += body.len;
4977
4950 break :blk .{4978 break :blk .{
4951 .param_block = extra.data.param_block,4979 .param_block = extra.data.param_block,
4980 .ret_ty_body = ret_ty_body,
4952 .body = body,4981 .body = body,
4953 };4982 };
4954 },4983 },
...@@ -4961,9 +4990,13 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4961,9 +4990,13 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4961 extra_index += @boolToInt(small.has_lib_name);4990 extra_index += @boolToInt(small.has_lib_name);
4962 extra_index += @boolToInt(small.has_cc);4991 extra_index += @boolToInt(small.has_cc);
4963 extra_index += @boolToInt(small.has_align);4992 extra_index += @boolToInt(small.has_align);
4993 const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
4994 extra_index += ret_ty_body.len;
4964 const body = zir.extra[extra_index..][0..extra.data.body_len];4995 const body = zir.extra[extra_index..][0..extra.data.body_len];
4996 extra_index += body.len;
4965 break :blk .{4997 break :blk .{
4966 .param_block = extra.data.param_block,4998 .param_block = extra.data.param_block,
4999 .ret_ty_body = ret_ty_body,
4967 .body = body,5000 .body = body,
4968 };5001 };
4969 },5002 },
...@@ -4983,6 +5016,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4983,6 +5016,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4983 }5016 }
4984 return .{5017 return .{
4985 .param_body = param_body,5018 .param_body = param_body,
5019 .ret_ty_body = info.ret_ty_body,
4986 .body = info.body,5020 .body = info.body,
4987 .total_params_len = total_params_len,5021 .total_params_len = total_params_len,
4988 };5022 };
src/codegen/llvm.zig+15-1
...@@ -575,6 +575,14 @@ pub const DeclGen = struct {...@@ -575,6 +575,14 @@ pub const DeclGen = struct {
575 const info = t.intInfo(self.module.getTarget());575 const info = t.intInfo(self.module.getTarget());
576 return self.context.intType(info.bits);576 return self.context.intType(info.bits);
577 },577 },
578 .Float => switch (t.floatBits(self.module.getTarget())) {
579 16 => return self.context.halfType(),
580 32 => return self.context.floatType(),
581 64 => return self.context.doubleType(),
582 80 => return self.context.x86FP80Type(),
583 128 => return self.context.fp128Type(),
584 else => unreachable,
585 },
578 .Bool => return self.context.intType(1),586 .Bool => return self.context.intType(1),
579 .Pointer => {587 .Pointer => {
580 if (t.isSlice()) {588 if (t.isSlice()) {
...@@ -661,7 +669,6 @@ pub const DeclGen = struct {...@@ -661,7 +669,6 @@ pub const DeclGen = struct {
661669
662 .BoundFn => @panic("TODO remove BoundFn from the language"),670 .BoundFn => @panic("TODO remove BoundFn from the language"),
663671
664 .Float,
665 .Enum,672 .Enum,
666 .Union,673 .Union,
667 .Opaque,674 .Opaque,
...@@ -699,6 +706,13 @@ pub const DeclGen = struct {...@@ -699,6 +706,13 @@ pub const DeclGen = struct {
699 }706 }
700 return llvm_int;707 return llvm_int;
701 },708 },
709 .Float => {
710 if (tv.ty.floatBits(self.module.getTarget()) <= 64) {
711 const llvm_ty = try self.llvmType(tv.ty);
712 return llvm_ty.constReal(tv.val.toFloat(f64));
713 }
714 return self.todo("bitcast to f128 from an integer", .{});
715 },
702 .Pointer => switch (tv.val.tag()) {716 .Pointer => switch (tv.val.tag()) {
703 .decl_ref => {717 .decl_ref => {
704 if (tv.ty.isSlice()) {718 if (tv.ty.isSlice()) {
src/codegen/llvm/bindings.zig+18
...@@ -31,6 +31,21 @@ pub const Context = opaque {...@@ -31,6 +31,21 @@ pub const Context = opaque {
31 pub const intType = LLVMIntTypeInContext;31 pub const intType = LLVMIntTypeInContext;
32 extern fn LLVMIntTypeInContext(C: *const Context, NumBits: c_uint) *const Type;32 extern fn LLVMIntTypeInContext(C: *const Context, NumBits: c_uint) *const Type;
3333
34 pub const halfType = LLVMHalfTypeInContext;
35 extern fn LLVMHalfTypeInContext(C: *const Context) *const Type;
36
37 pub const floatType = LLVMFloatTypeInContext;
38 extern fn LLVMFloatTypeInContext(C: *const Context) *const Type;
39
40 pub const doubleType = LLVMDoubleTypeInContext;
41 extern fn LLVMDoubleTypeInContext(C: *const Context) *const Type;
42
43 pub const x86FP80Type = LLVMX86FP80TypeInContext;
44 extern fn LLVMX86FP80TypeInContext(C: *const Context) *const Type;
45
46 pub const fp128Type = LLVMFP128TypeInContext;
47 extern fn LLVMFP128TypeInContext(C: *const Context) *const Type;
48
34 pub const voidType = LLVMVoidTypeInContext;49 pub const voidType = LLVMVoidTypeInContext;
35 extern fn LLVMVoidTypeInContext(C: *const Context) *const Type;50 extern fn LLVMVoidTypeInContext(C: *const Context) *const Type;
3651
...@@ -127,6 +142,9 @@ pub const Type = opaque {...@@ -127,6 +142,9 @@ pub const Type = opaque {
127 pub const constInt = LLVMConstInt;142 pub const constInt = LLVMConstInt;
128 extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value;143 extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value;
129144
145 pub const constReal = LLVMConstReal;
146 extern fn LLVMConstReal(RealTy: *const Type, N: f64) *const Value;
147
130 pub const constArray = LLVMConstArray;148 pub const constArray = LLVMConstArray;
131 extern fn LLVMConstArray(ElementTy: *const Type, ConstantVals: [*]*const Value, Length: c_uint) *const Value;149 extern fn LLVMConstArray(ElementTy: *const Type, ConstantVals: [*]*const Value, Length: c_uint) *const Value;
132150
src/print_air.zig+1-1
...@@ -222,7 +222,7 @@ const Writer = struct {...@@ -222,7 +222,7 @@ const Writer = struct {
222 const extra = w.air.extraData(Air.Block, ty_pl.payload);222 const extra = w.air.extraData(Air.Block, ty_pl.payload);
223 const body = w.air.extra[extra.end..][0..extra.data.body_len];223 const body = w.air.extra[extra.end..][0..extra.data.body_len];
224224
225 try s.writeAll("{\n");225 try s.print("{}, {{\n", .{w.air.getRefType(ty_pl.ty)});
226 const old_indent = w.indent;226 const old_indent = w.indent;
227 w.indent += 2;227 w.indent += 2;
228 try w.writeBody(s, body);228 try w.writeBody(s, body);
test/behavior/generics.zig+56
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const testing = std.testing;3const testing = std.testing;
3const expect = testing.expect;4const expect = testing.expect;
4const expectEqual = testing.expectEqual;5const expectEqual = testing.expectEqual;
...@@ -14,3 +15,58 @@ test "one param, explicit comptime" {...@@ -14,3 +15,58 @@ test "one param, explicit comptime" {
14fn checkSize(comptime T: type) usize {15fn checkSize(comptime T: type) usize {
15 return @sizeOf(T);16 return @sizeOf(T);
16}17}
18
19test "simple generic fn" {
20 try expect(max(i32, 3, -1) == 3);
21 try expect(max(u8, 1, 100) == 100);
22 if (!builtin.zig_is_stage2) {
23 // TODO: stage2 is incorrectly emitting the following:
24 // error: cast of value 1.23e-01 to type 'f32' loses information
25 try expect(max(f32, 0.123, 0.456) == 0.456);
26 }
27 try expect(add(2, 3) == 5);
28}
29
30fn max(comptime T: type, a: T, b: T) T {
31 if (!builtin.zig_is_stage2) {
32 // TODO: stage2 is incorrectly emitting AIR that allocates a result
33 // value, stores to it, but then returns void instead of the result.
34 return if (a > b) a else b;
35 }
36 if (a > b) {
37 return a;
38 } else {
39 return b;
40 }
41}
42
43fn add(comptime a: i32, b: i32) i32 {
44 return (comptime a) + b;
45}
46
47const the_max = max(u32, 1234, 5678);
48test "compile time generic eval" {
49 try expect(the_max == 5678);
50}
51
52fn gimmeTheBigOne(a: u32, b: u32) u32 {
53 return max(u32, a, b);
54}
55
56fn shouldCallSameInstance(a: u32, b: u32) u32 {
57 return max(u32, a, b);
58}
59
60fn sameButWithFloats(a: f64, b: f64) f64 {
61 return max(f64, a, b);
62}
63
64test "fn with comptime args" {
65 try expect(gimmeTheBigOne(1234, 5678) == 5678);
66 try expect(shouldCallSameInstance(34, 12) == 34);
67 if (!builtin.zig_is_stage2) {
68 // TODO: stage2 llvm backend needs to use fcmp instead of icmp
69 // probably AIR should just have different instructions for floats.
70 try expect(sameButWithFloats(0.43, 0.49) == 0.49);
71 }
72}
test/behavior/generics_stage1.zig+1-38
...@@ -3,44 +3,7 @@ const testing = std.testing;...@@ -3,44 +3,7 @@ const testing = std.testing;
3const expect = testing.expect;3const expect = testing.expect;
4const expectEqual = testing.expectEqual;4const expectEqual = testing.expectEqual;
55
6test "simple generic fn" {6test "anytype params" {
7 try expect(max(i32, 3, -1) == 3);
8 try expect(max(f32, 0.123, 0.456) == 0.456);
9 try expect(add(2, 3) == 5);
10}
11
12fn max(comptime T: type, a: T, b: T) T {
13 return if (a > b) a else b;
14}
15
16fn add(comptime a: i32, b: i32) i32 {
17 return (comptime a) + b;
18}
19
20const the_max = max(u32, 1234, 5678);
21test "compile time generic eval" {
22 try expect(the_max == 5678);
23}
24
25fn gimmeTheBigOne(a: u32, b: u32) u32 {
26 return max(u32, a, b);
27}
28
29fn shouldCallSameInstance(a: u32, b: u32) u32 {
30 return max(u32, a, b);
31}
32
33fn sameButWithFloats(a: f64, b: f64) f64 {
34 return max(f64, a, b);
35}
36
37test "fn with comptime args" {
38 try expect(gimmeTheBigOne(1234, 5678) == 5678);
39 try expect(shouldCallSameInstance(34, 12) == 34);
40 try expect(sameButWithFloats(0.43, 0.49) == 0.49);
41}
42
43test "var params" {
44 try expect(max_i32(12, 34) == 34);7 try expect(max_i32(12, 34) == 34);
45 try expect(max_f64(1.2, 3.4) == 3.4);8 try expect(max_f64(1.2, 3.4) == 3.4);
46}9}