comparison dmd/TypeFunction.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children fd4acc376c45
comparison
equal deleted inserted replaced
-1:000000000000 0:10317f0c89a5
1 module dmd.TypeFunction;
2
3 import dmd.TypeNext;
4 import dmd.TypeSArray;
5 import dmd.TypeArray;
6 import dmd.ArrayTypes;
7 import dmd.LINK;
8 import dmd.StructDeclaration;
9 import dmd.TypeStruct;
10 import dmd.Global;
11 import dmd.STC;
12 import dmd.MOD;
13 import dmd.Type;
14 import dmd.Loc;
15 import dmd.Scope;
16 import dmd.Identifier;
17 import dmd.OutBuffer;
18 import dmd.HdrGenState;
19 import dmd.CppMangleState;
20 import dmd.TypeInfoDeclaration;
21 import dmd.MATCH;
22 import dmd.Argument;
23 import dmd.Expression;
24 import dmd.RET;
25 import dmd.TY;
26 import dmd.Util;
27
28 import dmd.backend.TYPE;
29 import dmd.backend.PARAM;
30 import dmd.backend.Util;
31 import dmd.backend.TYM;
32 import dmd.backend.TF;
33 import dmd.backend.mTY;
34
35 import core.stdc.stdlib;
36 import core.stdc.string;
37
38 class TypeFunction : TypeNext
39 {
40 // .next is the return type
41
42 Arguments parameters; // function parameters
43 int varargs; // 1: T t, ...) style for variable number of arguments
44 // 2: T t ...) style for variable number of arguments
45 bool isnothrow; // true: nothrow
46 bool ispure; // true: pure
47 bool isproperty; // can be called without parentheses
48 bool isref; // true: returns a reference
49 LINK linkage; // calling convention
50
51 int inuse;
52
53 this(Arguments parameters, Type treturn, int varargs, LINK linkage)
54 {
55 super(TY.Tfunction, treturn);
56
57 //if (!treturn) *(char*)0=0;
58 // assert(treturn);
59 assert(0 <= varargs && varargs <= 2);
60 this.parameters = parameters;
61 this.varargs = varargs;
62 this.linkage = linkage;
63 }
64
65 Type syntaxCopy()
66 {
67 Type treturn = next ? next.syntaxCopy() : null;
68 Arguments params = Argument.arraySyntaxCopy(parameters);
69 TypeFunction t = new TypeFunction(params, treturn, varargs, linkage);
70 t.mod = mod;
71 t.isnothrow = isnothrow;
72 t.ispure = ispure;
73 t.isproperty = isproperty;
74 t.isref = isref;
75
76 return t;
77 }
78
79 version (DumbClone) {
80 } else {
81 final TypeFunction cloneTo(TypeFunction t)
82 {
83 super.cloneTo(t);
84
85 // these 3 should be set by ctor
86 assert(t.parameters is null);
87 assert(t.varargs == varargs);
88 assert(t.linkage == linkage);
89
90 t.isnothrow = isnothrow;
91 t.ispure = ispure;
92 t.isproperty = isproperty;
93 t.isref = isref;
94 t.inuse = inuse;
95
96 if (parameters)
97 {
98 t.parameters = parameters.copy();
99 for (size_t i = 0; i < parameters.dim; i++)
100 {
101 Argument arg = cast(Argument)parameters.data[i];
102 Argument cpy = arg.clone();
103 t.parameters.data[i] = cast(void*)cpy;
104 }
105 }
106
107 return t;
108 }
109
110 TypeFunction clone()
111 {
112 assert(this.classinfo == TypeFunction.classinfo);
113 return cloneTo(new TypeFunction(null, next, varargs, linkage));
114 }
115 }
116 Type semantic(Loc loc, Scope sc)
117 {
118 if (deco) // if semantic() already run
119 {
120 //printf("already done\n");
121 return this;
122 }
123 //printf("TypeFunction.semantic() this = %p\n", this);
124 //printf("TypeFunction.semantic() %s, sc.stc = %x\n", toChars(), sc.stc);
125
126 /* Copy in order to not mess up original.
127 * This can produce redundant copies if inferring return type,
128 * as semantic() will get called again on this.
129 */
130
131 TypeFunction tf = cast(TypeFunction)clone();
132
133 if (sc.stc & STC.STCpure)
134 tf.ispure = true;
135 if (sc.stc & STC.STCnothrow)
136 tf.isnothrow = true;
137 if (sc.stc & STC.STCref)
138 tf.isref = true;
139
140 tf.linkage = sc.linkage;
141 if (tf.next)
142 {
143 tf.next = tf.next.semantic(loc,sc);
144 if (tf.next.toBasetype().ty == TY.Tsarray)
145 { error(loc, "functions cannot return static array %s", tf.next.toChars());
146 tf.next = Type.terror;
147 }
148 if (tf.next.toBasetype().ty == TY.Tfunction)
149 { error(loc, "functions cannot return a function");
150 tf.next = Type.terror;
151 }
152 if (tf.next.toBasetype().ty == TY.Ttuple)
153 { error(loc, "functions cannot return a tuple");
154 tf.next = Type.terror;
155 }
156 if (tf.next.isauto() && !(sc.flags & SCOPE.SCOPEctor))
157 error(loc, "functions cannot return scope %s", tf.next.toChars());
158 }
159
160 if (tf.parameters)
161 { size_t dim = Argument.dim(tf.parameters);
162
163 for (size_t i = 0; i < dim; i++)
164 { Argument arg = Argument.getNth(tf.parameters, i);
165
166 tf.inuse++;
167 arg.type = arg.type.semantic(loc,sc);
168 if (tf.inuse == 1) tf.inuse--;
169
170 arg.type = arg.type.addStorageClass(arg.storageClass);
171
172 if (arg.storageClass & (STC.STCauto | STC.STCalias | STC.STCstatic))
173 {
174 if (!arg.type)
175 continue;
176 }
177
178 Type t = arg.type.toBasetype();
179
180 if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy))
181 {
182 if (t.ty == TY.Tsarray)
183 error(loc, "cannot have out or ref parameter of type %s", t.toChars());
184 if (arg.storageClass & STC.STCout && arg.type.mod)
185 error(loc, "cannot have const/invariant out parameter of type %s", t.toChars());
186 }
187 if (!(arg.storageClass & STC.STClazy) && t.ty == TY.Tvoid)
188 error(loc, "cannot have parameter of type %s", arg.type.toChars());
189
190 if (arg.defaultArg)
191 {
192 arg.defaultArg = arg.defaultArg.semantic(sc);
193 arg.defaultArg = resolveProperties(sc, arg.defaultArg);
194 arg.defaultArg = arg.defaultArg.implicitCastTo(sc, arg.type);
195 }
196
197 /* If arg turns out to be a tuple, the number of parameters may
198 * change.
199 */
200 if (t.ty == TY.Ttuple)
201 { dim = Argument.dim(tf.parameters);
202 i--;
203 }
204 }
205 }
206 if (tf.next)
207 tf.deco = tf.merge().deco;
208
209 if (tf.inuse)
210 { error(loc, "recursive type");
211 tf.inuse = 0;
212 return terror;
213 }
214
215 if (tf.varargs == 1 && tf.linkage != LINK.LINKd && Argument.dim(tf.parameters) == 0)
216 error(loc, "variadic functions with non-D linkage must have at least one parameter");
217
218 /* Don't return merge(), because arg identifiers and default args
219 * can be different
220 * even though the types match
221 */
222 return tf;
223 }
224
225 void toDecoBuffer(OutBuffer buf, int flag)
226 {
227 ubyte mc;
228
229 //printf("TypeFunction.toDecoBuffer() this = %p %s\n", this, toChars());
230 //static int nest; if (++nest == 50) *(char*)0=0;
231 if (inuse)
232 {
233 inuse = 2; // flag error to caller
234 return;
235 }
236 inuse++;
237 static if (true) {
238 if (mod & MOD.MODshared)
239 buf.writeByte('O');
240 if (mod & MOD.MODconst)
241 buf.writeByte('x');
242 else if (mod & MOD.MODinvariant)
243 buf.writeByte('y');
244 }
245 switch (linkage)
246 {
247 case LINK.LINKd: mc = 'F'; break;
248 case LINK.LINKc: mc = 'U'; break;
249 case LINK.LINKwindows: mc = 'W'; break;
250 case LINK.LINKpascal: mc = 'V'; break;
251 case LINK.LINKcpp: mc = 'R'; break;
252 }
253 buf.writeByte(mc);
254 if (ispure || isnothrow || isproperty || isref)
255 {
256 if (ispure)
257 buf.writestring("Na");
258 if (isnothrow)
259 buf.writestring("Nb");
260 if (isref)
261 buf.writestring("Nc");
262 if (isproperty)
263 buf.writestring("Nd");
264 }
265 // Write argument types
266 Argument.argsToDecoBuffer(buf, parameters);
267 //if (buf.data[buf.offset - 1] == '@') halt();
268 buf.writeByte('Z' - varargs); // mark end of arg list
269 next.toDecoBuffer(buf);
270 inuse--;
271 }
272
273 void toCBuffer(OutBuffer buf, Identifier ident, HdrGenState* hgs)
274 {
275 //printf("TypeFunction.toCBuffer() this = %p\n", this);
276 string p = null;
277
278 if (inuse)
279 {
280 inuse = 2; // flag error to caller
281 return;
282 }
283 inuse++;
284
285 /* Use 'storage class' style for attributes
286 */
287 if (mod & MODconst)
288 buf.writestring("const ");
289 if (mod & MODinvariant)
290 buf.writestring("immutable ");
291 if (mod & MODshared)
292 buf.writestring("shared ");
293
294 if (ispure)
295 buf.writestring("pure ");
296 if (isnothrow)
297 buf.writestring("nothrow ");
298 if (isproperty)
299 buf.writestring("@property ");
300 if (isref)
301 buf.writestring("ref ");
302
303 if (next && (!ident || ident.toHChars2() == ident.toChars()))
304 next.toCBuffer2(buf, hgs, MODundefined);
305 if (hgs.ddoc != 1)
306 {
307 switch (linkage)
308 {
309 case LINKd: p = null; break;
310 case LINKc: p = "C "; break;
311 case LINKwindows: p = "Windows "; break;
312 case LINKpascal: p = "Pascal "; break;
313 case LINKcpp: p = "C++ "; break;
314 default:
315 assert(0);
316 }
317 }
318
319 if (!hgs.hdrgen && p)
320 buf.writestring(p);
321 if (ident)
322 {
323 buf.writeByte(' ');
324 buf.writestring(ident.toHChars2());
325 }
326 Argument.argsToCBuffer(buf, hgs, parameters, varargs);
327 inuse--;
328 }
329
330 void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod)
331 {
332 //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref);
333 string p;
334
335 if (inuse)
336 {
337 inuse = 2; // flag error to caller
338 return;
339 }
340
341 inuse++;
342 if (next)
343 next.toCBuffer2(buf, hgs, MODundefined);
344
345 if (hgs.ddoc != 1)
346 {
347 switch (linkage)
348 {
349 case LINKd: p = null; break;
350 case LINKc: p = "C "; break;
351 case LINKwindows: p = "Windows "; break;
352 case LINKpascal: p = "Pascal "; break;
353 case LINKcpp: p = "C++ "; break;
354 default: assert(0);
355 }
356 }
357
358 if (!hgs.hdrgen && p)
359 buf.writestring(p);
360 buf.writestring(" function");
361 Argument.argsToCBuffer(buf, hgs, parameters, varargs);
362
363 /* Use postfix style for attributes
364 */
365 if (mod != this.mod)
366 {
367 modToBuffer(buf);
368 }
369
370 if (ispure)
371 buf.writestring(" pure");
372 if (isnothrow)
373 buf.writestring(" nothrow");
374 if (isproperty)
375 buf.writestring(" @property");
376 if (isref)
377 buf.writestring(" ref");
378
379 inuse--;
380 }
381
382 MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes)
383 {
384 assert(false);
385 }
386
387 TypeInfoDeclaration getTypeInfoDeclaration()
388 {
389 assert(false);
390 }
391
392 Type reliesOnTident()
393 {
394 if (parameters)
395 {
396 for (size_t i = 0; i < parameters.dim; i++)
397 {
398 Argument arg = cast(Argument)parameters.data[i];
399 Type t = arg.type.reliesOnTident();
400 if (t)
401 return t;
402 }
403 }
404 return next.reliesOnTident();
405 }
406
407 version (CPP_MANGLE) {
408 void toCppMangle(OutBuffer buf, CppMangleState* cms)
409 {
410 assert(false);
411 }
412 }
413
414 /***************************
415 * Examine function signature for parameter p and see if
416 * p can 'escape' the scope of the function.
417 */
418 bool parameterEscapes(Argument p)
419 {
420 /* Scope parameters do not escape.
421 * Allow 'lazy' to imply 'scope' -
422 * lazy parameters can be passed along
423 * as lazy parameters to the next function, but that isn't
424 * escaping.
425 */
426 if (p.storageClass & (STC.STCscope | STC.STClazy))
427 return false;
428
429 if (ispure)
430 { /* With pure functions, we need only be concerned if p escapes
431 * via any return statement.
432 */
433 Type tret = nextOf().toBasetype();
434 if (!isref && !tret.hasPointers())
435 { /* The result has no references, so p could not be escaping
436 * that way.
437 */
438 return false;
439 }
440 }
441
442 /* Assume it escapes in the absence of better information.
443 */
444 return true;
445 }
446
447 /********************************
448 * 'args' are being matched to function 'this'
449 * Determine match level.
450 * Returns:
451 * MATCHxxxx
452 */
453 MATCH callMatch(Expression ethis, Expressions args)
454 {
455 //printf("TypeFunction.callMatch() %s\n", toChars());
456 MATCH match = MATCH.MATCHexact; // assume exact match
457
458 if (ethis)
459 {
460 Type t = ethis.type;
461 if (t.toBasetype().ty == TY.Tpointer)
462 t = t.toBasetype().nextOf(); // change struct* to struct
463
464 if (t.mod != mod)
465 {
466 if (mod == MOD.MODconst)
467 match = MATCH.MATCHconst;
468 else
469 return MATCH.MATCHnomatch;
470 }
471 }
472
473 size_t nparams = Argument.dim(parameters);
474 size_t nargs = args ? args.dim : 0;
475 if (nparams == nargs) {
476 ;
477 } else if (nargs > nparams)
478 {
479 if (varargs == 0)
480 goto Nomatch; // too many args; no match
481 match = MATCH.MATCHconvert; // match ... with a "conversion" match level
482 }
483
484 for (size_t u = 0; u < nparams; u++)
485 {
486 MATCH m;
487 Expression arg;
488
489 // BUG: what about out and ref?
490
491 Argument p = Argument.getNth(parameters, u);
492 assert(p);
493 if (u >= nargs)
494 {
495 if (p.defaultArg)
496 continue;
497 if (varargs == 2 && u + 1 == nparams)
498 goto L1;
499 goto Nomatch; // not enough arguments
500 }
501
502 arg = cast(Expression)args.data[u];
503 assert(arg);
504
505 // Non-lvalues do not match ref or out parameters
506 if (p.storageClass & (STC.STCref | STC.STCout) && !arg.isLvalue())
507 goto Nomatch;
508
509 if (p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid && arg.type.ty != TY.Tvoid)
510 m = MATCH.MATCHconvert;
511 else
512 m = arg.implicitConvTo(p.type);
513 //printf("\tm = %d\n", m);
514 if (m == MATCH.MATCHnomatch) // if no match
515 {
516 L1:
517 if (varargs == 2 && u + 1 == nparams) // if last varargs param
518 {
519 Type tb = p.type.toBasetype();
520 TypeSArray tsa;
521 long sz;
522
523 switch (tb.ty)
524 {
525 case TY.Tsarray:
526 tsa = cast(TypeSArray)tb;
527 sz = tsa.dim.toInteger();
528 if (sz != nargs - u)
529 goto Nomatch;
530 case TY.Tarray:
531 {
532 TypeArray ta = cast(TypeArray)tb;
533 for (; u < nargs; u++)
534 {
535 arg = cast(Expression)args.data[u];
536 assert(arg);
537 static if (true) {
538 /* If lazy array of delegates,
539 * convert arg(s) to delegate(s)
540 */
541 Type tret = p.isLazyArray();
542 if (tret)
543 {
544 if (ta.next.equals(arg.type))
545 {
546 m = MATCH.MATCHexact;
547 }
548 else
549 {
550 m = arg.implicitConvTo(tret);
551 if (m == MATCH.MATCHnomatch)
552 {
553 if (tret.toBasetype().ty == TY.Tvoid)
554 m = MATCH.MATCHconvert;
555 }
556 }
557 }
558 else
559 m = arg.implicitConvTo(ta.next);
560 } else {
561 m = arg.implicitConvTo(ta.next);
562 }
563 if (m == MATCH.MATCHnomatch)
564 goto Nomatch;
565
566 if (m < match)
567 match = m;
568 }
569 goto Ldone;
570 }
571
572 case TY.Tclass:
573 // Should see if there's a constructor match?
574 // Or just leave it ambiguous?
575 goto Ldone;
576
577 default:
578 goto Nomatch;
579 }
580 }
581
582 goto Nomatch;
583 }
584
585 if (m < match)
586 match = m; // pick worst match
587 }
588
589 Ldone:
590 //printf("match = %d\n", match);
591 return match;
592
593 Nomatch:
594 //printf("no match\n");
595 return MATCH.MATCHnomatch;
596 }
597
598 type* toCtype()
599 {
600 if (ctype) {
601 return ctype;
602 }
603
604 type* t;
605 if (true)
606 {
607 param_t* paramtypes;
608 tym_t tyf;
609 type* tp;
610
611 paramtypes = null;
612 size_t nparams = Argument.dim(parameters);
613 for (size_t i = 0; i < nparams; i++)
614 {
615 Argument arg = Argument.getNth(parameters, i);
616 tp = arg.type.toCtype();
617 if (arg.storageClass & (STC.STCout | STC.STCref))
618 {
619 // C doesn't have reference types, so it's really a pointer
620 // to the parameter type
621 tp = type_allocn(TYM.TYref, tp);
622 }
623 param_append_type(&paramtypes,tp);
624 }
625 tyf = totym();
626 t = type_alloc(tyf);
627 t.Tflags |= TF.TFprototype;
628 if (varargs != 1)
629 t.Tflags |= TF.TFfixed;
630 ctype = t;
631 t.Tnext = next.toCtype();
632 t.Tnext.Tcount++;
633 t.Tparamtypes = paramtypes;
634 }
635 ctype = t;
636 return t;
637 }
638
639 /***************************
640 * Determine return style of function - whether in registers or
641 * through a hidden pointer to the caller's stack.
642 */
643 RET retStyle()
644 {
645 //printf("TypeFunction.retStyle() %s\n", toChars());
646 version (DMDV2) {
647 if (isref)
648 return RET.RETregs; // returns a pointer
649 }
650
651 Type tn = next.toBasetype();
652
653 if (tn.ty == TY.Tstruct)
654 {
655 StructDeclaration sd = (cast(TypeStruct)tn).sym;
656 if (global.params.isLinux && linkage != LINK.LINKd) {
657 ;
658 }
659 ///version (DMDV2) {
660 else if (sd.dtor || sd.cpctor) {
661 ;
662 }
663 ///}
664 else
665 {
666 switch (cast(int)tn.size())
667 {
668 case 1:
669 case 2:
670 case 4:
671 case 8:
672 return RET.RETregs; // return small structs in regs
673 // (not 3 byte structs!)
674 default:
675 break;
676 }
677 }
678 return RET.RETstack;
679 }
680 else if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
681 linkage == LINK.LINKc &&
682 tn.iscomplex())
683 {
684 if (tn.ty == TY.Tcomplex32)
685 return RET.RETregs; // in EDX:EAX, not ST1:ST0
686 else
687 return RET.RETstack;
688 }
689 else
690 return RET.RETregs;
691 }
692
693 TYM totym()
694 {
695 TYM tyf;
696
697 //printf("TypeFunction.totym(), linkage = %d\n", linkage);
698 switch (linkage)
699 {
700 case LINK.LINKwindows:
701 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYnsfunc;
702 break;
703
704 case LINK.LINKpascal:
705 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYnpfunc;
706 break;
707
708 case LINK.LINKc:
709 tyf = TYM.TYnfunc;
710 version (XXX) {///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
711 if (retStyle() == RET.RETstack)
712 tyf = TYM.TYhfunc;
713 }
714 break;
715
716 case LINK.LINKd:
717 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYjfunc;
718 break;
719
720 case LINK.LINKcpp:
721 tyf = TYM.TYnfunc;
722 break;
723
724 default:
725 writef("linkage = %d\n", linkage);
726 assert(0);
727 }
728 version (DMDV2) {
729 if (isnothrow)
730 tyf |= mTY.mTYnothrow;
731 }
732 return tyf;
733 }
734 }