mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Disambiguate types when they have the same name and need cast between each other.
This commit is contained in:
@@ -88,6 +88,7 @@
|
||||
- Deprecated `@select` in favor of `???`.
|
||||
- Enum inference, like `Foo x = $eval("A")`, now works correctly for `$eval`.
|
||||
- Fix regression where files were added more than once. #2442
|
||||
- Disambiguate types when they have the same name and need cast between each other.
|
||||
|
||||
### Stdlib changes
|
||||
- Add `==` to `Pair`, `Triple` and TzDateTime. Add print to `Pair` and `Triple`.
|
||||
|
||||
@@ -2584,6 +2584,9 @@ FunctionPrototype *type_get_resolved_prototype(Type *type);
|
||||
bool type_is_inner_type(Type *type);
|
||||
const char *type_to_error_string(Type *type);
|
||||
const char *type_quoted_error_string(Type *type);
|
||||
const char *type_quoted_error_string_with_path(Type *type);
|
||||
const char *type_error_string_maybe_with_path(Type *type, Type *other_type);
|
||||
const char *type_quoted_error_string_maybe_with_path(Type *type, Type *other_type);
|
||||
INLINE bool type_may_negate(Type *type);
|
||||
INLINE bool type_is_builtin(TypeKind kind);
|
||||
INLINE bool type_convert_will_trunc(Type *destination, Type *source);
|
||||
|
||||
@@ -727,21 +727,23 @@ static bool report_cast_error(CastContext *cc, bool may_cast_explicit)
|
||||
}
|
||||
if (may_cast_explicit)
|
||||
{
|
||||
Type *typeto = type_no_optional(to);
|
||||
Type *from = type_no_optional(expr->type);
|
||||
if (expr->type->canonical->type_kind == TYPE_DISTINCT
|
||||
&& type_no_optional(to)->canonical->type_kind == TYPE_DISTINCT)
|
||||
{
|
||||
RETURN_CAST_ERROR(expr,
|
||||
"Implicitly casting %s to %s is not permitted. It's possible to do an explicit cast by placing '(%s)' before the expression. However, explicit casts between distinct types are usually not intended and are not safe.",
|
||||
type_quoted_error_string(type_no_optional(expr->type)),
|
||||
type_quoted_error_string(to),
|
||||
type_to_error_string(type_no_optional(to)));
|
||||
type_quoted_error_string_maybe_with_path(from, typeto),
|
||||
type_quoted_error_string_maybe_with_path(to, from),
|
||||
type_error_string_maybe_with_path(typeto, from));
|
||||
|
||||
}
|
||||
RETURN_CAST_ERROR(expr,
|
||||
"Implicitly casting %s to %s is not permitted, but you may do an explicit cast by placing '(%s)' before the expression.",
|
||||
type_quoted_error_string(type_no_optional(expr->type)),
|
||||
type_quoted_error_string(to),
|
||||
type_to_error_string(type_no_optional(to)));
|
||||
type_quoted_error_string_maybe_with_path(from, typeto),
|
||||
type_quoted_error_string_maybe_with_path(to, from),
|
||||
type_error_string_maybe_with_path(typeto, from));
|
||||
}
|
||||
if (to->type_kind == TYPE_INTERFACE)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
|
||||
static Type *flatten_raw_function_type(Type *type);
|
||||
static const char *type_to_error_string_with_path(Type *type);
|
||||
|
||||
static struct
|
||||
{
|
||||
@@ -99,6 +100,18 @@ Type *type_int_unsigned_by_bitsize(BitSize bit_size)
|
||||
}
|
||||
}
|
||||
|
||||
const char *type_quoted_error_string_maybe_with_path(Type *type, Type *other_type)
|
||||
{
|
||||
if (!str_eq(type_no_optional(type)->name, type_no_optional(other_type)->name)) return type_quoted_error_string(type);
|
||||
return type_quoted_error_string_with_path(type);
|
||||
}
|
||||
|
||||
const char *type_error_string_maybe_with_path(Type *type, Type *other_type)
|
||||
{
|
||||
if (!str_eq(type_no_optional(type)->name, type_no_optional(other_type)->name)) return type_to_error_string(type);
|
||||
return type_to_error_string_with_path(type);
|
||||
}
|
||||
|
||||
const char *type_quoted_error_string(Type *type)
|
||||
{
|
||||
if (type->canonical != type)
|
||||
@@ -108,6 +121,15 @@ const char *type_quoted_error_string(Type *type)
|
||||
return str_printf("'%s'", type_to_error_string(type));
|
||||
}
|
||||
|
||||
const char *type_quoted_error_string_with_path(Type *type)
|
||||
{
|
||||
if (type->canonical != type)
|
||||
{
|
||||
return str_printf("'%s' (%s)", type_to_error_string_with_path(type), type_to_error_string_with_path(type->canonical));
|
||||
}
|
||||
return str_printf("'%s'", type_to_error_string_with_path(type));
|
||||
}
|
||||
|
||||
void type_append_name_to_scratch(Type *type)
|
||||
{
|
||||
type = type->canonical;
|
||||
@@ -234,6 +256,7 @@ static void type_add_parent_to_scratch(Decl *decl)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const char *type_to_error_string(Type *type)
|
||||
{
|
||||
switch (type->type_kind)
|
||||
@@ -301,6 +324,77 @@ const char *type_to_error_string(Type *type)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static const char *type_to_error_string_with_path(Type *type)
|
||||
{
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
return "poisoned";
|
||||
case TYPE_VOID:
|
||||
case TYPE_BOOL:
|
||||
case ALL_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_ANYFAULT:
|
||||
case TYPE_UNTYPED_LIST:
|
||||
case TYPE_ANY:
|
||||
case TYPE_MEMBER:
|
||||
case TYPE_WILDCARD:
|
||||
return type->name;
|
||||
case TYPE_ENUM:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_INTERFACE:
|
||||
{
|
||||
Decl *decl = type->decl;
|
||||
const char *suffix = decl->unit->module->generic_suffix;
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(decl->unit->module->name->module);
|
||||
scratch_buffer_append("::");
|
||||
if (suffix || type_is_inner_type(type))
|
||||
{
|
||||
type_add_parent_to_scratch(decl);
|
||||
}
|
||||
scratch_buffer_append(decl->name);
|
||||
if (suffix) scratch_buffer_append(suffix);
|
||||
return scratch_buffer_copy();
|
||||
}
|
||||
case TYPE_FUNC_PTR:
|
||||
type = type->pointer;
|
||||
FALLTHROUGH;
|
||||
case TYPE_FUNC_RAW:
|
||||
if (!type->function.prototype) return type->name;
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append("fn ");
|
||||
type_append_func_to_scratch(type->function.prototype);
|
||||
return scratch_buffer_copy();
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
return str_printf("%s[<*>]", type_to_error_string_with_path(type->array.base));
|
||||
case TYPE_VECTOR:
|
||||
return str_printf("%s[<%llu>]", type_to_error_string_with_path(type->array.base), (unsigned long long)type->array.len);
|
||||
case TYPE_TYPEINFO:
|
||||
return "typeinfo";
|
||||
case TYPE_TYPEID:
|
||||
return "typeid";
|
||||
case TYPE_POINTER:
|
||||
return str_printf("%s*", type_to_error_string_with_path(type->pointer));
|
||||
case TYPE_OPTIONAL:
|
||||
if (!type->optional) return "void?";
|
||||
return str_printf("%s?", type_to_error_string_with_path(type->optional));
|
||||
case TYPE_ARRAY:
|
||||
return str_printf("%s[%llu]", type_to_error_string_with_path(type->array.base), (unsigned long long)type->array.len);
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
return str_printf("%s[*]", type_to_error_string_with_path(type->array.base));
|
||||
case TYPE_SLICE:
|
||||
return str_printf("%s[]", type_to_error_string_with_path(type->array.base));
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
bool type_is_matching_int(CanonicalType *type1, CanonicalType *type2)
|
||||
{
|
||||
|
||||
15
test/test_suite/cast/implicit_cast_same_name.c3
Normal file
15
test/test_suite/cast/implicit_cast_same_name.c3
Normal file
@@ -0,0 +1,15 @@
|
||||
module foo::a;
|
||||
struct Lexer { int a; }
|
||||
fn void foo(Lexer *lex) {}
|
||||
|
||||
module foo::b;
|
||||
struct Lexer { int a; }
|
||||
fn void foo(Lexer *lex) {}
|
||||
|
||||
module foo;
|
||||
|
||||
fn void bar()
|
||||
{
|
||||
a::Lexer l;
|
||||
b::foo(&l); // #error: Implicitly casting 'foo::a::Lexer*' to 'foo::b::Lexer*' is not permitted, but you may do an explicit cast by placing '(foo::b::Lexer*)' before the expression
|
||||
}
|
||||
Reference in New Issue
Block a user