Generics with <>. Deprecation of {} generics.

This commit is contained in:
Christoffer Lerno
2026-01-18 00:33:43 +01:00
parent d3ebd4a130
commit c3b2694834
93 changed files with 179 additions and 197 deletions

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2023-2025 Eduardo José Gómez Hernández. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::atomic::types{Type};
module std::atomic::types <Type>;
struct Atomic
{

View File

@@ -4,7 +4,7 @@
<*
@require SIZE > 0 : "The size of the bitset in bits must be at least 1"
*>
module std::collections::bitset {SIZE};
module std::collections::bitset <SIZE>;
const BITS = uint.sizeof * 8;
const SZ = (SIZE + BITS - 1) / BITS;
@@ -172,7 +172,7 @@ fn void BitSet.set_bool(&self, usz i, bool value) @operator([]=) @inline
<*
@require Type.kindof == UNSIGNED_INT
*>
module std::collections::growablebitset{Type};
module std::collections::growablebitset <Type>;
import std::collections::list;
const BITS = Type.sizeof * 8;

View File

@@ -4,7 +4,7 @@
<*
@require MAX_SIZE >= 1 : `The size must be at least 1 element big.`
*>
module std::collections::elastic_array {Type, MAX_SIZE};
module std::collections::elastic_array <Type, MAX_SIZE>;
import std::io, std::math, std::collections::list_common;
alias ElementPredicate = fn bool(Type *type);

View File

@@ -1,7 +1,7 @@
<*
@require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enummap"
*>
module std::collections::enummap{Enum, ValueType};
module std::collections::enummap <Enum, ValueType>;
import std::io;
struct EnumMap (Printable)

View File

@@ -5,7 +5,7 @@
<*
@require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enumset"
*>
module std::collections::enumset{Enum};
module std::collections::enumset <Enum>;
import std::io;
const ENUM_COUNT @private = Enum.values.len;

View File

@@ -4,7 +4,7 @@
<*
@require $defined((Key){}.hash()) : `No .hash function found on the key`
*>
module std::collections::map{Key, Value};
module std::collections::map <Key, Value>;
import std::math;
import std::io @norecurse;

View File

@@ -1,7 +1,7 @@
<*
@require $defined((Value){}.hash()) : `No .hash function found on the value`
*>
module std::collections::set {Value};
module std::collections::set <Value>;
import std::math;
import std::io @norecurse;

View File

@@ -4,7 +4,7 @@
<*
@require Type.kindof == INTERFACE || Type.kindof == ANY : "The kind of an interfacelist must be an interface or `any`"
*>
module std::collections::interfacelist {Type};
module std::collections::interfacelist <Type>;
import std::io,std::math;
alias InterfacePredicate = fn bool(Type value);

View File

@@ -1,4 +1,4 @@
module std::collections::blockingqueue { Value };
module std::collections::blockingqueue <Value>;
import std::thread, std::time;

View File

@@ -4,7 +4,7 @@
<*
@require $defined((Key){}.hash()) : `No .hash function found on the key`
*>
module std::collections::map{Key, Value};
module std::collections::map <Key, Value>;
import std::math;
import std::io @norecurse;

View File

@@ -1,7 +1,7 @@
<*
@require $defined((Value){}.hash()) : `No .hash function found on the value`
*>
module std::collections::set {Value};
module std::collections::set <Value>;
import std::math;
import std::io @norecurse;

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::linkedlist{Type};
module std::collections::linkedlist <Type>;
import std::io;
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::list{Type};
module std::collections::list <Type>;
import std::io, std::math, std::collections::list_common;
alias ElementPredicate = fn bool(Type *type);

View File

@@ -1,4 +1,4 @@
module std::collections::maybe{Type};
module std::collections::maybe <Type>;
import std::io;
struct Maybe (Printable)

View File

@@ -20,16 +20,13 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
module std::collections::priorityqueue{Type};
import std::collections::priorityqueue::private;
typedef PriorityQueue = inline PrivatePriorityQueue{Type, false};
typedef PriorityQueueMax = inline PrivatePriorityQueue{Type, true};
module std::collections::priorityqueue::private{Type, MAX};
module std::collections::priorityqueue;
import std::collections::list, std::io;
struct PrivatePriorityQueue (Printable)
typedef PriorityQueue <Type> = inline PrivatePriorityQueue{Type, false};
typedef PriorityQueueMax <Type> = inline PrivatePriorityQueue{Type, true};
struct PrivatePriorityQueue (Printable) <Type, MAX>
{
List{Type} heap;
}

View File

@@ -1,7 +1,7 @@
<*
@require Type.is_ordered : "The type must be ordered"
*>
module std::collections::range{Type};
module std::collections::range <Type>;
import std::io;
struct Range (Printable)

View File

@@ -1,7 +1,7 @@
<*
@require Type.kindof == ARRAY : "Required an array type"
*>
module std::collections::ringbuffer{Type};
module std::collections::ringbuffer <Type>;
import std::io;
alias Element = $typeof((Type){}[0]);

View File

@@ -1,4 +1,4 @@
module std::collections::pair{Type1, Type2};
module std::collections::pair <Type1, Type2>;
import std::io;
struct Pair (Printable)
@@ -29,9 +29,7 @@ fn bool Pair.equal(self, Pair other) @operator(==) @if (types::has_equals(Type1)
return self.first == other.first && self.second == other.second;
}
module std::collections::triple{Type1, Type2, Type3};
module std::collections::triple <Type1, Type2, Type3>;
import std::io;
struct Triple (Printable)
@@ -65,11 +63,10 @@ fn bool Triple.equal(self, Triple other) @operator(==) @if (types::has_equals(Ty
return self.first == other.first && self.second == other.second && self.third == other.third;
}
module std::collections::tuple{Type1, Type2};
module std::collections::tuple <Type1, Type2>;
struct Tuple @deprecated("Use 'Pair' instead")
{
Type1 first;
Type2 second;
}
}

View File

@@ -1060,7 +1060,7 @@ fn void* __memcpy(void* dst, void* src, usz n) @weak @export("memcpy")
}
module std::core::mem::volatile { Type };
module std::core::mem::volatile <Type>;
typedef Volatile @structlike = Type;
@@ -1077,7 +1077,7 @@ macro Type Volatile.set(&self, Type val)
<*
@require mem::@constant_is_power_of_2(ALIGNMENT) : "The alignment must be a power of 2"
*>
module std::core::mem::alignment { Type, ALIGNMENT };
module std::core::mem::alignment <Type, ALIGNMENT>;
import std::core::mem @public;
<*

