diff --git a/lib/std/io/stream.c3 b/lib/std/io/stream.c3 index a49665913..77d355baf 100644 --- a/lib/std/io/stream.c3 +++ b/lib/std/io/stream.c3 @@ -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. *> diff --git a/lib/std/math/complex.c3 b/lib/std/math/complex.c3 index 96d87df9e..c3310f28b 100644 --- a/lib/std/math/complex.c3 +++ b/lib/std/math/complex.c3 @@ -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); } \ No newline at end of file diff --git a/lib/std/math/quaternion.c3 b/lib/std/math/quaternion.c3 index 589babd25..eb9d844ad 100644 --- a/lib/std/math/quaternion.c3 +++ b/lib/std/math/quaternion.c3 @@ -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; diff --git a/releasenotes.md b/releasenotes.md index 5a51ce266..85d71bb2f 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -6,6 +6,8 @@ - Add lengthof() compile time function #2439 - Allow doc comments on individual struct members, faultdefs and enum values #2427. - `$alignof`, `$offsetof` and `$nameof` can now be used in `$defined`. +- Infer generic parameters lhs -> rhs: `List{int} x = list::NOHEAP`. +- Unify generic and regular module namespace. ### Fixes - Compiler assert with var x @noinit = 0 #2452 @@ -24,6 +26,7 @@ - Stack object size limit error on a static object. #2476 - Compiler segfault when modifying variable using an inline assembly block inside defer #2450. - Compile time switch over type would not correctly compare function pointer types. +- Regression: Compiler segfault when assigning struct literal with too few members #2483 ### Stdlib changes - Added generic `InterfaceList` to store a list of values that implement a specific interface @@ -32,6 +35,7 @@ - Add `LinkedList` array_view to support `[]` and `foreach`/`foreach_r`. #2438 - Make `LinkedList` printable and add `==` operator. #2438 - CVaList support on MacOS aarch64, SysV ABI x64. +- Add `io::skip` and `io::read_le` and `io::write_le` family of functions. ## 0.7.5 Change list diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 3d0dd7c70..ea252d316 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -71,7 +71,6 @@ void compiler_init(BuildOptions *build_options) htable_init(&compiler.context.modules, 16 * 1024); pathtable_init(&compiler.context.path_symbols, INITIAL_SYMBOL_MAP); decltable_init(&compiler.context.symbols, INITIAL_SYMBOL_MAP); - decltable_init(&compiler.context.generic_symbols, INITIAL_GENERIC_SYMBOL_MAP); htable_init(&compiler.context.features, 1024); htable_init(&compiler.context.compiler_defines, 16 * 1024); @@ -1540,20 +1539,12 @@ void compile() compiler_compile(); } - - - void global_context_add_decl(Decl *decl) { decltable_set(&compiler.context.symbols, decl); pathtable_set(&compiler.context.path_symbols, decl); } -void global_context_add_generic_decl(Decl *decl) -{ - decltable_set(&compiler.context.generic_symbols, decl); -} - void linking_add_link(Linking *linking, const char *link) { FOREACH(const char *, existing_link, linking->links) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 63bd1f0fc..25609c55c 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1804,6 +1804,10 @@ struct SemaContext_ DynamicScope active_scope; Expr *return_expr; bool is_temp; + struct + { + Module *infer; + } generic; }; typedef struct @@ -1887,6 +1891,7 @@ typedef struct const char *symbol; Module *path_found; bool suppress_error; + bool is_parameterized; } NameResolve; typedef struct @@ -1936,7 +1941,6 @@ typedef struct Decl **method_extension_list; DeclTable symbols; PathTable path_symbols; - DeclTable generic_symbols; Path std_module_path; Type *string_type; Decl *panic_var; @@ -2251,7 +2255,6 @@ const char *build_base_name(void); void global_context_clear_errors(void); void global_context_add_type(Type *type); void global_context_add_decl(Decl *type_decl); -void global_context_add_generic_decl(Decl *decl); void linking_add_link(Linking *linker, const char *link); @@ -2443,7 +2446,6 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl void sema_expr_convert_enum_to_int(Expr *expr); Decl *sema_decl_stack_resolve_symbol(const char *symbol); Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name); -bool unit_resolve_parameterized_symbol(SemaContext *context, NameResolve *name_resolve); Decl *sema_resolve_type_method(SemaContext *context, CanonicalType *type, const char *method_name); Decl *sema_resolve_method(Decl *type, const char *method_name); Decl *sema_resolve_method_only(Decl *type, const char *method_name); @@ -2456,6 +2458,7 @@ Decl *sema_find_label_symbol(SemaContext *context, const char *symbol); Decl *sema_find_label_symbol_anywhere(SemaContext *context, const char *symbol); Decl *sema_find_local(SemaContext *context, const char *symbol); Decl *sema_resolve_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span); +Decl *sema_resolve_parameterized_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span); BoolErr sema_symbol_is_defined_in_scope(SemaContext *c, const char *symbol); bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, ArraySize *len_ref); @@ -3246,6 +3249,20 @@ INLINE bool type_is_user_defined(Type *type) return user_defined_types[type->type_kind]; } + +static inline Module *type_find_generic(Type *type) +{ + Type *canonical = type->canonical; + if (canonical != type && type_is_user_defined(canonical)) + { + Module *module = canonical->decl->unit->module; + if (module->generic_module) return module; + } + if (!type_is_user_defined(type)) return NULL; + Module *module = type->decl->unit->module; + if (module->generic_module) return module; + return module->generic_module ? module : NULL; +} static inline Type *type_flatten_to_int(Type *type) { while (1) diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index e4875a323..0a8d88f9a 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -4775,7 +4775,16 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local, bool *c CallEnvKind env_kind = context->call_env.kind; if (is_static) context->call_env.kind = CALL_ENV_FUNCTION_STATIC; decl->in_init = true; + + Module *generic = type_find_generic(decl->type); + if (generic) + { + Module *temp = context->generic.infer; + context->generic.infer = generic; + generic = temp; + } success = sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false, true, check_defined); + context->generic.infer = generic; if (!success && check_defined) return false; decl->in_init = false; context->call_env.kind = env_kind; @@ -5107,31 +5116,11 @@ static bool sema_analyse_generic_module_contracts(SemaContext *c, Module *module return true; } - -bool sema_parameterized_type_is_found(SemaContext *context, Path *decl_path, const char *name, SourceSpan span) -{ - NameResolve name_resolve = { - .path = decl_path, - .span = span, - .symbol = name, - .suppress_error = true - }; - - return unit_resolve_parameterized_symbol(context, &name_resolve); -} - Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span, Expr **params, bool *was_recursive_ref, SourceSpan invocation_span) { - NameResolve name_resolve = { - .path = decl_path, - .span = span, - .symbol = name - }; - - if (!unit_resolve_parameterized_symbol(c, &name_resolve)) return poisoned_decl; - Decl *alias = name_resolve.found; - ASSERT(alias); + Decl *alias = sema_resolve_parameterized_symbol(c, name, decl_path, span); + if (!alias) return poisoned_decl; Module *module = alias->unit->module; unsigned parameter_count = vec_size(module->parameters); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index bc24323c2..a90daf4e7 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -75,6 +75,7 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_ct_offsetof(SemaContext *context, Expr *expr, bool *failed_ref); static inline bool sema_expr_analyse_ct_call(SemaContext *context, Expr *expr, bool *failed_ref); +static inline bool sema_analyse_expr_rhs_param(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref); static inline bool sema_expr_analyse_retval(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_expr_list(SemaContext *context, Expr *expr); @@ -1544,7 +1545,7 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param, // This only happens in body arguments RETURN_SEMA_ERROR(arg, "Named arguments are not supported for body parameters."); } - if (!sema_analyse_expr_rhs(context, type, arg, true, no_match_ref, false)) return false; + if (!sema_analyse_expr_rhs_param(context, type, arg, no_match_ref)) return false; if (IS_OPTIONAL(arg)) *optional_ref = true; switch (sema_resolve_storage_type(context, arg->type)) { @@ -1573,7 +1574,7 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param, case VARDECL_PARAM_EXPR: if (param->type) { - if (!sema_analyse_expr_rhs(context, param->type, arg, true, NULL, false)) + if (!sema_analyse_expr_rhs_param(context, param->type, arg, NULL)) { RETURN_ERR_WITH_DEFINITION; } @@ -1595,7 +1596,7 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param, case VARDECL_PARAM_CT: // $foo ASSERT(macro); - if (!sema_analyse_expr_rhs(context, type, arg, true, no_match_ref, false)) + if (!sema_analyse_expr_rhs_param(context, type, arg, no_match_ref)) { RETURN_ERR_WITH_DEFINITION; } @@ -6850,9 +6851,20 @@ static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *lef bool is_unwrapped_var = expr_is_unwrapped_ident(left); + Module *generic = type_find_generic(left->type); + if (generic) + { + Module *temp = context->generic.infer; + context->generic.infer = generic; + generic = temp; + } // 3. Evaluate right side to required type. - if (!sema_expr_analyse_assign_right_side(context, expr, left->type, right, is_unwrapped_var, false, failed_ref)) return false; - + if (!sema_expr_analyse_assign_right_side(context, expr, left->type, right, is_unwrapped_var, false, failed_ref)) + { + context->generic.infer = generic; + return false; + } + context->generic.infer = generic; if (is_unwrapped_var && IS_OPTIONAL(right)) { sema_rewrap_var(context, left->ident_expr); @@ -11294,6 +11306,14 @@ bool sema_analyse_cond_expr(SemaContext *context, Expr *expr, CondResult *result return true; } +static inline bool sema_analyse_expr_rhs_param(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref) +{ + Module *generic_module = context->generic.infer; + context->generic.infer = to ? type_find_generic(to) : NULL; + bool success = sema_analyse_expr_rhs(context, to, expr, true, no_match_ref, false); + context->generic.infer = generic_module; + return success; +} bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allow_optional, bool *no_match_ref, bool as_binary) diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 8963a9ee5..314dddd80 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -247,7 +247,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte } if (i >= size) { - if (!no_match_ref) goto NO_MATCH; + if (no_match_ref) goto NO_MATCH; sema_not_enough_elements_error(context, initializer, (int)i); return false; } @@ -268,7 +268,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte } if (i >= size) { - if (!no_match_ref) goto NO_MATCH; + if (no_match_ref) goto NO_MATCH; sema_not_enough_elements_error(context, initializer, i); return false; } diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index d9b812e8c..ba1edc9f5 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -135,7 +135,7 @@ static inline Decl *sema_find_decl_in_module(Module *module, Path *path, const c return module_find_symbol(module, symbol); } -static bool sema_find_decl_in_imports(SemaContext *context, NameResolve *name_resolve, bool want_generic) +static bool sema_find_decl_in_imports(SemaContext *context, NameResolve *name_resolve) { Decl *decl = NULL; // 1. Loop over imports. @@ -144,7 +144,6 @@ static bool sema_find_decl_in_imports(SemaContext *context, NameResolve *name_re FOREACH(Decl *, import, context->unit->imports) { - if (import->import.module->is_generic != want_generic) continue; bool is_private_import = import->import.import_private_as_public; if (!path && (decl || !is_private_import)) continue; // Is the decl in the import. @@ -187,15 +186,11 @@ static bool sema_find_decl_in_imports(SemaContext *context, NameResolve *name_re return true; } -static inline Module *sema_is_path_found(Module **modules, Path *path, bool want_generic) +static inline Module *sema_is_path_found(Module **modules, Path *path) { FOREACH(Module *, module, modules) { - if (module->is_generic != want_generic) continue; - if (matches_subpath(module->name, path)) - { - return module; - } + if (matches_subpath(module->name, path)) return module; } return NULL; } @@ -359,8 +354,7 @@ static Decl *sema_find_decl_by_short_path(Path *path, const char *name) return pathtable_get(&compiler.context.path_symbols, (void*)path->module, (void*)name); } -static bool sema_find_decl_in_global(SemaContext *context, DeclTable *table, Module **module_list, - NameResolve *name_resolve, bool want_generic) +static bool sema_find_decl_in_global(SemaContext *context, DeclTable *table, Module **module_list, NameResolve *name_resolve) { const char *symbol = name_resolve->symbol; Path *path = name_resolve->path; @@ -370,7 +364,7 @@ static bool sema_find_decl_in_global(SemaContext *context, DeclTable *table, Mod if (!decl_ids) { // Update the path found - if (path && !name_resolve->path_found) name_resolve->path_found = sema_is_path_found(module_list, path, want_generic); + if (path && !name_resolve->path_found) name_resolve->path_found = sema_is_path_found(module_list, path); name_resolve->found = NULL; return true; } @@ -472,12 +466,11 @@ static bool sema_resolve_path_symbol(SemaContext *context, NameResolve *name_res return true; } // 3. Loop over imports. - if (!sema_find_decl_in_imports(context, name_resolve, false)) return false; + if (!sema_find_decl_in_imports(context, name_resolve)) return false; // 4. Go to global search if (name_resolve->found) return true; - return sema_find_decl_in_global(context, &compiler.context.symbols, compiler.context.module_list, - name_resolve, false); + return sema_find_decl_in_global(context, &compiler.context.symbols, compiler.context.module_list, name_resolve); } static inline Decl *sema_find_ct_local(SemaContext *context, const char *symbol) @@ -547,10 +540,10 @@ static bool sema_resolve_no_path_symbol(SemaContext *context, NameResolve *name_ return true; } - if (!sema_find_decl_in_imports(context, name_resolve, false)) return false; + if (!sema_find_decl_in_imports(context, name_resolve)) return false; if (name_resolve->found) return true; - return sema_find_decl_in_global(context, &compiler.context.symbols, NULL, name_resolve, false); + return sema_find_decl_in_global(context, &compiler.context.symbols, NULL, name_resolve); } #define MAX_TEST 256 @@ -754,6 +747,52 @@ static void sema_report_error_on_decl(SemaContext *context, NameResolve *name_re } } +INLINE Module *sema_module_matches_path(SemaContext *context, Module *module, Path *path) +{ + if (matches_subpath(module->name, path)) + { + FOREACH(Decl *, import, context->unit->imports) + { + Module *mod = module; + while (mod) + { + if (import->import.module == mod) + { + return module; + } + mod = mod->parent_module; + } + } + } + return NULL; +} + +INLINE Module *sema_find_module_for_path(SemaContext *context, Path *path, bool prefer_generic) +{ + if (prefer_generic) + { + FOREACH(Module *, module, compiler.context.generic_module_list) + { + Module *module_match = sema_module_matches_path(context, module, path); + if (module_match) return module_match; + } + } + FOREACH(Module *, module, compiler.context.module_list) + { + Module *module_match = sema_module_matches_path(context, module, path); + if (module_match) return module_match; + } + if (!prefer_generic) + { + FOREACH(Module *, module, compiler.context.generic_module_list) + { + Module *module_match = sema_module_matches_path(context, module, path); + if (module_match) return module_match; + } + } + return NULL; +} + INLINE bool sema_resolve_symbol_common(SemaContext *context, NameResolve *name_resolve) { name_resolve->ambiguous_other_decl = NULL; @@ -765,39 +804,7 @@ INLINE bool sema_resolve_symbol_common(SemaContext *context, NameResolve *name_r if (!name_resolve->found && !name_resolve->maybe_decl && !name_resolve->private_decl && !name_resolve->path_found) { if (name_resolve->suppress_error) return true; - Module *module_with_path = NULL; - FOREACH(Module *, module, compiler.context.module_list) - { - if (matches_subpath(module->name, name_resolve->path)) - { - FOREACH(Decl *, import, context->unit->imports) - { - Module *mod = module; - while (mod) - { - if (import->import.module == mod) - { - module_with_path = module; - goto MOD_FOUND; - } - mod = mod->parent_module; - } - } - } - } -MOD_FOUND: - if (!module_with_path) - { - FOREACH(Module *, module, compiler.context.generic_module_list) - { - if (matches_subpath(module->name, name_resolve->path)) - { - RETURN_SEMA_ERROR(name_resolve->path, - "%s is a generic module, did you forget to add the generic parameter(s) {...} after '%s'?", - module->name->module, name_resolve->symbol); - } - } - } + Module *module_with_path = sema_find_module_for_path(context, name_resolve->path, name_resolve->is_parameterized); if (module_with_path) { RETURN_SEMA_ERROR(name_resolve, "'%s' could not be found in %s.", name_resolve->symbol, module_with_path->name->module); @@ -817,13 +824,54 @@ MOD_FOUND: sema_report_error_on_decl(context, name_resolve); return false; } - unit_register_external_symbol(context, found); if (found->is_if && context->call_env.in_if_resolution.a) { sema_error_at(context, context->call_env.in_if_resolution, "This @if expression is dependent on '%s' which is also conditional.", found->name); SEMA_NOTE(found, "'%s' is defined here.", found->name); return false; } + unit_register_external_symbol(context, found); + if (found->unit->module->is_generic) + { + if (name_resolve->is_parameterized) return true; + if (context->generic.infer) + { + if (context->generic.infer->generic_module != found->unit->module) + { + if (name_resolve->suppress_error) return name_resolve->found = NULL, true; + RETURN_SEMA_ERROR_AT(name_resolve->span, "Found '%s' in the generic module '%s', but it doesn't match the inferred module '%s'.", found->name, found->unit->module->name->module, + context->generic.infer->generic_module->name->module); + } + Decl *symbol = module_find_symbol(context->generic.infer, found->name); + if (symbol) return name_resolve->found = symbol, true; + } + if (name_resolve->suppress_error) return name_resolve->found = NULL, true; + RETURN_SEMA_ERROR_AT(name_resolve->span, "'%s' is defined in the generic module '%s', but no parameters where given.", found->name, found->unit->module->name->module); + } + else + { + if (!name_resolve->is_parameterized) return true; + if (name_resolve->suppress_error) return name_resolve->found = NULL, true; + bool is_type = decl_is_user_defined_type(name_resolve->found); + const char *str = is_type ? "type" : "symbol"; + if (found->unit->module->generic_suffix) + { + if (found->unit->module->generic_module == context->unit->module->generic_module) + { + RETURN_SEMA_ERROR_AT(name_resolve->span, "Generating a parameterized %s '%s' in the same module as the original " + "is not allowed, you need to place it outside of the '%s' module.", + str, found->name, context->unit->module->generic_module->name->module); + } + RETURN_SEMA_ERROR_AT(name_resolve->span, "This %s was matched as '%s%s' in module '%s%s', so parameterizing it further doesn't work.", str, found->name, found->unit->module->generic_suffix, found->unit->module->generic_module->name->module, found->unit->module->generic_suffix); + } + if (is_type) + { + RETURN_SEMA_ERROR_AT(name_resolve->span, "'%s' is not a generic type. Did you want an initializer " + "but forgot () around the type? That is, you typed '%s { ... }' but intended '(%s) { ... }'?", + name_resolve->symbol, name_resolve->symbol, name_resolve->symbol); + } + RETURN_SEMA_ERROR_AT(name_resolve->span, "Found '%s' in module '%s', but it is not a generic %s.", found->name, found->unit->module->name->module, str); + } return true; } @@ -994,45 +1042,6 @@ Decl *sema_resolve_type_method(SemaContext *context, CanonicalType *type, const } } -bool unit_resolve_parameterized_symbol(SemaContext *context, NameResolve *name_resolve) -{ - name_resolve->ambiguous_other_decl = NULL; - name_resolve->private_decl = NULL; - name_resolve->path_found = NULL; - - if (!sema_find_decl_in_imports(context, name_resolve, true)) return false; - if (!name_resolve->found) - { - if (!sema_find_decl_in_global(context, &compiler.context.generic_symbols, - compiler.context.generic_module_list, - name_resolve, true)) return false; - } - // 14. Error report - if (!name_resolve->found || name_resolve->ambiguous_other_decl) - { - if (name_resolve->suppress_error) return name_resolve->found = NULL, false; - if (!name_resolve->ambiguous_other_decl) - { - BoolErr res = sema_symbol_is_defined_in_scope(context, name_resolve->symbol); - if (res == BOOL_TRUE) - { - sema_error_at(context, name_resolve->span, "'%s' is not a generic type. Did you want an initializer " - "but forgot () around the type? That is, you typed '%s { ... }' but intended '(%s) { ... }'?", - name_resolve->symbol, name_resolve->symbol, name_resolve->symbol); - return false; - } - } - sema_report_error_on_decl(context, name_resolve); - return false; - } - if (!decl_is_user_defined_type(name_resolve->found) && !name_resolve->path && !name_resolve->found->is_autoimport) - { - if (name_resolve->suppress_error) return false; - RETURN_SEMA_ERROR(name_resolve, "Function and variables must be prefixed with a path, e.g. 'foo::%s'.", name_resolve->symbol); - } - return true; -} - /** * Silently find a symbol, will return NULL, Poison or the value */ @@ -1121,6 +1130,36 @@ Decl *sema_resolve_symbol(SemaContext *context, const char *symbol, Path *path, return resolve.found; } +/** + * Resolves a symbol, return NULL if an error was found (and signalled), + * otherwise the decl. + */ +Decl *sema_resolve_parameterized_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span) +{ + NameResolve resolve = { + .path = path, + .span = span, + .symbol = symbol, + .is_parameterized = true + }; + if (!sema_resolve_symbol_common(context, &resolve)) return NULL; + Decl *found = resolve.found; + ASSERT(found); + if (!decl_ok(found)) return NULL; + return resolve.found; +} + +bool sema_parameterized_type_is_found(SemaContext *context, Path *decl_path, const char *name, SourceSpan span) +{ + NameResolve name_resolve = { + .path = decl_path, + .span = span, + .symbol = name, + .suppress_error = true, + .is_parameterized = true + }; + return sema_resolve_symbol_common(context, &name_resolve) && name_resolve.found; +} static inline void sema_append_local(SemaContext *context, Decl *decl) { diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 3ad30bfea..242290690 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -285,7 +285,7 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls) htable_set(&unit->module->symbols, (void *)decl->name, decl); if (decl->visibility == VISIBLE_PUBLIC) { - global_context_add_generic_decl(decl); + global_context_add_decl(decl); } } } diff --git a/test/test_suite/functions/test_regression.c3t b/test/test_suite/functions/test_regression.c3t index c1c05e79b..b37ba81ac 100644 --- a/test/test_suite/functions/test_regression.c3t +++ b/test/test_suite/functions/test_regression.c3t @@ -98,7 +98,7 @@ struct Foo alias getValueInt = test2::getValue{int}; alias getValueDouble = test2::getValue{double}; alias IntBlob = test2::Blob{int}; -alias DoubleBlob = Blob{double}; +alias DoubleBlob = test2::Blob{double}; alias getMultInt = test2::getMult{int}; alias getMultDouble = test2::getMult{double}; diff --git a/test/test_suite/functions/test_regression_mingw.c3t b/test/test_suite/functions/test_regression_mingw.c3t index b9c71e59a..318122b92 100644 --- a/test/test_suite/functions/test_regression_mingw.c3t +++ b/test/test_suite/functions/test_regression_mingw.c3t @@ -100,7 +100,7 @@ struct Foo alias getValueInt = test2::getValue{int}; alias getValueDouble = test2::getValue{double}; alias IntBlob = test2::Blob{int}; -alias DoubleBlob = Blob{double}; +alias DoubleBlob = test2::Blob{double}; alias getMultInt = test2::getMult{int}; alias getMultDouble = test2::getMult{double}; diff --git a/test/test_suite/generic/generic_inference.c3t b/test/test_suite/generic/generic_inference.c3t new file mode 100644 index 000000000..0c854e066 --- /dev/null +++ b/test/test_suite/generic/generic_inference.c3t @@ -0,0 +1,24 @@ +module test; +import std, libc, test2; + +fn void hello(Foo{int} x) {} +fn void main() +{ + List{int} l = list::ONHEAP; + Maybe{int} m = maybe::value(3); + List{int} y = (List){}; + Quaternion z = quaternion::IDENTITY; + z = z * quaternion::IDENTITY; + hello(test2::get_foo()); + hello((Foo){}); + hello(test2::get_foo{int}()); +} + +module test2 {Type}; + +fn Foo get_foo() => {}; + +struct Foo +{ + Type t; +} \ No newline at end of file diff --git a/test/test_suite/generic/generic_inference2.c3 b/test/test_suite/generic/generic_inference2.c3 new file mode 100644 index 000000000..7c9f95230 --- /dev/null +++ b/test/test_suite/generic/generic_inference2.c3 @@ -0,0 +1,8 @@ +import std; +alias TestMap = HashMap {int, List {int}}; +fn int main(String[] args) +{ + TestMap a; + a.set(0, (List){}); + return 0; +} diff --git a/test/test_suite/generic/generic_self_ref.c3 b/test/test_suite/generic/generic_self_ref.c3 index a518375a1..ce56a75b4 100644 --- a/test/test_suite/generic/generic_self_ref.c3 +++ b/test/test_suite/generic/generic_self_ref.c3 @@ -10,7 +10,7 @@ struct Widget List {any} children; } -fn void Widget{Label}.draw(Widget* self) // #error: The same method is generated by multiple instances +fn void Widget{Label}.draw(Widget* self) // #error: same module as the original is not allowed, you need to place it outside { io::printfn("Hello Label"); } diff --git a/test/test_suite/generic/generic_without_param.c3 b/test/test_suite/generic/generic_without_param.c3 index ff2954081..6896fe08c 100644 --- a/test/test_suite/generic/generic_without_param.c3 +++ b/test/test_suite/generic/generic_without_param.c3 @@ -3,7 +3,7 @@ import std; import abc; fn void main() { - abc::test(); // #error: {...} + abc::test(); // #error: but no parameters where given } module abc{Type}; fn void test() {} \ No newline at end of file diff --git a/test/test_suite/generic/recursive_generic.c3 b/test/test_suite/generic/recursive_generic.c3 index 0cdf3475a..af8ae363b 100644 --- a/test/test_suite/generic/recursive_generic.c3 +++ b/test/test_suite/generic/recursive_generic.c3 @@ -7,7 +7,7 @@ Aa {int} a; module test1 {Type}; import test2; -alias Cc = Aa {Bb {Type}}; // #error: Generic resolution of this type has become deeply nested +alias Cc = Aa {Bb {Type}}; // #error:in the same module as the original is not allowed struct Aa {Type a;} module test2 {Type}; diff --git a/test/test_suite/generic/used_without_param.c3 b/test/test_suite/generic/used_without_param.c3 index 10219cc8f..cec6d8f66 100644 --- a/test/test_suite/generic/used_without_param.c3 +++ b/test/test_suite/generic/used_without_param.c3 @@ -4,6 +4,6 @@ import std::collections::maybe; fn void main() { - Maybe{float} f = (Maybe) {.value=6.6, .has_value=true}; // #error: Did you mean the struct + Maybe{float} f = (Maybe) {.value=6.6, .has_value=true}; Maybe{int}g = (Maybe) {.value=8, .has_value=true}; } diff --git a/test/test_suite/generic/used_without_param2.c3 b/test/test_suite/generic/used_without_param2.c3 index b21b042e6..656f16403 100644 --- a/test/test_suite/generic/used_without_param2.c3 +++ b/test/test_suite/generic/used_without_param2.c3 @@ -4,7 +4,7 @@ import std::collections::maybe; fn void test() { - maybe::Maybe{float} f = (Maybe) {.value=6.6, .has_value=true}; // #error: Did you mean the struct - Maybe x; // #error: Did you mean the struct + maybe::Maybe{float} f = (Maybe) {.value=6.6, .has_value=true}; + Maybe x; // #error: but no parameters where given } diff --git a/test/test_suite/generic/used_without_param3.c3 b/test/test_suite/generic/used_without_param3.c3 index 79117adcf..a56cd8c41 100644 --- a/test/test_suite/generic/used_without_param3.c3 +++ b/test/test_suite/generic/used_without_param3.c3 @@ -4,5 +4,5 @@ import std::collections::maybe; fn void test() { - maybe::Maybe{float} f = (Maybe) {.value=6.6, .has_value=true}; // #error: Did you mean the struct + (Maybe) {.value=6.6, .has_value=true}; // #error: is defined in the generic module } \ No newline at end of file diff --git a/test/test_suite/struct/too_few_elements.c3 b/test/test_suite/struct/too_few_elements.c3 new file mode 100644 index 000000000..59447ccb5 --- /dev/null +++ b/test/test_suite/struct/too_few_elements.c3 @@ -0,0 +1,13 @@ +import std; +fn int main() +{ + Colour col = {255, 255, 0}; // #error: Too few elements in initializer + return 0; +} +struct Colour +{ + char a; + char r; + char g; + char b; +} \ No newline at end of file diff --git a/test/test_suite/switch/switch_in_defer_macro.c3t b/test/test_suite/switch/switch_in_defer_macro.c3t index 007b66ca0..a8017db4e 100644 --- a/test/test_suite/switch/switch_in_defer_macro.c3t +++ b/test/test_suite/switch/switch_in_defer_macro.c3t @@ -25,7 +25,7 @@ enum Kind : char } -alias TokenTrie = Trie{Token, ushort}; +alias TokenTrie = trie::Trie{Token, ushort}; alias Ident = fn bool (usz index, char c); @@ -404,8 +404,8 @@ module lexer_test; import lexer; import std::io; -alias Lexer = Lexer{Token, Comment}; -alias Kind = Kind{Token, Comment}; +alias Lexer = lexer::Lexer{Token, Comment}; +alias Kind = lexer::Kind{Token, Comment}; enum Token : char (String token) { @@ -638,7 +638,7 @@ fn bool Bitmap.is_empty(&self) module trie_test; import trie; -alias Trie = Trie{String, char}; +alias Trie = trie::Trie{String, char}; fn void test() { diff --git a/test/unit/stdlib/collections/bitset.c3 b/test/unit/stdlib/collections/bitset.c3 index 0f9f95260..870efa4e0 100644 --- a/test/unit/stdlib/collections/bitset.c3 +++ b/test/unit/stdlib/collections/bitset.c3 @@ -4,31 +4,31 @@ import std::collections::growablebitset; import std::collections::list; import std::io; -alias List = List {usz}; +alias List2 = List {usz}; -alias BitSet = BitSet {2048}; +alias BitSet2 = BitSet {2048}; fn void bit_ops_assign() { - BitSet bs; - BitSet bs2; + BitSet2 bs; + BitSet2 bs2; bs.set(4); bs.set(6); bs2.set(4); bs2.set(8); - BitSet bs3 = bs; + BitSet2 bs3 = bs; bs3 ^= bs2; assert(!bs3.get(4)); assert(!bs3.get(5)); assert(bs3.get(6)); assert(bs3.get(8)); - BitSet bs4 = bs; + BitSet2 bs4 = bs; bs4 |= bs2; assert(bs4.get(4)); assert(!bs4.get(5)); assert(bs4.get(6)); assert(bs4.get(8)); - BitSet bs5 = bs; + BitSet2 bs5 = bs; bs5 &= bs2; assert(bs5.get(4)); assert(!bs5.get(5)); @@ -38,23 +38,23 @@ fn void bit_ops_assign() fn void bit_ops() { - BitSet bs; - BitSet bs2; + BitSet2 bs; + BitSet2 bs2; bs.set(4); bs.set(6); bs2.set(4); bs2.set(8); - BitSet bs3 = bs ^ bs2; + BitSet2 bs3 = bs ^ bs2; assert(!bs3.get(4)); assert(!bs3.get(5)); assert(bs3.get(6)); assert(bs3.get(8)); - BitSet bs4 = bs | bs2; + BitSet2 bs4 = bs | bs2; assert(bs4.get(4)); assert(!bs4.get(5)); assert(bs4.get(6)); assert(bs4.get(8)); - BitSet bs5 = bs & bs2; + BitSet2 bs5 = bs & bs2; assert(bs5.get(4)); assert(!bs5.get(5)); assert(!bs5.get(6)); @@ -62,7 +62,7 @@ fn void bit_ops() } fn void set_get() { - BitSet bs; + BitSet2 bs; assert(bs.cardinality() == 0); assert(!bs.get(0)); @@ -75,7 +75,7 @@ fn void set_get() assert(bs.get(2000)); assert(bs.cardinality() == 2); - List found; + List2 found; foreach (i, x : bs) { switch (i) @@ -97,10 +97,10 @@ fn void set_get() assert(bs.cardinality() == 0); } -alias GrowableBitSet = GrowableBitSet{char}; +alias GrowableBitSetChar = GrowableBitSet{char}; fn void growable_set_get() { - GrowableBitSet bs; + GrowableBitSetChar bs; bs.tinit(); assert(bs.cardinality() == 0, "Invalid cardinality"); @@ -118,7 +118,7 @@ fn void growable_set_get() assert(bs.data.len() == 251, "Len should be 251"); assert(bs.len() == 2001, "Len should be 2001"); - List found; + List2 found; foreach (i, x : bs) { switch (i) diff --git a/test/unit/stdlib/collections/linked_map.c3 b/test/unit/stdlib/collections/linked_map.c3 index fab9be24f..1722f8000 100644 --- a/test/unit/stdlib/collections/linked_map.c3 +++ b/test/unit/stdlib/collections/linked_map.c3 @@ -11,7 +11,7 @@ struct MapTest String key; usz value; } -alias List = List{MapTest}; +alias ListMap = List{MapTest}; fn void linked_map_basic() { diff --git a/test/unit/stdlib/collections/map.c3 b/test/unit/stdlib/collections/map.c3 index fedd1fd8b..91d291976 100644 --- a/test/unit/stdlib/collections/map.c3 +++ b/test/unit/stdlib/collections/map.c3 @@ -11,7 +11,7 @@ struct MapTest String key; usz value; } -alias List = List{MapTest}; +alias ListMap = List{MapTest}; fn void map() { @@ -40,7 +40,7 @@ fn void map() assert(tc.value == v); } - List list; + ListMap list; list.tinit(); m.@each(;String key, usz value) { diff --git a/test/unit/stdlib/io/stream.c3 b/test/unit/stdlib/io/stream.c3 index cbd85b0cb..79c34e77d 100644 --- a/test/unit/stdlib/io/stream.c3 +++ b/test/unit/stdlib/io/stream.c3 @@ -6,24 +6,56 @@ fn void read_ushort_test() assert(io::read_be_ushort(&reader)!! == 0x348a); } +fn void read_le_ushort_test() +{ + ByteReader reader = io::wrap_bytes({0x34, 0x8a}); + assert(io::read_le_ushort(&reader)!! == 0x8a34); +} + fn void read_uint_test() { ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc}); assert(io::read_be_uint(&reader)!! == 0x348aefcc); } +fn void read_le_uint_test() +{ + ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc}); + assert(io::read_le_uint(&reader)!! == 0xccef8a34); +} + +fn void read_skip_test() +{ + ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc}); + io::skip(&reader, 0)!!; + io::skip(&reader, 1)!!; + assert(io::read_le_ushort(&reader)!! == 0xef8a); +} + fn void read_ulong_test() { ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc}); assert(io::read_be_ulong(&reader)!! == 0x348aefcc348aefcc); } +fn void read_le_ulong_test() +{ + ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc}); + assert(io::read_le_ulong(&reader)!! == 0xccef8a34ccef8a34); +} + fn void read_uint128_test() { ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc}); assert(io::read_be_uint128(&reader)!! == 0x348aefcc348aefcc348aefcc348aefcc); } +fn void read_le_uint128_test() +{ + ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc}); + test::eq(io::read_le_uint128(&reader)!!, 0xccef8a34ccef8a34ccef8a34ccef8a34); +} + fn void write_ushort_test() { ByteWriter bw; @@ -32,6 +64,14 @@ fn void write_ushort_test() assert(bw.str_view() == &&x'348a'); } +fn void write_le_ushort_test() +{ + ByteWriter bw; + bw.tinit(); + io::write_le_short(&bw, 0x348a)!!; + assert(bw.str_view() == &&x'8a34'); +} + fn void write_uint_test() { ByteWriter bw; @@ -40,6 +80,14 @@ fn void write_uint_test() assert(bw.str_view() == &&x'3421348a'); } +fn void write_le_uint_test() +{ + ByteWriter bw; + bw.tinit(); + io::write_le_int(&bw, 0x3421348a)!!; + assert(bw.str_view() == &&x'8a342134'); +} + fn void write_ulong_test() { ByteWriter bw; @@ -48,6 +96,14 @@ fn void write_ulong_test() assert(bw.str_view() == &&x'aabbccdd3421348a'); } +fn void write_le_ulong_test() +{ + ByteWriter bw; + bw.tinit(); + io::write_le_long(&bw, 0xaabbccdd3421348a)!!; + assert(bw.str_view() == &&x'8a342134ddccbbaa'); +} + fn void write_uint128_test() { ByteWriter bw; @@ -56,6 +112,14 @@ fn void write_uint128_test() assert(bw.str_view() == &&x'aabbccdd3421348aaabbccdd3421348a'); } +fn void write_le_uint128_test() +{ + ByteWriter bw; + bw.tinit(); + io::write_le_int128(&bw, 0xaabbccdd3421348aaabbccdd3421348a)!!; + assert(bw.str_view() == &&x'8a342134ddccbbaa8a342134ddccbbaa'); +} + fn void write_tiny_bytearray_test() { ByteWriter bw; diff --git a/test/unit/stdlib/sort/quicksort.c3 b/test/unit/stdlib/sort/quicksort.c3 index 60e134301..edb81f949 100644 --- a/test/unit/stdlib/sort/quicksort.c3 +++ b/test/unit/stdlib/sort/quicksort.c3 @@ -78,11 +78,11 @@ fn void quicksort_with_lambda() } } -alias List = List{int}; +alias List2 = List{int}; fn void quicksort_list() { - List list; + List2 list; list.push_all({ 2, 1, 3}); sort::quicksort(list, &sort::cmp_int_value); assert(check::int_sort(list.array_view()));