diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index dda8d846fa..b4d751ae30 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -346,14 +346,8 @@ pub const TypeInfo = union(enum) { decls: []const Declaration, }; - /// This data structure is used by the Zig language code generation and - /// therefore must be kept in sync with the compiler implementation. - /// TODO rename to Param and put inside `Fn`. - pub const FnArg = struct { - is_generic: bool, - is_noalias: bool, - arg_type: ?type, - }; + /// TODO deprecated use Fn.Param + pub const FnArg = Fn.Param; /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -363,7 +357,15 @@ pub const TypeInfo = union(enum) { is_generic: bool, is_var_args: bool, return_type: ?type, - args: []const FnArg, + args: []const Param, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Param = struct { + is_generic: bool, + is_noalias: bool, + arg_type: ?type, + }; }; /// This data structure is used by the Zig language code generation and diff --git a/lib/std/math.zig b/lib/std/math.zig index 71cb5a184c..5d5ac65cc7 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -947,7 +947,7 @@ fn testRem() !void { /// Result is an unsigned integer. pub fn absCast(x: anytype) switch (@typeInfo(@TypeOf(x))) { .ComptimeInt => comptime_int, - .Int => |intInfo| std.meta.Int(.unsigned, intInfo.bits), + .Int => |int_info| std.meta.Int(.unsigned, int_info.bits), else => @compileError("absCast only accepts integers"), } { switch (@typeInfo(@TypeOf(x))) { @@ -958,8 +958,9 @@ pub fn absCast(x: anytype) switch (@typeInfo(@TypeOf(x))) { return x; } }, - .Int => |intInfo| { - const Uint = std.meta.Int(.unsigned, intInfo.bits); + .Int => |int_info| { + if (int_info.signedness == .unsigned) return x; + const Uint = std.meta.Int(.unsigned, int_info.bits); if (x < 0) { return ~@bitCast(Uint, x +% -1); } else { diff --git a/src/Sema.zig b/src/Sema.zig index 88c559cfce..1de9714eb8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3351,9 +3351,10 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v // Check for the possibility of this pattern: // %a = ret_ptr // %b = store(%a, %c) - // Where %c is an error union. In such case we need to add to the current function's - // inferred error set, if any. - if (sema.typeOf(operand).zigTypeTag() == .ErrorUnion and + // Where %c is an error union or error set. In such case we need to add + // to the current function's inferred error set, if any. + if ((sema.typeOf(operand).zigTypeTag() == .ErrorUnion or + sema.typeOf(operand).zigTypeTag() == .ErrorSet) and sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { if (Zir.refToIndex(extra.lhs)) |ptr_index| { @@ -7665,6 +7666,8 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const container_type = try sema.resolveType(block, lhs_src, extra.lhs); const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs); + // tuples are structs but they don't have a namespace + if (container_type.isTuple()) return Air.Inst.Ref.bool_false; const namespace = container_type.getNamespace() orelse return sema.fail( block, lhs_src, @@ -9886,7 +9889,65 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }), ), .Fn => { + // TODO: look into memoizing this result. const info = ty.fnInfo(); + var params_anon_decl = try block.startAnonDecl(src); + defer params_anon_decl.deinit(); + + const param_vals = try params_anon_decl.arena().alloc(Value, info.param_types.len); + for (param_vals) |*param_val, i| { + const param_ty = info.param_types[i]; + const is_generic = param_ty.tag() == .generic_poison; + const param_ty_val = if (is_generic) + Value.@"null" + else + try Value.Tag.opt_payload.create( + params_anon_decl.arena(), + try Value.Tag.ty.create(params_anon_decl.arena(), param_ty), + ); + + const param_fields = try params_anon_decl.arena().create([3]Value); + param_fields.* = .{ + // is_generic: bool, + Value.makeBool(is_generic), + // is_noalias: bool, + Value.@"false", // TODO + // arg_type: ?type, + param_ty_val, + }; + param_val.* = try Value.Tag.@"struct".create(params_anon_decl.arena(), param_fields); + } + + const args_val = v: { + const fn_info_decl = (try sema.namespaceLookup( + block, + src, + type_info_ty.getNamespace().?, + "Fn", + )).?; + try sema.mod.declareDeclDependency(sema.owner_decl, fn_info_decl); + try sema.ensureDeclAnalyzed(fn_info_decl); + const param_info_decl = (try sema.namespaceLookup( + block, + src, + fn_info_decl.val.castTag(.ty).?.data.getNamespace().?, + "Param", + )).?; + try sema.mod.declareDeclDependency(sema.owner_decl, param_info_decl); + try sema.ensureDeclAnalyzed(param_info_decl); + const new_decl = try params_anon_decl.finish( + try Type.Tag.array.create(params_anon_decl.arena(), .{ + .len = param_vals.len, + .elem_type = param_info_decl.ty, + }), + try Value.Tag.array.create( + params_anon_decl.arena(), + param_vals, + ), + ); + break :v try Value.Tag.decl_ref.create(sema.arena, new_decl); + }; + const field_values = try sema.arena.alloc(Value, 6); // calling_convention: CallingConvention, field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc)); @@ -9897,9 +9958,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // is_var_args: bool, field_values[3] = Value.makeBool(info.is_var_args); // return_type: ?type, - field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); - // args: []const FnArg, - field_values[5] = Value.@"null"; // TODO + field_values[4] = try Value.Tag.ty.create(sema.arena, info.return_type); + // args: []const Fn.Param, + field_values[5] = args_val; return sema.addConstant( type_info_ty, @@ -10102,7 +10163,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }), try Value.Tag.array.create( fields_anon_decl.arena(), - try fields_anon_decl.arena().dupe(Value, enum_field_vals), + enum_field_vals, ), ); break :v try Value.Tag.decl_ref.create(sema.arena, new_decl); @@ -12128,7 +12189,7 @@ fn checkPtrOperand( ty: Type, ) CompileError!void { switch (ty.zigTypeTag()) { - .Pointer => {}, + .Pointer => return, .Fn => { const msg = msg: { const msg = try sema.errMsg( @@ -12145,8 +12206,10 @@ fn checkPtrOperand( }; return sema.failWithOwnedErrorMsg(msg); }, - else => return sema.fail(block, ty_src, "expected pointer, found '{}'", .{ty}), + .Optional => if (ty.isPtrLikeOptional()) return, + else => {}, } + return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}); } fn checkPtrType( @@ -12156,7 +12219,7 @@ fn checkPtrType( ty: Type, ) CompileError!void { switch (ty.zigTypeTag()) { - .Pointer => {}, + .Pointer => return, .Fn => { const msg = msg: { const msg = try sema.errMsg( @@ -12173,8 +12236,10 @@ fn checkPtrType( }; return sema.failWithOwnedErrorMsg(msg); }, - else => return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}), + .Optional => if (ty.isPtrLikeOptional()) return, + else => {}, } + return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}); } fn checkVectorElemType( diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 3ac1ddb51c..217a09d924 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -18750,8 +18750,8 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type; fields[4]->data.x_optional = return_type; } - // args: []TypeInfo.FnArg - ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr); + // args: []TypeInfo.Fn.Param + ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "Param", result->type); if ((err = type_resolve(g, type_info_fn_arg_type, ResolveStatusSizeKnown))) { zig_unreachable(); } @@ -19614,14 +19614,13 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ assert(args_arr->data.x_array.special == ConstArraySpecialNone); for (size_t i = 0; i < args_len; i++) { ZigValue *arg_value = &args_arr->data.x_array.data.s_none.elements[i]; - assert(arg_value->type == ir_type_info_get_type(ira, "FnArg", nullptr)); FnTypeParamInfo *info = &fn_type_id.param_info[i]; Error err; bool is_generic; if ((err = get_const_field_bool(ira, source_node, arg_value, "is_generic", 0, &is_generic))) return ira->codegen->invalid_inst_gen->value->type; if (is_generic) { - ir_add_error_node(ira, source_node, buf_sprintf("TypeInfo.FnArg.is_generic must be false for @Type")); + ir_add_error_node(ira, source_node, buf_sprintf("TypeInfo.Fn.Param.is_generic must be false for @Type")); return ira->codegen->invalid_inst_gen->value->type; } if ((err = get_const_field_bool(ira, source_node, arg_value, "is_noalias", 1, &info->is_noalias))) @@ -19629,7 +19628,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ ZigType *type = get_const_field_meta_type_optional( ira, source_node, arg_value, "arg_type", 2); if (type == nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("TypeInfo.FnArg.arg_type must be non-null for @Type")); + ir_add_error_node(ira, source_node, buf_sprintf("TypeInfo.Fn.Param.arg_type must be non-null for @Type")); return ira->codegen->invalid_inst_gen->value->type; } info->type = type; diff --git a/src/type.zig b/src/type.zig index 18ff2f2f38..2454dfb5b5 100644 --- a/src/type.zig +++ b/src/type.zig @@ -593,10 +593,12 @@ pub const Type = extern union { for (a_info.param_types) |a_param_ty, i| { const b_param_ty = b_info.param_types[i]; - if (!eql(a_param_ty, b_param_ty)) + if (a_info.comptime_params[i] != b_info.comptime_params[i]) return false; - if (a_info.comptime_params[i] != b_info.comptime_params[i]) + if (a_param_ty.tag() == .generic_poison) continue; + if (b_param_ty.tag() == .generic_poison) continue; + if (!eql(a_param_ty, b_param_ty)) return false; } diff --git a/test/behavior.zig b/test/behavior.zig index a034cf4b37..9a434aa6ee 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -120,6 +120,15 @@ test { _ = @import("behavior/sizeof_and_typeof.zig"); _ = @import("behavior/switch.zig"); _ = @import("behavior/widening.zig"); + _ = @import("behavior/bugs/421.zig"); + _ = @import("behavior/bugs/726.zig"); + _ = @import("behavior/bugs/1421.zig"); + _ = @import("behavior/bugs/2114.zig"); + _ = @import("behavior/bugs/3742.zig"); + _ = @import("behavior/struct_contains_null_ptr_itself.zig"); + _ = @import("behavior/switch_prong_err_enum.zig"); + _ = @import("behavior/switch_prong_implicit_cast.zig"); + _ = @import("behavior/union_with_members.zig"); if (builtin.zig_backend == .stage1) { // Tests that only pass for the stage1 backend. @@ -128,20 +137,15 @@ test { _ = @import("behavior/async_fn.zig"); } _ = @import("behavior/await_struct.zig"); - _ = @import("behavior/bugs/421.zig"); _ = @import("behavior/bugs/529.zig"); _ = @import("behavior/bugs/718.zig"); - _ = @import("behavior/bugs/726.zig"); _ = @import("behavior/bugs/828.zig"); _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/bugs/1120.zig"); - _ = @import("behavior/bugs/1421.zig"); _ = @import("behavior/bugs/1442.zig"); _ = @import("behavior/bugs/1607.zig"); _ = @import("behavior/bugs/1851.zig"); - _ = @import("behavior/bugs/2114.zig"); _ = @import("behavior/bugs/3384.zig"); - _ = @import("behavior/bugs/3742.zig"); _ = @import("behavior/bugs/3779.zig"); _ = @import("behavior/bugs/4328.zig"); _ = @import("behavior/bugs/5398.zig"); @@ -161,12 +165,8 @@ test { _ = @import("behavior/muladd.zig"); _ = @import("behavior/select.zig"); _ = @import("behavior/shuffle.zig"); - _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/struct_contains_slice_of_itself.zig"); - _ = @import("behavior/switch_prong_err_enum.zig"); - _ = @import("behavior/switch_prong_implicit_cast.zig"); _ = @import("behavior/typename.zig"); - _ = @import("behavior/union_with_members.zig"); _ = @import("behavior/vector.zig"); if (builtin.target.cpu.arch == .wasm32) { _ = @import("behavior/wasm.zig"); diff --git a/test/behavior/src.zig b/test/behavior/src.zig index bb0a0971b4..b0e4f2ba70 100644 --- a/test/behavior/src.zig +++ b/test/behavior/src.zig @@ -1,21 +1,20 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const expect = std.testing.expect; - -test "@src" { - // TODO why is this failing on stage1? - return error.SkipZigTest; - - // try doTheTest(); -} - fn doTheTest() !void { - const src = @src(); + const src = @src(); // do not move - try expect(src.line == 9); + try expect(src.line == 2); try expect(src.column == 17); try expect(std.mem.endsWith(u8, src.fn_name, "doTheTest")); try expect(std.mem.endsWith(u8, src.file, "src.zig")); try expect(src.fn_name[src.fn_name.len] == 0); try expect(src.file[src.file.len] == 0); } + +const std = @import("std"); +const builtin = @import("builtin"); +const expect = std.testing.expect; + +test "@src" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; + + try doTheTest(); +} diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index a3582719fd..8ba627e686 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -323,7 +323,9 @@ fn testOpaque() !void { } test "type info: function type info" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // wasm doesn't support align attributes on functions if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest; @@ -343,6 +345,7 @@ fn testFunction() !void { const fn_aligned_info = @typeInfo(@TypeOf(fooAligned)); try expect(fn_aligned_info.Fn.alignment == 4); + if (builtin.zig_backend != .stage1) return; // no bound fn in stage2 const test_instance: TestPackedStruct = undefined; const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo)); try expect(bound_fn_info == .BoundFn); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d1971e46bb..580c525dba 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -450,7 +450,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .is_generic = true, \\ .is_var_args = false, \\ .return_type = u0, - \\ .args = &[_]@import("std").builtin.TypeInfo.FnArg{}, + \\ .args = &[_]@import("std").builtin.TypeInfo.Fn.Param{}, \\ }, \\}); \\comptime { _ = Foo; } @@ -466,7 +466,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .is_generic = false, \\ .is_var_args = true, \\ .return_type = u0, - \\ .args = &[_]@import("std").builtin.TypeInfo.FnArg{}, + \\ .args = &[_]@import("std").builtin.TypeInfo.Fn.Param{}, \\ }, \\}); \\comptime { _ = Foo; } @@ -482,7 +482,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .is_generic = false, \\ .is_var_args = false, \\ .return_type = null, - \\ .args = &[_]@import("std").builtin.TypeInfo.FnArg{}, + \\ .args = &[_]@import("std").builtin.TypeInfo.Fn.Param{}, \\ }, \\}); \\comptime { _ = Foo; }