changed: interface syntax
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 4 Feb 2024 21:31:24 +0000 (15:31 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 4 Feb 2024 21:31:24 +0000 (15:31 -0600)
Interfaces now look more like procedures, with sentinels being specified using `t as T` in the body.

27 files changed:
compiler/include/astnodes.h
compiler/src/astnodes.c
compiler/src/checker.c
compiler/src/clone.c
compiler/src/doc.c
compiler/src/parser.c
compiler/src/polymorph.h
compiler/src/symres.c
core/builtin.onyx
core/container/iter.onyx
core/container/map.onyx
core/container/pair.onyx
core/container/set.onyx
core/container/slice.onyx
core/hash/hash.onyx
core/intrinsics/type_interfaces.onyx
core/misc/method_ops.onyx
core/string/string.onyx
examples/22_interfaces.onyx
tests/aoc-2020/day17.onyx
tests/aoc-2020/day20.onyx
tests/aoc-2021/day21.onyx
tests/complicated_polymorph.onyx
tests/interface_scopes.onyx
tests/interfaces
tests/interfaces.onyx
tests/where_clauses.onyx

index 6ac937210d0ab0b6ad73338f22295834aea38841..1968cd2bca43b5e887a2f1d288c18e53a68d9dcb 100644 (file)
@@ -1207,9 +1207,15 @@ struct AstOverloadedFunction {
 // @CLEANUP: Is this really necessary?
 typedef struct InterfaceParam {
     OnyxToken *value_token;
-    OnyxToken *type_token;
+    AstType   *value_type;
+    Type      *type;
 } InterfaceParam;
 
+typedef struct InterfaceSentinel {
+    OnyxToken *name;
+    AstType   *type;
+} InterfaceSentinel;
+
 typedef struct InterfaceConstraint {
     AstTyped *expr;
     AstType  *expected_type_expr;
@@ -1225,6 +1231,7 @@ struct AstInterface {
     char *name;
 
     bh_arr(InterfaceParam)      params;
+    bh_arr(InterfaceSentinel)   sentinels;
     bh_arr(InterfaceConstraint) exprs;
 
     Scope *scope;
@@ -1248,7 +1255,7 @@ struct AstConstraint {
     union {
         struct {
             AstInterface *              interface;
-            bh_arr(AstType *)           type_args;
+            bh_arr(AstTyped *)          args;
             Scope*                      scope;
             bh_arr(InterfaceConstraint) exprs;
             u32                         expr_idx;
index ea6ed878638494786f8e12793e0cfb52d29d8116..0a3381bdb9c118452f80f802252d8b01fd23a409 100644 (file)
@@ -929,7 +929,8 @@ TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) {
     // an instance of a type generic polymorphic structure.
     // For example, converting to an iterator can be tested with:
     //
-    //       IsIterable :: interface (t: $T) {
+    //       IsIterable :: interface (T: type_expr) {
+    //           t as T;
     //           { t->AsIterator() } -> Iterator;
     //       }
     //
@@ -1841,7 +1842,7 @@ AstPolyCallType* convert_call_to_polycall(AstCall* call) {
 
 b32 resolve_intrinsic_interface_constraint(AstConstraint *constraint) {
     AstInterface *interface = constraint->interface;
-    Type* type = type_build_from_ast(context.ast_alloc, constraint->type_args[0]);
+    Type* type = type_build_from_ast(context.ast_alloc, (AstType *) constraint->args[0]);
     if (!type) return 0;
 
     if (!strcmp(interface->name, "type_is_bool"))     return type_is_bool(type);
index 8fed0610304979e76fa0279524fd864dda52270f..fd3d9206963a0ec8e714bed4734e955cdc804524 100644 (file)
@@ -1,3 +1,5 @@
+#include "astnodes.h"
+#include "types.h"
 #define BH_INTERNAL_ALLOCATOR (global_heap_allocator)
 #define BH_DEBUG
 #include "parser.h"
@@ -3655,6 +3657,19 @@ CheckStatus check_macro(AstMacro* macro) {
     return Check_Success;
 }
 
+CheckStatus check_interface(AstInterface *interface) {
+    bh_arr_each(InterfaceParam, param, interface->params) {
+        CHECK(type, &param->value_type);
+
+        param->type = type_build_from_ast(context.ast_alloc, param->value_type);
+        if (!param->type) {
+            YIELD(param->value_type->token->pos, "Waiting for interface parameter's type to be constructed.");
+        }
+    }
+
+    return Check_Success;
+}
+
 CheckStatus check_interface_constraint(AstConstraint *constraint) {
     if (constraint->interface->kind != Ast_Kind_Interface) {
         // CLEANUP: This error message might not look totally right in some cases.
@@ -3690,25 +3705,35 @@ CheckStatus check_interface_constraint(AstConstraint *constraint) {
 
     constraint->scope = scope_create(context.ast_alloc, constraint->interface->scope, constraint->token->pos);
 
-    if (bh_arr_length(constraint->type_args) != bh_arr_length(constraint->interface->params)) {
+    if (bh_arr_length(constraint->args) != bh_arr_length(constraint->interface->params)) {
         ERROR_(constraint->token->pos, "Wrong number of arguments given to interface. Expected %d, got %d.",
             bh_arr_length(constraint->interface->params),
-            bh_arr_length(constraint->type_args));
+            bh_arr_length(constraint->args));
     }
 
     fori (i, 0, bh_arr_length(constraint->interface->params)) {
         InterfaceParam *ip = &constraint->interface->params[i];
 
-        AstTyped *sentinel = onyx_ast_node_new(context.ast_alloc, sizeof(AstTyped), Ast_Kind_Constraint_Sentinel);
-        sentinel->token = ip->value_token;
-        sentinel->type_node = constraint->type_args[i];
+        AstTyped *arg = constraint->args[i];
+        TYPE_CHECK(&arg, ip->type) {
+            ERROR_(arg->token->pos, "Mismatched type in interface construction. Expected something of type '%s', but got something of type '%s'.", type_get_name(ip->type), type_get_name(arg->type));
+        }
 
         AstAlias *type_alias = onyx_ast_node_new(context.ast_alloc, sizeof(AstAlias), Ast_Kind_Alias);
-        type_alias->token = ip->type_token;
-        type_alias->alias = (AstTyped *) constraint->type_args[i];
+        type_alias->token = ip->value_token;
+        type_alias->alias = arg;
+
+        symbol_introduce(constraint->scope, ip->value_token, (AstNode *) type_alias);
+    }
+
+    fori (i, 0, bh_arr_length(constraint->interface->sentinels)) {
+        InterfaceSentinel *is = &constraint->interface->sentinels[i];
 
-        symbol_introduce(constraint->scope, ip->value_token, (AstNode *) sentinel);
-        symbol_introduce(constraint->scope, ip->type_token, (AstNode *) type_alias);
+        AstTyped *sentinel = onyx_ast_node_new(context.ast_alloc, sizeof(AstTyped), Ast_Kind_Constraint_Sentinel);
+        sentinel->token = is->name;
+        sentinel->type_node = is->type;
+
+        symbol_introduce(constraint->scope, is->name, (AstNode *) sentinel);
     }
 
     assert(constraint->entity);
@@ -3858,7 +3883,11 @@ CheckStatus check_constraint_context(ConstraintContext *cc, Scope *scope, OnyxFi
                 if (cc->produce_errors) {
                     AstConstraint *constraint = cc->constraints[i];
                     char constraint_map[512] = {0};
-                    fori (i, 0, bh_arr_length(constraint->type_args)) {
+                    fori (i, 0, bh_arr_length(constraint->args)) {
+                        if (!node_is_type((AstNode *) constraint->args[i])) {
+                            continue;
+                        }
+
                         if (i != 0) strncat(constraint_map, ", ", 511);
 
                         OnyxToken* symbol = constraint->interface->params[i].value_token;
@@ -3867,7 +3896,7 @@ CheckStatus check_constraint_context(ConstraintContext *cc, Scope *scope, OnyxFi
                         token_toggle_end(symbol);
 
                         strncat(constraint_map, " is of type '", 511);
-                        strncat(constraint_map, type_get_name(type_build_from_ast(context.ast_alloc, constraint->type_args[i])), 511);
+                        strncat(constraint_map, type_get_name(type_build_from_ast(context.ast_alloc, (AstType *) constraint->args[i])), 511);
                         strncat(constraint_map, "'", 511);
                     }
 
@@ -4040,6 +4069,7 @@ void check_entity(Entity* ent) {
         case Entity_Type_Polymorph_Query:          cs = check_polyquery(ent->poly_query); break;
         case Entity_Type_Enum_Value:               cs = check_expression(&ent->enum_value->value); break;
         case Entity_Type_Process_Directive:        cs = check_process_directive((AstNode *) ent->expr); break;
+        case Entity_Type_Interface:                cs = check_interface(ent->interface); break;
 
         case Entity_Type_String_Literal:
         case Entity_Type_Expression:
index d96399383e5ac249922cc4aa87690a2caa822b82..c457bb35e7e88fb4348611526786ec958e595d26 100644 (file)
@@ -591,11 +591,11 @@ AstNode* ast_clone(bh_allocator a, void* n) {
             AstConstraint* dc = (AstConstraint *) nn;
             AstConstraint* sc = (AstConstraint *) node;
 
-            dc->type_args = NULL;
-            bh_arr_new(global_heap_allocator, dc->type_args, bh_arr_length(sc->type_args));
+            dc->args = NULL;
+            bh_arr_new(global_heap_allocator, dc->args, bh_arr_length(sc->args));
 
-            bh_arr_each(AstType *, type_arg, sc->type_args) {
-                bh_arr_push(dc->type_args, (AstType *) ast_clone(a, (AstNode *) *type_arg));
+            bh_arr_each(AstTyped *, arg, sc->args) {
+                bh_arr_push(dc->args, (AstTyped *) ast_clone(a, (AstNode *) *arg));
             }
 
             dc->phase = Constraint_Phase_Waiting_To_Be_Queued;
index 003e91c4e5d9616f76be3291fbb212b9a7fbff79..84f4539bcc99b0def7cab9dd1373da911f32f21d 100644 (file)
@@ -471,12 +471,12 @@ static void write_doc_constraints(bh_buffer *buffer, ConstraintContext *constrai
         write_type_node(&tmp_buffer, constraint->interface);
         bh_buffer_write_string(&tmp_buffer, "(");
 
-        bh_arr_each(AstType *, ptype_arg, constraint->type_args) {
-            if (ptype_arg != constraint->type_args) {
+        bh_arr_each(AstTyped *, ptype_arg, constraint->args) {
+            if (ptype_arg != constraint->args) {
                 bh_buffer_write_string(&tmp_buffer, ", ");
             }
 
-            AstType *type_arg = *ptype_arg;
+            AstTyped *type_arg = *ptype_arg;
             write_type_node(&tmp_buffer, type_arg);
         }
 
index 75739546e8c86a10807c45e725b2d34d5b134340..922003c026347e7ebda6b9fe94fa2461212f66a4 100644 (file)
@@ -3,6 +3,7 @@
 // such as procedure definitions, string literals, struct definitions
 // and declarations to be introduced into scopes.
 
+#include "astnodes.h"
 #define BH_INTERNAL_ALLOCATOR (global_heap_allocator)
 
 #include "parser.h"
@@ -2524,8 +2525,7 @@ static AstInterface* parse_interface(OnyxParser* parser) {
         InterfaceParam ip;
         ip.value_token = expect_token(parser, Token_Type_Symbol);
         expect_token(parser, ':');
-        expect_token(parser, '$');
-        ip.type_token  = expect_token(parser, Token_Type_Symbol);
+        ip.value_type  = parse_type(parser);
 
         bh_arr_push(interface->params, ip);
 
@@ -2539,6 +2539,7 @@ static AstInterface* parse_interface(OnyxParser* parser) {
     }
 
     bh_arr_new(global_heap_allocator, interface->exprs, 2);
+    bh_arr_new(global_heap_allocator, interface->sentinels, 2);
 
     type_create_scope(parser, &interface->scope, interface->token);
     parser->current_scope = interface->scope;
@@ -2558,6 +2559,18 @@ static AstInterface* parse_interface(OnyxParser* parser) {
             continue;
         }
 
+        if (next_tokens_are(parser, 2, Token_Type_Symbol, Token_Type_Keyword_As)) {
+            InterfaceSentinel sentinel;
+            sentinel.name = expect_token(parser, Token_Type_Symbol);
+            consume_token(parser);
+
+            sentinel.type = parse_type(parser);
+            bh_arr_push(interface->sentinels, sentinel);
+
+            consume_token_if_next(parser, ';');
+            continue;
+        }
+
         InterfaceConstraint ic = {0};
         if (parse_possible_directive(parser, "not")) {
             ic.invert_condition = 1;
@@ -2620,14 +2633,14 @@ static AstConstraint* parse_constraint(OnyxParser* parser) {
 
         constraint->token = constraint->interface->token;
 
-        bh_arr_new(global_heap_allocator, constraint->type_args, 2);
+        bh_arr_new(global_heap_allocator, constraint->args, 2);
 
         expect_token(parser, '(');
         while (!consume_token_if_next(parser, ')')) {
             if (parser->hit_unexpected_token) return constraint;
 
-            AstType* type_node = parse_type(parser);
-            bh_arr_push(constraint->type_args, type_node);
+            AstTyped* type_node = parse_expression(parser, 0);
+            bh_arr_push(constraint->args, type_node);
 
             if (parser->curr->type != ')')
                 expect_token(parser, ',');
index ee3742c925da7be303faf07e1375b767982dce2d..953a15d9e986ddb01bb274a8021f3cd0167ba6b3 100644 (file)
@@ -182,8 +182,8 @@ static AstSolidifiedFunction generate_solidified_function(
             constraint->interface = (AstInterface *) param->implicit_interface;
             constraint->token = constraint->interface->token;
 
-            bh_arr_new(global_heap_allocator, constraint->type_args, 1);
-            bh_arr_push(constraint->type_args, (AstType *) ast_clone(context.ast_alloc, param->poly_sym));
+            bh_arr_new(global_heap_allocator, constraint->args, 1);
+            bh_arr_push(constraint->args, (AstTyped *) ast_clone(context.ast_alloc, param->poly_sym));
 
             bh_arr_push(solidified_func.func->constraints.constraints, constraint);
         }
index d112cf0606cfcba58a0b0ad6019af75e0d58723a..c7844b5873b7fd1c4722b412eb8c5ba84963ddb8 100644 (file)
@@ -1658,14 +1658,22 @@ static SymresStatus symres_macro(AstMacro* macro) {
     return Symres_Success;
 }
 
+static SymresStatus symres_interface(AstInterface* interface) {
+    bh_arr_each(InterfaceParam, param, interface->params) {
+        SYMRES(type, &param->value_type);
+    }
+
+    return Symres_Success;
+}
+
 static SymresStatus symres_constraint(AstConstraint* constraint) {
     switch (constraint->phase) {
         case Constraint_Phase_Cloning_Expressions:
         case Constraint_Phase_Waiting_To_Be_Queued: {
             SYMRES(expression, (AstTyped **) &constraint->interface);
 
-            bh_arr_each(AstType *, type_arg, constraint->type_args) {
-                SYMRES(type, type_arg);
+            bh_arr_each(AstTyped *, arg, constraint->args) {
+                SYMRES(expression, arg);
             }
 
             return Symres_Success;
@@ -1943,6 +1951,8 @@ void symres_entity(Entity* ent) {
                                                   next_state = Entity_State_Finalized;
                                                   break;
 
+        case Entity_Type_Interface:               ss = symres_interface(ent->interface); break;
+
         case Entity_Type_Overloaded_Function:     ss = symres_overloaded_function(ent->overloaded_function); break;
         case Entity_Type_Expression:              ss = symres_expression(&ent->expr); break;
         case Entity_Type_Type_Alias:              ss = symres_type(&ent->type_alias); break;
index 4f166a45645ccd5613fb80482797bb03afc5fc23..9bc40c2e4f3ee228391a701dc1498e3fe2926f67 100644 (file)
@@ -377,7 +377,9 @@ cfree   :: (ptr: rawptr)            => raw_free(context.allocator, ptr);
     delete :: #match {}
 
     #local
-    Destroyable :: interface (t: $T) {
+    Destroyable :: interface (T: type_expr) {
+        t as T;
+
         { T.destroy(&t) } -> void;
     }
 
index c14dbefa12cf9a54472a2b799238012be0661211..0212b6e38ae85dac6c26978580decf42a74b3a66 100644 (file)
@@ -53,7 +53,8 @@ as_iter :: #match -> Iterator {}
     Helper interface to test if something can be passed to
     as_iter successfully.
 """
-Iterable :: interface (t: $T) {
+Iterable :: interface (T: type_expr) {
+    t as T;
     { as_iter(t) } -> Iterator;
 }
 
@@ -129,7 +130,9 @@ as_iter :: (x: &$T/ImplicitIterator) => {
 }
 
 #local
-ImplicitIterator :: interface (t: $T) {
+ImplicitIterator :: interface (T: type_expr) {
+    t as T;
+
     { t->iter_open() } -> void;
     t->iter_next();
     { t->iter_close() } -> void;
@@ -147,7 +150,9 @@ ImplicitIterator :: interface (t: $T) {
 as_iter :: macro (x: $T/HasAsIter) => x->as_iter();
 
 #local
-HasAsIter :: interface (t: $T) {
+HasAsIter :: interface (T: type_expr) {
+    t as T;
+
     { t->as_iter() } -> Iterator;
 }
 
index 93f11c47c09185c9b968b548e00087dd8222c636..4459fd66969d4d55572608b865c9ee33e1fb3166 100644 (file)
@@ -30,11 +30,13 @@ Map :: struct (Key_Type: type_expr, Value_Type: type_expr) where ValidKey(Key_Ty
     }
 }
 
-#local ValidKey :: interface (t: $T) {
+#local ValidKey :: interface (T: type_expr) {
     // In order to use a certain type as a key in a Map, you must
     // provide an implementation of core.hash.hash() for that type,
     // and you must provide an operator overload for ==.
 
+    t as T;
+
     { hash.hash(t) } -> u32;
     { t == t       } -> bool;
 }
index 9f02bc2d83ab8c5b790eff78aeb9b3dc55794dc4..e79402d88fc05836c43fa48a7db501eb8a289a84 100644 (file)
@@ -40,6 +40,7 @@ hash.hash :: (p: Pair($First_Type/hash.Hashable, $Second_Type/hash.Hashable)) =>
     return !(p1.first == p2.first) || !(p1.second == p2.second);
 }
 
-#local Equatable :: interface (t: $T) {
+#local Equatable :: interface (T: type_expr) {
+    t as T;
     { t == t } -> bool;
 }
index 83a4a1b0a35bce9f1fa259759d5052dd79dd2e82..9a28755fe1b61bbde9e928db36e3f206f6eae602 100644 (file)
@@ -8,7 +8,9 @@ use core.math
 
 use core {Optional}
 
-#local SetValue :: interface (t: $T) {
+#local SetValue :: interface (T: type_expr) {
+    t as T;
+
     { hash.hash(t) } -> u32;
     { t == t } -> bool;
 }
index 45c5a71229df6a3b0f586f1d6c993371a5f0616f..f0a5d09417058f79e16312d4d059dfb7a4ab0704 100644 (file)
@@ -654,7 +654,8 @@ group_by :: macro (arr_: [] $T, comp: Code, allocator := context.allocator) -> [
 
 
 
-#local HasEquals :: interface (t: $T) {
+#local HasEquals :: interface (T: type_expr) {
+    t as T;
     { t == t } -> bool;
 }
 
index 08fab5bf21179399411a30c415c5bf8c95384fca..4e08791ca006f74935b9f96e97717b1f15a4e7dd 100644 (file)
@@ -55,12 +55,14 @@ hash :: #match -> u32 {
 // Interface that holds true when the type has a hash() overload defined.
 // Useful in datastructure when the ability to hash is dependent on whether
 // the stored type is hashable. See core/container/pair.onyx for an example.
-Hashable :: interface (t: $T) {
+Hashable :: interface (T: type_expr) {
+    t as T;
     { hash(t) } -> u32;
 }
 
 #local
-HasHashMethod :: interface (t: $T) {
+HasHashMethod :: interface (T: type_expr) {
+    t as T;
     { t->hash() } -> u32;
 }
 
index 2b78c73d9fa39f9bbeeea994bbe8425394df5b30..04fd8b77c3e45b297ed847f8111d9eb7727dc0fe 100644 (file)
@@ -12,17 +12,17 @@ package core.intrinsics.types
 // Slice: [] $T
 // Function: () -> void
 
-type_is_bool     :: interface (t: $T) #intrinsic
-type_is_int      :: interface (t: $T) #intrinsic
-type_is_float    :: interface (t: $T) #intrinsic
-type_is_number   :: interface (t: $T) #intrinsic
-type_is_simd     :: interface (t: $T) #intrinsic
-type_is_pointer  :: interface (t: $T) #intrinsic
-type_is_enum     :: interface (t: $T) #intrinsic
-type_is_simple   :: interface (t: $T) #intrinsic
-type_is_array    :: interface (t: $T) #intrinsic
-type_is_slice    :: interface (t: $T) #intrinsic
-type_is_struct   :: interface (t: $T) #intrinsic
-type_is_compound :: interface (t: $T) #intrinsic
-type_is_function :: interface (t: $T) #intrinsic
+type_is_bool     :: interface (T: type_expr) #intrinsic
+type_is_int      :: interface (T: type_expr) #intrinsic
+type_is_float    :: interface (T: type_expr) #intrinsic
+type_is_number   :: interface (T: type_expr) #intrinsic
+type_is_simd     :: interface (T: type_expr) #intrinsic
+type_is_pointer  :: interface (T: type_expr) #intrinsic
+type_is_enum     :: interface (T: type_expr) #intrinsic
+type_is_simple   :: interface (T: type_expr) #intrinsic
+type_is_array    :: interface (T: type_expr) #intrinsic
+type_is_slice    :: interface (T: type_expr) #intrinsic
+type_is_struct   :: interface (T: type_expr) #intrinsic
+type_is_compound :: interface (T: type_expr) #intrinsic
+type_is_function :: interface (T: type_expr) #intrinsic
 
index 48e2fd53f9028f9bd9d554dddc7e93aec53e0546..926a8b184e5d203e5ab48a27183eeca78c862d51 100644 (file)
@@ -22,26 +22,26 @@ use runtime
 //
 
 #local {
-    __HasEqMethod     :: interface (t: $T, r: $R) { T.__eq(t, r); }
-    __HasNeMethod     :: interface (t: $T, r: $R) { T.__ne(t, r); }
-    __HasLtMethod     :: interface (t: $T, r: $R) { T.__lt(t, r); }
-    __HasLeMethod     :: interface (t: $T, r: $R) { T.__le(t, r); }
-    __HasGtMethod     :: interface (t: $T, r: $R) { T.__gt(t, r); }
-    __HasGeMethod     :: interface (t: $T, r: $R) { T.__ge(t, r); }
-    __HasAddMethod    :: interface (t: $T, r: $R) { T.__add(t, r); }
-    __HasMinusMethod  :: interface (t: $T, r: $R) { T.__minus(t, r); }
-    __HasMulMethod    :: interface (t: $T, r: $R) { T.__mul(t, r); }
-    __HasDivMethod    :: interface (t: $T, r: $R) { T.__div(t, r); }
-    __HasModMethod    :: interface (t: $T, r: $R) { T.__mod(t, r); }
-    __HasAndMethod    :: interface (t: $T, r: $R) { T.__and(t, r); }
-    __HasOrMethod     :: interface (t: $T, r: $R) { T.__or(t, r); }
-    __HasShlMethod    :: interface (t: $T, r: $R) { T.__shl(t, r); }
-    __HasShrMethod    :: interface (t: $T, r: $R) { T.__shr(t, r); }
-    __HasSarMethod    :: interface (t: $T, r: $R) { T.__sar(t, r); }
-    __HasXorMethod    :: interface (t: $T, r: $R) { T.__xor(t, r); }
-    __HasBandMethod   :: interface (t: $T, r: $R) { T.__band(t, r); }
-    __HasBorMethod    :: interface (t: $T, r: $R) { T.__bor(t, r); }
-    __HasSubMethod    :: interface (t: $T, r: $R) { T.__sub(t, r); }
+    __HasEqMethod     :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__eq(t, r); }
+    __HasNeMethod     :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__ne(t, r); }
+    __HasLtMethod     :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__lt(t, r); }
+    __HasLeMethod     :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__le(t, r); }
+    __HasGtMethod     :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__gt(t, r); }
+    __HasGeMethod     :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__ge(t, r); }
+    __HasAddMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__add(t, r); }
+    __HasMinusMethod  :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__minus(t, r); }
+    __HasMulMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__mul(t, r); }
+    __HasDivMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__div(t, r); }
+    __HasModMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__mod(t, r); }
+    __HasAndMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__and(t, r); }
+    __HasOrMethod     :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__or(t, r); }
+    __HasShlMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__shl(t, r); }
+    __HasShrMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__shr(t, r); }
+    __HasSarMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__sar(t, r); }
+    __HasXorMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__xor(t, r); }
+    __HasBandMethod   :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__band(t, r); }
+    __HasBorMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__bor(t, r); }
+    __HasSubMethod    :: interface (T: type_expr, R: type_expr) { t as T; r as R; T.__sub(t, r); }
 }
 
 #if #defined(runtime.vars.Onyx_Enable_Operator_Methods) {
index 86cca236151ccaec4b073312f189bae9e0aa2f9c..034a4aa2a0d7447a93b24f4188ac35e149be999e 100644 (file)
@@ -5,7 +5,9 @@ use core {package, *}
 #doc "Generic procedure for turning something into a string."
 as_str :: #match -> str {}
 
-#local HasAsStrMethod :: interface (t: $T) {
+#local HasAsStrMethod :: interface (T: type_expr) {
+    t as T;
+
     { T.as_str(t) } -> str;
 }
 
index da875cd5271589fd2646fce83bc5968386923614..ca83830bdd70be256738c0f308811cd8fe090043 100644 (file)
@@ -32,7 +32,9 @@ add_example :: () {
     // expressions do not type check correctly, then the set of parameters does not
     // satisfy the interface.
 
-    CanAdd :: interface (t: $T) {
+    CanAdd :: interface (T: type_expr) {
+        t as T;
+
         t + t;
     }
 
@@ -59,7 +61,9 @@ add_example :: () {
 
 // These have to be defined out here because #operator and #match are only allowed
 // as top level expressions currently.
-NumberLike :: interface (t: $T) {
+NumberLike :: interface (T: type_expr) {
+    t as T;
+
     // The constraints here are a little stricter than before. This syntax
     // allows you to specify the expected type of the expression. If the type
     // of the expression and the type after the arrow do not match, then the
@@ -101,7 +105,9 @@ overloaded_procedure_example :: () {
     // when the are combined with overloaded procedures.
 
     // Take this example. Here is the same CanAdd interface from before.
-    CanAdd :: interface (t: $T) {
+    CanAdd :: interface (T: type_expr) {
+        t as T;
+
         t + t;
     }
 
index a859448bfa2fd852c8bdf7f5edd98010654c3119..575060dc2161acbd275f39f3c94364a0be5c2b57 100644 (file)
@@ -2,7 +2,8 @@
 
 use core {package, *}
 
-OverloadsEqual :: interface (t: $T) {
+OverloadsEqual :: interface (T: type_expr) {
+    t as T;
     { T.equals(t, t) } -> bool;
 }
 
index 9267d08316c15fe1372561e3e146237a5f51f3ff..979f2785685108d64ad38f25323ac1191e35f9a3 100644 (file)
@@ -254,7 +254,7 @@ main :: (args: [] cstr) {
     // allocating memory that isn't technically free, but there
     // should be more than enough space in the allocator to not
     // run into that problem... Hopefully.
-    tile_data_ring := alloc.ring.make(tile_data);
+    tile_data_ring := alloc.ring.make(.{ ~~tile_data.data, 200 * sizeof TileData });
     tile_allocator := alloc.ring.make_allocator(&tile_data_ring);
 
     while !string.empty(file) {
index e3ad63177f35f2ef0ebb2aaa52c2e72391d1c945..8956121dae32deb0a4878cc768da36778954954c 100644 (file)
@@ -111,7 +111,9 @@ Player :: struct {
 }
 
 
-#local __HasEqMethod :: interface (t: $T) {
+#local __HasEqMethod :: interface (T: type_expr) {
+    t as T;
+
     { T.__eq(t, t) } -> bool;
 }
 
index 80162f03b4625c3644fbe25edcf8ae1dd636afcc..db0833fc0a1cefed8029696f1a80d879dbb3d856 100644 (file)
@@ -14,7 +14,9 @@ main :: (args: [] cstr) {
         return g(f(a));
     }
 
-    Number :: interface (t: $T) {
+    Number :: interface (T: type_expr) {
+        t as T;
+
         { t * t } -> T;
     }
 
index b63bfb334f63d24e465b89447fd25d41ab24070b..eeec1c166e122b6d43439109dcf36509569b1c92 100644 (file)
@@ -1,6 +1,8 @@
 use core {*}
 
-Speak :: interface (t: $T) {
+Speak :: interface (T: type_expr) {
+    t as T;
+
     { speak(t, str.{}) } -> void;
     { yell(t, str.{}) } -> void;
 
@@ -51,4 +53,4 @@ main :: () {
 
     speak_things(dog);
     speak_things(cat);
-}
\ No newline at end of file
+}
index af3069feda358b95ed8fc79be42da55b6e02397f..beece68b4925731083e94c4b779cff3666ad4c19 100644 (file)
@@ -11,3 +11,4 @@ false
 true
 false
 true
+[ 1, 2, 3, 4, 5 ]
index dcec9b542b10e1d580c3e6e56d6c0957b8aed363..cd3f236ec2fcf49f8e12f12959b98553491a8542 100644 (file)
@@ -8,7 +8,9 @@ use core.iter
 
 use core {println, printf}
 
-Hashable :: interface (t :$T) {
+Hashable :: interface (T: type_expr) {
+    t as T;
+
     { hash.to_u32(t) } -> u32;
 }
 
@@ -16,13 +18,14 @@ try_hash :: #match {
     macro (x: $T) where Hashable(T) {
         println(hash.to_u32(x));
     },
-
     (x: any) {
         printf("{} is not hashable!\n", x.type);
     },
 }
 
-CanCastTo :: interface (t: $T, d: $D) {
+CanCastTo :: interface (T: type_expr, D: type_expr) {
+    t as T;
+
     { cast(D) t } -> D;
 }
 
@@ -43,7 +46,9 @@ do_math :: macro (x, y: $T) -> T where SemiRing(T) {
     return x + y + x * y;
 }
 
-SemiRing :: interface (t: $T) {
+SemiRing :: interface (T: type_expr) {
+    t as T;
+
     {t + t} -> T;
     {t * t} -> T;
 }
@@ -52,7 +57,9 @@ bit_math :: (x, y: $T) -> T where BitField(T) {
     return (x & y) | (x ^ y);
 }
 
-BitField :: interface (t: $T) {
+BitField :: interface (T: type_expr) {
+    t as T;
+
     { ~t } -> T;
     { t & t } -> T;
     { t | t } -> T;
@@ -99,6 +106,25 @@ consume :: macro (x: $T/iter.Iterable) => {
     return consume_inner(iterator);
 }
 
+
+ReturnsArray :: interface (T: type_expr, N: i32) {
+    t as T;
+
+    { t->make_an_array() } -> [N] i32;
+}
+
+MakeArray :: struct {
+    member: i32;
+
+    make_an_array :: (self: &MakeArray) -> [5] i32 {
+        return .[ 1, 2, 3, 4, 5 ];
+    }
+}
+
+run_make_array :: (x: $T) where ReturnsArray(T, 5) {
+    x->make_an_array() |> println();
+}
+
 main :: (args: [] cstr) {
     try_hash("This is a test");
     try_hash(context);
@@ -124,4 +150,6 @@ main :: (args: [] cstr) {
 
     b: [10] i32;
     println(cast_able(b, [] i32));
+
+    run_make_array(&MakeArray.{});
 }
index 2d8f56c929e4ab8d6675e81fa1da3adb76d50e46..dd4aa8c8f89562ec281b864f3612802ad493ed82 100644 (file)
@@ -12,8 +12,10 @@ main :: () {
    d.values = c;
 }
 
-Adder :: interface(t: $T) {
-   { t + t } -> T;
+Adder :: interface(T: type_expr) {
+    t as T;
+
+    { t + t } -> T;
 }
 
 add :: (a, b: [$N]$T) -> [N]T
@@ -22,8 +24,10 @@ add :: (a, b: [$N]$T) -> [N]T
    return a + b;
 }
 
-CanBeIndexed :: interface(t: $T) {
-   t[0];
+CanBeIndexed :: interface(T: type_expr) {
+    t as T;
+
+    t[0];
 }
 
 Foo :: struct (T: type_expr) where CanBeIndexed(T) {