Commit 6ed7850972

Andrew Kelley <andrew@ziglang.org>
2021-12-28 03:39:28
Sema: fix anytype parameters whose types require comptime
1 parent fc1a5cd
src/Sema.zig
@@ -4187,10 +4187,17 @@ fn analyzeCall(
                         return sema.failWithNeededComptime(block, arg_src);
                     }
                 } else if (is_anytype) {
-                    // We insert into the map an instruction which is runtime-known
-                    // but has the type of the argument.
-                    const child_arg = try child_block.addArg(sema.typeOf(arg), 0);
-                    child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
+                    const arg_ty = sema.typeOf(arg);
+                    if (arg_ty.requiresComptime()) {
+                        const arg_val = try sema.resolveConstValue(block, arg_src, arg);
+                        const child_arg = try child_sema.addConstant(arg_ty, arg_val);
+                        child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
+                    } else {
+                        // We insert into the map an instruction which is runtime-known
+                        // but has the type of the argument.
+                        const child_arg = try child_block.addArg(arg_ty, 0);
+                        child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
+                    }
                 }
                 arg_i += 1;
             }
@@ -5130,9 +5137,8 @@ fn funcCommon(
         const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
         for (block.params.items) |param, i| {
             param_types[i] = param.ty;
-            comptime_params[i] = param.is_comptime;
-            is_generic = is_generic or param.is_comptime or
-                param.ty.tag() == .generic_poison or param.ty.requiresComptime();
+            comptime_params[i] = param.is_comptime or param.ty.requiresComptime();
+            is_generic = is_generic or comptime_params[i] or param.ty.tag() == .generic_poison;
         }
 
         if (align_val.tag() != .null_value) {
@@ -13146,7 +13152,7 @@ fn coerceInMemoryAllowedFns(
             return .no_match;
         }
 
-        // TODO: nolias
+        // TODO: noalias
 
         // Note: Cast direction is reversed here.
         const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
src/type.zig
@@ -4275,7 +4275,6 @@ pub const Type = extern union {
                 is_generic: bool,
 
                 pub fn paramIsComptime(self: @This(), i: usize) bool {
-                    if (!self.is_generic) return false;
                     assert(i < self.param_types.len);
                     return self.comptime_params[i];
                 }
test/behavior/enum.zig
@@ -822,3 +822,51 @@ test "enum with one member default to u0 tag type" {
     const E0 = enum { X };
     comptime try expect(Tag(E0) == u0);
 }
+
+const EnumWithOneMember = enum { Eof };
+
+fn doALoopThing(id: EnumWithOneMember) void {
+    while (true) {
+        if (id == EnumWithOneMember.Eof) {
+            break;
+        }
+        @compileError("above if condition should be comptime");
+    }
+}
+
+test "comparison operator on enum with one member is comptime known" {
+    doALoopThing(EnumWithOneMember.Eof);
+}
+
+const State = enum { Start };
+test "switch on enum with one member is comptime known" {
+    var state = State.Start;
+    switch (state) {
+        State.Start => return,
+    }
+    @compileError("analysis should not reach here");
+}
+
+test "method call on an enum" {
+    const S = struct {
+        const E = enum {
+            one,
+            two,
+
+            fn method(self: *E) bool {
+                return self.* == .two;
+            }
+
+            fn generic_method(self: *E, foo: anytype) bool {
+                return self.* == .two and foo == bool;
+            }
+        };
+        fn doTheTest() !void {
+            var e = E.two;
+            try expect(e.method());
+            try expect(e.generic_method(bool));
+        }
+    };
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
test/behavior/enum_llvm.zig
@@ -96,30 +96,6 @@ fn getC(data: *const BitFieldOfEnums) C {
     return data.c;
 }
 
-const EnumWithOneMember = enum { Eof };
-
-fn doALoopThing(id: EnumWithOneMember) void {
-    while (true) {
-        if (id == EnumWithOneMember.Eof) {
-            break;
-        }
-        @compileError("above if condition should be comptime");
-    }
-}
-
-test "comparison operator on enum with one member is comptime known" {
-    doALoopThing(EnumWithOneMember.Eof);
-}
-
-const State = enum { Start };
-test "switch on enum with one member is comptime known" {
-    var state = State.Start;
-    switch (state) {
-        State.Start => return,
-    }
-    @compileError("analysis should not reach here");
-}
-
 test "enum literal in array literal" {
     const Items = enum { one, two };
     const array = [_]Items{ .one, .two };
test/behavior/enum_stage1.zig
@@ -43,30 +43,6 @@ test "enum literal casting to error union with payload enum" {
     try expect((try bar) == Bar.B);
 }
 
-test "method call on an enum" {
-    const S = struct {
-        const E = enum {
-            one,
-            two,
-
-            fn method(self: *E) bool {
-                return self.* == .two;
-            }
-
-            fn generic_method(self: *E, foo: anytype) bool {
-                return self.* == .two and foo == bool;
-            }
-        };
-        fn doTheTest() !void {
-            var e = E.two;
-            try expect(e.method());
-            try expect(e.generic_method(bool));
-        }
-    };
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
 test "exporting enum type and value" {
     const S = struct {
         const E = enum(c_int) { one, two };
@@ -80,3 +56,41 @@ test "exporting enum type and value" {
     };
     try expect(S.e == .two);
 }
+
+test "constant enum initialization with differing sizes" {
+    try test3_1(test3_foo);
+    try test3_2(test3_bar);
+}
+const Test3Foo = union(enum) {
+    One: void,
+    Two: f32,
+    Three: Test3Point,
+};
+const Test3Point = struct {
+    x: i32,
+    y: i32,
+};
+const test3_foo = Test3Foo{
+    .Three = Test3Point{
+        .x = 3,
+        .y = 4,
+    },
+};
+const test3_bar = Test3Foo{ .Two = 13 };
+fn test3_1(f: Test3Foo) !void {
+    switch (f) {
+        Test3Foo.Three => |pt| {
+            try expect(pt.x == 3);
+            try expect(pt.y == 4);
+        },
+        else => unreachable,
+    }
+}
+fn test3_2(f: Test3Foo) !void {
+    switch (f) {
+        Test3Foo.Two => |x| {
+            try expect(x == 13);
+        },
+        else => unreachable,
+    }
+}
test/behavior/misc.zig
@@ -34,44 +34,6 @@ test "explicit cast optional pointers" {
     _ = b;
 }
 
-test "constant enum initialization with differing sizes" {
-    try test3_1(test3_foo);
-    try test3_2(test3_bar);
-}
-const Test3Foo = union(enum) {
-    One: void,
-    Two: f32,
-    Three: Test3Point,
-};
-const Test3Point = struct {
-    x: i32,
-    y: i32,
-};
-const test3_foo = Test3Foo{
-    .Three = Test3Point{
-        .x = 3,
-        .y = 4,
-    },
-};
-const test3_bar = Test3Foo{ .Two = 13 };
-fn test3_1(f: Test3Foo) !void {
-    switch (f) {
-        Test3Foo.Three => |pt| {
-            try expect(pt.x == 3);
-            try expect(pt.y == 4);
-        },
-        else => unreachable,
-    }
-}
-fn test3_2(f: Test3Foo) !void {
-    switch (f) {
-        Test3Foo.Two => |x| {
-            try expect(x == 13);
-        },
-        else => unreachable,
-    }
-}
-
 test "pointer comparison" {
     const a = @as([]const u8, "a");
     const b = &a;
test/behavior.zig
@@ -67,6 +67,7 @@ test {
             _ = @import("behavior/bugs/394.zig");
             _ = @import("behavior/bugs/656.zig");
             _ = @import("behavior/bugs/1277.zig");
+            _ = @import("behavior/bugs/1310.zig");
             _ = @import("behavior/bugs/1381.zig");
             _ = @import("behavior/bugs/1500.zig");
             _ = @import("behavior/bugs/1741.zig");
@@ -74,7 +75,9 @@ test {
             _ = @import("behavior/bugs/2578.zig");
             _ = @import("behavior/bugs/3007.zig");
             _ = @import("behavior/bugs/3112.zig");
+            _ = @import("behavior/bugs/3367.zig");
             _ = @import("behavior/bugs/7250.zig");
+            _ = @import("behavior/bugs/9584.zig");
             _ = @import("behavior/cast_llvm.zig");
             _ = @import("behavior/enum_llvm.zig");
             _ = @import("behavior/eval.zig");
@@ -121,7 +124,6 @@ test {
                 _ = @import("behavior/bugs/1025.zig");
                 _ = @import("behavior/bugs/1076.zig");
                 _ = @import("behavior/bugs/1120.zig");
-                _ = @import("behavior/bugs/1310.zig");
                 _ = @import("behavior/bugs/1322.zig");
                 _ = @import("behavior/bugs/1421.zig");
                 _ = @import("behavior/bugs/1442.zig");
@@ -130,7 +132,6 @@ test {
                 _ = @import("behavior/bugs/1851.zig");
                 _ = @import("behavior/bugs/1914.zig");
                 _ = @import("behavior/bugs/2114.zig");
-                _ = @import("behavior/bugs/3367.zig");
                 _ = @import("behavior/bugs/3384.zig");
                 _ = @import("behavior/bugs/3742.zig");
                 _ = @import("behavior/bugs/3779.zig");
@@ -144,7 +145,6 @@ test {
                 _ = @import("behavior/bugs/7003.zig");
                 _ = @import("behavior/bugs/7027.zig");
                 _ = @import("behavior/bugs/7047.zig");
-                _ = @import("behavior/bugs/9584.zig");
                 _ = @import("behavior/bugs/10147.zig");
                 _ = @import("behavior/byteswap.zig");
                 _ = @import("behavior/call_stage1.zig");