added test cases
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 29 Nov 2021 18:21:43 +0000 (12:21 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 29 Nov 2021 18:21:43 +0000 (12:21 -0600)
include/astnodes.h
src/checker.c
src/clone.c
src/symres.c
tests/caller_location [new file with mode: 0644]
tests/caller_location.onyx [new file with mode: 0644]
tests/interfaces [new file with mode: 0644]
tests/interfaces.onyx [new file with mode: 0644]

index bc948eb6812a353b84bc73b8194ee372d011f45a..d0ad9662236d315edfb9219c43d014adeb1fe32c 100644 (file)
@@ -1027,10 +1027,10 @@ struct AstInterface {
 };
 
 typedef enum ConstraintPhase {
-    Constraint_Phase_Waiting_To_Be_Queued,
-    Constraint_Phase_Cloning_Expressions,
-    Constraint_Phase_Checking_Expressions,
-    Constraint_Phase_Finished,
+    Constraint_Phase_Waiting_To_Be_Queued = 0,
+    Constraint_Phase_Cloning_Expressions  = 1,
+    Constraint_Phase_Checking_Expressions = 2,
+    Constraint_Phase_Finished             = 3,
 } ConstraintPhase;
 
 struct AstConstraint {
index d13312e500fc45f6346699c4bd63235dcac56fd0..6d9c94cdf3fd3a1cc0023e6e4ddaf2f9b54aa4f6 100644 (file)
@@ -2467,7 +2467,9 @@ CheckStatus check_constraint(AstConstraint *constraint) {
         case Constraint_Phase_Cloning_Expressions: {
             if (constraint->interface->kind != Ast_Kind_Interface) {
                 // CLEANUP: This error message might not look totally right in some cases.
-                ERROR_(constraint->token->pos, "'%b' is not an interface.", constraint->token->text, constraint->token->length);
+                ERROR_(constraint->token->pos, "'%b' is not an interface. It is a '%s'.",
+                    constraint->token->text, constraint->token->length,
+                    onyx_ast_node_kind_string(constraint->interface->kind));
             }
 
             bh_arr_new(global_heap_allocator, constraint->exprs, bh_arr_length(constraint->interface->exprs));
index b1411deb27fa29f75a81d830696c5c7cb6639210..e2b577d1ccc391241eec186008b732236e057571 100644 (file)
@@ -447,6 +447,7 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                 bh_arr_push(dc->type_args, (AstType *) ast_clone(a, (AstNode *) *type_arg));
             }
 
+            dc->phase = Constraint_Phase_Waiting_To_Be_Queued;
             break;
         }
 
index 3fddd70f895b0d535d6b6e49155738e3766a0efe..55f22e35f4c38e20476b6c5e8a5e8f1612c51084 100644 (file)
@@ -125,7 +125,6 @@ static SymresStatus symres_struct_type(AstStructType* s_node) {
         }
     }
 
-struct_symres_done:
     if (s_node->scope) scope_leave();
     return Symres_Success;
 }
