diff --git a/src/codegen.pr b/src/codegen.pr index 277d0b82..69947291 100644 --- a/src/codegen.pr +++ b/src/codegen.pr @@ -12,7 +12,7 @@ import builtins def type_to_str(tpe: &typechecking::Type) -> Str { if not tpe { return "void" } if tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk } var ret: StringBuffer = "" switch tpe.kind !int { @@ -30,7 +30,7 @@ def type_to_str(tpe: &typechecking::Type) -> Str { case 16; ret = "x86_fp80" case; assert } - case typechecking::TypeKind::POINTER + case typechecking::TypeKind::POINTER, typechecking::TypeKind::BYREF if tpe.tpe and tpe.tpe.kind != typechecking::TypeKind::STRUCTURAL { ret = type_to_str(tpe.tpe) ret += '*' @@ -39,7 +39,7 @@ def type_to_str(tpe: &typechecking::Type) -> Str { ret = "i8*" } case typechecking::TypeKind::REFERENCE, typechecking::TypeKind::WEAK_REF - ret = "{i64*, " + ret = "{{i64, i64}*, " if tpe.tpe and tpe.tpe.kind != typechecking::TypeKind::STRUCTURAL { ret += type_to_str(tpe.tpe) ret += '*' diff --git a/src/compiler.pr b/src/compiler.pr index ace7a2d3..be11e427 100644 --- a/src/compiler.pr +++ b/src/compiler.pr @@ -466,7 +466,7 @@ def take_snapshot(function: &Function) { export type Function = struct { is_global: bool - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module imported: bool dllimport: bool dllexport: bool @@ -518,9 +518,9 @@ export type Function = struct { // Closures is_closure: bool state: &typechecking::Type - scope: weak_ref(scope::Scope) - inner_scope: weak_ref(scope::Scope) - captures: &Vector(weak_ref(scope::Value)) + scope: weak &scope::Scope + inner_scope: weak &scope::Scope + captures: &Vector(weak &scope::Value) is_compiled: bool is_typechecked: bool @@ -567,7 +567,7 @@ type LoopState = struct { } export type State = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module global_counter: int meta_counter: int local_counter: int @@ -584,7 +584,7 @@ export type State = struct { // Used by eval globals: &SMap(*) mem: &arena::Arena - scope: weak_ref(scope::Scope) + scope: weak &scope::Scope // Destructor function finalizer: &Function consteval: bool @@ -600,6 +600,7 @@ export type State = struct { return_address: Value // This is used as the return address in inline functions return_br: &Insn // This is used to jump back to the end of the function inline_start_block: &Block // This represents the first block of the current function + context_ptr: int // Counts up the current free_context } export def destruct(state: *State) { @@ -1110,7 +1111,7 @@ def import_structure(tpe: &typechecking::Type, module: &toolchain::Module) { export def import_structures(tpe: &typechecking::Type, module: &toolchain::Module) { if not tpe { return } if tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk } switch tpe.kind !int { case typechecking::TypeKind::STRUCT..=typechecking::TypeKind::UNION @@ -1118,6 +1119,7 @@ export def import_structures(tpe: &typechecking::Type, module: &toolchain::Modul case typechecking::TypeKind::ARRAY, typechecking::TypeKind::STATIC_ARRAY, typechecking::TypeKind::POINTER, + typechecking::TypeKind::BYREF, typechecking::TypeKind::REFERENCE, typechecking::TypeKind::WEAK_REF import_structures(tpe.tpe, module) @@ -1420,106 +1422,138 @@ def convert_ref_to_ref(tpe: &typechecking::Type, value: Value, loc: &Value, stat add_type_meta(tpe, state) - let index1 = allocate_ref(int, 1) - index1(0) = 0 - - let extract1_ret = make_local_value(typechecking::pointer(builtins::int64_), null, state) - let extract1 = make_insn_dbg(InsnKind::EXTRACTVALUE, loc) - extract1.value.extract_value = [ - ret = extract1_ret, - value = value, - index = index1 - ] !InsnExtractValue - push_insn(extract1, state) + let extract1_ret = state.extract_value(pointer(ref_meta()), value, [0], loc) + let extract2_ret = state.extract_value(pointer(value.tpe.tpe), value, [1], loc) + let extract3_ret = state.extract_value(pointer(builtins::Type_), value, [2], loc) + let bitcast_ret = state.bitcast(pointer(tpe.tpe if tpe.tpe else builtins::int8_), extract2_ret, loc) + + // Convert weak ref to strong reference + // Need to check the ref count and return a null reference if its 0 + if is_weak_ref(value.tpe) and is_ref(tpe) { + let ref_value = state.ptr_to_int(extract1_ret, loc) + let isnull = state.icmp(CompareInt::eq, ref_value, + [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value, loc) + + let br1 = make_insn_dbg(InsnKind::BR, loc) + br1.value.br = [ cond = isnull ] !InsnBr + push_insn(br1, state) + let nonnull = make_label(state) + push_label(nonnull, state) + br1.value.br.if_false = nonnull + + let meta = state.load(ref_meta(), extract1_ret, loc) + let refcount = state.extract_value(builtins::int64_, meta, [0], loc) + let iszero = state.icmp(CompareInt::sle, refcount, + [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value, loc) + let res = state.alloca(value.tpe, loc) - let index2 = allocate_ref(int, 1) - index2(0) = 1 - - let extract2_ret = make_local_value(typechecking::pointer(value.tpe.tpe), null, state) - let extract2 = make_insn_dbg(InsnKind::EXTRACTVALUE, loc) - extract2.value.extract_value = [ - ret = extract2_ret, - value = value, - index = index2 - ] !InsnExtractValue - push_insn(extract2, state) + let br = make_insn_dbg(InsnKind::BR, loc) + br.value.br = [ cond = iszero ] !InsnBr + push_insn(br, state) + let if_true = make_label(state) + push_label(if_true, state) + br1.value.br.if_true = if_true + br.value.br.if_true = if_true - let index3 = allocate_ref(int, 1) - index3(0) = 2 - - let extract3_ret = make_local_value(typechecking::pointer(builtins::Type_), null, state) - let extract3 = make_insn_dbg(InsnKind::EXTRACTVALUE, loc) - extract3.value.extract_value = [ - ret = extract3_ret, - value = value, - index = index3 - ] !InsnExtractValue - push_insn(extract3, state) + // Null reference + var start = [ kind = ValueKind::ZEROINITIALIZER, tpe = tpe ] !Value + start = state.insert_value(tpe, start, extract3_ret, [2], loc) + state.store(res, start, loc) + let br_to_end = make_insn_dbg(InsnKind::BR_UNC, loc) + push_insn(br_to_end, state) - let bitcast_ret = make_local_value(typechecking::pointer(tpe.tpe if tpe.tpe else builtins::int8_), null, state) - let bitcast = make_insn_dbg(InsnKind::BITCAST, loc) - bitcast.value.convert = [ - ret = bitcast_ret, - value = extract2_ret - ] !InsnConvert - push_insn(bitcast, state) + let if_false = make_label(state) + br.value.br.if_false = if_false + push_label(if_false, state) - var start = [ kind = ValueKind::UNDEF, tpe = tpe ] !Value + start = [ kind = ValueKind::UNDEF, tpe = tpe ] !Value + start = state.insert_value(tpe, start, extract1_ret, [0], loc) + start = state.insert_value(tpe, start, bitcast_ret, [1], loc) + start = state.insert_value(tpe, start, extract3_ret, [2], loc) + state.store(res, start, loc) + push_insn(br_to_end, state) - let insert1_ret = make_local_value(tpe, null, state) - let insert1 = make_insn_dbg(InsnKind::INSERTVALUE, loc) - insert1.value.insert_value = [ - ret = insert1_ret, - value = start, - element = extract1_ret, - index = index1 - ] !InsnInsertValue - push_insn(insert1, state) + let end = make_label(state) + br_to_end.value.br_unc.label_ = end + push_label(end, state) - let insert2_ret = make_local_value(tpe, null, state) - let insert2 = make_insn_dbg(InsnKind::INSERTVALUE, loc) - insert2.value.insert_value = [ - ret = insert2_ret, - value = insert1_ret, - element = bitcast_ret, - index = index2 - ] !InsnInsertValue - push_insn(insert2, state) + return state.load(tpe, res, loc) + } - let insert3_ret = make_local_value(tpe, null, state) - let insert3 = make_insn_dbg(InsnKind::INSERTVALUE, loc) - insert3.value.insert_value = [ - ret = insert3_ret, - value = insert2_ret, - element = extract3_ret, - index = index3 - ] !InsnInsertValue - push_insn(insert3, state) + let start = [ kind = ValueKind::UNDEF, tpe = tpe ] !Value + let insert1_ret = state.insert_value(tpe, start, extract1_ret, [0], loc) + let insert2_ret = state.insert_value(tpe, insert1_ret, bitcast_ret, [1], loc) + let insert3_ret = state.insert_value(tpe, insert2_ret, extract3_ret, [2], loc) return insert3_ret } def convert_ref_to_ptr(tpe: &typechecking::Type, value: Value, loc: &Value, state: &State) -> Value { - let index = allocate_ref(int, 1) - index(0) = 1 - let extract_ret = make_local_value(typechecking::pointer(value.tpe.tpe), null, state) - let extract = make_insn_dbg(InsnKind::EXTRACTVALUE, loc) - extract.value.extract_value = [ - ret = extract_ret, - value = value, - index = index - ] !InsnExtractValue - push_insn(extract, state) + if is_weak_ref(value.tpe) { + let meta = state.extract_value(pointer(ref_meta()), value, [0], loc) - let bitcast_ret = make_local_value(typechecking::pointer(tpe.tpe), null, state) - let bitcast = make_insn_dbg(InsnKind::BITCAST, loc) - bitcast.value.convert = [ - ret = bitcast_ret, - value = extract_ret - ] !InsnConvert - push_insn(bitcast, state) + let ref_value = state.ptr_to_int(meta, loc) + let isnull = state.icmp(CompareInt::eq, ref_value, + [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value, loc) - return bitcast_ret + let br1 = make_insn_dbg(InsnKind::BR, loc) + br1.value.br = [ cond = isnull ] !InsnBr + push_insn(br1, state) + let nonnull = make_label(state) + push_label(nonnull, state) + br1.value.br.if_false = nonnull + + let meta_val = state.load(ref_meta(), meta, loc) + let cnt = state.extract_value(builtins::int64_, meta_val, [0], loc) + let iszero = state.icmp(CompareInt::sle, cnt, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) + let res = state.alloca(pointer(tpe.tpe), loc) + + let br = make_insn_dbg(InsnKind::BR, loc) + br.value.br = [ cond = iszero ] !InsnBr + push_insn(br, state) + let if_true = make_label(state) + push_label(if_true, state) + br.value.br.if_true = if_true + br1.value.br.if_true = if_true + + // Null pointer + state.store(res, [ kind = ValueKind::ZEROINITIALIZER, tpe = pointer(tpe.tpe) ] !Value) + + let br_to_end = make_insn_dbg(InsnKind::BR_UNC, loc) + push_insn(br_to_end, state) + + let if_false = make_label(state) + br.value.br.if_false = if_false + push_label(if_false, state) + + // Pointer value + let ptr = state.extract_value(pointer(value.tpe.tpe if value.tpe.tpe else builtins::int8_), value, [1], loc) + let ptr_casted = state.bitcast(pointer(tpe.tpe), ptr, loc) + state.store(res, ptr_casted, loc) + + push_insn(br_to_end, state) + let end = make_label(state) + br_to_end.value.br_unc.label_ = end + push_label(end, state) + + return state.load(pointer(tpe.tpe), res, loc) + } + + let ptr = state.extract_value(pointer(value.tpe.tpe if value.tpe.tpe else builtins::int8_), value, [1], loc) + let ptr_casted = state.bitcast(pointer(tpe.tpe), ptr, loc) + return ptr_casted +} + +// Reference metadata struct +var _ref_meta: &typechecking::Type +export def ref_meta -> &typechecking::Type { + if not _ref_meta { + _ref_meta = typechecking::make_struct_type([ + [ tpe = builtins::int64_, name = "refcount" ] !typechecking::StructMember, + [ tpe = builtins::int64_, name = "weakcount" ] !typechecking::StructMember + ]) + } + return _ref_meta } def convert_value_to_ref(tpe: &typechecking::Type, value: Value, loc: &Value, state: &State, initial_ref_count: size_t = 0) -> Value { @@ -1542,31 +1576,15 @@ def convert_value_to_ref(tpe: &typechecking::Type, value: Value, loc: &Value, st var refcount = [ kind = ValueKind::NULL, tpe = pointer(builtins::int64_) ] !Value if not is_null { + // create ref counts let args1 = allocate_ref(Value, 1) - args1(0) = [ kind = ValueKind::INT, tpe = builtins::int64_, i = builtins::int64_.size ] !Value - let call1_ret = make_local_value(typechecking::pointer(builtins::int8_), null, state) - let call1 = make_insn_dbg(InsnKind::CALL, loc) - call1.value.call = [ - name = [ kind = ValueKind::GLOBAL, name = "malloc" ] !Value, - ret = call1_ret, - args = args1 - ] !InsnCall - push_insn(call1, state) - - refcount = make_local_value(typechecking::pointer(builtins::int64_), null, state) - let bitcast1 = make_insn_dbg(InsnKind::BITCAST, loc) - bitcast1.value.convert = [ - ret = refcount, - value = call1_ret - ] !InsnConvert - push_insn(bitcast1, state) - - let store1 = make_insn_dbg(InsnKind::STORE, loc) - store1.value.store = [ - loc = refcount, - value = [ kind = ValueKind::INT, tpe = builtins::int64_, i = initial_ref_count ] !Value - ] !InsnStore - push_insn(store1, state) + args1(0) = [ kind = ValueKind::INT, tpe = builtins::int64_, i = ref_meta().size] !Value + var call1_ret = state.call("malloc", pointer(builtins::int8_), args1, loc) + call1_ret = state.bitcast(pointer(ref_meta()), call1_ret, loc) + refcount = state.gep(pointer(builtins::int64_), ref_meta(), call1_ret, [make_int_value(0), make_int_value(0)], loc) + let weakcount = state.gep(pointer(builtins::int64_), ref_meta(), call1_ret, [make_int_value(0), make_int_value(1)], loc) + state.store(refcount, [ kind = ValueKind::INT, tpe = builtins::int64_, i = initial_ref_count ] !Value) + state.store(weakcount, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value) } let start = [ kind = ValueKind::UNDEF, tpe = tpe ] !Value @@ -1666,7 +1684,7 @@ def convert_value_to_ref(tpe: &typechecking::Type, value: Value, loc: &Value, st array_val = state.gep(ptpe, value.tpe, data, [make_int_value(0), counter_value], loc) } - if is_ref(value.tpe.tpe) { + if is_ref_or_weak(value.tpe.tpe) { increase_ref_count(array_val, loc, state) } else if has_copy_constructor(value.tpe.tpe) { let val = state.load(value.tpe.tpe, array_val, loc) @@ -2151,8 +2169,8 @@ def convert_to(loc: &Value, value: Value, tpe: &typechecking::Type, state: &Stat var unwrap = load_value(value, loc, state) // Unwrap reference on the value side if is_ref(value.tpe) { - let ref = state.extract_value(pointer(right), unwrap, [1], loc) - unwrap = state.load(right, ref, loc) + let _ref = state.extract_value(pointer(right), unwrap, [1], loc) + unwrap = state.load(right, _ref, loc) } // Extract element var elem = state.extract_value(field.tpe, unwrap, [field.index !int], loc) @@ -2322,7 +2340,7 @@ def walk_StructLitUnion(node: &parser::Node, state: &State) -> Value { } var value = convert_to(arg, walk_expression(arg, state), arg_tpe, state) - if typechecking::is_ref(arg_tpe) { + if typechecking::is_ref_or_weak(arg_tpe) { increase_ref_count_of_value(value, loc, state) } else if typechecking::has_copy_constructor(arg_tpe) { let ret = state.alloca(arg_tpe, loc, no_yield_capture = true) @@ -2461,7 +2479,7 @@ def struct_lit_create_value(tpe: &typechecking::Type, kwargs: &Vector(&parser::N let field = tpe.fields(j) if field.name == name { values(j) = convert_to(kwarg, value, field.tpe, state) - if typechecking::is_ref(field.tpe) { + if typechecking::is_ref_or_weak(field.tpe) { increase_ref_count_of_value(values(j), loc, state) } else if typechecking::has_copy_constructor(field.tpe) { let ret = state.alloca(values(j).tpe, loc, no_yield_capture = true) @@ -2585,7 +2603,7 @@ def walk_ArrayLit(node: &parser::Node, state: &State) -> Value { for var i in 0..len { let v = node.value.struct_lit.args(i) var element = walk_and_load_expression(v, state) - if is_ref(element.tpe) { + if is_ref_or_weak(element.tpe) { increase_ref_count_of_value(element, loc, state) } else if typechecking::has_copy_constructor(element.tpe) { let ret = state.alloca(element.tpe, loc, no_yield_capture = true) @@ -3061,6 +3079,7 @@ def walk_Call(node: &parser::Node, state: &State) -> Value { insert_copy_constructor(ret, expr, loc, state) expr = state.load(expr.tpe, ret, loc) } + // TODO Does this need to do something for wk references? if typechecking::is_ref(last_np.tpe) and not typechecking::is_ref(n.tpe) { create_type(reference(n.tpe), state.module) // We need to increase the ref count and add the destructor call @@ -3149,7 +3168,7 @@ def walk_Call(node: &parser::Node, state: &State) -> Value { var array_val: Value if pass_varargs_as_array { for var i in 0..varargs.size { - if varargs(i).tpe.kind == typechecking::TypeKind::REFERENCE { + if is_ref_or_weak(varargs(i).tpe) { increase_ref_count_of_value(varargs(i), loc, state) } } @@ -3376,7 +3395,7 @@ def insert_copy_constructor(addr: Value, value: Value, loc: &Value, state: &Stat br.value.br.if_false = loop_inner let array_ptr = state.gep(pointer(value.tpe.tpe), value.tpe, addr, [make_int_value(0), counter_value]) - if typechecking::is_ref(value.tpe.tpe) { + if typechecking::is_ref_or_weak(value.tpe.tpe) { increase_ref_count(array_ptr, loc, state) } else { let value_ptr = state.gep(pointer(value.tpe.tpe), value.tpe, array_loc, [make_int_value(0), counter_value]) @@ -3435,8 +3454,64 @@ def insert_destructors(scpe: &scope::Scope, loc: &Value, state: &State) { } } +def check_clear_ref_meta(meta_ptr: Value, loc: &Value, state: &State) { + import_cstd_function("free", state) + + let meta = state.load(ref_meta(), meta_ptr, loc) + let cnt = state.extract_value(builtins::int64_, meta, [1], loc) + let cond = state.icmp(CompareInt::sle, cnt, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) + + let br = make_insn_dbg(InsnKind::BR, loc) + br.value.br = [ cond = cond ] !InsnBr + push_insn(br, state) + let if_true = make_label(state) + push_label(if_true, state) + br.value.br.if_true = if_true + + // Free reference metadata + let ref_count_i8_ptr = state.bitcast(pointer(builtins::int8_), meta_ptr) + state.call("free", null, [ref_count_i8_ptr]) + + let if_false = make_label(state) + let br_unc = make_insn_dbg(InsnKind::BR_UNC, loc) + br_unc.value.br_unc.label_ = if_false + push_insn(br_unc, state) + + push_label(if_false, state) + br.value.br.if_false = if_false +} + def insert_destructor(value: Value, loc: &Value, state: &State) { - if value.tpe.tpe and value.tpe.tpe.kind == typechecking::TypeKind::STATIC_ARRAY and typechecking::has_destructor(value.tpe.tpe) { + if is_weak_ref(value.tpe.tpe) { + // value refers to an address so we gotta load it first + value = state.load(value.tpe.tpe, value, loc) + let meta = state.extract_value(pointer(ref_meta()), value, [0], loc) + let ptr_addr = state.ptr_to_int(meta, loc) + let cond = state.icmp(CompareInt::eq, ptr_addr, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) + + let br = make_insn_dbg(InsnKind::BR, loc) + br.value.br = [ cond = cond ] !InsnBr + push_insn(br, state) + + let if_false = make_label(state) + push_label(if_false, state) + br.value.br.if_false = if_false + + let refcount = get_weak_count_ptr(value, loc, state) + let ptr_value = state.load(builtins::int64_, refcount, loc) + let ptr_add = state.sub(builtins::int64_, ptr_value, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value, loc) + state.store(refcount, ptr_add, loc) + + check_clear_ref_meta(meta, loc, state) + + let if_true = make_label(state) + let br_unc = make_insn_dbg(InsnKind::BR_UNC, loc) + br_unc.value.br_unc.label_ = if_true + push_insn(br_unc, state) + + push_label(if_true, state) + br.value.br.if_true = if_true + } else if value.tpe.tpe and value.tpe.tpe.kind == typechecking::TypeKind::STATIC_ARRAY and typechecking::has_destructor(value.tpe.tpe) { let counter_ptr = state.alloca(builtins::size_t_, loc) state.store(counter_ptr, [ kind = ValueKind::INT, tpe = builtins::size_t_, i = 0 ] !Value, loc) @@ -3493,8 +3568,11 @@ def insert_destructor(value: Value, loc: &Value, state: &State) { } } -def increase_pointer_by_one(value: Value, loc: &Value, state: &State) { - let ptr_addr = state.ptr_to_int(value, loc) +def increase_ref_count_of_value(value: Value, loc: &Value, state: &State) { + if not is_ref_or_weak(value.tpe) { return } + let meta = state.extract_value(pointer(ref_meta()), value, [0], loc) + + let ptr_addr = state.ptr_to_int(meta, loc) let cond = state.icmp(CompareInt::eq, ptr_addr, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) let br = make_insn_dbg(InsnKind::BR, loc) @@ -3505,9 +3583,16 @@ def increase_pointer_by_one(value: Value, loc: &Value, state: &State) { push_label(if_false, state) br.value.br.if_false = if_false - let ptr_value = state.load(builtins::int64_, value, loc) + var refcount: Value + if is_ref(value.tpe) { + refcount = get_ref_count_ptr(value, loc, state) + } else if is_weak_ref(value.tpe) { + refcount = get_weak_count_ptr(value, loc, state) + } + + let ptr_value = state.load(builtins::int64_, refcount, loc) let ptr_add = state.add(builtins::int64_, ptr_value, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value, loc) - state.store(value, ptr_add, loc) + state.store(refcount, ptr_add, loc) let if_true = make_label(state) let br_unc = make_insn_dbg(InsnKind::BR_UNC, loc) @@ -3517,47 +3602,11 @@ def increase_pointer_by_one(value: Value, loc: &Value, state: &State) { push_label(if_true, state) br.value.br.if_true = if_true } - -def increase_ref_count_of_value(value: Value, loc: &Value, state: &State) { - let index = allocate_ref(int, 1) - index(0) = 0 - - let extract_ret = make_local_value(typechecking::pointer(builtins::int64_), null, state) - let extract = make_insn_dbg(InsnKind::EXTRACTVALUE, loc) - extract.value.extract_value = [ - ret = extract_ret, - value = value, - index = index - ] !InsnExtractValue - push_insn(extract, state) - - increase_pointer_by_one(extract_ret, loc, state) -} def increase_ref_count(value: Value, loc: &Value, state: &State) { - let index1 = allocate_ref(Value, 2) - index1(0) = make_int_value(0) - index1(1) = make_int_value(0) - - let gep1_ret = make_local_value(typechecking::pointer(typechecking::pointer(builtins::int64_)), null, state) - let gep1 = make_insn_dbg(InsnKind::GETELEMENTPTR, loc) - gep1.value.gep = [ - ret = gep1_ret, - tpe = value.tpe.tpe, - value = value, - index = index1 - ] !InsnGetElementPtr - push_insn(gep1, state) - - let load1_ret = make_local_value(typechecking::pointer(builtins::int64_), null, state) - let load1 = make_insn_dbg(InsnKind::LOAD, loc) - load1.value.load = [ - value = load1_ret, - loc = gep1_ret - ] !InsnLoad - push_insn(load1, state) - - increase_pointer_by_one(load1_ret, loc, state) + if not is_ref_or_weak(value.tpe.tpe) { return } + value = state.load(value.tpe.tpe, value, loc) + increase_ref_count_of_value(value, loc, state) } // Leaving this in because it might be useful @@ -3569,9 +3618,13 @@ def copy_reference(value: Value, loc: &Value, state: &State) -> Value { let size = [ kind = ValueKind::INT, tpe = builtins::int64_, i = value.tpe.tpe.size ] !Value let size_int64 = [ kind = ValueKind::INT, tpe = builtins::int64_, i = builtins::int64_.size ] !Value - let ref_count_ptr_i8 = state.call("malloc", pointer(builtins::int8_), [size_int64], loc) - let ref_count_ptr = state.bitcast(pointer(builtins::int64_), ref_count_ptr_i8) - state.store(ref_count_ptr, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) + let ref_count_i8 = state.call("malloc", pointer(builtins::int8_), [[ kind = ValueKind::INT, tpe = builtins::size_t_, i = ref_meta().size ] !Value]) + let ref_count = state.bitcast(pointer(ref_meta()), ref_count_i8) + state.store(ref_count, [ kind = ValueKind::STRUCT, tpe = ref_meta(), values = [ + [kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value, + [kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value + ]] !Value) + let value_ptr = state.extract_value(pointer(value.tpe.tpe), value, [1], loc) let type_ptr = state.extract_value(pointer(builtins::Type_), value, [2], loc) @@ -3581,151 +3634,13 @@ def copy_reference(value: Value, loc: &Value, state: &State) -> Value { let copy_ptr = state.bitcast(pointer(value.tpe.tpe), copy_ptr_i8, loc) var ret = [ kind = ValueKind::UNDEF, tpe = value.tpe ] !Value - ret = state.insert_value(value.tpe, ret, ref_count_ptr, [0], loc) + ret = state.insert_value(value.tpe, ret, ref_count_i8, [0], loc) ret = state.insert_value(value.tpe, ret, copy_ptr, [1], loc) ret = state.insert_value(value.tpe, ret, type_ptr, [2], loc) return ret } -def assign_ref(value: Value, addr: Value, loc: &Value, is_initializer: bool, state: &State) { - if not value.addr { return } - - // First increase the ref count of the assigned value - increase_ref_count(@value.addr, loc, state) - - // Now decrease the ref count of the stored value - if not is_initializer { - insert_destructor(addr, loc, state) - } - - // Set the values for the new reference - let index1 = allocate_ref(Value, 2) - index1(0) = make_int_value(0) - index1(1) = make_int_value(0) - - let gep1_ret = make_local_value(typechecking::pointer(typechecking::pointer(builtins::int64_)), null, state) - let gep1 = make_insn_dbg(InsnKind::GETELEMENTPTR, loc) - gep1.value.gep = [ - ret = gep1_ret, - tpe = value.tpe, - value = value, - index = index1 - ] !InsnGetElementPtr - push_insn(gep1, state) - - let load1_ret = make_local_value(typechecking::pointer(builtins::int64_), null, state) - let load1 = make_insn_dbg(InsnKind::LOAD, loc) - load1.value.load = [ - value = load1_ret, - loc = gep1_ret - ] !InsnLoad - push_insn(load1, state) - - let gep2_ret = make_local_value(typechecking::pointer(typechecking::pointer(builtins::int64_)), null, state) - let gep2 = make_insn_dbg(InsnKind::GETELEMENTPTR, loc) - gep2.value.gep = [ - ret = gep2_ret, - tpe = addr.tpe.tpe, - value = addr, - index = index1 - ] !InsnGetElementPtr - push_insn(gep2, state) - - let index3 = allocate_ref(Value, 2) - index3(0) = make_int_value(0) - index3(1) = make_int_value(1) - - let gep3_ret = make_local_value(typechecking::pointer(typechecking::pointer(addr.tpe.tpe.tpe)), null, state) - let gep3 = make_insn_dbg(InsnKind::GETELEMENTPTR, loc) - gep3.value.gep = [ - ret = gep3_ret, - tpe = addr.tpe.tpe, - value = addr, - index = index3 - ] !InsnGetElementPtr - push_insn(gep3, state) - - let index4 = allocate_ref(Value, 2) - index4(0) = make_int_value(0) - index4(1) = make_int_value(2) - - let gep4_ret = make_local_value(typechecking::pointer(typechecking::pointer(builtins::Type_)), null, state) - let gep4 = make_insn_dbg(InsnKind::GETELEMENTPTR, loc) - gep4.value.gep = [ - ret = gep4_ret, - tpe = addr.tpe.tpe, - value = addr, - index = index4 - ] !InsnGetElementPtr - push_insn(gep4, state) - - let gep5_ret = make_local_value(typechecking::pointer(typechecking::pointer(value.tpe.tpe)), null, state) - let gep5 = make_insn_dbg(InsnKind::GETELEMENTPTR, loc) - gep5.value.gep = [ - ret = gep5_ret, - tpe = value.tpe, - value = @value.addr, - index = index3 - ] !InsnGetElementPtr - push_insn(gep5, state) - - let gep6_ret = make_local_value(typechecking::pointer(typechecking::pointer(builtins::Type_)), null, state) - let gep6 = make_insn_dbg(InsnKind::GETELEMENTPTR, loc) - gep6.value.gep = [ - ret = gep6_ret, - tpe = value.tpe, - value = @value.addr, - index = index4 - ] !InsnGetElementPtr - push_insn(gep6, state) - - let load3_ret = make_local_value(typechecking::pointer(value.tpe.tpe), null, state) - let load3 = make_insn_dbg(InsnKind::LOAD, loc) - load3.value.load = [ - value = load3_ret, - loc = gep5_ret - ] !InsnLoad - push_insn(load3, state) - - let bitcast_ret = make_local_value(typechecking::pointer(addr.tpe.tpe.tpe), null, state) - let bitcast = make_insn_dbg(InsnKind::BITCAST, loc) - bitcast.value.convert = [ - ret = bitcast_ret, - value = load3_ret - ] !InsnConvert - push_insn(bitcast, state) - - let load4_ret = make_local_value(typechecking::pointer(builtins::Type_), null, state) - let load4 = make_insn_dbg(InsnKind::LOAD, loc) - load4.value.load = [ - value = load4_ret, - loc = gep6_ret - ] !InsnLoad - push_insn(load4, state) - - let store2 = make_insn_dbg(InsnKind::STORE, loc) - store2.value.store = [ - loc = gep2_ret, - value = load1_ret - ] !InsnStore - push_insn(store2, state) - - let store3 = make_insn_dbg(InsnKind::STORE, loc) - store3.value.store = [ - loc = gep3_ret, - value = bitcast_ret - ] !InsnStore - push_insn(store3, state) - - let store4 = make_insn_dbg(InsnKind::STORE, loc) - store4.value.store = [ - loc = gep4_ret, - value = load4_ret - ] !InsnStore - push_insn(store4, state) -} - def call_set_attribute(n: &parser::Node, l: &parser::Node, value_type: &typechecking::Type, value: Value, loc: &Value, state: &State) -> bool { if not l or l.kind != parser::NodeKind::MEMBER_ACCESS { return false } @@ -3840,28 +3755,24 @@ def assign_post(n: &parser::Node, l: &parser::Node, value_type: &typechecking::T @ret = state.load(ret.tpe, tmp, loc) } - if typechecking::is_ref(l.tpe) and ret.addr and typechecking::is_ref(ret.addr.tpe) { - assign_ref(@ret.addr, @addr, loc, l.is_initializer, state) - } else { - if not l.is_initializer { - insert_destructor(@addr, loc, state) - } else if l.svalue and l.svalue.previous_underscore { - let pu = l.svalue.previous_underscore - let addr = [ kind = ValueKind::LOCAL, name = pu.assembly_name(state), tpe = pointer(pu.tpe) ] !Value - insert_destructor(addr, loc, state) - } - - let store = make_insn_dbg(InsnKind::STORE, loc) - (@store).value.store = [ - value = @ret, - loc = @addr - ] !InsnStore + if not l.is_initializer { + insert_destructor(@addr, loc, state) + } else if l.svalue and l.svalue.previous_underscore { + let pu = l.svalue.previous_underscore + let addr = [ kind = ValueKind::LOCAL, name = pu.assembly_name(state), tpe = pointer(pu.tpe) ] !Value + insert_destructor(addr, loc, state) + } + + let store = make_insn_dbg(InsnKind::STORE, loc) + (@store).value.store = [ + value = @ret, + loc = @addr + ] !InsnStore - push_insn(store, state) + push_insn(store, state) - if typechecking::is_ref(l.tpe) { - increase_ref_count(@addr, loc, state) - } + if typechecking::is_ref_or_weak(l.tpe) { + increase_ref_count(@addr, loc, state) } } return true @@ -4135,7 +4046,7 @@ def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, memb var member_type = member.tpe if member.tpe.kind == typechecking::TypeKind::BOX { - member_type = member.tpe.weak + member_type = member.tpe.wk } if tpe.kind == typechecking::TypeKind::UNION { @@ -4170,8 +4081,8 @@ def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, memb let res = walk_MemberAccess_gep(node, tpe, member_type, value, index, state) if member.is_embed and is_ref(member.tpe) { - let ref = state.load(member.tpe, @res.addr, loc) - let ptr = state.extract_value(pointer(member.tpe.tpe), ref, [1], loc) + let _ref = state.load(member.tpe, @res.addr, loc) + let ptr = state.extract_value(pointer(member.tpe.tpe), _ref, [1], loc) return make_address_value(pointer(member.tpe.tpe), ptr, state) } @@ -4419,8 +4330,8 @@ def walk_AlignOf(node: &parser::Node, state: &State) -> Value { return value } -def convert_ref_to_int(node: &parser::Node, value: Value, loc: &Value, state: &State) -> Value { - let gep_ret = state.extract_value(pointer(value.tpe.tpe), value, [1], loc) +def convert_ref_to_int(value: Value, loc: &Value, state: &State) -> Value { + let gep_ret = convert_ref_to_ptr(pointer(value.tpe.tpe if value.tpe.tpe else builtins::int8_), value, loc, state) return state.ptr_to_int(gep_ret, loc) } @@ -4532,10 +4443,10 @@ def compare(node: &parser::Node, left: Value, right: Value, state: &State) -> Va right = convert_to(node, right, builtins::size_t_, state) } if typechecking::is_ref_or_weak(left.tpe) { - left = convert_ref_to_int(node, left, loc, state) + left = convert_ref_to_int(left, loc, state) } if typechecking::is_ref_or_weak(right.tpe) { - right = convert_ref_to_int(node, right, loc, state) + right = convert_ref_to_int(right, loc, state) } if (@left.tpe).kind == typechecking::TypeKind::NULL { left = make_int_value(0) @@ -4702,7 +4613,7 @@ def walk_IfExpr(node: &parser::Node, state: &State) -> Value { push_label(entry_label, state) var true_value = convert_to(if_true, walk_expression(if_true, state), node.tpe, state) - if typechecking::is_ref(if_true.tpe) { + if typechecking::is_ref_or_weak(if_true.tpe) { increase_ref_count_of_value(true_value, loc, state) } else if typechecking::has_copy_constructor(if_true.tpe) { let ret = state.alloca(if_true.tpe, loc, no_yield_capture = true) @@ -4727,7 +4638,7 @@ def walk_IfExpr(node: &parser::Node, state: &State) -> Value { push_label(false_label, state) var false_value = convert_to(if_false, walk_expression(if_false, state), node.tpe, state) - if typechecking::is_ref(if_false.tpe) { + if typechecking::is_ref_or_weak(if_false.tpe) { increase_ref_count_of_value(false_value, loc, state) } else if typechecking::has_copy_constructor(if_false.tpe) { let ret = state.alloca(if_false.tpe, loc, no_yield_capture = true) @@ -4874,12 +4785,12 @@ export def walk_expression(node: &parser::Node, state: &State) -> Value { } if node.parent and node.parent.body and node.kind != parser::NodeKind::FUNC_CALL and node.kind != parser::NodeKind::ASSIGN and - expr.kind != ValueKind::NULL and expr.kind != ValueKind::ADDRESS and expr.tpe and expr.tpe.kind != typechecking::TypeKind::POINTER { + expr.kind != ValueKind::NULL and expr.kind != ValueKind::ADDRESS and expr.tpe and not is_pointer(expr.tpe) { let loc = make_location(node, state) let addr = state.alloca(expr.tpe, loc) state.store(addr, expr, loc) - if is_ref(expr.tpe) { + if is_ref_or_weak(expr.tpe) { increase_ref_count(addr, loc, state) } insert_destructor(addr, loc, state) @@ -5204,7 +5115,7 @@ def walk_Switch(node: &parser::Node, state: &State) { } def return_post(expr: Value, loc: &Value, state: &State) -> Value { - if is_ref(expr.tpe) { + if is_ref_or_weak(expr.tpe) { increase_ref_count_of_value(expr, loc, state) } if typechecking::has_copy_constructor(expr.tpe) { @@ -5540,7 +5451,7 @@ def walk_For_array(node: &parser::Node, state: &State) { var value = state.load(expr.tpe.tpe, value_ptr, loc) state.store(locv, value) - if is_ref(expr.tpe.tpe) { + if is_ref_or_weak(expr.tpe.tpe) { increase_ref_count(locv, loc, state) } else if has_copy_constructor(expr.tpe.tpe) { insert_copy_constructor(locv, value, loc, state) @@ -5975,9 +5886,12 @@ def create_closure_context(function: &Function, ret: Value, loc: &Value, state: let context_tpe = function.state let context_ptr_i8 = state.call("malloc", pointer(builtins::int8_), [[ kind = ValueKind::INT, tpe = builtins::size_t_, i = context_tpe.size ] !Value], loc) - let ref_count_i8 = state.call("malloc", pointer(builtins::int8_), [[ kind = ValueKind::INT, tpe = builtins::size_t_, i = builtins::int64_.size ] !Value], loc) - let ref_count = state.bitcast(pointer(builtins::int64_), ref_count_i8, loc) - state.store(ref_count, [ kind = ValueKind::INT, tpe = ValueKind::int64_, i = 1 ] !Value, loc) + let ref_count_i8 = state.call("malloc", pointer(builtins::int8_), [[ kind = ValueKind::INT, tpe = builtins::size_t_, i = ref_meta().size ] !Value], loc) + let ref_count = state.bitcast(pointer(ref_meta()), ref_count_i8, loc) + state.store(ref_count, [ kind = ValueKind::STRUCT, tpe = ref_meta(), values = [ + [kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value, + [kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value + ]] !Value, loc) let context_tpe_value = do_create_type(reference(context_tpe), state.module) @@ -6014,7 +5928,7 @@ def create_closure_context_captures(function: &Function, loc: &Value, state: &St value = [ kind = ValueKind::LOCAL, tpe = capture.tpe, name = svalue.assembly_name(state) ] !Value } else { let addr = [ kind = ValueKind::LOCAL, tpe = pointer(capture.tpe), name = svalue.assembly_name(state) ] !Value - if is_ref(addr.tpe.tpe) { + if is_ref_or_weak(addr.tpe.tpe) { increase_ref_count(addr, loc, state) value = state.load(capture.tpe, addr, loc) } else if has_copy_constructor(addr.tpe.tpe) { @@ -6715,9 +6629,9 @@ def di_ref_type(value: &Value, tpe: &typechecking::Type, is_weak: bool, state: & fields(0) = [ name = "ref_count", tpe = typechecking::pointer(builtins::int64_) ] !StructMember fields(1) = [ name = "value", tpe = typechecking::pointer(tpe.tpe) ] !StructMember fields(2) = [ name = "tpe", tpe = typechecking::pointer(builtins::Type_) ] !StructMember - let ref = typechecking::make_struct_type(fields) + let _ref = typechecking::make_struct_type(fields) - return di_composite_type(value, ref, "" if is_weak else "", "DW_TAG_structure_type", state) + return di_composite_type(value, _ref, "" if is_weak else "", "DW_TAG_structure_type", state) } def di_type(tpe: &typechecking::Type, state: &State) -> &Value { @@ -6740,7 +6654,7 @@ def di_type(tpe: &typechecking::Type, state: &State) -> &Value { (@state).ditypes(tpe) = ditpep if tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk } switch tpe.kind !int { // TODO compare with char for special casing @@ -6776,7 +6690,7 @@ def di_type(tpe: &typechecking::Type, state: &State) -> &Value { } case typechecking::TypeKind::FUNCTION @ditpe = @di_function_type(tpe, state) - case typechecking::TypeKind::POINTER + case typechecking::TypeKind::POINTER, typechecking::TypeKind::BYREF @ditpe = @di_pointer_type(tpe, state) case typechecking::TypeKind::REFERENCE, typechecking::TypeKind::WEAK_REF @ditpe = @di_ref_type(ditpep, tpe, tpe.kind == typechecking::TypeKind::WEAK_REF, state) @@ -7208,7 +7122,7 @@ def create_generator( let local_ptr = state.gep(pointer(par.tpe), context, context_ptr, [make_int_value(0), make_int_value(i + 1)]) state.store(local_ptr, [ kind = ValueKind::LOCAL, name = par.name + ".value", tpe = par.tpe ] !Value) - if typechecking::is_ref(par.tpe) { + if typechecking::is_ref_or_weak(par.tpe) { increase_ref_count(local_ptr, null, state) } } @@ -7227,11 +7141,12 @@ def create_generator( let context_ptr_i8_ptr = state.gep(pointer(generator.fields(1).tpe), generator, gen_ptr, [make_int_value(0), make_int_value(1)]) state.store(context_ptr_i8_ptr, context_ptr_i8) - let ref_count_ptr_i8 = state.call("malloc", typechecking::pointer(builtins::int8_), [ - [ kind = ValueKind::INT, tpe = builtins::size_t_, i = builtins::size_t_.size ] !Value - ]) - let ref_count = state.bitcast(pointer(builtins::size_t_), ref_count_ptr_i8) - state.store(ref_count, [ kind = ValueKind::INT, tpe = builtins::size_t_, i = 1 ] !Value) + let ref_count_i8 = state.call("malloc", pointer(builtins::int8_), [[ kind = ValueKind::INT, tpe = builtins::size_t_, i = ref_meta().size ] !Value]) + let ref_count = state.bitcast(pointer(ref_meta()), ref_count_i8) + state.store(ref_count, [ kind = ValueKind::STRUCT, tpe = ref_meta(), values = [ + [kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value, + [kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value + ]] !Value) var gen_ref = [ kind = ValueKind::ZEROINITIALIZER, tpe = reference(generator) ] !Value gen_ref = state.insert_value(reference(generator), gen_ref, ref_count, [0]) @@ -7586,7 +7501,7 @@ export def create_function( push_insn(store, state) - if typechecking::is_ref(value) { + if typechecking::is_ref_or_weak(value) { increase_ref_count(ret, null, state) } } @@ -7744,9 +7659,10 @@ export def create_function( let parameter_t2 = vector::make(typechecking::NamedParameter) parameter_t2.push([ name = "__context", _tpe = typechecking::pointer(null) ] !typechecking::NamedParameter) - let free_context_tpe = typechecking::make_function_type_n(parser::make_identifier(tpe.name + ".free_context"), - free_context_parameters, vector::make(type &typechecking::Type), state.module, context = state.module + let free_context_tpe = typechecking::make_function_type_n(parser::make_identifier(tpe.name + ".free_context." + state.context_ptr), + free_context_parameters, vector::make(type &typechecking::Type), state.module, context = function.module ) + state.context_ptr += 1 let free_context = predeclare_function(free_context_tpe, state.module) free_context.is_compiled = true @@ -8265,7 +8181,7 @@ def create_constructor(copy: Value, this: Value, state: &State) { let ctor = typechecking::get_constructor(member.tpe) state.call(ctor.tpe.type_name, null, [copy_ptr, this_ptr]) } - } else if typechecking::is_ref(member.tpe) { + } else if typechecking::is_ref_or_weak(member.tpe) { let copy_ptr = state.gep(pointer(member.tpe), copy.tpe.tpe, copy, [make_int_value(0), make_int_value(i)]) increase_ref_count(copy_ptr, null, state) } @@ -8327,9 +8243,18 @@ export def create_destructor(tpe: &typechecking::Type) { state.current_block = previous_block } +def get_ref_count_ptr(value: Value, loc: &Value, state: &State) -> Value { + let meta = state.extract_value(pointer(ref_meta()), value, [0], loc) + return state.gep(pointer(builtins::int64_), ref_meta(), meta, [make_int_value(0), make_int_value(0)], loc) +} +def get_weak_count_ptr(value: Value, loc: &Value, state: &State) -> Value { + let meta = state.extract_value(pointer(ref_meta()), value, [0], loc) + return state.gep(pointer(builtins::int64_), ref_meta(), meta, [make_int_value(0), make_int_value(1)], loc) +} + def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { if typechecking::is_polymorph(tpe) { return } - assert tpe.kind == typechecking::TypeKind::POINTER + assert is_pointer(tpe) if tpe.tpe and tpe.tpe.kind == typechecking::TypeKind::TUNION { let stpe = tpe.tpe @@ -8375,13 +8300,28 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { } var structure_type = tpe.tpe - var ref: Value, ref_count_ptr: Value + var _ref: Value + var ref_count: Value var null_br: &Insn, br: &Insn + var br1: &Insn if typechecking::is_ref(tpe.tpe) and tpe.tpe.tpe and not is_interface(tpe.tpe.tpe) { // Decrease ref count - ref = state.load(tpe.tpe, value) - ref_count_ptr = state.extract_value(pointer(builtins::int64_), ref, [0]) + _ref = state.load(tpe.tpe, value) + ref_count = state.extract_value(pointer(ref_meta()), _ref, [0]) + let ref_count_value1 = state.ptr_to_int(ref_count) + + let isnull = state.icmp(CompareInt::eq, ref_count_value1, + [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) + + br1 = make_insn(InsnKind::BR) + br1.value.br = [ cond = isnull ] !InsnBr + push_insn(br1, state) + let nonnull = make_label(state) + push_label(nonnull, state) + br1.value.br.if_false = nonnull + + let ref_count_ptr = state.gep(pointer(builtins::int64_), ref_meta(), ref_count, [make_int_value(0), make_int_value(0)]) let ref_count_value = state.ptr_to_int(ref_count_ptr) let null_cond = state.icmp(CompareInt::eq, ref_count_value, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) null_br = make_insn(InsnKind::BR) @@ -8412,13 +8352,13 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { var size = NO_VALUE var data = NO_VALUE if structure_type.kind == typechecking::TypeKind::ARRAY { - let array_ptr = state.extract_value(pointer(structure_type), ref, [1]) + let array_ptr = state.extract_value(pointer(structure_type), _ref, [1]) let array = state.load(structure_type, array_ptr) size = state.extract_value(builtins::size_t_, array, [0]) data = state.extract_value(pointer(structure_type.tpe), array, [1]) } else if structure_type.kind == typechecking::TypeKind::STATIC_ARRAY { size = [ kind = ValueKind::INT, tpe = builtins::size_t_, i = structure_type.length ] !Value - data = state.extract_value(pointer(structure_type), ref, [1]) + data = state.extract_value(pointer(structure_type), _ref, [1]) } let counter_ptr = state.alloca(builtins::size_t_) @@ -8470,10 +8410,10 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { var to_end = make_insn(InsnKind::BR_UNC) var null_br2: &Insn = null if typechecking::is_ref(tpe.tpe) and (not tpe.tpe.tpe or typechecking::is_interface(tpe.tpe.tpe)) { - let ref = state.load(tpe.tpe, value) + let _ref = state.load(tpe.tpe, value) // Extract type - let ref_count = state.extract_value(pointer(builtins::int64_), ref, [0]) + let ref_count = state.extract_value(pointer(builtins::int64_), _ref, [0]) let ref_count_value = state.ptr_to_int(ref_count) let cond = state.icmp(CompareInt::eq, ref_count_value, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) null_br2 = make_insn(InsnKind::BR) @@ -8486,7 +8426,7 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { let fp = unbox((builtins::Type_).field_types(15).tpe) - let ref_tpe = state.extract_value(pointer(builtins::Type_), ref, [2]) + let ref_tpe = state.extract_value(pointer(builtins::Type_), _ref, [2]) let ref_tpe_deref = state.load(builtins::Type_, ref_tpe) let dtor = state.extract_value(fp, ref_tpe_deref, [15]) @@ -8501,8 +8441,8 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { state.module.imported.add(destructor.tpe.type_name) if typechecking::is_ref(tpe.tpe) { - let ref = state.load(tpe.tpe, value) - value = state.extract_value(pointer(structure_type), ref, [1]) + let _ref = state.load(tpe.tpe, value) + value = state.extract_value(pointer(structure_type), _ref, [1]) } state.call(destructor.tpe.type_name, null, [value]) } @@ -8523,8 +8463,8 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { var obj: Value if typechecking::is_ref(value.tpe.tpe) { - let ref = state.load(tpe.tpe, value) - obj = state.extract_value(pointer(structure_type), ref, [1]) + let _ref = state.load(tpe.tpe, value) + obj = state.extract_value(pointer(structure_type), _ref, [1]) } else { obj = value } @@ -8539,11 +8479,17 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { if typechecking::is_polymorph(field.tpe) { continue } let ptpe = pointer(field.tpe) let name = debug::type_to_str(ptpe, full_name = true) - let destructor = typechecking::get_builtin_destructor(field.tpe) - - if destructor { + + if is_weak_ref(field.tpe) { let field_value = state.gep(ptpe, structure_type, obj, [make_int_value(0), make_int_value(i)]) - state.call(destructor.tpe.type_name, null, [field_value]) + insert_destructor(field_value, null, state) + } else { + let destructor = typechecking::get_builtin_destructor(field.tpe) + + if destructor { + let field_value = state.gep(ptpe, structure_type, obj, [make_int_value(0), make_int_value(i)]) + state.call(destructor.tpe.type_name, null, [field_value]) + } } } } @@ -8555,13 +8501,29 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { predeclare_function(fun, state.module) state.module.imported.add(fun.type_name) import_structure(builtins::Ref_, state.module) - state.call(fun.type_name, null, [convert_ref_to_ref(builtins::Ref_, ref, null, state)]) + state.call(fun.type_name, null, [convert_ref_to_ref(builtins::Ref_, _ref, null, state)]) } - let ref_count_i8_ptr = state.bitcast(pointer(builtins::int8_), ref_count_ptr) - state.call("free", null, [ref_count_i8_ptr]) + let ref_count_value1 = state.ptr_to_int(ref_count) + + let isnull = state.icmp(CompareInt::eq, ref_count_value1, + [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value) + + let br2 = make_insn(InsnKind::BR) + br2.value.br = [ cond = isnull ] !InsnBr + push_insn(br2, state) + let nonnull = make_label(state) + push_label(nonnull, state) + br2.value.br.if_false = nonnull - value = state.extract_value(pointer(tpe.tpe.tpe), ref, [1]) + let cnt = get_weak_count_ptr(_ref, null, state) + var cnt_value = state.load(builtins::int64_, cnt) + cnt_value = state.sub(builtins::int64_, cnt_value, [ kind = ValueKind::INT, tpe = builtins::int64_, i = 1 ] !Value) + state.store(cnt, cnt_value) + + check_clear_ref_meta(ref_count, null, state) + + value = state.extract_value(pointer(tpe.tpe.tpe), _ref, [1]) if tpe.tpe.tpe.kind == typechecking::TypeKind::ARRAY { let array = state.load(tpe.tpe.tpe, value) @@ -8580,6 +8542,9 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { to_end.value.br_unc.label_ = end_label br.value.br.if_false = end_label null_br.value.br.if_true = end_label + br1.value.br.if_true = end_label + br2.value.br.if_true = end_label + push_label(end_label, state) } } @@ -8741,7 +8706,7 @@ def push_enum_values(tpe: &typechecking::Type, global: Value, module: &toolchain let svalue = tpe.scope.fields(key) let name_values = allocate_ref(Value, 2) - name_values(0) = [ kind = ValueKind::INT, tpe = builtins::int64_, i = key.length() + 1 ] !Value + name_values(0) = [ kind = ValueKind::INT, tpe = builtins::int64_, i = key.length() + 1 ] !Value name_values(1) = [ kind = ValueKind::UNDEF, tpe = pointer(builtins::int8_) ] !Value let eval_values = allocate_ref(Value, 2) @@ -9005,7 +8970,7 @@ def do_create_type(tpe: &typechecking::Type, svalue: &scope::Value, module: &too if toolchain::no_stdlib { return NO_VALUE } if tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk } let generic = typechecking::get_generic(tpe) @@ -9228,7 +9193,7 @@ def do_create_type(tpe: &typechecking::Type, svalue: &scope::Value, module: &too // Map of ToResolve let types_to_resolve = map::make(ToResolve) type ToResolve = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module tpe: &typechecking::Type } @@ -9251,13 +9216,13 @@ export def resolve_types { type TypeEntry = struct { tpe: &typechecking::Type value: &scope::Value - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module } export def create_type(tpe: &typechecking::Type, module: &toolchain::Module, cache: &Vector(TypeEntry)) -> &Value { if not tpe { return null } if tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk } if tpe.tc_incomplete { return null } let generic = typechecking::get_generic(tpe) diff --git a/src/consteval.pr b/src/consteval.pr index 9957e667..419952b6 100644 --- a/src/consteval.pr +++ b/src/consteval.pr @@ -348,6 +348,9 @@ export def walk_Def(node: &parser::Node, state: &typechecking::State) { tpe.type_name = tpe.name = scope::last_path_element(param.value.param.name) } else { tpe = typechecking::type_lookup(param.value.param.tpe, state, null, true) + if param.value.param.is_ref { + tpe = typechecking::byref(tpe) + } } var value: &compiler::Value @@ -411,7 +414,7 @@ export def walk_Def(node: &parser::Node, state: &typechecking::State) { is_closure = node.parent.kind != parser::NodeKind::PROGRAM, scope = state.scope, inner_scope = node.inner_scope, - captures = vector::make(type weak_ref(scope::Value)), + captures = vector::make(type weak &scope::Value), dllimport = dllimport, dllexport = dllexport or test, test = test, @@ -444,10 +447,10 @@ export def walk_Def(node: &parser::Node, state: &typechecking::State) { let type_constructor = typechecking::get_type_constructor(first_param.tpe) if type_constructor and type_constructor.cache { let type_name = debug::type_to_str(first_param.tpe, full_name = true) - let ref = [module = state.get_context(), name = type_name] !typechecking::TypeRef - if not map::contains(type_constructor.cache, ref) { + let _ref = [module = state.get_context(), name = type_name] !typechecking::TypeRef + if not map::contains(type_constructor.cache, _ref) { typechecking::generate_concrete_functions(type_constructor, first_param.tpe, state) - type_constructor.cache(ref) = first_param.tpe + type_constructor.cache(_ref) = first_param.tpe } } } diff --git a/src/debug.pr b/src/debug.pr index 3dc490f4..7b316179 100644 --- a/src/debug.pr +++ b/src/debug.pr @@ -835,7 +835,7 @@ export def type_to_str(tpe: &typechecking::Type, full_name: bool = false) -> Str if tpe.tc_tpe { return tc_args_to_string(tpe, full_name) } switch tpe.kind !int { case typechecking::TypeKind::BOX - return "Box<" + type_to_str(tpe.weak, full_name) + ">" + return "Box<" + type_to_str(tpe.wk, full_name) + ">" case typechecking::TypeKind::VOID return "void" case typechecking::TypeKind::BOOL @@ -862,7 +862,7 @@ export def type_to_str(tpe: &typechecking::Type, full_name: bool = false) -> Str return function_t_to_string(tpe, full_name) case typechecking::TypeKind::TUPLE return tuple_t_to_string(tpe, full_name) - case typechecking::TypeKind::POINTER + case typechecking::TypeKind::POINTER, typechecking::TypeKind::BYREF return pointer_t_to_string(tpe, full_name) case typechecking::TypeKind::REFERENCE return reference_t_to_string(tpe, full_name) diff --git a/src/eval.pr b/src/eval.pr index ae8f6f5c..0e5d004e 100644 --- a/src/eval.pr +++ b/src/eval.pr @@ -127,11 +127,11 @@ export def get(mem: *, tpe: &typechecking::Type) -> compiler::Value { return [ kind = compiler::ValueKind::FLOAT, tpe = tpe, f = result ] !compiler::Value case typechecking::TypeKind::BOOL return [ kind = compiler::ValueKind::BOOL, tpe = tpe, i = (@(mem !*bool)) !int64 ] !compiler::Value - case typechecking::TypeKind::POINTER + case typechecking::TypeKind::POINTER, typechecking::TypeKind::BYREF return [ kind = compiler::ValueKind::POINTER, tpe = tpe, i = @(mem !*int64) ] !compiler::Value case typechecking::TypeKind::REFERENCE, typechecking::TypeKind::WEAK_REF let values = allocate_ref(compiler::Value, 3) - values(0) = [ kind = compiler::ValueKind::POINTER, tpe = typechecking::pointer(builtins::size_t_), i = @(mem !*int64) ] !compiler::Value + values(0) = [ kind = compiler::ValueKind::POINTER, tpe = typechecking::pointer(compiler::ref_meta()), i = @(mem !*int64) ] !compiler::Value values(1) = [ kind = compiler::ValueKind::POINTER, tpe = typechecking::pointer(tpe.tpe), i = @((mem ++ (size_of type *)) !*int64) ] !compiler::Value values(2) = [ kind = compiler::ValueKind::POINTER, tpe = typechecking::pointer(builtins::Type_), i = @((mem ++ (size_of type *) * 2) !*int64) ] !compiler::Value return [ kind = compiler::ValueKind::STRUCT, tpe = tpe, values = values ] !compiler::Value @@ -271,7 +271,7 @@ def set(mem: *, tpe: &typechecking::Type, value: compiler::Value) { } else { assert(false) } - case typechecking::TypeKind::POINTER + case typechecking::TypeKind::POINTER, typechecking::TypeKind::BYREF (@(mem !*int64)) = value.i case typechecking::TypeKind::REFERENCE, typechecking::TypeKind::WEAK_REF @(mem !*int64) = value.values(0).i @@ -364,7 +364,7 @@ def unwrap_undef(value: compiler::Value) -> compiler::Value { value = [ kind = compiler::ValueKind::ARRAY, tpe = value.tpe, values = values ] !compiler::Value } else if value.tpe.kind == typechecking::TypeKind::REFERENCE or value.tpe.kind == typechecking::TypeKind::WEAK_REF { let values = allocate_ref(compiler::Value, 3) - values(0) = [ kind = compiler::ValueKind::UNDEF, tpe = typechecking::pointer(builtins::size_t_) ] !compiler::Value + values(0) = [ kind = compiler::ValueKind::UNDEF, tpe = typechecking::pointer(compiler::ref_meta()) ] !compiler::Value values(1) = [ kind = compiler::ValueKind::UNDEF, tpe = typechecking::pointer(value.tpe.tpe) ] !compiler::Value values(2) = [ kind = compiler::ValueKind::UNDEF, tpe = typechecking::pointer(builtins::Type_) ] !compiler::Value value = [ kind = compiler::ValueKind::STRUCT, tpe = value.tpe, values = values ] !compiler::Value @@ -469,7 +469,7 @@ def eval_GetElementPtr(insn: &compiler::Insn, state: &State) { } } else if tpe.kind == typechecking::TypeKind::REFERENCE { if index == 0 { - tpe = typechecking::pointer(builtins::size_t_) + tpe = typechecking::pointer(compiler::ref_meta()) } else if index == 1 { addr = addr ++ (size_of type *) tpe = tpe.tpe diff --git a/src/lexer.pr b/src/lexer.pr index 111b73d1..bfeb07e2 100644 --- a/src/lexer.pr +++ b/src/lexer.pr @@ -99,7 +99,8 @@ export type TokenType = enum { K_ASSERT K_TYPE_OF K_UNDEF - K_WEAK_REF + K_REF + K_WEAK INTEGER FLOAT STRING @@ -223,9 +224,10 @@ let KEYWORDS = [ [token_type = TokenType::K_DEFINED, str = "defined"] !Keyword, [token_type = TokenType::K_DEFER, str = "defer"] !Keyword, [token_type = TokenType::K_TYPE_OF, str = "type_of"] !Keyword, - [token_type = TokenType::K_WEAK_REF, str = "weak_ref"] !Keyword, + [token_type = TokenType::K_WEAK, str = "weak"] !Keyword, [token_type = TokenType::K_YIELD, str = "yield"] !Keyword, - [token_type = TokenType::K_IMPLICIT, str = "implicit"] !Keyword + [token_type = TokenType::K_IMPLICIT, str = "implicit"] !Keyword, + [token_type = TokenType::K_REF, str = "ref"] !Keyword ] export def token_list_to_json(list: *TokenList) -> &Json { diff --git a/src/parser.pr b/src/parser.pr index ec02c3f3..e46ac1aa 100644 --- a/src/parser.pr +++ b/src/parser.pr @@ -181,6 +181,7 @@ export type NodeParam = struct { name: &Node tpe: &Node value: &Node + is_ref: bool } export type NodeImportModule = struct { @@ -464,7 +465,7 @@ export type Node = struct { // For things like if statements or functions inner_scope: &scope::Scope value: NodeValue - parent: weak_ref(Node) + parent: weak &Node // Set to prevent destructors being called on uninitalized values is_initializer: bool @@ -474,7 +475,7 @@ export type Node = struct { body: &Vector(&Node) // This is used by assignment to track let kw: VarDecl - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module is_recursive_type: bool // Need to keep copied type nodes in the tree @@ -1855,51 +1856,25 @@ def expect_array_or_tuple(parse_state: &ParseState) -> &Node { } def expect_weak_ref(parse_state: &ParseState, inline_types: bool) -> &Node { - var tok = expect(parse_state, lexer::TokenType::K_WEAK_REF, "Expected weak_ref") + var tok = expect(parse_state, lexer::TokenType::K_WEAK, "Expected weak") let line = tok.line let column = tok.column - - var tpe: &Node = null - var kw = VarDecl::VAR - tok = peek(parse_state) - if tok.tpe == lexer::TokenType::O_PAREN { - pop(parse_state) - skip_newline(parse_state) - tok = peek(parse_state) - if tok.tpe == lexer::TokenType::K_VAR { - pop(parse_state) - skip_newline(parse_state) - } else if tok.tpe == lexer::TokenType::K_LET { - pop(parse_state) - kw = VarDecl::LET - skip_newline(parse_state) - } - - var tokens = parse_state.tokens - tpe = parse_type(parse_state, inline_types) - if not tpe { - parse_state.tokens = tokens - } - - skip_newline(parse_state) - expect(parse_state, lexer::TokenType::C_PAREN, "Expected ')'") - } + let tpe = expect_type(parse_state) var node = make_node(NodeKind::WEAK_REF_T, line, column, parse_state) node.value.t_parr = [ - kw = kw, tpe = tpe ] !NodePtrArrayT - node._hash = combine_hashes(node.kind !uint64, kw !uint64, hash(tpe)) + node._hash = combine_hashes(node.kind !uint64, hash(tpe)) return node } -def expect_ptr_ref(parse_state: &ParseState, ref: bool, inline_types: bool) -> &Node { +def expect_ptr_ref(parse_state: &ParseState, _ref: bool, inline_types: bool) -> &Node { var kind: NodeKind var tok: lexer::Token - if ref { + if _ref { kind = NodeKind::REF_T tok = expect(parse_state, lexer::TokenType::OP_BAND, "Expected '&'") } else { @@ -2413,7 +2388,7 @@ def parse_type2(parse_state: &ParseState, inline_types: bool) -> &Node { tok.tpe == lexer::TokenType::OP_BAND { back(parse_state) return expect_ptr_ref(parse_state, tok.tpe == lexer::TokenType::OP_BAND, inline_types) - } else if tok.tpe == lexer::TokenType::K_WEAK_REF { + } else if tok.tpe == lexer::TokenType::K_WEAK { back(parse_state) return expect_weak_ref(parse_state, inline_types) } else if tok.tpe == lexer::TokenType::DOUBLE_COLON or @@ -3368,6 +3343,13 @@ def parse_def(parse_state: &ParseState, share: ShareMarker, impl: bool = false) var name: &Node = null var tpe: &Node = null var value: &Node = null + var is_ref = false + + if token.tpe == lexer::TokenType::K_REF { + pop(parse_state) + is_ref = true + token = peek(parse_state) + } if token.tpe == lexer::TokenType::OP_VARARGS { if varargs { @@ -3429,9 +3411,10 @@ def parse_def(parse_state: &ParseState, share: ShareMarker, impl: bool = false) kw = kw, name = name, tpe = tpe, - value = value + value = value, + is_ref = is_ref ] !NodeParam - param._hash = combine_hashes(param.kind !uint64, varargs !uint64, kw !uint64, hash(name), hash(tpe), hash(value)) + param._hash = combine_hashes(param.kind !uint64, varargs !uint64, kw !uint64, is_ref !uint64, hash(name), hash(tpe), hash(value)) params.push(param) diff --git a/src/repl.pr b/src/repl.pr index d9c9f186..a7447549 100644 --- a/src/repl.pr +++ b/src/repl.pr @@ -442,7 +442,7 @@ def execute(source: Str) { stack_frame = eval::make_stack_frame(main_function.block, "main", 1) - let mem = allocate(size_of type *) !** + let mem = allocate(16) !** // FIXME What are we doing here??? @mem = (*_args) !* stack_frame.locals("args.value") = mem diff --git a/src/runtime.pr b/src/runtime.pr index fbddf30b..cf15cafd 100644 --- a/src/runtime.pr +++ b/src/runtime.pr @@ -89,8 +89,13 @@ export type Field = struct { tpe: *Type } +export type Refcount = struct { + strong_cnt: int64 + weak_cnt: int64 +} + export type Ref = struct { - ref_count: *int64 + ref_count: *Refcount value: * tpe: *Type } diff --git a/src/scope.pr b/src/scope.pr index 69f80490..110b8157 100644 --- a/src/scope.pr +++ b/src/scope.pr @@ -16,11 +16,11 @@ export type Ident = struct { name: Str signature: Str _hash: uint64 - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module } export type ImportedModule = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module alias: &parser::Node } @@ -72,7 +72,7 @@ export def find(ident: Ident) -> &Value { export type Value = struct { // This is needed to store the location - name_node: weak_ref(parser::Node) + name_node: weak &parser::Node share: parser::ShareMarker modifier: parser::VarDecl // Name used by the source code @@ -85,7 +85,7 @@ export type Value = struct { tpe: &typechecking::Type value: &compiler::Value _scope: &Scope - _module: weak_ref(Scope) // This is needed for modules referencing each other + _module: weak &Scope // This is needed for modules referencing each other // In case multiple values share one name (overloaded functions) next: &Value phase: Phase @@ -97,7 +97,7 @@ export type Value = struct { dllimport: bool dllexport: bool // Definition of the value - node: weak_ref(parser::Node) + node: weak &parser::Node state: &typechecking::State // For imported scopes, this checks if a value is exported before accessing it // Also used by serialize to signal that a function is imported (ffi) @@ -122,7 +122,7 @@ export type Value = struct { references: &Vector(parser::SourceLoc) // Don't serialize these is_generated: bool - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module } export def assembly_name(value: &Value, state: &compiler::State) -> Str { @@ -198,16 +198,16 @@ export def find_references_to(value: &Value) -> &Vector(parser::SourceLoc) { } export type ReExport = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module pattern: &parser::Node } export type Scope = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module is_function: bool // Counter for local scopes (shadowing) scope_count: int - parent: weak_ref(Scope) + parent: weak &Scope fields: &SMap(&Value) implicits: &Vector(&Value) // This is a list of imported scopes, @@ -938,7 +938,7 @@ export def generate_function(scope: &Scope, node: &parser::Node, parameter_t: &V for var i in 0..found_member.return_t.length { var tpe = found_member.return_t(i) if tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk } return_t.push(typechecking::copy(tpe)) } @@ -970,7 +970,7 @@ export def generate_function(scope: &Scope, node: &parser::Node, parameter_t: &V module.dyn_dispatch_consteval.push(tpe) return value - } else if vector::length(parameter_t) == 1 and first_parameter.tpe.kind == typechecking::TypeKind::POINTER and + } else if vector::length(parameter_t) == 1 and is_pointer(first_parameter.tpe) and name == "__destruct__" and typechecking::has_destructor(first_parameter.tpe.tpe) { let args = vector::make(typechecking::NamedParameter) diff --git a/src/serialize.pr b/src/serialize.pr index b3f797cd..6817cdf9 100644 --- a/src/serialize.pr +++ b/src/serialize.pr @@ -14,7 +14,7 @@ import util import builtins type Serialize = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module types: &Map(&typechecking::Type, int64) dependencies: &Set(scope::Ident) } @@ -25,7 +25,7 @@ def add_type(tpe: &typechecking::Type, state: &Serialize) -> int64 { if not tpe { return -1 } if tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk assert tpe.kind != typechecking::TypeKind::BOX } @@ -139,7 +139,7 @@ def serialize_type(fp: File, tpe: &typechecking::Type, state: &Serialize) { return } if tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk } assert tpe.kind != typechecking::TypeKind::BOX @@ -1091,7 +1091,7 @@ type TypeEntry = struct { } export type Deserialize = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module types: &Vector(&typechecking::Type) nodes: &Vector(&parser::Node) // Strong references to nodes scopes: &Vector(&scope::Scope) // Strong references to enum scopes diff --git a/src/toolchain.pr b/src/toolchain.pr index e0ba116e..356bf4c9 100644 --- a/src/toolchain.pr +++ b/src/toolchain.pr @@ -216,7 +216,7 @@ export type Module = struct { difile: &compiler::Value stage: Stage imports: &Set(Str) - dependants: &Set(weak_ref(Module)) + dependants: &Set(weak &Module) // List of Type // This is a list of functions that are generated for dynamic dispatch dyn_dispatch_consteval: &Vector(&typechecking::Type) @@ -225,7 +225,7 @@ export type Module = struct { // This is needed to generate functions from create_destructor compiler_state: &compiler::State state: &typechecking::State - unresolved: &Map(scope::Ident, weak_ref(scope::Value)) + unresolved: &Map(scope::Ident, weak &scope::Value) // Incremental compilation // This is set to true if the source file is newer than the cache or // any of the dependencies changed @@ -304,10 +304,10 @@ export def make_module( code = compiler::make_block(), imported = set::make(), imports = set::make(Str), - dependants = set::make(type weak_ref(Module)), + dependants = set::make(type weak &Module), dyn_dispatch_consteval = vector::make(type &typechecking::Type), dyn_dispatch = vector::make(type &typechecking::Type), - unresolved = map::make(scope::Ident, type weak_ref(scope::Value)), + unresolved = map::make(scope::Ident, type weak &scope::Value), inlay_hints = vector::make(type &parser::Node), closures = vector::make(type &scope::Value), is_dirty = no_incremental, diff --git a/src/typechecking.pr b/src/typechecking.pr index c2b291bf..b9cdf251 100644 --- a/src/typechecking.pr +++ b/src/typechecking.pr @@ -31,6 +31,7 @@ export type TypeKind = enum { CLOSURE TUPLE POINTER + BYREF // ref parameter REFERENCE WEAK_REF ARRAY @@ -59,9 +60,9 @@ export type TypeKind = enum { // Tagged union types, very similar to VARIANT but the equality relation is different // This is actually called variant in runtime TUNION - // References to structs are using a weak reference, ie. Type::weak instead of Type::_tpe + // References to structs are using a wk reference, ie. Type::wk instead of Type::_tpe // This is because references to structs can cause cycles - // TODO I think we don't really need this because we can just use weak directly + // TODO I think we don't really need this because we can just use wk directly BOX VOID TO_INFER // Placeholder type for inference @@ -75,7 +76,7 @@ export type TypeMember = struct { export type StructMember = struct { // Source line line: int - node: weak_ref(parser::Node) + node: weak &parser::Node name: Str tpe: &Type // index into the field_types vector @@ -99,7 +100,7 @@ export type StructuralTypeMember = struct { } export type TypeRef = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module name: Str } @@ -120,10 +121,10 @@ export type Type = struct { kind: TypeKind // Source line line: int - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module // Module that this type was defined in - _defmodule: weak_ref(toolchain::Module) - context: weak_ref(toolchain::Module) + _defmodule: weak &toolchain::Module + context: weak &toolchain::Module state: &State // Name of the type as used by the source code // Might be the name of a typedef @@ -141,7 +142,7 @@ export type Type = struct { // This is also used for type arguments to specify the actual type // And tagged unions carry the underlying union type _tpe: &Type - weak: weak_ref(Type) + wk: weak &Type packed: bool // Fields for struct, array of StructMember fields: &[StructMember] @@ -154,18 +155,18 @@ export type Type = struct { // Vector of NamedParameter parameter_t: &Vector(NamedParameter) // Enum scope - scope: weak_ref(scope::Scope) + scope: weak &scope::Scope // Structural types // Vector of StructuralTypeMember members: &Vector(StructuralTypeMember) share: parser::ShareMarker // TODO Types should not have a share, this needs to be on the value instead (and only there) - node: weak_ref(parser::Node) + node: weak &parser::Node // Type constructors save a template of a type - tc_node: weak_ref(parser::Node) + tc_node: weak &parser::Node // Cache of specialized type constructor cache: &Map(TypeRef, &Type) // Type constructor instances have a type and arguments - tc_tpe: weak_ref(Type) + tc_tpe: weak &Type // Vector of Type, also used by GENERIC tc_args: &Vector(&Type) // True if some parameters weren't set yet @@ -174,10 +175,10 @@ export type Type = struct { // This is used by variant, tagged union and interface impl variants: &Set(&Type) _hash: uint64 - svalue: weak_ref(scope::Value) + svalue: weak &scope::Value // This is used by deserialization to check if a type is in the - // type cache, so that structs can keep a weak reference to the type + // type cache, so that structs can keep a wk reference to the type is_in_type_cache: bool // Set on type arguments is_type_argument: bool @@ -481,7 +482,7 @@ export def has_copy_constructor(tpe: &Type, lookup: bool = true) -> bool { return res } -export def defmodule(tpe: &Type) -> weak_ref(toolchain::Module) { +export def defmodule(tpe: &Type) -> weak &toolchain::Module { if not tpe { return null } if tpe._defmodule { return tpe._defmodule } return tpe.module @@ -490,7 +491,7 @@ export def defmodule(tpe: &Type) -> weak_ref(toolchain::Module) { export def tpe(tpe: &Type) -> &Type { if not tpe { return null } if tpe._tpe and tpe._tpe.kind == TypeKind::BOX { - return tpe._tpe.weak + return tpe._tpe.wk } return tpe._tpe } @@ -504,7 +505,7 @@ export def get_module(tpe: &Type) -> &toolchain::Module { export def box(tpe: &Type) -> &Type { if not tpe { return null } let box = make_type_raw(TypeKind::BOX) - box.weak = tpe + box.wk = tpe return box } @@ -513,24 +514,24 @@ export type NamedParameter = struct { name: Str _tpe: &Type varargs: bool - node: weak_ref(parser::Node) + node: weak &parser::Node value: &compiler::Value kw: parser::VarDecl - type_node: weak_ref(parser::Node) + type_node: weak &parser::Node } export def tpe(np: NamedParameter) -> &Type { if not np._tpe { return null } if np._tpe.kind == TypeKind::BOX { - return np._tpe.weak + return np._tpe.wk } return np._tpe } export type State = struct { - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module counter: int - scope: weak_ref(scope::Scope) + scope: weak &scope::Scope // Vector of Type function_stack: &Vector(&compiler::Function) in_defer: bool @@ -626,6 +627,7 @@ export def is_boolean(tpe: &Type, module: &Module) -> bool { (@tpe).kind == TypeKind::WORD or (@tpe).kind == TypeKind::FLOAT or (@tpe).kind == TypeKind::POINTER or + (@tpe).kind == TypeKind::BYREF or (@tpe).kind == TypeKind::REFERENCE or (@tpe).kind == TypeKind::WEAK_REF or tpe.kind == TypeKind::CHAR or @@ -637,8 +639,8 @@ export def is_boolean(tpe: &Type, module: &Module) -> bool { export def is_pointer(tpe: &Type) -> bool { if not tpe { return false } - return (@tpe).kind == TypeKind::POINTER - // TODO What about references? + return (@tpe).kind == TypeKind::POINTER or + tpe.kind == TypeKind::BYREF } export def is_ref(tpe: &Type) -> bool { @@ -661,6 +663,7 @@ export def is_ref_or_weak(tpe: &Type) -> bool { export def is_box(tpe: &Type) -> bool { if not tpe { return false } return tpe.kind == TypeKind::POINTER or + tpe.kind == TypeKind::BYREF or tpe.kind == TypeKind::REFERENCE or tpe.kind == TypeKind::WEAK_REF or tpe.kind == TypeKind::STATIC_ARRAY or @@ -670,7 +673,7 @@ export def is_box(tpe: &Type) -> bool { export def unbox(tpe: &Type) -> &Type { if not tpe { return null } if tpe.kind == TypeKind::BOX { - return tpe.weak + return tpe.wk } return tpe } @@ -829,6 +832,14 @@ export def pointer(tpe: &Type) -> &Type { return pointer(tpe, parser::VarDecl::VAR) } +export def byref(tpe: &Type) -> &Type { + var t = make_type_raw(TypeKind::BYREF) + t._tpe = tpe + t.size = (size_of *) + t.align = (align_of *) + return t +} + export def reference(tpe: &Type, kw: parser::VarDecl) -> &Type { var t = make_type_raw(TypeKind::REFERENCE) t._tpe = tpe @@ -1029,7 +1040,7 @@ export type TypeEntry = struct { export type TypeEntryMember = struct { function: &Type exported: bool - module: weak_ref(toolchain::Module) + module: weak &toolchain::Module } export def create_type_entry(tpe: &Type) -> &TypeEntry { @@ -1116,7 +1127,7 @@ export def copy(a: &Type) -> &Type { a.kind == TypeKind::TYPE_DEF or a.kind == TypeKind::TYPE { if a._tpe and a._tpe.kind == TypeKind::BOX { - t._tpe = copy(a._tpe.weak) // Unbox for copy + t._tpe = copy(a._tpe.wk) // Unbox for copy } else { t._tpe = copy(a._tpe) } @@ -1141,10 +1152,10 @@ export def equals(a: &Type, b: &Type) -> bool { } if not a or not b { return false } if a.kind == TypeKind::BOX { - a = a.weak + a = a.wk } if b.kind == TypeKind::BOX { - b = b.weak + b = b.wk } if a.kind != TypeKind::TYPE and a._hash and b._hash { @@ -1203,6 +1214,7 @@ export def equals(a: &Type, b: &Type) -> bool { } if kind == TypeKind::ARRAY or kind == TypeKind::POINTER or + kind == TypeKind::BYREF or kind == TypeKind::REFERENCE or kind == TypeKind::WEAK_REF { @@ -1276,7 +1288,7 @@ def has_function(entry: &TypeEntry, intf: &Type, mb: StructuralTypeMember, modul implements(reference(tpe), intf, module) } if tpe.kind == typechecking::TypeKind::REFERENCE or tpe.kind == typechecking::TypeKind::WEAK_REF or - tpe.kind == typechecking::TypeKind::POINTER { + is_pointer(tpe) { tpe = tpe.tpe } @@ -1329,7 +1341,7 @@ def has_function(entry: &TypeEntry, intf: &Type, mb: StructuralTypeMember, modul let ta = return_t(k) var tb = mb.return_t(k) if tb.kind == TypeKind::BOX { - tb = tb.weak + tb = tb.wk } if not equals(ta, tb) { mismatch = true @@ -1383,9 +1395,9 @@ export def implements(a: &Type, b: &Type, module: &toolchain::Module, visited: & for var k in 0..vector::length(ma.return_t) { var ta = ma.return_t(k) - if ta.kind == TypeKind::BOX { ta = ta.weak } + if ta.kind == TypeKind::BOX { ta = ta.wk } var tb = mb.return_t(k) - if tb.kind == TypeKind::BOX { ta = tb.weak } + if tb.kind == TypeKind::BOX { ta = tb.wk } if not equals(ta, tb) { mismatch = true break @@ -1536,15 +1548,21 @@ const IMPLICIT = 15 export def convert_type_score(a: &Type, b: &Type, module: &toolchain::Module, is_type: bool = false, impl: bool = true) -> int { if not a or not b { return 0 } if a.kind == TypeKind::BOX { - a = a.weak + a = a.wk } if b.kind == TypeKind::BOX { - b = b.weak + b = b.wk } if equals(a, b) { return 0 } + + // If both are either refs or pointers + if is_pointer(a) and is_pointer(b) and equals(a.tpe, b.tpe) { + return 2 + } + // Convert anonymous struct to value if a.kind == b.kind and b.kind == TypeKind::STRUCT and b.is_anon { if a.fields.size != b.fields.size { return -1 } @@ -1601,7 +1619,7 @@ export def convert_type_score(a: &Type, b: &Type, module: &toolchain::Module, is if a.kind == TypeKind::TYPE and (equals(b, pointer(builtins::Type_)) or b.may_be_type) { return 4 } - if (a.kind == TypeKind::POINTER or a.kind == TypeKind::REFERENCE or a.kind == TypeKind::WEAK_REF) and (@b).kind == TypeKind::NULL { + if (is_pointer(a) or a.kind == TypeKind::REFERENCE or a.kind == TypeKind::WEAK_REF) and (@b).kind == TypeKind::NULL { return 0 } if a.kind == TypeKind::REFERENCE and equals(a.tpe, b) { @@ -1631,13 +1649,14 @@ export def convert_type_score(a: &Type, b: &Type, module: &toolchain::Module, is ((@b).kind == TypeKind::WORD or b.kind == TypeKind::CHAR) { return 10 } - if ((@a).kind == TypeKind::POINTER and (@b).kind == TypeKind::POINTER or + if (is_pointer(a) and is_pointer(b) or (@a).kind == TypeKind::REFERENCE and (@b).kind == TypeKind::REFERENCE) and (@a).tpe == null { return 4 } if a.kind == TypeKind::POINTER and b.kind == TypeKind::POINTER or + a.kind == TypeKind::BYREF and b.kind == TypeKind::BYREF or a.kind == TypeKind::REFERENCE and b.kind == TypeKind::REFERENCE or a.kind == TypeKind::WEAK_REF and b.kind == TypeKind::WEAK_REF or a.kind == TypeKind::ARRAY and b.kind == TypeKind::ARRAY or @@ -1751,7 +1770,7 @@ export def convert_type_score(a: &Type, b: &Type, module: &toolchain::Module, is return 2 if has_right_return_types else 3 } - if a.kind == TypeKind::CLOSURE and b.kind == TypeKind::POINTER and b._tpe and b._tpe.kind == TypeKind::FUNCTION { + if a.kind == TypeKind::CLOSURE and is_pointer(b) and b._tpe and b._tpe.kind == TypeKind::FUNCTION { b = b._tpe if vector::length(a.parameter_t) != vector::length(b.parameter_t) { return -1 @@ -1805,7 +1824,7 @@ export def convert_type_score(a: &Type, b: &Type, module: &toolchain::Module, is } return -1 } - if a.kind == TypeKind::POINTER or a.kind == TypeKind::REFERENCE or a.kind == TypeKind::WEAK_REF or a.kind == TypeKind::STATIC_ARRAY { + if is_pointer(a) or a.kind == TypeKind::REFERENCE or a.kind == TypeKind::WEAK_REF or a.kind == TypeKind::STATIC_ARRAY { if a.kind == b.kind { return convert_type_score(a.tpe, b.tpe, module, true) } @@ -2463,11 +2482,11 @@ export def type_lookup(node: &parser::Node, state: &State, current_type: &Type = if tpe and type_constructor and type_constructor.kind != TypeKind::STUB { let type_name = debug::type_to_str(tpe, full_name = true) - let ref = [module = state.get_context(), name = type_name] !typechecking::TypeRef - if not map::contains(type_constructor.cache, ref) { - type_constructor.cache(ref) = null + let _ref = [module = state.get_context(), name = type_name] !typechecking::TypeRef + if not map::contains(type_constructor.cache, _ref) { + type_constructor.cache(_ref) = null generate_concrete_functions(type_constructor, tpe, state) - type_constructor.cache(ref) = (tpe if tpe.tc_tpe !* == type_constructor !* else null !&Type) + type_constructor.cache(_ref) = (tpe if tpe.tc_tpe !* == type_constructor !* else null !&Type) } } if tpe and (tpe.kind == TypeKind::STRUCT or tpe.kind == TypeKind::UNION) { @@ -2531,6 +2550,12 @@ def lookup_field_type(node: &parser::Node, state: &State, current_type: &Type, c node.kind == parser::NodeKind::WEAK_REF_T or node.kind == parser::NodeKind::FUNCTION_T or node.kind == parser::NodeKind::CLOSURE_T { + + let prev_node = node + if node.kind == parser::NodeKind::WEAK_REF_T { + // Unwrap weak ref + node = node.value.t_parr.tpe + } if node.kind == parser::NodeKind::FUNCTION_T { let box = box(type_lookup(node, state, current_type, false, cache)) @@ -2564,18 +2589,24 @@ def lookup_field_type(node: &parser::Node, state: &State, current_type: &Type, c } } - if node.kind == parser::NodeKind::PTR_T { + if prev_node.kind == parser::NodeKind::PTR_T { stub = pointer(stub, node.value.t_parr.kw) - } else if node.kind == parser::NodeKind::REF_T { + } else if prev_node.kind == parser::NodeKind::REF_T { stub = reference(stub, node.value.t_parr.kw) - } else if node.kind == parser::NodeKind::ARRAY_T { + } else if prev_node.kind == parser::NodeKind::ARRAY_T { stub = array(stub, node.value.t_parr.kw) - } else if node.kind == parser::NodeKind::WEAK_REF_T { + } + + if prev_node.kind == parser::NodeKind::WEAK_REF_T { stub = weak_reference(stub, node.value.t_parr.kw) + stub.module = state.module + stub.node = node + prev_node.tpe = stub + } else { + stub.module = state.module + stub.node = node + node.tpe = stub } - stub.module = state.module - stub.node = node - node.tpe = stub return stub } else { @@ -2653,7 +2684,10 @@ export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Typ node.scope = state.scope if node.value.t_parr.tpe { node.value.t_parr.tpe.parent = node } var tpe = type_lookup(node.value.t_parr.tpe, state, current_type, lookup_default, cache) - tpe = weak_reference(tpe, node.value.t_parr.kw) + if not tpe or tpe.kind != TypeKind::REFERENCE { + errors::errorn(node, "Weak reference must point at a reference!") + } + tpe = weak_reference(tpe.tpe, tpe.kw) return tpe } else if node.kind == parser::NodeKind::STRUCT_T or node.kind == parser::NodeKind::UNION_T { @@ -4199,7 +4233,13 @@ export def lookup_parameters(node: &parser::Node, state: &State) -> &Type { let named = tpe.parameter_t.get(i) if not named.tpe or named.tpe.kind != TypeKind::TYPE { - let new_type = type_lookup(param.value.param.tpe, state, named.tpe, false) + var new_type: &Type + if param.value.param.is_ref { + new_type = typechecking::byref(type_lookup(param.value.param.tpe, state, named.tpe.tpe, false)) + } else { + new_type = type_lookup(param.value.param.tpe, state, named.tpe, false) + } + if new_type { //generate_ctor_and_dtor(new_type) @named.tpe = @new_type @@ -4336,7 +4376,7 @@ export def walk_Lambda(node: &parser::Node, state: &State) { is_closure = true, scope = state.scope, inner_scope = inner_scope, - captures = vector::make(type weak_ref(scope::Value)) + captures = vector::make(type weak &scope::Value) ] !&compiler::Function node.value.lambda.function = function @@ -4558,7 +4598,7 @@ export def walk_Def(node: &parser::Node, state: &State, polymorph: bool = false) is_closure = node.parent.kind != parser::NodeKind::PROGRAM, scope = state.scope, inner_scope = inner_scope, - captures = vector::make(type weak_ref(scope::Value)), + captures = vector::make(type weak &scope::Value), dllimport = dllimport, dllexport = dllexport, test = test, @@ -5072,7 +5112,7 @@ export def walk_Call(node: &parser::Node, dry_run: bool, state: &State) -> bool var tpe = (@left).tpe if tpe and tpe.kind == typechecking::TypeKind::BOX { - tpe = tpe.weak + tpe = tpe.wk } var arguments = vector::make(NamedParameter) @@ -5617,14 +5657,18 @@ export def lookup_struct_member(member: StructMember, resolved: &SSet = null) { if resolved.contains(name) { return } resolved.add(name) - if (tpe.kind == TypeKind::POINTER or + if (is_pointer(tpe) or tpe.kind == TypeKind::REFERENCE or - tpe.kind == TypeKind::WEAK_REF or tpe.kind == TypeKind::ARRAY) { if tpe._tpe and tpe._tpe.kind == TypeKind::STUB and tpe._tpe.state { tpe._tpe = box(type_lookup(tpe._tpe.node, tpe._tpe.state)) } tpe._hash = 0 + } else if tpe.kind == TypeKind::WEAK_REF { + if tpe._tpe and tpe._tpe.kind == TypeKind::STUB and tpe._tpe.state { + tpe._tpe = box(type_lookup(tpe.node.value.t_parr.tpe, tpe._tpe.state)) + } + tpe._hash = 0 } else if tpe.kind == typechecking::TypeKind::STRUCT { for var i in 0..tpe.fields.size { let field = tpe.fields(i) @@ -5722,7 +5766,7 @@ def walk_MemberAccess_aggregate(node: &parser::Node, ucs: bool, state: &State) - return false } if rtpe.kind == TypeKind::BOX { - rtpe = rtpe.weak + rtpe = rtpe.wk } node.tpe = rtpe } else if (@tpe).kind == TypeKind::ARRAY or (@tpe).kind == TypeKind::STATIC_ARRAY { diff --git a/std/map.pr b/std/map.pr index 46d50303..1850b399 100644 --- a/std/map.pr +++ b/std/map.pr @@ -9,15 +9,15 @@ export type Entry(type K, type V) = struct { value: V next: &Entry(K, V) // We maintain a linked list for ordering - l_prev: weak_ref(Entry(K, V)) - l_next: weak_ref(Entry(K, V)) + l_prev: weak &Entry(K, V) + l_next: weak &Entry(K, V) } export type Map(type K, type V) = struct { size: size_t entries: [&Entry(K, V)] - tail: weak_ref(Entry(K, V)) - head: weak_ref(Entry(K, V)) + tail: weak &Entry(K, V) + head: weak &Entry(K, V) } export type SMap(type V) = Map(Str, V) diff --git a/std/std.pr b/std/std.pr index 88c70c26..6c66bc28 100644 --- a/std/std.pr +++ b/std/std.pr @@ -11,7 +11,7 @@ from strings export * import map type Root = struct { - ref: runtime::Ref + _ref: runtime::Ref file: Str line: int } @@ -20,7 +20,7 @@ from strings export * var ref_roots: *&map::Map(uint64, Root) = null // This is so that we keep the memory around // Internal methods - def add_root(ref: runtime::Ref, file: *char, line: int) { + def add_root(_ref: runtime::Ref, file: *char, line: int) { if lock { return } // This is because otherwise we stack overflow because adding a reference creates new roots var l = lock lock = true @@ -28,27 +28,27 @@ from strings export * ref_roots = zero_allocate(type &map::Map(uint64, Root)) @ref_roots = map::make(uint64, Root) } - (@ref_roots)(ref.value !uint64) = [ ref = ref, file = make_string(file), line = line ] !Root + (@ref_roots)(_ref.value !uint64) = [ _ref = _ref, file = make_string(file), line = line ] !Root lock = l } - def remove_root(ref: runtime::Ref) { + def remove_root(_ref: runtime::Ref) { if lock { return } if not ref_roots { return } var l = lock lock = true - (@ref_roots).remove(ref.value !uint64) + (@ref_roots).remove(_ref.value !uint64) lock = l } - def find_cycle_root(ref: uint64, n: *int, all: &Set(uint64), children: &Set(uint64)) -> uint64 { - let root = (@ref_roots)(ref) + def find_cycle_root(_ref: uint64, n: *int, all: &Set(uint64), children: &Set(uint64)) -> uint64 { + let root = (@ref_roots)(_ref) let visited = set::make(uint64) - let cycle = find_cycle(n, root.ref, visited, all, children) + let cycle = find_cycle(n, root._ref, visited, all, children) if cycle { - error("Cycle root: ", ref_type(root.ref).tpe.name, " ", root.file + "@" + root.line, " (", ref !*, ") \n") + error("Cycle root: ", ref_type(root._ref).tpe.name, " ", root.file + "@" + root.line, " (", _ref !*, ") \n") } - all.add(ref) + all.add(_ref) return cycle } @@ -64,9 +64,9 @@ from strings export * def find_cycle(tpe: *runtime::Type, n: *int, cur: *, visited: &Set(uint64), all: &Set(uint64), children: &Set(uint64)) -> uint64 { if tpe.kind == runtime::TypeKind::REFERENCE { - let ref = @(cur !*runtime::Ref) - let cycle = find_cycle(n, ref, copy(visited), all, children) - children.add(ref.value !uint64) + let _ref = @(cur !*runtime::Ref) + let cycle = find_cycle(n, _ref, copy(visited), all, children) + children.add(_ref.value !uint64) return cycle } else if tpe.kind == runtime::TypeKind::STRUCT or tpe.kind == runtime::TypeKind::UNION { for var i in 0..tpe.fields.size { @@ -138,15 +138,15 @@ from strings export * let children = set::make(uint64) var n = 1 for var i in 0..keys.size { - let ref = keys(i) - if not ref { continue } - let root = (@ref_roots)(ref) + let _ref = keys(i) + if not _ref { continue } + let root = (@ref_roots)(_ref) cstd::printf("[%*d/%d] ".value, 1 + log10(num_roots) !int, i + 1, num_roots) let prev_n = n - print(ref !*, ": ", root.ref.tpe.name, " (" , @root.ref.ref_count, ")") + print(_ref !*, ": ", root._ref.tpe.name, " (" , @root._ref.ref_count, ")") fflush(stdout()) - find_cycle_root(ref, *n, all, children) + find_cycle_root(_ref, *n, all, children) print("\x1B[2K\r") } print("\n") @@ -158,11 +158,11 @@ from strings export * var m = 0 for var i in 0..keys.size { - let ref = keys(i) - if not ref { continue } - if not children.contains(ref) { - let root = (@ref_roots)(ref) - error("No reference to ", ref !*, ": ", root.ref.tpe.name, " ", root.file, "@", root.line, " (", @root.ref.ref_count, ")\n") + let _ref = keys(i) + if not _ref { continue } + if not children.contains(_ref) { + let root = (@ref_roots)(_ref) + error("No reference to ", _ref !*, ": ", root._ref.tpe.name, " ", root.file, "@", root.line, " (", @root._ref.ref_count, ")\n") m += 1 } } @@ -274,17 +274,17 @@ export def error(args: &...) -> int { } def make_ref(tpe: *runtime::Type, value: *) -> runtime::Ref { - var ref: runtime::Ref - ref.tpe = tpe - ref.value = value - return ref + var _ref: runtime::Ref + _ref.tpe = tpe + _ref.value = value + return _ref } //TODO Clang craps itself when I use defer in here -def print_val(file: File, ref: runtime::Ref) -> int { - let reftpe = runtime::ref_type(ref) +def print_val(file: File, _ref: runtime::Ref) -> int { + let reftpe = runtime::ref_type(_ref) let tpe = reftpe.tpe if reftpe else null !*runtime::Type - let value = ref.value + let value = _ref.value if not tpe or not value { return cstd::fprintf(file, "%p".value, value) } else if tpe == string { @@ -294,7 +294,7 @@ def print_val(file: File, ref: runtime::Ref) -> int { } else if tpe.kind == runtime::TypeKind::STATIC_ARRAY and tpe.tpe == char { return cstd::fprintf(file, "%s".value, value !*char) } else if tpe == StringSlice { - let slc = ref !&StringSlice + let slc = _ref !&StringSlice if slc.data { cstd::fwrite(slc.data ++ slc.offset, 1, slc.count, file) } else { @@ -396,10 +396,10 @@ def print_val(file: File, ref: runtime::Ref) -> int { } return cstd::fprintf(file, "%s".value, str.value) } else if runtime::implements(reftpe, ToString) { - let str = (ref !&ToString).to_string() + let str = (_ref !&ToString).to_string() return print_val(file, str !Ref) } else if runtime::implements(reftpe, IString) { - let str = (ref !String) + let str = (_ref !String) for var c in str.chars() { cstd::putc(c, file) } diff --git a/test/test_parser.pr b/test/test_parser.pr index ec261437..21f2a106 100644 --- a/test/test_parser.pr +++ b/test/test_parser.pr @@ -1279,43 +1279,38 @@ def #test test_pointer_types { } }""")) - assert parse("(type weak_ref)") == program(json::parse(""" { - "kind": "WeakRefT", - "kw": "VAR", - "tpe": null - }""")) - - assert parse("(type weak_ref(T))") == program(json::parse("""{ + assert parse("(type weak &)") == program(json::parse("""{ "kind": "WeakRefT", "kw": "VAR", "tpe": { - "kind": "Identifier", - "path": [ - "T" - ], - "prefixed": false, - "args": null + "kind": "RefT", + "kw": "VAR", + "tpe": null } }""")) - assert parse("(type weak_ref(var T))") == program(json::parse("""{ + assert parse("(type weak &T)") == program(json::parse("""{ "kind": "WeakRefT", "kw": "VAR", "tpe": { - "kind": "Identifier", - "path": [ - "T" - ], - "prefixed": false, - "args": null + "kind": "RefT", + "kw": "VAR", + "tpe": { + "kind": "Identifier", + "path": [ + "T" + ], + "prefixed": false, + "args": null + } } }""")) - assert parse("(type weak_ref(let *T))") == program(json::parse("""{ + assert parse("(type weak &var T)") == program(json::parse("""{ "kind": "WeakRefT", - "kw": "LET", + "kw": "VAR", "tpe": { - "kind": "PtrT", + "kind": "RefT", "kw": "VAR", "tpe": { "kind": "Identifier", @@ -1328,22 +1323,55 @@ def #test test_pointer_types { } }""")) - assert parse("(type weak_ref())") == program(json::parse(""" { + assert parse("(type weak &let *T)") == program(json::parse(""" { "kind": "WeakRefT", "kw": "VAR", - "tpe": null + "tpe": { + "kind": "RefT", + "kw": "LET", + "tpe": { + "kind": "PtrT", + "kw": "VAR", + "tpe": { + "kind": "Identifier", + "path": [ + "T" + ], + "prefixed": false, + "args": null + } + } + } }""")) - assert parse("(type weak_ref(let))") == program(json::parse("""{ + assert parse("(type weak &)") == program(json::parse("""{ "kind": "WeakRefT", - "kw": "LET", - "tpe": null + "kw": "VAR", + "tpe": { + "kind": "RefT", + "kw": "VAR", + "tpe": null + } }""")) - assert parse("(type weak_ref(var))") == program(json::parse(""" { + assert parse("(type weak &let)") == program(json::parse("""{ "kind": "WeakRefT", "kw": "VAR", - "tpe": null + "tpe": { + "kind": "RefT", + "kw": "LET", + "tpe": null + } + }""")) + + assert parse("(type weak &var)") == program(json::parse("""{ + "kind": "WeakRefT", + "kw": "VAR", + "tpe": { + "kind": "RefT", + "kw": "VAR", + "tpe": null + } }""")) } diff --git a/version b/version index 739174e7..d143f18a 100644 --- a/version +++ b/version @@ -1 +1 @@ -VERSION=0.3.11 \ No newline at end of file +VERSION=0.3.13 \ No newline at end of file