Mercurial > projects > ldc
annotate dmd/template.c @ 1083:c1e9f612e2e2
Fix for dual operand form of fistp, also make reg ST(0) explicit and fix lindquists
previous code that allowed dual operand form of fstp but dissallowed the single
operand form accidently
author | Kelly Wilson <wilsonk cpsc.ucalgary.ca> |
---|---|
date | Tue, 10 Mar 2009 06:23:26 -0600 |
parents | 7ce8355fbcc6 |
children | d33b0d4b816a |
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 |
1067
7ce8355fbcc6
Improved template emission control for singleobj building.
Christian Kamm <kamm incasoftware de>
parents:
948
diff
changeset
|
2878 this->emittedInModule = NULL; |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
2879 this->tinst = NULL; |
948
780530d1cad3
Revert templates to old behavior.
Christian Kamm <kamm incasoftware de>
parents:
946
diff
changeset
|
2880 this->tmodule = NULL; |
336 | 2881 } |
2882 | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
2883 /***************** |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
2884 * 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
|
2885 * template to instantiate. |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
2886 */ |
336 | 2887 |
2888 TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) | |
2889 : ScopeDsymbol(NULL) | |
2890 { | |
2891 #if LOG | |
2892 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); | |
2893 #endif | |
2894 this->loc = loc; | |
2895 this->name = td->ident; | |
2896 this->tiargs = tiargs; | |
2897 this->tempdecl = td; | |
2898 this->inst = NULL; | |
2899 this->argsym = NULL; | |
2900 this->aliasdecl = NULL; | |
2901 this->semanticdone = 0; | |
2902 this->semantictiargsdone = 1; | |
2903 this->withsym = NULL; | |
2904 this->nest = 0; | |
2905 this->havetempdecl = 1; | |
2906 this->isnested = NULL; | |
2907 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
|
2908 |
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
|
2909 // LDC |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
2910 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
|
2911 this->tmodule = NULL; |
336 | 2912 |
2913 assert((size_t)tempdecl->scope > 0x10000); | |
2914 } | |
2915 | |
2916 | |
2917 Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) | |
2918 { | |
2919 Objects *a = NULL; | |
2920 if (objs) | |
2921 { a = new Objects(); | |
2922 a->setDim(objs->dim); | |
2923 for (size_t i = 0; i < objs->dim; i++) | |
2924 { | |
2925 Type *ta = isType((Object *)objs->data[i]); | |
2926 if (ta) | |
2927 a->data[i] = ta->syntaxCopy(); | |
2928 else | |
2929 { | |
2930 Expression *ea = isExpression((Object *)objs->data[i]); | |
2931 assert(ea); | |
2932 a->data[i] = ea->syntaxCopy(); | |
2933 } | |
2934 } | |
2935 } | |
2936 return a; | |
2937 } | |
2938 | |
2939 Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) | |
2940 { | |
2941 TemplateInstance *ti; | |
2942 | |
2943 if (s) | |
2944 ti = (TemplateInstance *)s; | |
2945 else | |
2946 ti = new TemplateInstance(loc, name); | |
2947 | |
2948 ti->tiargs = arraySyntaxCopy(tiargs); | |
2949 | |
2950 ScopeDsymbol::syntaxCopy(ti); | |
2951 return ti; | |
2952 } | |
2953 | |
2954 | |
2955 void TemplateInstance::semantic(Scope *sc) | |
2956 { | |
2957 if (global.errors) | |
2958 { | |
2959 if (!global.gag) | |
2960 { | |
2961 /* Trying to soldier on rarely generates useful messages | |
2962 * at this point. | |
2963 */ | |
2964 fatal(); | |
2965 } | |
2966 return; | |
2967 } | |
2968 #if LOG | |
2969 printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); | |
2970 #endif | |
2971 if (inst) // if semantic() was already run | |
2972 { | |
2973 #if LOG | |
2974 printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); | |
2975 #endif | |
2976 return; | |
2977 } | |
2978 | |
2979 if (semanticdone != 0) | |
2980 { | |
2981 error(loc, "recursive template expansion"); | |
2982 // inst = this; | |
2983 return; | |
2984 } | |
2985 semanticdone = 1; | |
2986 | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
2987 // 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
|
2988 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
|
2989 |
1714836f2c0b
Mostly rewrite debug info generation in terms of llvm/Analysis/DebugInfo.h.
Christian Kamm <kamm incasoftware de>
parents:
940
diff
changeset
|
2990 // 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
|
2991 if (tinst) |
1714836f2c0b
Mostly rewrite debug info generation in terms of llvm/Analysis/DebugInfo.h.
Christian Kamm <kamm incasoftware de>
parents:
940
diff
changeset
|
2992 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
|
2993 else |
1714836f2c0b
Mostly rewrite debug info generation in terms of llvm/Analysis/DebugInfo.h.
Christian Kamm <kamm incasoftware de>
parents:
940
diff
changeset
|
2994 tmodule = sc->module; |
948
780530d1cad3
Revert templates to old behavior.
Christian Kamm <kamm incasoftware de>
parents:
946
diff
changeset
|
2995 //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
|
2996 |
336 | 2997 #if LOG |
2998 printf("\tdo semantic\n"); | |
2999 #endif | |
3000 if (havetempdecl) | |
3001 { | |
3002 assert((size_t)tempdecl->scope > 0x10000); | |
3003 // Deduce tdtypes | |
3004 tdtypes.setDim(tempdecl->parameters->dim); | |
3005 if (!tempdecl->matchWithInstance(this, &tdtypes, 0)) | |
3006 { | |
3007 error("incompatible arguments for template instantiation"); | |
3008 inst = this; | |
3009 return; | |
3010 } | |
3011 } | |
3012 else | |
3013 { | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3014 /* 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
|
3015 * (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
|
3016 */ |
336 | 3017 semanticTiargs(sc); |
3018 | |
3019 tempdecl = findTemplateDeclaration(sc); | |
3020 if (tempdecl) | |
3021 tempdecl = findBestMatch(sc); | |
3022 if (!tempdecl || global.errors) | |
3023 { inst = this; | |
3024 //printf("error return %p, %d\n", tempdecl, global.errors); | |
3025 return; // error recovery | |
3026 } | |
3027 } | |
3028 | |
3029 isNested(tiargs); | |
3030 | |
3031 /* See if there is an existing TemplateInstantiation that already | |
3032 * implements the typeargs. If so, just refer to that one instead. | |
3033 */ | |
3034 | |
3035 for (size_t i = 0; i < tempdecl->instances.dim; i++) | |
3036 { | |
3037 TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i]; | |
3038 #if LOG | |
3039 printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); | |
3040 #endif | |
3041 assert(tdtypes.dim == ti->tdtypes.dim); | |
3042 | |
3043 // Nesting must match | |
3044 if (isnested != ti->isnested) | |
3045 continue; | |
3046 #if 0 | |
3047 if (isnested && sc->parent != ti->parent) | |
3048 continue; | |
3049 #endif | |
3050 for (size_t j = 0; j < tdtypes.dim; j++) | |
3051 { Object *o1 = (Object *)tdtypes.data[j]; | |
3052 Object *o2 = (Object *)ti->tdtypes.data[j]; | |
3053 if (!match(o1, o2, tempdecl, sc)) | |
3054 goto L1; | |
3055 } | |
3056 | |
3057 // It's a match | |
3058 inst = ti; | |
3059 parent = ti->parent; | |
3060 #if LOG | |
3061 printf("\tit's a match with instance %p\n", inst); | |
3062 #endif | |
3063 return; | |
3064 | |
3065 L1: | |
3066 ; | |
3067 } | |
3068 | |
3069 /* So, we need to implement 'this' instance. | |
3070 */ | |
3071 #if LOG | |
3072 printf("\timplement template instance '%s'\n", toChars()); | |
3073 #endif | |
3074 unsigned errorsave = global.errors; | |
3075 inst = this; | |
3076 int tempdecl_instance_idx = tempdecl->instances.dim; | |
3077 tempdecl->instances.push(this); | |
3078 parent = tempdecl->parent; | |
3079 //printf("parent = '%s'\n", parent->kind()); | |
3080 | |
3081 ident = genIdent(); // need an identifier for name mangling purposes. | |
3082 | |
3083 #if 1 | |
3084 if (isnested) | |
3085 parent = isnested; | |
3086 #endif | |
3087 //printf("parent = '%s'\n", parent->kind()); | |
3088 | |
3089 // Add 'this' to the enclosing scope's members[] so the semantic routines | |
3090 // will get called on the instance members | |
3091 #if 1 | |
3092 int dosemantic3 = 0; | |
3093 { Array *a; | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3094 |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3095 Scope *scx = sc; |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3096 #if 0 |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3097 for (scx = sc; scx; scx = scx->enclosing) |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3098 if (scx->scopesym) |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3099 break; |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3100 #endif |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3101 |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3102 //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
|
3103 if (scx && scx->scopesym && |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3104 scx->scopesym->members && !scx->scopesym->isTemplateMixin() && |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3105 /* 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
|
3106 * 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
|
3107 */ |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3108 //scx->module == tempdecl->getModule() |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3109 !scx->module->imports(scx->module) |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3110 ) |
336 | 3111 { |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3112 //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
|
3113 a = scx->scopesym->members; |
336 | 3114 } |
3115 else | |
3116 { Module *m = sc->module->importedFrom; | |
3117 //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); | |
3118 a = m->members; | |
3119 if (m->semanticdone >= 3) | |
3120 dosemantic3 = 1; | |
3121 } | |
3122 for (int i = 0; 1; i++) | |
3123 { | |
3124 if (i == a->dim) | |
3125 { | |
3126 a->push(this); | |
3127 break; | |
3128 } | |
3129 if (this == (Dsymbol *)a->data[i]) // if already in Array | |
3130 break; | |
3131 } | |
3132 } | |
3133 #endif | |
3134 | |
3135 // Copy the syntax trees from the TemplateDeclaration | |
3136 members = Dsymbol::arraySyntaxCopy(tempdecl->members); | |
3137 | |
3138 // Create our own scope for the template parameters | |
3139 Scope *scope = tempdecl->scope; | |
3140 if (!scope) | |
3141 { | |
3142 error("forward reference to template declaration %s\n", tempdecl->toChars()); | |
3143 return; | |
3144 } | |
3145 | |
3146 #if LOG | |
3147 printf("\tcreate scope for template parameters '%s'\n", toChars()); | |
3148 #endif | |
3149 argsym = new ScopeDsymbol(); | |
3150 argsym->parent = scope->parent; | |
3151 scope = scope->push(argsym); | |
3152 | |
3153 // Declare each template parameter as an alias for the argument type | |
3154 declareParameters(scope); | |
3155 | |
3156 // Add members of template instance to template instance symbol table | |
3157 // parent = scope->scopesym; | |
3158 symtab = new DsymbolTable(); | |
3159 int memnum = 0; | |
3160 for (int i = 0; i < members->dim; i++) | |
3161 { | |
3162 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3163 #if LOG | |
3164 printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); | |
3165 #endif | |
3166 memnum |= s->addMember(scope, this, memnum); | |
3167 } | |
3168 #if LOG | |
3169 printf("adding members done\n"); | |
3170 #endif | |
3171 | |
3172 /* See if there is only one member of template instance, and that | |
3173 * member has the same name as the template instance. | |
3174 * If so, this template instance becomes an alias for that member. | |
3175 */ | |
3176 //printf("members->dim = %d\n", members->dim); | |
3177 if (members->dim) | |
3178 { | |
3179 Dsymbol *s; | |
3180 if (Dsymbol::oneMembers(members, &s) && s) | |
3181 { | |
3182 //printf("s->kind = '%s'\n", s->kind()); | |
3183 //s->print(); | |
3184 //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); | |
3185 if (s->ident && s->ident->equals(tempdecl->ident)) | |
3186 { | |
3187 //printf("setting aliasdecl\n"); | |
3188 aliasdecl = new AliasDeclaration(loc, s->ident, s); | |
3189 } | |
3190 } | |
3191 } | |
3192 | |
3193 // Do semantic() analysis on template instance members | |
3194 #if LOG | |
3195 printf("\tdo semantic() on template instance members '%s'\n", toChars()); | |
3196 #endif | |
3197 Scope *sc2; | |
3198 sc2 = scope->push(this); | |
3199 //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); | |
3200 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
|
3201 sc2->tinst = this; |
336 | 3202 |
3203 #if !IN_LLVM | |
3204 #if _WIN32 | |
3205 __try | |
3206 { | |
3207 #endif | |
3208 #endif | |
3209 for (int i = 0; i < members->dim; i++) | |
3210 { | |
3211 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3212 //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); | |
3213 //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); | |
3214 // if (isnested) | |
3215 // s->parent = sc->parent; | |
3216 //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); | |
3217 s->semantic(sc2); | |
3218 //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); | |
3219 sc2->module->runDeferredSemantic(); | |
3220 } | |
3221 #if !IN_LLVM | |
3222 #if _WIN32 | |
3223 } | |
3224 __except (__ehfilter(GetExceptionInformation())) | |
3225 { | |
3226 global.gag = 0; // ensure error message gets printed | |
3227 error("recursive expansion"); | |
3228 fatal(); | |
3229 } | |
3230 #endif | |
3231 #endif | |
3232 | |
3233 /* If any of the instantiation members didn't get semantic() run | |
3234 * on them due to forward references, we cannot run semantic2() | |
3235 * or semantic3() yet. | |
3236 */ | |
3237 for (size_t i = 0; i < Module::deferred.dim; i++) | |
3238 { Dsymbol *sd = (Dsymbol *)Module::deferred.data[i]; | |
3239 | |
3240 if (sd->parent == this) | |
3241 goto Laftersemantic; | |
3242 } | |
3243 | |
3244 /* The problem is when to parse the initializer for a variable. | |
3245 * Perhaps VarDeclaration::semantic() should do it like it does | |
3246 * for initializers inside a function. | |
3247 */ | |
3248 // if (sc->parent->isFuncDeclaration()) | |
3249 | |
3250 /* BUG 782: this has problems if the classes this depends on | |
3251 * are forward referenced. Find a way to defer semantic() | |
3252 * on this template. | |
3253 */ | |
3254 semantic2(sc2); | |
3255 | |
3256 if (sc->func || dosemantic3) | |
3257 { | |
3258 semantic3(sc2); | |
3259 } | |
3260 | |
3261 Laftersemantic: | |
3262 sc2->pop(); | |
3263 | |
3264 scope->pop(); | |
3265 | |
3266 // Give additional context info if error occurred during instantiation | |
3267 if (global.errors != errorsave) | |
3268 { | |
3269 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
|
3270 if(tinst) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3271 tinst->printInstantiationTrace(); |
336 | 3272 errors = 1; |
3273 if (global.gag) | |
3274 tempdecl->instances.remove(tempdecl_instance_idx); | |
3275 } | |
3276 | |
3277 #if LOG | |
3278 printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); | |
3279 #endif | |
3280 } | |
3281 | |
3282 | |
3283 void TemplateInstance::semanticTiargs(Scope *sc) | |
3284 { | |
3285 //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); | |
3286 if (semantictiargsdone) | |
3287 return; | |
3288 semantictiargsdone = 1; | |
3289 semanticTiargs(loc, sc, tiargs); | |
3290 } | |
3291 | |
3292 void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs) | |
3293 { | |
3294 // Run semantic on each argument, place results in tiargs[] | |
3295 //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); | |
3296 if (!tiargs) | |
3297 return; | |
3298 for (size_t j = 0; j < tiargs->dim; j++) | |
3299 { | |
3300 Object *o = (Object *)tiargs->data[j]; | |
3301 Type *ta = isType(o); | |
3302 Expression *ea = isExpression(o); | |
3303 Dsymbol *sa = isDsymbol(o); | |
3304 | |
3305 //printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); | |
3306 if (ta) | |
3307 { | |
3308 //printf("type %s\n", ta->toChars()); | |
3309 // It might really be an Expression or an Alias | |
3310 ta->resolve(loc, sc, &ea, &ta, &sa); | |
3311 if (ea) | |
3312 { | |
3313 ea = ea->semantic(sc); | |
3314 ea = ea->optimize(WANTvalue | WANTinterpret); | |
3315 tiargs->data[j] = ea; | |
3316 } | |
3317 else if (sa) | |
3318 { tiargs->data[j] = sa; | |
3319 TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); | |
3320 if (d) | |
3321 { | |
3322 size_t dim = d->objects->dim; | |
3323 tiargs->remove(j); | |
3324 tiargs->insert(j, d->objects); | |
3325 j--; | |
3326 } | |
3327 } | |
3328 else if (ta) | |
3329 { | |
3330 if (ta->ty == Ttuple) | |
3331 { // Expand tuple | |
3332 TypeTuple *tt = (TypeTuple *)ta; | |
3333 size_t dim = tt->arguments->dim; | |
3334 tiargs->remove(j); | |
3335 if (dim) | |
3336 { tiargs->reserve(dim); | |
3337 for (size_t i = 0; i < dim; i++) | |
3338 { Argument *arg = (Argument *)tt->arguments->data[i]; | |
3339 tiargs->insert(j + i, arg->type); | |
3340 } | |
3341 } | |
3342 j--; | |
3343 } | |
3344 else | |
3345 tiargs->data[j] = ta; | |
3346 } | |
3347 else | |
3348 { | |
3349 assert(global.errors); | |
3350 tiargs->data[j] = Type::terror; | |
3351 } | |
3352 } | |
3353 else if (ea) | |
3354 { | |
3355 if (!ea) | |
3356 { assert(global.errors); | |
3357 ea = new IntegerExp(0); | |
3358 } | |
3359 assert(ea); | |
3360 ea = ea->semantic(sc); | |
3361 ea = ea->optimize(WANTvalue | WANTinterpret); | |
3362 tiargs->data[j] = ea; | |
3363 if (ea->op == TOKtype) | |
3364 tiargs->data[j] = ea->type; | |
3365 } | |
3366 else if (sa) | |
3367 { | |
3368 } | |
3369 else | |
3370 { | |
3371 assert(0); | |
3372 } | |
3373 //printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]); | |
3374 } | |
3375 #if 0 | |
3376 printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this); | |
3377 for (size_t j = 0; j < tiargs->dim; j++) | |
3378 { | |
3379 Object *o = (Object *)tiargs->data[j]; | |
3380 Type *ta = isType(o); | |
3381 Expression *ea = isExpression(o); | |
3382 Dsymbol *sa = isDsymbol(o); | |
3383 Tuple *va = isTuple(o); | |
3384 | |
3385 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); | |
3386 } | |
3387 #endif | |
3388 } | |
3389 | |
3390 /********************************************** | |
3391 * Find template declaration corresponding to template instance. | |
3392 */ | |
3393 | |
3394 TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) | |
3395 { | |
3396 //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); | |
3397 if (!tempdecl) | |
3398 { | |
3399 /* Given: | |
3400 * foo!( ... ) | |
3401 * figure out which TemplateDeclaration foo refers to. | |
3402 */ | |
3403 Dsymbol *s; | |
3404 Dsymbol *scopesym; | |
3405 Identifier *id; | |
3406 int i; | |
3407 | |
3408 id = name; | |
3409 s = sc->search(loc, id, &scopesym); | |
3410 if (!s) | |
3411 { error("identifier '%s' is not defined", id->toChars()); | |
3412 return NULL; | |
3413 } | |
3414 #if LOG | |
3415 printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); | |
3416 if (s->parent) | |
3417 printf("s->parent = '%s'\n", s->parent->toChars()); | |
3418 #endif | |
3419 withsym = scopesym->isWithScopeSymbol(); | |
3420 | |
3421 /* We might have found an alias within a template when | |
3422 * we really want the template. | |
3423 */ | |
3424 TemplateInstance *ti; | |
3425 if (s->parent && | |
3426 (ti = s->parent->isTemplateInstance()) != NULL) | |
3427 { | |
3428 if ( | |
3429 (ti->name == id || | |
3430 ti->toAlias()->ident == id) | |
3431 && | |
3432 ti->tempdecl) | |
3433 { | |
3434 /* This is so that one can refer to the enclosing | |
3435 * template, even if it has the same name as a member | |
3436 * of the template, if it has a !(arguments) | |
3437 */ | |
3438 tempdecl = ti->tempdecl; | |
3439 if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's | |
3440 tempdecl = tempdecl->overroot; // then get the start | |
3441 s = tempdecl; | |
3442 } | |
3443 } | |
3444 | |
3445 s = s->toAlias(); | |
3446 | |
3447 /* It should be a TemplateDeclaration, not some other symbol | |
3448 */ | |
3449 tempdecl = s->isTemplateDeclaration(); | |
3450 if (!tempdecl) | |
3451 { | |
3452 if (!s->parent && global.errors) | |
3453 return NULL; | |
3454 if (!s->parent && s->getType()) | |
3455 { Dsymbol *s2 = s->getType()->toDsymbol(sc); | |
3456 if (!s2) | |
3457 { | |
3458 error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); | |
3459 return NULL; | |
3460 } | |
3461 s = s2; | |
3462 } | |
3463 #ifdef DEBUG | |
3464 //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); | |
3465 #endif | |
3466 //assert(s->parent); | |
3467 TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; | |
3468 if (ti && | |
3469 (ti->name == id || | |
3470 ti->toAlias()->ident == id) | |
3471 && | |
3472 ti->tempdecl) | |
3473 { | |
3474 /* This is so that one can refer to the enclosing | |
3475 * template, even if it has the same name as a member | |
3476 * of the template, if it has a !(arguments) | |
3477 */ | |
3478 tempdecl = ti->tempdecl; | |
3479 if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's | |
3480 tempdecl = tempdecl->overroot; // then get the start | |
3481 } | |
3482 else | |
3483 { | |
3484 error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); | |
3485 return NULL; | |
3486 } | |
3487 } | |
3488 } | |
3489 else | |
3490 assert(tempdecl->isTemplateDeclaration()); | |
3491 return tempdecl; | |
3492 } | |
3493 | |
3494 TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) | |
3495 { | |
3496 /* Since there can be multiple TemplateDeclaration's with the same | |
3497 * name, look for the best match. | |
3498 */ | |
3499 TemplateDeclaration *td_ambig = NULL; | |
3500 TemplateDeclaration *td_best = NULL; | |
3501 MATCH m_best = MATCHnomatch; | |
3502 Objects dedtypes; | |
3503 | |
3504 #if LOG | |
3505 printf("TemplateInstance::findBestMatch()\n"); | |
3506 #endif | |
3507 for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) | |
3508 { | |
3509 MATCH m; | |
3510 | |
3511 //if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->data[0]); | |
3512 | |
3513 // If more arguments than parameters, | |
3514 // then this is no match. | |
3515 if (td->parameters->dim < tiargs->dim) | |
3516 { | |
3517 if (!td->isVariadic()) | |
3518 continue; | |
3519 } | |
3520 | |
3521 dedtypes.setDim(td->parameters->dim); | |
3522 dedtypes.zero(); | |
3523 if (!td->scope) | |
3524 { | |
3525 error("forward reference to template declaration %s", td->toChars()); | |
3526 return NULL; | |
3527 } | |
3528 m = td->matchWithInstance(this, &dedtypes, 0); | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3529 //printf("matchWithInstance = %d\n", m); |
336 | 3530 if (!m) // no match at all |
3531 continue; | |
3532 | |
3533 if (m < m_best) | |
3534 goto Ltd_best; | |
3535 if (m > m_best) | |
3536 goto Ltd; | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3537 |
336 | 3538 { |
3539 // Disambiguate by picking the most specialized TemplateDeclaration | |
3540 int c1 = td->leastAsSpecialized(td_best); | |
3541 int c2 = td_best->leastAsSpecialized(td); | |
3542 //printf("c1 = %d, c2 = %d\n", c1, c2); | |
3543 | |
3544 if (c1 > c2) | |
3545 goto Ltd; | |
3546 else if (c1 < c2) | |
3547 goto Ltd_best; | |
3548 else | |
3549 goto Lambig; | |
3550 } | |
3551 | |
3552 Lambig: // td_best and td are ambiguous | |
3553 td_ambig = td; | |
3554 continue; | |
3555 | |
3556 Ltd_best: // td_best is the best match so far | |
3557 td_ambig = NULL; | |
3558 continue; | |
3559 | |
3560 Ltd: // td is the new best match | |
3561 td_ambig = NULL; | |
3562 td_best = td; | |
3563 m_best = m; | |
3564 tdtypes.setDim(dedtypes.dim); | |
3565 memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *)); | |
3566 continue; | |
3567 } | |
3568 | |
3569 if (!td_best) | |
3570 { | |
3571 error("%s does not match any template declaration", toChars()); | |
3572 return NULL; | |
3573 } | |
3574 if (td_ambig) | |
3575 { | |
3576 error("%s matches more than one template declaration, %s and %s", | |
3577 toChars(), td_best->toChars(), td_ambig->toChars()); | |
3578 } | |
3579 | |
3580 /* The best match is td_best | |
3581 */ | |
3582 tempdecl = td_best; | |
3583 | |
3584 #if 0 | |
3585 /* Cast any value arguments to be same type as value parameter | |
3586 */ | |
3587 for (size_t i = 0; i < tiargs->dim; i++) | |
3588 { Object *o = (Object *)tiargs->data[i]; | |
3589 Expression *ea = isExpression(o); // value argument | |
3590 TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; | |
3591 assert(tp); | |
3592 TemplateValueParameter *tvp = tp->isTemplateValueParameter(); | |
3593 if (tvp) | |
3594 { | |
3595 assert(ea); | |
3596 ea = ea->castTo(tvp->valType); | |
3597 ea = ea->optimize(WANTvalue | WANTinterpret); | |
3598 tiargs->data[i] = (Object *)ea; | |
3599 } | |
3600 } | |
3601 #endif | |
3602 | |
3603 #if LOG | |
3604 printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); | |
3605 #endif | |
3606 return tempdecl; | |
3607 } | |
3608 | |
3609 | |
3610 /***************************************** | |
3611 * Determines if a TemplateInstance will need a nested | |
3612 * generation of the TemplateDeclaration. | |
3613 */ | |
3614 | |
3615 int TemplateInstance::isNested(Objects *args) | |
3616 { int nested = 0; | |
3617 //printf("TemplateInstance::isNested('%s')\n", tempdecl->ident->toChars()); | |
3618 | |
3619 /* A nested instance happens when an argument references a local | |
3620 * symbol that is on the stack. | |
3621 */ | |
3622 for (size_t i = 0; i < args->dim; i++) | |
3623 { Object *o = (Object *)args->data[i]; | |
3624 Expression *ea = isExpression(o); | |
3625 Dsymbol *sa = isDsymbol(o); | |
3626 Tuple *va = isTuple(o); | |
3627 if (ea) | |
3628 { | |
3629 if (ea->op == TOKvar) | |
3630 { | |
3631 sa = ((VarExp *)ea)->var; | |
3632 goto Lsa; | |
3633 } | |
3634 if (ea->op == TOKfunction) | |
3635 { | |
3636 sa = ((FuncExp *)ea)->fd; | |
3637 goto Lsa; | |
3638 } | |
3639 } | |
3640 else if (sa) | |
3641 { | |
3642 Lsa: | |
3643 Declaration *d = sa->isDeclaration(); | |
3644 if (d && !d->isDataseg() && | |
3645 #if DMDV2 | |
3646 !(d->storage_class & STCmanifest) && | |
3647 #endif | |
3648 (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && | |
3649 !isTemplateMixin()) | |
3650 { | |
3651 // if module level template | |
3652 if (tempdecl->toParent()->isModule()) | |
3653 { Dsymbol *dparent = d->toParent(); | |
3654 if (!isnested) | |
3655 isnested = dparent; | |
3656 else if (isnested != dparent) | |
3657 { | |
3658 /* Select the more deeply nested of the two. | |
3659 * Error if one is not nested inside the other. | |
3660 */ | |
3661 for (Dsymbol *p = isnested; p; p = p->parent) | |
3662 { | |
3663 if (p == dparent) | |
3664 goto L1; // isnested is most nested | |
3665 } | |
876
27a379f288bf
Merged DMD 1.039
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
875
diff
changeset
|
3666 for (Dsymbol *p = dparent; p; p = p->parent) |
336 | 3667 { |
3668 if (p == isnested) | |
3669 { isnested = dparent; | |
3670 goto L1; // dparent is most nested | |
3671 } | |
3672 } | |
876
27a379f288bf
Merged DMD 1.039
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
875
diff
changeset
|
3673 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
|
3674 toChars(), isnested->toChars(), dparent->toChars()); |
336 | 3675 } |
3676 L1: | |
3677 //printf("\tnested inside %s\n", isnested->toChars()); | |
3678 nested |= 1; | |
3679 } | |
3680 else | |
3681 error("cannot use local '%s' as template parameter", d->toChars()); | |
3682 } | |
3683 } | |
3684 else if (va) | |
3685 { | |
3686 nested |= isNested(&va->objects); | |
3687 } | |
3688 } | |
3689 return nested; | |
3690 } | |
3691 | |
3692 /**************************************** | |
3693 * This instance needs an identifier for name mangling purposes. | |
3694 * Create one by taking the template declaration name and adding | |
3695 * the type signature for it. | |
3696 */ | |
3697 | |
3698 Identifier *TemplateInstance::genIdent() | |
3699 { OutBuffer buf; | |
3700 char *id; | |
3701 Objects *args; | |
3702 | |
3703 //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); | |
3704 id = tempdecl->ident->toChars(); | |
3705 buf.printf("__T%"PRIuSIZE"%s", strlen(id), id); | |
3706 args = tiargs; | |
3707 for (int i = 0; i < args->dim; i++) | |
3708 { Object *o = (Object *)args->data[i]; | |
3709 Type *ta = isType(o); | |
3710 Expression *ea = isExpression(o); | |
3711 Dsymbol *sa = isDsymbol(o); | |
3712 Tuple *va = isTuple(o); | |
3713 //printf("\to %p ta %p ea %p sa %p va %p\n", o, ta, ea, sa, va); | |
3714 if (ta) | |
3715 { | |
3716 buf.writeByte('T'); | |
3717 if (ta->deco) | |
3718 buf.writestring(ta->deco); | |
3719 else | |
3720 { | |
3721 #ifdef DEBUG | |
3722 printf("ta = %d, %s\n", ta->ty, ta->toChars()); | |
3723 #endif | |
3724 assert(global.errors); | |
3725 } | |
3726 } | |
3727 else if (ea) | |
3728 { sinteger_t v; | |
3729 real_t r; | |
3730 | |
3731 if (ea->op == TOKvar) | |
3732 { | |
3733 sa = ((VarExp *)ea)->var; | |
3734 ea = NULL; | |
3735 goto Lsa; | |
3736 } | |
3737 if (ea->op == TOKfunction) | |
3738 { | |
3739 sa = ((FuncExp *)ea)->fd; | |
3740 ea = NULL; | |
3741 goto Lsa; | |
3742 } | |
3743 buf.writeByte('V'); | |
3744 if (ea->op == TOKtuple) | |
3745 { ea->error("tuple is not a valid template value argument"); | |
3746 continue; | |
3747 } | |
3748 #if 1 | |
3749 /* Use deco that matches what it would be for a function parameter | |
3750 */ | |
3751 buf.writestring(ea->type->deco); | |
3752 #else | |
3753 // Use type of parameter, not type of argument | |
3754 TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; | |
3755 assert(tp); | |
3756 TemplateValueParameter *tvp = tp->isTemplateValueParameter(); | |
3757 assert(tvp); | |
3758 buf.writestring(tvp->valType->deco); | |
3759 #endif | |
3760 ea->toMangleBuffer(&buf); | |
3761 } | |
3762 else if (sa) | |
3763 { | |
3764 Lsa: | |
3765 buf.writeByte('S'); | |
3766 Declaration *d = sa->isDeclaration(); | |
3767 if (d && !d->type->deco) | |
3768 error("forward reference of %s", d->toChars()); | |
3769 else | |
3770 { | |
3771 char *p = sa->mangle(); | |
3772 buf.printf("%"PRIuSIZE"%s", strlen(p), p); | |
3773 } | |
3774 } | |
3775 else if (va) | |
3776 { | |
3777 assert(i + 1 == args->dim); // must be last one | |
3778 args = &va->objects; | |
3779 i = -1; | |
3780 } | |
3781 else | |
3782 assert(0); | |
3783 } | |
3784 buf.writeByte('Z'); | |
3785 id = buf.toChars(); | |
3786 buf.data = NULL; | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3787 //printf("\tgenIdent = %s\n", id); |
336 | 3788 return new Identifier(id, TOKidentifier); |
3789 } | |
3790 | |
3791 | |
3792 /**************************************************** | |
3793 * Declare parameters of template instance, initialize them with the | |
3794 * template instance arguments. | |
3795 */ | |
3796 | |
3797 void TemplateInstance::declareParameters(Scope *scope) | |
3798 { | |
3799 //printf("TemplateInstance::declareParameters()\n"); | |
3800 for (int i = 0; i < tdtypes.dim; i++) | |
3801 { | |
3802 TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; | |
3803 //Object *o = (Object *)tiargs->data[i]; | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
3804 Object *o = (Object *)tdtypes.data[i]; // initializer for tp |
336 | 3805 |
3806 //printf("\ttdtypes[%d] = %p\n", i, o); | |
3807 tempdecl->declareParameter(scope, tp, o); | |
3808 } | |
3809 } | |
3810 | |
3811 | |
3812 void TemplateInstance::semantic2(Scope *sc) | |
3813 { int i; | |
3814 | |
3815 if (semanticdone >= 2) | |
3816 return; | |
3817 semanticdone = 2; | |
3818 #if LOG | |
3819 printf("+TemplateInstance::semantic2('%s')\n", toChars()); | |
3820 #endif | |
3821 if (!errors && members) | |
3822 { | |
3823 sc = tempdecl->scope; | |
3824 assert(sc); | |
3825 sc = sc->push(argsym); | |
3826 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
|
3827 sc->tinst = this; |
336 | 3828 for (i = 0; i < members->dim; i++) |
3829 { | |
3830 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3831 #if LOG | |
3832 printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); | |
3833 #endif | |
3834 s->semantic2(sc); | |
3835 } | |
3836 sc = sc->pop(); | |
3837 sc->pop(); | |
3838 } | |
3839 #if LOG | |
3840 printf("-TemplateInstance::semantic2('%s')\n", toChars()); | |
3841 #endif | |
3842 } | |
3843 | |
3844 void TemplateInstance::semantic3(Scope *sc) | |
3845 { | |
3846 #if LOG | |
3847 printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone); | |
3848 #endif | |
3849 //if (toChars()[0] == 'D') *(char*)0=0; | |
3850 if (semanticdone >= 3) | |
3851 return; | |
3852 semanticdone = 3; | |
3853 if (!errors && members) | |
3854 { | |
3855 sc = tempdecl->scope; | |
3856 sc = sc->push(argsym); | |
3857 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
|
3858 sc->tinst = this; |
336 | 3859 for (int i = 0; i < members->dim; i++) |
3860 { | |
3861 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3862 s->semantic3(sc); | |
3863 } | |
3864 sc = sc->pop(); | |
3865 sc->pop(); | |
3866 } | |
3867 } | |
3868 | |
3869 void TemplateInstance::toObjFile(int multiobj) | |
3870 { | |
3871 #if LOG | |
3872 printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); | |
3873 #endif | |
3874 if (!errors && members) | |
3875 { | |
3876 if (multiobj) | |
3877 // Append to list of object files to be written later | |
3878 //obj_append(this); | |
3879 assert(0 && "multiobj"); | |
3880 else | |
3881 { | |
3882 for (int i = 0; i < members->dim; i++) | |
3883 { | |
3884 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3885 s->toObjFile(multiobj); | |
3886 } | |
3887 } | |
3888 } | |
3889 } | |
3890 | |
3891 void TemplateInstance::inlineScan() | |
3892 { | |
3893 #if LOG | |
3894 printf("TemplateInstance::inlineScan('%s')\n", toChars()); | |
3895 #endif | |
3896 if (!errors && members) | |
3897 { | |
3898 for (int i = 0; i < members->dim; i++) | |
3899 { | |
3900 Dsymbol *s = (Dsymbol *)members->data[i]; | |
3901 s->inlineScan(); | |
3902 } | |
3903 } | |
3904 } | |
3905 | |
3906 void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3907 { | |
3908 int i; | |
3909 | |
3910 Identifier *id = name; | |
3911 buf->writestring(id->toChars()); | |
3912 buf->writestring("!("); | |
3913 if (nest) | |
3914 buf->writestring("..."); | |
3915 else | |
3916 { | |
3917 nest++; | |
3918 Objects *args = tiargs; | |
3919 for (i = 0; i < args->dim; i++) | |
3920 { | |
3921 if (i) | |
3922 buf->writeByte(','); | |
3923 Object *oarg = (Object *)args->data[i]; | |
3924 ObjectToCBuffer(buf, hgs, oarg); | |
3925 } | |
3926 nest--; | |
3927 } | |
3928 buf->writeByte(')'); | |
3929 } | |
3930 | |
3931 | |
3932 Dsymbol *TemplateInstance::toAlias() | |
3933 { | |
3934 #if LOG | |
3935 printf("TemplateInstance::toAlias()\n"); | |
3936 #endif | |
3937 if (!inst) | |
3938 { error("cannot resolve forward reference"); | |
3939 return this; | |
3940 } | |
3941 | |
3942 if (inst != this) | |
3943 return inst->toAlias(); | |
3944 | |
3945 if (aliasdecl) | |
3946 return aliasdecl->toAlias(); | |
3947 | |
3948 return inst; | |
3949 } | |
3950 | |
3951 AliasDeclaration *TemplateInstance::isAliasDeclaration() | |
3952 { | |
3953 return aliasdecl; | |
3954 } | |
3955 | |
3956 const char *TemplateInstance::kind() | |
3957 { | |
3958 return "template instance"; | |
3959 } | |
3960 | |
3961 int TemplateInstance::oneMember(Dsymbol **ps) | |
3962 { | |
3963 *ps = NULL; | |
3964 return TRUE; | |
3965 } | |
3966 | |
3967 char *TemplateInstance::toChars() | |
3968 { | |
3969 OutBuffer buf; | |
3970 HdrGenState hgs; | |
3971 char *s; | |
3972 | |
3973 toCBuffer(&buf, &hgs); | |
3974 s = buf.toChars(); | |
3975 buf.data = NULL; | |
3976 return s; | |
3977 } | |
3978 | |
561
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3979 void TemplateInstance::printInstantiationTrace() |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3980 { |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3981 if(global.gag) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3982 return; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3983 |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3984 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
|
3985 |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3986 // determine instantiation depth |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3987 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
|
3988 TemplateInstance* cur = this; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3989 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
|
3990 ++n_instantiations; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3991 |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3992 // 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
|
3993 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
|
3994 { |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3995 cur = this; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3996 while(cur) |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3997 { |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
3998 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
|
3999 cur = cur->tinst; |
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 } |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
4002 else |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
4003 { |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
4004 cur = this; |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
4005 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
|
4006 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
|
4007 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
|
4008 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
|
4009 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
|
4010 {} |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
4011 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
|
4012 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
|
4013 } |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
4014 } |
d4e95db0e62b
Introducing template instantiation traces for static asserts and errors within templates.
Christian Kamm <kamm incasoftware de>
parents:
527
diff
changeset
|
4015 |
336 | 4016 /* ======================== TemplateMixin ================================ */ |
4017 | |
4018 TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, | |
4019 Array *idents, Objects *tiargs) | |
4020 : TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1]) | |
4021 { | |
4022 //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); | |
4023 this->ident = ident; | |
4024 this->tqual = tqual; | |
4025 this->idents = idents; | |
4026 this->tiargs = tiargs ? tiargs : new Objects(); | |
4027 this->scope = NULL; | |
4028 } | |
4029 | |
4030 Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) | |
4031 { TemplateMixin *tm; | |
4032 | |
4033 Array *ids = new Array(); | |
4034 ids->setDim(idents->dim); | |
4035 for (int i = 0; i < idents->dim; i++) | |
4036 { // Matches TypeQualified::syntaxCopyHelper() | |
4037 Identifier *id = (Identifier *)idents->data[i]; | |
4038 if (id->dyncast() == DYNCAST_DSYMBOL) | |
4039 { | |
4040 TemplateInstance *ti = (TemplateInstance *)id; | |
4041 | |
4042 ti = (TemplateInstance *)ti->syntaxCopy(NULL); | |
4043 id = (Identifier *)ti; | |
4044 } | |
4045 ids->data[i] = id; | |
4046 } | |
4047 | |
4048 tm = new TemplateMixin(loc, ident, | |
4049 (Type *)(tqual ? tqual->syntaxCopy() : NULL), | |
4050 ids, tiargs); | |
4051 TemplateInstance::syntaxCopy(tm); | |
4052 return tm; | |
4053 } | |
4054 | |
4055 void TemplateMixin::semantic(Scope *sc) | |
4056 { | |
4057 #if LOG | |
4058 printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); | |
4059 fflush(stdout); | |
4060 #endif | |
4061 if (semanticdone && | |
4062 // This for when a class/struct contains mixin members, and | |
4063 // is done over because of forward references | |
4064 (!parent || !toParent()->isAggregateDeclaration())) | |
4065 { | |
4066 #if LOG | |
4067 printf("\tsemantic done\n"); | |
4068 #endif | |
4069 return; | |
4070 } | |
4071 if (!semanticdone) | |
4072 semanticdone = 1; | |
4073 #if LOG | |
4074 printf("\tdo semantic\n"); | |
4075 #endif | |
4076 | |
4077 #if !IN_LLVM | |
4078 // dont know what this is | |
4079 util_progress(); | |
4080 #endif | |
4081 | |
4082 Scope *scx = NULL; | |
4083 if (scope) | |
4084 { sc = scope; | |
4085 scx = scope; // save so we don't make redundant copies | |
4086 scope = NULL; | |
4087 } | |
4088 | |
4089 // Follow qualifications to find the TemplateDeclaration | |
4090 if (!tempdecl) | |
4091 { Dsymbol *s; | |
4092 int i; | |
4093 Identifier *id; | |
4094 | |
4095 if (tqual) | |
4096 { s = tqual->toDsymbol(sc); | |
4097 i = 0; | |
4098 } | |
4099 else | |
4100 { | |
4101 i = 1; | |
4102 id = (Identifier *)idents->data[0]; | |
4103 switch (id->dyncast()) | |
4104 { | |
4105 case DYNCAST_IDENTIFIER: | |
4106 s = sc->search(loc, id, NULL); | |
4107 break; | |
4108 | |
4109 case DYNCAST_DSYMBOL: | |
4110 { | |
4111 TemplateInstance *ti = (TemplateInstance *)id; | |
4112 ti->semantic(sc); | |
4113 s = ti; | |
4114 break; | |
4115 } | |
4116 default: | |
4117 assert(0); | |
4118 } | |
4119 } | |
4120 | |
4121 for (; i < idents->dim; i++) | |
4122 { | |
4123 if (!s) | |
4124 break; | |
4125 id = (Identifier *)idents->data[i]; | |
4126 s = s->searchX(loc, sc, id); | |
4127 } | |
4128 if (!s) | |
4129 { | |
4130 error("is not defined"); | |
4131 inst = this; | |
4132 return; | |
4133 } | |
4134 tempdecl = s->toAlias()->isTemplateDeclaration(); | |
4135 if (!tempdecl) | |
4136 { | |
4137 error("%s isn't a template", s->toChars()); | |
4138 inst = this; | |
4139 return; | |
4140 } | |
4141 } | |
4142 | |
4143 // Look for forward reference | |
4144 assert(tempdecl); | |
4145 for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) | |
4146 { | |
4147 if (!td->scope) | |
4148 { | |
4149 /* Cannot handle forward references if mixin is a struct member, | |
4150 * because addField must happen during struct's semantic, not | |
4151 * during the mixin semantic. | |
4152 * runDeferred will re-run mixin's semantic outside of the struct's | |
4153 * semantic. | |
4154 */ | |
4155 semanticdone = 0; | |
4156 AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); | |
4157 if (ad) | |
4158 ad->sizeok = 2; | |
4159 else | |
4160 { | |
4161 // Forward reference | |
4162 //printf("forward reference - deferring\n"); | |
4163 scope = scx ? scx : new Scope(*sc); | |
4164 scope->setNoFree(); | |
4165 scope->module->addDeferredSemantic(this); | |
4166 } | |
4167 return; | |
4168 } | |
4169 } | |
4170 | |
4171 // Run semantic on each argument, place results in tiargs[] | |
4172 semanticTiargs(sc); | |
4173 | |
4174 tempdecl = findBestMatch(sc); | |
4175 if (!tempdecl) | |
4176 { inst = this; | |
4177 return; // error recovery | |
4178 } | |
4179 | |
4180 if (!ident) | |
4181 ident = genIdent(); | |
4182 | |
4183 inst = this; | |
4184 parent = sc->parent; | |
4185 | |
4186 /* Detect recursive mixin instantiations. | |
4187 */ | |
4188 for (Dsymbol *s = parent; s; s = s->parent) | |
4189 { | |
4190 //printf("\ts = '%s'\n", s->toChars()); | |
4191 TemplateMixin *tm = s->isTemplateMixin(); | |
4192 if (!tm || tempdecl != tm->tempdecl) | |
4193 continue; | |
4194 | |
4195 /* Different argument list lengths happen with variadic args | |
4196 */ | |
4197 if (tiargs->dim != tm->tiargs->dim) | |
4198 continue; | |
4199 | |
4200 for (int i = 0; i < tiargs->dim; i++) | |
4201 { Object *o = (Object *)tiargs->data[i]; | |
4202 Type *ta = isType(o); | |
4203 Expression *ea = isExpression(o); | |
4204 Dsymbol *sa = isDsymbol(o); | |
4205 Object *tmo = (Object *)tm->tiargs->data[i]; | |
4206 if (ta) | |
4207 { | |
4208 Type *tmta = isType(tmo); | |
4209 if (!tmta) | |
4210 goto Lcontinue; | |
4211 if (!ta->equals(tmta)) | |
4212 goto Lcontinue; | |
4213 } | |
4214 else if (ea) | |
4215 { Expression *tme = isExpression(tmo); | |
4216 if (!tme || !ea->equals(tme)) | |
4217 goto Lcontinue; | |
4218 } | |
4219 else if (sa) | |
4220 { | |
4221 Dsymbol *tmsa = isDsymbol(tmo); | |
4222 if (sa != tmsa) | |
4223 goto Lcontinue; | |
4224 } | |
4225 else | |
4226 assert(0); | |
4227 } | |
4228 error("recursive mixin instantiation"); | |
4229 return; | |
4230 | |
4231 Lcontinue: | |
4232 continue; | |
4233 } | |
4234 | |
4235 // Copy the syntax trees from the TemplateDeclaration | |
4236 members = Dsymbol::arraySyntaxCopy(tempdecl->members); | |
4237 if (!members) | |
4238 return; | |
4239 | |
4240 symtab = new DsymbolTable(); | |
4241 | |
4242 for (Scope *sce = sc; 1; sce = sce->enclosing) | |
4243 { | |
4244 ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; | |
4245 if (sds) | |
4246 { | |
4247 sds->importScope(this, PROTpublic); | |
4248 break; | |
4249 } | |
4250 } | |
4251 | |
4252 #if LOG | |
4253 printf("\tcreate scope for template parameters '%s'\n", toChars()); | |
4254 #endif | |
4255 Scope *scy = sc; | |
4256 scy = sc->push(this); | |
4257 scy->parent = this; | |
4258 | |
4259 argsym = new ScopeDsymbol(); | |
4260 argsym->parent = scy->parent; | |
4261 Scope *scope = scy->push(argsym); | |
4262 | |
4263 unsigned errorsave = global.errors; | |
4264 | |
4265 // Declare each template parameter as an alias for the argument type | |
4266 declareParameters(scope); | |
4267 | |
4268 // Add members to enclosing scope, as well as this scope | |
4269 for (unsigned i = 0; i < members->dim; i++) | |
4270 { Dsymbol *s; | |
4271 | |
4272 s = (Dsymbol *)members->data[i]; | |
4273 s->addMember(scope, this, i); | |
4274 //sc->insert(s); | |
4275 //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); | |
4276 //printf("s->parent = %s\n", s->parent->toChars()); | |
4277 } | |
4278 | |
4279 // Do semantic() analysis on template instance members | |
4280 #if LOG | |
4281 printf("\tdo semantic() on template instance members '%s'\n", toChars()); | |
4282 #endif | |
4283 Scope *sc2; | |
4284 sc2 = scope->push(this); | |
4285 sc2->offset = sc->offset; | |
4286 for (int i = 0; i < members->dim; i++) | |
4287 { | |
4288 Dsymbol *s = (Dsymbol *)members->data[i]; | |
4289 s->semantic(sc2); | |
4290 } | |
4291 sc->offset = sc2->offset; | |
4292 | |
4293 /* The problem is when to parse the initializer for a variable. | |
4294 * Perhaps VarDeclaration::semantic() should do it like it does | |
4295 * for initializers inside a function. | |
4296 */ | |
4297 // if (sc->parent->isFuncDeclaration()) | |
4298 | |
4299 semantic2(sc2); | |
4300 | |
4301 if (sc->func) | |
4302 { | |
4303 semantic3(sc2); | |
4304 } | |
4305 | |
4306 // Give additional context info if error occurred during instantiation | |
4307 if (global.errors != errorsave) | |
4308 { | |
4309 error("error instantiating"); | |
4310 } | |
4311 | |
4312 sc2->pop(); | |
4313 | |
4314 scope->pop(); | |
4315 | |
4316 // if (!isAnonymous()) | |
4317 { | |
4318 scy->pop(); | |
4319 } | |
4320 #if LOG | |
4321 printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); | |
4322 #endif | |
4323 } | |
4324 | |
4325 void TemplateMixin::semantic2(Scope *sc) | |
4326 { int i; | |
4327 | |
4328 if (semanticdone >= 2) | |
4329 return; | |
4330 semanticdone = 2; | |
4331 #if LOG | |
4332 printf("+TemplateMixin::semantic2('%s')\n", toChars()); | |
4333 #endif | |
4334 if (members) | |
4335 { | |
4336 assert(sc); | |
4337 sc = sc->push(argsym); | |
4338 sc = sc->push(this); | |
4339 for (i = 0; i < members->dim; i++) | |
4340 { | |
4341 Dsymbol *s = (Dsymbol *)members->data[i]; | |
4342 #if LOG | |
4343 printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); | |
4344 #endif | |
4345 s->semantic2(sc); | |
4346 } | |
4347 sc = sc->pop(); | |
4348 sc->pop(); | |
4349 } | |
4350 #if LOG | |
4351 printf("-TemplateMixin::semantic2('%s')\n", toChars()); | |
4352 #endif | |
4353 } | |
4354 | |
4355 void TemplateMixin::semantic3(Scope *sc) | |
4356 { int i; | |
4357 | |
4358 if (semanticdone >= 3) | |
4359 return; | |
4360 semanticdone = 3; | |
4361 #if LOG | |
4362 printf("TemplateMixin::semantic3('%s')\n", toChars()); | |
4363 #endif | |
4364 if (members) | |
4365 { | |
4366 sc = sc->push(argsym); | |
4367 sc = sc->push(this); | |
4368 for (i = 0; i < members->dim; i++) | |
4369 { | |
4370 Dsymbol *s = (Dsymbol *)members->data[i]; | |
4371 s->semantic3(sc); | |
4372 } | |
4373 sc = sc->pop(); | |
4374 sc->pop(); | |
4375 } | |
4376 } | |
4377 | |
4378 void TemplateMixin::inlineScan() | |
4379 { | |
4380 TemplateInstance::inlineScan(); | |
4381 } | |
4382 | |
4383 const char *TemplateMixin::kind() | |
4384 { | |
4385 return "mixin"; | |
4386 } | |
4387 | |
4388 int TemplateMixin::oneMember(Dsymbol **ps) | |
4389 { | |
4390 return Dsymbol::oneMember(ps); | |
4391 } | |
4392 | |
4393 int TemplateMixin::hasPointers() | |
4394 { | |
4395 //printf("TemplateMixin::hasPointers() %s\n", toChars()); | |
4396 for (size_t i = 0; i < members->dim; i++) | |
4397 { | |
4398 Dsymbol *s = (Dsymbol *)members->data[i]; | |
4399 //printf(" s = %s %s\n", s->kind(), s->toChars()); | |
4400 if (s->hasPointers()) | |
4401 { | |
4402 return 1; | |
4403 } | |
4404 } | |
4405 return 0; | |
4406 } | |
4407 | |
4408 char *TemplateMixin::toChars() | |
4409 { | |
4410 OutBuffer buf; | |
4411 HdrGenState hgs; | |
4412 char *s; | |
4413 | |
4414 TemplateInstance::toCBuffer(&buf, &hgs); | |
4415 s = buf.toChars(); | |
4416 buf.data = NULL; | |
4417 return s; | |
4418 } | |
4419 | |
4420 void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
4421 { | |
4422 buf->writestring("mixin "); | |
4423 | |
4424 for (int i = 0; i < idents->dim; i++) | |
4425 { Identifier *id = (Identifier *)idents->data[i]; | |
4426 | |
4427 if (i) | |
4428 buf->writeByte('.'); | |
4429 buf->writestring(id->toChars()); | |
4430 } | |
4431 buf->writestring("!("); | |
4432 if (tiargs) | |
4433 { | |
4434 for (int i = 0; i < tiargs->dim; i++) | |
4435 { if (i) | |
4436 buf->writebyte(','); | |
4437 Object *oarg = (Object *)tiargs->data[i]; | |
4438 Type *t = isType(oarg); | |
4439 Expression *e = isExpression(oarg); | |
4440 Dsymbol *s = isDsymbol(oarg); | |
4441 if (t) | |
4442 t->toCBuffer(buf, NULL, hgs); | |
4443 else if (e) | |
4444 e->toCBuffer(buf, hgs); | |
4445 else if (s) | |
4446 { | |
4447 char *p = s->ident ? s->ident->toChars() : s->toChars(); | |
4448 buf->writestring(p); | |
4449 } | |
4450 else if (!oarg) | |
4451 { | |
4452 buf->writestring("NULL"); | |
4453 } | |
4454 else | |
4455 { | |
4456 assert(0); | |
4457 } | |
4458 } | |
4459 } | |
4460 buf->writebyte(')'); | |
4461 if (ident) | |
4462 { | |
4463 buf->writebyte(' '); | |
4464 buf->writestring(ident->toChars()); | |
4465 } | |
4466 buf->writebyte(';'); | |
4467 buf->writenl(); | |
4468 } | |
4469 | |
4470 | |
4471 void TemplateMixin::toObjFile(int multiobj) | |
4472 { | |
4473 //printf("TemplateMixin::toObjFile('%s')\n", toChars()); | |
4474 TemplateInstance::toObjFile(multiobj); | |
4475 } | |
4476 |