mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
int val = some_int + some_distinct_inline_int errors that int cannot be cast to DistinctInt #2468
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
- Correctly silence "unsupported architecture" warning with `--quiet` #2465
|
||||
- Overloading &[] should be enough for foreach. #2466
|
||||
- Any register allowed in X86_64 inline asm address. #2463
|
||||
- int val = some_int + some_distinct_inline_int errors that int cannot be cast to DistinctInt #2468
|
||||
|
||||
### Stdlib changes
|
||||
- Added generic `InterfaceList` to store a list of values that implement a specific interface
|
||||
|
||||
@@ -2541,7 +2541,7 @@ AlignSize type_abi_alignment(Type *type);
|
||||
bool type_func_match(Type *fn_type, Type *rtype, unsigned arg_count, ...);
|
||||
AlignSize type_alloca_alignment(Type *type);
|
||||
Type *type_find_largest_union_element(Type *type);
|
||||
Type *type_find_max_type(Type *type, Type *other);
|
||||
Type *type_find_max_type(Type *type, Type *other, Expr *first, Expr *second);
|
||||
Type *type_find_max_type_may_fail(Type *type, Type *other);
|
||||
Type *type_abi_find_single_struct_element(Type *type);
|
||||
Module *type_base_module(Type *type);
|
||||
@@ -3118,16 +3118,32 @@ static inline Type *type_base(Type *type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const bool is_distinct_like[TYPE_LAST + 1] = {
|
||||
[TYPE_ENUM] = true,
|
||||
[TYPE_CONST_ENUM] = true,
|
||||
[TYPE_DISTINCT] = true
|
||||
};
|
||||
|
||||
INLINE bool typekind_is_distinct_like(TypeKind kind)
|
||||
{
|
||||
return is_distinct_like[kind];
|
||||
}
|
||||
|
||||
INLINE bool type_is_distinct_like(Type *type)
|
||||
{
|
||||
TypeKind kind = type->type_kind;
|
||||
return kind == TYPE_DISTINCT || kind == TYPE_CONST_ENUM;
|
||||
return is_distinct_like[type->type_kind];
|
||||
}
|
||||
|
||||
static bool type_has_inline(Type *type)
|
||||
{
|
||||
return is_distinct_like[type->type_kind] && type->decl->is_substruct;
|
||||
}
|
||||
|
||||
static inline Type *type_inline(Type *type)
|
||||
{
|
||||
assert(type_is_distinct_like(type));
|
||||
return type->type_kind == TYPE_CONST_ENUM ? type->decl->enums.type_info->type : type->decl->distinct->type;
|
||||
return type->type_kind == TYPE_DISTINCT ? type->decl->distinct->type : type->decl->enums.type_info->type;
|
||||
}
|
||||
|
||||
|
||||
@@ -3136,16 +3152,8 @@ static inline Type *type_flat_distinct_inline(Type *type)
|
||||
while (1)
|
||||
{
|
||||
type = type->canonical;
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_CONST_ENUM:
|
||||
if (!type->decl->is_substruct) return type;
|
||||
type = type_inline(type);
|
||||
break;
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
if (!type_has_inline(type)) return type;
|
||||
type = type_inline(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1108,7 +1108,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Type *infer_t
|
||||
Type *right_canonical = right->type->canonical;
|
||||
if (left_canonical != right_canonical)
|
||||
{
|
||||
Type *max = type_find_max_type(type_no_optional(left_canonical), type_no_optional(right_canonical));
|
||||
Type *max = type_find_max_type(type_no_optional(left_canonical), type_no_optional(right_canonical), left, right);
|
||||
if (!max)
|
||||
{
|
||||
SEMA_ERROR(expr, "Cannot find a common parent type of '%s' and '%s'",
|
||||
@@ -2566,7 +2566,7 @@ static inline Type *context_unify_returns(SemaContext *context)
|
||||
if (common_type == rtype || (type_is_void(common_type) && rtype == type_wildcard)) continue;
|
||||
|
||||
// 4. Find the max of the old and new.
|
||||
Type *max = type_find_max_type(common_type, rtype); // NOLINT
|
||||
Type *max = type_find_max_type(common_type, rtype, NULL, NULL);
|
||||
|
||||
// 5. No match -> error.
|
||||
if (!max)
|
||||
@@ -4256,7 +4256,7 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range,
|
||||
if (IS_OPTIONAL(start)) range->is_optional = true;
|
||||
if (end && end_type != start_type)
|
||||
{
|
||||
Type *common = type_find_max_type(start_type, end_type);
|
||||
Type *common = type_find_max_type(start_type, end_type, NULL, NULL);
|
||||
if (!common)
|
||||
{
|
||||
SourceSpan span = start->span;
|
||||
@@ -7373,7 +7373,7 @@ static bool sema_binary_arithmetic_promotion(SemaContext *context, Expr *left, E
|
||||
}
|
||||
}
|
||||
|
||||
Type *max = cast_numeric_arithmetic_promotion(type_find_max_type(left_type, right_type));
|
||||
Type *max = cast_numeric_arithmetic_promotion(type_find_max_type(left_type, right_type, left, right));
|
||||
if (!max || (!type_underlying_is_numeric(max) && !(allow_bool_vec && type_flat_is_bool_vector(max))))
|
||||
{
|
||||
CHECK_ON_DEFINED(failed_ref);
|
||||
@@ -8275,7 +8275,7 @@ NEXT:
|
||||
|
||||
|
||||
// 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, right_type, left, right);
|
||||
|
||||
// 4. If no common type, then that's an error:
|
||||
if (!max)
|
||||
@@ -9143,7 +9143,7 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr,
|
||||
bool add_optional = type_is_optional(else_type);
|
||||
type = type_no_optional(type);
|
||||
else_type = type_no_optional(else_type);
|
||||
Type *common = type_find_max_type(type, else_type);
|
||||
Type *common = type_find_max_type(type, else_type, left, right);
|
||||
if (!common)
|
||||
{
|
||||
CHECK_ON_DEFINED(failed_ref);
|
||||
|
||||
@@ -1865,6 +1865,10 @@ Type *type_find_max_num_type(Type *num_type, Type *other_num)
|
||||
ASSERT(kind <= other_kind && "Expected ordering");
|
||||
ASSERT(kind != other_kind);
|
||||
|
||||
// If the other is a vector then we always set that one as the max.
|
||||
if (other_kind == TYPE_VECTOR) return other_num;
|
||||
|
||||
|
||||
// 1. The only conversions need to happen if the other type is a number.
|
||||
if (other_kind < TYPE_INTEGER_FIRST || other_kind > TYPE_FLOAT_LAST) return NULL;
|
||||
|
||||
@@ -1925,7 +1929,7 @@ static inline Type *type_find_max_ptr_type(Type *type, Type *other)
|
||||
// Slice and vararray can implicitly convert to a pointer.
|
||||
if (other->type_kind == TYPE_SLICE)
|
||||
{
|
||||
Type *max_type = type_find_max_type(type->pointer, other->pointer);
|
||||
Type *max_type = type_find_max_type(type->pointer, other->pointer, false, false);
|
||||
if (!max_type) return NULL;
|
||||
return type_get_ptr(max_type);
|
||||
}
|
||||
@@ -1959,7 +1963,7 @@ static inline Type *type_find_max_ptr_type(Type *type, Type *other)
|
||||
{
|
||||
return other;
|
||||
}
|
||||
Type *max_type = type_find_max_type(pointer_type, other_pointer_type);
|
||||
Type *max_type = type_find_max_type(pointer_type, other_pointer_type, false, false);
|
||||
if (!max_type) return NULL;
|
||||
return type_get_ptr(max_type);
|
||||
}
|
||||
@@ -2011,57 +2015,97 @@ static inline Type *type_find_max_distinct_type(Type *left, Type *right)
|
||||
}
|
||||
|
||||
|
||||
Type *type_find_max_type(Type *type, Type *other)
|
||||
Type *type_find_max_type(Type *type, Type *other, Expr *first, Expr *second)
|
||||
{
|
||||
type = type->canonical;
|
||||
other = other->canonical;
|
||||
ASSERT(!type_is_optional(type) && !type_is_optional(other));
|
||||
|
||||
RETRY_DISTINCT:
|
||||
// Same type, max is the type
|
||||
if (type == other) return type;
|
||||
|
||||
// One type is wildcard, max is the type which isn't wildcard
|
||||
if (type == type_wildcard) return other;
|
||||
if (other == type_wildcard) return type;
|
||||
|
||||
// Sort types
|
||||
// Sort types to make it easier
|
||||
if (type->type_kind > other->type_kind)
|
||||
{
|
||||
Type *temp = type;
|
||||
Expr *first_expr = first;
|
||||
type = other;
|
||||
first = second;
|
||||
other = temp;
|
||||
second = first_expr;
|
||||
}
|
||||
|
||||
// The following relies on type kind ordering
|
||||
// The following relies on type kind ordering, with the "lowest" type kind on top, this means the other type kind is
|
||||
// further down in the list
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
case TYPE_POISONED:
|
||||
case TYPE_OPTIONAL:
|
||||
case TYPE_WILDCARD:
|
||||
// Should never get here
|
||||
UNREACHABLE
|
||||
case TYPE_VOID:
|
||||
case TYPE_BOOL:
|
||||
case TYPE_TYPEINFO:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
if (type_has_inline(other))
|
||||
{
|
||||
other = type_flat_distinct_inline(other);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
return NULL;
|
||||
case ALL_INTS:
|
||||
if (type_is_distinct_like(other) && type_underlying_is_numeric(other)) return other;
|
||||
if (other->type_kind == TYPE_VECTOR) return other;
|
||||
{
|
||||
// If Foo + 1, then we allow this if Foo is a distinct type or const enum that has
|
||||
// integer or float as the base type.
|
||||
if (first && type_is_distinct_like(other) && type_underlying_is_numeric(other) && expr_is_const(first)) return other;
|
||||
// See if we can flatten it.
|
||||
if (type_has_inline(other))
|
||||
{
|
||||
other = type_flat_distinct_inline(other);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
// Now let's just compare the numerical type, including vectors
|
||||
return type_find_max_num_type(type, other);
|
||||
}
|
||||
case ALL_FLOATS:
|
||||
if (type_is_distinct_like(other) && type_is_float(type_flatten(other))) return other;
|
||||
if (other->type_kind == TYPE_VECTOR) return other;
|
||||
{
|
||||
// If Foo + 1.0, then we allow this if Foo is a distinct type or const enum that has
|
||||
// float as the base type.
|
||||
if (first && type_is_distinct_like(other) && type_underlying_is_numeric(other) && expr_is_const(first)) return other;
|
||||
// See if we can flatten it.
|
||||
if (type_has_inline(other))
|
||||
{
|
||||
other = type_flat_distinct_inline(other);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
// Now let's just compare the numerical type, including vectors
|
||||
return type_find_max_num_type(type, other);
|
||||
}
|
||||
case TYPE_ANY:
|
||||
// any + interface => any
|
||||
if (other == type_voidptr) return other;
|
||||
if (type_has_inline(other))
|
||||
{
|
||||
other = type_flat_distinct_inline(other);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
return other->type_kind == TYPE_INTERFACE ? type : NULL;
|
||||
case TYPE_INTERFACE:
|
||||
// interface + void* => void*
|
||||
if (type_has_inline(other))
|
||||
{
|
||||
other = type_flat_distinct_inline(other);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
return other == type_voidptr ? type_voidptr : NULL;
|
||||
case TYPE_POINTER:
|
||||
if (type_has_inline(other))
|
||||
{
|
||||
other = type_flat_distinct_inline(other);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
if (type->pointer->type_kind == TYPE_ARRAY)
|
||||
{
|
||||
Type *array_base = type->pointer->array.base->canonical;
|
||||
@@ -2092,38 +2136,62 @@ RETRY_DISTINCT:
|
||||
// And possibly the other pointer as well
|
||||
if (other->type_kind == TYPE_POINTER) other = type_decay_array_pointer(other);
|
||||
return type_find_max_ptr_type(type, other);
|
||||
case TYPE_ENUM:
|
||||
if (type->decl->is_substruct)
|
||||
{
|
||||
return type_find_max_type(type_flat_distinct_enum_inline(type), other);
|
||||
}
|
||||
return NULL;
|
||||
case TYPE_ANYFAULT:
|
||||
return type_fault;
|
||||
case TYPE_TYPEID:
|
||||
if (type_has_inline(other))
|
||||
{
|
||||
other = type_flat_distinct_inline(other);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
return type;
|
||||
case TYPE_FUNC_PTR:
|
||||
if (other == type_voidptr) return other;
|
||||
if (type_has_inline(other))
|
||||
{
|
||||
other = type_flat_distinct_inline(other);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
if (other->type_kind != TYPE_FUNC_PTR) return NULL;
|
||||
if (other->pointer->function.prototype->raw_type != type->pointer->function.prototype->raw_type) return NULL;
|
||||
return type;
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_CONST_ENUM:
|
||||
if (type_is_distinct_like(other))
|
||||
{
|
||||
return type_find_max_distinct_type(type, other);
|
||||
}
|
||||
// Try matching with its inline type
|
||||
if (type->decl->is_substruct)
|
||||
{
|
||||
type = type_inline(type);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
// distinct + any other type => no
|
||||
return NULL;
|
||||
case TYPE_ENUM:
|
||||
// Note that the int case is already handled
|
||||
if (type->decl->is_substruct)
|
||||
{
|
||||
return type_find_max_type(type_flat_distinct_enum_inline(type), other, first, second);
|
||||
}
|
||||
return NULL;
|
||||
case TYPE_FUNC_RAW:
|
||||
UNREACHABLE
|
||||
case TYPE_UNION:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_BITSTRUCT:
|
||||
// union/struct + anything else => no
|
||||
// even if the struct has an inline type, this should not
|
||||
// be implicit
|
||||
return NULL;
|
||||
case TYPE_TYPEDEF:
|
||||
UNREACHABLE // Should only handle canonical types
|
||||
case TYPE_UNTYPED_LIST:
|
||||
if (other->type_kind == TYPE_ARRAY) return other;
|
||||
if (other->type_kind == TYPE_VECTOR) return other;
|
||||
if (other->type_kind == TYPE_STRUCT) return other;
|
||||
if (other->type_kind == TYPE_SLICE) return other;
|
||||
return NULL;
|
||||
case TYPE_UNION:
|
||||
case TYPE_STRUCT:
|
||||
// union/struct + anything else => no
|
||||
// even if the struct has an inline type, this should not
|
||||
// be implicit
|
||||
return NULL;
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_MEMBER:
|
||||
return NULL;
|
||||
case TYPE_TYPEDEF:
|
||||
UNREACHABLE
|
||||
case TYPE_SLICE:
|
||||
// slice + [array, vector of the same type] => yes
|
||||
if (type_is_arraylike(other) && (other->array.base->canonical == type->array.base->canonical))
|
||||
@@ -2135,27 +2203,24 @@ RETRY_DISTINCT:
|
||||
case TYPE_ARRAY:
|
||||
// array + [other array, vector] => no
|
||||
return NULL;
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
// Already handled
|
||||
UNREACHABLE
|
||||
case TYPE_OPTIONAL:
|
||||
// Should never be passed here
|
||||
UNREACHABLE
|
||||
case TYPE_WILDCARD:
|
||||
// Handled above
|
||||
UNREACHABLE
|
||||
case TYPE_TYPEINFO:
|
||||
case TYPE_MEMBER:
|
||||
return NULL;
|
||||
UNREACHABLE
|
||||
case TYPE_VECTOR:
|
||||
// No implicit conversion between vectors
|
||||
return NULL;
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_CONST_ENUM:
|
||||
if (type_is_distinct_like(other))
|
||||
{
|
||||
return type_find_max_distinct_type(type, other);
|
||||
}
|
||||
if (other->type_kind == TYPE_ENUM && other->decl->is_substruct)
|
||||
{
|
||||
return type_find_max_type(type, type_flat_distinct_enum_inline(other));
|
||||
}
|
||||
// Try matching with its inline type
|
||||
if (type->decl->is_substruct)
|
||||
{
|
||||
type = type_inline(type);
|
||||
goto RETRY_DISTINCT;
|
||||
}
|
||||
// distinct + any other type => no
|
||||
return NULL;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
44
test/test_suite/expressions/casts/inline_to_underlying.c3t
Normal file
44
test/test_suite/expressions/casts/inline_to_underlying.c3t
Normal file
@@ -0,0 +1,44 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std;
|
||||
typedef DistinctInt = inline int;
|
||||
enum Foo : inline int
|
||||
{
|
||||
ABC,
|
||||
}
|
||||
enum Bar : const inline int
|
||||
{
|
||||
HELLO = 1
|
||||
}
|
||||
fn int main()
|
||||
{
|
||||
int a = 1;
|
||||
DistinctInt b = 2;
|
||||
int c = a + b;
|
||||
c = a + Bar.HELLO;
|
||||
c = a + Foo.ABC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%a = alloca i32, align 4
|
||||
%b = alloca i32, align 4
|
||||
%c = alloca i32, align 4
|
||||
store i32 1, ptr %a, align 4
|
||||
store i32 2, ptr %b, align 4
|
||||
%0 = load i32, ptr %a, align 4
|
||||
%1 = load i32, ptr %b, align 4
|
||||
%add = add i32 %0, %1
|
||||
store i32 %add, ptr %c, align 4
|
||||
%2 = load i32, ptr %a, align 4
|
||||
%add1 = add i32 %2, 1
|
||||
store i32 %add1, ptr %c, align 4
|
||||
%3 = load i32, ptr %a, align 4
|
||||
%add2 = add i32 %3, 0
|
||||
store i32 %add2, ptr %c, align 4
|
||||
ret i32 0
|
||||
}
|
||||
Reference in New Issue
Block a user