From f36e9fea488da552dd6d789d1615b1127303dc3e Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 22 Aug 2025 00:26:18 +0200 Subject: [PATCH] Types converts to typeid implicitly. --- lib/std/core/array.c3 | 8 +++++--- lib/std/core/values.c3 | 3 ++- lib/std/io/io.c3 | 8 ++++---- lib/std/io/stream.c3 | 14 ++++++++++++-- lib/std/math/math.c3 | 18 +++++++++--------- releasenotes.md | 1 + src/compiler/sema_expr.c | 3 ++- .../expressions/test_ct_param_bug.c3 | 2 +- 8 files changed, 36 insertions(+), 21 deletions(-) diff --git a/lib/std/core/array.c3 b/lib/std/core/array.c3 index 646c7d0f8..e932a7026 100644 --- a/lib/std/core/array.c3 +++ b/lib/std/core/array.c3 @@ -9,7 +9,7 @@ import std::collections::pair; @param [in] array @param [in] element @require @typekind(array) == SLICE || @typekind(array) == ARRAY - @require @typeis(array[0], $typeof(element)) : "array and element must have the same type" + @require @typematch(array[0], element) : "array and element must have the same type" *> macro bool contains(array, element) { @@ -26,6 +26,8 @@ macro bool contains(array, element) @param [in] array @param [in] element + @require @typekind(array) == SLICE || @typekind(array) == ARRAY + @require @typematch(array[0], element) : "array and element must have the same type" @return "the first index of the element" @return? NOT_FOUND *> @@ -87,7 +89,7 @@ macro rindex_of(array, element) @param [&inout] allocator : "The allocator to use, default is the heap allocator" @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY - @require @typeis(arr1[0], $typeof(arr2[0])) : "Arrays must have the same type" + @require @typematch(arr1[0], arr2[0]) : "Arrays must have the same type" @ensure result.len == arr1.len + arr2.len *> macro concat(Allocator allocator, arr1, arr2) @nodiscard @@ -113,7 +115,7 @@ macro concat(Allocator allocator, arr1, arr2) @nodiscard @param [in] arr2 @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY - @require @typeis(arr1[0], $typeof(arr2[0])) : "Arrays must have the same type" + @require @typematch(arr1[0], arr2[0]) : "Arrays must have the same type" @ensure return.len == arr1.len + arr2.len *> macro tconcat(arr1, arr2) @nodiscard => concat(tmem, arr1, arr2); diff --git a/lib/std/core/values.c3 b/lib/std/core/values.c3 index 5830370d2..b926381c5 100644 --- a/lib/std/core/values.c3 +++ b/lib/std/core/values.c3 @@ -2,10 +2,11 @@ module std::core::values; import std::core::types; +macro bool @typematch(#value1, #value2) @builtin @const => $typeof(#value1) == $typeof(#value2); <* Return true if two values have the same type before any conversions. *> -macro bool @is_same_type(#value1, #value2) @const => $typeof(#value1).typeid == $typeof(#value2).typeid; +macro bool @is_same_type(#value1, #value2) @const @deprecated("Use @typematch") => $typeof(#value1).typeid == $typeof(#value2).typeid; macro bool @is_bool(#value) @const => types::is_bool($typeof(#value)); macro bool @is_int(#value) @const => types::is_int($typeof(#value)); macro bool @is_flat_intlike(#value) @const => types::is_flat_intlike($typeof(#value)); diff --git a/lib/std/io/io.c3 b/lib/std/io/io.c3 index b0d0daaa4..ed43598fb 100644 --- a/lib/std/io/io.c3 +++ b/lib/std/io/io.c3 @@ -50,7 +50,7 @@ faultdef "\r" will be filtered from the String. @param stream : `The stream to read from.` - @require !($defined(&stream) &&& @is_instream(&stream)) : "The value for 'stream' should have been passed as a pointer and not as a value, please add '&'." + @require @is_not_instream_if_ptr(stream) : "The value for 'stream' should have been passed as a pointer and not as a value, please add '&'." @require @is_instream(stream) : `Make sure that the stream is actually an InStream.` @param [inout] allocator : `the allocator to use.` @return `The string containing the data read.` @@ -76,7 +76,7 @@ macro String? readline(Allocator allocator, stream = io::stdin()) on the temporary allocator and does not need to be freed. @param stream : `The stream to read from.` - @require !($defined(&stream) &&& @is_instream(&stream)) : "The value for 'stream' should have been passed as a pointer and not as a value, please add '&'." + @require @is_not_instream_if_ptr(stream) : "The value for 'stream' should have been passed as a pointer and not as a value, please add '&'." @require @is_instream(stream) : `The stream must implement InStream.` @return `The temporary string containing the data read.` *> @@ -90,8 +90,8 @@ macro String? treadline(stream = io::stdin()) @param out_stream : `The stream to write to` @param in_stream : `The stream to read from.` - @require !($defined(&in_stream) &&& @is_instream(&in_stream)) : "The value for 'in_stream' should have been passed as a pointer and not as a value, please add '&'." - @require !($defined(&out_stream) &&& @is_outstream(&out_stream)) : "The value for 'out_stream' should have been passed as a pointer and not as a value, please add '&'." + @require @is_not_instream_if_ptr(in_stream) : "The value for 'in_stream' should have been passed as a pointer and not as a value, please add '&'." + @require @is_not_outstream_if_ptr(out_stream) : "The value for 'out_stream' should have been passed as a pointer and not as a value, please add '&'." @require @is_instream(in_stream) : `The in_stream must implement InStream.` @require @is_outstream(out_stream) : `The out_stream must implement OutStream.` @return `The number of bytes written` diff --git a/lib/std/io/stream.c3 b/lib/std/io/stream.c3 index 48e63b7e0..dd850548b 100644 --- a/lib/std/io/stream.c3 +++ b/lib/std/io/stream.c3 @@ -37,16 +37,26 @@ fn usz? available(InStream s) return 0; } -macro bool @is_instream(#expr) +macro bool @is_instream(#expr) @const { return @assignable_to(#expr, InStream); } -macro bool @is_outstream(#expr) +macro bool @is_not_instream_if_ptr(#expr) @const +{ + return !$defined(&#expr) ||| !@is_instream(&#expr); +} + +macro bool @is_outstream(#expr) @const { return @assignable_to(#expr, OutStream); } +macro bool @is_not_outstream_if_ptr(#expr) @const +{ + return !$defined(&#expr) ||| !@is_outstream(&#expr); +} + <* @param [&out] ref @require @is_instream(stream) : "Expected a stream" diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index 6719c2d95..12009c2df 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -129,7 +129,7 @@ macro atan2(x, y) <* @require values::@is_int(x) || values::@is_float(x) : "Expected an integer or floating point value" @require @typekind(sinp) == POINTER : "Expected sinp to be a pointer" - @require values::@is_same_type(sinp, cosp) : "Expected sinp and cosp to have the same type" + @require @typematch(sinp, cosp) : "Expected sinp and cosp to have the same type" @require @assignable_to(x, $typeof(*sinp)) : "Expected x and sinp/cosp to have the same type" *> macro sincos_ref(x, sinp, cosp) @@ -368,7 +368,7 @@ macro log10(x) => $$log10(values::promote_int(x)); <* @require types::is_numerical($typeof(x)) : `The input must be a floating point value or float vector` - @require types::is_same($typeof(x), $typeof(y)) : `The input types must be equal` + @require @typematch(x, y) : `The input types must be equal` *> macro max(x, y, ...) { @@ -595,7 +595,7 @@ macro normalize(x) @private @param then_value : "The vector to get elements from where the mask is 'true'" @param else_value : "The vector to get elements from where the mask is 'false'" @require values::@is_vector(then_value) && values::@is_vector(else_value) : "'Then' and 'else' must be vectors." - @require values::@is_same_type(then_value, else_value) : "'Then' and 'else' vectors must be of the same type." + @require @typematch(then_value, else_value) : "'Then' and 'else' vectors must be of the same type." @require then_value.len == mask.len : "Mask and selected vectors must be of the same width." @return "a vector of the same type as then/else" @@ -1135,27 +1135,27 @@ macro overflow_mul_helper(x, y) @local <* @param [&out] out : "Where the result of the addition is stored" @return "Whether the addition resulted in an integer overflow" - @require values::@is_same_type(a, b) : "a and b must be the same type" + @require @typematch(a, b) : "a and b must be the same type" @require values::@is_flat_intlike(a) &&& values::@is_flat_intlike(b) : "a and b must both be integer or integer vector based" - @require $defined(*out) &&& values::@is_same_type(*out, a) : "out must be a pointer of the same type as a and b" + @require $defined(*out) &&& @typematch(*out, a) : "out must be a pointer of the same type as a and b" *> macro bool overflow_add(a, b, out) => $$overflow_add(a, b, out); <* @param [&out] out : "Where the result of the subtraction is stored" @return "Whether the subtraction resulted in an integer overflow" - @require values::@is_same_type(a, b) : "a and b must be the same type" + @require @typematch(a, b) : "a and b must be the same type" @require values::@is_flat_intlike(a) &&& values::@is_flat_intlike(b) : "a and b must both be integer or integer vector based" - @require $defined(*out) &&& values::@is_same_type(*out, a) : "out must be a pointer of the same type as a and b" + @require $defined(*out) &&& @typematch(*out, a) : "out must be a pointer of the same type as a and b" *> macro bool overflow_sub(a, b, out) => $$overflow_sub(a, b, out); <* @param [&out] out : "Where the result of the multiplication is stored" @return "Whether the multiplication resulted in an integer overflow" - @require values::@is_same_type(a, b) : "a and b must be the same type" + @require @typematch(a, b) : "a and b must be the same type" @require values::@is_flat_intlike(a) &&& values::@is_flat_intlike(b) : "a and b must both be integer or integer vector based" - @require $defined(*out) &&& values::@is_same_type(*out, a) : "out must be a pointer of the same type as a and b" + @require $defined(*out) &&& @typematch(*out, a) : "out must be a pointer of the same type as a and b" *> macro bool overflow_mul(a, b, out) => $$overflow_mul(a, b, out); diff --git a/releasenotes.md b/releasenotes.md index e2983ba43..d874690c5 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -19,6 +19,7 @@ - `foo[x][y] = b` now interpreted as `(*&foo[x])[y] = b` which allows overloads to do chained [] accesses. - Error if a stack allocated variable is too big (configurable with `--max-stack-object-size`). - Add `@safeinfer` to allow `var` to be used locally. +- Types converts to typeid implicitly. ### Fixes - List.remove_at would incorrectly trigger ASAN. diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index ce8ac3a3f..48bd3cddc 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -11179,7 +11179,8 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr, bool mutat if (mutate) sema_expr_flatten_const_ident(expr->access_resolved_expr.parent); return true; case EXPR_TYPEINFO: - RETURN_SEMA_ERROR(expr, "A type must be followed by either (...) or '.' unless passed as a macro type argument or assigned to a compile time type variable."); + expr_rewrite_const_typeid(expr, expr->type_expr->type); + return true; case EXPR_CT_IDENT: if (mutate && !sema_cast_ct_ident_rvalue(context, expr)) return false; break; diff --git a/test/test_suite/expressions/test_ct_param_bug.c3 b/test/test_suite/expressions/test_ct_param_bug.c3 index c8c19cf25..a9aa16973 100644 --- a/test/test_suite/expressions/test_ct_param_bug.c3 +++ b/test/test_suite/expressions/test_ct_param_bug.c3 @@ -2,6 +2,6 @@ module test; macro @foo($aaa) {} fn int main(String[] args) { - @foo(int); // #error: must be followed by either + @foo(int); return 0; } \ No newline at end of file