Mercurial > projects > ldc
comparison dmd2/opover.c @ 758:f04dde6e882c
Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:38:48 +0100 |
parents | |
children | 356e65836fb5 |
comparison
equal
deleted
inserted
replaced
757:2c730d530c98 | 758:f04dde6e882c |
---|---|
1 | |
2 // Compiler implementation of the D programming language | |
3 // Copyright (c) 1999-2007 by Digital Mars | |
4 // All Rights Reserved | |
5 // written by Walter Bright | |
6 // http://www.digitalmars.com | |
7 // License for redistribution is by either the Artistic License | |
8 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
9 // See the included readme.txt for details. | |
10 | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <ctype.h> | |
14 #include <assert.h> | |
15 #include <complex> | |
16 | |
17 #ifdef __APPLE__ | |
18 #define integer_t dmd_integer_t | |
19 #endif | |
20 | |
21 #if IN_GCC || IN_LLVM | |
22 #include "mem.h" | |
23 #elif POSIX | |
24 #include "../root/mem.h" | |
25 #elif _WIN32 | |
26 #include "..\root\mem.h" | |
27 #endif | |
28 | |
29 //#include "port.h" | |
30 #include "mtype.h" | |
31 #include "init.h" | |
32 #include "expression.h" | |
33 #include "id.h" | |
34 #include "declaration.h" | |
35 #include "aggregate.h" | |
36 #include "template.h" | |
37 | |
38 static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments); | |
39 static void inferApplyArgTypesZ(TemplateDeclaration *tstart, Arguments *arguments); | |
40 static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments); | |
41 static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments); | |
42 | |
43 /******************************** Expression **************************/ | |
44 | |
45 | |
46 /*********************************** | |
47 * Determine if operands of binary op can be reversed | |
48 * to fit operator overload. | |
49 */ | |
50 | |
51 int Expression::isCommutative() | |
52 { | |
53 return FALSE; // default is no reverse | |
54 } | |
55 | |
56 /*********************************** | |
57 * Get Identifier for operator overload. | |
58 */ | |
59 | |
60 Identifier *Expression::opId() | |
61 { | |
62 assert(0); | |
63 return NULL; | |
64 } | |
65 | |
66 /*********************************** | |
67 * Get Identifier for reverse operator overload, | |
68 * NULL if not supported for this operator. | |
69 */ | |
70 | |
71 Identifier *Expression::opId_r() | |
72 { | |
73 return NULL; | |
74 } | |
75 | |
76 /************************* Operators *****************************/ | |
77 | |
78 Identifier *UAddExp::opId() { return Id::uadd; } | |
79 | |
80 Identifier *NegExp::opId() { return Id::neg; } | |
81 | |
82 Identifier *ComExp::opId() { return Id::com; } | |
83 | |
84 Identifier *CastExp::opId() { return Id::cast; } | |
85 | |
86 Identifier *InExp::opId() { return Id::opIn; } | |
87 Identifier *InExp::opId_r() { return Id::opIn_r; } | |
88 | |
89 Identifier *PostExp::opId() { return (op == TOKplusplus) | |
90 ? Id::postinc | |
91 : Id::postdec; } | |
92 | |
93 int AddExp::isCommutative() { return TRUE; } | |
94 Identifier *AddExp::opId() { return Id::add; } | |
95 Identifier *AddExp::opId_r() { return Id::add_r; } | |
96 | |
97 Identifier *MinExp::opId() { return Id::sub; } | |
98 Identifier *MinExp::opId_r() { return Id::sub_r; } | |
99 | |
100 int MulExp::isCommutative() { return TRUE; } | |
101 Identifier *MulExp::opId() { return Id::mul; } | |
102 Identifier *MulExp::opId_r() { return Id::mul_r; } | |
103 | |
104 Identifier *DivExp::opId() { return Id::div; } | |
105 Identifier *DivExp::opId_r() { return Id::div_r; } | |
106 | |
107 Identifier *ModExp::opId() { return Id::mod; } | |
108 Identifier *ModExp::opId_r() { return Id::mod_r; } | |
109 | |
110 Identifier *ShlExp::opId() { return Id::shl; } | |
111 Identifier *ShlExp::opId_r() { return Id::shl_r; } | |
112 | |
113 Identifier *ShrExp::opId() { return Id::shr; } | |
114 Identifier *ShrExp::opId_r() { return Id::shr_r; } | |
115 | |
116 Identifier *UshrExp::opId() { return Id::ushr; } | |
117 Identifier *UshrExp::opId_r() { return Id::ushr_r; } | |
118 | |
119 int AndExp::isCommutative() { return TRUE; } | |
120 Identifier *AndExp::opId() { return Id::iand; } | |
121 Identifier *AndExp::opId_r() { return Id::iand_r; } | |
122 | |
123 int OrExp::isCommutative() { return TRUE; } | |
124 Identifier *OrExp::opId() { return Id::ior; } | |
125 Identifier *OrExp::opId_r() { return Id::ior_r; } | |
126 | |
127 int XorExp::isCommutative() { return TRUE; } | |
128 Identifier *XorExp::opId() { return Id::ixor; } | |
129 Identifier *XorExp::opId_r() { return Id::ixor_r; } | |
130 | |
131 Identifier *CatExp::opId() { return Id::cat; } | |
132 Identifier *CatExp::opId_r() { return Id::cat_r; } | |
133 | |
134 Identifier * AssignExp::opId() { return Id::assign; } | |
135 Identifier * AddAssignExp::opId() { return Id::addass; } | |
136 Identifier * MinAssignExp::opId() { return Id::subass; } | |
137 Identifier * MulAssignExp::opId() { return Id::mulass; } | |
138 Identifier * DivAssignExp::opId() { return Id::divass; } | |
139 Identifier * ModAssignExp::opId() { return Id::modass; } | |
140 Identifier * AndAssignExp::opId() { return Id::andass; } | |
141 Identifier * OrAssignExp::opId() { return Id::orass; } | |
142 Identifier * XorAssignExp::opId() { return Id::xorass; } | |
143 Identifier * ShlAssignExp::opId() { return Id::shlass; } | |
144 Identifier * ShrAssignExp::opId() { return Id::shrass; } | |
145 Identifier *UshrAssignExp::opId() { return Id::ushrass; } | |
146 Identifier * CatAssignExp::opId() { return Id::catass; } | |
147 | |
148 int EqualExp::isCommutative() { return TRUE; } | |
149 Identifier *EqualExp::opId() { return Id::eq; } | |
150 | |
151 int CmpExp::isCommutative() { return TRUE; } | |
152 Identifier *CmpExp::opId() { return Id::cmp; } | |
153 | |
154 Identifier *ArrayExp::opId() { return Id::index; } | |
155 Identifier *PtrExp::opId() { return Id::opStar; } | |
156 | |
157 /************************************ | |
158 * Operator overload. | |
159 * Check for operator overload, if so, replace | |
160 * with function call. | |
161 * Return NULL if not an operator overload. | |
162 */ | |
163 | |
164 Expression *UnaExp::op_overload(Scope *sc) | |
165 { | |
166 AggregateDeclaration *ad; | |
167 Dsymbol *fd; | |
168 Type *t1 = e1->type->toBasetype(); | |
169 | |
170 if (t1->ty == Tclass) | |
171 { | |
172 ad = ((TypeClass *)t1)->sym; | |
173 goto L1; | |
174 } | |
175 else if (t1->ty == Tstruct) | |
176 { | |
177 ad = ((TypeStruct *)t1)->sym; | |
178 | |
179 L1: | |
180 fd = search_function(ad, opId()); | |
181 if (fd) | |
182 { | |
183 if (op == TOKarray) | |
184 { | |
185 Expression *e; | |
186 ArrayExp *ae = (ArrayExp *)this; | |
187 | |
188 e = new DotIdExp(loc, e1, fd->ident); | |
189 e = new CallExp(loc, e, ae->arguments); | |
190 e = e->semantic(sc); | |
191 return e; | |
192 } | |
193 else | |
194 { | |
195 // Rewrite +e1 as e1.add() | |
196 return build_overload(loc, sc, e1, NULL, fd->ident); | |
197 } | |
198 } | |
199 } | |
200 return NULL; | |
201 } | |
202 | |
203 | |
204 Expression *BinExp::op_overload(Scope *sc) | |
205 { | |
206 //printf("BinExp::op_overload() (%s)\n", toChars()); | |
207 | |
208 AggregateDeclaration *ad; | |
209 Type *t1 = e1->type->toBasetype(); | |
210 Type *t2 = e2->type->toBasetype(); | |
211 Identifier *id = opId(); | |
212 Identifier *id_r = opId_r(); | |
213 | |
214 Match m; | |
215 Expressions args1; | |
216 Expressions args2; | |
217 int argsset = 0; | |
218 | |
219 AggregateDeclaration *ad1; | |
220 if (t1->ty == Tclass) | |
221 ad1 = ((TypeClass *)t1)->sym; | |
222 else if (t1->ty == Tstruct) | |
223 ad1 = ((TypeStruct *)t1)->sym; | |
224 else | |
225 ad1 = NULL; | |
226 | |
227 AggregateDeclaration *ad2; | |
228 if (t2->ty == Tclass) | |
229 ad2 = ((TypeClass *)t2)->sym; | |
230 else if (t2->ty == Tstruct) | |
231 ad2 = ((TypeStruct *)t2)->sym; | |
232 else | |
233 ad2 = NULL; | |
234 | |
235 Dsymbol *s = NULL; | |
236 Dsymbol *s_r = NULL; | |
237 FuncDeclaration *fd = NULL; | |
238 TemplateDeclaration *td = NULL; | |
239 if (ad1 && id) | |
240 { | |
241 s = search_function(ad1, id); | |
242 } | |
243 if (ad2 && id_r) | |
244 { | |
245 s_r = search_function(ad2, id_r); | |
246 } | |
247 | |
248 if (s || s_r) | |
249 { | |
250 /* Try: | |
251 * a.opfunc(b) | |
252 * b.opfunc_r(a) | |
253 * and see which is better. | |
254 */ | |
255 Expression *e; | |
256 FuncDeclaration *lastf; | |
257 | |
258 args1.setDim(1); | |
259 args1.data[0] = (void*) e1; | |
260 args2.setDim(1); | |
261 args2.data[0] = (void*) e2; | |
262 argsset = 1; | |
263 | |
264 memset(&m, 0, sizeof(m)); | |
265 m.last = MATCHnomatch; | |
266 | |
267 if (s) | |
268 { | |
269 fd = s->isFuncDeclaration(); | |
270 if (fd) | |
271 { | |
272 overloadResolveX(&m, fd, NULL, &args2); | |
273 } | |
274 else | |
275 { td = s->isTemplateDeclaration(); | |
276 templateResolve(&m, td, sc, loc, NULL, NULL, &args2); | |
277 } | |
278 } | |
279 | |
280 lastf = m.lastf; | |
281 | |
282 if (s_r) | |
283 { | |
284 fd = s_r->isFuncDeclaration(); | |
285 if (fd) | |
286 { | |
287 overloadResolveX(&m, fd, NULL, &args1); | |
288 } | |
289 else | |
290 { td = s_r->isTemplateDeclaration(); | |
291 templateResolve(&m, td, sc, loc, NULL, NULL, &args1); | |
292 } | |
293 } | |
294 | |
295 if (m.count > 1) | |
296 { | |
297 // Error, ambiguous | |
298 error("overloads %s and %s both match argument list for %s", | |
299 m.lastf->type->toChars(), | |
300 m.nextf->type->toChars(), | |
301 m.lastf->toChars()); | |
302 } | |
303 else if (m.last == MATCHnomatch) | |
304 { | |
305 m.lastf = m.anyf; | |
306 } | |
307 | |
308 if (op == TOKplusplus || op == TOKminusminus) | |
309 // Kludge because operator overloading regards e++ and e-- | |
310 // as unary, but it's implemented as a binary. | |
311 // Rewrite (e1 ++ e2) as e1.postinc() | |
312 // Rewrite (e1 -- e2) as e1.postdec() | |
313 e = build_overload(loc, sc, e1, NULL, id); | |
314 else if (lastf && m.lastf == lastf || m.last == MATCHnomatch) | |
315 // Rewrite (e1 op e2) as e1.opfunc(e2) | |
316 e = build_overload(loc, sc, e1, e2, id); | |
317 else | |
318 // Rewrite (e1 op e2) as e2.opfunc_r(e1) | |
319 e = build_overload(loc, sc, e2, e1, id_r); | |
320 return e; | |
321 } | |
322 | |
323 if (isCommutative()) | |
324 { | |
325 s = NULL; | |
326 s_r = NULL; | |
327 if (ad1 && id_r) | |
328 { | |
329 s_r = search_function(ad1, id_r); | |
330 } | |
331 if (ad2 && id) | |
332 { | |
333 s = search_function(ad2, id); | |
334 } | |
335 | |
336 if (s || s_r) | |
337 { | |
338 /* Try: | |
339 * a.opfunc_r(b) | |
340 * b.opfunc(a) | |
341 * and see which is better. | |
342 */ | |
343 Expression *e; | |
344 FuncDeclaration *lastf; | |
345 | |
346 if (!argsset) | |
347 { args1.setDim(1); | |
348 args1.data[0] = (void*) e1; | |
349 args2.setDim(1); | |
350 args2.data[0] = (void*) e2; | |
351 } | |
352 | |
353 memset(&m, 0, sizeof(m)); | |
354 m.last = MATCHnomatch; | |
355 | |
356 if (s_r) | |
357 { | |
358 fd = s_r->isFuncDeclaration(); | |
359 if (fd) | |
360 { | |
361 overloadResolveX(&m, fd, NULL, &args2); | |
362 } | |
363 else | |
364 { td = s_r->isTemplateDeclaration(); | |
365 templateResolve(&m, td, sc, loc, NULL, NULL, &args2); | |
366 } | |
367 } | |
368 lastf = m.lastf; | |
369 | |
370 if (s) | |
371 { | |
372 fd = s->isFuncDeclaration(); | |
373 if (fd) | |
374 { | |
375 overloadResolveX(&m, fd, NULL, &args1); | |
376 } | |
377 else | |
378 { td = s->isTemplateDeclaration(); | |
379 templateResolve(&m, td, sc, loc, NULL, NULL, &args1); | |
380 } | |
381 } | |
382 | |
383 if (m.count > 1) | |
384 { | |
385 // Error, ambiguous | |
386 error("overloads %s and %s both match argument list for %s", | |
387 m.lastf->type->toChars(), | |
388 m.nextf->type->toChars(), | |
389 m.lastf->toChars()); | |
390 } | |
391 else if (m.last == MATCHnomatch) | |
392 { | |
393 m.lastf = m.anyf; | |
394 } | |
395 | |
396 if (lastf && m.lastf == lastf || | |
397 id_r && m.last == MATCHnomatch) | |
398 // Rewrite (e1 op e2) as e1.opfunc_r(e2) | |
399 e = build_overload(loc, sc, e1, e2, id_r); | |
400 else | |
401 // Rewrite (e1 op e2) as e2.opfunc(e1) | |
402 e = build_overload(loc, sc, e2, e1, id); | |
403 | |
404 // When reversing operands of comparison operators, | |
405 // need to reverse the sense of the op | |
406 switch (op) | |
407 { | |
408 case TOKlt: op = TOKgt; break; | |
409 case TOKgt: op = TOKlt; break; | |
410 case TOKle: op = TOKge; break; | |
411 case TOKge: op = TOKle; break; | |
412 | |
413 // Floating point compares | |
414 case TOKule: op = TOKuge; break; | |
415 case TOKul: op = TOKug; break; | |
416 case TOKuge: op = TOKule; break; | |
417 case TOKug: op = TOKul; break; | |
418 | |
419 // These are symmetric | |
420 case TOKunord: | |
421 case TOKlg: | |
422 case TOKleg: | |
423 case TOKue: | |
424 break; | |
425 } | |
426 | |
427 return e; | |
428 } | |
429 } | |
430 | |
431 return NULL; | |
432 } | |
433 | |
434 /*********************************** | |
435 * Utility to build a function call out of this reference and argument. | |
436 */ | |
437 | |
438 Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id) | |
439 { | |
440 Expression *e; | |
441 | |
442 //printf("build_overload(id = '%s')\n", id->toChars()); | |
443 //earg->print(); | |
444 //earg->type->print(); | |
445 e = new DotIdExp(loc, ethis, id); | |
446 | |
447 if (earg) | |
448 e = new CallExp(loc, e, earg); | |
449 else | |
450 e = new CallExp(loc, e); | |
451 | |
452 e = e->semantic(sc); | |
453 return e; | |
454 } | |
455 | |
456 /*************************************** | |
457 * Search for function funcid in aggregate ad. | |
458 */ | |
459 | |
460 Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid) | |
461 { | |
462 Dsymbol *s; | |
463 FuncDeclaration *fd; | |
464 TemplateDeclaration *td; | |
465 | |
466 s = ad->search(0, funcid, 0); | |
467 if (s) | |
468 { Dsymbol *s2; | |
469 | |
470 //printf("search_function: s = '%s'\n", s->kind()); | |
471 s2 = s->toAlias(); | |
472 //printf("search_function: s2 = '%s'\n", s2->kind()); | |
473 fd = s2->isFuncDeclaration(); | |
474 if (fd && fd->type->ty == Tfunction) | |
475 return fd; | |
476 | |
477 td = s2->isTemplateDeclaration(); | |
478 if (td) | |
479 return td; | |
480 } | |
481 return NULL; | |
482 } | |
483 | |
484 | |
485 /***************************************** | |
486 * Given array of arguments and an aggregate type, | |
487 * if any of the argument types are missing, attempt to infer | |
488 * them from the aggregate type. | |
489 */ | |
490 | |
491 void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr) | |
492 { | |
493 if (!arguments || !arguments->dim) | |
494 return; | |
495 | |
496 /* Return if no arguments need types. | |
497 */ | |
498 for (size_t u = 0; 1; u++) | |
499 { if (u == arguments->dim) | |
500 return; | |
501 Argument *arg = (Argument *)arguments->data[u]; | |
502 if (!arg->type) | |
503 break; | |
504 } | |
505 | |
506 AggregateDeclaration *ad; | |
507 | |
508 Argument *arg = (Argument *)arguments->data[0]; | |
509 Type *taggr = aggr->type; | |
510 if (!taggr) | |
511 return; | |
512 Type *tab = taggr->toBasetype(); | |
513 switch (tab->ty) | |
514 { | |
515 case Tarray: | |
516 case Tsarray: | |
517 case Ttuple: | |
518 if (arguments->dim == 2) | |
519 { | |
520 if (!arg->type) | |
521 arg->type = Type::tsize_t; // key type | |
522 arg = (Argument *)arguments->data[1]; | |
523 } | |
524 if (!arg->type && tab->ty != Ttuple) | |
525 arg->type = tab->nextOf(); // value type | |
526 break; | |
527 | |
528 case Taarray: | |
529 { TypeAArray *taa = (TypeAArray *)tab; | |
530 | |
531 if (arguments->dim == 2) | |
532 { | |
533 if (!arg->type) | |
534 arg->type = taa->index; // key type | |
535 arg = (Argument *)arguments->data[1]; | |
536 } | |
537 if (!arg->type) | |
538 arg->type = taa->next; // value type | |
539 break; | |
540 } | |
541 | |
542 case Tclass: | |
543 ad = ((TypeClass *)tab)->sym; | |
544 goto Laggr; | |
545 | |
546 case Tstruct: | |
547 ad = ((TypeStruct *)tab)->sym; | |
548 goto Laggr; | |
549 | |
550 Laggr: | |
551 #if 0 | |
552 if (arguments->dim == 1) | |
553 { | |
554 if (!arg->type) | |
555 { | |
556 /* Look for an opNext() overload | |
557 */ | |
558 Dsymbol *s = search_function(ad, Id::next); | |
559 fd = s ? s->isFuncDeclaration() : NULL; | |
560 if (!fd) | |
561 goto Lapply; | |
562 arg->type = fd->type->next; | |
563 } | |
564 break; | |
565 } | |
566 #endif | |
567 Lapply: | |
568 { /* Look for an | |
569 * int opApply(int delegate(ref Type [, ...]) dg); | |
570 * overload | |
571 */ | |
572 Dsymbol *s = search_function(ad, | |
573 (op == TOKforeach_reverse) ? Id::applyReverse | |
574 : Id::apply); | |
575 if (s) | |
576 { | |
577 FuncDeclaration *fd = s->isFuncDeclaration(); | |
578 if (fd) | |
579 { inferApplyArgTypesX(fd, arguments); | |
580 break; | |
581 } | |
582 #if 0 | |
583 TemplateDeclaration *td = s->isTemplateDeclaration(); | |
584 if (td) | |
585 { inferApplyArgTypesZ(td, arguments); | |
586 break; | |
587 } | |
588 #endif | |
589 } | |
590 break; | |
591 } | |
592 | |
593 case Tdelegate: | |
594 { | |
595 if (0 && aggr->op == TOKdelegate) | |
596 { DelegateExp *de = (DelegateExp *)aggr; | |
597 | |
598 FuncDeclaration *fd = de->func->isFuncDeclaration(); | |
599 if (fd) | |
600 inferApplyArgTypesX(fd, arguments); | |
601 } | |
602 else | |
603 { | |
604 inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments); | |
605 } | |
606 break; | |
607 } | |
608 | |
609 default: | |
610 break; // ignore error, caught later | |
611 } | |
612 } | |
613 | |
614 /******************************** | |
615 * Recursive helper function, | |
616 * analogous to func.overloadResolveX(). | |
617 */ | |
618 | |
619 int fp3(void *param, FuncDeclaration *f) | |
620 { | |
621 Arguments *arguments = (Arguments *)param; | |
622 TypeFunction *tf = (TypeFunction *)f->type; | |
623 if (inferApplyArgTypesY(tf, arguments) == 1) | |
624 return 0; | |
625 if (arguments->dim == 0) | |
626 return 1; | |
627 return 0; | |
628 } | |
629 | |
630 static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments) | |
631 { | |
632 overloadApply(fstart, &fp3, arguments); | |
633 } | |
634 | |
635 /****************************** | |
636 * Infer arguments from type of function. | |
637 * Returns: | |
638 * 0 match for this function | |
639 * 1 no match for this function | |
640 */ | |
641 | |
642 static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments) | |
643 { size_t nparams; | |
644 Argument *p; | |
645 | |
646 if (Argument::dim(tf->parameters) != 1) | |
647 goto Lnomatch; | |
648 p = Argument::getNth(tf->parameters, 0); | |
649 if (p->type->ty != Tdelegate) | |
650 goto Lnomatch; | |
651 tf = (TypeFunction *)p->type->nextOf(); | |
652 assert(tf->ty == Tfunction); | |
653 | |
654 /* We now have tf, the type of the delegate. Match it against | |
655 * the arguments, filling in missing argument types. | |
656 */ | |
657 nparams = Argument::dim(tf->parameters); | |
658 if (nparams == 0 || tf->varargs) | |
659 goto Lnomatch; // not enough parameters | |
660 if (arguments->dim != nparams) | |
661 goto Lnomatch; // not enough parameters | |
662 | |
663 for (size_t u = 0; u < nparams; u++) | |
664 { | |
665 Argument *arg = (Argument *)arguments->data[u]; | |
666 Argument *param = Argument::getNth(tf->parameters, u); | |
667 if (arg->type) | |
668 { if (!arg->type->equals(param->type)) | |
669 { | |
670 /* Cannot resolve argument types. Indicate an | |
671 * error by setting the number of arguments to 0. | |
672 */ | |
673 arguments->dim = 0; | |
674 goto Lmatch; | |
675 } | |
676 continue; | |
677 } | |
678 arg->type = param->type; | |
679 } | |
680 Lmatch: | |
681 return 0; | |
682 | |
683 Lnomatch: | |
684 return 1; | |
685 } | |
686 | |
687 /******************************************* | |
688 * Infer foreach arg types from a template function opApply which looks like: | |
689 * int opApply(alias int func(ref uint))() { ... } | |
690 */ | |
691 | |
692 #if 0 | |
693 void inferApplyArgTypesZ(TemplateDeclaration *tstart, Arguments *arguments) | |
694 { | |
695 for (TemplateDeclaration *td = tstart; td; td = td->overnext) | |
696 { | |
697 if (!td->scope) | |
698 { | |
699 error("forward reference to template %s", td->toChars()); | |
700 return; | |
701 } | |
702 if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) | |
703 { | |
704 error("is not a function template"); | |
705 return; | |
706 } | |
707 if (!td->parameters || td->parameters->dim != 1) | |
708 continue; | |
709 TemplateParameter *tp = (TemplateParameter *)td->parameters->data[0]; | |
710 TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); | |
711 if (!tap || !tap->specType || tap->specType->ty != Tfunction) | |
712 continue; | |
713 TypeFunction *tf = (TypeFunction *)tap->specType; | |
714 if (inferApplyArgTypesY(tf, arguments) == 0) // found it | |
715 return; | |
716 } | |
717 } | |
718 #endif | |
719 | |
720 /************************************** | |
721 */ | |
722 | |
723 static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments) | |
724 { | |
725 FuncDeclaration *fd; | |
726 | |
727 assert(td); | |
728 fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, arguments); | |
729 if (!fd) | |
730 return; | |
731 m->anyf = fd; | |
732 if (m->last >= MATCHexact) | |
733 { | |
734 m->nextf = fd; | |
735 m->count++; | |
736 } | |
737 else | |
738 { | |
739 m->last = MATCHexact; | |
740 m->lastf = fd; | |
741 m->count = 1; | |
742 } | |
743 } | |
744 |