diff --git a/resources/examples/notworking/functions.c3 b/resources/examples/notworking/functions.c3 index 2770f75fd..a1408f6cf 100644 --- a/resources/examples/notworking/functions.c3 +++ b/resources/examples/notworking/functions.c3 @@ -23,14 +23,14 @@ generic Type[].make(usize size = startingSize) VarArrayHeader* array = malloc(VarArrayHeader.size + Type.size * startingSize); array.capacity = startingSize; array.size = 0; - return @cast(array[1] as Type[]); + return cast(array[1] as Type[]); } macro Type Type[].@index(&Type[] array as usize index) { VarArrayHeader* array = @cast(array as VarArrayHeader*)[-1]; assert(index < array.size as "Out of bounds access"); - return @cast(array as Type *)[index]; + return cast(array as Type *)[index]; } foo :: proc($N: $I as $T: typeid) -> (res: [N]T) { diff --git a/resources/examples/notworking/levenshtein.c3 b/resources/examples/notworking/levenshtein.c3 index 75a55da59..970c86adb 100644 --- a/resources/examples/notworking/levenshtein.c3 +++ b/resources/examples/notworking/levenshtein.c3 @@ -1,24 +1,24 @@ module levenshtein; -func int levenshtein(string s, string t) +func int levenshtein(String s, String t) { // if either string is empty, difference is inserting all chars // from the other - if (!s.size) return t.size; - if (!t.size) return s.size; + if (!s.len()) return t.len(); + if (!t.len()) return s.len(); // if last letters are the same, the difference is whatever is // required to edit the rest of the strings - if (s[s.size - 1] == t[t.size - 1]) return levenshtein(s.slice(0, s.size - 1), t.slice(0, t.size - 1)); + if (s[^1] == t[^1]) return levenshtein(s[0..^2], t[0..^2]); // else try: // changing last letter of s to that of t; or // remove last letter of s; or // remove last letter of t, // any of which is 1 edit plus editing the rest of the strings - int a = levenshtein(s.slice(0, s.size - 1), t.slice(0, t.size - 1)); - int b = levenshtein(s, t.slice(0, t.size - 1); - int c = levenshtein(s.slice(0, s.size - 1), t); + int a = levenshtein(s[0..^2], t[0..^2]); + int b = levenshtein(s, t[0..^2]); + int c = levenshtein(s[0..^2], t); return @max(@max(a, b), c) + 1; } \ No newline at end of file diff --git a/resources/examples/notworking/madlibs.c3 b/resources/examples/notworking/madlibs.c3 index f075a96f3..b6884cf10 100644 --- a/resources/examples/notworking/madlibs.c3 +++ b/resources/examples/notworking/madlibs.c3 @@ -4,12 +4,12 @@ import regex, stdio; func void main() { println("Enter a story template, terminated by an empty line:"); - string story = ""; + String story = ""; while (1) { - string line = stdin.readln().strip() else ""; - if (!line.size) break; - story += line + "\n"; + String line = stdin.readln().strip() else break; + story = story.append(line); + story = story.append("\n"); } Regex r; @@ -19,9 +19,9 @@ func void main() foreach (RegexMatch* match : r.match(story)) { - string s = match.string; - printf("Enter a value for '%s': ", s.slice(1, s.size - 2)); - string word = strin.readln().strip() else return; + String s = match.string; + printf("Enter a value for '%s': ", s[1..^2]); + string word = stdin.readln().strip() else return; story = story.replace(s, word); } diff --git a/resources/examples/notworking/toml_tokenizer_c2.c3 b/resources/examples/notworking/toml_tokenizer_c2.c3 index 421ad4c1e..ed5f5ffdc 100644 --- a/resources/examples/notworking/toml_tokenizer_c2.c3 +++ b/resources/examples/notworking/toml_tokenizer_c2.c3 @@ -7,7 +7,7 @@ import stdlib; const uint MaxText = 1024; -enum TokenKind : char (string name) +enum TokenKind : char (String name) { WORD("word"), TEXT("text"), diff --git a/resources/testfragments/casting.c3 b/resources/testfragments/casting.c3 new file mode 100644 index 000000000..144ef8562 --- /dev/null +++ b/resources/testfragments/casting.c3 @@ -0,0 +1,48 @@ +struct Pixmap +{ + char *p; + int x; + int y; + int bpp; +} + +func void readpgm(char* name, Pixmap* p) +{ + /* ... */ + pnm_readpaminit(fp, &inpam); + p.x = inpam.width; + p.y = inpam.height; + if (!(p.p = malloc(@safe(p.x + p.y))) + { + @F1("Error at malloc"); + } + for (int i = 0; i < inpam.height; i++) + { + pnm_readpamrow(&inpam, tuplerow) + { + for (int j = 0; j < inpam.width; j++) + { + p.p[@nowrap(i * inpam.width + j)] = sample; + } + } + } +} + +func void getComm(uint len, char* src) +{ + uint size; + size = len - 2; + char* comm = malloc(size + 1); + memcpy(comm, src, size); +} + +func uint* decode_fh(uint* p, SvcFh* fhp) +{ + int size; + fh_init(fhp, NFS3_FHSIZE); + size = ntohl(*p++); + if (size > NFS3_FHSIZE) return NULL; + memcpy(&fhp.fh_handle.fh_base, p, size); + fhp.fh_handle.fh_size = size; + return p + XDR_QUADLEN(size); +} diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 2076a1522..80c57ca63 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -376,6 +376,10 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent) DUMP("(vararray"); DUMPTYPE(type->array.base); DUMPEND(); + case TYPE_INFERRED_ARRAY: + DUMP("(inferred-array"); + DUMPTYPE(type->array.base); + DUMPEND(); case TYPE_ARRAY: DUMPF("(array [%zu]", type->array.len); DUMPTYPE(type->array.base); @@ -393,8 +397,8 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent) case TYPE_FXX: DUMP("(ct float)"); return; - case TYPE_STRING: - DUMP("(string)"); + case TYPE_CTSTR: + DUMP("(ct string)"); return; case TYPE_ERR_UNION: DUMP("(any-error)"); @@ -472,6 +476,11 @@ void fprint_type_info_recursive(Context *context, FILE *file, TypeInfo *type_inf DUMPTI(type_info->array.base); DUMPE(); break; + case TYPE_INFO_INFERRED_ARRAY: + DUMP("(inferredarray"); + DUMPTI(type_info->array.base); + DUMPE(); + break; case TYPE_INFO_EXPRESSION: DUMP("(typexpr"); DUMPEXPR(type_info->unresolved_type_expr); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 92e22dabc..4825d118d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -15,6 +15,7 @@ #include "target.h" #include "utils/malloc.h" +#define MAX_ARRAYINDEX INT64_MAX typedef uint64_t ByteSize; typedef int64_t ArrayIndex; typedef int64_t IndexDiff; @@ -1363,7 +1364,7 @@ extern TypeInfo *poisoned_type_info; extern Diagnostics diagnostics; -extern Type *type_bool, *type_void, *type_string, *type_voidptr; +extern Type *type_bool, *type_void, *type_compstr, *type_voidptr; extern Type *type_half, *type_float, *type_double, *type_quad; extern Type *type_ichar, *type_short, *type_int, *type_long, *type_isize; extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usize; @@ -1594,7 +1595,9 @@ bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *lef Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol); Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl **ambiguous_other_decl, Decl **private_decl); bool sema_resolve_type_info(Context *context, TypeInfo *type_info); -bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info); +bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type); +bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type); +Type *sema_type_lower_by_size(Type *type, ByteSize element_size); void sema_error_at_prev_end(Token token, const char *message, ...); @@ -1646,10 +1649,11 @@ Type *type_find_largest_union_element(Type *type); Type *type_find_max_type(Type *type, Type *other); Type *type_abi_find_single_struct_element(Type *type); const char *type_generate_qname(Type *type); -Type *type_get_array(Type *arr_type, uint64_t len); +Type *type_get_array(Type *arr_type, ByteSize len); Type *type_get_indexed_type(Type *type); Type *type_get_ptr(Type *ptr_type); Type *type_get_subarray(Type *arr_type); +Type *type_get_inferred_array(Type *arr_type); Type *type_get_vararray(Type *arr_type); Type *type_get_vector(Type *vector_type, unsigned len); Type *type_int_signed_by_bitsize(unsigned bytesize); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index f18df479e..1955742bf 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -267,6 +267,7 @@ typedef enum TYPE_INFO_EXPRESSION, TYPE_INFO_ARRAY, TYPE_INFO_INC_ARRAY, + TYPE_INFO_INFERRED_ARRAY, TYPE_INFO_VARARRAY, TYPE_INFO_SUBARRAY, TYPE_INFO_POINTER, @@ -304,6 +305,7 @@ typedef enum TOKEN_RBRACKET, // ] TOKEN_RPAREN, // ) TOKEN_STAR, // * + TOKEN_UNDERSCORE, // _ // two character tokens. TOKEN_AND, // && @@ -504,11 +506,12 @@ typedef enum TYPE_ERRTYPE, TYPE_ERR_UNION, TYPE_TYPEDEF, + TYPE_CTSTR, TYPE_DISTINCT, - TYPE_STRING, TYPE_ARRAY, TYPE_VARARRAY, TYPE_SUBARRAY, + TYPE_INFERRED_ARRAY, TYPE_TYPEINFO, TYPE_MEMBER, TYPE_VECTOR, diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 9d5c9ad37..38cf5ea8f 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -97,15 +97,17 @@ static void header_print_type(FILE *file, Type *type) OUTPUT("union %s__", type->decl->external_name); return; case TYPE_DISTINCT: - TODO + header_print_type(file, type->decl->distinct_decl.base_type); + return; case TYPE_ERRTYPE: break; case TYPE_ERR_UNION: break; case TYPE_TYPEDEF: break; - case TYPE_STRING: - break; + case TYPE_CTSTR: + case TYPE_INFERRED_ARRAY: + UNREACHABLE case TYPE_ARRAY: break; case TYPE_VARARRAY: diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 7bd4df0e0..304130d22 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -370,6 +370,11 @@ static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_to } EXIT:; uint32_t len = lexer->current - lexer->lexing_start; + if (!type) + { + if (!prefix && len == 1) return add_token(lexer, TOKEN_UNDERSCORE, "_"); + add_error_token(lexer, "An identifier may not consist of only '_' characters."); + } const char* interned_string = symtab_add(lexer->lexing_start, len, hash, &type); return add_token(lexer, type, interned_string); } diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 2d3a0f63c..ee7f0fd52 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -315,9 +315,9 @@ void llvm_emit_ptr_from_array(GenContext *c, BEValue *value) llvm_emit_load_aligned(c, pointer_type, pointer_addr, 0, "subarrptr"), value->type, alignment); return; } - case TYPE_VARARRAY: - case TYPE_STRING: + case TYPE_CTSTR: TODO + case TYPE_VARARRAY: default: UNREACHABLE } diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index 5ce4a1d3b..b1c3f2391 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -128,7 +128,7 @@ ABIArgInfo *x64_indirect_result(Type *type, unsigned free_int_regs) ABIArgInfo *x64_classify_reg_call_struct_type_check(Type *type, Registers *needed_registers) { - if (type->type_kind == TYPE_ERR_UNION || type->type_kind == TYPE_STRING || type->type_kind == TYPE_SUBARRAY) + if (type->type_kind == TYPE_ERR_UNION || type->type_kind == TYPE_SUBARRAY) { needed_registers->int_registers += 2; return abi_arg_new_direct(); @@ -438,6 +438,8 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_DISTINCT: + case TYPE_CTSTR: + case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_VOID: *current = CLASS_NO_CLASS; @@ -479,8 +481,6 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_ERRTYPE: x64_classify_struct_union(type, offset_base, current, lo_class, hi_class, named); break; - case TYPE_STRING: - TODO case TYPE_ARRAY: x64_classify_array(type, offset_base, current, lo_class, hi_class, named); break; @@ -611,7 +611,6 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty if (offset < 16) return abi_type_new_plain(type_usize); break; case TYPE_SUBARRAY: - case TYPE_STRING: if (offset < 8) return abi_type_new_plain(type_usize); if (offset < 16) return abi_type_new_plain(type_voidptr); break; @@ -633,6 +632,8 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_DISTINCT: + case TYPE_CTSTR: + case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_I128: case TYPE_U128: @@ -874,7 +875,6 @@ bool x64_type_is_structure(Type *type) case TYPE_STRUCT: case TYPE_ERRTYPE: case TYPE_ERR_UNION: - case TYPE_STRING: case TYPE_SUBARRAY: return true; default: diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index ff0b79602..c1fb0bde8 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -116,6 +116,8 @@ static bool x86_should_return_type_in_reg(Type *type) case TYPE_TYPEINFO: case TYPE_DISTINCT: case TYPE_ENUM: + case TYPE_CTSTR: + case TYPE_INFERRED_ARRAY: UNREACHABLE case ALL_INTS: case ALL_FLOATS: @@ -124,7 +126,6 @@ static bool x86_should_return_type_in_reg(Type *type) case TYPE_TYPEID: case TYPE_VARARRAY: case TYPE_ERR_UNION: - case TYPE_STRING: case TYPE_SUBARRAY: case TYPE_ERRTYPE: case TYPE_COMPLEX: @@ -592,6 +593,8 @@ static ABIArgInfo *x86_classify_argument(CallConvention call, Regs *regs, Type * case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEID: + case TYPE_CTSTR: + case TYPE_INFERRED_ARRAY: UNREACHABLE case ALL_FLOATS: case ALL_INTS: @@ -605,7 +608,6 @@ static ABIArgInfo *x86_classify_argument(CallConvention call, Regs *regs, Type * case TYPE_STRUCT: case TYPE_UNION: case TYPE_SUBARRAY: - case TYPE_STRING: case TYPE_ARRAY: case TYPE_ERR_UNION: case TYPE_COMPLEX: diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index abd66f79a..4e1675e29 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -487,6 +487,7 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * case TYPE_TYPEID: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_BOOL: return llvm_debug_simple_type(c, type, DW_ATE_boolean); @@ -529,7 +530,7 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * TODO case TYPE_TYPEDEF: return type->backend_debug_type = llvm_debug_typedef_type(c, type); - case TYPE_STRING: + case TYPE_CTSTR: TODO case TYPE_ARRAY: return type->backend_debug_type = llvm_debug_array_type(c, type); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index cd3b308c8..3c7afa2d8 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -169,7 +169,6 @@ static inline LLVMValueRef llvm_emit_subscript_addr_with_base(GenContext *c, Typ parent_value, &index_value, 1, "sarridx"); } case TYPE_VARARRAY: - case TYPE_STRING: TODO default: UNREACHABLE @@ -228,8 +227,9 @@ static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, case TYPE_VARARRAY: // TODO insert trap on overflow. TODO - case TYPE_STRING: - TODO + case TYPE_CTSTR: + // TODO insert trap on overflow. + return LLVMBuildInBoundsGEP(c->builder, parent->value, &index->value, 1, "ptridx"); default: UNREACHABLE @@ -366,6 +366,7 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind return value->value; case CAST_ERROR: UNREACHABLE + case CAST_STRPTR: case CAST_PTRPTR: llvm_value_rvalue(c, value); if (c->builder) @@ -396,8 +397,6 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind return value->value; case CAST_ARRPTR: TODO - case CAST_STRPTR: - TODO case CAST_EREU: case CAST_EUER: TODO @@ -1110,8 +1109,11 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l case TYPE_ARRAY: llvm_value_set(be_value, llvm_const_int(c, type_usize, expr_to_len->type->array.len), type_usize); break; + case TYPE_CTSTR: + TODO + break; + case TYPE_VARARRAY: - case TYPE_STRING: TODO default: UNREACHABLE @@ -1161,7 +1163,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ parent_base = parent_addr; break; case TYPE_VARARRAY: - case TYPE_STRING: + case TYPE_CTSTR: TODO default: UNREACHABLE @@ -1191,7 +1193,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ len = llvm_const_int(context, type_usize, parent_type->array.len); break; case TYPE_VARARRAY: - case TYPE_STRING: + case TYPE_CTSTR: TODO default: UNREACHABLE @@ -2154,7 +2156,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) case TYPE_BOOL: llvm_value_set_bool(be_value, LLVMConstInt(c->bool_type, expr->const_expr.b ? 1 : 0, 0)); return; - case TYPE_STRING: + case TYPE_CTSTR: { LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_ichar), expr->const_expr.string.len + 1), ""); LLVMSetLinkage(global_name, LLVMInternalLinkage); @@ -2214,6 +2216,8 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_DISTINCT: + case TYPE_CTSTR: + case TYPE_INFERRED_ARRAY: UNREACHABLE break; case TYPE_BOOL: @@ -2239,7 +2243,6 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM break; case TYPE_UNION: case TYPE_COMPLEX: - case TYPE_STRING: case TYPE_SUBARRAY: case TYPE_VECTOR: TODO diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 1766d440f..c4f7f2b7e 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -325,6 +325,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) case TYPE_POISONED: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_TYPEID: return any_type->backend_type = LLVMIntTypeInContext(c->context, any_type->builtin.bitsize); @@ -365,8 +366,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) return any_type->backend_type = LLVMIntTypeInContext(c->context, 8U); case TYPE_POINTER: return any_type->backend_type = llvm_type_from_ptr(c, any_type); - case TYPE_STRING: - // TODO + case TYPE_CTSTR: return any_type->backend_type = LLVMPointerType(llvm_get_type(c, type_char), 0); case TYPE_ARRAY: return any_type->backend_type = llvm_type_from_array(c, any_type); diff --git a/src/compiler/number.c b/src/compiler/number.c index 3711bbd98..41fce52a5 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -61,7 +61,7 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr) case TYPE_FXX: fprintf(file, "%Lf", expr->f); break; - case TYPE_STRING: + case TYPE_CTSTR: fprintf(file, "%.*s", expr->string.len, expr->string.chars); break; default: @@ -173,7 +173,7 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp return compare_fps(left->f, right->f, op); case TYPE_POINTER: return true; - case TYPE_STRING: + case TYPE_CTSTR: if (left->string.len != right->string.len) { is_eq = false; @@ -243,7 +243,7 @@ const char *expr_const_to_error_string(const ExprConst *expr) case TYPE_FXX: asprintf(&buff, "%Lf", expr->f); return buff; - case TYPE_STRING: + case TYPE_CTSTR: asprintf(&buff, "\"%*.s\"", expr->string.len, expr->string.chars); return buff; default: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 970454b24..ffebdcd4c 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -816,7 +816,7 @@ static Expr *parse_string_literal(Context *context, Expr *left) { assert(!left && "Had left hand side"); Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); - expr_string->type = type_string; + expr_string->type = type_compstr; char *str = NULL; size_t len = 0; @@ -850,8 +850,8 @@ static Expr *parse_string_literal(Context *context, Expr *left) str[len] = '\0'; expr_string->const_expr.string.chars = str; expr_string->const_expr.string.len = len; - expr_string->type = type_string; - expr_string->const_expr.kind = TYPE_STRING; + expr_string->type = type_compstr; + expr_string->const_expr.kind = TYPE_CTSTR; return expr_string; } diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 4c2cc5143..5c7c1c0d7 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -594,6 +594,14 @@ static inline TypeInfo *parse_array_type_index(Context *context, TypeInfo *type) RANGE_EXTEND_PREV(incr_array); return incr_array; } + if (try_consume(context, TOKEN_QUESTION)) + { + CONSUME_OR(TOKEN_RBRACKET, poisoned_type_info); + TypeInfo *inferred_array = type_info_new(TYPE_INFO_INFERRED_ARRAY, type->span); + inferred_array->array.base = type; + RANGE_EXTEND_PREV(inferred_array); + return inferred_array; + } if (try_consume(context, TOKEN_STAR)) { CONSUME_OR(TOKEN_RBRACKET, poisoned_type_info); diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index f6321ddea..a084c0764 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -1161,6 +1161,7 @@ Ast *parse_stmt(Context *context) case TOKEN_CT_ENDSWITCH: case TOKEN_RBRAPIPE: case TOKEN_BANGBANG: + case TOKEN_UNDERSCORE: SEMA_TOKEN_ERROR(context->tok, "Unexpected '%s' found when expecting a statement.", token_type_to_string(context->tok.type)); advance(context); return poisoned_ast; diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index e9ebf68f6..220a79e54 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -167,9 +167,21 @@ bool ptpt(Context *context, Expr* left, Type *from_canonical, Type *canonical, T bool strpt(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { + if (canonical->array.base->type_kind != TYPE_U8 && cast_type != CAST_TYPE_EXPLICIT) + { + if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; + return sema_type_mismatch(context, left, type, cast_type); + } + insert_cast(left, CAST_STRPTR, type); + return true; +} - // TODO - insert_cast(left, CAST_PTRPTR, canonical); +bool strsa(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + if (canonical->array.base->type_kind != TYPE_U8) return false; + Type *array_type = type_get_array(type_char, left->const_expr.string.len); + insert_cast(left, CAST_STRPTR, type_get_ptr(array_type)); + insert_cast(left, CAST_APTSA, type); return true; } @@ -733,13 +745,14 @@ CastKind cast_to_bool_kind(Type *type) { case TYPE_TYPEDEF: case TYPE_DISTINCT: + case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_POISONED: case TYPE_VOID: case TYPE_ERR_UNION: case TYPE_STRUCT: case TYPE_UNION: - case TYPE_STRING: + case TYPE_CTSTR: case TYPE_ERRTYPE: case TYPE_ENUM: case TYPE_FUNC: @@ -785,7 +798,9 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type) } switch (from_type->type_kind) { + case TYPE_INFERRED_ARRAY: case TYPE_POISONED: + UNREACHABLE case TYPE_VOID: case TYPE_TYPEID: case TYPE_TYPEINFO: @@ -875,8 +890,10 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type) break; case TYPE_TYPEDEF: UNREACHABLE - case TYPE_STRING: + case TYPE_CTSTR: + canonical = type_flatten(canonical); if (canonical->type_kind == TYPE_POINTER) return strpt(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_SUBARRAY) return strsa(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_ARRAY: // There is no valid cast from array to anything else. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 41489d8b4..af8a01eb9 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -679,7 +679,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib return ATTRIBUTE_NONE; } if (!sema_analyse_expr(context, NULL, attr->expr)) return false; - if (attr->expr->expr_kind != EXPR_CONST || attr->expr->type->canonical != type_string) + if (attr->expr->expr_kind != EXPR_CONST || attr->expr->type->canonical != type_compstr) { SEMA_ERROR(attr->expr, "Expected a constant string value as argument."); return ATTRIBUTE_NONE; @@ -805,7 +805,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl) { if (decl->var.type_info) { - if (!sema_resolve_type_info(context, decl->var.type_info)) return false; + if (!sema_resolve_type_info_maybe_inferred(context, decl->var.type_info, decl->var.init_expr != NULL)) return false; decl->type = decl->var.type_info->type; } @@ -863,6 +863,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl) Expr *init_expr = decl->var.init_expr; // 1. Check type. if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false; + // 2. Check const-ness if (!init_expr->constant) { @@ -878,15 +879,21 @@ static inline bool sema_analyse_global(Context *context, Decl *decl) { if (init_expr->expr_kind == EXPR_CAST) { - SEMA_ERROR(decl->var.init_expr, "The expression may not be a non constant cast."); + SEMA_ERROR(init_expr, "The expression may not be a non constant cast."); } else { - SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value."); + SEMA_ERROR(init_expr, "The expression must be a constant value."); } return false; } } + + if (decl->type->type_kind == TYPE_INFERRED_ARRAY) + { + assert(init_expr->type->canonical->type_kind == TYPE_ARRAY); + decl->type = type_get_array(decl->type->array.base, init_expr->type->canonical->array.len); + } } switch (decl->var.kind) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index cb9e688ef..9b4042ddf 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1333,9 +1333,9 @@ static bool expr_check_index_in_range(Context *context, Type *type, Expr *index_ } break; } + case TYPE_CTSTR: case TYPE_VARARRAY: case TYPE_SUBARRAY: - case TYPE_STRING: // If not from end, just check the negative values. if (!from_end) break; // From end we can only do sanity checks ^0 is invalid for non-end index. ^-1 and less is invalid for all. @@ -1537,12 +1537,12 @@ static inline void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *str { expr_to_rewrite->expr_kind = EXPR_CONST; expr_to_rewrite->constant = true; - expr_to_rewrite->const_expr.kind = TYPE_STRING; + expr_to_rewrite->const_expr.kind = TYPE_CTSTR; expr_to_rewrite->const_expr.string.chars = (char *)string; expr_to_rewrite->const_expr.string.len = (int)strlen(string); expr_to_rewrite->pure = true; expr_to_rewrite->resolve_status = RESOLVE_DONE; - expr_to_rewrite->type = type_string; + expr_to_rewrite->type = type_compstr; } @@ -2054,17 +2054,17 @@ static int64_t sema_analyse_designator_index(Context *context, Expr *index) return index_val; } -static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorElement **elements, unsigned *curr_index, bool *is_constant, bool *did_report_error) +static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorElement **elements, unsigned *curr_index, bool *is_constant, bool *did_report_error, ArrayIndex *max_index) { Type *type_lowered = type_lowering(type); DesignatorElement *element = elements[*curr_index]; if (element->kind == DESIGNATOR_ARRAY || element->kind == DESIGNATOR_RANGE) { - if (type_lowered->type_kind != TYPE_ARRAY) + if (type_lowered->type_kind != TYPE_ARRAY && type_lowered->type_kind != TYPE_INFERRED_ARRAY) { return NULL; } - ByteSize len = type_lowered->array.len; + ByteSize len = type_lowered->type_kind == TYPE_INFERRED_ARRAY ? MAX_ARRAYINDEX : type_lowered->array.len; ArrayIndex index = sema_analyse_designator_index(context, element->index_expr); if (index < 0) { @@ -2077,8 +2077,9 @@ static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorE *did_report_error = true; return NULL; } - element->index = index; + element->index = index; + if (max_index && *max_index < index) *max_index = index; if (element->kind == DESIGNATOR_RANGE) { int64_t end_index = sema_analyse_designator_index(context, element->index_end_expr); @@ -2100,6 +2101,7 @@ static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorE return NULL; } element->index_end = end_index; + if (max_index && *max_index < end_index) *max_index = end_index; } return type_lowered->array.base; } @@ -2113,7 +2115,7 @@ static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorE return member->type; } -static Type *sema_expr_analyse_designator(Context *context, Type *current, Expr *expr) +static Type *sema_expr_analyse_designator(Context *context, Type *current, Expr *expr, ArrayIndex *max_index) { DesignatorElement **path = expr->designator_expr.path; Expr *value = expr->designator_expr.value; @@ -2123,7 +2125,7 @@ static Type *sema_expr_analyse_designator(Context *context, Type *current, Expr bool did_report_error = false; for (unsigned i = 0; i < vec_size(path); i++) { - Type *new_current = sema_find_type_of_element(context, current, path, &i, &is_constant, &did_report_error); + Type *new_current = sema_find_type_of_element(context, current, path, &i, &is_constant, &did_report_error, i == 0 ? max_index : NULL); if (!new_current) { if (!did_report_error) SEMA_ERROR(expr, "This is not a valid member of '%s'.", type_to_error_string(current)); @@ -2508,10 +2510,11 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass initializer->pure = true; initializer->constant = true; + ArrayIndex max_index = -1; VECEACH(init_expressions, i) { Expr *expr = init_expressions[i]; - Type *result = sema_expr_analyse_designator(context, original, expr); + Type *result = sema_expr_analyse_designator(context, original, expr, &max_index); if (!result) return false; if (!sema_analyse_expr_of_required_type(context, result, expr->designator_expr.value, true)) return false; expr->pure &= expr->designator_expr.value->pure; @@ -2521,6 +2524,11 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass initializer->pure &= expr->pure; initializer->constant &= expr->constant; } + + if (!is_structlike && initializer->type->type_kind == TYPE_INFERRED_ARRAY) + { + initializer->type = sema_type_lower_by_size(initializer->type, max_index + 1); + } if (initializer->constant) { ConstInitializer *const_init = MALLOC(sizeof(ConstInitializer)); @@ -2630,15 +2638,15 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T Expr **elements = initializer->initializer_expr.initializer_expr; - assert(assigned->type_kind == TYPE_ARRAY && "The other types are not done yet."); + assert((assigned->type_kind == TYPE_ARRAY) && "The other types are not done yet."); Type *inner_type = type_get_indexed_type(assigned); assert(inner_type); - initializer->initializer_expr.init_type = INITIALIZER_NORMAL; unsigned size = vec_size(elements); unsigned expected_members = assigned->array.len; + if (assigned->type_kind != TYPE_ARRAY) expected_members = size; assert(size > 0 && "We should already have handled the size == 0 case."); if (expected_members == 0) @@ -2698,13 +2706,16 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T static inline bool sema_expr_analyse_initializer(Context *context, Type *external_type, Type *assigned, Expr *expr) { - expr->type = external_type; - Expr **init_expressions = expr->initializer_expr.initializer_expr; + unsigned init_expression_count = vec_size(init_expressions); + // 1. Zero size init will initialize to empty. - if (vec_size(init_expressions) == 0) + if (init_expression_count == 0) { + external_type = sema_type_lower_by_size(external_type, 0); + assigned = sema_type_lower_by_size(assigned, 0); + expr->type = external_type; ConstInitializer *initializer = CALLOCS(ConstInitializer); initializer->kind = CONST_INIT_ZERO; initializer->type = type_flatten(expr->type); @@ -2719,11 +2730,16 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *externa // this means that in this case we're actually not resolving macros here. if (init_expressions[0]->expr_kind == EXPR_DESIGNATOR) { + expr->type = external_type; return sema_expr_analyse_designated_initializer(context, assigned, expr); } + external_type = sema_type_lower_by_size(external_type, init_expression_count); + assigned = sema_type_lower_by_size(assigned, init_expression_count); + expr->type = external_type; + // 3. Otherwise use the plain initializer. - if (assigned->type_kind == TYPE_ARRAY) + if (assigned->type_kind == TYPE_ARRAY || assigned->type_kind == TYPE_INFERRED_ARRAY) { return sema_expr_analyse_array_plain_initializer(context, assigned, expr); } @@ -2741,6 +2757,7 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to case TYPE_UNION: case TYPE_ARRAY: case TYPE_ERRTYPE: + case TYPE_INFERRED_ARRAY: return sema_expr_analyse_initializer(context, to, assigned, expr); case TYPE_VARARRAY: TODO @@ -3870,6 +3887,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp case TYPE_MEMBER: case TYPE_TYPEDEF: case TYPE_DISTINCT: + case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_BOOL: case TYPE_ENUM: @@ -3878,7 +3896,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp case TYPE_STRUCT: case TYPE_UNION: case TYPE_ERR_UNION: - case TYPE_STRING: + case TYPE_CTSTR: case TYPE_ARRAY: case TYPE_VARARRAY: case TYPE_SUBARRAY: @@ -4204,7 +4222,7 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr * case ALL_FLOATS: expr->const_expr.b = inner->const_expr.f == 0.0; break; - case TYPE_STRING: + case TYPE_CTSTR: expr->const_expr.b = !inner->const_expr.string.len; break; case TYPE_ERRTYPE: @@ -4226,6 +4244,7 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr * case TYPE_TYPEDEF: case TYPE_ERR_UNION: case TYPE_DISTINCT: + case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_FUNC: case TYPE_ARRAY: @@ -4242,7 +4261,7 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr * case TYPE_STRUCT: case TYPE_UNION: case TYPE_VOID: - case TYPE_STRING: + case TYPE_CTSTR: case TYPE_ENUM: case TYPE_ERRTYPE: case TYPE_TYPEID: @@ -4568,6 +4587,7 @@ static TypeInfo *type_info_copy_from_macro(Context *context, TypeInfo *source) copy->array.base = type_info_copy_from_macro(context, source->array.base); return copy; case TYPE_INFO_INC_ARRAY: + case TYPE_INFO_INFERRED_ARRAY: case TYPE_INFO_VARARRAY: case TYPE_INFO_SUBARRAY: assert(source->resolve_status == RESOLVE_NOT_DONE); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 37c7882c8..40a75e2eb 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -352,31 +352,47 @@ static inline bool sema_analyse_local_decl(Context *context, Decl *decl) } if (!decl->var.type_info) { + if (!sema_analyse_expr(context, NULL, init_expr)) return false; + decl->type = init_expr->type; // Skip further evaluation. - return true; + goto EXIT_OK; } } - if (!sema_resolve_type_info(context, decl->var.type_info)) return decl_poison(decl); + if (!sema_resolve_type_info_maybe_inferred(context, decl->var.type_info, decl->var.init_expr != NULL)) return decl_poison(decl); decl->type = decl->var.type_info->type; - if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type); if (decl->var.init_expr) { + bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY; Expr *init = decl->var.init_expr; // Handle explicit undef if (init->expr_kind == EXPR_TYPEINFO && init->type_expr->resolve_status == RESOLVE_DONE && init->type_expr->type->type_kind == TYPE_VOID) { + if (type_is_inferred) + { + SEMA_ERROR(decl->var.type_info, "Size of the array cannot be inferred with explicit undef."); + return false; + } init->expr_kind = EXPR_UNDEF; init->resolve_status = RESOLVE_DONE; - return true; + goto EXIT_OK; } if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, decl->var.failable || decl->var.unwrap ? FAILABLE_YES : FAILABLE_NO)) return decl_poison(decl); + + if (type_is_inferred) + { + Type *right_side_type = init->type->canonical; + assert(right_side_type->type_kind == TYPE_ARRAY); + decl->type = type_get_array(decl->type->array.base, right_side_type->array.len); + } if (decl->var.unwrap && !init->failable) { SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here."); return decl_poison(decl); } } + EXIT_OK: + if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type); return true; } @@ -1112,6 +1128,8 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st assert(to_type); Expr *case_expr = case_stmt->case_stmt.expr; + // TODO string switch. + // 1. Try to do implicit conversion to the correct type. if (!sema_analyse_expr(context, to_type, case_expr)) return false; @@ -1226,7 +1244,8 @@ static inline bool sema_check_value_case(Context *context, Type *switch_type, As static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases) { bool use_type_id = false; - switch (switch_type->type_kind) + Type *switch_type_flattened = type_flatten(switch_type); + switch (switch_type_flattened->type_kind) { case TYPE_TYPEID: case TYPE_ERR_UNION: @@ -1236,8 +1255,13 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpa assert(switch_type->type_kind != TYPE_IXX); case TYPE_BOOL: case TYPE_ENUM: - case TYPE_STRING: break; + case TYPE_DISTINCT: + UNREACHABLE + case TYPE_SUBARRAY: + // Allow switching over char[] and String + if (switch_type_flattened->array.base->type_kind == TYPE_U8) break; + FALLTHROUGH; default: sema_error_range3(expr_span, "It is not possible to switch over '%s'.", type_to_error_string(switch_type)); return false; @@ -1602,8 +1626,8 @@ bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement) Expr *message = statement->ct_assert_stmt.message; if (message) { - if (!sema_analyse_expr(context, type_string, message)) return false; - if (message->type->type_kind != TYPE_STRING) + if (!sema_analyse_expr(context, type_compstr, message)) return false; + if (message->type->type_kind != TYPE_CTSTR) { SEMA_ERROR(message, "Expected a string as the error message."); } @@ -1633,8 +1657,8 @@ bool sema_analyse_assert_stmt(Context *context, Ast *statement) Expr *message = statement->ct_assert_stmt.message; if (message) { - if (!sema_analyse_expr(context, type_string, message)) return false; - if (message->type->type_kind != TYPE_STRING) + if (!sema_analyse_expr(context, type_compstr, message)) return false; + if (message->type->type_kind != TYPE_CTSTR) { SEMA_ERROR(message, "Expected a string as the error message."); } diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 51b08b2b6..a50dbf6a2 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -9,7 +9,7 @@ static inline bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info) { - if (!sema_resolve_type_shallow(context, type_info->pointer)) + if (!sema_resolve_type_shallow(context, type_info->pointer, false)) { return type_info_poison(type_info); } @@ -32,7 +32,10 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type) break; case TYPE_INFO_SUBARRAY: type->type = type_get_subarray(type->array.base->type); - break;; + break; + case TYPE_INFO_INFERRED_ARRAY: + type->type = type_get_inferred_array(type->array.base->type); + break; case TYPE_INFO_ARRAY: if (!sema_analyse_expr(context, type_usize, type->array.len)) return type_info_poison(type); if (type->array.len->expr_kind != EXPR_CONST) @@ -154,7 +157,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) } -bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info) +bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type) { if (type_info->resolve_status == RESOLVE_DONE) return type_info_ok(type_info); @@ -183,6 +186,13 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info) return type_info_poison(type_info); } TODO + case TYPE_INFO_INFERRED_ARRAY: + if (!allow_inferred_type) + { + SEMA_ERROR(type_info, "Inferred array types can only be used in declarations with initializers."); + return type_info_poison(type_info); + } + FALLTHROUGH; case TYPE_INFO_SUBARRAY: case TYPE_INFO_VARARRAY: case TYPE_INFO_ARRAY: @@ -193,4 +203,11 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info) break; } return true; -} \ No newline at end of file +} + +Type *sema_type_lower_by_size(Type *type, ByteSize element_size) +{ + if (type->type_kind != TYPE_INFERRED_ARRAY) return type; + + return type_get_array(type->array.base, element_size); +} diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 1fe6c9b29..f35c9a7fc 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -10,12 +10,17 @@ void sema_shadow_error(Decl *decl, Decl *old) SEMA_PREV(old, "The previous use of '%s' was here.", decl->name); } -bool sema_resolve_type_info(Context *context, TypeInfo *type_info) +bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type) { - if (!sema_resolve_type_shallow(context, type_info)) return false; + if (!sema_resolve_type_shallow(context, type_info, allow_inferred_type)) return false; Type *type = type_info->type; // usize and similar typedefs will not have a decl. if (type->type_kind == TYPE_TYPEDEF && type->decl == NULL) return true; if (!type_is_user_defined(type)) return true; return sema_analyse_decl(context, type->decl); } + +bool sema_resolve_type_info(Context *context, TypeInfo *type_info) +{ + return sema_resolve_type_info_maybe_inferred(context, type_info, false); +} diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index df30ad795..4e11ae624 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -66,6 +66,8 @@ const char *token_type_to_string(TokenType type) return ")"; case TOKEN_STAR: return "*"; + case TOKEN_UNDERSCORE: + return "_"; // Two character tokens case TOKEN_AND: diff --git a/src/compiler/types.c b/src/compiler/types.c index 3f07562c0..ac7ab9850 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -11,10 +11,10 @@ static Type t_usz, t_isz; static Type t_cus, t_cui, t_cul, t_cull; static Type t_cs, t_ci, t_cl, t_cll; static Type t_voidstar, t_typeid, t_error, t_typeinfo; +static Type t_str; Type *type_bool = &t_u1; Type *type_void = &t_u0; -Type *type_string = &t_str; Type *type_voidptr = &t_voidstar; Type *type_half = &t_f16; Type *type_float = &t_f32; @@ -36,6 +36,7 @@ Type *type_u128 = &t_u128; Type *type_usize = &t_usz; Type *type_compint = &t_ixx; Type *type_compfloat = &t_fxx; +Type *type_compstr = &t_str; Type *type_c_short = &t_cs; Type *type_c_int = &t_ci; Type *type_c_long = &t_cl; @@ -52,9 +53,10 @@ unsigned size_error_code; unsigned alignment_error_code; #define PTR_OFFSET 0 -#define SUB_ARRAY_OFFSET 1 -#define VAR_ARRAY_OFFSET 2 -#define ARRAY_OFFSET 3 +#define INFERRED_ARRAY_OFFSET 1 +#define SUB_ARRAY_OFFSET 2 +#define VAR_ARRAY_OFFSET 3 +#define ARRAY_OFFSET 4 Type *type_int_signed_by_bitsize(unsigned bytesize) { @@ -127,14 +129,17 @@ const char *type_to_error_string(Type *type) } asprintf(&buffer, "%s*", type_to_error_string(type->pointer)); return buffer; - case TYPE_STRING: - return "string"; + case TYPE_CTSTR: + return "compile time string"; case TYPE_ARRAY: asprintf(&buffer, "%s[%llu]", type_to_error_string(type->array.base), (unsigned long long)type->array.len); return buffer; case TYPE_VARARRAY: asprintf(&buffer, "%s[*]", type_to_error_string(type->array.base)); return buffer; + case TYPE_INFERRED_ARRAY: + asprintf(&buffer, "%s[?]", type_to_error_string(type->array.base)); + return buffer; case TYPE_SUBARRAY: asprintf(&buffer, "%s[]", type_to_error_string(type->array.base)); return buffer; @@ -183,6 +188,7 @@ ByteSize type_size(Type *type) case TYPE_POISONED: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_INFERRED_ARRAY: UNREACHABLE; case TYPE_TYPEDEF: return type_size(type->canonical); @@ -202,10 +208,10 @@ ByteSize type_size(Type *type) case ALL_FLOATS: case TYPE_ERR_UNION: return type->builtin.bytesize; + case TYPE_CTSTR: case TYPE_FUNC: case TYPE_POINTER: case TYPE_VARARRAY: - case TYPE_STRING: return t_usz.canonical->builtin.bytesize; case TYPE_ARRAY: return type_size(type->array.base) * type->array.len; @@ -332,7 +338,7 @@ bool type_is_abi_aggregate(Type *type) case TYPE_POINTER: case TYPE_ENUM: case TYPE_FUNC: - case TYPE_STRING: + case TYPE_CTSTR: case TYPE_VECTOR: return false; case TYPE_ERRTYPE: @@ -345,6 +351,7 @@ bool type_is_abi_aggregate(Type *type) return true; case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_INFERRED_ARRAY: UNREACHABLE } UNREACHABLE @@ -477,8 +484,9 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) case TYPE_MEMBER: case TYPE_TYPEID: case TYPE_FUNC: - case TYPE_STRING: + case TYPE_CTSTR: case TYPE_SUBARRAY: + case TYPE_INFERRED_ARRAY: return false; case TYPE_ERR_UNION: *base = type_usize->canonical; @@ -608,6 +616,7 @@ AlignSize type_abi_alignment(Type *type) case TYPE_POISONED: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_INFERRED_ARRAY: UNREACHABLE; case TYPE_VECTOR: case TYPE_COMPLEX: @@ -635,7 +644,7 @@ AlignSize type_abi_alignment(Type *type) case TYPE_FUNC: case TYPE_POINTER: case TYPE_VARARRAY: - case TYPE_STRING: + case TYPE_CTSTR: return t_usz.canonical->builtin.abi_alignment; case TYPE_ARRAY: return type_abi_alignment(type->array.base); @@ -706,6 +715,32 @@ static Type *type_generate_subarray(Type *arr_type, bool canonical) return arr; } +static Type *type_generate_inferred_array(Type *arr_type, bool canonical) +{ + if (canonical) arr_type = arr_type->canonical; + if (!arr_type->type_cache) + { + create_type_cache(arr_type); + } + + Type *arr = arr_type->type_cache[INFERRED_ARRAY_OFFSET]; + if (arr == NULL) + { + arr = type_new(TYPE_INFERRED_ARRAY, strformat("%s[_]", arr_type->name)); + arr->array.base = arr_type; + arr_type->type_cache[INFERRED_ARRAY_OFFSET] = arr; + if (arr_type == arr_type->canonical) + { + arr->canonical = arr; + } + else + { + arr->canonical = type_generate_inferred_array(arr_type->canonical, true); + } + } + return arr; +} + static Type *type_generate_vararray(Type *arr_type, bool canonical) { if (canonical) arr_type = arr_type->canonical; @@ -743,6 +778,11 @@ Type *type_get_subarray(Type *arr_type) return type_generate_subarray(arr_type, false); } +Type *type_get_inferred_array(Type *arr_type) +{ + return type_generate_inferred_array(arr_type, false); +} + Type *type_get_vararray(Type *arr_type) { return type_generate_subarray(arr_type, false); @@ -774,8 +814,9 @@ Type *type_get_indexed_type(Type *type) case TYPE_VARARRAY: case TYPE_ARRAY: case TYPE_SUBARRAY: + case TYPE_INFERRED_ARRAY: return type->array.base; - case TYPE_STRING: + case TYPE_CTSTR: return type_char; case TYPE_DISTINCT: type = type->decl->distinct_decl.base_type; @@ -836,7 +877,7 @@ static Type *type_create_array(Type *element_type, uint64_t len, bool vector, bo return vec_arr; } -Type *type_get_array(Type *arr_type, uint64_t len) +Type *type_get_array(Type *arr_type, ByteSize len) { return type_create_array(arr_type, len, false, false); } @@ -900,7 +941,7 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target- DEF_TYPE(u128, t_u128, TYPE_U128, 128, i128); DEF_TYPE(void, t_u0, TYPE_VOID, 8, byte); - DEF_TYPE(string, t_str, TYPE_STRING, target->width_pointer, pointer); + DEF_TYPE(string, t_str, TYPE_CTSTR, target->width_pointer, pointer); #undef DEF_TYPE @@ -939,6 +980,7 @@ bool type_is_scalar(Type *type) case TYPE_POISONED: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_VOID: case TYPE_FUNC: @@ -951,6 +993,7 @@ bool type_is_scalar(Type *type) case TYPE_BOOL: case ALL_INTS: case ALL_FLOATS: + case TYPE_CTSTR: case TYPE_TYPEID: case TYPE_POINTER: case TYPE_ENUM: @@ -965,8 +1008,6 @@ bool type_is_scalar(Type *type) case TYPE_TYPEDEF: type = type->canonical; goto RETRY; - case TYPE_STRING: - TODO } UNREACHABLE } @@ -1156,7 +1197,9 @@ Type *type_find_max_type(Type *type, Type *other) switch (type->type_kind) { + case TYPE_INFERRED_ARRAY: case TYPE_POISONED: + UNREACHABLE case TYPE_VOID: case TYPE_BOOL: case TYPE_TYPEINFO: @@ -1183,8 +1226,6 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_ERRTYPE: if (other->type_kind == TYPE_ERRTYPE) return type_error; return NULL; - case TYPE_DISTINCT: - return NULL; case TYPE_FUNC: case TYPE_UNION: case TYPE_ERR_UNION: @@ -1193,8 +1234,17 @@ Type *type_find_max_type(Type *type, Type *other) TODO case TYPE_TYPEDEF: UNREACHABLE - case TYPE_STRING: - TODO + case TYPE_CTSTR: + if (other->type_kind == TYPE_DISTINCT) + { + // In this case we only react to the flattened type. + Type *flatten_other = type_flatten(other); + if (flatten_other->type_kind == TYPE_SUBARRAY && flatten_other->array.base->type_kind == TYPE_U8) return other; + if (flatten_other->type_kind == TYPE_POINTER && flatten_other->pointer->type_kind == TYPE_U8) return other; + } + return NULL; + case TYPE_DISTINCT: + return NULL; case TYPE_ARRAY: return NULL; case TYPE_VARARRAY: diff --git a/test/test_suite/symbols/various.c3 b/test/test_suite/symbols/various.c3 index 747e8f715..ba588b419 100644 --- a/test/test_suite/symbols/various.c3 +++ b/test/test_suite/symbols/various.c3 @@ -70,7 +70,7 @@ func void test10() const char B = 1; char* c = &B; const A = 1; - char* b = &A; // #error: To take the address of a temporary value, use '&&' instead of '&' + char* b = &A; // #error: either type it or use && to take the reference to a temporary } enum Enum : int @@ -125,7 +125,7 @@ func void test16() func void test17() { - int a = "test"; // #error: cast 'string' to 'int' + int a = "test"; // #error: cast 'compile time string' to 'int' } func void test18() diff --git a/test/test_suite/types/enum_errors.c3 b/test/test_suite/types/enum_errors.c3 index 5c08c05de..55e5541f4 100644 --- a/test/test_suite/types/enum_errors.c3 +++ b/test/test_suite/types/enum_errors.c3 @@ -12,6 +12,6 @@ func int foo() enum State { A = foo(), // #error: Expected a constant expression for enum - B = "hello", // #error: Cannot implicitly cast 'string' to 'int' + B = "hello", // #error: Cannot implicitly cast 'compile time string' to 'int' C = true, // #error: Cannot implicitly cast 'bool' to 'int' }