From 21d8a8b6daae586ff695382cd9d27df75f358f47 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 1 Jul 2023 23:58:00 +0200 Subject: [PATCH] Fix #809 missing checks on generic types, accepting both types where constants should be and vice versa. --- lib/std/collections/enummap.c3 | 18 +- lib/std/collections/enumset.c3 | 76 ++--- lib/std/collections/linkedlist.c3 | 226 +++++++------- lib/std/collections/list.c3 | 278 +++++++++--------- src/compiler/sema_decls.c | 12 + src/utils/lib.h | 1 + src/utils/stringutils.c | 12 + src/version.h | 2 +- .../generic/incorrect_argument_type.c3 | 11 + 9 files changed, 329 insertions(+), 307 deletions(-) create mode 100644 test/test_suite/generic/incorrect_argument_type.c3 diff --git a/lib/std/collections/enummap.c3 b/lib/std/collections/enummap.c3 index b6adf1c40..ce980fc02 100644 --- a/lib/std/collections/enummap.c3 +++ b/lib/std/collections/enummap.c3 @@ -5,19 +5,19 @@ struct EnumMap ValueType[Enum.len] values; } -fn void EnumMap.init(EnumMap* this, ValueType init_value) +fn void EnumMap.init(&self, ValueType init_value) { - foreach(&a : this.values) + foreach(&a : self.values) { *a = init_value; } } -fn void! EnumMap.to_format(EnumMap* map, Formatter* formatter) @dynamic +fn void! EnumMap.to_format(&self, Formatter* formatter) @dynamic { formatter.print("{ ")!; - foreach (i, &value : map.values) + foreach (i, &value : self.values) { if (i != 0) formatter.print(", ")!; formatter.printf("%s: %s", (Enum)i, *value)!; @@ -25,11 +25,11 @@ fn void! EnumMap.to_format(EnumMap* map, Formatter* formatter) @dynamic formatter.print(" }")!; } -fn String EnumMap.to_string(EnumMap* map, Allocator* using = mem::heap()) @dynamic +fn String EnumMap.to_string(&self, Allocator* using = mem::heap()) @dynamic { - return string::printf("%s", *map); + return string::printf("%s", *self); } -fn uint EnumMap.len(EnumMap* this) @operator(len) => this.values.len; -fn ValueType EnumMap.get(EnumMap* this, Enum key) @operator([]) => this.values[key.ordinal]; -fn void EnumMap.set(EnumMap* this, Enum key, ValueType value) @operator([]=) => this.values[key.ordinal] = value; +fn uint EnumMap.len(&self) @operator(len) => self.values.len; +fn ValueType EnumMap.get(&self, Enum key) @operator([]) => self.values[key.ordinal]; +fn void EnumMap.set(&self, Enum key, ValueType value) @operator([]=) => self.values[key.ordinal] = value; diff --git a/lib/std/collections/enumset.c3 b/lib/std/collections/enumset.c3 index 9b3ee5730..81e4db5ca 100644 --- a/lib/std/collections/enumset.c3 +++ b/lib/std/collections/enumset.c3 @@ -1,5 +1,5 @@ // Copyright (c) 2021 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by the MIT license +// Use of self source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. /** @@ -12,120 +12,120 @@ def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @pri const IS_CHAR_ARRAY = Enum.elements > 128; def EnumSet = distinct EnumSetType; -fn void EnumSet.add(EnumSet* this, Enum v) +fn void EnumSet.add(&self, Enum v) { $if IS_CHAR_ARRAY: - (*this)[(usz)v / 8] |= (char)(1u << ((usz)v % 8)); + (*self)[(usz)v / 8] |= (char)(1u << ((usz)v % 8)); $else - *this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v); + *self = (EnumSet)((EnumSetType)*self | 1u << (EnumSetType)v); $endif } -fn void EnumSet.clear(EnumSet* this) +fn void EnumSet.clear(&self) { $if IS_CHAR_ARRAY: - *this = {}; + *self = {}; $else - *this = 0; + *self = 0; $endif } -fn bool EnumSet.remove(EnumSet* this, Enum v) +fn bool EnumSet.remove(&self, Enum v) { $if IS_CHAR_ARRAY: - if (!this.has(v) @inline) return false; - (*this)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8)); + if (!self.has(v) @inline) return false; + (*self)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8)); return true; $else - EnumSetType old = (EnumSetType)*this; + EnumSetType old = (EnumSetType)*self; EnumSetType new = old & ~(1u << (EnumSetType)v); - *this = (EnumSet)new; + *self = (EnumSet)new; return old != new; $endif } -fn bool EnumSet.has(EnumSet* this, Enum v) +fn bool EnumSet.has(&self, Enum v) { $if IS_CHAR_ARRAY: - return (bool)(((*this)[(usz)v / 8] << ((usz)v % 8)) & 0x01); + return (bool)(((*self)[(usz)v / 8] << ((usz)v % 8)) & 0x01); $else - return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0; + return ((EnumSetType)*self & (1u << (EnumSetType)v)) != 0; $endif } -fn void EnumSet.add_all(EnumSet* this, EnumSet s) +fn void EnumSet.add_all(&self, EnumSet s) { $if IS_CHAR_ARRAY: - foreach (i, c : s) (*this)[i] |= c; + foreach (i, c : s) (*self)[i] |= c; $else - *this = (EnumSet)((EnumSetType)*this | (EnumSetType)s); + *self = (EnumSet)((EnumSetType)*self | (EnumSetType)s); $endif } -fn void EnumSet.retain_all(EnumSet* this, EnumSet s) +fn void EnumSet.retain_all(&self, EnumSet s) { $if IS_CHAR_ARRAY: - foreach (i, c : s) (*this)[i] &= c; + foreach (i, c : s) (*self)[i] &= c; $else - *this = (EnumSet)((EnumSetType)*this & (EnumSetType)s); + *self = (EnumSet)((EnumSetType)*self & (EnumSetType)s); $endif } -fn void EnumSet.remove_all(EnumSet* this, EnumSet s) +fn void EnumSet.remove_all(&self, EnumSet s) { $if IS_CHAR_ARRAY: - foreach (i, c : s) (*this)[i] &= ~c; + foreach (i, c : s) (*self)[i] &= ~c; $else - *this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s); + *self = (EnumSet)((EnumSetType)*self & ~(EnumSetType)s); $endif } -fn EnumSet EnumSet.and_of(EnumSet* this, EnumSet s) +fn EnumSet EnumSet.and_of(&self, EnumSet s) { $if IS_CHAR_ARRAY: - EnumSet copy = *this; + EnumSet copy = *self; copy.retain_all(s); return copy; $else - return (EnumSet)((EnumSetType)*this & (EnumSetType)s); + return (EnumSet)((EnumSetType)*self & (EnumSetType)s); $endif } -fn EnumSet EnumSet.or_of(EnumSet* this, EnumSet s) +fn EnumSet EnumSet.or_of(&self, EnumSet s) { $if IS_CHAR_ARRAY: - EnumSet copy = *this; + EnumSet copy = *self; copy.add_all(s); return copy; $else - return (EnumSet)((EnumSetType)*this | (EnumSetType)s); + return (EnumSet)((EnumSetType)*self | (EnumSetType)s); $endif } -fn EnumSet EnumSet.diff_of(EnumSet* this, EnumSet s) +fn EnumSet EnumSet.diff_of(&self, EnumSet s) { $if IS_CHAR_ARRAY: - EnumSet copy = *this; + EnumSet copy = *self; copy.remove_all(s); return copy; $else - return (EnumSet)((EnumSetType)*this & ~(EnumSetType)s); + return (EnumSet)((EnumSetType)*self & ~(EnumSetType)s); $endif } -fn EnumSet EnumSet.xor_of(EnumSet* this, EnumSet s) +fn EnumSet EnumSet.xor_of(&self, EnumSet s) { $if IS_CHAR_ARRAY: - EnumSet copy = *this; + EnumSet copy = *self; foreach (i, c : s) copy[i] ^= c; return copy; $else - return (EnumSet)((EnumSetType)*this ^ (EnumSetType)s); + return (EnumSet)((EnumSetType)*self ^ (EnumSetType)s); $endif } -fn void! EnumSet.to_format(EnumSet* set, Formatter* formatter) @dynamic +fn void! EnumSet.to_format(&set, Formatter* formatter) @dynamic { formatter.print("[")!; bool found = false; @@ -139,7 +139,7 @@ fn void! EnumSet.to_format(EnumSet* set, Formatter* formatter) @dynamic formatter.print("]")!; } -fn String EnumSet.to_string(EnumSet* set, Allocator* using = mem::heap()) @dynamic +fn String EnumSet.to_string(&set, Allocator* using = mem::heap()) @dynamic { return string::printf("%s", *set); } diff --git a/lib/std/collections/linkedlist.c3 b/lib/std/collections/linkedlist.c3 index 85b1ffd15..e7bec6878 100644 --- a/lib/std/collections/linkedlist.c3 +++ b/lib/std/collections/linkedlist.c3 @@ -1,5 +1,5 @@ // Copyright (c) 2021 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by the MIT license +// 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; @@ -18,161 +18,161 @@ struct LinkedList Node *_last; } -fn void LinkedList.push(LinkedList* list, Type value) +fn void LinkedList.push(&self, Type value) { - list.link_first(value); + self.link_first(value); } -fn void LinkedList.push_last(LinkedList* list, Type value) +fn void LinkedList.push_last(&self, Type value) { - list.link_last(value); + self.link_last(value); } -fn void LinkedList.init(LinkedList* list, Allocator* using = mem::heap()) +fn void LinkedList.init(&self, Allocator* using = mem::heap()) { - *list = { .allocator = using }; + *self = { .allocator = using }; } -fn void LinkedList.tinit(LinkedList* list) => list.init(mem::temp()) @inline; +fn void LinkedList.tinit(&self) => self.init(mem::temp()) @inline; /** - * @require list.allocator + * @require self.allocator **/ -macro void LinkedList.@free_node(LinkedList &list, Node* node) @private +macro void LinkedList.free_node(&self, Node* node) @private { - list.allocator.free(node)!!; + self.allocator.free(node)!!; } -macro Node* LinkedList.@alloc_node(LinkedList &list) @private +macro Node* LinkedList.alloc_node(&self) @private { - if (!list.allocator) list.allocator = mem::heap(); - return malloc(Node, .using = list.allocator); + if (!self.allocator) self.allocator = mem::heap(); + return malloc(Node, .using = self.allocator); } -fn void LinkedList.link_first(LinkedList* list, Type value) @private +fn void LinkedList.link_first(&self, Type value) @private { - Node *first = list._first; - Node *new_node = list.@alloc_node(); + Node *first = self._first; + Node *new_node = self.alloc_node(); *new_node = { .next = first, .value = value }; - list._first = new_node; + self._first = new_node; if (!first) { - list._last = new_node; + self._last = new_node; } else { first.prev = new_node; } - list.size++; + self.size++; } -fn void LinkedList.link_last(LinkedList* list, Type value) @private +fn void LinkedList.link_last(&self, Type value) @private { - Node *last = list._last; - Node *new_node = list.@alloc_node(); + Node *last = self._last; + Node *new_node = self.alloc_node(); *new_node = { .prev = last, .value = value }; - list._last = new_node; + self._last = new_node; if (!last) { - list._first = new_node; + self._first = new_node; } else { last.next = new_node; } - list.size++; + self.size++; } -fn Type! LinkedList.peek(LinkedList* list) => list.first() @inline; -fn Type! LinkedList.peek_last(LinkedList* list) => list.last() @inline; +fn Type! LinkedList.peek(&self) => self.first() @inline; +fn Type! LinkedList.peek_last(&self) => self.last() @inline; -fn Type! LinkedList.first(LinkedList *list) +fn Type! LinkedList.first(&self) { - if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; - return list._first.value; + if (!self._first) return IteratorResult.NO_MORE_ELEMENT?; + return self._first.value; } -fn Type! LinkedList.last(LinkedList* list) +fn Type! LinkedList.last(&self) { - if (!list._last) return IteratorResult.NO_MORE_ELEMENT?; - return list._last.value; + if (!self._last) return IteratorResult.NO_MORE_ELEMENT?; + return self._last.value; } -fn void LinkedList.free(LinkedList* list) => list.clear() @inline; +fn void LinkedList.free(&self) => self.clear() @inline; -fn void LinkedList.clear(LinkedList* list) +fn void LinkedList.clear(&self) { - for (Node* node = list._first; node != null;) + for (Node* node = self._first; node != null;) { Node* next = node.next; - list.@free_node(node); + self.free_node(node); node = next; } - list._first = null; - list._last = null; - list.size = 0; + self._first = null; + self._last = null; + self.size = 0; } -fn usz LinkedList.len(LinkedList* list) @inline => list.size; +fn usz LinkedList.len(&self) @inline => self.size; /** - * @require index < list.size + * @require index < self.size **/ -macro Node* LinkedList.node_at_index(LinkedList* list, usz index) +macro Node* LinkedList.node_at_index(&self, usz index) { - if (index * 2 >= list.size) + if (index * 2 >= self.size) { - Node* node = list._last; - index = list.size - index - 1; + Node* node = self._last; + index = self.size - index - 1; while (index--) node = node.prev; return node; } - Node* node = list._first; + Node* node = self._first; while (index--) node = node.next; return node; } /** - * @require index < list.size + * @require index < self.size **/ -fn Type LinkedList.get(LinkedList* list, usz index) +fn Type LinkedList.get(&self, usz index) { - return list.node_at_index(index).value; + return self.node_at_index(index).value; } /** - * @require index < list.size + * @require index < self.size **/ -fn void LinkedList.set(LinkedList* list, usz index, Type element) +fn void LinkedList.set(&self, usz index, Type element) { - list.node_at_index(index).value = element; + self.node_at_index(index).value = element; } /** - * @require index < list.size + * @require index < self.size **/ -fn void LinkedList.remove(LinkedList* list, usz index) +fn void LinkedList.remove(&self, usz index) { - list.unlink(list.node_at_index(index)); + self.unlink(self.node_at_index(index)); } /** - * @require index <= list.size + * @require index <= self.size **/ -fn void LinkedList.insert(LinkedList* list, usz index, Type element) +fn void LinkedList.insert(&self, usz index, Type element) { switch (index) { case 0: - list.push(element); - case list.size: - list.push_last(element); + self.push(element); + case self.size: + self.push_last(element); default: - list.link_before(list.node_at_index(index), element); + self.link_before(self.node_at_index(index), element); } } /** * @require succ != null **/ -fn void LinkedList.link_before(LinkedList *list, Node *succ, Type value) @private +fn void LinkedList.link_before(&self, Node *succ, Type value) @private { Node* pred = succ.prev; Node* new_node = malloc(Node); @@ -180,120 +180,110 @@ fn void LinkedList.link_before(LinkedList *list, Node *succ, Type value) @privat succ.prev = new_node; if (!pred) { - list._first = new_node; + self._first = new_node; } else { pred.next = new_node; } - list.size++; + self.size++; } /** - * @require list && list._first + * @require self._first **/ -fn void LinkedList.unlink_first(LinkedList* list) @private +fn void LinkedList.unlink_first(&self) @private { - Node* f = list._first; + Node* f = self._first; Node* next = f.next; - list.@free_node(f); - list._first = next; + self.free_node(f); + self._first = next; if (!next) { - list._last = null; + self._last = null; } else { next.prev = null; } - list.size--; + self.size--; } -fn bool LinkedList.remove_value(LinkedList* list, Type t) +fn bool LinkedList.remove_value(&self, Type t) { - for (Node* node = list._first; node != null; node = node.next) + for (Node* node = self._first; node != null; node = node.next) { if (node.value == t) { - list.unlink(node); + self.unlink(node); return true; } } return false; } -fn bool LinkedList.remove_last_value(LinkedList* list, Type t) +fn bool LinkedList.remove_last_value(&self, Type t) { - for (Node* node = list._last; node != null; node = node.prev) + for (Node* node = self._last; node != null; node = node.prev) { if (node.value == t) { - list.unlink(node); + self.unlink(node); return true; } } return false; } -/** - * @param [&inout] list - **/ -fn Type! LinkedList.pop(LinkedList* list) +fn Type! LinkedList.pop(&self) { - if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; - defer list.unlink_first(); - return list._first.value; + if (!self._first) return IteratorResult.NO_MORE_ELEMENT?; + defer self.unlink_first(); + return self._first.value; +} + +fn void! LinkedList.remove_last(&self) +{ + if (!self._first) return IteratorResult.NO_MORE_ELEMENT?; + self.unlink_last(); +} + +fn void! LinkedList.remove_first(&self) +{ + if (!self._first) return IteratorResult.NO_MORE_ELEMENT?; + self.unlink_first(); } /** - * @param [&inout] list + * @require self._last **/ -fn void! LinkedList.remove_last(LinkedList* list) +fn void LinkedList.unlink_last(&self) @inline @private { - if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; - list.unlink_last(); -} - -/** - * @param [&inout] list - **/ -fn void! LinkedList.remove_first(LinkedList* list) -{ - if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; - list.unlink_first(); -} - -/** - * @param [&inout] list - * @require list._last - **/ -fn void LinkedList.unlink_last(LinkedList *list) @inline @private -{ - Node* l = list._last; + Node* l = self._last; Node* prev = l.prev; - list._last = prev; - list.@free_node(l); + self._last = prev; + self.free_node(l); if (!prev) { - list._first = null; + self._first = null; } else { prev.next = null; } - list.size--; + self.size--; } /** - * @require list != null, x != null + * @require x != null **/ -fn void LinkedList.unlink(LinkedList* list, Node* x) @private +fn void LinkedList.unlink(&self, Node* x) @private { Node* next = x.next; Node* prev = x.prev; if (!prev) { - list._first = next; + self._first = next; } else { @@ -301,12 +291,12 @@ fn void LinkedList.unlink(LinkedList* list, Node* x) @private } if (!next) { - list._last = prev; + self._last = prev; } else { next.prev = prev; } - list.@free_node(x); - list.size--; + self.free_node(x); + self.size--; } diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index ba01f884c..ac5332561 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -1,5 +1,5 @@ // Copyright (c) 2021 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by the MIT license +// 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; import std::math; @@ -19,38 +19,38 @@ struct List /** * @require using != null "A valid allocator must be provided" **/ -fn void List.init(List* list, usz initial_capacity = 16, Allocator* using = mem::heap()) +fn void List.init(&self, usz initial_capacity = 16, Allocator* using = mem::heap()) { - list.allocator = using; - list.size = 0; + self.allocator = using; + self.size = 0; if (initial_capacity > 0) { initial_capacity = math::next_power_of_2(initial_capacity); - list.entries = malloc_aligned(Type, initial_capacity, .alignment = Type[1].alignof, .using = using)!!; + self.entries = malloc_aligned(Type, initial_capacity, .alignment = Type[1].alignof, .using = using)!!; } else { - list.entries = null; + self.entries = null; } - list.capacity = initial_capacity; + self.capacity = initial_capacity; } -fn void List.tinit(List* list, usz initial_capacity = 16) +fn void List.tinit(&self, usz initial_capacity = 16) { - list.init(initial_capacity, mem::temp()) @inline; + self.init(initial_capacity, mem::temp()) @inline; } -fn void! List.to_format(List* list, Formatter* formatter) @dynamic +fn void! List.to_format(&self, Formatter* formatter) @dynamic { - switch (list.size) + switch (self.size) { case 0: formatter.print("[]")!; case 1: - formatter.printf("[%s]", list.entries[0])!; + formatter.printf("[%s]", self.entries[0])!; default: formatter.print("[")!; - foreach (i, element : list.entries[:list.size]) + foreach (i, element : self.entries[:self.size]) { if (i != 0) formatter.print(", ")!; formatter.printf("%s", element)!; @@ -59,277 +59,273 @@ fn void! List.to_format(List* list, Formatter* formatter) @dynamic } } -fn String List.to_string(List* list, Allocator* using = mem::heap()) @dynamic +fn String List.to_string(&self, Allocator* using = mem::heap()) @dynamic { - return string::printf("%s", *list); + return string::printf("%s", *self); } -fn void List.push(List* list, Type element) @inline +fn void List.push(&self, Type element) @inline { - list.append(element); + self.append(element); } -fn void List.append(List* list, Type element) +fn void List.append(&self, Type element) { - list.ensure_capacity(); - list.entries[list.size++] = element; + self.ensure_capacity(); + self.entries[self.size++] = element; } /** - * @require list.size > 0 + * @require self.size > 0 */ -fn Type List.pop(List* list) +fn Type List.pop(&self) { - return list.entries[--list.size]; + return self.entries[--self.size]; } -fn void List.clear(List* list) +fn void List.clear(&self) { - list.size = 0; + self.size = 0; } /** - * @require list.size > 0 + * @require self.size > 0 */ -fn Type List.pop_first(List* list) +fn Type List.pop_first(&self) { - Type value = list.entries[0]; - list.remove_at(0); + Type value = self.entries[0]; + self.remove_at(0); return value; } -fn void List.remove_at(List* list, usz index) +fn void List.remove_at(&self, usz index) { - for (usz i = index + 1; i < list.size; i++) + for (usz i = index + 1; i < self.size; i++) { - list.entries[i - 1] = list.entries[i]; + self.entries[i - 1] = self.entries[i]; } - list.size--; + self.size--; } -fn void List.add_all(List* list, List* other_list) +fn void List.add_all(&self, List* other_list) { if (!other_list.size) return; - list.reserve(other_list.size); + self.reserve(other_list.size); foreach (&value : other_list) { - list.entries[list.size++] = *value; + self.entries[self.size++] = *value; } } -fn Type[] List.to_array(List* list, Allocator* using = mem::heap()) +fn Type[] List.to_array(&self, Allocator* using = mem::heap()) { - if (!list.size) return Type[] {}; - Type[] result = malloc(Type, list.size, .using = using); - result[..] = list.entries[:list.size]; + if (!self.size) return Type[] {}; + Type[] result = malloc(Type, self.size, .using = using); + result[..] = self.entries[:self.size]; return result; } /** * Reverse the elements in a list. - * - * @param [&inout] list "The list to reverse" **/ -fn void List.reverse(List* list) +fn void List.reverse(&self) { - if (list.size < 2) return; - usz half = list.size / 2U; - usz end = list.size - 1; + if (self.size < 2) return; + usz half = self.size / 2U; + usz end = self.size - 1; for (usz i = 0; i < half; i++) { - @swap(list.entries[i], list.entries[end - i]); + @swap(self.entries[i], self.entries[end - i]); } } -fn Type[] List.array_view(List* list) +fn Type[] List.array_view(&self) { - return list.entries[:list.size]; + return self.entries[:self.size]; } -fn void List.add_array(List* list, Type[] array) +fn void List.add_array(&self, Type[] array) { if (!array.len) return; - list.reserve(array.len); + self.reserve(array.len); foreach (&value : array) { - list.entries[list.size++] = *value; + self.entries[self.size++] = *value; } } -fn void List.push_front(List* list, Type type) @inline +fn void List.push_front(&self, Type type) @inline { - list.insert_at(0, type); + self.insert_at(0, type); } -fn void List.insert_at(List* list, usz index, Type type) +fn void List.insert_at(&self, usz index, Type type) { - list.ensure_capacity(); - for (usz i = list.size; i > index; i--) + self.ensure_capacity(); + for (usz i = self.size; i > index; i--) { - list.entries[i] = list.entries[i - 1]; + self.entries[i] = self.entries[i - 1]; } - list.size++; - list.entries[index] = type; + self.size++; + self.entries[index] = type; } /** - * @require index < list.size + * @require index < self.size **/ -fn void List.set_at(List* list, usz index, Type type) +fn void List.set_at(&self, usz index, Type type) { - list.entries[index] = type; + self.entries[index] = type; } -fn void List.remove_last(List* list) +fn void List.remove_last(&self) { - list.size--; + self.size--; } -fn void List.remove_first(List* list) +fn void List.remove_first(&self) { - list.remove_at(0); + self.remove_at(0); } -fn Type* List.first(List* list) +fn Type* List.first(&self) { - return list.size ? &list.entries[0] : null; + return self.size ? &self.entries[0] : null; } -fn Type* List.last(List* list) +fn Type* List.last(&self) { - return list.size ? &list.entries[list.size - 1] : null; + return self.size ? &self.entries[self.size - 1] : null; } -fn bool List.is_empty(List* list) +fn bool List.is_empty(&self) { - return !list.size; + return !self.size; } -fn usz List.len(List* list) @operator(len) +fn usz List.len(&self) @operator(len) { - return list.size; + return self.size; } -fn Type List.get(List* list, usz index) +fn Type List.get(&self, usz index) { - return list.entries[index]; + return self.entries[index]; } -fn void List.free(List* list) +fn void List.free(&self) { - if (!list.allocator) return; - free_aligned(list.entries, .using = list.allocator); - list.capacity = 0; - list.size = 0; - list.entries = null; + if (!self.allocator) return; + free_aligned(self.entries, .using = self.allocator); + self.capacity = 0; + self.size = 0; + self.entries = null; } -fn void List.swap(List* list, usz i, usz j) +fn void List.swap(&self, usz i, usz j) { - @swap(list.entries[i], list.entries[j]); + @swap(self.entries[i], self.entries[j]); } /** - * @param [&inout] list "The list to remove elements from" * @param filter "The function to determine if it should be removed or not" * @return "the number of deleted elements" **/ -fn usz List.remove_if(List* list, ElementPredicate filter) +fn usz List.remove_if(&self, ElementPredicate filter) { - usz size = list.size; + usz size = self.size; for (usz i = size; i > 0; i--) { - if (filter(&list.entries[i - 1])) continue; + if (filter(&self.entries[i - 1])) continue; for (usz j = i; j < size; j++) { - list.entries[j - 1] = list.entries[j]; + self.entries[j - 1] = self.entries[j]; } - list.size--; + self.size--; } - return size - list.size; + return size - self.size; } /** - * @param [&inout] list "The list to remove elements from" * @param selection "The function to determine if it should be kept or not" * @return "the number of deleted elements" **/ -fn usz List.retain_if(List* list, ElementPredicate selection) +fn usz List.retain_if(&self, ElementPredicate selection) { - usz size = list.size; + usz size = self.size; for (usz i = size; i > 0; i--) { - if (!selection(&list.entries[i - 1])) continue; + if (!selection(&self.entries[i - 1])) continue; for (usz j = i; j < size; j++) { - list.entries[j - 1] = list.entries[j]; + self.entries[j - 1] = self.entries[j]; } - list.size--; + self.size--; } - return size - list.size; + return size - self.size; } /** * Reserve at least min_capacity **/ -fn void List.reserve(List* list, usz min_capacity) +fn void List.reserve(&self, usz min_capacity) { if (!min_capacity) return; - if (list.capacity >= min_capacity) return; - if (!list.allocator) list.allocator = mem::heap(); + if (self.capacity >= min_capacity) return; + if (!self.allocator) self.allocator = mem::heap(); min_capacity = math::next_power_of_2(min_capacity); - list.entries = realloc_aligned(list.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = list.allocator) ?? null; - list.capacity = min_capacity; + self.entries = realloc_aligned(self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = self.allocator) ?? null; + self.capacity = min_capacity; } -macro Type List.@item_at(List &list, usz index) @operator([]) +macro Type List.@item_at(&self, usz index) @operator([]) { - return list.entries[index]; + return self.entries[index]; } -fn Type* List.get_ref(List* list, usz index) @operator(&[]) @inline +fn Type* List.get_ref(&self, usz index) @operator(&[]) @inline { - return &list.entries[index]; + return &self.entries[index]; } -fn void List.ensure_capacity(List* list, usz added = 1) @inline @private +fn void List.ensure_capacity(&self, usz added = 1) @inline @private { - usz new_size = list.size + added; - if (list.capacity > new_size) return; + usz new_size = self.size + added; + if (self.capacity > new_size) return; assert(new_size < usz.max / 2U); - usz new_capacity = list.capacity ? 2U * list.capacity : 16U; + usz new_capacity = self.capacity ? 2U * self.capacity : 16U; while (new_size >= new_capacity) new_capacity *= 2U; - list.reserve(new_capacity); + self.reserve(new_capacity); } // Functions for equatable types -fn usz! List.index_of(List* list, Type type) @if(ELEMENT_IS_EQUATABLE) +fn usz! List.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE) { - foreach (i, v : list) + foreach (i, v : self) { if (v == type) return i; } return SearchResult.MISSING?; } -fn usz! List.rindex_of(List* list, Type type) @if(ELEMENT_IS_EQUATABLE) +fn usz! List.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE) { - foreach_r (i, v : list) + foreach_r (i, v : self) { if (v == type) return i; } return SearchResult.MISSING?; } -fn bool List.equals(List* list, List other_list) @if(ELEMENT_IS_EQUATABLE) +fn bool List.equals(&self, List other_list) @if(ELEMENT_IS_EQUATABLE) { - if (list.size != other_list.size) return false; - foreach (i, v : list) + if (self.size != other_list.size) return false; + foreach (i, v : self) { if (v != other_list.entries[i]) return false; } @@ -339,13 +335,13 @@ fn bool List.equals(List* list, List other_list) @if(ELEMENT_IS_EQUATABLE) /** * Check for presence of a value in a list. * - * @param [&in] list "the list to find elements in" + * @param [&in] self "the list to find elements in" * @param value "The value to search for" * @return "True if the value is found, false otherwise" **/ -fn bool List.contains(List* list, Type value) @if(ELEMENT_IS_EQUATABLE) +fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { - foreach (i, v : list) + foreach (i, v : self) { if (v == value) return true; } @@ -354,53 +350,53 @@ fn bool List.contains(List* list, Type value) @if(ELEMENT_IS_EQUATABLE) /** - * @param [&inout] list "The list to remove elements from" + * @param [&inout] self "The list to remove elements from" * @param value "The value to remove" * @return "the number of deleted elements." **/ -fn usz List.remove(List* list, Type value) @if(ELEMENT_IS_EQUATABLE) +fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { - usz size = list.size; + usz size = self.size; for (usz i = size; i > 0; i--) { - if (list.entries[i - 1] != value) continue; + if (self.entries[i - 1] != value) continue; for (usz j = i; j < size; j++) { - list.entries[j - 1] = list.entries[j]; + self.entries[j - 1] = self.entries[j]; } - list.size--; + self.size--; } - return size - list.size; + return size - self.size; } -fn void List.remove_all(List* list, List* other_list) @if(ELEMENT_IS_EQUATABLE) +fn void List.remove_all(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE) { if (!other_list.size) return; - foreach (v : other_list) list.remove(v); + foreach (v : other_list) self.remove(v); } /** - * @param [&in] list + * @param [&in] self * @return "The number non-null values in the list" **/ -fn usz List.compact_count(List* list) @if(ELEMENT_IS_POINTER) +fn usz List.compact_count(&self) @if(ELEMENT_IS_POINTER) { usz vals = 0; - foreach (v : list) if (v) vals++; + foreach (v : self) if (v) vals++; return vals; } -fn usz List.compact(List* list) @if(ELEMENT_IS_POINTER) +fn usz List.compact(&self) @if(ELEMENT_IS_POINTER) { - usz size = list.size; + usz size = self.size; for (usz i = size; i > 0; i--) { - if (list.entries[i - 1]) continue; + if (self.entries[i - 1]) continue; for (usz j = i; j < size; j++) { - list.entries[j - 1] = list.entries[j]; + self.entries[j - 1] = self.entries[j]; } - list.size--; + self.size--; } - return size - list.size; + return size - self.size; } diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 22beee25f..011111219 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -3005,9 +3005,15 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module, VECEACH(module->parameters, i) { const char *param_name = module->parameters[i]; + bool is_value = str_is_valid_constant(param_name); Expr *param = params[i]; if (param->expr_kind != EXPR_TYPEINFO) { + if (!is_value) + { + SEMA_ERROR(param, "Expected a type, not a value."); + return NULL; + } Decl *decl = decl_new_var(param_name, param->span, NULL, VARDECL_CONST); decl->var.init_expr = param; decl->type = param->type; @@ -3015,6 +3021,11 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module, vec_add(first_context->global_decls, decl); continue; } + if (is_value) + { + SEMA_ERROR(param, "Expected a value, not a type."); + return NULL; + } Decl *decl = decl_new_with_type(param_name, params[i]->span, DECL_TYPEDEF); decl->resolve_status = RESOLVE_DONE; TypeInfo *type_info = param->type_expr; @@ -3233,6 +3244,7 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl) path->len = scratch_buffer.len; instantiated_module = module_instantiate_generic(c, module, path, decl->define_decl.generic_params, decl->span); + if (!instantiated_module) return decl_poison(decl); sema_analyze_stage(instantiated_module, c->unit->module->stage - 1); } if (global_context.errors_found) return decl_poison(decl); diff --git a/src/utils/lib.h b/src/utils/lib.h index d748bbab0..9b5903290 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -115,6 +115,7 @@ char *str_printf(const char *var, ...) __printflike(1, 2); char *str_vprintf(const char *var, va_list list); void str_ellide_in_place(char *string, size_t max_size_shown); bool str_is_valid_lowercase_name(const char *string); +bool str_is_valid_constant(const char *string); bool str_has_no_uppercase(const char *string); char *str_copy(const char *start, size_t str_len); diff --git a/src/utils/stringutils.c b/src/utils/stringutils.c index 61be56ed7..0fe14687a 100644 --- a/src/utils/stringutils.c +++ b/src/utils/stringutils.c @@ -43,6 +43,18 @@ bool str_is_valid_lowercase_name(const char *string) return true; } +bool str_is_valid_constant(const char *string) +{ + char c; + // Must start with a lower case + int length = 0; + while ((c = *(string++)) != '\0') + { + if (!char_is_upper(c) && c != '_') return false; + } + return true; +} + void str_ellide_in_place(char *string, size_t max_size_shown) { size_t len = strlen(string); diff --git a/src/version.h b/src/version.h index d07e5011d..7ae8a4741 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.547" \ No newline at end of file +#define COMPILER_VERSION "0.4.548" \ No newline at end of file diff --git a/test/test_suite/generic/incorrect_argument_type.c3 b/test/test_suite/generic/incorrect_argument_type.c3 new file mode 100644 index 000000000..9c965469b --- /dev/null +++ b/test/test_suite/generic/incorrect_argument_type.c3 @@ -0,0 +1,11 @@ +module foo; + +struct Foo +{ + Type[SIZE] x; +} +module bar; +import foo; + +def Bar = Foo; // #error: Expected a value, not a type +def Baz = Foo<5, 4>; // #error: Expected a type, not a value