diff --git a/tests/caller_location b/tests/caller_location
new file mode 100644 (file)
index 0000000..8d59fc3
--- /dev/null
@@ -0,0 +1,6 @@
+Hello
+I was called from caller_location.onyx:12:19
+1234.0000
+I was called from caller_location.onyx:13:19
+1234
+I was called from caller_location.onyx:24:23
diff --git a/tests/caller_location.onyx b/tests/caller_location.onyx
new file mode 100644 (file)
index 0000000..9e4a073
--- /dev/null
@@ -0,0 +1,26 @@
+#load "core/std"
+
+use package core
+
+using_callsite :: (value: $T, site := #callsite) {
+    println(value);
+    path := string.split(site.file, #char "/");
+    printf("I was called from {}:{}:{}\n", path[path.count - 1], site.line, site.column);
+}
+
+main :: (args: [] cstr) {
+    using_callsite("Hello");
+    using_callsite(1234.0f);
+
+    something := Something.{};
+    something->method();
+}
+
+
+Something :: struct {
+    member := cast(u32) 1234;
+
+    method :: (use s: ^Something) {
+        using_callsite(member);
+    }
+}
\ No newline at end of file
diff --git a/tests/interfaces b/tests/interfaces
new file mode 100644 (file)
index 0000000..4526d7c
--- /dev/null
@@ -0,0 +1,10 @@
+-1500840774
+OnyxContext is not hashable!
+Allocator is not hashable!
+19
+-460.00 + 1060.00i
+7
+[ 4.0000, 2.0000, 4.0000, 7.0000, 4.0000 ]
+[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
+true
+false
diff --git a/tests/interfaces.onyx b/tests/interfaces.onyx
new file mode 100644 (file)
index 0000000..9ba92e0
--- /dev/null
@@ -0,0 +1,111 @@
+#load "core/std"
+
+use package core
+
+Hashable :: interface (T: type_expr) {
+    hash.to_u32(T);
+}
+
+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: type_expr, D: type_expr) {
+    cast(typeof D) T;
+}
+
+// I don't know why this doesn't work... It is complaining that it couldn't match
+// either of these cases, but if I remove the first, it matches the second. This
+// is clearly wrong behavior, but I don't immediately see where the problem is.
+// cast_able :: #match {
+//     (_: $T, $D: type_expr) -> bool where CanCastTo(T, D) do return true; ,
+//     (_: any, d: type_expr) -> bool { return false; },
+// }
+
+cast_able_to_int :: #match {
+    macro (_: $T)  -> bool where CanCastTo(T, i32) { return true; },
+    macro (_: any) -> bool { return false; },
+}
+
+do_math :: macro (x, y: $T) -> T where SemiRing(T) {
+    return x + y + x * y;
+}
+
+SemiRing :: interface (T: type_expr) {
+    T + T;
+    T * T;
+}
+
+bit_math :: (x, y: $T) -> T where BitField(T) {
+    return (x & y) | (x ^ y);
+}
+
+BitField :: interface (T: type_expr) {
+    ~T;
+    T & T;
+    T | T;
+    T ^ T;
+}
+
+Complex :: struct { x, y: f32; }
+#match io.write (w: ^io.Writer, c: Complex) {
+    io.write_format(w, "{.2} + {.2}i", c.x, c.y);
+}
+
+#operator + (c1, c2: Complex) => Complex.{ c1.x + c2.x, c1.y + c2.y };
+#operator * (c1, c2: Complex) => Complex.{ c1.x * c2.x - c1.y * c2.y, c1.x * c2.y + c1.y * c2.x };
+
+consume :: macro (x: $T) -> #auto where iter.Iterable(T) {
+    // This is a weird limitation of the Onyx type system.
+    // In order to be able tell what the iterator produces, you
+    // have to pattern match it in a procedure parameter. This means
+    // that you have to declare an internal macro that pattern
+    // matches the variable out. Also, you need to use #auto as the
+    // return type otherwise you can't say the correct type.
+    // I can't think of a better way of doing this without making
+    // everything WAY more complicated.
+    consume_inner :: #match {
+        // Iterator over pointers get dereferenced
+        macro (iter: Iterator(^$T)) -> [..] T {
+            arr := array.make(T);
+            for it: iter do arr << *it;
+            return arr;
+        },
+
+        macro (iter: Iterator($T)) -> [..] T {
+            arr := array.make(T);
+            for it: iter do arr << it;
+            return arr;
+        },
+    }
+
+    iterator := iter.as_iterator(x);
+    return consume_inner(iterator);
+}
+
+main :: (args: [] cstr) {
+    try_hash("This is a test");
+    try_hash(context);
+    try_hash(context.allocator);
+
+    printf("{p}\n", do_math(3, 4));
+    println(do_math(Complex.{ 10, 20 }, .{ 30, 40 }));
+
+    println(bit_math(3, 5));
+    // println(bit_math(3.0, 4.0));
+
+    a := consume(f32.[4,2,4,7,4]);
+    defer array.free(^a);
+    println(a);
+
+    consume(1 .. 10) |> println();
+
+    println(cast_able_to_int(12.34));
+    println(cast_able_to_int("test"));
+}