]>
Commit | Line | Data |
---|---|---|
5fee5ec3 IB |
1 | /** |
2 | * Defines a D type. | |
3 | * | |
c43b5909 IB |
4 | * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved |
5 | * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) | |
6 | * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | |
5fee5ec3 IB |
7 | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d) |
8 | * Documentation: https://dlang.org/phobos/dmd_mtype.html | |
9 | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mtype.d | |
10 | */ | |
11 | ||
12 | module dmd.mtype; | |
13 | ||
14 | import core.checkedint; | |
15 | import core.stdc.stdarg; | |
16 | import core.stdc.stdio; | |
17 | import core.stdc.stdlib; | |
18 | import core.stdc.string; | |
19 | ||
20 | import dmd.aggregate; | |
21 | import dmd.arraytypes; | |
22 | import dmd.attrib; | |
23 | import dmd.astenums; | |
24 | import dmd.ast_node; | |
25 | import dmd.gluelayer; | |
26 | import dmd.dclass; | |
27 | import dmd.declaration; | |
28 | import dmd.denum; | |
29 | import dmd.dmangle; | |
30 | import dmd.dscope; | |
31 | import dmd.dstruct; | |
32 | import dmd.dsymbol; | |
33 | import dmd.dsymbolsem; | |
34 | import dmd.dtemplate; | |
35 | import dmd.errors; | |
36 | import dmd.expression; | |
37 | import dmd.expressionsem; | |
38 | import dmd.func; | |
39 | import dmd.globals; | |
40 | import dmd.hdrgen; | |
41 | import dmd.id; | |
42 | import dmd.identifier; | |
43 | import dmd.init; | |
44 | import dmd.opover; | |
45 | import dmd.root.ctfloat; | |
0fb57034 | 46 | import dmd.common.outbuffer; |
5fee5ec3 IB |
47 | import dmd.root.rmem; |
48 | import dmd.root.rootobject; | |
49 | import dmd.root.stringtable; | |
50 | import dmd.target; | |
51 | import dmd.tokens; | |
52 | import dmd.typesem; | |
53 | import dmd.visitor; | |
54 | ||
55 | enum LOGDOTEXP = 0; // log ::dotExp() | |
56 | enum LOGDEFAULTINIT = 0; // log ::defaultInit() | |
57 | ||
fbdaa581 | 58 | enum SIZE_INVALID = (~cast(uinteger_t)0); // error return from size() functions |
5fee5ec3 IB |
59 | |
60 | ||
61 | /*************************** | |
62 | * Return !=0 if modfrom can be implicitly converted to modto | |
63 | */ | |
64 | bool MODimplicitConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe | |
65 | { | |
66 | if (modfrom == modto) | |
67 | return true; | |
68 | ||
69 | //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto); | |
70 | auto X(T, U)(T m, U n) | |
71 | { | |
72 | return ((m << 4) | n); | |
73 | } | |
74 | ||
75 | switch (X(modfrom & ~MODFlags.shared_, modto & ~MODFlags.shared_)) | |
76 | { | |
77 | case X(0, MODFlags.const_): | |
78 | case X(MODFlags.wild, MODFlags.const_): | |
79 | case X(MODFlags.wild, MODFlags.wildconst): | |
80 | case X(MODFlags.wildconst, MODFlags.const_): | |
81 | return (modfrom & MODFlags.shared_) == (modto & MODFlags.shared_); | |
82 | ||
83 | case X(MODFlags.immutable_, MODFlags.const_): | |
84 | case X(MODFlags.immutable_, MODFlags.wildconst): | |
85 | return true; | |
86 | default: | |
87 | return false; | |
88 | } | |
89 | } | |
90 | ||
91 | /*************************** | |
92 | * Return MATCH.exact or MATCH.constant if a method of type '() modfrom' can call a method of type '() modto'. | |
93 | */ | |
94 | MATCH MODmethodConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe | |
95 | { | |
96 | if (modfrom == modto) | |
97 | return MATCH.exact; | |
98 | if (MODimplicitConv(modfrom, modto)) | |
99 | return MATCH.constant; | |
100 | ||
101 | auto X(T, U)(T m, U n) | |
102 | { | |
103 | return ((m << 4) | n); | |
104 | } | |
105 | ||
106 | switch (X(modfrom, modto)) | |
107 | { | |
108 | case X(0, MODFlags.wild): | |
109 | case X(MODFlags.immutable_, MODFlags.wild): | |
110 | case X(MODFlags.const_, MODFlags.wild): | |
111 | case X(MODFlags.wildconst, MODFlags.wild): | |
112 | case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild): | |
113 | case X(MODFlags.shared_ | MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild): | |
114 | case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild): | |
115 | case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild): | |
116 | return MATCH.constant; | |
117 | ||
118 | default: | |
119 | return MATCH.nomatch; | |
120 | } | |
121 | } | |
122 | ||
123 | /*************************** | |
124 | * Merge mod bits to form common mod. | |
125 | */ | |
126 | MOD MODmerge(MOD mod1, MOD mod2) pure nothrow @nogc @safe | |
127 | { | |
128 | if (mod1 == mod2) | |
129 | return mod1; | |
130 | ||
131 | //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2); | |
132 | MOD result = 0; | |
133 | if ((mod1 | mod2) & MODFlags.shared_) | |
134 | { | |
135 | // If either type is shared, the result will be shared | |
136 | result |= MODFlags.shared_; | |
137 | mod1 &= ~MODFlags.shared_; | |
138 | mod2 &= ~MODFlags.shared_; | |
139 | } | |
140 | if (mod1 == 0 || mod1 == MODFlags.mutable || mod1 == MODFlags.const_ || mod2 == 0 || mod2 == MODFlags.mutable || mod2 == MODFlags.const_) | |
141 | { | |
142 | // If either type is mutable or const, the result will be const. | |
143 | result |= MODFlags.const_; | |
144 | } | |
145 | else | |
146 | { | |
147 | // MODFlags.immutable_ vs MODFlags.wild | |
148 | // MODFlags.immutable_ vs MODFlags.wildconst | |
149 | // MODFlags.wild vs MODFlags.wildconst | |
150 | assert(mod1 & MODFlags.wild || mod2 & MODFlags.wild); | |
151 | result |= MODFlags.wildconst; | |
152 | } | |
153 | return result; | |
154 | } | |
155 | ||
156 | /********************************* | |
157 | * Store modifier name into buf. | |
158 | */ | |
159 | void MODtoBuffer(OutBuffer* buf, MOD mod) nothrow | |
160 | { | |
161 | buf.writestring(MODtoString(mod)); | |
162 | } | |
163 | ||
164 | /********************************* | |
165 | * Returns: | |
166 | * a human readable representation of `mod`, | |
167 | * which is the token `mod` corresponds to | |
168 | */ | |
169 | const(char)* MODtoChars(MOD mod) nothrow pure | |
170 | { | |
171 | /// Works because we return a literal | |
172 | return MODtoString(mod).ptr; | |
173 | } | |
174 | ||
175 | /// Ditto | |
176 | string MODtoString(MOD mod) nothrow pure | |
177 | { | |
178 | final switch (mod) | |
179 | { | |
180 | case 0: | |
181 | return ""; | |
182 | ||
183 | case MODFlags.immutable_: | |
184 | return "immutable"; | |
185 | ||
186 | case MODFlags.shared_: | |
187 | return "shared"; | |
188 | ||
189 | case MODFlags.shared_ | MODFlags.const_: | |
190 | return "shared const"; | |
191 | ||
192 | case MODFlags.const_: | |
193 | return "const"; | |
194 | ||
195 | case MODFlags.shared_ | MODFlags.wild: | |
196 | return "shared inout"; | |
197 | ||
198 | case MODFlags.wild: | |
199 | return "inout"; | |
200 | ||
201 | case MODFlags.shared_ | MODFlags.wildconst: | |
202 | return "shared inout const"; | |
203 | ||
204 | case MODFlags.wildconst: | |
205 | return "inout const"; | |
206 | } | |
207 | } | |
208 | ||
6384eff5 IB |
209 | /************************************************* |
210 | * Pick off one of the trust flags from trust, | |
211 | * and return a string representation of it. | |
212 | */ | |
213 | string trustToString(TRUST trust) pure nothrow @nogc @safe | |
214 | { | |
215 | final switch (trust) | |
216 | { | |
217 | case TRUST.default_: | |
218 | return null; | |
219 | case TRUST.system: | |
220 | return "@system"; | |
221 | case TRUST.trusted: | |
222 | return "@trusted"; | |
223 | case TRUST.safe: | |
224 | return "@safe"; | |
225 | } | |
226 | } | |
227 | ||
228 | unittest | |
229 | { | |
230 | assert(trustToString(TRUST.default_) == ""); | |
231 | assert(trustToString(TRUST.system) == "@system"); | |
232 | assert(trustToString(TRUST.trusted) == "@trusted"); | |
233 | assert(trustToString(TRUST.safe) == "@safe"); | |
234 | } | |
5fee5ec3 IB |
235 | |
236 | /************************************ | |
237 | * Convert MODxxxx to STCxxx | |
238 | */ | |
239 | StorageClass ModToStc(uint mod) pure nothrow @nogc @safe | |
240 | { | |
241 | StorageClass stc = 0; | |
242 | if (mod & MODFlags.immutable_) | |
243 | stc |= STC.immutable_; | |
244 | if (mod & MODFlags.const_) | |
245 | stc |= STC.const_; | |
246 | if (mod & MODFlags.wild) | |
247 | stc |= STC.wild; | |
248 | if (mod & MODFlags.shared_) | |
249 | stc |= STC.shared_; | |
250 | return stc; | |
251 | } | |
252 | ||
253 | ///Returns true if ty is char, wchar, or dchar | |
254 | bool isSomeChar(TY ty) pure nothrow @nogc @safe | |
255 | { | |
256 | return ty == Tchar || ty == Twchar || ty == Tdchar; | |
257 | } | |
258 | ||
d7569187 IB |
259 | /************************************ |
260 | * Determine mutability of indirections in (ref) t. | |
261 | * | |
262 | * Returns: When the type has any mutable indirections, returns 0. | |
263 | * When all indirections are immutable, returns 2. | |
264 | * Otherwise, when the type has const/inout indirections, returns 1. | |
265 | * | |
266 | * Params: | |
267 | * isref = if true, check `ref t`; otherwise, check just `t` | |
268 | * t = the type that is being checked | |
269 | */ | |
270 | int mutabilityOfType(bool isref, Type t) | |
271 | { | |
272 | if (isref) | |
273 | { | |
274 | if (t.mod & MODFlags.immutable_) | |
275 | return 2; | |
276 | if (t.mod & (MODFlags.const_ | MODFlags.wild)) | |
277 | return 1; | |
278 | return 0; | |
279 | } | |
280 | ||
281 | t = t.baseElemOf(); | |
282 | ||
283 | if (!t.hasPointers() || t.mod & MODFlags.immutable_) | |
284 | return 2; | |
285 | ||
286 | /* Accept immutable(T)[] and immutable(T)* as being strongly pure | |
287 | */ | |
288 | if (t.ty == Tarray || t.ty == Tpointer) | |
289 | { | |
290 | Type tn = t.nextOf().toBasetype(); | |
291 | if (tn.mod & MODFlags.immutable_) | |
292 | return 2; | |
293 | if (tn.mod & (MODFlags.const_ | MODFlags.wild)) | |
294 | return 1; | |
295 | } | |
296 | ||
297 | /* The rest of this is too strict; fix later. | |
298 | * For example, the only pointer members of a struct may be immutable, | |
299 | * which would maintain strong purity. | |
300 | * (Just like for dynamic arrays and pointers above.) | |
301 | */ | |
302 | if (t.mod & (MODFlags.const_ | MODFlags.wild)) | |
303 | return 1; | |
304 | ||
305 | /* Should catch delegates and function pointers, and fold in their purity | |
306 | */ | |
307 | return 0; | |
308 | } | |
309 | ||
5fee5ec3 IB |
310 | /**************** |
311 | * dotExp() bit flags | |
312 | */ | |
313 | enum DotExpFlag | |
314 | { | |
315 | gag = 1, // don't report "not a property" error and just return null | |
316 | noDeref = 2, // the use of the expression will not attempt a dereference | |
0fb57034 | 317 | noAliasThis = 4, // don't do 'alias this' resolution |
5fee5ec3 IB |
318 | } |
319 | ||
320 | /// Result of a check whether two types are covariant | |
321 | enum Covariant | |
322 | { | |
323 | distinct = 0, /// types are distinct | |
324 | yes = 1, /// types are covariant | |
325 | no = 2, /// arguments match as far as overloading goes, but types are not covariant | |
326 | fwdref = 3, /// cannot determine covariance because of forward references | |
327 | } | |
328 | ||
329 | /*********************************************************** | |
330 | */ | |
331 | extern (C++) abstract class Type : ASTNode | |
332 | { | |
333 | TY ty; | |
334 | MOD mod; // modifiers MODxxxx | |
335 | char* deco; | |
336 | ||
337 | static struct Mcache | |
338 | { | |
339 | /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc. | |
340 | * They should not be referenced by anybody but mtype.d. | |
341 | * They can be null if not lazily evaluated yet. | |
342 | * Note that there is no "shared immutable", because that is just immutable | |
343 | * The point of this is to reduce the size of each Type instance as | |
344 | * we bank on the idea that usually only one of variants exist. | |
345 | * It will also speed up code because these are rarely referenced and | |
346 | * so need not be in the cache. | |
347 | */ | |
348 | Type cto; // MODFlags.const_ | |
349 | Type ito; // MODFlags.immutable_ | |
350 | Type sto; // MODFlags.shared_ | |
351 | Type scto; // MODFlags.shared_ | MODFlags.const_ | |
352 | Type wto; // MODFlags.wild | |
353 | Type wcto; // MODFlags.wildconst | |
354 | Type swto; // MODFlags.shared_ | MODFlags.wild | |
355 | Type swcto; // MODFlags.shared_ | MODFlags.wildconst | |
356 | } | |
357 | private Mcache* mcache; | |
358 | ||
359 | Type pto; // merged pointer to this type | |
360 | Type rto; // reference to this type | |
361 | Type arrayof; // array of this type | |
362 | ||
363 | TypeInfoDeclaration vtinfo; // TypeInfo object for this Type | |
364 | ||
365 | type* ctype; // for back end | |
366 | ||
367 | extern (C++) __gshared Type tvoid; | |
368 | extern (C++) __gshared Type tint8; | |
369 | extern (C++) __gshared Type tuns8; | |
370 | extern (C++) __gshared Type tint16; | |
371 | extern (C++) __gshared Type tuns16; | |
372 | extern (C++) __gshared Type tint32; | |
373 | extern (C++) __gshared Type tuns32; | |
374 | extern (C++) __gshared Type tint64; | |
375 | extern (C++) __gshared Type tuns64; | |
376 | extern (C++) __gshared Type tint128; | |
377 | extern (C++) __gshared Type tuns128; | |
378 | extern (C++) __gshared Type tfloat32; | |
379 | extern (C++) __gshared Type tfloat64; | |
380 | extern (C++) __gshared Type tfloat80; | |
381 | extern (C++) __gshared Type timaginary32; | |
382 | extern (C++) __gshared Type timaginary64; | |
383 | extern (C++) __gshared Type timaginary80; | |
384 | extern (C++) __gshared Type tcomplex32; | |
385 | extern (C++) __gshared Type tcomplex64; | |
386 | extern (C++) __gshared Type tcomplex80; | |
387 | extern (C++) __gshared Type tbool; | |
388 | extern (C++) __gshared Type tchar; | |
389 | extern (C++) __gshared Type twchar; | |
390 | extern (C++) __gshared Type tdchar; | |
391 | ||
392 | // Some special types | |
393 | extern (C++) __gshared Type tshiftcnt; | |
394 | extern (C++) __gshared Type tvoidptr; // void* | |
395 | extern (C++) __gshared Type tstring; // immutable(char)[] | |
396 | extern (C++) __gshared Type twstring; // immutable(wchar)[] | |
397 | extern (C++) __gshared Type tdstring; // immutable(dchar)[] | |
398 | extern (C++) __gshared Type terror; // for error recovery | |
399 | extern (C++) __gshared Type tnull; // for null type | |
400 | extern (C++) __gshared Type tnoreturn; // for bottom type typeof(*null) | |
401 | ||
402 | extern (C++) __gshared Type tsize_t; // matches size_t alias | |
403 | extern (C++) __gshared Type tptrdiff_t; // matches ptrdiff_t alias | |
404 | extern (C++) __gshared Type thash_t; // matches hash_t alias | |
405 | ||
406 | extern (C++) __gshared ClassDeclaration dtypeinfo; | |
407 | extern (C++) __gshared ClassDeclaration typeinfoclass; | |
408 | extern (C++) __gshared ClassDeclaration typeinfointerface; | |
409 | extern (C++) __gshared ClassDeclaration typeinfostruct; | |
410 | extern (C++) __gshared ClassDeclaration typeinfopointer; | |
411 | extern (C++) __gshared ClassDeclaration typeinfoarray; | |
412 | extern (C++) __gshared ClassDeclaration typeinfostaticarray; | |
413 | extern (C++) __gshared ClassDeclaration typeinfoassociativearray; | |
414 | extern (C++) __gshared ClassDeclaration typeinfovector; | |
415 | extern (C++) __gshared ClassDeclaration typeinfoenum; | |
416 | extern (C++) __gshared ClassDeclaration typeinfofunction; | |
417 | extern (C++) __gshared ClassDeclaration typeinfodelegate; | |
418 | extern (C++) __gshared ClassDeclaration typeinfotypelist; | |
419 | extern (C++) __gshared ClassDeclaration typeinfoconst; | |
420 | extern (C++) __gshared ClassDeclaration typeinfoinvariant; | |
421 | extern (C++) __gshared ClassDeclaration typeinfoshared; | |
422 | extern (C++) __gshared ClassDeclaration typeinfowild; | |
423 | ||
424 | extern (C++) __gshared TemplateDeclaration rtinfo; | |
425 | ||
426 | extern (C++) __gshared Type[TMAX] basic; | |
427 | ||
428 | extern (D) __gshared StringTable!Type stringtable; | |
6384eff5 | 429 | extern (D) private static immutable ubyte[TMAX] sizeTy = () |
5fee5ec3 IB |
430 | { |
431 | ubyte[TMAX] sizeTy = __traits(classInstanceSize, TypeBasic); | |
432 | sizeTy[Tsarray] = __traits(classInstanceSize, TypeSArray); | |
433 | sizeTy[Tarray] = __traits(classInstanceSize, TypeDArray); | |
434 | sizeTy[Taarray] = __traits(classInstanceSize, TypeAArray); | |
435 | sizeTy[Tpointer] = __traits(classInstanceSize, TypePointer); | |
436 | sizeTy[Treference] = __traits(classInstanceSize, TypeReference); | |
437 | sizeTy[Tfunction] = __traits(classInstanceSize, TypeFunction); | |
438 | sizeTy[Tdelegate] = __traits(classInstanceSize, TypeDelegate); | |
439 | sizeTy[Tident] = __traits(classInstanceSize, TypeIdentifier); | |
440 | sizeTy[Tinstance] = __traits(classInstanceSize, TypeInstance); | |
441 | sizeTy[Ttypeof] = __traits(classInstanceSize, TypeTypeof); | |
442 | sizeTy[Tenum] = __traits(classInstanceSize, TypeEnum); | |
443 | sizeTy[Tstruct] = __traits(classInstanceSize, TypeStruct); | |
444 | sizeTy[Tclass] = __traits(classInstanceSize, TypeClass); | |
445 | sizeTy[Ttuple] = __traits(classInstanceSize, TypeTuple); | |
446 | sizeTy[Tslice] = __traits(classInstanceSize, TypeSlice); | |
447 | sizeTy[Treturn] = __traits(classInstanceSize, TypeReturn); | |
448 | sizeTy[Terror] = __traits(classInstanceSize, TypeError); | |
449 | sizeTy[Tnull] = __traits(classInstanceSize, TypeNull); | |
450 | sizeTy[Tvector] = __traits(classInstanceSize, TypeVector); | |
451 | sizeTy[Ttraits] = __traits(classInstanceSize, TypeTraits); | |
452 | sizeTy[Tmixin] = __traits(classInstanceSize, TypeMixin); | |
453 | sizeTy[Tnoreturn] = __traits(classInstanceSize, TypeNoreturn); | |
454 | sizeTy[Ttag] = __traits(classInstanceSize, TypeTag); | |
455 | return sizeTy; | |
456 | }(); | |
457 | ||
458 | final extern (D) this(TY ty) | |
459 | { | |
460 | this.ty = ty; | |
461 | } | |
462 | ||
463 | const(char)* kind() const nothrow pure @nogc @safe | |
464 | { | |
465 | assert(false); // should be overridden | |
466 | } | |
467 | ||
468 | final Type copy() nothrow const | |
469 | { | |
470 | Type t = cast(Type)mem.xmalloc(sizeTy[ty]); | |
471 | memcpy(cast(void*)t, cast(void*)this, sizeTy[ty]); | |
472 | return t; | |
473 | } | |
474 | ||
475 | Type syntaxCopy() | |
476 | { | |
477 | fprintf(stderr, "this = %s, ty = %d\n", toChars(), ty); | |
478 | assert(0); | |
479 | } | |
480 | ||
481 | override bool equals(const RootObject o) const | |
482 | { | |
483 | Type t = cast(Type)o; | |
484 | //printf("Type::equals(%s, %s)\n", toChars(), t.toChars()); | |
485 | // deco strings are unique | |
486 | // and semantic() has been run | |
487 | if (this == o || ((t && deco == t.deco) && deco !is null)) | |
488 | { | |
489 | //printf("deco = '%s', t.deco = '%s'\n", deco, t.deco); | |
490 | return true; | |
491 | } | |
492 | //if (deco && t && t.deco) printf("deco = '%s', t.deco = '%s'\n", deco, t.deco); | |
493 | return false; | |
494 | } | |
495 | ||
496 | final bool equivalent(Type t) | |
497 | { | |
498 | return immutableOf().equals(t.immutableOf()); | |
499 | } | |
500 | ||
501 | // kludge for template.isType() | |
502 | override final DYNCAST dyncast() const | |
503 | { | |
504 | return DYNCAST.type; | |
505 | } | |
506 | ||
0fb57034 IB |
507 | /// Returns a non-zero unique ID for this Type, or returns 0 if the Type does not (yet) have a unique ID. |
508 | /// If `semantic()` has not been run, 0 is returned. | |
509 | final size_t getUniqueID() const | |
510 | { | |
511 | return cast(size_t) deco; | |
512 | } | |
513 | ||
5fee5ec3 IB |
514 | extern (D) |
515 | final Mcache* getMcache() | |
516 | { | |
517 | if (!mcache) | |
518 | mcache = cast(Mcache*) mem.xcalloc(Mcache.sizeof, 1); | |
519 | return mcache; | |
520 | } | |
521 | ||
522 | /******************************* | |
523 | * Covariant means that 'this' can substitute for 't', | |
524 | * i.e. a pure function is a match for an impure type. | |
525 | * Params: | |
526 | * t = type 'this' is covariant with | |
527 | * pstc = if not null, store STCxxxx which would make it covariant | |
610d7898 | 528 | * cppCovariant = true if extern(C++) function types should follow C++ covariant rules |
5fee5ec3 IB |
529 | * Returns: |
530 | * An enum value of either `Covariant.yes` or a reason it's not covariant. | |
531 | */ | |
610d7898 | 532 | final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false) |
5fee5ec3 IB |
533 | { |
534 | version (none) | |
535 | { | |
536 | printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars()); | |
537 | printf("deco = %p, %p\n", deco, t.deco); | |
538 | // printf("ty = %d\n", next.ty); | |
539 | printf("mod = %x, %x\n", mod, t.mod); | |
540 | } | |
541 | if (pstc) | |
542 | *pstc = 0; | |
543 | StorageClass stc = 0; | |
544 | ||
545 | bool notcovariant = false; | |
546 | ||
547 | if (equals(t)) | |
548 | return Covariant.yes; | |
549 | ||
550 | TypeFunction t1 = this.isTypeFunction(); | |
551 | TypeFunction t2 = t.isTypeFunction(); | |
552 | ||
553 | if (!t1 || !t2) | |
554 | goto Ldistinct; | |
555 | ||
556 | if (t1.parameterList.varargs != t2.parameterList.varargs) | |
557 | goto Ldistinct; | |
558 | ||
559 | if (t1.parameterList.parameters && t2.parameterList.parameters) | |
560 | { | |
561 | if (t1.parameterList.length != t2.parameterList.length) | |
562 | goto Ldistinct; | |
563 | ||
564 | foreach (i, fparam1; t1.parameterList) | |
565 | { | |
566 | Parameter fparam2 = t2.parameterList[i]; | |
610d7898 IB |
567 | Type tp1 = fparam1.type; |
568 | Type tp2 = fparam2.type; | |
5fee5ec3 | 569 | |
610d7898 | 570 | if (!tp1.equals(tp2)) |
5fee5ec3 | 571 | { |
5fee5ec3 IB |
572 | if (tp1.ty == tp2.ty) |
573 | { | |
574 | if (auto tc1 = tp1.isTypeClass()) | |
575 | { | |
576 | if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) | |
577 | goto Lcov; | |
578 | } | |
579 | else if (auto ts1 = tp1.isTypeStruct()) | |
580 | { | |
581 | if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) | |
582 | goto Lcov; | |
583 | } | |
584 | else if (tp1.ty == Tpointer) | |
585 | { | |
586 | if (tp2.implicitConvTo(tp1)) | |
587 | goto Lcov; | |
588 | } | |
589 | else if (tp1.ty == Tarray) | |
590 | { | |
591 | if (tp2.implicitConvTo(tp1)) | |
592 | goto Lcov; | |
593 | } | |
594 | else if (tp1.ty == Tdelegate) | |
595 | { | |
9c7d5e88 | 596 | if (tp2.implicitConvTo(tp1)) |
5fee5ec3 IB |
597 | goto Lcov; |
598 | } | |
599 | } | |
600 | goto Ldistinct; | |
601 | } | |
602 | Lcov: | |
603 | notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); | |
610d7898 IB |
604 | |
605 | /* https://issues.dlang.org/show_bug.cgi?id=23135 | |
606 | * extern(C++) mutable parameters are not covariant with const. | |
607 | */ | |
608 | if (t1.linkage == LINK.cpp && cppCovariant) | |
609 | { | |
610 | notcovariant |= tp1.isNaked() != tp2.isNaked(); | |
611 | if (auto tpn1 = tp1.nextOf()) | |
612 | notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked(); | |
613 | } | |
5fee5ec3 IB |
614 | } |
615 | } | |
616 | else if (t1.parameterList.parameters != t2.parameterList.parameters) | |
617 | { | |
618 | if (t1.parameterList.length || t2.parameterList.length) | |
619 | goto Ldistinct; | |
620 | } | |
621 | ||
622 | // The argument lists match | |
623 | if (notcovariant) | |
624 | goto Lnotcovariant; | |
625 | if (t1.linkage != t2.linkage) | |
626 | goto Lnotcovariant; | |
627 | ||
628 | { | |
629 | // Return types | |
630 | Type t1n = t1.next; | |
631 | Type t2n = t2.next; | |
632 | ||
633 | if (!t1n || !t2n) // happens with return type inference | |
634 | goto Lnotcovariant; | |
635 | ||
636 | if (t1n.equals(t2n)) | |
637 | goto Lcovariant; | |
638 | if (t1n.ty == Tclass && t2n.ty == Tclass) | |
639 | { | |
640 | /* If same class type, but t2n is const, then it's | |
641 | * covariant. Do this test first because it can work on | |
642 | * forward references. | |
643 | */ | |
644 | if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) | |
645 | goto Lcovariant; | |
646 | ||
647 | // If t1n is forward referenced: | |
648 | ClassDeclaration cd = (cast(TypeClass)t1n).sym; | |
649 | if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) | |
650 | cd.dsymbolSemantic(null); | |
651 | if (!cd.isBaseInfoComplete()) | |
652 | { | |
653 | return Covariant.fwdref; | |
654 | } | |
655 | } | |
656 | if (t1n.ty == Tstruct && t2n.ty == Tstruct) | |
657 | { | |
658 | if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) | |
659 | goto Lcovariant; | |
660 | } | |
661 | else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) | |
1027dc45 IB |
662 | { |
663 | if (t1.isref && t2.isref) | |
664 | { | |
665 | // Treat like pointers to t1n and t2n | |
666 | if (t1n.constConv(t2n) < MATCH.constant) | |
667 | goto Lnotcovariant; | |
668 | } | |
5fee5ec3 | 669 | goto Lcovariant; |
1027dc45 | 670 | } |
5fee5ec3 IB |
671 | else if (t1n.ty == Tnull) |
672 | { | |
673 | // NULL is covariant with any pointer type, but not with any | |
674 | // dynamic arrays, associative arrays or delegates. | |
675 | // https://issues.dlang.org/show_bug.cgi?id=8589 | |
676 | // https://issues.dlang.org/show_bug.cgi?id=19618 | |
677 | Type t2bn = t2n.toBasetype(); | |
678 | if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass) | |
679 | goto Lcovariant; | |
680 | } | |
681 | // bottom type is covariant to any type | |
682 | else if (t1n.ty == Tnoreturn) | |
683 | goto Lcovariant; | |
684 | } | |
685 | goto Lnotcovariant; | |
686 | ||
687 | Lcovariant: | |
688 | if (t1.isref != t2.isref) | |
689 | goto Lnotcovariant; | |
690 | ||
691 | if (!t1.isref && (t1.isScopeQual || t2.isScopeQual)) | |
692 | { | |
693 | StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0; | |
694 | StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0; | |
695 | if (t1.isreturn) | |
696 | { | |
697 | stc1 |= STC.return_; | |
698 | if (!t1.isScopeQual) | |
699 | stc1 |= STC.ref_; | |
700 | } | |
701 | if (t2.isreturn) | |
702 | { | |
703 | stc2 |= STC.return_; | |
704 | if (!t2.isScopeQual) | |
705 | stc2 |= STC.ref_; | |
706 | } | |
707 | if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) | |
708 | goto Lnotcovariant; | |
709 | } | |
710 | ||
711 | // We can subtract 'return ref' from 'this', but cannot add it | |
712 | else if (t1.isreturn && !t2.isreturn) | |
713 | goto Lnotcovariant; | |
714 | ||
610d7898 IB |
715 | /* https://issues.dlang.org/show_bug.cgi?id=23135 |
716 | * extern(C++) mutable member functions are not covariant with const. | |
717 | */ | |
718 | if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked()) | |
719 | goto Lnotcovariant; | |
720 | ||
5fee5ec3 IB |
721 | /* Can convert mutable to const |
722 | */ | |
723 | if (!MODimplicitConv(t2.mod, t1.mod)) | |
724 | { | |
725 | version (none) | |
726 | { | |
727 | //stop attribute inference with const | |
728 | // If adding 'const' will make it covariant | |
729 | if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) | |
730 | stc |= STC.const_; | |
731 | else | |
732 | goto Lnotcovariant; | |
733 | } | |
734 | else | |
735 | { | |
736 | goto Ldistinct; | |
737 | } | |
738 | } | |
739 | ||
740 | /* Can convert pure to impure, nothrow to throw, and nogc to gc | |
741 | */ | |
742 | if (!t1.purity && t2.purity) | |
743 | stc |= STC.pure_; | |
744 | ||
745 | if (!t1.isnothrow && t2.isnothrow) | |
746 | stc |= STC.nothrow_; | |
747 | ||
748 | if (!t1.isnogc && t2.isnogc) | |
749 | stc |= STC.nogc; | |
750 | ||
751 | /* Can convert safe/trusted to system | |
752 | */ | |
753 | if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) | |
754 | { | |
755 | // Should we infer trusted or safe? Go with safe. | |
756 | stc |= STC.safe; | |
757 | } | |
758 | ||
759 | if (stc) | |
760 | { | |
761 | if (pstc) | |
762 | *pstc = stc; | |
763 | goto Lnotcovariant; | |
764 | } | |
765 | ||
766 | //printf("\tcovaraint: 1\n"); | |
767 | return Covariant.yes; | |
768 | ||
769 | Ldistinct: | |
770 | //printf("\tcovaraint: 0\n"); | |
771 | return Covariant.distinct; | |
772 | ||
773 | Lnotcovariant: | |
774 | //printf("\tcovaraint: 2\n"); | |
775 | return Covariant.no; | |
776 | } | |
777 | ||
778 | /******************************** | |
779 | * For pretty-printing a type. | |
780 | */ | |
781 | final override const(char)* toChars() const | |
782 | { | |
783 | OutBuffer buf; | |
784 | buf.reserve(16); | |
785 | HdrGenState hgs; | |
786 | hgs.fullQual = (ty == Tclass && !mod); | |
787 | ||
788 | .toCBuffer(this, &buf, null, &hgs); | |
789 | return buf.extractChars(); | |
790 | } | |
791 | ||
792 | /// ditto | |
793 | final char* toPrettyChars(bool QualifyTypes = false) | |
794 | { | |
795 | OutBuffer buf; | |
796 | buf.reserve(16); | |
797 | HdrGenState hgs; | |
798 | hgs.fullQual = QualifyTypes; | |
799 | ||
800 | .toCBuffer(this, &buf, null, &hgs); | |
801 | return buf.extractChars(); | |
802 | } | |
803 | ||
804 | static void _init() | |
805 | { | |
806 | stringtable._init(14_000); | |
807 | ||
808 | // Set basic types | |
809 | __gshared TY* basetab = | |
810 | [ | |
811 | Tvoid, | |
812 | Tint8, | |
813 | Tuns8, | |
814 | Tint16, | |
815 | Tuns16, | |
816 | Tint32, | |
817 | Tuns32, | |
818 | Tint64, | |
819 | Tuns64, | |
820 | Tint128, | |
821 | Tuns128, | |
822 | Tfloat32, | |
823 | Tfloat64, | |
824 | Tfloat80, | |
825 | Timaginary32, | |
826 | Timaginary64, | |
827 | Timaginary80, | |
828 | Tcomplex32, | |
829 | Tcomplex64, | |
830 | Tcomplex80, | |
831 | Tbool, | |
832 | Tchar, | |
833 | Twchar, | |
834 | Tdchar, | |
835 | Terror | |
836 | ]; | |
837 | ||
838 | for (size_t i = 0; basetab[i] != Terror; i++) | |
839 | { | |
840 | Type t = new TypeBasic(basetab[i]); | |
841 | t = t.merge(); | |
842 | basic[basetab[i]] = t; | |
843 | } | |
844 | basic[Terror] = new TypeError(); | |
845 | ||
846 | tnoreturn = new TypeNoreturn(); | |
847 | tnoreturn.deco = tnoreturn.merge().deco; | |
848 | basic[Tnoreturn] = tnoreturn; | |
849 | ||
850 | tvoid = basic[Tvoid]; | |
851 | tint8 = basic[Tint8]; | |
852 | tuns8 = basic[Tuns8]; | |
853 | tint16 = basic[Tint16]; | |
854 | tuns16 = basic[Tuns16]; | |
855 | tint32 = basic[Tint32]; | |
856 | tuns32 = basic[Tuns32]; | |
857 | tint64 = basic[Tint64]; | |
858 | tuns64 = basic[Tuns64]; | |
859 | tint128 = basic[Tint128]; | |
860 | tuns128 = basic[Tuns128]; | |
861 | tfloat32 = basic[Tfloat32]; | |
862 | tfloat64 = basic[Tfloat64]; | |
863 | tfloat80 = basic[Tfloat80]; | |
864 | ||
865 | timaginary32 = basic[Timaginary32]; | |
866 | timaginary64 = basic[Timaginary64]; | |
867 | timaginary80 = basic[Timaginary80]; | |
868 | ||
869 | tcomplex32 = basic[Tcomplex32]; | |
870 | tcomplex64 = basic[Tcomplex64]; | |
871 | tcomplex80 = basic[Tcomplex80]; | |
872 | ||
873 | tbool = basic[Tbool]; | |
874 | tchar = basic[Tchar]; | |
875 | twchar = basic[Twchar]; | |
876 | tdchar = basic[Tdchar]; | |
877 | ||
878 | tshiftcnt = tint32; | |
879 | terror = basic[Terror]; | |
880 | tnoreturn = basic[Tnoreturn]; | |
881 | tnull = new TypeNull(); | |
882 | tnull.deco = tnull.merge().deco; | |
883 | ||
884 | tvoidptr = tvoid.pointerTo(); | |
885 | tstring = tchar.immutableOf().arrayOf(); | |
886 | twstring = twchar.immutableOf().arrayOf(); | |
887 | tdstring = tdchar.immutableOf().arrayOf(); | |
888 | ||
889 | const isLP64 = target.isLP64; | |
890 | ||
891 | tsize_t = basic[isLP64 ? Tuns64 : Tuns32]; | |
892 | tptrdiff_t = basic[isLP64 ? Tint64 : Tint32]; | |
893 | thash_t = tsize_t; | |
894 | } | |
895 | ||
896 | /** | |
897 | * Deinitializes the global state of the compiler. | |
898 | * | |
899 | * This can be used to restore the state set by `_init` to its original | |
900 | * state. | |
901 | */ | |
902 | static void deinitialize() | |
903 | { | |
904 | stringtable = stringtable.init; | |
905 | } | |
906 | ||
fbdaa581 | 907 | final uinteger_t size() |
5fee5ec3 IB |
908 | { |
909 | return size(Loc.initial); | |
910 | } | |
911 | ||
fbdaa581 | 912 | uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
913 | { |
914 | error(loc, "no size for type `%s`", toChars()); | |
915 | return SIZE_INVALID; | |
916 | } | |
917 | ||
918 | uint alignsize() | |
919 | { | |
920 | return cast(uint)size(Loc.initial); | |
921 | } | |
922 | ||
923 | final Type trySemantic(const ref Loc loc, Scope* sc) | |
924 | { | |
925 | //printf("+trySemantic(%s) %d\n", toChars(), global.errors); | |
926 | ||
927 | // Needed to display any deprecations that were gagged | |
928 | auto tcopy = this.syntaxCopy(); | |
929 | ||
930 | const errors = global.startGagging(); | |
931 | Type t = typeSemantic(this, loc, sc); | |
932 | if (global.endGagging(errors) || t.ty == Terror) // if any errors happened | |
933 | { | |
934 | t = null; | |
935 | } | |
936 | else | |
937 | { | |
938 | // If `typeSemantic` succeeded, there may have been deprecations that | |
c8dfa79c | 939 | // were gagged due the `startGagging` above. Run again to display |
5fee5ec3 IB |
940 | // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 |
941 | if (global.gaggedWarnings > 0) | |
942 | typeSemantic(tcopy, loc, sc); | |
943 | } | |
944 | //printf("-trySemantic(%s) %d\n", toChars(), global.errors); | |
945 | return t; | |
946 | } | |
947 | ||
948 | /************************************* | |
949 | * This version does a merge even if the deco is already computed. | |
950 | * Necessary for types that have a deco, but are not merged. | |
951 | */ | |
952 | final Type merge2() | |
953 | { | |
954 | //printf("merge2(%s)\n", toChars()); | |
955 | Type t = this; | |
956 | assert(t); | |
957 | if (!t.deco) | |
958 | return t.merge(); | |
959 | ||
960 | auto sv = stringtable.lookup(t.deco, strlen(t.deco)); | |
961 | if (sv && sv.value) | |
962 | { | |
963 | t = sv.value; | |
964 | assert(t.deco); | |
965 | } | |
966 | else | |
967 | assert(0); | |
968 | return t; | |
969 | } | |
970 | ||
971 | /********************************* | |
972 | * Store this type's modifier name into buf. | |
973 | */ | |
974 | final void modToBuffer(OutBuffer* buf) nothrow const | |
975 | { | |
976 | if (mod) | |
977 | { | |
978 | buf.writeByte(' '); | |
979 | MODtoBuffer(buf, mod); | |
980 | } | |
981 | } | |
982 | ||
983 | /********************************* | |
984 | * Return this type's modifier name. | |
985 | */ | |
986 | final char* modToChars() nothrow const | |
987 | { | |
988 | OutBuffer buf; | |
989 | buf.reserve(16); | |
990 | modToBuffer(&buf); | |
991 | return buf.extractChars(); | |
992 | } | |
993 | ||
994 | bool isintegral() | |
995 | { | |
996 | return false; | |
997 | } | |
998 | ||
999 | // real, imaginary, or complex | |
1000 | bool isfloating() | |
1001 | { | |
1002 | return false; | |
1003 | } | |
1004 | ||
1005 | bool isreal() | |
1006 | { | |
1007 | return false; | |
1008 | } | |
1009 | ||
1010 | bool isimaginary() | |
1011 | { | |
1012 | return false; | |
1013 | } | |
1014 | ||
1015 | bool iscomplex() | |
1016 | { | |
1017 | return false; | |
1018 | } | |
1019 | ||
1020 | bool isscalar() | |
1021 | { | |
1022 | return false; | |
1023 | } | |
1024 | ||
1025 | bool isunsigned() | |
1026 | { | |
1027 | return false; | |
1028 | } | |
1029 | ||
1030 | bool isscope() | |
1031 | { | |
1032 | return false; | |
1033 | } | |
1034 | ||
1035 | bool isString() | |
1036 | { | |
1037 | return false; | |
1038 | } | |
1039 | ||
1040 | /************************** | |
1041 | * When T is mutable, | |
1042 | * Given: | |
1043 | * T a, b; | |
1044 | * Can we bitwise assign: | |
1045 | * a = b; | |
1046 | * ? | |
1047 | */ | |
1048 | bool isAssignable() | |
1049 | { | |
1050 | return true; | |
1051 | } | |
1052 | ||
1053 | /************************** | |
1054 | * Returns true if T can be converted to boolean value. | |
1055 | */ | |
1056 | bool isBoolean() | |
1057 | { | |
1058 | return isscalar(); | |
1059 | } | |
1060 | ||
1061 | /********************************* | |
1062 | * Check type to see if it is based on a deprecated symbol. | |
1063 | */ | |
1064 | void checkDeprecated(const ref Loc loc, Scope* sc) | |
1065 | { | |
1066 | if (Dsymbol s = toDsymbol(sc)) | |
1067 | { | |
1068 | s.checkDeprecated(loc, sc); | |
1069 | } | |
1070 | } | |
1071 | ||
1072 | final bool isConst() const nothrow pure @nogc @safe | |
1073 | { | |
1074 | return (mod & MODFlags.const_) != 0; | |
1075 | } | |
1076 | ||
1077 | final bool isImmutable() const nothrow pure @nogc @safe | |
1078 | { | |
1079 | return (mod & MODFlags.immutable_) != 0; | |
1080 | } | |
1081 | ||
1082 | final bool isMutable() const nothrow pure @nogc @safe | |
1083 | { | |
1084 | return (mod & (MODFlags.const_ | MODFlags.immutable_ | MODFlags.wild)) == 0; | |
1085 | } | |
1086 | ||
1087 | final bool isShared() const nothrow pure @nogc @safe | |
1088 | { | |
1089 | return (mod & MODFlags.shared_) != 0; | |
1090 | } | |
1091 | ||
1092 | final bool isSharedConst() const nothrow pure @nogc @safe | |
1093 | { | |
1094 | return (mod & (MODFlags.shared_ | MODFlags.const_)) == (MODFlags.shared_ | MODFlags.const_); | |
1095 | } | |
1096 | ||
1097 | final bool isWild() const nothrow pure @nogc @safe | |
1098 | { | |
1099 | return (mod & MODFlags.wild) != 0; | |
1100 | } | |
1101 | ||
1102 | final bool isWildConst() const nothrow pure @nogc @safe | |
1103 | { | |
1104 | return (mod & MODFlags.wildconst) == MODFlags.wildconst; | |
1105 | } | |
1106 | ||
1107 | final bool isSharedWild() const nothrow pure @nogc @safe | |
1108 | { | |
1109 | return (mod & (MODFlags.shared_ | MODFlags.wild)) == (MODFlags.shared_ | MODFlags.wild); | |
1110 | } | |
1111 | ||
1112 | final bool isNaked() const nothrow pure @nogc @safe | |
1113 | { | |
1114 | return mod == 0; | |
1115 | } | |
1116 | ||
1117 | /******************************** | |
1118 | * Return a copy of this type with all attributes null-initialized. | |
1119 | * Useful for creating a type with different modifiers. | |
1120 | */ | |
1121 | final Type nullAttributes() nothrow const | |
1122 | { | |
1123 | uint sz = sizeTy[ty]; | |
1124 | Type t = cast(Type)mem.xmalloc(sz); | |
1125 | memcpy(cast(void*)t, cast(void*)this, sz); | |
1126 | // t.mod = NULL; // leave mod unchanged | |
1127 | t.deco = null; | |
1128 | t.arrayof = null; | |
1129 | t.pto = null; | |
1130 | t.rto = null; | |
1131 | t.vtinfo = null; | |
1132 | t.ctype = null; | |
1133 | t.mcache = null; | |
1134 | if (t.ty == Tstruct) | |
1135 | (cast(TypeStruct)t).att = AliasThisRec.fwdref; | |
1136 | if (t.ty == Tclass) | |
1137 | (cast(TypeClass)t).att = AliasThisRec.fwdref; | |
1138 | return t; | |
1139 | } | |
1140 | ||
1141 | /******************************** | |
1142 | * Convert to 'const'. | |
1143 | */ | |
1144 | final Type constOf() | |
1145 | { | |
1146 | //printf("Type::constOf() %p %s\n", this, toChars()); | |
1147 | if (mod == MODFlags.const_) | |
1148 | return this; | |
1149 | if (mcache && mcache.cto) | |
1150 | { | |
1151 | assert(mcache.cto.mod == MODFlags.const_); | |
1152 | return mcache.cto; | |
1153 | } | |
1154 | Type t = makeConst(); | |
1155 | t = t.merge(); | |
1156 | t.fixTo(this); | |
1157 | //printf("-Type::constOf() %p %s\n", t, t.toChars()); | |
1158 | return t; | |
1159 | } | |
1160 | ||
1161 | /******************************** | |
1162 | * Convert to 'immutable'. | |
1163 | */ | |
1164 | final Type immutableOf() | |
1165 | { | |
1166 | //printf("Type::immutableOf() %p %s\n", this, toChars()); | |
1167 | if (isImmutable()) | |
1168 | return this; | |
1169 | if (mcache && mcache.ito) | |
1170 | { | |
1171 | assert(mcache.ito.isImmutable()); | |
1172 | return mcache.ito; | |
1173 | } | |
1174 | Type t = makeImmutable(); | |
1175 | t = t.merge(); | |
1176 | t.fixTo(this); | |
1177 | //printf("\t%p\n", t); | |
1178 | return t; | |
1179 | } | |
1180 | ||
1181 | /******************************** | |
1182 | * Make type mutable. | |
1183 | */ | |
1184 | final Type mutableOf() | |
1185 | { | |
1186 | //printf("Type::mutableOf() %p, %s\n", this, toChars()); | |
1187 | Type t = this; | |
1188 | if (isImmutable()) | |
1189 | { | |
1190 | getMcache(); | |
1191 | t = mcache.ito; // immutable => naked | |
1192 | assert(!t || (t.isMutable() && !t.isShared())); | |
1193 | } | |
1194 | else if (isConst()) | |
1195 | { | |
1196 | getMcache(); | |
1197 | if (isShared()) | |
1198 | { | |
1199 | if (isWild()) | |
1200 | t = mcache.swcto; // shared wild const -> shared | |
1201 | else | |
1202 | t = mcache.sto; // shared const => shared | |
1203 | } | |
1204 | else | |
1205 | { | |
1206 | if (isWild()) | |
1207 | t = mcache.wcto; // wild const -> naked | |
1208 | else | |
1209 | t = mcache.cto; // const => naked | |
1210 | } | |
1211 | assert(!t || t.isMutable()); | |
1212 | } | |
1213 | else if (isWild()) | |
1214 | { | |
1215 | getMcache(); | |
1216 | if (isShared()) | |
1217 | t = mcache.sto; // shared wild => shared | |
1218 | else | |
1219 | t = mcache.wto; // wild => naked | |
1220 | assert(!t || t.isMutable()); | |
1221 | } | |
1222 | if (!t) | |
1223 | { | |
1224 | t = makeMutable(); | |
1225 | t = t.merge(); | |
1226 | t.fixTo(this); | |
1227 | } | |
1228 | else | |
1229 | t = t.merge(); | |
1230 | assert(t.isMutable()); | |
1231 | return t; | |
1232 | } | |
1233 | ||
1234 | final Type sharedOf() | |
1235 | { | |
1236 | //printf("Type::sharedOf() %p, %s\n", this, toChars()); | |
1237 | if (mod == MODFlags.shared_) | |
1238 | return this; | |
1239 | if (mcache && mcache.sto) | |
1240 | { | |
1241 | assert(mcache.sto.mod == MODFlags.shared_); | |
1242 | return mcache.sto; | |
1243 | } | |
1244 | Type t = makeShared(); | |
1245 | t = t.merge(); | |
1246 | t.fixTo(this); | |
1247 | //printf("\t%p\n", t); | |
1248 | return t; | |
1249 | } | |
1250 | ||
1251 | final Type sharedConstOf() | |
1252 | { | |
1253 | //printf("Type::sharedConstOf() %p, %s\n", this, toChars()); | |
1254 | if (mod == (MODFlags.shared_ | MODFlags.const_)) | |
1255 | return this; | |
1256 | if (mcache && mcache.scto) | |
1257 | { | |
1258 | assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1259 | return mcache.scto; | |
1260 | } | |
1261 | Type t = makeSharedConst(); | |
1262 | t = t.merge(); | |
1263 | t.fixTo(this); | |
1264 | //printf("\t%p\n", t); | |
1265 | return t; | |
1266 | } | |
1267 | ||
1268 | /******************************** | |
1269 | * Make type unshared. | |
1270 | * 0 => 0 | |
1271 | * const => const | |
1272 | * immutable => immutable | |
1273 | * shared => 0 | |
1274 | * shared const => const | |
1275 | * wild => wild | |
1276 | * wild const => wild const | |
1277 | * shared wild => wild | |
1278 | * shared wild const => wild const | |
1279 | */ | |
1280 | final Type unSharedOf() | |
1281 | { | |
1282 | //printf("Type::unSharedOf() %p, %s\n", this, toChars()); | |
1283 | Type t = this; | |
1284 | ||
1285 | if (isShared()) | |
1286 | { | |
1287 | getMcache(); | |
1288 | if (isWild()) | |
1289 | { | |
1290 | if (isConst()) | |
1291 | t = mcache.wcto; // shared wild const => wild const | |
1292 | else | |
1293 | t = mcache.wto; // shared wild => wild | |
1294 | } | |
1295 | else | |
1296 | { | |
1297 | if (isConst()) | |
1298 | t = mcache.cto; // shared const => const | |
1299 | else | |
1300 | t = mcache.sto; // shared => naked | |
1301 | } | |
1302 | assert(!t || !t.isShared()); | |
1303 | } | |
1304 | ||
1305 | if (!t) | |
1306 | { | |
1307 | t = this.nullAttributes(); | |
1308 | t.mod = mod & ~MODFlags.shared_; | |
1309 | t.ctype = ctype; | |
1310 | t = t.merge(); | |
1311 | t.fixTo(this); | |
1312 | } | |
1313 | else | |
1314 | t = t.merge(); | |
1315 | assert(!t.isShared()); | |
1316 | return t; | |
1317 | } | |
1318 | ||
1319 | /******************************** | |
1320 | * Convert to 'wild'. | |
1321 | */ | |
1322 | final Type wildOf() | |
1323 | { | |
1324 | //printf("Type::wildOf() %p %s\n", this, toChars()); | |
1325 | if (mod == MODFlags.wild) | |
1326 | return this; | |
1327 | if (mcache && mcache.wto) | |
1328 | { | |
1329 | assert(mcache.wto.mod == MODFlags.wild); | |
1330 | return mcache.wto; | |
1331 | } | |
1332 | Type t = makeWild(); | |
1333 | t = t.merge(); | |
1334 | t.fixTo(this); | |
1335 | //printf("\t%p %s\n", t, t.toChars()); | |
1336 | return t; | |
1337 | } | |
1338 | ||
1339 | final Type wildConstOf() | |
1340 | { | |
1341 | //printf("Type::wildConstOf() %p %s\n", this, toChars()); | |
1342 | if (mod == MODFlags.wildconst) | |
1343 | return this; | |
1344 | if (mcache && mcache.wcto) | |
1345 | { | |
1346 | assert(mcache.wcto.mod == MODFlags.wildconst); | |
1347 | return mcache.wcto; | |
1348 | } | |
1349 | Type t = makeWildConst(); | |
1350 | t = t.merge(); | |
1351 | t.fixTo(this); | |
1352 | //printf("\t%p %s\n", t, t.toChars()); | |
1353 | return t; | |
1354 | } | |
1355 | ||
1356 | final Type sharedWildOf() | |
1357 | { | |
1358 | //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); | |
1359 | if (mod == (MODFlags.shared_ | MODFlags.wild)) | |
1360 | return this; | |
1361 | if (mcache && mcache.swto) | |
1362 | { | |
1363 | assert(mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1364 | return mcache.swto; | |
1365 | } | |
1366 | Type t = makeSharedWild(); | |
1367 | t = t.merge(); | |
1368 | t.fixTo(this); | |
1369 | //printf("\t%p %s\n", t, t.toChars()); | |
1370 | return t; | |
1371 | } | |
1372 | ||
1373 | final Type sharedWildConstOf() | |
1374 | { | |
1375 | //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars()); | |
1376 | if (mod == (MODFlags.shared_ | MODFlags.wildconst)) | |
1377 | return this; | |
1378 | if (mcache && mcache.swcto) | |
1379 | { | |
1380 | assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1381 | return mcache.swcto; | |
1382 | } | |
1383 | Type t = makeSharedWildConst(); | |
1384 | t = t.merge(); | |
1385 | t.fixTo(this); | |
1386 | //printf("\t%p %s\n", t, t.toChars()); | |
1387 | return t; | |
1388 | } | |
1389 | ||
1390 | /********************************** | |
1391 | * For our new type 'this', which is type-constructed from t, | |
1392 | * fill in the cto, ito, sto, scto, wto shortcuts. | |
1393 | */ | |
1394 | final void fixTo(Type t) | |
1395 | { | |
1396 | // If fixing this: immutable(T*) by t: immutable(T)*, | |
1397 | // cache t to this.xto won't break transitivity. | |
1398 | Type mto = null; | |
1399 | Type tn = nextOf(); | |
1400 | if (!tn || ty != Tsarray && tn.mod == t.nextOf().mod) | |
1401 | { | |
1402 | switch (t.mod) | |
1403 | { | |
1404 | case 0: | |
1405 | mto = t; | |
1406 | break; | |
1407 | ||
1408 | case MODFlags.const_: | |
1409 | getMcache(); | |
1410 | mcache.cto = t; | |
1411 | break; | |
1412 | ||
1413 | case MODFlags.wild: | |
1414 | getMcache(); | |
1415 | mcache.wto = t; | |
1416 | break; | |
1417 | ||
1418 | case MODFlags.wildconst: | |
1419 | getMcache(); | |
1420 | mcache.wcto = t; | |
1421 | break; | |
1422 | ||
1423 | case MODFlags.shared_: | |
1424 | getMcache(); | |
1425 | mcache.sto = t; | |
1426 | break; | |
1427 | ||
1428 | case MODFlags.shared_ | MODFlags.const_: | |
1429 | getMcache(); | |
1430 | mcache.scto = t; | |
1431 | break; | |
1432 | ||
1433 | case MODFlags.shared_ | MODFlags.wild: | |
1434 | getMcache(); | |
1435 | mcache.swto = t; | |
1436 | break; | |
1437 | ||
1438 | case MODFlags.shared_ | MODFlags.wildconst: | |
1439 | getMcache(); | |
1440 | mcache.swcto = t; | |
1441 | break; | |
1442 | ||
1443 | case MODFlags.immutable_: | |
1444 | getMcache(); | |
1445 | mcache.ito = t; | |
1446 | break; | |
1447 | ||
1448 | default: | |
1449 | break; | |
1450 | } | |
1451 | } | |
1452 | assert(mod != t.mod); | |
1453 | ||
1454 | if (mod) | |
1455 | { | |
1456 | getMcache(); | |
1457 | t.getMcache(); | |
1458 | } | |
1459 | switch (mod) | |
1460 | { | |
1461 | case 0: | |
1462 | break; | |
1463 | ||
1464 | case MODFlags.const_: | |
1465 | mcache.cto = mto; | |
1466 | t.mcache.cto = this; | |
1467 | break; | |
1468 | ||
1469 | case MODFlags.wild: | |
1470 | mcache.wto = mto; | |
1471 | t.mcache.wto = this; | |
1472 | break; | |
1473 | ||
1474 | case MODFlags.wildconst: | |
1475 | mcache.wcto = mto; | |
1476 | t.mcache.wcto = this; | |
1477 | break; | |
1478 | ||
1479 | case MODFlags.shared_: | |
1480 | mcache.sto = mto; | |
1481 | t.mcache.sto = this; | |
1482 | break; | |
1483 | ||
1484 | case MODFlags.shared_ | MODFlags.const_: | |
1485 | mcache.scto = mto; | |
1486 | t.mcache.scto = this; | |
1487 | break; | |
1488 | ||
1489 | case MODFlags.shared_ | MODFlags.wild: | |
1490 | mcache.swto = mto; | |
1491 | t.mcache.swto = this; | |
1492 | break; | |
1493 | ||
1494 | case MODFlags.shared_ | MODFlags.wildconst: | |
1495 | mcache.swcto = mto; | |
1496 | t.mcache.swcto = this; | |
1497 | break; | |
1498 | ||
1499 | case MODFlags.immutable_: | |
1500 | t.mcache.ito = this; | |
1501 | if (t.mcache.cto) | |
1502 | t.mcache.cto.getMcache().ito = this; | |
1503 | if (t.mcache.sto) | |
1504 | t.mcache.sto.getMcache().ito = this; | |
1505 | if (t.mcache.scto) | |
1506 | t.mcache.scto.getMcache().ito = this; | |
1507 | if (t.mcache.wto) | |
1508 | t.mcache.wto.getMcache().ito = this; | |
1509 | if (t.mcache.wcto) | |
1510 | t.mcache.wcto.getMcache().ito = this; | |
1511 | if (t.mcache.swto) | |
1512 | t.mcache.swto.getMcache().ito = this; | |
1513 | if (t.mcache.swcto) | |
1514 | t.mcache.swcto.getMcache().ito = this; | |
1515 | break; | |
1516 | ||
1517 | default: | |
1518 | assert(0); | |
1519 | } | |
1520 | ||
1521 | check(); | |
1522 | t.check(); | |
1523 | //printf("fixTo: %s, %s\n", toChars(), t.toChars()); | |
1524 | } | |
1525 | ||
1526 | /*************************** | |
1527 | * Look for bugs in constructing types. | |
1528 | */ | |
1529 | final void check() | |
1530 | { | |
1531 | if (mcache) | |
1532 | with (mcache) | |
1533 | switch (mod) | |
1534 | { | |
1535 | case 0: | |
1536 | if (cto) | |
1537 | assert(cto.mod == MODFlags.const_); | |
1538 | if (ito) | |
1539 | assert(ito.mod == MODFlags.immutable_); | |
1540 | if (sto) | |
1541 | assert(sto.mod == MODFlags.shared_); | |
1542 | if (scto) | |
1543 | assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1544 | if (wto) | |
1545 | assert(wto.mod == MODFlags.wild); | |
1546 | if (wcto) | |
1547 | assert(wcto.mod == MODFlags.wildconst); | |
1548 | if (swto) | |
1549 | assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1550 | if (swcto) | |
1551 | assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1552 | break; | |
1553 | ||
1554 | case MODFlags.const_: | |
1555 | if (cto) | |
1556 | assert(cto.mod == 0); | |
1557 | if (ito) | |
1558 | assert(ito.mod == MODFlags.immutable_); | |
1559 | if (sto) | |
1560 | assert(sto.mod == MODFlags.shared_); | |
1561 | if (scto) | |
1562 | assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1563 | if (wto) | |
1564 | assert(wto.mod == MODFlags.wild); | |
1565 | if (wcto) | |
1566 | assert(wcto.mod == MODFlags.wildconst); | |
1567 | if (swto) | |
1568 | assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1569 | if (swcto) | |
1570 | assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1571 | break; | |
1572 | ||
1573 | case MODFlags.wild: | |
1574 | if (cto) | |
1575 | assert(cto.mod == MODFlags.const_); | |
1576 | if (ito) | |
1577 | assert(ito.mod == MODFlags.immutable_); | |
1578 | if (sto) | |
1579 | assert(sto.mod == MODFlags.shared_); | |
1580 | if (scto) | |
1581 | assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1582 | if (wto) | |
1583 | assert(wto.mod == 0); | |
1584 | if (wcto) | |
1585 | assert(wcto.mod == MODFlags.wildconst); | |
1586 | if (swto) | |
1587 | assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1588 | if (swcto) | |
1589 | assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1590 | break; | |
1591 | ||
1592 | case MODFlags.wildconst: | |
1593 | assert(!cto || cto.mod == MODFlags.const_); | |
1594 | assert(!ito || ito.mod == MODFlags.immutable_); | |
1595 | assert(!sto || sto.mod == MODFlags.shared_); | |
1596 | assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1597 | assert(!wto || wto.mod == MODFlags.wild); | |
1598 | assert(!wcto || wcto.mod == 0); | |
1599 | assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1600 | assert(!swcto || swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1601 | break; | |
1602 | ||
1603 | case MODFlags.shared_: | |
1604 | if (cto) | |
1605 | assert(cto.mod == MODFlags.const_); | |
1606 | if (ito) | |
1607 | assert(ito.mod == MODFlags.immutable_); | |
1608 | if (sto) | |
1609 | assert(sto.mod == 0); | |
1610 | if (scto) | |
1611 | assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1612 | if (wto) | |
1613 | assert(wto.mod == MODFlags.wild); | |
1614 | if (wcto) | |
1615 | assert(wcto.mod == MODFlags.wildconst); | |
1616 | if (swto) | |
1617 | assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1618 | if (swcto) | |
1619 | assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1620 | break; | |
1621 | ||
1622 | case MODFlags.shared_ | MODFlags.const_: | |
1623 | if (cto) | |
1624 | assert(cto.mod == MODFlags.const_); | |
1625 | if (ito) | |
1626 | assert(ito.mod == MODFlags.immutable_); | |
1627 | if (sto) | |
1628 | assert(sto.mod == MODFlags.shared_); | |
1629 | if (scto) | |
1630 | assert(scto.mod == 0); | |
1631 | if (wto) | |
1632 | assert(wto.mod == MODFlags.wild); | |
1633 | if (wcto) | |
1634 | assert(wcto.mod == MODFlags.wildconst); | |
1635 | if (swto) | |
1636 | assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1637 | if (swcto) | |
1638 | assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1639 | break; | |
1640 | ||
1641 | case MODFlags.shared_ | MODFlags.wild: | |
1642 | if (cto) | |
1643 | assert(cto.mod == MODFlags.const_); | |
1644 | if (ito) | |
1645 | assert(ito.mod == MODFlags.immutable_); | |
1646 | if (sto) | |
1647 | assert(sto.mod == MODFlags.shared_); | |
1648 | if (scto) | |
1649 | assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1650 | if (wto) | |
1651 | assert(wto.mod == MODFlags.wild); | |
1652 | if (wcto) | |
1653 | assert(wcto.mod == MODFlags.wildconst); | |
1654 | if (swto) | |
1655 | assert(swto.mod == 0); | |
1656 | if (swcto) | |
1657 | assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1658 | break; | |
1659 | ||
1660 | case MODFlags.shared_ | MODFlags.wildconst: | |
1661 | assert(!cto || cto.mod == MODFlags.const_); | |
1662 | assert(!ito || ito.mod == MODFlags.immutable_); | |
1663 | assert(!sto || sto.mod == MODFlags.shared_); | |
1664 | assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1665 | assert(!wto || wto.mod == MODFlags.wild); | |
1666 | assert(!wcto || wcto.mod == MODFlags.wildconst); | |
1667 | assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1668 | assert(!swcto || swcto.mod == 0); | |
1669 | break; | |
1670 | ||
1671 | case MODFlags.immutable_: | |
1672 | if (cto) | |
1673 | assert(cto.mod == MODFlags.const_); | |
1674 | if (ito) | |
1675 | assert(ito.mod == 0); | |
1676 | if (sto) | |
1677 | assert(sto.mod == MODFlags.shared_); | |
1678 | if (scto) | |
1679 | assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
1680 | if (wto) | |
1681 | assert(wto.mod == MODFlags.wild); | |
1682 | if (wcto) | |
1683 | assert(wcto.mod == MODFlags.wildconst); | |
1684 | if (swto) | |
1685 | assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); | |
1686 | if (swcto) | |
1687 | assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
1688 | break; | |
1689 | ||
1690 | default: | |
1691 | assert(0); | |
1692 | } | |
1693 | ||
1694 | Type tn = nextOf(); | |
1695 | if (tn && ty != Tfunction && tn.ty != Tfunction && ty != Tenum) | |
1696 | { | |
1697 | // Verify transitivity | |
1698 | switch (mod) | |
1699 | { | |
1700 | case 0: | |
1701 | case MODFlags.const_: | |
1702 | case MODFlags.wild: | |
1703 | case MODFlags.wildconst: | |
1704 | case MODFlags.shared_: | |
1705 | case MODFlags.shared_ | MODFlags.const_: | |
1706 | case MODFlags.shared_ | MODFlags.wild: | |
1707 | case MODFlags.shared_ | MODFlags.wildconst: | |
1708 | case MODFlags.immutable_: | |
1709 | assert(tn.mod == MODFlags.immutable_ || (tn.mod & mod) == mod); | |
1710 | break; | |
1711 | ||
1712 | default: | |
1713 | assert(0); | |
1714 | } | |
1715 | tn.check(); | |
1716 | } | |
1717 | } | |
1718 | ||
1719 | /************************************* | |
1720 | * Apply STCxxxx bits to existing type. | |
1721 | * Use *before* semantic analysis is run. | |
1722 | */ | |
1723 | final Type addSTC(StorageClass stc) | |
1724 | { | |
1725 | Type t = this; | |
1726 | if (t.isImmutable()) | |
1727 | { | |
1728 | } | |
1729 | else if (stc & STC.immutable_) | |
1730 | { | |
1731 | t = t.makeImmutable(); | |
1732 | } | |
1733 | else | |
1734 | { | |
1735 | if ((stc & STC.shared_) && !t.isShared()) | |
1736 | { | |
1737 | if (t.isWild()) | |
1738 | { | |
1739 | if (t.isConst()) | |
1740 | t = t.makeSharedWildConst(); | |
1741 | else | |
1742 | t = t.makeSharedWild(); | |
1743 | } | |
1744 | else | |
1745 | { | |
1746 | if (t.isConst()) | |
1747 | t = t.makeSharedConst(); | |
1748 | else | |
1749 | t = t.makeShared(); | |
1750 | } | |
1751 | } | |
1752 | if ((stc & STC.const_) && !t.isConst()) | |
1753 | { | |
1754 | if (t.isShared()) | |
1755 | { | |
1756 | if (t.isWild()) | |
1757 | t = t.makeSharedWildConst(); | |
1758 | else | |
1759 | t = t.makeSharedConst(); | |
1760 | } | |
1761 | else | |
1762 | { | |
1763 | if (t.isWild()) | |
1764 | t = t.makeWildConst(); | |
1765 | else | |
1766 | t = t.makeConst(); | |
1767 | } | |
1768 | } | |
1769 | if ((stc & STC.wild) && !t.isWild()) | |
1770 | { | |
1771 | if (t.isShared()) | |
1772 | { | |
1773 | if (t.isConst()) | |
1774 | t = t.makeSharedWildConst(); | |
1775 | else | |
1776 | t = t.makeSharedWild(); | |
1777 | } | |
1778 | else | |
1779 | { | |
1780 | if (t.isConst()) | |
1781 | t = t.makeWildConst(); | |
1782 | else | |
1783 | t = t.makeWild(); | |
1784 | } | |
1785 | } | |
1786 | } | |
1787 | return t; | |
1788 | } | |
1789 | ||
1790 | /************************************ | |
1791 | * Apply MODxxxx bits to existing type. | |
1792 | */ | |
1793 | final Type castMod(MOD mod) | |
1794 | { | |
1795 | Type t; | |
1796 | switch (mod) | |
1797 | { | |
1798 | case 0: | |
1799 | t = unSharedOf().mutableOf(); | |
1800 | break; | |
1801 | ||
1802 | case MODFlags.const_: | |
1803 | t = unSharedOf().constOf(); | |
1804 | break; | |
1805 | ||
1806 | case MODFlags.wild: | |
1807 | t = unSharedOf().wildOf(); | |
1808 | break; | |
1809 | ||
1810 | case MODFlags.wildconst: | |
1811 | t = unSharedOf().wildConstOf(); | |
1812 | break; | |
1813 | ||
1814 | case MODFlags.shared_: | |
1815 | t = mutableOf().sharedOf(); | |
1816 | break; | |
1817 | ||
1818 | case MODFlags.shared_ | MODFlags.const_: | |
1819 | t = sharedConstOf(); | |
1820 | break; | |
1821 | ||
1822 | case MODFlags.shared_ | MODFlags.wild: | |
1823 | t = sharedWildOf(); | |
1824 | break; | |
1825 | ||
1826 | case MODFlags.shared_ | MODFlags.wildconst: | |
1827 | t = sharedWildConstOf(); | |
1828 | break; | |
1829 | ||
1830 | case MODFlags.immutable_: | |
1831 | t = immutableOf(); | |
1832 | break; | |
1833 | ||
1834 | default: | |
1835 | assert(0); | |
1836 | } | |
1837 | return t; | |
1838 | } | |
1839 | ||
1840 | /************************************ | |
1841 | * Add MODxxxx bits to existing type. | |
1842 | * We're adding, not replacing, so adding const to | |
1843 | * a shared type => "shared const" | |
1844 | */ | |
1845 | final Type addMod(MOD mod) | |
1846 | { | |
1847 | /* Add anything to immutable, and it remains immutable | |
1848 | */ | |
1849 | Type t = this; | |
1850 | if (!t.isImmutable()) | |
1851 | { | |
1852 | //printf("addMod(%x) %s\n", mod, toChars()); | |
1853 | switch (mod) | |
1854 | { | |
1855 | case 0: | |
1856 | break; | |
1857 | ||
1858 | case MODFlags.const_: | |
1859 | if (isShared()) | |
1860 | { | |
1861 | if (isWild()) | |
1862 | t = sharedWildConstOf(); | |
1863 | else | |
1864 | t = sharedConstOf(); | |
1865 | } | |
1866 | else | |
1867 | { | |
1868 | if (isWild()) | |
1869 | t = wildConstOf(); | |
1870 | else | |
1871 | t = constOf(); | |
1872 | } | |
1873 | break; | |
1874 | ||
1875 | case MODFlags.wild: | |
1876 | if (isShared()) | |
1877 | { | |
1878 | if (isConst()) | |
1879 | t = sharedWildConstOf(); | |
1880 | else | |
1881 | t = sharedWildOf(); | |
1882 | } | |
1883 | else | |
1884 | { | |
1885 | if (isConst()) | |
1886 | t = wildConstOf(); | |
1887 | else | |
1888 | t = wildOf(); | |
1889 | } | |
1890 | break; | |
1891 | ||
1892 | case MODFlags.wildconst: | |
1893 | if (isShared()) | |
1894 | t = sharedWildConstOf(); | |
1895 | else | |
1896 | t = wildConstOf(); | |
1897 | break; | |
1898 | ||
1899 | case MODFlags.shared_: | |
1900 | if (isWild()) | |
1901 | { | |
1902 | if (isConst()) | |
1903 | t = sharedWildConstOf(); | |
1904 | else | |
1905 | t = sharedWildOf(); | |
1906 | } | |
1907 | else | |
1908 | { | |
1909 | if (isConst()) | |
1910 | t = sharedConstOf(); | |
1911 | else | |
1912 | t = sharedOf(); | |
1913 | } | |
1914 | break; | |
1915 | ||
1916 | case MODFlags.shared_ | MODFlags.const_: | |
1917 | if (isWild()) | |
1918 | t = sharedWildConstOf(); | |
1919 | else | |
1920 | t = sharedConstOf(); | |
1921 | break; | |
1922 | ||
1923 | case MODFlags.shared_ | MODFlags.wild: | |
1924 | if (isConst()) | |
1925 | t = sharedWildConstOf(); | |
1926 | else | |
1927 | t = sharedWildOf(); | |
1928 | break; | |
1929 | ||
1930 | case MODFlags.shared_ | MODFlags.wildconst: | |
1931 | t = sharedWildConstOf(); | |
1932 | break; | |
1933 | ||
1934 | case MODFlags.immutable_: | |
1935 | t = immutableOf(); | |
1936 | break; | |
1937 | ||
1938 | default: | |
1939 | assert(0); | |
1940 | } | |
1941 | } | |
1942 | return t; | |
1943 | } | |
1944 | ||
1945 | /************************************ | |
1946 | * Add storage class modifiers to type. | |
1947 | */ | |
1948 | Type addStorageClass(StorageClass stc) | |
1949 | { | |
1950 | /* Just translate to MOD bits and let addMod() do the work | |
1951 | */ | |
1952 | MOD mod = 0; | |
1953 | if (stc & STC.immutable_) | |
1954 | mod = MODFlags.immutable_; | |
1955 | else | |
1956 | { | |
1957 | if (stc & (STC.const_ | STC.in_)) | |
1958 | mod |= MODFlags.const_; | |
1959 | if (stc & STC.wild) | |
1960 | mod |= MODFlags.wild; | |
1961 | if (stc & STC.shared_) | |
1962 | mod |= MODFlags.shared_; | |
1963 | } | |
1964 | return addMod(mod); | |
1965 | } | |
1966 | ||
1967 | final Type pointerTo() | |
1968 | { | |
1969 | if (ty == Terror) | |
1970 | return this; | |
1971 | if (!pto) | |
1972 | { | |
1973 | Type t = new TypePointer(this); | |
1974 | if (ty == Tfunction) | |
1975 | { | |
1976 | t.deco = t.merge().deco; | |
1977 | pto = t; | |
1978 | } | |
1979 | else | |
1980 | pto = t.merge(); | |
1981 | } | |
1982 | return pto; | |
1983 | } | |
1984 | ||
1985 | final Type referenceTo() | |
1986 | { | |
1987 | if (ty == Terror) | |
1988 | return this; | |
1989 | if (!rto) | |
1990 | { | |
1991 | Type t = new TypeReference(this); | |
1992 | rto = t.merge(); | |
1993 | } | |
1994 | return rto; | |
1995 | } | |
1996 | ||
1997 | final Type arrayOf() | |
1998 | { | |
1999 | if (ty == Terror) | |
2000 | return this; | |
2001 | if (!arrayof) | |
2002 | { | |
2003 | Type t = new TypeDArray(this); | |
2004 | arrayof = t.merge(); | |
2005 | } | |
2006 | return arrayof; | |
2007 | } | |
2008 | ||
2009 | // Make corresponding static array type without semantic | |
2010 | final Type sarrayOf(dinteger_t dim) | |
2011 | { | |
2012 | assert(deco); | |
2013 | Type t = new TypeSArray(this, new IntegerExp(Loc.initial, dim, Type.tsize_t)); | |
2014 | // according to TypeSArray::semantic() | |
2015 | t = t.addMod(mod); | |
2016 | t = t.merge(); | |
2017 | return t; | |
2018 | } | |
2019 | ||
2020 | final bool hasDeprecatedAliasThis() | |
2021 | { | |
2022 | auto ad = isAggregate(this); | |
2023 | return ad && ad.aliasthis && (ad.aliasthis.isDeprecated || ad.aliasthis.sym.isDeprecated); | |
2024 | } | |
2025 | ||
2026 | final Type aliasthisOf() | |
2027 | { | |
2028 | auto ad = isAggregate(this); | |
2029 | if (!ad || !ad.aliasthis) | |
2030 | return null; | |
2031 | ||
2032 | auto s = ad.aliasthis.sym; | |
2033 | if (s.isAliasDeclaration()) | |
2034 | s = s.toAlias(); | |
2035 | ||
2036 | if (s.isTupleDeclaration()) | |
2037 | return null; | |
2038 | ||
2039 | if (auto vd = s.isVarDeclaration()) | |
2040 | { | |
2041 | auto t = vd.type; | |
2042 | if (vd.needThis()) | |
2043 | t = t.addMod(this.mod); | |
2044 | return t; | |
2045 | } | |
2046 | if (auto fd = s.isFuncDeclaration()) | |
2047 | { | |
2048 | fd = resolveFuncCall(Loc.initial, null, fd, null, this, null, FuncResolveFlag.quiet); | |
2049 | if (!fd || fd.errors || !fd.functionSemantic()) | |
2050 | return Type.terror; | |
2051 | ||
2052 | auto t = fd.type.nextOf(); | |
2053 | if (!t) // issue 14185 | |
2054 | return Type.terror; | |
2055 | t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod); | |
2056 | return t; | |
2057 | } | |
2058 | if (auto d = s.isDeclaration()) | |
2059 | { | |
2060 | assert(d.type); | |
2061 | return d.type; | |
2062 | } | |
2063 | if (auto ed = s.isEnumDeclaration()) | |
2064 | { | |
2065 | return ed.type; | |
2066 | } | |
2067 | if (auto td = s.isTemplateDeclaration()) | |
2068 | { | |
2069 | assert(td._scope); | |
2070 | auto fd = resolveFuncCall(Loc.initial, null, td, null, this, null, FuncResolveFlag.quiet); | |
2071 | if (!fd || fd.errors || !fd.functionSemantic()) | |
2072 | return Type.terror; | |
2073 | ||
2074 | auto t = fd.type.nextOf(); | |
2075 | if (!t) | |
2076 | return Type.terror; | |
2077 | t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod); | |
2078 | return t; | |
2079 | } | |
2080 | ||
2081 | //printf("%s\n", s.kind()); | |
2082 | return null; | |
2083 | } | |
2084 | ||
2085 | extern (D) final bool checkAliasThisRec() | |
2086 | { | |
2087 | Type tb = toBasetype(); | |
2088 | AliasThisRec* pflag; | |
2089 | if (tb.ty == Tstruct) | |
2090 | pflag = &(cast(TypeStruct)tb).att; | |
2091 | else if (tb.ty == Tclass) | |
2092 | pflag = &(cast(TypeClass)tb).att; | |
2093 | else | |
2094 | return false; | |
2095 | ||
2096 | AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask); | |
2097 | if (flag == AliasThisRec.fwdref) | |
2098 | { | |
2099 | Type att = aliasthisOf(); | |
2100 | flag = att && att.implicitConvTo(this) ? AliasThisRec.yes : AliasThisRec.no; | |
2101 | } | |
2102 | *pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask)); | |
2103 | return flag == AliasThisRec.yes; | |
2104 | } | |
2105 | ||
2106 | Type makeConst() | |
2107 | { | |
2108 | //printf("Type::makeConst() %p, %s\n", this, toChars()); | |
2109 | if (mcache && mcache.cto) | |
2110 | return mcache.cto; | |
2111 | Type t = this.nullAttributes(); | |
2112 | t.mod = MODFlags.const_; | |
2113 | //printf("-Type::makeConst() %p, %s\n", t, toChars()); | |
2114 | return t; | |
2115 | } | |
2116 | ||
2117 | Type makeImmutable() | |
2118 | { | |
2119 | if (mcache && mcache.ito) | |
2120 | return mcache.ito; | |
2121 | Type t = this.nullAttributes(); | |
2122 | t.mod = MODFlags.immutable_; | |
2123 | return t; | |
2124 | } | |
2125 | ||
2126 | Type makeShared() | |
2127 | { | |
2128 | if (mcache && mcache.sto) | |
2129 | return mcache.sto; | |
2130 | Type t = this.nullAttributes(); | |
2131 | t.mod = MODFlags.shared_; | |
2132 | return t; | |
2133 | } | |
2134 | ||
2135 | Type makeSharedConst() | |
2136 | { | |
2137 | if (mcache && mcache.scto) | |
2138 | return mcache.scto; | |
2139 | Type t = this.nullAttributes(); | |
2140 | t.mod = MODFlags.shared_ | MODFlags.const_; | |
2141 | return t; | |
2142 | } | |
2143 | ||
2144 | Type makeWild() | |
2145 | { | |
2146 | if (mcache && mcache.wto) | |
2147 | return mcache.wto; | |
2148 | Type t = this.nullAttributes(); | |
2149 | t.mod = MODFlags.wild; | |
2150 | return t; | |
2151 | } | |
2152 | ||
2153 | Type makeWildConst() | |
2154 | { | |
2155 | if (mcache && mcache.wcto) | |
2156 | return mcache.wcto; | |
2157 | Type t = this.nullAttributes(); | |
2158 | t.mod = MODFlags.wildconst; | |
2159 | return t; | |
2160 | } | |
2161 | ||
2162 | Type makeSharedWild() | |
2163 | { | |
2164 | if (mcache && mcache.swto) | |
2165 | return mcache.swto; | |
2166 | Type t = this.nullAttributes(); | |
2167 | t.mod = MODFlags.shared_ | MODFlags.wild; | |
2168 | return t; | |
2169 | } | |
2170 | ||
2171 | Type makeSharedWildConst() | |
2172 | { | |
2173 | if (mcache && mcache.swcto) | |
2174 | return mcache.swcto; | |
2175 | Type t = this.nullAttributes(); | |
2176 | t.mod = MODFlags.shared_ | MODFlags.wildconst; | |
2177 | return t; | |
2178 | } | |
2179 | ||
2180 | Type makeMutable() | |
2181 | { | |
2182 | Type t = this.nullAttributes(); | |
2183 | t.mod = mod & MODFlags.shared_; | |
2184 | return t; | |
2185 | } | |
2186 | ||
2187 | Dsymbol toDsymbol(Scope* sc) | |
2188 | { | |
2189 | return null; | |
2190 | } | |
2191 | ||
2192 | /******************************* | |
2193 | * If this is a shell around another type, | |
2194 | * get that other type. | |
2195 | */ | |
2196 | final Type toBasetype() | |
2197 | { | |
2198 | /* This function is used heavily. | |
2199 | * De-virtualize it so it can be easily inlined. | |
2200 | */ | |
2201 | TypeEnum te; | |
2202 | return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this; | |
2203 | } | |
2204 | ||
2205 | bool isBaseOf(Type t, int* poffset) | |
2206 | { | |
2207 | return 0; // assume not | |
2208 | } | |
2209 | ||
2210 | /******************************** | |
2211 | * Determine if 'this' can be implicitly converted | |
2212 | * to type 'to'. | |
2213 | * Returns: | |
2214 | * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact | |
2215 | */ | |
2216 | MATCH implicitConvTo(Type to) | |
2217 | { | |
2218 | //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); | |
2219 | //printf("from: %s\n", toChars()); | |
2220 | //printf("to : %s\n", to.toChars()); | |
2221 | if (this.equals(to)) | |
2222 | return MATCH.exact; | |
2223 | return MATCH.nomatch; | |
2224 | } | |
2225 | ||
2226 | /******************************* | |
2227 | * Determine if converting 'this' to 'to' is an identity operation, | |
2228 | * a conversion to const operation, or the types aren't the same. | |
2229 | * Returns: | |
2230 | * MATCH.exact 'this' == 'to' | |
2231 | * MATCH.constant 'to' is const | |
2232 | * MATCH.nomatch conversion to mutable or invariant | |
2233 | */ | |
2234 | MATCH constConv(Type to) | |
2235 | { | |
2236 | //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to.toChars()); | |
2237 | if (equals(to)) | |
2238 | return MATCH.exact; | |
2239 | if (ty == to.ty && MODimplicitConv(mod, to.mod)) | |
2240 | return MATCH.constant; | |
2241 | return MATCH.nomatch; | |
2242 | } | |
2243 | ||
2244 | /*************************************** | |
2245 | * Compute MOD bits matching `this` argument type to wild parameter type. | |
2246 | * Params: | |
2247 | * t = corresponding parameter type | |
2248 | * isRef = parameter is `ref` or `out` | |
2249 | * Returns: | |
2250 | * MOD bits | |
2251 | */ | |
2252 | MOD deduceWild(Type t, bool isRef) | |
2253 | { | |
2254 | //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm.toChars()); | |
2255 | if (t.isWild()) | |
2256 | { | |
2257 | if (isImmutable()) | |
2258 | return MODFlags.immutable_; | |
2259 | else if (isWildConst()) | |
2260 | { | |
2261 | if (t.isWildConst()) | |
2262 | return MODFlags.wild; | |
2263 | else | |
2264 | return MODFlags.wildconst; | |
2265 | } | |
2266 | else if (isWild()) | |
2267 | return MODFlags.wild; | |
2268 | else if (isConst()) | |
2269 | return MODFlags.const_; | |
2270 | else if (isMutable()) | |
2271 | return MODFlags.mutable; | |
2272 | else | |
2273 | assert(0); | |
2274 | } | |
2275 | return 0; | |
2276 | } | |
2277 | ||
2278 | Type substWildTo(uint mod) | |
2279 | { | |
2280 | //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod); | |
2281 | Type t; | |
2282 | ||
2283 | if (Type tn = nextOf()) | |
2284 | { | |
2285 | // substitution has no effect on function pointer type. | |
2286 | if (ty == Tpointer && tn.ty == Tfunction) | |
2287 | { | |
2288 | t = this; | |
2289 | goto L1; | |
2290 | } | |
2291 | ||
2292 | t = tn.substWildTo(mod); | |
2293 | if (t == tn) | |
2294 | t = this; | |
2295 | else | |
2296 | { | |
2297 | if (ty == Tpointer) | |
2298 | t = t.pointerTo(); | |
2299 | else if (ty == Tarray) | |
2300 | t = t.arrayOf(); | |
2301 | else if (ty == Tsarray) | |
2302 | t = new TypeSArray(t, (cast(TypeSArray)this).dim.syntaxCopy()); | |
2303 | else if (ty == Taarray) | |
2304 | { | |
2305 | t = new TypeAArray(t, (cast(TypeAArray)this).index.syntaxCopy()); | |
2306 | } | |
2307 | else if (ty == Tdelegate) | |
2308 | { | |
2309 | t = new TypeDelegate(t.isTypeFunction()); | |
2310 | } | |
2311 | else | |
2312 | assert(0); | |
2313 | ||
2314 | t = t.merge(); | |
2315 | } | |
2316 | } | |
2317 | else | |
2318 | t = this; | |
2319 | ||
2320 | L1: | |
2321 | if (isWild()) | |
2322 | { | |
2323 | if (mod == MODFlags.immutable_) | |
2324 | { | |
2325 | t = t.immutableOf(); | |
2326 | } | |
2327 | else if (mod == MODFlags.wildconst) | |
2328 | { | |
2329 | t = t.wildConstOf(); | |
2330 | } | |
2331 | else if (mod == MODFlags.wild) | |
2332 | { | |
2333 | if (isWildConst()) | |
2334 | t = t.wildConstOf(); | |
2335 | else | |
2336 | t = t.wildOf(); | |
2337 | } | |
2338 | else if (mod == MODFlags.const_) | |
2339 | { | |
2340 | t = t.constOf(); | |
2341 | } | |
2342 | else | |
2343 | { | |
2344 | if (isWildConst()) | |
2345 | t = t.constOf(); | |
2346 | else | |
2347 | t = t.mutableOf(); | |
2348 | } | |
2349 | } | |
2350 | if (isConst()) | |
2351 | t = t.addMod(MODFlags.const_); | |
2352 | if (isShared()) | |
2353 | t = t.addMod(MODFlags.shared_); | |
2354 | ||
2355 | //printf("-Type::substWildTo t = %s\n", t.toChars()); | |
2356 | return t; | |
2357 | } | |
2358 | ||
2359 | final Type unqualify(uint m) | |
2360 | { | |
2361 | Type t = mutableOf().unSharedOf(); | |
2362 | ||
2363 | Type tn = ty == Tenum ? null : nextOf(); | |
2364 | if (tn && tn.ty != Tfunction) | |
2365 | { | |
2366 | Type utn = tn.unqualify(m); | |
2367 | if (utn != tn) | |
2368 | { | |
2369 | if (ty == Tpointer) | |
2370 | t = utn.pointerTo(); | |
2371 | else if (ty == Tarray) | |
2372 | t = utn.arrayOf(); | |
2373 | else if (ty == Tsarray) | |
2374 | t = new TypeSArray(utn, (cast(TypeSArray)this).dim); | |
2375 | else if (ty == Taarray) | |
2376 | { | |
2377 | t = new TypeAArray(utn, (cast(TypeAArray)this).index); | |
2378 | } | |
2379 | else | |
2380 | assert(0); | |
2381 | ||
2382 | t = t.merge(); | |
2383 | } | |
2384 | } | |
2385 | t = t.addMod(mod & ~m); | |
2386 | return t; | |
2387 | } | |
2388 | ||
2389 | /************************** | |
2390 | * Return type with the top level of it being mutable. | |
2391 | */ | |
2392 | inout(Type) toHeadMutable() inout | |
2393 | { | |
2394 | if (!mod) | |
2395 | return this; | |
2396 | Type unqualThis = cast(Type) this; | |
2397 | // `mutableOf` needs a mutable `this` only for caching | |
2398 | return cast(inout(Type)) unqualThis.mutableOf(); | |
2399 | } | |
2400 | ||
2401 | inout(ClassDeclaration) isClassHandle() inout | |
2402 | { | |
2403 | return null; | |
2404 | } | |
2405 | ||
2406 | /************************************ | |
2407 | * Return alignment to use for this type. | |
2408 | */ | |
2409 | structalign_t alignment() | |
2410 | { | |
0fb57034 IB |
2411 | structalign_t s; |
2412 | s.setDefault(); | |
2413 | return s; | |
5fee5ec3 IB |
2414 | } |
2415 | ||
2416 | /*************************************** | |
2417 | * Use when we prefer the default initializer to be a literal, | |
2418 | * rather than a global immutable variable. | |
2419 | */ | |
2420 | Expression defaultInitLiteral(const ref Loc loc) | |
2421 | { | |
2422 | static if (LOGDEFAULTINIT) | |
2423 | { | |
2424 | printf("Type::defaultInitLiteral() '%s'\n", toChars()); | |
2425 | } | |
2426 | return defaultInit(this, loc); | |
2427 | } | |
2428 | ||
2429 | // if initializer is 0 | |
2430 | bool isZeroInit(const ref Loc loc) | |
2431 | { | |
2432 | return false; // assume not | |
2433 | } | |
2434 | ||
2435 | final Identifier getTypeInfoIdent() | |
2436 | { | |
2437 | // _init_10TypeInfo_%s | |
2438 | OutBuffer buf; | |
2439 | buf.reserve(32); | |
2440 | mangleToBuffer(this, &buf); | |
2441 | ||
2442 | const slice = buf[]; | |
2443 | ||
2444 | // Allocate buffer on stack, fail over to using malloc() | |
2445 | char[128] namebuf; | |
2446 | const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; | |
2447 | auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); | |
2448 | ||
2449 | const length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ", | |
2450 | cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); | |
2451 | //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); | |
2452 | assert(0 < length && length < namelen); // don't overflow the buffer | |
2453 | ||
2454 | auto id = Identifier.idPool(name, length); | |
2455 | ||
2456 | if (name != namebuf.ptr) | |
2457 | free(name); | |
2458 | return id; | |
2459 | } | |
2460 | ||
2461 | /*************************************** | |
2462 | * Return !=0 if the type or any of its subtypes is wild. | |
2463 | */ | |
2464 | int hasWild() const | |
2465 | { | |
2466 | return mod & MODFlags.wild; | |
2467 | } | |
2468 | ||
2469 | /*************************************** | |
2470 | * Return !=0 if type has pointers that need to | |
2471 | * be scanned by the GC during a collection cycle. | |
2472 | */ | |
2473 | bool hasPointers() | |
2474 | { | |
2475 | //printf("Type::hasPointers() %s, %d\n", toChars(), ty); | |
2476 | return false; | |
2477 | } | |
2478 | ||
2479 | /************************************* | |
2480 | * Detect if type has pointer fields that are initialized to void. | |
2481 | * Local stack variables with such void fields can remain uninitialized, | |
2482 | * leading to pointer bugs. | |
2483 | * Returns: | |
2484 | * true if so | |
2485 | */ | |
2486 | bool hasVoidInitPointers() | |
2487 | { | |
2488 | return false; | |
2489 | } | |
2490 | ||
2491 | /*************************************** | |
2492 | * Returns: true if type has any invariants | |
2493 | */ | |
2494 | bool hasInvariant() | |
2495 | { | |
2496 | //printf("Type::hasInvariant() %s, %d\n", toChars(), ty); | |
2497 | return false; | |
2498 | } | |
2499 | ||
2500 | /************************************* | |
2501 | * If this is a type of something, return that something. | |
2502 | */ | |
2503 | Type nextOf() | |
2504 | { | |
2505 | return null; | |
2506 | } | |
2507 | ||
2508 | /************************************* | |
2509 | * If this is a type of static array, return its base element type. | |
2510 | */ | |
2511 | final Type baseElemOf() | |
2512 | { | |
2513 | Type t = toBasetype(); | |
2514 | TypeSArray tsa; | |
2515 | while ((tsa = t.isTypeSArray()) !is null) | |
2516 | t = tsa.next.toBasetype(); | |
2517 | return t; | |
2518 | } | |
2519 | ||
2520 | /******************************************* | |
2521 | * Compute number of elements for a (possibly multidimensional) static array, | |
2522 | * or 1 for other types. | |
2523 | * Params: | |
2524 | * loc = for error message | |
2525 | * Returns: | |
2526 | * number of elements, uint.max on overflow | |
2527 | */ | |
2528 | final uint numberOfElems(const ref Loc loc) | |
2529 | { | |
2530 | //printf("Type::numberOfElems()\n"); | |
2531 | uinteger_t n = 1; | |
2532 | Type tb = this; | |
2533 | while ((tb = tb.toBasetype()).ty == Tsarray) | |
2534 | { | |
2535 | bool overflow = false; | |
2536 | n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow); | |
2537 | if (overflow || n >= uint.max) | |
2538 | { | |
2539 | error(loc, "static array `%s` size overflowed to %llu", toChars(), cast(ulong)n); | |
2540 | return uint.max; | |
2541 | } | |
2542 | tb = (cast(TypeSArray)tb).next; | |
2543 | } | |
2544 | return cast(uint)n; | |
2545 | } | |
2546 | ||
2547 | /**************************************** | |
2548 | * Return the mask that an integral type will | |
2549 | * fit into. | |
2550 | */ | |
2551 | final uinteger_t sizemask() | |
2552 | { | |
2553 | uinteger_t m; | |
2554 | switch (toBasetype().ty) | |
2555 | { | |
2556 | case Tbool: | |
2557 | m = 1; | |
2558 | break; | |
2559 | case Tchar: | |
2560 | case Tint8: | |
2561 | case Tuns8: | |
2562 | m = 0xFF; | |
2563 | break; | |
2564 | case Twchar: | |
2565 | case Tint16: | |
2566 | case Tuns16: | |
2567 | m = 0xFFFFU; | |
2568 | break; | |
2569 | case Tdchar: | |
2570 | case Tint32: | |
2571 | case Tuns32: | |
2572 | m = 0xFFFFFFFFU; | |
2573 | break; | |
2574 | case Tint64: | |
2575 | case Tuns64: | |
2576 | m = 0xFFFFFFFFFFFFFFFFUL; | |
2577 | break; | |
2578 | default: | |
2579 | assert(0); | |
2580 | } | |
2581 | return m; | |
2582 | } | |
2583 | ||
2584 | /******************************** | |
2585 | * true if when type goes out of scope, it needs a destructor applied. | |
2586 | * Only applies to value types, not ref types. | |
2587 | */ | |
2588 | bool needsDestruction() | |
2589 | { | |
2590 | return false; | |
2591 | } | |
2592 | ||
2593 | /******************************** | |
2594 | * true if when type is copied, it needs a copy constructor or postblit | |
2595 | * applied. Only applies to value types, not ref types. | |
2596 | */ | |
2597 | bool needsCopyOrPostblit() | |
2598 | { | |
2599 | return false; | |
2600 | } | |
2601 | ||
2602 | /********************************* | |
2603 | * | |
2604 | */ | |
2605 | bool needsNested() | |
2606 | { | |
2607 | return false; | |
2608 | } | |
2609 | ||
2610 | /************************************* | |
2611 | * https://issues.dlang.org/show_bug.cgi?id=14488 | |
2612 | * Check if the inner most base type is complex or imaginary. | |
2613 | * Should only give alerts when set to emit transitional messages. | |
2614 | * Params: | |
2615 | * loc = The source location. | |
2616 | * sc = scope of the type | |
2617 | */ | |
2618 | extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc) | |
2619 | { | |
2620 | if (sc.isDeprecated()) | |
2621 | return false; | |
2622 | // Don't complain if we're inside a template constraint | |
2623 | // https://issues.dlang.org/show_bug.cgi?id=21831 | |
2624 | if (sc.flags & SCOPE.constraint) | |
2625 | return false; | |
2626 | ||
2627 | Type t = baseElemOf(); | |
2628 | while (t.ty == Tpointer || t.ty == Tarray) | |
2629 | t = t.nextOf().baseElemOf(); | |
2630 | ||
2631 | // Basetype is an opaque enum, nothing to check. | |
2632 | if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) | |
2633 | return false; | |
2634 | ||
2635 | if (t.isimaginary() || t.iscomplex()) | |
2636 | { | |
2637 | Type rt; | |
2638 | switch (t.ty) | |
2639 | { | |
2640 | case Tcomplex32: | |
2641 | case Timaginary32: | |
2642 | rt = Type.tfloat32; | |
2643 | break; | |
2644 | ||
2645 | case Tcomplex64: | |
2646 | case Timaginary64: | |
2647 | rt = Type.tfloat64; | |
2648 | break; | |
2649 | ||
2650 | case Tcomplex80: | |
2651 | case Timaginary80: | |
2652 | rt = Type.tfloat80; | |
2653 | break; | |
2654 | ||
2655 | default: | |
2656 | assert(0); | |
2657 | } | |
6384eff5 IB |
2658 | // @@@DEPRECATED_2.117@@@ |
2659 | // Deprecated in 2.097 - Can be made an error from 2.117. | |
2660 | // The deprecation period is longer than usual as `cfloat`, | |
2661 | // `cdouble`, and `creal` were quite widely used. | |
5fee5ec3 IB |
2662 | if (t.iscomplex()) |
2663 | { | |
2664 | deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", | |
2665 | toChars(), rt.toChars()); | |
2666 | return true; | |
2667 | } | |
2668 | else | |
2669 | { | |
2670 | deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", | |
2671 | toChars(), rt.toChars()); | |
2672 | return true; | |
2673 | } | |
2674 | } | |
2675 | return false; | |
2676 | } | |
2677 | ||
2678 | // For eliminating dynamic_cast | |
2679 | TypeBasic isTypeBasic() | |
2680 | { | |
2681 | return null; | |
2682 | } | |
2683 | ||
2684 | final pure inout nothrow @nogc | |
2685 | { | |
2686 | /**************** | |
2687 | * Is this type a pointer to a function? | |
2688 | * Returns: | |
2689 | * the function type if it is | |
2690 | */ | |
2691 | inout(TypeFunction) isPtrToFunction() | |
2692 | { | |
2693 | return (ty == Tpointer && (cast(TypePointer)this).next.ty == Tfunction) | |
2694 | ? cast(typeof(return))(cast(TypePointer)this).next | |
2695 | : null; | |
2696 | } | |
2697 | ||
2698 | /***************** | |
2699 | * Is this type a function, delegate, or pointer to a function? | |
2700 | * Returns: | |
2701 | * the function type if it is | |
2702 | */ | |
2703 | inout(TypeFunction) isFunction_Delegate_PtrToFunction() | |
2704 | { | |
2705 | return ty == Tfunction ? cast(typeof(return))this : | |
2706 | ||
2707 | ty == Tdelegate ? cast(typeof(return))(cast(TypePointer)this).next : | |
2708 | ||
2709 | ty == Tpointer && (cast(TypePointer)this).next.ty == Tfunction ? | |
2710 | cast(typeof(return))(cast(TypePointer)this).next : | |
2711 | ||
2712 | null; | |
2713 | } | |
2714 | } | |
2715 | ||
2716 | final pure inout nothrow @nogc @safe | |
2717 | { | |
2718 | inout(TypeError) isTypeError() { return ty == Terror ? cast(typeof(return))this : null; } | |
2719 | inout(TypeVector) isTypeVector() { return ty == Tvector ? cast(typeof(return))this : null; } | |
2720 | inout(TypeSArray) isTypeSArray() { return ty == Tsarray ? cast(typeof(return))this : null; } | |
2721 | inout(TypeDArray) isTypeDArray() { return ty == Tarray ? cast(typeof(return))this : null; } | |
2722 | inout(TypeAArray) isTypeAArray() { return ty == Taarray ? cast(typeof(return))this : null; } | |
2723 | inout(TypePointer) isTypePointer() { return ty == Tpointer ? cast(typeof(return))this : null; } | |
2724 | inout(TypeReference) isTypeReference() { return ty == Treference ? cast(typeof(return))this : null; } | |
2725 | inout(TypeFunction) isTypeFunction() { return ty == Tfunction ? cast(typeof(return))this : null; } | |
2726 | inout(TypeDelegate) isTypeDelegate() { return ty == Tdelegate ? cast(typeof(return))this : null; } | |
2727 | inout(TypeIdentifier) isTypeIdentifier() { return ty == Tident ? cast(typeof(return))this : null; } | |
2728 | inout(TypeInstance) isTypeInstance() { return ty == Tinstance ? cast(typeof(return))this : null; } | |
2729 | inout(TypeTypeof) isTypeTypeof() { return ty == Ttypeof ? cast(typeof(return))this : null; } | |
2730 | inout(TypeReturn) isTypeReturn() { return ty == Treturn ? cast(typeof(return))this : null; } | |
2731 | inout(TypeStruct) isTypeStruct() { return ty == Tstruct ? cast(typeof(return))this : null; } | |
2732 | inout(TypeEnum) isTypeEnum() { return ty == Tenum ? cast(typeof(return))this : null; } | |
2733 | inout(TypeClass) isTypeClass() { return ty == Tclass ? cast(typeof(return))this : null; } | |
2734 | inout(TypeTuple) isTypeTuple() { return ty == Ttuple ? cast(typeof(return))this : null; } | |
2735 | inout(TypeSlice) isTypeSlice() { return ty == Tslice ? cast(typeof(return))this : null; } | |
2736 | inout(TypeNull) isTypeNull() { return ty == Tnull ? cast(typeof(return))this : null; } | |
2737 | inout(TypeMixin) isTypeMixin() { return ty == Tmixin ? cast(typeof(return))this : null; } | |
2738 | inout(TypeTraits) isTypeTraits() { return ty == Ttraits ? cast(typeof(return))this : null; } | |
2739 | inout(TypeNoreturn) isTypeNoreturn() { return ty == Tnoreturn ? cast(typeof(return))this : null; } | |
2740 | inout(TypeTag) isTypeTag() { return ty == Ttag ? cast(typeof(return))this : null; } | |
2741 | } | |
2742 | ||
2743 | override void accept(Visitor v) | |
2744 | { | |
2745 | v.visit(this); | |
2746 | } | |
2747 | ||
2748 | final TypeFunction toTypeFunction() | |
2749 | { | |
2750 | if (ty != Tfunction) | |
2751 | assert(0); | |
2752 | return cast(TypeFunction)this; | |
2753 | } | |
2754 | ||
2755 | extern (D) static Types* arraySyntaxCopy(Types* types) | |
2756 | { | |
2757 | Types* a = null; | |
2758 | if (types) | |
2759 | { | |
2760 | a = new Types(types.length); | |
2761 | foreach (i, t; *types) | |
2762 | { | |
2763 | (*a)[i] = t ? t.syntaxCopy() : null; | |
2764 | } | |
2765 | } | |
2766 | return a; | |
2767 | } | |
2768 | } | |
2769 | ||
2770 | /*********************************************************** | |
2771 | */ | |
2772 | extern (C++) final class TypeError : Type | |
2773 | { | |
2774 | extern (D) this() | |
2775 | { | |
2776 | super(Terror); | |
2777 | } | |
2778 | ||
2779 | override const(char)* kind() const | |
2780 | { | |
2781 | return "error"; | |
2782 | } | |
2783 | ||
2784 | override TypeError syntaxCopy() | |
2785 | { | |
2786 | // No semantic analysis done, no need to copy | |
2787 | return this; | |
2788 | } | |
2789 | ||
fbdaa581 | 2790 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
2791 | { |
2792 | return SIZE_INVALID; | |
2793 | } | |
2794 | ||
2795 | override Expression defaultInitLiteral(const ref Loc loc) | |
2796 | { | |
2797 | return ErrorExp.get(); | |
2798 | } | |
2799 | ||
2800 | override void accept(Visitor v) | |
2801 | { | |
2802 | v.visit(this); | |
2803 | } | |
2804 | } | |
2805 | ||
2806 | /*********************************************************** | |
2807 | */ | |
2808 | extern (C++) abstract class TypeNext : Type | |
2809 | { | |
2810 | Type next; | |
2811 | ||
2812 | final extern (D) this(TY ty, Type next) | |
2813 | { | |
2814 | super(ty); | |
2815 | this.next = next; | |
2816 | } | |
2817 | ||
2818 | override final void checkDeprecated(const ref Loc loc, Scope* sc) | |
2819 | { | |
2820 | Type.checkDeprecated(loc, sc); | |
2821 | if (next) // next can be NULL if TypeFunction and auto return type | |
2822 | next.checkDeprecated(loc, sc); | |
2823 | } | |
2824 | ||
2825 | override final int hasWild() const | |
2826 | { | |
2827 | if (ty == Tfunction) | |
2828 | return 0; | |
2829 | if (ty == Tdelegate) | |
2830 | return Type.hasWild(); | |
2831 | return mod & MODFlags.wild || (next && next.hasWild()); | |
2832 | } | |
2833 | ||
2834 | /******************************* | |
2835 | * For TypeFunction, nextOf() can return NULL if the function return | |
2836 | * type is meant to be inferred, and semantic() hasn't yet ben run | |
2837 | * on the function. After semantic(), it must no longer be NULL. | |
2838 | */ | |
2839 | override final Type nextOf() | |
2840 | { | |
2841 | return next; | |
2842 | } | |
2843 | ||
2844 | override final Type makeConst() | |
2845 | { | |
2846 | //printf("TypeNext::makeConst() %p, %s\n", this, toChars()); | |
2847 | if (mcache && mcache.cto) | |
2848 | { | |
2849 | assert(mcache.cto.mod == MODFlags.const_); | |
2850 | return mcache.cto; | |
2851 | } | |
2852 | TypeNext t = cast(TypeNext)Type.makeConst(); | |
2853 | if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) | |
2854 | { | |
2855 | if (next.isShared()) | |
2856 | { | |
2857 | if (next.isWild()) | |
2858 | t.next = next.sharedWildConstOf(); | |
2859 | else | |
2860 | t.next = next.sharedConstOf(); | |
2861 | } | |
2862 | else | |
2863 | { | |
2864 | if (next.isWild()) | |
2865 | t.next = next.wildConstOf(); | |
2866 | else | |
2867 | t.next = next.constOf(); | |
2868 | } | |
2869 | } | |
2870 | //printf("TypeNext::makeConst() returns %p, %s\n", t, t.toChars()); | |
2871 | return t; | |
2872 | } | |
2873 | ||
2874 | override final Type makeImmutable() | |
2875 | { | |
2876 | //printf("TypeNext::makeImmutable() %s\n", toChars()); | |
2877 | if (mcache && mcache.ito) | |
2878 | { | |
2879 | assert(mcache.ito.isImmutable()); | |
2880 | return mcache.ito; | |
2881 | } | |
2882 | TypeNext t = cast(TypeNext)Type.makeImmutable(); | |
2883 | if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) | |
2884 | { | |
2885 | t.next = next.immutableOf(); | |
2886 | } | |
2887 | return t; | |
2888 | } | |
2889 | ||
2890 | override final Type makeShared() | |
2891 | { | |
2892 | //printf("TypeNext::makeShared() %s\n", toChars()); | |
2893 | if (mcache && mcache.sto) | |
2894 | { | |
2895 | assert(mcache.sto.mod == MODFlags.shared_); | |
2896 | return mcache.sto; | |
2897 | } | |
2898 | TypeNext t = cast(TypeNext)Type.makeShared(); | |
2899 | if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) | |
2900 | { | |
2901 | if (next.isWild()) | |
2902 | { | |
2903 | if (next.isConst()) | |
2904 | t.next = next.sharedWildConstOf(); | |
2905 | else | |
2906 | t.next = next.sharedWildOf(); | |
2907 | } | |
2908 | else | |
2909 | { | |
2910 | if (next.isConst()) | |
2911 | t.next = next.sharedConstOf(); | |
2912 | else | |
2913 | t.next = next.sharedOf(); | |
2914 | } | |
2915 | } | |
2916 | //printf("TypeNext::makeShared() returns %p, %s\n", t, t.toChars()); | |
2917 | return t; | |
2918 | } | |
2919 | ||
2920 | override final Type makeSharedConst() | |
2921 | { | |
2922 | //printf("TypeNext::makeSharedConst() %s\n", toChars()); | |
2923 | if (mcache && mcache.scto) | |
2924 | { | |
2925 | assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_)); | |
2926 | return mcache.scto; | |
2927 | } | |
2928 | TypeNext t = cast(TypeNext)Type.makeSharedConst(); | |
2929 | if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) | |
2930 | { | |
2931 | if (next.isWild()) | |
2932 | t.next = next.sharedWildConstOf(); | |
2933 | else | |
2934 | t.next = next.sharedConstOf(); | |
2935 | } | |
2936 | //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t.toChars()); | |
2937 | return t; | |
2938 | } | |
2939 | ||
2940 | override final Type makeWild() | |
2941 | { | |
2942 | //printf("TypeNext::makeWild() %s\n", toChars()); | |
2943 | if (mcache && mcache.wto) | |
2944 | { | |
2945 | assert(mcache.wto.mod == MODFlags.wild); | |
2946 | return mcache.wto; | |
2947 | } | |
2948 | TypeNext t = cast(TypeNext)Type.makeWild(); | |
2949 | if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) | |
2950 | { | |
2951 | if (next.isShared()) | |
2952 | { | |
2953 | if (next.isConst()) | |
2954 | t.next = next.sharedWildConstOf(); | |
2955 | else | |
2956 | t.next = next.sharedWildOf(); | |
2957 | } | |
2958 | else | |
2959 | { | |
2960 | if (next.isConst()) | |
2961 | t.next = next.wildConstOf(); | |
2962 | else | |
2963 | t.next = next.wildOf(); | |
2964 | } | |
2965 | } | |
2966 | //printf("TypeNext::makeWild() returns %p, %s\n", t, t.toChars()); | |
2967 | return t; | |
2968 | } | |
2969 | ||
2970 | override final Type makeWildConst() | |
2971 | { | |
2972 | //printf("TypeNext::makeWildConst() %s\n", toChars()); | |
2973 | if (mcache && mcache.wcto) | |
2974 | { | |
2975 | assert(mcache.wcto.mod == MODFlags.wildconst); | |
2976 | return mcache.wcto; | |
2977 | } | |
2978 | TypeNext t = cast(TypeNext)Type.makeWildConst(); | |
2979 | if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) | |
2980 | { | |
2981 | if (next.isShared()) | |
2982 | t.next = next.sharedWildConstOf(); | |
2983 | else | |
2984 | t.next = next.wildConstOf(); | |
2985 | } | |
2986 | //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t.toChars()); | |
2987 | return t; | |
2988 | } | |
2989 | ||
2990 | override final Type makeSharedWild() | |
2991 | { | |
2992 | //printf("TypeNext::makeSharedWild() %s\n", toChars()); | |
2993 | if (mcache && mcache.swto) | |
2994 | { | |
2995 | assert(mcache.swto.isSharedWild()); | |
2996 | return mcache.swto; | |
2997 | } | |
2998 | TypeNext t = cast(TypeNext)Type.makeSharedWild(); | |
2999 | if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) | |
3000 | { | |
3001 | if (next.isConst()) | |
3002 | t.next = next.sharedWildConstOf(); | |
3003 | else | |
3004 | t.next = next.sharedWildOf(); | |
3005 | } | |
3006 | //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t.toChars()); | |
3007 | return t; | |
3008 | } | |
3009 | ||
3010 | override final Type makeSharedWildConst() | |
3011 | { | |
3012 | //printf("TypeNext::makeSharedWildConst() %s\n", toChars()); | |
3013 | if (mcache && mcache.swcto) | |
3014 | { | |
3015 | assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); | |
3016 | return mcache.swcto; | |
3017 | } | |
3018 | TypeNext t = cast(TypeNext)Type.makeSharedWildConst(); | |
3019 | if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) | |
3020 | { | |
3021 | t.next = next.sharedWildConstOf(); | |
3022 | } | |
3023 | //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t.toChars()); | |
3024 | return t; | |
3025 | } | |
3026 | ||
3027 | override final Type makeMutable() | |
3028 | { | |
3029 | //printf("TypeNext::makeMutable() %p, %s\n", this, toChars()); | |
3030 | TypeNext t = cast(TypeNext)Type.makeMutable(); | |
3031 | if (ty == Tsarray) | |
3032 | { | |
3033 | t.next = next.mutableOf(); | |
3034 | } | |
3035 | //printf("TypeNext::makeMutable() returns %p, %s\n", t, t.toChars()); | |
3036 | return t; | |
3037 | } | |
3038 | ||
3039 | override MATCH constConv(Type to) | |
3040 | { | |
3041 | //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to.toChars()); | |
3042 | if (equals(to)) | |
3043 | return MATCH.exact; | |
3044 | ||
3045 | if (!(ty == to.ty && MODimplicitConv(mod, to.mod))) | |
3046 | return MATCH.nomatch; | |
3047 | ||
3048 | Type tn = to.nextOf(); | |
3049 | if (!(tn && next.ty == tn.ty)) | |
3050 | return MATCH.nomatch; | |
3051 | ||
3052 | MATCH m; | |
3053 | if (to.isConst()) // whole tail const conversion | |
3054 | { | |
3055 | // Recursive shared level check | |
3056 | m = next.constConv(tn); | |
3057 | if (m == MATCH.exact) | |
3058 | m = MATCH.constant; | |
3059 | } | |
3060 | else | |
3061 | { | |
3062 | //printf("\tnext => %s, to.next => %s\n", next.toChars(), tn.toChars()); | |
3063 | m = next.equals(tn) ? MATCH.constant : MATCH.nomatch; | |
3064 | } | |
3065 | return m; | |
3066 | } | |
3067 | ||
3068 | override final MOD deduceWild(Type t, bool isRef) | |
3069 | { | |
3070 | if (ty == Tfunction) | |
3071 | return 0; | |
3072 | ||
3073 | ubyte wm; | |
3074 | ||
3075 | Type tn = t.nextOf(); | |
3076 | if (!isRef && (ty == Tarray || ty == Tpointer) && tn) | |
3077 | { | |
3078 | wm = next.deduceWild(tn, true); | |
3079 | if (!wm) | |
3080 | wm = Type.deduceWild(t, true); | |
3081 | } | |
3082 | else | |
3083 | { | |
3084 | wm = Type.deduceWild(t, isRef); | |
3085 | if (!wm && tn) | |
3086 | wm = next.deduceWild(tn, true); | |
3087 | } | |
3088 | ||
3089 | return wm; | |
3090 | } | |
3091 | ||
3092 | final void transitive() | |
3093 | { | |
3094 | /* Invoke transitivity of type attributes | |
3095 | */ | |
3096 | next = next.addMod(mod); | |
3097 | } | |
3098 | ||
3099 | override void accept(Visitor v) | |
3100 | { | |
3101 | v.visit(this); | |
3102 | } | |
3103 | } | |
3104 | ||
3105 | /*********************************************************** | |
3106 | */ | |
3107 | extern (C++) final class TypeBasic : Type | |
3108 | { | |
3109 | const(char)* dstring; | |
3110 | uint flags; | |
3111 | ||
3112 | extern (D) this(TY ty) | |
3113 | { | |
3114 | super(ty); | |
3115 | const(char)* d; | |
3116 | uint flags = 0; | |
3117 | switch (ty) | |
3118 | { | |
3119 | case Tvoid: | |
3120 | d = Token.toChars(TOK.void_); | |
3121 | break; | |
3122 | ||
3123 | case Tint8: | |
3124 | d = Token.toChars(TOK.int8); | |
3125 | flags |= TFlags.integral; | |
3126 | break; | |
3127 | ||
3128 | case Tuns8: | |
3129 | d = Token.toChars(TOK.uns8); | |
3130 | flags |= TFlags.integral | TFlags.unsigned; | |
3131 | break; | |
3132 | ||
3133 | case Tint16: | |
3134 | d = Token.toChars(TOK.int16); | |
3135 | flags |= TFlags.integral; | |
3136 | break; | |
3137 | ||
3138 | case Tuns16: | |
3139 | d = Token.toChars(TOK.uns16); | |
3140 | flags |= TFlags.integral | TFlags.unsigned; | |
3141 | break; | |
3142 | ||
3143 | case Tint32: | |
3144 | d = Token.toChars(TOK.int32); | |
3145 | flags |= TFlags.integral; | |
3146 | break; | |
3147 | ||
3148 | case Tuns32: | |
3149 | d = Token.toChars(TOK.uns32); | |
3150 | flags |= TFlags.integral | TFlags.unsigned; | |
3151 | break; | |
3152 | ||
3153 | case Tfloat32: | |
3154 | d = Token.toChars(TOK.float32); | |
3155 | flags |= TFlags.floating | TFlags.real_; | |
3156 | break; | |
3157 | ||
3158 | case Tint64: | |
3159 | d = Token.toChars(TOK.int64); | |
3160 | flags |= TFlags.integral; | |
3161 | break; | |
3162 | ||
3163 | case Tuns64: | |
3164 | d = Token.toChars(TOK.uns64); | |
3165 | flags |= TFlags.integral | TFlags.unsigned; | |
3166 | break; | |
3167 | ||
3168 | case Tint128: | |
3169 | d = Token.toChars(TOK.int128); | |
3170 | flags |= TFlags.integral; | |
3171 | break; | |
3172 | ||
3173 | case Tuns128: | |
3174 | d = Token.toChars(TOK.uns128); | |
3175 | flags |= TFlags.integral | TFlags.unsigned; | |
3176 | break; | |
3177 | ||
3178 | case Tfloat64: | |
3179 | d = Token.toChars(TOK.float64); | |
3180 | flags |= TFlags.floating | TFlags.real_; | |
3181 | break; | |
3182 | ||
3183 | case Tfloat80: | |
3184 | d = Token.toChars(TOK.float80); | |
3185 | flags |= TFlags.floating | TFlags.real_; | |
3186 | break; | |
3187 | ||
3188 | case Timaginary32: | |
3189 | d = Token.toChars(TOK.imaginary32); | |
3190 | flags |= TFlags.floating | TFlags.imaginary; | |
3191 | break; | |
3192 | ||
3193 | case Timaginary64: | |
3194 | d = Token.toChars(TOK.imaginary64); | |
3195 | flags |= TFlags.floating | TFlags.imaginary; | |
3196 | break; | |
3197 | ||
3198 | case Timaginary80: | |
3199 | d = Token.toChars(TOK.imaginary80); | |
3200 | flags |= TFlags.floating | TFlags.imaginary; | |
3201 | break; | |
3202 | ||
3203 | case Tcomplex32: | |
3204 | d = Token.toChars(TOK.complex32); | |
3205 | flags |= TFlags.floating | TFlags.complex; | |
3206 | break; | |
3207 | ||
3208 | case Tcomplex64: | |
3209 | d = Token.toChars(TOK.complex64); | |
3210 | flags |= TFlags.floating | TFlags.complex; | |
3211 | break; | |
3212 | ||
3213 | case Tcomplex80: | |
3214 | d = Token.toChars(TOK.complex80); | |
3215 | flags |= TFlags.floating | TFlags.complex; | |
3216 | break; | |
3217 | ||
3218 | case Tbool: | |
3219 | d = "bool"; | |
3220 | flags |= TFlags.integral | TFlags.unsigned; | |
3221 | break; | |
3222 | ||
3223 | case Tchar: | |
3224 | d = Token.toChars(TOK.char_); | |
3225 | flags |= TFlags.integral | TFlags.unsigned; | |
3226 | break; | |
3227 | ||
3228 | case Twchar: | |
3229 | d = Token.toChars(TOK.wchar_); | |
3230 | flags |= TFlags.integral | TFlags.unsigned; | |
3231 | break; | |
3232 | ||
3233 | case Tdchar: | |
3234 | d = Token.toChars(TOK.dchar_); | |
3235 | flags |= TFlags.integral | TFlags.unsigned; | |
3236 | break; | |
3237 | ||
3238 | default: | |
3239 | assert(0); | |
3240 | } | |
3241 | this.dstring = d; | |
3242 | this.flags = flags; | |
3243 | merge(this); | |
3244 | } | |
3245 | ||
3246 | override const(char)* kind() const | |
3247 | { | |
3248 | return dstring; | |
3249 | } | |
3250 | ||
3251 | override TypeBasic syntaxCopy() | |
3252 | { | |
3253 | // No semantic analysis done on basic types, no need to copy | |
3254 | return this; | |
3255 | } | |
3256 | ||
610d7898 | 3257 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
3258 | { |
3259 | uint size; | |
3260 | //printf("TypeBasic::size()\n"); | |
3261 | switch (ty) | |
3262 | { | |
3263 | case Tint8: | |
3264 | case Tuns8: | |
3265 | size = 1; | |
3266 | break; | |
3267 | ||
3268 | case Tint16: | |
3269 | case Tuns16: | |
3270 | size = 2; | |
3271 | break; | |
3272 | ||
3273 | case Tint32: | |
3274 | case Tuns32: | |
3275 | case Tfloat32: | |
3276 | case Timaginary32: | |
3277 | size = 4; | |
3278 | break; | |
3279 | ||
3280 | case Tint64: | |
3281 | case Tuns64: | |
3282 | case Tfloat64: | |
3283 | case Timaginary64: | |
3284 | size = 8; | |
3285 | break; | |
3286 | ||
3287 | case Tfloat80: | |
3288 | case Timaginary80: | |
3289 | size = target.realsize; | |
3290 | break; | |
3291 | ||
3292 | case Tcomplex32: | |
3293 | size = 8; | |
3294 | break; | |
3295 | ||
3296 | case Tcomplex64: | |
3297 | case Tint128: | |
3298 | case Tuns128: | |
3299 | size = 16; | |
3300 | break; | |
3301 | ||
3302 | case Tcomplex80: | |
3303 | size = target.realsize * 2; | |
3304 | break; | |
3305 | ||
3306 | case Tvoid: | |
3307 | //size = Type::size(); // error message | |
3308 | size = 1; | |
3309 | break; | |
3310 | ||
3311 | case Tbool: | |
3312 | size = 1; | |
3313 | break; | |
3314 | ||
3315 | case Tchar: | |
3316 | size = 1; | |
3317 | break; | |
3318 | ||
3319 | case Twchar: | |
3320 | size = 2; | |
3321 | break; | |
3322 | ||
3323 | case Tdchar: | |
3324 | size = 4; | |
3325 | break; | |
3326 | ||
3327 | default: | |
3328 | assert(0); | |
3329 | } | |
3330 | //printf("TypeBasic::size() = %d\n", size); | |
3331 | return size; | |
3332 | } | |
3333 | ||
3334 | override uint alignsize() | |
3335 | { | |
3336 | return target.alignsize(this); | |
3337 | } | |
3338 | ||
3339 | override bool isintegral() | |
3340 | { | |
3341 | //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags); | |
3342 | return (flags & TFlags.integral) != 0; | |
3343 | } | |
3344 | ||
610d7898 | 3345 | override bool isfloating() |
5fee5ec3 IB |
3346 | { |
3347 | return (flags & TFlags.floating) != 0; | |
3348 | } | |
3349 | ||
610d7898 | 3350 | override bool isreal() |
5fee5ec3 IB |
3351 | { |
3352 | return (flags & TFlags.real_) != 0; | |
3353 | } | |
3354 | ||
610d7898 | 3355 | override bool isimaginary() |
5fee5ec3 IB |
3356 | { |
3357 | return (flags & TFlags.imaginary) != 0; | |
3358 | } | |
3359 | ||
610d7898 | 3360 | override bool iscomplex() |
5fee5ec3 IB |
3361 | { |
3362 | return (flags & TFlags.complex) != 0; | |
3363 | } | |
3364 | ||
610d7898 | 3365 | override bool isscalar() |
5fee5ec3 IB |
3366 | { |
3367 | return (flags & (TFlags.integral | TFlags.floating)) != 0; | |
3368 | } | |
3369 | ||
610d7898 | 3370 | override bool isunsigned() |
5fee5ec3 IB |
3371 | { |
3372 | return (flags & TFlags.unsigned) != 0; | |
3373 | } | |
3374 | ||
3375 | override MATCH implicitConvTo(Type to) | |
3376 | { | |
3377 | //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars()); | |
3378 | if (this == to) | |
3379 | return MATCH.exact; | |
3380 | ||
3381 | if (ty == to.ty) | |
3382 | { | |
3383 | if (mod == to.mod) | |
3384 | return MATCH.exact; | |
3385 | else if (MODimplicitConv(mod, to.mod)) | |
3386 | return MATCH.constant; | |
3387 | else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching | |
3388 | return MATCH.constant; | |
3389 | else | |
3390 | return MATCH.convert; | |
3391 | } | |
3392 | ||
3393 | if (ty == Tvoid || to.ty == Tvoid) | |
3394 | return MATCH.nomatch; | |
3395 | if (to.ty == Tbool) | |
3396 | return MATCH.nomatch; | |
3397 | ||
3398 | TypeBasic tob; | |
3399 | if (to.ty == Tvector && to.deco) | |
3400 | { | |
3401 | TypeVector tv = cast(TypeVector)to; | |
3402 | tob = tv.elementType(); | |
3403 | } | |
3404 | else if (auto te = to.isTypeEnum()) | |
3405 | { | |
3406 | EnumDeclaration ed = te.sym; | |
3407 | if (ed.isSpecial()) | |
3408 | { | |
3409 | /* Special enums that allow implicit conversions to them | |
3410 | * with a MATCH.convert | |
3411 | */ | |
3412 | tob = to.toBasetype().isTypeBasic(); | |
3413 | } | |
3414 | else | |
3415 | return MATCH.nomatch; | |
3416 | } | |
3417 | else | |
3418 | tob = to.isTypeBasic(); | |
3419 | if (!tob) | |
3420 | return MATCH.nomatch; | |
3421 | ||
3422 | if (flags & TFlags.integral) | |
3423 | { | |
3424 | // Disallow implicit conversion of integers to imaginary or complex | |
3425 | if (tob.flags & (TFlags.imaginary | TFlags.complex)) | |
3426 | return MATCH.nomatch; | |
3427 | ||
3428 | // If converting from integral to integral | |
3429 | if (tob.flags & TFlags.integral) | |
3430 | { | |
fbdaa581 IB |
3431 | const sz = size(Loc.initial); |
3432 | const tosz = tob.size(Loc.initial); | |
5fee5ec3 IB |
3433 | |
3434 | /* Can't convert to smaller size | |
3435 | */ | |
3436 | if (sz > tosz) | |
3437 | return MATCH.nomatch; | |
3438 | /* Can't change sign if same size | |
3439 | */ | |
3440 | //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned) | |
3441 | // return MATCH.nomatch; | |
3442 | } | |
3443 | } | |
3444 | else if (flags & TFlags.floating) | |
3445 | { | |
3446 | // Disallow implicit conversion of floating point to integer | |
3447 | if (tob.flags & TFlags.integral) | |
3448 | return MATCH.nomatch; | |
3449 | ||
3450 | assert(tob.flags & TFlags.floating || to.ty == Tvector); | |
3451 | ||
3452 | // Disallow implicit conversion from complex to non-complex | |
3453 | if (flags & TFlags.complex && !(tob.flags & TFlags.complex)) | |
3454 | return MATCH.nomatch; | |
3455 | ||
3456 | // Disallow implicit conversion of real or imaginary to complex | |
3457 | if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex) | |
3458 | return MATCH.nomatch; | |
3459 | ||
3460 | // Disallow implicit conversion to-from real and imaginary | |
3461 | if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary))) | |
3462 | return MATCH.nomatch; | |
3463 | } | |
3464 | return MATCH.convert; | |
3465 | } | |
3466 | ||
610d7898 | 3467 | override bool isZeroInit(const ref Loc loc) |
5fee5ec3 IB |
3468 | { |
3469 | switch (ty) | |
3470 | { | |
3471 | case Tchar: | |
3472 | case Twchar: | |
3473 | case Tdchar: | |
3474 | case Timaginary32: | |
3475 | case Timaginary64: | |
3476 | case Timaginary80: | |
3477 | case Tfloat32: | |
3478 | case Tfloat64: | |
3479 | case Tfloat80: | |
3480 | case Tcomplex32: | |
3481 | case Tcomplex64: | |
3482 | case Tcomplex80: | |
3483 | return false; // no | |
3484 | default: | |
3485 | return true; // yes | |
3486 | } | |
3487 | } | |
3488 | ||
3489 | // For eliminating dynamic_cast | |
3490 | override TypeBasic isTypeBasic() | |
3491 | { | |
3492 | return this; | |
3493 | } | |
3494 | ||
3495 | override void accept(Visitor v) | |
3496 | { | |
3497 | v.visit(this); | |
3498 | } | |
3499 | } | |
3500 | ||
3501 | /*********************************************************** | |
3502 | * The basetype must be one of: | |
3503 | * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2] | |
3504 | * For AVX: | |
3505 | * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4] | |
3506 | */ | |
3507 | extern (C++) final class TypeVector : Type | |
3508 | { | |
3509 | Type basetype; | |
3510 | ||
3511 | extern (D) this(Type basetype) | |
3512 | { | |
3513 | super(Tvector); | |
3514 | this.basetype = basetype; | |
3515 | } | |
3516 | ||
3517 | static TypeVector create(Type basetype) | |
3518 | { | |
3519 | return new TypeVector(basetype); | |
3520 | } | |
3521 | ||
3522 | override const(char)* kind() const | |
3523 | { | |
3524 | return "vector"; | |
3525 | } | |
3526 | ||
3527 | override TypeVector syntaxCopy() | |
3528 | { | |
3529 | return new TypeVector(basetype.syntaxCopy()); | |
3530 | } | |
3531 | ||
fbdaa581 | 3532 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
3533 | { |
3534 | return basetype.size(); | |
3535 | } | |
3536 | ||
3537 | override uint alignsize() | |
3538 | { | |
3539 | return cast(uint)basetype.size(); | |
3540 | } | |
3541 | ||
3542 | override bool isintegral() | |
3543 | { | |
3544 | //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags); | |
3545 | return basetype.nextOf().isintegral(); | |
3546 | } | |
3547 | ||
3548 | override bool isfloating() | |
3549 | { | |
3550 | return basetype.nextOf().isfloating(); | |
3551 | } | |
3552 | ||
3553 | override bool isscalar() | |
3554 | { | |
3555 | return basetype.nextOf().isscalar(); | |
3556 | } | |
3557 | ||
3558 | override bool isunsigned() | |
3559 | { | |
3560 | return basetype.nextOf().isunsigned(); | |
3561 | } | |
3562 | ||
610d7898 | 3563 | override bool isBoolean() |
5fee5ec3 IB |
3564 | { |
3565 | return false; | |
3566 | } | |
3567 | ||
3568 | override MATCH implicitConvTo(Type to) | |
3569 | { | |
3570 | //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars()); | |
3571 | if (this == to) | |
3572 | return MATCH.exact; | |
3573 | if (to.ty != Tvector) | |
3574 | return MATCH.nomatch; | |
3575 | ||
3576 | TypeVector tv = cast(TypeVector)to; | |
3577 | assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray); | |
3578 | ||
3579 | // Can't convert to a vector which has different size. | |
3580 | if (basetype.size() != tv.basetype.size()) | |
3581 | return MATCH.nomatch; | |
3582 | ||
3583 | // Allow conversion to void[] | |
3584 | if (tv.basetype.nextOf().ty == Tvoid) | |
3585 | return MATCH.convert; | |
3586 | ||
3587 | // Otherwise implicitly convertible only if basetypes are. | |
3588 | return basetype.implicitConvTo(tv.basetype); | |
3589 | } | |
3590 | ||
3591 | override Expression defaultInitLiteral(const ref Loc loc) | |
3592 | { | |
3593 | //printf("TypeVector::defaultInitLiteral()\n"); | |
3594 | assert(basetype.ty == Tsarray); | |
3595 | Expression e = basetype.defaultInitLiteral(loc); | |
3596 | auto ve = new VectorExp(loc, e, this); | |
3597 | ve.type = this; | |
3598 | ve.dim = cast(int)(basetype.size(loc) / elementType().size(loc)); | |
3599 | return ve; | |
3600 | } | |
3601 | ||
3602 | TypeBasic elementType() | |
3603 | { | |
3604 | assert(basetype.ty == Tsarray); | |
3605 | TypeSArray t = cast(TypeSArray)basetype; | |
3606 | TypeBasic tb = t.nextOf().isTypeBasic(); | |
3607 | assert(tb); | |
3608 | return tb; | |
3609 | } | |
3610 | ||
3611 | override bool isZeroInit(const ref Loc loc) | |
3612 | { | |
3613 | return basetype.isZeroInit(loc); | |
3614 | } | |
3615 | ||
3616 | override void accept(Visitor v) | |
3617 | { | |
3618 | v.visit(this); | |
3619 | } | |
3620 | } | |
3621 | ||
3622 | /*********************************************************** | |
3623 | */ | |
3624 | extern (C++) abstract class TypeArray : TypeNext | |
3625 | { | |
3626 | final extern (D) this(TY ty, Type next) | |
3627 | { | |
3628 | super(ty, next); | |
3629 | } | |
3630 | ||
3631 | override void accept(Visitor v) | |
3632 | { | |
3633 | v.visit(this); | |
3634 | } | |
3635 | } | |
3636 | ||
3637 | /*********************************************************** | |
3638 | * Static array, one with a fixed dimension | |
3639 | */ | |
3640 | extern (C++) final class TypeSArray : TypeArray | |
3641 | { | |
3642 | Expression dim; | |
3643 | ||
3644 | extern (D) this(Type t, Expression dim) | |
3645 | { | |
3646 | super(Tsarray, t); | |
3647 | //printf("TypeSArray(%s)\n", dim.toChars()); | |
3648 | this.dim = dim; | |
3649 | } | |
3650 | ||
0fb57034 IB |
3651 | extern (D) this(Type t) // for incomplete type |
3652 | { | |
3653 | super(Tsarray, t); | |
3654 | //printf("TypeSArray()\n"); | |
3655 | this.dim = new IntegerExp(0); | |
3656 | } | |
3657 | ||
5fee5ec3 IB |
3658 | override const(char)* kind() const |
3659 | { | |
3660 | return "sarray"; | |
3661 | } | |
3662 | ||
3663 | override TypeSArray syntaxCopy() | |
3664 | { | |
3665 | Type t = next.syntaxCopy(); | |
3666 | Expression e = dim.syntaxCopy(); | |
3667 | auto result = new TypeSArray(t, e); | |
3668 | result.mod = mod; | |
3669 | return result; | |
3670 | } | |
3671 | ||
0fb57034 IB |
3672 | /*** |
3673 | * C11 6.7.6.2-4 incomplete array type | |
3674 | * Returns: true if incomplete type | |
3675 | */ | |
3676 | bool isIncomplete() | |
3677 | { | |
3678 | return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0; | |
3679 | } | |
3680 | ||
fbdaa581 | 3681 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
3682 | { |
3683 | //printf("TypeSArray::size()\n"); | |
3684 | const n = numberOfElems(loc); | |
3685 | const elemsize = baseElemOf().size(loc); | |
3686 | bool overflow = false; | |
3687 | const sz = mulu(n, elemsize, overflow); | |
3688 | if (overflow || sz >= uint.max) | |
3689 | { | |
3690 | if (elemsize != SIZE_INVALID && n != uint.max) | |
3691 | error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz); | |
3692 | return SIZE_INVALID; | |
3693 | } | |
3694 | return sz; | |
3695 | } | |
3696 | ||
3697 | override uint alignsize() | |
3698 | { | |
3699 | return next.alignsize(); | |
3700 | } | |
3701 | ||
3702 | override bool isString() | |
3703 | { | |
3704 | TY nty = next.toBasetype().ty; | |
3705 | return nty.isSomeChar; | |
3706 | } | |
3707 | ||
3708 | override bool isZeroInit(const ref Loc loc) | |
3709 | { | |
3710 | return next.isZeroInit(loc); | |
3711 | } | |
3712 | ||
3713 | override structalign_t alignment() | |
3714 | { | |
3715 | return next.alignment(); | |
3716 | } | |
3717 | ||
3718 | override MATCH constConv(Type to) | |
3719 | { | |
3720 | if (auto tsa = to.isTypeSArray()) | |
3721 | { | |
3722 | if (!dim.equals(tsa.dim)) | |
3723 | return MATCH.nomatch; | |
3724 | } | |
3725 | return TypeNext.constConv(to); | |
3726 | } | |
3727 | ||
3728 | override MATCH implicitConvTo(Type to) | |
3729 | { | |
3730 | //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); | |
3731 | if (auto ta = to.isTypeDArray()) | |
3732 | { | |
3733 | if (!MODimplicitConv(next.mod, ta.next.mod)) | |
3734 | return MATCH.nomatch; | |
3735 | ||
3736 | /* Allow conversion to void[] | |
3737 | */ | |
3738 | if (ta.next.ty == Tvoid) | |
3739 | { | |
3740 | return MATCH.convert; | |
3741 | } | |
3742 | ||
3743 | MATCH m = next.constConv(ta.next); | |
3744 | if (m > MATCH.nomatch) | |
3745 | { | |
3746 | return MATCH.convert; | |
3747 | } | |
3748 | return MATCH.nomatch; | |
3749 | } | |
3750 | if (auto tsa = to.isTypeSArray()) | |
3751 | { | |
3752 | if (this == to) | |
3753 | return MATCH.exact; | |
3754 | ||
3755 | if (dim.equals(tsa.dim)) | |
3756 | { | |
3757 | MATCH m = next.implicitConvTo(tsa.next); | |
3758 | ||
3759 | /* Allow conversion to non-interface base class. | |
3760 | */ | |
3761 | if (m == MATCH.convert && | |
3762 | next.ty == Tclass) | |
3763 | { | |
3764 | if (auto toc = tsa.next.isTypeClass) | |
3765 | { | |
3766 | if (!toc.sym.isInterfaceDeclaration) | |
3767 | return MATCH.convert; | |
3768 | } | |
3769 | } | |
3770 | ||
3771 | /* Since static arrays are value types, allow | |
3772 | * conversions from const elements to non-const | |
3773 | * ones, just like we allow conversion from const int | |
3774 | * to int. | |
3775 | */ | |
3776 | if (m >= MATCH.constant) | |
3777 | { | |
3778 | if (mod != to.mod) | |
3779 | m = MATCH.constant; | |
3780 | return m; | |
3781 | } | |
3782 | } | |
3783 | } | |
3784 | return MATCH.nomatch; | |
3785 | } | |
3786 | ||
3787 | override Expression defaultInitLiteral(const ref Loc loc) | |
3788 | { | |
3789 | static if (LOGDEFAULTINIT) | |
3790 | { | |
3791 | printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars()); | |
3792 | } | |
3793 | size_t d = cast(size_t)dim.toInteger(); | |
3794 | Expression elementinit; | |
3795 | if (next.ty == Tvoid) | |
3796 | elementinit = tuns8.defaultInitLiteral(loc); | |
3797 | else | |
3798 | elementinit = next.defaultInitLiteral(loc); | |
3799 | auto elements = new Expressions(d); | |
3800 | foreach (ref e; *elements) | |
3801 | e = null; | |
3802 | auto ae = new ArrayLiteralExp(Loc.initial, this, elementinit, elements); | |
3803 | return ae; | |
3804 | } | |
3805 | ||
3806 | override bool hasPointers() | |
3807 | { | |
3808 | /* Don't want to do this, because: | |
3809 | * struct S { T* array[0]; } | |
3810 | * may be a variable length struct. | |
3811 | */ | |
3812 | //if (dim.toInteger() == 0) | |
3813 | // return false; | |
3814 | ||
3815 | if (next.ty == Tvoid) | |
3816 | { | |
3817 | // Arrays of void contain arbitrary data, which may include pointers | |
3818 | return true; | |
3819 | } | |
3820 | else | |
3821 | return next.hasPointers(); | |
3822 | } | |
3823 | ||
3824 | override bool hasInvariant() | |
3825 | { | |
3826 | return next.hasInvariant(); | |
3827 | } | |
3828 | ||
3829 | override bool needsDestruction() | |
3830 | { | |
3831 | return next.needsDestruction(); | |
3832 | } | |
3833 | ||
3834 | override bool needsCopyOrPostblit() | |
3835 | { | |
3836 | return next.needsCopyOrPostblit(); | |
3837 | } | |
3838 | ||
3839 | /********************************* | |
3840 | * | |
3841 | */ | |
3842 | override bool needsNested() | |
3843 | { | |
3844 | return next.needsNested(); | |
3845 | } | |
3846 | ||
3847 | override void accept(Visitor v) | |
3848 | { | |
3849 | v.visit(this); | |
3850 | } | |
3851 | } | |
3852 | ||
3853 | /*********************************************************** | |
3854 | * Dynamic array, no dimension | |
3855 | */ | |
3856 | extern (C++) final class TypeDArray : TypeArray | |
3857 | { | |
3858 | extern (D) this(Type t) | |
3859 | { | |
3860 | super(Tarray, t); | |
3861 | //printf("TypeDArray(t = %p)\n", t); | |
3862 | } | |
3863 | ||
3864 | override const(char)* kind() const | |
3865 | { | |
3866 | return "darray"; | |
3867 | } | |
3868 | ||
3869 | override TypeDArray syntaxCopy() | |
3870 | { | |
3871 | Type t = next.syntaxCopy(); | |
3872 | if (t == next) | |
3873 | return this; | |
3874 | ||
3875 | auto result = new TypeDArray(t); | |
3876 | result.mod = mod; | |
3877 | return result; | |
3878 | } | |
3879 | ||
610d7898 | 3880 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
3881 | { |
3882 | //printf("TypeDArray::size()\n"); | |
3883 | return target.ptrsize * 2; | |
3884 | } | |
3885 | ||
610d7898 | 3886 | override uint alignsize() |
5fee5ec3 IB |
3887 | { |
3888 | // A DArray consists of two ptr-sized values, so align it on pointer size | |
3889 | // boundary | |
3890 | return target.ptrsize; | |
3891 | } | |
3892 | ||
3893 | override bool isString() | |
3894 | { | |
3895 | TY nty = next.toBasetype().ty; | |
3896 | return nty.isSomeChar; | |
3897 | } | |
3898 | ||
610d7898 | 3899 | override bool isZeroInit(const ref Loc loc) |
5fee5ec3 IB |
3900 | { |
3901 | return true; | |
3902 | } | |
3903 | ||
610d7898 | 3904 | override bool isBoolean() |
5fee5ec3 IB |
3905 | { |
3906 | return true; | |
3907 | } | |
3908 | ||
3909 | override MATCH implicitConvTo(Type to) | |
3910 | { | |
3911 | //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); | |
3912 | if (equals(to)) | |
3913 | return MATCH.exact; | |
3914 | ||
3915 | if (auto ta = to.isTypeDArray()) | |
3916 | { | |
3917 | if (!MODimplicitConv(next.mod, ta.next.mod)) | |
3918 | return MATCH.nomatch; // not const-compatible | |
3919 | ||
3920 | /* Allow conversion to void[] | |
3921 | */ | |
3922 | if (next.ty != Tvoid && ta.next.ty == Tvoid) | |
3923 | { | |
3924 | return MATCH.convert; | |
3925 | } | |
3926 | ||
3927 | MATCH m = next.constConv(ta.next); | |
3928 | if (m > MATCH.nomatch) | |
3929 | { | |
3930 | if (m == MATCH.exact && mod != to.mod) | |
3931 | m = MATCH.constant; | |
3932 | return m; | |
3933 | } | |
3934 | } | |
3935 | return Type.implicitConvTo(to); | |
3936 | } | |
3937 | ||
610d7898 | 3938 | override bool hasPointers() |
5fee5ec3 IB |
3939 | { |
3940 | return true; | |
3941 | } | |
3942 | ||
3943 | override void accept(Visitor v) | |
3944 | { | |
3945 | v.visit(this); | |
3946 | } | |
3947 | } | |
3948 | ||
3949 | /*********************************************************** | |
3950 | */ | |
3951 | extern (C++) final class TypeAArray : TypeArray | |
3952 | { | |
3953 | Type index; // key type | |
3954 | Loc loc; | |
3955 | ||
3956 | extern (D) this(Type t, Type index) | |
3957 | { | |
3958 | super(Taarray, t); | |
3959 | this.index = index; | |
3960 | } | |
3961 | ||
3962 | static TypeAArray create(Type t, Type index) | |
3963 | { | |
3964 | return new TypeAArray(t, index); | |
3965 | } | |
3966 | ||
3967 | override const(char)* kind() const | |
3968 | { | |
3969 | return "aarray"; | |
3970 | } | |
3971 | ||
3972 | override TypeAArray syntaxCopy() | |
3973 | { | |
3974 | Type t = next.syntaxCopy(); | |
3975 | Type ti = index.syntaxCopy(); | |
3976 | if (t == next && ti == index) | |
3977 | return this; | |
3978 | ||
3979 | auto result = new TypeAArray(t, ti); | |
3980 | result.mod = mod; | |
3981 | return result; | |
3982 | } | |
3983 | ||
610d7898 | 3984 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
3985 | { |
3986 | return target.ptrsize; | |
3987 | } | |
3988 | ||
610d7898 | 3989 | override bool isZeroInit(const ref Loc loc) |
5fee5ec3 IB |
3990 | { |
3991 | return true; | |
3992 | } | |
3993 | ||
610d7898 | 3994 | override bool isBoolean() |
5fee5ec3 IB |
3995 | { |
3996 | return true; | |
3997 | } | |
3998 | ||
610d7898 | 3999 | override bool hasPointers() |
5fee5ec3 IB |
4000 | { |
4001 | return true; | |
4002 | } | |
4003 | ||
4004 | override MATCH implicitConvTo(Type to) | |
4005 | { | |
4006 | //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); | |
4007 | if (equals(to)) | |
4008 | return MATCH.exact; | |
4009 | ||
4010 | if (auto ta = to.isTypeAArray()) | |
4011 | { | |
4012 | if (!MODimplicitConv(next.mod, ta.next.mod)) | |
4013 | return MATCH.nomatch; // not const-compatible | |
4014 | ||
4015 | if (!MODimplicitConv(index.mod, ta.index.mod)) | |
4016 | return MATCH.nomatch; // not const-compatible | |
4017 | ||
4018 | MATCH m = next.constConv(ta.next); | |
4019 | MATCH mi = index.constConv(ta.index); | |
4020 | if (m > MATCH.nomatch && mi > MATCH.nomatch) | |
4021 | { | |
4022 | return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch; | |
4023 | } | |
4024 | } | |
4025 | return Type.implicitConvTo(to); | |
4026 | } | |
4027 | ||
4028 | override MATCH constConv(Type to) | |
4029 | { | |
4030 | if (auto taa = to.isTypeAArray()) | |
4031 | { | |
4032 | MATCH mindex = index.constConv(taa.index); | |
4033 | MATCH mkey = next.constConv(taa.next); | |
4034 | // Pick the worst match | |
4035 | return mkey < mindex ? mkey : mindex; | |
4036 | } | |
4037 | return Type.constConv(to); | |
4038 | } | |
4039 | ||
4040 | override void accept(Visitor v) | |
4041 | { | |
4042 | v.visit(this); | |
4043 | } | |
4044 | } | |
4045 | ||
4046 | /*********************************************************** | |
4047 | */ | |
4048 | extern (C++) final class TypePointer : TypeNext | |
4049 | { | |
4050 | extern (D) this(Type t) | |
4051 | { | |
4052 | super(Tpointer, t); | |
4053 | } | |
4054 | ||
4055 | static TypePointer create(Type t) | |
4056 | { | |
4057 | return new TypePointer(t); | |
4058 | } | |
4059 | ||
4060 | override const(char)* kind() const | |
4061 | { | |
4062 | return "pointer"; | |
4063 | } | |
4064 | ||
4065 | override TypePointer syntaxCopy() | |
4066 | { | |
4067 | Type t = next.syntaxCopy(); | |
4068 | if (t == next) | |
4069 | return this; | |
4070 | ||
4071 | auto result = new TypePointer(t); | |
4072 | result.mod = mod; | |
4073 | return result; | |
4074 | } | |
4075 | ||
610d7898 | 4076 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
4077 | { |
4078 | return target.ptrsize; | |
4079 | } | |
4080 | ||
4081 | override MATCH implicitConvTo(Type to) | |
4082 | { | |
4083 | //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars()); | |
4084 | if (equals(to)) | |
4085 | return MATCH.exact; | |
4086 | ||
0fb57034 IB |
4087 | // Only convert between pointers |
4088 | auto tp = to.isTypePointer(); | |
4089 | if (!tp) | |
5fee5ec3 | 4090 | return MATCH.nomatch; |
0fb57034 IB |
4091 | |
4092 | assert(this.next); | |
4093 | assert(tp.next); | |
4094 | ||
4095 | // Conversion to void* | |
4096 | if (tp.next.ty == Tvoid) | |
5fee5ec3 | 4097 | { |
0fb57034 IB |
4098 | // Function pointer conversion doesn't check constness? |
4099 | if (this.next.ty == Tfunction) | |
4100 | return MATCH.convert; | |
5fee5ec3 IB |
4101 | |
4102 | if (!MODimplicitConv(next.mod, tp.next.mod)) | |
4103 | return MATCH.nomatch; // not const-compatible | |
4104 | ||
0fb57034 | 4105 | return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert; |
5fee5ec3 | 4106 | } |
0fb57034 IB |
4107 | |
4108 | // Conversion between function pointers | |
4109 | if (auto thisTf = this.next.isTypeFunction()) | |
4110 | return thisTf.implicitPointerConv(tp.next); | |
4111 | ||
4112 | // Default, no implicit conversion between the pointer targets | |
4113 | MATCH m = next.constConv(tp.next); | |
4114 | ||
4115 | if (m == MATCH.exact && mod != to.mod) | |
4116 | m = MATCH.constant; | |
4117 | return m; | |
5fee5ec3 IB |
4118 | } |
4119 | ||
4120 | override MATCH constConv(Type to) | |
4121 | { | |
4122 | if (next.ty == Tfunction) | |
4123 | { | |
4124 | if (to.nextOf() && next.equals((cast(TypeNext)to).next)) | |
4125 | return Type.constConv(to); | |
4126 | else | |
4127 | return MATCH.nomatch; | |
4128 | } | |
4129 | return TypeNext.constConv(to); | |
4130 | } | |
4131 | ||
610d7898 | 4132 | override bool isscalar() |
5fee5ec3 IB |
4133 | { |
4134 | return true; | |
4135 | } | |
4136 | ||
610d7898 | 4137 | override bool isZeroInit(const ref Loc loc) |
5fee5ec3 IB |
4138 | { |
4139 | return true; | |
4140 | } | |
4141 | ||
610d7898 | 4142 | override bool hasPointers() |
5fee5ec3 IB |
4143 | { |
4144 | return true; | |
4145 | } | |
4146 | ||
4147 | override void accept(Visitor v) | |
4148 | { | |
4149 | v.visit(this); | |
4150 | } | |
4151 | } | |
4152 | ||
4153 | /*********************************************************** | |
4154 | */ | |
4155 | extern (C++) final class TypeReference : TypeNext | |
4156 | { | |
4157 | extern (D) this(Type t) | |
4158 | { | |
4159 | super(Treference, t); | |
4160 | // BUG: what about references to static arrays? | |
4161 | } | |
4162 | ||
4163 | override const(char)* kind() const | |
4164 | { | |
4165 | return "reference"; | |
4166 | } | |
4167 | ||
4168 | override TypeReference syntaxCopy() | |
4169 | { | |
4170 | Type t = next.syntaxCopy(); | |
4171 | if (t == next) | |
4172 | return this; | |
4173 | ||
4174 | auto result = new TypeReference(t); | |
4175 | result.mod = mod; | |
4176 | return result; | |
4177 | } | |
4178 | ||
610d7898 | 4179 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
4180 | { |
4181 | return target.ptrsize; | |
4182 | } | |
4183 | ||
610d7898 | 4184 | override bool isZeroInit(const ref Loc loc) |
5fee5ec3 IB |
4185 | { |
4186 | return true; | |
4187 | } | |
4188 | ||
4189 | override void accept(Visitor v) | |
4190 | { | |
4191 | v.visit(this); | |
4192 | } | |
4193 | } | |
4194 | ||
4195 | enum RET : int | |
4196 | { | |
4197 | regs = 1, // returned in registers | |
4198 | stack = 2, // returned on stack | |
4199 | } | |
4200 | ||
4201 | enum TRUSTformat : int | |
4202 | { | |
4203 | TRUSTformatDefault, // do not emit @system when trust == TRUST.default_ | |
4204 | TRUSTformatSystem, // emit @system when trust == TRUST.default_ | |
4205 | } | |
4206 | ||
4207 | alias TRUSTformatDefault = TRUSTformat.TRUSTformatDefault; | |
4208 | alias TRUSTformatSystem = TRUSTformat.TRUSTformatSystem; | |
4209 | ||
4210 | /*********************************************************** | |
4211 | */ | |
4212 | extern (C++) final class TypeFunction : TypeNext | |
4213 | { | |
4214 | // .next is the return type | |
4215 | ||
4216 | ParameterList parameterList; // function parameters | |
4217 | ||
235d5a96 IB |
4218 | // These flags can be accessed like `bool` properties, |
4219 | // getters and setters are generated for them | |
31350635 IB |
4220 | private extern (D) static struct BitFields |
4221 | { | |
4222 | bool isnothrow; /// nothrow | |
4223 | bool isnogc; /// is @nogc | |
4224 | bool isproperty; /// can be called without parentheses | |
4225 | bool isref; /// returns a reference | |
4226 | bool isreturn; /// 'this' is returned by ref | |
4227 | bool isScopeQual; /// 'this' is scope | |
4228 | bool isreturninferred; /// 'this' is return from inference | |
4229 | bool isscopeinferred; /// 'this' is scope from inference | |
4230 | bool islive; /// is @live | |
4231 | bool incomplete; /// return type or default arguments removed | |
4232 | bool isInOutParam; /// inout on the parameters | |
4233 | bool isInOutQual; /// inout on the qualifier | |
4234 | bool isctor; /// the function is a constructor | |
4235 | bool isreturnscope; /// `this` is returned by value | |
4236 | } | |
4237 | ||
4238 | import dmd.common.bitfields : generateBitFields; | |
4239 | mixin(generateBitFields!(BitFields, ushort)); | |
5fee5ec3 IB |
4240 | |
4241 | LINK linkage; // calling convention | |
5fee5ec3 IB |
4242 | TRUST trust; // level of trust |
4243 | PURE purity = PURE.impure; | |
4244 | byte inuse; | |
4245 | Expressions* fargs; // function arguments | |
4246 | ||
4247 | extern (D) this(ParameterList pl, Type treturn, LINK linkage, StorageClass stc = 0) | |
4248 | { | |
4249 | super(Tfunction, treturn); | |
4250 | //if (!treturn) *(char*)0=0; | |
4251 | // assert(treturn); | |
4252 | assert(VarArg.none <= pl.varargs && pl.varargs <= VarArg.typesafe); | |
4253 | this.parameterList = pl; | |
4254 | this.linkage = linkage; | |
4255 | ||
4256 | if (stc & STC.pure_) | |
4257 | this.purity = PURE.fwdref; | |
4258 | if (stc & STC.nothrow_) | |
4259 | this.isnothrow = true; | |
4260 | if (stc & STC.nogc) | |
4261 | this.isnogc = true; | |
4262 | if (stc & STC.property) | |
4263 | this.isproperty = true; | |
4264 | if (stc & STC.live) | |
4265 | this.islive = true; | |
4266 | ||
4267 | if (stc & STC.ref_) | |
4268 | this.isref = true; | |
4269 | if (stc & STC.return_) | |
4270 | this.isreturn = true; | |
7e287503 IB |
4271 | if (stc & STC.returnScope) |
4272 | this.isreturnscope = true; | |
5fee5ec3 IB |
4273 | if (stc & STC.returninferred) |
4274 | this.isreturninferred = true; | |
4275 | if (stc & STC.scope_) | |
4276 | this.isScopeQual = true; | |
4277 | if (stc & STC.scopeinferred) | |
4278 | this.isscopeinferred = true; | |
4279 | ||
4280 | this.trust = TRUST.default_; | |
4281 | if (stc & STC.safe) | |
4282 | this.trust = TRUST.safe; | |
6384eff5 | 4283 | else if (stc & STC.system) |
5fee5ec3 | 4284 | this.trust = TRUST.system; |
6384eff5 | 4285 | else if (stc & STC.trusted) |
5fee5ec3 IB |
4286 | this.trust = TRUST.trusted; |
4287 | } | |
4288 | ||
4289 | static TypeFunction create(Parameters* parameters, Type treturn, ubyte varargs, LINK linkage, StorageClass stc = 0) | |
4290 | { | |
4291 | return new TypeFunction(ParameterList(parameters, cast(VarArg)varargs), treturn, linkage, stc); | |
4292 | } | |
4293 | ||
4294 | override const(char)* kind() const | |
4295 | { | |
4296 | return "function"; | |
4297 | } | |
4298 | ||
4299 | override TypeFunction syntaxCopy() | |
4300 | { | |
4301 | Type treturn = next ? next.syntaxCopy() : null; | |
4302 | auto t = new TypeFunction(parameterList.syntaxCopy(), treturn, linkage); | |
4303 | t.mod = mod; | |
4304 | t.isnothrow = isnothrow; | |
4305 | t.isnogc = isnogc; | |
4306 | t.islive = islive; | |
4307 | t.purity = purity; | |
4308 | t.isproperty = isproperty; | |
4309 | t.isref = isref; | |
4310 | t.isreturn = isreturn; | |
7e287503 | 4311 | t.isreturnscope = isreturnscope; |
5fee5ec3 IB |
4312 | t.isScopeQual = isScopeQual; |
4313 | t.isreturninferred = isreturninferred; | |
4314 | t.isscopeinferred = isscopeinferred; | |
4315 | t.isInOutParam = isInOutParam; | |
4316 | t.isInOutQual = isInOutQual; | |
4317 | t.trust = trust; | |
4318 | t.fargs = fargs; | |
4319 | t.isctor = isctor; | |
4320 | return t; | |
4321 | } | |
4322 | ||
4323 | /******************************************** | |
4324 | * Set 'purity' field of 'this'. | |
4325 | * Do this lazily, as the parameter types might be forward referenced. | |
4326 | */ | |
4327 | void purityLevel() | |
4328 | { | |
4329 | TypeFunction tf = this; | |
4330 | if (tf.purity != PURE.fwdref) | |
4331 | return; | |
4332 | ||
d7569187 | 4333 | purity = PURE.const_; // assume strong until something weakens it |
5fee5ec3 IB |
4334 | |
4335 | /* Evaluate what kind of purity based on the modifiers for the parameters | |
4336 | */ | |
d7569187 | 4337 | foreach (i, fparam; tf.parameterList) |
5fee5ec3 IB |
4338 | { |
4339 | Type t = fparam.type; | |
4340 | if (!t) | |
4341 | continue; | |
4342 | ||
4343 | if (fparam.storageClass & (STC.lazy_ | STC.out_)) | |
4344 | { | |
4345 | purity = PURE.weak; | |
4346 | break; | |
4347 | } | |
d7569187 IB |
4348 | const pref = (fparam.storageClass & STC.ref_) != 0; |
4349 | if (mutabilityOfType(pref, t) == 0) | |
4350 | purity = PURE.weak; | |
5fee5ec3 IB |
4351 | } |
4352 | ||
5fee5ec3 IB |
4353 | tf.purity = purity; |
4354 | } | |
4355 | ||
4356 | /******************************************** | |
4357 | * Return true if there are lazy parameters. | |
4358 | */ | |
4359 | bool hasLazyParameters() | |
4360 | { | |
4361 | foreach (i, fparam; parameterList) | |
4362 | { | |
ec486b73 | 4363 | if (fparam.isLazy()) |
5fee5ec3 IB |
4364 | return true; |
4365 | } | |
4366 | return false; | |
4367 | } | |
4368 | ||
4369 | /******************************* | |
4370 | * Check for `extern (D) U func(T t, ...)` variadic function type, | |
4371 | * which has `_arguments[]` added as the first argument. | |
4372 | * Returns: | |
4373 | * true if D-style variadic | |
4374 | */ | |
4375 | bool isDstyleVariadic() const pure nothrow | |
4376 | { | |
4377 | return linkage == LINK.d && parameterList.varargs == VarArg.variadic; | |
4378 | } | |
4379 | ||
5fee5ec3 IB |
4380 | /************************************ |
4381 | * Take the specified storage class for p, | |
4382 | * and use the function signature to infer whether | |
4383 | * STC.scope_ and STC.return_ should be OR'd in. | |
4384 | * (This will not affect the name mangling.) | |
4385 | * Params: | |
4386 | * tthis = type of `this` parameter, null if none | |
4387 | * p = parameter to this function | |
4388 | * Returns: | |
4389 | * storage class with STC.scope_ or STC.return_ OR'd in | |
4390 | */ | |
4391 | StorageClass parameterStorageClass(Type tthis, Parameter p) | |
4392 | { | |
4393 | //printf("parameterStorageClass(p: %s)\n", p.toChars()); | |
4394 | auto stc = p.storageClass; | |
5fee5ec3 IB |
4395 | |
4396 | // When the preview switch is enable, `in` parameters are `scope` | |
4397 | if (stc & STC.in_ && global.params.previewIn) | |
4398 | return stc | STC.scope_; | |
4399 | ||
4400 | if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) | |
4401 | return stc; | |
4402 | ||
4403 | /* If haven't inferred the return type yet, can't infer storage classes | |
4404 | */ | |
ae56e2da | 4405 | if (!nextOf() || !isnothrow()) |
5fee5ec3 IB |
4406 | return stc; |
4407 | ||
4408 | purityLevel(); | |
4409 | ||
b7a586be IB |
4410 | static bool mayHavePointers(Type t) |
4411 | { | |
4412 | if (auto ts = t.isTypeStruct()) | |
4413 | { | |
4414 | auto sym = ts.sym; | |
4415 | if (sym.members && !sym.determineFields() && sym.type != Type.terror) | |
4416 | // struct is forward referenced, so "may have" pointers | |
4417 | return true; | |
4418 | } | |
4419 | return t.hasPointers(); | |
4420 | } | |
4421 | ||
5fee5ec3 IB |
4422 | // See if p can escape via any of the other parameters |
4423 | if (purity == PURE.weak) | |
4424 | { | |
4425 | // Check escaping through parameters | |
4426 | foreach (i, fparam; parameterList) | |
4427 | { | |
5fee5ec3 IB |
4428 | Type t = fparam.type; |
4429 | if (!t) | |
4430 | continue; | |
b7a586be | 4431 | t = t.baseElemOf(); // punch thru static arrays |
5fee5ec3 IB |
4432 | if (t.isMutable() && t.hasPointers()) |
4433 | { | |
b7a586be IB |
4434 | if (fparam.isReference() && fparam != p) |
4435 | return stc; | |
4436 | ||
4437 | if (t.ty == Tdelegate) | |
4438 | return stc; // could escape thru delegate | |
4439 | ||
4440 | if (t.ty == Tclass) | |
4441 | return stc; | |
4442 | ||
4443 | /* if t is a pointer to mutable pointer | |
4444 | */ | |
4445 | if (auto tn = t.nextOf()) | |
5fee5ec3 | 4446 | { |
b7a586be IB |
4447 | if (tn.isMutable() && mayHavePointers(tn)) |
4448 | return stc; // escape through pointers | |
5fee5ec3 | 4449 | } |
5fee5ec3 IB |
4450 | } |
4451 | } | |
4452 | ||
4453 | // Check escaping through `this` | |
4454 | if (tthis && tthis.isMutable()) | |
4455 | { | |
208fbc77 | 4456 | foreach (VarDeclaration v; isAggregate(tthis).fields) |
5fee5ec3 IB |
4457 | { |
4458 | if (v.hasPointers()) | |
4459 | return stc; | |
4460 | } | |
4461 | } | |
4462 | } | |
4463 | ||
ae56e2da IB |
4464 | // Check escaping through return value |
4465 | Type tret = nextOf().toBasetype(); | |
4466 | if (isref || tret.hasPointers()) | |
5eb9927a | 4467 | { |
ae56e2da | 4468 | return stc | STC.scope_ | STC.return_ | STC.returnScope; |
5eb9927a | 4469 | } |
5fee5ec3 | 4470 | else |
ae56e2da | 4471 | return stc | STC.scope_; |
5fee5ec3 IB |
4472 | } |
4473 | ||
4474 | override Type addStorageClass(StorageClass stc) | |
4475 | { | |
4476 | //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0); | |
4477 | TypeFunction t = Type.addStorageClass(stc).toTypeFunction(); | |
4478 | if ((stc & STC.pure_ && !t.purity) || | |
4479 | (stc & STC.nothrow_ && !t.isnothrow) || | |
4480 | (stc & STC.nogc && !t.isnogc) || | |
4481 | (stc & STC.scope_ && !t.isScopeQual) || | |
4482 | (stc & STC.safe && t.trust < TRUST.trusted)) | |
4483 | { | |
4484 | // Klunky to change these | |
4485 | auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0); | |
4486 | tf.mod = t.mod; | |
4487 | tf.fargs = fargs; | |
4488 | tf.purity = t.purity; | |
4489 | tf.isnothrow = t.isnothrow; | |
4490 | tf.isnogc = t.isnogc; | |
4491 | tf.isproperty = t.isproperty; | |
4492 | tf.isref = t.isref; | |
4493 | tf.isreturn = t.isreturn; | |
7e287503 | 4494 | tf.isreturnscope = t.isreturnscope; |
5fee5ec3 IB |
4495 | tf.isScopeQual = t.isScopeQual; |
4496 | tf.isreturninferred = t.isreturninferred; | |
4497 | tf.isscopeinferred = t.isscopeinferred; | |
4498 | tf.trust = t.trust; | |
4499 | tf.isInOutParam = t.isInOutParam; | |
4500 | tf.isInOutQual = t.isInOutQual; | |
4501 | tf.isctor = t.isctor; | |
4502 | ||
4503 | if (stc & STC.pure_) | |
4504 | tf.purity = PURE.fwdref; | |
4505 | if (stc & STC.nothrow_) | |
4506 | tf.isnothrow = true; | |
4507 | if (stc & STC.nogc) | |
4508 | tf.isnogc = true; | |
4509 | if (stc & STC.safe) | |
4510 | tf.trust = TRUST.safe; | |
4511 | if (stc & STC.scope_) | |
4512 | { | |
4513 | tf.isScopeQual = true; | |
4514 | if (stc & STC.scopeinferred) | |
4515 | tf.isscopeinferred = true; | |
4516 | } | |
4517 | ||
4518 | tf.deco = tf.merge().deco; | |
4519 | t = tf; | |
4520 | } | |
4521 | return t; | |
4522 | } | |
4523 | ||
4524 | override Type substWildTo(uint) | |
4525 | { | |
4526 | if (!iswild && !(mod & MODFlags.wild)) | |
4527 | return this; | |
4528 | ||
4529 | // Substitude inout qualifier of function type to mutable or immutable | |
4530 | // would break type system. Instead substitude inout to the most weak | |
4531 | // qualifer - const. | |
4532 | uint m = MODFlags.const_; | |
4533 | ||
4534 | assert(next); | |
4535 | Type tret = next.substWildTo(m); | |
4536 | Parameters* params = parameterList.parameters; | |
4537 | if (mod & MODFlags.wild) | |
4538 | params = parameterList.parameters.copy(); | |
4539 | for (size_t i = 0; i < params.dim; i++) | |
4540 | { | |
4541 | Parameter p = (*params)[i]; | |
4542 | Type t = p.type.substWildTo(m); | |
4543 | if (t == p.type) | |
4544 | continue; | |
4545 | if (params == parameterList.parameters) | |
4546 | params = parameterList.parameters.copy(); | |
4547 | (*params)[i] = new Parameter(p.storageClass, t, null, null, null); | |
4548 | } | |
4549 | if (next == tret && params == parameterList.parameters) | |
4550 | return this; | |
4551 | ||
4552 | // Similar to TypeFunction::syntaxCopy; | |
4553 | auto t = new TypeFunction(ParameterList(params, parameterList.varargs), tret, linkage); | |
4554 | t.mod = ((mod & MODFlags.wild) ? (mod & ~MODFlags.wild) | MODFlags.const_ : mod); | |
4555 | t.isnothrow = isnothrow; | |
4556 | t.isnogc = isnogc; | |
4557 | t.purity = purity; | |
4558 | t.isproperty = isproperty; | |
4559 | t.isref = isref; | |
4560 | t.isreturn = isreturn; | |
7e287503 | 4561 | t.isreturnscope = isreturnscope; |
5fee5ec3 IB |
4562 | t.isScopeQual = isScopeQual; |
4563 | t.isreturninferred = isreturninferred; | |
4564 | t.isscopeinferred = isscopeinferred; | |
4565 | t.isInOutParam = false; | |
4566 | t.isInOutQual = false; | |
4567 | t.trust = trust; | |
4568 | t.fargs = fargs; | |
4569 | t.isctor = isctor; | |
4570 | return t.merge(); | |
4571 | } | |
4572 | ||
4573 | // arguments get specially formatted | |
4574 | private const(char)* getParamError(Expression arg, Parameter par) | |
4575 | { | |
4576 | if (global.gag && !global.params.showGaggedErrors) | |
4577 | return null; | |
4578 | // show qualification when toChars() is the same but types are different | |
fbdaa581 IB |
4579 | // https://issues.dlang.org/show_bug.cgi?id=19948 |
4580 | // when comparing the type with strcmp, we need to drop the qualifier | |
4581 | auto at = arg.type.mutableOf().toChars(); | |
4582 | bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.mutableOf().toChars()) == 0; | |
5fee5ec3 IB |
4583 | if (qual) |
4584 | at = arg.type.toPrettyChars(true); | |
4585 | OutBuffer buf; | |
4586 | // only mention rvalue if it's relevant | |
4587 | const rv = !arg.isLvalue() && par.isReference(); | |
4588 | buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", | |
4589 | rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, | |
4590 | parameterToChars(par, this, qual)); | |
4591 | return buf.extractChars(); | |
4592 | } | |
4593 | ||
4594 | private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args) | |
4595 | { | |
4596 | if (global.gag && !global.params.showGaggedErrors) | |
4597 | return null; | |
4598 | OutBuffer buf; | |
4599 | buf.printf(format, args); | |
4600 | return buf.extractChars(); | |
4601 | } | |
4602 | ||
4603 | /******************************** | |
4604 | * 'args' are being matched to function 'this' | |
4605 | * Determine match level. | |
4606 | * Params: | |
4607 | * tthis = type of `this` pointer, null if not member function | |
4608 | * args = array of function arguments | |
4609 | * flag = 1: performing a partial ordering match | |
4610 | * pMessage = address to store error message, or null | |
4611 | * sc = context | |
4612 | * Returns: | |
4613 | * MATCHxxxx | |
4614 | */ | |
4615 | extern (D) MATCH callMatch(Type tthis, Expression[] args, int flag = 0, const(char)** pMessage = null, Scope* sc = null) | |
4616 | { | |
4617 | //printf("TypeFunction::callMatch() %s\n", toChars()); | |
4618 | MATCH match = MATCH.exact; // assume exact match | |
4619 | ubyte wildmatch = 0; | |
4620 | ||
4621 | if (tthis) | |
4622 | { | |
4623 | Type t = tthis; | |
4624 | if (t.toBasetype().ty == Tpointer) | |
4625 | t = t.toBasetype().nextOf(); // change struct* to struct | |
4626 | if (t.mod != mod) | |
4627 | { | |
4628 | if (MODimplicitConv(t.mod, mod)) | |
4629 | match = MATCH.constant; | |
4630 | else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_)) | |
4631 | { | |
4632 | match = MATCH.constant; | |
4633 | } | |
4634 | else | |
4635 | return MATCH.nomatch; | |
4636 | } | |
4637 | if (isWild()) | |
4638 | { | |
4639 | if (t.isWild()) | |
4640 | wildmatch |= MODFlags.wild; | |
4641 | else if (t.isConst()) | |
4642 | wildmatch |= MODFlags.const_; | |
4643 | else if (t.isImmutable()) | |
4644 | wildmatch |= MODFlags.immutable_; | |
4645 | else | |
4646 | wildmatch |= MODFlags.mutable; | |
4647 | } | |
4648 | } | |
4649 | ||
4650 | const nparams = parameterList.length; | |
4651 | const nargs = args.length; | |
4652 | if (nargs > nparams) | |
4653 | { | |
4654 | if (parameterList.varargs == VarArg.none) | |
4655 | { | |
4656 | // suppress early exit if an error message is wanted, | |
4657 | // so we can check any matching args are valid | |
4658 | if (!pMessage) | |
c8dfa79c | 4659 | return MATCH.nomatch; |
5fee5ec3 IB |
4660 | } |
4661 | // too many args; no match | |
4662 | match = MATCH.convert; // match ... with a "conversion" match level | |
4663 | } | |
4664 | ||
31350635 IB |
4665 | // https://issues.dlang.org/show_bug.cgi?id=22997 |
4666 | if (parameterList.varargs == VarArg.none && nparams > nargs && !parameterList[nargs].defaultArg) | |
4667 | { | |
4668 | OutBuffer buf; | |
4669 | buf.printf("too few arguments, expected `%d`, got `%d`", cast(int)nparams, cast(int)nargs); | |
4670 | if (pMessage) | |
4671 | *pMessage = buf.extractChars(); | |
c8dfa79c | 4672 | return MATCH.nomatch; |
31350635 IB |
4673 | } |
4674 | ||
5fee5ec3 IB |
4675 | foreach (u, p; parameterList) |
4676 | { | |
4677 | if (u == nargs) | |
4678 | break; | |
4679 | ||
4680 | Expression arg = args[u]; | |
4681 | assert(arg); | |
4682 | Type tprm = p.type; | |
4683 | Type targ = arg.type; | |
4684 | ||
ec486b73 | 4685 | if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)) |
5fee5ec3 IB |
4686 | { |
4687 | const isRef = p.isReference(); | |
4688 | wildmatch |= targ.deduceWild(tprm, isRef); | |
4689 | } | |
4690 | } | |
4691 | if (wildmatch) | |
4692 | { | |
4693 | /* Calculate wild matching modifier | |
4694 | */ | |
4695 | if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) | |
4696 | wildmatch = MODFlags.const_; | |
4697 | else if (wildmatch & MODFlags.immutable_) | |
4698 | wildmatch = MODFlags.immutable_; | |
4699 | else if (wildmatch & MODFlags.wild) | |
4700 | wildmatch = MODFlags.wild; | |
4701 | else | |
4702 | { | |
4703 | assert(wildmatch & MODFlags.mutable); | |
4704 | wildmatch = MODFlags.mutable; | |
4705 | } | |
4706 | } | |
4707 | ||
4708 | foreach (u, p; parameterList) | |
4709 | { | |
4710 | MATCH m; | |
4711 | ||
4712 | assert(p); | |
c8dfa79c IB |
4713 | |
4714 | // One or more arguments remain | |
4715 | if (u < nargs) | |
5fee5ec3 IB |
4716 | { |
4717 | Expression arg = args[u]; | |
4718 | assert(arg); | |
c8dfa79c | 4719 | m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage); |
5fee5ec3 | 4720 | } |
c8dfa79c IB |
4721 | else if (p.defaultArg) |
4722 | continue; | |
5fee5ec3 IB |
4723 | |
4724 | /* prefer matching the element type rather than the array | |
4725 | * type when more arguments are present with T[]... | |
4726 | */ | |
4727 | if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && nargs > nparams) | |
4728 | goto L1; | |
4729 | ||
4730 | //printf("\tm = %d\n", m); | |
4731 | if (m == MATCH.nomatch) // if no match | |
4732 | { | |
4733 | L1: | |
4734 | if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param | |
4735 | { | |
c8dfa79c IB |
4736 | auto trailingArgs = args[u .. $]; |
4737 | if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage)) | |
4738 | return vmatch < match ? vmatch : match; | |
4739 | // Error message was already generated in `matchTypeSafeVarArgs` | |
4740 | return MATCH.nomatch; | |
5fee5ec3 | 4741 | } |
c8dfa79c | 4742 | if (pMessage && u >= nargs) |
5fee5ec3 IB |
4743 | *pMessage = getMatchError("missing argument for parameter #%d: `%s`", |
4744 | u + 1, parameterToChars(p, this, false)); | |
c8dfa79c IB |
4745 | // If an error happened previously, `pMessage` was already filled |
4746 | else if (pMessage && !*pMessage) | |
4747 | *pMessage = getParamError(args[u], p); | |
4748 | ||
4749 | return MATCH.nomatch; | |
5fee5ec3 IB |
4750 | } |
4751 | if (m < match) | |
4752 | match = m; // pick worst match | |
4753 | } | |
4754 | ||
5fee5ec3 IB |
4755 | if (pMessage && !parameterList.varargs && nargs > nparams) |
4756 | { | |
4757 | // all parameters had a match, but there are surplus args | |
4758 | *pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs); | |
c8dfa79c | 4759 | return MATCH.nomatch; |
5fee5ec3 IB |
4760 | } |
4761 | //printf("match = %d\n", match); | |
4762 | return match; | |
5fee5ec3 IB |
4763 | } |
4764 | ||
0fb57034 IB |
4765 | /+ |
4766 | + Checks whether this function type is convertible to ` to` | |
4767 | + when used in a function pointer / delegate. | |
4768 | + | |
4769 | + Params: | |
4770 | + to = target type | |
4771 | + | |
4772 | + Returns: | |
4773 | + MATCH.nomatch: `to` is not a covaraint function | |
4774 | + MATCH.convert: `to` is a covaraint function | |
4775 | + MATCH.exact: `to` is identical to this function | |
4776 | +/ | |
4777 | private MATCH implicitPointerConv(Type to) | |
4778 | { | |
4779 | assert(to); | |
4780 | ||
9c7d5e88 | 4781 | if (this.equals(to)) |
0fb57034 IB |
4782 | return MATCH.constant; |
4783 | ||
4784 | if (this.covariant(to) == Covariant.yes) | |
4785 | { | |
4786 | Type tret = this.nextOf(); | |
4787 | Type toret = to.nextOf(); | |
4788 | if (tret.ty == Tclass && toret.ty == Tclass) | |
4789 | { | |
4790 | /* https://issues.dlang.org/show_bug.cgi?id=10219 | |
4791 | * Check covariant interface return with offset tweaking. | |
4792 | * interface I {} | |
4793 | * class C : Object, I {} | |
4794 | * I function() dg = function C() {} // should be error | |
4795 | */ | |
4796 | int offset = 0; | |
4797 | if (toret.isBaseOf(tret, &offset) && offset != 0) | |
4798 | return MATCH.nomatch; | |
4799 | } | |
4800 | return MATCH.convert; | |
4801 | } | |
4802 | ||
4803 | return MATCH.nomatch; | |
4804 | } | |
4805 | ||
5fee5ec3 IB |
4806 | /** Extends TypeNext.constConv by also checking for matching attributes **/ |
4807 | override MATCH constConv(Type to) | |
4808 | { | |
4809 | // Attributes need to match exactly, otherwise it's an implicit conversion | |
4810 | if (this.ty != to.ty || !this.attributesEqual(cast(TypeFunction) to)) | |
4811 | return MATCH.nomatch; | |
4812 | ||
4813 | return super.constConv(to); | |
4814 | } | |
4815 | ||
4816 | extern (D) bool checkRetType(const ref Loc loc) | |
4817 | { | |
4818 | Type tb = next.toBasetype(); | |
4819 | if (tb.ty == Tfunction) | |
4820 | { | |
4821 | error(loc, "functions cannot return a function"); | |
4822 | next = Type.terror; | |
4823 | } | |
4824 | if (tb.ty == Ttuple) | |
4825 | { | |
4826 | error(loc, "functions cannot return a tuple"); | |
4827 | next = Type.terror; | |
4828 | } | |
4829 | if (!isref && (tb.ty == Tstruct || tb.ty == Tsarray)) | |
4830 | { | |
4831 | if (auto ts = tb.baseElemOf().isTypeStruct()) | |
4832 | { | |
4833 | if (!ts.sym.members) | |
4834 | { | |
4835 | error(loc, "functions cannot return opaque type `%s` by value", tb.toChars()); | |
4836 | next = Type.terror; | |
4837 | } | |
4838 | } | |
4839 | } | |
4840 | if (tb.ty == Terror) | |
4841 | return true; | |
4842 | return false; | |
4843 | } | |
4844 | ||
5fee5ec3 | 4845 | |
5fee5ec3 IB |
4846 | /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise. |
4847 | bool iswild() const pure nothrow @safe @nogc | |
4848 | { | |
31350635 | 4849 | return isInOutParam || isInOutQual; |
5fee5ec3 IB |
4850 | } |
4851 | ||
4852 | /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other` | |
4853 | bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc | |
4854 | { | |
5fee5ec3 IB |
4855 | return this.trust == other.trust && |
4856 | this.purity == other.purity && | |
31350635 IB |
4857 | this.isnothrow == other.isnothrow && |
4858 | this.isnogc == other.isnogc && | |
4859 | this.islive == other.islive; | |
5fee5ec3 IB |
4860 | } |
4861 | ||
4862 | override void accept(Visitor v) | |
4863 | { | |
4864 | v.visit(this); | |
4865 | } | |
4866 | } | |
4867 | ||
4868 | /*********************************************************** | |
4869 | */ | |
4870 | extern (C++) final class TypeDelegate : TypeNext | |
4871 | { | |
4872 | // .next is a TypeFunction | |
4873 | ||
4874 | extern (D) this(TypeFunction t) | |
4875 | { | |
4876 | super(Tfunction, t); | |
4877 | ty = Tdelegate; | |
4878 | } | |
4879 | ||
4880 | static TypeDelegate create(TypeFunction t) | |
4881 | { | |
4882 | return new TypeDelegate(t); | |
4883 | } | |
4884 | ||
4885 | override const(char)* kind() const | |
4886 | { | |
4887 | return "delegate"; | |
4888 | } | |
4889 | ||
4890 | override TypeDelegate syntaxCopy() | |
4891 | { | |
4892 | auto tf = next.syntaxCopy().isTypeFunction(); | |
4893 | if (tf == next) | |
4894 | return this; | |
4895 | ||
4896 | auto result = new TypeDelegate(tf); | |
4897 | result.mod = mod; | |
4898 | return result; | |
4899 | } | |
4900 | ||
4901 | override Type addStorageClass(StorageClass stc) | |
4902 | { | |
4903 | TypeDelegate t = cast(TypeDelegate)Type.addStorageClass(stc); | |
5fee5ec3 IB |
4904 | return t; |
4905 | } | |
4906 | ||
610d7898 | 4907 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
4908 | { |
4909 | return target.ptrsize * 2; | |
4910 | } | |
4911 | ||
610d7898 | 4912 | override uint alignsize() |
5fee5ec3 IB |
4913 | { |
4914 | return target.ptrsize; | |
4915 | } | |
4916 | ||
4917 | override MATCH implicitConvTo(Type to) | |
4918 | { | |
4919 | //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to); | |
4920 | //printf("from: %s\n", toChars()); | |
4921 | //printf("to : %s\n", to.toChars()); | |
9c7d5e88 | 4922 | if (this.equals(to)) |
5fee5ec3 IB |
4923 | return MATCH.exact; |
4924 | ||
0fb57034 | 4925 | if (auto toDg = to.isTypeDelegate()) |
5fee5ec3 | 4926 | { |
0fb57034 IB |
4927 | MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next); |
4928 | ||
4929 | // Retain the old behaviour for this refactoring | |
4930 | // Should probably be changed to constant to match function pointers | |
4931 | if (m > MATCH.convert) | |
4932 | m = MATCH.convert; | |
4933 | ||
4934 | return m; | |
5fee5ec3 IB |
4935 | } |
4936 | ||
4937 | return MATCH.nomatch; | |
4938 | } | |
4939 | ||
610d7898 | 4940 | override bool isZeroInit(const ref Loc loc) |
5fee5ec3 IB |
4941 | { |
4942 | return true; | |
4943 | } | |
4944 | ||
610d7898 | 4945 | override bool isBoolean() |
5fee5ec3 IB |
4946 | { |
4947 | return true; | |
4948 | } | |
4949 | ||
610d7898 | 4950 | override bool hasPointers() |
5fee5ec3 IB |
4951 | { |
4952 | return true; | |
4953 | } | |
4954 | ||
4955 | override void accept(Visitor v) | |
4956 | { | |
4957 | v.visit(this); | |
4958 | } | |
4959 | } | |
4960 | ||
4961 | /** | |
4962 | * This is a shell containing a TraitsExp that can be | |
4963 | * either resolved to a type or to a symbol. | |
4964 | * | |
4965 | * The point is to allow AliasDeclarationY to use `__traits()`, see issue 7804. | |
4966 | */ | |
4967 | extern (C++) final class TypeTraits : Type | |
4968 | { | |
4969 | Loc loc; | |
4970 | /// The expression to resolve as type or symbol. | |
4971 | TraitsExp exp; | |
5eb9927a IB |
4972 | /// Cached type/symbol after semantic analysis. |
4973 | RootObject obj; | |
5fee5ec3 IB |
4974 | |
4975 | final extern (D) this(const ref Loc loc, TraitsExp exp) | |
4976 | { | |
4977 | super(Ttraits); | |
4978 | this.loc = loc; | |
4979 | this.exp = exp; | |
4980 | } | |
4981 | ||
4982 | override const(char)* kind() const | |
4983 | { | |
4984 | return "traits"; | |
4985 | } | |
4986 | ||
4987 | override TypeTraits syntaxCopy() | |
4988 | { | |
4989 | TraitsExp te = exp.syntaxCopy(); | |
4990 | TypeTraits tt = new TypeTraits(loc, te); | |
4991 | tt.mod = mod; | |
4992 | return tt; | |
4993 | } | |
4994 | ||
4995 | override Dsymbol toDsymbol(Scope* sc) | |
4996 | { | |
4997 | Type t; | |
4998 | Expression e; | |
4999 | Dsymbol s; | |
5000 | resolve(this, loc, sc, e, t, s); | |
5001 | if (t && t.ty != Terror) | |
5002 | s = t.toDsymbol(sc); | |
5003 | else if (e) | |
5004 | s = getDsymbol(e); | |
5005 | ||
5006 | return s; | |
5007 | } | |
5008 | ||
5009 | override void accept(Visitor v) | |
5010 | { | |
5011 | v.visit(this); | |
5012 | } | |
5013 | ||
fbdaa581 | 5014 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
5015 | { |
5016 | return SIZE_INVALID; | |
5017 | } | |
5018 | } | |
5019 | ||
5020 | /****** | |
5021 | * Implements mixin types. | |
5022 | * | |
5023 | * Semantic analysis will convert it to a real type. | |
5024 | */ | |
5025 | extern (C++) final class TypeMixin : Type | |
5026 | { | |
5027 | Loc loc; | |
5028 | Expressions* exps; | |
5029 | RootObject obj; // cached result of semantic analysis. | |
5030 | ||
5031 | extern (D) this(const ref Loc loc, Expressions* exps) | |
5032 | { | |
5033 | super(Tmixin); | |
5034 | this.loc = loc; | |
5035 | this.exps = exps; | |
5036 | } | |
5037 | ||
5038 | override const(char)* kind() const | |
5039 | { | |
5040 | return "mixin"; | |
5041 | } | |
5042 | ||
5043 | override TypeMixin syntaxCopy() | |
5044 | { | |
5045 | return new TypeMixin(loc, Expression.arraySyntaxCopy(exps)); | |
5046 | } | |
5047 | ||
5048 | override Dsymbol toDsymbol(Scope* sc) | |
5049 | { | |
5050 | Type t; | |
5051 | Expression e; | |
5052 | Dsymbol s; | |
5053 | resolve(this, loc, sc, e, t, s); | |
5054 | if (t) | |
5055 | s = t.toDsymbol(sc); | |
5056 | else if (e) | |
5057 | s = getDsymbol(e); | |
5058 | ||
5059 | return s; | |
5060 | } | |
5061 | ||
5062 | override void accept(Visitor v) | |
5063 | { | |
5064 | v.visit(this); | |
5065 | } | |
5066 | } | |
5067 | ||
5068 | /*********************************************************** | |
5069 | */ | |
5070 | extern (C++) abstract class TypeQualified : Type | |
5071 | { | |
5072 | Loc loc; | |
5073 | ||
5074 | // array of Identifier and TypeInstance, | |
5075 | // representing ident.ident!tiargs.ident. ... etc. | |
5076 | Objects idents; | |
5077 | ||
5078 | final extern (D) this(TY ty, Loc loc) | |
5079 | { | |
5080 | super(ty); | |
5081 | this.loc = loc; | |
5082 | } | |
5083 | ||
5084 | // abstract override so that using `TypeQualified.syntaxCopy` gets | |
5085 | // us a `TypeQualified` | |
5086 | abstract override TypeQualified syntaxCopy(); | |
5087 | ||
5088 | final void syntaxCopyHelper(TypeQualified t) | |
5089 | { | |
5090 | //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t.toChars(), toChars()); | |
5091 | idents.setDim(t.idents.dim); | |
5092 | for (size_t i = 0; i < idents.dim; i++) | |
5093 | { | |
5094 | RootObject id = t.idents[i]; | |
5095 | with (DYNCAST) final switch (id.dyncast()) | |
5096 | { | |
5097 | case object: | |
5098 | break; | |
5099 | case expression: | |
5100 | Expression e = cast(Expression)id; | |
5101 | e = e.syntaxCopy(); | |
5102 | id = e; | |
5103 | break; | |
5104 | case dsymbol: | |
5105 | TemplateInstance ti = cast(TemplateInstance)id; | |
5106 | ti = ti.syntaxCopy(null); | |
5107 | id = ti; | |
5108 | break; | |
5109 | case type: | |
5110 | Type tx = cast(Type)id; | |
5111 | tx = tx.syntaxCopy(); | |
5112 | id = tx; | |
5113 | break; | |
5114 | case identifier: | |
5115 | case tuple: | |
5116 | case parameter: | |
5117 | case statement: | |
5118 | case condition: | |
5119 | case templateparameter: | |
5120 | case initializer: | |
5121 | } | |
5122 | idents[i] = id; | |
5123 | } | |
5124 | } | |
5125 | ||
5126 | final void addIdent(Identifier ident) | |
5127 | { | |
5128 | idents.push(ident); | |
5129 | } | |
5130 | ||
5131 | final void addInst(TemplateInstance inst) | |
5132 | { | |
5133 | idents.push(inst); | |
5134 | } | |
5135 | ||
5136 | final void addIndex(RootObject e) | |
5137 | { | |
5138 | idents.push(e); | |
5139 | } | |
5140 | ||
fbdaa581 | 5141 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
5142 | { |
5143 | error(this.loc, "size of type `%s` is not known", toChars()); | |
5144 | return SIZE_INVALID; | |
5145 | } | |
5146 | ||
5147 | override void accept(Visitor v) | |
5148 | { | |
5149 | v.visit(this); | |
5150 | } | |
5151 | } | |
5152 | ||
5153 | /*********************************************************** | |
5154 | */ | |
5155 | extern (C++) final class TypeIdentifier : TypeQualified | |
5156 | { | |
5157 | Identifier ident; | |
5158 | ||
5159 | // The symbol representing this identifier, before alias resolution | |
5160 | Dsymbol originalSymbol; | |
5161 | ||
5162 | extern (D) this(const ref Loc loc, Identifier ident) | |
5163 | { | |
5164 | super(Tident, loc); | |
5165 | this.ident = ident; | |
5166 | } | |
5167 | ||
0fb57034 IB |
5168 | static TypeIdentifier create(const ref Loc loc, Identifier ident) |
5169 | { | |
5170 | return new TypeIdentifier(loc, ident); | |
5171 | } | |
5172 | ||
5fee5ec3 IB |
5173 | override const(char)* kind() const |
5174 | { | |
5175 | return "identifier"; | |
5176 | } | |
5177 | ||
5178 | override TypeIdentifier syntaxCopy() | |
5179 | { | |
5180 | auto t = new TypeIdentifier(loc, ident); | |
5181 | t.syntaxCopyHelper(this); | |
5182 | t.mod = mod; | |
5183 | return t; | |
5184 | } | |
5185 | ||
5186 | /***************************************** | |
5187 | * See if type resolves to a symbol, if so, | |
5188 | * return that symbol. | |
5189 | */ | |
5190 | override Dsymbol toDsymbol(Scope* sc) | |
5191 | { | |
5192 | //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); | |
5193 | if (!sc) | |
5194 | return null; | |
5195 | ||
5196 | Type t; | |
5197 | Expression e; | |
5198 | Dsymbol s; | |
5199 | resolve(this, loc, sc, e, t, s); | |
5200 | if (t && t.ty != Tident) | |
5201 | s = t.toDsymbol(sc); | |
5202 | if (e) | |
5203 | s = getDsymbol(e); | |
5204 | ||
5205 | return s; | |
5206 | } | |
5207 | ||
5208 | override void accept(Visitor v) | |
5209 | { | |
5210 | v.visit(this); | |
5211 | } | |
5212 | } | |
5213 | ||
5214 | /*********************************************************** | |
5215 | * Similar to TypeIdentifier, but with a TemplateInstance as the root | |
5216 | */ | |
5217 | extern (C++) final class TypeInstance : TypeQualified | |
5218 | { | |
5219 | TemplateInstance tempinst; | |
5220 | ||
5221 | extern (D) this(const ref Loc loc, TemplateInstance tempinst) | |
5222 | { | |
5223 | super(Tinstance, loc); | |
5224 | this.tempinst = tempinst; | |
5225 | } | |
5226 | ||
5227 | override const(char)* kind() const | |
5228 | { | |
5229 | return "instance"; | |
5230 | } | |
5231 | ||
5232 | override TypeInstance syntaxCopy() | |
5233 | { | |
5234 | //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim); | |
5235 | auto t = new TypeInstance(loc, tempinst.syntaxCopy(null)); | |
5236 | t.syntaxCopyHelper(this); | |
5237 | t.mod = mod; | |
5238 | return t; | |
5239 | } | |
5240 | ||
5241 | override Dsymbol toDsymbol(Scope* sc) | |
5242 | { | |
5243 | Type t; | |
5244 | Expression e; | |
5245 | Dsymbol s; | |
5246 | //printf("TypeInstance::semantic(%s)\n", toChars()); | |
5247 | resolve(this, loc, sc, e, t, s); | |
5248 | if (t && t.ty != Tinstance) | |
5249 | s = t.toDsymbol(sc); | |
5250 | return s; | |
5251 | } | |
5252 | ||
5253 | override void accept(Visitor v) | |
5254 | { | |
5255 | v.visit(this); | |
5256 | } | |
5257 | } | |
5258 | ||
5259 | /*********************************************************** | |
5260 | */ | |
5261 | extern (C++) final class TypeTypeof : TypeQualified | |
5262 | { | |
5263 | Expression exp; | |
5264 | int inuse; | |
5265 | ||
5266 | extern (D) this(const ref Loc loc, Expression exp) | |
5267 | { | |
5268 | super(Ttypeof, loc); | |
5269 | this.exp = exp; | |
5270 | } | |
5271 | ||
5272 | override const(char)* kind() const | |
5273 | { | |
5274 | return "typeof"; | |
5275 | } | |
5276 | ||
5277 | override TypeTypeof syntaxCopy() | |
5278 | { | |
5279 | //printf("TypeTypeof::syntaxCopy() %s\n", toChars()); | |
5280 | auto t = new TypeTypeof(loc, exp.syntaxCopy()); | |
5281 | t.syntaxCopyHelper(this); | |
5282 | t.mod = mod; | |
5283 | return t; | |
5284 | } | |
5285 | ||
5286 | override Dsymbol toDsymbol(Scope* sc) | |
5287 | { | |
5288 | //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); | |
5289 | Expression e; | |
5290 | Type t; | |
5291 | Dsymbol s; | |
5292 | resolve(this, loc, sc, e, t, s); | |
5293 | return s; | |
5294 | } | |
5295 | ||
fbdaa581 | 5296 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
5297 | { |
5298 | if (exp.type) | |
5299 | return exp.type.size(loc); | |
5300 | else | |
5301 | return TypeQualified.size(loc); | |
5302 | } | |
5303 | ||
5304 | override void accept(Visitor v) | |
5305 | { | |
5306 | v.visit(this); | |
5307 | } | |
5308 | } | |
5309 | ||
5310 | /*********************************************************** | |
5311 | */ | |
5312 | extern (C++) final class TypeReturn : TypeQualified | |
5313 | { | |
5314 | extern (D) this(const ref Loc loc) | |
5315 | { | |
5316 | super(Treturn, loc); | |
5317 | } | |
5318 | ||
5319 | override const(char)* kind() const | |
5320 | { | |
5321 | return "return"; | |
5322 | } | |
5323 | ||
5324 | override TypeReturn syntaxCopy() | |
5325 | { | |
5326 | auto t = new TypeReturn(loc); | |
5327 | t.syntaxCopyHelper(this); | |
5328 | t.mod = mod; | |
5329 | return t; | |
5330 | } | |
5331 | ||
5332 | override Dsymbol toDsymbol(Scope* sc) | |
5333 | { | |
5334 | Expression e; | |
5335 | Type t; | |
5336 | Dsymbol s; | |
5337 | resolve(this, loc, sc, e, t, s); | |
5338 | return s; | |
5339 | } | |
5340 | ||
5341 | override void accept(Visitor v) | |
5342 | { | |
5343 | v.visit(this); | |
5344 | } | |
5345 | } | |
5346 | ||
5347 | /*********************************************************** | |
5348 | */ | |
5349 | extern (C++) final class TypeStruct : Type | |
5350 | { | |
5351 | StructDeclaration sym; | |
5352 | AliasThisRec att = AliasThisRec.fwdref; | |
5353 | bool inuse = false; // struct currently subject of recursive method call | |
5354 | ||
5355 | extern (D) this(StructDeclaration sym) | |
5356 | { | |
5357 | super(Tstruct); | |
5358 | this.sym = sym; | |
5359 | } | |
5360 | ||
5361 | static TypeStruct create(StructDeclaration sym) | |
5362 | { | |
5363 | return new TypeStruct(sym); | |
5364 | } | |
5365 | ||
5366 | override const(char)* kind() const | |
5367 | { | |
5368 | return "struct"; | |
5369 | } | |
5370 | ||
fbdaa581 | 5371 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
5372 | { |
5373 | return sym.size(loc); | |
5374 | } | |
5375 | ||
5376 | override uint alignsize() | |
5377 | { | |
5378 | sym.size(Loc.initial); // give error for forward references | |
5379 | return sym.alignsize; | |
5380 | } | |
5381 | ||
5382 | override TypeStruct syntaxCopy() | |
5383 | { | |
5384 | return this; | |
5385 | } | |
5386 | ||
5387 | override Dsymbol toDsymbol(Scope* sc) | |
5388 | { | |
5389 | return sym; | |
5390 | } | |
5391 | ||
5392 | override structalign_t alignment() | |
5393 | { | |
0fb57034 | 5394 | if (sym.alignment.isUnknown()) |
5fee5ec3 IB |
5395 | sym.size(sym.loc); |
5396 | return sym.alignment; | |
5397 | } | |
5398 | ||
5399 | /*************************************** | |
5400 | * Use when we prefer the default initializer to be a literal, | |
5401 | * rather than a global immutable variable. | |
5402 | */ | |
5403 | override Expression defaultInitLiteral(const ref Loc loc) | |
5404 | { | |
5405 | static if (LOGDEFAULTINIT) | |
5406 | { | |
5407 | printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); | |
5408 | } | |
5409 | sym.size(loc); | |
5410 | if (sym.sizeok != Sizeok.done) | |
5411 | return ErrorExp.get(); | |
5412 | ||
5413 | auto structelems = new Expressions(sym.nonHiddenFields()); | |
5414 | uint offset = 0; | |
5415 | foreach (j; 0 .. structelems.dim) | |
5416 | { | |
5417 | VarDeclaration vd = sym.fields[j]; | |
5418 | Expression e; | |
5419 | if (vd.inuse) | |
5420 | { | |
5421 | error(loc, "circular reference to `%s`", vd.toPrettyChars()); | |
5422 | return ErrorExp.get(); | |
5423 | } | |
5424 | if (vd.offset < offset || vd.type.size() == 0) | |
5425 | e = null; | |
5426 | else if (vd._init) | |
5427 | { | |
5428 | if (vd._init.isVoidInitializer()) | |
5429 | e = null; | |
5430 | else | |
5431 | e = vd.getConstInitializer(false); | |
5432 | } | |
5433 | else | |
5434 | e = vd.type.defaultInitLiteral(loc); | |
9c7d5e88 | 5435 | if (e && e.op == EXP.error) |
5fee5ec3 IB |
5436 | return e; |
5437 | if (e) | |
5438 | offset = vd.offset + cast(uint)vd.type.size(); | |
5439 | (*structelems)[j] = e; | |
5440 | } | |
5441 | auto structinit = new StructLiteralExp(loc, sym, structelems); | |
5442 | ||
5443 | /* Copy from the initializer symbol for larger symbols, | |
5444 | * otherwise the literals expressed as code get excessively large. | |
5445 | */ | |
5446 | if (size(loc) > target.ptrsize * 4 && !needsNested()) | |
5447 | structinit.useStaticInit = true; | |
5448 | ||
5449 | structinit.type = this; | |
5450 | return structinit; | |
5451 | } | |
5452 | ||
5453 | override bool isZeroInit(const ref Loc loc) | |
5454 | { | |
5455 | // Determine zeroInit here, as this can be called before semantic2 | |
5456 | sym.determineSize(sym.loc); | |
5457 | return sym.zeroInit; | |
5458 | } | |
5459 | ||
5460 | override bool isAssignable() | |
5461 | { | |
5462 | bool assignable = true; | |
5463 | uint offset = ~0; // dead-store initialize to prevent spurious warning | |
5464 | ||
5465 | sym.determineSize(sym.loc); | |
5466 | ||
5467 | /* If any of the fields are const or immutable, | |
5468 | * then one cannot assign this struct. | |
5469 | */ | |
5470 | for (size_t i = 0; i < sym.fields.dim; i++) | |
5471 | { | |
5472 | VarDeclaration v = sym.fields[i]; | |
5473 | //printf("%s [%d] v = (%s) %s, v.offset = %d, v.parent = %s\n", sym.toChars(), i, v.kind(), v.toChars(), v.offset, v.parent.kind()); | |
5474 | if (i == 0) | |
5475 | { | |
5476 | } | |
5477 | else if (v.offset == offset) | |
5478 | { | |
5479 | /* If any fields of anonymous union are assignable, | |
5480 | * then regard union as assignable. | |
5481 | * This is to support unsafe things like Rebindable templates. | |
5482 | */ | |
5483 | if (assignable) | |
5484 | continue; | |
5485 | } | |
5486 | else | |
5487 | { | |
5488 | if (!assignable) | |
5489 | return false; | |
5490 | } | |
5491 | assignable = v.type.isMutable() && v.type.isAssignable(); | |
5492 | offset = v.offset; | |
5493 | //printf(" -> assignable = %d\n", assignable); | |
5494 | } | |
5495 | ||
5496 | return assignable; | |
5497 | } | |
5498 | ||
610d7898 | 5499 | override bool isBoolean() |
5fee5ec3 IB |
5500 | { |
5501 | return false; | |
5502 | } | |
5503 | ||
610d7898 | 5504 | override bool needsDestruction() |
5fee5ec3 IB |
5505 | { |
5506 | return sym.dtor !is null; | |
5507 | } | |
5508 | ||
5509 | override bool needsCopyOrPostblit() | |
5510 | { | |
5511 | return sym.hasCopyCtor || sym.postblit; | |
5512 | } | |
5513 | ||
5514 | override bool needsNested() | |
5515 | { | |
5516 | if (inuse) return false; // circular type, error instead of crashing | |
5517 | ||
5518 | inuse = true; | |
5519 | scope(exit) inuse = false; | |
5520 | ||
5521 | if (sym.isNested()) | |
5522 | return true; | |
5523 | ||
5524 | for (size_t i = 0; i < sym.fields.dim; i++) | |
5525 | { | |
5526 | VarDeclaration v = sym.fields[i]; | |
5527 | if (!v.isDataseg() && v.type.needsNested()) | |
5528 | return true; | |
5529 | } | |
5530 | return false; | |
5531 | } | |
5532 | ||
5533 | override bool hasPointers() | |
5534 | { | |
5535 | // Probably should cache this information in sym rather than recompute | |
5536 | StructDeclaration s = sym; | |
5537 | ||
5538 | if (sym.members && !sym.determineFields() && sym.type != Type.terror) | |
5539 | error(sym.loc, "no size because of forward references"); | |
5540 | ||
5541 | foreach (VarDeclaration v; s.fields) | |
5542 | { | |
5543 | if (v.storage_class & STC.ref_ || v.hasPointers()) | |
5544 | return true; | |
5545 | } | |
5546 | return false; | |
5547 | } | |
5548 | ||
5549 | override bool hasVoidInitPointers() | |
5550 | { | |
5551 | // Probably should cache this information in sym rather than recompute | |
5552 | StructDeclaration s = sym; | |
5553 | ||
5554 | sym.size(Loc.initial); // give error for forward references | |
5555 | foreach (VarDeclaration v; s.fields) | |
5556 | { | |
5557 | if (v._init && v._init.isVoidInitializer() && v.type.hasPointers()) | |
5558 | return true; | |
5559 | if (!v._init && v.type.hasVoidInitPointers()) | |
5560 | return true; | |
5561 | } | |
5562 | return false; | |
5563 | } | |
5564 | ||
5565 | override bool hasInvariant() | |
5566 | { | |
5567 | // Probably should cache this information in sym rather than recompute | |
5568 | StructDeclaration s = sym; | |
5569 | ||
5570 | sym.size(Loc.initial); // give error for forward references | |
5571 | ||
5572 | if (s.hasInvariant()) | |
5573 | return true; | |
5574 | ||
5575 | foreach (VarDeclaration v; s.fields) | |
5576 | { | |
5577 | if (v.type.hasInvariant()) | |
5578 | return true; | |
5579 | } | |
5580 | return false; | |
5581 | } | |
5582 | ||
5583 | extern (D) MATCH implicitConvToWithoutAliasThis(Type to) | |
5584 | { | |
5585 | MATCH m; | |
5586 | ||
5587 | if (ty == to.ty && sym == (cast(TypeStruct)to).sym) | |
5588 | { | |
5589 | m = MATCH.exact; // exact match | |
5590 | if (mod != to.mod) | |
5591 | { | |
5592 | m = MATCH.constant; | |
5593 | if (MODimplicitConv(mod, to.mod)) | |
5594 | { | |
5595 | } | |
5596 | else | |
5597 | { | |
5598 | /* Check all the fields. If they can all be converted, | |
5599 | * allow the conversion. | |
5600 | */ | |
5601 | uint offset = ~0; // dead-store to prevent spurious warning | |
5602 | for (size_t i = 0; i < sym.fields.dim; i++) | |
5603 | { | |
5604 | VarDeclaration v = sym.fields[i]; | |
5605 | if (i == 0) | |
5606 | { | |
5607 | } | |
5608 | else if (v.offset == offset) | |
5609 | { | |
5610 | if (m > MATCH.nomatch) | |
5611 | continue; | |
5612 | } | |
5613 | else | |
5614 | { | |
5615 | if (m == MATCH.nomatch) | |
5616 | return m; | |
5617 | } | |
5618 | ||
5619 | // 'from' type | |
5620 | Type tvf = v.type.addMod(mod); | |
5621 | ||
5622 | // 'to' type | |
5623 | Type tv = v.type.addMod(to.mod); | |
5624 | ||
5625 | // field match | |
5626 | MATCH mf = tvf.implicitConvTo(tv); | |
5627 | //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), mf); | |
5628 | ||
5629 | if (mf == MATCH.nomatch) | |
5630 | return mf; | |
5631 | if (mf < m) // if field match is worse | |
5632 | m = mf; | |
5633 | offset = v.offset; | |
5634 | } | |
5635 | } | |
5636 | } | |
5637 | } | |
5638 | return m; | |
5639 | } | |
5640 | ||
5641 | extern (D) MATCH implicitConvToThroughAliasThis(Type to) | |
5642 | { | |
5643 | MATCH m; | |
5644 | if (!(ty == to.ty && sym == (cast(TypeStruct)to).sym) && sym.aliasthis && !(att & AliasThisRec.tracing)) | |
5645 | { | |
5646 | if (auto ato = aliasthisOf()) | |
5647 | { | |
5648 | att = cast(AliasThisRec)(att | AliasThisRec.tracing); | |
5649 | m = ato.implicitConvTo(to); | |
5650 | att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); | |
5651 | } | |
5652 | else | |
5653 | m = MATCH.nomatch; // no match | |
5654 | } | |
5655 | return m; | |
5656 | } | |
5657 | ||
5658 | override MATCH implicitConvTo(Type to) | |
5659 | { | |
5660 | //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars()); | |
5661 | MATCH m = implicitConvToWithoutAliasThis(to); | |
5662 | return m ? m : implicitConvToThroughAliasThis(to); | |
5663 | } | |
5664 | ||
5665 | override MATCH constConv(Type to) | |
5666 | { | |
5667 | if (equals(to)) | |
5668 | return MATCH.exact; | |
5669 | if (ty == to.ty && sym == (cast(TypeStruct)to).sym && MODimplicitConv(mod, to.mod)) | |
5670 | return MATCH.constant; | |
5671 | return MATCH.nomatch; | |
5672 | } | |
5673 | ||
5674 | override MOD deduceWild(Type t, bool isRef) | |
5675 | { | |
5676 | if (ty == t.ty && sym == (cast(TypeStruct)t).sym) | |
5677 | return Type.deduceWild(t, isRef); | |
5678 | ||
5679 | ubyte wm = 0; | |
5680 | ||
5681 | if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing)) | |
5682 | { | |
5683 | if (auto ato = aliasthisOf()) | |
5684 | { | |
5685 | att = cast(AliasThisRec)(att | AliasThisRec.tracing); | |
5686 | wm = ato.deduceWild(t, isRef); | |
5687 | att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); | |
5688 | } | |
5689 | } | |
5690 | ||
5691 | return wm; | |
5692 | } | |
5693 | ||
5694 | override inout(Type) toHeadMutable() inout | |
5695 | { | |
5696 | return this; | |
5697 | } | |
5698 | ||
5699 | override void accept(Visitor v) | |
5700 | { | |
5701 | v.visit(this); | |
5702 | } | |
5703 | } | |
5704 | ||
5705 | /*********************************************************** | |
5706 | */ | |
5707 | extern (C++) final class TypeEnum : Type | |
5708 | { | |
5709 | EnumDeclaration sym; | |
5710 | ||
5711 | extern (D) this(EnumDeclaration sym) | |
5712 | { | |
5713 | super(Tenum); | |
5714 | this.sym = sym; | |
5715 | } | |
5716 | ||
5717 | override const(char)* kind() const | |
5718 | { | |
5719 | return "enum"; | |
5720 | } | |
5721 | ||
5722 | override TypeEnum syntaxCopy() | |
5723 | { | |
5724 | return this; | |
5725 | } | |
5726 | ||
fbdaa581 | 5727 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
5728 | { |
5729 | return sym.getMemtype(loc).size(loc); | |
5730 | } | |
5731 | ||
5732 | Type memType(const ref Loc loc = Loc.initial) | |
5733 | { | |
5734 | return sym.getMemtype(loc); | |
5735 | } | |
610d7898 | 5736 | |
5fee5ec3 IB |
5737 | override uint alignsize() |
5738 | { | |
5739 | Type t = memType(); | |
5740 | if (t.ty == Terror) | |
5741 | return 4; | |
5742 | return t.alignsize(); | |
5743 | } | |
5744 | ||
5745 | override Dsymbol toDsymbol(Scope* sc) | |
5746 | { | |
5747 | return sym; | |
5748 | } | |
5749 | ||
5750 | override bool isintegral() | |
5751 | { | |
5752 | return memType().isintegral(); | |
5753 | } | |
5754 | ||
5755 | override bool isfloating() | |
5756 | { | |
5757 | return memType().isfloating(); | |
5758 | } | |
5759 | ||
5760 | override bool isreal() | |
5761 | { | |
5762 | return memType().isreal(); | |
5763 | } | |
5764 | ||
5765 | override bool isimaginary() | |
5766 | { | |
5767 | return memType().isimaginary(); | |
5768 | } | |
5769 | ||
5770 | override bool iscomplex() | |
5771 | { | |
5772 | return memType().iscomplex(); | |
5773 | } | |
5774 | ||
5775 | override bool isscalar() | |
5776 | { | |
5777 | return memType().isscalar(); | |
5778 | } | |
5779 | ||
5780 | override bool isunsigned() | |
5781 | { | |
5782 | return memType().isunsigned(); | |
5783 | } | |
5784 | ||
5785 | override bool isBoolean() | |
5786 | { | |
5787 | return memType().isBoolean(); | |
5788 | } | |
5789 | ||
5790 | override bool isString() | |
5791 | { | |
5792 | return memType().isString(); | |
5793 | } | |
5794 | ||
5795 | override bool isAssignable() | |
5796 | { | |
5797 | return memType().isAssignable(); | |
5798 | } | |
5799 | ||
5800 | override bool needsDestruction() | |
5801 | { | |
5802 | return memType().needsDestruction(); | |
5803 | } | |
5804 | ||
5805 | override bool needsCopyOrPostblit() | |
5806 | { | |
5807 | return memType().needsCopyOrPostblit(); | |
5808 | } | |
5809 | ||
5810 | override bool needsNested() | |
5811 | { | |
5812 | return memType().needsNested(); | |
5813 | } | |
5814 | ||
5815 | override MATCH implicitConvTo(Type to) | |
5816 | { | |
5817 | MATCH m; | |
5818 | //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars()); | |
5819 | if (ty == to.ty && sym == (cast(TypeEnum)to).sym) | |
5820 | m = (mod == to.mod) ? MATCH.exact : MATCH.constant; | |
5821 | else if (sym.getMemtype(Loc.initial).implicitConvTo(to)) | |
5822 | m = MATCH.convert; // match with conversions | |
5823 | else | |
5824 | m = MATCH.nomatch; // no match | |
5825 | return m; | |
5826 | } | |
5827 | ||
5828 | override MATCH constConv(Type to) | |
5829 | { | |
5830 | if (equals(to)) | |
5831 | return MATCH.exact; | |
5832 | if (ty == to.ty && sym == (cast(TypeEnum)to).sym && MODimplicitConv(mod, to.mod)) | |
5833 | return MATCH.constant; | |
5834 | return MATCH.nomatch; | |
5835 | } | |
5836 | ||
5837 | extern (D) Type toBasetype2() | |
5838 | { | |
5839 | if (!sym.members && !sym.memtype) | |
5840 | return this; | |
5841 | auto tb = sym.getMemtype(Loc.initial).toBasetype(); | |
5842 | return tb.castMod(mod); // retain modifier bits from 'this' | |
5843 | } | |
5844 | ||
5845 | override bool isZeroInit(const ref Loc loc) | |
5846 | { | |
9c7d5e88 | 5847 | return sym.getDefaultValue(loc).toBool().hasValue(false); |
5fee5ec3 IB |
5848 | } |
5849 | ||
5850 | override bool hasPointers() | |
5851 | { | |
5852 | return memType().hasPointers(); | |
5853 | } | |
5854 | ||
5855 | override bool hasVoidInitPointers() | |
5856 | { | |
5857 | return memType().hasVoidInitPointers(); | |
5858 | } | |
5859 | ||
5860 | override bool hasInvariant() | |
5861 | { | |
5862 | return memType().hasInvariant(); | |
5863 | } | |
5864 | ||
5865 | override Type nextOf() | |
5866 | { | |
5867 | return memType().nextOf(); | |
5868 | } | |
5869 | ||
5870 | override void accept(Visitor v) | |
5871 | { | |
5872 | v.visit(this); | |
5873 | } | |
5874 | } | |
5875 | ||
5876 | /*********************************************************** | |
5877 | */ | |
5878 | extern (C++) final class TypeClass : Type | |
5879 | { | |
5880 | ClassDeclaration sym; | |
5881 | AliasThisRec att = AliasThisRec.fwdref; | |
5882 | CPPMANGLE cppmangle = CPPMANGLE.def; | |
5883 | ||
5884 | extern (D) this(ClassDeclaration sym) | |
5885 | { | |
5886 | super(Tclass); | |
5887 | this.sym = sym; | |
5888 | } | |
5889 | ||
5890 | override const(char)* kind() const | |
5891 | { | |
5892 | return "class"; | |
5893 | } | |
5894 | ||
610d7898 | 5895 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
5896 | { |
5897 | return target.ptrsize; | |
5898 | } | |
5899 | ||
5900 | override TypeClass syntaxCopy() | |
5901 | { | |
5902 | return this; | |
5903 | } | |
5904 | ||
5905 | override Dsymbol toDsymbol(Scope* sc) | |
5906 | { | |
5907 | return sym; | |
5908 | } | |
5909 | ||
5910 | override inout(ClassDeclaration) isClassHandle() inout | |
5911 | { | |
5912 | return sym; | |
5913 | } | |
5914 | ||
5915 | override bool isBaseOf(Type t, int* poffset) | |
5916 | { | |
5917 | if (t && t.ty == Tclass) | |
5918 | { | |
5919 | ClassDeclaration cd = (cast(TypeClass)t).sym; | |
c8dfa79c IB |
5920 | if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) |
5921 | cd.dsymbolSemantic(null); | |
5922 | if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) | |
5923 | sym.dsymbolSemantic(null); | |
5924 | ||
5fee5ec3 IB |
5925 | if (sym.isBaseOf(cd, poffset)) |
5926 | return true; | |
5927 | } | |
5928 | return false; | |
5929 | } | |
5930 | ||
5931 | extern (D) MATCH implicitConvToWithoutAliasThis(Type to) | |
5932 | { | |
d7569187 | 5933 | // Run semantic before checking whether class is convertible |
5fee5ec3 IB |
5934 | ClassDeclaration cdto = to.isClassHandle(); |
5935 | if (cdto) | |
5936 | { | |
5937 | //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete()); | |
5938 | if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete()) | |
5939 | cdto.dsymbolSemantic(null); | |
5940 | if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) | |
5941 | sym.dsymbolSemantic(null); | |
d7569187 IB |
5942 | } |
5943 | MATCH m = constConv(to); | |
5944 | if (m > MATCH.nomatch) | |
5945 | return m; | |
5946 | ||
5947 | if (cdto && cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod)) | |
5948 | { | |
5949 | //printf("'to' is base\n"); | |
5950 | return MATCH.convert; | |
5fee5ec3 IB |
5951 | } |
5952 | return MATCH.nomatch; | |
5953 | } | |
5954 | ||
5955 | extern (D) MATCH implicitConvToThroughAliasThis(Type to) | |
5956 | { | |
5957 | MATCH m; | |
5958 | if (sym.aliasthis && !(att & AliasThisRec.tracing)) | |
5959 | { | |
5960 | if (auto ato = aliasthisOf()) | |
5961 | { | |
5962 | att = cast(AliasThisRec)(att | AliasThisRec.tracing); | |
5963 | m = ato.implicitConvTo(to); | |
5964 | att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); | |
5965 | } | |
5966 | } | |
5967 | return m; | |
5968 | } | |
5969 | ||
5970 | override MATCH implicitConvTo(Type to) | |
5971 | { | |
5972 | //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars()); | |
5973 | MATCH m = implicitConvToWithoutAliasThis(to); | |
5974 | return m ? m : implicitConvToThroughAliasThis(to); | |
5975 | } | |
5976 | ||
5977 | override MATCH constConv(Type to) | |
5978 | { | |
5979 | if (equals(to)) | |
5980 | return MATCH.exact; | |
5981 | if (ty == to.ty && sym == (cast(TypeClass)to).sym && MODimplicitConv(mod, to.mod)) | |
5982 | return MATCH.constant; | |
5983 | ||
5984 | /* Conversion derived to const(base) | |
5985 | */ | |
5986 | int offset = 0; | |
7e287503 | 5987 | if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod)) |
5fee5ec3 IB |
5988 | { |
5989 | // Disallow: | |
5990 | // derived to base | |
5991 | // inout(derived) to inout(base) | |
5992 | if (!to.isMutable() && !to.isWild()) | |
5993 | return MATCH.convert; | |
5994 | } | |
5995 | ||
5996 | return MATCH.nomatch; | |
5997 | } | |
5998 | ||
5999 | override MOD deduceWild(Type t, bool isRef) | |
6000 | { | |
6001 | ClassDeclaration cd = t.isClassHandle(); | |
6002 | if (cd && (sym == cd || cd.isBaseOf(sym, null))) | |
6003 | return Type.deduceWild(t, isRef); | |
6004 | ||
6005 | ubyte wm = 0; | |
6006 | ||
6007 | if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing)) | |
6008 | { | |
6009 | if (auto ato = aliasthisOf()) | |
6010 | { | |
6011 | att = cast(AliasThisRec)(att | AliasThisRec.tracing); | |
6012 | wm = ato.deduceWild(t, isRef); | |
6013 | att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); | |
6014 | } | |
6015 | } | |
6016 | ||
6017 | return wm; | |
6018 | } | |
6019 | ||
6020 | override inout(Type) toHeadMutable() inout | |
6021 | { | |
6022 | return this; | |
6023 | } | |
6024 | ||
610d7898 | 6025 | override bool isZeroInit(const ref Loc loc) |
5fee5ec3 IB |
6026 | { |
6027 | return true; | |
6028 | } | |
6029 | ||
610d7898 | 6030 | override bool isscope() |
5fee5ec3 IB |
6031 | { |
6032 | return sym.stack; | |
6033 | } | |
6034 | ||
610d7898 | 6035 | override bool isBoolean() |
5fee5ec3 IB |
6036 | { |
6037 | return true; | |
6038 | } | |
6039 | ||
610d7898 | 6040 | override bool hasPointers() |
5fee5ec3 IB |
6041 | { |
6042 | return true; | |
6043 | } | |
6044 | ||
6045 | override void accept(Visitor v) | |
6046 | { | |
6047 | v.visit(this); | |
6048 | } | |
6049 | } | |
6050 | ||
6051 | /*********************************************************** | |
6052 | */ | |
6053 | extern (C++) final class TypeTuple : Type | |
6054 | { | |
6055 | // 'logically immutable' cached global - don't modify! | |
6056 | __gshared TypeTuple empty = new TypeTuple(); | |
6057 | ||
6058 | Parameters* arguments; // types making up the tuple | |
6059 | ||
6060 | extern (D) this(Parameters* arguments) | |
6061 | { | |
6062 | super(Ttuple); | |
6063 | //printf("TypeTuple(this = %p)\n", this); | |
6064 | this.arguments = arguments; | |
6065 | //printf("TypeTuple() %p, %s\n", this, toChars()); | |
6066 | debug | |
6067 | { | |
6068 | if (arguments) | |
6069 | { | |
6070 | for (size_t i = 0; i < arguments.dim; i++) | |
6071 | { | |
6072 | Parameter arg = (*arguments)[i]; | |
6073 | assert(arg && arg.type); | |
6074 | } | |
6075 | } | |
6076 | } | |
6077 | } | |
6078 | ||
6079 | /**************** | |
6080 | * Form TypeTuple from the types of the expressions. | |
6081 | * Assume exps[] is already tuple expanded. | |
6082 | */ | |
6083 | extern (D) this(Expressions* exps) | |
6084 | { | |
6085 | super(Ttuple); | |
c8dfa79c | 6086 | auto arguments = new Parameters(exps ? exps.dim : 0); |
5fee5ec3 IB |
6087 | if (exps) |
6088 | { | |
5fee5ec3 IB |
6089 | for (size_t i = 0; i < exps.dim; i++) |
6090 | { | |
6091 | Expression e = (*exps)[i]; | |
6092 | if (e.type.ty == Ttuple) | |
6093 | e.error("cannot form tuple of tuples"); | |
6094 | auto arg = new Parameter(STC.undefined_, e.type, null, null, null); | |
6095 | (*arguments)[i] = arg; | |
6096 | } | |
6097 | } | |
6098 | this.arguments = arguments; | |
6099 | //printf("TypeTuple() %p, %s\n", this, toChars()); | |
6100 | } | |
6101 | ||
6102 | static TypeTuple create(Parameters* arguments) | |
6103 | { | |
6104 | return new TypeTuple(arguments); | |
6105 | } | |
6106 | ||
6107 | /******************************************* | |
6108 | * Type tuple with 0, 1 or 2 types in it. | |
6109 | */ | |
6110 | extern (D) this() | |
6111 | { | |
6112 | super(Ttuple); | |
6113 | arguments = new Parameters(); | |
6114 | } | |
6115 | ||
6116 | extern (D) this(Type t1) | |
6117 | { | |
6118 | super(Ttuple); | |
6119 | arguments = new Parameters(); | |
6120 | arguments.push(new Parameter(0, t1, null, null, null)); | |
6121 | } | |
6122 | ||
6123 | extern (D) this(Type t1, Type t2) | |
6124 | { | |
6125 | super(Ttuple); | |
6126 | arguments = new Parameters(); | |
6127 | arguments.push(new Parameter(0, t1, null, null, null)); | |
6128 | arguments.push(new Parameter(0, t2, null, null, null)); | |
6129 | } | |
6130 | ||
6131 | static TypeTuple create() | |
6132 | { | |
6133 | return new TypeTuple(); | |
6134 | } | |
6135 | ||
6136 | static TypeTuple create(Type t1) | |
6137 | { | |
6138 | return new TypeTuple(t1); | |
6139 | } | |
6140 | ||
6141 | static TypeTuple create(Type t1, Type t2) | |
6142 | { | |
6143 | return new TypeTuple(t1, t2); | |
6144 | } | |
6145 | ||
6146 | override const(char)* kind() const | |
6147 | { | |
6148 | return "tuple"; | |
6149 | } | |
6150 | ||
6151 | override TypeTuple syntaxCopy() | |
6152 | { | |
6153 | Parameters* args = Parameter.arraySyntaxCopy(arguments); | |
6154 | auto t = new TypeTuple(args); | |
6155 | t.mod = mod; | |
6156 | return t; | |
6157 | } | |
6158 | ||
6159 | override bool equals(const RootObject o) const | |
6160 | { | |
6161 | Type t = cast(Type)o; | |
6162 | //printf("TypeTuple::equals(%s, %s)\n", toChars(), t.toChars()); | |
6163 | if (this == t) | |
6164 | return true; | |
6165 | if (auto tt = t.isTypeTuple()) | |
6166 | { | |
6167 | if (arguments.dim == tt.arguments.dim) | |
6168 | { | |
6169 | for (size_t i = 0; i < tt.arguments.dim; i++) | |
6170 | { | |
6171 | const Parameter arg1 = (*arguments)[i]; | |
6172 | Parameter arg2 = (*tt.arguments)[i]; | |
6173 | if (!arg1.type.equals(arg2.type)) | |
6174 | return false; | |
6175 | } | |
6176 | return true; | |
6177 | } | |
6178 | } | |
6179 | return false; | |
6180 | } | |
6181 | ||
0fb57034 IB |
6182 | override MATCH implicitConvTo(Type to) |
6183 | { | |
6184 | if (this == to) | |
6185 | return MATCH.exact; | |
6186 | if (auto tt = to.isTypeTuple()) | |
6187 | { | |
6188 | if (arguments.dim == tt.arguments.dim) | |
6189 | { | |
6190 | MATCH m = MATCH.exact; | |
6191 | for (size_t i = 0; i < tt.arguments.dim; i++) | |
6192 | { | |
6193 | Parameter arg1 = (*arguments)[i]; | |
6194 | Parameter arg2 = (*tt.arguments)[i]; | |
6195 | MATCH mi = arg1.type.implicitConvTo(arg2.type); | |
6196 | if (mi < m) | |
6197 | m = mi; | |
6198 | } | |
6199 | return m; | |
6200 | } | |
6201 | } | |
6202 | return MATCH.nomatch; | |
6203 | } | |
6204 | ||
5fee5ec3 IB |
6205 | override void accept(Visitor v) |
6206 | { | |
6207 | v.visit(this); | |
6208 | } | |
6209 | } | |
6210 | ||
6211 | /*********************************************************** | |
6212 | * This is so we can slice a TypeTuple | |
6213 | */ | |
6214 | extern (C++) final class TypeSlice : TypeNext | |
6215 | { | |
6216 | Expression lwr; | |
6217 | Expression upr; | |
6218 | ||
6219 | extern (D) this(Type next, Expression lwr, Expression upr) | |
6220 | { | |
6221 | super(Tslice, next); | |
6222 | //printf("TypeSlice[%s .. %s]\n", lwr.toChars(), upr.toChars()); | |
6223 | this.lwr = lwr; | |
6224 | this.upr = upr; | |
6225 | } | |
6226 | ||
6227 | override const(char)* kind() const | |
6228 | { | |
6229 | return "slice"; | |
6230 | } | |
6231 | ||
6232 | override TypeSlice syntaxCopy() | |
6233 | { | |
6234 | auto t = new TypeSlice(next.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy()); | |
6235 | t.mod = mod; | |
6236 | return t; | |
6237 | } | |
6238 | ||
6239 | override void accept(Visitor v) | |
6240 | { | |
6241 | v.visit(this); | |
6242 | } | |
6243 | } | |
6244 | ||
6245 | /*********************************************************** | |
6246 | */ | |
6247 | extern (C++) final class TypeNull : Type | |
6248 | { | |
6249 | extern (D) this() | |
6250 | { | |
6251 | //printf("TypeNull %p\n", this); | |
6252 | super(Tnull); | |
6253 | } | |
6254 | ||
6255 | override const(char)* kind() const | |
6256 | { | |
6257 | return "null"; | |
6258 | } | |
6259 | ||
6260 | override TypeNull syntaxCopy() | |
6261 | { | |
6262 | // No semantic analysis done, no need to copy | |
6263 | return this; | |
6264 | } | |
6265 | ||
6266 | override MATCH implicitConvTo(Type to) | |
6267 | { | |
6268 | //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to); | |
6269 | //printf("from: %s\n", toChars()); | |
6270 | //printf("to : %s\n", to.toChars()); | |
6271 | MATCH m = Type.implicitConvTo(to); | |
6272 | if (m != MATCH.nomatch) | |
6273 | return m; | |
6274 | ||
6275 | // NULL implicitly converts to any pointer type or dynamic array | |
6276 | //if (type.ty == Tpointer && type.nextOf().ty == Tvoid) | |
6277 | { | |
6278 | Type tb = to.toBasetype(); | |
6279 | if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate) | |
6280 | return MATCH.constant; | |
6281 | } | |
6282 | ||
6283 | return MATCH.nomatch; | |
6284 | } | |
6285 | ||
6286 | override bool hasPointers() | |
6287 | { | |
6288 | /* Although null isn't dereferencable, treat it as a pointer type for | |
6289 | * attribute inference, generic code, etc. | |
6290 | */ | |
6291 | return true; | |
6292 | } | |
6293 | ||
610d7898 | 6294 | override bool isBoolean() |
5fee5ec3 IB |
6295 | { |
6296 | return true; | |
6297 | } | |
6298 | ||
610d7898 | 6299 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
6300 | { |
6301 | return tvoidptr.size(loc); | |
6302 | } | |
6303 | ||
6304 | override void accept(Visitor v) | |
6305 | { | |
6306 | v.visit(this); | |
6307 | } | |
6308 | } | |
6309 | ||
6310 | /*********************************************************** | |
6311 | */ | |
6312 | extern (C++) final class TypeNoreturn : Type | |
6313 | { | |
6314 | extern (D) this() | |
6315 | { | |
6316 | //printf("TypeNoreturn %p\n", this); | |
6317 | super(Tnoreturn); | |
6318 | } | |
6319 | ||
6320 | override const(char)* kind() const | |
6321 | { | |
6322 | return "noreturn"; | |
6323 | } | |
6324 | ||
6325 | override TypeNoreturn syntaxCopy() | |
6326 | { | |
6327 | // No semantic analysis done, no need to copy | |
6328 | return this; | |
6329 | } | |
6330 | ||
6331 | override MATCH implicitConvTo(Type to) | |
6332 | { | |
6333 | //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to); | |
6334 | //printf("from: %s\n", toChars()); | |
6335 | //printf("to : %s\n", to.toChars()); | |
6336 | if (this.equals(to)) | |
6337 | return MATCH.exact; | |
6338 | ||
6339 | // Different qualifiers? | |
6340 | if (to.ty == Tnoreturn) | |
6341 | return MATCH.constant; | |
6342 | ||
6343 | // Implicitly convertible to any type | |
6344 | return MATCH.convert; | |
6345 | } | |
6346 | ||
6347 | override MATCH constConv(Type to) | |
6348 | { | |
6349 | // Either another noreturn or conversion to any type | |
6350 | return this.implicitConvTo(to); | |
6351 | } | |
6352 | ||
610d7898 | 6353 | override bool isBoolean() |
5fee5ec3 IB |
6354 | { |
6355 | return true; // bottom type can be implicitly converted to any other type | |
6356 | } | |
6357 | ||
610d7898 | 6358 | override uinteger_t size(const ref Loc loc) |
5fee5ec3 IB |
6359 | { |
6360 | return 0; | |
6361 | } | |
6362 | ||
6363 | override uint alignsize() | |
6364 | { | |
6365 | return 0; | |
6366 | } | |
6367 | ||
6368 | override void accept(Visitor v) | |
6369 | { | |
6370 | v.visit(this); | |
6371 | } | |
6372 | } | |
6373 | ||
6374 | /*********************************************************** | |
6375 | * Unlike D, C can declare/define struct/union/enum tag names | |
6376 | * inside Declarators, instead of separately as in D. | |
6377 | * The order these appear in the symbol table must be in lexical | |
6378 | * order. There isn't enough info at the parsing stage to determine if | |
6379 | * it's a declaration or a reference to an existing name, so this Type | |
6380 | * collects the necessary info and defers it to semantic(). | |
6381 | */ | |
6382 | extern (C++) final class TypeTag : Type | |
6383 | { | |
6384 | Loc loc; /// location of declaration | |
6385 | TOK tok; /// TOK.struct_, TOK.union_, TOK.enum_ | |
6386 | Identifier id; /// tag name identifier | |
d7569187 | 6387 | Type base; /// base type for enums otherwise null |
5fee5ec3 IB |
6388 | Dsymbols* members; /// members of struct, null if none |
6389 | ||
6390 | Type resolved; /// type after semantic() in case there are more others | |
6391 | /// pointing to this instance, which can happen with | |
6392 | /// struct S { int a; } s1, *s2; | |
208fbc77 | 6393 | MOD mod; /// modifiers to apply after type is resolved (only MODFlags.const_ at the moment) |
5fee5ec3 | 6394 | |
d7569187 | 6395 | extern (D) this(const ref Loc loc, TOK tok, Identifier id, Type base, Dsymbols* members) |
5fee5ec3 | 6396 | { |
208fbc77 | 6397 | //printf("TypeTag ctor %s %p\n", id ? id.toChars() : "null".ptr, this); |
5fee5ec3 IB |
6398 | super(Ttag); |
6399 | this.loc = loc; | |
6400 | this.tok = tok; | |
6401 | this.id = id; | |
d7569187 | 6402 | this.base = base; |
5fee5ec3 | 6403 | this.members = members; |
208fbc77 | 6404 | this.mod = 0; |
5fee5ec3 IB |
6405 | } |
6406 | ||
6407 | override const(char)* kind() const | |
6408 | { | |
6409 | return "tag"; | |
6410 | } | |
6411 | ||
6412 | override TypeTag syntaxCopy() | |
6413 | { | |
208fbc77 | 6414 | //printf("TypeTag syntaxCopy()\n"); |
5fee5ec3 IB |
6415 | // No semantic analysis done, no need to copy |
6416 | return this; | |
6417 | } | |
6418 | ||
6419 | override void accept(Visitor v) | |
6420 | { | |
6421 | v.visit(this); | |
6422 | } | |
6423 | } | |
6424 | ||
6425 | /*********************************************************** | |
6426 | * Represents a function's formal parameters + variadics info. | |
6427 | * Length, indexing and iteration are based on a depth-first tuple expansion. | |
6428 | * https://dlang.org/spec/function.html#ParameterList | |
6429 | */ | |
6430 | extern (C++) struct ParameterList | |
6431 | { | |
6432 | /// The raw (unexpanded) formal parameters, possibly containing tuples. | |
6433 | Parameters* parameters; | |
6434 | StorageClass stc; // storage class of ... | |
6435 | VarArg varargs = VarArg.none; | |
6436 | bool hasIdentifierList; // true if C identifier-list style | |
6437 | ||
6438 | this(Parameters* parameters, VarArg varargs = VarArg.none, StorageClass stc = 0) | |
6439 | { | |
6440 | this.parameters = parameters; | |
6441 | this.varargs = varargs; | |
6442 | this.stc = stc; | |
6443 | } | |
6444 | ||
6445 | /// Returns the number of expanded parameters. Complexity: O(N). | |
6446 | size_t length() | |
6447 | { | |
6448 | return Parameter.dim(parameters); | |
6449 | } | |
6450 | ||
6451 | /// Returns the expanded parameter at the given index, or null if out of | |
6452 | /// bounds. Complexity: O(i). | |
6453 | Parameter opIndex(size_t i) | |
6454 | { | |
6455 | return Parameter.getNth(parameters, i); | |
6456 | } | |
6457 | ||
6458 | /// Iterates over the expanded parameters. Complexity: O(N). | |
6459 | /// Prefer this to avoid the O(N + N^2/2) complexity of calculating length | |
6460 | /// and calling N times opIndex. | |
6461 | extern (D) int opApply(scope Parameter.ForeachDg dg) | |
6462 | { | |
6463 | return Parameter._foreach(parameters, dg); | |
6464 | } | |
6465 | ||
6466 | /// Iterates over the expanded parameters, matching them with the unexpanded | |
6467 | /// ones, for semantic processing | |
6468 | extern (D) int opApply(scope Parameter.SemanticForeachDg dg) | |
6469 | { | |
6470 | return Parameter._foreach(this.parameters, dg); | |
6471 | } | |
6472 | ||
6473 | extern (D) ParameterList syntaxCopy() | |
6474 | { | |
6475 | return ParameterList(Parameter.arraySyntaxCopy(parameters), varargs); | |
6476 | } | |
6477 | ||
6478 | /// Compares this to another ParameterList (and expands tuples if necessary) | |
6479 | extern (D) bool opEquals(scope ref ParameterList other) const | |
6480 | { | |
6481 | if (stc != other.stc || varargs != other.varargs || (!parameters != !other.parameters)) | |
6482 | return false; | |
6483 | ||
6484 | if (this.parameters is other.parameters) | |
6485 | return true; | |
6486 | ||
6487 | size_t idx; | |
6488 | bool diff; | |
6489 | ||
6490 | // Pairwise compare each parameter | |
6491 | // Can this avoid the O(n) indexing for the second list? | |
6492 | foreach (_, p1; cast() this) | |
6493 | { | |
6494 | auto p2 = other[idx++]; | |
6495 | if (!p2 || p1 != p2) { | |
6496 | diff = true; | |
6497 | break; | |
6498 | } | |
6499 | } | |
6500 | ||
6501 | // Ensure no remaining parameters in `other` | |
6502 | return !diff && other[idx] is null; | |
6503 | } | |
6504 | } | |
6505 | ||
6506 | ||
6507 | /*********************************************************** | |
6508 | */ | |
6509 | extern (C++) final class Parameter : ASTNode | |
6510 | { | |
6511 | import dmd.attrib : UserAttributeDeclaration; | |
6512 | ||
6513 | StorageClass storageClass; | |
6514 | Type type; | |
6515 | Identifier ident; | |
6516 | Expression defaultArg; | |
6517 | UserAttributeDeclaration userAttribDecl; // user defined attributes | |
6518 | ||
6519 | extern (D) this(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) | |
6520 | { | |
6521 | this.type = type; | |
6522 | this.ident = ident; | |
6523 | this.storageClass = storageClass; | |
6524 | this.defaultArg = defaultArg; | |
6525 | this.userAttribDecl = userAttribDecl; | |
6526 | } | |
6527 | ||
6528 | static Parameter create(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) | |
6529 | { | |
6530 | return new Parameter(storageClass, type, ident, defaultArg, userAttribDecl); | |
6531 | } | |
6532 | ||
6533 | Parameter syntaxCopy() | |
6534 | { | |
6535 | return new Parameter(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? userAttribDecl.syntaxCopy(null) : null); | |
6536 | } | |
6537 | ||
6538 | /**************************************************** | |
6539 | * Determine if parameter is a lazy array of delegates. | |
6540 | * If so, return the return type of those delegates. | |
6541 | * If not, return NULL. | |
6542 | * | |
6543 | * Returns T if the type is one of the following forms: | |
6544 | * T delegate()[] | |
6545 | * T delegate()[dim] | |
6546 | */ | |
6547 | Type isLazyArray() | |
6548 | { | |
6549 | Type tb = type.toBasetype(); | |
6550 | if (tb.ty == Tsarray || tb.ty == Tarray) | |
6551 | { | |
6552 | Type tel = (cast(TypeArray)tb).next.toBasetype(); | |
6553 | if (auto td = tel.isTypeDelegate()) | |
6554 | { | |
6555 | TypeFunction tf = td.next.toTypeFunction(); | |
6556 | if (tf.parameterList.varargs == VarArg.none && tf.parameterList.length == 0) | |
6557 | { | |
6558 | return tf.next; // return type of delegate | |
6559 | } | |
6560 | } | |
6561 | } | |
6562 | return null; | |
6563 | } | |
6564 | ||
ec486b73 IB |
6565 | /// Returns: Whether the function parameter is lazy |
6566 | bool isLazy() const @safe pure nothrow @nogc | |
6567 | { | |
6568 | return (this.storageClass & (STC.lazy_)) != 0; | |
6569 | } | |
6570 | ||
5fee5ec3 IB |
6571 | /// Returns: Whether the function parameter is a reference (out / ref) |
6572 | bool isReference() const @safe pure nothrow @nogc | |
6573 | { | |
6574 | return (this.storageClass & (STC.ref_ | STC.out_)) != 0; | |
6575 | } | |
6576 | ||
6577 | // kludge for template.isType() | |
6578 | override DYNCAST dyncast() const | |
6579 | { | |
6580 | return DYNCAST.parameter; | |
6581 | } | |
6582 | ||
6583 | override void accept(Visitor v) | |
6584 | { | |
6585 | v.visit(this); | |
6586 | } | |
6587 | ||
6588 | extern (D) static Parameters* arraySyntaxCopy(Parameters* parameters) | |
6589 | { | |
6590 | Parameters* params = null; | |
6591 | if (parameters) | |
6592 | { | |
6593 | params = new Parameters(parameters.dim); | |
6594 | for (size_t i = 0; i < params.dim; i++) | |
6595 | (*params)[i] = (*parameters)[i].syntaxCopy(); | |
6596 | } | |
6597 | return params; | |
6598 | } | |
6599 | ||
6600 | /*************************************** | |
6601 | * Determine number of arguments, folding in tuples. | |
6602 | */ | |
6603 | static size_t dim(Parameters* parameters) | |
6604 | { | |
6605 | size_t nargs = 0; | |
6606 | ||
6607 | int dimDg(size_t n, Parameter p) | |
6608 | { | |
6609 | ++nargs; | |
6610 | return 0; | |
6611 | } | |
6612 | ||
6613 | _foreach(parameters, &dimDg); | |
6614 | return nargs; | |
6615 | } | |
6616 | ||
6617 | /** | |
6618 | * Get nth `Parameter`, folding in tuples. | |
6619 | * | |
6620 | * Since `parameters` can include tuples, which would increase its | |
6621 | * length, this function allows to get the `nth` parameter as if | |
6622 | * all tuples transitively contained in `parameters` were flattened. | |
6623 | * | |
6624 | * Params: | |
6625 | * parameters = Array of `Parameter` to iterate over | |
6626 | * nth = Index of the desired parameter. | |
6627 | * | |
6628 | * Returns: | |
6629 | * The parameter at index `nth` (taking tuples into account), | |
6630 | * or `null` if out of bound. | |
6631 | */ | |
6632 | static Parameter getNth(Parameters* parameters, size_t nth) | |
6633 | { | |
6634 | Parameter param; | |
6635 | ||
6636 | int getNthParamDg(size_t n, Parameter p) | |
6637 | { | |
6638 | if (n == nth) | |
6639 | { | |
6640 | param = p; | |
6641 | return 1; | |
6642 | } | |
6643 | return 0; | |
6644 | } | |
6645 | ||
6646 | int res = _foreach(parameters, &getNthParamDg); | |
6647 | return res ? param : null; | |
6648 | } | |
6649 | ||
6650 | /// Type of delegate when iterating solely on the parameters | |
6651 | alias ForeachDg = extern (D) int delegate(size_t paramidx, Parameter param); | |
6652 | /// Type of delegate when iterating on both the original set of parameters, | |
6653 | /// and the type tuple. Useful for semantic analysis. | |
6654 | /// 'o' stands for 'original' and 'e' stands for 'expanded'. | |
6655 | alias SemanticForeachDg = extern (D) int delegate( | |
6656 | size_t oidx, Parameter oparam, size_t eidx, Parameter eparam); | |
6657 | ||
6658 | /*************************************** | |
6659 | * Expands tuples in args in depth first order. Calls | |
6660 | * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter. | |
6661 | * If dg returns !=0, stops and returns that value else returns 0. | |
6662 | * Use this function to avoid the O(N + N^2/2) complexity of | |
6663 | * calculating dim and calling N times getNth. | |
6664 | */ | |
6665 | extern (D) static int _foreach(Parameters* parameters, scope ForeachDg dg) | |
6666 | { | |
6667 | assert(dg !is null); | |
6668 | return _foreach(parameters, (_oidx, _oparam, idx, param) => dg(idx, param)); | |
6669 | } | |
6670 | ||
6671 | /// Ditto | |
6672 | extern (D) static int _foreach( | |
6673 | Parameters* parameters, scope SemanticForeachDg dg) | |
6674 | { | |
6675 | assert(dg !is null); | |
6676 | if (parameters is null) | |
6677 | return 0; | |
6678 | ||
6679 | size_t eidx; | |
6680 | foreach (oidx; 0 .. parameters.length) | |
6681 | { | |
6682 | Parameter oparam = (*parameters)[oidx]; | |
6683 | if (auto r = _foreachImpl(dg, oidx, oparam, eidx, /* eparam */ oparam)) | |
6684 | return r; | |
6685 | } | |
6686 | return 0; | |
6687 | } | |
6688 | ||
6689 | /// Implementation of the iteration process, which recurses in itself | |
6690 | /// and just forwards `oidx` and `oparam`. | |
6691 | extern (D) private static int _foreachImpl(scope SemanticForeachDg dg, | |
6692 | size_t oidx, Parameter oparam, ref size_t eidx, Parameter eparam) | |
6693 | { | |
6694 | if (eparam is null) | |
6695 | return 0; | |
6696 | ||
6697 | Type t = eparam.type.toBasetype(); | |
6698 | if (auto tu = t.isTypeTuple()) | |
6699 | { | |
6700 | // Check for empty tuples | |
6701 | if (tu.arguments is null) | |
6702 | return 0; | |
6703 | ||
6704 | foreach (nidx; 0 .. tu.arguments.length) | |
6705 | { | |
6706 | Parameter nextep = (*tu.arguments)[nidx]; | |
6707 | if (auto r = _foreachImpl(dg, oidx, oparam, eidx, nextep)) | |
6708 | return r; | |
6709 | } | |
6710 | } | |
6711 | else | |
6712 | { | |
6713 | if (auto r = dg(oidx, oparam, eidx, eparam)) | |
6714 | return r; | |
6715 | // The only place where we should increment eidx is here, | |
6716 | // as a TypeTuple doesn't count as a parameter (for arity) | |
6717 | // it it is empty. | |
6718 | eidx++; | |
6719 | } | |
6720 | return 0; | |
6721 | } | |
6722 | ||
6723 | override const(char)* toChars() const | |
6724 | { | |
6725 | return ident ? ident.toChars() : "__anonymous_param"; | |
6726 | } | |
6727 | ||
6728 | /********************************* | |
6729 | * Compute covariance of parameters `this` and `p` | |
6730 | * as determined by the storage classes of both. | |
6731 | * | |
6732 | * Params: | |
6733 | * returnByRef = true if the function returns by ref | |
6734 | * p = Parameter to compare with | |
6735 | * previewIn = Whether `-preview=in` is being used, and thus if | |
6736 | * `in` means `scope [ref]`. | |
6737 | * | |
6738 | * Returns: | |
6739 | * true = `this` can be used in place of `p` | |
6740 | * false = nope | |
6741 | */ | |
6742 | bool isCovariant(bool returnByRef, const Parameter p, bool previewIn = global.params.previewIn) | |
6743 | const pure nothrow @nogc @safe | |
6744 | { | |
6745 | ulong thisSTC = this.storageClass; | |
6746 | ulong otherSTC = p.storageClass; | |
6747 | ||
6748 | if (previewIn) | |
6749 | { | |
6750 | if (thisSTC & STC.in_) | |
6751 | thisSTC |= STC.scope_; | |
6752 | if (otherSTC & STC.in_) | |
6753 | otherSTC |= STC.scope_; | |
6754 | } | |
6755 | ||
6756 | const mask = STC.ref_ | STC.out_ | STC.lazy_ | (previewIn ? STC.in_ : 0); | |
6757 | if ((thisSTC & mask) != (otherSTC & mask)) | |
6758 | return false; | |
6759 | return isCovariantScope(returnByRef, thisSTC, otherSTC); | |
6760 | } | |
6761 | ||
6762 | extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe | |
6763 | { | |
235d5a96 IB |
6764 | // Workaround for failing covariance when finding a common type of delegates, |
6765 | // some of which have parameters with inferred scope | |
6766 | // https://issues.dlang.org/show_bug.cgi?id=21285 | |
6767 | // The root cause is that scopeinferred is not part of the mangle, and mangle | |
6768 | // is used for type equality checks | |
6769 | if (to & STC.returninferred) | |
6770 | to &= ~STC.return_; | |
6771 | // note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope | |
6772 | if (to & STC.scopeinferred && !(to & STC.return_)) | |
6773 | to &= ~STC.scope_; | |
6774 | ||
5fee5ec3 IB |
6775 | if (from == to) |
6776 | return true; | |
6777 | ||
6778 | /* result is true if the 'from' can be used as a 'to' | |
6779 | */ | |
6780 | ||
6781 | if ((from ^ to) & STC.ref_) // differing in 'ref' means no covariance | |
6782 | return false; | |
6783 | ||
6784 | /* workaround until we get STC.returnScope reliably set correctly | |
6785 | */ | |
6786 | if (returnByRef) | |
6787 | { | |
6788 | from &= ~STC.returnScope; | |
6789 | to &= ~STC.returnScope; | |
6790 | } | |
6791 | else | |
6792 | { | |
6793 | from |= STC.returnScope; | |
6794 | to |= STC.returnScope; | |
6795 | } | |
6796 | return covariant[buildScopeRef(from)][buildScopeRef(to)]; | |
6797 | } | |
6798 | ||
6799 | extern (D) private static bool[ScopeRef.max + 1][ScopeRef.max + 1] covariantInit() pure nothrow @nogc @safe | |
6800 | { | |
6801 | /* Initialize covariant[][] with this: | |
6802 | ||
6803 | From\To n rs s | |
6804 | None X | |
6805 | ReturnScope X X | |
6806 | Scope X X X | |
6807 | ||
6808 | From\To r rr rs rr-s r-rs | |
6809 | Ref X X | |
6810 | ReturnRef X | |
6811 | RefScope X X X X X | |
6812 | ReturnRef-Scope X X | |
6813 | Ref-ReturnScope X X X | |
6814 | */ | |
6815 | bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant; | |
6816 | ||
6817 | foreach (i; 0 .. ScopeRef.max + 1) | |
6818 | { | |
6819 | covariant[i][i] = true; | |
6820 | covariant[ScopeRef.RefScope][i] = true; | |
6821 | } | |
6822 | covariant[ScopeRef.ReturnScope][ScopeRef.None] = true; | |
6823 | covariant[ScopeRef.Scope ][ScopeRef.None] = true; | |
6824 | covariant[ScopeRef.Scope ][ScopeRef.ReturnScope] = true; | |
6825 | ||
6826 | covariant[ScopeRef.Ref ][ScopeRef.ReturnRef] = true; | |
6827 | covariant[ScopeRef.ReturnRef_Scope][ScopeRef.ReturnRef] = true; | |
6828 | covariant[ScopeRef.Ref_ReturnScope][ScopeRef.Ref ] = true; | |
6829 | covariant[ScopeRef.Ref_ReturnScope][ScopeRef.ReturnRef] = true; | |
6830 | ||
6831 | return covariant; | |
6832 | } | |
6833 | ||
6834 | extern (D) private static immutable bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant = covariantInit(); | |
6835 | ||
6836 | extern (D) bool opEquals(const Parameter other) const | |
6837 | { | |
6838 | return this.storageClass == other.storageClass | |
6839 | && this.type == other.type; | |
6840 | } | |
6841 | } | |
6842 | ||
6843 | /************************************************************* | |
6844 | * For printing two types with qualification when necessary. | |
6845 | * Params: | |
6846 | * t1 = The first type to receive the type name for | |
6847 | * t2 = The second type to receive the type name for | |
6848 | * Returns: | |
6849 | * The fully-qualified names of both types if the two type names are not the same, | |
6850 | * or the unqualified names of both types if the two type names are the same. | |
6851 | */ | |
6852 | const(char*)[2] toAutoQualChars(Type t1, Type t2) | |
6853 | { | |
6854 | auto s1 = t1.toChars(); | |
6855 | auto s2 = t2.toChars(); | |
6856 | // show qualification only if it's different | |
6857 | if (!t1.equals(t2) && strcmp(s1, s2) == 0) | |
6858 | { | |
6859 | s1 = t1.toPrettyChars(true); | |
6860 | s2 = t2.toPrettyChars(true); | |
6861 | } | |
6862 | return [s1, s2]; | |
6863 | } | |
6864 | ||
6865 | ||
6866 | /** | |
6867 | * For each active modifier (MODFlags.const_, MODFlags.immutable_, etc) call `fp` with a | |
6868 | * void* for the work param and a string representation of the attribute. | |
6869 | */ | |
6870 | void modifiersApply(const TypeFunction tf, void delegate(string) dg) | |
6871 | { | |
6872 | immutable ubyte[4] modsArr = [MODFlags.const_, MODFlags.immutable_, MODFlags.wild, MODFlags.shared_]; | |
6873 | ||
6874 | foreach (modsarr; modsArr) | |
6875 | { | |
6876 | if (tf.mod & modsarr) | |
6877 | { | |
6878 | dg(MODtoString(modsarr)); | |
6879 | } | |
6880 | } | |
6881 | } | |
6882 | ||
6883 | /** | |
6884 | * For each active attribute (ref/const/nogc/etc) call `fp` with a void* for the | |
6885 | * work param and a string representation of the attribute. | |
6886 | */ | |
6887 | void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTformat trustFormat = TRUSTformatDefault) | |
6888 | { | |
6889 | if (tf.purity) | |
6890 | dg("pure"); | |
6891 | if (tf.isnothrow) | |
6892 | dg("nothrow"); | |
6893 | if (tf.isnogc) | |
6894 | dg("@nogc"); | |
6895 | if (tf.isproperty) | |
6896 | dg("@property"); | |
6897 | if (tf.isref) | |
6898 | dg("ref"); | |
6899 | if (tf.isreturn && !tf.isreturninferred) | |
6900 | dg("return"); | |
6901 | if (tf.isScopeQual && !tf.isscopeinferred) | |
6902 | dg("scope"); | |
6903 | if (tf.islive) | |
6904 | dg("@live"); | |
6905 | ||
6906 | TRUST trustAttrib = tf.trust; | |
6907 | ||
6908 | if (trustAttrib == TRUST.default_) | |
6909 | { | |
6384eff5 IB |
6910 | if (trustFormat != TRUSTformatSystem) |
6911 | return; | |
6912 | trustAttrib = TRUST.system; // avoid calling with an empty string | |
5fee5ec3 IB |
6913 | } |
6914 | ||
6915 | dg(trustToString(trustAttrib)); | |
6916 | } | |
6917 | ||
6918 | /** | |
6919 | * If the type is a class or struct, returns the symbol for it, | |
6920 | * else null. | |
6921 | */ | |
6922 | extern (C++) AggregateDeclaration isAggregate(Type t) | |
6923 | { | |
6924 | t = t.toBasetype(); | |
6925 | if (t.ty == Tclass) | |
6926 | return (cast(TypeClass)t).sym; | |
6927 | if (t.ty == Tstruct) | |
6928 | return (cast(TypeStruct)t).sym; | |
6929 | return null; | |
6930 | } | |
6931 | ||
6932 | /*************************************************** | |
6933 | * Determine if type t can be indexed or sliced given that it is not an | |
6934 | * aggregate with operator overloads. | |
6935 | * Params: | |
6936 | * t = type to check | |
6937 | * Returns: | |
6938 | * true if an expression of type t can be e1 in an array expression | |
6939 | */ | |
6940 | bool isIndexableNonAggregate(Type t) | |
6941 | { | |
6942 | t = t.toBasetype(); | |
6943 | return (t.ty == Tpointer || t.ty == Tsarray || t.ty == Tarray || t.ty == Taarray || | |
6944 | t.ty == Ttuple || t.ty == Tvector); | |
6945 | } | |
6946 | ||
6947 | /*************************************************** | |
6948 | * Determine if type t is copyable. | |
6949 | * Params: | |
6950 | * t = type to check | |
6951 | * Returns: | |
6952 | * true if we can copy it | |
6953 | */ | |
6954 | bool isCopyable(Type t) | |
6955 | { | |
6956 | //printf("isCopyable() %s\n", t.toChars()); | |
6957 | if (auto ts = t.isTypeStruct()) | |
6958 | { | |
6959 | if (ts.sym.postblit && | |
6960 | ts.sym.postblit.storage_class & STC.disable) | |
6961 | return false; | |
6962 | if (ts.sym.hasCopyCtor) | |
6963 | { | |
6964 | // check if there is a matching overload of the copy constructor and whether it is disabled or not | |
6965 | // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 | |
6966 | Dsymbol ctor = search_function(ts.sym, Id.ctor); | |
6967 | assert(ctor); | |
6968 | scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue | |
6969 | el.type = cast() ts; | |
6970 | Expressions args; | |
6971 | args.push(el); | |
6972 | FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, &args, FuncResolveFlag.quiet); | |
6973 | if (!f || f.storage_class & STC.disable) | |
6974 | return false; | |
6975 | } | |
6976 | } | |
6977 | return true; | |
6978 | } | |
6979 | ||
6980 | /*************************************** | |
6981 | * Computes how a parameter may be returned. | |
6982 | * Shrinking the representation is necessary because StorageClass is so wide | |
6983 | * Params: | |
6984 | * stc = storage class of parameter | |
6985 | * Returns: | |
6986 | * value from enum ScopeRef | |
6987 | */ | |
6988 | ScopeRef buildScopeRef(StorageClass stc) pure nothrow @nogc @safe | |
6989 | { | |
6990 | if (stc & STC.out_) | |
6991 | stc |= STC.ref_; // treat `out` and `ref` the same | |
6992 | ||
6993 | ScopeRef result; | |
6994 | final switch (stc & (STC.ref_ | STC.scope_ | STC.return_)) | |
6995 | { | |
6996 | case 0: result = ScopeRef.None; break; | |
6997 | ||
6998 | /* can occur in case test/compilable/testsctreturn.d | |
6999 | * related to https://issues.dlang.org/show_bug.cgi?id=20149 | |
7000 | * where inout adds `return` without `scope` or `ref` | |
7001 | */ | |
7002 | case STC.return_: result = ScopeRef.Return; break; | |
7003 | ||
7004 | case STC.ref_: result = ScopeRef.Ref; break; | |
7005 | case STC.scope_: result = ScopeRef.Scope; break; | |
7006 | case STC.return_ | STC.ref_: result = ScopeRef.ReturnRef; break; | |
7007 | case STC.return_ | STC.scope_: result = ScopeRef.ReturnScope; break; | |
7008 | case STC.ref_ | STC.scope_: result = ScopeRef.RefScope; break; | |
7009 | ||
7010 | case STC.return_ | STC.ref_ | STC.scope_: | |
7011 | result = stc & STC.returnScope ? ScopeRef.Ref_ReturnScope | |
7012 | : ScopeRef.ReturnRef_Scope; | |
7013 | break; | |
7014 | } | |
7015 | return result; | |
7016 | } | |
7017 | ||
7018 | /** | |
7019 | * Classification of 'scope-return-ref' possibilities | |
7020 | */ | |
7021 | enum ScopeRef | |
7022 | { | |
7023 | None, | |
7024 | Scope, | |
7025 | ReturnScope, | |
7026 | Ref, | |
7027 | ReturnRef, | |
7028 | RefScope, | |
7029 | ReturnRef_Scope, | |
7030 | Ref_ReturnScope, | |
7031 | Return, | |
7032 | } | |
7033 | ||
7034 | /********************************* | |
7035 | * Give us a nice string for debugging purposes. | |
7036 | * Params: | |
7037 | * sr = value | |
7038 | * Returns: | |
7039 | * corresponding string | |
7040 | */ | |
7041 | const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe | |
7042 | { | |
7043 | with (ScopeRef) | |
7044 | { | |
7045 | static immutable char*[ScopeRef.max + 1] names = | |
7046 | [ | |
7047 | None: "None", | |
7048 | Scope: "Scope", | |
7049 | ReturnScope: "ReturnScope", | |
7050 | Ref: "Ref", | |
7051 | ReturnRef: "ReturnRef", | |
7052 | RefScope: "RefScope", | |
7053 | ReturnRef_Scope: "ReturnRef_Scope", | |
7054 | Ref_ReturnScope: "Ref_ReturnScope", | |
7055 | Return: "Return", | |
7056 | ]; | |
7057 | return names[sr]; | |
7058 | } | |
7059 | } | |
c8dfa79c IB |
7060 | |
7061 | /** | |
7062 | * Used by `callMatch` to check if the copy constructor may be called to | |
7063 | * copy the argument | |
7064 | * | |
7065 | * This is done by seeing if a call to the copy constructor can be made: | |
7066 | * ``` | |
7067 | * typeof(tprm) __copytmp; | |
7068 | * copytmp.__copyCtor(arg); | |
7069 | * ``` | |
7070 | */ | |
7071 | private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, | |
7072 | Expression arg, Type tprm, Scope* sc, const(char)** pMessage) | |
7073 | { | |
7074 | auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); | |
7075 | tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; | |
7076 | tmp.dsymbolSemantic(sc); | |
7077 | Expression ve = new VarExp(arg.loc, tmp); | |
7078 | Expression e = new DotIdExp(arg.loc, ve, Id.ctor); | |
7079 | e = new CallExp(arg.loc, e, arg); | |
7080 | //printf("e = %s\n", e.toChars()); | |
7081 | if (.trySemantic(e, sc)) | |
7082 | return true; | |
7083 | ||
7084 | if (pMessage) | |
7085 | { | |
7086 | /* https://issues.dlang.org/show_bug.cgi?id=22202 | |
7087 | * | |
7088 | * If a function was deduced by semantic on the CallExp, | |
7089 | * it means that resolveFuncCall completed succesfully. | |
7090 | * Therefore, there exists a callable copy constructor, | |
7091 | * however, it cannot be called because scope constraints | |
7092 | * such as purity, safety or nogc. | |
7093 | */ | |
7094 | OutBuffer buf; | |
7095 | auto callExp = e.isCallExp(); | |
7096 | if (auto f = callExp.f) | |
7097 | { | |
7098 | char[] s; | |
7099 | if (!f.isPure && sc.func.setImpure()) | |
7100 | s ~= "pure "; | |
7101 | if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) | |
7102 | s ~= "@safe "; | |
7103 | if (!f.isNogc && sc.func.setGC()) | |
7104 | s ~= "nogc "; | |
7105 | if (s) | |
7106 | { | |
7107 | s[$-1] = '\0'; | |
7108 | buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); | |
7109 | } | |
7110 | else if (f.isGenerated() && f.isDisabled()) | |
7111 | { | |
7112 | /* https://issues.dlang.org/show_bug.cgi?id=23097 | |
7113 | * Compiler generated copy constructor failed. | |
7114 | */ | |
7115 | buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", | |
7116 | argStruct.toChars()); | |
7117 | } | |
7118 | else | |
7119 | { | |
7120 | /* Although a copy constructor may exist, no suitable match was found. | |
7121 | * i.e: `inout` constructor creates `const` object, not mutable. | |
7122 | * Fallback to using the original generic error before bugzilla 22202. | |
7123 | */ | |
7124 | goto Lnocpctor; | |
7125 | } | |
7126 | } | |
7127 | else | |
7128 | { | |
7129 | Lnocpctor: | |
7130 | buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", | |
7131 | argStruct.toChars(), arg.type.toChars(), tprm.toChars()); | |
7132 | } | |
7133 | ||
7134 | *pMessage = buf.extractChars(); | |
7135 | } | |
7136 | return false; | |
7137 | } | |
7138 | ||
7139 | /** | |
7140 | * Match a single parameter to an argument. | |
7141 | * | |
7142 | * This function is called by `TypeFunction.callMatch` while iterating over | |
7143 | * the list of parameter. Here we check if `arg` is a match for `p`, | |
7144 | * which is mostly about checking if `arg.type` converts to `p`'s type | |
7145 | * and some check about value reference. | |
7146 | * | |
7147 | * Params: | |
7148 | * tf = The `TypeFunction`, only used for error reporting | |
7149 | * p = The parameter of `tf` being matched | |
7150 | * arg = Argument being passed (bound) to `p` | |
7151 | * wildmatch = Wild (`inout`) matching level, derived from the full argument list | |
7152 | * flag = A non-zero value means we're doing a partial ordering check | |
7153 | * (no value semantic check) | |
7154 | * sc = Scope we are in | |
7155 | * pMessage = A buffer to write the error in, or `null` | |
7156 | * | |
7157 | * Returns: Whether `trailingArgs` match `p`. | |
7158 | */ | |
7159 | private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, | |
7160 | Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) | |
7161 | { | |
7162 | //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); | |
7163 | MATCH m; | |
7164 | Type targ = arg.type; | |
7165 | Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; | |
7166 | ||
7167 | if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) | |
7168 | m = MATCH.convert; | |
7169 | else if (flag) | |
7170 | { | |
7171 | // for partial ordering, value is an irrelevant mockup, just look at the type | |
7172 | m = targ.implicitConvTo(tprm); | |
7173 | } | |
7174 | else | |
7175 | { | |
7176 | const isRef = p.isReference(); | |
7177 | StructDeclaration argStruct, prmStruct; | |
7178 | ||
7179 | // first look for a copy constructor | |
7180 | if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) | |
7181 | { | |
7182 | // if the argument and the parameter are of the same unqualified struct type | |
7183 | argStruct = (cast(TypeStruct)targ).sym; | |
7184 | prmStruct = (cast(TypeStruct)tprm).sym; | |
7185 | } | |
7186 | ||
7187 | // check if the copy constructor may be called to copy the argument | |
7188 | if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) | |
7189 | { | |
7190 | if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) | |
7191 | return MATCH.nomatch; | |
7192 | m = MATCH.exact; | |
7193 | } | |
7194 | else | |
7195 | { | |
7196 | import dmd.dcast : cimplicitConvTo; | |
7197 | m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); | |
7198 | } | |
7199 | } | |
7200 | ||
7201 | // Non-lvalues do not match ref or out parameters | |
7202 | if (p.isReference()) | |
7203 | { | |
7204 | // https://issues.dlang.org/show_bug.cgi?id=13783 | |
7205 | // Don't use toBasetype() to handle enum types. | |
7206 | Type ta = targ; | |
7207 | Type tp = tprm; | |
7208 | //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); | |
7209 | ||
7210 | if (m && !arg.isLvalue()) | |
7211 | { | |
7212 | if (p.storageClass & STC.out_) | |
7213 | { | |
7214 | if (pMessage) *pMessage = tf.getParamError(arg, p); | |
7215 | return MATCH.nomatch; | |
7216 | } | |
7217 | ||
7218 | if (arg.op == EXP.string_ && tp.ty == Tsarray) | |
7219 | { | |
7220 | if (ta.ty != Tsarray) | |
7221 | { | |
7222 | Type tn = tp.nextOf().castMod(ta.nextOf().mod); | |
7223 | dinteger_t dim = (cast(StringExp)arg).len; | |
7224 | ta = tn.sarrayOf(dim); | |
7225 | } | |
7226 | } | |
7227 | else if (arg.op == EXP.slice && tp.ty == Tsarray) | |
7228 | { | |
7229 | // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] | |
7230 | if (ta.ty != Tsarray) | |
7231 | { | |
7232 | Type tn = ta.nextOf(); | |
7233 | dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); | |
7234 | ta = tn.sarrayOf(dim); | |
7235 | } | |
7236 | } | |
7237 | else if ((p.storageClass & STC.in_) && global.params.previewIn) | |
7238 | { | |
7239 | // Allow converting a literal to an `in` which is `ref` | |
7240 | if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) | |
7241 | { | |
7242 | Type tn = tp.nextOf(); | |
7243 | dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); | |
7244 | ta = tn.sarrayOf(dim); | |
7245 | } | |
7246 | ||
7247 | // Need to make this a rvalue through a temporary | |
7248 | m = MATCH.convert; | |
7249 | } | |
7250 | else if (global.params.rvalueRefParam != FeatureState.enabled || | |
7251 | p.storageClass & STC.out_ || | |
7252 | !arg.type.isCopyable()) // can't copy to temp for ref parameter | |
7253 | { | |
7254 | if (pMessage) *pMessage = tf.getParamError(arg, p); | |
7255 | return MATCH.nomatch; | |
7256 | } | |
7257 | else | |
7258 | { | |
7259 | /* in functionParameters() we'll convert this | |
7260 | * rvalue into a temporary | |
7261 | */ | |
7262 | m = MATCH.convert; | |
7263 | } | |
7264 | } | |
7265 | ||
7266 | /* If the match is not already perfect or if the arg | |
7267 | is not a lvalue then try the `alias this` chain | |
7268 | see https://issues.dlang.org/show_bug.cgi?id=15674 | |
7269 | and https://issues.dlang.org/show_bug.cgi?id=21905 | |
7270 | */ | |
7271 | if (ta != tp || !arg.isLvalue()) | |
7272 | { | |
7273 | Type firsttab = ta.toBasetype(); | |
7274 | while (1) | |
7275 | { | |
7276 | Type tab = ta.toBasetype(); | |
7277 | Type tat = tab.aliasthisOf(); | |
7278 | if (!tat || !tat.implicitConvTo(tprm)) | |
7279 | break; | |
7280 | if (tat == tab || tat == firsttab) | |
7281 | break; | |
7282 | ta = tat; | |
7283 | } | |
7284 | } | |
7285 | ||
7286 | /* A ref variable should work like a head-const reference. | |
7287 | * e.g. disallows: | |
7288 | * ref T <- an lvalue of const(T) argument | |
7289 | * ref T[dim] <- an lvalue of const(T[dim]) argument | |
7290 | */ | |
7291 | if (!ta.constConv(tp)) | |
7292 | { | |
7293 | if (pMessage) *pMessage = tf.getParamError(arg, p); | |
7294 | return MATCH.nomatch; | |
7295 | } | |
7296 | } | |
7297 | return m; | |
7298 | } | |
7299 | ||
7300 | /** | |
7301 | * Match the remaining arguments `trailingArgs` with parameter `p`. | |
7302 | * | |
7303 | * Assume we already checked that `p` is the last parameter of `tf`, | |
7304 | * and we want to know whether the arguments would match `p`. | |
7305 | * | |
7306 | * Params: | |
7307 | * tf = The `TypeFunction`, only used for error reporting | |
7308 | * p = The last parameter of `tf` which is variadic | |
7309 | * trailingArgs = The remaining arguments that should match `p` | |
7310 | * pMessage = A buffer to write the error in, or `null` | |
7311 | * | |
7312 | * Returns: Whether `trailingArgs` match `p`. | |
7313 | */ | |
7314 | private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, | |
7315 | Expression[] trailingArgs, const(char)** pMessage) | |
7316 | { | |
7317 | Type tb = p.type.toBasetype(); | |
7318 | ||
7319 | switch (tb.ty) | |
7320 | { | |
7321 | case Tsarray: | |
7322 | TypeSArray tsa = cast(TypeSArray)tb; | |
7323 | dinteger_t sz = tsa.dim.toInteger(); | |
7324 | if (sz != trailingArgs.length) | |
7325 | { | |
7326 | if (pMessage) | |
7327 | *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", | |
7328 | sz, trailingArgs.length); | |
7329 | return MATCH.nomatch; | |
7330 | } | |
7331 | goto case Tarray; | |
7332 | case Tarray: | |
7333 | { | |
7334 | MATCH match = MATCH.exact; | |
7335 | TypeArray ta = cast(TypeArray)tb; | |
7336 | foreach (arg; trailingArgs) | |
7337 | { | |
7338 | MATCH m; | |
7339 | assert(arg); | |
7340 | ||
7341 | /* If lazy array of delegates, | |
7342 | * convert arg(s) to delegate(s) | |
7343 | */ | |
7344 | Type tret = p.isLazyArray(); | |
7345 | if (tret) | |
7346 | { | |
7347 | if (ta.next.equals(arg.type)) | |
7348 | m = MATCH.exact; | |
7349 | else if (tret.toBasetype().ty == Tvoid) | |
7350 | m = MATCH.convert; | |
7351 | else | |
7352 | { | |
7353 | m = arg.implicitConvTo(tret); | |
7354 | if (m == MATCH.nomatch) | |
7355 | m = arg.implicitConvTo(ta.next); | |
7356 | } | |
7357 | } | |
7358 | else | |
7359 | m = arg.implicitConvTo(ta.next); | |
7360 | ||
7361 | if (m == MATCH.nomatch) | |
7362 | { | |
7363 | if (pMessage) *pMessage = tf.getParamError(arg, p); | |
7364 | return MATCH.nomatch; | |
7365 | } | |
7366 | if (m < match) | |
7367 | match = m; | |
7368 | } | |
7369 | return match; | |
7370 | } | |
7371 | case Tclass: | |
7372 | // We leave it up to the actual constructor call to do the matching. | |
7373 | return MATCH.exact; | |
7374 | ||
7375 | default: | |
7376 | // We can have things as `foo(int[int] wat...)` but they only match | |
7377 | // with an associative array proper. | |
7378 | if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); | |
7379 | return MATCH.nomatch; | |
7380 | } | |
7381 | } |