]>
Commit | Line | Data |
---|---|---|
5fee5ec3 IB |
1 | /** |
2 | * Semantic analysis for cast-expressions. | |
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/dcast.d, _dcast.d) |
8 | * Documentation: https://dlang.org/phobos/dmd_dcast.html | |
9 | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dcast.d | |
10 | */ | |
11 | ||
12 | module dmd.dcast; | |
13 | ||
14 | import core.stdc.stdio; | |
15 | import core.stdc.string; | |
16 | import dmd.aggregate; | |
17 | import dmd.aliasthis; | |
18 | import dmd.arrayop; | |
19 | import dmd.arraytypes; | |
20 | import dmd.astenums; | |
21 | import dmd.dclass; | |
22 | import dmd.declaration; | |
23 | import dmd.dscope; | |
24 | import dmd.dstruct; | |
25 | import dmd.dsymbol; | |
26 | import dmd.errors; | |
27 | import dmd.escape; | |
28 | import dmd.expression; | |
29 | import dmd.expressionsem; | |
30 | import dmd.func; | |
31 | import dmd.globals; | |
9c7d5e88 | 32 | import dmd.hdrgen; |
5fee5ec3 IB |
33 | import dmd.impcnvtab; |
34 | import dmd.id; | |
0fb57034 | 35 | import dmd.importc; |
5fee5ec3 IB |
36 | import dmd.init; |
37 | import dmd.intrange; | |
38 | import dmd.mtype; | |
39 | import dmd.opover; | |
40 | import dmd.root.ctfloat; | |
0fb57034 | 41 | import dmd.common.outbuffer; |
5fee5ec3 | 42 | import dmd.root.rmem; |
c43b5909 | 43 | import dmd.root.utf; |
5fee5ec3 IB |
44 | import dmd.tokens; |
45 | import dmd.typesem; | |
5fee5ec3 IB |
46 | import dmd.visitor; |
47 | ||
48 | enum LOG = false; | |
49 | ||
50 | /** | |
51 | * Attempt to implicitly cast the expression into type `t`. | |
52 | * | |
53 | * This routine will change `e`. To check the matching level, | |
54 | * use `implicitConvTo`. | |
55 | * | |
56 | * Params: | |
57 | * e = Expression that is to be casted | |
58 | * sc = Current scope | |
59 | * t = Expected resulting type | |
60 | * | |
61 | * Returns: | |
62 | * The resulting casted expression (mutating `e`), or `ErrorExp` | |
63 | * if such an implicit conversion is not possible. | |
64 | */ | |
65 | Expression implicitCastTo(Expression e, Scope* sc, Type t) | |
66 | { | |
6384eff5 | 67 | Expression visit(Expression e) |
5fee5ec3 | 68 | { |
6384eff5 | 69 | //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); |
5fee5ec3 | 70 | |
6384eff5 | 71 | if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t)) |
5fee5ec3 | 72 | { |
6384eff5 IB |
73 | if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t))) |
74 | { | |
75 | /* Do not emit CastExp for const conversions and | |
76 | * unique conversions on rvalue. | |
77 | */ | |
78 | auto result = e.copy(); | |
79 | result.type = t; | |
80 | return result; | |
81 | } | |
5fee5ec3 | 82 | |
6384eff5 IB |
83 | auto ad = isAggregate(e.type); |
84 | if (ad && ad.aliasthis) | |
5fee5ec3 | 85 | { |
6384eff5 IB |
86 | auto ts = ad.type.isTypeStruct(); |
87 | const adMatch = ts | |
88 | ? ts.implicitConvToWithoutAliasThis(t) | |
89 | : ad.type.isTypeClass().implicitConvToWithoutAliasThis(t); | |
5fee5ec3 | 90 | |
6384eff5 | 91 | if (!adMatch) |
5fee5ec3 | 92 | { |
6384eff5 IB |
93 | Type tob = t.toBasetype(); |
94 | Type t1b = e.type.toBasetype(); | |
95 | if (ad != isAggregate(tob)) | |
5fee5ec3 | 96 | { |
6384eff5 | 97 | if (t1b.ty == Tclass && tob.ty == Tclass) |
5fee5ec3 | 98 | { |
6384eff5 IB |
99 | ClassDeclaration t1cd = t1b.isClassHandle(); |
100 | ClassDeclaration tocd = tob.isClassHandle(); | |
101 | int offset; | |
102 | if (tocd.isBaseOf(t1cd, &offset)) | |
5fee5ec3 | 103 | { |
6384eff5 IB |
104 | auto result = new CastExp(e.loc, e, t); |
105 | result.type = t; | |
106 | return result; | |
5fee5ec3 | 107 | } |
6384eff5 | 108 | } |
5fee5ec3 | 109 | |
6384eff5 IB |
110 | /* Forward the cast to our alias this member, rewrite to: |
111 | * cast(to)e1.aliasthis | |
112 | */ | |
113 | auto result = resolveAliasThis(sc, e); | |
114 | return result.castTo(sc, t); | |
115 | } | |
5fee5ec3 | 116 | } |
5fee5ec3 IB |
117 | } |
118 | ||
6384eff5 IB |
119 | return e.castTo(sc, t); |
120 | } | |
5fee5ec3 | 121 | |
6384eff5 IB |
122 | auto result = e.optimize(WANTvalue); |
123 | if (result != e) | |
124 | { | |
125 | return implicitCastTo(result, sc, t); | |
5fee5ec3 IB |
126 | } |
127 | ||
6384eff5 | 128 | if (t.ty != Terror && e.type.ty != Terror) |
5fee5ec3 | 129 | { |
6384eff5 IB |
130 | if (!t.deco) |
131 | { | |
132 | e.error("forward reference to type `%s`", t.toChars()); | |
133 | } | |
134 | else | |
5fee5ec3 | 135 | { |
6384eff5 IB |
136 | //printf("type %p ty %d deco %p\n", type, type.ty, type.deco); |
137 | //type = type.typeSemantic(loc, sc); | |
138 | //printf("type %s t %s\n", type.deco, t.deco); | |
139 | auto ts = toAutoQualChars(e.type, t); | |
140 | e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", | |
141 | e.toChars(), ts[0], ts[1]); | |
5fee5ec3 IB |
142 | } |
143 | } | |
6384eff5 IB |
144 | return ErrorExp.get(); |
145 | } | |
5fee5ec3 | 146 | |
6384eff5 IB |
147 | Expression visitString(StringExp e) |
148 | { | |
149 | //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); | |
150 | auto result = visit(e); | |
151 | if (auto se = result.isStringExp()) | |
5fee5ec3 | 152 | { |
6384eff5 IB |
153 | // Retain polysemous nature if it started out that way |
154 | se.committed = e.committed; | |
5fee5ec3 | 155 | } |
6384eff5 IB |
156 | return result; |
157 | } | |
158 | ||
159 | Expression visitError(ErrorExp e) | |
160 | { | |
161 | return e; | |
162 | } | |
5fee5ec3 | 163 | |
6384eff5 IB |
164 | Expression visitFunc(FuncExp e) |
165 | { | |
166 | //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); | |
167 | FuncExp fe; | |
168 | if (e.matchType(t, sc, &fe) > MATCH.nomatch) | |
5fee5ec3 | 169 | { |
6384eff5 | 170 | return fe; |
5fee5ec3 | 171 | } |
6384eff5 IB |
172 | return visit(e); |
173 | } | |
5fee5ec3 | 174 | |
6384eff5 IB |
175 | Expression visitArrayLiteral(ArrayLiteralExp e) |
176 | { | |
177 | auto result = visit(e); | |
5fee5ec3 | 178 | |
6384eff5 IB |
179 | Type tb = result.type.toBasetype(); |
180 | if (auto ta = tb.isTypeDArray()) | |
181 | if (global.params.useTypeInfo && Type.dtypeinfo) | |
182 | semanticTypeInfo(sc, ta.next); | |
183 | return result; | |
184 | } | |
5fee5ec3 | 185 | |
6384eff5 IB |
186 | Expression visitSlice(SliceExp e) |
187 | { | |
188 | auto result = visit(e); | |
5fee5ec3 | 189 | |
6384eff5 IB |
190 | if (auto se = result.isSliceExp()) |
191 | if (auto ale = se.e1.isArrayLiteralExp()) | |
192 | { | |
193 | Type tb = t.toBasetype(); | |
194 | Type tx = (tb.ty == Tsarray) | |
195 | ? tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0) | |
196 | : tb.nextOf().arrayOf(); | |
197 | se.e1 = ale.implicitCastTo(sc, tx); | |
198 | } | |
199 | ||
200 | return result; | |
5fee5ec3 IB |
201 | } |
202 | ||
6384eff5 IB |
203 | switch (e.op) |
204 | { | |
205 | default : return visit (e); | |
206 | case EXP.string_ : return visitString (e.isStringExp()); | |
207 | case EXP.error : return visitError (e.isErrorExp()); | |
208 | case EXP.function_ : return visitFunc (e.isFuncExp()); | |
209 | case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp()); | |
210 | case EXP.slice : return visitSlice (e.isSliceExp()); | |
211 | } | |
5fee5ec3 IB |
212 | } |
213 | ||
214 | /** | |
215 | * Checks whether or not an expression can be implicitly converted | |
216 | * to type `t`. | |
217 | * | |
218 | * Unlike `implicitCastTo`, this routine does not perform the actual cast, | |
219 | * but only checks up to what `MATCH` level the conversion would be possible. | |
220 | * | |
221 | * Params: | |
222 | * e = Expression that is to be casted | |
223 | * t = Expected resulting type | |
224 | * | |
225 | * Returns: | |
226 | * The `MATCH` level between `e.type` and `t`. | |
227 | */ | |
228 | MATCH implicitConvTo(Expression e, Type t) | |
229 | { | |
6384eff5 | 230 | MATCH visit(Expression e) |
5fee5ec3 | 231 | { |
6384eff5 IB |
232 | version (none) |
233 | { | |
234 | printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
235 | } | |
236 | //static int nest; if (++nest == 10) assert(0); | |
237 | if (t == Type.terror) | |
238 | return MATCH.nomatch; | |
239 | if (!e.type) | |
240 | { | |
241 | e.error("`%s` is not an expression", e.toChars()); | |
242 | e.type = Type.terror; | |
243 | } | |
5fee5ec3 | 244 | |
6384eff5 IB |
245 | Expression ex = e.optimize(WANTvalue); |
246 | if (ex.type.equals(t)) | |
247 | { | |
248 | return MATCH.exact; | |
249 | } | |
250 | if (ex != e) | |
5fee5ec3 | 251 | { |
6384eff5 IB |
252 | //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars()); |
253 | return ex.implicitConvTo(t); | |
5fee5ec3 IB |
254 | } |
255 | ||
6384eff5 IB |
256 | MATCH match = e.type.implicitConvTo(t); |
257 | if (match != MATCH.nomatch) | |
5fee5ec3 | 258 | { |
6384eff5 IB |
259 | return match; |
260 | } | |
5fee5ec3 | 261 | |
6384eff5 IB |
262 | /* See if we can do integral narrowing conversions |
263 | */ | |
264 | if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic()) | |
265 | { | |
266 | IntRange src = getIntRange(e); | |
267 | IntRange target = IntRange.fromType(t); | |
268 | if (target.contains(src)) | |
5fee5ec3 | 269 | { |
6384eff5 | 270 | return MATCH.convert; |
5fee5ec3 | 271 | } |
6384eff5 IB |
272 | } |
273 | return MATCH.nomatch; | |
274 | } | |
5fee5ec3 | 275 | |
6384eff5 IB |
276 | /****** |
277 | * Given expression e of type t, see if we can implicitly convert e | |
278 | * to type tprime, where tprime is type t with mod bits added. | |
279 | * Returns: | |
280 | * match level | |
281 | */ | |
282 | static MATCH implicitMod(Expression e, Type t, MOD mod) | |
283 | { | |
284 | Type tprime; | |
285 | if (t.ty == Tpointer) | |
286 | tprime = t.nextOf().castMod(mod).pointerTo(); | |
287 | else if (t.ty == Tarray) | |
288 | tprime = t.nextOf().castMod(mod).arrayOf(); | |
289 | else if (t.ty == Tsarray) | |
290 | tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size()); | |
291 | else | |
292 | tprime = t.castMod(mod); | |
5fee5ec3 | 293 | |
6384eff5 IB |
294 | return e.implicitConvTo(tprime); |
295 | } | |
5fee5ec3 | 296 | |
6384eff5 IB |
297 | static MATCH implicitConvToAddMin(BinExp e, Type t) |
298 | { | |
299 | /* Is this (ptr +- offset)? If so, then ask ptr | |
300 | * if the conversion can be done. | |
301 | * This is to support doing things like implicitly converting a mutable unique | |
302 | * pointer to an immutable pointer. | |
5fee5ec3 | 303 | */ |
5fee5ec3 | 304 | |
6384eff5 IB |
305 | Type tb = t.toBasetype(); |
306 | Type typeb = e.type.toBasetype(); | |
307 | ||
308 | if (typeb.ty != Tpointer || tb.ty != Tpointer) | |
309 | return MATCH.nomatch; | |
310 | ||
311 | Type t1b = e.e1.type.toBasetype(); | |
312 | Type t2b = e.e2.type.toBasetype(); | |
313 | if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb)) | |
314 | { | |
315 | // ptr + offset | |
316 | // ptr - offset | |
317 | MATCH m = e.e1.implicitConvTo(t); | |
318 | return (m > MATCH.constant) ? MATCH.constant : m; | |
5fee5ec3 | 319 | } |
6384eff5 IB |
320 | if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb)) |
321 | { | |
322 | // offset + ptr | |
323 | MATCH m = e.e2.implicitConvTo(t); | |
324 | return (m > MATCH.constant) ? MATCH.constant : m; | |
325 | } | |
326 | ||
327 | return MATCH.nomatch; | |
328 | } | |
5fee5ec3 | 329 | |
7e7ebe3e IB |
330 | // Apply mod bits to each function parameter, |
331 | // and see if we can convert the function argument to the modded type | |
332 | static bool parametersModMatch(Expressions* args, TypeFunction tf, MOD mod) | |
333 | { | |
334 | const size_t nparams = tf.parameterList.length; | |
335 | const size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended | |
336 | foreach (const i; j .. args.dim) | |
337 | { | |
338 | Expression earg = (*args)[i]; | |
339 | Type targ = earg.type.toBasetype(); | |
340 | static if (LOG) | |
341 | { | |
342 | printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); | |
343 | } | |
344 | if (i - j < nparams) | |
345 | { | |
346 | Parameter fparam = tf.parameterList[i - j]; | |
347 | if (fparam.isLazy()) | |
348 | return false; // not sure what to do with this | |
349 | Type tparam = fparam.type; | |
350 | if (!tparam) | |
351 | continue; | |
352 | if (fparam.isReference()) | |
353 | { | |
354 | if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) | |
355 | return false; | |
356 | continue; | |
357 | } | |
358 | } | |
359 | static if (LOG) | |
360 | { | |
361 | printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); | |
362 | } | |
363 | if (implicitMod(earg, targ, mod) == MATCH.nomatch) | |
364 | return false; | |
365 | } | |
366 | return true; | |
367 | } | |
368 | ||
6384eff5 IB |
369 | MATCH visitAdd(AddExp e) |
370 | { | |
371 | version (none) | |
5fee5ec3 | 372 | { |
6384eff5 IB |
373 | printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); |
374 | } | |
375 | auto result = visit(e); | |
376 | if (result == MATCH.nomatch) | |
377 | result = implicitConvToAddMin(e, t); | |
378 | return result; | |
379 | } | |
5fee5ec3 | 380 | |
6384eff5 IB |
381 | MATCH visitMin(MinExp e) |
382 | { | |
383 | version (none) | |
384 | { | |
385 | printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
386 | } | |
387 | auto result = visit(e); | |
388 | if (result == MATCH.nomatch) | |
389 | result = implicitConvToAddMin(e, t); | |
390 | return result; | |
391 | } | |
5fee5ec3 | 392 | |
6384eff5 IB |
393 | MATCH visitInteger(IntegerExp e) |
394 | { | |
395 | version (none) | |
396 | { | |
397 | printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
398 | } | |
399 | MATCH m = e.type.implicitConvTo(t); | |
400 | if (m >= MATCH.constant) | |
401 | { | |
402 | return m; | |
403 | } | |
5fee5ec3 | 404 | |
6384eff5 IB |
405 | TY ty = e.type.toBasetype().ty; |
406 | TY toty = t.toBasetype().ty; | |
407 | TY oldty = ty; | |
5fee5ec3 | 408 | |
6384eff5 | 409 | if (m == MATCH.nomatch && t.ty == Tenum) |
5fee5ec3 | 410 | return MATCH.nomatch; |
5fee5ec3 | 411 | |
6384eff5 | 412 | if (auto tv = t.isTypeVector()) |
5fee5ec3 | 413 | { |
6384eff5 IB |
414 | TypeBasic tb = tv.elementType(); |
415 | if (tb.ty == Tvoid) | |
416 | return MATCH.nomatch; | |
417 | toty = tb.ty; | |
5fee5ec3 IB |
418 | } |
419 | ||
6384eff5 | 420 | switch (ty) |
5fee5ec3 | 421 | { |
6384eff5 IB |
422 | case Tbool: |
423 | case Tint8: | |
424 | case Tchar: | |
425 | case Tuns8: | |
426 | case Tint16: | |
427 | case Tuns16: | |
428 | case Twchar: | |
429 | ty = Tint32; | |
430 | break; | |
431 | ||
432 | case Tdchar: | |
433 | ty = Tuns32; | |
434 | break; | |
435 | ||
436 | default: | |
437 | break; | |
5fee5ec3 IB |
438 | } |
439 | ||
6384eff5 IB |
440 | // Only allow conversion if no change in value |
441 | immutable dinteger_t value = e.toInteger(); | |
442 | ||
443 | bool isLosslesslyConvertibleToFP(T)() | |
5fee5ec3 | 444 | { |
6384eff5 | 445 | if (e.type.isunsigned()) |
5fee5ec3 | 446 | { |
6384eff5 IB |
447 | const f = cast(T) value; |
448 | return cast(dinteger_t) f == value; | |
5fee5ec3 IB |
449 | } |
450 | ||
6384eff5 IB |
451 | const f = cast(T) cast(sinteger_t) value; |
452 | return cast(sinteger_t) f == cast(sinteger_t) value; | |
453 | } | |
5fee5ec3 | 454 | |
6384eff5 IB |
455 | switch (toty) |
456 | { | |
457 | case Tbool: | |
458 | if ((value & 1) != value) | |
459 | return MATCH.nomatch; | |
460 | break; | |
5fee5ec3 | 461 | |
6384eff5 IB |
462 | case Tint8: |
463 | if (ty == Tuns64 && value & ~0x7FU) | |
464 | return MATCH.nomatch; | |
465 | else if (cast(byte)value != value) | |
466 | return MATCH.nomatch; | |
467 | break; | |
5fee5ec3 | 468 | |
6384eff5 IB |
469 | case Tchar: |
470 | if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) | |
471 | return MATCH.nomatch; | |
472 | goto case Tuns8; | |
473 | case Tuns8: | |
31350635 | 474 | //printf("value = %llu %llu\n", cast(dinteger_t)cast(ubyte)value, value); |
6384eff5 IB |
475 | if (cast(ubyte)value != value) |
476 | return MATCH.nomatch; | |
477 | break; | |
5fee5ec3 | 478 | |
6384eff5 IB |
479 | case Tint16: |
480 | if (ty == Tuns64 && value & ~0x7FFFU) | |
481 | return MATCH.nomatch; | |
482 | else if (cast(short)value != value) | |
483 | return MATCH.nomatch; | |
484 | break; | |
5fee5ec3 | 485 | |
6384eff5 IB |
486 | case Twchar: |
487 | if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) | |
488 | return MATCH.nomatch; | |
489 | goto case Tuns16; | |
490 | case Tuns16: | |
491 | if (cast(ushort)value != value) | |
492 | return MATCH.nomatch; | |
493 | break; | |
5fee5ec3 | 494 | |
6384eff5 IB |
495 | case Tint32: |
496 | if (ty == Tuns32) | |
5fee5ec3 | 497 | { |
5fee5ec3 | 498 | } |
6384eff5 IB |
499 | else if (ty == Tuns64 && value & ~0x7FFFFFFFU) |
500 | return MATCH.nomatch; | |
501 | else if (cast(int)value != value) | |
502 | return MATCH.nomatch; | |
503 | break; | |
5fee5ec3 | 504 | |
6384eff5 IB |
505 | case Tuns32: |
506 | if (ty == Tint32) | |
5fee5ec3 | 507 | { |
6384eff5 IB |
508 | } |
509 | else if (cast(uint)value != value) | |
510 | return MATCH.nomatch; | |
511 | break; | |
5fee5ec3 | 512 | |
6384eff5 IB |
513 | case Tdchar: |
514 | if (value > 0x10FFFFU) | |
515 | return MATCH.nomatch; | |
516 | break; | |
5fee5ec3 | 517 | |
6384eff5 IB |
518 | case Tfloat32: |
519 | if (!isLosslesslyConvertibleToFP!float) | |
520 | return MATCH.nomatch; | |
521 | break; | |
5fee5ec3 | 522 | |
6384eff5 IB |
523 | case Tfloat64: |
524 | if (!isLosslesslyConvertibleToFP!double) | |
525 | return MATCH.nomatch; | |
526 | break; | |
5fee5ec3 | 527 | |
6384eff5 IB |
528 | case Tfloat80: |
529 | if (!isLosslesslyConvertibleToFP!real_t) | |
530 | return MATCH.nomatch; | |
531 | break; | |
5fee5ec3 | 532 | |
6384eff5 | 533 | case Tpointer: |
31350635 IB |
534 | //printf("type = %s\n", type.toBasetype().toChars()); |
535 | //printf("t = %s\n", t.toBasetype().toChars()); | |
6384eff5 IB |
536 | if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty) |
537 | { | |
538 | /* Allow things like: | |
539 | * const char* P = cast(char *)3; | |
540 | * char* q = P; | |
541 | */ | |
5fee5ec3 | 542 | break; |
6384eff5 IB |
543 | } |
544 | goto default; | |
5fee5ec3 | 545 | |
6384eff5 IB |
546 | default: |
547 | return visit(e); | |
548 | } | |
5fee5ec3 | 549 | |
6384eff5 IB |
550 | //printf("MATCH.convert\n"); |
551 | return MATCH.convert; | |
552 | } | |
5fee5ec3 | 553 | |
6384eff5 IB |
554 | MATCH visitError(ErrorExp e) |
555 | { | |
556 | return MATCH.nomatch; | |
557 | } | |
5fee5ec3 | 558 | |
6384eff5 IB |
559 | MATCH visitNull(NullExp e) |
560 | { | |
561 | version (none) | |
562 | { | |
563 | printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
5fee5ec3 | 564 | } |
6384eff5 | 565 | if (e.type.equals(t)) |
5fee5ec3 | 566 | { |
6384eff5 | 567 | return MATCH.exact; |
5fee5ec3 IB |
568 | } |
569 | ||
6384eff5 IB |
570 | /* Allow implicit conversions from immutable to mutable|const, |
571 | * and mutable to immutable. It works because, after all, a null | |
572 | * doesn't actually point to anything. | |
573 | */ | |
574 | if (t.equivalent(e.type)) | |
5fee5ec3 | 575 | { |
6384eff5 IB |
576 | return MATCH.constant; |
577 | } | |
5fee5ec3 | 578 | |
6384eff5 IB |
579 | return visit(e); |
580 | } | |
5fee5ec3 | 581 | |
6384eff5 IB |
582 | MATCH visitStructLiteral(StructLiteralExp e) |
583 | { | |
584 | version (none) | |
585 | { | |
586 | printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
5fee5ec3 | 587 | } |
6384eff5 IB |
588 | auto result = visit(e); |
589 | if (result != MATCH.nomatch) | |
590 | return result; | |
591 | if (e.type.ty == t.ty && e.type.isTypeStruct() && e.type.isTypeStruct().sym == t.isTypeStruct().sym) | |
5fee5ec3 | 592 | { |
6384eff5 IB |
593 | result = MATCH.constant; |
594 | foreach (i, el; (*e.elements)[]) | |
5fee5ec3 | 595 | { |
6384eff5 IB |
596 | if (!el) |
597 | continue; | |
598 | Type te = e.sd.fields[i].type.addMod(t.mod); | |
599 | MATCH m2 = el.implicitConvTo(te); | |
600 | //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2); | |
601 | if (m2 < result) | |
602 | result = m2; | |
5fee5ec3 IB |
603 | } |
604 | } | |
6384eff5 IB |
605 | return result; |
606 | } | |
5fee5ec3 | 607 | |
6384eff5 IB |
608 | MATCH visitString(StringExp e) |
609 | { | |
610 | version (none) | |
5fee5ec3 | 611 | { |
6384eff5 IB |
612 | printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars()); |
613 | } | |
614 | if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) | |
615 | return MATCH.nomatch; | |
5fee5ec3 | 616 | |
6384eff5 IB |
617 | if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer)) |
618 | return visit(e); | |
5fee5ec3 | 619 | |
6384eff5 | 620 | TY tyn = e.type.nextOf().ty; |
5fee5ec3 | 621 | |
6384eff5 IB |
622 | if (!tyn.isSomeChar) |
623 | return visit(e); | |
5fee5ec3 | 624 | |
6384eff5 IB |
625 | switch (t.ty) |
626 | { | |
627 | case Tsarray: | |
628 | if (e.type.ty == Tsarray) | |
5fee5ec3 | 629 | { |
6384eff5 IB |
630 | TY tynto = t.nextOf().ty; |
631 | if (tynto == tyn) | |
5fee5ec3 | 632 | { |
6384eff5 | 633 | if (e.type.isTypeSArray().dim.toInteger() == t.isTypeSArray().dim.toInteger()) |
5fee5ec3 | 634 | { |
6384eff5 | 635 | return MATCH.exact; |
5fee5ec3 | 636 | } |
6384eff5 | 637 | return MATCH.nomatch; |
5fee5ec3 | 638 | } |
6384eff5 | 639 | if (tynto.isSomeChar) |
5fee5ec3 | 640 | { |
6384eff5 IB |
641 | if (e.committed && tynto != tyn) |
642 | return MATCH.nomatch; | |
643 | size_t fromlen = e.numberOfCodeUnits(tynto); | |
644 | size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger(); | |
645 | if (tolen < fromlen) | |
646 | return MATCH.nomatch; | |
647 | if (tolen != fromlen) | |
5fee5ec3 | 648 | { |
6384eff5 IB |
649 | // implicit length extending |
650 | return MATCH.convert; | |
5fee5ec3 | 651 | } |
6384eff5 IB |
652 | } |
653 | if (!e.committed && tynto.isSomeChar) | |
654 | { | |
655 | return MATCH.exact; | |
656 | } | |
657 | } | |
658 | else if (e.type.ty == Tarray) | |
659 | { | |
660 | TY tynto = t.nextOf().ty; | |
661 | if (tynto.isSomeChar) | |
662 | { | |
663 | if (e.committed && tynto != tyn) | |
664 | return MATCH.nomatch; | |
665 | size_t fromlen = e.numberOfCodeUnits(tynto); | |
666 | size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger(); | |
667 | if (tolen < fromlen) | |
668 | return MATCH.nomatch; | |
669 | if (tolen != fromlen) | |
5fee5ec3 | 670 | { |
6384eff5 IB |
671 | // implicit length extending |
672 | return MATCH.convert; | |
5fee5ec3 IB |
673 | } |
674 | } | |
6384eff5 | 675 | if (tynto == tyn) |
5fee5ec3 | 676 | { |
6384eff5 | 677 | return MATCH.exact; |
5fee5ec3 | 678 | } |
6384eff5 | 679 | if (!e.committed && tynto.isSomeChar) |
5fee5ec3 | 680 | { |
6384eff5 IB |
681 | return MATCH.exact; |
682 | } | |
683 | } | |
684 | goto case; /+ fall through +/ | |
685 | case Tarray: | |
686 | case Tpointer: | |
687 | Type tn = t.nextOf(); | |
688 | MATCH m = MATCH.exact; | |
689 | if (e.type.nextOf().mod != tn.mod) | |
690 | { | |
691 | // https://issues.dlang.org/show_bug.cgi?id=16183 | |
692 | if (!tn.isConst() && !tn.isImmutable()) | |
693 | return MATCH.nomatch; | |
694 | m = MATCH.constant; | |
695 | } | |
696 | if (!e.committed) | |
697 | { | |
698 | switch (tn.ty) | |
699 | { | |
700 | case Tchar: | |
701 | if (e.postfix == 'w' || e.postfix == 'd') | |
702 | m = MATCH.convert; | |
703 | return m; | |
704 | case Twchar: | |
705 | if (e.postfix != 'w') | |
706 | m = MATCH.convert; | |
707 | return m; | |
708 | case Tdchar: | |
709 | if (e.postfix != 'd') | |
710 | m = MATCH.convert; | |
711 | return m; | |
712 | case Tenum: | |
713 | if (tn.isTypeEnum().sym.isSpecial()) | |
5fee5ec3 | 714 | { |
6384eff5 IB |
715 | /* Allow string literal -> const(wchar_t)[] |
716 | */ | |
717 | if (TypeBasic tob = tn.toBasetype().isTypeBasic()) | |
718 | return tn.implicitConvTo(tob); | |
5fee5ec3 | 719 | } |
6384eff5 IB |
720 | break; |
721 | default: | |
722 | break; | |
5fee5ec3 | 723 | } |
5fee5ec3 | 724 | } |
6384eff5 | 725 | break; |
5fee5ec3 | 726 | |
6384eff5 IB |
727 | default: |
728 | break; | |
5fee5ec3 IB |
729 | } |
730 | ||
6384eff5 IB |
731 | return visit(e); |
732 | } | |
733 | ||
734 | MATCH visitArrayLiteral(ArrayLiteralExp e) | |
735 | { | |
736 | version (none) | |
5fee5ec3 | 737 | { |
6384eff5 IB |
738 | printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); |
739 | } | |
740 | Type tb = t.toBasetype(); | |
741 | Type typeb = e.type.toBasetype(); | |
742 | ||
743 | auto result = MATCH.nomatch; | |
744 | if ((tb.ty == Tarray || tb.ty == Tsarray) && | |
745 | (typeb.ty == Tarray || typeb.ty == Tsarray)) | |
746 | { | |
747 | result = MATCH.exact; | |
748 | Type typen = typeb.nextOf().toBasetype(); | |
749 | ||
750 | if (auto tsa = tb.isTypeSArray()) | |
5fee5ec3 | 751 | { |
6384eff5 IB |
752 | if (e.elements.dim != tsa.dim.toInteger()) |
753 | result = MATCH.nomatch; | |
5fee5ec3 | 754 | } |
5fee5ec3 | 755 | |
6384eff5 IB |
756 | Type telement = tb.nextOf(); |
757 | if (!e.elements.dim) | |
5fee5ec3 | 758 | { |
6384eff5 IB |
759 | if (typen.ty != Tvoid) |
760 | result = typen.implicitConvTo(telement); | |
5fee5ec3 | 761 | } |
6384eff5 | 762 | else |
5fee5ec3 | 763 | { |
6384eff5 | 764 | if (e.basis) |
5fee5ec3 | 765 | { |
6384eff5 | 766 | MATCH m = e.basis.implicitConvTo(telement); |
5fee5ec3 | 767 | if (m < result) |
6384eff5 | 768 | result = m; |
5fee5ec3 | 769 | } |
6384eff5 | 770 | for (size_t i = 0; i < e.elements.dim; i++) |
5fee5ec3 | 771 | { |
6384eff5 IB |
772 | Expression el = (*e.elements)[i]; |
773 | if (result == MATCH.nomatch) | |
774 | break; | |
775 | if (!el) | |
776 | continue; | |
5fee5ec3 IB |
777 | MATCH m = el.implicitConvTo(telement); |
778 | if (m < result) | |
779 | result = m; // remember worst match | |
5fee5ec3 | 780 | } |
5fee5ec3 IB |
781 | } |
782 | ||
6384eff5 IB |
783 | if (!result) |
784 | result = e.type.implicitConvTo(t); | |
5fee5ec3 | 785 | |
6384eff5 IB |
786 | return result; |
787 | } | |
788 | else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) | |
5fee5ec3 | 789 | { |
5fee5ec3 | 790 | result = MATCH.exact; |
6384eff5 IB |
791 | // Convert array literal to vector type |
792 | TypeVector tv = tb.isTypeVector(); | |
793 | TypeSArray tbase = tv.basetype.isTypeSArray(); | |
794 | assert(tbase); | |
795 | const edim = e.elements.dim; | |
796 | const tbasedim = tbase.dim.toInteger(); | |
797 | if (edim > tbasedim) | |
798 | { | |
799 | return MATCH.nomatch; | |
800 | } | |
801 | ||
802 | Type telement = tv.elementType(); | |
803 | if (edim < tbasedim) | |
5fee5ec3 | 804 | { |
6384eff5 IB |
805 | Expression el = typeb.nextOf.defaultInitLiteral(e.loc); |
806 | MATCH m = el.implicitConvTo(telement); | |
5fee5ec3 IB |
807 | if (m < result) |
808 | result = m; // remember worst match | |
6384eff5 IB |
809 | } |
810 | foreach (el; (*e.elements)[]) | |
811 | { | |
812 | MATCH m = el.implicitConvTo(telement); | |
5fee5ec3 IB |
813 | if (m < result) |
814 | result = m; // remember worst match | |
815 | if (result == MATCH.nomatch) | |
816 | break; // no need to check for worse | |
817 | } | |
6384eff5 | 818 | return result; |
5fee5ec3 IB |
819 | } |
820 | ||
6384eff5 IB |
821 | return visit(e); |
822 | } | |
823 | ||
824 | MATCH visitAssocArrayLiteral(AssocArrayLiteralExp e) | |
825 | { | |
826 | auto taa = t.toBasetype().isTypeAArray(); | |
827 | Type typeb = e.type.toBasetype(); | |
828 | ||
829 | if (!(taa && typeb.ty == Taarray)) | |
830 | return visit(e); | |
831 | ||
832 | auto result = MATCH.exact; | |
833 | foreach (i, el; (*e.keys)[]) | |
5fee5ec3 | 834 | { |
6384eff5 IB |
835 | MATCH m = el.implicitConvTo(taa.index); |
836 | if (m < result) | |
837 | result = m; // remember worst match | |
838 | if (result == MATCH.nomatch) | |
839 | break; // no need to check for worse | |
840 | el = (*e.values)[i]; | |
841 | m = el.implicitConvTo(taa.nextOf()); | |
842 | if (m < result) | |
843 | result = m; // remember worst match | |
844 | if (result == MATCH.nomatch) | |
845 | break; // no need to check for worse | |
846 | } | |
847 | return result; | |
848 | } | |
5fee5ec3 | 849 | |
6384eff5 IB |
850 | MATCH visitCall(CallExp e) |
851 | { | |
852 | enum LOG = false; | |
853 | static if (LOG) | |
854 | { | |
855 | printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
856 | } | |
5fee5ec3 | 857 | |
6384eff5 IB |
858 | auto result = visit(e); |
859 | if (result != MATCH.nomatch) | |
860 | return result; | |
5fee5ec3 | 861 | |
6384eff5 IB |
862 | /* Allow the result of strongly pure functions to |
863 | * convert to immutable | |
864 | */ | |
865 | if (e.f && | |
610d7898 IB |
866 | (!global.params.fixImmutableConv || e.f.isPure() >= PURE.const_) && |
867 | e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive. | |
6384eff5 IB |
868 | ) |
869 | { | |
870 | result = e.type.immutableOf().implicitConvTo(t); | |
871 | if (result > MATCH.constant) // Match level is MATCH.constant at best. | |
872 | result = MATCH.constant; | |
873 | return result; | |
874 | } | |
5fee5ec3 | 875 | |
6384eff5 IB |
876 | /* Conversion is 'const' conversion if: |
877 | * 1. function is pure (weakly pure is ok) | |
878 | * 2. implicit conversion only fails because of mod bits | |
879 | * 3. each function parameter can be implicitly converted to the mod bits | |
880 | */ | |
881 | auto tf = (e.f ? e.f.type : e.e1.type).toBasetype().isTypeFunction(); | |
882 | if (!tf) | |
883 | return result; | |
884 | ||
885 | if (tf.purity == PURE.impure) | |
886 | return result; | |
887 | if (e.f && e.f.isNested()) | |
888 | return result; | |
889 | ||
890 | /* See if fail only because of mod bits. | |
891 | * | |
892 | * https://issues.dlang.org/show_bug.cgi?id=14155 | |
893 | * All pure functions can access global immutable data. | |
894 | * So the returned pointer may refer an immutable global data, | |
895 | * and then the returned pointer that points non-mutable object | |
896 | * cannot be unique pointer. | |
897 | * | |
898 | * Example: | |
899 | * immutable g; | |
900 | * static this() { g = 1; } | |
901 | * const(int*) foo() pure { return &g; } | |
902 | * void test() { | |
903 | * immutable(int*) ip = foo(); // OK | |
904 | * int* mp = foo(); // should be disallowed | |
905 | * } | |
906 | */ | |
907 | if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) | |
908 | { | |
909 | return result; | |
910 | } | |
911 | // Allow a conversion to immutable type, or | |
912 | // conversions of mutable types between thread-local and shared. | |
5fee5ec3 | 913 | |
6384eff5 IB |
914 | /* Get mod bits of what we're converting to |
915 | */ | |
916 | Type tb = t.toBasetype(); | |
917 | MOD mod = tb.mod; | |
918 | if (tf.isref) | |
919 | { | |
920 | } | |
921 | else | |
922 | { | |
923 | if (Type ti = getIndirection(t)) | |
924 | mod = ti.mod; | |
925 | } | |
926 | static if (LOG) | |
927 | { | |
928 | printf("mod = x%x\n", mod); | |
929 | } | |
930 | if (mod & MODFlags.wild) | |
931 | return result; // not sure what to do with this | |
5fee5ec3 | 932 | |
6384eff5 IB |
933 | /* Apply mod bits to each function parameter, |
934 | * and see if we can convert the function argument to the modded type | |
935 | */ | |
6384eff5 IB |
936 | if (auto dve = e.e1.isDotVarExp()) |
937 | { | |
938 | /* Treat 'this' as just another function argument | |
5fee5ec3 | 939 | */ |
6384eff5 IB |
940 | Type targ = dve.e1.type; |
941 | if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) | |
942 | return result; | |
943 | } | |
7e7ebe3e IB |
944 | |
945 | if (!parametersModMatch(e.arguments, tf, mod)) | |
946 | return result; | |
5fee5ec3 | 947 | |
6384eff5 IB |
948 | /* Success |
949 | */ | |
950 | return MATCH.constant; | |
951 | } | |
952 | ||
953 | MATCH visitAddr(AddrExp e) | |
954 | { | |
955 | version (none) | |
5fee5ec3 | 956 | { |
6384eff5 IB |
957 | printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); |
958 | } | |
959 | auto result = e.type.implicitConvTo(t); | |
960 | //printf("\tresult = %d\n", result); | |
5fee5ec3 | 961 | |
6384eff5 IB |
962 | if (result != MATCH.nomatch) |
963 | return result; | |
5fee5ec3 | 964 | |
6384eff5 IB |
965 | Type tb = t.toBasetype(); |
966 | Type typeb = e.type.toBasetype(); | |
5fee5ec3 | 967 | |
6384eff5 IB |
968 | // Look for pointers to functions where the functions are overloaded. |
969 | if (e.e1.op == EXP.overloadSet && | |
970 | (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) | |
971 | { | |
972 | OverExp eo = e.e1.isOverExp(); | |
973 | FuncDeclaration f = null; | |
974 | foreach (s; eo.vars.a[]) | |
5fee5ec3 | 975 | { |
6384eff5 IB |
976 | FuncDeclaration f2 = s.isFuncDeclaration(); |
977 | assert(f2); | |
978 | if (f2.overloadExactMatch(tb.nextOf())) | |
5fee5ec3 | 979 | { |
6384eff5 | 980 | if (f) |
5fee5ec3 | 981 | { |
6384eff5 IB |
982 | /* Error if match in more than one overload set, |
983 | * even if one is a 'better' match than the other. | |
984 | */ | |
985 | ScopeDsymbol.multiplyDefined(e.loc, f, f2); | |
5fee5ec3 | 986 | } |
6384eff5 IB |
987 | else |
988 | f = f2; | |
989 | result = MATCH.exact; | |
5fee5ec3 IB |
990 | } |
991 | } | |
6384eff5 | 992 | } |
5fee5ec3 | 993 | |
6384eff5 IB |
994 | if (e.e1.op == EXP.variable && |
995 | typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && | |
996 | tb.ty == Tpointer && tb.nextOf().ty == Tfunction) | |
997 | { | |
998 | /* I don't think this can ever happen - | |
999 | * it should have been | |
1000 | * converted to a SymOffExp. | |
1001 | */ | |
1002 | assert(0); | |
5fee5ec3 IB |
1003 | } |
1004 | ||
6384eff5 IB |
1005 | //printf("\tresult = %d\n", result); |
1006 | return result; | |
1007 | } | |
1008 | ||
1009 | MATCH visitSymOff(SymOffExp e) | |
1010 | { | |
1011 | version (none) | |
5fee5ec3 | 1012 | { |
6384eff5 IB |
1013 | printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); |
1014 | } | |
1015 | auto result = e.type.implicitConvTo(t); | |
1016 | //printf("\tresult = %d\n", result); | |
1017 | if (result != MATCH.nomatch) | |
1018 | return result; | |
5fee5ec3 | 1019 | |
6384eff5 IB |
1020 | Type tb = t.toBasetype(); |
1021 | Type typeb = e.type.toBasetype(); | |
5fee5ec3 | 1022 | |
6384eff5 IB |
1023 | // Look for pointers to functions where the functions are overloaded. |
1024 | if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && | |
1025 | (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) | |
1026 | { | |
1027 | if (FuncDeclaration f = e.var.isFuncDeclaration()) | |
5fee5ec3 | 1028 | { |
6384eff5 IB |
1029 | f = f.overloadExactMatch(tb.nextOf()); |
1030 | if (f) | |
5fee5ec3 | 1031 | { |
6384eff5 IB |
1032 | if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) || |
1033 | (tb.ty == Tpointer && !(f.needThis() || f.isNested()))) | |
5fee5ec3 | 1034 | { |
6384eff5 | 1035 | result = MATCH.exact; |
5fee5ec3 IB |
1036 | } |
1037 | } | |
1038 | } | |
5fee5ec3 | 1039 | } |
6384eff5 IB |
1040 | //printf("\tresult = %d\n", result); |
1041 | return result; | |
1042 | } | |
5fee5ec3 | 1043 | |
6384eff5 IB |
1044 | MATCH visitDelegate(DelegateExp e) |
1045 | { | |
1046 | version (none) | |
5fee5ec3 | 1047 | { |
6384eff5 IB |
1048 | printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); |
1049 | } | |
1050 | auto result = e.type.implicitConvTo(t); | |
1051 | if (result != MATCH.nomatch) | |
1052 | return result; | |
5fee5ec3 | 1053 | |
6384eff5 IB |
1054 | Type tb = t.toBasetype(); |
1055 | Type typeb = e.type.toBasetype(); | |
5fee5ec3 | 1056 | |
6384eff5 IB |
1057 | // Look for pointers to functions where the functions are overloaded. |
1058 | if (typeb.ty == Tdelegate && tb.ty == Tdelegate) | |
1059 | { | |
1060 | if (e.func && e.func.overloadExactMatch(tb.nextOf())) | |
1061 | result = MATCH.exact; | |
5fee5ec3 | 1062 | } |
6384eff5 IB |
1063 | return result; |
1064 | } | |
5fee5ec3 | 1065 | |
6384eff5 IB |
1066 | MATCH visitFunc(FuncExp e) |
1067 | { | |
1068 | //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); | |
1069 | MATCH m = e.matchType(t, null, null, 1); | |
1070 | if (m > MATCH.nomatch) | |
5fee5ec3 | 1071 | { |
6384eff5 | 1072 | return m; |
5fee5ec3 | 1073 | } |
6384eff5 IB |
1074 | return visit(e); |
1075 | } | |
5fee5ec3 | 1076 | |
6384eff5 IB |
1077 | MATCH visitAnd(AndExp e) |
1078 | { | |
1079 | auto result = visit(e); | |
1080 | if (result != MATCH.nomatch) | |
1081 | return result; | |
5fee5ec3 | 1082 | |
6384eff5 IB |
1083 | MATCH m1 = e.e1.implicitConvTo(t); |
1084 | MATCH m2 = e.e2.implicitConvTo(t); | |
5fee5ec3 | 1085 | |
6384eff5 IB |
1086 | // Pick the worst match |
1087 | return (m1 < m2) ? m1 : m2; | |
1088 | } | |
5fee5ec3 | 1089 | |
6384eff5 IB |
1090 | MATCH visitOr(OrExp e) |
1091 | { | |
1092 | auto result = visit(e); | |
1093 | if (result != MATCH.nomatch) | |
1094 | return result; | |
5fee5ec3 | 1095 | |
6384eff5 IB |
1096 | MATCH m1 = e.e1.implicitConvTo(t); |
1097 | MATCH m2 = e.e2.implicitConvTo(t); | |
5fee5ec3 | 1098 | |
6384eff5 IB |
1099 | // Pick the worst match |
1100 | return (m1 < m2) ? m1 : m2; | |
1101 | } | |
5fee5ec3 | 1102 | |
6384eff5 IB |
1103 | MATCH visitXor(XorExp e) |
1104 | { | |
1105 | auto result = visit(e); | |
1106 | if (result != MATCH.nomatch) | |
1107 | return result; | |
5fee5ec3 | 1108 | |
6384eff5 IB |
1109 | MATCH m1 = e.e1.implicitConvTo(t); |
1110 | MATCH m2 = e.e2.implicitConvTo(t); | |
5fee5ec3 | 1111 | |
6384eff5 IB |
1112 | // Pick the worst match |
1113 | return (m1 < m2) ? m1 : m2; | |
1114 | } | |
5fee5ec3 | 1115 | |
6384eff5 IB |
1116 | MATCH visitCond(CondExp e) |
1117 | { | |
b6df1132 IB |
1118 | e.econd = e.econd.optimize(WANTvalue); |
1119 | const opt = e.econd.toBool(); | |
1120 | if (opt.isPresent()) | |
1121 | { | |
1122 | auto result = visit(e); | |
1123 | if (result != MATCH.nomatch) | |
1124 | return result; | |
1125 | } | |
31350635 | 1126 | |
6384eff5 IB |
1127 | MATCH m1 = e.e1.implicitConvTo(t); |
1128 | MATCH m2 = e.e2.implicitConvTo(t); | |
1129 | //printf("CondExp: m1 %d m2 %d\n", m1, m2); | |
5fee5ec3 | 1130 | |
6384eff5 IB |
1131 | // Pick the worst match |
1132 | return (m1 < m2) ? m1 : m2; | |
1133 | } | |
5fee5ec3 | 1134 | |
6384eff5 IB |
1135 | MATCH visitComma(CommaExp e) |
1136 | { | |
1137 | return e.e2.implicitConvTo(t); | |
1138 | } | |
1139 | ||
1140 | MATCH visitCast(CastExp e) | |
1141 | { | |
1142 | version (none) | |
5fee5ec3 | 1143 | { |
6384eff5 | 1144 | printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); |
5fee5ec3 | 1145 | } |
6384eff5 IB |
1146 | auto result = e.type.implicitConvTo(t); |
1147 | if (result != MATCH.nomatch) | |
1148 | return result; | |
5fee5ec3 | 1149 | |
6384eff5 IB |
1150 | if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch) |
1151 | result = MATCH.convert; | |
1152 | else | |
1153 | result = visit(e); | |
1154 | return result; | |
1155 | } | |
5fee5ec3 | 1156 | |
6384eff5 IB |
1157 | MATCH visitNew(NewExp e) |
1158 | { | |
1159 | version (none) | |
1160 | { | |
1161 | printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
5fee5ec3 | 1162 | } |
6384eff5 IB |
1163 | auto result = visit(e); |
1164 | if (result != MATCH.nomatch) | |
1165 | return result; | |
5fee5ec3 | 1166 | |
6384eff5 IB |
1167 | /* Calling new() is like calling a pure function. We can implicitly convert the |
1168 | * return from new() to t using the same algorithm as in CallExp, with the function | |
1169 | * 'arguments' being: | |
1170 | * thisexp | |
1171 | * arguments | |
1172 | * .init | |
1173 | * 'member' need to be pure. | |
1174 | */ | |
5fee5ec3 | 1175 | |
6384eff5 IB |
1176 | /* See if fail only because of mod bits |
1177 | */ | |
1178 | if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch) | |
1179 | return MATCH.nomatch; | |
5fee5ec3 | 1180 | |
6384eff5 IB |
1181 | /* Get mod bits of what we're converting to |
1182 | */ | |
1183 | Type tb = t.toBasetype(); | |
1184 | MOD mod = tb.mod; | |
1185 | if (Type ti = getIndirection(t)) | |
1186 | mod = ti.mod; | |
1187 | static if (LOG) | |
1188 | { | |
1189 | printf("mod = x%x\n", mod); | |
1190 | } | |
1191 | if (mod & MODFlags.wild) | |
1192 | return MATCH.nomatch; // not sure what to do with this | |
5fee5ec3 | 1193 | |
6384eff5 IB |
1194 | /* Apply mod bits to each argument, |
1195 | * and see if we can convert the argument to the modded type | |
1196 | */ | |
5fee5ec3 | 1197 | |
6384eff5 IB |
1198 | if (e.thisexp) |
1199 | { | |
1200 | /* Treat 'this' as just another function argument | |
5fee5ec3 | 1201 | */ |
6384eff5 IB |
1202 | Type targ = e.thisexp.type; |
1203 | if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) | |
1204 | return MATCH.nomatch; | |
1205 | } | |
5fee5ec3 | 1206 | |
6384eff5 IB |
1207 | /* Check call to 'member' |
1208 | */ | |
1209 | if (e.member) | |
1210 | { | |
1211 | FuncDeclaration fd = e.member; | |
1212 | if (fd.errors || fd.type.ty != Tfunction) | |
1213 | return MATCH.nomatch; // error | |
1214 | TypeFunction tf = fd.type.isTypeFunction(); | |
1215 | if (tf.purity == PURE.impure) | |
1216 | return MATCH.nomatch; // impure | |
1217 | ||
7e7ebe3e IB |
1218 | // Allow a conversion to immutable type, or |
1219 | // conversions of mutable types between thread-local and shared. | |
6384eff5 | 1220 | if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) |
5fee5ec3 | 1221 | { |
6384eff5 | 1222 | return MATCH.nomatch; |
5fee5ec3 IB |
1223 | } |
1224 | ||
7e7ebe3e | 1225 | if (!parametersModMatch(e.arguments, tf, mod)) |
6384eff5 | 1226 | { |
7e7ebe3e | 1227 | return MATCH.nomatch; |
5fee5ec3 | 1228 | } |
6384eff5 | 1229 | } |
5fee5ec3 | 1230 | |
6384eff5 IB |
1231 | /* If no 'member', then construction is by simple assignment, |
1232 | * and just straight check 'arguments' | |
1233 | */ | |
1234 | if (!e.member && e.arguments) | |
1235 | { | |
1236 | for (size_t i = 0; i < e.arguments.dim; ++i) | |
5fee5ec3 | 1237 | { |
6384eff5 IB |
1238 | Expression earg = (*e.arguments)[i]; |
1239 | if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853 | |
1240 | // if it's on overlapped field | |
1241 | continue; | |
1242 | Type targ = earg.type.toBasetype(); | |
1243 | static if (LOG) | |
5fee5ec3 | 1244 | { |
6384eff5 IB |
1245 | printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); |
1246 | printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); | |
5fee5ec3 | 1247 | } |
6384eff5 IB |
1248 | if (implicitMod(earg, targ, mod) == MATCH.nomatch) |
1249 | return MATCH.nomatch; | |
5fee5ec3 | 1250 | } |
6384eff5 | 1251 | } |
5fee5ec3 | 1252 | |
6384eff5 IB |
1253 | /* Consider the .init expression as an argument |
1254 | */ | |
1255 | Type ntb = e.newtype.toBasetype(); | |
1256 | if (ntb.ty == Tarray) | |
1257 | ntb = ntb.nextOf().toBasetype(); | |
1258 | if (auto ts = ntb.isTypeStruct()) | |
1259 | { | |
1260 | // Don't allow nested structs - uplevel reference may not be convertible | |
1261 | StructDeclaration sd = ts.sym; | |
1262 | sd.size(e.loc); // resolve any forward references | |
1263 | if (sd.isNested()) | |
1264 | return MATCH.nomatch; | |
1265 | } | |
1266 | if (ntb.isZeroInit(e.loc)) | |
1267 | { | |
1268 | /* Zeros are implicitly convertible, except for special cases. | |
5fee5ec3 | 1269 | */ |
6384eff5 | 1270 | if (auto tc = ntb.isTypeClass()) |
5fee5ec3 | 1271 | { |
6384eff5 | 1272 | /* With new() must look at the class instance initializer. |
5fee5ec3 | 1273 | */ |
6384eff5 | 1274 | ClassDeclaration cd = tc.sym; |
5fee5ec3 | 1275 | |
6384eff5 | 1276 | cd.size(e.loc); // resolve any forward references |
5fee5ec3 | 1277 | |
6384eff5 IB |
1278 | if (cd.isNested()) |
1279 | return MATCH.nomatch; // uplevel reference may not be convertible | |
5fee5ec3 | 1280 | |
6384eff5 | 1281 | assert(!cd.isInterfaceDeclaration()); |
5fee5ec3 | 1282 | |
6384eff5 IB |
1283 | struct ClassCheck |
1284 | { | |
1285 | extern (C++) static bool convertible(Expression e, ClassDeclaration cd, MOD mod) | |
5fee5ec3 | 1286 | { |
6384eff5 | 1287 | for (size_t i = 0; i < cd.fields.dim; i++) |
5fee5ec3 | 1288 | { |
6384eff5 IB |
1289 | VarDeclaration v = cd.fields[i]; |
1290 | Initializer _init = v._init; | |
1291 | if (_init) | |
5fee5ec3 | 1292 | { |
6384eff5 IB |
1293 | if (_init.isVoidInitializer()) |
1294 | { | |
1295 | } | |
1296 | else if (ExpInitializer ei = _init.isExpInitializer()) | |
5fee5ec3 | 1297 | { |
6384eff5 IB |
1298 | // https://issues.dlang.org/show_bug.cgi?id=21319 |
1299 | // This is to prevent re-analyzing the same expression | |
1300 | // over and over again. | |
1301 | if (ei.exp == e) | |
1302 | return false; | |
1303 | Type tb = v.type.toBasetype(); | |
1304 | if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch) | |
5fee5ec3 | 1305 | return false; |
5fee5ec3 | 1306 | } |
6384eff5 IB |
1307 | else |
1308 | { | |
1309 | /* Enhancement: handle StructInitializer and ArrayInitializer | |
1310 | */ | |
5fee5ec3 | 1311 | return false; |
6384eff5 | 1312 | } |
5fee5ec3 | 1313 | } |
6384eff5 IB |
1314 | else if (!v.type.isZeroInit(e.loc)) |
1315 | return false; | |
5fee5ec3 | 1316 | } |
6384eff5 | 1317 | return cd.baseClass ? convertible(e, cd.baseClass, mod) : true; |
5fee5ec3 | 1318 | } |
5fee5ec3 | 1319 | } |
5fee5ec3 | 1320 | |
6384eff5 IB |
1321 | if (!ClassCheck.convertible(e, cd, mod)) |
1322 | return MATCH.nomatch; | |
5fee5ec3 | 1323 | } |
6384eff5 IB |
1324 | } |
1325 | else | |
1326 | { | |
1327 | Expression earg = e.newtype.defaultInitLiteral(e.loc); | |
1328 | Type targ = e.newtype.toBasetype(); | |
5fee5ec3 | 1329 | |
6384eff5 IB |
1330 | if (implicitMod(earg, targ, mod) == MATCH.nomatch) |
1331 | return MATCH.nomatch; | |
5fee5ec3 IB |
1332 | } |
1333 | ||
6384eff5 IB |
1334 | /* Success |
1335 | */ | |
1336 | return MATCH.constant; | |
1337 | } | |
1338 | ||
1339 | MATCH visitSlice(SliceExp e) | |
1340 | { | |
1341 | //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars()); | |
1342 | auto result = visit(e); | |
1343 | if (result != MATCH.nomatch) | |
1344 | return result; | |
5fee5ec3 | 1345 | |
6384eff5 IB |
1346 | Type tb = t.toBasetype(); |
1347 | Type typeb = e.type.toBasetype(); | |
5fee5ec3 | 1348 | |
6384eff5 IB |
1349 | if (tb.ty == Tsarray && typeb.ty == Tarray) |
1350 | { | |
1351 | typeb = toStaticArrayType(e); | |
1352 | if (typeb) | |
5fee5ec3 | 1353 | { |
6384eff5 IB |
1354 | // Try: T[] -> T[dim] |
1355 | // (Slice with compile-time known boundaries to static array) | |
1356 | result = typeb.implicitConvTo(t); | |
1357 | if (result > MATCH.convert) | |
1358 | result = MATCH.convert; // match with implicit conversion at most | |
5fee5ec3 | 1359 | } |
6384eff5 IB |
1360 | return result; |
1361 | } | |
5fee5ec3 | 1362 | |
6384eff5 IB |
1363 | /* If the only reason it won't convert is because of the mod bits, |
1364 | * then test for conversion by seeing if e1 can be converted with those | |
1365 | * same mod bits. | |
1366 | */ | |
1367 | Type t1b = e.e1.type.toBasetype(); | |
1368 | if (tb.ty == Tarray && typeb.equivalent(tb)) | |
1369 | { | |
1370 | Type tbn = tb.nextOf(); | |
1371 | Type tx = null; | |
5fee5ec3 | 1372 | |
6384eff5 IB |
1373 | /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1 |
1374 | * is equivalent with the uniqueness of the referred data. And in here | |
1375 | * we can have arbitrary typed reference for that. | |
1376 | */ | |
1377 | if (t1b.ty == Tarray) | |
1378 | tx = tbn.arrayOf(); | |
1379 | if (t1b.ty == Tpointer) | |
1380 | tx = tbn.pointerTo(); | |
1381 | ||
1382 | /* If e.e1 is static array, at least it should be an rvalue. | |
1383 | * If not, e.e1 is a reference, and its uniqueness does not link | |
1384 | * to the uniqueness of the referred data. | |
1385 | */ | |
1386 | if (t1b.ty == Tsarray && !e.e1.isLvalue()) | |
1387 | tx = tbn.sarrayOf(t1b.size() / tbn.size()); | |
5fee5ec3 | 1388 | |
6384eff5 IB |
1389 | if (tx) |
1390 | { | |
1391 | result = e.e1.implicitConvTo(tx); | |
1392 | if (result > MATCH.constant) // Match level is MATCH.constant at best. | |
1393 | result = MATCH.constant; | |
5fee5ec3 | 1394 | } |
5fee5ec3 | 1395 | } |
0fb57034 | 1396 | |
6384eff5 IB |
1397 | // Enhancement 10724 |
1398 | if (tb.ty == Tpointer && e.e1.op == EXP.string_) | |
1399 | result = e.e1.implicitConvTo(t); | |
1400 | return result; | |
1401 | } | |
0fb57034 | 1402 | |
6384eff5 IB |
1403 | MATCH visitTuple(TupleExp e) |
1404 | { | |
1405 | auto result = e.type.implicitConvTo(t); | |
1406 | if (result != MATCH.nomatch) | |
1407 | return result; | |
1408 | ||
1409 | /* If target type is a tuple of same length, test conversion of | |
1410 | * each expression to the corresponding type in the tuple. | |
1411 | */ | |
1412 | TypeTuple totuple = t.isTypeTuple(); | |
1413 | if (totuple && e.exps.length == totuple.arguments.length) | |
1414 | { | |
1415 | result = MATCH.exact; | |
1416 | foreach (i, ex; *e.exps) | |
0fb57034 | 1417 | { |
6384eff5 IB |
1418 | auto to = (*totuple.arguments)[i].type; |
1419 | MATCH mi = ex.implicitConvTo(to); | |
1420 | if (mi < result) | |
1421 | result = mi; | |
0fb57034 IB |
1422 | } |
1423 | } | |
6384eff5 | 1424 | return result; |
5fee5ec3 IB |
1425 | } |
1426 | ||
6384eff5 IB |
1427 | switch (e.op) |
1428 | { | |
1429 | default : return visit(e); | |
1430 | case EXP.add : return visitAdd(e.isAddExp()); | |
1431 | case EXP.min : return visitMin(e.isMinExp()); | |
1432 | case EXP.int64 : return visitInteger(e.isIntegerExp()); | |
1433 | case EXP.error : return visitError(e.isErrorExp()); | |
1434 | case EXP.null_ : return visitNull(e.isNullExp()); | |
1435 | case EXP.structLiteral : return visitStructLiteral(e.isStructLiteralExp()); | |
1436 | case EXP.string_ : return visitString(e.isStringExp()); | |
1437 | case EXP.arrayLiteral : return visitArrayLiteral(e.isArrayLiteralExp()); | |
1438 | case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); | |
1439 | case EXP.call : return visitCall(e.isCallExp()); | |
1440 | case EXP.address : return visitAddr(e.isAddrExp()); | |
1441 | case EXP.symbolOffset : return visitSymOff(e.isSymOffExp()); | |
1442 | case EXP.delegate_ : return visitDelegate(e.isDelegateExp()); | |
1443 | case EXP.function_ : return visitFunc(e.isFuncExp()); | |
1444 | case EXP.and : return visitAnd(e.isAndExp()); | |
1445 | case EXP.or : return visitOr(e.isOrExp()); | |
1446 | case EXP.xor : return visitXor(e.isXorExp()); | |
1447 | case EXP.question : return visitCond(e.isCondExp()); | |
1448 | case EXP.comma : return visitComma(e.isCommaExp()); | |
1449 | case EXP.cast_ : return visitCast(e.isCastExp()); | |
1450 | case EXP.new_ : return visitNew(e.isNewExp()); | |
1451 | case EXP.slice : return visitSlice(e.isSliceExp()); | |
1452 | case EXP.tuple : return visitTuple(e.isTupleExp()); | |
1453 | } | |
5fee5ec3 IB |
1454 | } |
1455 | ||
1456 | /** | |
1457 | * Same as implicitConvTo(); except follow C11 rules, which are quite a bit | |
1458 | * more permissive than D. | |
1459 | * C11 6.3 and 6.5.16.1 | |
1460 | * Params: | |
1461 | * e = Expression that is to be casted | |
1462 | * t = Expected resulting type | |
1463 | * Returns: | |
1464 | * The `MATCH` level between `e.type` and `t`. | |
1465 | */ | |
1466 | MATCH cimplicitConvTo(Expression e, Type t) | |
1467 | { | |
1468 | Type tb = t.toBasetype(); | |
1469 | Type typeb = e.type.toBasetype(); | |
1470 | ||
1471 | if (tb.equals(typeb)) | |
1472 | return MATCH.exact; | |
1473 | if ((typeb.isintegral() || typeb.isfloating()) && | |
1474 | (tb.isintegral() || tb.isfloating())) | |
1475 | return MATCH.convert; | |
1476 | if (tb.ty == Tpointer && typeb.isintegral()) // C11 6.3.2.3-5 | |
1477 | return MATCH.convert; | |
1478 | if (tb.isintegral() && typeb.ty == Tpointer) // C11 6.3.2.3-6 | |
1479 | return MATCH.convert; | |
0fb57034 IB |
1480 | if (tb.ty == Tpointer && typeb.ty == Tpointer) // C11 6.3.2.3-7 |
1481 | return MATCH.convert; | |
5fee5ec3 IB |
1482 | |
1483 | return implicitConvTo(e, t); | |
1484 | } | |
1485 | ||
1486 | /***************************************** | |
1487 | */ | |
1488 | Type toStaticArrayType(SliceExp e) | |
1489 | { | |
1490 | if (e.lwr && e.upr) | |
1491 | { | |
1492 | // For the following code to work, e should be optimized beforehand. | |
1493 | // (eg. $ in lwr and upr should be already resolved, if possible) | |
1494 | Expression lwr = e.lwr.optimize(WANTvalue); | |
1495 | Expression upr = e.upr.optimize(WANTvalue); | |
1496 | if (lwr.isConst() && upr.isConst()) | |
1497 | { | |
1498 | size_t len = cast(size_t)(upr.toUInteger() - lwr.toUInteger()); | |
1499 | return e.type.toBasetype().nextOf().sarrayOf(len); | |
1500 | } | |
1501 | } | |
1502 | else | |
1503 | { | |
1504 | Type t1b = e.e1.type.toBasetype(); | |
1505 | if (t1b.ty == Tsarray) | |
1506 | return t1b; | |
1507 | } | |
1508 | return null; | |
1509 | } | |
1510 | ||
1511 | /************************************** | |
1512 | * Do an explicit cast. | |
1513 | * Assume that the expression `e` does not have any indirections. | |
1514 | * (Parameter 'att' is used to stop 'alias this' recursion) | |
1515 | */ | |
1516 | Expression castTo(Expression e, Scope* sc, Type t, Type att = null) | |
1517 | { | |
6384eff5 | 1518 | Expression visit(Expression e) |
5fee5ec3 | 1519 | { |
6384eff5 IB |
1520 | //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars()); |
1521 | version (none) | |
5fee5ec3 | 1522 | { |
6384eff5 | 1523 | printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); |
5fee5ec3 | 1524 | } |
6384eff5 | 1525 | if (e.type.equals(t)) |
5fee5ec3 | 1526 | { |
6384eff5 IB |
1527 | return e; |
1528 | } | |
1529 | if (auto ve = e.isVarExp()) | |
1530 | { | |
1531 | VarDeclaration v = ve.var.isVarDeclaration(); | |
1532 | if (v && v.storage_class & STC.manifest) | |
5fee5ec3 | 1533 | { |
6384eff5 IB |
1534 | auto result = e.ctfeInterpret(); |
1535 | /* https://issues.dlang.org/show_bug.cgi?id=18236 | |
1536 | * | |
1537 | * The expression returned by ctfeInterpret points | |
1538 | * to the line where the manifest constant was declared | |
1539 | * so we need to update the location before trying to cast | |
1540 | */ | |
1541 | result.loc = e.loc; | |
1542 | return result.castTo(sc, t); | |
5fee5ec3 | 1543 | } |
6384eff5 | 1544 | } |
5fee5ec3 | 1545 | |
6384eff5 IB |
1546 | Type tob = t.toBasetype(); |
1547 | Type t1b = e.type.toBasetype(); | |
1548 | if (tob.equals(t1b)) | |
1549 | { | |
1550 | auto result = e.copy(); // because of COW for assignment to e.type | |
1551 | result.type = t; | |
1552 | return result; | |
1553 | } | |
5fee5ec3 | 1554 | |
6384eff5 IB |
1555 | /* Make semantic error against invalid cast between concrete types. |
1556 | * Assume that 'e' is never be any placeholder expressions. | |
1557 | * The result of these checks should be consistent with CastExp::toElem(). | |
1558 | */ | |
5fee5ec3 | 1559 | |
6384eff5 IB |
1560 | // Fat Value types |
1561 | const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray || tob.ty == Tvector); | |
1562 | const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray || t1b.ty == Tvector); | |
5fee5ec3 | 1563 | |
6384eff5 IB |
1564 | // Fat Reference types |
1565 | const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate); | |
1566 | const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate); | |
5fee5ec3 | 1567 | |
6384eff5 IB |
1568 | // Reference types |
1569 | const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass); | |
1570 | const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass); | |
5fee5ec3 | 1571 | |
6384eff5 IB |
1572 | // Arithmetic types (== valueable basic types) |
1573 | const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector); | |
1574 | const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector); | |
5fee5ec3 | 1575 | |
6384eff5 IB |
1576 | // Try casting the alias this member. |
1577 | // Return the expression if it succeeds, null otherwise. | |
1578 | Expression tryAliasThisCast() | |
1579 | { | |
1580 | if (isRecursiveAliasThis(att, t1b)) | |
1581 | return null; | |
5fee5ec3 | 1582 | |
6384eff5 IB |
1583 | /* Forward the cast to our alias this member, rewrite to: |
1584 | * cast(to)e1.aliasthis | |
1585 | */ | |
1586 | auto exp = resolveAliasThis(sc, e); | |
1587 | const errors = global.startGagging(); | |
1588 | exp = castTo(exp, sc, t, att); | |
1589 | return global.endGagging(errors) ? null : exp; | |
1590 | } | |
5fee5ec3 | 1591 | |
6384eff5 IB |
1592 | bool hasAliasThis; |
1593 | if (AggregateDeclaration t1ad = isAggregate(t1b)) | |
1594 | { | |
1595 | AggregateDeclaration toad = isAggregate(tob); | |
1596 | if (t1ad != toad && t1ad.aliasthis) | |
5fee5ec3 | 1597 | { |
6384eff5 | 1598 | if (t1b.ty == Tclass && tob.ty == Tclass) |
5fee5ec3 | 1599 | { |
6384eff5 IB |
1600 | ClassDeclaration t1cd = t1b.isClassHandle(); |
1601 | ClassDeclaration tocd = tob.isClassHandle(); | |
1602 | int offset; | |
1603 | if (tocd.isBaseOf(t1cd, &offset)) | |
5fee5ec3 IB |
1604 | goto Lok; |
1605 | } | |
6384eff5 | 1606 | hasAliasThis = true; |
5fee5ec3 | 1607 | } |
6384eff5 IB |
1608 | } |
1609 | else if (tob.ty == Tvector && t1b.ty != Tvector) | |
1610 | { | |
1611 | //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars()); | |
1612 | TypeVector tv = tob.isTypeVector(); | |
1613 | Expression result = new CastExp(e.loc, e, tv.elementType()); | |
1614 | result = new VectorExp(e.loc, result, tob); | |
1615 | result = result.expressionSemantic(sc); | |
1616 | return result; | |
1617 | } | |
1618 | else if (tob.ty != Tvector && t1b.ty == Tvector) | |
1619 | { | |
1620 | // T[n] <-- __vector(U[m]) | |
1621 | if (tob.ty == Tsarray) | |
5fee5ec3 | 1622 | { |
6384eff5 IB |
1623 | if (t1b.size(e.loc) == tob.size(e.loc)) |
1624 | goto Lok; | |
5fee5ec3 | 1625 | } |
6384eff5 IB |
1626 | goto Lfail; |
1627 | } | |
1628 | else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf())) | |
1629 | { | |
1630 | auto result = e.copy(); | |
1631 | result.type = t; | |
1632 | return result; | |
1633 | } | |
5fee5ec3 | 1634 | |
6384eff5 IB |
1635 | // arithmetic values vs. other arithmetic values |
1636 | // arithmetic values vs. T* | |
1637 | if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer)) | |
1638 | { | |
1639 | goto Lok; | |
1640 | } | |
1641 | ||
1642 | // arithmetic values vs. references or fat values | |
1643 | if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV)) | |
1644 | { | |
1645 | goto Lfail; | |
1646 | } | |
5fee5ec3 | 1647 | |
6384eff5 IB |
1648 | // Bugzlla 3133: A cast between fat values is possible only when the sizes match. |
1649 | if (tob_isFV && t1b_isFV) | |
1650 | { | |
1651 | if (hasAliasThis) | |
5fee5ec3 | 1652 | { |
6384eff5 IB |
1653 | auto result = tryAliasThisCast(); |
1654 | if (result) | |
1655 | return result; | |
5fee5ec3 IB |
1656 | } |
1657 | ||
6384eff5 IB |
1658 | if (t1b.size(e.loc) == tob.size(e.loc)) |
1659 | goto Lok; | |
5fee5ec3 | 1660 | |
6384eff5 IB |
1661 | auto ts = toAutoQualChars(e.type, t); |
1662 | e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes", | |
1663 | e.toChars(), ts[0], ts[1]); | |
1664 | return ErrorExp.get(); | |
1665 | } | |
5fee5ec3 | 1666 | |
6384eff5 IB |
1667 | // Fat values vs. null or references |
1668 | if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR)) | |
1669 | { | |
1670 | if (tob.ty == Tpointer && t1b.ty == Tsarray) | |
1671 | { | |
1672 | // T[n] sa; | |
1673 | // cast(U*)sa; // ==> cast(U*)sa.ptr; | |
1674 | return new AddrExp(e.loc, e, t); | |
5fee5ec3 | 1675 | } |
6384eff5 | 1676 | if (tob.ty == Tarray && t1b.ty == Tsarray) |
5fee5ec3 | 1677 | { |
6384eff5 IB |
1678 | // T[n] sa; |
1679 | // cast(U[])sa; // ==> cast(U[])sa[]; | |
6384eff5 IB |
1680 | const fsize = t1b.nextOf().size(); |
1681 | const tsize = tob.nextOf().size(); | |
1682 | if (fsize == SIZE_INVALID || tsize == SIZE_INVALID) | |
1683 | { | |
1684 | return ErrorExp.get(); | |
1685 | } | |
1686 | if (fsize != tsize) | |
1687 | { | |
1688 | const dim = t1b.isTypeSArray().dim.toInteger(); | |
1689 | if (tsize == 0 || (dim * fsize) % tsize != 0) | |
5fee5ec3 | 1690 | { |
6384eff5 IB |
1691 | e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up", |
1692 | e.toChars(), e.type.toChars(), t.toChars()); | |
1693 | return ErrorExp.get(); | |
5fee5ec3 | 1694 | } |
5fee5ec3 | 1695 | } |
6384eff5 | 1696 | goto Lok; |
5fee5ec3 | 1697 | } |
6384eff5 IB |
1698 | goto Lfail; |
1699 | } | |
5fee5ec3 | 1700 | |
6384eff5 IB |
1701 | /* For references, any reinterpret casts are allowed to same 'ty' type. |
1702 | * T* to U* | |
1703 | * R1 function(P1) to R2 function(P2) | |
1704 | * R1 delegate(P1) to R2 delegate(P2) | |
1705 | * T[] to U[] | |
1706 | * V1[K1] to V2[K2] | |
1707 | * class/interface A to B (will be a dynamic cast if possible) | |
1708 | */ | |
1709 | if (tob.ty == t1b.ty && tob_isR && t1b_isR) | |
1710 | goto Lok; | |
5fee5ec3 | 1711 | |
6384eff5 IB |
1712 | // typeof(null) <-- non-null references or values |
1713 | if (tob.ty == Tnull && t1b.ty != Tnull) | |
1714 | goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629 | |
1715 | // typeof(null) --> non-null references or arithmetic values | |
1716 | if (t1b.ty == Tnull && tob.ty != Tnull) | |
1717 | goto Lok; | |
5fee5ec3 | 1718 | |
6384eff5 IB |
1719 | // Check size mismatch of references. |
1720 | // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof. | |
1721 | if (tob_isFR && t1b_isR || t1b_isFR && tob_isR) | |
1722 | { | |
1723 | if (tob.ty == Tpointer && t1b.ty == Tarray) | |
5fee5ec3 | 1724 | { |
6384eff5 IB |
1725 | // T[] da; |
1726 | // cast(U*)da; // ==> cast(U*)da.ptr; | |
1727 | goto Lok; | |
5fee5ec3 | 1728 | } |
6384eff5 | 1729 | if (tob.ty == Tpointer && t1b.ty == Tdelegate) |
5fee5ec3 | 1730 | { |
6384eff5 IB |
1731 | // void delegate() dg; |
1732 | // cast(U*)dg; // ==> cast(U*)dg.ptr; | |
1733 | // Note that it happens even when U is a Tfunction! | |
1734 | e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars()); | |
1735 | goto Lok; | |
5fee5ec3 | 1736 | } |
6384eff5 | 1737 | goto Lfail; |
5fee5ec3 IB |
1738 | } |
1739 | ||
6384eff5 | 1740 | if (t1b.ty == Tvoid && tob.ty != Tvoid) |
5fee5ec3 | 1741 | { |
6384eff5 IB |
1742 | Lfail: |
1743 | /* if the cast cannot be performed, maybe there is an alias | |
1744 | * this that can be used for casting. | |
1745 | */ | |
1746 | if (hasAliasThis) | |
1747 | { | |
1748 | auto result = tryAliasThisCast(); | |
1749 | if (result) | |
1750 | return result; | |
1751 | } | |
1752 | e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars()); | |
1753 | return ErrorExp.get(); | |
5fee5ec3 IB |
1754 | } |
1755 | ||
6384eff5 IB |
1756 | Lok: |
1757 | auto result = new CastExp(e.loc, e, t); | |
1758 | result.type = t; // Don't call semantic() | |
1759 | //printf("Returning: %s\n", result.toChars()); | |
1760 | return result; | |
1761 | } | |
1762 | ||
1763 | Expression visitError(ErrorExp e) | |
1764 | { | |
1765 | return e; | |
1766 | } | |
1767 | ||
1768 | Expression visitReal(RealExp e) | |
1769 | { | |
1770 | if (!e.type.equals(t)) | |
5fee5ec3 | 1771 | { |
6384eff5 | 1772 | if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary())) |
5fee5ec3 | 1773 | { |
6384eff5 IB |
1774 | auto result = e.copy(); |
1775 | result.type = t; | |
1776 | return result; | |
5fee5ec3 | 1777 | } |
6384eff5 IB |
1778 | else |
1779 | return visit(e); | |
5fee5ec3 | 1780 | } |
6384eff5 IB |
1781 | return e; |
1782 | } | |
5fee5ec3 | 1783 | |
6384eff5 IB |
1784 | Expression visitComplex(ComplexExp e) |
1785 | { | |
1786 | if (!e.type.equals(t)) | |
5fee5ec3 | 1787 | { |
6384eff5 | 1788 | if (e.type.iscomplex() && t.iscomplex()) |
5fee5ec3 | 1789 | { |
6384eff5 IB |
1790 | auto result = e.copy(); |
1791 | result.type = t; | |
1792 | return result; | |
5fee5ec3 | 1793 | } |
6384eff5 IB |
1794 | else |
1795 | return visit(e); | |
5fee5ec3 | 1796 | } |
6384eff5 IB |
1797 | return e; |
1798 | } | |
1799 | ||
1800 | Expression visitStructLiteral(StructLiteralExp e) | |
1801 | { | |
1802 | auto result = visit(e); | |
1803 | if (auto sle = result.isStructLiteralExp()) | |
1804 | sle.stype = t; // commit type | |
1805 | return result; | |
1806 | } | |
1807 | ||
1808 | Expression visitString(StringExp e) | |
1809 | { | |
1810 | /* This follows copy-on-write; any changes to 'this' | |
1811 | * will result in a copy. | |
1812 | * The this.string member is considered immutable. | |
1813 | */ | |
1814 | int copied = 0; | |
5fee5ec3 | 1815 | |
6384eff5 IB |
1816 | //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed); |
1817 | ||
1818 | if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid && | |
1819 | (!sc || !(sc.flags & SCOPE.Cfile))) | |
5fee5ec3 | 1820 | { |
6384eff5 IB |
1821 | e.error("cannot convert string literal to `void*`"); |
1822 | return ErrorExp.get(); | |
5fee5ec3 IB |
1823 | } |
1824 | ||
6384eff5 IB |
1825 | StringExp se = e; |
1826 | ||
1827 | Expression lcast() | |
5fee5ec3 | 1828 | { |
6384eff5 IB |
1829 | auto result = new CastExp(e.loc, se, t); |
1830 | result.type = t; // so semantic() won't be run on e | |
1831 | return result; | |
1832 | } | |
5fee5ec3 | 1833 | |
6384eff5 IB |
1834 | if (!e.committed) |
1835 | { | |
1836 | se = e.copy().isStringExp(); | |
1837 | se.committed = 1; | |
1838 | copied = 1; | |
1839 | } | |
1840 | ||
1841 | if (e.type.equals(t)) | |
1842 | { | |
1843 | return se; | |
1844 | } | |
1845 | ||
1846 | Type tb = t.toBasetype(); | |
1847 | Type typeb = e.type.toBasetype(); | |
1848 | ||
1849 | //printf("\ttype = %s\n", e.type.toChars()); | |
1850 | if (tb.ty == Tdelegate && typeb.ty != Tdelegate) | |
1851 | { | |
1852 | return visit(e); | |
1853 | } | |
5fee5ec3 | 1854 | |
6384eff5 IB |
1855 | if (typeb.equals(tb)) |
1856 | { | |
1857 | if (!copied) | |
5fee5ec3 | 1858 | { |
6384eff5 IB |
1859 | se = e.copy().isStringExp(); |
1860 | copied = 1; | |
5fee5ec3 | 1861 | } |
6384eff5 IB |
1862 | se.type = t; |
1863 | return se; | |
1864 | } | |
5fee5ec3 | 1865 | |
6384eff5 IB |
1866 | /* Handle reinterpret casts: |
1867 | * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000] | |
1868 | * cast(wchar[2])"abcd"c --> [\u6261, \u6463] | |
1869 | * cast(wchar[1])"abcd"c --> [\u6261] | |
1870 | * cast(char[4])"a" --> ['a', 0, 0, 0] | |
1871 | */ | |
1872 | if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray) | |
1873 | { | |
1874 | se = e.copy().isStringExp(); | |
fbdaa581 | 1875 | uinteger_t szx = tb.nextOf().size(); |
6384eff5 IB |
1876 | assert(szx <= 255); |
1877 | se.sz = cast(ubyte)szx; | |
1878 | se.len = cast(size_t)tb.isTypeSArray().dim.toInteger(); | |
1879 | se.committed = 1; | |
1880 | se.type = t; | |
9c7d5e88 | 1881 | |
6384eff5 IB |
1882 | /* If larger than source, pad with zeros. |
1883 | */ | |
1884 | const fullSize = (se.len + 1) * se.sz; // incl. terminating 0 | |
1885 | if (fullSize > (e.len + 1) * e.sz) | |
9c7d5e88 | 1886 | { |
6384eff5 IB |
1887 | void* s = mem.xmalloc(fullSize); |
1888 | const srcSize = e.len * e.sz; | |
1889 | const data = se.peekData(); | |
1890 | memcpy(s, data.ptr, srcSize); | |
1891 | memset(s + srcSize, 0, fullSize - srcSize); | |
1892 | se.setData(s, se.len, se.sz); | |
9c7d5e88 | 1893 | } |
6384eff5 IB |
1894 | return se; |
1895 | } | |
9c7d5e88 | 1896 | |
6384eff5 IB |
1897 | if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer) |
1898 | { | |
1899 | if (!copied) | |
5fee5ec3 | 1900 | { |
b3f58f87 | 1901 | se = e.copy().isStringExp(); |
5fee5ec3 IB |
1902 | copied = 1; |
1903 | } | |
6384eff5 IB |
1904 | return lcast(); |
1905 | } | |
1906 | if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer) | |
1907 | { | |
1908 | if (!copied) | |
5fee5ec3 | 1909 | { |
6384eff5 IB |
1910 | se = e.copy().isStringExp(); |
1911 | copied = 1; | |
5fee5ec3 | 1912 | } |
6384eff5 IB |
1913 | return lcast(); |
1914 | } | |
5fee5ec3 | 1915 | |
6384eff5 IB |
1916 | const nextSz = typeb.nextOf().size(); |
1917 | if (nextSz == SIZE_INVALID) | |
1918 | { | |
1919 | return ErrorExp.get(); | |
1920 | } | |
1921 | if (nextSz == tb.nextOf().size()) | |
1922 | { | |
1923 | if (!copied) | |
5fee5ec3 | 1924 | { |
6384eff5 IB |
1925 | se = e.copy().isStringExp(); |
1926 | copied = 1; | |
5fee5ec3 | 1927 | } |
6384eff5 IB |
1928 | if (tb.ty == Tsarray) |
1929 | goto L2; // handle possible change in static array dimension | |
1930 | se.type = t; | |
1931 | return se; | |
1932 | } | |
1933 | ||
1934 | if (e.committed) | |
1935 | goto Lcast; | |
1936 | ||
1937 | auto X(T, U)(T tf, U tt) | |
1938 | { | |
1939 | return (cast(int)tf * 256 + cast(int)tt); | |
1940 | } | |
5fee5ec3 | 1941 | |
6384eff5 IB |
1942 | { |
1943 | OutBuffer buffer; | |
1944 | size_t newlen = 0; | |
1945 | int tfty = typeb.nextOf().toBasetype().ty; | |
1946 | int ttty = tb.nextOf().toBasetype().ty; | |
1947 | switch (X(tfty, ttty)) | |
5fee5ec3 | 1948 | { |
6384eff5 IB |
1949 | case X(Tchar, Tchar): |
1950 | case X(Twchar, Twchar): | |
1951 | case X(Tdchar, Tdchar): | |
1952 | break; | |
1953 | ||
1954 | case X(Tchar, Twchar): | |
1955 | for (size_t u = 0; u < e.len;) | |
5fee5ec3 | 1956 | { |
6384eff5 IB |
1957 | dchar c; |
1958 | if (const s = utf_decodeChar(se.peekString(), u, c)) | |
1959 | e.error("%.*s", cast(int)s.length, s.ptr); | |
1960 | else | |
1961 | buffer.writeUTF16(c); | |
5fee5ec3 | 1962 | } |
6384eff5 IB |
1963 | newlen = buffer.length / 2; |
1964 | buffer.writeUTF16(0); | |
1965 | goto L1; | |
5fee5ec3 | 1966 | |
6384eff5 IB |
1967 | case X(Tchar, Tdchar): |
1968 | for (size_t u = 0; u < e.len;) | |
5fee5ec3 | 1969 | { |
6384eff5 IB |
1970 | dchar c; |
1971 | if (const s = utf_decodeChar(se.peekString(), u, c)) | |
1972 | e.error("%.*s", cast(int)s.length, s.ptr); | |
1973 | buffer.write4(c); | |
1974 | newlen++; | |
5fee5ec3 | 1975 | } |
6384eff5 IB |
1976 | buffer.write4(0); |
1977 | goto L1; | |
5fee5ec3 | 1978 | |
6384eff5 IB |
1979 | case X(Twchar, Tchar): |
1980 | for (size_t u = 0; u < e.len;) | |
5fee5ec3 | 1981 | { |
6384eff5 IB |
1982 | dchar c; |
1983 | if (const s = utf_decodeWchar(se.peekWstring(), u, c)) | |
1984 | e.error("%.*s", cast(int)s.length, s.ptr); | |
1985 | else | |
1986 | buffer.writeUTF8(c); | |
5fee5ec3 | 1987 | } |
6384eff5 IB |
1988 | newlen = buffer.length; |
1989 | buffer.writeUTF8(0); | |
1990 | goto L1; | |
1991 | ||
1992 | case X(Twchar, Tdchar): | |
1993 | for (size_t u = 0; u < e.len;) | |
5fee5ec3 | 1994 | { |
6384eff5 IB |
1995 | dchar c; |
1996 | if (const s = utf_decodeWchar(se.peekWstring(), u, c)) | |
1997 | e.error("%.*s", cast(int)s.length, s.ptr); | |
1998 | buffer.write4(c); | |
1999 | newlen++; | |
5fee5ec3 | 2000 | } |
6384eff5 IB |
2001 | buffer.write4(0); |
2002 | goto L1; | |
5fee5ec3 | 2003 | |
6384eff5 IB |
2004 | case X(Tdchar, Tchar): |
2005 | for (size_t u = 0; u < e.len; u++) | |
5fee5ec3 | 2006 | { |
6384eff5 IB |
2007 | uint c = se.peekDstring()[u]; |
2008 | if (!utf_isValidDchar(c)) | |
2009 | e.error("invalid UCS-32 char \\U%08x", c); | |
2010 | else | |
2011 | buffer.writeUTF8(c); | |
2012 | newlen++; | |
5fee5ec3 | 2013 | } |
6384eff5 IB |
2014 | newlen = buffer.length; |
2015 | buffer.writeUTF8(0); | |
2016 | goto L1; | |
5fee5ec3 | 2017 | |
6384eff5 IB |
2018 | case X(Tdchar, Twchar): |
2019 | for (size_t u = 0; u < e.len; u++) | |
5fee5ec3 | 2020 | { |
6384eff5 IB |
2021 | uint c = se.peekDstring()[u]; |
2022 | if (!utf_isValidDchar(c)) | |
2023 | e.error("invalid UCS-32 char \\U%08x", c); | |
2024 | else | |
2025 | buffer.writeUTF16(c); | |
2026 | newlen++; | |
5fee5ec3 | 2027 | } |
6384eff5 IB |
2028 | newlen = buffer.length / 2; |
2029 | buffer.writeUTF16(0); | |
2030 | goto L1; | |
5fee5ec3 | 2031 | |
6384eff5 IB |
2032 | L1: |
2033 | if (!copied) | |
2034 | { | |
2035 | se = e.copy().isStringExp(); | |
2036 | copied = 1; | |
2037 | } | |
5fee5ec3 | 2038 | |
5fee5ec3 | 2039 | { |
fbdaa581 | 2040 | uinteger_t szx = tb.nextOf().size(); |
6384eff5 IB |
2041 | assert(szx <= 255); |
2042 | se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx); | |
5fee5ec3 | 2043 | } |
6384eff5 | 2044 | break; |
5fee5ec3 | 2045 | |
6384eff5 IB |
2046 | default: |
2047 | assert(typeb.nextOf().size() != tb.nextOf().size()); | |
2048 | goto Lcast; | |
2049 | } | |
5fee5ec3 | 2050 | } |
6384eff5 IB |
2051 | L2: |
2052 | assert(copied); | |
5fee5ec3 | 2053 | |
6384eff5 IB |
2054 | // See if need to truncate or extend the literal |
2055 | if (auto tsa = tb.isTypeSArray()) | |
5fee5ec3 | 2056 | { |
6384eff5 | 2057 | size_t dim2 = cast(size_t)tsa.dim.toInteger(); |
31350635 | 2058 | //printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2); |
6384eff5 IB |
2059 | |
2060 | // Changing dimensions | |
2061 | if (dim2 != se.len) | |
5fee5ec3 | 2062 | { |
6384eff5 IB |
2063 | // Copy when changing the string literal |
2064 | const newsz = se.sz; | |
2065 | const d = (dim2 < se.len) ? dim2 : se.len; | |
2066 | void* s = mem.xmalloc((dim2 + 1) * newsz); | |
2067 | memcpy(s, se.peekData().ptr, d * newsz); | |
2068 | // Extend with 0, add terminating 0 | |
2069 | memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz); | |
2070 | se.setData(s, dim2, newsz); | |
5fee5ec3 | 2071 | } |
6384eff5 IB |
2072 | } |
2073 | se.type = t; | |
2074 | return se; | |
5fee5ec3 | 2075 | |
6384eff5 IB |
2076 | Lcast: |
2077 | auto result = new CastExp(e.loc, se, t); | |
2078 | result.type = t; // so semantic() won't be run on e | |
2079 | return result; | |
2080 | } | |
5fee5ec3 | 2081 | |
6384eff5 IB |
2082 | Expression visitAddr(AddrExp e) |
2083 | { | |
2084 | version (none) | |
2085 | { | |
2086 | printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
2087 | } | |
2088 | Type tb = t.toBasetype(); | |
2089 | Type typeb = e.type.toBasetype(); | |
5fee5ec3 | 2090 | |
6384eff5 IB |
2091 | if (tb.equals(typeb)) |
2092 | { | |
2093 | auto result = e.copy(); | |
2094 | result.type = t; | |
2095 | return result; | |
2096 | } | |
5fee5ec3 | 2097 | |
6384eff5 IB |
2098 | // Look for pointers to functions where the functions are overloaded. |
2099 | if (e.e1.isOverExp() && | |
2100 | (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) | |
2101 | { | |
2102 | OverExp eo = e.e1.isOverExp(); | |
2103 | FuncDeclaration f = null; | |
2104 | for (size_t i = 0; i < eo.vars.a.dim; i++) | |
5fee5ec3 | 2105 | { |
6384eff5 IB |
2106 | auto s = eo.vars.a[i]; |
2107 | auto f2 = s.isFuncDeclaration(); | |
2108 | assert(f2); | |
2109 | if (f2.overloadExactMatch(tb.nextOf())) | |
5fee5ec3 | 2110 | { |
5fee5ec3 IB |
2111 | if (f) |
2112 | { | |
6384eff5 IB |
2113 | /* Error if match in more than one overload set, |
2114 | * even if one is a 'better' match than the other. | |
2115 | */ | |
2116 | ScopeDsymbol.multiplyDefined(e.loc, f, f2); | |
5fee5ec3 | 2117 | } |
6384eff5 IB |
2118 | else |
2119 | f = f2; | |
5fee5ec3 IB |
2120 | } |
2121 | } | |
6384eff5 IB |
2122 | if (f) |
2123 | { | |
2124 | f.tookAddressOf++; | |
2125 | auto se = new SymOffExp(e.loc, f, 0, false); | |
2126 | auto se2 = se.expressionSemantic(sc); | |
2127 | // Let SymOffExp::castTo() do the heavy lifting | |
2128 | return visit(se2); | |
2129 | } | |
2130 | } | |
5fee5ec3 | 2131 | |
6384eff5 IB |
2132 | if (e.e1.isVarExp() && |
2133 | typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && | |
2134 | tb.ty == Tpointer && tb.nextOf().ty == Tfunction) | |
2135 | { | |
2136 | auto ve = e.e1.isVarExp(); | |
2137 | auto f = ve.var.isFuncDeclaration(); | |
2138 | if (f) | |
5fee5ec3 | 2139 | { |
6384eff5 IB |
2140 | assert(f.isImportedSymbol()); |
2141 | f = f.overloadExactMatch(tb.nextOf()); | |
2142 | if (f) | |
5fee5ec3 | 2143 | { |
6384eff5 IB |
2144 | Expression result = new VarExp(e.loc, f, false); |
2145 | result.type = f.type; | |
2146 | result = new AddrExp(e.loc, result, t); | |
2147 | return result; | |
5fee5ec3 IB |
2148 | } |
2149 | } | |
5fee5ec3 IB |
2150 | } |
2151 | ||
6384eff5 | 2152 | if (auto f = isFuncAddress(e)) |
5fee5ec3 | 2153 | { |
6384eff5 | 2154 | if (f.checkForwardRef(e.loc)) |
5fee5ec3 | 2155 | { |
6384eff5 | 2156 | return ErrorExp.get(); |
5fee5ec3 | 2157 | } |
5fee5ec3 IB |
2158 | } |
2159 | ||
6384eff5 IB |
2160 | return visit(e); |
2161 | } | |
2162 | ||
2163 | Expression visitTuple(TupleExp e) | |
2164 | { | |
2165 | if (e.type.equals(t)) | |
5fee5ec3 | 2166 | { |
6384eff5 IB |
2167 | return e; |
2168 | } | |
5fee5ec3 | 2169 | |
6384eff5 IB |
2170 | /* If target type is a tuple of same length, cast each expression to |
2171 | * the corresponding type in the tuple. | |
2172 | */ | |
2173 | TypeTuple totuple; | |
2174 | if (auto tt = t.isTypeTuple()) | |
2175 | totuple = e.exps.length == tt.arguments.length ? tt : null; | |
2176 | ||
2177 | TupleExp te = e.copy().isTupleExp(); | |
2178 | te.e0 = e.e0 ? e.e0.copy() : null; | |
2179 | te.exps = e.exps.copy(); | |
2180 | for (size_t i = 0; i < te.exps.dim; i++) | |
2181 | { | |
2182 | Expression ex = (*te.exps)[i]; | |
2183 | ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t); | |
2184 | (*te.exps)[i] = ex; | |
2185 | } | |
2186 | if (totuple) | |
2187 | te.type = totuple; | |
2188 | return te; | |
2189 | ||
2190 | /* Questionable behavior: In here, result.type is not set to t | |
2191 | * if target type is not a tuple of same length. | |
2192 | * Therefoe: | |
2193 | * TypeTuple!(int, int) values; | |
2194 | * auto values2 = cast(long)values; | |
2195 | * // typeof(values2) == TypeTuple!(int, int) !! | |
2196 | * | |
2197 | * Only when the casted tuple is immediately expanded, it would work. | |
2198 | * auto arr = [cast(long)values]; | |
2199 | * // typeof(arr) == long[] | |
2200 | */ | |
2201 | } | |
5fee5ec3 | 2202 | |
6384eff5 IB |
2203 | Expression visitArrayLiteral(ArrayLiteralExp e) |
2204 | { | |
2205 | version (none) | |
2206 | { | |
2207 | printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
2208 | } | |
2209 | ||
2210 | ArrayLiteralExp ae = e; | |
5fee5ec3 | 2211 | |
6384eff5 | 2212 | Type tb = t.toBasetype(); |
5eb9927a | 2213 | if (tb.ty == Tarray) |
6384eff5 IB |
2214 | { |
2215 | if (checkArrayLiteralEscape(sc, ae, false)) | |
5fee5ec3 | 2216 | { |
6384eff5 | 2217 | return ErrorExp.get(); |
5fee5ec3 | 2218 | } |
6384eff5 | 2219 | } |
5fee5ec3 | 2220 | |
6384eff5 IB |
2221 | if (e.type == t) |
2222 | { | |
2223 | return e; | |
2224 | } | |
2225 | Type typeb = e.type.toBasetype(); | |
5fee5ec3 | 2226 | |
6384eff5 IB |
2227 | if ((tb.ty == Tarray || tb.ty == Tsarray) && |
2228 | (typeb.ty == Tarray || typeb.ty == Tsarray)) | |
2229 | { | |
2230 | if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid) | |
2231 | { | |
2232 | // Don't do anything to cast non-void[] to void[] | |
5fee5ec3 | 2233 | } |
6384eff5 | 2234 | else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid) |
5fee5ec3 | 2235 | { |
6384eff5 | 2236 | // Don't do anything for casting void[n] to others |
5fee5ec3 | 2237 | } |
6384eff5 | 2238 | else |
5fee5ec3 | 2239 | { |
6384eff5 IB |
2240 | if (auto tsa = tb.isTypeSArray()) |
2241 | { | |
2242 | if (e.elements.dim != tsa.dim.toInteger()) | |
2243 | goto L1; | |
2244 | } | |
5fee5ec3 IB |
2245 | |
2246 | ae = e.copy().isArrayLiteralExp(); | |
6384eff5 IB |
2247 | if (e.basis) |
2248 | ae.basis = e.basis.castTo(sc, tb.nextOf()); | |
5fee5ec3 | 2249 | ae.elements = e.elements.copy(); |
6384eff5 | 2250 | for (size_t i = 0; i < e.elements.dim; i++) |
5fee5ec3 IB |
2251 | { |
2252 | Expression ex = (*e.elements)[i]; | |
6384eff5 IB |
2253 | if (!ex) |
2254 | continue; | |
2255 | ex = ex.castTo(sc, tb.nextOf()); | |
5fee5ec3 IB |
2256 | (*ae.elements)[i] = ex; |
2257 | } | |
6384eff5 IB |
2258 | ae.type = t; |
2259 | return ae; | |
5fee5ec3 | 2260 | } |
5fee5ec3 | 2261 | } |
6384eff5 | 2262 | else if (tb.ty == Tpointer && typeb.ty == Tsarray) |
5fee5ec3 | 2263 | { |
6384eff5 IB |
2264 | Type tp = typeb.nextOf().pointerTo(); |
2265 | if (!tp.equals(ae.type)) | |
5fee5ec3 | 2266 | { |
6384eff5 IB |
2267 | ae = e.copy().isArrayLiteralExp(); |
2268 | ae.type = tp; | |
5fee5ec3 | 2269 | } |
5fee5ec3 | 2270 | } |
6384eff5 | 2271 | else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) |
5fee5ec3 | 2272 | { |
6384eff5 IB |
2273 | // Convert array literal to vector type |
2274 | TypeVector tv = tb.isTypeVector(); | |
2275 | TypeSArray tbase = tv.basetype.isTypeSArray(); | |
2276 | assert(tbase.ty == Tsarray); | |
2277 | const edim = e.elements.dim; | |
2278 | const tbasedim = tbase.dim.toInteger(); | |
2279 | if (edim > tbasedim) | |
2280 | goto L1; | |
2281 | ||
2282 | ae = e.copy().isArrayLiteralExp(); | |
2283 | ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642 | |
2284 | ae.elements = e.elements.copy(); | |
2285 | Type telement = tv.elementType(); | |
2286 | foreach (i; 0 .. edim) | |
5fee5ec3 | 2287 | { |
6384eff5 IB |
2288 | Expression ex = (*e.elements)[i]; |
2289 | ex = ex.castTo(sc, telement); | |
2290 | (*ae.elements)[i] = ex; | |
5fee5ec3 | 2291 | } |
6384eff5 IB |
2292 | // Fill in the rest with the default initializer |
2293 | ae.elements.setDim(cast(size_t)tbasedim); | |
2294 | foreach (i; edim .. cast(size_t)tbasedim) | |
5fee5ec3 | 2295 | { |
6384eff5 IB |
2296 | Expression ex = typeb.nextOf.defaultInitLiteral(e.loc); |
2297 | ex = ex.castTo(sc, telement); | |
2298 | (*ae.elements)[i] = ex; | |
5fee5ec3 | 2299 | } |
6384eff5 IB |
2300 | Expression ev = new VectorExp(e.loc, ae, tb); |
2301 | ev = ev.expressionSemantic(sc); | |
2302 | return ev; | |
2303 | } | |
2304 | L1: | |
2305 | return visit(ae); | |
2306 | } | |
2307 | ||
2308 | Expression visitAssocArrayLiteral(AssocArrayLiteralExp e) | |
2309 | { | |
2310 | //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
2311 | if (e.type == t) | |
2312 | { | |
2313 | return e; | |
2314 | } | |
5fee5ec3 | 2315 | |
6384eff5 IB |
2316 | Type tb = t.toBasetype(); |
2317 | Type typeb = e.type.toBasetype(); | |
5fee5ec3 | 2318 | |
6384eff5 IB |
2319 | if (tb.ty == Taarray && typeb.ty == Taarray && |
2320 | tb.nextOf().toBasetype().ty != Tvoid) | |
2321 | { | |
2322 | AssocArrayLiteralExp ae = e.copy().isAssocArrayLiteralExp(); | |
2323 | ae.keys = e.keys.copy(); | |
2324 | ae.values = e.values.copy(); | |
2325 | assert(e.keys.dim == e.values.dim); | |
2326 | for (size_t i = 0; i < e.keys.dim; i++) | |
5fee5ec3 | 2327 | { |
6384eff5 IB |
2328 | Expression ex = (*e.values)[i]; |
2329 | ex = ex.castTo(sc, tb.nextOf()); | |
2330 | (*ae.values)[i] = ex; | |
2331 | ||
2332 | ex = (*e.keys)[i]; | |
2333 | ex = ex.castTo(sc, tb.isTypeAArray().index); | |
2334 | (*ae.keys)[i] = ex; | |
5fee5ec3 | 2335 | } |
6384eff5 IB |
2336 | ae.type = t; |
2337 | return ae; | |
2338 | } | |
2339 | return visit(e); | |
2340 | } | |
2341 | ||
2342 | Expression visitSymOff(SymOffExp e) | |
2343 | { | |
2344 | version (none) | |
2345 | { | |
2346 | printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
2347 | } | |
2348 | if (e.type == t && !e.hasOverloads) | |
2349 | { | |
2350 | return e; | |
2351 | } | |
2352 | ||
2353 | Type tb = t.toBasetype(); | |
2354 | Type typeb = e.type.toBasetype(); | |
2355 | ||
2356 | if (tb.equals(typeb)) | |
2357 | { | |
2358 | auto result = e.copy(); | |
2359 | result.type = t; | |
2360 | result.isSymOffExp().hasOverloads = false; | |
2361 | return result; | |
2362 | } | |
5fee5ec3 | 2363 | |
6384eff5 IB |
2364 | // Look for pointers to functions where the functions are overloaded. |
2365 | if (e.hasOverloads && | |
2366 | typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && | |
2367 | (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) | |
2368 | { | |
2369 | FuncDeclaration f = e.var.isFuncDeclaration(); | |
2370 | f = f ? f.overloadExactMatch(tb.nextOf()) : null; | |
2371 | if (f) | |
5fee5ec3 | 2372 | { |
6384eff5 IB |
2373 | Expression result; |
2374 | if (tb.ty == Tdelegate) | |
5fee5ec3 | 2375 | { |
6384eff5 | 2376 | if (f.needThis() && hasThis(sc)) |
5fee5ec3 | 2377 | { |
6384eff5 IB |
2378 | result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false); |
2379 | result = result.expressionSemantic(sc); | |
2380 | } | |
2381 | else if (f.needThis()) | |
2382 | { | |
2383 | e.error("no `this` to create delegate for `%s`", f.toChars()); | |
2384 | return ErrorExp.get(); | |
2385 | } | |
2386 | else if (f.isNested()) | |
2387 | { | |
2388 | result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false); | |
2389 | result = result.expressionSemantic(sc); | |
5fee5ec3 IB |
2390 | } |
2391 | else | |
2392 | { | |
6384eff5 IB |
2393 | e.error("cannot cast from function pointer to delegate"); |
2394 | return ErrorExp.get(); | |
5fee5ec3 | 2395 | } |
5fee5ec3 | 2396 | } |
6384eff5 | 2397 | else |
5fee5ec3 | 2398 | { |
6384eff5 IB |
2399 | result = new SymOffExp(e.loc, f, 0, false); |
2400 | result.type = t; | |
5fee5ec3 | 2401 | } |
6384eff5 IB |
2402 | f.tookAddressOf++; |
2403 | return result; | |
5fee5ec3 | 2404 | } |
5fee5ec3 IB |
2405 | } |
2406 | ||
6384eff5 | 2407 | if (auto f = isFuncAddress(e)) |
5fee5ec3 | 2408 | { |
6384eff5 | 2409 | if (f.checkForwardRef(e.loc)) |
5fee5ec3 | 2410 | { |
6384eff5 | 2411 | return ErrorExp.get(); |
5fee5ec3 | 2412 | } |
6384eff5 | 2413 | } |
5fee5ec3 | 2414 | |
6384eff5 IB |
2415 | return visit(e); |
2416 | } | |
5fee5ec3 | 2417 | |
6384eff5 IB |
2418 | Expression visitDelegate(DelegateExp e) |
2419 | { | |
2420 | version (none) | |
2421 | { | |
2422 | printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); | |
2423 | } | |
7e287503 | 2424 | static immutable msg = "cannot form delegate due to covariant return type"; |
5fee5ec3 | 2425 | |
6384eff5 IB |
2426 | Type tb = t.toBasetype(); |
2427 | Type typeb = e.type.toBasetype(); | |
2428 | ||
2429 | if (tb.equals(typeb) && !e.hasOverloads) | |
2430 | { | |
2431 | int offset; | |
2432 | e.func.tookAddressOf++; | |
2433 | if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset) | |
7e287503 | 2434 | e.error("%s", msg.ptr); |
6384eff5 IB |
2435 | auto result = e.copy(); |
2436 | result.type = t; | |
2437 | return result; | |
2438 | } | |
5fee5ec3 | 2439 | |
6384eff5 IB |
2440 | // Look for delegates to functions where the functions are overloaded. |
2441 | if (typeb.ty == Tdelegate && tb.ty == Tdelegate) | |
2442 | { | |
2443 | if (e.func) | |
5fee5ec3 | 2444 | { |
6384eff5 IB |
2445 | auto f = e.func.overloadExactMatch(tb.nextOf()); |
2446 | if (f) | |
5fee5ec3 | 2447 | { |
6384eff5 IB |
2448 | int offset; |
2449 | if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) | |
7e287503 | 2450 | e.error("%s", msg.ptr); |
6384eff5 IB |
2451 | if (f != e.func) // if address not already marked as taken |
2452 | f.tookAddressOf++; | |
2453 | auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2); | |
2454 | result.type = t; | |
2455 | return result; | |
5fee5ec3 | 2456 | } |
6384eff5 | 2457 | if (e.func.tintro) |
7e287503 | 2458 | e.error("%s", msg.ptr); |
5fee5ec3 | 2459 | } |
5fee5ec3 IB |
2460 | } |
2461 | ||
6384eff5 | 2462 | if (auto f = isFuncAddress(e)) |
5fee5ec3 | 2463 | { |
6384eff5 | 2464 | if (f.checkForwardRef(e.loc)) |
5fee5ec3 | 2465 | { |
6384eff5 | 2466 | return ErrorExp.get(); |
5fee5ec3 | 2467 | } |
5fee5ec3 IB |
2468 | } |
2469 | ||
6384eff5 IB |
2470 | return visit(e); |
2471 | } | |
2472 | ||
2473 | Expression visitFunc(FuncExp e) | |
2474 | { | |
2475 | //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars()); | |
2476 | FuncExp fe; | |
2477 | if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch) | |
5fee5ec3 | 2478 | { |
6384eff5 | 2479 | return fe; |
5fee5ec3 | 2480 | } |
6384eff5 IB |
2481 | return visit(e); |
2482 | } | |
5fee5ec3 | 2483 | |
6384eff5 IB |
2484 | Expression visitCond(CondExp e) |
2485 | { | |
2486 | if (!e.type.equals(t)) | |
5fee5ec3 | 2487 | { |
6384eff5 IB |
2488 | auto result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t)); |
2489 | result.type = t; | |
2490 | return result; | |
5fee5ec3 | 2491 | } |
6384eff5 IB |
2492 | return e; |
2493 | } | |
5fee5ec3 | 2494 | |
6384eff5 IB |
2495 | Expression visitComma(CommaExp e) |
2496 | { | |
2497 | Expression e2c = e.e2.castTo(sc, t); | |
2498 | ||
2499 | if (e2c != e.e2) | |
2500 | { | |
2501 | auto result = new CommaExp(e.loc, e.e1, e2c); | |
2502 | result.type = e2c.type; | |
2503 | return result; | |
2504 | } | |
2505 | else | |
5fee5ec3 | 2506 | { |
6384eff5 IB |
2507 | e.type = e.e2.type; |
2508 | return e; | |
2509 | } | |
2510 | } | |
2511 | ||
2512 | Expression visitSlice(SliceExp e) | |
2513 | { | |
2514 | //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars()); | |
2515 | ||
2516 | Type tb = t.toBasetype(); | |
2517 | Type typeb = e.type.toBasetype(); | |
5fee5ec3 | 2518 | |
6384eff5 IB |
2519 | if (e.type.equals(t) || typeb.ty != Tarray || |
2520 | (tb.ty != Tarray && tb.ty != Tsarray)) | |
2521 | { | |
2522 | return visit(e); | |
2523 | } | |
5fee5ec3 | 2524 | |
6384eff5 IB |
2525 | if (tb.ty == Tarray) |
2526 | { | |
2527 | if (typeb.nextOf().equivalent(tb.nextOf())) | |
5fee5ec3 | 2528 | { |
6384eff5 IB |
2529 | // T[] to const(T)[] |
2530 | auto result = e.copy(); | |
2531 | result.type = t; | |
2532 | return result; | |
5fee5ec3 | 2533 | } |
6384eff5 | 2534 | else |
5fee5ec3 | 2535 | { |
6384eff5 | 2536 | return visit(e); |
5fee5ec3 | 2537 | } |
6384eff5 | 2538 | } |
5fee5ec3 | 2539 | |
6384eff5 | 2540 | // Handle the cast from Tarray to Tsarray with CT-known slicing |
5fee5ec3 | 2541 | |
6384eff5 IB |
2542 | TypeSArray tsa = toStaticArrayType(e).isTypeSArray(); |
2543 | if (tsa && tsa.size(e.loc) == tb.size(e.loc)) | |
2544 | { | |
2545 | /* Match if the sarray sizes are equal: | |
2546 | * T[a .. b] to const(T)[b-a] | |
2547 | * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim) | |
2548 | * | |
2549 | * If a SliceExp has Tsarray, it will become lvalue. | |
2550 | * That's handled in SliceExp::isLvalue and toLvalue | |
2551 | */ | |
2552 | auto result = e.copy(); | |
2553 | result.type = t; | |
2554 | return result; | |
2555 | } | |
2556 | if (tsa && tsa.dim.equals(tb.isTypeSArray().dim)) | |
2557 | { | |
2558 | /* Match if the dimensions are equal | |
2559 | * with the implicit conversion of e.e1: | |
2560 | * cast(float[2]) [2.0, 1.0, 0.0][0..2]; | |
2561 | */ | |
2562 | Type t1b = e.e1.type.toBasetype(); | |
2563 | if (t1b.ty == Tsarray) | |
2564 | t1b = tb.nextOf().sarrayOf(t1b.isTypeSArray().dim.toInteger()); | |
2565 | else if (t1b.ty == Tarray) | |
2566 | t1b = tb.nextOf().arrayOf(); | |
2567 | else if (t1b.ty == Tpointer) | |
2568 | t1b = tb.nextOf().pointerTo(); | |
2569 | else | |
2570 | assert(0); | |
2571 | if (e.e1.implicitConvTo(t1b) > MATCH.nomatch) | |
5fee5ec3 | 2572 | { |
6384eff5 IB |
2573 | Expression e1x = e.e1.implicitCastTo(sc, t1b); |
2574 | assert(e1x.op != EXP.error); | |
2575 | e = e.copy().isSliceExp(); | |
2576 | e.e1 = e1x; | |
2577 | e.type = t; | |
2578 | return e; | |
5fee5ec3 | 2579 | } |
5fee5ec3 | 2580 | } |
6384eff5 IB |
2581 | auto ts = toAutoQualChars(tsa ? tsa : e.type, t); |
2582 | e.error("cannot cast expression `%s` of type `%s` to `%s`", | |
2583 | e.toChars(), ts[0], ts[1]); | |
2584 | return ErrorExp.get(); | |
5fee5ec3 IB |
2585 | } |
2586 | ||
2587 | // Casting to noreturn isn't an actual cast | |
2588 | // Rewrite cast(<qual> noreturn) <exp> | |
2589 | // as <exp>, assert(false) | |
2590 | if (t.isTypeNoreturn()) | |
2591 | { | |
2592 | // Don't generate an unreachable assert(false) if e will abort | |
2593 | if (e.type.isTypeNoreturn()) | |
2594 | { | |
2595 | // Paint e to accomodate for different type qualifiers | |
2596 | e.type = t; | |
2597 | return e; | |
2598 | } | |
2599 | ||
2600 | auto ini = t.defaultInitLiteral(e.loc); | |
2601 | return Expression.combine(e, ini); | |
2602 | } | |
2603 | ||
6384eff5 IB |
2604 | switch (e.op) |
2605 | { | |
2606 | default : return visit(e); | |
2607 | case EXP.error : return visitError(e.isErrorExp()); | |
2608 | case EXP.float64 : return visitReal(e.isRealExp()); | |
2609 | case EXP.complex80 : return visitComplex(e.isComplexExp()); | |
2610 | case EXP.structLiteral : return visitStructLiteral(e.isStructLiteralExp()); | |
2611 | case EXP.string_ : return visitString(e.isStringExp()); | |
2612 | case EXP.address : return visitAddr(e.isAddrExp()); | |
2613 | case EXP.tuple : return visitTuple(e.isTupleExp()); | |
2614 | case EXP.arrayLiteral : return visitArrayLiteral(e.isArrayLiteralExp()); | |
2615 | case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); | |
2616 | case EXP.symbolOffset : return visitSymOff(e.isSymOffExp()); | |
2617 | case EXP.delegate_ : return visitDelegate(e.isDelegateExp()); | |
2618 | case EXP.function_ : return visitFunc(e.isFuncExp()); | |
2619 | case EXP.question : return visitCond(e.isCondExp()); | |
2620 | case EXP.comma : return visitComma(e.isCommaExp()); | |
2621 | case EXP.slice : return visitSlice(e.isSliceExp()); | |
2622 | } | |
5fee5ec3 IB |
2623 | } |
2624 | ||
2625 | /**************************************** | |
2626 | * Set type inference target | |
2627 | * t Target type | |
2628 | * flag 1: don't put an error when inference fails | |
2629 | */ | |
2630 | Expression inferType(Expression e, Type t, int flag = 0) | |
2631 | { | |
2632 | Expression visitAle(ArrayLiteralExp ale) | |
2633 | { | |
2634 | Type tb = t.toBasetype(); | |
2635 | if (tb.ty == Tarray || tb.ty == Tsarray) | |
2636 | { | |
2637 | Type tn = tb.nextOf(); | |
2638 | if (ale.basis) | |
2639 | ale.basis = inferType(ale.basis, tn, flag); | |
2640 | for (size_t i = 0; i < ale.elements.dim; i++) | |
2641 | { | |
2642 | if (Expression e = (*ale.elements)[i]) | |
2643 | { | |
2644 | e = inferType(e, tn, flag); | |
2645 | (*ale.elements)[i] = e; | |
2646 | } | |
2647 | } | |
2648 | } | |
2649 | return ale; | |
2650 | } | |
2651 | ||
2652 | Expression visitAar(AssocArrayLiteralExp aale) | |
2653 | { | |
2654 | Type tb = t.toBasetype(); | |
2655 | if (auto taa = tb.isTypeAArray()) | |
2656 | { | |
2657 | Type ti = taa.index; | |
2658 | Type tv = taa.nextOf(); | |
2659 | for (size_t i = 0; i < aale.keys.dim; i++) | |
2660 | { | |
2661 | if (Expression e = (*aale.keys)[i]) | |
2662 | { | |
2663 | e = inferType(e, ti, flag); | |
2664 | (*aale.keys)[i] = e; | |
2665 | } | |
2666 | } | |
2667 | for (size_t i = 0; i < aale.values.dim; i++) | |
2668 | { | |
2669 | if (Expression e = (*aale.values)[i]) | |
2670 | { | |
2671 | e = inferType(e, tv, flag); | |
2672 | (*aale.values)[i] = e; | |
2673 | } | |
2674 | } | |
2675 | } | |
2676 | return aale; | |
2677 | } | |
2678 | ||
2679 | Expression visitFun(FuncExp fe) | |
2680 | { | |
2681 | //printf("FuncExp::inferType('%s'), to=%s\n", fe.type ? fe.type.toChars() : "null", t.toChars()); | |
2682 | if (t.ty == Tdelegate || t.ty == Tpointer && t.nextOf().ty == Tfunction) | |
2683 | { | |
2684 | fe.fd.treq = t; | |
2685 | } | |
2686 | return fe; | |
2687 | } | |
2688 | ||
2689 | Expression visitTer(CondExp ce) | |
2690 | { | |
2691 | Type tb = t.toBasetype(); | |
2692 | ce.e1 = inferType(ce.e1, tb, flag); | |
2693 | ce.e2 = inferType(ce.e2, tb, flag); | |
2694 | return ce; | |
2695 | } | |
2696 | ||
2697 | if (t) switch (e.op) | |
2698 | { | |
b3f58f87 IB |
2699 | case EXP.arrayLiteral: return visitAle(e.isArrayLiteralExp()); |
2700 | case EXP.assocArrayLiteral: return visitAar(e.isAssocArrayLiteralExp()); | |
2701 | case EXP.function_: return visitFun(e.isFuncExp()); | |
2702 | case EXP.question: return visitTer(e.isCondExp()); | |
5fee5ec3 IB |
2703 | default: |
2704 | } | |
2705 | return e; | |
2706 | } | |
2707 | ||
2708 | /**************************************** | |
2709 | * Scale addition/subtraction to/from pointer. | |
2710 | */ | |
2711 | Expression scaleFactor(BinExp be, Scope* sc) | |
2712 | { | |
2713 | Type t1b = be.e1.type.toBasetype(); | |
2714 | Type t2b = be.e2.type.toBasetype(); | |
2715 | Expression eoff; | |
2716 | ||
2717 | if (t1b.ty == Tpointer && t2b.isintegral()) | |
2718 | { | |
2719 | // Need to adjust operator by the stride | |
2720 | // Replace (ptr + int) with (ptr + (int * stride)) | |
2721 | Type t = Type.tptrdiff_t; | |
2722 | ||
fbdaa581 | 2723 | uinteger_t stride = t1b.nextOf().size(be.loc); |
5fee5ec3 IB |
2724 | if (!t.equals(t2b)) |
2725 | be.e2 = be.e2.castTo(sc, t); | |
2726 | eoff = be.e2; | |
2727 | be.e2 = new MulExp(be.loc, be.e2, new IntegerExp(Loc.initial, stride, t)); | |
2728 | be.e2.type = t; | |
2729 | be.type = be.e1.type; | |
2730 | } | |
2731 | else if (t2b.ty == Tpointer && t1b.isintegral()) | |
2732 | { | |
2733 | // Need to adjust operator by the stride | |
2734 | // Replace (int + ptr) with (ptr + (int * stride)) | |
2735 | Type t = Type.tptrdiff_t; | |
2736 | Expression e; | |
2737 | ||
fbdaa581 | 2738 | uinteger_t stride = t2b.nextOf().size(be.loc); |
5fee5ec3 IB |
2739 | if (!t.equals(t1b)) |
2740 | e = be.e1.castTo(sc, t); | |
2741 | else | |
2742 | e = be.e1; | |
2743 | eoff = e; | |
2744 | e = new MulExp(be.loc, e, new IntegerExp(Loc.initial, stride, t)); | |
2745 | e.type = t; | |
2746 | be.type = be.e2.type; | |
2747 | be.e1 = be.e2; | |
2748 | be.e2 = e; | |
2749 | } | |
2750 | else | |
2751 | assert(0); | |
2752 | ||
610d7898 IB |
2753 | |
2754 | eoff = eoff.optimize(WANTvalue); | |
2755 | if (eoff.op == EXP.int64 && eoff.toInteger() == 0) | |
5fee5ec3 | 2756 | { |
610d7898 IB |
2757 | } |
2758 | else if (sc.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions")) | |
2759 | { | |
2760 | return ErrorExp.get(); | |
5fee5ec3 IB |
2761 | } |
2762 | ||
2763 | return be; | |
2764 | } | |
2765 | ||
2766 | /************************************** | |
2767 | * Return true if e is an empty array literal with dimensionality | |
2768 | * equal to or less than type of other array. | |
2769 | * [], [[]], [[[]]], etc. | |
2770 | * I.e., make sure that [1,2] is compatible with [], | |
2771 | * [[1,2]] is compatible with [[]], etc. | |
2772 | */ | |
2773 | private bool isVoidArrayLiteral(Expression e, Type other) | |
2774 | { | |
b3f58f87 | 2775 | while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && (e.isArrayLiteralExp().elements.dim == 1)) |
5fee5ec3 | 2776 | { |
b3f58f87 | 2777 | auto ale = e.isArrayLiteralExp(); |
5fee5ec3 IB |
2778 | e = ale[0]; |
2779 | if (other.ty == Tsarray || other.ty == Tarray) | |
2780 | other = other.nextOf(); | |
2781 | else | |
2782 | return false; | |
2783 | } | |
2784 | if (other.ty != Tsarray && other.ty != Tarray) | |
2785 | return false; | |
2786 | Type t = e.type; | |
b3f58f87 | 2787 | return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && e.isArrayLiteralExp().elements.dim == 0); |
5fee5ec3 IB |
2788 | } |
2789 | ||
2790 | /** | |
2791 | * Merge types of `e1` and `e2` into a common subset | |
2792 | * | |
2793 | * Parameters `e1` and `e2` will be rewritten in place as needed. | |
2794 | * | |
2795 | * Params: | |
2796 | * sc = Current scope | |
9c7d5e88 | 2797 | * op = Operator such as `e1 op e2`. In practice, either EXP.question |
5fee5ec3 IB |
2798 | * or one of the binary operator. |
2799 | * pe1 = The LHS of the operation, will be rewritten | |
2800 | * pe2 = The RHS of the operation, will be rewritten | |
2801 | * | |
2802 | * Returns: | |
2803 | * The resulting type in case of success, `null` in case of error | |
2804 | */ | |
9c7d5e88 | 2805 | Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2) |
5fee5ec3 IB |
2806 | { |
2807 | //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars()); | |
2808 | ||
2809 | Expression e1 = pe1; | |
2810 | Expression e2 = pe2; | |
2811 | ||
0fb57034 IB |
2812 | // ImportC: do array/function conversions |
2813 | if (sc) | |
2814 | { | |
2815 | e1 = e1.arrayFuncConv(sc); | |
2816 | e2 = e2.arrayFuncConv(sc); | |
2817 | } | |
2818 | ||
5fee5ec3 IB |
2819 | Type Lret(Type result) |
2820 | { | |
2821 | pe1 = e1; | |
2822 | pe2 = e2; | |
2823 | ||
2824 | version (none) | |
2825 | { | |
2826 | printf("-typeMerge() %s op %s\n", e1.toChars(), e2.toChars()); | |
2827 | if (e1.type) | |
2828 | printf("\tt1 = %s\n", e1.type.toChars()); | |
2829 | if (e2.type) | |
2830 | printf("\tt2 = %s\n", e2.type.toChars()); | |
2831 | printf("\ttype = %s\n", result.toChars()); | |
2832 | } | |
2833 | return result; | |
2834 | } | |
2835 | ||
0fb57034 | 2836 | /// Converts one of the expression to the other |
5fee5ec3 IB |
2837 | Type convert(ref Expression from, Type to) |
2838 | { | |
2839 | from = from.castTo(sc, to); | |
2840 | return Lret(to); | |
2841 | } | |
2842 | ||
2843 | /// Converts both expression to a third type | |
2844 | Type coerce(Type towards) | |
2845 | { | |
2846 | e1 = e1.castTo(sc, towards); | |
2847 | e2 = e2.castTo(sc, towards); | |
2848 | return Lret(towards); | |
2849 | } | |
2850 | ||
2851 | Type t1b = e1.type.toBasetype(); | |
2852 | Type t2b = e2.type.toBasetype(); | |
2853 | ||
0fb57034 IB |
2854 | if (sc && sc.flags & SCOPE.Cfile) |
2855 | { | |
2856 | // Integral types can be implicitly converted to pointers | |
2857 | if ((t1b.ty == Tpointer) != (t2b.ty == Tpointer)) | |
2858 | { | |
2859 | if (t1b.isintegral()) | |
2860 | { | |
2861 | return convert(e1, t2b); | |
2862 | } | |
2863 | else if (t2b.isintegral()) | |
2864 | { | |
2865 | return convert(e2, t1b); | |
2866 | } | |
2867 | } | |
2868 | } | |
2869 | ||
9c7d5e88 | 2870 | if (op != EXP.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic())) |
5fee5ec3 | 2871 | { |
9c7d5e88 | 2872 | if (op == EXP.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar()) |
5fee5ec3 IB |
2873 | { |
2874 | e1 = e1.castTo(sc, Type.tdchar); | |
2875 | e2 = e2.castTo(sc, Type.tdchar); | |
2876 | } | |
2877 | else | |
2878 | { | |
2879 | e1 = integralPromotions(e1, sc); | |
2880 | e2 = integralPromotions(e2, sc); | |
2881 | } | |
2882 | } | |
2883 | ||
2884 | MATCH m; | |
2885 | Type t1 = e1.type; | |
2886 | Type t2 = e2.type; | |
2887 | assert(t1); | |
2888 | Type t = t1; | |
2889 | ||
2890 | /* The start type of alias this type recursion. | |
2891 | * In following case, we should save A, and stop recursion | |
2892 | * if it appears again. | |
2893 | * X -> Y -> [A] -> B -> A -> B -> ... | |
2894 | */ | |
2895 | Type att1 = null; | |
2896 | Type att2 = null; | |
2897 | ||
2898 | if (t1.mod != t2.mod && | |
2899 | t1.ty == Tenum && t2.ty == Tenum && | |
2900 | t1.isTypeEnum().sym == t2.isTypeEnum().sym) | |
2901 | { | |
2902 | ubyte mod = MODmerge(t1.mod, t2.mod); | |
2903 | t1 = t1.castMod(mod); | |
2904 | t2 = t2.castMod(mod); | |
2905 | } | |
2906 | ||
2907 | Lagain: | |
2908 | t1b = t1.toBasetype(); | |
2909 | t2b = t2.toBasetype(); | |
2910 | ||
2911 | const ty = implicitConvCommonTy(t1b.ty, t2b.ty); | |
2912 | if (ty != Terror) | |
2913 | { | |
2914 | const ty1 = implicitConvTy1(t1b.ty, t2b.ty); | |
2915 | const ty2 = implicitConvTy1(t2b.ty, t1b.ty); | |
2916 | ||
2917 | if (t1b.ty == ty1) // if no promotions | |
2918 | { | |
2919 | if (t1.equals(t2)) | |
2920 | return Lret(t1); | |
2921 | ||
2922 | if (t1b.equals(t2b)) | |
2923 | return Lret(t1b); | |
2924 | } | |
2925 | ||
2926 | t1 = Type.basic[ty1]; | |
2927 | t2 = Type.basic[ty2]; | |
b6df1132 IB |
2928 | |
2929 | if (!(t1 && t2)) | |
2930 | return null; | |
5fee5ec3 IB |
2931 | e1 = e1.castTo(sc, t1); |
2932 | e2 = e2.castTo(sc, t2); | |
2933 | return Lret(Type.basic[ty]); | |
2934 | } | |
2935 | ||
2936 | t1 = t1b; | |
2937 | t2 = t2b; | |
2938 | ||
2939 | if (t1.ty == Ttuple || t2.ty == Ttuple) | |
2940 | return null; | |
2941 | ||
2942 | if (t1.equals(t2)) | |
2943 | { | |
2944 | // merging can not result in new enum type | |
2945 | if (t.ty == Tenum) | |
2946 | return Lret(t1b); | |
2947 | return Lret(t); | |
2948 | } | |
2949 | ||
2950 | if ((t1.ty == Tpointer && t2.ty == Tpointer) || (t1.ty == Tdelegate && t2.ty == Tdelegate)) | |
2951 | { | |
2952 | // Bring pointers to compatible type | |
2953 | Type t1n = t1.nextOf(); | |
2954 | Type t2n = t2.nextOf(); | |
2955 | ||
2956 | if (t1n.equals(t2n)) | |
2957 | return Lret(t); | |
2958 | ||
2959 | if (t1n.ty == Tvoid) // pointers to void are always compatible | |
c8dfa79c | 2960 | return Lret(t1); |
5fee5ec3 IB |
2961 | |
2962 | if (t2n.ty == Tvoid) | |
c8dfa79c | 2963 | return Lret(t2); |
5fee5ec3 IB |
2964 | |
2965 | if (t1.implicitConvTo(t2)) | |
2966 | return convert(e1, t2); | |
2967 | ||
2968 | if (t2.implicitConvTo(t1)) | |
2969 | return convert(e2, t1); | |
2970 | ||
2971 | if (t1n.ty == Tfunction && t2n.ty == Tfunction) | |
2972 | { | |
2973 | TypeFunction tf1 = t1n.isTypeFunction(); | |
2974 | TypeFunction tf2 = t2n.isTypeFunction(); | |
2975 | tf1.purityLevel(); | |
2976 | tf2.purityLevel(); | |
2977 | ||
2978 | TypeFunction d = tf1.syntaxCopy(); | |
2979 | ||
2980 | if (tf1.purity != tf2.purity) | |
2981 | d.purity = PURE.impure; | |
2982 | assert(d.purity != PURE.fwdref); | |
2983 | ||
2984 | d.isnothrow = (tf1.isnothrow && tf2.isnothrow); | |
2985 | d.isnogc = (tf1.isnogc && tf2.isnogc); | |
2986 | ||
2987 | if (tf1.trust == tf2.trust) | |
2988 | d.trust = tf1.trust; | |
2989 | else if (tf1.trust <= TRUST.system || tf2.trust <= TRUST.system) | |
2990 | d.trust = TRUST.system; | |
2991 | else | |
2992 | d.trust = TRUST.trusted; | |
2993 | ||
2994 | Type tx = (t1.ty == Tdelegate) ? new TypeDelegate(d) : d.pointerTo(); | |
2995 | tx = tx.typeSemantic(e1.loc, sc); | |
2996 | ||
2997 | if (t1.implicitConvTo(tx) && t2.implicitConvTo(tx)) | |
2998 | return coerce(tx); | |
2999 | return null; | |
3000 | } | |
3001 | ||
3002 | if (t1n.mod != t2n.mod) | |
3003 | { | |
3004 | if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared()) | |
3005 | return null; | |
3006 | ubyte mod = MODmerge(t1n.mod, t2n.mod); | |
3007 | t1 = t1n.castMod(mod).pointerTo(); | |
3008 | t2 = t2n.castMod(mod).pointerTo(); | |
3009 | t = t1; | |
3010 | goto Lagain; | |
3011 | } | |
3012 | ||
3013 | if (t1n.ty == Tclass && t2n.ty == Tclass) | |
3014 | { | |
3015 | ClassDeclaration cd1 = t1n.isClassHandle(); | |
3016 | ClassDeclaration cd2 = t2n.isClassHandle(); | |
3017 | int offset; | |
3018 | if (cd1.isBaseOf(cd2, &offset)) | |
3019 | { | |
3020 | if (offset) | |
3021 | e2 = e2.castTo(sc, t); | |
3022 | return Lret(t); | |
3023 | } | |
3024 | ||
3025 | if (cd2.isBaseOf(cd1, &offset)) | |
3026 | { | |
3027 | if (offset) | |
3028 | e1 = e1.castTo(sc, t2); | |
3029 | return Lret(t2); | |
3030 | } | |
3031 | ||
3032 | return null; | |
3033 | } | |
3034 | ||
3035 | t1 = t1n.constOf().pointerTo(); | |
3036 | t2 = t2n.constOf().pointerTo(); | |
3037 | if (t1.implicitConvTo(t2)) | |
3038 | return convert(e1, t2); | |
3039 | if (t2.implicitConvTo(t1)) | |
3040 | return convert(e2, t1); | |
3041 | return null; | |
3042 | } | |
3043 | ||
9c7d5e88 | 3044 | if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1))) |
5fee5ec3 IB |
3045 | { |
3046 | /* (T[n] op void*) => T[] | |
3047 | * (T[] op void*) => T[] | |
3048 | * (T[n] op void[0]) => T[] | |
3049 | * (T[] op void[0]) => T[] | |
3050 | * (T[n] op void[]) => T[] | |
3051 | * (T[] op void[]) => T[] | |
3052 | */ | |
3053 | return coerce(t1.nextOf().arrayOf()); | |
3054 | } | |
3055 | ||
9c7d5e88 | 3056 | if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2))) |
5fee5ec3 IB |
3057 | { |
3058 | /* (void* op T[n]) => T[] | |
3059 | * (void* op T[]) => T[] | |
3060 | * (void[0] op T[n]) => T[] | |
3061 | * (void[0] op T[]) => T[] | |
3062 | * (void[] op T[n]) => T[] | |
3063 | * (void[] op T[]) => T[] | |
3064 | */ | |
3065 | return coerce(t2.nextOf().arrayOf()); | |
3066 | } | |
3067 | ||
3068 | if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch) | |
3069 | { | |
3070 | // https://issues.dlang.org/show_bug.cgi?id=7285 | |
3071 | // Tsarray op [x, y, ...] should to be Tsarray | |
3072 | // https://issues.dlang.org/show_bug.cgi?id=14737 | |
3073 | // Tsarray ~ [x, y, ...] should to be Tarray | |
9c7d5e88 | 3074 | if (t1.ty == Tsarray && e2.op == EXP.arrayLiteral && op != EXP.concatenate) |
5fee5ec3 | 3075 | return convert(e2, t1); |
9c7d5e88 | 3076 | if (m == MATCH.constant && (op == EXP.addAssign || op == EXP.minAssign || op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || op == EXP.powAssign || op == EXP.andAssign || op == EXP.orAssign || op == EXP.xorAssign)) |
5fee5ec3 IB |
3077 | { |
3078 | // Don't make the lvalue const | |
3079 | return Lret(t2); | |
3080 | } | |
3081 | return convert(e1, t2); | |
3082 | } | |
3083 | ||
3084 | if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1)) | |
3085 | { | |
3086 | // https://issues.dlang.org/show_bug.cgi?id=7285 | |
3087 | // https://issues.dlang.org/show_bug.cgi?id=14737 | |
9c7d5e88 | 3088 | if (t2.ty == Tsarray && e1.op == EXP.arrayLiteral && op != EXP.concatenate) |
5fee5ec3 IB |
3089 | return convert(e1, t2); |
3090 | return convert(e2, t1); | |
3091 | } | |
3092 | ||
3093 | if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod) | |
3094 | { | |
3095 | /* If one is mutable and the other immutable, then retry | |
3096 | * with both of them as const | |
3097 | */ | |
3098 | Type t1n = t1.nextOf(); | |
3099 | Type t2n = t2.nextOf(); | |
3100 | ubyte mod; | |
9c7d5e88 | 3101 | if (e1.op == EXP.null_ && e2.op != EXP.null_) |
5fee5ec3 | 3102 | mod = t2n.mod; |
9c7d5e88 | 3103 | else if (e1.op != EXP.null_ && e2.op == EXP.null_) |
5fee5ec3 IB |
3104 | mod = t1n.mod; |
3105 | else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared()) | |
3106 | return null; | |
3107 | else | |
3108 | mod = MODmerge(t1n.mod, t2n.mod); | |
3109 | ||
3110 | if (t1.ty == Tpointer) | |
3111 | t1 = t1n.castMod(mod).pointerTo(); | |
3112 | else | |
3113 | t1 = t1n.castMod(mod).arrayOf(); | |
3114 | ||
3115 | if (t2.ty == Tpointer) | |
3116 | t2 = t2n.castMod(mod).pointerTo(); | |
3117 | else | |
3118 | t2 = t2n.castMod(mod).arrayOf(); | |
3119 | t = t1; | |
3120 | goto Lagain; | |
3121 | } | |
3122 | ||
3123 | if (t1.ty == Tclass && t2.ty == Tclass) | |
3124 | { | |
3125 | if (t1.mod != t2.mod) | |
3126 | { | |
3127 | ubyte mod; | |
9c7d5e88 | 3128 | if (e1.op == EXP.null_ && e2.op != EXP.null_) |
5fee5ec3 | 3129 | mod = t2.mod; |
9c7d5e88 | 3130 | else if (e1.op != EXP.null_ && e2.op == EXP.null_) |
5fee5ec3 IB |
3131 | mod = t1.mod; |
3132 | else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) | |
3133 | return null; | |
3134 | else | |
3135 | mod = MODmerge(t1.mod, t2.mod); | |
3136 | t1 = t1.castMod(mod); | |
3137 | t2 = t2.castMod(mod); | |
3138 | t = t1; | |
3139 | goto Lagain; | |
3140 | } | |
3141 | goto Lcc; | |
3142 | } | |
3143 | ||
3144 | if (t1.ty == Tclass || t2.ty == Tclass) | |
3145 | { | |
3146 | Lcc: | |
3147 | while (1) | |
3148 | { | |
0fb57034 IB |
3149 | MATCH i1woat = MATCH.exact; |
3150 | MATCH i2woat = MATCH.exact; | |
3151 | ||
3152 | if (auto t2c = t2.isTypeClass()) | |
3153 | i1woat = t2c.implicitConvToWithoutAliasThis(t1); | |
3154 | if (auto t1c = t1.isTypeClass()) | |
3155 | i2woat = t1c.implicitConvToWithoutAliasThis(t2); | |
3156 | ||
5fee5ec3 IB |
3157 | MATCH i1 = e2.implicitConvTo(t1); |
3158 | MATCH i2 = e1.implicitConvTo(t2); | |
3159 | ||
3160 | if (i1 && i2) | |
3161 | { | |
3162 | // We have the case of class vs. void*, so pick class | |
3163 | if (t1.ty == Tpointer) | |
3164 | i1 = MATCH.nomatch; | |
3165 | else if (t2.ty == Tpointer) | |
3166 | i2 = MATCH.nomatch; | |
3167 | } | |
3168 | ||
0fb57034 IB |
3169 | // Match but without 'alias this' on classes |
3170 | if (i2 && i2woat) | |
5fee5ec3 | 3171 | return coerce(t2); |
0fb57034 | 3172 | if (i1 && i1woat) |
5fee5ec3 IB |
3173 | return coerce(t1); |
3174 | ||
0fb57034 IB |
3175 | // Here use implicitCastTo() instead of castTo() to try 'alias this' on classes |
3176 | Type coerceImplicit(Type towards) | |
3177 | { | |
3178 | e1 = e1.implicitCastTo(sc, towards); | |
3179 | e2 = e2.implicitCastTo(sc, towards); | |
3180 | return Lret(towards); | |
3181 | } | |
3182 | ||
3183 | // Implicit conversion with 'alias this' | |
3184 | if (i2) | |
3185 | return coerceImplicit(t2); | |
3186 | if (i1) | |
3187 | return coerceImplicit(t1); | |
3188 | ||
5fee5ec3 IB |
3189 | if (t1.ty == Tclass && t2.ty == Tclass) |
3190 | { | |
3191 | TypeClass tc1 = t1.isTypeClass(); | |
3192 | TypeClass tc2 = t2.isTypeClass(); | |
3193 | ||
3194 | /* Pick 'tightest' type | |
3195 | */ | |
3196 | ClassDeclaration cd1 = tc1.sym.baseClass; | |
3197 | ClassDeclaration cd2 = tc2.sym.baseClass; | |
3198 | if (cd1 && cd2) | |
3199 | { | |
3200 | t1 = cd1.type.castMod(t1.mod); | |
3201 | t2 = cd2.type.castMod(t2.mod); | |
3202 | } | |
3203 | else if (cd1) | |
3204 | t1 = cd1.type; | |
3205 | else if (cd2) | |
3206 | t2 = cd2.type; | |
3207 | else | |
3208 | return null; | |
3209 | } | |
3210 | else if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis) | |
3211 | { | |
3212 | if (isRecursiveAliasThis(att1, e1.type)) | |
3213 | return null; | |
3214 | //printf("att tmerge(c || c) e1 = %s\n", e1.type.toChars()); | |
3215 | e1 = resolveAliasThis(sc, e1); | |
3216 | t1 = e1.type; | |
3217 | continue; | |
3218 | } | |
3219 | else if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis) | |
3220 | { | |
3221 | if (isRecursiveAliasThis(att2, e2.type)) | |
3222 | return null; | |
3223 | //printf("att tmerge(c || c) e2 = %s\n", e2.type.toChars()); | |
3224 | e2 = resolveAliasThis(sc, e2); | |
3225 | t2 = e2.type; | |
3226 | continue; | |
3227 | } | |
3228 | else | |
3229 | return null; | |
3230 | } | |
3231 | } | |
3232 | ||
3233 | if (t1.ty == Tstruct && t2.ty == Tstruct) | |
3234 | { | |
3235 | if (t1.mod != t2.mod) | |
3236 | { | |
3237 | if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) | |
3238 | return null; | |
3239 | ubyte mod = MODmerge(t1.mod, t2.mod); | |
3240 | t1 = t1.castMod(mod); | |
3241 | t2 = t2.castMod(mod); | |
3242 | t = t1; | |
3243 | goto Lagain; | |
3244 | } | |
3245 | ||
3246 | TypeStruct ts1 = t1.isTypeStruct(); | |
3247 | TypeStruct ts2 = t2.isTypeStruct(); | |
3248 | if (ts1.sym != ts2.sym) | |
3249 | { | |
3250 | if (!ts1.sym.aliasthis && !ts2.sym.aliasthis) | |
3251 | return null; | |
3252 | ||
3253 | MATCH i1 = MATCH.nomatch; | |
3254 | MATCH i2 = MATCH.nomatch; | |
3255 | ||
3256 | Expression e1b = null; | |
3257 | Expression e2b = null; | |
3258 | if (ts2.sym.aliasthis) | |
3259 | { | |
3260 | if (isRecursiveAliasThis(att2, e2.type)) | |
3261 | return null; | |
3262 | //printf("att tmerge(s && s) e2 = %s\n", e2.type.toChars()); | |
3263 | e2b = resolveAliasThis(sc, e2); | |
3264 | i1 = e2b.implicitConvTo(t1); | |
3265 | } | |
3266 | if (ts1.sym.aliasthis) | |
3267 | { | |
3268 | if (isRecursiveAliasThis(att1, e1.type)) | |
3269 | return null; | |
3270 | //printf("att tmerge(s && s) e1 = %s\n", e1.type.toChars()); | |
3271 | e1b = resolveAliasThis(sc, e1); | |
3272 | i2 = e1b.implicitConvTo(t2); | |
3273 | } | |
3274 | if (i1 && i2) | |
3275 | return null; | |
3276 | ||
3277 | if (i1) | |
3278 | return convert(e2, t1); | |
3279 | if (i2) | |
3280 | return convert(e1, t2); | |
3281 | ||
3282 | if (e1b) | |
3283 | { | |
3284 | e1 = e1b; | |
3285 | t1 = e1b.type.toBasetype(); | |
3286 | } | |
3287 | if (e2b) | |
3288 | { | |
3289 | e2 = e2b; | |
3290 | t2 = e2b.type.toBasetype(); | |
3291 | } | |
3292 | t = t1; | |
3293 | goto Lagain; | |
3294 | } | |
3295 | } | |
3296 | ||
0fb57034 | 3297 | if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis) |
5fee5ec3 | 3298 | { |
0fb57034 IB |
3299 | if (isRecursiveAliasThis(att1, e1.type)) |
3300 | return null; | |
3301 | //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars()); | |
3302 | e1 = resolveAliasThis(sc, e1); | |
3303 | t1 = e1.type; | |
3304 | t = t1; | |
3305 | goto Lagain; | |
3306 | } | |
3307 | ||
3308 | if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis) | |
3309 | { | |
3310 | if (isRecursiveAliasThis(att2, e2.type)) | |
3311 | return null; | |
3312 | //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars()); | |
3313 | e2 = resolveAliasThis(sc, e2); | |
3314 | t2 = e2.type; | |
3315 | t = t2; | |
3316 | goto Lagain; | |
5fee5ec3 IB |
3317 | } |
3318 | ||
9c7d5e88 | 3319 | if ((e1.op == EXP.string_ || e1.op == EXP.null_) && e1.implicitConvTo(t2)) |
5fee5ec3 | 3320 | return convert(e1, t2); |
9c7d5e88 | 3321 | if ((e2.op == EXP.string_ || e2.op == EXP.null_) && e2.implicitConvTo(t1)) |
5fee5ec3 IB |
3322 | return convert(e2, t1); |
3323 | if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf())) | |
3324 | return coerce(t1.nextOf().arrayOf()); | |
3325 | if (t1.ty == Tsarray && t2.ty == Tsarray && e1.implicitConvTo(t2.nextOf().arrayOf())) | |
3326 | return coerce(t2.nextOf().arrayOf()); | |
3327 | ||
3328 | if (t1.ty == Tvector && t2.ty == Tvector) | |
3329 | { | |
3330 | // https://issues.dlang.org/show_bug.cgi?id=13841 | |
3331 | // all vector types should have no common types between | |
3332 | // different vectors, even though their sizes are same. | |
3333 | auto tv1 = t1.isTypeVector(); | |
3334 | auto tv2 = t2.isTypeVector(); | |
3335 | if (!tv1.basetype.equals(tv2.basetype)) | |
3336 | return null; | |
3337 | ||
3338 | goto LmodCompare; | |
3339 | } | |
3340 | ||
3341 | if (t1.ty == Tvector && t2.ty != Tvector && e2.implicitConvTo(t1)) | |
3342 | { | |
3343 | e2 = e2.castTo(sc, t1); | |
3344 | t2 = t1; | |
3345 | t = t1; | |
3346 | goto Lagain; | |
3347 | } | |
3348 | ||
3349 | if (t2.ty == Tvector && t1.ty != Tvector && e1.implicitConvTo(t2)) | |
3350 | { | |
3351 | e1 = e1.castTo(sc, t2); | |
3352 | t1 = t2; | |
3353 | t = t1; | |
3354 | goto Lagain; | |
3355 | } | |
3356 | ||
3357 | if (t1.isintegral() && t2.isintegral()) | |
3358 | { | |
3359 | if (t1.ty != t2.ty) | |
3360 | { | |
3361 | if (t1.ty == Tvector || t2.ty == Tvector) | |
3362 | return null; | |
3363 | e1 = integralPromotions(e1, sc); | |
3364 | e2 = integralPromotions(e2, sc); | |
3365 | t1 = e1.type; | |
3366 | t2 = e2.type; | |
3367 | goto Lagain; | |
3368 | } | |
3369 | assert(t1.ty == t2.ty); | |
3370 | LmodCompare: | |
3371 | if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) | |
3372 | return null; | |
3373 | ubyte mod = MODmerge(t1.mod, t2.mod); | |
3374 | ||
3375 | t1 = t1.castMod(mod); | |
3376 | t2 = t2.castMod(mod); | |
3377 | t = t1; | |
3378 | e1 = e1.castTo(sc, t); | |
3379 | e2 = e2.castTo(sc, t); | |
3380 | goto Lagain; | |
3381 | } | |
3382 | ||
3383 | if (t1.ty == Tnull && t2.ty == Tnull) | |
3384 | { | |
3385 | ubyte mod = MODmerge(t1.mod, t2.mod); | |
3386 | return coerce(t1.castMod(mod)); | |
3387 | } | |
3388 | ||
3389 | if (t2.ty == Tnull && (t1.ty == Tpointer || t1.ty == Taarray || t1.ty == Tarray)) | |
3390 | return convert(e2, t1); | |
3391 | if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray)) | |
3392 | return convert(e1, t2); | |
3393 | ||
9c7d5e88 IB |
3394 | /// Covers array operations for user-defined types |
3395 | Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope *sc) | |
3396 | { | |
3397 | // scalar op scalar - we shouldn't be here | |
3398 | if (e1.type.ty != Tarray && e1.type.ty != Tsarray && e2.type.ty != Tarray && e2.type.ty != Tsarray) | |
3399 | return null; | |
3400 | ||
3401 | // only supporting slices and array literals | |
3402 | if (!e1.isSliceExp() && !e1.isArrayLiteralExp() && !e2.isSliceExp() && !e2.isArrayLiteralExp()) | |
3403 | return null; | |
3404 | ||
3405 | // start with e1 op e2 and if either one of e1 or e2 is a slice or array literal, | |
3406 | // replace it with the first element of the array | |
3407 | Expression lhs = e1; | |
3408 | Expression rhs = e2; | |
3409 | ||
3410 | // T[x .. y] op ? | |
b3f58f87 IB |
3411 | if (auto se1 = e1.isSliceExp()) |
3412 | lhs = new IndexExp(Loc.initial, se1.e1, IntegerExp.literal!0); | |
9c7d5e88 IB |
3413 | |
3414 | // [t1, t2, .. t3] op ? | |
b3f58f87 IB |
3415 | if (auto ale1 = e1.isArrayLiteralExp()) |
3416 | lhs = ale1.opIndex(0); | |
9c7d5e88 IB |
3417 | |
3418 | // ? op U[z .. t] | |
b3f58f87 IB |
3419 | if (auto se2 = e2.isSliceExp()) |
3420 | rhs = new IndexExp(Loc.initial, se2.e1, IntegerExp.literal!0); | |
9c7d5e88 IB |
3421 | |
3422 | // ? op [u1, u2, .. u3] | |
b3f58f87 IB |
3423 | if (auto ale2 = e2.isArrayLiteralExp()) |
3424 | rhs = ale2.opIndex(0); | |
9c7d5e88 IB |
3425 | |
3426 | // create a new binary expression with the new lhs and rhs (at this stage, at least | |
3427 | // one of lhs/rhs has been replaced with the 0'th element of the array it was before) | |
3428 | Expression exp; | |
3429 | switch (op) | |
3430 | { | |
3431 | case EXP.add: | |
3432 | exp = new AddExp(Loc.initial, lhs, rhs); break; | |
3433 | case EXP.min: | |
3434 | exp = new MinExp(Loc.initial, lhs, rhs); break; | |
3435 | case EXP.mul: | |
3436 | exp = new MulExp(Loc.initial, lhs, rhs); break; | |
3437 | case EXP.div: | |
3438 | exp = new DivExp(Loc.initial, lhs, rhs); break; | |
3439 | case EXP.pow: | |
3440 | exp = new PowExp(Loc.initial, lhs, rhs); break; | |
3441 | default: | |
3442 | exp = null; | |
3443 | } | |
3444 | ||
3445 | if (exp) | |
3446 | { | |
3447 | // if T op U is valid and has type V | |
3448 | // then T[] op U and T op U[] should be valid and have type V[] | |
3449 | Expression e = exp.trySemantic(sc); | |
3450 | if (e && e.type) | |
3451 | return e.type.arrayOf; | |
3452 | } | |
3453 | ||
3454 | return null; | |
3455 | } | |
3456 | ||
5fee5ec3 IB |
3457 | if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1)) |
3458 | { | |
3459 | if (e2.implicitConvTo(t1.nextOf())) | |
3460 | { | |
3461 | // T[] op T | |
3462 | // T[] op cast(T)U | |
3463 | e2 = e2.castTo(sc, t1.nextOf()); | |
3464 | return Lret(t1.nextOf().arrayOf()); | |
3465 | } | |
3466 | if (t1.nextOf().implicitConvTo(e2.type)) | |
3467 | { | |
3468 | // (cast(T)U)[] op T (https://issues.dlang.org/show_bug.cgi?id=12780) | |
3469 | // e1 is left as U[], it will be handled in arrayOp() later. | |
3470 | return Lret(e2.type.arrayOf()); | |
3471 | } | |
3472 | if (t2.ty == Tarray && isArrayOpOperand(e2)) | |
3473 | { | |
3474 | if (t1.nextOf().implicitConvTo(t2.nextOf())) | |
3475 | { | |
3476 | // (cast(T)U)[] op T[] (https://issues.dlang.org/show_bug.cgi?id=12780) | |
3477 | t = t2.nextOf().arrayOf(); | |
3478 | // if cast won't be handled in arrayOp() later | |
3479 | if (!isArrayOpImplicitCast(t1.isTypeDArray(), t2.isTypeDArray())) | |
3480 | e1 = e1.castTo(sc, t); | |
3481 | return Lret(t); | |
3482 | } | |
3483 | if (t2.nextOf().implicitConvTo(t1.nextOf())) | |
3484 | { | |
3485 | // T[] op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780) | |
3486 | // e2 is left as U[], it will be handled in arrayOp() later. | |
3487 | t = t1.nextOf().arrayOf(); | |
3488 | // if cast won't be handled in arrayOp() later | |
3489 | if (!isArrayOpImplicitCast(t2.isTypeDArray(), t1.isTypeDArray())) | |
3490 | e2 = e2.castTo(sc, t); | |
3491 | return Lret(t); | |
3492 | } | |
5fee5ec3 | 3493 | } |
9c7d5e88 IB |
3494 | |
3495 | t = checkArrayOpType(e1, e2, op, sc); | |
3496 | if (t !is null) | |
3497 | return Lret(t); | |
3498 | ||
5fee5ec3 IB |
3499 | return null; |
3500 | } | |
3501 | else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2)) | |
3502 | { | |
3503 | if (e1.implicitConvTo(t2.nextOf())) | |
3504 | { | |
3505 | // T op T[] | |
3506 | // cast(T)U op T[] | |
3507 | e1 = e1.castTo(sc, t2.nextOf()); | |
3508 | t = t2.nextOf().arrayOf(); | |
3509 | } | |
3510 | else if (t2.nextOf().implicitConvTo(e1.type)) | |
3511 | { | |
3512 | // T op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780) | |
3513 | // e2 is left as U[], it will be handled in arrayOp() later. | |
3514 | t = e1.type.arrayOf(); | |
3515 | } | |
3516 | else | |
9c7d5e88 IB |
3517 | { |
3518 | t = checkArrayOpType(e1, e2, op, sc); | |
3519 | if (t is null) | |
3520 | return null; | |
3521 | } | |
5fee5ec3 | 3522 | |
9c7d5e88 | 3523 | //printf("test %s\n", EXPtoString(op).ptr); |
5fee5ec3 IB |
3524 | e1 = e1.optimize(WANTvalue); |
3525 | if (isCommutative(op) && e1.isConst()) | |
3526 | { | |
3527 | /* Swap operands to minimize number of functions generated | |
3528 | */ | |
9c7d5e88 | 3529 | //printf("swap %s\n", EXPtoString(op).ptr); |
5fee5ec3 IB |
3530 | Expression tmp = e1; |
3531 | e1 = e2; | |
3532 | e2 = tmp; | |
3533 | } | |
3534 | return Lret(t); | |
3535 | } | |
3536 | ||
3537 | return null; | |
3538 | } | |
3539 | ||
3540 | /************************************ | |
3541 | * Bring leaves to common type. | |
3542 | * Returns: | |
3543 | * null on success, ErrorExp if error occurs | |
3544 | */ | |
3545 | Expression typeCombine(BinExp be, Scope* sc) | |
3546 | { | |
3547 | Expression errorReturn() | |
3548 | { | |
3549 | Expression ex = be.incompatibleTypes(); | |
9c7d5e88 | 3550 | if (ex.op == EXP.error) |
5fee5ec3 IB |
3551 | return ex; |
3552 | return ErrorExp.get(); | |
3553 | } | |
3554 | ||
3555 | Type t1 = be.e1.type.toBasetype(); | |
3556 | Type t2 = be.e2.type.toBasetype(); | |
3557 | ||
9c7d5e88 | 3558 | if (be.op == EXP.min || be.op == EXP.add) |
5fee5ec3 IB |
3559 | { |
3560 | // struct+struct, and class+class are errors | |
3561 | if (t1.ty == Tstruct && t2.ty == Tstruct) | |
3562 | return errorReturn(); | |
3563 | else if (t1.ty == Tclass && t2.ty == Tclass) | |
3564 | return errorReturn(); | |
3565 | else if (t1.ty == Taarray && t2.ty == Taarray) | |
3566 | return errorReturn(); | |
3567 | } | |
3568 | ||
3569 | if (auto result = typeMerge(sc, be.op, be.e1, be.e2)) | |
3570 | { | |
3571 | if (be.type is null) | |
3572 | be.type = result; | |
3573 | } | |
3574 | else | |
3575 | return errorReturn(); | |
3576 | ||
3577 | // If the types have no value, return an error | |
9c7d5e88 | 3578 | if (be.e1.op == EXP.error) |
5fee5ec3 | 3579 | return be.e1; |
9c7d5e88 | 3580 | if (be.e2.op == EXP.error) |
5fee5ec3 IB |
3581 | return be.e2; |
3582 | return null; | |
3583 | } | |
3584 | ||
3585 | /*********************************** | |
3586 | * Do integral promotions (convertchk). | |
3587 | * Don't convert <array of> to <pointer to> | |
3588 | */ | |
3589 | Expression integralPromotions(Expression e, Scope* sc) | |
3590 | { | |
3591 | //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars()); | |
3592 | switch (e.type.toBasetype().ty) | |
3593 | { | |
3594 | case Tvoid: | |
3595 | e.error("void has no value"); | |
3596 | return ErrorExp.get(); | |
3597 | ||
3598 | case Tint8: | |
3599 | case Tuns8: | |
3600 | case Tint16: | |
3601 | case Tuns16: | |
3602 | case Tbool: | |
3603 | case Tchar: | |
3604 | case Twchar: | |
3605 | e = e.castTo(sc, Type.tint32); | |
3606 | break; | |
3607 | ||
3608 | case Tdchar: | |
3609 | e = e.castTo(sc, Type.tuns32); | |
3610 | break; | |
3611 | ||
3612 | default: | |
3613 | break; | |
3614 | } | |
3615 | return e; | |
3616 | } | |
3617 | ||
3618 | /****************************************************** | |
3619 | * This provides a transition from the non-promoting behavior | |
3620 | * of unary + - ~ to the C-like integral promotion behavior. | |
3621 | * Params: | |
3622 | * sc = context | |
3623 | * ue = NegExp, UAddExp, or ComExp which is revised per rules | |
3624 | * References: | |
3625 | * https://issues.dlang.org/show_bug.cgi?id=16997 | |
3626 | */ | |
3627 | ||
3628 | void fix16997(Scope* sc, UnaExp ue) | |
3629 | { | |
3630 | if (global.params.fix16997 || sc.flags & SCOPE.Cfile) | |
3631 | ue.e1 = integralPromotions(ue.e1, sc); // desired C-like behavor | |
3632 | else | |
3633 | { | |
3634 | switch (ue.e1.type.toBasetype.ty) | |
3635 | { | |
3636 | case Tint8: | |
3637 | case Tuns8: | |
3638 | case Tint16: | |
3639 | case Tuns16: | |
3640 | //case Tbool: // these operations aren't allowed on bool anyway | |
3641 | case Tchar: | |
3642 | case Twchar: | |
3643 | case Tdchar: | |
9c7d5e88 IB |
3644 | ue.deprecation("integral promotion not done for `%s`, remove '-revert=intpromote' switch or `%scast(int)(%s)`", |
3645 | ue.toChars(), EXPtoString(ue.op).ptr, ue.e1.toChars()); | |
5fee5ec3 IB |
3646 | break; |
3647 | ||
3648 | default: | |
3649 | break; | |
3650 | } | |
3651 | } | |
3652 | } | |
3653 | ||
3654 | /*********************************** | |
3655 | * See if both types are arrays that can be compared | |
3656 | * for equality without any casting. Return true if so. | |
3657 | * This is to enable comparing things like an immutable | |
3658 | * array with a mutable one. | |
3659 | */ | |
3660 | extern (C++) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2) | |
3661 | { | |
3662 | t1 = t1.toBasetype(); | |
3663 | t2 = t2.toBasetype(); | |
3664 | ||
3665 | if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && t2.ty == t1.ty) | |
3666 | { | |
3667 | if (t1.nextOf().implicitConvTo(t2.nextOf()) >= MATCH.constant || t2.nextOf().implicitConvTo(t1.nextOf()) >= MATCH.constant) | |
3668 | return true; | |
3669 | } | |
3670 | return false; | |
3671 | } | |
3672 | ||
3673 | /******************************************************************/ | |
3674 | /* Determine the integral ranges of an expression. | |
3675 | * This is used to determine if implicit narrowing conversions will | |
3676 | * be allowed. | |
3677 | */ | |
6384eff5 | 3678 | @trusted |
5fee5ec3 IB |
3679 | IntRange getIntRange(Expression e) |
3680 | { | |
6384eff5 | 3681 | IntRange visit(Expression e) |
5fee5ec3 | 3682 | { |
6384eff5 IB |
3683 | return IntRange.fromType(e.type); |
3684 | } | |
5fee5ec3 | 3685 | |
6384eff5 IB |
3686 | IntRange visitInteger(IntegerExp e) |
3687 | { | |
3688 | return IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type); | |
3689 | } | |
5fee5ec3 | 3690 | |
6384eff5 IB |
3691 | IntRange visitCast(CastExp e) |
3692 | { | |
3693 | return getIntRange(e.e1)._cast(e.type); | |
3694 | } | |
5fee5ec3 | 3695 | |
6384eff5 IB |
3696 | IntRange visitAdd(AddExp e) |
3697 | { | |
3698 | IntRange ir1 = getIntRange(e.e1); | |
3699 | IntRange ir2 = getIntRange(e.e2); | |
3700 | return (ir1 + ir2)._cast(e.type); | |
3701 | } | |
5fee5ec3 | 3702 | |
6384eff5 IB |
3703 | IntRange visitMin(MinExp e) |
3704 | { | |
3705 | IntRange ir1 = getIntRange(e.e1); | |
3706 | IntRange ir2 = getIntRange(e.e2); | |
3707 | return (ir1 - ir2)._cast(e.type); | |
3708 | } | |
5fee5ec3 | 3709 | |
6384eff5 IB |
3710 | IntRange visitDiv(DivExp e) |
3711 | { | |
3712 | IntRange ir1 = getIntRange(e.e1); | |
3713 | IntRange ir2 = getIntRange(e.e2); | |
5fee5ec3 | 3714 | |
6384eff5 IB |
3715 | return (ir1 / ir2)._cast(e.type); |
3716 | } | |
5fee5ec3 | 3717 | |
6384eff5 IB |
3718 | IntRange visitMul(MulExp e) |
3719 | { | |
3720 | IntRange ir1 = getIntRange(e.e1); | |
3721 | IntRange ir2 = getIntRange(e.e2); | |
5fee5ec3 | 3722 | |
6384eff5 IB |
3723 | return (ir1 * ir2)._cast(e.type); |
3724 | } | |
5fee5ec3 | 3725 | |
6384eff5 IB |
3726 | IntRange visitMod(ModExp e) |
3727 | { | |
3728 | IntRange ir1 = getIntRange(e.e1); | |
3729 | IntRange ir2 = getIntRange(e.e2); | |
5fee5ec3 | 3730 | |
6384eff5 IB |
3731 | // Modding on 0 is invalid anyway. |
3732 | if (!ir2.absNeg().imin.negative) | |
5fee5ec3 | 3733 | { |
6384eff5 | 3734 | return visit(e); |
5fee5ec3 | 3735 | } |
6384eff5 IB |
3736 | return (ir1 % ir2)._cast(e.type); |
3737 | } | |
5fee5ec3 | 3738 | |
6384eff5 IB |
3739 | IntRange visitAnd(AndExp e) |
3740 | { | |
3741 | IntRange result; | |
3742 | bool hasResult = false; | |
3743 | result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult); | |
5fee5ec3 | 3744 | |
6384eff5 IB |
3745 | assert(hasResult); |
3746 | return result._cast(e.type); | |
3747 | } | |
5fee5ec3 | 3748 | |
6384eff5 IB |
3749 | IntRange visitOr(OrExp e) |
3750 | { | |
3751 | IntRange result; | |
3752 | bool hasResult = false; | |
3753 | result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult); | |
5fee5ec3 | 3754 | |
6384eff5 IB |
3755 | assert(hasResult); |
3756 | return result._cast(e.type); | |
3757 | } | |
5fee5ec3 | 3758 | |
6384eff5 IB |
3759 | IntRange visitXor(XorExp e) |
3760 | { | |
3761 | IntRange result; | |
3762 | bool hasResult = false; | |
3763 | result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult); | |
5fee5ec3 | 3764 | |
6384eff5 IB |
3765 | assert(hasResult); |
3766 | return result._cast(e.type); | |
3767 | } | |
5fee5ec3 | 3768 | |
6384eff5 IB |
3769 | IntRange visitShl(ShlExp e) |
3770 | { | |
3771 | IntRange ir1 = getIntRange(e.e1); | |
3772 | IntRange ir2 = getIntRange(e.e2); | |
5fee5ec3 | 3773 | |
6384eff5 IB |
3774 | return (ir1 << ir2)._cast(e.type); |
3775 | } | |
5fee5ec3 | 3776 | |
6384eff5 IB |
3777 | IntRange visitShr(ShrExp e) |
3778 | { | |
3779 | IntRange ir1 = getIntRange(e.e1); | |
3780 | IntRange ir2 = getIntRange(e.e2); | |
5fee5ec3 | 3781 | |
6384eff5 IB |
3782 | return (ir1 >> ir2)._cast(e.type); |
3783 | } | |
5fee5ec3 | 3784 | |
6384eff5 IB |
3785 | IntRange visitUshr(UshrExp e) |
3786 | { | |
3787 | IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type); | |
3788 | IntRange ir2 = getIntRange(e.e2); | |
5fee5ec3 | 3789 | |
6384eff5 IB |
3790 | return (ir1 >>> ir2)._cast(e.type); |
3791 | } | |
5fee5ec3 | 3792 | |
6384eff5 IB |
3793 | IntRange visitAssign(AssignExp e) |
3794 | { | |
3795 | return getIntRange(e.e2)._cast(e.type); | |
3796 | } | |
5fee5ec3 | 3797 | |
6384eff5 IB |
3798 | IntRange visitCond(CondExp e) |
3799 | { | |
3800 | // No need to check e.econd; assume caller has called optimize() | |
3801 | IntRange ir1 = getIntRange(e.e1); | |
3802 | IntRange ir2 = getIntRange(e.e2); | |
3803 | return ir1.unionWith(ir2)._cast(e.type); | |
3804 | } | |
5fee5ec3 | 3805 | |
6384eff5 IB |
3806 | IntRange visitVar(VarExp e) |
3807 | { | |
3808 | Expression ie; | |
3809 | VarDeclaration vd = e.var.isVarDeclaration(); | |
3810 | if (vd && vd.range) | |
3811 | return vd.range._cast(e.type); | |
3812 | else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null) | |
3813 | return getIntRange(ie); | |
3814 | else | |
3815 | return visit(e); | |
3816 | } | |
5fee5ec3 | 3817 | |
6384eff5 IB |
3818 | IntRange visitComma(CommaExp e) |
3819 | { | |
3820 | return getIntRange(e.e2); | |
3821 | } | |
5fee5ec3 | 3822 | |
6384eff5 IB |
3823 | IntRange visitCom(ComExp e) |
3824 | { | |
3825 | IntRange ir = getIntRange(e.e1); | |
3826 | return IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type); | |
3827 | } | |
5fee5ec3 | 3828 | |
6384eff5 IB |
3829 | IntRange visitNeg(NegExp e) |
3830 | { | |
3831 | IntRange ir = getIntRange(e.e1); | |
3832 | return (-ir)._cast(e.type); | |
5fee5ec3 IB |
3833 | } |
3834 | ||
6384eff5 IB |
3835 | switch (e.op) |
3836 | { | |
3837 | default : return visit(e); | |
3838 | case EXP.int64 : return visitInteger(e.isIntegerExp()); | |
3839 | case EXP.cast_ : return visitCast(e.isCastExp()); | |
3840 | case EXP.add : return visitAdd(e.isAddExp()); | |
3841 | case EXP.min : return visitMin(e.isMinExp()); | |
3842 | case EXP.div : return visitDiv(e.isDivExp()); | |
3843 | case EXP.mul : return visitMul(e.isMulExp()); | |
3844 | case EXP.mod : return visitMod(e.isModExp()); | |
3845 | case EXP.and : return visitAnd(e.isAndExp()); | |
3846 | case EXP.or : return visitOr(e.isOrExp()); | |
3847 | case EXP.xor : return visitXor(e.isXorExp()); | |
3848 | case EXP.leftShift : return visitShl(e.isShlExp()); | |
3849 | case EXP.rightShift : return visitShr(e.isShrExp()); | |
3850 | case EXP.unsignedRightShift : return visitUshr(e.isUshrExp()); | |
3851 | case EXP.blit : return visitAssign(e.isBlitExp()); | |
3852 | case EXP.construct : return visitAssign(e.isConstructExp()); | |
3853 | case EXP.assign : return visitAssign(e.isAssignExp()); | |
3854 | case EXP.question : return visitCond(e.isCondExp()); | |
3855 | case EXP.variable : return visitVar(e.isVarExp()); | |
3856 | case EXP.comma : return visitComma(e.isCommaExp()); | |
3857 | case EXP.tilde : return visitCom(e.isComExp()); | |
3858 | case EXP.negate : return visitNeg(e.isNegExp()); | |
3859 | } | |
5fee5ec3 | 3860 | } |