Mercurial > hg > CbC > CbC_gcc
comparison gcc/d/dmd/opover.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 | |
2 /* Compiler implementation of the D programming language | |
3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved | |
4 * written by Walter Bright | |
5 * http://www.digitalmars.com | |
6 * Distributed under the Boost Software License, Version 1.0. | |
7 * http://www.boost.org/LICENSE_1_0.txt | |
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/opover.c | |
9 */ | |
10 | |
11 #include "root/dsystem.h" // memset() | |
12 #include "root/rmem.h" | |
13 | |
14 #include "mars.h" | |
15 #include "mtype.h" | |
16 #include "init.h" | |
17 #include "expression.h" | |
18 #include "statement.h" | |
19 #include "scope.h" | |
20 #include "id.h" | |
21 #include "declaration.h" | |
22 #include "aggregate.h" | |
23 #include "template.h" | |
24 #include "tokens.h" | |
25 | |
26 static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters); | |
27 static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags = 0); | |
28 Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id); | |
29 bool MODimplicitConv(MOD modfrom, MOD modto); | |
30 Expression *trySemantic(Expression *e, Scope *sc); | |
31 Expression *binSemanticProp(BinExp *e, Scope *sc); | |
32 Expression *semantic(Expression *e, Scope *sc); | |
33 | |
34 /******************************** Expression **************************/ | |
35 | |
36 | |
37 /*********************************** | |
38 * Determine if operands of binary op can be reversed | |
39 * to fit operator overload. | |
40 */ | |
41 | |
42 bool isCommutative(TOK op) | |
43 { | |
44 switch (op) | |
45 { | |
46 case TOKadd: | |
47 case TOKmul: | |
48 case TOKand: | |
49 case TOKor: | |
50 case TOKxor: | |
51 | |
52 // EqualExp | |
53 case TOKequal: | |
54 case TOKnotequal: | |
55 | |
56 // CmpExp | |
57 case TOKlt: | |
58 case TOKle: | |
59 case TOKgt: | |
60 case TOKge: | |
61 return true; | |
62 | |
63 default: | |
64 break; | |
65 } | |
66 return false; | |
67 } | |
68 | |
69 /*********************************** | |
70 * Get Identifier for operator overload. | |
71 */ | |
72 | |
73 static Identifier *opId(Expression *e) | |
74 { | |
75 class OpIdVisitor : public Visitor | |
76 { | |
77 public: | |
78 Identifier *id; | |
79 void visit(Expression *) { assert(0); } | |
80 void visit(UAddExp *) { id = Id::uadd; } | |
81 void visit(NegExp *) { id = Id::neg; } | |
82 void visit(ComExp *) { id = Id::com; } | |
83 void visit(CastExp *) { id = Id::_cast; } | |
84 void visit(InExp *) { id = Id::opIn; } | |
85 void visit(PostExp *e) { id = (e->op == TOKplusplus) ? Id::postinc : Id::postdec; } | |
86 void visit(AddExp *) { id = Id::add; } | |
87 void visit(MinExp *) { id = Id::sub; } | |
88 void visit(MulExp *) { id = Id::mul; } | |
89 void visit(DivExp *) { id = Id::div; } | |
90 void visit(ModExp *) { id = Id::mod; } | |
91 void visit(PowExp *) { id = Id::pow; } | |
92 void visit(ShlExp *) { id = Id::shl; } | |
93 void visit(ShrExp *) { id = Id::shr; } | |
94 void visit(UshrExp *) { id = Id::ushr; } | |
95 void visit(AndExp *) { id = Id::iand; } | |
96 void visit(OrExp *) { id = Id::ior; } | |
97 void visit(XorExp *) { id = Id::ixor; } | |
98 void visit(CatExp *) { id = Id::cat; } | |
99 void visit(AssignExp *) { id = Id::assign; } | |
100 void visit(AddAssignExp *) { id = Id::addass; } | |
101 void visit(MinAssignExp *) { id = Id::subass; } | |
102 void visit(MulAssignExp *) { id = Id::mulass; } | |
103 void visit(DivAssignExp *) { id = Id::divass; } | |
104 void visit(ModAssignExp *) { id = Id::modass; } | |
105 void visit(AndAssignExp *) { id = Id::andass; } | |
106 void visit(OrAssignExp *) { id = Id::orass; } | |
107 void visit(XorAssignExp *) { id = Id::xorass; } | |
108 void visit(ShlAssignExp *) { id = Id::shlass; } | |
109 void visit(ShrAssignExp *) { id = Id::shrass; } | |
110 void visit(UshrAssignExp *) { id = Id::ushrass; } | |
111 void visit(CatAssignExp *) { id = Id::catass; } | |
112 void visit(PowAssignExp *) { id = Id::powass; } | |
113 void visit(EqualExp *) { id = Id::eq; } | |
114 void visit(CmpExp *) { id = Id::cmp; } | |
115 void visit(ArrayExp *) { id = Id::index; } | |
116 void visit(PtrExp *) { id = Id::opStar; } | |
117 }; | |
118 OpIdVisitor v; | |
119 e->accept(&v); | |
120 return v.id; | |
121 } | |
122 | |
123 /*********************************** | |
124 * Get Identifier for reverse operator overload, | |
125 * NULL if not supported for this operator. | |
126 */ | |
127 | |
128 static Identifier *opId_r(Expression *e) | |
129 { | |
130 class OpIdRVisitor : public Visitor | |
131 { | |
132 public: | |
133 Identifier *id; | |
134 void visit(Expression *) { id = NULL; } | |
135 void visit(InExp *) { id = Id::opIn_r; } | |
136 void visit(AddExp *) { id = Id::add_r; } | |
137 void visit(MinExp *) { id = Id::sub_r; } | |
138 void visit(MulExp *) { id = Id::mul_r; } | |
139 void visit(DivExp *) { id = Id::div_r; } | |
140 void visit(ModExp *) { id = Id::mod_r; } | |
141 void visit(PowExp *) { id = Id::pow_r; } | |
142 void visit(ShlExp *) { id = Id::shl_r; } | |
143 void visit(ShrExp *) { id = Id::shr_r; } | |
144 void visit(UshrExp *) { id = Id::ushr_r; } | |
145 void visit(AndExp *) { id = Id::iand_r; } | |
146 void visit(OrExp *) { id = Id::ior_r; } | |
147 void visit(XorExp *) { id = Id::ixor_r; } | |
148 void visit(CatExp *) { id = Id::cat_r; } | |
149 }; | |
150 OpIdRVisitor v; | |
151 e->accept(&v); | |
152 return v.id; | |
153 } | |
154 | |
155 /************************************ | |
156 * If type is a class or struct, return the symbol for it, | |
157 * else NULL | |
158 */ | |
159 AggregateDeclaration *isAggregate(Type *t) | |
160 { | |
161 t = t->toBasetype(); | |
162 if (t->ty == Tclass) | |
163 { | |
164 return ((TypeClass *)t)->sym; | |
165 } | |
166 else if (t->ty == Tstruct) | |
167 { | |
168 return ((TypeStruct *)t)->sym; | |
169 } | |
170 return NULL; | |
171 } | |
172 | |
173 /******************************************* | |
174 * Helper function to turn operator into template argument list | |
175 */ | |
176 Objects *opToArg(Scope *sc, TOK op) | |
177 { | |
178 /* Remove the = from op= | |
179 */ | |
180 switch (op) | |
181 { | |
182 case TOKaddass: op = TOKadd; break; | |
183 case TOKminass: op = TOKmin; break; | |
184 case TOKmulass: op = TOKmul; break; | |
185 case TOKdivass: op = TOKdiv; break; | |
186 case TOKmodass: op = TOKmod; break; | |
187 case TOKandass: op = TOKand; break; | |
188 case TOKorass: op = TOKor; break; | |
189 case TOKxorass: op = TOKxor; break; | |
190 case TOKshlass: op = TOKshl; break; | |
191 case TOKshrass: op = TOKshr; break; | |
192 case TOKushrass: op = TOKushr; break; | |
193 case TOKcatass: op = TOKcat; break; | |
194 case TOKpowass: op = TOKpow; break; | |
195 default: break; | |
196 } | |
197 Expression *e = new StringExp(Loc(), const_cast<char *>(Token::toChars(op))); | |
198 e = semantic(e, sc); | |
199 Objects *tiargs = new Objects(); | |
200 tiargs->push(e); | |
201 return tiargs; | |
202 } | |
203 | |
204 /************************************ | |
205 * Operator overload. | |
206 * Check for operator overload, if so, replace | |
207 * with function call. | |
208 * Return NULL if not an operator overload. | |
209 */ | |
210 | |
211 Expression *op_overload(Expression *e, Scope *sc) | |
212 { | |
213 class OpOverload : public Visitor | |
214 { | |
215 public: | |
216 Scope *sc; | |
217 Expression *result; | |
218 | |
219 OpOverload(Scope *sc) | |
220 : sc(sc) | |
221 { | |
222 result = NULL; | |
223 } | |
224 | |
225 void visit(Expression *) | |
226 { | |
227 assert(0); | |
228 } | |
229 | |
230 void visit(UnaExp *e) | |
231 { | |
232 //printf("UnaExp::op_overload() (%s)\n", e->toChars()); | |
233 | |
234 if (e->e1->op == TOKarray) | |
235 { | |
236 ArrayExp *ae = (ArrayExp *)e->e1; | |
237 ae->e1 = semantic(ae->e1, sc); | |
238 ae->e1 = resolveProperties(sc, ae->e1); | |
239 Expression *ae1old = ae->e1; | |
240 | |
241 const bool maybeSlice = | |
242 (ae->arguments->dim == 0 || | |
243 (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval)); | |
244 IntervalExp *ie = NULL; | |
245 if (maybeSlice && ae->arguments->dim) | |
246 { | |
247 assert((*ae->arguments)[0]->op == TOKinterval); | |
248 ie = (IntervalExp *)(*ae->arguments)[0]; | |
249 } | |
250 | |
251 while (true) | |
252 { | |
253 if (ae->e1->op == TOKerror) | |
254 { | |
255 result = ae->e1; | |
256 return; | |
257 } | |
258 Expression *e0 = NULL; | |
259 Expression *ae1save = ae->e1; | |
260 ae->lengthVar = NULL; | |
261 | |
262 Type *t1b = ae->e1->type->toBasetype(); | |
263 AggregateDeclaration *ad = isAggregate(t1b); | |
264 if (!ad) | |
265 break; | |
266 if (search_function(ad, Id::opIndexUnary)) | |
267 { | |
268 // Deal with $ | |
269 result = resolveOpDollar(sc, ae, &e0); | |
270 if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j) | |
271 goto Lfallback; | |
272 if (result->op == TOKerror) | |
273 return; | |
274 | |
275 /* Rewrite op(a[arguments]) as: | |
276 * a.opIndexUnary!(op)(arguments) | |
277 */ | |
278 Expressions *a = (Expressions *)ae->arguments->copy(); | |
279 Objects *tiargs = opToArg(sc, e->op); | |
280 result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexUnary, tiargs); | |
281 result = new CallExp(e->loc, result, a); | |
282 if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)() | |
283 result = trySemantic(result, sc); | |
284 else | |
285 result = semantic(result, sc); | |
286 if (result) | |
287 { | |
288 result = Expression::combine(e0, result); | |
289 return; | |
290 } | |
291 } | |
292 Lfallback: | |
293 if (maybeSlice && search_function(ad, Id::opSliceUnary)) | |
294 { | |
295 // Deal with $ | |
296 result = resolveOpDollar(sc, ae, ie, &e0); | |
297 if (result->op == TOKerror) | |
298 return; | |
299 | |
300 /* Rewrite op(a[i..j]) as: | |
301 * a.opSliceUnary!(op)(i, j) | |
302 */ | |
303 Expressions *a = new Expressions(); | |
304 if (ie) | |
305 { | |
306 a->push(ie->lwr); | |
307 a->push(ie->upr); | |
308 } | |
309 Objects *tiargs = opToArg(sc, e->op); | |
310 result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceUnary, tiargs); | |
311 result = new CallExp(e->loc, result, a); | |
312 result = semantic(result, sc); | |
313 result = Expression::combine(e0, result); | |
314 return; | |
315 } | |
316 | |
317 // Didn't find it. Forward to aliasthis | |
318 if (ad->aliasthis && t1b != ae->att1) | |
319 { | |
320 if (!ae->att1 && t1b->checkAliasThisRec()) | |
321 ae->att1 = t1b; | |
322 | |
323 /* Rewrite op(a[arguments]) as: | |
324 * op(a.aliasthis[arguments]) | |
325 */ | |
326 ae->e1 = resolveAliasThis(sc, ae1save, true); | |
327 if (ae->e1) | |
328 continue; | |
329 } | |
330 break; | |
331 } | |
332 ae->e1 = ae1old; // recovery | |
333 ae->lengthVar = NULL; | |
334 } | |
335 | |
336 e->e1 = semantic(e->e1, sc); | |
337 e->e1 = resolveProperties(sc, e->e1); | |
338 if (e->e1->op == TOKerror) | |
339 { | |
340 result = e->e1; | |
341 return; | |
342 } | |
343 | |
344 AggregateDeclaration *ad = isAggregate(e->e1->type); | |
345 if (ad) | |
346 { | |
347 Dsymbol *fd = NULL; | |
348 #if 1 // Old way, kept for compatibility with D1 | |
349 if (e->op != TOKpreplusplus && e->op != TOKpreminusminus) | |
350 { | |
351 fd = search_function(ad, opId(e)); | |
352 if (fd) | |
353 { | |
354 // Rewrite +e1 as e1.add() | |
355 result = build_overload(e->loc, sc, e->e1, NULL, fd); | |
356 return; | |
357 } | |
358 } | |
359 #endif | |
360 | |
361 /* Rewrite as: | |
362 * e1.opUnary!(op)() | |
363 */ | |
364 fd = search_function(ad, Id::opUnary); | |
365 if (fd) | |
366 { | |
367 Objects *tiargs = opToArg(sc, e->op); | |
368 result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs); | |
369 result = new CallExp(e->loc, result); | |
370 result = semantic(result, sc); | |
371 return; | |
372 } | |
373 | |
374 // Didn't find it. Forward to aliasthis | |
375 if (ad->aliasthis && e->e1->type != e->att1) | |
376 { | |
377 /* Rewrite op(e1) as: | |
378 * op(e1.aliasthis) | |
379 */ | |
380 //printf("att una %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars()); | |
381 Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident); | |
382 UnaExp *ue = (UnaExp *)e->copy(); | |
383 if (!ue->att1 && e->e1->type->checkAliasThisRec()) | |
384 ue->att1 = e->e1->type; | |
385 ue->e1 = e1; | |
386 result = trySemantic(ue, sc); | |
387 return; | |
388 } | |
389 } | |
390 } | |
391 | |
392 void visit(ArrayExp *ae) | |
393 { | |
394 //printf("ArrayExp::op_overload() (%s)\n", ae->toChars()); | |
395 ae->e1 = semantic(ae->e1, sc); | |
396 ae->e1 = resolveProperties(sc, ae->e1); | |
397 Expression *ae1old = ae->e1; | |
398 | |
399 const bool maybeSlice = | |
400 (ae->arguments->dim == 0 || | |
401 (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval)); | |
402 IntervalExp *ie = NULL; | |
403 if (maybeSlice && ae->arguments->dim) | |
404 { | |
405 assert((*ae->arguments)[0]->op == TOKinterval); | |
406 ie = (IntervalExp *)(*ae->arguments)[0]; | |
407 } | |
408 | |
409 while (true) | |
410 { | |
411 if (ae->e1->op == TOKerror) | |
412 { | |
413 result = ae->e1; | |
414 return; | |
415 } | |
416 Expression *e0 = NULL; | |
417 Expression *ae1save = ae->e1; | |
418 ae->lengthVar = NULL; | |
419 | |
420 Type *t1b = ae->e1->type->toBasetype(); | |
421 AggregateDeclaration *ad = isAggregate(t1b); | |
422 if (!ad) | |
423 { | |
424 // If the non-aggregate expression ae->e1 is indexable or sliceable, | |
425 // convert it to the corresponding concrete expression. | |
426 if (t1b->ty == Tpointer || | |
427 t1b->ty == Tsarray || | |
428 t1b->ty == Tarray || | |
429 t1b->ty == Taarray || | |
430 t1b->ty == Ttuple || | |
431 t1b->ty == Tvector || | |
432 ae->e1->op == TOKtype) | |
433 { | |
434 // Convert to SliceExp | |
435 if (maybeSlice) | |
436 { | |
437 result = new SliceExp(ae->loc, ae->e1, ie); | |
438 result = semantic(result, sc); | |
439 return; | |
440 } | |
441 // Convert to IndexExp | |
442 if (ae->arguments->dim == 1) | |
443 { | |
444 result = new IndexExp(ae->loc, ae->e1, (*ae->arguments)[0]); | |
445 result = semantic(result, sc); | |
446 return; | |
447 } | |
448 } | |
449 break; | |
450 } | |
451 if (search_function(ad, Id::index)) | |
452 { | |
453 // Deal with $ | |
454 result = resolveOpDollar(sc, ae, &e0); | |
455 if (!result) // a[i..j] might be: a.opSlice(i, j) | |
456 goto Lfallback; | |
457 if (result->op == TOKerror) | |
458 return; | |
459 | |
460 /* Rewrite e1[arguments] as: | |
461 * e1.opIndex(arguments) | |
462 */ | |
463 Expressions *a = (Expressions *)ae->arguments->copy(); | |
464 result = new DotIdExp(ae->loc, ae->e1, Id::index); | |
465 result = new CallExp(ae->loc, result, a); | |
466 if (maybeSlice) // a[] might be: a.opSlice() | |
467 result = trySemantic(result, sc); | |
468 else | |
469 result = semantic(result, sc); | |
470 if (result) | |
471 { | |
472 result = Expression::combine(e0, result); | |
473 return; | |
474 } | |
475 } | |
476 Lfallback: | |
477 if (maybeSlice && ae->e1->op == TOKtype) | |
478 { | |
479 result = new SliceExp(ae->loc, ae->e1, ie); | |
480 result = semantic(result, sc); | |
481 result = Expression::combine(e0, result); | |
482 return; | |
483 } | |
484 if (maybeSlice && search_function(ad, Id::slice)) | |
485 { | |
486 // Deal with $ | |
487 result = resolveOpDollar(sc, ae, ie, &e0); | |
488 if (result->op == TOKerror) | |
489 return; | |
490 | |
491 /* Rewrite a[i..j] as: | |
492 * a.opSlice(i, j) | |
493 */ | |
494 Expressions *a = new Expressions(); | |
495 if (ie) | |
496 { | |
497 a->push(ie->lwr); | |
498 a->push(ie->upr); | |
499 } | |
500 result = new DotIdExp(ae->loc, ae->e1, Id::slice); | |
501 result = new CallExp(ae->loc, result, a); | |
502 result = semantic(result, sc); | |
503 result = Expression::combine(e0, result); | |
504 return; | |
505 } | |
506 | |
507 // Didn't find it. Forward to aliasthis | |
508 if (ad->aliasthis && t1b != ae->att1) | |
509 { | |
510 if (!ae->att1 && t1b->checkAliasThisRec()) | |
511 ae->att1 = t1b; | |
512 //printf("att arr e1 = %s\n", this->e1->type->toChars()); | |
513 | |
514 /* Rewrite op(a[arguments]) as: | |
515 * op(a.aliasthis[arguments]) | |
516 */ | |
517 ae->e1 = resolveAliasThis(sc, ae1save, true); | |
518 if (ae->e1) | |
519 continue; | |
520 } | |
521 break; | |
522 } | |
523 ae->e1 = ae1old; // recovery | |
524 ae->lengthVar = NULL; | |
525 } | |
526 | |
527 /*********************************************** | |
528 * This is mostly the same as UnaryExp::op_overload(), but has | |
529 * a different rewrite. | |
530 */ | |
531 void visit(CastExp *e) | |
532 { | |
533 //printf("CastExp::op_overload() (%s)\n", e->toChars()); | |
534 AggregateDeclaration *ad = isAggregate(e->e1->type); | |
535 if (ad) | |
536 { | |
537 Dsymbol *fd = NULL; | |
538 /* Rewrite as: | |
539 * e1.opCast!(T)() | |
540 */ | |
541 fd = search_function(ad, Id::_cast); | |
542 if (fd) | |
543 { | |
544 #if 1 // Backwards compatibility with D1 if opCast is a function, not a template | |
545 if (fd->isFuncDeclaration()) | |
546 { | |
547 // Rewrite as: e1.opCast() | |
548 result = build_overload(e->loc, sc, e->e1, NULL, fd); | |
549 return; | |
550 } | |
551 #endif | |
552 Objects *tiargs = new Objects(); | |
553 tiargs->push(e->to); | |
554 result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs); | |
555 result = new CallExp(e->loc, result); | |
556 result = semantic(result, sc); | |
557 return; | |
558 } | |
559 | |
560 // Didn't find it. Forward to aliasthis | |
561 if (ad->aliasthis) | |
562 { | |
563 /* Rewrite op(e1) as: | |
564 * op(e1.aliasthis) | |
565 */ | |
566 Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident); | |
567 result = e->copy(); | |
568 ((UnaExp *)result)->e1 = e1; | |
569 result = trySemantic(result, sc); | |
570 return; | |
571 } | |
572 } | |
573 } | |
574 | |
575 void visit(BinExp *e) | |
576 { | |
577 //printf("BinExp::op_overload() (%s)\n", e->toChars()); | |
578 | |
579 Identifier *id = opId(e); | |
580 Identifier *id_r = opId_r(e); | |
581 | |
582 Expressions args1; | |
583 Expressions args2; | |
584 int argsset = 0; | |
585 | |
586 AggregateDeclaration *ad1 = isAggregate(e->e1->type); | |
587 AggregateDeclaration *ad2 = isAggregate(e->e2->type); | |
588 | |
589 if (e->op == TOKassign && ad1 == ad2) | |
590 { | |
591 StructDeclaration *sd = ad1->isStructDeclaration(); | |
592 if (sd && !sd->hasIdentityAssign) | |
593 { | |
594 /* This is bitwise struct assignment. */ | |
595 return; | |
596 } | |
597 } | |
598 | |
599 Dsymbol *s = NULL; | |
600 Dsymbol *s_r = NULL; | |
601 | |
602 #if 1 // the old D1 scheme | |
603 if (ad1 && id) | |
604 { | |
605 s = search_function(ad1, id); | |
606 } | |
607 if (ad2 && id_r) | |
608 { | |
609 s_r = search_function(ad2, id_r); | |
610 | |
611 // Bugzilla 12778: If both x.opBinary(y) and y.opBinaryRight(x) found, | |
612 // and they are exactly same symbol, x.opBinary(y) should be preferred. | |
613 if (s_r && s_r == s) | |
614 s_r = NULL; | |
615 } | |
616 #endif | |
617 | |
618 Objects *tiargs = NULL; | |
619 if (e->op == TOKplusplus || e->op == TOKminusminus) | |
620 { | |
621 // Bug4099 fix | |
622 if (ad1 && search_function(ad1, Id::opUnary)) | |
623 return; | |
624 } | |
625 if (!s && !s_r && e->op != TOKequal && e->op != TOKnotequal && e->op != TOKassign && | |
626 e->op != TOKplusplus && e->op != TOKminusminus) | |
627 { | |
628 /* Try the new D2 scheme, opBinary and opBinaryRight | |
629 */ | |
630 if (ad1) | |
631 { | |
632 s = search_function(ad1, Id::opBinary); | |
633 if (s && !s->isTemplateDeclaration()) | |
634 { | |
635 e->e1->error("%s.opBinary isn't a template", e->e1->toChars()); | |
636 result = new ErrorExp(); | |
637 return; | |
638 } | |
639 } | |
640 if (ad2) | |
641 { | |
642 s_r = search_function(ad2, Id::opBinaryRight); | |
643 if (s_r && !s_r->isTemplateDeclaration()) | |
644 { | |
645 e->e2->error("%s.opBinaryRight isn't a template", e->e2->toChars()); | |
646 result = new ErrorExp(); | |
647 return; | |
648 } | |
649 if (s_r && s_r == s) // Bugzilla 12778 | |
650 s_r = NULL; | |
651 } | |
652 | |
653 // Set tiargs, the template argument list, which will be the operator string | |
654 if (s || s_r) | |
655 { | |
656 id = Id::opBinary; | |
657 id_r = Id::opBinaryRight; | |
658 tiargs = opToArg(sc, e->op); | |
659 } | |
660 } | |
661 | |
662 if (s || s_r) | |
663 { | |
664 /* Try: | |
665 * a.opfunc(b) | |
666 * b.opfunc_r(a) | |
667 * and see which is better. | |
668 */ | |
669 | |
670 args1.setDim(1); | |
671 args1[0] = e->e1; | |
672 expandTuples(&args1); | |
673 args2.setDim(1); | |
674 args2[0] = e->e2; | |
675 expandTuples(&args2); | |
676 argsset = 1; | |
677 | |
678 Match m; | |
679 memset(&m, 0, sizeof(m)); | |
680 m.last = MATCHnomatch; | |
681 | |
682 if (s) | |
683 { | |
684 functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2); | |
685 if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors)) | |
686 { | |
687 result = new ErrorExp(); | |
688 return; | |
689 } | |
690 } | |
691 | |
692 FuncDeclaration *lastf = m.lastf; | |
693 | |
694 if (s_r) | |
695 { | |
696 functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1); | |
697 if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors)) | |
698 { | |
699 result = new ErrorExp(); | |
700 return; | |
701 } | |
702 } | |
703 | |
704 if (m.count > 1) | |
705 { | |
706 // Error, ambiguous | |
707 e->error("overloads %s and %s both match argument list for %s", | |
708 m.lastf->type->toChars(), | |
709 m.nextf->type->toChars(), | |
710 m.lastf->toChars()); | |
711 } | |
712 else if (m.last <= MATCHnomatch) | |
713 { | |
714 m.lastf = m.anyf; | |
715 if (tiargs) | |
716 goto L1; | |
717 } | |
718 | |
719 if (e->op == TOKplusplus || e->op == TOKminusminus) | |
720 { | |
721 // Kludge because operator overloading regards e++ and e-- | |
722 // as unary, but it's implemented as a binary. | |
723 // Rewrite (e1 ++ e2) as e1.postinc() | |
724 // Rewrite (e1 -- e2) as e1.postdec() | |
725 result = build_overload(e->loc, sc, e->e1, NULL, m.lastf ? m.lastf : s); | |
726 } | |
727 else if ((lastf && m.lastf == lastf) || (!s_r && m.last <= MATCHnomatch)) | |
728 { | |
729 // Rewrite (e1 op e2) as e1.opfunc(e2) | |
730 result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s); | |
731 } | |
732 else | |
733 { | |
734 // Rewrite (e1 op e2) as e2.opfunc_r(e1) | |
735 result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r); | |
736 } | |
737 return; | |
738 } | |
739 | |
740 L1: | |
741 #if 1 // Retained for D1 compatibility | |
742 if (isCommutative(e->op) && !tiargs) | |
743 { | |
744 s = NULL; | |
745 s_r = NULL; | |
746 if (ad1 && id_r) | |
747 { | |
748 s_r = search_function(ad1, id_r); | |
749 } | |
750 if (ad2 && id) | |
751 { | |
752 s = search_function(ad2, id); | |
753 if (s && s == s_r) // Bugzilla 12778 | |
754 s = NULL; | |
755 } | |
756 | |
757 if (s || s_r) | |
758 { | |
759 /* Try: | |
760 * a.opfunc_r(b) | |
761 * b.opfunc(a) | |
762 * and see which is better. | |
763 */ | |
764 | |
765 if (!argsset) | |
766 { | |
767 args1.setDim(1); | |
768 args1[0] = e->e1; | |
769 expandTuples(&args1); | |
770 args2.setDim(1); | |
771 args2[0] = e->e2; | |
772 expandTuples(&args2); | |
773 } | |
774 | |
775 Match m; | |
776 memset(&m, 0, sizeof(m)); | |
777 m.last = MATCHnomatch; | |
778 | |
779 if (s_r) | |
780 { | |
781 functionResolve(&m, s_r, e->loc, sc, tiargs, e->e1->type, &args2); | |
782 if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors)) | |
783 { | |
784 result = new ErrorExp(); | |
785 return; | |
786 } | |
787 } | |
788 | |
789 FuncDeclaration *lastf = m.lastf; | |
790 | |
791 if (s) | |
792 { | |
793 functionResolve(&m, s, e->loc, sc, tiargs, e->e2->type, &args1); | |
794 if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors)) | |
795 { | |
796 result = new ErrorExp(); | |
797 return; | |
798 } | |
799 } | |
800 | |
801 if (m.count > 1) | |
802 { | |
803 // Error, ambiguous | |
804 e->error("overloads %s and %s both match argument list for %s", | |
805 m.lastf->type->toChars(), | |
806 m.nextf->type->toChars(), | |
807 m.lastf->toChars()); | |
808 } | |
809 else if (m.last <= MATCHnomatch) | |
810 { | |
811 m.lastf = m.anyf; | |
812 } | |
813 | |
814 if ((lastf && m.lastf == lastf) || (!s && m.last <= MATCHnomatch)) | |
815 { | |
816 // Rewrite (e1 op e2) as e1.opfunc_r(e2) | |
817 result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s_r); | |
818 } | |
819 else | |
820 { | |
821 // Rewrite (e1 op e2) as e2.opfunc(e1) | |
822 result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s); | |
823 } | |
824 | |
825 // When reversing operands of comparison operators, | |
826 // need to reverse the sense of the op | |
827 switch (e->op) | |
828 { | |
829 case TOKlt: e->op = TOKgt; break; | |
830 case TOKgt: e->op = TOKlt; break; | |
831 case TOKle: e->op = TOKge; break; | |
832 case TOKge: e->op = TOKle; break; | |
833 default: break; | |
834 } | |
835 | |
836 return; | |
837 } | |
838 } | |
839 #endif | |
840 | |
841 // Try alias this on first operand | |
842 if (ad1 && ad1->aliasthis && | |
843 !(e->op == TOKassign && ad2 && ad1 == ad2)) // See Bugzilla 2943 | |
844 { | |
845 /* Rewrite (e1 op e2) as: | |
846 * (e1.aliasthis op e2) | |
847 */ | |
848 if (e->att1 && e->e1->type == e->att1) | |
849 return; | |
850 //printf("att bin e1 = %s\n", this->e1->type->toChars()); | |
851 Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident); | |
852 BinExp *be = (BinExp *)e->copy(); | |
853 if (!be->att1 && e->e1->type->checkAliasThisRec()) | |
854 be->att1 = e->e1->type; | |
855 be->e1 = e1; | |
856 result = trySemantic(be, sc); | |
857 return; | |
858 } | |
859 | |
860 // Try alias this on second operand | |
861 /* Bugzilla 2943: make sure that when we're copying the struct, we don't | |
862 * just copy the alias this member | |
863 */ | |
864 if (ad2 && ad2->aliasthis && | |
865 !(e->op == TOKassign && ad1 && ad1 == ad2)) | |
866 { | |
867 /* Rewrite (e1 op e2) as: | |
868 * (e1 op e2.aliasthis) | |
869 */ | |
870 if (e->att2 && e->e2->type == e->att2) | |
871 return; | |
872 //printf("att bin e2 = %s\n", e->e2->type->toChars()); | |
873 Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident); | |
874 BinExp *be = (BinExp *)e->copy(); | |
875 if (!be->att2 && e->e2->type->checkAliasThisRec()) | |
876 be->att2 = e->e2->type; | |
877 be->e2 = e2; | |
878 result = trySemantic(be, sc); | |
879 return; | |
880 } | |
881 return; | |
882 } | |
883 | |
884 static bool needsDirectEq(Type *t1, Type *t2, Scope *sc) | |
885 { | |
886 Type *t1n = t1->nextOf()->toBasetype(); | |
887 Type *t2n = t2->nextOf()->toBasetype(); | |
888 if (((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) && | |
889 (t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) || | |
890 (t1n->ty == Tvoid || t2n->ty == Tvoid)) | |
891 { | |
892 return false; | |
893 } | |
894 if (t1n->constOf() != t2n->constOf()) | |
895 return true; | |
896 | |
897 Type *t = t1n; | |
898 while (t->toBasetype()->nextOf()) | |
899 t = t->nextOf()->toBasetype(); | |
900 if (t->ty != Tstruct) | |
901 return false; | |
902 | |
903 if (global.params.useTypeInfo && Type::dtypeinfo) | |
904 semanticTypeInfo(sc, t); | |
905 | |
906 return ((TypeStruct *)t)->sym->hasIdentityEquals; | |
907 } | |
908 | |
909 void visit(EqualExp *e) | |
910 { | |
911 //printf("EqualExp::op_overload() (%s)\n", e->toChars()); | |
912 | |
913 Type *t1 = e->e1->type->toBasetype(); | |
914 Type *t2 = e->e2->type->toBasetype(); | |
915 | |
916 /* Check for array equality. | |
917 */ | |
918 if ((t1->ty == Tarray || t1->ty == Tsarray) && | |
919 (t2->ty == Tarray || t2->ty == Tsarray)) | |
920 { | |
921 if (needsDirectEq(t1, t2, sc)) | |
922 { | |
923 /* Rewrite as: | |
924 * __ArrayEq(e1, e2) | |
925 */ | |
926 Expression *eeq = new IdentifierExp(e->loc, Id::__ArrayEq); | |
927 result = new CallExp(e->loc, eeq, e->e1, e->e2); | |
928 if (e->op == TOKnotequal) | |
929 result = new NotExp(e->loc, result); | |
930 result = trySemantic(result, sc); // for better error message | |
931 if (!result) | |
932 { | |
933 e->error("cannot compare %s and %s", t1->toChars(), t2->toChars()); | |
934 result = new ErrorExp(); | |
935 } | |
936 return; | |
937 } | |
938 } | |
939 | |
940 /* Check for class equality with null literal or typeof(null). | |
941 */ | |
942 if ((t1->ty == Tclass && e->e2->op == TOKnull) || | |
943 (t2->ty == Tclass && e->e1->op == TOKnull)) | |
944 { | |
945 e->error("use '%s' instead of '%s' when comparing with null", | |
946 Token::toChars(e->op == TOKequal ? TOKidentity : TOKnotidentity), | |
947 Token::toChars(e->op)); | |
948 result = new ErrorExp(); | |
949 return; | |
950 } | |
951 if ((t1->ty == Tclass && t2->ty == Tnull) || | |
952 (t1->ty == Tnull && t2->ty == Tclass)) | |
953 { | |
954 // Comparing a class with typeof(null) should not call opEquals | |
955 return; | |
956 } | |
957 | |
958 /* Check for class equality. | |
959 */ | |
960 if (t1->ty == Tclass && t2->ty == Tclass) | |
961 { | |
962 ClassDeclaration *cd1 = t1->isClassHandle(); | |
963 ClassDeclaration *cd2 = t2->isClassHandle(); | |
964 | |
965 if (!(cd1->cpp || cd2->cpp)) | |
966 { | |
967 /* Rewrite as: | |
968 * .object.opEquals(e1, e2) | |
969 */ | |
970 Expression *e1x = e->e1; | |
971 Expression *e2x = e->e2; | |
972 | |
973 /* The explicit cast is necessary for interfaces, | |
974 * see Bugzilla 4088. | |
975 */ | |
976 Type *to = ClassDeclaration::object->getType(); | |
977 if (cd1->isInterfaceDeclaration()) | |
978 e1x = new CastExp(e->loc, e->e1, t1->isMutable() ? to : to->constOf()); | |
979 if (cd2->isInterfaceDeclaration()) | |
980 e2x = new CastExp(e->loc, e->e2, t2->isMutable() ? to : to->constOf()); | |
981 | |
982 result = new IdentifierExp(e->loc, Id::empty); | |
983 result = new DotIdExp(e->loc, result, Id::object); | |
984 result = new DotIdExp(e->loc, result, Id::eq); | |
985 result = new CallExp(e->loc, result, e1x, e2x); | |
986 if (e->op == TOKnotequal) | |
987 result = new NotExp(e->loc, result); | |
988 result = semantic(result, sc); | |
989 return; | |
990 } | |
991 } | |
992 | |
993 result = compare_overload(e, sc, Id::eq); | |
994 if (result) | |
995 { | |
996 if (result->op == TOKcall && e->op == TOKnotequal) | |
997 { | |
998 result = new NotExp(result->loc, result); | |
999 result = semantic(result, sc); | |
1000 } | |
1001 return; | |
1002 } | |
1003 | |
1004 /* Check for pointer equality. | |
1005 */ | |
1006 if (t1->ty == Tpointer || t2->ty == Tpointer) | |
1007 { | |
1008 /* Rewrite: | |
1009 * ptr1 == ptr2 | |
1010 * as: | |
1011 * ptr1 is ptr2 | |
1012 * | |
1013 * This is just a rewriting for deterministic AST representation | |
1014 * as the backend input. | |
1015 */ | |
1016 TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity; | |
1017 result = new IdentityExp(op2, e->loc, e->e1, e->e2); | |
1018 result = semantic(result, sc); | |
1019 return; | |
1020 } | |
1021 | |
1022 /* Check for struct equality without opEquals. | |
1023 */ | |
1024 if (t1->ty == Tstruct && t2->ty == Tstruct) | |
1025 { | |
1026 StructDeclaration *sd = ((TypeStruct *)t1)->sym; | |
1027 if (sd != ((TypeStruct *)t2)->sym) | |
1028 return; | |
1029 | |
1030 if (!needOpEquals(sd)) | |
1031 { | |
1032 // Use bitwise equality. | |
1033 TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity; | |
1034 result = new IdentityExp(op2, e->loc, e->e1, e->e2); | |
1035 result = semantic(result, sc); | |
1036 return; | |
1037 } | |
1038 | |
1039 /* Do memberwise equality. | |
1040 * Rewrite: | |
1041 * e1 == e2 | |
1042 * as: | |
1043 * e1.tupleof == e2.tupleof | |
1044 * | |
1045 * If sd is a nested struct, and if it's nested in a class, it will | |
1046 * also compare the parent class's equality. Otherwise, compares | |
1047 * the identity of parent context through void*. | |
1048 */ | |
1049 if (e->att1 && t1 == e->att1) | |
1050 return; | |
1051 if (e->att2 && t2 == e->att2) | |
1052 return; | |
1053 | |
1054 e = (EqualExp *)e->copy(); | |
1055 if (!e->att1) | |
1056 e->att1 = t1; | |
1057 if (!e->att2) | |
1058 e->att2 = t2; | |
1059 e->e1 = new DotIdExp(e->loc, e->e1, Id::_tupleof); | |
1060 e->e2 = new DotIdExp(e->loc, e->e2, Id::_tupleof); | |
1061 result = semantic(e, sc); | |
1062 | |
1063 /* Bugzilla 15292, if the rewrite result is same with the original, | |
1064 * the equality is unresolvable because it has recursive definition. | |
1065 */ | |
1066 if (result->op == e->op && | |
1067 ((EqualExp *)result)->e1->type->toBasetype() == t1) | |
1068 { | |
1069 e->error("cannot compare %s because its auto generated member-wise equality has recursive definition", | |
1070 t1->toChars()); | |
1071 result = new ErrorExp(); | |
1072 } | |
1073 return; | |
1074 } | |
1075 | |
1076 /* Check for tuple equality. | |
1077 */ | |
1078 if (e->e1->op == TOKtuple && e->e2->op == TOKtuple) | |
1079 { | |
1080 TupleExp *tup1 = (TupleExp *)e->e1; | |
1081 TupleExp *tup2 = (TupleExp *)e->e2; | |
1082 size_t dim = tup1->exps->dim; | |
1083 if (dim != tup2->exps->dim) | |
1084 { | |
1085 e->error("mismatched tuple lengths, %d and %d", | |
1086 (int)dim, (int)tup2->exps->dim); | |
1087 result = new ErrorExp(); | |
1088 return; | |
1089 } | |
1090 | |
1091 if (dim == 0) | |
1092 { | |
1093 // zero-length tuple comparison should always return true or false. | |
1094 result = new IntegerExp(e->loc, (e->op == TOKequal), Type::tbool); | |
1095 } | |
1096 else | |
1097 { | |
1098 for (size_t i = 0; i < dim; i++) | |
1099 { | |
1100 Expression *ex1 = (*tup1->exps)[i]; | |
1101 Expression *ex2 = (*tup2->exps)[i]; | |
1102 EqualExp *eeq = new EqualExp(e->op, e->loc, ex1, ex2); | |
1103 eeq->att1 = e->att1; | |
1104 eeq->att2 = e->att2; | |
1105 | |
1106 if (!result) | |
1107 result = eeq; | |
1108 else if (e->op == TOKequal) | |
1109 result = new AndAndExp(e->loc, result, eeq); | |
1110 else | |
1111 result = new OrOrExp(e->loc, result, eeq); | |
1112 } | |
1113 assert(result); | |
1114 } | |
1115 result = Expression::combine(Expression::combine(tup1->e0, tup2->e0), result); | |
1116 result = semantic(result, sc); | |
1117 return; | |
1118 } | |
1119 } | |
1120 | |
1121 void visit(CmpExp *e) | |
1122 { | |
1123 //printf("CmpExp::op_overload() (%s)\n", e->toChars()); | |
1124 | |
1125 result = compare_overload(e, sc, Id::cmp); | |
1126 } | |
1127 | |
1128 /********************************* | |
1129 * Operator overloading for op= | |
1130 */ | |
1131 void visit(BinAssignExp *e) | |
1132 { | |
1133 //printf("BinAssignExp::op_overload() (%s)\n", e->toChars()); | |
1134 | |
1135 if (e->e1->op == TOKarray) | |
1136 { | |
1137 ArrayExp *ae = (ArrayExp *)e->e1; | |
1138 ae->e1 = semantic(ae->e1, sc); | |
1139 ae->e1 = resolveProperties(sc, ae->e1); | |
1140 Expression *ae1old = ae->e1; | |
1141 | |
1142 const bool maybeSlice = | |
1143 (ae->arguments->dim == 0 || | |
1144 (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval)); | |
1145 IntervalExp *ie = NULL; | |
1146 if (maybeSlice && ae->arguments->dim) | |
1147 { | |
1148 assert((*ae->arguments)[0]->op == TOKinterval); | |
1149 ie = (IntervalExp *)(*ae->arguments)[0]; | |
1150 } | |
1151 | |
1152 while (true) | |
1153 { | |
1154 if (ae->e1->op == TOKerror) | |
1155 { | |
1156 result = ae->e1; | |
1157 return; | |
1158 } | |
1159 Expression *e0 = NULL; | |
1160 Expression *ae1save = ae->e1; | |
1161 ae->lengthVar = NULL; | |
1162 | |
1163 Type *t1b = ae->e1->type->toBasetype(); | |
1164 AggregateDeclaration *ad = isAggregate(t1b); | |
1165 if (!ad) | |
1166 break; | |
1167 if (search_function(ad, Id::opIndexOpAssign)) | |
1168 { | |
1169 // Deal with $ | |
1170 result = resolveOpDollar(sc, ae, &e0); | |
1171 if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j) | |
1172 goto Lfallback; | |
1173 if (result->op == TOKerror) | |
1174 return; | |
1175 | |
1176 result = semantic(e->e2, sc); | |
1177 if (result->op == TOKerror) | |
1178 return; | |
1179 e->e2 = result; | |
1180 | |
1181 /* Rewrite a[arguments] op= e2 as: | |
1182 * a.opIndexOpAssign!(op)(e2, arguments) | |
1183 */ | |
1184 Expressions *a = (Expressions *)ae->arguments->copy(); | |
1185 a->insert(0, e->e2); | |
1186 Objects *tiargs = opToArg(sc, e->op); | |
1187 result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexOpAssign, tiargs); | |
1188 result = new CallExp(e->loc, result, a); | |
1189 if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2) | |
1190 result = trySemantic(result, sc); | |
1191 else | |
1192 result = semantic(result, sc); | |
1193 if (result) | |
1194 { | |
1195 result = Expression::combine(e0, result); | |
1196 return; | |
1197 } | |
1198 } | |
1199 Lfallback: | |
1200 if (maybeSlice && search_function(ad, Id::opSliceOpAssign)) | |
1201 { | |
1202 // Deal with $ | |
1203 result = resolveOpDollar(sc, ae, ie, &e0); | |
1204 if (result->op == TOKerror) | |
1205 return; | |
1206 | |
1207 result = semantic(e->e2, sc); | |
1208 if (result->op == TOKerror) | |
1209 return; | |
1210 e->e2 = result; | |
1211 | |
1212 /* Rewrite (a[i..j] op= e2) as: | |
1213 * a.opSliceOpAssign!(op)(e2, i, j) | |
1214 */ | |
1215 Expressions *a = new Expressions(); | |
1216 a->push(e->e2); | |
1217 if (ie) | |
1218 { | |
1219 a->push(ie->lwr); | |
1220 a->push(ie->upr); | |
1221 } | |
1222 Objects *tiargs = opToArg(sc, e->op); | |
1223 result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceOpAssign, tiargs); | |
1224 result = new CallExp(e->loc, result, a); | |
1225 result = semantic(result, sc); | |
1226 result = Expression::combine(e0, result); | |
1227 return; | |
1228 } | |
1229 | |
1230 // Didn't find it. Forward to aliasthis | |
1231 if (ad->aliasthis && t1b != ae->att1) | |
1232 { | |
1233 if (!ae->att1 && t1b->checkAliasThisRec()) | |
1234 ae->att1 = t1b; | |
1235 | |
1236 /* Rewrite (a[arguments] op= e2) as: | |
1237 * a.aliasthis[arguments] op= e2 | |
1238 */ | |
1239 ae->e1 = resolveAliasThis(sc, ae1save, true); | |
1240 if (ae->e1) | |
1241 continue; | |
1242 } | |
1243 break; | |
1244 } | |
1245 ae->e1 = ae1old; // recovery | |
1246 ae->lengthVar = NULL; | |
1247 } | |
1248 | |
1249 result = binSemanticProp(e, sc); | |
1250 if (result) | |
1251 return; | |
1252 | |
1253 // Don't attempt 'alias this' if an error occured | |
1254 if (e->e1->type->ty == Terror || e->e2->type->ty == Terror) | |
1255 { | |
1256 result = new ErrorExp(); | |
1257 return; | |
1258 } | |
1259 | |
1260 Identifier *id = opId(e); | |
1261 | |
1262 Expressions args2; | |
1263 | |
1264 AggregateDeclaration *ad1 = isAggregate(e->e1->type); | |
1265 | |
1266 Dsymbol *s = NULL; | |
1267 | |
1268 #if 1 // the old D1 scheme | |
1269 if (ad1 && id) | |
1270 { | |
1271 s = search_function(ad1, id); | |
1272 } | |
1273 #endif | |
1274 | |
1275 Objects *tiargs = NULL; | |
1276 if (!s) | |
1277 { | |
1278 /* Try the new D2 scheme, opOpAssign | |
1279 */ | |
1280 if (ad1) | |
1281 { | |
1282 s = search_function(ad1, Id::opOpAssign); | |
1283 if (s && !s->isTemplateDeclaration()) | |
1284 { | |
1285 e->error("%s.opOpAssign isn't a template", e->e1->toChars()); | |
1286 result = new ErrorExp(); | |
1287 return; | |
1288 } | |
1289 } | |
1290 | |
1291 // Set tiargs, the template argument list, which will be the operator string | |
1292 if (s) | |
1293 { | |
1294 id = Id::opOpAssign; | |
1295 tiargs = opToArg(sc, e->op); | |
1296 } | |
1297 } | |
1298 | |
1299 if (s) | |
1300 { | |
1301 /* Try: | |
1302 * a.opOpAssign(b) | |
1303 */ | |
1304 | |
1305 args2.setDim(1); | |
1306 args2[0] = e->e2; | |
1307 expandTuples(&args2); | |
1308 | |
1309 Match m; | |
1310 memset(&m, 0, sizeof(m)); | |
1311 m.last = MATCHnomatch; | |
1312 | |
1313 if (s) | |
1314 { | |
1315 functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2); | |
1316 if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors)) | |
1317 { | |
1318 result = new ErrorExp(); | |
1319 return; | |
1320 } | |
1321 } | |
1322 | |
1323 if (m.count > 1) | |
1324 { | |
1325 // Error, ambiguous | |
1326 e->error("overloads %s and %s both match argument list for %s", | |
1327 m.lastf->type->toChars(), | |
1328 m.nextf->type->toChars(), | |
1329 m.lastf->toChars()); | |
1330 } | |
1331 else if (m.last <= MATCHnomatch) | |
1332 { | |
1333 m.lastf = m.anyf; | |
1334 if (tiargs) | |
1335 goto L1; | |
1336 } | |
1337 | |
1338 // Rewrite (e1 op e2) as e1.opOpAssign(e2) | |
1339 result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s); | |
1340 return; | |
1341 } | |
1342 | |
1343 L1: | |
1344 | |
1345 // Try alias this on first operand | |
1346 if (ad1 && ad1->aliasthis) | |
1347 { | |
1348 /* Rewrite (e1 op e2) as: | |
1349 * (e1.aliasthis op e2) | |
1350 */ | |
1351 if (e->att1 && e->e1->type == e->att1) | |
1352 return; | |
1353 //printf("att %s e1 = %s\n", Token::toChars(e->op), e->e1->type->toChars()); | |
1354 Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident); | |
1355 BinExp *be = (BinExp *)e->copy(); | |
1356 if (!be->att1 && e->e1->type->checkAliasThisRec()) | |
1357 be->att1 = e->e1->type; | |
1358 be->e1 = e1; | |
1359 result = trySemantic(be, sc); | |
1360 return; | |
1361 } | |
1362 | |
1363 // Try alias this on second operand | |
1364 AggregateDeclaration *ad2 = isAggregate(e->e2->type); | |
1365 if (ad2 && ad2->aliasthis) | |
1366 { | |
1367 /* Rewrite (e1 op e2) as: | |
1368 * (e1 op e2.aliasthis) | |
1369 */ | |
1370 if (e->att2 && e->e2->type == e->att2) | |
1371 return; | |
1372 //printf("att %s e2 = %s\n", Token::toChars(e->op), e->e2->type->toChars()); | |
1373 Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident); | |
1374 BinExp *be = (BinExp *)e->copy(); | |
1375 if (!be->att2 && e->e2->type->checkAliasThisRec()) | |
1376 be->att2 = e->e2->type; | |
1377 be->e2 = e2; | |
1378 result = trySemantic(be, sc); | |
1379 return; | |
1380 } | |
1381 } | |
1382 }; | |
1383 | |
1384 OpOverload v(sc); | |
1385 e->accept(&v); | |
1386 return v.result; | |
1387 } | |
1388 | |
1389 /****************************************** | |
1390 * Common code for overloading of EqualExp and CmpExp | |
1391 */ | |
1392 Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id) | |
1393 { | |
1394 //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), e->toChars()); | |
1395 | |
1396 AggregateDeclaration *ad1 = isAggregate(e->e1->type); | |
1397 AggregateDeclaration *ad2 = isAggregate(e->e2->type); | |
1398 | |
1399 Dsymbol *s = NULL; | |
1400 Dsymbol *s_r = NULL; | |
1401 | |
1402 if (ad1) | |
1403 { | |
1404 s = search_function(ad1, id); | |
1405 } | |
1406 if (ad2) | |
1407 { | |
1408 s_r = search_function(ad2, id); | |
1409 if (s == s_r) | |
1410 s_r = NULL; | |
1411 } | |
1412 | |
1413 Objects *tiargs = NULL; | |
1414 | |
1415 if (s || s_r) | |
1416 { | |
1417 /* Try: | |
1418 * a.opEquals(b) | |
1419 * b.opEquals(a) | |
1420 * and see which is better. | |
1421 */ | |
1422 | |
1423 Expressions args1; | |
1424 Expressions args2; | |
1425 | |
1426 args1.setDim(1); | |
1427 args1[0] = e->e1; | |
1428 expandTuples(&args1); | |
1429 args2.setDim(1); | |
1430 args2[0] = e->e2; | |
1431 expandTuples(&args2); | |
1432 | |
1433 Match m; | |
1434 memset(&m, 0, sizeof(m)); | |
1435 m.last = MATCHnomatch; | |
1436 | |
1437 if (0 && s && s_r) | |
1438 { | |
1439 printf("s : %s\n", s->toPrettyChars()); | |
1440 printf("s_r: %s\n", s_r->toPrettyChars()); | |
1441 } | |
1442 | |
1443 if (s) | |
1444 { | |
1445 functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2); | |
1446 if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors)) | |
1447 return new ErrorExp(); | |
1448 } | |
1449 | |
1450 FuncDeclaration *lastf = m.lastf; | |
1451 int count = m.count; | |
1452 | |
1453 if (s_r) | |
1454 { | |
1455 functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1); | |
1456 if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors)) | |
1457 return new ErrorExp(); | |
1458 } | |
1459 | |
1460 if (m.count > 1) | |
1461 { | |
1462 /* The following if says "not ambiguous" if there's one match | |
1463 * from s and one from s_r, in which case we pick s. | |
1464 * This doesn't follow the spec, but is a workaround for the case | |
1465 * where opEquals was generated from templates and we cannot figure | |
1466 * out if both s and s_r came from the same declaration or not. | |
1467 * The test case is: | |
1468 * import std.typecons; | |
1469 * void main() { | |
1470 * assert(tuple("has a", 2u) == tuple("has a", 1)); | |
1471 * } | |
1472 */ | |
1473 if (!(m.lastf == lastf && m.count == 2 && count == 1)) | |
1474 { | |
1475 // Error, ambiguous | |
1476 e->error("overloads %s and %s both match argument list for %s", | |
1477 m.lastf->type->toChars(), | |
1478 m.nextf->type->toChars(), | |
1479 m.lastf->toChars()); | |
1480 } | |
1481 } | |
1482 else if (m.last <= MATCHnomatch) | |
1483 { | |
1484 m.lastf = m.anyf; | |
1485 } | |
1486 | |
1487 Expression *result; | |
1488 if ((lastf && m.lastf == lastf) || (!s_r && m.last <= MATCHnomatch)) | |
1489 { | |
1490 // Rewrite (e1 op e2) as e1.opfunc(e2) | |
1491 result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s); | |
1492 } | |
1493 else | |
1494 { | |
1495 // Rewrite (e1 op e2) as e2.opfunc_r(e1) | |
1496 result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r); | |
1497 | |
1498 // When reversing operands of comparison operators, | |
1499 // need to reverse the sense of the op | |
1500 switch (e->op) | |
1501 { | |
1502 case TOKlt: e->op = TOKgt; break; | |
1503 case TOKgt: e->op = TOKlt; break; | |
1504 case TOKle: e->op = TOKge; break; | |
1505 case TOKge: e->op = TOKle; break; | |
1506 | |
1507 // The rest are symmetric | |
1508 default: | |
1509 break; | |
1510 } | |
1511 } | |
1512 | |
1513 return result; | |
1514 } | |
1515 | |
1516 // Try alias this on first operand | |
1517 if (ad1 && ad1->aliasthis) | |
1518 { | |
1519 /* Rewrite (e1 op e2) as: | |
1520 * (e1.aliasthis op e2) | |
1521 */ | |
1522 if (e->att1 && e->e1->type == e->att1) | |
1523 return NULL; | |
1524 //printf("att cmp_bin e1 = %s\n", e->e1->type->toChars()); | |
1525 Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident); | |
1526 BinExp *be = (BinExp *)e->copy(); | |
1527 if (!be->att1 && e->e1->type->checkAliasThisRec()) | |
1528 be->att1 = e->e1->type; | |
1529 be->e1 = e1; | |
1530 return trySemantic(be, sc); | |
1531 } | |
1532 | |
1533 // Try alias this on second operand | |
1534 if (ad2 && ad2->aliasthis) | |
1535 { | |
1536 /* Rewrite (e1 op e2) as: | |
1537 * (e1 op e2.aliasthis) | |
1538 */ | |
1539 if (e->att2 && e->e2->type == e->att2) | |
1540 return NULL; | |
1541 //printf("att cmp_bin e2 = %s\n", e->e2->type->toChars()); | |
1542 Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident); | |
1543 BinExp *be = (BinExp *)e->copy(); | |
1544 if (!be->att2 && e->e2->type->checkAliasThisRec()) | |
1545 be->att2 = e->e2->type; | |
1546 be->e2 = e2; | |
1547 return trySemantic(be, sc); | |
1548 } | |
1549 | |
1550 return NULL; | |
1551 } | |
1552 | |
1553 /*********************************** | |
1554 * Utility to build a function call out of this reference and argument. | |
1555 */ | |
1556 | |
1557 Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, | |
1558 Dsymbol *d) | |
1559 { | |
1560 assert(d); | |
1561 Expression *e; | |
1562 | |
1563 //printf("build_overload(id = '%s')\n", id->toChars()); | |
1564 //earg->print(); | |
1565 //earg->type->print(); | |
1566 Declaration *decl = d->isDeclaration(); | |
1567 if (decl) | |
1568 e = new DotVarExp(loc, ethis, decl, false); | |
1569 else | |
1570 e = new DotIdExp(loc, ethis, d->ident); | |
1571 e = new CallExp(loc, e, earg); | |
1572 | |
1573 e = semantic(e, sc); | |
1574 return e; | |
1575 } | |
1576 | |
1577 /*************************************** | |
1578 * Search for function funcid in aggregate ad. | |
1579 */ | |
1580 | |
1581 Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid) | |
1582 { | |
1583 Dsymbol *s = ad->search(Loc(), funcid); | |
1584 if (s) | |
1585 { | |
1586 //printf("search_function: s = '%s'\n", s->kind()); | |
1587 Dsymbol *s2 = s->toAlias(); | |
1588 //printf("search_function: s2 = '%s'\n", s2->kind()); | |
1589 FuncDeclaration *fd = s2->isFuncDeclaration(); | |
1590 if (fd && fd->type->ty == Tfunction) | |
1591 return fd; | |
1592 | |
1593 TemplateDeclaration *td = s2->isTemplateDeclaration(); | |
1594 if (td) | |
1595 return td; | |
1596 } | |
1597 return NULL; | |
1598 } | |
1599 | |
1600 | |
1601 bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply) | |
1602 { | |
1603 //printf("inferAggregate(%s)\n", fes->aggr->toChars()); | |
1604 Identifier *idapply = (fes->op == TOKforeach) ? Id::apply : Id::applyReverse; | |
1605 Identifier *idfront = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback; | |
1606 int sliced = 0; | |
1607 Type *tab; | |
1608 Type *att = NULL; | |
1609 Expression *aggr = fes->aggr; | |
1610 AggregateDeclaration *ad; | |
1611 | |
1612 while (1) | |
1613 { | |
1614 aggr = semantic(aggr, sc); | |
1615 aggr = resolveProperties(sc, aggr); | |
1616 aggr = aggr->optimize(WANTvalue); | |
1617 if (!aggr->type || aggr->op == TOKerror) | |
1618 goto Lerr; | |
1619 | |
1620 tab = aggr->type->toBasetype(); | |
1621 switch (tab->ty) | |
1622 { | |
1623 case Tarray: | |
1624 case Tsarray: | |
1625 case Ttuple: | |
1626 case Taarray: | |
1627 break; | |
1628 | |
1629 case Tclass: | |
1630 ad = ((TypeClass *)tab)->sym; | |
1631 goto Laggr; | |
1632 | |
1633 case Tstruct: | |
1634 ad = ((TypeStruct *)tab)->sym; | |
1635 goto Laggr; | |
1636 | |
1637 Laggr: | |
1638 if (!sliced) | |
1639 { | |
1640 sapply = search_function(ad, idapply); | |
1641 if (sapply) | |
1642 { | |
1643 // opApply aggregate | |
1644 break; | |
1645 } | |
1646 | |
1647 if (fes->aggr->op != TOKtype) | |
1648 { | |
1649 Expression *rinit = new ArrayExp(fes->aggr->loc, fes->aggr); | |
1650 rinit = trySemantic(rinit, sc); | |
1651 if (rinit) // if application of [] succeeded | |
1652 { | |
1653 aggr = rinit; | |
1654 sliced = 1; | |
1655 continue; | |
1656 } | |
1657 } | |
1658 } | |
1659 | |
1660 if (ad->search(Loc(), idfront)) | |
1661 { | |
1662 // range aggregate | |
1663 break; | |
1664 } | |
1665 | |
1666 if (ad->aliasthis) | |
1667 { | |
1668 if (att == tab) | |
1669 goto Lerr; | |
1670 if (!att && tab->checkAliasThisRec()) | |
1671 att = tab; | |
1672 aggr = resolveAliasThis(sc, aggr); | |
1673 continue; | |
1674 } | |
1675 goto Lerr; | |
1676 | |
1677 case Tdelegate: | |
1678 if (aggr->op == TOKdelegate) | |
1679 { | |
1680 sapply = ((DelegateExp *)aggr)->func; | |
1681 } | |
1682 break; | |
1683 | |
1684 case Terror: | |
1685 break; | |
1686 | |
1687 default: | |
1688 goto Lerr; | |
1689 } | |
1690 break; | |
1691 } | |
1692 fes->aggr = aggr; | |
1693 return true; | |
1694 | |
1695 Lerr: | |
1696 return false; | |
1697 } | |
1698 | |
1699 /***************************************** | |
1700 * Given array of parameters and an aggregate type, | |
1701 * if any of the parameter types are missing, attempt to infer | |
1702 * them from the aggregate type. | |
1703 */ | |
1704 | |
1705 bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply) | |
1706 { | |
1707 if (!fes->parameters || !fes->parameters->dim) | |
1708 return false; | |
1709 | |
1710 if (sapply) // prefer opApply | |
1711 { | |
1712 for (size_t u = 0; u < fes->parameters->dim; u++) | |
1713 { | |
1714 Parameter *p = (*fes->parameters)[u]; | |
1715 if (p->type) | |
1716 { | |
1717 p->type = p->type->semantic(fes->loc, sc); | |
1718 p->type = p->type->addStorageClass(p->storageClass); | |
1719 } | |
1720 } | |
1721 | |
1722 Expression *ethis; | |
1723 Type *tab = fes->aggr->type->toBasetype(); | |
1724 if (tab->ty == Tclass || tab->ty == Tstruct) | |
1725 ethis = fes->aggr; | |
1726 else | |
1727 { assert(tab->ty == Tdelegate && fes->aggr->op == TOKdelegate); | |
1728 ethis = ((DelegateExp *)fes->aggr)->e1; | |
1729 } | |
1730 | |
1731 /* Look for like an | |
1732 * int opApply(int delegate(ref Type [, ...]) dg); | |
1733 * overload | |
1734 */ | |
1735 FuncDeclaration *fd = sapply->isFuncDeclaration(); | |
1736 if (fd) | |
1737 { | |
1738 sapply = inferApplyArgTypesX(ethis, fd, fes->parameters); | |
1739 } | |
1740 return sapply != NULL; | |
1741 } | |
1742 | |
1743 /* Return if no parameters need types. | |
1744 */ | |
1745 for (size_t u = 0; u < fes->parameters->dim; u++) | |
1746 { | |
1747 Parameter *p = (*fes->parameters)[u]; | |
1748 if (!p->type) | |
1749 break; | |
1750 } | |
1751 | |
1752 AggregateDeclaration *ad; | |
1753 | |
1754 Parameter *p = (*fes->parameters)[0]; | |
1755 Type *taggr = fes->aggr->type; | |
1756 assert(taggr); | |
1757 Type *tab = taggr->toBasetype(); | |
1758 switch (tab->ty) | |
1759 { | |
1760 case Tarray: | |
1761 case Tsarray: | |
1762 case Ttuple: | |
1763 if (fes->parameters->dim == 2) | |
1764 { | |
1765 if (!p->type) | |
1766 { | |
1767 p->type = Type::tsize_t; // key type | |
1768 p->type = p->type->addStorageClass(p->storageClass); | |
1769 } | |
1770 p = (*fes->parameters)[1]; | |
1771 } | |
1772 if (!p->type && tab->ty != Ttuple) | |
1773 { | |
1774 p->type = tab->nextOf(); // value type | |
1775 p->type = p->type->addStorageClass(p->storageClass); | |
1776 } | |
1777 break; | |
1778 | |
1779 case Taarray: | |
1780 { | |
1781 TypeAArray *taa = (TypeAArray *)tab; | |
1782 | |
1783 if (fes->parameters->dim == 2) | |
1784 { | |
1785 if (!p->type) | |
1786 { | |
1787 p->type = taa->index; // key type | |
1788 p->type = p->type->addStorageClass(p->storageClass); | |
1789 if (p->storageClass & STCref) // key must not be mutated via ref | |
1790 p->type = p->type->addMod(MODconst); | |
1791 } | |
1792 p = (*fes->parameters)[1]; | |
1793 } | |
1794 if (!p->type) | |
1795 { | |
1796 p->type = taa->next; // value type | |
1797 p->type = p->type->addStorageClass(p->storageClass); | |
1798 } | |
1799 break; | |
1800 } | |
1801 | |
1802 case Tclass: | |
1803 ad = ((TypeClass *)tab)->sym; | |
1804 goto Laggr; | |
1805 | |
1806 case Tstruct: | |
1807 ad = ((TypeStruct *)tab)->sym; | |
1808 goto Laggr; | |
1809 | |
1810 Laggr: | |
1811 if (fes->parameters->dim == 1) | |
1812 { | |
1813 if (!p->type) | |
1814 { | |
1815 /* Look for a front() or back() overload | |
1816 */ | |
1817 Identifier *id = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback; | |
1818 Dsymbol *s = ad->search(Loc(), id); | |
1819 FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; | |
1820 if (fd) | |
1821 { | |
1822 // Resolve inout qualifier of front type | |
1823 p->type = fd->type->nextOf(); | |
1824 if (p->type) | |
1825 { | |
1826 p->type = p->type->substWildTo(tab->mod); | |
1827 p->type = p->type->addStorageClass(p->storageClass); | |
1828 } | |
1829 } | |
1830 else if (s && s->isTemplateDeclaration()) | |
1831 ; | |
1832 else if (s && s->isDeclaration()) | |
1833 p->type = ((Declaration *)s)->type; | |
1834 else | |
1835 break; | |
1836 } | |
1837 break; | |
1838 } | |
1839 break; | |
1840 | |
1841 case Tdelegate: | |
1842 { | |
1843 if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), fes->parameters)) | |
1844 return false; | |
1845 break; | |
1846 } | |
1847 | |
1848 default: | |
1849 break; // ignore error, caught later | |
1850 } | |
1851 return true; | |
1852 } | |
1853 | |
1854 static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters) | |
1855 { | |
1856 struct ParamOpOver | |
1857 { | |
1858 Parameters *parameters; | |
1859 MOD mod; | |
1860 MATCH match; | |
1861 FuncDeclaration *fd_best; | |
1862 FuncDeclaration *fd_ambig; | |
1863 | |
1864 static int fp(void *param, Dsymbol *s) | |
1865 { | |
1866 FuncDeclaration *f = s->isFuncDeclaration(); | |
1867 if (!f) | |
1868 return 0; | |
1869 ParamOpOver *p = (ParamOpOver *)param; | |
1870 TypeFunction *tf = (TypeFunction *)f->type; | |
1871 MATCH m = MATCHexact; | |
1872 | |
1873 if (f->isThis()) | |
1874 { | |
1875 if (!MODimplicitConv(p->mod, tf->mod)) | |
1876 m = MATCHnomatch; | |
1877 else if (p->mod != tf->mod) | |
1878 m = MATCHconst; | |
1879 } | |
1880 if (!inferApplyArgTypesY(tf, p->parameters, 1)) | |
1881 m = MATCHnomatch; | |
1882 | |
1883 if (m > p->match) | |
1884 { | |
1885 p->fd_best = f; | |
1886 p->fd_ambig = NULL; | |
1887 p->match = m; | |
1888 } | |
1889 else if (m == p->match) | |
1890 p->fd_ambig = f; | |
1891 return 0; | |
1892 } | |
1893 }; | |
1894 ParamOpOver p; | |
1895 p.parameters = parameters; | |
1896 p.mod = ethis->type->mod; | |
1897 p.match = MATCHnomatch; | |
1898 p.fd_best = NULL; | |
1899 p.fd_ambig = NULL; | |
1900 overloadApply(fstart, &p, &ParamOpOver::fp); | |
1901 if (p.fd_best) | |
1902 { | |
1903 inferApplyArgTypesY((TypeFunction *)p.fd_best->type, parameters); | |
1904 if (p.fd_ambig) | |
1905 { ::error(ethis->loc, "%s.%s matches more than one declaration:\n%s: %s\nand:\n%s: %s", | |
1906 ethis->toChars(), fstart->ident->toChars(), | |
1907 p.fd_best ->loc.toChars(), p.fd_best ->type->toChars(), | |
1908 p.fd_ambig->loc.toChars(), p.fd_ambig->type->toChars()); | |
1909 p.fd_best = NULL; | |
1910 } | |
1911 } | |
1912 return p.fd_best; | |
1913 } | |
1914 | |
1915 /****************************** | |
1916 * Infer parameters from type of function. | |
1917 * Returns: | |
1918 * 1 match for this function | |
1919 * 0 no match for this function | |
1920 */ | |
1921 | |
1922 static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags) | |
1923 { size_t nparams; | |
1924 Parameter *p; | |
1925 | |
1926 if (Parameter::dim(tf->parameters) != 1) | |
1927 goto Lnomatch; | |
1928 p = Parameter::getNth(tf->parameters, 0); | |
1929 if (p->type->ty != Tdelegate) | |
1930 goto Lnomatch; | |
1931 tf = (TypeFunction *)p->type->nextOf(); | |
1932 assert(tf->ty == Tfunction); | |
1933 | |
1934 /* We now have tf, the type of the delegate. Match it against | |
1935 * the parameters, filling in missing parameter types. | |
1936 */ | |
1937 nparams = Parameter::dim(tf->parameters); | |
1938 if (nparams == 0 || tf->varargs) | |
1939 goto Lnomatch; // not enough parameters | |
1940 if (parameters->dim != nparams) | |
1941 goto Lnomatch; // not enough parameters | |
1942 | |
1943 for (size_t u = 0; u < nparams; u++) | |
1944 { | |
1945 p = (*parameters)[u]; | |
1946 Parameter *param = Parameter::getNth(tf->parameters, u); | |
1947 if (p->type) | |
1948 { | |
1949 if (!p->type->equals(param->type)) | |
1950 goto Lnomatch; | |
1951 } | |
1952 else if (!flags) | |
1953 { | |
1954 p->type = param->type; | |
1955 p->type = p->type->addStorageClass(p->storageClass); | |
1956 } | |
1957 } | |
1958 return 1; | |
1959 | |
1960 Lnomatch: | |
1961 return 0; | |
1962 } | |
1963 |