Allow using inferred type on method first parameter.

This commit is contained in:
Christoffer Lerno
2023-07-01 22:47:43 +02:00
parent 2ac213a3ce
commit 45820d45e5
5 changed files with 124 additions and 11 deletions

View File

@@ -3,6 +3,7 @@
## 0.5.0 Change List
### Changes / improvements
- Allow inferred type on method first argument.
- Fix to void expression blocks
- Temporary objects may now invoke methods using ref parameters.
- Delete object files after successful linking.

View File

@@ -8,7 +8,7 @@
static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, bool is_func, bool *erase_decl);
static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig);
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfoId type_parent);
static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl);
static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *current, unsigned current_index, unsigned count);
@@ -693,7 +693,7 @@ static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl, bool *erase
}
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig)
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfoId type_parent)
{
Variadic variadic_type = sig->variadic;
Decl **params = sig->params;
@@ -740,6 +740,33 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig)
return false;
}
// Fill in the type if the first parameter is lacking a type.
if (type_parent && params && params[0] && !params[0]->var.type_info)
{
TypeInfo *method_parent = type_infoptr(type_parent);
if (!sema_resolve_type_info(context, method_parent)) return false;
Decl *param = params[0];
Type *inferred_type = NULL;
switch (param->var.kind)
{
case VARDECL_PARAM_REF:
if (!is_macro)
{
inferred_type = type_get_ptr(method_parent->type);
param->var.kind = VARDECL_PARAM;
break;
}
FALLTHROUGH;
case VARDECL_PARAM:
inferred_type = method_parent->type;
break;
default:
goto CHECK_PARAMS;
}
param->var.type_info = type_info_new_base(inferred_type, param->span);
}
CHECK_PARAMS:
// Check parameters
for (unsigned i = 0; i < param_count; i++)
@@ -782,8 +809,9 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig)
SEMA_ERROR(param, "Only regular parameters are allowed for functions.");
return decl_poison(param);
}
if (!is_macro_at_name)
if (!is_macro_at_name && (!type_parent || i != 0 || var_kind != VARDECL_PARAM_REF))
{
SEMA_ERROR(param, "Ref and expression parameters are not allowed in function-like macros. Prefix the macro name with '@'.");
return decl_poison(param);
}
@@ -878,18 +906,18 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig)
}
Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallABI abi, Signature *signature, bool is_real_function)
Type *sema_analyse_function_signature(SemaContext *context, Decl *func_decl, CallABI abi, Signature *signature, bool is_real_function)
{
// Get param count and variadic type
Decl **params = signature->params;
if (!sema_analyse_signature(context, signature)) return NULL;
if (!sema_analyse_signature(context, signature, func_decl->func_decl.type_parent)) return NULL;
Variadic variadic_type = signature->variadic;
// Remove the last empty value.
if (variadic_type == VARIADIC_RAW)
{
assert(!params[signature->vararg_index] && "The last parameter must have been a raw variadic.");
assert(params && !params[signature->vararg_index] && "The last parameter must have been a raw variadic.");
assert(signature->vararg_index == vec_size(params) - 1);
vec_pop(params);
}
@@ -907,10 +935,10 @@ Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallAB
if (!all_ok) return NULL;
Type *raw_type = type_get_func(signature, abi);
Type *type = type_new(TYPE_FUNC, parent->name);
Type *type = type_new(TYPE_FUNC, func_decl->name);
type->canonical = type;
type->function.signature = signature;
type->function.module = parent->unit->module;
type->function.module = func_decl->unit->module;
type->function.prototype = raw_type->function.prototype;
return type;
}
@@ -2580,7 +2608,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
if (!sema_analyse_func_macro(context, decl, false, erase_decl)) return false;
if (*erase_decl) return true;
if (!sema_analyse_signature(context, &decl->func_decl.signature)) return decl_poison(decl);
if (!sema_analyse_signature(context, &decl->func_decl.signature, decl->func_decl.type_parent)) return decl_poison(decl);
if (!decl->func_decl.signature.is_at_macro && decl->func_decl.body_param)
{
@@ -2594,6 +2622,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
unsigned body_param_count = vec_size(body_parameters);
for (unsigned i = 0; i < body_param_count; i++)
{
assert(body_parameters);
Decl *param = body_parameters[i];
param->resolve_status = RESOLVE_RUNNING;
assert(param->decl_kind == DECL_VAR);

View File

@@ -80,7 +80,7 @@ bool sema_analyse_asm(SemaContext *context, AsmInlineBlock *block, Ast *asm_stmt
bool sema_bit_assignment_check(Expr *right, Decl *member);
int sema_check_comp_time_bool(SemaContext *context, Expr *expr);
bool sema_expr_check_assign(SemaContext *c, Expr *expr);
Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallABI abi, Signature *signature, bool is_real_function);
Type *sema_analyse_function_signature(SemaContext *context, Decl *func_decl, CallABI abi, Signature *signature, bool is_real_function);
bool cast_widen_top_down(SemaContext *context, Expr *expr, Type *type);
bool cast_promote_vararg(Expr *arg);
Type *cast_numeric_arithmetic_promotion(Type *type);

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.546"
#define COMPILER_VERSION "0.4.547"

View File

@@ -0,0 +1,83 @@
// #target: macos-x64
module test;
def Foo = distinct int;
struct Abc
{
int a;
int b;
}
fn void Foo.add(&f)
{
*f = *f + 1;
}
macro void Foo.add_macro(&f)
{
f++;
}
fn int Abc.add(&a)
{
return a.a + a.b;
}
macro int Abc.add_macro(&a)
{
return a.a + a.b;
}
fn void test()
{
Abc x = { 3, 4 };
int a = x.add();
int b = x.add_macro();
Foo f = 100;
f.add();
f.add_macro();
}
/* #expect: test.ll
define void @test.Foo.add(ptr %0) #0 {
entry:
%1 = load i32, ptr %0, align 4
%add = add i32 %1, 1
store i32 %add, ptr %0, align 4
ret void
}
define i32 @test.Abc.add(ptr %0) #0 {
entry:
%1 = getelementptr inbounds %Abc, ptr %0, i32 0, i32 0
%2 = load i32, ptr %1, align 4
%3 = getelementptr inbounds %Abc, ptr %0, i32 0, i32 1
%4 = load i32, ptr %3, align 4
%add = add i32 %2, %4
ret i32 %add
}
define void @test.test() #0 {
entry:
%x = alloca %Abc, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
%f = alloca i32, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @.__const, i32 8, i1 false)
%0 = call i32 @test.Abc.add(ptr %x)
store i32 %0, ptr %a, align 4
%1 = getelementptr inbounds %Abc, ptr %x, i32 0, i32 0
%2 = load i32, ptr %1, align 4
%3 = getelementptr inbounds %Abc, ptr %x, i32 0, i32 1
%4 = load i32, ptr %3, align 4
%add = add i32 %2, %4
store i32 %add, ptr %b, align 4
store i32 100, ptr %f, align 4
call void @test.Foo.add(ptr %f)
%5 = load i32, ptr %f, align 4
%add1 = add i32 %5, 1
store i32 %add1, ptr %f, align 4
ret void
}