View File

@@ -8,7 +8,7 @@
@require !$defined(Type.dealloc) ||| $defined(Type.dealloc(&&(Type){})) : "'dealloc' must only take a pointer to the underlying type"
@require !$defined(Type.dealloc) ||| $typeof((Type){}.dealloc()) == void : "'dealloc' must return 'void'"
*>
module std::core::mem::ref { Type };
module std::core::mem::ref <Type>;
import std::thread, std::atomic;
const OVERALIGNED @private = Type.alignof > mem::DEFAULT_MEM_ALIGNMENT;

View File

@@ -1,10 +1,10 @@
module std::core::array::slice {Type};
module std::core::array;
<*
A slice2d allows slicing an array like int[10][10] into an arbitrary "int[][]"-like counterpart
Typically you'd use array::slice2d(...) to create one.
*>
struct Slice2d
struct Slice2d <Type>
{
Type* ptr;
usz inner_len;

View File

@@ -1,4 +1,4 @@
module std::experimental::scheduler{Event};
module std::experimental::scheduler <Event>;
import std::collections, std::thread, std::time;
struct DelayedSchedulerEvent @local

View File

@@ -1,4 +1,4 @@
module std::hash::hmac{HashAlg, HASH_BYTES, BLOCK_BYTES};
module std::hash::hmac <HashAlg, HASH_BYTES, BLOCK_BYTES>;
import std::crypto;
struct Hmac

View File

@@ -4,7 +4,7 @@
<*
@require @in(DIGEST_BITS, ...PERMISSIBLE_SIZES_BITS) : "Invalid DIGEST_BITS; must be one of {128, 160, 256, 320}."
*>
module std::hash::ripemd { DIGEST_BITS };
module std::hash::ripemd <DIGEST_BITS>;
<* Unchanging block size. *>

View File

@@ -48,7 +48,7 @@ alias hash = siphash::hash { uint128, 4, 8 };
@require OutType.typeid == uint128.typeid || OutType.typeid == ulong.typeid : "Module OutType must be either uint128 or ulong."
*>
module std::hash::siphash { OutType, BLOCK_ROUNDS, FINALIZE_ROUNDS };
module std::hash::siphash <OutType, BLOCK_ROUNDS, FINALIZE_ROUNDS>;
struct SipHash

View File

@@ -16,7 +16,7 @@ alias I_F @builtin = complex::IMAGINARY { float };
@require Real.kindof == FLOAT : "A complex number must use a floating type"
*>
module std::math::complex {Real};
module std::math::complex <Real>;
import std::io;
union ComplexNumber (Printable)

View File

@@ -28,7 +28,7 @@ alias MATRIX4F_IDENTITY @builtin = matrix::IDENTITY4 {float};
@require Real.kindof == FLOAT : "A matrix must use a floating type"
*>
module std::math::matrix {Real};
module std::math::matrix <Real>;
import std::math::vector;
struct Matrix2x2

View File

@@ -13,7 +13,7 @@ alias QUATERNIONF_IDENTITY @builtin = quaternion::IDENTITY {float};
@require Real.kindof == FLOAT : "A quaternion must use a floating type"
*>
module std::math::quaternion {Real};
module std::math::quaternion <Real>;
import std::math::vector;
union QuaternionNumber
{

View File

@@ -39,7 +39,7 @@ macro void quicksort_indexed(list, start, end, cmp = EMPTY_MACRO_SLOT, context =
$endif
}
module std::sort::cs{Type, KeyFn};
module std::sort::cs <Type, KeyFn>;
alias Counts @private = usz[256];
alias Ranges @private = usz[257];

View File

@@ -17,7 +17,7 @@ macro void insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLO
$endif
}
module std::sort::is{Type, CmpFn, Context};
module std::sort::is <Type, CmpFn, Context>;
alias ElementType = $typeof(((Type){})[0]);
const bool IS_SLICE = Type.kindof == SLICE;

View File

@@ -37,7 +37,7 @@ macro quickselect(list, isz k, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLO
$endif
}
module std::sort::qs{Type, CmpFn, Context};
module std::sort::qs <Type, CmpFn, Context>;
alias ElementType = $typeof(((Type){})[0]);
const bool IS_SLICE = Type.kindof == SLICE;

View File

@@ -1,4 +1,4 @@
module std::thread::channel{Type};
module std::thread::channel <Type>;
typedef BufferedChannel = void*;

View File

@@ -1,4 +1,4 @@
module std::thread::pool{SIZE};
module std::thread::pool <SIZE>;
import std::thread;
struct ThreadPool

View File

@@ -1,4 +1,4 @@
module std::thread::channel {Type};
module std::thread::channel <Type>;
typedef UnbufferedChannel = void*;

View File

@@ -11,12 +11,13 @@
- Testing for the presence of methods at the top level is prohibited previous to method registration.
- `$$MASK_TO_INT` and `$$INT_TO_MASK` to create bool masks from integers and back.
- Better error messages when slicing a pointer to a slice or vector. #2681
- Generics using `@generic` rather than module based.
- Generics using ad-hoc `<...>` rather than module based.
- Reduced memory usage for backtraces on Linux.
- On win32 utf-8 console output is now enabled by default in compiled programs
- Add `$$VERSION` and `$$PRERELEASE` compile time constants.
- Require () around assignment in conditionals. #2716
- $$unaligned_load and $$unaligned_store now also takes a "is_volatile" parameter.
- Module-based generics using {} is deprecated.
### Fixes
- Regression with npot vector in struct triggering an assert #2219.

View File

@@ -2,7 +2,7 @@ module std::container::faults;
faultdef KEY_NOT_FOUND;
module std::container::map{Key, Type};
module std::container::map <Key, Type>;
import std::core::builtin;
import std::io;

View File

@@ -279,7 +279,6 @@ typedef enum
ATTRIBUTE_EXTERN,
ATTRIBUTE_FINALIZER,
ATTRIBUTE_FORMAT,
ATTRIBUTE_GENERIC,
ATTRIBUTE_IF,
ATTRIBUTE_INLINE,
ATTRIBUTE_INIT,

View File

@@ -414,7 +414,7 @@ static Expr *parse_lambda(ParseContext *c, Expr *left, SourceSpan lhs_span UNUSE
sig->params = decls;
sig->rtype = return_type ? type_infoid(return_type) : 0;
sig->variadic = variadic;
if (!parse_attributes(c, &func->attributes, NULL, NULL, NULL, NULL)) return poisoned_expr;
if (!parse_attributes(c, &func->attributes, NULL, NULL, NULL)) return poisoned_expr;
RANGE_EXTEND_PREV(func);
if (tok_is(c, TOKEN_IMPLIES))
{

View File

@@ -312,11 +312,13 @@ bool parse_module(ParseContext *c, AstId contracts)
Visibility visibility = VISIBLE_PUBLIC;
Attr** attrs = NULL;
bool is_cond = false;
Decl *generic_decl = NULL;
if (!parse_attributes(c, &attrs, &visibility, NULL, &is_cond, &generic_decl)) return false;
ASSIGN_DECL_OR_RET(Decl *generic_decl, parse_generic_decl(c), false);
if (!parse_attributes(c, &attrs, &visibility, NULL, &is_cond)) return false;
if (generic_decl_old)
{
//SEMA_DEPRECATED(generic_decl, "Module-based generics is deprecated, use `@generic` instead.");
SEMA_DEPRECATED(generic_decl_old, "Module-based generics is deprecated, use `<...>` instead.");
if (generic_decl)
{
SEMA_NOTE(generic_decl_old, "Old generics combined with new will ignore the former.");
@@ -929,7 +931,7 @@ Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type)
advance(c);
bool is_cond;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, NULL)) return poisoned_decl;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
decl->is_cond = is_cond;
if (tok_is(c, TOKEN_EQ))
{
@@ -1010,7 +1012,7 @@ Decl *parse_const_declaration(ParseContext *c, bool is_global, bool is_extern)
else
{
bool is_cond;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, NULL)) return poisoned_decl;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
decl->is_cond = is_cond;
}
@@ -1041,7 +1043,7 @@ Decl *parse_var_decl(ParseContext *c)
case TOKEN_IDENT:
decl = decl_new_var_current(c, NULL, VARDECL_LOCAL);
advance(c);
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, NULL)) return poisoned_decl;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
decl->is_cond = is_cond;
if (!tok_is(c, TOKEN_EQ))
{
@@ -1056,7 +1058,7 @@ Decl *parse_var_decl(ParseContext *c)
decl = decl_new_var_current(c, NULL, c->tok == TOKEN_CT_IDENT ? VARDECL_LOCAL_CT : VARDECL_LOCAL_CT_TYPE);
advance(c);
span = c->span;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, NULL)) return poisoned_decl;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
if (is_cond || decl->attributes)
{
print_error_at(span, "Attributes are not allowed on compile time variables.");
@@ -1216,22 +1218,6 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref, bool expect_eos)
advance(c);
Expr **list = NULL;
// Special handling of generic attributes
if (!attr->is_custom && attr->attr_kind == ATTRIBUTE_GENERIC)
{
CONSUME_OR_RET(TOKEN_LPAREN, false);
while (1)
{
ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), false);
vec_add(list, expr);
if (try_consume(c, TOKEN_RPAREN)) break;
CONSUME_OR_RET(TOKEN_COMMA, false);
}
attr->exprs = list;
*attribute_ref = attr;
return true;
}
// Consume the optional (expr | attr_param, ...)
if (try_consume(c, TOKEN_LPAREN))
{
@@ -1322,9 +1308,9 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
decl->is_export = c->unit->export_by_default;
bool is_builtin = false;
bool is_cond;
Decl *generics = NULL;
bool can_be_generic = decl_may_be_generic(decl);
if (!parse_attributes(c, &decl->attributes, &visibility, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, &generics)) return false;
ASSIGN_DECL_OR_RET(Decl *generics, parse_generic_decl(c), false);
if (!parse_attributes(c, &decl->attributes, &visibility, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond)) return false;
if (generics)
{
if (!can_be_generic)
@@ -1349,8 +1335,7 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
return true;
}
static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, Decl **
generic_ref, bool use_comma)
static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, bool use_comma)
{
Visibility visibility = -1; // NOLINT
if (cond_ref) *cond_ref = false;
@@ -1368,39 +1353,6 @@ static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref,
bool parsed_builtin = false;
switch (attr->attr_kind)
{
case ATTRIBUTE_GENERIC:
{
if (!generic_ref) RETURN_PRINT_ERROR_AT(false, attr, "'%s' cannot be used here.", attr->name);
if (*generic_ref) RETURN_PRINT_ERROR_AT(false, attr, "Only a single '%s' attribute may be added.", attr->name);
if (vec_size(attr->exprs) < 1) RETURN_PRINT_ERROR_AT(false, attr, "'%s' must have at least one parameter.", attr->name);
*generic_ref = decl_new(DECL_GENERIC, "", attr->span);
const char **names = NULL;
FOREACH(Expr *, expr, attr->exprs)
{
switch (expr->expr_kind)
{
case EXPR_TYPEINFO:
{
TypeInfo *type_info = expr->type_expr;
if (type_info->kind != TYPE_INFO_IDENTIFIER || type_info->subtype != TYPE_COMPRESSED_NONE) break;
if (type_info->unresolved.path) break;
vec_add(names, type_info->unresolved.name);
continue;
}
case EXPR_UNRESOLVED_IDENTIFIER:
{
if (!expr->unresolved_ident_expr.is_const || expr->unresolved_ident_expr.path) break;
vec_add(names, expr->unresolved_ident_expr.ident);
continue;
}
default:
break;
}
RETURN_PRINT_ERROR_AT(false, expr, "Generic parameters must be type or constant identifiers.");
}
(*generic_ref)->generic_decl.parameters = names;
break;
}
case ATTRIBUTE_PUBLIC:
parsed_visibility = VISIBLE_PUBLIC;
break;
@@ -1441,12 +1393,54 @@ static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref,
if (other_attr->name == name) RETURN_PRINT_ERROR_AT(false, attr, "Repeat of attribute '%s' here.", name);
}
ADD:
if (attr->attr_kind != ATTRIBUTE_GENERIC) vec_add(*attributes_ref, attr);
vec_add(*attributes_ref, attr);
if (use_comma && !try_consume(c, TOKEN_COMMA)) break;
}
return true;
}
Decl *parse_generic_decl(ParseContext *c)
{
SourceSpan start = c->span;
if (!try_consume(c, TOKEN_LESS)) return NULL;
if (try_consume(c, TOKEN_GREATER)) RETURN_PRINT_ERROR_HERE("The generic parameter list cannot be empty, it needs at least one element.");
const char **tokens = NULL;
// No params
while (1)
{
switch (c->tok)
{
case TOKEN_TYPE_IDENT:
case TOKEN_CONST_IDENT:
break;
case TOKEN_COMMA:
PRINT_ERROR_HERE("Unexpected ','");
return poisoned_decl;
case TOKEN_IDENT:
PRINT_ERROR_HERE("The generic parameter must be a type or a constant.");
return poisoned_decl;
case TOKEN_CT_IDENT:
case TOKEN_CT_TYPE_IDENT:
PRINT_ERROR_HERE("The generic parameter cannot be a $-prefixed name.");
return poisoned_decl;
default:
PRINT_ERROR_HERE("Only generic parameters are allowed here.");
return poisoned_decl;
}
vec_add(tokens, symstr(c));
advance(c);
if (!try_consume(c, TOKEN_COMMA))
{
if (!consume(c, TOKEN_GREATER, "Expected '>'.")) return false;
Decl *decl = decl_new(DECL_GENERIC, "", extend_span_with_token(start, c->prev_span));
decl->generic_decl.parameters = tokens;
return decl;
}
}
}
/**
* attribute_list ::= attribute*
*
@@ -1454,10 +1448,9 @@ ADD:
*
* @return true if parsing succeeded, false if recovery is needed
*/
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, Decl **
generic_ref)
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref)
{
return parse_attribute_list(c, attributes_ref, visibility_ref, builtin_ref, cond_ref, generic_ref, false);
return parse_attribute_list(c, attributes_ref, visibility_ref, builtin_ref, cond_ref, false);
}
/**
@@ -1575,7 +1568,7 @@ static inline bool parse_enum_param_decl(ParseContext *c, Decl*** parameters)
if (token_is_some_ident(c->tok)) RETURN_PRINT_ERROR_HERE("Expected a name starting with a lower-case letter.");
RETURN_PRINT_ERROR_HERE("Expected a member name here.");
}
if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL, NULL)) return false;
if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL)) return false;
vec_add(*parameters, param);
RANGE_EXTEND_PREV(param);
return true;
@@ -1822,7 +1815,7 @@ CHECK_ELLIPSIS:
Decl *param = decl_new_var(name, span, type, param_kind);
param->var.type_info = type ? type_infoid(type) : 0;
param->var.self_addr = ref;
if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL, NULL)) return false;
if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL)) return false;
if (!no_name)
{
if (try_consume(c, TOKEN_EQ))
@@ -1962,7 +1955,7 @@ static bool parse_struct_body(ParseContext *c, Decl *parent)
else
{
bool is_cond;
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond, NULL)) return false;
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond)) return false;
member->is_cond = true;
if (!parse_struct_body(c, member)) return decl_poison(parent);
}
@@ -2005,7 +1998,7 @@ static bool parse_struct_body(ParseContext *c, Decl *parent)
}
advance(c);
bool is_cond;
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond, NULL)) return false;
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond)) return false;
member->is_cond = true;
if (!try_consume(c, TOKEN_COMMA)) break;
if (was_inline)
@@ -2155,7 +2148,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
is_consecutive = true;
}
bool is_cond = false;
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond, NULL)) return false;
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond)) return false;
member_decl->is_cond = is_cond;
CONSUME_OR_RET(TOKEN_EOS, false);
unsigned index = vec_size(decl->strukt.members);
@@ -2176,7 +2169,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
member_decl->var.end = NULL;
}
bool is_cond = false;
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond, NULL)) return false;
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond)) return false;
member_decl->is_cond = is_cond;
CONSUME_EOS_OR_RET(false);
if (is_consecutive)
@@ -2362,7 +2355,7 @@ static inline Decl *parse_alias_type(ParseContext *c, AstId contracts)
{
return poisoned_decl;
}
if (!parse_attributes(c, &decl_type->attributes, NULL, NULL, NULL, NULL)) return poisoned_decl;
if (!parse_attributes(c, &decl_type->attributes, NULL, NULL, NULL)) return poisoned_decl;
RANGE_EXTEND_PREV(decl_type);
RANGE_EXTEND_PREV(decl);
CONSUME_EOS_OR_RET(poisoned_decl);
@@ -2545,7 +2538,7 @@ static inline Decl *parse_attrdef(ParseContext *c)
bool is_cond;
bool is_builtin = false;
if (!parse_attribute_list(c, &attributes, NULL, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, NULL,true)) return poisoned_decl;
if (!parse_attribute_list(c, &attributes, NULL, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, true)) return poisoned_decl;
decl->attr_decl.attrs = attributes;
CONSUME_EOS_OR_RET(poisoned_decl);
return decl;

View File

@@ -46,8 +46,8 @@ Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool is_regular_f
bool parse_attribute(ParseContext *c, Attr **attribute_ref, bool expect_eos);
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, Decl **
generic_ref);
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref);
Decl *parse_generic_decl(ParseContext *c);
bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, TokenType default_type);
Expr *parse_ct_expression_list(ParseContext *c, bool allow_decl);

View File

@@ -3097,7 +3097,6 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
[ATTRIBUTE_EXTERN] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES,
[ATTRIBUTE_FINALIZER] = ATTR_FUNC,
[ATTRIBUTE_FORMAT] = ATTR_FUNC | ATTR_MACRO | ATTR_FNTYPE,
[ATTRIBUTE_GENERIC] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | ATTR_UNION | ATTR_STRUCT | ATTR_INTERFACE | ATTR_ALIAS,
[ATTRIBUTE_IF] = (AttributeDomain)~(ATTR_CALL | ATTR_PARAM),
[ATTRIBUTE_INIT] = ATTR_FUNC,
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
@@ -3352,8 +3351,6 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
case ATTRIBUTE_NOALIAS:
decl->var.no_alias = true;
return true;
case ATTRIBUTE_GENERIC:
UNREACHABLE;
case ATTRIBUTE_IF:
if (!expr) RETURN_SEMA_ERROR(attr, "'@if' requires a boolean argument.");
if (!sema_analyse_expr_rvalue(context, expr)) return false;

View File

@@ -353,7 +353,6 @@ void symtab_init(uint32_t capacity)
attribute_list[ATTRIBUTE_EXTERN] = KW_DEF("@extern");
attribute_list[ATTRIBUTE_FINALIZER] = KW_DEF("@finalizer");
attribute_list[ATTRIBUTE_FORMAT] = KW_DEF("@format");
attribute_list[ATTRIBUTE_GENERIC] = KW_DEF("@generic");
attribute_list[ATTRIBUTE_IF] = KW_DEF("@if");
attribute_list[ATTRIBUTE_INIT] = KW_DEF("@init");
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("@inline");

View File

@@ -3,7 +3,7 @@ interface IOp
{
fn void op();
}
module mylib{Type};
module mylib <Type>;
import std::io;
import mylib::ifaces;
struct Op (IOp)

View File

@@ -1,4 +1,4 @@
module foo{Type};
module foo <Type>;
interface Baz
{}

View File

@@ -1,4 +1,4 @@
module my_module { GENNY };
module my_module <GENNY>;
import std::io;
const uint[5] H = { 1, 2, 3, 4, 5 };

View File

@@ -20,7 +20,7 @@ fn int main()
<*
This contains macros for working with arrays at compile time
*>
module assert_repro::macros { ValueT };
module assert_repro::macros <ValueT>;
alias SliceT = ValueT[];
macro SliceT slice(SliceT $from, usz $start, usz $end = usz.max)

View File

@@ -14,7 +14,7 @@ fn int main()
return 0;
}
module foo {Type};
module foo <Type>;
struct Foo
{

View File

@@ -1,4 +1,4 @@
module foo{Type};
module foo <Type>;
import std::io;
macro @hello(Type thing) {

View File

@@ -1,4 +1,4 @@
module foo{Type};
module foo <Type>;
import std::io;
macro @hello(Type thing) {

View File

@@ -1,4 +1,4 @@
module generic_module_enum{N};
module generic_module_enum <N>;
enum Foo : char (String s)
{

View File

@@ -10,7 +10,7 @@ fn void main()
blurb::test(&hello_int);
}
module foo{Type};
module foo <Type>;
fn void hello() {}

View File

@@ -181,14 +181,14 @@ fn void hello()
printf("Mult %f\n", doubleMult(11.1));
}
module foo{Type};
module foo <Type>;
fn Type check(Type i)
{
return i * i;
}
module test2{Type};
module test2 <Type>;
struct Blob
{

View File

@@ -183,14 +183,14 @@ fn void hello()
printf("Mult %f\n", doubleMult(11.1));
}
module foo{Type};
module foo <Type>;
fn Type check(Type i)
{
return i * i;
}
module test2{Type};
module test2 <Type>;
struct Blob
{

View File

@@ -6,14 +6,14 @@ fn int main()
return 0;
}
module test2{Type};
module test2 <Type>;
struct Foo
{
Type f;
}
module test2{Type, FOO};
module test2 <Type, FOO>;
struct Foo1
{

View File

@@ -1,4 +1,4 @@
module add{Type};
module add <Type>;
fn Type add(Type a, Type b) @builtin =>
a + b;

View File

@@ -1,7 +1,7 @@
import std::io;
<* @require Type.kindof == SIGNED_INT *>
struct Foo @generic(Type)
struct Foo <Type>
{
Type a;
}

View File

@@ -1,4 +1,4 @@
module foo{Type};
module foo <Type>;
fn void abc()
{

View File

@@ -9,7 +9,7 @@ struct Test
BazTest t;
}
module bar{Test};
module bar <Test>;
struct Baz
{

View File

@@ -1,4 +1,4 @@
fn Type test_val(Type val = Type{}) @generic(Type) => val; // #error: 'Type' is not a generic type. Did you want an initializer but forgot () around the type? That is, you typed 'Type { ... }' but intended '(Type) { ... }'
fn Type test_val(Type val = Type{}) <Type> => val; // #error: 'Type' is not a generic type. Did you want an initializer but forgot () around the type? That is, you typed 'Type { ... }' but intended '(Type) { ... }'
fn int main()
{

View File

@@ -8,7 +8,7 @@ fn void main()
Foo $f = 1;
test1::foo{$f}();
}
module test1 {FOO};
module test1 <FOO>;
fn void foo() {}

View File

@@ -1,4 +1,4 @@
module abc {Type};
module abc <Type>;
attrdef @Hello = @inline;
faultdef ABC;

View File

@@ -1,4 +1,4 @@
module g{T};
module g <T>;
faultdef F0, F1;

View File

@@ -1,5 +1,5 @@
// #target: macos-aarch64
module gen{Type};
module gen <Type>;
fn Type mult(Type x)
{

View File

@@ -1,9 +1,9 @@
import std;
struct Result @generic(WithType2)
struct Result <WithType2>
{
fault error;
}
macro err(fault error) @generic(OfType, SOME_CONST) @builtin => (Result{OfType}){ .error = error };
macro err(fault error) <OfType, SOME_CONST> @builtin => (Result{OfType}){ .error = error };
faultdef TESTIN;

View File

@@ -1,9 +1,9 @@
import std;
struct Result @generic(WithType2)
struct Result <WithType2>
{
fault error;
}
macro err(fault error) @generic(OfType) @builtin => (Result{OfType}){ .error = error };
macro err(fault error) <OfType> @builtin => (Result{OfType}){ .error = error };
faultdef TESTIN;

View File

@@ -14,7 +14,7 @@ fn void main()
hello(test2::get_foo{int}());
}
module test2 {Type};
module test2 <Type>;
fn Foo get_foo() => {};

View File

@@ -1,7 +1,7 @@
// #target: macos-aarch64
module base;
module test{MyType};
module test <MyType>;
import base;
interface Zzz
{

View File

@@ -5,7 +5,7 @@ module abc_faults;
faultdef UNTERMINATED_TAG, EMPTY_TAG, MISSING_TAG, UNSUPPORTED_TAG;
<* @require Type.kindof == STRUCT *>
module abc{Type};
module abc <Type>;
import std::io, abc_faults, std::collections::list;
alias TextTagList = List{TextTag};

View File

@@ -15,7 +15,7 @@ import foo::private;
// Bug #856
typedef Foo = inline PrivateFoo{int}; // #error: could not be found
module foo::private{Type} @local;
module foo::private <Type> @local;
struct PrivateFoo
{

View File

@@ -1,9 +1,9 @@
<* @require THE_CONST < 5 *>
module the_generic @generic(THE_CONST, Type);
module the_generic <THE_CONST, Type>;
struct Abc
{ int a; }
module the_generic @generic(THE_CONST, Type);
module the_generic <THE_CONST, Type>;
struct TheStruct
{

View File

@@ -1,4 +1,4 @@
module custom_type @generic(Type, VALUE);
module custom_type <Type, VALUE>;
struct Example
{

View File

@@ -21,10 +21,9 @@ fn void c()
fn int main()
{
return 0;
}
module bar{Type};
module bar <Type>;
fn void test()
{}

View File

@@ -1,4 +1,4 @@
module values {Type};
module values <Type>;
struct Values
{

View File

@@ -1,5 +1,5 @@
// #target: macos-x64
module hello{Type, FOO};
module hello <Type, FOO>;
fn Type x(Type t)
{

View File

@@ -1,5 +1,5 @@
// #target: macos-x64
module test_generic{Type, Func};
module test_generic<Type, Func>;
fn void sort(Type list, isz, isz, Func cmp)
{}

View File

@@ -1,5 +1,5 @@
// #target: macos-x64
module playground::bug{Ty};
module playground::bug <Ty>;
import std::io;
struct Foo
@@ -12,7 +12,7 @@ fn void Foo.print_it(&self)
io::printf("Method %s\n", self.x);
}
module playground::bug{Ty};
module playground::bug <Ty>;
import std::io;
macro void print_it(...)

View File

@@ -1,4 +1,4 @@
module gui::widget {Type};
module gui::widget <Type>;
import gui::widget_types;
import std::collections::list;
import std::io;

View File

@@ -1,9 +1,9 @@
// #target: macos-aarch64
module the_generic @generic(THE_CONST, Type);
module the_generic <THE_CONST, Type>;
struct Abc
{ int a; }
module the_generic @generic(THE_CONST, Type);
module the_generic <THE_CONST, Type>;
struct TheStruct
{
@@ -37,8 +37,8 @@ module test;
import the_generic;
<* @require Type.sizeof < 5 *>
fn Type square(Type t) @generic(Type) => t * 3;
fn Type bob(Type2 t) @generic(Type2) => feok * 3;
fn Type square(Type t) <Type> => t * 3;
fn Type bob(Type2 t) <Type2> => feok * 3;
fn int main()
{

View File

@@ -1,5 +1,5 @@
// #target: macos-x64
module test{Type};
module test <Type>;
alias Callback = fn Type();

View File

@@ -9,5 +9,5 @@ fn void main() {
<*
Hello
*>
module generic{Param};
module generic <Param>;
struct Generic { int a; }

View File

@@ -1,5 +1,5 @@
// #target: macos-x64
module test{FOO};
module test <FOO>;
const Z = FOO;

View File

@@ -5,5 +5,5 @@ fn void main()
{
abc::test(); // #error: 'test' is a generic function, did you forget the parameters '{ ... }'?
}
module abc{Type};
module abc <Type>;
fn void test() {}

View File

@@ -13,6 +13,6 @@ module abc::foo;
struct Def { int x; }
module abc::cde{Type};
module abc::cde <Type>;
struct Abc { Type a, b; }

View File

@@ -1,4 +1,4 @@
module foo{Type, SIZE};
module foo <Type, SIZE>;
struct Foo
{

View File

@@ -1,5 +1,5 @@
// #target: macos-x64
module broken{Type};
module broken <Type>;
typedef Bar = Type;
alias Bar2 = Type;
struct Baz

View File

@@ -1,9 +1,9 @@
import std;
struct Result @generic(WithType2)
struct Result <WithType2>
{
fault error;
}
macro Result{WithType} err(fault error) @generic(WithType) => { .error = error };
macro Result{WithType} err(fault error) <WithType> => { .error = error };
faultdef TESTIN;

View File

@@ -5,10 +5,10 @@ fn int main() => 0;
Aa {int} a;
module test1 {Type};
module test1 <Type>;
import test2;
alias Cc = Aa {Bb {Type}}; // #error: Generic resolution of this type has become deeply nested
struct Aa {Type a;}
module test2 {Type};
module test2 <Type>;
struct Bb {Type b;}

View File

@@ -1,4 +1,4 @@
module foo { Type };
module foo <Type>;
import std::collections::list;

View File

@@ -8,6 +8,6 @@ fn int main(String[] args)
return 0;
}
module some_module { F };
module some_module <F>;
import std;
const A_CONST = 12 + 2 * math::log2(F / 25); // #error: This expression cannot be evaluated at compile time

View File

@@ -15,7 +15,7 @@ fn int main() {
return 0;
}
module test::generic{Type};
module test::generic <Type>;
struct Test
{

View File

@@ -11,7 +11,7 @@ fn int main()
<*
@require $defined(String.hash)
*>
module test::generic{Some_Type};
module test::generic <Some_Type>;
enum Test
{

View File

@@ -4,7 +4,7 @@ fn void main()
test{int}();
}
module test{Type};
module test <Type>;
fn void test()
{
Type a;

View File

@@ -10,7 +10,7 @@ faultdef TRIE_FULL;
@require $defined((Token){}.token)
@require $defined((Comment){}.start) && $defined((Comment){}.end)
*>
module lexer {Token, Comment};
module lexer <Token, Comment>;
import std::io;
import trie;
@@ -456,7 +456,7 @@ fn int main(String[] args)
<*
@require Index.kindof == TypeKind.UNSIGNED_INT
*>
module trie{Value, Index};
module trie <Value, Index>;
import std::collections::list;
import trie::bitmap;
import lexer::faults;