Generic inference (#2475)

* Change generic symbol resolution.
* Infer generic parameters lhs -> rhs: `List{int} x = list::NOHEAP`.
* Regression: Compiler segfault when assigning struct literal with too few members #2483
This commit is contained in:
Christoffer Lerno
2025-09-16 18:05:21 +02:00
committed by GitHub
parent 8342ac80d3
commit 92aefb15f8
28 changed files with 563 additions and 214 deletions

View File

@@ -1,5 +1,7 @@
module std::io;
import std::math;
import std::core::env;
interface InStream
{
@@ -260,6 +262,16 @@ macro ushort? read_be_ushort(stream)
return (ushort)(hi_byte << 8 | lo_byte);
}
<*
@require @is_instream(stream)
*>
macro ushort? read_le_ushort(stream)
{
char lo_byte = stream.read_byte()!;
char hi_byte = stream.read_byte()!;
return (ushort)(hi_byte << 8 | lo_byte);
}
<*
@require @is_instream(stream)
*>
@@ -268,6 +280,14 @@ macro short? read_be_short(stream)
return read_be_ushort(stream);
}
<*
@require @is_instream(stream)
*>
macro short? read_le_short(stream)
{
return read_le_ushort(stream);
}
<*
@require @is_outstream(stream)
*>
@@ -277,6 +297,15 @@ macro void? write_be_short(stream, ushort s)
stream.write_byte((char)s)!;
}
<*
@require @is_outstream(stream)
*>
macro void? write_le_short(stream, ushort s)
{
stream.write_byte((char)s)!;
stream.write_byte((char)(s >> 8))!;
}
<*
@require @is_instream(stream)
*>
@@ -288,6 +317,17 @@ macro uint? read_be_uint(stream)
return val + stream.read_byte()!;
}
<*
@require @is_instream(stream)
*>
macro uint? read_le_uint(stream)
{
uint val = stream.read_byte()!;
val += stream.read_byte()! << 8;
val += stream.read_byte()! << 16;
return val + stream.read_byte()! << 24;
}
<*
@require @is_instream(stream)
*>
@@ -296,6 +336,14 @@ macro int? read_be_int(stream)
return read_be_uint(stream);
}
<*
@require @is_instream(stream)
*>
macro int? read_le_int(stream)
{
return read_le_uint(stream);
}
<*
@require @is_outstream(stream)
*>
@@ -307,6 +355,17 @@ macro void? write_be_int(stream, uint s)
stream.write_byte((char)s)!;
}
<*
@require @is_outstream(stream)
*>
macro void? write_le_int(stream, uint s)
{
stream.write_byte((char)s)!;
stream.write_byte((char)(s >> 8))!;
stream.write_byte((char)(s >> 16))!;
stream.write_byte((char)(s >> 24))!;
}
<*
@require @is_instream(stream)
*>
@@ -322,6 +381,21 @@ macro ulong? read_be_ulong(stream)
return val + stream.read_byte()!;
}
<*
@require @is_instream(stream)
*>
macro ulong? read_le_ulong(stream)
{
ulong val = (ulong)stream.read_byte()!;
val += (ulong)stream.read_byte()! << 8;
val += (ulong)stream.read_byte()! << 16;
val += (ulong)stream.read_byte()! << 24;
val += (ulong)stream.read_byte()! << 32;
val += (ulong)stream.read_byte()! << 40;
val += (ulong)stream.read_byte()! << 48;
return val + (ulong)stream.read_byte()! << 56;
}
<*
@require @is_instream(stream)
*>
@@ -330,6 +404,14 @@ macro long? read_be_long(stream)
return read_be_ulong(stream);
}
<*
@require @is_instream(stream)
*>
macro long? read_le_long(stream)
{
return read_le_ulong(stream);
}
<*
@require @is_outstream(stream)
*>
@@ -345,6 +427,21 @@ macro void? write_be_long(stream, ulong s)
stream.write_byte((char)s)!;
}
<*
@require @is_outstream(stream)
*>
macro void? write_le_long(stream, ulong s)
{
stream.write_byte((char)s)!;
stream.write_byte((char)(s >> 8))!;
stream.write_byte((char)(s >> 16))!;
stream.write_byte((char)(s >> 24))!;
stream.write_byte((char)(s >> 32))!;
stream.write_byte((char)(s >> 40))!;
stream.write_byte((char)(s >> 48))!;
stream.write_byte((char)(s >> 56))!;
}
<*
@require @is_instream(stream)
*>
@@ -368,6 +465,29 @@ macro uint128? read_be_uint128(stream)
return val + stream.read_byte()!;
}
<*
@require @is_instream(stream)
*>
macro uint128? read_le_uint128(stream)
{
uint128 val = stream.read_byte()!;
val += (uint128)stream.read_byte()! << 8;
val += (uint128)stream.read_byte()! << 16;
val += (uint128)stream.read_byte()! << 24;
val += (uint128)stream.read_byte()! << 32;
val += (uint128)stream.read_byte()! << 40;
val += (uint128)stream.read_byte()! << 48;
val += (uint128)stream.read_byte()! << 56;
val += (uint128)stream.read_byte()! << 64;
val += (uint128)stream.read_byte()! << 72;
val += (uint128)stream.read_byte()! << 80;
val += (uint128)stream.read_byte()! << 88;
val += (uint128)stream.read_byte()! << 96;
val += (uint128)stream.read_byte()! << 104;
val += (uint128)stream.read_byte()! << 112;
return val + (uint128)stream.read_byte()! << 120;
}
<*
@require @is_instream(stream)
*>
@@ -376,6 +496,14 @@ macro int128? read_be_int128(stream)
return read_be_uint128(stream);
}
<*
@require @is_instream(stream)
*>
macro int128? read_le_int128(stream)
{
return read_le_uint128(stream);
}
<*
@require @is_outstream(stream)
*>
@@ -399,6 +527,30 @@ macro void? write_be_int128(stream, uint128 s)
stream.write_byte((char)s)!;
}
<*
@require @is_outstream(stream)
*>
macro void? write_le_int128(stream, uint128 s)
{
stream.write_byte((char)s)!;
stream.write_byte((char)(s >> 8))!;
stream.write_byte((char)(s >> 16))!;
stream.write_byte((char)(s >> 24))!;
stream.write_byte((char)(s >> 32))!;
stream.write_byte((char)(s >> 40))!;
stream.write_byte((char)(s >> 48))!;
stream.write_byte((char)(s >> 56))!;
stream.write_byte((char)(s >> 64))!;
stream.write_byte((char)(s >> 72))!;
stream.write_byte((char)(s >> 80))!;
stream.write_byte((char)(s >> 88))!;
stream.write_byte((char)(s >> 96))!;
stream.write_byte((char)(s >> 104))!;
stream.write_byte((char)(s >> 112))!;
stream.write_byte((char)(s >> 120))!;
}
<*
@require @is_outstream(stream)
@require data.len < 256 : "Data exceeded 255"
@@ -443,6 +595,34 @@ macro char[]? read_short_bytearray(stream, Allocator allocator)
return data;
}
<*
@require @is_instream(stream)
*>
macro void? skip(stream, usz bytes)
{
if (!bytes) return;
$switch:
$case !$defined(stream.seek):
for (usz i = 0; i < bytes; i++)
{
stream.read()!;
}
return;
$case $typeof(stream) == InStream:
if (!&stream.seek)
{
for (usz i = 0; i < bytes; i++)
{
stream.read()!;
}
return;
}
stream.seek(bytes, CURSOR)!;
$default:
stream.seek(bytes, CURSOR)!;
$endswitch
}
<*
Wrap bytes for reading using io functions.
*>

