Mercurial > projects > ldc
annotate dmd/template.c @ 837:331a176c1f4f
Removed error on naked, not fully complete, but I'll be doing more work on it during this Christmas, and some things do work.
Fixed taking delegate of final class method. see mini/delegate3.d.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 09 Dec 2008 14:07:30 +0100 |
parents | eef8ac26c66c |
children | 330f999ade44 |
rev | line source |
---|---|
336 | 1 |
2 // Compiler implementation of the D programming language | |
3 // Copyright (c) 1999-2008 by Digital Mars | |
4 // All Rights Reserved | |
5 // written by Walter Bright | |
6 // http://www.digitalmars.com | |
7 // License for redistribution is by either the Artistic License | |
8 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
9 // See the included readme.txt for details. | |
10 | |
11 // Handle template implementation | |
12 | |
13 #include <stdio.h> | |
14 #include <assert.h> | |
15 | |
16 #if !IN_LLVM | |
17 #if _WIN32 | |
18 #include <windows.h> | |
19 long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); | |
20 #endif | |
21 #endif | |
22 | |
23 #include "root.h" | |
24 #include "mem.h" | |
25 #include "stringtable.h" | |
26 #include "mars.h" | |
27 #include "identifier.h" | |
28 #include "mtype.h" | |
29 #include "template.h" | |
30 #include "init.h" | |
31 #include "expression.h" | |
32 #include "scope.h" | |
33 #include "module.h" | |
34 #include "aggregate.h" | |
35 #include "declaration.h" | |
36 #include "dsymbol.h" | |
37 #include "hdrgen.h" | |
38 | |
39 #define LOG 0 | |
40 | |
41 /******************************************** | |
42 * These functions substitute for dynamic_cast. dynamic_cast does not work | |
43 * on earlier versions of gcc. | |
44 */ | |
45 | |
46 Expression *isExpression(Object *o) | |
47 { | |
48 //return dynamic_cast<Expression *>(o); | |
49 if (!o || o->dyncast() != DYNCAST_EXPRESSION) | |
50 return NULL; | |
51 return (Expression *)o; | |
52 } | |
53 | |
54 Dsymbol *isDsymbol(Object *o) | |
55 { | |
56 //return dynamic_cast<Dsymbol *>(o); | |
57 if (!o || o->dyncast() != DYNCAST_DSYMBOL) | |
58 return NULL; | |
59 return (Dsymbol *)o; | |
60 } | |
61 | |
62 Type *isType(Object *o) | |
63 { | |
64 //return dynamic_cast<Type *>(o); | |
65 if (!o || o->dyncast() != DYNCAST_TYPE) | |
66 return NULL; | |
67 return (Type *)o; | |
68 } | |
69 | |
70 Tuple *isTuple(Object *o) | |
71 { | |
72 //return dynamic_cast<Tuple *>(o); | |
73 if (!o || o->dyncast() != DYNCAST_TUPLE) | |
74 return NULL; | |
75 return (Tuple *)o; | |
76 } | |
77 | |
78 | |
79 /*********************** | |
80 * Try to get arg as a type. | |
81 */ | |
82 | |
83 Type *getType(Object *o) | |
84 { | |
85 Type *t = isType(o); | |
86 if (!t) | |
87 { Expression *e = isExpression(o); | |
88 if (e) | |
89 t = e->type; | |
90 } | |
91 return t; | |
92 } | |
93 | |
94 Dsymbol *getDsymbol(Object *oarg) | |
95 { | |
96 Dsymbol *sa; | |
97 Expression *ea = isExpression(oarg); | |
98 if (ea) | |
99 { // Try to convert Expression to symbol | |
100 if (ea->op == TOKvar) | |
101 sa = ((VarExp *)ea)->var; | |
102 else if (ea->op == TOKfunction) | |
103 sa = ((FuncExp *)ea)->fd; | |
104 else | |
105 sa = NULL; | |
106 } | |
107 else | |
108 { // Try to convert Type to symbol | |
109 Type *ta = isType(oarg); | |
110 if (ta) | |
111 sa = ta->toDsymbol(NULL); | |
112 else | |
113 sa = isDsymbol(oarg); // if already a symbol | |
114 } | |
115 return sa; | |
116 } | |
117 | |
118 /****************************** | |
119 * If o1 matches o2, return 1. | |
120 * Else, return 0. | |
121 */ | |
122 | |
123 int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) | |
124 { | |
125 Type *t1 = isType(o1); | |
126 Type *t2 = isType(o2); | |
127 Expression *e1 = isExpression(o1); | |
128 Expression *e2 = isExpression(o2); | |
129 Dsymbol *s1 = isDsymbol(o1); | |
130 Dsymbol *s2 = isDsymbol(o2); | |
131 Tuple *v1 = isTuple(o1); | |
132 Tuple *v2 = isTuple(o2); | |
133 | |
134 //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2); | |
135 | |
136 /* A proper implementation of the various equals() overrides | |
137 * should make it possible to just do o1->equals(o2), but | |
138 * we'll do that another day. | |
139 */ | |
140 | |
141 if (t1) | |
142 { | |
143 /* if t1 is an instance of ti, then give error | |
144 * about recursive expansions. | |
145 */ | |
146 Dsymbol *s = t1->toDsymbol(sc); | |
147 if (s && s->parent) | |
148 { TemplateInstance *ti1 = s->parent->isTemplateInstance(); | |
149 if (ti1 && ti1->tempdecl == tempdecl) | |
150 { | |
151 for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) | |
152 { | |
153 if (sc1->scopesym == ti1) | |
154 { | |
155 error("recursive template expansion for template argument %s", t1->toChars()); | |
156 return 1; // fake a match | |
157 } | |
158 } | |
159 } | |
160 } | |
161 | |
162 if (!t2 || !t1->equals(t2)) | |
163 goto Lnomatch; | |
164 } | |
165 else if (e1) | |
166 { | |
167 #if 0 | |
168 if (e1 && e2) | |
169 { | |
170 printf("match %d\n", e1->equals(e2)); | |
171 e1->print(); | |
172 e2->print(); | |
173 e1->type->print(); | |
174 e2->type->print(); | |
175 } | |
176 #endif | |
177 if (!e2) | |
178 goto Lnomatch; | |
179 if (!e1->equals(e2)) | |
180 goto Lnomatch; | |
181 } | |
182 else if (s1) | |
183 { | |
184 //printf("%p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars()); | |
185 if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) | |
186 { | |
187 goto Lnomatch; | |
188 } | |
189 } | |
190 else if (v1) | |
191 { | |
192 if (!v2) | |
193 goto Lnomatch; | |
194 if (v1->objects.dim != v2->objects.dim) | |
195 goto Lnomatch; | |
196 for (size_t i = 0; i < v1->objects.dim; i++) | |
197 { | |
198 if (!match((Object *)v1->objects.data[i], | |
199 (Object *)v2->objects.data[i], | |
200 tempdecl, sc)) | |
201 goto Lnomatch; | |
202 } | |
203 } | |
204 return 1; // match | |
205 Lnomatch: | |
206 return 0; // nomatch; | |
207 } | |
208 | |
209 /**************************************** | |
210 */ | |
211 | |
212 void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) | |
213 { | |
214 //printf("ObjectToCBuffer()\n"); | |
215 Type *t = isType(oarg); | |
216 Expression *e = isExpression(oarg); | |
217 Dsymbol *s = isDsymbol(oarg); | |
218 Tuple *v = isTuple(oarg); | |
219 if (t) | |
220 { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); | |
221 t->toCBuffer(buf, NULL, hgs); | |
222 } | |
223 else if (e) | |
224 e->toCBuffer(buf, hgs); | |
225 else if (s) | |
226 { | |
227 char *p = s->ident ? s->ident->toChars() : s->toChars(); | |
228 buf->writestring(p); | |
229 } | |
230 else if (v) | |
231 { | |
232 Objects *args = &v->objects; | |
233 for (size_t i = 0; i < args->dim; i++) | |
234 { | |
235 if (i) | |
236 buf->writeByte(','); | |
237 Object *o = (Object *)args->data[i]; | |
238 ObjectToCBuffer(buf, hgs, o); | |
239 } | |
240 } | |
241 else if (!oarg) | |
242 { | |
243 buf->writestring("NULL"); | |
244 } | |
245 else | |
246 { | |
247 #ifdef DEBUG | |
248 printf("bad Object = %p\n", oarg); | |
249 #endif | |
250 assert(0); | |
251 } | |
252 } | |
253 | |
254 | |
255 | |
256 /* ======================== TemplateDeclaration ============================= */ | |
257 | |
258 TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs) | |
259 : ScopeDsymbol(id) | |
260 { | |
261 #if LOG | |
262 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); | |
263 #endif | |
264 #if 0 | |
265 if (parameters) | |
266 for (int i = 0; i < parameters->dim; i++) | |
267 { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
268 //printf("\tparameter[%d] = %p\n", i, tp); | |
269 TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); | |
270 | |
271 if (ttp) | |
272 { | |
273 printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); | |
274 } | |
275 } | |
276 #endif | |
277 this->loc = loc; | |
278 this->parameters = parameters; | |
279 this->origParameters = parameters; | |
280 this->members = decldefs; | |
281 this->overnext = NULL; | |
282 this->overroot = NULL; | |
283 this->scope = NULL; | |
284 this->onemember = NULL; | |
285 } | |
286 | |
287 Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) | |
288 { | |
289 //printf("TemplateDeclaration::syntaxCopy()\n"); | |
290 TemplateDeclaration *td; | |
291 TemplateParameters *p; | |
292 Array *d; | |
293 | |
294 p = NULL; | |
295 if (parameters) | |
296 { | |
297 p = new TemplateParameters(); | |
298 p->setDim(parameters->dim); | |
299 for (int i = 0; i < p->dim; i++) | |
300 { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
301 p->data[i] = (void *)tp->syntaxCopy(); | |
302 } | |
303 } | |
304 d = Dsymbol::arraySyntaxCopy(members); | |
305 td = new TemplateDeclaration(loc, ident, p, d); | |
527
cecfee2d01a8
Added support for overloaded intrinsics.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
306 |
664
eef8ac26c66c
Some missed LLVMDC -> LDC.
Christian Kamm <kamm incasoftware de>
parents:
561
diff
changeset
|
307 // LDC |
527
cecfee2d01a8
Added support for overloaded intrinsics.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
308 td->intrinsicName = intrinsicName; |
cecfee2d01a8
Added support for overloaded intrinsics.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
309 |
336 | 310 return td; |
311 } | |
312 | |
313 void TemplateDeclaration::semantic(Scope *sc) | |
314 { | |
315 #if LOG | |
316 printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); | |
317 #endif | |
318 if (scope) | |
319 return; // semantic() already run | |
320 | |
321 if (sc->func) | |
322 { | |
323 error("cannot declare template at function scope %s", sc->func->toChars()); | |
324 } | |
325 | |
326 if (/*global.params.useArrayBounds &&*/ sc->module) | |
327 { | |
328 // Generate this function as it may be used | |
329 // when template is instantiated in other modules | |
330 sc->module->toModuleArray(); | |
331 } | |
332 | |
333 if (/*global.params.useAssert &&*/ sc->module) | |
334 { | |
335 // Generate this function as it may be used | |
336 // when template is instantiated in other modules | |
337 sc->module->toModuleAssert(); | |
338 } | |
339 | |
340 /* Remember Scope for later instantiations, but make | |
341 * a copy since attributes can change. | |
342 */ | |
343 this->scope = new Scope(*sc); | |
344 this->scope->setNoFree(); | |
345 | |
346 // Set up scope for parameters | |
347 ScopeDsymbol *paramsym = new ScopeDsymbol(); | |
348 paramsym->parent = sc->parent; | |
349 Scope *paramscope = sc->push(paramsym); | |
350 paramscope->parameterSpecialization = 1; | |
351 | |
352 if (global.params.doDocComments) | |
353 { | |
354 origParameters = new TemplateParameters(); | |
355 origParameters->setDim(parameters->dim); | |
356 for (int i = 0; i < parameters->dim; i++) | |
357 { | |
358 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
359 origParameters->data[i] = (void *)tp->syntaxCopy(); | |
360 } | |
361 } | |
362 | |
363 for (int i = 0; i < parameters->dim; i++) | |
364 { | |
365 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
366 | |
367 tp->declareParameter(paramscope); | |
368 } | |
369 | |
370 for (int i = 0; i < parameters->dim; i++) | |
371 { | |
372 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
373 | |
374 tp->semantic(paramscope); | |
375 if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) | |
376 error("template tuple parameter must be last one"); | |
377 } | |
378 | |
379 paramscope->pop(); | |
380 | |
381 if (members) | |
382 { | |
383 Dsymbol *s; | |
384 if (Dsymbol::oneMembers(members, &s)) | |
385 { | |
386 if (s && s->ident && s->ident->equals(ident)) | |
387 { | |
388 onemember = s; | |
389 s->parent = this; | |
390 } | |
391 } | |
392 } | |
393 | |
394 /* BUG: should check: | |
395 * o no virtual functions or non-static data members of classes | |
396 */ | |
397 } | |
398 | |
399 const char *TemplateDeclaration::kind() | |
400 { | |
401 return (onemember && onemember->isAggregateDeclaration()) | |
402 ? onemember->kind() | |
403 : (char *)"template"; | |
404 } | |
405 | |
406 /********************************** | |
407 * Overload existing TemplateDeclaration 'this' with the new one 's'. | |
408 * Return !=0 if successful; i.e. no conflict. | |
409 */ | |
410 | |
411 int TemplateDeclaration::overloadInsert(Dsymbol *s) | |
412 { | |
413 TemplateDeclaration **pf; | |
414 TemplateDeclaration *f; | |
415 | |
416 #if LOG | |
417 printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); | |
418 #endif | |
419 f = s->isTemplateDeclaration(); | |
420 if (!f) | |
421 return FALSE; | |
422 TemplateDeclaration *pthis = this; | |
423 for (pf = &pthis; *pf; pf = &(*pf)->overnext) | |
424 { | |
425 #if 0 | |
426 // Conflict if TemplateParameter's match | |
427 // Will get caught anyway later with TemplateInstance, but | |
428 // should check it now. | |
429 TemplateDeclaration *f2 = *pf; | |
430 | |
431 if (f->parameters->dim != f2->parameters->dim) | |
432 goto Lcontinue; | |
433 | |
434 for (int i = 0; i < f->parameters->dim; i++) | |
435 { TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i]; | |
436 TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i]; | |
437 | |
438 if (!p1->overloadMatch(p2)) | |
439 goto Lcontinue; | |
440 } | |
441 | |
442 #if LOG | |
443 printf("\tfalse: conflict\n"); | |
444 #endif | |
445 return FALSE; | |
446 | |
447 Lcontinue: | |
448 ; | |
449 #endif | |
450 } | |
451 | |
452 f->overroot = this; | |
453 *pf = f; | |
454 #if LOG | |
455 printf("\ttrue: no conflict\n"); | |
456 #endif | |
457 return TRUE; | |
458 } | |
459 | |
460 /*************************************** | |
461 * Given that ti is an instance of this TemplateDeclaration, | |
462 * deduce the types of the parameters to this, and store | |
463 * those deduced types in dedtypes[]. | |
464 * Input: | |
465 * flag 1: don't do semantic() because of dummy types | |
466 * 2: don't change types in matchArg() | |
467 * Output: | |
468 * dedtypes deduced arguments | |
469 * Return match level. | |
470 */ | |
471 | |
472 MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, | |
473 Objects *dedtypes, int flag) | |
474 { MATCH m; | |
475 int dedtypes_dim = dedtypes->dim; | |
476 | |
477 #define LOGM 0 | |
478 #if LOGM | |
479 printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); | |
480 #endif | |
481 | |
482 #if 0 | |
483 printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); | |
484 if (ti->tiargs->dim) | |
485 printf("ti->tiargs->dim = %d, [0] = %p\n", | |
486 ti->tiargs->dim, | |
487 ti->tiargs->data[0]); | |
488 #endif | |
489 dedtypes->zero(); | |
490 | |
491 int parameters_dim = parameters->dim; | |
492 int variadic = isVariadic() != NULL; | |
493 | |
494 // If more arguments than parameters, no match | |
495 if (ti->tiargs->dim > parameters_dim && !variadic) | |
496 { | |
497 #if LOGM | |
498 printf(" no match: more arguments than parameters\n"); | |
499 #endif | |
500 return MATCHnomatch; | |
501 } | |
502 | |
503 assert(dedtypes_dim == parameters_dim); | |
504 assert(dedtypes_dim >= ti->tiargs->dim || variadic); | |
505 | |
506 // Set up scope for parameters | |
507 assert((size_t)scope > 0x10000); | |
508 ScopeDsymbol *paramsym = new ScopeDsymbol(); | |
509 paramsym->parent = scope->parent; | |
510 Scope *paramscope = scope->push(paramsym); | |
511 | |
512 // Attempt type deduction | |
513 m = MATCHexact; | |
514 for (int i = 0; i < dedtypes_dim; i++) | |
515 { MATCH m2; | |
516 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
517 Declaration *sparam; | |
518 | |
519 //printf("\targument [%d]\n", i); | |
520 #if LOGM | |
521 //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); | |
522 TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); | |
523 if (ttp) | |
524 printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); | |
525 #endif | |
526 | |
527 #if DMDV1 | |
528 m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); | |
529 #else | |
530 m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); | |
531 | |
532 #endif | |
533 //printf("\tm2 = %d\n", m2); | |
534 | |
535 if (m2 == MATCHnomatch) | |
536 { | |
537 #if 0 | |
538 printf("\tmatchArg() for parameter %i failed\n", i); | |
539 #endif | |
540 goto Lnomatch; | |
541 } | |
542 | |
543 if (m2 < m) | |
544 m = m2; | |
545 | |
546 if (!flag) | |
547 sparam->semantic(paramscope); | |
548 if (!paramscope->insert(sparam)) | |
549 goto Lnomatch; | |
550 } | |
551 | |
552 if (!flag) | |
553 { | |
554 // Any parameter left without a type gets the type of its corresponding arg | |
555 for (int i = 0; i < dedtypes_dim; i++) | |
556 { | |
557 if (!dedtypes->data[i]) | |
558 { assert(i < ti->tiargs->dim); | |
559 dedtypes->data[i] = ti->tiargs->data[i]; | |
560 } | |
561 } | |
562 } | |
563 | |
564 #if LOGM | |
565 // Print out the results | |
566 printf("--------------------------\n"); | |
567 printf("template %s\n", toChars()); | |
568 printf("instance %s\n", ti->toChars()); | |
569 if (m) | |
570 { | |
571 for (int i = 0; i < dedtypes_dim; i++) | |
572 { | |
573 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
574 Object *oarg; | |
575 | |
576 printf(" [%d]", i); | |
577 | |
578 if (i < ti->tiargs->dim) | |
579 oarg = (Object *)ti->tiargs->data[i]; | |
580 else | |
581 oarg = NULL; | |
582 tp->print(oarg, (Object *)dedtypes->data[i]); | |
583 } | |
584 } | |
585 else | |
586 goto Lnomatch; | |
587 #endif | |
588 | |
589 #if LOGM | |
590 printf(" match = %d\n", m); | |
591 #endif | |
592 goto Lret; | |
593 | |
594 Lnomatch: | |
595 #if LOGM | |
596 printf(" no match\n"); | |
597 #endif | |
598 m = MATCHnomatch; | |
599 | |
600 Lret: | |
601 paramscope->pop(); | |
602 #if LOGM | |
603 printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); | |
604 #endif | |
605 return m; | |
606 } | |
607 | |
608 /******************************************** | |
609 * Determine partial specialization order of 'this' vs td2. | |
610 * Returns: | |
611 * 1 this is at least as specialized as td2 | |
612 * 0 td2 is more specialized than this | |
613 */ | |
614 | |
615 int TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) | |
616 { | |
617 /* This works by taking the template parameters to this template | |
618 * declaration and feeding them to td2 as if it were a template | |
619 * instance. | |
620 * If it works, then this template is at least as specialized | |
621 * as td2. | |
622 */ | |
623 | |
624 TemplateInstance ti(0, ident); // create dummy template instance | |
625 Objects dedtypes; | |
626 | |
627 #define LOG_LEASTAS 0 | |
628 | |
629 #if LOG_LEASTAS | |
630 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); | |
631 #endif | |
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 = (TemplateParameter *)parameters->data[i]; | |
640 | |
641 void *p = tp->dummyArg(); | |
642 if (p) | |
643 ti.tiargs->data[i] = p; | |
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 if (td2->matchWithInstance(&ti, &dedtypes, 1)) | |
654 { | |
655 /* A non-variadic template is more specialized than a | |
656 * variadic one. | |
657 */ | |
658 if (isVariadic() && !td2->isVariadic()) | |
659 goto L1; | |
660 | |
661 #if LOG_LEASTAS | |
662 printf(" matches, so is least as specialized\n"); | |
663 #endif | |
664 return 1; | |
665 } | |
666 L1: | |
667 #if LOG_LEASTAS | |
668 printf(" doesn't match, so is not as specialized\n"); | |
669 #endif | |
670 return 0; | |
671 } | |
672 | |
673 | |
674 /************************************************* | |
675 * Match function arguments against a specific template function. | |
676 * Input: | |
677 * targsi Expression/Type initial list of template arguments | |
678 * fargs arguments to function | |
679 * Output: | |
680 * dedargs Expression/Type deduced template arguments | |
681 * Returns: | |
682 * match level | |
683 */ | |
684 | |
685 MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, | |
686 Objects *dedargs) | |
687 { | |
688 size_t i; | |
689 size_t nfparams; | |
690 size_t nfargs; | |
691 size_t nargsi; // array size of targsi | |
692 int fptupindex = -1; | |
693 int tuple_dim = 0; | |
694 MATCH match = MATCHexact; | |
695 FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); | |
696 TypeFunction *fdtype; // type of fd | |
697 TemplateTupleParameter *tp; | |
698 Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T | |
699 | |
700 #if 0 | |
701 printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); | |
702 for (i = 0; i < fargs->dim; i++) | |
703 { Expression *e = (Expression *)fargs->data[i]; | |
704 printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); | |
705 } | |
706 #endif | |
707 | |
708 assert((size_t)scope > 0x10000); | |
709 | |
710 dedargs->setDim(parameters->dim); | |
711 dedargs->zero(); | |
712 | |
713 dedtypes.setDim(parameters->dim); | |
714 dedtypes.zero(); | |
715 | |
716 // Set up scope for parameters | |
717 ScopeDsymbol *paramsym = new ScopeDsymbol(); | |
718 paramsym->parent = scope->parent; | |
719 Scope *paramscope = scope->push(paramsym); | |
720 | |
721 tp = isVariadic(); | |
722 | |
723 nargsi = 0; | |
724 if (targsi) | |
725 { // Set initial template arguments | |
726 | |
727 nargsi = targsi->dim; | |
728 if (nargsi > parameters->dim) | |
729 { if (!tp) | |
730 goto Lnomatch; | |
731 dedargs->setDim(nargsi); | |
732 dedargs->zero(); | |
733 } | |
734 | |
735 memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data)); | |
736 | |
737 for (i = 0; i < nargsi; i++) | |
738 { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
739 MATCH m; | |
740 Declaration *sparam; | |
741 | |
742 m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); | |
743 //printf("\tdeduceType m = %d\n", m); | |
744 if (m == MATCHnomatch) | |
745 goto Lnomatch; | |
746 if (m < match) | |
747 match = m; | |
748 | |
749 sparam->semantic(paramscope); | |
750 if (!paramscope->insert(sparam)) | |
751 goto Lnomatch; | |
752 } | |
753 } | |
754 | |
755 assert(fd->type->ty == Tfunction); | |
756 fdtype = (TypeFunction *)fd->type; | |
757 | |
758 nfparams = Argument::dim(fdtype->parameters); // number of function parameters | |
759 nfargs = fargs->dim; // number of function arguments | |
760 | |
761 /* Check for match of function arguments with variadic template | |
762 * parameter, such as: | |
763 * | |
764 * template Foo(T, A...) { void Foo(T t, A a); } | |
765 * void main() { Foo(1,2,3); } | |
766 */ | |
767 tp = isVariadic(); | |
768 if (tp) // if variadic | |
769 { | |
770 if (nfparams == 0) // if no function parameters | |
771 { | |
772 Tuple *t = new Tuple(); | |
773 //printf("t = %p\n", t); | |
774 dedargs->data[parameters->dim - 1] = (void *)t; | |
775 goto L2; | |
776 } | |
777 else if (nfargs < nfparams - 1) | |
778 goto L1; | |
779 else | |
780 { | |
781 /* Figure out which of the function parameters matches | |
782 * the tuple template parameter. Do this by matching | |
783 * type identifiers. | |
784 * Set the index of this function parameter to fptupindex. | |
785 */ | |
786 for (fptupindex = 0; fptupindex < nfparams; fptupindex++) | |
787 { | |
788 Argument *fparam = (Argument *)fdtype->parameters->data[fptupindex]; | |
789 if (fparam->type->ty != Tident) | |
790 continue; | |
791 TypeIdentifier *tid = (TypeIdentifier *)fparam->type; | |
792 if (!tp->ident->equals(tid->ident) || tid->idents.dim) | |
793 continue; | |
794 | |
795 if (fdtype->varargs) // variadic function doesn't | |
796 goto Lnomatch; // go with variadic template | |
797 | |
798 /* The types of the function arguments | |
799 * now form the tuple argument. | |
800 */ | |
801 Tuple *t = new Tuple(); | |
802 dedargs->data[parameters->dim - 1] = (void *)t; | |
803 | |
804 tuple_dim = nfargs - (nfparams - 1); | |
805 t->objects.setDim(tuple_dim); | |
806 for (i = 0; i < tuple_dim; i++) | |
807 { Expression *farg = (Expression *)fargs->data[fptupindex + i]; | |
808 t->objects.data[i] = (void *)farg->type; | |
809 } | |
810 goto L2; | |
811 } | |
812 fptupindex = -1; | |
813 } | |
814 } | |
815 | |
816 L1: | |
817 if (nfparams == nfargs) | |
818 ; | |
819 else if (nfargs > nfparams) | |
820 { | |
821 if (fdtype->varargs == 0) | |
822 goto Lnomatch; // too many args, no match | |
823 match = MATCHconvert; // match ... with a conversion | |
824 } | |
825 | |
826 L2: | |
827 // Loop through the function parameters | |
828 for (i = 0; i < nfparams; i++) | |
829 { | |
830 /* Skip over function parameters which wound up | |
831 * as part of a template tuple parameter. | |
832 */ | |
833 if (i == fptupindex) | |
834 { if (fptupindex == nfparams - 1) | |
835 break; | |
836 i += tuple_dim - 1; | |
837 continue; | |
838 } | |
839 | |
840 Argument *fparam = Argument::getNth(fdtype->parameters, i); | |
841 | |
842 if (i >= nfargs) // if not enough arguments | |
843 { | |
844 if (fparam->defaultArg) | |
845 { /* Default arguments do not participate in template argument | |
846 * deduction. | |
847 */ | |
848 goto Lmatch; | |
849 } | |
850 } | |
851 else | |
852 { Expression *farg = (Expression *)fargs->data[i]; | |
853 #if 0 | |
854 printf("\tfarg->type = %s\n", farg->type->toChars()); | |
855 printf("\tfparam->type = %s\n", fparam->type->toChars()); | |
856 #endif | |
857 | |
858 MATCH m; | |
859 m = farg->type->deduceType(scope, fparam->type, parameters, &dedtypes); | |
860 //printf("\tdeduceType m = %d\n", m); | |
861 | |
862 /* If no match, see if there's a conversion to a delegate | |
863 */ | |
864 if (!m && fparam->type->toBasetype()->ty == Tdelegate) | |
865 { | |
866 TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); | |
867 TypeFunction *tf = (TypeFunction *)td->next; | |
868 | |
869 if (!tf->varargs && Argument::dim(tf->parameters) == 0) | |
870 { | |
871 m = farg->type->deduceType(scope, tf->next, parameters, &dedtypes); | |
872 if (!m && tf->next->toBasetype()->ty == Tvoid) | |
873 m = MATCHconvert; | |
874 } | |
875 //printf("\tm2 = %d\n", m); | |
876 } | |
877 | |
878 if (m) | |
879 { if (m < match) | |
880 match = m; // pick worst match | |
881 continue; | |
882 } | |
883 } | |
884 | |
885 /* The following code for variadic arguments closely | |
886 * matches TypeFunction::callMatch() | |
887 */ | |
888 if (!(fdtype->varargs == 2 && i + 1 == nfparams)) | |
889 goto Lnomatch; | |
890 | |
891 /* Check for match with function parameter T... | |
892 */ | |
893 Type *tb = fparam->type->toBasetype(); | |
894 switch (tb->ty) | |
895 { | |
896 // Perhaps we can do better with this, see TypeFunction::callMatch() | |
897 case Tsarray: | |
898 { TypeSArray *tsa = (TypeSArray *)tb; | |
899 integer_t sz = tsa->dim->toInteger(); | |
900 if (sz != nfargs - i) | |
901 goto Lnomatch; | |
902 } | |
903 case Tarray: | |
904 { TypeArray *ta = (TypeArray *)tb; | |
905 for (; i < nfargs; i++) | |
906 { | |
907 Expression *arg = (Expression *)fargs->data[i]; | |
908 assert(arg); | |
909 MATCH m; | |
910 /* If lazy array of delegates, | |
911 * convert arg(s) to delegate(s) | |
912 */ | |
913 Type *tret = fparam->isLazyArray(); | |
914 if (tret) | |
915 { | |
916 if (ta->next->equals(arg->type)) | |
917 { m = MATCHexact; | |
918 } | |
919 else | |
920 { | |
921 m = arg->implicitConvTo(tret); | |
922 if (m == MATCHnomatch) | |
923 { | |
924 if (tret->toBasetype()->ty == Tvoid) | |
925 m = MATCHconvert; | |
926 } | |
927 } | |
928 } | |
929 else | |
930 { | |
931 m = arg->type->deduceType(scope, ta->next, parameters, &dedtypes); | |
932 //m = arg->implicitConvTo(ta->next); | |
933 } | |
934 if (m == MATCHnomatch) | |
935 goto Lnomatch; | |
936 if (m < match) | |
937 match = m; | |
938 } | |
939 goto Lmatch; | |
940 } | |
941 case Tclass: | |
942 case Tident: | |
943 goto Lmatch; | |
944 | |
945 default: | |
946 goto Lnomatch; | |
947 } | |
948 } | |
949 | |
950 Lmatch: | |
951 | |
952 /* Fill in any missing arguments with their defaults. | |
953 */ | |
954 for (i = nargsi; i < dedargs->dim; i++) | |
955 { | |
956 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
957 //printf("tp[%d] = %s\n", i, tp->ident->toChars()); | |
958 /* For T:T*, the dedargs is the T*, dedtypes is the T | |
959 * But for function templates, we really need them to match | |
960 */ | |
961 Object *oarg = (Object *)dedargs->data[i]; | |
962 Object *oded = (Object *)dedtypes.data[i]; | |
963 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); | |
964 if (!oarg) | |
965 { | |
966 if (oded) | |
967 { | |
968 if (tp->specialization()) | |
969 { /* The specialization can work as long as afterwards | |
970 * the oded == oarg | |
971 */ | |
972 Declaration *sparam; | |
973 dedargs->data[i] = (void *)oded; | |
974 MATCH m2 = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); | |
975 //printf("m2 = %d\n", m2); | |
976 if (!m2) | |
977 goto Lnomatch; | |
978 if (m2 < match) | |
979 match = m2; // pick worst match | |
980 if (dedtypes.data[i] != oded) | |
981 error("specialization not allowed for deduced parameter %s", tp->ident->toChars()); | |
982 } | |
983 } | |
984 else | |
985 { oded = tp->defaultArg(paramscope); | |
986 if (!oded) | |
987 goto Lnomatch; | |
988 } | |
989 declareParameter(paramscope, tp, oded); | |
990 dedargs->data[i] = (void *)oded; | |
991 } | |
992 } | |
993 | |
994 #if 0 | |
995 for (i = 0; i < dedargs->dim; i++) | |
996 { Type *t = (Type *)dedargs->data[i]; | |
997 printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); | |
998 } | |
999 #endif | |
1000 | |
1001 paramscope->pop(); | |
1002 //printf("\tmatch %d\n", match); | |
1003 return match; | |
1004 | |
1005 Lnomatch: | |
1006 paramscope->pop(); | |
1007 //printf("\tnomatch\n"); | |
1008 return MATCHnomatch; | |
1009 } | |
1010 | |
1011 /************************************************** | |
1012 * Declare template parameter tp with value o. | |
1013 */ | |
1014 | |
1015 void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) | |
1016 { | |
1017 //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); | |
1018 | |
1019 Type *targ = isType(o); | |
1020 Expression *ea = isExpression(o); | |
1021 Dsymbol *sa = isDsymbol(o); | |
1022 Tuple *va = isTuple(o); | |
1023 | |
1024 Dsymbol *s; | |
1025 | |
1026 if (targ) | |
1027 { | |
1028 //printf("type %s\n", targ->toChars()); | |
1029 s = new AliasDeclaration(0, tp->ident, targ); | |
1030 } | |
1031 else if (sa) | |
1032 { | |
1033 //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); | |
1034 s = new AliasDeclaration(0, tp->ident, sa); | |
1035 } | |
1036 else if (ea) | |
1037 { | |
1038 // tdtypes.data[i] always matches ea here | |
1039 Initializer *init = new ExpInitializer(loc, ea); | |
1040 TemplateValueParameter *tvp = tp->isTemplateValueParameter(); | |
1041 assert(tvp); | |
1042 | |
1043 VarDeclaration *v = new VarDeclaration(loc, tvp->valType, tp->ident, init); | |
1044 v->storage_class = STCconst; | |
1045 s = v; | |
1046 } | |
1047 else if (va) | |
1048 { | |
1049 //printf("\ttuple\n"); | |
1050 s = new TupleDeclaration(loc, tp->ident, &va->objects); | |
1051 } | |
1052 else | |
1053 { | |
1054 #ifdef DEBUG | |
1055 o->print(); | |
1056 #endif | |
1057 assert(0); | |
1058 } | |
1059 if (!sc->insert(s)) | |
1060 error("declaration %s is already defined", tp->ident->toChars()); | |
1061 s->semantic(sc); | |
1062 } | |
1063 | |
1064 /************************************** | |
1065 * Determine if TemplateDeclaration is variadic. | |
1066 */ | |
1067 | |
1068 TemplateTupleParameter *isVariadic(TemplateParameters *parameters) | |
1069 { size_t dim = parameters->dim; | |
1070 TemplateTupleParameter *tp = NULL; | |
1071 | |
1072 if (dim) | |
1073 tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter(); | |
1074 return tp; | |
1075 } | |
1076 | |
1077 TemplateTupleParameter *TemplateDeclaration::isVariadic() | |
1078 { | |
1079 return ::isVariadic(parameters); | |
1080 } | |
1081 | |
1082 /*********************************** | |
1083 * We can overload templates. | |
1084 */ | |
1085 | |
1086 int TemplateDeclaration::isOverloadable() | |
1087 { | |
1088 return 1; | |
1089 } | |
1090 | |
1091 /************************************************* | |
1092 * Given function arguments, figure out which template function | |
1093 * to expand, and return that function. | |
1094 * If no match, give error message and return NULL. | |
1095 * Input: | |
1096 * sc instantiation scope | |
1097 * loc instantiation location | |
1098 * targsi initial list of template arguments | |
1099 * fargs arguments to function | |
1100 */ | |
1101 | |
1102 FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, | |
1103 Objects *targsi, Expressions *fargs) | |
1104 { | |
1105 MATCH m_best = MATCHnomatch; | |
1106 TemplateDeclaration *td_ambig = NULL; | |
1107 TemplateDeclaration *td_best = NULL; | |
1108 Objects *tdargs = new Objects(); | |
1109 TemplateInstance *ti; | |
1110 FuncDeclaration *fd; | |
1111 | |
1112 #if 0 | |
1113 printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); | |
1114 printf(" targsi:\n"); | |
1115 if (targsi) | |
1116 { for (int i = 0; i < targsi->dim; i++) | |
1117 { Object *arg = (Object *)targsi->data[i]; | |
1118 printf("\t%s\n", arg->toChars()); | |
1119 } | |
1120 } | |
1121 printf(" fargs:\n"); | |
1122 for (int i = 0; i < fargs->dim; i++) | |
1123 { Expression *arg = (Expression *)fargs->data[i]; | |
1124 printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); | |
1125 //printf("\tty = %d\n", arg->type->ty); | |
1126 } | |
1127 #endif | |
1128 | |
1129 for (TemplateDeclaration *td = this; td; td = td->overnext) | |
1130 { | |
1131 if (!td->scope) | |
1132 { | |
1133 error("forward reference to template %s", td->toChars()); | |
1134 goto Lerror; | |
1135 } | |
1136 if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) | |
1137 { | |
1138 error("is not a function template"); | |
1139 goto Lerror; | |
1140 } | |
1141 | |
1142 MATCH m; | |
1143 Objects dedargs; | |
1144 | |
1145 m = td->deduceFunctionTemplateMatch(targsi, fargs, &dedargs); | |
1146 //printf("deduceFunctionTemplateMatch = %d\n", m); | |
1147 if (!m) // if no match | |
1148 continue; | |
1149 | |
1150 if (m < m_best) | |
1151 goto Ltd_best; | |
1152 if (m > m_best) | |
1153 goto Ltd; | |
1154 | |
1155 { | |
1156 // Disambiguate by picking the most specialized TemplateDeclaration | |
1157 int c1 = td->leastAsSpecialized(td_best); | |
1158 int c2 = td_best->leastAsSpecialized(td); | |
1159 //printf("c1 = %d, c2 = %d\n", c1, c2); | |
1160 | |
1161 if (c1 > c2) | |
1162 goto Ltd; | |
1163 else if (c1 < c2) | |
1164 goto Ltd_best; | |
1165 else | |
1166 goto Lambig; | |
1167 } | |
1168 | |
1169 Lambig: // td_best and td are ambiguous | |
1170 td_ambig = td; | |
1171 continue; | |
1172 | |
1173 Ltd_best: // td_best is the best match so far | |
1174 td_ambig = NULL; | |
1175 continue; | |
1176 | |
1177 Ltd: // td is the new best match | |
1178 td_ambig = NULL; | |
1179 assert((size_t)td->scope > 0x10000); | |
1180 td_best = td; | |
1181 m_best = m; | |
1182 tdargs->setDim(dedargs.dim); | |
1183 memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *)); | |
1184 continue; | |
1185 } | |
1186 if (!td_best) | |
1187 { | |
1188 error(loc, "does not match any template declaration"); | |
1189 goto Lerror; | |
1190 } | |
1191 if (td_ambig) | |
1192 { | |
1193 error(loc, "%s matches more than one function template declaration, %s and %s", | |
1194 toChars(), td_best->toChars(), td_ambig->toChars()); | |
1195 } | |
1196 | |
1197 /* The best match is td_best with arguments tdargs. | |
1198 * Now instantiate the template. | |
1199 */ | |
1200 assert((size_t)td_best->scope > 0x10000); | |
1201 ti = new TemplateInstance(loc, td_best, tdargs); | |
1202 ti->semantic(sc); | |
1203 fd = ti->toAlias()->isFuncDeclaration(); | |
1204 if (!fd) | |
1205 goto Lerror; | |
1206 return fd; | |
1207 | |
1208 Lerror: | |
1209 { | |
1210 OutBuffer buf; | |
1211 HdrGenState hgs; | |
1212 | |
1213 argExpTypesToCBuffer(&buf, fargs, &hgs); | |
1214 error(loc, "cannot deduce template function from argument types (%s)", | |
1215 buf.toChars()); | |
1216 return NULL; | |
1217 } | |
1218 } | |
1219 | |
1220 void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
1221 { | |
1222 #if 0 // Should handle template functions | |
1223 if (onemember && onemember->isFuncDeclaration()) | |
1224 buf->writestring("foo "); | |
1225 #endif | |
1226 buf->writestring(kind()); | |
1227 buf->writeByte(' '); | |
1228 buf->writestring(ident->toChars()); | |
1229 buf->writeByte('('); | |
1230 for (int i = 0; i < parameters->dim; i++) | |
1231 { | |
1232 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
1233 if (hgs->ddoc) | |
1234 tp = (TemplateParameter *)origParameters->data[i]; | |
1235 if (i) | |
1236 buf->writeByte(','); | |
1237 tp->toCBuffer(buf, hgs); | |
1238 } | |
1239 buf->writeByte(')'); | |
1240 | |
1241 if (hgs->hdrgen) | |
1242 { | |
1243 hgs->tpltMember++; | |
1244 buf->writenl(); | |
1245 buf->writebyte('{'); | |
1246 buf->writenl(); | |
1247 for (int i = 0; i < members->dim; i++) | |
1248 { | |
1249 Dsymbol *s = (Dsymbol *)members->data[i]; | |
1250 s->toCBuffer(buf, hgs); | |
1251 } | |
1252 buf->writebyte('}'); | |
1253 buf->writenl(); | |
1254 hgs->tpltMember--; | |
1255 } | |
1256 } | |
1257 | |
1258 | |
1259 char *TemplateDeclaration::toChars() | |
1260 { OutBuffer buf; | |
1261 HdrGenState hgs; | |
1262 | |
1263 memset(&hgs, 0, sizeof(hgs)); | |
1264 buf.writestring(ident->toChars()); | |
1265 buf.writeByte('('); | |
1266 for (int i = 0; i < parameters->dim; i++) | |
1267 { | |
1268 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
1269 if (i) | |
1270 buf.writeByte(','); | |
1271 tp->toCBuffer(&buf, &hgs); | |
1272 } | |
1273 buf.writeByte(')'); | |
1274 buf.writeByte(0); | |
1275 return (char *)buf.extractData(); | |
1276 } | |
1277 | |
1278 /* ======================== Type ============================================ */ | |
1279 | |
1280 /**** | |
1281 * Given an identifier, figure out which TemplateParameter it is. | |
1282 * Return -1 if not found. | |
1283 */ | |
1284 | |
1285 int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) | |
1286 { | |
1287 for (size_t i = 0; i < parameters->dim; i++) | |
1288 { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
1289 | |
1290 if (tp->ident->equals(id)) | |
1291 return i; | |
1292 } | |
1293 return -1; | |
1294 } | |
1295 | |
1296 int templateParameterLookup(Type *tparam, TemplateParameters *parameters) | |
1297 { | |
1298 assert(tparam->ty == Tident); | |
1299 TypeIdentifier *tident = (TypeIdentifier *)tparam; | |
1300 //printf("\ttident = '%s'\n", tident->toChars()); | |
1301 if (tident->idents.dim == 0) | |
1302 { | |
1303 return templateIdentifierLookup(tident->ident, parameters); | |
1304 } | |
1305 return -1; | |
1306 } | |
1307 | |
1308 /* These form the heart of template argument deduction. | |
1309 * Given 'this' being the type argument to the template instance, | |
1310 * it is matched against the template declaration parameter specialization | |
1311 * 'tparam' to determine the type to be used for the parameter. | |
1312 * Example: | |
1313 * template Foo(T:T*) // template declaration | |
1314 * Foo!(int*) // template instantiation | |
1315 * Input: | |
1316 * this = int* | |
1317 * tparam = T | |
1318 * parameters = [ T:T* ] // Array of TemplateParameter's | |
1319 * Output: | |
1320 * dedtypes = [ int ] // Array of Expression/Type's | |
1321 */ | |
1322 | |
1323 MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, | |
1324 Objects *dedtypes) | |
1325 { | |
1326 //printf("Type::deduceType()\n"); | |
1327 //printf("\tthis = %d, ", ty); print(); | |
1328 //printf("\ttparam = %d, ", tparam->ty); tparam->print(); | |
1329 if (!tparam) | |
1330 goto Lnomatch; | |
1331 | |
1332 if (this == tparam) | |
1333 goto Lexact; | |
1334 | |
1335 if (tparam->ty == Tident) | |
1336 { | |
1337 // Determine which parameter tparam is | |
1338 int i = templateParameterLookup(tparam, parameters); | |
1339 if (i == -1) | |
1340 { | |
1341 if (!sc) | |
1342 goto Lnomatch; | |
1343 | |
1344 /* Need a loc to go with the semantic routine. | |
1345 */ | |
1346 Loc loc; | |
1347 if (parameters->dim) | |
1348 { | |
1349 TemplateParameter *tp = (TemplateParameter *)parameters->data[0]; | |
1350 loc = tp->loc; | |
1351 } | |
1352 | |
1353 /* BUG: what if tparam is a template instance, that | |
1354 * has as an argument another Tident? | |
1355 */ | |
1356 tparam = tparam->semantic(loc, sc); | |
1357 assert(tparam->ty != Tident); | |
1358 return deduceType(sc, tparam, parameters, dedtypes); | |
1359 } | |
1360 | |
1361 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
1362 | |
1363 // Found the corresponding parameter tp | |
1364 if (!tp->isTemplateTypeParameter()) | |
1365 goto Lnomatch; | |
1366 Type *at = (Type *)dedtypes->data[i]; | |
1367 if (!at) | |
1368 { | |
1369 dedtypes->data[i] = (void *)this; | |
1370 goto Lexact; | |
1371 } | |
1372 if (equals(at)) | |
1373 goto Lexact; | |
1374 else if (ty == Tclass && at->ty == Tclass) | |
1375 { | |
1376 return (MATCH) implicitConvTo(at); | |
1377 } | |
1378 else if (ty == Tsarray && at->ty == Tarray && | |
1379 nextOf()->equals(at->nextOf())) | |
1380 { | |
1381 goto Lexact; | |
1382 } | |
1383 else | |
1384 goto Lnomatch; | |
1385 } | |
1386 | |
1387 if (ty != tparam->ty) | |
1388 return implicitConvTo(tparam); | |
1389 // goto Lnomatch; | |
1390 | |
1391 if (nextOf()) | |
1392 return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes); | |
1393 | |
1394 Lexact: | |
1395 return MATCHexact; | |
1396 | |
1397 Lnomatch: | |
1398 return MATCHnomatch; | |
1399 } | |
1400 | |
1401 MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, | |
1402 Objects *dedtypes) | |
1403 { | |
1404 #if 0 | |
1405 printf("TypeSArray::deduceType()\n"); | |
1406 printf("\tthis = %d, ", ty); print(); | |
1407 printf("\ttparam = %d, ", tparam->ty); tparam->print(); | |
1408 #endif | |
1409 | |
1410 // Extra check that array dimensions must match | |
1411 if (tparam) | |
1412 { | |
1413 if (tparam->ty == Tsarray) | |
1414 { | |
1415 TypeSArray *tp = (TypeSArray *)tparam; | |
1416 | |
1417 if (tp->dim->op == TOKvar && | |
1418 ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) | |
1419 { int i = templateIdentifierLookup(((VarExp *)tp->dim)->var->ident, parameters); | |
1420 // This code matches code in TypeInstance::deduceType() | |
1421 if (i == -1) | |
1422 goto Lnomatch; | |
1423 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
1424 TemplateValueParameter *tvp = tp->isTemplateValueParameter(); | |
1425 if (!tvp) | |
1426 goto Lnomatch; | |
1427 Expression *e = (Expression *)dedtypes->data[i]; | |
1428 if (e) | |
1429 { | |
1430 if (!dim->equals(e)) | |
1431 goto Lnomatch; | |
1432 } | |
1433 else | |
1434 { Type *vt = tvp->valType->semantic(0, sc); | |
1435 MATCH m = (MATCH)dim->implicitConvTo(vt); | |
1436 if (!m) | |
1437 goto Lnomatch; | |
1438 dedtypes->data[i] = dim; | |
1439 } | |
1440 } | |
1441 else if (dim->toInteger() != tp->dim->toInteger()) | |
1442 return MATCHnomatch; | |
1443 } | |
1444 else if (tparam->ty == Taarray) | |
1445 { | |
1446 TypeAArray *tp = (TypeAArray *)tparam; | |
1447 if (tp->index->ty == Tident) | |
1448 { TypeIdentifier *tident = (TypeIdentifier *)tp->index; | |
1449 | |
1450 if (tident->idents.dim == 0) | |
1451 { Identifier *id = tident->ident; | |
1452 | |
1453 for (size_t i = 0; i < parameters->dim; i++) | |
1454 { | |
1455 TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; | |
1456 | |
1457 if (tp->ident->equals(id)) | |
1458 { // Found the corresponding template parameter | |
1459 TemplateValueParameter *tvp = tp->isTemplateValueParameter(); | |
1460 if (!tvp || !tvp->valType->isintegral()) | |
1461 goto Lnomatch; | |
1462 | |
1463 if (dedtypes->data[i]) | |
1464 { | |
1465 if (!dim->equals((Object *)dedtypes->data[i])) | |
1466 goto Lnomatch; | |
1467 } | |
1468 else | |
1469 { dedtypes->data[i] = (void *)dim; | |
1470 } | |
1471 return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); | |
1472 } | |
1473 } | |
1474 } | |
1475 } | |
1476 } | |
1477 else if (tparam->ty == Tarray) | |
1478 { MATCH m; | |
1479 | |
1480 m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); | |
1481 if (m == MATCHexact) | |
1482 m = MATCHconvert; | |
1483 return m; | |
1484 } | |
1485 } | |
1486 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1487 | |
1488 Lnomatch: | |
1489 return MATCHnomatch; | |
1490 } | |
1491 | |
1492 MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) | |
1493 { | |
1494 #if 0 | |
1495 printf("TypeAArray::deduceType()\n"); | |
1496 printf("\tthis = %d, ", ty); print(); | |
1497 printf("\ttparam = %d, ", tparam->ty); tparam->print(); | |
1498 #endif | |
1499 | |
1500 // Extra check that index type must match | |
1501 if (tparam && tparam->ty == Taarray) | |
1502 { | |
1503 TypeAArray *tp = (TypeAArray *)tparam; | |
1504 if (!index->deduceType(sc, tp->index, parameters, dedtypes)) | |
1505 { | |
1506 return MATCHnomatch; | |
1507 } | |
1508 } | |
1509 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1510 } | |
1511 | |
1512 MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) | |
1513 { | |
1514 //printf("TypeFunction::deduceType()\n"); | |
1515 //printf("\tthis = %d, ", ty); print(); | |
1516 //printf("\ttparam = %d, ", tparam->ty); tparam->print(); | |
1517 | |
1518 // Extra check that function characteristics must match | |
1519 if (tparam && tparam->ty == Tfunction) | |
1520 { | |
1521 TypeFunction *tp = (TypeFunction *)tparam; | |
1522 if (varargs != tp->varargs || | |
1523 linkage != tp->linkage) | |
1524 return MATCHnomatch; | |
1525 | |
1526 size_t nfargs = Argument::dim(this->parameters); | |
1527 size_t nfparams = Argument::dim(tp->parameters); | |
1528 | |
1529 /* See if tuple match | |
1530 */ | |
1531 if (nfparams > 0 && nfargs >= nfparams - 1) | |
1532 { | |
1533 /* See if 'A' of the template parameter matches 'A' | |
1534 * of the type of the last function parameter. | |
1535 */ | |
1536 Argument *fparam = (Argument *)tp->parameters->data[nfparams - 1]; | |
1537 if (fparam->type->ty != Tident) | |
1538 goto L1; | |
1539 TypeIdentifier *tid = (TypeIdentifier *)fparam->type; | |
1540 if (tid->idents.dim) | |
1541 goto L1; | |
1542 | |
1543 /* Look through parameters to find tuple matching tid->ident | |
1544 */ | |
1545 size_t tupi = 0; | |
1546 for (; 1; tupi++) | |
1547 { if (tupi == parameters->dim) | |
1548 goto L1; | |
1549 TemplateParameter *t = (TemplateParameter *)parameters->data[tupi]; | |
1550 TemplateTupleParameter *tup = t->isTemplateTupleParameter(); | |
1551 if (tup && tup->ident->equals(tid->ident)) | |
1552 break; | |
1553 } | |
1554 | |
1555 /* The types of the function arguments [nfparams - 1 .. nfargs] | |
1556 * now form the tuple argument. | |
1557 */ | |
1558 int tuple_dim = nfargs - (nfparams - 1); | |
1559 | |
1560 /* See if existing tuple, and whether it matches or not | |
1561 */ | |
1562 Object *o = (Object *)dedtypes->data[tupi]; | |
1563 if (o) | |
1564 { // Existing deduced argument must be a tuple, and must match | |
1565 Tuple *t = isTuple(o); | |
1566 if (!t || t->objects.dim != tuple_dim) | |
1567 return MATCHnomatch; | |
1568 for (size_t i = 0; i < tuple_dim; i++) | |
1569 { Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i); | |
1570 if (!arg->type->equals((Object *)t->objects.data[i])) | |
1571 return MATCHnomatch; | |
1572 } | |
1573 } | |
1574 else | |
1575 { // Create new tuple | |
1576 Tuple *t = new Tuple(); | |
1577 t->objects.setDim(tuple_dim); | |
1578 for (size_t i = 0; i < tuple_dim; i++) | |
1579 { Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i); | |
1580 t->objects.data[i] = (void *)arg->type; | |
1581 } | |
1582 dedtypes->data[tupi] = (void *)t; | |
1583 } | |
1584 nfparams--; // don't consider the last parameter for type deduction | |
1585 goto L2; | |
1586 } | |
1587 | |
1588 L1: | |
1589 if (nfargs != nfparams) | |
1590 return MATCHnomatch; | |
1591 L2: | |
1592 for (size_t i = 0; i < nfparams; i++) | |
1593 { | |
1594 Argument *a = Argument::getNth(this->parameters, i); | |
1595 Argument *ap = Argument::getNth(tp->parameters, i); | |
1596 if (a->storageClass != ap->storageClass || | |
1597 !a->type->deduceType(sc, ap->type, parameters, dedtypes)) | |
1598 return MATCHnomatch; | |
1599 } | |
1600 } | |
1601 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1602 } | |
1603 | |
1604 MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) | |
1605 { | |
1606 // Extra check | |
1607 if (tparam && tparam->ty == Tident) | |
1608 { | |
1609 TypeIdentifier *tp = (TypeIdentifier *)tparam; | |
1610 | |
1611 for (int i = 0; i < idents.dim; i++) | |
1612 { | |
1613 Identifier *id1 = (Identifier *)idents.data[i]; | |
1614 Identifier *id2 = (Identifier *)tp->idents.data[i]; | |
1615 | |
1616 if (!id1->equals(id2)) | |
1617 return MATCHnomatch; | |
1618 } | |
1619 } | |
1620 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1621 } | |
1622 | |
1623 MATCH TypeInstance::deduceType(Scope *sc, | |
1624 Type *tparam, TemplateParameters *parameters, | |
1625 Objects *dedtypes) | |
1626 { | |
1627 //printf("TypeInstance::deduceType(tparam = %s) %s\n", tparam->toChars(), toChars()); | |
1628 //printf("\ttparam = %d, ", tparam->ty); tparam->print(); | |
1629 | |
1630 // Extra check | |
1631 if (tparam && tparam->ty == Tinstance) | |
1632 { | |
1633 TypeInstance *tp = (TypeInstance *)tparam; | |
1634 | |
1635 //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); | |
1636 //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); | |
1637 if (!tp->tempinst->tempdecl) | |
1638 { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); | |
1639 if (!tp->tempinst->name->equals(tempinst->name)) | |
1640 { | |
1641 /* Handle case of: | |
1642 * template Foo(T : sa!(T), alias sa) | |
1643 */ | |
1644 int i = templateIdentifierLookup(tp->tempinst->name, parameters); | |
1645 if (i == -1) | |
1646 { /* Didn't find it as a parameter identifier. Try looking | |
1647 * it up and seeing if is an alias. See Bugzilla 1454 | |
1648 */ | |
1649 Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL); | |
1650 if (s) | |
1651 { | |
1652 s = s->toAlias(); | |
1653 TemplateDeclaration *td = s->isTemplateDeclaration(); | |
1654 if (td && td == tempinst->tempdecl) | |
1655 goto L2; | |
1656 } | |
1657 goto Lnomatch; | |
1658 } | |
1659 TemplateParameter *tpx = (TemplateParameter *)parameters->data[i]; | |
1660 // This logic duplicates tpx->matchArg() | |
1661 TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); | |
1662 if (!ta) | |
1663 goto Lnomatch; | |
1664 Dsymbol *sa = tempinst->tempdecl; | |
1665 if (!sa) | |
1666 goto Lnomatch; | |
1667 if (ta->specAlias && sa != ta->specAlias) | |
1668 goto Lnomatch; | |
1669 if (dedtypes->data[i]) | |
1670 { // Must match already deduced symbol | |
1671 Dsymbol *s = (Dsymbol *)dedtypes->data[i]; | |
1672 | |
1673 if (s != sa) | |
1674 goto Lnomatch; | |
1675 } | |
1676 dedtypes->data[i] = sa; | |
1677 } | |
1678 } | |
1679 else if (tempinst->tempdecl != tp->tempinst->tempdecl) | |
1680 goto Lnomatch; | |
1681 | |
1682 L2: | |
1683 if (tempinst->tiargs->dim != tp->tempinst->tiargs->dim) | |
1684 goto Lnomatch; | |
1685 | |
1686 for (int i = 0; i < tempinst->tiargs->dim; i++) | |
1687 { | |
1688 //printf("\ttest: tempinst->tiargs[%d]\n", i); | |
1689 int j; | |
1690 Object *o1 = (Object *)tempinst->tiargs->data[i]; | |
1691 Object *o2 = (Object *)tp->tempinst->tiargs->data[i]; | |
1692 | |
1693 Type *t1 = isType(o1); | |
1694 Type *t2 = isType(o2); | |
1695 | |
1696 Expression *e1 = isExpression(o1); | |
1697 Expression *e2 = isExpression(o2); | |
1698 | |
1699 #if 0 | |
1700 if (t1) printf("t1 = %s\n", t1->toChars()); | |
1701 if (t2) printf("t2 = %s\n", t2->toChars()); | |
1702 if (e1) printf("e1 = %s\n", e1->toChars()); | |
1703 if (e2) printf("e2 = %s\n", e2->toChars()); | |
1704 #endif | |
1705 | |
1706 if (t1 && t2) | |
1707 { | |
1708 if (!t1->deduceType(sc, t2, parameters, dedtypes)) | |
1709 goto Lnomatch; | |
1710 } | |
1711 else if (e1 && e2) | |
1712 { | |
1713 if (!e1->equals(e2)) | |
1714 { if (e2->op == TOKvar) | |
1715 { | |
1716 /* | |
1717 * (T:Number!(e2), int e2) | |
1718 */ | |
1719 j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); | |
1720 goto L1; | |
1721 } | |
1722 goto Lnomatch; | |
1723 } | |
1724 } | |
1725 else if (e1 && t2 && t2->ty == Tident) | |
1726 { | |
1727 j = templateParameterLookup(t2, parameters); | |
1728 L1: | |
1729 if (j == -1) | |
1730 goto Lnomatch; | |
1731 TemplateParameter *tp = (TemplateParameter *)parameters->data[j]; | |
1732 // BUG: use tp->matchArg() instead of the following | |
1733 TemplateValueParameter *tv = tp->isTemplateValueParameter(); | |
1734 if (!tv) | |
1735 goto Lnomatch; | |
1736 Expression *e = (Expression *)dedtypes->data[j]; | |
1737 if (e) | |
1738 { | |
1739 if (!e1->equals(e)) | |
1740 goto Lnomatch; | |
1741 } | |
1742 else | |
1743 { Type *vt = tv->valType->semantic(0, sc); | |
1744 MATCH m = (MATCH)e1->implicitConvTo(vt); | |
1745 if (!m) | |
1746 goto Lnomatch; | |
1747 dedtypes->data[j] = e1; | |
1748 } | |
1749 } | |
1750 // BUG: Need to handle alias and tuple parameters | |
1751 else | |
1752 goto Lnomatch; | |
1753 } | |
1754 } | |
1755 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1756 | |
1757 Lnomatch: | |
1758 return MATCHnomatch; | |
1759 } | |
1760 | |
1761 MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) | |
1762 { | |
1763 //printf("TypeStruct::deduceType()\n"); | |
1764 //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); | |
1765 //printf("\ttparam = %d, ", tparam->ty); tparam->print(); | |
1766 | |
1767 /* If this struct is a template struct, and we're matching | |
1768 * it against a template instance, convert the struct type | |
1769 * to a template instance, too, and try again. | |
1770 */ | |
1771 TemplateInstance *ti = sym->parent->isTemplateInstance(); | |
1772 | |
1773 if (tparam && tparam->ty == Tinstance) | |
1774 { | |
1775 if (ti && ti->toAlias() == sym) | |
1776 { | |
1777 TypeInstance *t = new TypeInstance(0, ti); | |
1778 return t->deduceType(sc, tparam, parameters, dedtypes); | |
1779 } | |
1780 | |
1781 /* Match things like: | |
1782 * S!(T).foo | |
1783 */ | |
1784 TypeInstance *tpi = (TypeInstance *)tparam; | |
1785 if (tpi->idents.dim) | |
1786 { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; | |
1787 if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) | |
1788 { | |
1789 Type *tparent = sym->parent->getType(); | |
1790 if (tparent) | |
1791 { | |
1792 /* Slice off the .foo in S!(T).foo | |
1793 */ | |
1794 tpi->idents.dim--; | |
1795 MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); | |
1796 tpi->idents.dim++; | |
1797 return m; | |
1798 } | |
1799 } | |
1800 } | |
1801 } | |
1802 | |
1803 // Extra check | |
1804 if (tparam && tparam->ty == Tstruct) | |
1805 { | |
1806 TypeStruct *tp = (TypeStruct *)tparam; | |
1807 | |
1808 if (sym != tp->sym) | |
1809 return MATCHnomatch; | |
1810 } | |
1811 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1812 } | |
1813 | |
1814 MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) | |
1815 { | |
1816 // Extra check | |
1817 if (tparam && tparam->ty == Tenum) | |
1818 { | |
1819 TypeEnum *tp = (TypeEnum *)tparam; | |
1820 | |
1821 if (sym != tp->sym) | |
1822 return MATCHnomatch; | |
1823 } | |
1824 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1825 } | |
1826 | |
1827 MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) | |
1828 { | |
1829 // Extra check | |
1830 if (tparam && tparam->ty == Ttypedef) | |
1831 { | |
1832 TypeTypedef *tp = (TypeTypedef *)tparam; | |
1833 | |
1834 if (sym != tp->sym) | |
1835 return MATCHnomatch; | |
1836 } | |
1837 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1838 } | |
1839 | |
1840 MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) | |
1841 { | |
1842 //printf("TypeClass::deduceType(this = %s)\n", toChars()); | |
1843 | |
1844 /* If this class is a template class, and we're matching | |
1845 * it against a template instance, convert the class type | |
1846 * to a template instance, too, and try again. | |
1847 */ | |
1848 TemplateInstance *ti = sym->parent->isTemplateInstance(); | |
1849 | |
1850 if (tparam && tparam->ty == Tinstance) | |
1851 { | |
1852 if (ti && ti->toAlias() == sym) | |
1853 { | |
1854 TypeInstance *t = new TypeInstance(0, ti); | |
1855 return t->deduceType(sc, tparam, parameters, dedtypes); | |
1856 } | |
1857 | |
1858 /* Match things like: | |
1859 * S!(T).foo | |
1860 */ | |
1861 TypeInstance *tpi = (TypeInstance *)tparam; | |
1862 if (tpi->idents.dim) | |
1863 { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; | |
1864 if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) | |
1865 { | |
1866 Type *tparent = sym->parent->getType(); | |
1867 if (tparent) | |
1868 { | |
1869 /* Slice off the .foo in S!(T).foo | |
1870 */ | |
1871 tpi->idents.dim--; | |
1872 MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); | |
1873 tpi->idents.dim++; | |
1874 return m; | |
1875 } | |
1876 } | |
1877 } | |
1878 } | |
1879 | |
1880 // Extra check | |
1881 if (tparam && tparam->ty == Tclass) | |
1882 { | |
1883 TypeClass *tp = (TypeClass *)tparam; | |
1884 | |
1885 //printf("\t%d\n", (MATCH) implicitConvTo(tp)); | |
1886 return (MATCH) implicitConvTo(tp); | |
1887 } | |
1888 return Type::deduceType(sc, tparam, parameters, dedtypes); | |
1889 } | |
1890 | |
1891 /* ======================== TemplateParameter =============================== */ | |
1892 | |
1893 TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) | |
1894 { | |
1895 this->loc = loc; | |
1896 this->ident = ident; | |
1897 this->sparam = NULL; | |
1898 } | |
1899 | |
1900 TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() | |
1901 { | |
1902 return NULL; | |
1903 } | |
1904 | |
1905 TemplateValueParameter *TemplateParameter::isTemplateValueParameter() | |
1906 { | |
1907 return NULL; | |
1908 } | |
1909 | |
1910 TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() | |
1911 { | |
1912 return NULL; | |
1913 } | |
1914 | |
1915 TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() | |
1916 { | |
1917 return NULL; | |
1918 } | |
1919 | |
1920 #if DMDV2 | |
1921 TemplateThisParameter *TemplateParameter::isTemplateThisParameter() | |
1922 { | |
1923 return NULL; | |
1924 } | |
1925 #endif | |
1926 | |
1927 /* ======================== TemplateTypeParameter =========================== */ | |
1928 | |
1929 // type-parameter | |
1930 | |
1931 TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, | |
1932 Type *defaultType) | |
1933 : TemplateParameter(loc, ident) | |
1934 { | |
1935 this->ident = ident; | |
1936 this->specType = specType; | |
1937 this->defaultType = defaultType; | |
1938 } | |
1939 | |
1940 TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() | |
1941 { | |
1942 return this; | |
1943 } | |
1944 | |
1945 TemplateParameter *TemplateTypeParameter::syntaxCopy() | |
1946 { | |
1947 TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); | |
1948 if (tp->specType) | |
1949 tp->specType = specType->syntaxCopy(); | |
1950 if (defaultType) | |
1951 tp->defaultType = defaultType->syntaxCopy(); | |
1952 return tp; | |
1953 } | |
1954 | |
1955 void TemplateTypeParameter::declareParameter(Scope *sc) | |
1956 { | |
1957 //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); | |
1958 TypeIdentifier *ti = new TypeIdentifier(loc, ident); | |
1959 sparam = new AliasDeclaration(loc, ident, ti); | |
1960 if (!sc->insert(sparam)) | |
1961 error(loc, "parameter '%s' multiply defined", ident->toChars()); | |
1962 } | |
1963 | |
1964 void TemplateTypeParameter::semantic(Scope *sc) | |
1965 { | |
1966 //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); | |
1967 if (specType) | |
1968 { | |
1969 specType = specType->semantic(loc, sc); | |
1970 } | |
1971 #if 0 // Don't do semantic() until instantiation | |
1972 if (defaultType) | |
1973 { | |
1974 defaultType = defaultType->semantic(loc, sc); | |
1975 } | |
1976 #endif | |
1977 } | |
1978 | |
1979 /**************************************** | |
1980 * Determine if two TemplateParameters are the same | |
1981 * as far as TemplateDeclaration overloading goes. | |
1982 * Returns: | |
1983 * 1 match | |
1984 * 0 no match | |
1985 */ | |
1986 | |
1987 int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) | |
1988 { | |
1989 TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); | |
1990 | |
1991 if (ttp) | |
1992 { | |
1993 if (specType != ttp->specType) | |
1994 goto Lnomatch; | |
1995 | |
1996 if (specType && !specType->equals(ttp->specType)) | |
1997 goto Lnomatch; | |
1998 | |
1999 return 1; // match | |
2000 } | |
2001 | |
2002 Lnomatch: | |
2003 return 0; | |
2004 } | |
2005 | |
2006 /******************************************* | |
2007 * Match to a particular TemplateParameter. | |
2008 * Input: | |
2009 * i i'th argument | |
2010 * tiargs[] actual arguments to template instance | |
2011 * parameters[] template parameters | |
2012 * dedtypes[] deduced arguments to template instance | |
2013 * *psparam set to symbol declared and initialized to dedtypes[i] | |
2014 */ | |
2015 | |
2016 MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, | |
2017 int i, TemplateParameters *parameters, Objects *dedtypes, | |
2018 Declaration **psparam) | |
2019 { | |
2020 //printf("TemplateTypeParameter::matchArg()\n"); | |
2021 Type *t; | |
2022 Object *oarg; | |
2023 MATCH m = MATCHexact; | |
2024 Type *ta; | |
2025 | |
2026 if (i < tiargs->dim) | |
2027 oarg = (Object *)tiargs->data[i]; | |
2028 else | |
2029 { // Get default argument instead | |
2030 oarg = defaultArg(sc); | |
2031 if (!oarg) | |
2032 { assert(i < dedtypes->dim); | |
2033 // It might have already been deduced | |
2034 oarg = (Object *)dedtypes->data[i]; | |
2035 if (!oarg) | |
2036 goto Lnomatch; | |
2037 } | |
2038 } | |
2039 | |
2040 ta = isType(oarg); | |
2041 if (!ta) | |
2042 goto Lnomatch; | |
2043 //printf("ta is %s\n", ta->toChars()); | |
2044 | |
2045 t = (Type *)dedtypes->data[i]; | |
2046 | |
2047 if (specType) | |
2048 { | |
2049 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); | |
2050 MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); | |
2051 if (m2 == MATCHnomatch) | |
2052 { //printf("\tfailed deduceType\n"); | |
2053 goto Lnomatch; | |
2054 } | |
2055 | |
2056 if (m2 < m) | |
2057 m = m2; | |
2058 t = (Type *)dedtypes->data[i]; | |
2059 } | |
2060 else | |
2061 { | |
2062 // So that matches with specializations are better | |
2063 m = MATCHconvert; | |
2064 if (t) | |
2065 { // Must match already deduced type | |
2066 | |
2067 m = MATCHexact; | |
2068 if (!t->equals(ta)) | |
2069 { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); | |
2070 goto Lnomatch; | |
2071 } | |
2072 } | |
2073 } | |
2074 | |
2075 if (!t) | |
2076 { | |
2077 dedtypes->data[i] = ta; | |
2078 t = ta; | |
2079 } | |
2080 *psparam = new AliasDeclaration(loc, ident, t); | |
2081 //printf("\tm = %d\n", m); | |
2082 return m; | |
2083 | |
2084 Lnomatch: | |
2085 *psparam = NULL; | |
2086 //printf("\tm = %d\n", MATCHnomatch); | |
2087 return MATCHnomatch; | |
2088 } | |
2089 | |
2090 | |
2091 void TemplateTypeParameter::print(Object *oarg, Object *oded) | |
2092 { | |
2093 printf(" %s\n", ident->toChars()); | |
2094 | |
2095 Type *t = isType(oarg); | |
2096 Type *ta = isType(oded); | |
2097 | |
2098 assert(ta); | |
2099 | |
2100 if (specType) | |
2101 printf("\tSpecialization: %s\n", specType->toChars()); | |
2102 if (defaultType) | |
2103 printf("\tDefault: %s\n", defaultType->toChars()); | |
2104 printf("\tArgument: %s\n", t ? t->toChars() : "NULL"); | |
2105 printf("\tDeduced Type: %s\n", ta->toChars()); | |
2106 } | |
2107 | |
2108 | |
2109 void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2110 { | |
2111 buf->writestring(ident->toChars()); | |
2112 if (specType) | |
2113 { | |
2114 buf->writestring(" : "); | |
2115 specType->toCBuffer(buf, NULL, hgs); | |
2116 } | |
2117 if (defaultType) | |
2118 { | |
2119 buf->writestring(" = "); | |
2120 defaultType->toCBuffer(buf, NULL, hgs); | |
2121 } | |
2122 } | |
2123 | |
2124 | |
2125 void *TemplateTypeParameter::dummyArg() | |
2126 { Type *t; | |
2127 | |
2128 if (specType) | |
2129 t = specType; | |
2130 else | |
2131 { // Use this for alias-parameter's too (?) | |
2132 t = new TypeIdentifier(loc, ident); | |
2133 } | |
2134 return (void *)t; | |
2135 } | |
2136 | |
2137 | |
2138 Object *TemplateTypeParameter::specialization() | |
2139 { | |
2140 return specType; | |
2141 } | |
2142 | |
2143 | |
2144 Object *TemplateTypeParameter::defaultArg(Scope *sc) | |
2145 { | |
2146 Type *t; | |
2147 | |
2148 t = defaultType; | |
2149 if (t) | |
2150 { | |
2151 t = t->syntaxCopy(); | |
2152 t = t->semantic(loc, sc); | |
2153 } | |
2154 return t; | |
2155 } | |
2156 | |
2157 /* ======================== TemplateThisParameter =========================== */ | |
2158 | |
2159 #if DMDV2 | |
2160 // this-parameter | |
2161 | |
2162 TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, | |
2163 Type *specType, | |
2164 Type *defaultType) | |
2165 : TemplateTypeParameter(loc, ident, specType, defaultType) | |
2166 { | |
2167 } | |
2168 | |
2169 TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() | |
2170 { | |
2171 return this; | |
2172 } | |
2173 | |
2174 TemplateParameter *TemplateThisParameter::syntaxCopy() | |
2175 { | |
2176 TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); | |
2177 if (tp->specType) | |
2178 tp->specType = specType->syntaxCopy(); | |
2179 if (defaultType) | |
2180 tp->defaultType = defaultType->syntaxCopy(); | |
2181 return tp; | |
2182 } | |
2183 | |
2184 void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2185 { | |
2186 buf->writestring("this "); | |
2187 TemplateTypeParameter::toCBuffer(buf, hgs); | |
2188 } | |
2189 #endif | |
2190 | |
2191 /* ======================== TemplateAliasParameter ========================== */ | |
2192 | |
2193 // alias-parameter | |
2194 | |
2195 Dsymbol *TemplateAliasParameter::sdummy = NULL; | |
2196 | |
2197 TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias) | |
2198 : TemplateParameter(loc, ident) | |
2199 { | |
2200 this->ident = ident; | |
2201 this->specAliasT = specAliasT; | |
2202 this->defaultAlias = defaultAlias; | |
2203 | |
2204 this->specAlias = NULL; | |
2205 } | |
2206 | |
2207 TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() | |
2208 { | |
2209 return this; | |
2210 } | |
2211 | |
2212 TemplateParameter *TemplateAliasParameter::syntaxCopy() | |
2213 { | |
2214 TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias); | |
2215 if (tp->specAliasT) | |
2216 tp->specAliasT = specAliasT->syntaxCopy(); | |
2217 if (defaultAlias) | |
2218 tp->defaultAlias = defaultAlias->syntaxCopy(); | |
2219 return tp; | |
2220 } | |
2221 | |
2222 void TemplateAliasParameter::declareParameter(Scope *sc) | |
2223 { | |
2224 TypeIdentifier *ti = new TypeIdentifier(loc, ident); | |
2225 sparam = new AliasDeclaration(loc, ident, ti); | |
2226 if (!sc->insert(sparam)) | |
2227 error(loc, "parameter '%s' multiply defined", ident->toChars()); | |
2228 } | |
2229 | |
2230 void TemplateAliasParameter::semantic(Scope *sc) | |
2231 { | |
2232 if (specAliasT) | |
2233 { | |
2234 specAlias = specAliasT->toDsymbol(sc); | |
2235 if (!specAlias) | |
2236 error(loc, "%s is not a symbol", specAliasT->toChars()); | |
2237 } | |
2238 #if 0 // Don't do semantic() until instantiation | |
2239 if (defaultAlias) | |
2240 defaultAlias = defaultAlias->semantic(loc, sc); | |
2241 #endif | |
2242 } | |
2243 | |
2244 int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) | |
2245 { | |
2246 TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); | |
2247 | |
2248 if (tap) | |
2249 { | |
2250 if (specAlias != tap->specAlias) | |
2251 goto Lnomatch; | |
2252 | |
2253 return 1; // match | |
2254 } | |
2255 | |
2256 Lnomatch: | |
2257 return 0; | |
2258 } | |
2259 | |
2260 MATCH TemplateAliasParameter::matchArg(Scope *sc, | |
2261 Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, | |
2262 Declaration **psparam) | |
2263 { | |
2264 Dsymbol *sa; | |
2265 Object *oarg; | |
2266 Expression *ea; | |
2267 | |
2268 //printf("TemplateAliasParameter::matchArg()\n"); | |
2269 | |
2270 if (i < tiargs->dim) | |
2271 oarg = (Object *)tiargs->data[i]; | |
2272 else | |
2273 { // Get default argument instead | |
2274 oarg = defaultArg(sc); | |
2275 if (!oarg) | |
2276 { assert(i < dedtypes->dim); | |
2277 // It might have already been deduced | |
2278 oarg = (Object *)dedtypes->data[i]; | |
2279 if (!oarg) | |
2280 goto Lnomatch; | |
2281 } | |
2282 } | |
2283 | |
2284 sa = getDsymbol(oarg); | |
2285 if (!sa) | |
2286 goto Lnomatch; | |
2287 | |
2288 if (specAlias) | |
2289 { | |
2290 if (!sa || sa == sdummy) | |
2291 goto Lnomatch; | |
2292 if (sa != specAlias) | |
2293 goto Lnomatch; | |
2294 } | |
2295 else if (dedtypes->data[i]) | |
2296 { // Must match already deduced symbol | |
2297 Dsymbol *s = (Dsymbol *)dedtypes->data[i]; | |
2298 | |
2299 if (!sa || s != sa) | |
2300 goto Lnomatch; | |
2301 } | |
2302 dedtypes->data[i] = sa; | |
2303 | |
2304 *psparam = new AliasDeclaration(loc, ident, sa); | |
2305 return MATCHexact; | |
2306 | |
2307 Lnomatch: | |
2308 *psparam = NULL; | |
2309 return MATCHnomatch; | |
2310 } | |
2311 | |
2312 | |
2313 void TemplateAliasParameter::print(Object *oarg, Object *oded) | |
2314 { | |
2315 printf(" %s\n", ident->toChars()); | |
2316 | |
2317 Dsymbol *sa = isDsymbol(oded); | |
2318 assert(sa); | |
2319 | |
2320 printf("\tArgument alias: %s\n", sa->toChars()); | |
2321 } | |
2322 | |
2323 void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2324 { | |
2325 buf->writestring("alias "); | |
2326 buf->writestring(ident->toChars()); | |
2327 if (specAliasT) | |
2328 { | |
2329 buf->writestring(" : "); | |
2330 specAliasT->toCBuffer(buf, NULL, hgs); | |
2331 } | |
2332 if (defaultAlias) | |
2333 { | |
2334 buf->writestring(" = "); | |
2335 defaultAlias->toCBuffer(buf, NULL, hgs); | |
2336 } | |
2337 } | |
2338 | |
2339 | |
2340 void *TemplateAliasParameter::dummyArg() | |
2341 { Dsymbol *s; | |
2342 | |
2343 s = specAlias; | |
2344 if (!s) | |
2345 { | |
2346 if (!sdummy) | |
2347 sdummy = new Dsymbol(); | |
2348 s = sdummy; | |
2349 } | |
2350 return (void*)s; | |
2351 } | |
2352 | |
2353 | |
2354 Object *TemplateAliasParameter::specialization() | |
2355 { | |
2356 return specAliasT; | |
2357 } | |
2358 | |
2359 | |
2360 Object *TemplateAliasParameter::defaultArg(Scope *sc) | |
2361 { | |
2362 Dsymbol *s = NULL; | |
2363 | |
2364 if (defaultAlias) | |
2365 { | |
2366 s = defaultAlias->toDsymbol(sc); | |
2367 if (!s) | |
2368 error("%s is not a symbol", defaultAlias->toChars()); | |
2369 } | |
2370 return s; | |
2371 } | |
2372 | |
2373 /* ======================== TemplateValueParameter ========================== */ | |
2374 | |
2375 // value-parameter | |
2376 | |
2377 Expression *TemplateValueParameter::edummy = NULL; | |
2378 | |
2379 TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, | |
2380 Expression *specValue, Expression *defaultValue) | |
2381 : TemplateParameter(loc, ident) | |
2382 { | |
2383 this->ident = ident; | |
2384 this->valType = valType; | |
2385 this->specValue = specValue; | |
2386 this->defaultValue = defaultValue; | |
2387 } | |
2388 | |
2389 TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() | |
2390 { | |
2391 return this; | |
2392 } | |
2393 | |
2394 TemplateParameter *TemplateValueParameter::syntaxCopy() | |
2395 { | |
2396 TemplateValueParameter *tp = | |
2397 new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); | |
2398 tp->valType = valType->syntaxCopy(); | |
2399 if (specValue) | |
2400 tp->specValue = specValue->syntaxCopy(); | |
2401 if (defaultValue) | |
2402 tp->defaultValue = defaultValue->syntaxCopy(); | |
2403 return tp; | |
2404 } | |
2405 | |
2406 void TemplateValueParameter::declareParameter(Scope *sc) | |
2407 { | |
2408 VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL); | |
2409 v->storage_class = STCtemplateparameter; | |
2410 if (!sc->insert(v)) | |
2411 error(loc, "parameter '%s' multiply defined", ident->toChars()); | |
2412 sparam = v; | |
2413 } | |
2414 | |
2415 void TemplateValueParameter::semantic(Scope *sc) | |
2416 { | |
2417 sparam->semantic(sc); | |
2418 valType = valType->semantic(loc, sc); | |
2419 if (!(valType->isintegral() || valType->isfloating() || valType->isString()) && | |
2420 valType->ty != Tident) | |
2421 error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); | |
2422 | |
2423 if (specValue) | |
2424 { Expression *e = specValue; | |
2425 | |
2426 e = e->semantic(sc); | |
2427 e = e->implicitCastTo(sc, valType); | |
2428 e = e->optimize(WANTvalue | WANTinterpret); | |
2429 if (e->op == TOKint64 || e->op == TOKfloat64 || | |
2430 e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) | |
2431 specValue = e; | |
2432 //e->toInteger(); | |
2433 } | |
2434 | |
2435 #if 0 // defer semantic analysis to arg match | |
2436 if (defaultValue) | |
2437 { Expression *e = defaultValue; | |
2438 | |
2439 e = e->semantic(sc); | |
2440 e = e->implicitCastTo(sc, valType); | |
2441 e = e->optimize(WANTvalue | WANTinterpret); | |
2442 if (e->op == TOKint64) | |
2443 defaultValue = e; | |
2444 //e->toInteger(); | |
2445 } | |
2446 #endif | |
2447 } | |
2448 | |
2449 int TemplateValueParameter::overloadMatch(TemplateParameter *tp) | |
2450 { | |
2451 TemplateValueParameter *tvp = tp->isTemplateValueParameter(); | |
2452 | |
2453 if (tvp) | |
2454 { | |
2455 if (valType != tvp->valType) | |
2456 goto Lnomatch; | |
2457 | |
2458 if (valType && !valType->equals(tvp->valType)) | |
2459 goto Lnomatch; | |
2460 | |
2461 if (specValue != tvp->specValue) | |
2462 goto Lnomatch; | |
2463 | |
2464 return 1; // match | |
2465 } | |
2466 | |
2467 Lnomatch: | |
2468 return 0; | |
2469 } | |
2470 | |
2471 | |
2472 MATCH TemplateValueParameter::matchArg(Scope *sc, | |
2473 Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, | |
2474 Declaration **psparam) | |
2475 { | |
2476 //printf("TemplateValueParameter::matchArg()\n"); | |
2477 | |
2478 Initializer *init; | |
2479 Declaration *sparam; | |
2480 MATCH m = MATCHexact; | |
2481 Expression *ei; | |
2482 Object *oarg; | |
2483 | |
2484 if (i < tiargs->dim) | |
2485 oarg = (Object *)tiargs->data[i]; | |
2486 else | |
2487 { // Get default argument instead | |
2488 oarg = defaultArg(sc); | |
2489 if (!oarg) | |
2490 { assert(i < dedtypes->dim); | |
2491 // It might have already been deduced | |
2492 oarg = (Object *)dedtypes->data[i]; | |
2493 if (!oarg) | |
2494 goto Lnomatch; | |
2495 } | |
2496 } | |
2497 | |
2498 ei = isExpression(oarg); | |
2499 Type *vt; | |
2500 | |
2501 if (!ei && oarg) | |
2502 goto Lnomatch; | |
2503 | |
2504 if (specValue) | |
2505 { | |
2506 if (!ei || ei == edummy) | |
2507 goto Lnomatch; | |
2508 | |
2509 Expression *e = specValue; | |
2510 | |
2511 e = e->semantic(sc); | |
2512 e = e->implicitCastTo(sc, valType); | |
2513 e = e->optimize(WANTvalue | WANTinterpret); | |
2514 | |
2515 ei = ei->syntaxCopy(); | |
2516 ei = ei->semantic(sc); | |
2517 ei = ei->optimize(WANTvalue | WANTinterpret); | |
2518 //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); | |
2519 //printf("e : %s, %s\n", e->toChars(), e->type->toChars()); | |
2520 if (!ei->equals(e)) | |
2521 goto Lnomatch; | |
2522 } | |
2523 else if (dedtypes->data[i]) | |
2524 { // Must match already deduced value | |
2525 Expression *e = (Expression *)dedtypes->data[i]; | |
2526 | |
2527 if (!ei || !ei->equals(e)) | |
2528 goto Lnomatch; | |
2529 } | |
2530 Lmatch: | |
2531 //printf("valType: %s, ty = %d\n", valType->toChars(), valType->ty); | |
2532 vt = valType->semantic(0, sc); | |
2533 //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); | |
2534 if (ei->type) | |
2535 { | |
2536 m = (MATCH)ei->implicitConvTo(vt); | |
2537 //printf("m: %d\n", m); | |
2538 if (!m) | |
2539 goto Lnomatch; | |
2540 } | |
2541 dedtypes->data[i] = ei; | |
2542 | |
2543 init = new ExpInitializer(loc, ei); | |
2544 sparam = new VarDeclaration(loc, vt, ident, init); | |
2545 sparam->storage_class = STCconst; | |
2546 *psparam = sparam; | |
2547 return m; | |
2548 | |
2549 Lnomatch: | |
2550 //printf("\tno match\n"); | |
2551 *psparam = NULL; | |
2552 return MATCHnomatch; | |
2553 } | |
2554 | |
2555 | |
2556 void TemplateValueParameter::print(Object *oarg, Object *oded) | |
2557 { | |
2558 printf(" %s\n", ident->toChars()); | |
2559 | |
2560 Expression *ea = isExpression(oded); | |
2561 | |
2562 if (specValue) | |
2563 printf("\tSpecialization: %s\n", specValue->toChars()); | |
2564 printf("\tArgument Value: %s\n", ea ? ea->toChars() : "NULL"); | |
2565 } | |
2566 | |
2567 | |
2568 void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2569 { | |
2570 valType->toCBuffer(buf, ident, hgs); | |
2571 if (specValue) | |
2572 { | |
2573 buf->writestring(" : "); | |
2574 specValue->toCBuffer(buf, hgs); | |
2575 } | |
2576 if (defaultValue) | |
2577 { | |
2578 buf->writestring(" = "); | |
2579 defaultValue->toCBuffer(buf, hgs); | |
2580 } | |
2581 } | |
2582 | |
2583 | |
2584 void *TemplateValueParameter::dummyArg() | |
2585 { Expression *e; | |
2586 | |
2587 e = specValue; | |
2588 if (!e) | |
2589 { | |
2590 // Create a dummy value | |
2591 if (!edummy) | |
2592 edummy = valType->defaultInit(); | |
2593 e = edummy; | |
2594 } | |
2595 return (void *)e; | |
2596 } | |
2597 | |
2598 | |
2599 Object *TemplateValueParameter::specialization() | |
2600 { | |
2601 return specValue; | |
2602 } | |
2603 | |
2604 | |
2605 Object *TemplateValueParameter::defaultArg(Scope *sc) | |
2606 { | |
2607 Expression *e = defaultValue; | |
2608 if (e) | |
2609 { | |
2610 e = e->syntaxCopy(); | |
2611 e = e->semantic(sc); | |
2612 #if DMDV2 | |
2613 if (e->op == TOKdefault) | |
2614 { DefaultInitExp *de = (DefaultInitExp *)e; | |
2615 e = de->resolve(loc, sc); | |
2616 } | |
2617 #endif | |
2618 } | |
2619 return e; | |
2620 } | |
2621 | |
2622 /* ======================== TemplateTupleParameter ========================== */ | |
2623 | |
2624 // variadic-parameter | |
2625 | |
2626 TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) | |
2627 : TemplateParameter(loc, ident) | |
2628 { | |
2629 this->ident = ident; | |
2630 } | |
2631 | |
2632 TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() | |
2633 { | |
2634 return this; | |
2635 } | |
2636 | |
2637 TemplateParameter *TemplateTupleParameter::syntaxCopy() | |
2638 { | |
2639 TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); | |
2640 return tp; | |
2641 } | |
2642 | |
2643 void TemplateTupleParameter::declareParameter(Scope *sc) | |
2644 { | |
2645 TypeIdentifier *ti = new TypeIdentifier(loc, ident); | |
2646 sparam = new AliasDeclaration(loc, ident, ti); | |
2647 if (!sc->insert(sparam)) | |
2648 error(loc, "parameter '%s' multiply defined", ident->toChars()); | |
2649 } | |
2650 | |
2651 void TemplateTupleParameter::semantic(Scope *sc) | |
2652 { | |
2653 } | |
2654 | |
2655 int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) | |
2656 { | |
2657 TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); | |
2658 | |
2659 if (tvp) | |
2660 { | |
2661 return 1; // match | |
2662 } | |
2663 | |
2664 Lnomatch: | |
2665 return 0; | |
2666 } | |
2667 | |
2668 MATCH TemplateTupleParameter::matchArg(Scope *sc, | |
2669 Objects *tiargs, int i, TemplateParameters *parameters, | |
2670 Objects *dedtypes, | |
2671 Declaration **psparam) | |
2672 { | |
2673 //printf("TemplateTupleParameter::matchArg()\n"); | |
2674 | |
2675 /* The rest of the actual arguments (tiargs[]) form the match | |
2676 * for the variadic parameter. | |
2677 */ | |
2678 assert(i + 1 == dedtypes->dim); // must be the last one | |
2679 Tuple *ovar; | |
2680 if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i])) | |
2681 ovar = isTuple((Object *)tiargs->data[i]); | |
2682 else | |
2683 { | |
2684 ovar = new Tuple(); | |
2685 //printf("ovar = %p\n", ovar); | |
2686 if (i < tiargs->dim) | |
2687 { | |
2688 //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); | |
2689 ovar->objects.setDim(tiargs->dim - i); | |
2690 for (size_t j = 0; j < ovar->objects.dim; j++) | |
2691 ovar->objects.data[j] = tiargs->data[i + j]; | |
2692 } | |
2693 } | |
2694 *psparam = new TupleDeclaration(loc, ident, &ovar->objects); | |
2695 dedtypes->data[i] = (void *)ovar; | |
2696 return MATCHexact; | |
2697 } | |
2698 | |
2699 | |
2700 void TemplateTupleParameter::print(Object *oarg, Object *oded) | |
2701 { | |
2702 printf(" %s... [", ident->toChars()); | |
2703 Tuple *v = isTuple(oded); | |
2704 assert(v); | |
2705 | |
2706 //printf("|%d| ", v->objects.dim); | |
2707 for (int i = 0; i < v->objects.dim; i++) | |
2708 { | |
2709 if (i) | |
2710 printf(", "); | |
2711 | |
2712 Object *o = (Object *)v->objects.data[i]; | |
2713 | |
2714 Dsymbol *sa = isDsymbol(o); | |
2715 if (sa) | |
2716 printf("alias: %s", sa->toChars()); | |
2717 | |
2718 Type *ta = isType(o); | |
2719 if (ta) | |
2720 printf("type: %s", ta->toChars()); | |
2721 | |
2722 Expression *ea = isExpression(o); | |
2723 if (ea) | |
2724 printf("exp: %s", ea->toChars()); | |
2725 | |
2726 assert(!isTuple(o)); // no nested Tuple arguments | |
2727 } | |
2728 | |
2729 printf("]\n"); | |
2730 } | |
2731 | |
2732 void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2733 { | |
2734 buf->writestring(ident->toChars()); | |
2735 buf->writestring("..."); | |
2736 } | |
2737 | |
2738 | |
2739 void *TemplateTupleParameter::dummyArg() | |
2740 { | |
2741 return NULL; | |
2742 } | |
2743 | |
2744 | |
2745 Object *TemplateTupleParameter::specialization() | |
2746 { | |
2747 return NULL; | |
2748 } | |
2749 | |
2750 | |
2751 Object *TemplateTupleParameter::defaultArg(Scope *sc) | |
2752 { | |
2753 return NULL; | |
2754 } | |
2755 | |
2756 /* ======================== TemplateInstance ================================ */ | |
2757 | |
2758 TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) | |
2759 : ScopeDsymbol(NULL) | |
2760 { | |
2761 #if LOG | |
2762 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null"); | |
2763 #endif | |
2764 this->loc = loc; | |
2765 this->name = ident; | |
2766 this->tiargs = NULL; | |
2767 this->tempdecl = NULL; | |
2768 this->inst = NULL; | |
2769 this->argsym = NULL; | |
2770 this->aliasdecl = NULL; | |
2771 this->semanticdone = 0; | |
2772 this->semantictiargsdone = 0; | |
2773 this->withsym = NULL; | |
2774 this->nest = 0; | |
2775 this->havetempdecl = 0; | |
2776 this->isnested = NULL; | |
2777 this->errors = 0; | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
2778 this->tinst = NULL; |
336 | 2779 } |
2780 | |
2781 | |
2782 TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) | |
2783 : ScopeDsymbol(NULL) | |
2784 { | |
2785 #if LOG | |
2786 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); | |
2787 #endif | |
2788 this->loc = loc; | |
2789 this->name = td->ident; | |
2790 this->tiargs = tiargs; | |
2791 this->tempdecl = td; | |
2792 this->inst = NULL; | |
2793 this->argsym = NULL; | |
2794 this->aliasdecl = NULL; | |
2795 this->semanticdone = 0; | |
2796 this->semantictiargsdone = 1; | |
2797 this->withsym = NULL; | |
2798 this->nest = 0; | |
2799 this->havetempdecl = 1; | |
2800 this->isnested = NULL; | |
2801 this->errors = 0; | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
2802 this->tinst = NULL; |
336 | 2803 |
2804 assert((size_t)tempdecl->scope > 0x10000); | |
2805 } | |
2806 | |
2807 | |
2808 Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) | |
2809 { | |
2810 Objects *a = NULL; | |
2811 if (objs) | |
2812 { a = new Objects(); | |
2813 a->setDim(objs->dim); | |
2814 for (size_t i = 0; i < objs->dim; i++) | |
2815 { | |
2816 Type *ta = isType((Object *)objs->data[i]); | |
2817 if (ta) | |
2818 a->data[i] = ta->syntaxCopy(); | |
2819 else | |
2820 { | |
2821 Expression *ea = isExpression((Object *)objs->data[i]); | |
2822 assert(ea); | |
2823 a->data[i] = ea->syntaxCopy(); | |
2824 } | |
2825 } | |
2826 } | |
2827 return a; | |
2828 } | |
2829 | |
2830 Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) | |
2831 { | |
2832 TemplateInstance *ti; | |
2833 int i; | |
2834 | |
2835 if (s) | |
2836 ti = (TemplateInstance *)s; | |
2837 else | |
2838 ti = new TemplateInstance(loc, name); | |
2839 | |
2840 ti->tiargs = arraySyntaxCopy(tiargs); | |
2841 | |
2842 ScopeDsymbol::syntaxCopy(ti); | |
2843 return ti; | |
2844 } | |
2845 | |
2846 | |
2847 void TemplateInstance::semantic(Scope *sc) | |
2848 { | |
2849 if (global.errors) | |
2850 { | |
2851 if (!global.gag) | |
2852 { | |
2853 /* Trying to soldier on rarely generates useful messages | |
2854 * at this point. | |
2855 */ | |
2856 fatal(); | |
2857 } | |
2858 return; | |
2859 } | |
2860 #if LOG | |
2861 printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); | |
2862 #endif | |
2863 if (inst) // if semantic() was already run | |
2864 { | |
2865 #if LOG | |
2866 printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); | |
2867 #endif | |
2868 return; | |
2869 } | |
2870 | |
2871 if (semanticdone != 0) | |
2872 { | |
2873 error(loc, "recursive template expansion"); | |
2874 // inst = this; | |
2875 return; | |
2876 } | |
2877 semanticdone = 1; | |
2878 | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
2879 // get the enclosing template instance from the scope tinst |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
2880 tinst = sc->tinst; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
2881 |
336 | 2882 #if LOG |
2883 printf("\tdo semantic\n"); | |
2884 #endif | |
2885 if (havetempdecl) | |
2886 { | |
2887 assert((size_t)tempdecl->scope > 0x10000); | |
2888 // Deduce tdtypes | |
2889 tdtypes.setDim(tempdecl->parameters->dim); | |
2890 if (!tempdecl->matchWithInstance(this, &tdtypes, 0)) | |
2891 { | |
2892 error("incompatible arguments for template instantiation"); | |
2893 inst = this; | |
2894 return; | |
2895 } | |
2896 } | |
2897 else | |
2898 { | |
2899 // Run semantic on each argument, place results in tiargs[] | |
2900 semanticTiargs(sc); | |
2901 | |
2902 tempdecl = findTemplateDeclaration(sc); | |
2903 if (tempdecl) | |
2904 tempdecl = findBestMatch(sc); | |
2905 if (!tempdecl || global.errors) | |
2906 { inst = this; | |
2907 //printf("error return %p, %d\n", tempdecl, global.errors); | |
2908 return; // error recovery | |
2909 } | |
2910 } | |
2911 | |
2912 isNested(tiargs); | |
2913 | |
2914 /* See if there is an existing TemplateInstantiation that already | |
2915 * implements the typeargs. If so, just refer to that one instead. | |
2916 */ | |
2917 | |
2918 for (size_t i = 0; i < tempdecl->instances.dim; i++) | |
2919 { | |
2920 TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i]; | |
2921 #if LOG | |
2922 printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); | |
2923 #endif | |
2924 assert(tdtypes.dim == ti->tdtypes.dim); | |
2925 | |
2926 // Nesting must match | |
2927 if (isnested != ti->isnested) | |
2928 continue; | |
2929 #if 0 | |
2930 if (isnested && sc->parent != ti->parent) | |
2931 continue; | |
2932 #endif | |
2933 for (size_t j = 0; j < tdtypes.dim; j++) | |
2934 { Object *o1 = (Object *)tdtypes.data[j]; | |
2935 Object *o2 = (Object *)ti->tdtypes.data[j]; | |
2936 if (!match(o1, o2, tempdecl, sc)) | |
2937 goto L1; | |
2938 } | |
2939 | |
2940 // It's a match | |
2941 inst = ti; | |
2942 parent = ti->parent; | |
2943 #if LOG | |
2944 printf("\tit's a match with instance %p\n", inst); | |
2945 #endif | |
2946 return; | |
2947 | |
2948 L1: | |
2949 ; | |
2950 } | |
2951 | |
2952 /* So, we need to implement 'this' instance. | |
2953 */ | |
2954 #if LOG | |
2955 printf("\timplement template instance '%s'\n", toChars()); | |
2956 #endif | |
2957 unsigned errorsave = global.errors; | |
2958 inst = this; | |
2959 int tempdecl_instance_idx = tempdecl->instances.dim; | |
2960 tempdecl->instances.push(this); | |
2961 parent = tempdecl->parent; | |
2962 //printf("parent = '%s'\n", parent->kind()); | |
2963 | |
2964 ident = genIdent(); // need an identifier for name mangling purposes. | |
2965 | |
2966 #if 1 | |
2967 if (isnested) | |
2968 parent = isnested; | |
2969 #endif | |
2970 //printf("parent = '%s'\n", parent->kind()); | |
2971 | |
2972 // Add 'this' to the enclosing scope's members[] so the semantic routines | |
2973 // will get called on the instance members | |
2974 #if 1 | |
2975 int dosemantic3 = 0; | |
2976 { Array *a; | |
2977 int i; | |
2978 | |
2979 if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin()) | |
2980 { | |
2981 //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars()); | |
2982 a = sc->scopesym->members; | |
2983 } | |
2984 else | |
2985 { Module *m = sc->module->importedFrom; | |
2986 //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); | |
2987 a = m->members; | |
2988 if (m->semanticdone >= 3) | |
2989 dosemantic3 = 1; | |
2990 } | |
2991 for (int i = 0; 1; i++) | |
2992 { | |
2993 if (i == a->dim) | |
2994 { | |
2995 a->push(this); | |
2996 break; | |
2997 } | |
2998 if (this == (Dsymbol *)a->data[i]) // if already in Array | |
2999 break; | |
3000 } | |
3001 } | |
3002 #endif | |
3003 | |
3004 // Copy the syntax trees from the TemplateDeclaration | |
3005 members = Dsymbol::arraySyntaxCopy(tempdecl->members); | |
3006 | |
3007 // Create our own scope for the template parameters | |
3008 Scope *scope = tempdecl->scope; | |
3009 if (!scope) | |
3010 { | |
3011 error("forward reference to template declaration %s\n", tempdecl->toChars()); | |
3012 return; | |
3013 } | |
3014 | |
3015 #if LOG | |
3016 printf("\tcreate scope for template parameters '%s'\n", toChars()); | |
3017 #endif | |
3018 argsym = new ScopeDsymbol(); | |
3019 argsym->parent = scope->parent; | |
3020 scope = scope->push(argsym); | |
3021 | |
3022 // Declare each template parameter as an alias for the argument type | |
3023 declareParameters(scope); | |
3024 | |
3025 // Add members of template instance to template instance symbol table | |
3026 // parent = scope->scopesym; | |
3027 symtab = new DsymbolTable(); | |
3028 int memnum = 0; | |
3029 for (int i = 0; i < members->dim; i++) | |
3030 { | |
3031 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3032 #if LOG | |
3033 printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); | |
3034 #endif | |
3035 memnum |= s->addMember(scope, this, memnum); | |
3036 } | |
3037 #if LOG | |
3038 printf("adding members done\n"); | |
3039 #endif | |
3040 | |
3041 /* See if there is only one member of template instance, and that | |
3042 * member has the same name as the template instance. | |
3043 * If so, this template instance becomes an alias for that member. | |
3044 */ | |
3045 //printf("members->dim = %d\n", members->dim); | |
3046 if (members->dim) | |
3047 { | |
3048 Dsymbol *s; | |
3049 if (Dsymbol::oneMembers(members, &s) && s) | |
3050 { | |
3051 //printf("s->kind = '%s'\n", s->kind()); | |
3052 //s->print(); | |
3053 //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); | |
3054 if (s->ident && s->ident->equals(tempdecl->ident)) | |
3055 { | |
3056 //printf("setting aliasdecl\n"); | |
3057 aliasdecl = new AliasDeclaration(loc, s->ident, s); | |
3058 } | |
3059 } | |
3060 } | |
3061 | |
3062 // Do semantic() analysis on template instance members | |
3063 #if LOG | |
3064 printf("\tdo semantic() on template instance members '%s'\n", toChars()); | |
3065 #endif | |
3066 Scope *sc2; | |
3067 sc2 = scope->push(this); | |
3068 //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); | |
3069 sc2->parent = /*isnested ? sc->parent :*/ this; | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3070 sc2->tinst = this; |
336 | 3071 |
3072 #if !IN_LLVM | |
3073 #if _WIN32 | |
3074 __try | |
3075 { | |
3076 #endif | |
3077 #endif | |
3078 for (int i = 0; i < members->dim; i++) | |
3079 { | |
3080 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3081 //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); | |
3082 //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); | |
3083 // if (isnested) | |
3084 // s->parent = sc->parent; | |
3085 //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); | |
3086 s->semantic(sc2); | |
3087 //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); | |
3088 sc2->module->runDeferredSemantic(); | |
3089 } | |
3090 #if !IN_LLVM | |
3091 #if _WIN32 | |
3092 } | |
3093 __except (__ehfilter(GetExceptionInformation())) | |
3094 { | |
3095 global.gag = 0; // ensure error message gets printed | |
3096 error("recursive expansion"); | |
3097 fatal(); | |
3098 } | |
3099 #endif | |
3100 #endif | |
3101 | |
3102 /* If any of the instantiation members didn't get semantic() run | |
3103 * on them due to forward references, we cannot run semantic2() | |
3104 * or semantic3() yet. | |
3105 */ | |
3106 for (size_t i = 0; i < Module::deferred.dim; i++) | |
3107 { Dsymbol *sd = (Dsymbol *)Module::deferred.data[i]; | |
3108 | |
3109 if (sd->parent == this) | |
3110 goto Laftersemantic; | |
3111 } | |
3112 | |
3113 /* The problem is when to parse the initializer for a variable. | |
3114 * Perhaps VarDeclaration::semantic() should do it like it does | |
3115 * for initializers inside a function. | |
3116 */ | |
3117 // if (sc->parent->isFuncDeclaration()) | |
3118 | |
3119 /* BUG 782: this has problems if the classes this depends on | |
3120 * are forward referenced. Find a way to defer semantic() | |
3121 * on this template. | |
3122 */ | |
3123 semantic2(sc2); | |
3124 | |
3125 if (sc->func || dosemantic3) | |
3126 { | |
3127 semantic3(sc2); | |
3128 } | |
3129 | |
3130 Laftersemantic: | |
3131 sc2->pop(); | |
3132 | |
3133 scope->pop(); | |
3134 | |
3135 // Give additional context info if error occurred during instantiation | |
3136 if (global.errors != errorsave) | |
3137 { | |
3138 error("error instantiating"); | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3139 if(tinst) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3140 tinst->printInstantiationTrace(); |
336 | 3141 errors = 1; |
3142 if (global.gag) | |
3143 tempdecl->instances.remove(tempdecl_instance_idx); | |
3144 } | |
3145 | |
3146 #if LOG | |
3147 printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); | |
3148 #endif | |
3149 } | |
3150 | |
3151 | |
3152 void TemplateInstance::semanticTiargs(Scope *sc) | |
3153 { | |
3154 //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); | |
3155 if (semantictiargsdone) | |
3156 return; | |
3157 semantictiargsdone = 1; | |
3158 semanticTiargs(loc, sc, tiargs); | |
3159 } | |
3160 | |
3161 void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs) | |
3162 { | |
3163 // Run semantic on each argument, place results in tiargs[] | |
3164 //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); | |
3165 if (!tiargs) | |
3166 return; | |
3167 for (size_t j = 0; j < tiargs->dim; j++) | |
3168 { | |
3169 Object *o = (Object *)tiargs->data[j]; | |
3170 Type *ta = isType(o); | |
3171 Expression *ea = isExpression(o); | |
3172 Dsymbol *sa = isDsymbol(o); | |
3173 | |
3174 //printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); | |
3175 if (ta) | |
3176 { | |
3177 //printf("type %s\n", ta->toChars()); | |
3178 // It might really be an Expression or an Alias | |
3179 ta->resolve(loc, sc, &ea, &ta, &sa); | |
3180 if (ea) | |
3181 { | |
3182 ea = ea->semantic(sc); | |
3183 ea = ea->optimize(WANTvalue | WANTinterpret); | |
3184 tiargs->data[j] = ea; | |
3185 } | |
3186 else if (sa) | |
3187 { tiargs->data[j] = sa; | |
3188 TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); | |
3189 if (d) | |
3190 { | |
3191 size_t dim = d->objects->dim; | |
3192 tiargs->remove(j); | |
3193 tiargs->insert(j, d->objects); | |
3194 j--; | |
3195 } | |
3196 } | |
3197 else if (ta) | |
3198 { | |
3199 if (ta->ty == Ttuple) | |
3200 { // Expand tuple | |
3201 TypeTuple *tt = (TypeTuple *)ta; | |
3202 size_t dim = tt->arguments->dim; | |
3203 tiargs->remove(j); | |
3204 if (dim) | |
3205 { tiargs->reserve(dim); | |
3206 for (size_t i = 0; i < dim; i++) | |
3207 { Argument *arg = (Argument *)tt->arguments->data[i]; | |
3208 tiargs->insert(j + i, arg->type); | |
3209 } | |
3210 } | |
3211 j--; | |
3212 } | |
3213 else | |
3214 tiargs->data[j] = ta; | |
3215 } | |
3216 else | |
3217 { | |
3218 assert(global.errors); | |
3219 tiargs->data[j] = Type::terror; | |
3220 } | |
3221 } | |
3222 else if (ea) | |
3223 { | |
3224 if (!ea) | |
3225 { assert(global.errors); | |
3226 ea = new IntegerExp(0); | |
3227 } | |
3228 assert(ea); | |
3229 ea = ea->semantic(sc); | |
3230 ea = ea->optimize(WANTvalue | WANTinterpret); | |
3231 tiargs->data[j] = ea; | |
3232 if (ea->op == TOKtype) | |
3233 tiargs->data[j] = ea->type; | |
3234 } | |
3235 else if (sa) | |
3236 { | |
3237 } | |
3238 else | |
3239 { | |
3240 assert(0); | |
3241 } | |
3242 //printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]); | |
3243 } | |
3244 #if 0 | |
3245 printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this); | |
3246 for (size_t j = 0; j < tiargs->dim; j++) | |
3247 { | |
3248 Object *o = (Object *)tiargs->data[j]; | |
3249 Type *ta = isType(o); | |
3250 Expression *ea = isExpression(o); | |
3251 Dsymbol *sa = isDsymbol(o); | |
3252 Tuple *va = isTuple(o); | |
3253 | |
3254 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); | |
3255 } | |
3256 #endif | |
3257 } | |
3258 | |
3259 /********************************************** | |
3260 * Find template declaration corresponding to template instance. | |
3261 */ | |
3262 | |
3263 TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) | |
3264 { | |
3265 //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); | |
3266 if (!tempdecl) | |
3267 { | |
3268 /* Given: | |
3269 * foo!( ... ) | |
3270 * figure out which TemplateDeclaration foo refers to. | |
3271 */ | |
3272 Dsymbol *s; | |
3273 Dsymbol *scopesym; | |
3274 Identifier *id; | |
3275 int i; | |
3276 | |
3277 id = name; | |
3278 s = sc->search(loc, id, &scopesym); | |
3279 if (!s) | |
3280 { error("identifier '%s' is not defined", id->toChars()); | |
3281 return NULL; | |
3282 } | |
3283 #if LOG | |
3284 printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); | |
3285 if (s->parent) | |
3286 printf("s->parent = '%s'\n", s->parent->toChars()); | |
3287 #endif | |
3288 withsym = scopesym->isWithScopeSymbol(); | |
3289 | |
3290 /* We might have found an alias within a template when | |
3291 * we really want the template. | |
3292 */ | |
3293 TemplateInstance *ti; | |
3294 if (s->parent && | |
3295 (ti = s->parent->isTemplateInstance()) != NULL) | |
3296 { | |
3297 if ( | |
3298 (ti->name == id || | |
3299 ti->toAlias()->ident == id) | |
3300 && | |
3301 ti->tempdecl) | |
3302 { | |
3303 /* This is so that one can refer to the enclosing | |
3304 * template, even if it has the same name as a member | |
3305 * of the template, if it has a !(arguments) | |
3306 */ | |
3307 tempdecl = ti->tempdecl; | |
3308 if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's | |
3309 tempdecl = tempdecl->overroot; // then get the start | |
3310 s = tempdecl; | |
3311 } | |
3312 } | |
3313 | |
3314 s = s->toAlias(); | |
3315 | |
3316 /* It should be a TemplateDeclaration, not some other symbol | |
3317 */ | |
3318 tempdecl = s->isTemplateDeclaration(); | |
3319 if (!tempdecl) | |
3320 { | |
3321 if (!s->parent && global.errors) | |
3322 return NULL; | |
3323 if (!s->parent && s->getType()) | |
3324 { Dsymbol *s2 = s->getType()->toDsymbol(sc); | |
3325 if (!s2) | |
3326 { | |
3327 error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); | |
3328 return NULL; | |
3329 } | |
3330 s = s2; | |
3331 } | |
3332 #ifdef DEBUG | |
3333 //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); | |
3334 #endif | |
3335 //assert(s->parent); | |
3336 TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; | |
3337 if (ti && | |
3338 (ti->name == id || | |
3339 ti->toAlias()->ident == id) | |
3340 && | |
3341 ti->tempdecl) | |
3342 { | |
3343 /* This is so that one can refer to the enclosing | |
3344 * template, even if it has the same name as a member | |
3345 * of the template, if it has a !(arguments) | |
3346 */ | |
3347 tempdecl = ti->tempdecl; | |
3348 if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's | |
3349 tempdecl = tempdecl->overroot; // then get the start | |
3350 } | |
3351 else | |
3352 { | |
3353 error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); | |
3354 return NULL; | |
3355 } | |
3356 } | |
3357 } | |
3358 else | |
3359 assert(tempdecl->isTemplateDeclaration()); | |
3360 return tempdecl; | |
3361 } | |
3362 | |
3363 TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) | |
3364 { | |
3365 /* Since there can be multiple TemplateDeclaration's with the same | |
3366 * name, look for the best match. | |
3367 */ | |
3368 TemplateDeclaration *td_ambig = NULL; | |
3369 TemplateDeclaration *td_best = NULL; | |
3370 MATCH m_best = MATCHnomatch; | |
3371 Objects dedtypes; | |
3372 | |
3373 #if LOG | |
3374 printf("TemplateInstance::findBestMatch()\n"); | |
3375 #endif | |
3376 for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) | |
3377 { | |
3378 MATCH m; | |
3379 | |
3380 //if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->data[0]); | |
3381 | |
3382 // If more arguments than parameters, | |
3383 // then this is no match. | |
3384 if (td->parameters->dim < tiargs->dim) | |
3385 { | |
3386 if (!td->isVariadic()) | |
3387 continue; | |
3388 } | |
3389 | |
3390 dedtypes.setDim(td->parameters->dim); | |
3391 dedtypes.zero(); | |
3392 if (!td->scope) | |
3393 { | |
3394 error("forward reference to template declaration %s", td->toChars()); | |
3395 return NULL; | |
3396 } | |
3397 m = td->matchWithInstance(this, &dedtypes, 0); | |
3398 //printf("m = %d\n", m); | |
3399 if (!m) // no match at all | |
3400 continue; | |
3401 | |
3402 #if 1 | |
3403 if (m < m_best) | |
3404 goto Ltd_best; | |
3405 if (m > m_best) | |
3406 goto Ltd; | |
3407 #else | |
3408 if (!m_best) | |
3409 goto Ltd; | |
3410 #endif | |
3411 { | |
3412 // Disambiguate by picking the most specialized TemplateDeclaration | |
3413 int c1 = td->leastAsSpecialized(td_best); | |
3414 int c2 = td_best->leastAsSpecialized(td); | |
3415 //printf("c1 = %d, c2 = %d\n", c1, c2); | |
3416 | |
3417 if (c1 > c2) | |
3418 goto Ltd; | |
3419 else if (c1 < c2) | |
3420 goto Ltd_best; | |
3421 else | |
3422 goto Lambig; | |
3423 } | |
3424 | |
3425 Lambig: // td_best and td are ambiguous | |
3426 td_ambig = td; | |
3427 continue; | |
3428 | |
3429 Ltd_best: // td_best is the best match so far | |
3430 td_ambig = NULL; | |
3431 continue; | |
3432 | |
3433 Ltd: // td is the new best match | |
3434 td_ambig = NULL; | |
3435 td_best = td; | |
3436 m_best = m; | |
3437 tdtypes.setDim(dedtypes.dim); | |
3438 memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *)); | |
3439 continue; | |
3440 } | |
3441 | |
3442 if (!td_best) | |
3443 { | |
3444 error("%s does not match any template declaration", toChars()); | |
3445 return NULL; | |
3446 } | |
3447 if (td_ambig) | |
3448 { | |
3449 error("%s matches more than one template declaration, %s and %s", | |
3450 toChars(), td_best->toChars(), td_ambig->toChars()); | |
3451 } | |
3452 | |
3453 /* The best match is td_best | |
3454 */ | |
3455 tempdecl = td_best; | |
3456 | |
3457 #if 0 | |
3458 /* Cast any value arguments to be same type as value parameter | |
3459 */ | |
3460 for (size_t i = 0; i < tiargs->dim; i++) | |
3461 { Object *o = (Object *)tiargs->data[i]; | |
3462 Expression *ea = isExpression(o); // value argument | |
3463 TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; | |
3464 assert(tp); | |
3465 TemplateValueParameter *tvp = tp->isTemplateValueParameter(); | |
3466 if (tvp) | |
3467 { | |
3468 assert(ea); | |
3469 ea = ea->castTo(tvp->valType); | |
3470 ea = ea->optimize(WANTvalue | WANTinterpret); | |
3471 tiargs->data[i] = (Object *)ea; | |
3472 } | |
3473 } | |
3474 #endif | |
3475 | |
3476 #if LOG | |
3477 printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); | |
3478 #endif | |
3479 return tempdecl; | |
3480 } | |
3481 | |
3482 | |
3483 /***************************************** | |
3484 * Determines if a TemplateInstance will need a nested | |
3485 * generation of the TemplateDeclaration. | |
3486 */ | |
3487 | |
3488 int TemplateInstance::isNested(Objects *args) | |
3489 { int nested = 0; | |
3490 //printf("TemplateInstance::isNested('%s')\n", tempdecl->ident->toChars()); | |
3491 | |
3492 /* A nested instance happens when an argument references a local | |
3493 * symbol that is on the stack. | |
3494 */ | |
3495 for (size_t i = 0; i < args->dim; i++) | |
3496 { Object *o = (Object *)args->data[i]; | |
3497 Expression *ea = isExpression(o); | |
3498 Dsymbol *sa = isDsymbol(o); | |
3499 Tuple *va = isTuple(o); | |
3500 if (ea) | |
3501 { | |
3502 if (ea->op == TOKvar) | |
3503 { | |
3504 sa = ((VarExp *)ea)->var; | |
3505 goto Lsa; | |
3506 } | |
3507 if (ea->op == TOKfunction) | |
3508 { | |
3509 sa = ((FuncExp *)ea)->fd; | |
3510 goto Lsa; | |
3511 } | |
3512 } | |
3513 else if (sa) | |
3514 { | |
3515 Lsa: | |
3516 Declaration *d = sa->isDeclaration(); | |
3517 if (d && !d->isDataseg() && | |
3518 #if DMDV2 | |
3519 !(d->storage_class & STCmanifest) && | |
3520 #endif | |
3521 (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && | |
3522 !isTemplateMixin()) | |
3523 { | |
3524 // if module level template | |
3525 if (tempdecl->toParent()->isModule()) | |
3526 { Dsymbol *dparent = d->toParent(); | |
3527 if (!isnested) | |
3528 isnested = dparent; | |
3529 else if (isnested != dparent) | |
3530 { | |
3531 /* Select the more deeply nested of the two. | |
3532 * Error if one is not nested inside the other. | |
3533 */ | |
3534 for (Dsymbol *p = isnested; p; p = p->parent) | |
3535 { | |
3536 if (p == dparent) | |
3537 goto L1; // isnested is most nested | |
3538 } | |
3539 for (Dsymbol *p = dparent; 1; p = p->parent) | |
3540 { | |
3541 if (p == isnested) | |
3542 { isnested = dparent; | |
3543 goto L1; // dparent is most nested | |
3544 } | |
3545 } | |
3546 error("is nested in both %s and %s", isnested->toChars(), dparent->toChars()); | |
3547 } | |
3548 L1: | |
3549 //printf("\tnested inside %s\n", isnested->toChars()); | |
3550 nested |= 1; | |
3551 } | |
3552 else | |
3553 error("cannot use local '%s' as template parameter", d->toChars()); | |
3554 } | |
3555 } | |
3556 else if (va) | |
3557 { | |
3558 nested |= isNested(&va->objects); | |
3559 } | |
3560 } | |
3561 return nested; | |
3562 } | |
3563 | |
3564 /**************************************** | |
3565 * This instance needs an identifier for name mangling purposes. | |
3566 * Create one by taking the template declaration name and adding | |
3567 * the type signature for it. | |
3568 */ | |
3569 | |
3570 Identifier *TemplateInstance::genIdent() | |
3571 { OutBuffer buf; | |
3572 char *id; | |
3573 Objects *args; | |
3574 | |
3575 //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); | |
3576 id = tempdecl->ident->toChars(); | |
3577 buf.printf("__T%"PRIuSIZE"%s", strlen(id), id); | |
3578 args = tiargs; | |
3579 for (int i = 0; i < args->dim; i++) | |
3580 { Object *o = (Object *)args->data[i]; | |
3581 Type *ta = isType(o); | |
3582 Expression *ea = isExpression(o); | |
3583 Dsymbol *sa = isDsymbol(o); | |
3584 Tuple *va = isTuple(o); | |
3585 //printf("\to %p ta %p ea %p sa %p va %p\n", o, ta, ea, sa, va); | |
3586 if (ta) | |
3587 { | |
3588 buf.writeByte('T'); | |
3589 if (ta->deco) | |
3590 buf.writestring(ta->deco); | |
3591 else | |
3592 { | |
3593 #ifdef DEBUG | |
3594 printf("ta = %d, %s\n", ta->ty, ta->toChars()); | |
3595 #endif | |
3596 assert(global.errors); | |
3597 } | |
3598 } | |
3599 else if (ea) | |
3600 { sinteger_t v; | |
3601 real_t r; | |
3602 | |
3603 if (ea->op == TOKvar) | |
3604 { | |
3605 sa = ((VarExp *)ea)->var; | |
3606 ea = NULL; | |
3607 goto Lsa; | |
3608 } | |
3609 if (ea->op == TOKfunction) | |
3610 { | |
3611 sa = ((FuncExp *)ea)->fd; | |
3612 ea = NULL; | |
3613 goto Lsa; | |
3614 } | |
3615 buf.writeByte('V'); | |
3616 if (ea->op == TOKtuple) | |
3617 { ea->error("tuple is not a valid template value argument"); | |
3618 continue; | |
3619 } | |
3620 #if 1 | |
3621 /* Use deco that matches what it would be for a function parameter | |
3622 */ | |
3623 buf.writestring(ea->type->deco); | |
3624 #else | |
3625 // Use type of parameter, not type of argument | |
3626 TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; | |
3627 assert(tp); | |
3628 TemplateValueParameter *tvp = tp->isTemplateValueParameter(); | |
3629 assert(tvp); | |
3630 buf.writestring(tvp->valType->deco); | |
3631 #endif | |
3632 ea->toMangleBuffer(&buf); | |
3633 } | |
3634 else if (sa) | |
3635 { | |
3636 Lsa: | |
3637 buf.writeByte('S'); | |
3638 Declaration *d = sa->isDeclaration(); | |
3639 if (d && !d->type->deco) | |
3640 error("forward reference of %s", d->toChars()); | |
3641 else | |
3642 { | |
3643 char *p = sa->mangle(); | |
3644 buf.printf("%"PRIuSIZE"%s", strlen(p), p); | |
3645 } | |
3646 } | |
3647 else if (va) | |
3648 { | |
3649 assert(i + 1 == args->dim); // must be last one | |
3650 args = &va->objects; | |
3651 i = -1; | |
3652 } | |
3653 else | |
3654 assert(0); | |
3655 } | |
3656 buf.writeByte('Z'); | |
3657 id = buf.toChars(); | |
3658 buf.data = NULL; | |
3659 return new Identifier(id, TOKidentifier); | |
3660 } | |
3661 | |
3662 | |
3663 /**************************************************** | |
3664 * Declare parameters of template instance, initialize them with the | |
3665 * template instance arguments. | |
3666 */ | |
3667 | |
3668 void TemplateInstance::declareParameters(Scope *scope) | |
3669 { | |
3670 //printf("TemplateInstance::declareParameters()\n"); | |
3671 for (int i = 0; i < tdtypes.dim; i++) | |
3672 { | |
3673 TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; | |
3674 //Object *o = (Object *)tiargs->data[i]; | |
3675 Object *o = (Object *)tdtypes.data[i]; | |
3676 | |
3677 //printf("\ttdtypes[%d] = %p\n", i, o); | |
3678 tempdecl->declareParameter(scope, tp, o); | |
3679 } | |
3680 } | |
3681 | |
3682 | |
3683 void TemplateInstance::semantic2(Scope *sc) | |
3684 { int i; | |
3685 | |
3686 if (semanticdone >= 2) | |
3687 return; | |
3688 semanticdone = 2; | |
3689 #if LOG | |
3690 printf("+TemplateInstance::semantic2('%s')\n", toChars()); | |
3691 #endif | |
3692 if (!errors && members) | |
3693 { | |
3694 sc = tempdecl->scope; | |
3695 assert(sc); | |
3696 sc = sc->push(argsym); | |
3697 sc = sc->push(this); | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3698 sc->tinst = this; |
336 | 3699 for (i = 0; i < members->dim; i++) |
3700 { | |
3701 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3702 #if LOG | |
3703 printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); | |
3704 #endif | |
3705 s->semantic2(sc); | |
3706 } | |
3707 sc = sc->pop(); | |
3708 sc->pop(); | |
3709 } | |
3710 #if LOG | |
3711 printf("-TemplateInstance::semantic2('%s')\n", toChars()); | |
3712 #endif | |
3713 } | |
3714 | |
3715 void TemplateInstance::semantic3(Scope *sc) | |
3716 { | |
3717 #if LOG | |
3718 printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone); | |
3719 #endif | |
3720 //if (toChars()[0] == 'D') *(char*)0=0; | |
3721 if (semanticdone >= 3) | |
3722 return; | |
3723 semanticdone = 3; | |
3724 if (!errors && members) | |
3725 { | |
3726 sc = tempdecl->scope; | |
3727 sc = sc->push(argsym); | |
3728 sc = sc->push(this); | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3729 sc->tinst = this; |
336 | 3730 for (int i = 0; i < members->dim; i++) |
3731 { | |
3732 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3733 s->semantic3(sc); | |
3734 } | |
3735 sc = sc->pop(); | |
3736 sc->pop(); | |
3737 } | |
3738 } | |
3739 | |
3740 void TemplateInstance::toObjFile(int multiobj) | |
3741 { | |
3742 #if LOG | |
3743 printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); | |
3744 #endif | |
3745 if (!errors && members) | |
3746 { | |
3747 if (multiobj) | |
3748 // Append to list of object files to be written later | |
3749 //obj_append(this); | |
3750 assert(0 && "multiobj"); | |
3751 else | |
3752 { | |
3753 for (int i = 0; i < members->dim; i++) | |
3754 { | |
3755 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3756 s->toObjFile(multiobj); | |
3757 } | |
3758 } | |
3759 } | |
3760 } | |
3761 | |
3762 void TemplateInstance::inlineScan() | |
3763 { | |
3764 #if LOG | |
3765 printf("TemplateInstance::inlineScan('%s')\n", toChars()); | |
3766 #endif | |
3767 if (!errors && members) | |
3768 { | |
3769 for (int i = 0; i < members->dim; i++) | |
3770 { | |
3771 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3772 s->inlineScan(); | |
3773 } | |
3774 } | |
3775 } | |
3776 | |
3777 void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3778 { | |
3779 int i; | |
3780 | |
3781 Identifier *id = name; | |
3782 buf->writestring(id->toChars()); | |
3783 buf->writestring("!("); | |
3784 if (nest) | |
3785 buf->writestring("..."); | |
3786 else | |
3787 { | |
3788 nest++; | |
3789 Objects *args = tiargs; | |
3790 for (i = 0; i < args->dim; i++) | |
3791 { | |
3792 if (i) | |
3793 buf->writeByte(','); | |
3794 Object *oarg = (Object *)args->data[i]; | |
3795 ObjectToCBuffer(buf, hgs, oarg); | |
3796 } | |
3797 nest--; | |
3798 } | |
3799 buf->writeByte(')'); | |
3800 } | |
3801 | |
3802 | |
3803 Dsymbol *TemplateInstance::toAlias() | |
3804 { | |
3805 #if LOG | |
3806 printf("TemplateInstance::toAlias()\n"); | |
3807 #endif | |
3808 if (!inst) | |
3809 { error("cannot resolve forward reference"); | |
3810 return this; | |
3811 } | |
3812 | |
3813 if (inst != this) | |
3814 return inst->toAlias(); | |
3815 | |
3816 if (aliasdecl) | |
3817 return aliasdecl->toAlias(); | |
3818 | |
3819 return inst; | |
3820 } | |
3821 | |
3822 AliasDeclaration *TemplateInstance::isAliasDeclaration() | |
3823 { | |
3824 return aliasdecl; | |
3825 } | |
3826 | |
3827 const char *TemplateInstance::kind() | |
3828 { | |
3829 return "template instance"; | |
3830 } | |
3831 | |
3832 int TemplateInstance::oneMember(Dsymbol **ps) | |
3833 { | |
3834 *ps = NULL; | |
3835 return TRUE; | |
3836 } | |
3837 | |
3838 char *TemplateInstance::toChars() | |
3839 { | |
3840 OutBuffer buf; | |
3841 HdrGenState hgs; | |
3842 char *s; | |
3843 | |
3844 toCBuffer(&buf, &hgs); | |
3845 s = buf.toChars(); | |
3846 buf.data = NULL; | |
3847 return s; | |
3848 } | |
3849 | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3850 void TemplateInstance::printInstantiationTrace() |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3851 { |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3852 if(global.gag) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3853 return; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3854 |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3855 const int max_shown = 6; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3856 |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3857 // determine instantiation depth |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3858 int n_instantiations = 1; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3859 TemplateInstance* cur = this; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3860 while(cur = cur->tinst) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3861 ++n_instantiations; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3862 |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3863 // show full trace only if it's short or verbose is on |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3864 if(n_instantiations <= max_shown || global.params.verbose) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3865 { |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3866 cur = this; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3867 while(cur) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3868 { |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3869 fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3870 cur = cur->tinst; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3871 } |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3872 } |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3873 else |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3874 { |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3875 cur = this; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3876 size_t i = 0; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3877 for(; i < max_shown/2; ++i, cur = cur->tinst) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3878 fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3879 fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3880 for(; i < n_instantiations - max_shown + max_shown/2; ++i, cur = cur->tinst) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3881 {} |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3882 for(; i < n_instantiations; ++i, cur = cur->tinst) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3883 fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3884 } |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3885 } |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3886 |
336 | 3887 /* ======================== TemplateMixin ================================ */ |
3888 | |
3889 TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, | |
3890 Array *idents, Objects *tiargs) | |
3891 : TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1]) | |
3892 { | |
3893 //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); | |
3894 this->ident = ident; | |
3895 this->tqual = tqual; | |
3896 this->idents = idents; | |
3897 this->tiargs = tiargs ? tiargs : new Objects(); | |
3898 this->scope = NULL; | |
3899 } | |
3900 | |
3901 Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) | |
3902 { TemplateMixin *tm; | |
3903 | |
3904 Array *ids = new Array(); | |
3905 ids->setDim(idents->dim); | |
3906 for (int i = 0; i < idents->dim; i++) | |
3907 { // Matches TypeQualified::syntaxCopyHelper() | |
3908 Identifier *id = (Identifier *)idents->data[i]; | |
3909 if (id->dyncast() == DYNCAST_DSYMBOL) | |
3910 { | |
3911 TemplateInstance *ti = (TemplateInstance *)id; | |
3912 | |
3913 ti = (TemplateInstance *)ti->syntaxCopy(NULL); | |
3914 id = (Identifier *)ti; | |
3915 } | |
3916 ids->data[i] = id; | |
3917 } | |
3918 | |
3919 tm = new TemplateMixin(loc, ident, | |
3920 (Type *)(tqual ? tqual->syntaxCopy() : NULL), | |
3921 ids, tiargs); | |
3922 TemplateInstance::syntaxCopy(tm); | |
3923 return tm; | |
3924 } | |
3925 | |
3926 void TemplateMixin::semantic(Scope *sc) | |
3927 { | |
3928 #if LOG | |
3929 printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); | |
3930 fflush(stdout); | |
3931 #endif | |
3932 if (semanticdone && | |
3933 // This for when a class/struct contains mixin members, and | |
3934 // is done over because of forward references | |
3935 (!parent || !toParent()->isAggregateDeclaration())) | |
3936 { | |
3937 #if LOG | |
3938 printf("\tsemantic done\n"); | |
3939 #endif | |
3940 return; | |
3941 } | |
3942 if (!semanticdone) | |
3943 semanticdone = 1; | |
3944 #if LOG | |
3945 printf("\tdo semantic\n"); | |
3946 #endif | |
3947 | |
3948 #if !IN_LLVM | |
3949 // dont know what this is | |
3950 util_progress(); | |
3951 #endif | |
3952 | |
3953 Scope *scx = NULL; | |
3954 if (scope) | |
3955 { sc = scope; | |
3956 scx = scope; // save so we don't make redundant copies | |
3957 scope = NULL; | |
3958 } | |
3959 | |
3960 // Follow qualifications to find the TemplateDeclaration | |
3961 if (!tempdecl) | |
3962 { Dsymbol *s; | |
3963 int i; | |
3964 Identifier *id; | |
3965 | |
3966 if (tqual) | |
3967 { s = tqual->toDsymbol(sc); | |
3968 i = 0; | |
3969 } | |
3970 else | |
3971 { | |
3972 i = 1; | |
3973 id = (Identifier *)idents->data[0]; | |
3974 switch (id->dyncast()) | |
3975 { | |
3976 case DYNCAST_IDENTIFIER: | |
3977 s = sc->search(loc, id, NULL); | |
3978 break; | |
3979 | |
3980 case DYNCAST_DSYMBOL: | |
3981 { | |
3982 TemplateInstance *ti = (TemplateInstance *)id; | |
3983 ti->semantic(sc); | |
3984 s = ti; | |
3985 break; | |
3986 } | |
3987 default: | |
3988 assert(0); | |
3989 } | |
3990 } | |
3991 | |
3992 for (; i < idents->dim; i++) | |
3993 { | |
3994 if (!s) | |
3995 break; | |
3996 id = (Identifier *)idents->data[i]; | |
3997 s = s->searchX(loc, sc, id); | |
3998 } | |
3999 if (!s) | |
4000 { | |
4001 error("is not defined"); | |
4002 inst = this; | |
4003 return; | |
4004 } | |
4005 tempdecl = s->toAlias()->isTemplateDeclaration(); | |
4006 if (!tempdecl) | |
4007 { | |
4008 error("%s isn't a template", s->toChars()); | |
4009 inst = this; | |
4010 return; | |
4011 } | |
4012 } | |
4013 | |
4014 // Look for forward reference | |
4015 assert(tempdecl); | |
4016 for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) | |
4017 { | |
4018 if (!td->scope) | |
4019 { | |
4020 /* Cannot handle forward references if mixin is a struct member, | |
4021 * because addField must happen during struct's semantic, not | |
4022 * during the mixin semantic. | |
4023 * runDeferred will re-run mixin's semantic outside of the struct's | |
4024 * semantic. | |
4025 */ | |
4026 semanticdone = 0; | |
4027 AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); | |
4028 if (ad) | |
4029 ad->sizeok = 2; | |
4030 else | |
4031 { | |
4032 // Forward reference | |
4033 //printf("forward reference - deferring\n"); | |
4034 scope = scx ? scx : new Scope(*sc); | |
4035 scope->setNoFree(); | |
4036 scope->module->addDeferredSemantic(this); | |
4037 } | |
4038 return; | |
4039 } | |
4040 } | |
4041 | |
4042 // Run semantic on each argument, place results in tiargs[] | |
4043 semanticTiargs(sc); | |
4044 | |
4045 tempdecl = findBestMatch(sc); | |
4046 if (!tempdecl) | |
4047 { inst = this; | |
4048 return; // error recovery | |
4049 } | |
4050 | |
4051 if (!ident) | |
4052 ident = genIdent(); | |
4053 | |
4054 inst = this; | |
4055 parent = sc->parent; | |
4056 | |
4057 /* Detect recursive mixin instantiations. | |
4058 */ | |
4059 for (Dsymbol *s = parent; s; s = s->parent) | |
4060 { | |
4061 //printf("\ts = '%s'\n", s->toChars()); | |
4062 TemplateMixin *tm = s->isTemplateMixin(); | |
4063 if (!tm || tempdecl != tm->tempdecl) | |
4064 continue; | |
4065 | |
4066 /* Different argument list lengths happen with variadic args | |
4067 */ | |
4068 if (tiargs->dim != tm->tiargs->dim) | |
4069 continue; | |
4070 | |
4071 for (int i = 0; i < tiargs->dim; i++) | |
4072 { Object *o = (Object *)tiargs->data[i]; | |
4073 Type *ta = isType(o); | |
4074 Expression *ea = isExpression(o); | |
4075 Dsymbol *sa = isDsymbol(o); | |
4076 Object *tmo = (Object *)tm->tiargs->data[i]; | |
4077 if (ta) | |
4078 { | |
4079 Type *tmta = isType(tmo); | |
4080 if (!tmta) | |
4081 goto Lcontinue; | |
4082 if (!ta->equals(tmta)) | |
4083 goto Lcontinue; | |
4084 } | |
4085 else if (ea) | |
4086 { Expression *tme = isExpression(tmo); | |
4087 if (!tme || !ea->equals(tme)) | |
4088 goto Lcontinue; | |
4089 } | |
4090 else if (sa) | |
4091 { | |
4092 Dsymbol *tmsa = isDsymbol(tmo); | |
4093 if (sa != tmsa) | |
4094 goto Lcontinue; | |
4095 } | |
4096 else | |
4097 assert(0); | |
4098 } | |
4099 error("recursive mixin instantiation"); | |
4100 return; | |
4101 | |
4102 Lcontinue: | |
4103 continue; | |
4104 } | |
4105 | |
4106 // Copy the syntax trees from the TemplateDeclaration | |
4107 members = Dsymbol::arraySyntaxCopy(tempdecl->members); | |
4108 if (!members) | |
4109 return; | |
4110 | |
4111 symtab = new DsymbolTable(); | |
4112 | |
4113 for (Scope *sce = sc; 1; sce = sce->enclosing) | |
4114 { | |
4115 ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; | |
4116 if (sds) | |
4117 { | |
4118 sds->importScope(this, PROTpublic); | |
4119 break; | |
4120 } | |
4121 } | |
4122 | |
4123 #if LOG | |
4124 printf("\tcreate scope for template parameters '%s'\n", toChars()); | |
4125 #endif | |
4126 Scope *scy = sc; | |
4127 scy = sc->push(this); | |
4128 scy->parent = this; | |
4129 | |
4130 argsym = new ScopeDsymbol(); | |
4131 argsym->parent = scy->parent; | |
4132 Scope *scope = scy->push(argsym); | |
4133 | |
4134 unsigned errorsave = global.errors; | |
4135 | |
4136 // Declare each template parameter as an alias for the argument type | |
4137 declareParameters(scope); | |
4138 | |
4139 // Add members to enclosing scope, as well as this scope | |
4140 for (unsigned i = 0; i < members->dim; i++) | |
4141 { Dsymbol *s; | |
4142 | |
4143 s = (Dsymbol *)members->data[i]; | |
4144 s->addMember(scope, this, i); | |
4145 //sc->insert(s); | |
4146 //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); | |
4147 //printf("s->parent = %s\n", s->parent->toChars()); | |
4148 } | |
4149 | |
4150 // Do semantic() analysis on template instance members | |
4151 #if LOG | |
4152 printf("\tdo semantic() on template instance members '%s'\n", toChars()); | |
4153 #endif | |
4154 Scope *sc2; | |
4155 sc2 = scope->push(this); | |
4156 sc2->offset = sc->offset; | |
4157 for (int i = 0; i < members->dim; i++) | |
4158 { | |
4159 Dsymbol *s = (Dsymbol *)members->data[i]; | |
4160 s->semantic(sc2); | |
4161 } | |
4162 sc->offset = sc2->offset; | |
4163 | |
4164 /* The problem is when to parse the initializer for a variable. | |
4165 * Perhaps VarDeclaration::semantic() should do it like it does | |
4166 * for initializers inside a function. | |
4167 */ | |
4168 // if (sc->parent->isFuncDeclaration()) | |
4169 | |
4170 semantic2(sc2); | |
4171 | |
4172 if (sc->func) | |
4173 { | |
4174 semantic3(sc2); | |
4175 } | |
4176 | |
4177 // Give additional context info if error occurred during instantiation | |
4178 if (global.errors != errorsave) | |
4179 { | |
4180 error("error instantiating"); | |
4181 } | |
4182 | |
4183 sc2->pop(); | |
4184 | |
4185 scope->pop(); | |
4186 | |
4187 // if (!isAnonymous()) | |
4188 { | |
4189 scy->pop(); | |
4190 } | |
4191 #if LOG | |
4192 printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); | |
4193 #endif | |
4194 } | |
4195 | |
4196 void TemplateMixin::semantic2(Scope *sc) | |
4197 { int i; | |
4198 | |
4199 if (semanticdone >= 2) | |
4200 return; | |
4201 semanticdone = 2; | |
4202 #if LOG | |
4203 printf("+TemplateMixin::semantic2('%s')\n", toChars()); | |
4204 #endif | |
4205 if (members) | |
4206 { | |
4207 assert(sc); | |
4208 sc = sc->push(argsym); | |
4209 sc = sc->push(this); | |
4210 for (i = 0; i < members->dim; i++) | |
4211 { | |
4212 Dsymbol *s = (Dsymbol *)members->data[i]; | |
4213 #if LOG | |
4214 printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); | |
4215 #endif | |
4216 s->semantic2(sc); | |
4217 } | |
4218 sc = sc->pop(); | |
4219 sc->pop(); | |
4220 } | |
4221 #if LOG | |
4222 printf("-TemplateMixin::semantic2('%s')\n", toChars()); | |
4223 #endif | |
4224 } | |
4225 | |
4226 void TemplateMixin::semantic3(Scope *sc) | |
4227 { int i; | |
4228 | |
4229 if (semanticdone >= 3) | |
4230 return; | |
4231 semanticdone = 3; | |
4232 #if LOG | |
4233 printf("TemplateMixin::semantic3('%s')\n", toChars()); | |
4234 #endif | |
4235 if (members) | |
4236 { | |
4237 sc = sc->push(argsym); | |
4238 sc = sc->push(this); | |
4239 for (i = 0; i < members->dim; i++) | |
4240 { | |
4241 Dsymbol *s = (Dsymbol *)members->data[i]; | |
4242 s->semantic3(sc); | |
4243 } | |
4244 sc = sc->pop(); | |
4245 sc->pop(); | |
4246 } | |
4247 } | |
4248 | |
4249 void TemplateMixin::inlineScan() | |
4250 { | |
4251 TemplateInstance::inlineScan(); | |
4252 } | |
4253 | |
4254 const char *TemplateMixin::kind() | |
4255 { | |
4256 return "mixin"; | |
4257 } | |
4258 | |
4259 int TemplateMixin::oneMember(Dsymbol **ps) | |
4260 { | |
4261 return Dsymbol::oneMember(ps); | |
4262 } | |
4263 | |
4264 int TemplateMixin::hasPointers() | |
4265 { | |
4266 //printf("TemplateMixin::hasPointers() %s\n", toChars()); | |
4267 for (size_t i = 0; i < members->dim; i++) | |
4268 { | |
4269 Dsymbol *s = (Dsymbol *)members->data[i]; | |
4270 //printf(" s = %s %s\n", s->kind(), s->toChars()); | |
4271 if (s->hasPointers()) | |
4272 { | |
4273 return 1; | |
4274 } | |
4275 } | |
4276 return 0; | |
4277 } | |
4278 | |
4279 char *TemplateMixin::toChars() | |
4280 { | |
4281 OutBuffer buf; | |
4282 HdrGenState hgs; | |
4283 char *s; | |
4284 | |
4285 TemplateInstance::toCBuffer(&buf, &hgs); | |
4286 s = buf.toChars(); | |
4287 buf.data = NULL; | |
4288 return s; | |
4289 } | |
4290 | |
4291 void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
4292 { | |
4293 buf->writestring("mixin "); | |
4294 | |
4295 for (int i = 0; i < idents->dim; i++) | |
4296 { Identifier *id = (Identifier *)idents->data[i]; | |
4297 | |
4298 if (i) | |
4299 buf->writeByte('.'); | |
4300 buf->writestring(id->toChars()); | |
4301 } | |
4302 buf->writestring("!("); | |
4303 if (tiargs) | |
4304 { | |
4305 for (int i = 0; i < tiargs->dim; i++) | |
4306 { if (i) | |
4307 buf->writebyte(','); | |
4308 Object *oarg = (Object *)tiargs->data[i]; | |
4309 Type *t = isType(oarg); | |
4310 Expression *e = isExpression(oarg); | |
4311 Dsymbol *s = isDsymbol(oarg); | |
4312 if (t) | |
4313 t->toCBuffer(buf, NULL, hgs); | |
4314 else if (e) | |
4315 e->toCBuffer(buf, hgs); | |
4316 else if (s) | |
4317 { | |
4318 char *p = s->ident ? s->ident->toChars() : s->toChars(); | |
4319 buf->writestring(p); | |
4320 } | |
4321 else if (!oarg) | |
4322 { | |
4323 buf->writestring("NULL"); | |
4324 } | |
4325 else | |
4326 { | |
4327 assert(0); | |
4328 } | |
4329 } | |
4330 } | |
4331 buf->writebyte(')'); | |
4332 if (ident) | |
4333 { | |
4334 buf->writebyte(' '); | |
4335 buf->writestring(ident->toChars()); | |
4336 } | |
4337 buf->writebyte(';'); | |
4338 buf->writenl(); | |
4339 } | |
4340 | |
4341 | |
4342 void TemplateMixin::toObjFile(int multiobj) | |
4343 { | |
4344 //printf("TemplateMixin::toObjFile('%s')\n", toChars()); | |
4345 TemplateInstance::toObjFile(multiobj); | |
4346 } | |
4347 |