Skip to content

Commit 17e4a49

Browse files
committed
language: improve template handling
* accept alternate template syntax: template<T, N=0> definition, template(T, N=0) definition * support template block definitions: template<T> { definition ... } * support multiple template argument syntax * simplify function declaration builders * add TemplateExpr and TemplateSpec ast nodes * simplify and extend templated function call parsing * handle struct templates (at last) * add template samples
1 parent 226ddf7 commit 17e4a49

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1900
-500
lines changed

analyser/conversion_checker_expr.c2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ fn ExprWidth getExprWidth(const Expr* e) {
6464
return getTypeWidth(e.getType());
6565
case Type:
6666
break;
67+
case Template:
6768
case Call:
6869
return getTypeWidth(e.getType());
6970
case InitList:

analyser/module_analyser_call.c2

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,31 @@ const char[] DiagTooManyArgs = "too many arguments to %sfunction call, expected
2929
const char[] DiagTooFewArgs = "too few arguments to %sfunction call, expected %d, have %d";
3030
const char[] NoteDeclaredHere = "'%s' is defined here";
3131

32+
fn QualType Analyser.analyseTemplateExpr(Analyser* ma, Expr** e_ptr) {
33+
Expr* e = *e_ptr;
34+
TemplateExpr* tp = (TemplateExpr*)e;
35+
Expr** func = tp.getFunc2();
36+
Expr* origFn = tp.getFunc(); // store here to avoid the likely inserted FunctionPointerDecay cast
37+
QualType qt = ma.analyseExpr(func, true, RHS);
38+
if (qt.isInvalid()) return QualType_Invalid;
39+
FunctionType* ft = qt.getFunctionTypeOrNil();
40+
if (!ft) {
41+
ma.errorRange(origFn.getLoc(), origFn.getRange(), "object type %s is not a function template", qt.diagName());
42+
return QualType_Invalid;
43+
}
44+
FunctionDecl* fd = ft.getDecl();
45+
if (!fd.isTemplate() || fd.isTemplateTypeFunction()) {
46+
ma.errorRange(e.getLoc(), e.getRange(), "function %s is not a template function", fd.asDecl().getFullName());
47+
return QualType_Invalid;
48+
}
49+
50+
FunctionDecl* fd2 = ma.instantiateFunctionTemplate(fd, tp.getInstanceASTIdx(), tp.getArgs(), tp.getNumArgs());
51+
if (!fd2) return QualType_Invalid;
52+
fd2.asDecl().setUsed();
53+
tp.setDecl(fd2.asDecl());
54+
return fd2.asDecl().getType();
55+
}
56+
3257
fn QualType Analyser.analyseCallExpr(Analyser* ma, Expr** e_ptr) {
3358
Expr* e = *e_ptr;
3459
CallExpr* call = (CallExpr*)e;
@@ -60,17 +85,10 @@ fn QualType Analyser.analyseCallExpr(Analyser* ma, Expr** e_ptr) {
6085
if (fd.hasAttrNoReturn()) call.setNoreturn();
6186

6287
if (fd.isTemplate()) {
63-
if (!call.getTemplateArg()) {
64-
ma.errorRange(e.getLoc(), e.getRange(), "function %s requires a template argument", fd.asDecl().getFullName());
65-
return QualType_Invalid;
66-
}
67-
fd = ma.instantiateTemplateFunction(call, fd);
68-
if (!fd) return QualType_Invalid;
69-
} else {
70-
if (call.getTemplateArg()) {
71-
ma.errorRange(e.getLoc(), e.getRange(), "function %s is not a template function", fd.asDecl().getFullName());
72-
return QualType_Invalid;
73-
}
88+
// TODO handle default type arguments
89+
// TODO auto-instantiate based on actual argument types
90+
ma.errorRange(e.getLoc(), e.getRange(), "function %s requires a template argument", fd.asDecl().getFullName());
91+
return QualType_Invalid;
7492
}
7593

7694
if (fd.hasAttrDeprecated() && !ma.warnings.no_deprecated) {
@@ -624,12 +642,18 @@ fn void Analyser.opaque_callback(void* arg, SrcLoc loc, Decl* d) {
624642
ma.error(loc," using opaque type '%s'", qt.diagName());
625643
}
626644

627-
fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* call, FunctionDecl* fd) {
628-
TypeRef* template_arg = call.getTemplateArg();
645+
fn FunctionDecl* Analyser.instantiateFunctionTemplate(Analyser* ma, FunctionDecl* fd, u16 instance_ast_idx, Expr** args, u32 num_args) {
646+
// Only handle first argument for now, convert to type
647+
TypeRef* template_arg = ma.getTemplateArg(*args);
648+
if (!template_arg) return nil;
629649
QualType templateType = ma.analyseTypeRef(template_arg);
630650
if (templateType.isInvalid()) return nil;
631651

632-
FunctionDecl* instance = ma.mod.findInstance(fd, templateType);
652+
// TODO create instiator, analyse/evaluate template expressions,
653+
// initialize TemplateSubst array from values or qualtypes,
654+
// compute instance name and check if name exists already
655+
656+
FunctionDecl* instance = (FunctionDecl*)ma.mod.findInstance(fd.asDecl(), templateType);
633657
if (!instance) {
634658
// note: template_arg decl is set here
635659
bool used_opaque = false;
@@ -639,11 +663,14 @@ fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* ca
639663
Decl* d = (Decl*)std;
640664
used_opaque = (std.isOpaque() && d.getModule() != ma.mod);
641665
}
666+
// TODO: use TemplateSpec in Instantiator
667+
const TemplateSpec* spec = fd.getTemplateSpec();
642668
Instantiator inst = {
643669
.c = ma.context,
644670
.ref = template_arg,
645-
.template_name = fd.getTemplateNameIdx(),
646-
.instance_ast_idx = call.getInstanceASTIdx(),
671+
.template_vars = spec.getTemplateVars(),
672+
.template_len = spec.getTemplateLen(),
673+
.instance_ast_idx = instance_ast_idx,
647674
.used_opaque = used_opaque,
648675
.arg = ma,
649676
.on_error = Analyser.opaque_callback,
@@ -654,6 +681,13 @@ fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* ca
654681
if (ma.has_error) return nil;
655682
d.setChecked();
656683

684+
// add instance to avoid recursive instantiation for the same type
685+
u16 instance_idx = ma.mod.addInstance(fd.asDecl(), templateType, instance.asDecl());
686+
char[64] name;
687+
// TODO: use a more readable name, eg: max$i32
688+
create_template_name(name, fd.asDecl().getName(), instance_idx);
689+
d.setNameIdx(ma.astPool.addStr(name, true));
690+
657691
// Note: we need a separate scope for the body
658692
Module* template_mod = fd.asDecl().getModule();
659693
Analyser* analyser = create(ma.diags, ma.context, ma.astPool, ma.builder, ma.allmodules, ma.warnings);
@@ -669,15 +703,7 @@ fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* ca
669703
analyser.free();
670704

671705
if (ma.has_error) return nil;
672-
673-
u16 instance_idx = ma.mod.addInstance(fd, templateType, instance);
674-
instance.setTemplateInstanceIdx(instance_idx);
675-
char[64] name;
676-
create_template_name(name, d.getName(), instance_idx);
677-
instance.setInstanceName(ma.astPool.addStr(name, true));
678706
}
679-
call.setTemplateIdx(instance.getTemplateInstanceIdx());
680-
681707
return instance;
682708
}
683709

analyser/module_analyser_expr.c2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ fn QualType Analyser.analyseExprInner(Analyser* ma, Expr** e_ptr, u32 side) {
6767
return d.getType();
6868
case Type:
6969
break;
70+
case Template:
71+
return ma.analyseTemplateExpr(e_ptr);
7072
case Call:
7173
return ma.analyseCallExpr(e_ptr);
7274
case InitList:

analyser/module_analyser_function.c2

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,15 @@ import scope;
2222
// Note: only analyses prototype + args, not the function body
2323
fn void Analyser.analyseFunction(Analyser* ma, FunctionDecl* fd) {
2424
if (fd.isTemplate()) {
25-
// do analyze template name (eg X) for name clash
26-
ma.scope.checkGlobalSymbol(fd.getTemplateNameIdx(), fd.getTemplateLoc());
25+
// do analyze template names (eg X) for name clash
26+
const TemplateSpec* spec = fd.getTemplateSpec();
27+
if (spec) {
28+
u32 len = spec.getTemplateLen();
29+
const TemplateVar* vars = spec.getTemplateVars();
30+
for (u32 i = 0; i < len; i++) {
31+
ma.scope.checkGlobalSymbol(vars[i].name, vars[i].loc);
32+
}
33+
}
2734

2835
// check rtype for array-type
2936
TypeRef* rtype = fd.getReturnTypeRef();
@@ -128,16 +135,15 @@ fn void Analyser.analyseFunction(Analyser* ma, FunctionDecl* fd) {
128135
bool is_typefn = false;
129136
if (num_params && fd.hasPrefix()) {
130137
// check if SF if first arg is (const) Struct* or (const) Struct
131-
// Note: use TypeRef, since it's faster to check
132-
const Ref* prefix = fd.getPrefix();
133-
const Decl* pd = prefix.decl;
134-
assert(pd);
135-
QualType prefixType = pd.getType();
136-
137-
TypeRef* ref = params[0].getTypeRef();
138-
const Ref* param_ref = ref.getUser();
139-
// Note: for enum types it can be the Type or a pointer to that type
140-
bool is_non_static = ((param_ref && param_ref.decl == prefix.decl) || ref.isPointerTo(prefixType.getIndex()));
138+
// Note: use TypeRef, since it's simpler to check
139+
const Ref* func_prefix = fd.getPrefix();
140+
const TypeRef* arg_ref = params[0].getTypeRef();
141+
const Ref* user = arg_ref.getUser();
142+
bool is_non_static = (user &&
143+
user.name_idx == func_prefix.name_idx &&
144+
arg_ref.getNumPointers() <= 1 &&
145+
!arg_ref.hasPrefix() &&
146+
!arg_ref.isTemplate());
141147
if (is_non_static) {
142148
fd.setCallKind(TypeFunc);
143149
is_typefn = true;

analyser/module_analyser_struct.c2

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ import name_vector local;
2020
import size_analyser;
2121

2222
fn void Analyser.analyseStructType(Analyser* ma, StructTypeDecl* d) {
23+
if (d.isTemplate()) {
24+
// do analyze template names (eg X) for name clash
25+
const TemplateSpec* spec = d.getTemplateSpec();
26+
u32 len = spec.getTemplateLen();
27+
const TemplateVar* vars = spec.getTemplateVars();
28+
for (u32 i = 0; i < len; i++) {
29+
ma.scope.checkGlobalSymbol(vars[i].name, vars[i].loc);
30+
}
31+
return; // only analyse on instantiation
32+
}
33+
2334
if (d.isOpaque()) {
2435
ma.checkStack[ma.checkIndex-1].usedPublic = false;
2536
ma.usedPublic = false;
@@ -198,10 +209,11 @@ fn void Analyser.analyseStructNames(Analyser* ma, StructTypeDecl* d, NameVector*
198209
if (names.find(name_idx, &old_index)) {
199210
ma.error(member.getLoc(), "duplicate struct/union member '%s'", member.getName());
200211
ma.note(locs.get(old_index), "previous declaration is here");
201-
return;
212+
//return;
213+
} else {
214+
names.add(name_idx);
215+
locs.add(member.getLoc());
202216
}
203-
names.add(name_idx);
204-
locs.add(member.getLoc());
205217

206218
if (member.isStructType()) {
207219
NameVector sub_names.init(sub.getNumMembers());

0 commit comments

Comments
 (0)