Disambiguate types when they have the same name and need cast between each other.

This commit is contained in:
Christoffer Lerno
2025-08-31 15:16:52 +02:00
parent c0387221af
commit c7f09f2879
5 changed files with 121 additions and 6 deletions

View File

@@ -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`.

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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)
{

View 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
}