Skip to content

Commit fb44417

Browse files
committed
syntax: allow function types as struct member type
type Foo struct { fn void (void* arg, i32 a) callback; }
1 parent eed082d commit fb44417

25 files changed

+581
-122
lines changed

analyser/conversion_checker.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ fn bool Checker.checkFunc2Builtin(Checker* c, const Type* lcanon, const Type* rc
497497
// only allow Callback types or weak-functions
498498
FunctionType* ft = (FunctionType*)rcanon;
499499
FunctionDecl* fd = ft.getDecl();
500-
if (fd.isType() || fd.hasAttrWeak()) return true; // Variable with Function type (eg callback)
500+
if (fd.canBeNil()) return true; // Variable with Function type (eg callback)
501501

502502
// TODO not always comparision (bool b = test1);
503503
c.diags.error(c.loc, "comparison of function '%s' will always be true", fd.asDecl().getFullName());

analyser/module_analyser_struct.c2

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ fn void Analyser.analyseStructMembers(Analyser* ma, StructTypeDecl* d) {
5757
member.setCheckInProgress();
5858
ma.analyseStructMember(vd);
5959

60+
#if 0
61+
// TODO decide whether to allow this
62+
QualType qt = member.getType();
63+
if (is_packed && qt.isPointerOrFunction()) {
64+
ma.error(member.getLoc(), "pointer types are not allowed in packed structs");
65+
}
66+
#endif
67+
6068
Expr* bitfield = vd.getBitfield();
6169
if (bitfield) {
6270
// canonical must be builtin type/enum

analyser/module_analyser_type.c2

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ fn void Analyser.analyseEnumType(Analyser* ma, EnumTypeDecl* d) {
9696
}
9797
}
9898

99+
fn QualType Analyser.analyseStructMemberTypeRef(Analyser* ma, TypeRef* ref) {
100+
const Ref* member = ref.getStructMemberType();
101+
// Member.decl is uninitialized!? (member is ok)
102+
assert(member.decl);
103+
assert(member.decl.isFunction());
104+
105+
FunctionDecl* fd = (FunctionDecl*)member.decl;
106+
ma.analyseFunction(fd);
107+
if (ma.has_error) return QualType_Invalid;
108+
return member.decl.getType();
109+
}
110+
99111
fn QualType Analyser.analyseUserTypeRef(Analyser* ma, TypeRef* ref) {
100112
assert(ma.mod);
101113
const Ref* user = ref.getUser();
@@ -166,14 +178,22 @@ fn QualType Analyser.analyseUserTypeRef(Analyser* ma, TypeRef* ref) {
166178

167179
fn QualType Analyser.analyseTypeRef(Analyser* ma, TypeRef* ref) {
168180
QualType base;
169-
if (ref.isUser()) {
170-
base = ma.analyseUserTypeRef(ref);
171-
if (base.isInvalid()) return base;
172-
if (!base.hasCanonicalType()) return QualType_Invalid;
173-
} else {
181+
switch (ref.getKind()) {
182+
case Builtin:
174183
BuiltinKind kind = ref.getBuiltinKind();
175184
base = ma.builder.actOnBuiltinType(kind);
176185
assert(base.isValid());
186+
break;
187+
case User:
188+
base = ma.analyseUserTypeRef(ref);
189+
if (base.isInvalid()) return base;
190+
if (!base.hasCanonicalType()) return QualType_Invalid;
191+
break;
192+
case StructMemberType:
193+
base = ma.analyseStructMemberTypeRef(ref);
194+
if (base.isInvalid()) return base;
195+
if (!base.hasCanonicalType()) return QualType_Invalid;
196+
break;
177197
}
178198

179199
if (ref.isConst()) base.setConst();

ast/function_decl.c2

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type FunctionDeclBits struct {
4343
u32 has_return : 1; // if it returns something, set during analysis
4444
u32 is_template : 1;
4545
u32 is_type : 1; // part of FunctionTypeDecl
46+
u32 is_member_type : 1; // if function is defined in struct as member type
4647
u32 has_body : 1; // if function is defined in C2
4748
}
4849

@@ -125,16 +126,16 @@ public fn FunctionDecl* FunctionDecl.create(ast_context.Context* c,
125126
}
126127

127128
public fn FunctionDecl* FunctionDecl.createTemplate(ast_context.Context* c,
128-
u32 name,
129-
SrcLoc loc,
130-
bool is_public,
131-
u32 ast_idx,
132-
const TypeRefHolder* rtype,
133-
u32 template_name,
134-
SrcLoc template_loc,
135-
VarDecl** params,
136-
u32 num_params,
137-
bool is_variadic)
129+
u32 name,
130+
SrcLoc loc,
131+
bool is_public,
132+
u32 ast_idx,
133+
const TypeRefHolder* rtype,
134+
u32 template_name,
135+
SrcLoc template_loc,
136+
VarDecl** params,
137+
u32 num_params,
138+
bool is_variadic)
138139
{
139140
u32 size = sizeof(FunctionDecl) + num_params * sizeof(VarDecl*) + rtype.getExtraSize();
140141
FunctionDecl* d = c.alloc(size);
@@ -238,6 +239,11 @@ public fn bool FunctionDecl.isInline(const FunctionDecl* d) {
238239
return true;
239240
}
240241

242+
public fn bool FunctionDecl.canBeNil(const FunctionDecl* d) {
243+
// Variable with Function type (eg callback)
244+
return d.isType() || d.isMemberType() || d.hasAttrWeak();
245+
}
246+
241247
public fn bool FunctionDecl.isType(const FunctionDecl* d) {
242248
return d.base.functionDeclBits.is_type;
243249
}
@@ -426,6 +432,14 @@ public fn const char* FunctionDecl.getDiagKind(const FunctionDecl* d) {
426432
return "";
427433
}
428434

435+
public fn void FunctionDecl.setMemberType(FunctionDecl* d) {
436+
d.base.functionDeclBits.is_member_type = 1;
437+
}
438+
439+
public fn bool FunctionDecl.isMemberType(const FunctionDecl* d) {
440+
return d.base.functionDeclBits.is_member_type;
441+
}
442+
429443
fn void FunctionDecl.print(const FunctionDecl* d, string_buffer.Buf* out, u32 indent) {
430444
bool valid_type = d.base.qt.isValid();
431445
d.base.printKind(out, indent, valid_type);
@@ -441,6 +455,7 @@ fn void FunctionDecl.print(const FunctionDecl* d, string_buffer.Buf* out, u32 in
441455
out.add(callKind_names[d.getCallKind()]);
442456
d.base.printAttrs(out);
443457
if (d.base.functionDeclBits.is_type) out.add(" Type");
458+
if (d.base.functionDeclBits.is_member_type) out.add(" MemberType");
444459
out.color(col_Expr); // purple
445460
if (d.hasAttrUnusedParams()) out.add(" unused-params");
446461
if (d.hasAttrNoReturn()) out.add(" noreturn");

ast/qualtype.c2

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ public fn bool QualType.isPointer(const QualType* qt) {
243243
return qt.getTypeOrNil().isPointerType();
244244
}
245245

246+
public fn bool QualType.isPointerOrFunction(const QualType* qt) @(unused) {
247+
const Type* t = qt.getTypeOrNil();
248+
return t.isPointerType() || t.isFunctionType();
249+
}
250+
246251
// NOTE: does not check if kind is ok
247252
public fn QualType QualType.getPointerBaseType(const QualType* qt) {
248253
const PointerType* pt = qt.getPointerType();

0 commit comments

Comments
 (0)