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