diff --git a/src/builtins.pr b/src/builtins.pr index df1f9f1..1f8b484 100644 --- a/src/builtins.pr +++ b/src/builtins.pr @@ -139,5 +139,16 @@ export var Generator_: &typechecking::Type = null export var TestEnvironment_: &typechecking::Type = null export var TypeT_: &typechecking::Type = null +export def type_t -> &typechecking::Type { + if TypeT_ { return TypeT_ } + let reflection = toolchain::find_module("reflection") + let value = reflection.scope.get(parser::make_identifier("Type"), force_compile = false) + if value { + TypeT_ = value.value.value_tpe + } + return TypeT_ +} + + //export var Field_: &typechecking::Type = null //export var EnumValue_: &typechecking::Type = null \ No newline at end of file diff --git a/src/compiler.pr b/src/compiler.pr index 46be6b9..afe4128 100644 --- a/src/compiler.pr +++ b/src/compiler.pr @@ -1336,8 +1336,9 @@ export def create_type(tpe: &typechecking::Type, module: &toolchain::Module) -> let res = vector::make(TypeEntry) let ret = create_type(tpe, module, res) + resolve_stub_types() resolve_types(res) - generate_reflection_data(res) + generate_reflection_data_queued() return ret } @@ -2175,6 +2176,10 @@ def convert_to(loc: &Value, value: Value, tpe: &typechecking::Type, state: &Stat let cast = [src = value.tpe, dst = tpe] !toolchain::Cast if state.module.dyn_casts.contains(cast) { + if consteval::is_static { + create_dyn_casts(state) + } + let fun = state.module.dyn_casts(cast) var dst = cast.dst @@ -4154,12 +4159,16 @@ def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, memb def walk_MemberAccess(node: &parser::Node, state: &State) -> Value { let loc = make_location(node, state) - if not node.tpe { return NO_VALUE } + if not node.tpe { + return NO_VALUE + } let left = node.value.bin_op.left let right = node.value.bin_op.right var tpe = (@left).tpe - if not tpe { return NO_VALUE } + if not tpe { + return NO_VALUE + } var value = walk_expression(left, state) if not value.addr { @@ -8100,7 +8109,9 @@ export def create_dyn_dispatch(dyn_dispatch: &Vector(&typechecking::Type), state export def create_dyn_casts(state: &State) { let dyn_casts = state.module.dyn_casts for var cast in @dyn_casts.keys() { - let function = predeclare_function(dyn_casts(cast), state.module) + let dyn_cast_tpe = dyn_casts(cast) + if state.module.result.functions.contains(dyn_cast_tpe.type_name) { continue } + let function = predeclare_function(dyn_cast_tpe, state.module) create_dyn_cast_function(function, cast, state) consteval::const_module.result.functions(function.name) = function } @@ -8801,26 +8812,35 @@ def do_create_type(tpe: &typechecking::Type, svalue: &scope::Value, module: &too // TODO Types have modules now, check if these functions need a separate module anymore // Map of ToResolve -let types_to_resolve = map::make(ToResolve) +var types_to_resolve = map::make(ToResolve) type ToResolve = struct { module: weak &toolchain::Module tpe: &typechecking::Type } + +var lock: bool // This is needed because some of the types might be stubs when they are first referenced // Resolve these later -export def resolve_types { +export def resolve_stub_types { + if lock { return } + lock = true let keys = map::keys(types_to_resolve) for var i in 0..keys.size { - let to_resolve = types_to_resolve(keys(i)) + let key = keys(i) + let to_resolve = types_to_resolve(key) let tpe = to_resolve.tpe - if tpe.kind == typechecking::TypeKind::STUB { continue } + if is_stub_rec(tpe) { + types_to_resolve.remove(key) + continue + } let ident = make_identifier(debug::type_to_str(tpe, true)) ident.loc.module = "type" create_type(tpe, to_resolve.module) } + lock = false } type TypeEntry = struct { @@ -8840,7 +8860,7 @@ export def create_type(tpe: &typechecking::Type, module: &toolchain::Module, res if tpe.kind == typechecking::TypeKind::TYPE_DEF { return null } let name = debug::type_to_str(tpe, full_name = true) - if tpe.kind == typechecking::TypeKind::STUB { + if is_stub(tpe) { if name { let to_resolve = [ module = module, tpe = tpe ] !ToResolve types_to_resolve(name) = to_resolve @@ -8855,14 +8875,17 @@ export def create_type(tpe: &typechecking::Type, module: &toolchain::Module, res var svalue = scope::get(toolchain::types.scope, ident, false, false) if not svalue { + print("create_type: ", name, "\n") svalue = scope::create_variable( toolchain::types.scope, ident, parser::ShareMarker::NONE, parser::VarDecl::CONST, builtins::Type_, - false, false, false, null, scope::Phase::DEFINED, null, null) + false, false, false, null, scope::Phase::COMPILED, null, null) + + let entry = [ tpe = tpe, value = svalue, module = module ] !TypeEntry + res.push(entry) + all_types.push(entry) + queued_types(name) = tpe - res.push([ - tpe = tpe, value = svalue, module = module - ] !TypeEntry) /*svalue = scope::create_variable( toolchain::types.scope, ident, parser::ShareMarker::NONE, parser::VarDecl::CONST, @@ -8894,31 +8917,6 @@ export def create_type(tpe: &typechecking::Type, module: &toolchain::Module, res create_type(vtpe, module, res) } } - // Member functions - // TODO Factor out, see generate_reflection_data_2 - for var member in typechecking::iterate_member_functions(tpe) { - if member.function.parameter_t(0).tpe.kind == typechecking::TypeKind::TYPE { continue } - - let function = member.function - - var is_incomplete = false - for var i in 0..vector::length(function.parameter_t) { - let np = function.parameter_t(i) - let generic = typechecking::get_generic(np.tpe) - if generic and generic.tc_incomplete or (np.tpe and np.tpe.kind == typechecking::TypeKind::TYPE_DEF) { - is_incomplete = true - break - } - } - if is_incomplete { continue } - - for var param in function.parameter_t { - create_type(param.tpe, module, res) - } - for var rtpe in function.return_t { - create_type(rtpe, module, res) - } - } } let state = toolchain::types_state @@ -9009,7 +9007,10 @@ export let all_types = vector::make(TypeEntry) // This gets called once export def generate_reflection_data { - let data, strings = generate_reflection_data(all_types) + for var entry in all_types { + queued_types(debug::type_to_str(entry.tpe, full_name = true)) = entry.tpe + } + let data, strings = generate_reflection_data_queued() // Need to 0 terminate the whole thing so that it can be converted to a Str data.write(0 !uint8) @@ -9018,18 +9019,19 @@ export def generate_reflection_data { make_global_data("__reflection_data", data, toolchain::types_state) make_global_data("__reflection_data_size", data.data().size, toolchain::types_state) make_global_data("__reflection_strings", strings.strings, toolchain::types_state) - make_global_data("__reflection_num_types", all_types.length, toolchain::types_state) + make_global_data("__reflection_num_types", queued_types.size, toolchain::types_state) } var fun_load_types: &scope::Value +var fun_load_types_rec_lock: bool var fun_load_types_count: size_t = 0 -var queued_types = set::make(type &typechecking::Type) +var queued_types = map::make(type &typechecking::Type) -export def generate_reflection_data(types: &Vector(TypeEntry)) -> &io::ByteStream, &UniquedStrings{ +export def generate_reflection_data_queued -> &io::ByteStream, &UniquedStrings{ let data = io::make_stream() let strings = [ strings = io::make_stream(), map = map::make(size_t) ] !&UniquedStrings - if types.length == 0 { + if queued_types.size == 0 { return data, strings } @@ -9039,28 +9041,70 @@ export def generate_reflection_data(types: &Vector(TypeEntry)) -> &io::ByteStrea let reflection = toolchain::find_module("reflection") fun_load_types = scope::get(reflection.scope, parser::make_identifier("load_types"), force_compile = not consteval::is_static) if consteval::is_static and fun_load_types { + var lock = fun_load_types_rec_lock + fun_load_types_rec_lock = true consteval::compile_function(fun_load_types, state.scope) + create_builtin_functions() + fun_load_types_rec_lock = lock } } - let types_set = set::make(type &typechecking::Type) - for var entry in types { - types_set.add(entry.tpe) - } - - if not fun_load_types { - queued_types.add_all(types_set) + if not fun_load_types or fun_load_types_rec_lock { return data, strings - } + } + + let all_type_members = map::make(type &typechecking::Type, type &Vector(typechecking::TypeEntryMember)) - types_set.add_all(queued_types) - queued_types.clear() + let all_types = map::make(type &typechecking::Type) + let res = vector::make(TypeEntry) + while queued_types.size > 0 { + for var name in @queued_types.keys() { + let tpe = queued_types(name) + let type_members = vector::make(typechecking::TypeEntryMember) + all_type_members(tpe) = type_members + queued_types.remove(name) + all_types(name) = tpe + + for var member in typechecking::iterate_member_functions(tpe) { + if member.function.parameter_t(0).tpe.kind == typechecking::TypeKind::TYPE { continue } + + let function = member.function + + print(member.function.type_name, " (") + + var is_incomplete = false + for var i in 0..vector::length(function.parameter_t) { + let np = function.parameter_t(i) + // TODO This really only matters for compile time reflection and shouldn't happen otherwise + if is_stub_rec(np.tpe) { is_incomplete = true; break } + let generic = typechecking::get_generic(np.tpe) + if generic and generic.tc_incomplete or (np.tpe and np.tpe.kind == typechecking::TypeKind::TYPE_DEF) { + is_incomplete = true + break + } - for var tpe in @types_set.keys() { + create_type(np.tpe, state.module, res) + } + for var tpe in function.return_t { + if is_stub_rec(tpe) { is_incomplete = true; break } + create_type(tpe, state.module, res) + print(debug::type_to_str(tpe, full_name = true), " ") + } + if is_incomplete { continue } + type_members.push(member) + } + } + } + + resolve_types(res) + + for var name in @all_types.keys() { + let tpe = all_types(name) generate_reflection_data_1(tpe, data, strings) } - for var tpe in @types_set.keys() { - generate_reflection_data_2(tpe, data, strings) + for var name in @all_types.keys() { + let tpe = all_types(name) + generate_reflection_data_2(tpe, data, strings, all_type_members(tpe)) } if consteval::is_static { @@ -9073,8 +9117,8 @@ export def generate_reflection_data(types: &Vector(TypeEntry)) -> &io::ByteStrea let args = allocate_ref(Value, 4) args(0) = [ kind = ValueKind::GLOBAL, name = "__reflection_data", tpe = pointer(builtins::uint8_)] !Value args(1) = [ kind = ValueKind::INT, tpe = builtins::uint64_, i = data.data().size ] !Value - args(2) = [ kind = ValueKind::GLOBAL, name = strings_ident, tpe = pointer(builtins::char_)] - args(3) = [ kind = ValueKind::INT, tpe = builtins::uint64_, i = types.length ] !Value + args(2) = [ kind = ValueKind::INT, tpe = builtins::uint64_, i = all_types.size ] !Value + args(3) = [ kind = ValueKind::GLOBAL, name = strings_ident, tpe = pointer(builtins::char_)] call.value.call = [ name = [ kind = ValueKind::GLOBAL, name = fun_load_types.tpe.type_name ], @@ -9085,11 +9129,15 @@ export def generate_reflection_data(types: &Vector(TypeEntry)) -> &io::ByteStrea block.insn.push(call) // load globals - state.globals("__reflection_data") = data.data().value + state.globals("__reflection_data") = *data.data().value + + let sz = strings.strings.data().size + let strings_data = state.mem.allocate(sz) + std::memcopy(strings.strings.data().value, strings_data, sz) - let strings_data = allocate(char, strings.strings.data().size) - std::memcopy(strings.strings.data().value, strings_data.value, strings_data.size) - state.globals(strings_ident) = strings_data.value // This is a copy so we can keep it here + let strings_ptr = state.mem.allocate(size_of *) !** + @strings_ptr = strings_data + state.globals(strings_ident) = strings_ptr // This is a copy so we can keep it here eval::eval(state, block) @@ -9114,26 +9162,7 @@ def write_zt(uniqued: &UniquedStrings, s: Str) -> int { return val !int } -def generate_reflection_data_2(tpe: &typechecking::Type, data: &ByteStream, strings: &UniquedStrings) { - // Collect type members - let type_members = vector::make(typechecking::TypeEntryMember) - for var member in typechecking::iterate_member_functions(tpe) { - if member.function.parameter_t(0).tpe.kind == typechecking::TypeKind::TYPE { continue } - - let function = member.function - - var is_incomplete = false - for var i in 0..vector::length(function.parameter_t) { - let np = function.parameter_t(i) - let generic = typechecking::get_generic(np.tpe) - if generic and generic.tc_incomplete or (np.tpe and np.tpe.kind == typechecking::TypeKind::TYPE_DEF) { - is_incomplete = true - break - } - } - if is_incomplete { continue } - type_members.push(member) - } +def generate_reflection_data_2(tpe: &typechecking::Type, data: &ByteStream, strings: &UniquedStrings, type_members: &Vector(TypeEntryMember)) { // Write type members data.write(type_members.length !int) @@ -9200,7 +9229,7 @@ def generate_reflection_data_2(tpe: &typechecking::Type, data: &ByteStream, stri } def generate_reflection_data_1(tpe: &typechecking::Type, data: &ByteStream, strings: &UniquedStrings) { - data.write(tpe.kind) // This does rely on the values beind the same + data.write(tpe.kind) // This does rely on the values being the same data.write(strings.write_zt(debug::type_to_str(tpe, full_name = true))) data.write(strings.write_zt(tpe.module.module if tpe.module else to_str(""))) data.write(tpe.hash) diff --git a/src/consteval.pr b/src/consteval.pr index 73c0e6d..243064f 100644 --- a/src/consteval.pr +++ b/src/consteval.pr @@ -426,8 +426,8 @@ export def walk_Def(node: &parser::Node, state: &typechecking::State) { if has_yield { let generator_ctor = typechecking::type_lookup(parser::make_identifier("Generator"), state, lookup_default = true) - var generator = [ kind = typechecking::TypeKind::GENERIC ] !&typechecking::Type - generator.tc_incomplete = true + var generator = typechecking::make_struct_type([] !&[StructMember]) + //generator.tc_incomplete = true generator.tc_args = vector::make(type &typechecking::Type) generator.tc_args.push(tpe.return_t(0)) generator.tc_tpe = generator_ctor @@ -1168,7 +1168,7 @@ export def consteval(module: &toolchain::Module) { if module.module == "std" { toolchain::load_file_type() - } else if module.module == "reflection" { + } else if module.module == "reflection" and builtins::TypeT_ != null { builtins::TypeT_ = module.scope.get_type(parser::make_identifier("Type")) } } diff --git a/src/eval.pr b/src/eval.pr index cb151fe..c970d14 100644 --- a/src/eval.pr +++ b/src/eval.pr @@ -272,7 +272,18 @@ def set(mem: *, tpe: &typechecking::Type, value: compiler::Value) { assert(false) } case typechecking::TypeKind::POINTER, typechecking::TypeKind::BYREF - (@(mem !*int64)) = value.i + if tpe.tpe and tpe.tpe.kind == typechecking::TypeKind::FUNCTION and value.kind == compiler::ValueKind::GLOBAL { + var function = consteval::const_module.result.functions.get_or_default(value.name, null) + if function { + let ptr = allocate(1) + let fp = [ is_fp = false ] !FunctionPtr + fp.function = function + function_store.store(ptr !size_t) = fp + (@(mem !*int64)) = ptr !int64 + } + } else { + (@(mem !*int64)) = value.i + } case typechecking::TypeKind::REFERENCE, typechecking::TypeKind::WEAK_REF @(mem !*int64) = value.values(0).i @((mem ++ (size_of type *)) !*int64) = value.values(1).i @@ -991,7 +1002,7 @@ def eval_Call(insn: &compiler::Insn, state: &State) { push_stack_frame(stack_frame, state) - if toolchain::trace_consteval { + /*if toolchain::trace_consteval { print(function.name, "\n") print("==========================\n") var block = function.block @@ -999,8 +1010,8 @@ def eval_Call(insn: &compiler::Insn, state: &State) { codegen::emit_block(std::stdout(), block) block = block.next } - } - + }*/ + eval(function.block, state) if ret.tpe { diff --git a/src/toolchain.pr b/src/toolchain.pr index 5c39b4d..6a571b3 100644 --- a/src/toolchain.pr +++ b/src/toolchain.pr @@ -722,7 +722,7 @@ export def create_types_main { } export def load_file_type { - if no_stdlib { return } + if no_stdlib or builtins::File_ != null { return } var std_module = find_module("std") if not std_module { std_module = create_module_if_absent(find_module_file("/std", null), "std") @@ -826,7 +826,7 @@ export def compile_main_file(filename: String) { if not continue_on_output { return } } - reset_types() + //reset_types() compiler::import_structures(builtins::Type_, types) compile_module(module) @@ -840,7 +840,7 @@ export def compile_main_file(filename: String) { } debug::trace("Resolving types") - compiler::resolve_types() // TODO Remove this function + compiler::resolve_stub_types() // TODO Remove this function compiler::generate_reflection_data() debug::trace("Creating builtin functions") compiler::create_builtin_functions() diff --git a/src/typechecking.pr b/src/typechecking.pr index 6d82619..3df2171 100644 --- a/src/typechecking.pr +++ b/src/typechecking.pr @@ -38,6 +38,8 @@ export type TypeKind = enum { VARIANT TUPLE TYPE + // This is a type with arguments + TYPE_CONSTRUCTOR // Forward declaration STUB @@ -57,8 +59,6 @@ export type TypeKind = enum { // Null NULL UNDEF - // This is a type with arguments - TYPE_CONSTRUCTOR // This is used as a function parameter that is generic GENERIC // References to structs are using a wk reference, ie. Type::wk instead of Type::_tpe @@ -722,7 +722,7 @@ export def is_stub(tpe: &Type) -> bool { } // TODO Actually go inside of function types, etc -def is_stub_rec(tpe: &Type) -> bool { +export def is_stub_rec(tpe: &Type) -> bool { if not tpe { return false } if is_box(tpe) { return is_stub_rec(tpe.tpe) @@ -1167,6 +1167,7 @@ export def equals(a: &Type, b: &Type) -> bool { if b.kind == TypeKind::BOX { b = b.wk } + if not a or not b { return false } if a.kind != TypeKind::TYPE and a._hash and b._hash { // Speed up equality if hashes are defined @@ -1318,18 +1319,15 @@ def has_function(entry: &TypeEntry, intf: &Type, mb: StructuralTypeMember, modul if tpe and tpe.kind == typechecking::TypeKind::STRUCT { let fields = flatten_fields(tpe) if is_setter(mb) { - let name = mb.name.slice(6, mb.name.length() - 2496) + let name = mb.name.slice(6, mb.name.length() - 2) for var field in fields { - if field.name == name and equals(mb.parameter_t(0).tpe, field.tpe) { return true } + let tpe = resolve_member(tpe, field.name) + if field.name == name and equals(mb.parameter_t(0).tpe, tpe) { return true } } } else if is_getter(mb) { for var field in fields { - if field.name == mb.name and equals(mb.return_t(0), field.tpe) { return true } - } - if tpe.const_fields { - for var field in @tpe.const_fields { - if field.name == mb.name and equals(mb.return_t(0), field.tpe) { return true } - } + let tpe = resolve_member(tpe, field.name) + if field.name == mb.name and equals(mb.return_t(0), tpe) { return true } } } } @@ -1434,7 +1432,7 @@ export def implements(a: &Type, b: &Type, module: &toolchain::Module, visited: & if not found { found = has_function(type_entry, b, mb, module, visited.copy(), check_embed) } - if not found { + if not found { type_entry.cached(nameb) = CacheEntry::NOT_CONTAINS return false } @@ -2302,6 +2300,7 @@ export def make_stub_type(ident: &parser::Node, state: &State, prefix: bool = tr export def make_union_type(fields: &[StructMember], const_fields: &[StructMember], current_type: &Type = null) -> &Type { let tpe = make_type_raw(TypeKind::UNION) if not current_type else current_type + tpe.kind = TypeKind::UNION let field_types = vector::make(TypeMember) var size = 0 !size_t @@ -2352,6 +2351,7 @@ export def make_tuple_type(types: &Vector(&Type)) -> &Type { export def make_struct_type(fields: &[StructMember], const_fields: &[StructMember] = null, current_type: &Type = null) -> &Type { let struct_tpe = make_type_raw(TypeKind::STRUCT) if not current_type else current_type + struct_tpe.kind = TypeKind::STRUCT let field_types = vector::make(TypeMember) var j = 0 @@ -2900,7 +2900,9 @@ export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Typ let member = node.value.body(i) if not member { continue } var current_member: *StructuralTypeMember = null - if current_type { current_member = current_type.members.get(i) } + if current_type and current_type.members { + current_member = current_type.members.get(i) + } let name_node = member.value.structural_member.name if not name_node { continue } @@ -4177,7 +4179,11 @@ def walk_Cast(node: &parser::Node, state: &State) { state.module) // Dynamic cast - state.module.dyn_casts([src = ltpe, dst = rtpe,] !Cast) = fun + let cast = [src = ltpe, dst = rtpe] !toolchain::Cast + state.module.dyn_casts(cast) = fun + if consteval::is_static { + consteval::const_module.dyn_casts(cast) = fun + } } else if is_struct(ltpe) or is_struct(rtpe) { if ltpe.kind != rtpe.kind and not is_ref(rtpe) { errors::errorn(left, "Invalid cast") @@ -4849,13 +4855,19 @@ export def walk_TypeDecl(node: &parser::Node, state: &State) { value = right(i) } - var tpe = make_type_raw(TypeKind::STUB) - left.svalue = scope::create_type(state.scope, name, share, tpe, scope::Phase::COMPILED, node, null) + var tpe: &Type + if left.tpe { + tpe = left.tpe + } else { + tpe = make_type_raw(TypeKind::STUB) + left.svalue = scope::create_type(state.scope, name, share, tpe, scope::Phase::COMPILED, node, null) + } + if value { if left.kind == parser::NodeKind::TYPE_CONSTRUCTOR { tpe = lookup_type_constructor(left, value, state) } else { - tpe = copy(type_lookup(value, state)) + tpe = copy(type_lookup(value, state, tpe)) if tpe and not tpe.tc_args { tpe.module = state.module } @@ -5550,27 +5562,44 @@ def for_setup_generator(expr: &parser::Node, node: &parser::Node, state: &State) export def for_setup_generator(expr: &parser::Node, node: &parser::Node, scpe: &scope::Scope) { let parameter_t = vector::make(NamedParameter) parameter_t.push([ _tpe = expr.tpe ] !NamedParameter) - let generator_next = scpe.get_function( + var generator_next = scpe.get_function( id = parser::make_identifier("next"), - parameter_t = parameter_t + dry_run = false, + parameter_t = parameter_t, + force_compile = not consteval::is_static ) - node.value.for_loop.generator_next = generator_next + + if generator_next and consteval::is_static { + generator_next = consteval::compile_function(generator_next, scpe.module.scope, parameter_t) + } let parameter_t2 = vector::make(NamedParameter) parameter_t2.push([ _tpe = generator_next.tpe.return_t(0) ] !NamedParameter) - let generator_get = scpe.get_function( + var generator_get = scpe.get_function( id = parser::make_identifier("get"), - parameter_t = parameter_t2 + dry_run = false, + parameter_t = parameter_t2, + force_compile = not consteval::is_static ) + + if generator_get and consteval::is_static { + generator_get = consteval::compile_function(generator_get, scpe.module.scope, parameter_t2) + } + node.value.for_loop.generator_get = generator_get + node.value.for_loop.generator_next = generator_next } def wrap_iterable(expr: &parser::Node, state: &State) -> &parser::Node { let args = vector::make(NamedParameter) args.push([ _tpe = expr.tpe ] !NamedParameter) let ident = parser::make_identifier("iterate") - let fun = scope::get_function(state.scope, ident, args, true, context = state.context) + let fun = scope::get_function(state.scope, ident, args, true, context = state.context, force_compile = not consteval::is_static) if fun { + if consteval::is_static { + consteval::compile_function(fun, state.context, args) + } + let args = vector::make(type &parser::Node) args.push(expr) @@ -5805,7 +5834,7 @@ def walk_MemberAccess(node: &parser::Node, state: &State) { walk(node, left, state) if is_type(left.tpe) { // Swap out type - left.tpe = builtins::TypeT_ + left.tpe = builtins::type_t() } let tpe = (@left).tpe @@ -5814,7 +5843,7 @@ def walk_MemberAccess(node: &parser::Node, state: &State) { if tpe and not is_ref_or_weak(tpe) and tpe.kind != TypeKind::TUNION { errors::errorn(node, "Can't get type from `" + debug::type_to_str(tpe) + "`, only references or variants allowed") } else { - node.tpe = builtins::TypeT_ + node.tpe = builtins::type_t() } return } @@ -5905,6 +5934,11 @@ def flatten_fields(tpe: &Type, v: &Vector(StructMember) = null) -> &Vector(Struc v.push(field) } } + if tpe.const_fields { + for var field in @tpe.const_fields { + v.push(field) + } + } return v } diff --git a/std/strings.pr b/std/strings.pr index fddb4ab..deedeb5 100644 --- a/std/strings.pr +++ b/std/strings.pr @@ -154,6 +154,7 @@ export type StringBuffer = struct { blocked: bool // This is annoying but needed to free the linked list without recursion } +// TODO Rewrite this, its not thread safe and really ugly. If there's no way to make it work change destructors to make it work. export def destruct(this: *StringBuffer) -> bool { __destruct__(*this.data) if this.blocked { return false }