Added "distinct" types.

This commit is contained in:
Christoffer Lerno
2021-01-24 21:08:43 +01:00
committed by Christoffer Lerno
parent 3a24fbfa6d
commit 7fc12192f4
29 changed files with 402 additions and 111 deletions

View File

@@ -96,7 +96,7 @@ the r/ProgrammingLanguages Discord: https://discord.gg/cfu4wdk
- [ ] CT type constants
- [ ] Reflection methods
- [ ] Anonymous structs
- [ ] Distinct types
- [x] Distinct types
- [ ] LTO/ThinLTO setup
- [ ] Built-in linking
- [ ] `global` / `shared` for globals
@@ -106,7 +106,7 @@ the r/ProgrammingLanguages Discord: https://discord.gg/cfu4wdk
- [ ] Implicit capturing macros
- [ ] Trailing body macros
- [ ] Subarray initializers
- [ ] slice initializers e.g. `{ [1..2] = 2 }`
- [x] range initializers e.g. `{ [1..2] = 2 }`
- [ ] Bitstructs
- [ ] `asm` section
- [ ] `$switch`

View File

@@ -87,6 +87,9 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility
case DECL_ENUM:
kind = TYPE_ENUM;
break;
case DECL_DISTINCT:
kind = TYPE_DISTINCT;
break;
case DECL_TYPEDEF:
kind = TYPE_TYPEDEF;
break;
@@ -326,7 +329,9 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent)
}
switch (type->type_kind)
{
case TYPE_DISTINCT:
DUMPF("(distinct %s)", type->name);
return;
case TYPE_COMPLEX:
DUMP("(type complex");
return;
@@ -878,6 +883,17 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
DUMPTI(decl->typedef_decl.type_info);
}
DUMPEND();
case DECL_DISTINCT:
DUMPF("(distinct %s", decl->name);
if (decl->typedef_decl.is_func)
{
fprint_func_signature(context, file, &decl->typedef_decl.function_signature, indent + 1);
}
else
{
DUMPTI(decl->typedef_decl.type_info);
}
DUMPEND();
case DECL_CT_IF:
DUMP("(ct-if");
DUMPEXPR(decl->ct_if_decl.expr);

View File

@@ -393,6 +393,16 @@ typedef struct
};
} TypedefDecl;
typedef struct
{
union
{
TypedefDecl typedef_decl;
Type *base_type;
};
Decl** methods;
} DistinctDecl;
typedef struct
{
bool failable : 1;
@@ -482,6 +492,7 @@ typedef struct _Decl
FuncDecl func;
AttrDecl attr;
TypedefDecl typedef_decl;
DistinctDecl distinct_decl;
MacroDecl macro_decl;
GenericDecl generic_decl;
DefineDecl define_decl;
@@ -1313,21 +1324,22 @@ extern Type *type_typeid, *type_error, *type_typeinfo;
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
extern const char *kw_main;
extern const char *kw_sizeof;
extern const char *kw_alignof;
extern const char *kw_align;
extern const char *kw_offsetof;
extern const char *kw_kindof;
extern const char *kw_nameof;
extern const char *kw_qnameof;
extern const char *kw_len;
extern const char *kw_alignof;
extern const char *kw_distinct;
extern const char *kw_inline;
extern const char *kw_kindof;
extern const char *kw_len;
extern const char *kw_main;
extern const char *kw_nameof;
extern const char *kw_offsetof;
extern const char *kw_ordinal;
extern const char *kw___round;
extern const char *kw_qnameof;
extern const char *kw_sizeof;
extern const char *kw___ceil;
extern const char *kw___trunc;
extern const char *kw___round;
extern const char *kw___sqrt;
extern const char *kw___trunc;
#define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, source_span_from_token_id(_token.id))
#define AST_NEW(_kind, _loc) new_ast(_kind, _loc)
@@ -1748,11 +1760,6 @@ static inline bool type_convert_will_trunc(Type *destination, Type *source)
return (unsigned)destination->canonical->builtin.bitsize < (unsigned)source->canonical->builtin.bitsize;
}
static inline bool type_is_numeric(Type *type)
{
if (type->type_kind == TYPE_TYPEDEF) type = type->canonical;
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX;
}
UnaryOp unaryop_from_token(TokenType type);
TokenType unaryop_to_token(UnaryOp type);
@@ -1779,6 +1786,11 @@ static inline void advance_and_verify(Context *context, TokenType token_type)
}
static inline Type *type_flatten(Type *type)
{
type = type->canonical;
return type->type_kind == TYPE_DISTINCT ? type->decl->distinct_decl.base_type : type;
}
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; }
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_I64; }
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U64; }
@@ -1788,6 +1800,13 @@ static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
bool type_is_scalar(Type *type);
static inline bool type_is_numeric(Type *type)
{
type = type_flatten(type);
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX;
}
static inline bool type_kind_is_derived(TypeKind kind)
{
switch (kind)
@@ -1819,7 +1838,7 @@ static inline bool type_is_structlike(Type *type)
static inline Type *type_lowering(Type *type)
{
Type *canonical = type->canonical;
Type *canonical = type_flatten(type);
if (canonical->type_kind == TYPE_ENUM) return canonical->decl->enums.type_info->type->canonical;
if (canonical->type_kind == TYPE_TYPEID) return type_usize->canonical;
return canonical;

View File

@@ -120,6 +120,7 @@ void context_register_global_decl(Context *context, Decl *decl)
case DECL_STRUCT:
case DECL_UNION:
case DECL_TYPEDEF:
case DECL_DISTINCT:
case DECL_ERR:
vec_add(context->types, decl);
decl_set_external_name(decl);

View File

@@ -134,6 +134,7 @@ typedef enum
DECL_LABEL,
DECL_ENUM_CONSTANT,
DECL_TYPEDEF,
DECL_DISTINCT,
DECL_STRUCT,
DECL_UNION,
DECL_ENUM,
@@ -488,6 +489,7 @@ typedef enum
TYPE_ERRTYPE,
TYPE_ERR_UNION,
TYPE_TYPEDEF,
TYPE_DISTINCT,
TYPE_STRING,
TYPE_ARRAY,
TYPE_VARARRAY,

View File

@@ -96,6 +96,8 @@ static void header_print_type(FILE *file, Type *type)
case TYPE_UNION:
OUTPUT("union %s__", type->decl->external_name);
return;
case TYPE_DISTINCT:
TODO
case TYPE_ERRTYPE:
break;
case TYPE_ERR_UNION:
@@ -204,6 +206,7 @@ static void header_gen_decl(FILE *file, int indent, Decl *decl)
case DECL_FUNC:
TODO
case DECL_TYPEDEF:
case DECL_DISTINCT:
TODO
case DECL_STRUCT:
header_gen_struct(file, indent, decl);

View File

@@ -667,7 +667,7 @@ void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type)
value->value = llvm_value;
value->alignment = type_abi_alignment(type);
value->kind = BE_VALUE;
value->type = type;
value->type = type_flatten(type);
}
bool llvm_value_is_const(BEValue *value)
@@ -680,11 +680,11 @@ void llvm_value_set_address_align(BEValue *value, LLVMValueRef llvm_value, Type
value->value = llvm_value;
value->alignment = alignment;
value->kind = BE_ADDRESS;
value->type = type;
value->type = type_flatten(type);
}
void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type)
{
llvm_value_set_address_align(value, llvm_value, type, type_abi_alignment(type));
llvm_value_set_address_align(value, llvm_value, type_flatten(type), type_abi_alignment(type));
}
void llvm_value_fold_failable(GenContext *c, BEValue *value)
@@ -782,6 +782,9 @@ static void gencontext_emit_decl(GenContext *context, Decl *decl)
break;
case DECL_TYPEDEF:
break;
case DECL_DISTINCT:
// TODO
break;
case DECL_ENUM_CONSTANT:
// TODO
break;;

