Skip to content

Commit 673ef37

Browse files
Calculate comptime integer arithmetic
1 parent d5e735b commit 673ef37

4 files changed

Lines changed: 320 additions & 51 deletions

File tree

src/analyser/InternPool.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3823,6 +3823,15 @@ pub fn toInt(ip: *InternPool, val: Index, comptime T: type) ?T {
38233823
};
38243824
}
38253825

3826+
pub fn toBigInt(ip: *InternPool, gpa: Allocator, val: Index) !?std.math.big.int.Managed {
3827+
return switch (ip.indexToKey(val)) {
3828+
.int_u64_value => |int_value| try .initSet(gpa, int_value.int),
3829+
.int_i64_value => |int_value| try .initSet(gpa, int_value.int),
3830+
.int_big_value => |int_value| try int_value.getConst(ip).toManaged(gpa),
3831+
else => try .initSet(gpa, ip.toInt(val, i64) orelse return null),
3832+
};
3833+
}
3834+
38263835
pub fn getBigInt(ip: *InternPool, ty: Index, int: std.math.big.int.Const) Allocator.Error!Index {
38273836
assert(ip.isType(ty));
38283837
return try ip.get(.{

src/analysis.zig

Lines changed: 185 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,148 @@ fn resolveIntegerLiteral(analyser: *Analyser, comptime T: type, options: Resolve
13501350
return analyser.ip.toInt(ip_index, T);
13511351
}
13521352

1353+
const IntInfo = union(enum) {
1354+
comptime_int,
1355+
fixed_int: std.builtin.Type.Int,
1356+
};
1357+
1358+
fn intInfo(analyser: *Analyser, ty: InternPool.Index) ?IntInfo {
1359+
const type_tag = analyser.ip.zigTypeTag(ty) orelse return null;
1360+
return switch (type_tag) {
1361+
.comptime_int => .comptime_int,
1362+
.int => .{ .fixed_int = analyser.ip.intInfo(ty, builtin.target) },
1363+
else => null,
1364+
};
1365+
}
1366+
1367+
fn resolveUnaryIntegerExpression(
1368+
analyser: *Analyser,
1369+
tag: std.zig.Ast.Node.Tag,
1370+
instance: Type,
1371+
) !?Type {
1372+
const index = instance.ipIndex() orelse return null;
1373+
const ty = analyser.ip.typeOf(index);
1374+
const int_info = analyser.intInfo(ty) orelse return null;
1375+
var result = try analyser.ip.toBigInt(analyser.gpa, index) orelse return null;
1376+
defer result.deinit();
1377+
switch (tag) {
1378+
.bit_not => switch (int_info) {
1379+
.comptime_int => return null,
1380+
.fixed_int => |info| _ = try result.bitNotWrap(&result, info.signedness, info.bits),
1381+
},
1382+
.negation => result.negate(),
1383+
.negation_wrap => switch (int_info) {
1384+
.comptime_int => result.negate(),
1385+
.fixed_int => |info| {
1386+
// TODO: std.math.big.int does not have a negateWrap method
1387+
_ = info;
1388+
return null;
1389+
},
1390+
},
1391+
else => unreachable,
1392+
}
1393+
return try analyser.resolveIntegerExpressionResult(ty, result.toConst());
1394+
}
1395+
1396+
fn resolveBinaryIntegerExpression(
1397+
analyser: *Analyser,
1398+
tag: std.zig.Ast.Node.Tag,
1399+
instance: Type,
1400+
lhs_instance: Type,
1401+
rhs_instance: Type,
1402+
) !?Type {
1403+
const lhs_index = lhs_instance.ipIndex() orelse return null;
1404+
const rhs_index = rhs_instance.ipIndex() orelse return null;
1405+
const type_of = try instance.typeOf(analyser);
1406+
const ty = type_of.ipIndex() orelse return null;
1407+
const int_info = analyser.intInfo(ty) orelse return null;
1408+
var lhs = try analyser.ip.toBigInt(analyser.gpa, lhs_index) orelse return null;
1409+
defer lhs.deinit();
1410+
var rhs = try analyser.ip.toBigInt(analyser.gpa, rhs_index) orelse return null;
1411+
defer rhs.deinit();
1412+
var result: std.math.big.int.Managed = try .init(analyser.gpa);
1413+
defer result.deinit();
1414+
switch (tag) {
1415+
.mul => try result.mul(&lhs, &rhs),
1416+
.div => {
1417+
var temp: std.math.big.int.Managed = try .init(analyser.gpa);
1418+
defer temp.deinit();
1419+
try result.divTrunc(&temp, &lhs, &rhs);
1420+
},
1421+
.mod => {
1422+
var temp: std.math.big.int.Managed = try .init(analyser.gpa);
1423+
defer temp.deinit();
1424+
try temp.divTrunc(&result, &lhs, &rhs);
1425+
},
1426+
.add => try result.add(&lhs, &rhs),
1427+
.sub => try result.sub(&lhs, &rhs),
1428+
.shl => try result.shiftLeft(&lhs, rhs.toInt(usize) catch return null),
1429+
.shr => try result.shiftRight(&lhs, rhs.toInt(usize) catch return null),
1430+
.bit_and => try result.bitAnd(&lhs, &rhs),
1431+
.bit_xor => try result.bitXor(&lhs, &rhs),
1432+
.bit_or => try result.bitOr(&lhs, &rhs),
1433+
.add_wrap,
1434+
.sub_wrap,
1435+
.mul_wrap,
1436+
.add_sat,
1437+
.sub_sat,
1438+
.mul_sat,
1439+
.shl_sat,
1440+
=> switch (int_info) {
1441+
.comptime_int => switch (tag) {
1442+
.add_wrap, .add_sat => try result.add(&lhs, &rhs),
1443+
.sub_wrap, .sub_sat => try result.sub(&lhs, &rhs),
1444+
.mul_wrap, .mul_sat => try result.mul(&lhs, &rhs),
1445+
.shl_sat => try result.shiftLeft(&lhs, rhs.toInt(usize) catch return null),
1446+
else => unreachable,
1447+
},
1448+
.fixed_int => |info| switch (tag) {
1449+
.add_wrap => _ = try result.addWrap(&lhs, &rhs, info.signedness, info.bits),
1450+
.sub_wrap => _ = try result.subWrap(&lhs, &rhs, info.signedness, info.bits),
1451+
.mul_wrap => _ = try result.mulWrap(&lhs, &rhs, info.signedness, info.bits),
1452+
.add_sat => try result.addSat(&lhs, &rhs, info.signedness, info.bits),
1453+
.sub_sat => try result.subSat(&lhs, &rhs, info.signedness, info.bits),
1454+
.mul_sat => {
1455+
// std.math.big.int does not have a mulSat method
1456+
try result.mul(&lhs, &rhs);
1457+
try result.saturate(&result, info.signedness, info.bits);
1458+
},
1459+
.shl_sat => try result.shiftLeftSat(&lhs, rhs.toInt(usize) catch return null, info.signedness, info.bits),
1460+
else => unreachable,
1461+
},
1462+
},
1463+
else => unreachable,
1464+
}
1465+
return try analyser.resolveIntegerExpressionResult(ty, result.toConst());
1466+
}
1467+
1468+
fn resolveIntegerExpressionResult(
1469+
analyser: *Analyser,
1470+
ty: InternPool.Index,
1471+
result: std.math.big.int.Const,
1472+
) !?Type {
1473+
const int_info = analyser.intInfo(ty) orelse return null;
1474+
switch (int_info) {
1475+
.comptime_int => {},
1476+
.fixed_int => |info| {
1477+
if (!result.fitsInTwosComp(info.signedness, info.bits)) {
1478+
return null;
1479+
}
1480+
},
1481+
}
1482+
const index = index: {
1483+
if (result.positive) blk: {
1484+
const int = result.toInt(u64) catch break :blk;
1485+
break :index try analyser.ip.get(.{ .int_u64_value = .{ .ty = ty, .int = int } });
1486+
} else blk: {
1487+
const int = result.toInt(i64) catch break :blk;
1488+
break :index try analyser.ip.get(.{ .int_i64_value = .{ .ty = ty, .int = int } });
1489+
}
1490+
break :index try analyser.ip.getBigInt(ty, result);
1491+
};
1492+
return Type.fromIP(analyser, ty, index);
1493+
}
1494+
13531495
fn extractArrayData(data: *Type.Data) ?*Type.Data {
13541496
return switch (data.*) {
13551497
.array => data,
@@ -1869,8 +2011,9 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error
18692011
const node = node_handle.node;
18702012
const handle = node_handle.handle;
18712013
const tree = &handle.tree;
2014+
const node_tag = tree.nodeTag(node);
18722015

1873-
switch (tree.nodeTag(node)) {
2016+
switch (node_tag) {
18742017
.global_var_decl,
18752018
.local_var_decl,
18762019
.simple_var_decl,
@@ -2670,7 +2813,7 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error
26702813
=> {
26712814
const ty = try analyser.resolveTypeOfNodeInternal(.of(tree.nodeData(node).node, handle)) orelse return null;
26722815
if (ty.is_type_val) return null;
2673-
return ty.withoutIPIndex(analyser);
2816+
return try analyser.resolveUnaryIntegerExpression(node_tag, ty) orelse ty.withoutIPIndex(analyser);
26742817
},
26752818

26762819
.multiline_string_literal => {
@@ -2815,64 +2958,70 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error
28152958
.bit_or,
28162959
=> {
28172960
const lhs, const rhs = tree.nodeData(node).node_and_node;
2818-
var lhs_ty = try analyser.resolveTypeOfNodeInternal(.of(lhs, handle)) orelse return null;
2819-
if (lhs_ty.is_type_val) return null;
2820-
var rhs_ty = try analyser.resolveTypeOfNodeInternal(.of(rhs, handle)) orelse return null;
2821-
if (rhs_ty.is_type_val) return null;
2822-
lhs_ty = lhs_ty.withoutIPIndex(analyser);
2823-
rhs_ty = rhs_ty.withoutIPIndex(analyser);
2824-
return analyser.resolvePeerTypes(lhs_ty, rhs_ty);
2961+
const lhs_instance = try analyser.resolveTypeOfNodeInternal(.of(lhs, handle)) orelse return null;
2962+
if (lhs_instance.is_type_val) return null;
2963+
const rhs_instance = try analyser.resolveTypeOfNodeInternal(.of(rhs, handle)) orelse return null;
2964+
if (rhs_instance.is_type_val) return null;
2965+
const lhs_no_value = lhs_instance.withoutIPIndex(analyser);
2966+
const rhs_no_value = rhs_instance.withoutIPIndex(analyser);
2967+
const instance = try analyser.resolvePeerTypes(lhs_no_value, rhs_no_value) orelse return null;
2968+
return try analyser.resolveBinaryIntegerExpression(node_tag, instance, lhs_instance, rhs_instance) orelse return instance;
28252969
},
28262970

28272971
.add => {
28282972
const lhs, const rhs = tree.nodeData(node).node_and_node;
2829-
var lhs_ty = try analyser.resolveTypeOfNodeInternal(.of(lhs, handle)) orelse return null;
2830-
if (lhs_ty.is_type_val) return null;
2831-
var rhs_ty = try analyser.resolveTypeOfNodeInternal(.of(rhs, handle)) orelse return null;
2832-
if (rhs_ty.is_type_val) return null;
2833-
lhs_ty = lhs_ty.withoutIPIndex(analyser);
2834-
rhs_ty = rhs_ty.withoutIPIndex(analyser);
2835-
return switch (lhs_ty.data) {
2973+
const lhs_instance = try analyser.resolveTypeOfNodeInternal(.of(lhs, handle)) orelse return null;
2974+
if (lhs_instance.is_type_val) return null;
2975+
const rhs_instance = try analyser.resolveTypeOfNodeInternal(.of(rhs, handle)) orelse return null;
2976+
if (rhs_instance.is_type_val) return null;
2977+
const lhs_no_value = lhs_instance.withoutIPIndex(analyser);
2978+
const rhs_no_value = rhs_instance.withoutIPIndex(analyser);
2979+
const instance = switch (lhs_no_value.data) {
28362980
.pointer => |lhs_info| switch (lhs_info.size) {
2837-
.many, .c => lhs_ty,
2981+
.many, .c => lhs_no_value,
28382982
else => null,
28392983
},
2840-
else => try analyser.resolvePeerTypes(lhs_ty, rhs_ty),
2841-
};
2984+
else => try analyser.resolvePeerTypes(lhs_no_value, rhs_no_value),
2985+
} orelse return null;
2986+
return try analyser.resolveBinaryIntegerExpression(node_tag, instance, lhs_instance, rhs_instance) orelse return instance;
28422987
},
28432988

28442989
.sub => {
28452990
const lhs, const rhs = tree.nodeData(node).node_and_node;
2846-
var lhs_ty = try analyser.resolveTypeOfNodeInternal(.of(lhs, handle)) orelse return null;
2847-
if (lhs_ty.is_type_val) return null;
2848-
var rhs_ty = try analyser.resolveTypeOfNodeInternal(.of(rhs, handle)) orelse return null;
2849-
if (rhs_ty.is_type_val) return null;
2850-
lhs_ty = lhs_ty.withoutIPIndex(analyser);
2851-
rhs_ty = rhs_ty.withoutIPIndex(analyser);
2852-
return switch (lhs_ty.data) {
2853-
.pointer => |lhs_info| switch (rhs_ty.data) {
2854-
.pointer => |rhs_info| {
2991+
const lhs_instance = try analyser.resolveTypeOfNodeInternal(.of(lhs, handle)) orelse return null;
2992+
if (lhs_instance.is_type_val) return null;
2993+
const rhs_instance = try analyser.resolveTypeOfNodeInternal(.of(rhs, handle)) orelse return null;
2994+
if (rhs_instance.is_type_val) return null;
2995+
const lhs_no_value = lhs_instance.withoutIPIndex(analyser);
2996+
const rhs_no_value = rhs_instance.withoutIPIndex(analyser);
2997+
const instance = switch (lhs_no_value.data) {
2998+
.pointer => |lhs_info| switch (rhs_no_value.data) {
2999+
.pointer => |rhs_info| blk: {
28553000
if (lhs_info.size == .slice) return null;
28563001
if (rhs_info.size == .slice) return null;
2857-
return Type.fromIP(analyser, .usize_type, null);
3002+
break :blk Type.fromIP(analyser, .usize_type, null);
28583003
},
28593004
else => switch (lhs_info.size) {
2860-
.many, .c => lhs_ty,
3005+
.many, .c => lhs_no_value,
28613006
else => null,
28623007
},
28633008
},
2864-
else => try analyser.resolvePeerTypes(lhs_ty, rhs_ty),
2865-
};
3009+
else => try analyser.resolvePeerTypes(lhs_no_value, rhs_no_value),
3010+
} orelse return null;
3011+
return try analyser.resolveBinaryIntegerExpression(node_tag, instance, lhs_instance, rhs_instance) orelse return instance;
28663012
},
28673013

28683014
.shl,
28693015
.shl_sat,
28703016
.shr,
28713017
=> {
2872-
const lhs, _ = tree.nodeData(node).node_and_node;
2873-
const lhs_ty = try analyser.resolveTypeOfNodeInternal(.of(lhs, handle)) orelse return null;
2874-
if (lhs_ty.is_type_val) return null;
2875-
return lhs_ty.withoutIPIndex(analyser);
3018+
const lhs, const rhs = tree.nodeData(node).node_and_node;
3019+
const lhs_instance = try analyser.resolveTypeOfNodeInternal(.of(lhs, handle)) orelse return null;
3020+
if (lhs_instance.is_type_val) return null;
3021+
const lhs_no_value = lhs_instance.withoutIPIndex(analyser);
3022+
const rhs_instance = try analyser.resolveTypeOfNodeInternal(.of(rhs, handle)) orelse return lhs_no_value;
3023+
if (rhs_instance.is_type_val) return lhs_no_value;
3024+
return try analyser.resolveBinaryIntegerExpression(node_tag, lhs_no_value, lhs_instance, rhs_instance) orelse return lhs_no_value;
28763025
},
28773026

28783027
.array_mult => {

0 commit comments

Comments
 (0)