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