View File

@@ -437,6 +437,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
case TYPE_FUNC:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
case TYPE_DISTINCT:
UNREACHABLE
case TYPE_VOID:
*current = CLASS_NO_CLASS;
@@ -631,6 +632,7 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
case TYPE_TYPEDEF:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
case TYPE_DISTINCT:
UNREACHABLE
case TYPE_I128:
case TYPE_U128:

View File

@@ -114,11 +114,12 @@ static bool x86_should_return_type_in_reg(Type *type)
case TYPE_FUNC:
case TYPE_TYPEDEF:
case TYPE_TYPEINFO:
case TYPE_DISTINCT:
case TYPE_ENUM:
UNREACHABLE
case ALL_INTS:
case ALL_FLOATS:
case TYPE_BOOL:
case TYPE_ENUM:
case TYPE_POINTER:
case TYPE_TYPEID:
case TYPE_VARARRAY:
@@ -588,6 +589,7 @@ static ABIArgInfo *x86_classify_argument(CallConvention call, Regs *regs, Type *
case TYPE_TYPEDEF:
case TYPE_VOID:
case TYPE_ENUM:
case TYPE_DISTINCT:
case TYPE_FUNC:
case TYPE_TYPEID:
UNREACHABLE

View File

@@ -525,6 +525,8 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
case TYPE_STRUCT:
case TYPE_UNION:
return type->backend_debug_type = llvm_debug_structlike_type(c, type, scope);
case TYPE_DISTINCT:
TODO
case TYPE_TYPEDEF:
return type->backend_debug_type = llvm_debug_typedef_type(c, type);
case TYPE_STRING:

View File

@@ -136,7 +136,7 @@ static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *ty
static inline void gencontext_emit_subscript_addr_base(GenContext *context, BEValue *value, Expr *parent)
{
LLVMValueRef parent_value;
Type *type = parent->type->canonical;
Type *type = type_flatten(parent->type);
switch (type->type_kind)
{
case TYPE_POINTER:
@@ -226,7 +226,7 @@ static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValu
static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index)
{
assert(llvm_value_is_addr(parent));
Type *type = parent->type->canonical;
Type *type = type_flatten(parent->type);
switch (type->type_kind)
{
case TYPE_POINTER:
@@ -342,7 +342,7 @@ static inline void gencontext_emit_access_addr(GenContext *context, BEValue *be_
llvm_emit_expr(context, be_value, parent);
Decl *member = expr->access_expr.ref;
gencontext_emit_member_addr(context, be_value, parent->type->canonical->decl, member);
gencontext_emit_member_addr(context, be_value, type_flatten(parent->type)->decl, member);
}
static void gencontext_emit_scoped_expr(GenContext *context, BEValue *value, Expr *expr)
@@ -524,9 +524,11 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind
void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type)
{
to_type = type_flatten(to_type);
from_type = type_flatten(from_type);
value->value = gencontext_emit_cast_inner(c, cast_kind, value, to_type, from_type);
value->type = to_type;
value->kind = to_type->type_kind == TYPE_BOOL ? BE_BOOLEAN : BE_VALUE;
value->type = type_flatten(to_type);
value->kind = value->type->type_kind == TYPE_BOOL ? BE_BOOLEAN : BE_VALUE;
}
static inline void gencontext_emit_cast_expr(GenContext *context, BEValue *be_value, Expr *expr)
@@ -535,8 +537,8 @@ static inline void gencontext_emit_cast_expr(GenContext *context, BEValue *be_va
llvm_emit_cast(context,
expr->cast_expr.kind,
be_value,
expr->type->canonical,
expr->cast_expr.expr->type->canonical);
expr->type,
expr->cast_expr.expr->type);
}
@@ -634,7 +636,7 @@ static void llvm_emit_inititialize_reference_const(GenContext *c, BEValue *ref,
switch (const_init->kind)
{
case CONST_INIT_ZERO:
if (type_is_builtin(ref->type->canonical->type_kind) || ref->type->canonical->type_kind == TYPE_ARRAY)
if (type_is_builtin(ref->type->type_kind) || ref->type->type_kind == TYPE_ARRAY)
{
llvm_store_bevalue_raw(c, ref, llvm_get_zero(c, ref->type));
return;
@@ -725,16 +727,11 @@ static void llvm_emit_inititialize_reference_const(GenContext *c, BEValue *ref,
}
static inline void llvm_emit_initialize_reference_const(GenContext *c, BEValue *ref, Expr *expr)
{
// Getting ready to initialize, get the real type.
Type *real_type = ref->type->canonical;
ConstInitializer *initializer = expr->initializer_expr.initializer;
// Make sure we have an address.
llvm_value_addr(c, ref);
Type *canonical = expr->type->canonical;
LLVMTypeRef type = llvm_get_type(c, canonical);
llvm_emit_inititialize_reference_const(c, ref, initializer);
}
@@ -742,7 +739,7 @@ static inline void llvm_emit_initialize_reference_const(GenContext *c, BEValue *
static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *ref, Expr *expr)
{
// Getting ready to initialize, get the real type.
Type *real_type = ref->type->canonical;
Type *real_type = type_flatten(ref->type);
Expr **elements = expr->initializer_expr.initializer_expr;
// Make sure we have an address.
@@ -784,12 +781,12 @@ static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *r
offset = i * type_size(array_element_type);
LLVMValueRef index = llvm_const_int(c, type_uint, i);
LLVMValueRef ptr = LLVMBuildInBoundsGEP2(c->builder, array_element_type_llvm, value, &index, 1, "");
unsigned alignment = aligned_offset(offset, ref->alignment);
unsigned alignment = type_min_alignment(offset, ref->alignment);
llvm_value_set_address_align(&pointer, ptr, element->type, alignment);
}
else
{
llvm_value_set_address_align(&pointer, value, element->type, 0);
llvm_value_set_address_align(&pointer, value, element->type, ref->alignment);
}
// If this is an initializer, we want to actually run the initialization recursively.
if (element->expr_kind == EXPR_INITIALIZER_LIST)
@@ -915,7 +912,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_
unsigned decl_alignment = decl_abi_alignment(decl);
if (ref->type->type_kind == TYPE_UNION)
{
llvm_value_set_address_align(&value, llvm_emit_bitcast(c, ref->value, type_get_ptr(type)), type, aligned_offset(offset, decl_alignment));
llvm_value_set_address_align(&value, llvm_emit_bitcast(c, ref->value, type_get_ptr(type)), type, type_min_alignment(offset, decl_alignment));
}
else
{
@@ -926,7 +923,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_
}
case DESIGNATOR_ARRAY:
{
Type *type = ref->type->canonical->array.base;
Type *type = ref->type->array.base;
LLVMValueRef indices[2];
if (curr->index_expr->expr_kind == EXPR_CONST)
{
@@ -943,7 +940,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_
indices[1] = llvm_value_rvalue_store(c, &res);
}
LLVMValueRef ptr = LLVMBuildInBoundsGEP2(c->builder, llvm_get_type(c, ref->type), ref->value, indices, 2, "");
llvm_value_set_address_align(&value, ptr, type, aligned_offset(offset, type_abi_alignment(type)));
llvm_value_set_address_align(&value, ptr, type, type_min_alignment(offset, type_abi_alignment(type)));
llvm_emit_initialize_designated(c, &value, offset, current + 1, last, expr, emitted_value);
break;
}
@@ -965,14 +962,15 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_
static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEValue *ref, Expr *expr)
{
// Getting ready to initialize, get the real type.
Type *real_type = ref->type->canonical;
Type *real_type = type_flatten(ref->type);
Expr **elements = expr->initializer_expr.initializer_expr;
assert(vec_size(elements));
// Make sure we have an address.
llvm_value_addr(c, ref);
// Clear the memory
llvm_emit_memclear(c, ref);
// Clear the memory if not union.
if (real_type->type_kind != TYPE_UNION) llvm_emit_memclear(c, ref);
LLVMValueRef value = ref->value;
@@ -1188,7 +1186,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
llvm_value_addr(c, value);
// Transform to value
value->kind = BE_VALUE;
value->type = expr->type;
value->type = type_flatten(expr->type);
return;
case UNARYOP_DEREF:
llvm_emit_expr(c, value, expr->unary_expr.expr);
@@ -1196,7 +1194,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
llvm_value_rvalue(c, value);
// Convert pointer to address
value->kind = BE_ADDRESS;
value->type = expr->type;
value->type = type_flatten(expr->type);
return;
case UNARYOP_INC:
llvm_emit_pre_inc_dec(c, value, expr->unary_expr.expr, 1, false);
@@ -2144,7 +2142,7 @@ void gencontext_emit_elvis_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_value_rvalue(c, value);
LLVMValueRef lhs = value->value;
Type *cond_type = expr->ternary_expr.cond->type->canonical;
Type *cond_type = expr->ternary_expr.cond->type;
// If the cond is not a boolean, we need to do the cast.
if (value->kind != BE_BOOLEAN)
@@ -2316,7 +2314,7 @@ static void gencontext_expand_struct_to_args(GenContext *context, Type *param_ty
static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values)
{
REDO:
switch (param_type->type_kind)
switch (type_flatten(param_type)->type_kind)
{
case TYPE_POISONED:
case TYPE_VOID:
@@ -2326,6 +2324,7 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
case TYPE_FUNC:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
case TYPE_DISTINCT:
UNREACHABLE
break;
case TYPE_BOOL:

View File

@@ -615,6 +615,7 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl)
{
case DECL_POISONED:
case DECL_TYPEDEF:
case DECL_DISTINCT:
UNREACHABLE;
case DECL_FUNC:
decl->backend_ref = LLVMAddFunction(context->module, decl->cname ?: decl->external_name,

View File

@@ -33,7 +33,7 @@ typedef struct
{
BackendValueKind kind : 5;
AlignSize alignment;
Type *type;
Type *type; // Should never be a distinct or canonical type.
LLVMValueRef value;
LLVMValueRef failable;
} BEValue;

View File

@@ -134,7 +134,7 @@ void gencontext_emit_decl_expr_list(GenContext *context, BEValue *be_value, Expr
}
if (bool_cast)
{
type = type->canonical;
type = type_flatten(type);
if (type->type_kind != TYPE_BOOL)
{
CastKind cast = cast_to_bool_kind(type);

View File

@@ -30,6 +30,8 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
}
case DECL_TYPEDEF:
return llvm_get_type(c, decl->typedef_decl.type_info->type);
case DECL_DISTINCT:
return llvm_get_type(c, decl->distinct_decl.base_type);
case DECL_STRUCT:
{
LLVMTypeRef *types = NULL;
@@ -328,6 +330,8 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
return any_type->backend_type = LLVMIntTypeInContext(c->context, any_type->builtin.bitsize);
case TYPE_TYPEDEF:
return any_type->backend_type = llvm_get_type(c, any_type->canonical);
case TYPE_DISTINCT:
return any_type->backend_type = llvm_get_type(c, any_type->decl->distinct_decl.base_type);
case TYPE_ENUM:
return any_type->backend_type = llvm_get_type(c, any_type->decl->enums.type_info->type->canonical);
case TYPE_ERR_UNION:

View File

@@ -1419,9 +1419,6 @@ static inline Decl *parse_attribute_declaration(Context *context, Visibility vis
return decl;
}
/**
*
*/
/**
* func_typedef
* : FUNC failable_type opt_parameter_type_list
@@ -1446,6 +1443,14 @@ static inline bool parse_func_typedef(Context *context, Decl *decl, Visibility v
}
/**
* typedef_declaration
* : TYPEDEF (func_typedef | type) AS ('distinct')? type_ident
*
* @param context
* @param visibility
* @return
*/
static inline Decl *parse_typedef_declaration(Context *context, Visibility visibility)
{
advance_and_verify(context, TOKEN_TYPEDEF);
@@ -1460,6 +1465,14 @@ static inline Decl *parse_typedef_declaration(Context *context, Visibility visib
decl->typedef_decl.is_func = false;
}
CONSUME_OR(TOKEN_AS, poisoned_decl);
// Parse optional "distinct"
if (context->tok.type == TOKEN_IDENT && TOKSTR(context->tok) == kw_distinct)
{
advance(context);
decl->type->type_kind = TYPE_DISTINCT;
decl->decl_kind = DECL_DISTINCT;
}
decl->name = TOKSTR(context->tok);
decl->type->name = TOKSTR(context->tok);
decl->name_token = context->tok.id;

View File

@@ -729,10 +729,11 @@ bool cast_implicit(Context *context, Expr *expr, Type *to_type)
CastKind cast_to_bool_kind(Type *type)
{
switch (type->type_kind)
switch (type_flatten(type)->type_kind)
{
case TYPE_TYPEDEF:
return cast_to_bool_kind(type->canonical);
case TYPE_DISTINCT:
UNREACHABLE
case TYPE_POISONED:
case TYPE_VOID:
case TYPE_ERR_UNION:
@@ -772,6 +773,16 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type)
Type *from_type = expr->type->canonical;
Type *canonical = to_type->canonical;
if (from_type == canonical) return true;
if (cast_type == CAST_TYPE_EXPLICIT)
{
canonical = type_flatten(canonical);
from_type = type_flatten(from_type);
if (from_type == canonical)
{
expr->type = to_type;
return true;
}
}
switch (from_type->type_kind)
{
case TYPE_POISONED:
@@ -779,6 +790,7 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type)
case TYPE_TYPEID:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
case TYPE_DISTINCT:
break;
case TYPE_BOOL:
// Bool may convert into integers and floats but only explicitly.
@@ -790,6 +802,7 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type)
if (to_type->type_kind == TYPE_ERRTYPE) return euer(context, expr, canonical, to_type, cast_type);
break;
case TYPE_IXX:
canonical = type_flatten(canonical);
// Compile time integers may convert into ints, floats, bools
if (expr->expr_kind != EXPR_CONST && !expr->reeval)
{
@@ -818,6 +831,10 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type)
if (canonical->type_kind == TYPE_POINTER) return xipt(context, expr, from_type, canonical, to_type, cast_type);
break;
case ALL_FLOATS:
if (from_type->type_kind == TYPE_FXX)
{
canonical = type_flatten(canonical);
}
// Compile time integers may convert into ints, floats, bools
if (from_type->type_kind == TYPE_FXX && expr->expr_kind != EXPR_CONST && !expr->reeval)
{

View File

@@ -444,6 +444,22 @@ static inline bool sema_analyse_typedef(Context *context, Decl *decl)
return true;
}
static inline bool sema_analyse_distinct(Context *context, Decl *decl)
{
if (decl->distinct_decl.typedef_decl.is_func)
{
Type *func_type = sema_analyse_function_signature(context, &decl->distinct_decl.typedef_decl.function_signature, false);
if (!func_type) return false;
decl->distinct_decl.base_type = type_get_ptr(func_type);
return true;
}
TypeInfo *info = decl->distinct_decl.typedef_decl.type_info;
if (!sema_resolve_type_info(context, info)) return false;
decl->distinct_decl.base_type = info->type->canonical;
// Do we need anything else?
return true;
}
static inline bool sema_analyse_enum(Context *context, Decl *decl)
{
// Resolve the type of the enum.
@@ -942,6 +958,9 @@ bool sema_analyse_decl(Context *context, Decl *decl)
if (!sema_analyse_global(context, decl)) return decl_poison(decl);
decl_set_external_name(decl);
break;
case DECL_DISTINCT:
if (!sema_analyse_distinct(context, decl)) return decl_poison(decl);
break;
case DECL_TYPEDEF:
if (!sema_analyse_typedef(context, decl)) return decl_poison(decl);
break;

View File

@@ -65,7 +65,7 @@ static inline bool both_const(Expr *left, Expr *right)
static inline bool both_any_integer(Expr *left, Expr *right)
{
return type_is_any_integer(left->type->canonical) && type_is_any_integer(right->type->canonical);
return type_is_any_integer(type_flatten(left->type)) && type_is_any_integer(type_flatten(right->type));
}
static inline void context_pop_returns(Context *context, Ast **restore)
@@ -163,6 +163,8 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
return true;
case DECL_VAR:
break;
case DECL_DISTINCT:
TODO
case DECL_TYPEDEF:
UNREACHABLE
case DECL_POISONED:
@@ -1412,7 +1414,7 @@ static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr)
expr->failable = expr->subscript_expr.expr->failable;
assert(expr->expr_kind == EXPR_SUBSCRIPT);
Expr *subscripted = expr->subscript_expr.expr;
Type *type = subscripted->type->canonical;
Type *type = type_flatten(subscripted->type);
Expr *index = expr->subscript_expr.index;
Type *current_type = type;
Expr *current_expr = subscripted;
@@ -1448,7 +1450,7 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr)
Expr *subscripted = expr->slice_expr.expr;
expr->pure = subscripted->pure;
expr->constant = subscripted->constant;
Type *type = subscripted->type->canonical;
Type *type = type_flatten(subscripted->type);
Expr *start = expr->slice_expr.start;
Expr *end = expr->slice_expr.end;
@@ -1928,12 +1930,12 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
assert(parent->resolve_status == RESOLVE_DONE);
Type *parent_type = parent->type;
Type *type = parent_type->canonical;
Type *type = type_flatten(parent_type);
bool is_pointer = type->type_kind == TYPE_POINTER;
if (is_pointer)
{
type = type->pointer;
type = type_flatten(type->pointer);
if (!sema_cast_rvalue(context, NULL, parent)) return false;
insert_access_deref(expr);
parent = expr->access_expr.parent;
@@ -1941,6 +1943,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
const char *kw = TOKSTR(expr->access_expr.sub_element);
Expr *current_parent = parent;
CHECK_DEEPER:
switch (type->type_kind)
{
case TYPE_SUBARRAY:
@@ -2187,7 +2190,7 @@ static void sema_create_const_initializer_value(ConstInitializer *const_init, Ex
return;
}
const_init->init_value = value;
const_init->type = value->type->canonical;
const_init->type = type_flatten(value->type);
const_init->kind = CONST_INIT_VALUE;
}
@@ -2228,7 +2231,7 @@ static inline void sema_update_const_initializer_with_designator_struct(ConstIni
{
// Create zero initializers for each of those { a: zeroinit, b: zeroinit, ... }
ConstInitializer *element_init = MALLOC(sizeof(ConstInitializer));
element_init->type = elements[i]->type->canonical;
element_init->type = type_flatten(elements[i]->type);
element_init->kind = CONST_INIT_ZERO;
const_inits[i] = element_init;
}
@@ -2296,7 +2299,7 @@ static inline void sema_update_const_initializer_with_designator_union(ConstInit
}
// Update of the sub element.
sub_element->type = const_init->type->decl->strukt.members[element->index]->type->canonical;
sub_element->type = type_flatten(const_init->type->decl->strukt.members[element->index]->type);
// And the index
const_init->init_union.index = element->index;
@@ -2338,7 +2341,7 @@ static inline void sema_update_const_initializer_with_designator_array(ConstInit
const_init->init_array.elements = NULL;
}
Type *element_type = const_init->type->array.base;
Type *element_type = type_flatten(const_init->type->array.base);
DesignatorElement **next_element = curr + 1;
bool is_last_path_element = next_element == end;
@@ -2444,10 +2447,16 @@ static inline void sema_update_const_initializer_with_designator(
}
/**
* Create a const initializer.
*/
static void sema_create_const_initializer(ConstInitializer *const_init, Expr *initializer)
{
const_init->kind = CONST_INIT_ZERO;
const_init->type = initializer->type->canonical;
// Flatten the type since the external type might be typedef or a distinct type.
const_init->type = type_flatten(initializer->type);
// Loop through the initializers.
Expr **init_expressions = initializer->initializer_expr.initializer_expr;
VECEACH(init_expressions, i)
{
@@ -2623,7 +2632,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
{
ConstInitializer *const_init = CALLOCS(ConstInitializer);
const_init->kind = CONST_INIT_STRUCT;
const_init->type = initializer->type->canonical;
const_init->type = type_flatten(initializer->type);
ConstInitializer **inits = MALLOC(sizeof(ConstInitializer *) * vec_size(elements));
VECEACH(elements, i)
{
@@ -2701,7 +2710,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T
{
ConstInitializer *const_init = CALLOCS(ConstInitializer);
const_init->kind = CONST_INIT_ARRAY_FULL;
const_init->type = initializer->type->canonical;
const_init->type = type_flatten(initializer->type);
ConstInitializer **inits = MALLOC(sizeof(ConstInitializer *) * vec_size(elements));
VECEACH(elements, i)
{
@@ -2725,9 +2734,9 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T
return true;
}
static inline bool sema_expr_analyse_initializer(Context *context, Type *assigned, Expr *expr)
static inline bool sema_expr_analyse_initializer(Context *context, Type *external_type, Type *assigned, Expr *expr)
{
expr->type = assigned;
expr->type = external_type;
Expr **init_expressions = expr->initializer_expr.initializer_expr;
@@ -2736,7 +2745,7 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *assigne
{
ConstInitializer *initializer = CALLOCS(ConstInitializer);
initializer->kind = CONST_INIT_ZERO;
initializer->type = expr->type;
initializer->type = type_flatten(expr->type);
expr->initializer_expr.init_type = INITIALIZER_CONST;
expr->initializer_expr.initializer = initializer;
expr->constant = true;
@@ -2763,15 +2772,14 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *assigne
static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to, Expr *expr)
{
assert(to);
Type *assigned = to->canonical;
assert(assigned);
Type *assigned = type_flatten(to);
switch (assigned->type_kind)
{
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ARRAY:
case TYPE_ERRTYPE:
return sema_expr_analyse_initializer(context, assigned, expr);
return sema_expr_analyse_initializer(context, to, assigned, expr);
case TYPE_VARARRAY:
TODO
default:
@@ -3857,8 +3865,8 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
bool is_equality_type_op = expr->binary_expr.operator == BINARYOP_NE || expr->binary_expr.operator == BINARYOP_EQ;
Type *left_type = left->type->canonical;
Type *right_type = right->type->canonical;
Type *left_type = type_flatten(left->type);
Type *right_type = type_flatten(right->type);
// 2. Handle the case of signed comparisons.
// This happens when either side has a definite integer type
@@ -3873,7 +3881,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
else
{
// 3. In the normal case, treat this as a binary op, finding the max type.
Type *max = type_find_max_type(left_type, right_type);
Type *max = type_find_max_type(left->type->canonical, right->type->canonical);
// 4. If no common type, then that's an error:
if (!max)
@@ -3886,7 +3894,12 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
// so we need to check that as well.
if (!is_equality_type_op)
{
switch (max->type_kind)
Type *effective_type = max;
if (max->type_kind == TYPE_DISTINCT)
{
effective_type = max->decl->distinct_decl.base_type;
}
switch (effective_type->type_kind)
{
case TYPE_POISONED:
return false;
@@ -3894,6 +3907,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
case TYPE_TYPEINFO:
case TYPE_MEMBER:
case TYPE_TYPEDEF:
case TYPE_DISTINCT:
UNREACHABLE
case TYPE_BOOL:
case TYPE_ENUM:
@@ -4241,13 +4255,14 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *
return true;
}
Type *canonical = inner->type->canonical;
switch (canonical->type_kind)
switch (type_flatten(canonical)->type_kind)
{
case TYPE_POISONED:
case TYPE_IXX:
case TYPE_FXX:
case TYPE_TYPEDEF:
case TYPE_ERR_UNION:
case TYPE_DISTINCT:
UNREACHABLE
case TYPE_FUNC:
case TYPE_ARRAY:

View File

@@ -116,6 +116,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
case DECL_ERR:
case DECL_ENUM:
case DECL_TYPEDEF:
case DECL_DISTINCT:
type_info->type = decl->type;
type_info->resolve_status = RESOLVE_DONE;
DEBUG_LOG("Resolved %s.", TOKSTR(type_info->unresolved.name_loc));

View File

@@ -36,21 +36,22 @@ static SymTab symtab;
const char *attribute_list[NUMBER_OF_ATTRIBUTES];
const char *kw_main;
const char *kw_sizeof;
const char *kw_alignof;
const char *kw_align;
const char *kw_offsetof;
const char *kw_nameof;
const char *kw_qnameof;
const char *kw_alignof;
const char *kw_distinct;
const char *kw_inline;
const char *kw_kindof;
const char *kw_len;
const char *kw_inline;
const char *kw_main;
const char *kw_nameof;
const char *kw_offsetof;
const char *kw_ordinal;
const char *kw___round;
const char *kw_qnameof;
const char *kw_sizeof;
const char *kw___ceil;
const char *kw___trunc;
const char *kw___round;
const char *kw___sqrt;
const char *kw___trunc;
void symtab_init(uint32_t capacity)
{
@@ -84,21 +85,22 @@ void symtab_init(uint32_t capacity)
// Init some constant idents
TokenType type = TOKEN_IDENT;
#define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type)
kw_inline = KW_DEF("inline");
kw_main = KW_DEF("main");
kw_sizeof = KW_DEF("sizeof");
kw_align = KW_DEF("align");
kw_alignof = KW_DEF("alignof");
kw_offsetof = KW_DEF("offsetof");
kw_nameof = KW_DEF("nameof");
kw_qnameof = KW_DEF("qnameof");
kw_distinct = KW_DEF("distinct");
kw_inline = KW_DEF("inline");
kw_kindof = KW_DEF("kindof");
kw_len = KW_DEF("len");
kw_align = KW_DEF("align");
kw_main = KW_DEF("main");
kw_nameof = KW_DEF("nameof");
kw_offsetof = KW_DEF("offsetof");
kw_ordinal = KW_DEF("ordinal");
kw_qnameof = KW_DEF("qnameof");
kw_sizeof = KW_DEF("sizeof");
kw___ceil = KW_DEF("__ceil");
kw___round = KW_DEF("__round");
kw___sqrt = KW_DEF("__sqrt");
kw___trunc = KW_DEF("__trunc");
kw___ceil = KW_DEF("__ceil");
attribute_list[ATTRIBUTE_INLINE] = kw_inline;
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline");

View File

@@ -97,6 +97,7 @@ const char *type_to_error_string(Type *type)
case ALL_FLOATS:
case TYPE_UNION:
case TYPE_ERRTYPE:
case TYPE_DISTINCT:
return type->name;
case TYPE_FUNC:
{
@@ -173,6 +174,8 @@ ByteSize type_size(Type *type)
{
switch (type->type_kind)
{
case TYPE_DISTINCT:
return type_size(type->decl->distinct_decl.base_type);
case TYPE_VECTOR:
return type_size(type->vector.base) * type->vector.len;
case TYPE_COMPLEX:
@@ -316,6 +319,8 @@ bool type_is_abi_aggregate(Type *type)
{
case TYPE_POISONED:
return false;
case TYPE_DISTINCT:
return type_is_abi_aggregate(type->decl->distinct_decl.base_type);
case TYPE_TYPEDEF:
return type_is_abi_aggregate(type->canonical);
case ALL_FLOATS:
@@ -462,6 +467,8 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
*base = type->complex;
*elements = 2;
break;
case TYPE_DISTINCT:
return type_is_homogenous_aggregate(type->decl->distinct_decl.base_type, base, elements);
case TYPE_FXX:
case TYPE_POISONED:
case TYPE_IXX:
@@ -602,6 +609,8 @@ AlignSize type_abi_alignment(Type *type)
TODO
case TYPE_VOID:
return 1;
case TYPE_DISTINCT:
return type_abi_alignment(type->decl->distinct_decl.base_type);
case TYPE_TYPEDEF:
return type_abi_alignment(type->canonical);
case TYPE_ENUM:
@@ -752,6 +761,7 @@ bool type_is_user_defined(Type *type)
Type *type_get_indexed_type(Type *type)
{
RETRY:
switch (type->type_kind)
{
case TYPE_POINTER:
@@ -762,13 +772,15 @@ Type *type_get_indexed_type(Type *type)
return type->array.base;
case TYPE_STRING:
return type_char;
case TYPE_DISTINCT:
type = type->decl->distinct_decl.base_type;
goto RETRY;
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
default:
break;
return NULL;
}
Type *canonical = type->canonical;
if (canonical != type) return type_get_indexed_type(type);
return NULL;
}
@@ -942,6 +954,9 @@ bool type_is_scalar(Type *type)
case TYPE_VARARRAY:
case TYPE_COMPLEX:
return true;
case TYPE_DISTINCT:
type = type->decl->distinct_decl.base_type;
goto RETRY;
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
@@ -1142,10 +1157,17 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_TYPEINFO:
case TYPE_MEMBER:
return NULL;
case ALL_INTS:
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
case TYPE_IXX:
if (other->type_kind == TYPE_DISTINCT && type_is_numeric(other->decl->distinct_decl.base_type)) return other;
FALLTHROUGH;
case ALL_FLOATS:
case ALL_SIGNED_INTS:
case ALL_UNSIGNED_INTS:
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
return type_find_max_num_type(type, other);
case TYPE_FXX:
if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct_decl.base_type)) return other;
FALLTHROUGH;
case ALL_REAL_FLOATS:
return type_find_max_num_type(type, other);
case TYPE_POINTER:
return type_find_max_ptr_type(type, other);
@@ -1156,11 +1178,12 @@ 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:
case TYPE_TYPEID:
return NULL;
case TYPE_STRUCT:
TODO
case TYPE_TYPEDEF:

View File

@@ -0,0 +1,28 @@
struct Struct
{
int x;
double y;
}
typedef Struct as distinct Foo;
struct Struct2
{
Foo f;
int d;
struct bar
{
Foo x;
}
}
Foo f = { 1, 1.0 };
func void test(int x)
{
Struct s = { 1, 2.0 };
Foo f2 = cast(s as Foo);
Foo f3 = { .x = 1 };
Struct2 s2 = { .f = { 1, 2.0 } };
Struct2 s3 = { .bar.x.y = 3.0 };
}

View File

@@ -0,0 +1,20 @@
module test;
typedef int as distinct Foo;
struct Struct
{
Foo x;
int y;
}
typedef Struct as distinct Struct2;
typedef Struct2[3] as distinct StructArr;
func void test(int x)
{
StructArr z = { { .x = 1 }, { .y = x }, { 1, 2 }};
usize xr = z.sizeof;
usize len = z.len;
Foo zz = z[2].x;
}

View File

@@ -0,0 +1,34 @@
module test;
union Union
{
int x;
double y;
}
typedef Union as distinct Foo;
union Union2
{
Foo f;
int d;
struct bar
{
Foo x;
}
}
Foo f = { .x = 1 };
typedef Union2 as distinct Union3;
typedef Union3[3] as distinct UnionArr;
func void test(int x)
{
Union s = { .y = 2.0 };
Foo f2 = cast(s as Foo);
Foo f3 = { .x = 1 };
Union2 s2 = { .f = { .y = 1 } };
Union2 s3 = { .bar.x.y = 3.0 };
UnionArr a = { [0].bar.x.x = 100 };
}

View File

@@ -0,0 +1,11 @@
module test;
typedef int as distinct Int2;
func void test()
{
Int2 a = 1;
a = a + 1;
int b;
a = b; // #error: Cannot implicitly cast 'int' to 'Int2'
}

View File

@@ -0,0 +1,29 @@
module test;
typedef int as distinct Foo;
func int test1()
{
Foo x = 1;
x += 2;
Foo y = 3;
y = x + y;
int z = 4;
y += cast(z as Foo);
y = y << z;
y = y >> z;
y = y + y;
y = y - y;
y = y * y;
y = y / y;
y = y & y;
y = y ^ y;
y = y | y;
bool a1 = y != y;
bool a2 = y < y;
bool a3 = y <= y;
bool a4 = y == y;
y = y == 1 ? 1 : y;
y = y < (y + 1) ? 1 : y;
return cast(y as int);
}

View File

@@ -0,0 +1,24 @@
module test;
struct Struct
{
int x;
double y;
}
typedef Struct as distinct Foo;
struct Struct2
{
Foo f;
int d;
}
Foo f = { 1, 1.0 };
func void test(int x)
{
Struct s = { 1, 2.0 };
Foo f2 = cast(s as Foo);
Foo f3 = { .x = 1 };
Struct2 s2 = { .f = { 1, 2.0 } };
}

View File

@@ -21,10 +21,11 @@ func void test()
entry:
%b = alloca %test.UnionB, align 8
%1 = bitcast %test.UnionB* %b to i32*
%2 = call i32 @bar()
store i32 %2, i32* %1, align 4
%3 = bitcast %test.UnionB* %b to %test.b*
%4 = bitcast %test.b* %3 to i8*
call void @llvm.memset.p0i8.i64(i8* %4, i8 0, i64 4, i1 false)
%0 = bitcast %test.UnionB* %b to i32*
%1 = call i32 @bar()
store i32 %1, i32* %0, align 4
%2 = bitcast %test.UnionB* %b to %test.b*
%3 = bitcast %test.b* %2 to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %3, i8 0, i64 4, i1 false)
ret void