View File

@@ -2,8 +2,8 @@ module std::math;
// Complex number aliases.
alias Complexf = Complex {float};
alias Complex = Complex {double};
alias Complexf = ComplexNumber {float};
alias Complex = ComplexNumber {double};
alias COMPLEX_IDENTITY @builtin = complex::IDENTITY {double};
alias COMPLEXF_IDENTITY @builtin = complex::IDENTITY {float};
alias IMAGINARY @builtin @deprecated("Use I") = complex::IMAGINARY { double };
@@ -19,7 +19,7 @@ alias I_F @builtin = complex::IMAGINARY { float };
module std::math::complex {Real};
import std::io;
union Complex (Printable)
union ComplexNumber (Printable)
{
struct
{
@@ -28,39 +28,39 @@ union Complex (Printable)
Real[<2>] v;
}
const Complex IDENTITY = { 1, 0 };
const Complex IMAGINARY = { 0, 1 };
const ComplexNumber IDENTITY = { 1, 0 };
const ComplexNumber IMAGINARY = { 0, 1 };
macro Complex Complex.add(self, Complex b) @operator(+) => { .v = self.v + b.v };
macro Complex Complex.add_this(&self, Complex b) @operator(+=) => { .v = self.v += b.v };
macro Complex Complex.add_real(self, Real r) @operator_s(+) => { .v = self.v + (Real[<2>]) { r, 0 } };
macro Complex Complex.add_each(self, Real b) => { .v = self.v + b };
macro Complex Complex.sub(self, Complex b) @operator(-) => { .v = self.v - b.v };
macro Complex Complex.sub_this(&self, Complex b) @operator(-=) => { .v = self.v -= b.v };
macro Complex Complex.sub_real(self, Real r) @operator(-) => { .v = self.v - (Real[<2>]) { r, 0 } };
macro Complex Complex.sub_real_inverse(self, Real r) @operator_r(-) => { .v = (Real[<2>]) { r, 0 } - self.v };
macro Complex Complex.sub_each(self, Real b) => { .v = self.v - b };
macro Complex Complex.scale(self, Real r) @operator_s(*) => { .v = self.v * r };
macro Complex Complex.mul(self, Complex b)@operator(*) => { self.r * b.r - self.c * b.c, self.r * b.c + b.r * self.c };
macro Complex Complex.div_real(self, Real r) @operator(/) => { .v = self.v / r };
macro Complex Complex.div_real_inverse(Complex c, Real r) @operator_r(/) => ((Complex) { .r = r }).div(c);
macro Complex Complex.div(self, Complex b) @operator(/)
macro ComplexNumber ComplexNumber.add(self, ComplexNumber b) @operator(+) => { .v = self.v + b.v };
macro ComplexNumber ComplexNumber.add_this(&self, ComplexNumber b) @operator(+=) => { .v = self.v += b.v };
macro ComplexNumber ComplexNumber.add_real(self, Real r) @operator_s(+) => { .v = self.v + (Real[<2>]) { r, 0 } };
macro ComplexNumber ComplexNumber.add_each(self, Real b) => { .v = self.v + b };
macro ComplexNumber ComplexNumber.sub(self, ComplexNumber b) @operator(-) => { .v = self.v - b.v };
macro ComplexNumber ComplexNumber.sub_this(&self, ComplexNumber b) @operator(-=) => { .v = self.v -= b.v };
macro ComplexNumber ComplexNumber.sub_real(self, Real r) @operator(-) => { .v = self.v - (Real[<2>]) { r, 0 } };
macro ComplexNumber ComplexNumber.sub_real_inverse(self, Real r) @operator_r(-) => { .v = (Real[<2>]) { r, 0 } - self.v };
macro ComplexNumber ComplexNumber.sub_each(self, Real b) => { .v = self.v - b };
macro ComplexNumber ComplexNumber.scale(self, Real r) @operator_s(*) => { .v = self.v * r };
macro ComplexNumber ComplexNumber.mul(self, ComplexNumber b)@operator(*) => { self.r * b.r - self.c * b.c, self.r * b.c + b.r * self.c };
macro ComplexNumber ComplexNumber.div_real(self, Real r) @operator(/) => { .v = self.v / r };
macro ComplexNumber ComplexNumber.div_real_inverse(ComplexNumber c, Real r) @operator_r(/) => ((ComplexNumber) { .r = r }).div(c);
macro ComplexNumber ComplexNumber.div(self, ComplexNumber b) @operator(/)
{
Real div = b.v.dot(b.v);
return { (self.r * b.r + self.c * b.c) / div, (self.c * b.r - self.r * b.c) / div };
}
macro Complex Complex.inverse(self)
macro ComplexNumber ComplexNumber.inverse(self)
{
Real sqr = self.v.dot(self.v);
return { self.r / sqr, -self.c / sqr };
}
macro Complex Complex.conjugate(self) => { .r = self.r, .c = -self.c };
macro Complex Complex.negate(self) @operator(-) => { .v = -self.v };
macro bool Complex.equals(self, Complex b) @operator(==) => self.v == b.v;
macro bool Complex.equals_real(self, Real r) @operator_s(==) => self.v == { r, 0 };
macro bool Complex.not_equals(self, Complex b) @operator(!=) => self.v != b.v;
macro ComplexNumber ComplexNumber.conjugate(self) => { .r = self.r, .c = -self.c };
macro ComplexNumber ComplexNumber.negate(self) @operator(-) => { .v = -self.v };
macro bool ComplexNumber.equals(self, ComplexNumber b) @operator(==) => self.v == b.v;
macro bool ComplexNumber.equals_real(self, Real r) @operator_s(==) => self.v == { r, 0 };
macro bool ComplexNumber.not_equals(self, ComplexNumber b) @operator(!=) => self.v != b.v;
fn usz? Complex.to_format(&self, Formatter* f) @dynamic
fn usz? ComplexNumber.to_format(&self, Formatter* f) @dynamic
{
return f.printf("%g%+gi", self.r, self.c);
}

View File

@@ -2,8 +2,8 @@ module std::math;
// Predefined quaternion aliases.
alias Quaternionf = Quaternion {float};
alias Quaternion = Quaternion {double};
alias Quaternionf = QuaternionNumber {float};
alias Quaternion = QuaternionNumber {double};
alias QUATERNION_IDENTITY @builtin = quaternion::IDENTITY {double};
alias QUATERNIONF_IDENTITY @builtin = quaternion::IDENTITY {float};
@@ -15,7 +15,7 @@ alias QUATERNIONF_IDENTITY @builtin = quaternion::IDENTITY {float};
module std::math::quaternion {Real};
import std::math::vector;
union Quaternion
union QuaternionNumber
{
struct
{
@@ -24,22 +24,22 @@ union Quaternion
Real[<4>] v;
}
const Quaternion IDENTITY = { 0, 0, 0, 1 };
const QuaternionNumber IDENTITY = { 0, 0, 0, 1 };
macro Quaternion Quaternion.add(self, Quaternion b) @operator(+) => { .v = self.v + b.v };
macro Quaternion Quaternion.add_each(self, Real b) => { .v = self.v + b };
macro Quaternion Quaternion.sub(self, Quaternion b) @operator(-) => { .v = self.v - b.v };
macro Quaternion Quaternion.negate(self) @operator(-) => { .v = -self.v };
macro Quaternion Quaternion.sub_each(self, Real b) => { .v = self.v - b };
macro Quaternion Quaternion.scale(self, Real s) @operator_s(*) => { .v = self.v * s };
macro Quaternion Quaternion.normalize(self) => { .v = self.v.normalize() };
macro Real Quaternion.length(self) => self.v.length();
macro Quaternion Quaternion.lerp(self, Quaternion q2, Real amount) => { .v = self.v.lerp(q2.v, amount) };
macro Matrix4f Quaternion.to_matrixf(&self) => into_matrix(self, Matrix4f);
macro Matrix4 Quaternion.to_matrix(&self) => into_matrix(self, Matrix4);
fn Quaternion Quaternion.nlerp(self, Quaternion q2, Real amount) => { .v = self.v.lerp(q2.v, amount).normalize() };
macro QuaternionNumber QuaternionNumber.add(self, QuaternionNumber b) @operator(+) => { .v = self.v + b.v };
macro QuaternionNumber QuaternionNumber.add_each(self, Real b) => { .v = self.v + b };
macro QuaternionNumber QuaternionNumber.sub(self, QuaternionNumber b) @operator(-) => { .v = self.v - b.v };
macro QuaternionNumber QuaternionNumber.negate(self) @operator(-) => { .v = -self.v };
macro QuaternionNumber QuaternionNumber.sub_each(self, Real b) => { .v = self.v - b };
macro QuaternionNumber QuaternionNumber.scale(self, Real s) @operator_s(*) => { .v = self.v * s };
macro QuaternionNumber QuaternionNumber.normalize(self) => { .v = self.v.normalize() };
macro Real QuaternionNumber.length(self) => self.v.length();
macro QuaternionNumber QuaternionNumber.lerp(self, QuaternionNumber q2, Real amount) => { .v = self.v.lerp(q2.v, amount) };
macro Matrix4f QuaternionNumber.to_matrixf(&self) => into_matrix(self, Matrix4f);
macro Matrix4 QuaternionNumber.to_matrix(&self) => into_matrix(self, Matrix4);
fn QuaternionNumber QuaternionNumber.nlerp(self, QuaternionNumber q2, Real amount) => { .v = self.v.lerp(q2.v, amount).normalize() };
fn Quaternion Quaternion.invert(self)
fn QuaternionNumber QuaternionNumber.invert(self)
{
Real length_sq = self.v.dot(self.v);
if (length_sq <= 0) return self;
@@ -47,9 +47,9 @@ fn Quaternion Quaternion.invert(self)
return { self.v[0] * -inv_length, self.v[1] * -inv_length, self.v[2] * -inv_length, self.v[3] * inv_length };
}
fn Quaternion Quaternion.slerp(self, Quaternion q2, Real amount)
fn QuaternionNumber QuaternionNumber.slerp(self, QuaternionNumber q2, Real amount)
{
Quaternion result = {};
QuaternionNumber result = {};
Real[<4>] q2v = q2.v;
Real cos_half_theta = self.v.dot(q2v);
@@ -76,7 +76,7 @@ fn Quaternion Quaternion.slerp(self, Quaternion q2, Real amount)
return { .v = q1v * ratio_a + q2v * ratio_b };
}
fn Quaternion Quaternion.mul(self, Quaternion b) @operator(*)
fn QuaternionNumber QuaternionNumber.mul(self, QuaternionNumber b) @operator(*)
{
return { self.i * b.l + self.l * b.i + self.j * b.k - self.k * b.j,
self.j * b.l + self.l * b.j + self.k * b.i - self.i * b.k,
@@ -84,9 +84,9 @@ fn Quaternion Quaternion.mul(self, Quaternion b) @operator(*)
self.l * b.l - self.i * b.i - self.j * self.j - self.k * self.k };
}
macro into_matrix(Quaternion* q, $Type) @private
macro into_matrix(QuaternionNumber* q, $Type) @private
{
Quaternion rotation = q.normalize();
QuaternionNumber rotation = q.normalize();
var x = rotation.i;
var y = rotation.j;
var z = rotation.k;