mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Method resolution and $define now works together well unless definitions are out of order for real.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
## 0.7.10 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Method resolution and `$define` now works together well unless definitions are out of order for real.
|
||||
|
||||
### Stdlib changes
|
||||
- Summarize sort macros as generic function wrappers to reduce the amount of generated code. #2831
|
||||
|
||||
@@ -720,6 +720,7 @@ typedef struct Decl_
|
||||
bool attr_structlike : 1;
|
||||
bool is_template : 1;
|
||||
bool is_templated : 1;
|
||||
bool is_method_checked : 1;
|
||||
union
|
||||
{
|
||||
void *backend_ref;
|
||||
@@ -2016,6 +2017,7 @@ typedef struct
|
||||
HTable features;
|
||||
Module std_module;
|
||||
MethodTable method_extensions;
|
||||
Type **types_with_failed_methods;
|
||||
Decl **method_extension_list;
|
||||
DeclTable symbols;
|
||||
PathTable path_symbols;
|
||||
|
||||
@@ -13,7 +13,7 @@ static inline bool sema_check_param_uniqueness_and_type(SemaContext *context, De
|
||||
static inline bool sema_analyse_method(SemaContext *context, Decl *decl);
|
||||
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type, bool is_dynamic);
|
||||
static inline bool sema_analyse_macro_method(SemaContext *context, Decl *decl);
|
||||
static inline bool unit_add_base_extension_method(SemaContext *context, Decl *method);
|
||||
static inline bool unit_add_base_extension_method(SemaContext *context, Type *type, Decl *method);
|
||||
static inline bool type_add_method(SemaContext *context, Type *parent_type, Decl *method);
|
||||
static bool sema_analyse_operator_common(SemaContext *context, Decl *method, TypeInfo **rtype_ptr, Decl ***params_ptr, uint32_t parameters);
|
||||
static inline bool sema_analyse_operator_element_at(SemaContext *context, Decl *method);
|
||||
@@ -2295,7 +2295,7 @@ INLINE SourceSpan method_find_overload_span(Decl *method)
|
||||
return method->attrs_resolved->overload;
|
||||
}
|
||||
|
||||
static inline bool unit_add_base_extension_method(SemaContext *context, Decl *method)
|
||||
static inline bool unit_add_base_extension_method(SemaContext *context, Type *type, Decl *method)
|
||||
{
|
||||
Decl *other = declptrzero(methodtable_set(&compiler.context.method_extensions, method));
|
||||
if (other)
|
||||
@@ -2304,6 +2304,13 @@ static inline bool unit_add_base_extension_method(SemaContext *context, Decl *me
|
||||
SEMA_NOTE(other, "The previous definition was here.");
|
||||
return false;
|
||||
}
|
||||
FOREACH(Type *, t, compiler.context.types_with_failed_methods)
|
||||
{
|
||||
if (t == type)
|
||||
{
|
||||
RETURN_SEMA_ERROR(method, "A method was added to %s which already was checked for method availability, declarations must be reordered.", type_quoted_error_string(type));
|
||||
}
|
||||
}
|
||||
vec_add(compiler.context.method_extension_list, method);
|
||||
DEBUG_LOG("Builtin type method '%s' analysed.", method->name);
|
||||
return true;
|
||||
@@ -2636,7 +2643,7 @@ static inline bool type_add_method(SemaContext *context, Type *parent_type, Decl
|
||||
return true;
|
||||
}
|
||||
// Is it a base extension?
|
||||
if (!type_is_user_defined(parent_type)) return unit_add_base_extension_method(context, method);
|
||||
if (!type_is_user_defined(parent_type)) return unit_add_base_extension_method(context, parent_type, method);
|
||||
|
||||
// Resolve it as a user-defined type extension.
|
||||
Decl *parent = parent_type->decl;
|
||||
@@ -2653,7 +2660,10 @@ static inline bool type_add_method(SemaContext *context, Type *parent_type, Decl
|
||||
SEMA_NOTE(other, "The previous definition was here.");
|
||||
return decl_poison(method);
|
||||
}
|
||||
|
||||
if (parent->is_method_checked)
|
||||
{
|
||||
RETURN_SEMA_ERROR(method, "A method was added to %s which already was checked for method availability, declarations must be reordered.", type_quoted_error_string(parent_type));
|
||||
}
|
||||
DEBUG_LOG("Method-like '%s.%s' analysed.", parent->name, method->name);
|
||||
|
||||
Methods *table = parent->method_table;
|
||||
|
||||
@@ -5059,7 +5059,11 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member)
|
||||
{
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
if (missing_ref)
|
||||
{
|
||||
vec_add(compiler.context.types_with_failed_methods, parent_type);
|
||||
goto MISSING_REF;
|
||||
}
|
||||
RETURN_SEMA_ERROR(expr, "'%s' does not have a property or method '%s'.", type_to_error_string(parent_type), name);
|
||||
}
|
||||
expr_resolve_ident(expr, member);
|
||||
@@ -5106,8 +5110,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
||||
{
|
||||
if (decl->unit->module->stage < ANALYSIS_POST_REGISTER)
|
||||
{
|
||||
bool err = SEMA_WARN_STRICT(expr, "There might be a method '%s' for %s, but methods for the type have not yet been completely registered, so a warning is issued.", name, type_quoted_error_string(parent_type));
|
||||
if (err) return false;
|
||||
decl->is_method_checked = true;
|
||||
}
|
||||
goto MISSING_REF;
|
||||
}
|
||||
@@ -5205,6 +5208,8 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e
|
||||
sema_create_const_membersof(expr, decl->type->canonical, parent->const_expr.member.align, parent->const_expr.member.offset);
|
||||
return true;
|
||||
case TYPE_PROPERTY_METHODSOF:
|
||||
decl->is_method_checked = true;
|
||||
FALLTHROUGH;
|
||||
case TYPE_PROPERTY_KINDOF:
|
||||
case TYPE_PROPERTY_SIZEOF:
|
||||
return sema_expr_rewrite_to_type_property(context, expr, decl->type->canonical, type_property, decl->type->canonical);
|
||||
@@ -5260,6 +5265,7 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e
|
||||
return true;
|
||||
MISSING_REF:
|
||||
*missing_ref = true;
|
||||
decl->is_method_checked = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6551,7 +6557,11 @@ CHECK_DEEPER:
|
||||
Decl *method = sema_resolve_type_method(context, type, kw);
|
||||
if (!method)
|
||||
{
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
if (missing_ref)
|
||||
{
|
||||
vec_add(compiler.context.types_with_failed_methods, type);
|
||||
goto MISSING_REF;
|
||||
}
|
||||
RETURN_SEMA_ERROR(expr, "There is no member or method '%s' on %s", kw, type_quoted_error_string(parent->type));
|
||||
}
|
||||
|
||||
@@ -6608,6 +6618,13 @@ CHECK_DEEPER:
|
||||
// 11. If we didn't find a match...
|
||||
if (!member)
|
||||
{
|
||||
Type *parent_type = type_no_optional(parent->type)->canonical;
|
||||
ASSERT(type_is_user_defined(parent_type));
|
||||
// Tag as maybe wrong.
|
||||
if (!private && missing_ref && parent_type->decl->unit->module->stage < ANALYSIS_POST_REGISTER)
|
||||
{
|
||||
parent_type->decl->is_method_checked = true;
|
||||
}
|
||||
// 11a. We have a potential embedded struct check:
|
||||
Expr *substruct = sema_enter_inline_member(current_parent, type);
|
||||
if (substruct)
|
||||
@@ -6625,13 +6642,7 @@ CHECK_DEEPER:
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
RETURN_SEMA_ERROR(expr, "The method '%s' has private visibility.", kw);
|
||||
}
|
||||
Type *parent_type = type_no_optional(parent->type)->canonical;
|
||||
ASSERT(type_is_user_defined(parent_type));
|
||||
if (missing_ref && parent_type->decl->unit->module->stage < ANALYSIS_POST_REGISTER)
|
||||
{
|
||||
bool err = SEMA_WARN_STRICT(expr, "There might be a method '%s' for %s, but methods have not yet been completely registered, so analysis fails.", kw, type_quoted_error_string(parent->type));
|
||||
if (err) return false;
|
||||
}
|
||||
|
||||
if (parent_type->type_kind == TYPE_INTERFACE)
|
||||
{
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
@@ -6666,7 +6677,6 @@ CHECK_DEEPER:
|
||||
}
|
||||
}
|
||||
// 13. Copy properties.
|
||||
|
||||
expr->access_resolved_expr = (ExprResolvedAccess) { .parent = current_parent, .ref = member };
|
||||
if (expr->expr_kind == EXPR_ACCESS_UNRESOLVED) expr->expr_kind = EXPR_ACCESS_RESOLVED;
|
||||
expr->type = type_add_optional(member->type, optional);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define UINT20_MAX 1048575U
|
||||
|
||||
#define SEMA_WARN(_node, ...) (sema_warn_at(context, (_node)->span, __VA_ARGS__))
|
||||
#define SEMA_WARN_STRICT(_node, ...) (sema_warn_very_strict(context, (_node)->span, __VA_ARGS__))
|
||||
#define SEMA_ERROR(_node, ...) sema_error_at(context, (_node)->span, __VA_ARGS__)
|
||||
#define RETURN_SEMA_ERROR(_node, ...) do { sema_error_at(context, (_node)->span, __VA_ARGS__); return false; } while (0)
|
||||
#define RETURN_VAL_SEMA_ERROR(val__, _node, ...) do { sema_error_at(context, (_node)->span, __VA_ARGS__); return (val__); } while (0)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module test2;
|
||||
import test3;
|
||||
struct Bar @if($defined(Foo.b)) // warning: There might be a method 'b' for 'Foo', but methods for the type have not yet been
|
||||
struct Bar @if($defined(Foo.b))
|
||||
{
|
||||
int a;
|
||||
}
|
||||
|
||||
struct Bar2 @if($defined((Foo){}.b)) // warning: There might be a method 'b' for 'Foo', but methods have not yet been completely
|
||||
struct Bar2 @if($defined((Foo){}.b))
|
||||
{
|
||||
int a;
|
||||
}
|
||||
@@ -15,6 +15,8 @@ struct Foo
|
||||
{
|
||||
int a;
|
||||
}
|
||||
fn void Foo.b(&self) {} // #error: A method was added to 'Foo' which already was checked for method availability
|
||||
|
||||
module test;
|
||||
|
||||
import test2;
|
||||
@@ -22,6 +24,6 @@ import test3;
|
||||
|
||||
fn int main()
|
||||
{
|
||||
Bar b; // #error: 'Bar' could not be found, did you spell it right
|
||||
Bar b;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user