Mercurial > projects > ddmd
annotate dmd/TemplateDeclaration.d @ 110:12c0c84d13fd
merged in 2.036 changes
author | Trass3r |
---|---|
date | Tue, 31 Aug 2010 22:29:00 +0200 |
parents | acd69f84627e a1cf34da9ebe |
children | 3482c73a991b |
rev | line source |
---|---|
0 | 1 module dmd.TemplateDeclaration; |
2 | |
3 import dmd.Loc; | |
4 import dmd.ScopeDsymbol; | |
5 import dmd.ArrayTypes; | |
6 import dmd.Dsymbol; | |
7 import dmd.STC; | |
8 import dmd.TemplateThisParameter; | |
9 import dmd.Global; | |
10 import dmd.Array; | |
11 import dmd.Identifier; | |
12 import dmd.TypeArray; | |
13 import dmd.Expression; | |
14 import dmd.Scope; | |
15 import dmd.TypeIdentifier; | |
16 import dmd.TypeDelegate; | |
17 import dmd.IntegerExp; | |
18 import dmd.TypeSArray; | |
19 import dmd.StringExp; | |
20 import dmd.TOK; | |
21 import dmd.Argument; | |
22 import dmd.CtorDeclaration; | |
23 import dmd.TypeFunction; | |
24 import dmd.TY; | |
25 import dmd.OutBuffer; | |
26 import dmd.Declaration; | |
27 import dmd.HdrGenState; | |
28 import dmd.TemplateInstance; | |
29 import dmd.WANT; | |
30 import dmd.FuncDeclaration; | |
31 import dmd.TemplateTupleParameter; | |
32 import dmd.MATCH; | |
33 import dmd.Type; | |
34 import dmd.Tuple; | |
35 import dmd.TupleDeclaration; | |
36 import dmd.Initializer; | |
79 | 37 import dmd.Json; |
0 | 38 import dmd.ExpInitializer; |
39 import dmd.TemplateValueParameter; | |
40 import dmd.AliasDeclaration; | |
41 import dmd.VarDeclaration; | |
42 import dmd.TemplateParameter; | |
43 import dmd.TemplateTypeParameter; | |
44 | |
45 import dmd.expression.Util; | |
46 | |
47 import std.stdio; | |
48 | |
49 /************************************** | |
50 * Determine if TemplateDeclaration is variadic. | |
51 */ | |
52 | |
53 TemplateTupleParameter isVariadic(TemplateParameters parameters) | |
54 { | |
55 size_t dim = parameters.dim; | |
104 | 56 TemplateTupleParameter tp = null; |
0 | 57 |
104 | 58 if (dim) |
0 | 59 tp = (cast(TemplateParameter)parameters.data[dim - 1]).isTemplateTupleParameter(); |
60 | |
104 | 61 return tp; |
0 | 62 } |
63 | |
64 void ObjectToCBuffer(OutBuffer buf, HdrGenState* hgs, Object oarg) | |
65 { | |
104 | 66 //printf("ObjectToCBuffer()\n"); |
67 Type t = isType(oarg); | |
68 Expression e = isExpression(oarg); | |
69 Dsymbol s = isDsymbol(oarg); | |
70 Tuple v = isTuple(oarg); | |
71 if (t) | |
72 { | |
0 | 73 //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); |
74 t.toCBuffer(buf, null, hgs); | |
104 | 75 } |
76 else if (e) | |
0 | 77 e.toCBuffer(buf, hgs); |
104 | 78 else if (s) |
79 { | |
0 | 80 string p = s.ident ? s.ident.toChars() : s.toChars(); |
81 buf.writestring(p); | |
104 | 82 } |
83 else if (v) | |
84 { | |
0 | 85 Objects args = v.objects; |
86 for (size_t i = 0; i < args.dim; i++) | |
87 { | |
88 if (i) | |
89 buf.writeByte(','); | |
90 Object o = cast(Object)args.data[i]; | |
91 ObjectToCBuffer(buf, hgs, o); | |
92 } | |
104 | 93 } |
94 else if (!oarg) | |
95 { | |
0 | 96 buf.writestring("null"); |
104 | 97 } |
98 else | |
99 { | |
0 | 100 debug writef("bad Object = %p\n", oarg); |
101 assert(0); | |
104 | 102 } |
0 | 103 } |
104 | |
105 class TemplateDeclaration : ScopeDsymbol | |
106 { | |
104 | 107 TemplateParameters parameters; // array of TemplateParameter's |
0 | 108 |
104 | 109 TemplateParameters origParameters; // originals for Ddoc |
110 Expression constraint; | |
111 Array instances; // array of TemplateInstance's | |
0 | 112 |
104 | 113 TemplateDeclaration overnext; // next overloaded TemplateDeclaration |
114 TemplateDeclaration overroot; // first in overnext list | |
0 | 115 |
104 | 116 int semanticRun; // 1 semantic() run |
0 | 117 |
104 | 118 Dsymbol onemember; // if !=NULL then one member of this template |
0 | 119 |
104 | 120 int literal; // this template declaration is a literal |
0 | 121 |
104 | 122 this(Loc loc, Identifier id, TemplateParameters parameters, Expression constraint, Dsymbols decldefs) |
0 | 123 { |
124 super(id); | |
125 | |
126 version (LOG) { | |
127 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id.toChars()); | |
128 } | |
129 static if (false) { | |
130 if (parameters) | |
131 for (int i = 0; i < parameters.dim; i++) | |
132 { | |
133 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
134 //printf("\tparameter[%d] = %p\n", i, tp); | |
135 TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); | |
136 | |
137 if (ttp) | |
138 { | |
139 printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); | |
140 } | |
141 } | |
142 } | |
143 | |
144 this.loc = loc; | |
145 this.parameters = parameters; | |
146 this.origParameters = parameters; | |
147 this.constraint = constraint; | |
148 this.members = decldefs; | |
149 | |
150 instances = new Array(); | |
151 } | |
152 | |
104 | 153 override Dsymbol syntaxCopy(Dsymbol) |
0 | 154 { |
51 | 155 //printf("TemplateDeclaration.syntaxCopy()\n"); |
156 TemplateDeclaration td; | |
157 TemplateParameters p; | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
158 Dsymbols d; |
51 | 159 |
160 p = null; | |
161 if (parameters) | |
162 { | |
163 p = new TemplateParameters(); | |
164 p.setDim(parameters.dim); | |
165 for (int i = 0; i < p.dim; i++) | |
166 { | |
167 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
168 p.data[i] = cast(void*)tp.syntaxCopy(); | |
169 } | |
170 } | |
171 | |
172 Expression e = null; | |
173 if (constraint) | |
174 e = constraint.syntaxCopy(); | |
175 d = Dsymbol.arraySyntaxCopy(members); | |
176 td = new TemplateDeclaration(loc, ident, p, e, d); | |
177 return td; | |
0 | 178 } |
179 | |
104 | 180 override void semantic(Scope sc) |
0 | 181 { |
182 version (LOG) { | |
183 printf("TemplateDeclaration.semantic(this = %p, id = '%s')\n", this, ident.toChars()); | |
184 } | |
185 if (semanticRun) | |
186 return; // semantic() already run | |
187 semanticRun = 1; | |
188 | |
189 if (sc.func) | |
190 { | |
191 version (DMDV1) { | |
192 error("cannot declare template at function scope %s", sc.func.toChars()); | |
193 } | |
194 } | |
195 | |
196 if (/*global.params.useArrayBounds &&*/ sc.module_) | |
197 { | |
198 // Generate this function as it may be used | |
199 // when template is instantiated in other modules | |
200 sc.module_.toModuleArray(); | |
201 } | |
202 | |
203 if (/*global.params.useAssert &&*/ sc.module_) | |
204 { | |
205 // Generate this function as it may be used | |
206 // when template is instantiated in other modules | |
207 sc.module_.toModuleAssert(); | |
208 } | |
209 | |
210 /* Remember Scope for later instantiations, but make | |
211 * a copy since attributes can change. | |
212 */ | |
87
b17640f0e4e8
Fixed a bug with a Scope.this(Scope enclosing) being called instead of Scope.clone() method (as a copy ctor replacement)
korDen
parents:
79
diff
changeset
|
213 this.scope_ = sc.clone(); |
0 | 214 this.scope_.setNoFree(); |
215 | |
216 // Set up scope for parameters | |
217 ScopeDsymbol paramsym = new ScopeDsymbol(); | |
218 paramsym.parent = sc.parent; | |
219 Scope paramscope = sc.push(paramsym); | |
220 paramscope.parameterSpecialization = 1; | |
221 paramscope.stc = STCundefined; | |
222 | |
223 if (!parent) | |
224 parent = sc.parent; | |
225 | |
226 if (global.params.doDocComments) | |
227 { | |
228 origParameters = new TemplateParameters(); | |
229 origParameters.setDim(parameters.dim); | |
230 for (int i = 0; i < parameters.dim; i++) | |
231 { | |
232 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
233 origParameters.data[i] = cast(void*)tp.syntaxCopy(); | |
234 } | |
235 } | |
236 | |
237 for (int i = 0; i < parameters.dim; i++) | |
238 { | |
239 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
240 tp.declareParameter(paramscope); | |
241 } | |
242 | |
243 for (int i = 0; i < parameters.dim; i++) | |
244 { | |
245 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
246 | |
247 tp.semantic(paramscope); | |
248 if (i + 1 != parameters.dim && tp.isTemplateTupleParameter()) | |
249 error("template tuple parameter must be last one"); | |
250 } | |
251 | |
252 paramscope.pop(); | |
253 | |
254 if (members) | |
255 { | |
256 Dsymbol s; | |
257 if (Dsymbol.oneMembers(members, &s)) | |
258 { | |
259 if (s && s.ident && s.ident.equals(ident)) | |
260 { | |
261 onemember = s; | |
262 s.parent = this; | |
263 } | |
264 } | |
265 } | |
266 | |
267 /* BUG: should check: | |
268 * o no virtual functions or non-static data members of classes | |
269 */ | |
270 } | |
271 | |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
272 /********************************** |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
273 * Overload existing TemplateDeclaration 'this' with the new one 's'. |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
274 * Return !=0 if successful; i.e. no conflict. |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
275 */ |
104 | 276 override bool overloadInsert(Dsymbol s) |
0 | 277 { |
50 | 278 TemplateDeclaration *pf; |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
279 TemplateDeclaration f; |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
280 |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
281 version (LOG) { |
50 | 282 printf("TemplateDeclaration.overloadInsert('%.*s')\n", s.toChars()); |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
283 } |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
284 f = s.isTemplateDeclaration(); |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
285 if (!f) |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
286 return false; |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
287 |
50 | 288 TemplateDeclaration pthis = this; |
289 for (pf = &pthis; *pf; pf = &(*pf).overnext) | |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
290 { |
50 | 291 static if (false) { |
292 // Conflict if TemplateParameter's match | |
293 // Will get caught anyway later with TemplateInstance, but | |
294 // should check it now. | |
295 if (f.parameters.dim != f2.parameters.dim) | |
296 goto Lcontinue; | |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
297 |
50 | 298 for (int i = 0; i < f.parameters.dim; i++) |
299 { | |
300 TemplateParameter p1 = cast(TemplateParameter)f.parameters.data[i]; | |
301 TemplateParameter p2 = cast(TemplateParameter)f2.parameters.data[i]; | |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
302 |
50 | 303 if (!p1.overloadMatch(p2)) |
304 goto Lcontinue; | |
305 } | |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
306 |
50 | 307 version (LOG) { |
308 printf("\tfalse: conflict\n"); | |
309 } | |
310 return false; | |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
311 |
50 | 312 Lcontinue: |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
313 ; |
50 | 314 } |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
315 } |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
316 |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
317 f.overroot = this; |
50 | 318 *pf = f; |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
319 version (LOG) { |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
320 printf("\ttrue: no conflict\n"); |
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
321 } |
50 | 322 |
8
d42cd5917df4
wysiwyg strings, alias this, templates, TypeSlice implementation
dkoroskin <>
parents:
0
diff
changeset
|
323 return true; |
0 | 324 } |
325 | |
104 | 326 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 327 { |
104 | 328 static if (false) // Should handle template functions |
329 { | |
330 if (onemember && onemember.isFuncDeclaration()) | |
331 buf.writestring("foo "); | |
332 } | |
333 buf.writestring(kind()); | |
334 buf.writeByte(' '); | |
335 buf.writestring(ident.toChars()); | |
336 buf.writeByte('('); | |
337 for (int i = 0; i < parameters.dim; i++) | |
338 { | |
339 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
340 if (hgs.ddoc) | |
341 tp = cast(TemplateParameter)origParameters.data[i]; | |
342 if (i) | |
343 buf.writeByte(','); | |
344 tp.toCBuffer(buf, hgs); | |
345 } | |
346 buf.writeByte(')'); | |
347 version(DMDV2) | |
348 { | |
349 if (constraint) | |
350 { buf.writestring(" if ("); | |
351 constraint.toCBuffer(buf, hgs); | |
352 buf.writeByte(')'); | |
353 } | |
354 } | |
355 | |
356 if (hgs.hdrgen) | |
357 { | |
358 hgs.tpltMember++; | |
359 buf.writenl(); | |
360 buf.writebyte('{'); | |
361 buf.writenl(); | |
362 foreach (Dsymbol s; members) | |
363 s.toCBuffer(buf, hgs); | |
364 | |
365 buf.writebyte('}'); | |
366 buf.writenl(); | |
367 hgs.tpltMember--; | |
368 } | |
0 | 369 } |
370 | |
79 | 371 override void toJsonBuffer(OutBuffer buf) |
372 { | |
373 //writef("TemplateDeclaration.toJsonBuffer()\n"); | |
374 | |
375 buf.writestring("{\n"); | |
376 | |
377 JsonProperty(buf, Pname, toChars()); | |
378 JsonProperty(buf, Pkind, kind()); | |
379 if (comment) | |
380 JsonProperty(buf, Pcomment, comment); | |
381 | |
382 if (loc.linnum) | |
383 JsonProperty(buf, Pline, loc.linnum); | |
384 | |
385 JsonString(buf, Pmembers); | |
386 buf.writestring(" : [\n"); | |
387 size_t offset = buf.offset; | |
388 foreach (Dsymbol s; members) | |
389 { | |
390 if (offset != buf.offset) | |
96 | 391 { buf.writestring(",\n"); |
79 | 392 offset = buf.offset; |
393 } | |
394 s.toJsonBuffer(buf); | |
395 } | |
96 | 396 JsonRemoveComma(buf); |
79 | 397 buf.writestring("]\n"); |
398 | |
399 buf.writestring("}\n"); | |
400 } | |
401 | |
104 | 402 override string kind() |
0 | 403 { |
50 | 404 return (onemember && onemember.isAggregateDeclaration()) |
405 ? onemember.kind() | |
406 : "template"; | |
0 | 407 } |
408 | |
104 | 409 override string toChars() |
0 | 410 { |
49 | 411 OutBuffer buf = new OutBuffer(); |
412 HdrGenState hgs; | |
413 | |
414 /// memset(&hgs, 0, hgs.sizeof); | |
415 buf.writestring(ident.toChars()); | |
416 buf.writeByte('('); | |
417 for (int i = 0; i < parameters.dim; i++) | |
418 { | |
419 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
420 if (i) | |
421 buf.writeByte(','); | |
422 tp.toCBuffer(buf, &hgs); | |
423 } | |
424 buf.writeByte(')'); | |
425 version (DMDV2) { | |
426 if (constraint) | |
427 { | |
428 buf.writestring(" if ("); | |
429 constraint.toCBuffer(buf, &hgs); | |
430 buf.writeByte(')'); | |
431 } | |
432 } | |
433 buf.writeByte(0); | |
434 return buf.extractString(); | |
0 | 435 } |
436 | |
104 | 437 override void emitComment(Scope sc) |
0 | 438 { |
439 assert(false); | |
440 } | |
50 | 441 |
104 | 442 // void toDocBuffer(OutBuffer *buf); |
0 | 443 |
444 /*************************************** | |
445 * Given that ti is an instance of this TemplateDeclaration, | |
446 * deduce the types of the parameters to this, and store | |
447 * those deduced types in dedtypes[]. | |
448 * Input: | |
449 * flag 1: don't do semantic() because of dummy types | |
450 * 2: don't change types in matchArg() | |
451 * Output: | |
452 * dedtypes deduced arguments | |
453 * Return match level. | |
454 */ | |
104 | 455 MATCH matchWithInstance(TemplateInstance ti, Objects dedtypes, int flag) |
0 | 456 { |
457 MATCH m; | |
458 int dedtypes_dim = dedtypes.dim; | |
459 | |
460 version (LOGM) { | |
50 | 461 printf("\n+TemplateDeclaration.matchWithInstance(this = %.*s, ti = %.*s, flag = %d)\n", toChars(), ti.toChars(), flag); |
0 | 462 } |
463 | |
464 static if (false) { | |
465 printf("dedtypes.dim = %d, parameters.dim = %d\n", dedtypes_dim, parameters.dim); | |
466 if (ti.tiargs.dim) | |
467 printf("ti.tiargs.dim = %d, [0] = %p\n", ti.tiargs.dim, ti.tiargs.data[0]); | |
468 } | |
469 dedtypes.zero(); | |
470 | |
471 int parameters_dim = parameters.dim; | |
472 int variadic = isVariadic() !is null; | |
473 | |
474 // If more arguments than parameters, no match | |
475 if (ti.tiargs.dim > parameters_dim && !variadic) | |
476 { | |
477 version (LOGM) { | |
50 | 478 printf(" no match: more arguments than parameters\n"); |
0 | 479 } |
50 | 480 return MATCHnomatch; |
0 | 481 } |
482 | |
483 assert(dedtypes_dim == parameters_dim); | |
484 assert(dedtypes_dim >= ti.tiargs.dim || variadic); | |
485 | |
486 // Set up scope for parameters | |
487 assert(cast(size_t)cast(void*)scope_ > 0x10000); | |
488 ScopeDsymbol paramsym = new ScopeDsymbol(); | |
489 paramsym.parent = scope_.parent; | |
490 Scope paramscope = scope_.push(paramsym); | |
491 paramscope.stc = STCundefined; | |
492 | |
493 // Attempt type deduction | |
494 m = MATCHexact; | |
495 for (int i = 0; i < dedtypes_dim; i++) | |
496 { | |
497 MATCH m2; | |
498 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
499 Declaration sparam; | |
500 | |
501 //printf("\targument [%d]\n", i); | |
502 version (LOGM) { | |
503 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); | |
504 TemplateTypeParameter *ttp = tp.isTemplateTypeParameter(); | |
505 if (ttp) | |
506 printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); | |
507 } | |
508 | |
509 version (DMDV1) { | |
510 m2 = tp.matchArg(paramscope, ti.tiargs, i, parameters, dedtypes, &sparam); | |
511 } else { | |
512 m2 = tp.matchArg(paramscope, ti.tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); | |
513 } | |
514 //printf("\tm2 = %d\n", m2); | |
515 | |
516 if (m2 == MATCHnomatch) | |
517 { | |
518 static if (false) { | |
519 printf("\tmatchArg() for parameter %i failed\n", i); | |
520 } | |
521 goto Lnomatch; | |
522 } | |
523 | |
524 if (m2 < m) | |
525 m = m2; | |
526 | |
527 if (!flag) | |
528 sparam.semantic(paramscope); | |
529 if (!paramscope.insert(sparam)) | |
530 goto Lnomatch; | |
531 } | |
532 | |
533 if (!flag) | |
534 { | |
535 /* Any parameter left without a type gets the type of | |
536 * its corresponding arg | |
537 */ | |
538 for (int i = 0; i < dedtypes_dim; i++) | |
539 { | |
540 if (!dedtypes.data[i]) | |
541 { | |
542 assert(i < ti.tiargs.dim); | |
543 dedtypes.data[i] = ti.tiargs.data[i]; | |
544 } | |
545 } | |
546 } | |
547 | |
548 version (DMDV2) { | |
549 if (m && constraint && !(flag & 1)) | |
550 { /* Check to see if constraint is satisfied. | |
551 */ | |
552 Expression e = constraint.syntaxCopy(); | |
553 paramscope.flags |= SCOPE.SCOPEstaticif; | |
554 e = e.semantic(paramscope); | |
555 e = e.optimize(WANTvalue | WANTinterpret); | |
556 if (e.isBool(true)) { | |
557 ; | |
558 } else if (e.isBool(false)) | |
559 goto Lnomatch; | |
560 else | |
561 { | |
562 e.error("constraint %s is not constant or does not evaluate to a bool", e.toChars()); | |
563 } | |
564 } | |
565 } | |
566 | |
567 version (LOGM) { | |
568 // Print out the results | |
569 printf("--------------------------\n"); | |
570 printf("template %s\n", toChars()); | |
571 printf("instance %s\n", ti.toChars()); | |
572 if (m) | |
573 { | |
574 for (int i = 0; i < dedtypes_dim; i++) | |
575 { | |
576 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
577 Object oarg; | |
578 | |
579 printf(" [%d]", i); | |
580 | |
581 if (i < ti.tiargs.dim) | |
582 oarg = cast(Object)ti.tiargs.data[i]; | |
583 else | |
584 oarg = null; | |
585 tp.print(oarg, cast(Object)dedtypes.data[i]); | |
586 } | |
587 } | |
588 else | |
589 goto Lnomatch; | |
590 } | |
591 | |
592 version (LOGM) { | |
593 printf(" match = %d\n", m); | |
594 } | |
595 goto Lret; | |
596 | |
597 Lnomatch: | |
598 version (LOGM) { | |
599 printf(" no match\n"); | |
600 } | |
601 m = MATCHnomatch; | |
602 | |
603 Lret: | |
604 paramscope.pop(); | |
605 version (LOGM) { | |
606 printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); | |
607 } | |
608 return m; | |
609 } | |
610 | |
51 | 611 /******************************************** |
612 * Determine partial specialization order of 'this' vs td2. | |
613 * Returns: | |
614 * match this is at least as specialized as td2 | |
615 * 0 td2 is more specialized than this | |
616 */ | |
104 | 617 MATCH leastAsSpecialized(TemplateDeclaration td2) |
0 | 618 { |
104 | 619 /* This works by taking the template parameters to this template |
51 | 620 * declaration and feeding them to td2 as if it were a template |
621 * instance. | |
622 * If it works, then this template is at least as specialized | |
623 * as td2. | |
624 */ | |
625 | |
626 scope TemplateInstance ti = new TemplateInstance(Loc(0), ident); // create dummy template instance | |
627 scope Objects dedtypes = new Objects(); | |
628 | |
629 version (LOG_LEASTAS) { | |
630 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); | |
631 } | |
632 | |
633 // Set type arguments to dummy template instance to be types | |
634 // generated from the parameters to this template declaration | |
635 ti.tiargs = new Objects(); | |
636 ti.tiargs.setDim(parameters.dim); | |
637 for (int i = 0; i < ti.tiargs.dim; i++) | |
638 { | |
639 TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; | |
640 | |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
641 auto p = tp.dummyArg(); |
51 | 642 if (p) |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
643 ti.tiargs[i] = p; |
51 | 644 else |
645 ti.tiargs.setDim(i); | |
646 } | |
647 | |
648 // Temporary Array to hold deduced types | |
649 //dedtypes.setDim(parameters.dim); | |
650 dedtypes.setDim(td2.parameters.dim); | |
651 | |
652 // Attempt a type deduction | |
653 MATCH m = td2.matchWithInstance(ti, dedtypes, 1); | |
654 if (m) | |
655 { | |
656 /* A non-variadic template is more specialized than a | |
657 * variadic one. | |
658 */ | |
659 if (isVariadic() && !td2.isVariadic()) | |
660 goto L1; | |
661 | |
662 version (LOG_LEASTAS) { | |
663 printf(" matches %d, so is least as specialized\n", m); | |
664 } | |
665 return m; | |
666 } | |
667 L1: | |
668 version (LOG_LEASTAS) { | |
669 printf(" doesn't match, so is not as specialized\n"); | |
670 } | |
671 return MATCHnomatch; | |
0 | 672 } |
673 | |
674 /************************************************* | |
675 * Match function arguments against a specific template function. | |
676 * Input: | |
677 * loc instantiation location | |
678 * targsi Expression/Type initial list of template arguments | |
679 * ethis 'this' argument if !null | |
680 * fargs arguments to function | |
681 * Output: | |
682 * dedargs Expression/Type deduced template arguments | |
683 * Returns: | |
684 * match level | |
685 */ | |
104 | 686 MATCH deduceFunctionTemplateMatch(Loc loc, Objects targsi, Expression ethis, Expressions fargs, Objects dedargs) |
0 | 687 { |
688 size_t nfparams; | |
689 size_t nfargs; | |
690 size_t nargsi; // array size of targsi | |
691 int fptupindex = -1; | |
692 int tuple_dim = 0; | |
693 MATCH match = MATCHexact; | |
694 FuncDeclaration fd = onemember.toAlias().isFuncDeclaration(); | |
695 Arguments fparameters; // function parameter list | |
696 int fvarargs; // function varargs | |
697 scope Objects dedtypes = new Objects(); // for T:T*, the dedargs is the T*, dedtypes is the T | |
698 | |
79 | 699 static if (false) |
700 { | |
0 | 701 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); |
702 for (i = 0; i < fargs.dim; i++) | |
703 { | |
704 Expression e = cast(Expression)fargs.data[i]; | |
705 printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars()); | |
706 } | |
707 printf("fd = %s\n", fd.toChars()); | |
708 printf("fd.type = %p\n", fd.type); | |
709 } | |
710 | |
711 assert(cast(size_t)cast(void*)scope_ > 0x10000); | |
712 | |
713 dedargs.setDim(parameters.dim); | |
714 dedargs.zero(); | |
715 | |
716 dedtypes.setDim(parameters.dim); | |
717 dedtypes.zero(); | |
718 | |
719 // Set up scope for parameters | |
720 ScopeDsymbol paramsym = new ScopeDsymbol(); | |
721 paramsym.parent = scope_.parent; | |
722 Scope paramscope = scope_.push(paramsym); | |
723 | |
724 TemplateTupleParameter tp = isVariadic(); | |
725 | |
79 | 726 static if (false) |
727 { | |
0 | 728 for (i = 0; i < dedargs.dim; i++) |
729 { | |
730 printf("\tdedarg[%d] = ", i); | |
731 Object oarg = cast(Object)dedargs.data[i]; | |
732 if (oarg) printf("%s", oarg.toChars()); | |
733 printf("\n"); | |
734 } | |
735 } | |
736 | |
737 | |
738 nargsi = 0; | |
739 if (targsi) | |
79 | 740 { |
741 // Set initial template arguments | |
0 | 742 nargsi = targsi.dim; |
79 | 743 size_t n = parameters.dim; |
0 | 744 if (tp) |
745 n--; | |
746 if (nargsi > n) | |
747 { | |
748 if (!tp) | |
749 goto Lnomatch; | |
750 | |
751 /* The extra initial template arguments | |
752 * now form the tuple argument. | |
753 */ | |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
754 auto t = new Tuple(); |
0 | 755 assert(parameters.dim); |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
756 dedargs[parameters.dim - 1] = t; |
0 | 757 |
758 tuple_dim = nargsi - n; | |
759 t.objects.setDim(tuple_dim); | |
760 for (size_t i = 0; i < tuple_dim; i++) | |
761 { | |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
762 t.objects[i] = targsi[n + i]; |
0 | 763 } |
764 declareParameter(paramscope, tp, t); | |
765 } | |
766 else | |
767 n = nargsi; | |
768 | |
769 memcpy(dedargs.data, targsi.data, n * (*dedargs.data).sizeof); | |
770 | |
771 for (size_t i = 0; i < n; i++) | |
772 { | |
773 assert(i < parameters.dim); | |
774 TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; | |
775 MATCH m; | |
776 Declaration sparam = null; | |
777 | |
778 m = tp2.matchArg(paramscope, dedargs, i, parameters, dedtypes, &sparam); | |
779 //printf("\tdeduceType m = %d\n", m); | |
780 if (m == MATCHnomatch) | |
781 goto Lnomatch; | |
782 if (m < match) | |
783 match = m; | |
784 | |
785 sparam.semantic(paramscope); | |
786 if (!paramscope.insert(sparam)) | |
787 goto Lnomatch; | |
788 } | |
789 } | |
79 | 790 static if (false) |
791 { | |
0 | 792 for (i = 0; i < dedargs.dim; i++) |
793 { | |
794 printf("\tdedarg[%d] = ", i); | |
795 Object oarg = cast(Object)dedargs.data[i]; | |
796 if (oarg) printf("%s", oarg.toChars()); | |
797 printf("\n"); | |
798 } | |
799 } | |
800 | |
801 if (fd.type) | |
802 { | |
803 assert(fd.type.ty == Tfunction); | |
804 TypeFunction fdtype = cast(TypeFunction)fd.type; | |
805 fparameters = fdtype.parameters; | |
806 fvarargs = fdtype.varargs; | |
807 } | |
808 else | |
809 { | |
810 CtorDeclaration fctor = fd.isCtorDeclaration(); | |
811 assert(fctor); | |
812 fparameters = fctor.arguments; | |
813 fvarargs = fctor.varargs; | |
814 } | |
815 | |
816 nfparams = Argument.dim(fparameters); // number of function parameters | |
817 nfargs = fargs ? fargs.dim : 0; // number of function arguments | |
818 | |
819 /* Check for match of function arguments with variadic template | |
820 * parameter, such as: | |
821 * | |
822 * template Foo(T, A...) { void Foo(T t, A a); } | |
823 * void main() { Foo(1,2,3); } | |
824 */ | |
825 if (tp) // if variadic | |
826 { | |
79 | 827 if (nfparams == 0 && nfargs != 0) // if no function parameters |
0 | 828 { |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
829 auto t = new Tuple(); |
0 | 830 //printf("t = %p\n", t); |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
831 dedargs[parameters.dim - 1] = t; |
0 | 832 declareParameter(paramscope, tp, t); |
833 goto L2; | |
834 } | |
835 else if (nfargs < nfparams - 1) | |
836 goto L1; | |
837 else | |
838 { | |
839 /* Figure out which of the function parameters matches | |
840 * the tuple template parameter. Do this by matching | |
841 * type identifiers. | |
842 * Set the index of this function parameter to fptupindex. | |
843 */ | |
844 for (fptupindex = 0; fptupindex < nfparams; fptupindex++) | |
845 { | |
846 Argument fparam = cast(Argument)fparameters.data[fptupindex]; | |
847 if (fparam.type.ty != Tident) | |
848 continue; | |
849 TypeIdentifier tid = cast(TypeIdentifier)fparam.type; | |
850 if (!tp.ident.equals(tid.ident) || tid.idents.dim) | |
851 continue; | |
852 | |
853 if (fvarargs) // variadic function doesn't | |
854 goto Lnomatch; // go with variadic template | |
855 | |
856 /* The types of the function arguments | |
857 * now form the tuple argument. | |
858 */ | |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
859 auto t = new Tuple(); |
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
860 dedargs[parameters.dim - 1] = t; |
0 | 861 |
862 tuple_dim = nfargs - (nfparams - 1); | |
863 t.objects.setDim(tuple_dim); | |
864 for (size_t i = 0; i < tuple_dim; i++) | |
865 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
87
diff
changeset
|
866 auto farg = fargs[fptupindex + i]; |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
867 t.objects[i] = farg.type; |
0 | 868 } |
869 declareParameter(paramscope, tp, t); | |
870 goto L2; | |
871 } | |
872 fptupindex = -1; | |
873 } | |
874 } | |
875 | |
876 L1: | |
877 if (nfparams == nfargs) { | |
878 ; | |
879 } else if (nfargs > nfparams) { | |
880 if (fvarargs == 0) | |
881 goto Lnomatch; // too many args, no match | |
882 match = MATCHconvert; // match ... with a conversion | |
883 } | |
884 | |
885 L2: | |
886 version (DMDV2) { | |
887 // Match 'ethis' to any TemplateThisParameter's | |
888 if (ethis) | |
889 { | |
890 for (size_t i = 0; i < parameters.dim; i++) | |
891 { | |
892 TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; | |
893 TemplateThisParameter ttp = tp2.isTemplateThisParameter(); | |
894 if (ttp) | |
895 { | |
896 MATCH m; | |
897 | |
898 Type t = new TypeIdentifier(Loc(0), ttp.ident); | |
899 m = ethis.type.deduceType(paramscope, t, parameters, dedtypes); | |
900 if (!m) | |
901 goto Lnomatch; | |
902 if (m < match) | |
903 match = m; // pick worst match | |
904 } | |
905 } | |
906 } | |
907 } | |
908 | |
909 // Loop through the function parameters | |
910 for (size_t i = 0; i < nfparams; i++) | |
911 { | |
912 /* Skip over function parameters which wound up | |
913 * as part of a template tuple parameter. | |
914 */ | |
915 if (i == fptupindex) | |
916 { | |
917 if (fptupindex == nfparams - 1) | |
918 break; | |
919 i += tuple_dim - 1; | |
920 continue; | |
921 } | |
922 | |
923 Argument fparam = Argument.getNth(fparameters, i); | |
924 | |
925 if (i >= nfargs) // if not enough arguments | |
926 { | |
927 if (fparam.defaultArg) | |
928 { | |
929 /* Default arguments do not participate in template argument | |
930 * deduction. | |
931 */ | |
932 goto Lmatch; | |
933 } | |
934 } | |
935 else | |
936 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
87
diff
changeset
|
937 auto farg = fargs[i]; |
0 | 938 static if (false) { |
939 printf("\tfarg.type = %s\n", farg.type.toChars()); | |
940 printf("\tfparam.type = %s\n", fparam.type.toChars()); | |
941 } | |
942 Type argtype = farg.type; | |
943 | |
944 version (DMDV2) { | |
945 /* Allow string literals which are type [] to match with [dim] | |
946 */ | |
947 if (farg.op == TOKstring) | |
948 { | |
949 StringExp se = cast(StringExp)farg; | |
950 if (!se.committed && argtype.ty == Tarray && | |
951 fparam.type.toBasetype().ty == Tsarray) | |
952 { | |
953 argtype = new TypeSArray(argtype.nextOf(), new IntegerExp(se.loc, se.len, Type.tindex)); | |
954 argtype = argtype.semantic(se.loc, null); | |
955 argtype = argtype.invariantOf(); | |
956 } | |
957 } | |
958 } | |
959 | |
960 MATCH m; | |
961 m = argtype.deduceType(paramscope, fparam.type, parameters, dedtypes); | |
962 //printf("\tdeduceType m = %d\n", m); | |
963 | |
964 /* If no match, see if there's a conversion to a delegate | |
965 */ | |
966 if (!m && fparam.type.toBasetype().ty == Tdelegate) | |
967 { | |
968 TypeDelegate td = cast(TypeDelegate)fparam.type.toBasetype(); | |
969 TypeFunction tf = cast(TypeFunction)td.next; | |
970 | |
971 if (!tf.varargs && Argument.dim(tf.parameters) == 0) | |
972 { | |
973 m = farg.type.deduceType(paramscope, tf.next, parameters, dedtypes); | |
974 if (!m && tf.next.toBasetype().ty == Tvoid) | |
975 m = MATCHconvert; | |
976 } | |
977 //printf("\tm2 = %d\n", m); | |
978 } | |
979 | |
980 if (m) | |
981 { | |
982 if (m < match) | |
983 match = m; // pick worst match | |
984 continue; | |
985 } | |
986 } | |
987 | |
988 /* The following code for variadic arguments closely | |
989 * matches TypeFunction.callMatch() | |
990 */ | |
991 if (!(fvarargs == 2 && i + 1 == nfparams)) | |
992 goto Lnomatch; | |
993 | |
994 /* Check for match with function parameter T... | |
995 */ | |
996 Type tb = fparam.type.toBasetype(); | |
997 switch (tb.ty) | |
998 { | |
999 // Perhaps we can do better with this, see TypeFunction.callMatch() | |
1000 case Tsarray: | |
1001 { | |
1002 TypeSArray tsa = cast(TypeSArray)tb; | |
1003 ulong sz = tsa.dim.toInteger(); | |
1004 if (sz != nfargs - i) | |
1005 goto Lnomatch; | |
1006 } | |
1007 case Tarray: | |
1008 { | |
1009 TypeArray ta = cast(TypeArray)tb; | |
1010 for (; i < nfargs; i++) | |
1011 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
87
diff
changeset
|
1012 auto arg = fargs[i]; |
0 | 1013 assert(arg); |
1014 MATCH m; | |
1015 /* If lazy array of delegates, | |
1016 * convert arg(s) to delegate(s) | |
1017 */ | |
1018 Type tret = fparam.isLazyArray(); | |
1019 if (tret) | |
1020 { | |
1021 if (ta.next.equals(arg.type)) | |
1022 { | |
1023 m = MATCHexact; | |
1024 } | |
1025 else | |
1026 { | |
1027 m = arg.implicitConvTo(tret); | |
1028 if (m == MATCHnomatch) | |
1029 { | |
1030 if (tret.toBasetype().ty == Tvoid) | |
1031 m = MATCHconvert; | |
1032 } | |
1033 } | |
1034 } | |
1035 else | |
1036 { | |
1037 m = arg.type.deduceType(paramscope, ta.next, parameters, dedtypes); | |
1038 //m = arg.implicitConvTo(ta.next); | |
1039 } | |
1040 if (m == MATCHnomatch) | |
1041 goto Lnomatch; | |
1042 if (m < match) | |
1043 match = m; | |
1044 } | |
1045 goto Lmatch; | |
1046 } | |
1047 case Tclass: | |
1048 case Tident: | |
1049 goto Lmatch; | |
1050 | |
1051 default: | |
1052 goto Lnomatch; | |
1053 } | |
1054 } | |
1055 | |
1056 Lmatch: | |
1057 | |
1058 /* Fill in any missing arguments with their defaults. | |
1059 */ | |
1060 for (size_t i = nargsi; i < dedargs.dim; i++) | |
1061 { | |
1062 TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; | |
1063 //printf("tp2[%d] = %s\n", i, tp2.ident.toChars()); | |
1064 /* For T:T*, the dedargs is the T*, dedtypes is the T | |
1065 * But for function templates, we really need them to match | |
1066 */ | |
1067 Object oarg = cast(Object)dedargs.data[i]; | |
1068 Object oded = cast(Object)dedtypes.data[i]; | |
1069 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); | |
1070 //if (oarg) printf("oarg: %s\n", oarg.toChars()); | |
1071 //if (oded) printf("oded: %s\n", oded.toChars()); | |
1072 if (!oarg) | |
1073 { | |
1074 if (oded) | |
1075 { | |
1076 if (tp2.specialization()) | |
1077 { | |
1078 /* The specialization can work as long as afterwards | |
1079 * the oded == oarg | |
1080 */ | |
1081 Declaration sparam; | |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
1082 dedargs[i] = oded; |
0 | 1083 MATCH m2 = tp2.matchArg(paramscope, dedargs, i, parameters, dedtypes, &sparam, 0); |
1084 //printf("m2 = %d\n", m2); | |
1085 if (!m2) | |
1086 goto Lnomatch; | |
1087 if (m2 < match) | |
1088 match = m2; // pick worst match | |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
1089 if (dedtypes[i] !is oded) |
0 | 1090 error("specialization not allowed for deduced parameter %s", tp2.ident.toChars()); |
1091 } | |
1092 } | |
1093 else | |
1094 { | |
1095 oded = tp2.defaultArg(loc, paramscope); | |
1096 if (!oded) | |
1097 goto Lnomatch; | |
1098 } | |
1099 declareParameter(paramscope, tp2, oded); | |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
90
diff
changeset
|
1100 dedargs[i] = oded; |
0 | 1101 } |
1102 } | |
1103 | |
1104 version (DMDV2) { | |
1105 if (constraint) | |
1106 { /* Check to see if constraint is satisfied. | |
1107 */ | |
1108 Expression e = constraint.syntaxCopy(); | |
1109 paramscope.flags |= SCOPE.SCOPEstaticif; | |
1110 e = e.semantic(paramscope); | |
1111 e = e.optimize(WANTvalue | WANTinterpret); | |
1112 if (e.isBool(true)) { | |
1113 ; | |
1114 } else if (e.isBool(false)) | |
1115 goto Lnomatch; | |
1116 else | |
1117 { | |
1118 e.error("constraint %s is not constant or does not evaluate to a bool", e.toChars()); | |
1119 } | |
1120 } | |
1121 } | |
1122 | |
1123 static if (false) { | |
1124 for (i = 0; i < dedargs.dim; i++) | |
1125 { | |
1126 Type t = cast(Type)dedargs.data[i]; | |
1127 printf("\tdedargs[%d] = %d, %s\n", i, t.dyncast(), t.toChars()); | |
1128 } | |
1129 } | |
1130 | |
1131 paramscope.pop(); | |
1132 //printf("\tmatch %d\n", match); | |
1133 return match; | |
1134 | |
1135 Lnomatch: | |
1136 paramscope.pop(); | |
1137 //printf("\tnomatch\n"); | |
1138 return MATCHnomatch; | |
1139 } | |
104 | 1140 |
0 | 1141 /************************************************* |
1142 * Given function arguments, figure out which template function | |
1143 * to expand, and return that function. | |
1144 * If no match, give error message and return null. | |
1145 * Input: | |
1146 * sc instantiation scope | |
1147 * loc instantiation location | |
1148 * targsi initial list of template arguments | |
1149 * ethis if !null, the 'this' pointer argument | |
1150 * fargs arguments to function | |
1151 * flags 1: do not issue error message on no match, just return null | |
1152 */ | |
1153 FuncDeclaration deduceFunctionTemplate(Scope sc, Loc loc, Objects targsi, Expression ethis, Expressions fargs, int flags = 0) | |
1154 { | |
1155 MATCH m_best = MATCHnomatch; | |
1156 TemplateDeclaration td_ambig = null; | |
1157 TemplateDeclaration td_best = null; | |
1158 Objects tdargs = new Objects(); | |
1159 TemplateInstance ti; | |
1160 FuncDeclaration fd; | |
1161 | |
1162 static if (false) { | |
1163 printf("TemplateDeclaration.deduceFunctionTemplate() %s\n", toChars()); | |
104 | 1164 printf(" targsi:\n"); |
0 | 1165 if (targsi) |
1166 { | |
1167 for (int i = 0; i < targsi.dim; i++) | |
1168 { | |
1169 Object arg = cast(Object)targsi.data[i]; | |
1170 printf("\t%s\n", arg.toChars()); | |
1171 } | |
1172 } | |
104 | 1173 printf(" fargs:\n"); |
0 | 1174 for (int i = 0; i < fargs.dim; i++) |
1175 { | |
1176 Expression arg = cast(Expression)fargs.data[i]; | |
1177 printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); | |
1178 //printf("\tty = %d\n", arg.type.ty); | |
1179 } | |
1180 } | |
1181 | |
1182 for (TemplateDeclaration td = this; td; td = td.overnext) | |
1183 { | |
1184 if (!td.semanticRun) | |
1185 { | |
1186 error("forward reference to template %s", td.toChars()); | |
1187 goto Lerror; | |
1188 } | |
1189 if (!td.onemember || !td.onemember.toAlias().isFuncDeclaration()) | |
1190 { | |
1191 error("is not a function template"); | |
1192 goto Lerror; | |
1193 } | |
1194 | |
1195 MATCH m; | |
1196 scope Objects dedargs = new Objects(); | |
1197 | |
1198 m = td.deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, dedargs); | |
1199 //printf("deduceFunctionTemplateMatch = %d\n", m); | |
1200 if (!m) // if no match | |
1201 continue; | |
1202 | |
1203 if (m < m_best) | |
1204 goto Ltd_best; | |
1205 if (m > m_best) | |
1206 goto Ltd; | |
1207 | |
1208 { | |
1209 // Disambiguate by picking the most specialized TemplateDeclaration | |
1210 MATCH c1 = td.leastAsSpecialized(td_best); | |
1211 MATCH c2 = td_best.leastAsSpecialized(td); | |
1212 //printf("c1 = %d, c2 = %d\n", c1, c2); | |
1213 | |
1214 if (c1 > c2) | |
1215 goto Ltd; | |
1216 else if (c1 < c2) | |
1217 goto Ltd_best; | |
1218 else | |
1219 goto Lambig; | |
1220 } | |
1221 | |
1222 Lambig: // td_best and td are ambiguous | |
1223 td_ambig = td; | |
1224 continue; | |
1225 | |
1226 Ltd_best: // td_best is the best match so far | |
1227 td_ambig = null; | |
1228 continue; | |
1229 | |
1230 Ltd: // td is the new best match | |
1231 td_ambig = null; | |
1232 assert(cast(size_t)cast(void*)td.scope_ > 0x10000); | |
1233 td_best = td; | |
1234 m_best = m; | |
1235 tdargs.setDim(dedargs.dim); | |
1236 memcpy(tdargs.data, dedargs.data, tdargs.dim * (void*).sizeof); | |
1237 continue; | |
1238 } | |
1239 if (!td_best) | |
1240 { | |
1241 if (!(flags & 1)) | |
1242 error(loc, "does not match any function template declaration"); | |
1243 goto Lerror; | |
1244 } | |
1245 if (td_ambig) | |
1246 { | |
1247 error(loc, "matches more than one function template declaration:\n %s\nand:\n %s", | |
1248 td_best.toChars(), td_ambig.toChars()); | |
1249 } | |
1250 | |
1251 /* The best match is td_best with arguments tdargs. | |
1252 * Now instantiate the template. | |
1253 */ | |
1254 assert(cast(size_t)cast(void*)td_best.scope_ > 0x10000); | |
1255 ti = new TemplateInstance(loc, td_best, tdargs); | |
1256 ti.semantic(sc); | |
1257 fd = ti.toAlias().isFuncDeclaration(); | |
1258 if (!fd) | |
1259 goto Lerror; | |
1260 return fd; | |
1261 | |
1262 Lerror: | |
1263 /// version (DMDV2) { | |
1264 if (!(flags & 1)) | |
1265 /// } | |
1266 { | |
1267 HdrGenState hgs; | |
1268 | |
1269 scope OutBuffer bufa = new OutBuffer(); | |
1270 Objects args = targsi; | |
1271 if (args) | |
1272 { | |
1273 for (int i = 0; i < args.dim; i++) | |
1274 { | |
1275 if (i) | |
1276 bufa.writeByte(','); | |
1277 Object oarg = cast(Object)args.data[i]; | |
1278 ObjectToCBuffer(bufa, &hgs, oarg); | |
1279 } | |
1280 } | |
1281 | |
1282 scope OutBuffer buf = new OutBuffer(); | |
1283 argExpTypesToCBuffer(buf, fargs, &hgs); | |
1284 error(loc, "cannot deduce template function from argument types !(%s)(%s)", bufa.toChars(), buf.toChars()); | |
1285 } | |
1286 return null; | |
1287 } | |
1288 | |
1289 /************************************************** | |
1290 * Declare template parameter tp with value o, and install it in the scope sc. | |
1291 */ | |
104 | 1292 void declareParameter(Scope sc, TemplateParameter tp, Object o) |
0 | 1293 { |
1294 //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); | |
1295 | |
1296 Type targ = isType(o); | |
1297 Expression ea = isExpression(o); | |
1298 Dsymbol sa = isDsymbol(o); | |
1299 Tuple va = isTuple(o); | |
1300 | |
1301 Dsymbol s; | |
1302 | |
1303 // See if tp.ident already exists with a matching definition | |
1304 Dsymbol scopesym; | |
1305 s = sc.search(loc, tp.ident, &scopesym); | |
1306 if (s && scopesym == sc.scopesym) | |
1307 { | |
1308 TupleDeclaration td = s.isTupleDeclaration(); | |
1309 if (va && td) | |
1310 { | |
1311 Tuple tup = new Tuple(); | |
1312 assert(false); // < not implemented | |
1313 ///tup.objects = *td.objects; | |
1314 if (match(va, tup, this, sc)) | |
1315 { | |
1316 return; | |
1317 } | |
1318 } | |
1319 } | |
1320 | |
1321 if (targ) | |
1322 { | |
1323 //printf("type %s\n", targ.toChars()); | |
1324 s = new AliasDeclaration(Loc(0), tp.ident, targ); | |
1325 } | |
1326 else if (sa) | |
1327 { | |
1328 //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); | |
1329 s = new AliasDeclaration(Loc(0), tp.ident, sa); | |
1330 } | |
1331 else if (ea) | |
1332 { | |
1333 // tdtypes.data[i] always matches ea here | |
1334 Initializer init = new ExpInitializer(loc, ea); | |
1335 TemplateValueParameter tvp = tp.isTemplateValueParameter(); | |
1336 | |
1337 Type t = tvp ? tvp.valType : null; | |
1338 | |
1339 VarDeclaration v = new VarDeclaration(loc, t, tp.ident, init); | |
1340 v.storage_class = STCmanifest; | |
1341 s = v; | |
1342 } | |
1343 else if (va) | |
1344 { | |
1345 //printf("\ttuple\n"); | |
1346 s = new TupleDeclaration(loc, tp.ident, va.objects); | |
1347 } | |
1348 else | |
1349 { | |
1350 debug writefln(o.toString()); | |
1351 assert(0); | |
1352 } | |
1353 | |
1354 if (!sc.insert(s)) | |
1355 error("declaration %s is already defined", tp.ident.toChars()); | |
1356 | |
1357 s.semantic(sc); | |
1358 } | |
1359 | |
104 | 1360 override TemplateDeclaration isTemplateDeclaration() { return this; } |
0 | 1361 |
104 | 1362 TemplateTupleParameter isVariadic() |
0 | 1363 { |
1364 return .isVariadic(parameters); | |
1365 } | |
1366 | |
63 | 1367 /*********************************** |
1368 * We can overload templates. | |
1369 */ | |
104 | 1370 override bool isOverloadable() |
0 | 1371 { |
104 | 1372 return true; |
0 | 1373 } |
72 | 1374 } |