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