diff --git a/src/typechecking.pr b/src/typechecking.pr index ac679d12..5221c245 100644 --- a/src/typechecking.pr +++ b/src/typechecking.pr @@ -164,6 +164,9 @@ export type Type = struct { // Interface implementation intf: &Type + // This gets set if it might also be a type argument, in that case we also consider the overload with a type + // As an example, consider [int], this might be an array of types or an array type + may_be_type: &Type } export def hash(tpe: &Type) -> uint64 { @@ -1494,7 +1497,7 @@ export def convert_type_score(a: &Type, b: &Type, module: &toolchain::Module, is if a.kind == TypeKind::TYPE_DEF { return convert_type_score(a.tpe, b, module, true) } - if a.kind == TypeKind::TYPE and equals(b, pointer(builtins::Type_)) { + 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 { @@ -1942,9 +1945,11 @@ export def overload_score( } var score = -1 if lvalue and lvalue.kind == TypeKind::TYPE { + // TODO This is not documented and weird in more than one place + // I think the confusion comes from the fact that sometimes the type is stored in the NamedParameter + // and sometimes in the type directly. The latter would make more sense if equals(right.tpe, pointer(builtins::Type_)) { if left.value { - // TODO It's better to give TYPE a tpe, see below if equals(left.value.value_tpe, right.tpe.tpe.tpe) { score = 0 } @@ -1963,6 +1968,13 @@ export def overload_score( } else if left.tpe.tpe and right.tpe.tpe and equals(left.tpe.tpe, right.tpe.tpe) { score = 0 } + } else if right.tpe.may_be_type { + // This is what it should look like for the others as well + if not left.tpe.tpe { + score = 4 + } else if right.tpe.may_be_type.tpe and equals(left.tpe.tpe, right.tpe.may_be_type.tpe) { + score = 0 + } } } else { score = convert_type_score(lvalue, right.tpe, module, impl = impl) @@ -2295,6 +2307,23 @@ export def type_lookup(node: &parser::Node, state: &State, current_type: &Type = return tpe } +def convert_ambiguous_expr_to_type(node: &parser::Node, state: &State) -> &Type { + if node.kind == parser::NodeKind::ARRAY_LIT { + var res = { kind = parser::NodeKind::ARRAY_T } !&parser::Node + res.value.t_parr.tpe = node.value.body[0] + res.value.t_parr.tpe.tpe = convert_ambiguous_expr_to_type(res.value.t_parr.tpe, state) + res.tpe = type_lookup(res, state) + let arr_tpe = make_type_raw(TypeKind::TYPE) + arr_tpe._tpe = res.tpe + res.tpe = arr_tpe + res.tpe.node = null + + return res.tpe + } else if node.kind == parser::NodeKind::IDENTIFIER { + return type_lookup(node, state) + } +} + def lookup_field_type(node: &parser::Node, state: &State, current_type: &Type, cache: &map::SMap(&Type)) -> &Type { if not node { return null } node.scope = state.scope @@ -3087,13 +3116,17 @@ def walk_Identifier(node: &parser::Node, state: &State) { def implicit_conversion(node: &parser::Node, tpe: &Type, state: &State) { if not tpe { return } - // TODO For integers we need to check the boundaries - // TODO What about stuff like --10? I mean its kinda useless but for completeness - if node.kind == parser::NodeKind::NULL and is_pointer(tpe) or + // Convert type + if tpe.kind == TypeKind::TYPE and node.tpe and node.tpe.may_be_type { + node.tpe = node.tpe.may_be_type + } else if node.kind == parser::NodeKind::NULL and is_pointer(tpe) or is_arithmetic(tpe) and (node.kind == parser::NodeKind::INTEGER or (node.kind == parser::NodeKind::USUB or node.kind == parser::NodeKind::UADD) and (@node.value.expr).kind == parser::NodeKind::INTEGER) { + // TODO For integers we need to check the boundaries + // TODO What about stuff like --10? I mean its kinda useless but for completeness + node.tpe = tpe } else if is_function_pointer(tpe) and node.kind == parser::NodeKind::PTR and @@ -5214,6 +5247,11 @@ def walk_ArrayLit(node: &parser::Node, state: &State) { ret_tpe.size = len * (@tpe).size ret_tpe.align = (@tpe).align + // Check if we have a type array, in this case it might also be a type + if equals(tpe, pointer(builtins::Type_)) or tpe.may_be_type { + ret_tpe.may_be_type = convert_ambiguous_expr_to_type(node, state) + } + node.tpe = ret_tpe } @@ -5594,7 +5632,14 @@ export def walk_Def_with_type_argument(node: &parser::Node, parameter_t: &Vector } if left and equals(left.tpe, builtins::type_) { - left.value = { kind = compiler::ValueKind::TYPE, tpe = builtins::type_, value_tpe = np.tpe.tpe.tpe } !&compiler::Value + if np.tpe and np.tpe.may_be_type { + np._tpe = np.tpe.may_be_type + left.value = { kind = compiler::ValueKind::TYPE, tpe = builtins::type_, value_tpe = np.tpe.tpe } !&compiler::Value + left.tpe = np.tpe.may_be_type + parameter_t[i] = np + } else { + left.value = { kind = compiler::ValueKind::TYPE, tpe = builtins::type_, value_tpe = np.tpe.tpe.tpe } !&compiler::Value + } } } @@ -5624,7 +5669,19 @@ export def walk_Def_with_type_argument(node: &parser::Node, parameter_t: &Vector let old_scope = state.scope state.scope = node.inner_scope node.value.def_.has_lookup = false - node.tpe = tpe = lookup_parameters(node, state) + node.tpe = lookup_parameters(node, state) + + // Replace contextual type parameters + for var i in 0..node.tpe.parameter_t.length { + let left = node.tpe.parameter_t.get(i) + if i >= tpe.parameter_t.length { break } + let right = tpe.parameter_t.get(i) + if is_type(left.tpe) { + left._tpe._tpe = right.value.value_tpe + } + } + + tpe = node.tpe if vector::length(tpe.parameter_t) > 0 { let first_param = tpe.parameter_t[0]