1 /**
2 * Semantic analysis for D types.
3 *
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)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d)
8 * Documentation: https://dlang.org/phobos/dmd_typesem.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d
10 */
11
12 module dmd.typesem;
13
14 import core.checkedint;
15 import core.stdc.string;
16 import core.stdc.stdio;
17
18 import dmd.access;
19 import dmd.aggregate;
20 import dmd.aliasthis;
21 import dmd.arrayop;
22 import dmd.arraytypes;
23 import dmd.astcodegen;
24 import dmd.astenums;
25 import dmd.dcast;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.denum;
29 import dmd.dimport;
30 import dmd.dmangle;
31 import dmd.dmodule;
32 import dmd.dscope;
33 import dmd.dstruct;
34 import dmd.dsymbol;
35 import dmd.dsymbolsem;
36 import dmd.dtemplate;
37 import dmd.errors;
38 import dmd.expression;
39 import dmd.expressionsem;
40 import dmd.func;
41 import dmd.globals;
42 import dmd.hdrgen;
43 import dmd.id;
44 import dmd.identifier;
45 import dmd.imphint;
46 import dmd.importc;
47 import dmd.init;
48 import dmd.initsem;
49 import dmd.visitor;
50 import dmd.mtype;
51 import dmd.objc;
52 import dmd.opover;
53 import dmd.parse;
54 import dmd.root.complex;
55 import dmd.root.ctfloat;
56 import dmd.root.rmem;
57 import dmd.common.outbuffer;
58 import dmd.root.rootobject;
59 import dmd.root.string;
60 import dmd.root.stringtable;
61 import dmd.safe;
62 import dmd.semantic3;
63 import dmd.sideeffect;
64 import dmd.target;
65 import dmd.tokens;
66
67 /**************************
68 * This evaluates exp while setting length to be the number
69 * of elements in the tuple t.
70 */
semanticLength(Scope * sc,Type t,Expression exp)71 private Expression semanticLength(Scope* sc, Type t, Expression exp)
72 {
73 if (auto tt = t.isTypeTuple())
74 {
75 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
76 sym.parent = sc.scopesym;
77 sc = sc.push(sym);
78 sc = sc.startCTFE();
79 exp = exp.expressionSemantic(sc);
80 exp = resolveProperties(sc, exp);
81 sc = sc.endCTFE();
82 sc.pop();
83 }
84 else
85 {
86 sc = sc.startCTFE();
87 exp = exp.expressionSemantic(sc);
88 exp = resolveProperties(sc, exp);
89 sc = sc.endCTFE();
90 }
91 return exp;
92 }
93
semanticLength(Scope * sc,TupleDeclaration tup,Expression exp)94 private Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
95 {
96 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
97 sym.parent = sc.scopesym;
98
99 sc = sc.push(sym);
100 sc = sc.startCTFE();
101 exp = exp.expressionSemantic(sc);
102 exp = resolveProperties(sc, exp);
103 sc = sc.endCTFE();
104 sc.pop();
105
106 return exp;
107 }
108
109 /*************************************
110 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
111 * Setting one of pe/pt/ps.
112 * Params:
113 * loc = location for error messages
114 * sc = context
115 * s = symbol being indexed - could be a tuple, could be an expression
116 * pe = set if s[oindex] is an Expression, otherwise null
117 * pt = set if s[oindex] is a Type, otherwise null
118 * ps = set if s[oindex] is a Dsymbol, otherwise null
119 * oindex = index into s
120 */
resolveTupleIndex(const ref Loc loc,Scope * sc,Dsymbol s,out Expression pe,out Type pt,out Dsymbol ps,RootObject oindex)121 private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
122 {
123 auto tup = s.isTupleDeclaration();
124
125 auto eindex = isExpression(oindex);
126 auto tindex = isType(oindex);
127 auto sindex = isDsymbol(oindex);
128
129 if (!tup)
130 {
131 // It's really an index expression
132 if (tindex)
133 eindex = new TypeExp(loc, tindex);
134 else if (sindex)
135 eindex = symbolToExp(sindex, loc, sc, false);
136 Expression e = new IndexExp(loc, symbolToExp(s, loc, sc, false), eindex);
137 e = e.expressionSemantic(sc);
138 resolveExp(e, pt, pe, ps);
139 return;
140 }
141
142 // Convert oindex to Expression, then try to resolve to constant.
143 if (tindex)
144 tindex.resolve(loc, sc, eindex, tindex, sindex);
145 if (sindex)
146 eindex = symbolToExp(sindex, loc, sc, false);
147 if (!eindex)
148 {
149 .error(loc, "index `%s` is not an expression", oindex.toChars());
150 pt = Type.terror;
151 return;
152 }
153
154 eindex = semanticLength(sc, tup, eindex);
155 eindex = eindex.ctfeInterpret();
156 if (eindex.op == EXP.error)
157 {
158 pt = Type.terror;
159 return;
160 }
161 const(uinteger_t) d = eindex.toUInteger();
162 if (d >= tup.objects.dim)
163 {
164 .error(loc, "tuple index `%llu` exceeds length %llu", d, cast(ulong)tup.objects.dim);
165 pt = Type.terror;
166 return;
167 }
168
169 RootObject o = (*tup.objects)[cast(size_t)d];
170 ps = isDsymbol(o);
171 if (auto t = isType(o))
172 pt = t.typeSemantic(loc, sc);
173 if (auto e = isExpression(o))
174 resolveExp(e, pt, pe, ps);
175 }
176
177 /*************************************
178 * Takes an array of Identifiers and figures out if
179 * it represents a Type, Expression, or Dsymbol.
180 * Params:
181 * mt = array of identifiers
182 * loc = location for error messages
183 * sc = context
184 * s = symbol to start search at
185 * scopesym = unused
186 * pe = set if expression otherwise null
187 * pt = set if type otherwise null
188 * ps = set if symbol otherwise null
189 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
190 */
191 private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
192 out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
193 {
version(none)194 version (none)
195 {
196 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars());
197 if (scopesym)
198 printf("\tscopesym = '%s'\n", scopesym.toChars());
199 }
200
201 if (!s)
202 {
203 /* Look for what user might have intended
204 */
205 const p = mt.mutableOf().unSharedOf().toChars();
206 auto id = Identifier.idPool(p, cast(uint)strlen(p));
207 if (const n = importHint(id.toString()))
208 error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr);
209 else if (auto s2 = sc.search_correct(id))
210 error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
211 else if (const q = Scope.search_correct_C(id))
212 error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
213 else if ((id == Id.This && sc.getStructClassScope()) ||
214 (id == Id._super && sc.getClassScope()))
215 error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p);
216 else
217 error(loc, "undefined identifier `%s`", p);
218
219 pt = Type.terror;
220 return;
221 }
222
223 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
224 Declaration d = s.isDeclaration();
225 if (d && (d.storage_class & STC.templateparameter))
226 s = s.toAlias();
227 else
228 {
229 // check for deprecated or disabled aliases
230 // functions are checked after overloading
231 // templates are checked after matching constraints
232 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
233 s.checkDeprecated(loc, sc);
234 if (d)
235 d.checkDisabled(loc, sc, true);
236 }
237 s = s.toAlias();
238 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
239 for (size_t i = 0; i < mt.idents.dim; i++)
240 {
241 RootObject id = mt.idents[i];
242 if (id.dyncast() == DYNCAST.expression ||
243 id.dyncast() == DYNCAST.type)
244 {
245 Type tx;
246 Expression ex;
247 Dsymbol sx;
248 resolveTupleIndex(loc, sc, s, ex, tx, sx, id);
249 if (sx)
250 {
251 s = sx.toAlias();
252 continue;
253 }
254 if (tx)
255 ex = new TypeExp(loc, tx);
256 assert(ex);
257
258 ex = typeToExpressionHelper(mt, ex, i + 1);
259 ex = ex.expressionSemantic(sc);
260 resolveExp(ex, pt, pe, ps);
261 return;
262 }
263
264 Type t = s.getType(); // type symbol, type alias, or type tuple?
265 uint errorsave = global.errors;
266 int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports;
267
268 Dsymbol sm = s.searchX(loc, sc, id, flags);
269 if (sm)
270 {
271 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
272 {
273 .error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
274 sm = null;
275 }
276 // Same check as in Expression.semanticY(DotIdExp)
277 else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
278 {
279 // @@@DEPRECATED_2.106@@@
280 // Should be an error in 2.106. Just remove the deprecation call
281 // and uncomment the null assignment
282 deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
283 //sm = null;
284 }
285 }
286 if (global.errors != errorsave)
287 {
288 pt = Type.terror;
289 return;
290 }
291
helper3()292 void helper3()
293 {
294 Expression e;
295 VarDeclaration v = s.isVarDeclaration();
296 FuncDeclaration f = s.isFuncDeclaration();
297 if (intypeid || !v && !f)
298 e = symbolToExp(s, loc, sc, true);
299 else
300 e = new VarExp(loc, s.isDeclaration(), true);
301
302 e = typeToExpressionHelper(mt, e, i);
303 e = e.expressionSemantic(sc);
304 resolveExp(e, pt, pe, ps);
305 }
306
307 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
308 if (intypeid && !t && sm && sm.needThis())
309 return helper3();
310
311 if (VarDeclaration v = s.isVarDeclaration())
312 {
313 // https://issues.dlang.org/show_bug.cgi?id=19913
314 // v.type would be null if it is a forward referenced member.
315 if (v.type is null)
316 v.dsymbolSemantic(sc);
317 if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
318 v.type.isConst() || v.type.isImmutable())
319 {
320 // https://issues.dlang.org/show_bug.cgi?id=13087
321 // this.field is not constant always
322 if (!v.isThisDeclaration())
323 return helper3();
324 }
325 }
326 if (!sm)
327 {
328 if (!t)
329 {
330 if (s.isDeclaration()) // var, func, or tuple declaration?
331 {
332 t = s.isDeclaration().type;
333 if (!t && s.isTupleDeclaration()) // expression tuple?
334 return helper3();
335 }
336 else if (s.isTemplateInstance() ||
337 s.isImport() || s.isPackage() || s.isModule())
338 {
339 return helper3();
340 }
341 }
342 if (t)
343 {
344 sm = t.toDsymbol(sc);
345 if (sm && id.dyncast() == DYNCAST.identifier)
346 {
347 sm = sm.search(loc, cast(Identifier)id, IgnorePrivateImports);
348 if (!sm)
349 return helper3();
350 }
351 else
352 return helper3();
353 }
354 else
355 {
356 if (id.dyncast() == DYNCAST.dsymbol)
357 {
358 // searchX already handles errors for template instances
359 assert(global.errors);
360 }
361 else
362 {
363 assert(id.dyncast() == DYNCAST.identifier);
364 sm = s.search_correct(cast(Identifier)id);
365 if (sm)
366 error(loc, "identifier `%s` of `%s` is not defined, did you mean %s `%s`?", id.toChars(), mt.toChars(), sm.kind(), sm.toChars());
367 else
368 error(loc, "identifier `%s` of `%s` is not defined", id.toChars(), mt.toChars());
369 }
370 pe = ErrorExp.get();
371 return;
372 }
373 }
374 s = sm.toAlias();
375 }
376
377 if (auto em = s.isEnumMember())
378 {
379 // It's not a type, it's an expression
380 pe = em.getVarExp(loc, sc);
381 return;
382 }
383 if (auto v = s.isVarDeclaration())
384 {
385 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
386 * because some variables used in type context need to prevent lowering
387 * to a literal or contextful expression. For example:
388 *
389 * enum a = 1; alias b = a;
390 * template X(alias e){ alias v = e; } alias x = X!(1);
391 * struct S { int v; alias w = v; }
392 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
393 * // because getDsymbol() need to work in AliasDeclaration::semantic().
394 */
395 if (!v.type ||
396 !v.type.deco && v.inuse)
397 {
398 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
399 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
400 else
401 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
402 pt = Type.terror;
403 return;
404 }
405 if (v.type.ty == Terror)
406 pt = Type.terror;
407 else
408 pe = new VarExp(loc, v);
409 return;
410 }
411 if (auto fld = s.isFuncLiteralDeclaration())
412 {
413 //printf("'%s' is a function literal\n", fld.toChars());
414 auto e = new FuncExp(loc, fld);
415 pe = e.expressionSemantic(sc);
416 return;
417 }
version(none)418 version (none)
419 {
420 if (FuncDeclaration fd = s.isFuncDeclaration())
421 {
422 pe = new DsymbolExp(loc, fd);
423 return;
424 }
425 }
426
427 Type t;
428 while (1)
429 {
430 t = s.getType();
431 if (t)
432 break;
433 ps = s;
434 return;
435 }
436
437 if (auto ti = t.isTypeInstance())
438 if (ti != mt && !ti.deco)
439 {
440 if (!ti.tempinst.errors)
441 error(loc, "forward reference to `%s`", ti.toChars());
442 pt = Type.terror;
443 return;
444 }
445
446 if (t.ty == Ttuple)
447 pt = t;
448 else
449 pt = t.merge();
450 }
451
452 /************************************
453 * Transitively search a type for all function types.
454 * If any function types with parameters are found that have parameter identifiers
455 * or default arguments, remove those and create a new type stripped of those.
456 * This is used to determine the "canonical" version of a type which is useful for
457 * comparisons.
458 * Params:
459 * t = type to scan
460 * Returns:
461 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
462 * the same as t but with no parameter identifiers or default arguments.
463 */
stripDefaultArgs(Type t)464 private Type stripDefaultArgs(Type t)
465 {
466 static Parameters* stripParams(Parameters* parameters)
467 {
468 static Parameter stripParameter(Parameter p)
469 {
470 Type t = stripDefaultArgs(p.type);
471 return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
472 ? new Parameter(p.storageClass, t, null, null, null)
473 : null;
474 }
475
476 if (parameters)
477 {
478 foreach (i, p; *parameters)
479 {
480 Parameter ps = stripParameter(p);
481 if (ps)
482 {
483 // Replace params with a copy we can modify
484 Parameters* nparams = new Parameters(parameters.dim);
485
486 foreach (j, ref np; *nparams)
487 {
488 Parameter pj = (*parameters)[j];
489 if (j < i)
490 np = pj;
491 else if (j == i)
492 np = ps;
493 else
494 {
495 Parameter nps = stripParameter(pj);
496 np = nps ? nps : pj;
497 }
498 }
499 return nparams;
500 }
501 }
502 }
503 return parameters;
504 }
505
506 if (t is null)
507 return t;
508
509 if (auto tf = t.isTypeFunction())
510 {
511 Type tret = stripDefaultArgs(tf.next);
512 Parameters* params = stripParams(tf.parameterList.parameters);
513 if (tret == tf.next && params == tf.parameterList.parameters)
514 return t;
515 TypeFunction tr = tf.copy().isTypeFunction();
516 tr.parameterList.parameters = params;
517 tr.next = tret;
518 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
519 return tr;
520 }
521 else if (auto tt = t.isTypeTuple())
522 {
523 Parameters* args = stripParams(tt.arguments);
524 if (args == tt.arguments)
525 return t;
526 TypeTuple tr = t.copy().isTypeTuple();
527 tr.arguments = args;
528 return tr;
529 }
530 else if (t.ty == Tenum)
531 {
532 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
533 return t;
534 }
535 else
536 {
537 Type tn = t.nextOf();
538 Type n = stripDefaultArgs(tn);
539 if (n == tn)
540 return t;
541 TypeNext tr = cast(TypeNext)t.copy();
542 tr.next = n;
543 return tr;
544 }
545 }
546
547 /******************************************
548 * We've mistakenly parsed `t` as a type.
549 * Redo `t` as an Expression only if there are no type modifiers.
550 * Params:
551 * t = mistaken type
552 * Returns:
553 * t redone as Expression, null if cannot
554 */
typeToExpression(Type t)555 Expression typeToExpression(Type t)
556 {
557 static Expression visitSArray(TypeSArray t)
558 {
559 if (auto e = t.next.typeToExpression())
560 return new ArrayExp(t.dim.loc, e, t.dim);
561 return null;
562 }
563
564 static Expression visitAArray(TypeAArray t)
565 {
566 if (auto e = t.next.typeToExpression())
567 {
568 if (auto ei = t.index.typeToExpression())
569 return new ArrayExp(t.loc, e, ei);
570 }
571 return null;
572 }
573
574 static Expression visitIdentifier(TypeIdentifier t)
575 {
576 return typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident));
577 }
578
579 static Expression visitInstance(TypeInstance t)
580 {
581 return typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst));
582 }
583
584 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
585 static Expression visitMixin(TypeMixin t)
586 {
587 return new TypeExp(t.loc, t);
588 }
589
590 if (t.mod)
591 return null;
592 switch (t.ty)
593 {
594 case Tsarray: return visitSArray(t.isTypeSArray());
595 case Taarray: return visitAArray(t.isTypeAArray());
596 case Tident: return visitIdentifier(t.isTypeIdentifier());
597 case Tinstance: return visitInstance(t.isTypeInstance());
598 case Tmixin: return visitMixin(t.isTypeMixin());
599 default: return null;
600 }
601 }
602
603 /* Helper function for `typeToExpression`. Contains common code
604 * for TypeQualified derived classes.
605 */
606 Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
607 {
608 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
609 foreach (id; t.idents[i .. t.idents.dim])
610 {
611 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
612
613 final switch (id.dyncast())
614 {
615 // ... '. ident'
616 case DYNCAST.identifier:
617 e = new DotIdExp(e.loc, e, cast(Identifier)id);
618 break;
619
620 // ... '. name!(tiargs)'
621 case DYNCAST.dsymbol:
622 auto ti = (cast(Dsymbol)id).isTemplateInstance();
623 assert(ti);
624 e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
625 break;
626
627 // ... '[type]'
628 case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215
629 e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
630 break;
631
632 // ... '[expr]'
633 case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215
634 e = new ArrayExp(t.loc, e, cast(Expression)id);
635 break;
636
637 case DYNCAST.object:
638 case DYNCAST.tuple:
639 case DYNCAST.parameter:
640 case DYNCAST.statement:
641 case DYNCAST.condition:
642 case DYNCAST.templateparameter:
643 case DYNCAST.initializer:
644 assert(0);
645 }
646 }
647 return e;
648 }
649
650 /******************************************
651 * Perform semantic analysis on a type.
652 * Params:
653 * type = Type AST node
654 * loc = the location of the type
655 * sc = context
656 * Returns:
657 * `Type` with completed semantic analysis, `Terror` if errors
658 * were encountered
659 */
typeSemantic(Type type,const ref Loc loc,Scope * sc)660 extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
661 {
662 static Type error()
663 {
664 return Type.terror;
665 }
666
667 Type visitType(Type t)
668 {
669 // @@@DEPRECATED_2.110@@@
670 // Use of `cent` and `ucent` has always been an error.
671 // Starting from 2.100, recommend core.int128 as a replace for the
672 // lack of compiler support.
673 if (t.ty == Tint128 || t.ty == Tuns128)
674 {
675 .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
676 return error();
677 }
678
679 return t.merge();
680 }
681
682 Type visitVector(TypeVector mtype)
683 {
684 const errors = global.errors;
685 mtype.basetype = mtype.basetype.typeSemantic(loc, sc);
686 if (errors != global.errors)
687 return error();
688 mtype.basetype = mtype.basetype.toBasetype().mutableOf();
689 if (mtype.basetype.ty != Tsarray)
690 {
691 .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars());
692 return error();
693 }
694 TypeSArray t = mtype.basetype.isTypeSArray();
695 const sz = cast(int)t.size(loc);
696 final switch (target.isVectorTypeSupported(sz, t.nextOf()))
697 {
698 case 0:
699 // valid
700 break;
701
702 case 1:
703 // no support at all
704 .error(loc, "SIMD vector types not supported on this platform");
705 return error();
706
707 case 2:
708 // invalid base type
709 .error(loc, "vector type `%s` is not supported on this platform", mtype.toChars());
710 return error();
711
712 case 3:
713 // invalid size
714 .error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars());
715 return error();
716 }
717 return merge(mtype);
718 }
719
720 Type visitSArray(TypeSArray mtype)
721 {
722 //printf("TypeSArray::semantic() %s\n", toChars());
723 Type t;
724 Expression e;
725 Dsymbol s;
726 mtype.next.resolve(loc, sc, e, t, s);
727
728 if (auto tup = s ? s.isTupleDeclaration() : null)
729 {
730 mtype.dim = semanticLength(sc, tup, mtype.dim);
731 mtype.dim = mtype.dim.ctfeInterpret();
732 if (mtype.dim.op == EXP.error)
733 return error();
734
735 uinteger_t d = mtype.dim.toUInteger();
736 if (d >= tup.objects.dim)
737 {
738 .error(loc, "tuple index %llu exceeds %llu", cast(ulong)d, cast(ulong)tup.objects.dim);
739 return error();
740 }
741
742 RootObject o = (*tup.objects)[cast(size_t)d];
743 if (o.dyncast() != DYNCAST.type)
744 {
745 .error(loc, "`%s` is not a type", mtype.toChars());
746 return error();
747 }
748 return (cast(Type)o).addMod(mtype.mod);
749 }
750
751 if (t && t.ty == Terror)
752 return error();
753
754 Type tn = mtype.next.typeSemantic(loc, sc);
755 if (tn.ty == Terror)
756 return error();
757
758 Type tbn = tn.toBasetype();
759 if (mtype.dim)
760 {
761 auto errors = global.errors;
762 mtype.dim = semanticLength(sc, tbn, mtype.dim);
763 if (errors != global.errors)
764 return error();
765
766 mtype.dim = mtype.dim.optimize(WANTvalue);
767 mtype.dim = mtype.dim.ctfeInterpret();
768 if (mtype.dim.op == EXP.error)
769 return error();
770
771 errors = global.errors;
772 dinteger_t d1 = mtype.dim.toInteger();
773 if (errors != global.errors)
774 return error();
775
776 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
777 mtype.dim = mtype.dim.optimize(WANTvalue);
778 if (mtype.dim.op == EXP.error)
779 return error();
780
781 errors = global.errors;
782 dinteger_t d2 = mtype.dim.toInteger();
783 if (errors != global.errors)
784 return error();
785
786 if (mtype.dim.op == EXP.error)
787 return error();
788
789 Type overflowError()
790 {
791 .error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
792 mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, target.maxStaticDataSize);
793 return error();
794 }
795
796 if (d1 != d2)
797 return overflowError();
798
799 Type tbx = tbn.baseElemOf();
800 if (tbx.ty == Tstruct && !tbx.isTypeStruct().sym.members ||
801 tbx.ty == Tenum && !tbx.isTypeEnum().sym.members)
802 {
803 /* To avoid meaningless error message, skip the total size limit check
804 * when the bottom of element type is opaque.
805 */
806 }
807 else if (tbn.isTypeBasic() ||
808 tbn.ty == Tpointer ||
809 tbn.ty == Tarray ||
810 tbn.ty == Tsarray ||
811 tbn.ty == Taarray ||
812 (tbn.ty == Tstruct && tbn.isTypeStruct().sym.sizeok == Sizeok.done) ||
813 tbn.ty == Tclass)
814 {
815 /* Only do this for types that don't need to have semantic()
816 * run on them for the size, since they may be forward referenced.
817 */
818 bool overflow = false;
819 if (mulu(tbn.size(loc), d2, overflow) >= target.maxStaticDataSize || overflow)
820 return overflowError();
821 }
822 }
823 switch (tbn.ty)
824 {
825 case Ttuple:
826 {
827 // Index the tuple to get the type
828 assert(mtype.dim);
829 TypeTuple tt = tbn.isTypeTuple();
830 uinteger_t d = mtype.dim.toUInteger();
831 if (d >= tt.arguments.dim)
832 {
833 .error(loc, "tuple index %llu exceeds %llu", cast(ulong)d, cast(ulong)tt.arguments.dim);
834 return error();
835 }
836 Type telem = (*tt.arguments)[cast(size_t)d].type;
837 return telem.addMod(mtype.mod);
838 }
839
840 case Tfunction:
841 case Tnone:
842 .error(loc, "cannot have array of `%s`", tbn.toChars());
843 return error();
844
845 default:
846 break;
847 }
848 if (tbn.isscope())
849 {
850 .error(loc, "cannot have array of scope `%s`", tbn.toChars());
851 return error();
852 }
853
854 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
855 * and const(T)[3] become const(T[3])
856 */
857 mtype.next = tn;
858 mtype.transitive();
859 return mtype.addMod(tn.mod).merge();
860 }
861
862 Type visitDArray(TypeDArray mtype)
863 {
864 Type tn = mtype.next.typeSemantic(loc, sc);
865 Type tbn = tn.toBasetype();
866 switch (tbn.ty)
867 {
868 case Ttuple:
869 return tbn;
870
871 case Tfunction:
872 case Tnone:
873 .error(loc, "cannot have array of `%s`", tbn.toChars());
874 return error();
875
876 case Terror:
877 return error();
878
879 default:
880 break;
881 }
882 if (tn.isscope())
883 {
884 .error(loc, "cannot have array of scope `%s`", tn.toChars());
885 return error();
886 }
887 mtype.next = tn;
888 mtype.transitive();
889 return merge(mtype);
890 }
891
892 Type visitAArray(TypeAArray mtype)
893 {
894 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
895 if (mtype.deco)
896 {
897 return mtype;
898 }
899
900 mtype.loc = loc;
901 if (sc)
902 sc.setNoFree();
903
904 // Deal with the case where we thought the index was a type, but
905 // in reality it was an expression.
906 if (mtype.index.ty == Tident || mtype.index.ty == Tinstance || mtype.index.ty == Tsarray || mtype.index.ty == Ttypeof || mtype.index.ty == Treturn || mtype.index.ty == Tmixin)
907 {
908 Expression e;
909 Type t;
910 Dsymbol s;
911 mtype.index.resolve(loc, sc, e, t, s);
912
913 // https://issues.dlang.org/show_bug.cgi?id=15478
914 if (s)
915 e = symbolToExp(s, loc, sc, false);
916
917 if (e)
918 {
919 // It was an expression -
920 // Rewrite as a static array
921 auto tsa = new TypeSArray(mtype.next, e);
922 return tsa.typeSemantic(loc, sc);
923 }
924 else if (t)
925 mtype.index = t.typeSemantic(loc, sc);
926 else
927 {
928 .error(loc, "index is not a type or an expression");
929 return error();
930 }
931 }
932 else
933 mtype.index = mtype.index.typeSemantic(loc, sc);
934 mtype.index = mtype.index.merge2();
935
936 if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable())
937 {
938 mtype.index = mtype.index.constOf().mutableOf();
939 version (none)
940 {
941 printf("index is %p %s\n", mtype.index, mtype.index.toChars());
942 mtype.index.check();
943 printf("index.mod = x%x\n", mtype.index.mod);
944 printf("index.ito = x%p\n", mtype.index.getMcache().ito);
945 if (mtype.index.getMcache().ito)
946 {
947 printf("index.ito.mod = x%x\n", mtype.index.getMcache().ito.mod);
948 printf("index.ito.ito = x%p\n", mtype.index.getMcache().ito.getMcache().ito);
949 }
950 }
951 }
952
953 switch (mtype.index.toBasetype().ty)
954 {
955 case Tfunction:
956 case Tvoid:
957 case Tnone:
958 case Ttuple:
959 .error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars());
960 goto case Terror;
961 case Terror:
962 return error();
963
964 default:
965 break;
966 }
967 Type tbase = mtype.index.baseElemOf();
968 while (tbase.ty == Tarray)
969 tbase = tbase.nextOf().baseElemOf();
970 if (auto ts = tbase.isTypeStruct())
971 {
972 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
973 */
974 StructDeclaration sd = ts.sym;
975 if (sd.semanticRun < PASS.semanticdone)
976 sd.dsymbolSemantic(null);
977
978 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
979 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
980
981 if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
982 {
983 uint errors = global.startGagging();
984 sd.xeq.semantic3(sd.xeq._scope);
985 if (global.endGagging(errors))
986 sd.xeq = sd.xerreq;
987 }
988
989
990 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
991 const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : "";
992 if (!sd.xeq)
993 {
994 // If sd.xhash != NULL:
995 // sd or its fields have user-defined toHash.
996 // AA assumes that its result is consistent with bitwise equality.
997 // else:
998 // bitwise equality & hashing
999 }
1000 else if (sd.xeq == sd.xerreq)
1001 {
1002 if (search_function(sd, Id.eq))
1003 {
1004 .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars());
1005 }
1006 else
1007 {
1008 .error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars());
1009 }
1010 return error();
1011 }
1012 else if (!sd.xhash)
1013 {
1014 if (search_function(sd, Id.eq))
1015 {
1016 .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars());
1017 }
1018 else
1019 {
1020 .error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars());
1021 }
1022 return error();
1023 }
1024 else
1025 {
1026 // defined equality & hashing
1027 assert(sd.xeq && sd.xhash);
1028
1029 /* xeq and xhash may be implicitly defined by compiler. For example:
1030 * struct S { int[] arr; }
1031 * With 'arr' field equality and hashing, compiler will implicitly
1032 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
1033 */
1034 }
1035 }
1036 else if (tbase.ty == Tclass && !tbase.isTypeClass().sym.isInterfaceDeclaration())
1037 {
1038 ClassDeclaration cd = tbase.isTypeClass().sym;
1039 if (cd.semanticRun < PASS.semanticdone)
1040 cd.dsymbolSemantic(null);
1041
1042 if (!ClassDeclaration.object)
1043 {
1044 .error(Loc.initial, "missing or corrupt object.d");
1045 fatal();
1046 }
1047
1048 __gshared FuncDeclaration feq = null;
1049 __gshared FuncDeclaration fcmp = null;
1050 __gshared FuncDeclaration fhash = null;
1051 if (!feq)
1052 feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration();
1053 if (!fcmp)
1054 fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration();
1055 if (!fhash)
1056 fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration();
1057 assert(fcmp && feq && fhash);
1058
1059 if (feq.vtblIndex < cd.vtbl.dim && cd.vtbl[feq.vtblIndex] == feq)
1060 {
1061 version (all)
1062 {
1063 if (fcmp.vtblIndex < cd.vtbl.dim && cd.vtbl[fcmp.vtblIndex] != fcmp)
1064 {
1065 const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : "";
1066 .error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars());
1067 errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`.");
1068 }
1069 }
1070 }
1071 }
1072 mtype.next = mtype.next.typeSemantic(loc, sc).merge2();
1073 mtype.transitive();
1074
1075 switch (mtype.next.toBasetype().ty)
1076 {
1077 case Tfunction:
1078 case Tvoid:
1079 case Tnone:
1080 case Ttuple:
1081 .error(loc, "cannot have associative array of `%s`", mtype.next.toChars());
1082 goto case Terror;
1083 case Terror:
1084 return error();
1085 default:
1086 break;
1087 }
1088 if (mtype.next.isscope())
1089 {
1090 .error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
1091 return error();
1092 }
1093 return merge(mtype);
1094 }
1095
1096 Type visitPointer(TypePointer mtype)
1097 {
1098 //printf("TypePointer::semantic() %s\n", toChars());
1099 if (mtype.deco)
1100 {
1101 return mtype;
1102 }
1103 Type n = mtype.next.typeSemantic(loc, sc);
1104 switch (n.toBasetype().ty)
1105 {
1106 case Ttuple:
1107 .error(loc, "cannot have pointer to `%s`", n.toChars());
1108 goto case Terror;
1109 case Terror:
1110 return error();
1111 default:
1112 break;
1113 }
1114 if (n != mtype.next)
1115 {
1116 mtype.deco = null;
1117 }
1118 mtype.next = n;
1119 if (mtype.next.ty != Tfunction)
1120 {
1121 mtype.transitive();
1122 return merge(mtype);
1123 }
1124 version (none)
1125 {
1126 return merge(mtype);
1127 }
1128 else
1129 {
1130 mtype.deco = merge(mtype).deco;
1131 /* Don't return merge(), because arg identifiers and default args
1132 * can be different
1133 * even though the types match
1134 */
1135 return mtype;
1136 }
1137 }
1138
1139 Type visitReference(TypeReference mtype)
1140 {
1141 //printf("TypeReference::semantic()\n");
1142 Type n = mtype.next.typeSemantic(loc, sc);
1143 if (n != mtype.next)
1144 mtype.deco = null;
1145 mtype.next = n;
1146 mtype.transitive();
1147 return merge(mtype);
1148 }
1149
1150 Type visitFunction(TypeFunction mtype)
1151 {
1152 if (mtype.deco) // if semantic() already run
1153 {
1154 //printf("already done\n");
1155 return mtype;
1156 }
1157 //printf("TypeFunction::semantic() this = %p\n", this);
1158 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
1159
1160 bool errors = false;
1161
1162 if (mtype.inuse > global.recursionLimit)
1163 {
1164 mtype.inuse = 0;
1165 .error(loc, "recursive type");
1166 return error();
1167 }
1168
1169 /* Copy in order to not mess up original.
1170 * This can produce redundant copies if inferring return type,
1171 * as semantic() will get called again on this.
1172 */
1173 TypeFunction tf = mtype.copy().toTypeFunction();
1174 if (mtype.parameterList.parameters)
1175 {
1176 tf.parameterList.parameters = mtype.parameterList.parameters.copy();
1177 for (size_t i = 0; i < mtype.parameterList.parameters.dim; i++)
1178 {
1179 Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter));
1180 memcpy(cast(void*)p, cast(void*)(*mtype.parameterList.parameters)[i], __traits(classInstanceSize, Parameter));
1181 (*tf.parameterList.parameters)[i] = p;
1182 }
1183 }
1184
1185 if (sc.stc & STC.pure_)
1186 tf.purity = PURE.fwdref;
1187 if (sc.stc & STC.nothrow_)
1188 tf.isnothrow = true;
1189 if (sc.stc & STC.nogc)
1190 tf.isnogc = true;
1191 if (sc.stc & STC.ref_)
1192 tf.isref = true;
1193 if (sc.stc & STC.return_)
1194 tf.isreturn = true;
1195 if (sc.stc & STC.returnScope)
1196 tf.isreturnscope = true;
1197 if (sc.stc & STC.returninferred)
1198 tf.isreturninferred = true;
1199 if (sc.stc & STC.scope_)
1200 tf.isScopeQual = true;
1201 if (sc.stc & STC.scopeinferred)
1202 tf.isscopeinferred = true;
1203
1204 // if (tf.isreturn && !tf.isref)
1205 // tf.isScopeQual = true; // return by itself means 'return scope'
1206
1207 if (tf.trust == TRUST.default_)
1208 {
1209 if (sc.stc & STC.safe)
1210 tf.trust = TRUST.safe;
1211 else if (sc.stc & STC.system)
1212 tf.trust = TRUST.system;
1213 else if (sc.stc & STC.trusted)
1214 tf.trust = TRUST.trusted;
1215 }
1216
1217 if (sc.stc & STC.property)
1218 tf.isproperty = true;
1219 if (sc.stc & STC.live)
1220 tf.islive = true;
1221
1222 tf.linkage = sc.linkage;
1223 if (tf.linkage == LINK.system)
1224 tf.linkage = target.systemLinkage();
1225
1226 version (none)
1227 {
1228 /* If the parent is @safe, then this function defaults to safe
1229 * too.
1230 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1231 * to be inferred first.
1232 */
1233 if (tf.trust == TRUST.default_)
1234 for (Dsymbol p = sc.func; p; p = p.toParent2())
1235 {
1236 FuncDeclaration fd = p.isFuncDeclaration();
1237 if (fd)
1238 {
1239 if (fd.isSafeBypassingInference())
1240 tf.trust = TRUST.safe; // default to @safe
1241 break;
1242 }
1243 }
1244 }
1245
1246 bool wildreturn = false;
1247 if (tf.next)
1248 {
1249 sc = sc.push();
1250 sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR);
1251 tf.next = tf.next.typeSemantic(loc, sc);
1252 sc = sc.pop();
1253 errors |= tf.checkRetType(loc);
1254 if (tf.next.isscope() && !tf.isctor)
1255 {
1256 .error(loc, "functions cannot return `scope %s`", tf.next.toChars());
1257 errors = true;
1258 }
1259 if (tf.next.hasWild())
1260 wildreturn = true;
1261
1262 if (tf.isreturn && !tf.isref && !tf.next.hasPointers())
1263 {
1264 tf.isreturn = false;
1265 }
1266 }
1267
1268 /// Perform semantic on the default argument to a parameter
1269 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1270 /// Returns `false` whether an error was encountered.
1271 static bool defaultArgSemantic (ref Parameter fparam, Scope* sc)
1272 {
1273 Expression e = fparam.defaultArg;
1274 const isRefOrOut = fparam.isReference();
1275 const isAuto = fparam.storageClass & (STC.auto_ | STC.autoref);
1276 if (isRefOrOut && !isAuto)
1277 {
1278 e = e.expressionSemantic(sc);
1279 e = resolveProperties(sc, e);
1280 }
1281 else
1282 {
1283 e = inferType(e, fparam.type);
1284 Initializer iz = new ExpInitializer(e.loc, e);
1285 iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
1286 e = iz.initializerToExpression();
1287 }
1288 if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
1289 {
1290 FuncExp fe = e.isFuncExp();
1291 // Replace function literal with a function symbol,
1292 // since default arg expression must be copied when used
1293 // and copying the literal itself is wrong.
1294 e = new VarExp(e.loc, fe.fd, false);
1295 e = new AddrExp(e.loc, e);
1296 e = e.expressionSemantic(sc);
1297 }
1298 if (isRefOrOut && (!isAuto || e.isLvalue())
1299 && !MODimplicitConv(e.type.mod, fparam.type.mod))
1300 {
1301 const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
1302 .error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1303 e.toChars(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
1304 }
1305 e = e.implicitCastTo(sc, fparam.type);
1306
1307 // default arg must be an lvalue
1308 if (isRefOrOut && !isAuto &&
1309 !(global.params.previewIn && (fparam.storageClass & STC.in_)) &&
1310 global.params.rvalueRefParam != FeatureState.enabled)
1311 e = e.toLvalue(sc, e);
1312
1313 fparam.defaultArg = e;
1314 return (e.op != EXP.error);
1315 }
1316
1317 ubyte wildparams = 0;
1318 if (tf.parameterList.parameters)
1319 {
1320 /* Create a scope for evaluating the default arguments for the parameters
1321 */
1322 Scope* argsc = sc.push();
1323 argsc.stc = 0; // don't inherit storage class
1324 argsc.visibility = Visibility(Visibility.Kind.public_);
1325 argsc.func = null;
1326
1327 size_t dim = tf.parameterList.length;
1328 for (size_t i = 0; i < dim; i++)
1329 {
1330 Parameter fparam = tf.parameterList[i];
1331 fparam.storageClass |= STC.parameter;
1332 mtype.inuse++;
1333 fparam.type = fparam.type.typeSemantic(loc, argsc);
1334 mtype.inuse--;
1335
1336 if (fparam.type.ty == Terror)
1337 {
1338 errors = true;
1339 continue;
1340 }
1341
1342 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
1343
1344 if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_))
1345 {
1346 if (!fparam.type)
1347 continue;
1348 }
1349
1350 fparam.type = fparam.type.cAdjustParamType(sc); // adjust C array and function parameter types
1351
1352 Type t = fparam.type.toBasetype();
1353
1354 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
1355 * change.
1356 */
1357 if (auto tt = t.isTypeTuple())
1358 {
1359 /* TypeFunction::parameter also is used as the storage of
1360 * Parameter objects for FuncDeclaration. So we should copy
1361 * the elements of TypeTuple::arguments to avoid unintended
1362 * sharing of Parameter object among other functions.
1363 */
1364 if (tt.arguments && tt.arguments.dim)
1365 {
1366 /* Propagate additional storage class from tuple parameters to their
1367 * element-parameters.
1368 * Make a copy, as original may be referenced elsewhere.
1369 */
1370 size_t tdim = tt.arguments.dim;
1371 auto newparams = new Parameters(tdim);
1372 for (size_t j = 0; j < tdim; j++)
1373 {
1374 Parameter narg = (*tt.arguments)[j];
1375
1376 // https://issues.dlang.org/show_bug.cgi?id=12744
1377 // If the storage classes of narg
1378 // conflict with the ones in fparam, it's ignored.
1379 StorageClass stc = fparam.storageClass | narg.storageClass;
1380 StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
1381 StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
1382 if (stc1 && stc2 && stc1 != stc2)
1383 {
1384 OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0));
1385 OutBuffer buf2; stcToBuffer(&buf2, stc2);
1386
1387 .error(loc, "incompatible parameter storage classes `%s` and `%s`",
1388 buf1.peekChars(), buf2.peekChars());
1389 errors = true;
1390 stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_));
1391 }
1392 (*newparams)[j] = new Parameter(
1393 stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
1394 }
1395 fparam.type = new TypeTuple(newparams);
1396 fparam.type = fparam.type.typeSemantic(loc, argsc);
1397 }
1398 fparam.storageClass = STC.parameter;
1399
1400 /* Reset number of parameters, and back up one to do this fparam again,
1401 * now that it is a tuple
1402 */
1403 dim = tf.parameterList.length;
1404 i--;
1405 continue;
1406 }
1407
1408 if (t.ty == Tfunction)
1409 {
1410 .error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars());
1411 errors = true;
1412 }
1413 else if (!fparam.isReference() &&
1414 (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum))
1415 {
1416 Type tb2 = t.baseElemOf();
1417 if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members ||
1418 tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype)
1419 {
1420 if (global.params.previewIn && (fparam.storageClass & STC.in_))
1421 {
1422 .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
1423 fparam.toChars(), fparam.type.toChars());
1424 }
1425 else
1426 .error(loc, "cannot have parameter of opaque type `%s` by value",
1427 fparam.type.toChars());
1428 errors = true;
1429 }
1430 }
1431 else if (!(fparam.storageClass & STC.lazy_) && t.ty == Tvoid)
1432 {
1433 .error(loc, "cannot have parameter of type `%s`", fparam.type.toChars());
1434 errors = true;
1435 }
1436
1437 if (fparam.storageClass & STC.return_)
1438 {
1439 if (fparam.isReference())
1440 {
1441 // Disabled for the moment awaiting improvement to allow return by ref
1442 // to be transformed into return by scope.
1443 if (0 && !tf.isref)
1444 {
1445 auto stc = fparam.storageClass & (STC.ref_ | STC.out_);
1446 .error(loc, "parameter `%s` is `return %s` but function does not return by `ref`",
1447 fparam.ident ? fparam.ident.toChars() : "",
1448 stcToString(stc).ptr);
1449 errors = true;
1450 }
1451 }
1452 else
1453 {
1454 if (!(fparam.storageClass & STC.scope_))
1455 fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
1456 if (tf.isref)
1457 {
1458 }
1459 else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid)
1460 {
1461 fparam.storageClass &= ~STC.return_; // https://issues.dlang.org/show_bug.cgi?id=18963
1462 }
1463 }
1464
1465 if (i + 1 == dim && tf.parameterList.varargs == VarArg.typesafe &&
1466 (t.isTypeDArray() || t.isTypeClass()))
1467 {
1468 /* This is because they can be constructed on the stack
1469 * https://dlang.org/spec/function.html#typesafe_variadic_functions
1470 */
1471 .error(loc, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
1472 fparam.ident ? fparam.ident.toChars() : "", t.toChars());
1473 errors = true;
1474 }
1475 }
1476
1477 if (fparam.storageClass & STC.out_)
1478 {
1479 if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild))
1480 {
1481 .error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars());
1482 errors = true;
1483 }
1484 else
1485 {
1486 Type tv = t.baseElemOf();
1487 if (tv.ty == Tstruct && tv.isTypeStruct().sym.noDefaultCtor)
1488 {
1489 .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars());
1490 errors = true;
1491 }
1492 }
1493 }
1494
1495 if (t.hasWild())
1496 {
1497 wildparams |= 1;
1498 //if (tf.next && !wildreturn)
1499 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
1500 }
1501
1502 /* Scope attribute is not necessary if the parameter type does not have pointers
1503 */
1504 const sr = buildScopeRef(fparam.storageClass);
1505 switch (sr)
1506 {
1507 case ScopeRef.Scope:
1508 case ScopeRef.RefScope:
1509 case ScopeRef.ReturnRef_Scope:
1510 if (!fparam.type.hasPointers())
1511 fparam.storageClass &= ~STC.scope_;
1512 break;
1513
1514 case ScopeRef.ReturnScope:
1515 case ScopeRef.Ref_ReturnScope:
1516 if (!fparam.type.hasPointers())
1517 fparam.storageClass &= ~(STC.return_ | STC.scope_ | STC.returnScope);
1518 break;
1519
1520 default:
1521 break;
1522 }
1523
1524 // Remove redundant storage classes for type, they are already applied
1525 fparam.storageClass &= ~(STC.TYPECTOR);
1526
1527 // -preview=in: add `ref` storage class to suited `in` params
1528 if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
1529 {
1530 auto ts = t.baseElemOf().isTypeStruct();
1531 const isPOD = !ts || ts.sym.isPOD();
1532 if (!isPOD || target.preferPassByRef(t))
1533 fparam.storageClass |= STC.ref_;
1534 }
1535 }
1536
1537 // Now that we completed semantic for the argument types,
1538 // run semantic on their default values,
1539 // bearing in mind tuples have been expanded.
1540 // We need to keep a pair of [oidx, eidx] (original index,
1541 // extended index), as we need to run semantic when `oidx` changes.
1542 size_t tupleOrigIdx = size_t.max;
1543 size_t tupleExtIdx = size_t.max;
1544 foreach (oidx, oparam, eidx, eparam; tf.parameterList)
1545 {
1546 // oparam (original param) will always have the default arg
1547 // if there's one, but `eparam` will not if it's an expanded
1548 // tuple. When we see an expanded tuple, we need to save its
1549 // position to get the offset in it later on.
1550 if (oparam.defaultArg)
1551 {
1552 // Get the obvious case out of the way
1553 if (oparam is eparam)
1554 errors |= !defaultArgSemantic(eparam, argsc);
1555 // We're seeing a new tuple
1556 else if (tupleOrigIdx == size_t.max || tupleOrigIdx < oidx)
1557 {
1558 /* https://issues.dlang.org/show_bug.cgi?id=18572
1559 *
1560 * If a tuple parameter has a default argument, when expanding the parameter
1561 * tuple the default argument tuple must also be expanded.
1562 */
1563 tupleOrigIdx = oidx;
1564 tupleExtIdx = eidx;
1565 errors |= !defaultArgSemantic(oparam, argsc);
1566 TupleExp te = oparam.defaultArg.isTupleExp();
1567 if (te && te.exps && te.exps.length)
1568 eparam.defaultArg = (*te.exps)[0];
1569 }
1570 // Processing an already-seen tuple
1571 else
1572 {
1573 TupleExp te = oparam.defaultArg.isTupleExp();
1574 if (te && te.exps && te.exps.length)
1575 eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
1576 }
1577 }
1578
1579 // We need to know the default argument to resolve `auto ref`,
1580 // hence why this has to take place as the very last step.
1581 /* Resolve "auto ref" storage class to be either ref or value,
1582 * based on the argument matching the parameter
1583 */
1584 if (eparam.storageClass & STC.auto_)
1585 {
1586 Expression farg = mtype.fargs && eidx < mtype.fargs.dim ?
1587 (*mtype.fargs)[eidx] : eparam.defaultArg;
1588 if (farg && (eparam.storageClass & STC.ref_))
1589 {
1590 if (!farg.isLvalue())
1591 eparam.storageClass &= ~STC.ref_; // value parameter
1592 eparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656
1593 eparam.storageClass |= STC.autoref;
1594 }
1595 else if (mtype.incomplete && (eparam.storageClass & STC.ref_))
1596 {
1597 // the default argument may have been temporarily removed,
1598 // see usage of `TypeFunction.incomplete`.
1599 // https://issues.dlang.org/show_bug.cgi?id=19891
1600 eparam.storageClass &= ~STC.auto_;
1601 eparam.storageClass |= STC.autoref;
1602 }
1603 else
1604 {
1605 .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
1606 errors = true;
1607 }
1608 }
1609 }
1610
1611 argsc.pop();
1612 }
1613 if (tf.isWild())
1614 wildparams |= 2;
1615
1616 if (wildreturn && !wildparams)
1617 {
1618 .error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars());
1619 errors = true;
1620 }
1621 tf.isInOutParam = (wildparams & 1) != 0;
1622 tf.isInOutQual = (wildparams & 2) != 0;
1623
1624 if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
1625 {
1626 .error(loc, "properties can only have zero, one, or two parameter");
1627 errors = true;
1628 }
1629
1630 if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
1631 !(sc.flags & SCOPE.Cfile))
1632 {
1633 .error(loc, "variadic functions with non-D linkage must have at least one parameter");
1634 errors = true;
1635 }
1636
1637 if (errors)
1638 return error();
1639
1640 if (tf.next)
1641 tf.deco = tf.merge().deco;
1642
1643 /* Don't return merge(), because arg identifiers and default args
1644 * can be different
1645 * even though the types match
1646 */
1647 return tf;
1648 }
1649
1650 Type visitDelegate(TypeDelegate mtype)
1651 {
1652 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
1653 if (mtype.deco) // if semantic() already run
1654 {
1655 //printf("already done\n");
1656 return mtype;
1657 }
1658 mtype.next = mtype.next.typeSemantic(loc, sc);
1659 if (mtype.next.ty != Tfunction)
1660 return error();
1661
1662 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
1663 * perhaps default arguments should
1664 * be removed from next before the merge.
1665 */
1666 version (none)
1667 {
1668 return mtype.merge();
1669 }
1670 else
1671 {
1672 /* Don't return merge(), because arg identifiers and default args
1673 * can be different
1674 * even though the types match
1675 */
1676 mtype.deco = mtype.merge().deco;
1677 return mtype;
1678 }
1679 }
1680
1681 Type visitIdentifier(TypeIdentifier mtype)
1682 {
1683 Type t;
1684 Expression e;
1685 Dsymbol s;
1686 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
1687 mtype.resolve(loc, sc, e, t, s);
1688 if (t)
1689 {
1690 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
1691 return t.addMod(mtype.mod);
1692 }
1693 else
1694 {
1695 if (s)
1696 {
1697 auto td = s.isTemplateDeclaration;
1698 if (td && td.onemember && td.onemember.isAggregateDeclaration)
1699 .error(loc, "template %s `%s` is used as a type without instantiation"
1700 ~ "; to instantiate it use `%s!(arguments)`",
1701 s.kind, s.toPrettyChars, s.ident.toChars);
1702 else
1703 .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
1704 //assert(0);
1705 }
1706 else if (e.op == EXP.variable) // special case: variable is used as a type
1707 {
1708 /*
1709 N.B. This branch currently triggers for the following code
1710 template test(x* x)
1711 {
1712
1713 }
1714 i.e. the compiler prints "variable x is used as a type"
1715 which isn't a particularly good error message (x is a variable?).
1716 */
1717 Dsymbol varDecl = mtype.toDsymbol(sc);
1718 const(Loc) varDeclLoc = varDecl.getLoc();
1719 Module varDeclModule = varDecl.getModule(); //This can be null
1720
1721 .error(loc, "variable `%s` is used as a type", mtype.toChars());
1722 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
1723 if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
1724 {
1725 const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
1726 .errorSupplemental(
1727 varDeclModuleImportLoc,
1728 "variable `%s` is imported here from: `%s`",
1729 varDecl.toChars,
1730 varDeclModule.toPrettyChars,
1731 );
1732 }
1733
1734 .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
1735 }
1736 else
1737 .error(loc, "`%s` is used as a type", mtype.toChars());
1738 return error();
1739 }
1740 }
1741
1742 Type visitInstance(TypeInstance mtype)
1743 {
1744 Type t;
1745 Expression e;
1746 Dsymbol s;
1747
1748 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
1749 {
1750 const errors = global.errors;
1751 mtype.resolve(loc, sc, e, t, s);
1752 // if we had an error evaluating the symbol, suppress further errors
1753 if (!t && errors != global.errors)
1754 return error();
1755 }
1756
1757 if (!t)
1758 {
1759 if (!e && s && s.errors)
1760 {
1761 // if there was an error evaluating the symbol, it might actually
1762 // be a type. Avoid misleading error messages.
1763 .error(loc, "`%s` had previous errors", mtype.toChars());
1764 }
1765 else
1766 .error(loc, "`%s` is used as a type", mtype.toChars());
1767 return error();
1768 }
1769 return t;
1770 }
1771
1772 Type visitTypeof(TypeTypeof mtype)
1773 {
1774 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
1775 Expression e;
1776 Type t;
1777 Dsymbol s;
1778 mtype.resolve(loc, sc, e, t, s);
1779 if (s && (t = s.getType()) !is null)
1780 t = t.addMod(mtype.mod);
1781 if (!t)
1782 {
1783 .error(loc, "`%s` is used as a type", mtype.toChars());
1784 return error();
1785 }
1786 return t;
1787 }
1788
1789 Type visitTraits(TypeTraits mtype)
1790 {
1791 if (mtype.ty == Terror)
1792 return mtype;
1793
1794 const inAlias = (sc.flags & SCOPE.alias_) != 0;
1795 if (mtype.exp.ident != Id.allMembers &&
1796 mtype.exp.ident != Id.derivedMembers &&
1797 mtype.exp.ident != Id.getMember &&
1798 mtype.exp.ident != Id.parent &&
1799 mtype.exp.ident != Id.parameters &&
1800 mtype.exp.ident != Id.child &&
1801 mtype.exp.ident != Id.toType &&
1802 mtype.exp.ident != Id.getOverloads &&
1803 mtype.exp.ident != Id.getVirtualFunctions &&
1804 mtype.exp.ident != Id.getVirtualMethods &&
1805 mtype.exp.ident != Id.getAttributes &&
1806 mtype.exp.ident != Id.getUnitTests &&
1807 mtype.exp.ident != Id.getAliasThis)
1808 {
1809 static immutable (const(char)*)[2] ctxt = ["as type", "in alias"];
1810 .error(mtype.loc, "trait `%s` is either invalid or not supported %s",
1811 mtype.exp.ident.toChars, ctxt[inAlias]);
1812 mtype.ty = Terror;
1813 return mtype;
1814 }
1815
1816 import dmd.traits : semanticTraits;
1817 Type result;
1818
1819 if (Expression e = semanticTraits(mtype.exp, sc))
1820 {
1821 switch (e.op)
1822 {
1823 case EXP.dotVariable:
1824 mtype.sym = e.isDotVarExp().var;
1825 break;
1826 case EXP.variable:
1827 mtype.sym = e.isVarExp().var;
1828 break;
1829 case EXP.function_:
1830 auto fe = e.isFuncExp();
1831 mtype.sym = fe.td ? fe.td : fe.fd;
1832 break;
1833 case EXP.dotTemplateDeclaration:
1834 mtype.sym = e.isDotTemplateExp().td;
1835 break;
1836 case EXP.dSymbol:
1837 mtype.sym = e.isDsymbolExp().s;
1838 break;
1839 case EXP.template_:
1840 mtype.sym = e.isTemplateExp().td;
1841 break;
1842 case EXP.scope_:
1843 mtype.sym = e.isScopeExp().sds;
1844 break;
1845 case EXP.tuple:
1846 TupleExp te = e.isTupleExp();
1847 Objects* elems = new Objects(te.exps.dim);
1848 foreach (i; 0 .. elems.dim)
1849 {
1850 auto src = (*te.exps)[i];
1851 switch (src.op)
1852 {
1853 case EXP.type:
1854 (*elems)[i] = src.isTypeExp().type;
1855 break;
1856 case EXP.dotType:
1857 (*elems)[i] = src.isDotTypeExp().sym.isType();
1858 break;
1859 case EXP.overloadSet:
1860 (*elems)[i] = src.isOverExp().type;
1861 break;
1862 default:
1863 if (auto sym = isDsymbol(src))
1864 (*elems)[i] = sym;
1865 else
1866 (*elems)[i] = src;
1867 }
1868 }
1869 TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
1870 mtype.sym = td;
1871 break;
1872 case EXP.dotType:
1873 result = e.isDotTypeExp().sym.isType();
1874 break;
1875 case EXP.type:
1876 result = e.isTypeExp().type;
1877 break;
1878 case EXP.overloadSet:
1879 result = e.isOverExp().type;
1880 break;
1881 default:
1882 break;
1883 }
1884 }
1885
1886 if (result)
1887 result = result.addMod(mtype.mod);
1888 if (!inAlias && !result)
1889 {
1890 if (!global.errors)
1891 .error(mtype.loc, "`%s` does not give a valid type", mtype.toChars);
1892 return error();
1893 }
1894
1895 return result;
1896 }
1897
1898 Type visitReturn(TypeReturn mtype)
1899 {
1900 //printf("TypeReturn::semantic() %s\n", toChars());
1901 Expression e;
1902 Type t;
1903 Dsymbol s;
1904 mtype.resolve(loc, sc, e, t, s);
1905 if (s && (t = s.getType()) !is null)
1906 t = t.addMod(mtype.mod);
1907 if (!t)
1908 {
1909 .error(loc, "`%s` is used as a type", mtype.toChars());
1910 return error();
1911 }
1912 return t;
1913 }
1914
1915 Type visitStruct(TypeStruct mtype)
1916 {
1917 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
1918 if (mtype.deco)
1919 return mtype;
1920
1921 /* Don't semantic for sym because it should be deferred until
1922 * sizeof needed or its members accessed.
1923 */
1924 // instead, parent should be set correctly
1925 assert(mtype.sym.parent);
1926
1927 if (mtype.sym.type.ty == Terror)
1928 return error();
1929
1930 return merge(mtype);
1931 }
1932
1933 Type visitEnum(TypeEnum mtype)
1934 {
1935 //printf("TypeEnum::semantic() %s\n", toChars());
1936 return mtype.deco ? mtype : merge(mtype);
1937 }
1938
1939 Type visitClass(TypeClass mtype)
1940 {
1941 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
1942 if (mtype.deco)
1943 return mtype;
1944
1945 /* Don't semantic for sym because it should be deferred until
1946 * sizeof needed or its members accessed.
1947 */
1948 // instead, parent should be set correctly
1949 assert(mtype.sym.parent);
1950
1951 if (mtype.sym.type.ty == Terror)
1952 return error();
1953
1954 return merge(mtype);
1955 }
1956
1957 Type visitTuple(TypeTuple mtype)
1958 {
1959 //printf("TypeTuple::semantic(this = %p)\n", this);
1960 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
1961 if (!mtype.deco)
1962 mtype.deco = merge(mtype).deco;
1963
1964 /* Don't return merge(), because a tuple with one type has the
1965 * same deco as that type.
1966 */
1967 return mtype;
1968 }
1969
1970 Type visitSlice(TypeSlice mtype)
1971 {
1972 //printf("TypeSlice::semantic() %s\n", toChars());
1973 Type tn = mtype.next.typeSemantic(loc, sc);
1974 //printf("next: %s\n", tn.toChars());
1975
1976 Type tbn = tn.toBasetype();
1977 if (tbn.ty != Ttuple)
1978 {
1979 .error(loc, "can only slice tuple types, not `%s`", tbn.toChars());
1980 return error();
1981 }
1982 TypeTuple tt = cast(TypeTuple)tbn;
1983
1984 mtype.lwr = semanticLength(sc, tbn, mtype.lwr);
1985 mtype.upr = semanticLength(sc, tbn, mtype.upr);
1986 mtype.lwr = mtype.lwr.ctfeInterpret();
1987 mtype.upr = mtype.upr.ctfeInterpret();
1988 if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error)
1989 return error();
1990
1991 uinteger_t i1 = mtype.lwr.toUInteger();
1992 uinteger_t i2 = mtype.upr.toUInteger();
1993 if (!(i1 <= i2 && i2 <= tt.arguments.dim))
1994 {
1995 .error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
1996 cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.dim);
1997 return error();
1998 }
1999
2000 mtype.next = tn;
2001 mtype.transitive();
2002
2003 auto args = new Parameters();
2004 args.reserve(cast(size_t)(i2 - i1));
2005 foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2])
2006 {
2007 args.push(arg);
2008 }
2009 Type t = new TypeTuple(args);
2010 return t.typeSemantic(loc, sc);
2011 }
2012
2013 Type visitMixin(TypeMixin mtype)
2014 {
2015 //printf("TypeMixin::semantic() %s\n", toChars());
2016
2017 Expression e;
2018 Type t;
2019 Dsymbol s;
2020 mtype.resolve(loc, sc, e, t, s);
2021
2022 if (t && t.ty != Terror)
2023 return t;
2024
2025 .error(mtype.loc, "`mixin(%s)` does not give a valid type", mtype.obj.toChars);
2026 return error();
2027 }
2028
2029 Type visitTag(TypeTag mtype)
2030 {
2031 //printf("TypeTag.semantic() %s\n", mtype.toChars());
2032 if (mtype.resolved)
2033 {
2034 /* struct S s, *p;
2035 */
2036 //printf("already resolved\n");
2037 return mtype.resolved;
2038 }
2039
2040 /* Find the current scope by skipping tag scopes.
2041 * In C, tag scopes aren't considered scopes.
2042 */
2043 Scope* sc2 = sc;
2044 while (1)
2045 {
2046 sc2 = sc2.inner();
2047 auto scopesym = sc2.scopesym;
2048 if (scopesym.isStructDeclaration())
2049 {
2050 sc2 = sc2.enclosing;
2051 continue;
2052 }
2053 break;
2054 }
2055
2056 /* Declare mtype as a struct/union/enum declaration
2057 */
2058 void declareTag()
2059 {
2060 void declare(ScopeDsymbol sd)
2061 {
2062 sd.members = mtype.members;
2063 auto scopesym = sc2.inner().scopesym;
2064 if (scopesym.members)
2065 scopesym.members.push(sd);
2066 if (scopesym.symtab && !scopesym.symtabInsert(sd))
2067 {
2068 Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
2069 handleTagSymbols(*sc2, sd, s2, scopesym);
2070 }
2071 sd.parent = sc2.parent;
2072 sd.dsymbolSemantic(sc2);
2073 }
2074
2075 switch (mtype.tok)
2076 {
2077 case TOK.enum_:
2078 auto ed = new EnumDeclaration(mtype.loc, mtype.id, mtype.base);
2079 declare(ed);
2080 mtype.resolved = visitEnum(new TypeEnum(ed));
2081 break;
2082
2083 case TOK.struct_:
2084 auto sd = new StructDeclaration(mtype.loc, mtype.id, false);
2085 declare(sd);
2086 mtype.resolved = visitStruct(new TypeStruct(sd));
2087 break;
2088
2089 case TOK.union_:
2090 auto ud = new UnionDeclaration(mtype.loc, mtype.id);
2091 declare(ud);
2092 mtype.resolved = visitStruct(new TypeStruct(ud));
2093 break;
2094
2095 default:
2096 assert(0);
2097 }
2098 }
2099
2100 /* If it doesn't have a tag by now, supply one.
2101 * It'll be unique, and therefore introducing.
2102 * Declare it, and done.
2103 */
2104 if (!mtype.id)
2105 {
2106 mtype.id = Identifier.generateId("__tag"[]);
2107 declareTag();
2108 return mtype.resolved;
2109 }
2110
2111 /* look for pre-existing declaration
2112 */
2113 Dsymbol scopesym;
2114 auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
2115 if (!s || s.isModule())
2116 {
2117 // no pre-existing declaration, so declare it
2118 if (mtype.tok == TOK.enum_ && !mtype.members)
2119 .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
2120 declareTag();
2121 return mtype.resolved;
2122 }
2123
2124 /* A redeclaration only happens if both declarations are in
2125 * the same scope
2126 */
2127 const bool redeclar = (scopesym == sc2.inner().scopesym);
2128
2129 if (redeclar)
2130 {
2131 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
2132 {
2133 auto ed = s.isEnumDeclaration();
2134 if (mtype.members && ed.members)
2135 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
2136 else if (!ed.members)
2137 {
2138 ed.members = mtype.members;
2139 }
2140 else
2141 {
2142 }
2143 mtype.resolved = ed.type;
2144 }
2145 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
2146 mtype.tok == TOK.struct_ && s.isStructDeclaration())
2147 {
2148 // Add members to original declaration
2149 auto sd = s.isStructDeclaration();
2150 if (mtype.members && sd.members)
2151 {
2152 /* struct S { int b; };
2153 * struct S { int a; } *s;
2154 */
2155 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
2156 }
2157 else if (!sd.members)
2158 {
2159 /* struct S;
2160 * struct S { int a; } *s;
2161 */
2162 sd.members = mtype.members;
2163 if (sd.semanticRun == PASS.semanticdone)
2164 {
2165 /* The first semantic pass marked `sd` as an opaque struct.
2166 * Re-run semantic so that all newly assigned members are
2167 * picked up and added to the symtab.
2168 */
2169 sd.semanticRun = PASS.semantic;
2170 sd.dsymbolSemantic(sc2);
2171 }
2172 }
2173 else
2174 {
2175 /* struct S { int a; };
2176 * struct S *s;
2177 */
2178 }
2179 mtype.resolved = sd.type;
2180 }
2181 else
2182 {
2183 /* int S;
2184 * struct S { int a; } *s;
2185 */
2186 .error(mtype.loc, "redeclaration of `%s`", mtype.id.toChars());
2187 mtype.resolved = error();
2188 }
2189 }
2190 else if (mtype.members)
2191 {
2192 /* struct S;
2193 * { struct S { int a; } *s; }
2194 */
2195 declareTag();
2196 }
2197 else
2198 {
2199 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
2200 {
2201 mtype.resolved = s.isEnumDeclaration().type;
2202 }
2203 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
2204 mtype.tok == TOK.struct_ && s.isStructDeclaration())
2205 {
2206 /* struct S;
2207 * { struct S *s; }
2208 */
2209 mtype.resolved = s.isStructDeclaration().type;
2210 }
2211 else
2212 {
2213 /* union S;
2214 * { struct S *s; }
2215 */
2216 .error(mtype.loc, "redeclaring `%s %s` as `%s %s`",
2217 s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars());
2218 declareTag();
2219 }
2220 }
2221 return mtype.resolved;
2222 }
2223
2224 switch (type.ty)
2225 {
2226 default: return visitType(type);
2227 case Tvector: return visitVector(type.isTypeVector());
2228 case Tsarray: return visitSArray(type.isTypeSArray());
2229 case Tarray: return visitDArray(type.isTypeDArray());
2230 case Taarray: return visitAArray(type.isTypeAArray());
2231 case Tpointer: return visitPointer(type.isTypePointer());
2232 case Treference: return visitReference(type.isTypeReference());
2233 case Tfunction: return visitFunction(type.isTypeFunction());
2234 case Tdelegate: return visitDelegate(type.isTypeDelegate());
2235 case Tident: return visitIdentifier(type.isTypeIdentifier());
2236 case Tinstance: return visitInstance(type.isTypeInstance());
2237 case Ttypeof: return visitTypeof(type.isTypeTypeof());
2238 case Ttraits: return visitTraits(type.isTypeTraits());
2239 case Treturn: return visitReturn(type.isTypeReturn());
2240 case Tstruct: return visitStruct(type.isTypeStruct());
2241 case Tenum: return visitEnum(type.isTypeEnum());
2242 case Tclass: return visitClass(type.isTypeClass());
2243 case Ttuple: return visitTuple(type.isTypeTuple());
2244 case Tslice: return visitSlice(type.isTypeSlice());
2245 case Tmixin: return visitMixin(type.isTypeMixin());
2246 case Ttag: return visitTag(type.isTypeTag());
2247 }
2248 }
2249
2250 /******************************************
2251 * Compile the MixinType, returning the type or expression AST.
2252 *
2253 * Doesn't run semantic() on the returned object.
2254 * Params:
2255 * tm = mixin to compile as a type or expression
2256 * loc = location for error messages
2257 * sc = context
2258 * Return:
2259 * null if error, else RootObject AST as parsed
2260 */
compileTypeMixin(TypeMixin tm,Loc loc,Scope * sc)2261 RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
2262 {
2263 OutBuffer buf;
2264 if (expressionsToString(buf, sc, tm.exps))
2265 return null;
2266
2267 const errors = global.errors;
2268 const len = buf.length;
2269 buf.writeByte(0);
2270 const str = buf.extractSlice()[0 .. len];
2271 scope p = new Parser!ASTCodegen(loc, sc._module, str, false);
2272 p.nextToken();
2273 //printf("p.loc.linnum = %d\n", p.loc.linnum);
2274
2275 auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
2276 if (errors != global.errors)
2277 {
2278 assert(global.errors != errors); // should have caught all these cases
2279 return null;
2280 }
2281 if (p.token.value != TOK.endOfFile)
2282 {
2283 .error(loc, "incomplete mixin type `%s`", str.ptr);
2284 return null;
2285 }
2286
2287 return o;
2288 }
2289
2290
2291 /************************************
2292 * If an identical type to `type` is in `type.stringtable`, return
2293 * the latter one. Otherwise, add it to `type.stringtable`.
2294 * Some types don't get merged and are returned as-is.
2295 * Params:
2296 * type = Type to check against existing types
2297 * Returns:
2298 * the type that was merged
2299 */
merge(Type type)2300 extern (C++) Type merge(Type type)
2301 {
2302 switch (type.ty)
2303 {
2304 case Terror:
2305 case Ttypeof:
2306 case Tident:
2307 case Tinstance:
2308 case Tmixin:
2309 case Ttag:
2310 return type; // don't merge placeholder types
2311
2312 case Tsarray:
2313 // prevents generating the mangle if the array dim is not yet known
2314 if (!type.isTypeSArray().dim.isIntegerExp())
2315 return type;
2316 goto default;
2317
2318 case Tenum:
2319 break;
2320
2321 case Taarray:
2322 if (!type.isTypeAArray().index.merge().deco)
2323 return type;
2324 goto default;
2325
2326 default:
2327 if (type.nextOf() && !type.nextOf().deco)
2328 return type;
2329 break;
2330 }
2331
2332 //printf("merge(%s)\n", toChars());
2333 if (!type.deco)
2334 {
2335 OutBuffer buf;
2336 buf.reserve(32);
2337
2338 mangleToBuffer(type, &buf);
2339
2340 auto sv = type.stringtable.update(buf[]);
2341 if (sv.value)
2342 {
2343 Type t = sv.value;
2344 debug
2345 {
2346 import core.stdc.stdio;
2347 if (!t.deco)
2348 printf("t = %s\n", t.toChars());
2349 }
2350 assert(t.deco);
2351 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2352 return t;
2353 }
2354 else
2355 {
2356 Type t = stripDefaultArgs(type);
2357 sv.value = t;
2358 type.deco = t.deco = cast(char*)sv.toDchars();
2359 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2360 return t;
2361 }
2362 }
2363 return type;
2364 }
2365
2366 /***************************************
2367 * Calculate built-in properties which just the type is necessary.
2368 *
2369 * Params:
2370 * t = the type for which the property is calculated
2371 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2372 * loc = the location where the property is encountered
2373 * ident = the identifier of the property
2374 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2375 * Returns:
2376 * expression representing the property, or null if not a property and (flag & 1)
2377 */
getProperty(Type t,Scope * scope_,const ref Loc loc,Identifier ident,int flag)2378 Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag)
2379 {
2380 Expression visitType(Type mt)
2381 {
2382 Expression e;
2383 static if (LOGDOTEXP)
2384 {
2385 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2386 }
2387 if (ident == Id.__sizeof)
2388 {
2389 const sz = mt.size(loc);
2390 if (sz == SIZE_INVALID)
2391 return ErrorExp.get();
2392 e = new IntegerExp(loc, sz, Type.tsize_t);
2393 }
2394 else if (ident == Id.__xalignof)
2395 {
2396 const explicitAlignment = mt.alignment();
2397 const naturalAlignment = mt.alignsize();
2398 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
2399 e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
2400 }
2401 else if (ident == Id._init)
2402 {
2403 Type tb = mt.toBasetype();
2404 e = mt.defaultInitLiteral(loc);
2405 if (tb.ty == Tstruct && tb.needsNested())
2406 {
2407 e.isStructLiteralExp().useStaticInit = true;
2408 }
2409 }
2410 else if (ident == Id._mangleof)
2411 {
2412 if (!mt.deco)
2413 {
2414 error(loc, "forward reference of type `%s.mangleof`", mt.toChars());
2415 e = ErrorExp.get();
2416 }
2417 else
2418 {
2419 e = new StringExp(loc, mt.deco.toDString());
2420 Scope sc;
2421 e = e.expressionSemantic(&sc);
2422 }
2423 }
2424 else if (ident == Id.stringof)
2425 {
2426 const s = mt.toChars();
2427 e = new StringExp(loc, s.toDString());
2428 Scope sc;
2429 e = e.expressionSemantic(&sc);
2430 }
2431 else if (flag && mt != Type.terror)
2432 {
2433 return null;
2434 }
2435 else
2436 {
2437 Dsymbol s = null;
2438 if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
2439 s = mt.toDsymbol(null);
2440 if (s)
2441 s = s.search_correct(ident);
2442 if (s && !symbolIsVisible(scope_, s))
2443 s = null;
2444 if (mt != Type.terror)
2445 {
2446 if (s)
2447 error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
2448 else if (ident == Id.call && mt.ty == Tclass)
2449 error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
2450
2451 else if (const n = importHint(ident.toString()))
2452 error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
2453 else
2454 {
2455 error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
2456 if (auto dsym = mt.toDsymbol(scope_))
2457 if (auto sym = dsym.isAggregateDeclaration())
2458 {
2459 if (auto fd = search_function(sym, Id.opDispatch))
2460 errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
2461 else if (!sym.members)
2462 errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
2463 }
2464 }
2465 }
2466 e = ErrorExp.get();
2467 }
2468 return e;
2469 }
2470
2471 Expression visitError(TypeError)
2472 {
2473 return ErrorExp.get();
2474 }
2475
2476 Expression visitBasic(TypeBasic mt)
2477 {
2478 Expression integerValue(dinteger_t i)
2479 {
2480 return new IntegerExp(loc, i, mt);
2481 }
2482
2483 Expression intValue(dinteger_t i)
2484 {
2485 return new IntegerExp(loc, i, Type.tint32);
2486 }
2487
2488 Expression floatValue(real_t r)
2489 {
2490 if (mt.isreal() || mt.isimaginary())
2491 return new RealExp(loc, r, mt);
2492 else
2493 {
2494 return new ComplexExp(loc, complex_t(r, r), mt);
2495 }
2496 }
2497
2498 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
2499 if (ident == Id.max)
2500 {
2501 switch (mt.ty)
2502 {
2503 case Tint8: return integerValue(byte.max);
2504 case Tuns8: return integerValue(ubyte.max);
2505 case Tint16: return integerValue(short.max);
2506 case Tuns16: return integerValue(ushort.max);
2507 case Tint32: return integerValue(int.max);
2508 case Tuns32: return integerValue(uint.max);
2509 case Tint64: return integerValue(long.max);
2510 case Tuns64: return integerValue(ulong.max);
2511 case Tbool: return integerValue(bool.max);
2512 case Tchar: return integerValue(char.max);
2513 case Twchar: return integerValue(wchar.max);
2514 case Tdchar: return integerValue(dchar.max);
2515 case Tcomplex32:
2516 case Timaginary32:
2517 case Tfloat32: return floatValue(target.FloatProperties.max);
2518 case Tcomplex64:
2519 case Timaginary64:
2520 case Tfloat64: return floatValue(target.DoubleProperties.max);
2521 case Tcomplex80:
2522 case Timaginary80:
2523 case Tfloat80: return floatValue(target.RealProperties.max);
2524 default: break;
2525 }
2526 }
2527 else if (ident == Id.min)
2528 {
2529 switch (mt.ty)
2530 {
2531 case Tint8: return integerValue(byte.min);
2532 case Tuns8:
2533 case Tuns16:
2534 case Tuns32:
2535 case Tuns64:
2536 case Tbool:
2537 case Tchar:
2538 case Twchar:
2539 case Tdchar: return integerValue(0);
2540 case Tint16: return integerValue(short.min);
2541 case Tint32: return integerValue(int.min);
2542 case Tint64: return integerValue(long.min);
2543 default: break;
2544 }
2545 }
2546 else if (ident == Id.min_normal)
2547 {
2548 switch (mt.ty)
2549 {
2550 case Tcomplex32:
2551 case Timaginary32:
2552 case Tfloat32: return floatValue(target.FloatProperties.min_normal);
2553 case Tcomplex64:
2554 case Timaginary64:
2555 case Tfloat64: return floatValue(target.DoubleProperties.min_normal);
2556 case Tcomplex80:
2557 case Timaginary80:
2558 case Tfloat80: return floatValue(target.RealProperties.min_normal);
2559 default: break;
2560 }
2561 }
2562 else if (ident == Id.nan)
2563 {
2564 switch (mt.ty)
2565 {
2566 case Tcomplex32:
2567 case Tcomplex64:
2568 case Tcomplex80:
2569 case Timaginary32:
2570 case Timaginary64:
2571 case Timaginary80:
2572 case Tfloat32:
2573 case Tfloat64:
2574 case Tfloat80: return floatValue(target.RealProperties.nan);
2575 default: break;
2576 }
2577 }
2578 else if (ident == Id.infinity)
2579 {
2580 switch (mt.ty)
2581 {
2582 case Tcomplex32:
2583 case Tcomplex64:
2584 case Tcomplex80:
2585 case Timaginary32:
2586 case Timaginary64:
2587 case Timaginary80:
2588 case Tfloat32:
2589 case Tfloat64:
2590 case Tfloat80: return floatValue(target.RealProperties.infinity);
2591 default: break;
2592 }
2593 }
2594 else if (ident == Id.dig)
2595 {
2596 switch (mt.ty)
2597 {
2598 case Tcomplex32:
2599 case Timaginary32:
2600 case Tfloat32: return intValue(target.FloatProperties.dig);
2601 case Tcomplex64:
2602 case Timaginary64:
2603 case Tfloat64: return intValue(target.DoubleProperties.dig);
2604 case Tcomplex80:
2605 case Timaginary80:
2606 case Tfloat80: return intValue(target.RealProperties.dig);
2607 default: break;
2608 }
2609 }
2610 else if (ident == Id.epsilon)
2611 {
2612 switch (mt.ty)
2613 {
2614 case Tcomplex32:
2615 case Timaginary32:
2616 case Tfloat32: return floatValue(target.FloatProperties.epsilon);
2617 case Tcomplex64:
2618 case Timaginary64:
2619 case Tfloat64: return floatValue(target.DoubleProperties.epsilon);
2620 case Tcomplex80:
2621 case Timaginary80:
2622 case Tfloat80: return floatValue(target.RealProperties.epsilon);
2623 default: break;
2624 }
2625 }
2626 else if (ident == Id.mant_dig)
2627 {
2628 switch (mt.ty)
2629 {
2630 case Tcomplex32:
2631 case Timaginary32:
2632 case Tfloat32: return intValue(target.FloatProperties.mant_dig);
2633 case Tcomplex64:
2634 case Timaginary64:
2635 case Tfloat64: return intValue(target.DoubleProperties.mant_dig);
2636 case Tcomplex80:
2637 case Timaginary80:
2638 case Tfloat80: return intValue(target.RealProperties.mant_dig);
2639 default: break;
2640 }
2641 }
2642 else if (ident == Id.max_10_exp)
2643 {
2644 switch (mt.ty)
2645 {
2646 case Tcomplex32:
2647 case Timaginary32:
2648 case Tfloat32: return intValue(target.FloatProperties.max_10_exp);
2649 case Tcomplex64:
2650 case Timaginary64:
2651 case Tfloat64: return intValue(target.DoubleProperties.max_10_exp);
2652 case Tcomplex80:
2653 case Timaginary80:
2654 case Tfloat80: return intValue(target.RealProperties.max_10_exp);
2655 default: break;
2656 }
2657 }
2658 else if (ident == Id.max_exp)
2659 {
2660 switch (mt.ty)
2661 {
2662 case Tcomplex32:
2663 case Timaginary32:
2664 case Tfloat32: return intValue(target.FloatProperties.max_exp);
2665 case Tcomplex64:
2666 case Timaginary64:
2667 case Tfloat64: return intValue(target.DoubleProperties.max_exp);
2668 case Tcomplex80:
2669 case Timaginary80:
2670 case Tfloat80: return intValue(target.RealProperties.max_exp);
2671 default: break;
2672 }
2673 }
2674 else if (ident == Id.min_10_exp)
2675 {
2676 switch (mt.ty)
2677 {
2678 case Tcomplex32:
2679 case Timaginary32:
2680 case Tfloat32: return intValue(target.FloatProperties.min_10_exp);
2681 case Tcomplex64:
2682 case Timaginary64:
2683 case Tfloat64: return intValue(target.DoubleProperties.min_10_exp);
2684 case Tcomplex80:
2685 case Timaginary80:
2686 case Tfloat80: return intValue(target.RealProperties.min_10_exp);
2687 default: break;
2688 }
2689 }
2690 else if (ident == Id.min_exp)
2691 {
2692 switch (mt.ty)
2693 {
2694 case Tcomplex32:
2695 case Timaginary32:
2696 case Tfloat32: return intValue(target.FloatProperties.min_exp);
2697 case Tcomplex64:
2698 case Timaginary64:
2699 case Tfloat64: return intValue(target.DoubleProperties.min_exp);
2700 case Tcomplex80:
2701 case Timaginary80:
2702 case Tfloat80: return intValue(target.RealProperties.min_exp);
2703 default: break;
2704 }
2705 }
2706 return visitType(mt);
2707 }
2708
2709 Expression visitVector(TypeVector mt)
2710 {
2711 return visitType(mt);
2712 }
2713
2714 Expression visitEnum(TypeEnum mt)
2715 {
2716 Expression e;
2717 if (ident == Id.max || ident == Id.min)
2718 {
2719 return mt.sym.getMaxMinValue(loc, ident);
2720 }
2721 else if (ident == Id._init)
2722 {
2723 e = mt.defaultInitLiteral(loc);
2724 }
2725 else if (ident == Id.stringof)
2726 {
2727 e = new StringExp(loc, mt.toString());
2728 Scope sc;
2729 e = e.expressionSemantic(&sc);
2730 }
2731 else if (ident == Id._mangleof)
2732 {
2733 e = visitType(mt);
2734 }
2735 else
2736 {
2737 e = mt.toBasetype().getProperty(scope_, loc, ident, flag);
2738 }
2739 return e;
2740 }
2741
2742 Expression visitTuple(TypeTuple mt)
2743 {
2744 Expression e;
2745 static if (LOGDOTEXP)
2746 {
2747 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2748 }
2749 if (ident == Id.length)
2750 {
2751 e = new IntegerExp(loc, mt.arguments.dim, Type.tsize_t);
2752 }
2753 else if (ident == Id._init)
2754 {
2755 e = mt.defaultInitLiteral(loc);
2756 }
2757 else if (flag)
2758 {
2759 e = null;
2760 }
2761 else
2762 {
2763 error(loc, "no property `%s` for tuple `%s`", ident.toChars(), mt.toChars());
2764 e = ErrorExp.get();
2765 }
2766 return e;
2767 }
2768
2769 switch (t.ty)
2770 {
2771 default: return t.isTypeBasic() ?
2772 visitBasic(cast(TypeBasic)t) :
2773 visitType(t);
2774
2775 case Terror: return visitError (t.isTypeError());
2776 case Tvector: return visitVector(t.isTypeVector());
2777 case Tenum: return visitEnum (t.isTypeEnum());
2778 case Ttuple: return visitTuple (t.isTypeTuple());
2779 }
2780 }
2781
2782 /***************************************
2783 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
2784 * Params:
2785 * exp = Expression to look at
2786 * t = if exp should be a Type, set t to that Type else null
2787 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
2788 * e = if exp should remain an Expression, set e to that Expression else null
2789 *
2790 */
resolveExp(Expression exp,out Type t,out Expression e,out Dsymbol s)2791 private void resolveExp(Expression exp, out Type t, out Expression e, out Dsymbol s)
2792 {
2793 if (exp.isTypeExp())
2794 t = exp.type;
2795 else if (auto ve = exp.isVarExp())
2796 {
2797 if (auto v = ve.var.isVarDeclaration())
2798 e = exp;
2799 else
2800 s = ve.var;
2801 }
2802 else if (auto te = exp.isTemplateExp())
2803 s = te.td;
2804 else if (auto se = exp.isScopeExp())
2805 s = se.sds;
2806 else if (exp.isFuncExp())
2807 s = getDsymbol(exp);
2808 else if (auto dte = exp.isDotTemplateExp())
2809 s = dte.td;
2810 else if (exp.isErrorExp())
2811 t = Type.terror;
2812 else
2813 e = exp;
2814 }
2815
2816 /************************************
2817 * Resolve type 'mt' to either type, symbol, or expression.
2818 * If errors happened, resolved to Type.terror.
2819 *
2820 * Params:
2821 * mt = type to be resolved
2822 * loc = the location where the type is encountered
2823 * sc = the scope of the type
2824 * pe = is set if t is an expression
2825 * pt = is set if t is a type
2826 * ps = is set if t is a symbol
2827 * intypeid = true if in type id
2828 */
2829 void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
2830 {
returnExp(Expression e)2831 void returnExp(Expression e)
2832 {
2833 pe = e;
2834 pt = null;
2835 ps = null;
2836 }
2837
returnType(Type t)2838 void returnType(Type t)
2839 {
2840 pe = null;
2841 pt = t;
2842 ps = null;
2843 }
2844
returnSymbol(Dsymbol s)2845 void returnSymbol(Dsymbol s)
2846 {
2847 pe = null;
2848 pt = null;
2849 ps = s;
2850 }
2851
returnError()2852 void returnError()
2853 {
2854 returnType(Type.terror);
2855 }
2856
visitType(Type mt)2857 void visitType(Type mt)
2858 {
2859 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
2860 Type t = typeSemantic(mt, loc, sc);
2861 assert(t);
2862 returnType(t);
2863 }
2864
visitSArray(TypeSArray mt)2865 void visitSArray(TypeSArray mt)
2866 {
2867 //printf("TypeSArray::resolve() %s\n", mt.toChars());
2868 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2869 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2870 if (pe)
2871 {
2872 // It's really an index expression
2873 if (Dsymbol s = getDsymbol(pe))
2874 pe = new DsymbolExp(loc, s);
2875 returnExp(new ArrayExp(loc, pe, mt.dim));
2876 }
2877 else if (ps)
2878 {
2879 Dsymbol s = ps;
2880 if (auto tup = s.isTupleDeclaration())
2881 {
2882 mt.dim = semanticLength(sc, tup, mt.dim);
2883 mt.dim = mt.dim.ctfeInterpret();
2884 if (mt.dim.op == EXP.error)
2885 return returnError();
2886
2887 const d = mt.dim.toUInteger();
2888 if (d >= tup.objects.dim)
2889 {
2890 error(loc, "tuple index `%llu` exceeds length %llu", d, cast(ulong) tup.objects.dim);
2891 return returnError();
2892 }
2893
2894 RootObject o = (*tup.objects)[cast(size_t)d];
2895 if (o.dyncast() == DYNCAST.dsymbol)
2896 {
2897 return returnSymbol(cast(Dsymbol)o);
2898 }
2899 if (o.dyncast() == DYNCAST.expression)
2900 {
2901 Expression e = cast(Expression)o;
2902 if (e.op == EXP.dSymbol)
2903 return returnSymbol(e.isDsymbolExp().s);
2904 else
2905 return returnExp(e);
2906 }
2907 if (o.dyncast() == DYNCAST.type)
2908 {
2909 return returnType((cast(Type)o).addMod(mt.mod));
2910 }
2911
2912 /* Create a new TupleDeclaration which
2913 * is a slice [d..d+1] out of the old one.
2914 * Do it this way because TemplateInstance::semanticTiargs()
2915 * can handle unresolved Objects this way.
2916 */
2917 auto objects = new Objects(1);
2918 (*objects)[0] = o;
2919 return returnSymbol(new TupleDeclaration(loc, tup.ident, objects));
2920 }
2921 else
2922 return visitType(mt);
2923 }
2924 else
2925 {
2926 if (pt.ty != Terror)
2927 mt.next = pt; // prevent re-running semantic() on 'next'
2928 visitType(mt);
2929 }
2930
2931 }
2932
visitDArray(TypeDArray mt)2933 void visitDArray(TypeDArray mt)
2934 {
2935 //printf("TypeDArray::resolve() %s\n", mt.toChars());
2936 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2937 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2938 if (pe)
2939 {
2940 // It's really a slice expression
2941 if (Dsymbol s = getDsymbol(pe))
2942 pe = new DsymbolExp(loc, s);
2943 returnExp(new ArrayExp(loc, pe));
2944 }
2945 else if (ps)
2946 {
2947 if (auto tup = ps.isTupleDeclaration())
2948 {
2949 // keep ps
2950 }
2951 else
2952 visitType(mt);
2953 }
2954 else
2955 {
2956 if (pt.ty != Terror)
2957 mt.next = pt; // prevent re-running semantic() on 'next'
2958 visitType(mt);
2959 }
2960 }
2961
visitAArray(TypeAArray mt)2962 void visitAArray(TypeAArray mt)
2963 {
2964 //printf("TypeAArray::resolve() %s\n", mt.toChars());
2965 // Deal with the case where we thought the index was a type, but
2966 // in reality it was an expression.
2967 if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray)
2968 {
2969 Expression e;
2970 Type t;
2971 Dsymbol s;
2972 mt.index.resolve(loc, sc, e, t, s, intypeid);
2973 if (e)
2974 {
2975 // It was an expression -
2976 // Rewrite as a static array
2977 auto tsa = new TypeSArray(mt.next, e);
2978 tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done
2979 return tsa.resolve(loc, sc, pe, pt, ps, intypeid);
2980 }
2981 else if (t)
2982 mt.index = t;
2983 else
2984 .error(loc, "index is not a type or an expression");
2985 }
2986 visitType(mt);
2987 }
2988
2989 /*************************************
2990 * Takes an array of Identifiers and figures out if
2991 * it represents a Type or an Expression.
2992 * Output:
2993 * if expression, pe is set
2994 * if type, pt is set
2995 */
visitIdentifier(TypeIdentifier mt)2996 void visitIdentifier(TypeIdentifier mt)
2997 {
2998 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2999 if (mt.ident == Id.ctfe)
3000 {
3001 error(loc, "variable `__ctfe` cannot be read at compile time");
3002 return returnError();
3003 }
3004 if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h
3005 {
3006 /* Since we don't support __builtin_va_start, -arg, -end, we don't
3007 * have to actually care what -list is. A void* will do.
3008 * If we ever do care, import core.stdc.stdarg and pull
3009 * the definition out of that, similarly to how std.math is handled for PowExp
3010 */
3011 pt = target.va_listType(loc, sc);
3012 return;
3013 }
3014
3015 Dsymbol scopesym;
3016 Dsymbol s = sc.search(loc, mt.ident, &scopesym);
3017 /*
3018 * https://issues.dlang.org/show_bug.cgi?id=1170
3019 * https://issues.dlang.org/show_bug.cgi?id=10739
3020 *
3021 * If a symbol is not found, it might be declared in
3022 * a mixin-ed string or a mixin-ed template, so before
3023 * issuing an error semantically analyze all string/template
3024 * mixins that are members of the current ScopeDsymbol.
3025 */
3026 if (!s && sc.enclosing)
3027 {
3028 ScopeDsymbol sds = sc.enclosing.scopesym;
3029 if (sds && sds.members)
3030 {
3031 void semanticOnMixin(Dsymbol member)
3032 {
3033 if (auto compileDecl = member.isCompileDeclaration())
3034 compileDecl.dsymbolSemantic(sc);
3035 else if (auto mixinTempl = member.isTemplateMixin())
3036 mixinTempl.dsymbolSemantic(sc);
3037 }
3038 sds.members.foreachDsymbol( s => semanticOnMixin(s) );
3039 s = sc.search(loc, mt.ident, &scopesym);
3040 }
3041 }
3042
3043 if (s)
3044 {
3045 // https://issues.dlang.org/show_bug.cgi?id=16042
3046 // If `f` is really a function template, then replace `f`
3047 // with the function template declaration.
3048 if (auto f = s.isFuncDeclaration())
3049 {
3050 if (auto td = getFuncTemplateDecl(f))
3051 {
3052 // If not at the beginning of the overloaded list of
3053 // `TemplateDeclaration`s, then get the beginning
3054 if (td.overroot)
3055 td = td.overroot;
3056 s = td;
3057 }
3058 }
3059 }
3060
3061 mt.resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
3062 if (pt)
3063 pt = pt.addMod(mt.mod);
3064 }
3065
visitInstance(TypeInstance mt)3066 void visitInstance(TypeInstance mt)
3067 {
3068 // Note close similarity to TypeIdentifier::resolve()
3069
3070 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
3071 mt.tempinst.dsymbolSemantic(sc);
3072 if (!global.gag && mt.tempinst.errors)
3073 return returnError();
3074
3075 mt.resolveHelper(loc, sc, mt.tempinst, null, pe, pt, ps, intypeid);
3076 if (pt)
3077 pt = pt.addMod(mt.mod);
3078 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
3079 }
3080
visitTypeof(TypeTypeof mt)3081 void visitTypeof(TypeTypeof mt)
3082 {
3083 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
3084 //static int nest; if (++nest == 50) *(char*)0=0;
3085 if (sc is null)
3086 {
3087 error(loc, "invalid scope");
3088 return returnError();
3089 }
3090 if (mt.inuse)
3091 {
3092 mt.inuse = 2;
3093 error(loc, "circular `typeof` definition");
3094 Lerr:
3095 mt.inuse--;
3096 return returnError();
3097 }
3098 mt.inuse++;
3099
3100 /* Currently we cannot evaluate 'exp' in speculative context, because
3101 * the type implementation may leak to the final execution. Consider:
3102 *
3103 * struct S(T) {
3104 * string toString() const { return "x"; }
3105 * }
3106 * void main() {
3107 * alias X = typeof(S!int());
3108 * assert(typeid(X).toString() == "x");
3109 * }
3110 */
3111 Scope* sc2 = sc.push();
3112
3113 if (!mt.exp.isTypeidExp())
3114 /* Treat typeof(typeid(exp)) as needing
3115 * the full semantic analysis of the typeid.
3116 * https://issues.dlang.org/show_bug.cgi?id=20958
3117 */
3118 sc2.intypeof = 1;
3119
3120 auto exp2 = mt.exp.expressionSemantic(sc2);
3121 exp2 = resolvePropertiesOnly(sc2, exp2);
3122 sc2.pop();
3123
3124 if (exp2.op == EXP.error)
3125 {
3126 if (!global.gag)
3127 mt.exp = exp2;
3128 goto Lerr;
3129 }
3130 mt.exp = exp2;
3131
3132 if (mt.exp.op == EXP.type ||
3133 mt.exp.op == EXP.scope_)
3134 {
3135 if (mt.exp.checkType())
3136 goto Lerr;
3137
3138 /* Today, 'typeof(func)' returns void if func is a
3139 * function template (TemplateExp), or
3140 * template lambda (FuncExp).
3141 * It's actually used in Phobos as an idiom, to branch code for
3142 * template functions.
3143 */
3144 }
3145 if (auto f = mt.exp.op == EXP.variable ? mt.exp.isVarExp().var.isFuncDeclaration()
3146 : mt.exp.op == EXP.dotVariable ? mt.exp.isDotVarExp().var.isFuncDeclaration() : null)
3147 {
3148 // f might be a unittest declaration which is incomplete when compiled
3149 // without -unittest. That causes a segfault in checkForwardRef, see
3150 // https://issues.dlang.org/show_bug.cgi?id=20626
3151 if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && f.checkForwardRef(loc))
3152 goto Lerr;
3153 }
3154 if (auto f = isFuncAddress(mt.exp))
3155 {
3156 if (f.checkForwardRef(loc))
3157 goto Lerr;
3158 }
3159
3160 Type t = mt.exp.type;
3161 if (!t)
3162 {
3163 error(loc, "expression `%s` has no type", mt.exp.toChars());
3164 goto Lerr;
3165 }
3166 if (t.ty == Ttypeof)
3167 {
3168 error(loc, "forward reference to `%s`", mt.toChars());
3169 goto Lerr;
3170 }
3171 if (mt.idents.dim == 0)
3172 {
3173 returnType(t.addMod(mt.mod));
3174 }
3175 else
3176 {
3177 if (Dsymbol s = t.toDsymbol(sc))
3178 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
3179 else
3180 {
3181 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
3182 e = e.expressionSemantic(sc);
3183 resolveExp(e, pt, pe, ps);
3184 }
3185 if (pt)
3186 pt = pt.addMod(mt.mod);
3187 }
3188 mt.inuse--;
3189 }
3190
visitReturn(TypeReturn mt)3191 void visitReturn(TypeReturn mt)
3192 {
3193 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3194 Type t;
3195 {
3196 FuncDeclaration func = sc.func;
3197 if (!func)
3198 {
3199 error(loc, "`typeof(return)` must be inside function");
3200 return returnError();
3201 }
3202 if (func.fes)
3203 func = func.fes.func;
3204 t = func.type.nextOf();
3205 if (!t)
3206 {
3207 error(loc, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc.func.toChars());
3208 return returnError();
3209 }
3210 }
3211 if (mt.idents.dim == 0)
3212 {
3213 return returnType(t.addMod(mt.mod));
3214 }
3215 else
3216 {
3217 if (Dsymbol s = t.toDsymbol(sc))
3218 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
3219 else
3220 {
3221 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
3222 e = e.expressionSemantic(sc);
3223 resolveExp(e, pt, pe, ps);
3224 }
3225 if (pt)
3226 pt = pt.addMod(mt.mod);
3227 }
3228 }
3229
visitSlice(TypeSlice mt)3230 void visitSlice(TypeSlice mt)
3231 {
3232 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
3233 if (pe)
3234 {
3235 // It's really a slice expression
3236 if (Dsymbol s = getDsymbol(pe))
3237 pe = new DsymbolExp(loc, s);
3238 return returnExp(new ArrayExp(loc, pe, new IntervalExp(loc, mt.lwr, mt.upr)));
3239 }
3240 else if (ps)
3241 {
3242 Dsymbol s = ps;
3243 TupleDeclaration td = s.isTupleDeclaration();
3244 if (td)
3245 {
3246 /* It's a slice of a TupleDeclaration
3247 */
3248 ScopeDsymbol sym = new ArrayScopeSymbol(sc, td);
3249 sym.parent = sc.scopesym;
3250 sc = sc.push(sym);
3251 sc = sc.startCTFE();
3252 mt.lwr = mt.lwr.expressionSemantic(sc);
3253 mt.upr = mt.upr.expressionSemantic(sc);
3254 sc = sc.endCTFE();
3255 sc = sc.pop();
3256
3257 mt.lwr = mt.lwr.ctfeInterpret();
3258 mt.upr = mt.upr.ctfeInterpret();
3259 const i1 = mt.lwr.toUInteger();
3260 const i2 = mt.upr.toUInteger();
3261 if (!(i1 <= i2 && i2 <= td.objects.dim))
3262 {
3263 error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1, i2, cast(ulong) td.objects.dim);
3264 return returnError();
3265 }
3266
3267 if (i1 == 0 && i2 == td.objects.dim)
3268 {
3269 return returnSymbol(td);
3270 }
3271
3272 /* Create a new TupleDeclaration which
3273 * is a slice [i1..i2] out of the old one.
3274 */
3275 auto objects = new Objects(cast(size_t)(i2 - i1));
3276 for (size_t i = 0; i < objects.dim; i++)
3277 {
3278 (*objects)[i] = (*td.objects)[cast(size_t)i1 + i];
3279 }
3280
3281 return returnSymbol(new TupleDeclaration(loc, td.ident, objects));
3282 }
3283 else
3284 visitType(mt);
3285 }
3286 else
3287 {
3288 if (pt.ty != Terror)
3289 mt.next = pt; // prevent re-running semantic() on 'next'
3290 visitType(mt);
3291 }
3292 }
3293
visitMixin(TypeMixin mt)3294 void visitMixin(TypeMixin mt)
3295 {
3296 RootObject o = mt.obj;
3297
3298 // if already resolved just set pe/pt/ps and return.
3299 if (o)
3300 {
3301 pe = o.isExpression();
3302 pt = o.isType();
3303 ps = o.isDsymbol();
3304 return;
3305 }
3306
3307 o = mt.compileTypeMixin(loc, sc);
3308 if (auto t = o.isType())
3309 {
3310 resolve(t, loc, sc, pe, pt, ps, intypeid);
3311 if (pt)
3312 pt = pt.addMod(mt.mod);
3313 }
3314 else if (auto e = o.isExpression())
3315 {
3316 e = e.expressionSemantic(sc);
3317 if (auto et = e.isTypeExp())
3318 returnType(et.type.addMod(mt.mod));
3319 else
3320 returnExp(e);
3321 }
3322 else
3323 returnError();
3324
3325 // save the result
3326 mt.obj = pe ? pe : (pt ? pt : ps);
3327 }
3328
visitTraits(TypeTraits tt)3329 void visitTraits(TypeTraits tt)
3330 {
3331 if (Type t = typeSemantic(tt, loc, sc))
3332 returnType(t);
3333 else if (tt.sym)
3334 returnSymbol(tt.sym);
3335 else
3336 return returnError();
3337 }
3338
3339 switch (mt.ty)
3340 {
3341 default: visitType (mt); break;
3342 case Tsarray: visitSArray (mt.isTypeSArray()); break;
3343 case Tarray: visitDArray (mt.isTypeDArray()); break;
3344 case Taarray: visitAArray (mt.isTypeAArray()); break;
3345 case Tident: visitIdentifier(mt.isTypeIdentifier()); break;
3346 case Tinstance: visitInstance (mt.isTypeInstance()); break;
3347 case Ttypeof: visitTypeof (mt.isTypeTypeof()); break;
3348 case Treturn: visitReturn (mt.isTypeReturn()); break;
3349 case Tslice: visitSlice (mt.isTypeSlice()); break;
3350 case Tmixin: visitMixin (mt.isTypeMixin()); break;
3351 case Ttraits: visitTraits (mt.isTypeTraits()); break;
3352 }
3353 }
3354
3355 /************************
3356 * Access the members of the object e. This type is same as e.type.
3357 * Params:
3358 * mt = type for which the dot expression is used
3359 * sc = instantiating scope
3360 * e = expression to convert
3361 * ident = identifier being used
3362 * flag = DotExpFlag bit flags
3363 *
3364 * Returns:
3365 * resulting expression with e.ident resolved
3366 */
dotExp(Type mt,Scope * sc,Expression e,Identifier ident,int flag)3367 Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
3368 {
3369 Expression visitType(Type mt)
3370 {
3371 VarDeclaration v = null;
3372 static if (LOGDOTEXP)
3373 {
3374 printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3375 }
3376 Expression ex = e.lastComma();
3377 if (ex.op == EXP.dotVariable)
3378 {
3379 DotVarExp dv = cast(DotVarExp)ex;
3380 v = dv.var.isVarDeclaration();
3381 }
3382 else if (ex.op == EXP.variable)
3383 {
3384 VarExp ve = cast(VarExp)ex;
3385 v = ve.var.isVarDeclaration();
3386 }
3387 if (v)
3388 {
3389 if (ident == Id.offsetof)
3390 {
3391 v.dsymbolSemantic(null);
3392 if (v.isField())
3393 {
3394 auto ad = v.toParent().isAggregateDeclaration();
3395 objc.checkOffsetof(e, ad);
3396 ad.size(e.loc);
3397 if (ad.sizeok != Sizeok.done)
3398 return ErrorExp.get();
3399 return new IntegerExp(e.loc, v.offset, Type.tsize_t);
3400 }
3401 }
3402 else if (ident == Id._init)
3403 {
3404 Type tb = mt.toBasetype();
3405 e = mt.defaultInitLiteral(e.loc);
3406 if (tb.ty == Tstruct && tb.needsNested())
3407 {
3408 e.isStructLiteralExp().useStaticInit = true;
3409 }
3410 goto Lreturn;
3411 }
3412 }
3413 if (ident == Id.stringof)
3414 {
3415 /* https://issues.dlang.org/show_bug.cgi?id=3796
3416 * this should demangle e.type.deco rather than
3417 * pretty-printing the type.
3418 */
3419 e = new StringExp(e.loc, e.toString());
3420 }
3421 else
3422 e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag);
3423
3424 Lreturn:
3425 if (e)
3426 e = e.expressionSemantic(sc);
3427 return e;
3428 }
3429
3430 Expression visitError(TypeError)
3431 {
3432 return ErrorExp.get();
3433 }
3434
3435 Expression visitBasic(TypeBasic mt)
3436 {
3437 static if (LOGDOTEXP)
3438 {
3439 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3440 }
3441 Type t;
3442 if (ident == Id.re)
3443 {
3444 switch (mt.ty)
3445 {
3446 case Tcomplex32:
3447 t = mt.tfloat32;
3448 goto L1;
3449
3450 case Tcomplex64:
3451 t = mt.tfloat64;
3452 goto L1;
3453
3454 case Tcomplex80:
3455 t = mt.tfloat80;
3456 goto L1;
3457 L1:
3458 e = e.castTo(sc, t);
3459 break;
3460
3461 case Tfloat32:
3462 case Tfloat64:
3463 case Tfloat80:
3464 break;
3465
3466 case Timaginary32:
3467 t = mt.tfloat32;
3468 goto L2;
3469
3470 case Timaginary64:
3471 t = mt.tfloat64;
3472 goto L2;
3473
3474 case Timaginary80:
3475 t = mt.tfloat80;
3476 goto L2;
3477 L2:
3478 e = new RealExp(e.loc, CTFloat.zero, t);
3479 break;
3480
3481 default:
3482 e = mt.Type.getProperty(sc, e.loc, ident, flag);
3483 break;
3484 }
3485 }
3486 else if (ident == Id.im)
3487 {
3488 Type t2;
3489 switch (mt.ty)
3490 {
3491 case Tcomplex32:
3492 t = mt.timaginary32;
3493 t2 = mt.tfloat32;
3494 goto L3;
3495
3496 case Tcomplex64:
3497 t = mt.timaginary64;
3498 t2 = mt.tfloat64;
3499 goto L3;
3500
3501 case Tcomplex80:
3502 t = mt.timaginary80;
3503 t2 = mt.tfloat80;
3504 goto L3;
3505 L3:
3506 e = e.castTo(sc, t);
3507 e.type = t2;
3508 break;
3509
3510 case Timaginary32:
3511 t = mt.tfloat32;
3512 goto L4;
3513
3514 case Timaginary64:
3515 t = mt.tfloat64;
3516 goto L4;
3517
3518 case Timaginary80:
3519 t = mt.tfloat80;
3520 goto L4;
3521 L4:
3522 e = e.copy();
3523 e.type = t;
3524 break;
3525
3526 case Tfloat32:
3527 case Tfloat64:
3528 case Tfloat80:
3529 e = new RealExp(e.loc, CTFloat.zero, mt);
3530 break;
3531
3532 default:
3533 e = mt.Type.getProperty(sc, e.loc, ident, flag);
3534 break;
3535 }
3536 }
3537 else
3538 {
3539 return visitType(mt);
3540 }
3541 if (!(flag & 1) || e)
3542 e = e.expressionSemantic(sc);
3543 return e;
3544 }
3545
3546 Expression visitVector(TypeVector mt)
3547 {
3548 static if (LOGDOTEXP)
3549 {
3550 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3551 }
3552 if (ident == Id.ptr && e.op == EXP.call)
3553 {
3554 /* The trouble with EXP.call is the return ABI for float[4] is different from
3555 * __vector(float[4]), and a type paint won't do.
3556 */
3557 e = new AddrExp(e.loc, e);
3558 e = e.expressionSemantic(sc);
3559 return e.castTo(sc, mt.basetype.nextOf().pointerTo());
3560 }
3561 if (ident == Id.array)
3562 {
3563 //e = e.castTo(sc, basetype);
3564 // Keep lvalue-ness
3565 e = new VectorArrayExp(e.loc, e);
3566 e = e.expressionSemantic(sc);
3567 return e;
3568 }
3569 if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof)
3570 {
3571 // init should return a new VectorExp
3572 // https://issues.dlang.org/show_bug.cgi?id=12776
3573 // offsetof does not work on a cast expression, so use e directly
3574 // stringof should not add a cast to the output
3575 return visitType(mt);
3576 }
3577
3578 // Properties based on the vector element type and are values of the element type
3579 if (ident == Id.max || ident == Id.min || ident == Id.min_normal ||
3580 ident == Id.nan || ident == Id.infinity || ident == Id.epsilon)
3581 {
3582 auto vet = mt.basetype.isTypeSArray().next; // vector element type
3583 if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag))
3584 return ev.castTo(sc, mt); // 'broadcast' ev to the vector elements
3585 }
3586
3587 return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag);
3588 }
3589
3590 Expression visitArray(TypeArray mt)
3591 {
3592 static if (LOGDOTEXP)
3593 {
3594 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3595 }
3596
3597 e = visitType(mt);
3598
3599 if (!(flag & 1) || e)
3600 e = e.expressionSemantic(sc);
3601 return e;
3602 }
3603
3604 Expression visitSArray(TypeSArray mt)
3605 {
3606 static if (LOGDOTEXP)
3607 {
3608 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3609 }
3610 if (ident == Id.length)
3611 {
3612 Loc oldLoc = e.loc;
3613 e = mt.dim.copy();
3614 e.loc = oldLoc;
3615 }
3616 else if (ident == Id.ptr)
3617 {
3618 if (e.op == EXP.type)
3619 {
3620 e.error("`%s` is not an expression", e.toChars());
3621 return ErrorExp.get();
3622 }
3623 else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
3624 {
3625 // .ptr on static array is @safe unless size is 0
3626 // https://issues.dlang.org/show_bug.cgi?id=20853
3627 return ErrorExp.get();
3628 }
3629 e = e.castTo(sc, e.type.nextOf().pointerTo());
3630 }
3631 else if (ident == Id._tupleof)
3632 {
3633 if (e.isTypeExp())
3634 {
3635 e.error("`.tupleof` cannot be used on type `%s`", mt.toChars);
3636 return ErrorExp.get();
3637 }
3638 else
3639 {
3640 Expression e0;
3641 Expression ev = e;
3642 ev = extractSideEffect(sc, "__tup", e0, ev);
3643
3644 const length = cast(size_t)mt.dim.toUInteger();
3645 auto exps = new Expressions();
3646 exps.reserve(length);
3647 foreach (i; 0 .. length)
3648 exps.push(new IndexExp(e.loc, ev, new IntegerExp(e.loc, i, Type.tsize_t)));
3649 e = new TupleExp(e.loc, e0, exps);
3650 }
3651 }
3652 else
3653 {
3654 e = visitArray(mt);
3655 }
3656 if (!(flag & 1) || e)
3657 e = e.expressionSemantic(sc);
3658 return e;
3659 }
3660
3661 Expression visitDArray(TypeDArray mt)
3662 {
3663 static if (LOGDOTEXP)
3664 {
3665 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3666 }
3667 if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
3668 {
3669 e.error("`%s` is not an expression", e.toChars());
3670 return ErrorExp.get();
3671 }
3672 if (ident == Id.length)
3673 {
3674 if (e.op == EXP.string_)
3675 {
3676 StringExp se = cast(StringExp)e;
3677 return new IntegerExp(se.loc, se.len, Type.tsize_t);
3678 }
3679 if (e.op == EXP.null_)
3680 {
3681 return new IntegerExp(e.loc, 0, Type.tsize_t);
3682 }
3683 if (checkNonAssignmentArrayOp(e))
3684 {
3685 return ErrorExp.get();
3686 }
3687 e = new ArrayLengthExp(e.loc, e);
3688 e.type = Type.tsize_t;
3689 return e;
3690 }
3691 else if (ident == Id.ptr)
3692 {
3693 if (checkUnsafeDotExp(sc, e, ident, flag))
3694 return ErrorExp.get();
3695 return e.castTo(sc, mt.next.pointerTo());
3696 }
3697 else
3698 {
3699 return visitArray(mt);
3700 }
3701 }
3702
3703 Expression visitAArray(TypeAArray mt)
3704 {
3705 static if (LOGDOTEXP)
3706 {
3707 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3708 }
3709 if (ident == Id.length)
3710 {
3711 __gshared FuncDeclaration fd_aaLen = null;
3712 if (fd_aaLen is null)
3713 {
3714 auto fparams = new Parameters();
3715 fparams.push(new Parameter(STC.const_ | STC.scope_, mt, null, null, null));
3716 fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen);
3717 TypeFunction tf = fd_aaLen.type.toTypeFunction();
3718 tf.purity = PURE.const_;
3719 tf.isnothrow = true;
3720 tf.isnogc = false;
3721 }
3722 Expression ev = new VarExp(e.loc, fd_aaLen, false);
3723 e = new CallExp(e.loc, ev, e);
3724 e.type = fd_aaLen.type.toTypeFunction().next;
3725 return e;
3726 }
3727 else
3728 {
3729 return visitType(mt);
3730 }
3731 }
3732
3733 Expression visitReference(TypeReference mt)
3734 {
3735 static if (LOGDOTEXP)
3736 {
3737 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3738 }
3739 // References just forward things along
3740 return mt.next.dotExp(sc, e, ident, flag);
3741 }
3742
3743 Expression visitDelegate(TypeDelegate mt)
3744 {
3745 static if (LOGDOTEXP)
3746 {
3747 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3748 }
3749 if (ident == Id.ptr)
3750 {
3751 e = new DelegatePtrExp(e.loc, e);
3752 e = e.expressionSemantic(sc);
3753 }
3754 else if (ident == Id.funcptr)
3755 {
3756 if (checkUnsafeDotExp(sc, e, ident, flag))
3757 {
3758 return ErrorExp.get();
3759 }
3760 e = new DelegateFuncptrExp(e.loc, e);
3761 e = e.expressionSemantic(sc);
3762 }
3763 else
3764 {
3765 return visitType(mt);
3766 }
3767 return e;
3768 }
3769
3770 /***************************************
3771 * `ident` was not found as a member of `mt`.
3772 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
3773 * If that fails, forward to visitType().
3774 * Params:
3775 * mt = class or struct
3776 * sc = context
3777 * e = `this` for `ident`
3778 * ident = name of member
3779 * flag = flag & 1, don't report "not a property" error and just return NULL.
3780 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
3781 * Returns:
3782 * resolved expression if found, otherwise null
3783 */
3784 Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
3785 {
3786 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
3787
3788 bool gagError = flag & 1;
3789
3790 __gshared int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
3791
3792 static Expression returnExp(Expression e)
3793 {
3794 --nest;
3795 return e;
3796 }
3797
3798 if (++nest > global.recursionLimit)
3799 {
3800 .error(e.loc, "cannot resolve identifier `%s`", ident.toChars());
3801 return returnExp(gagError ? null : ErrorExp.get());
3802 }
3803
3804
3805 assert(mt.ty == Tstruct || mt.ty == Tclass);
3806 auto sym = mt.toDsymbol(sc).isAggregateDeclaration();
3807 assert(sym);
3808 if (// https://issues.dlang.org/show_bug.cgi?id=22054
3809 // if a class or struct does not have a body
3810 // there is no point in searching for its members
3811 sym.members &&
3812 ident != Id.__sizeof &&
3813 ident != Id.__xalignof &&
3814 ident != Id._init &&
3815 ident != Id._mangleof &&
3816 ident != Id.stringof &&
3817 ident != Id.offsetof &&
3818 // https://issues.dlang.org/show_bug.cgi?id=15045
3819 // Don't forward special built-in member functions.
3820 ident != Id.ctor &&
3821 ident != Id.dtor &&
3822 ident != Id.__xdtor &&
3823 ident != Id.postblit &&
3824 ident != Id.__xpostblit)
3825 {
3826 /* Look for overloaded opDot() to see if we should forward request
3827 * to it.
3828 */
3829 if (auto fd = search_function(sym, Id.opDot))
3830 {
3831 /* Rewrite e.ident as:
3832 * e.opDot().ident
3833 */
3834 e = build_overload(e.loc, sc, e, null, fd);
3835 // @@@DEPRECATED_2.110@@@.
3836 // Deprecated in 2.082, made an error in 2.100.
3837 e.error("`opDot` is obsolete. Use `alias this`");
3838 return ErrorExp.get();
3839 }
3840
3841 /* Look for overloaded opDispatch to see if we should forward request
3842 * to it.
3843 */
3844 if (auto fd = search_function(sym, Id.opDispatch))
3845 {
3846 /* Rewrite e.ident as:
3847 * e.opDispatch!("ident")
3848 */
3849 TemplateDeclaration td = fd.isTemplateDeclaration();
3850 if (!td)
3851 {
3852 fd.error("must be a template `opDispatch(string s)`, not a %s", fd.kind());
3853 return returnExp(ErrorExp.get());
3854 }
3855 auto se = new StringExp(e.loc, ident.toString());
3856 auto tiargs = new Objects();
3857 tiargs.push(se);
3858 auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs);
3859 dti.ti.tempdecl = td;
3860 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
3861 * e.g.
3862 * template opDispatch(name) if (isValid!name) { ... }
3863 */
3864 uint errors = gagError ? global.startGagging() : 0;
3865 e = dti.semanticY(sc, 0);
3866 if (gagError && global.endGagging(errors))
3867 e = null;
3868 return returnExp(e);
3869 }
3870
3871 /* See if we should forward to the alias this.
3872 */
3873 auto alias_e = flag & DotExpFlag.noAliasThis ? null
3874 : resolveAliasThis(sc, e, gagError);
3875 if (alias_e && alias_e != e)
3876 {
3877 /* Rewrite e.ident as:
3878 * e.aliasthis.ident
3879 */
3880 auto die = new DotIdExp(e.loc, alias_e, ident);
3881
3882 auto errors = gagError ? 0 : global.startGagging();
3883 auto exp = die.semanticY(sc, gagError);
3884 if (!gagError)
3885 {
3886 global.endGagging(errors);
3887 if (exp && exp.op == EXP.error)
3888 exp = null;
3889 }
3890
3891 if (exp && gagError)
3892 // now that we know that the alias this leads somewhere useful,
3893 // go back and print deprecations/warnings that we skipped earlier due to the gag
3894 resolveAliasThis(sc, e, false);
3895
3896 return returnExp(exp);
3897 }
3898 }
3899 return returnExp(visitType(mt));
3900 }
3901
3902 Expression visitStruct(TypeStruct mt)
3903 {
3904 Dsymbol s;
3905 static if (LOGDOTEXP)
3906 {
3907 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3908 }
3909 assert(e.op != EXP.dot);
3910
3911 // https://issues.dlang.org/show_bug.cgi?id=14010
3912 if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
3913 {
3914 return mt.getProperty(sc, e.loc, ident, flag & 1);
3915 }
3916
3917 /* If e.tupleof
3918 */
3919 if (ident == Id._tupleof)
3920 {
3921 /* Create a TupleExp out of the fields of the struct e:
3922 * (e.field0, e.field1, e.field2, ...)
3923 */
3924 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
3925
3926 if (!mt.sym.determineFields())
3927 {
3928 error(e.loc, "unable to determine fields of `%s` because of forward references", mt.toChars());
3929 }
3930
3931 Expression e0;
3932 Expression ev = e.op == EXP.type ? null : e;
3933 if (ev)
3934 ev = extractSideEffect(sc, "__tup", e0, ev);
3935
3936 auto exps = new Expressions();
3937 exps.reserve(mt.sym.fields.dim);
3938 for (size_t i = 0; i < mt.sym.fields.dim; i++)
3939 {
3940 VarDeclaration v = mt.sym.fields[i];
3941 Expression ex;
3942 if (ev)
3943 ex = new DotVarExp(e.loc, ev, v);
3944 else
3945 {
3946 ex = new VarExp(e.loc, v);
3947 ex.type = ex.type.addMod(e.type.mod);
3948 }
3949 exps.push(ex);
3950 }
3951
3952 e = new TupleExp(e.loc, e0, exps);
3953 Scope* sc2 = sc.push();
3954 sc2.flags |= SCOPE.noaccesscheck;
3955 e = e.expressionSemantic(sc2);
3956 sc2.pop();
3957 return e;
3958 }
3959
3960 immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
3961 s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
3962 L1:
3963 if (!s)
3964 {
3965 return noMember(mt, sc, e, ident, flag);
3966 }
3967 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
3968 {
3969 return noMember(mt, sc, e, ident, flag);
3970 }
3971 s = s.toAlias();
3972
3973 if (auto em = s.isEnumMember())
3974 {
3975 return em.getVarExp(e.loc, sc);
3976 }
3977 if (auto v = s.isVarDeclaration())
3978 {
3979 v.checkDeprecated(e.loc, sc);
3980 v.checkDisabled(e.loc, sc);
3981 if (!v.type ||
3982 !v.type.deco && v.inuse)
3983 {
3984 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
3985 e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
3986 else
3987 e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
3988 return ErrorExp.get();
3989 }
3990 if (v.type.ty == Terror)
3991 {
3992 return ErrorExp.get();
3993 }
3994
3995 if ((v.storage_class & STC.manifest) && v._init)
3996 {
3997 if (v.inuse)
3998 {
3999 e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
4000 return ErrorExp.get();
4001 }
4002 checkAccess(e.loc, sc, null, v);
4003 Expression ve = new VarExp(e.loc, v);
4004 if (!isTrivialExp(e))
4005 {
4006 ve = new CommaExp(e.loc, e, ve);
4007 }
4008 return ve.expressionSemantic(sc);
4009 }
4010 }
4011
4012 if (auto t = s.getType())
4013 {
4014 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
4015 }
4016
4017 TemplateMixin tm = s.isTemplateMixin();
4018 if (tm)
4019 {
4020 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
4021 }
4022
4023 TemplateDeclaration td = s.isTemplateDeclaration();
4024 if (td)
4025 {
4026 if (e.op == EXP.type)
4027 e = new TemplateExp(e.loc, td);
4028 else
4029 e = new DotTemplateExp(e.loc, e, td);
4030 return e.expressionSemantic(sc);
4031 }
4032
4033 TemplateInstance ti = s.isTemplateInstance();
4034 if (ti)
4035 {
4036 if (!ti.semanticRun)
4037 {
4038 ti.dsymbolSemantic(sc);
4039 if (!ti.inst || ti.errors) // if template failed to expand
4040 {
4041 return ErrorExp.get();
4042 }
4043 }
4044 s = ti.inst.toAlias();
4045 if (!s.isTemplateInstance())
4046 goto L1;
4047 if (e.op == EXP.type)
4048 e = new ScopeExp(e.loc, ti);
4049 else
4050 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
4051 return e.expressionSemantic(sc);
4052 }
4053
4054 if (s.isImport() || s.isModule() || s.isPackage())
4055 {
4056 return symbolToExp(s, e.loc, sc, false);
4057 }
4058
4059 OverloadSet o = s.isOverloadSet();
4060 if (o)
4061 {
4062 auto oe = new OverExp(e.loc, o);
4063 if (e.op == EXP.type)
4064 {
4065 return oe;
4066 }
4067 return new DotExp(e.loc, e, oe);
4068 }
4069
4070 Declaration d = s.isDeclaration();
4071 if (!d)
4072 {
4073 e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars());
4074 return ErrorExp.get();
4075 }
4076
4077 if (e.op == EXP.type)
4078 {
4079 /* It's:
4080 * Struct.d
4081 */
4082 if (TupleDeclaration tup = d.isTupleDeclaration())
4083 {
4084 e = new TupleExp(e.loc, tup);
4085 return e.expressionSemantic(sc);
4086 }
4087 if (d.needThis() && sc.intypeof != 1)
4088 {
4089 /* Rewrite as:
4090 * this.d
4091 */
4092 if (hasThis(sc))
4093 {
4094 e = new DotVarExp(e.loc, new ThisExp(e.loc), d);
4095 return e.expressionSemantic(sc);
4096 }
4097 }
4098 if (d.semanticRun == PASS.initial)
4099 d.dsymbolSemantic(null);
4100 checkAccess(e.loc, sc, e, d);
4101 auto ve = new VarExp(e.loc, d);
4102 if (d.isVarDeclaration() && d.needThis())
4103 ve.type = d.type.addMod(e.type.mod);
4104 return ve;
4105 }
4106
4107 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
4108 if (d.isDataseg() || unreal && d.isField())
4109 {
4110 // (e, d)
4111 checkAccess(e.loc, sc, e, d);
4112 Expression ve = new VarExp(e.loc, d);
4113 e = unreal ? ve : new CommaExp(e.loc, e, ve);
4114 return e.expressionSemantic(sc);
4115 }
4116
4117 e = new DotVarExp(e.loc, e, d);
4118 return e.expressionSemantic(sc);
4119 }
4120
4121 Expression visitEnum(TypeEnum mt)
4122 {
4123 static if (LOGDOTEXP)
4124 {
4125 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), mt.toChars());
4126 }
4127 // https://issues.dlang.org/show_bug.cgi?id=14010
4128 if (ident == Id._mangleof)
4129 {
4130 return mt.getProperty(sc, e.loc, ident, flag & 1);
4131 }
4132
4133 if (mt.sym.semanticRun < PASS.semanticdone)
4134 mt.sym.dsymbolSemantic(null);
4135
4136 Dsymbol s = mt.sym.search(e.loc, ident);
4137 if (!s)
4138 {
4139 if (ident == Id.max || ident == Id.min || ident == Id._init)
4140 {
4141 return mt.getProperty(sc, e.loc, ident, flag & 1);
4142 }
4143
4144 Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, 1);
4145 if (!(flag & 1) && !res)
4146 {
4147 if (auto ns = mt.sym.search_correct(ident))
4148 e.error("no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
4149 ns.toChars());
4150 else
4151 e.error("no property `%s` for type `%s`", ident.toChars(),
4152 mt.toChars());
4153
4154 return ErrorExp.get();
4155 }
4156 return res;
4157 }
4158 EnumMember m = s.isEnumMember();
4159 return m.getVarExp(e.loc, sc);
4160 }
4161
4162 Expression visitClass(TypeClass mt)
4163 {
4164 Dsymbol s;
4165 static if (LOGDOTEXP)
4166 {
4167 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4168 }
4169 assert(e.op != EXP.dot);
4170
4171 // https://issues.dlang.org/show_bug.cgi?id=12543
4172 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
4173 {
4174 return mt.Type.getProperty(sc, e.loc, ident, 0);
4175 }
4176
4177 /* If e.tupleof
4178 */
4179 if (ident == Id._tupleof)
4180 {
4181 objc.checkTupleof(e, mt);
4182
4183 /* Create a TupleExp
4184 */
4185 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
4186
4187 mt.sym.size(e.loc); // do semantic of type
4188
4189 Expression e0;
4190 Expression ev = e.op == EXP.type ? null : e;
4191 if (ev)
4192 ev = extractSideEffect(sc, "__tup", e0, ev);
4193
4194 auto exps = new Expressions();
4195 exps.reserve(mt.sym.fields.dim);
4196 for (size_t i = 0; i < mt.sym.fields.dim; i++)
4197 {
4198 VarDeclaration v = mt.sym.fields[i];
4199 // Don't include hidden 'this' pointer
4200 if (v.isThisDeclaration())
4201 continue;
4202 Expression ex;
4203 if (ev)
4204 ex = new DotVarExp(e.loc, ev, v);
4205 else
4206 {
4207 ex = new VarExp(e.loc, v);
4208 ex.type = ex.type.addMod(e.type.mod);
4209 }
4210 exps.push(ex);
4211 }
4212
4213 e = new TupleExp(e.loc, e0, exps);
4214 Scope* sc2 = sc.push();
4215 sc2.flags |= SCOPE.noaccesscheck;
4216 e = e.expressionSemantic(sc2);
4217 sc2.pop();
4218 return e;
4219 }
4220
4221 int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
4222 s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
4223
4224 L1:
4225 if (!s)
4226 {
4227 // See if it's a 'this' class or a base class
4228 if (mt.sym.ident == ident)
4229 {
4230 if (e.op == EXP.type)
4231 {
4232 return mt.Type.getProperty(sc, e.loc, ident, 0);
4233 }
4234 e = new DotTypeExp(e.loc, e, mt.sym);
4235 e = e.expressionSemantic(sc);
4236 return e;
4237 }
4238 if (auto cbase = mt.sym.searchBase(ident))
4239 {
4240 if (e.op == EXP.type)
4241 {
4242 return mt.Type.getProperty(sc, e.loc, ident, 0);
4243 }
4244 if (auto ifbase = cbase.isInterfaceDeclaration())
4245 e = new CastExp(e.loc, e, ifbase.type);
4246 else
4247 e = new DotTypeExp(e.loc, e, cbase);
4248 e = e.expressionSemantic(sc);
4249 return e;
4250 }
4251
4252 if (ident == Id.classinfo)
4253 {
4254 if (!Type.typeinfoclass)
4255 {
4256 error(e.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4257 return ErrorExp.get();
4258 }
4259
4260 Type t = Type.typeinfoclass.type;
4261 if (e.op == EXP.type || e.op == EXP.dotType)
4262 {
4263 /* For type.classinfo, we know the classinfo
4264 * at compile time.
4265 */
4266 if (!mt.sym.vclassinfo)
4267 mt.sym.vclassinfo = new TypeInfoClassDeclaration(mt.sym.type);
4268 e = new VarExp(e.loc, mt.sym.vclassinfo);
4269 e = e.addressOf();
4270 e.type = t; // do this so we don't get redundant dereference
4271 }
4272 else
4273 {
4274 /* For class objects, the classinfo reference is the first
4275 * entry in the vtbl[]
4276 */
4277 e = new PtrExp(e.loc, e);
4278 e.type = t.pointerTo();
4279 if (mt.sym.isInterfaceDeclaration())
4280 {
4281 if (mt.sym.isCPPinterface())
4282 {
4283 /* C++ interface vtbl[]s are different in that the
4284 * first entry is always pointer to the first virtual
4285 * function, not classinfo.
4286 * We can't get a .classinfo for it.
4287 */
4288 error(e.loc, "no `.classinfo` for C++ interface objects");
4289 }
4290 /* For an interface, the first entry in the vtbl[]
4291 * is actually a pointer to an instance of struct Interface.
4292 * The first member of Interface is the .classinfo,
4293 * so add an extra pointer indirection.
4294 */
4295 e.type = e.type.pointerTo();
4296 e = new PtrExp(e.loc, e);
4297 e.type = t.pointerTo();
4298 }
4299 e = new PtrExp(e.loc, e, t);
4300 }
4301 return e;
4302 }
4303
4304 if (ident == Id.__vptr)
4305 {
4306 /* The pointer to the vtbl[]
4307 * *cast(immutable(void*)**)e
4308 */
4309 e = e.castTo(sc, mt.tvoidptr.immutableOf().pointerTo().pointerTo());
4310 e = new PtrExp(e.loc, e);
4311 e = e.expressionSemantic(sc);
4312 return e;
4313 }
4314
4315 if (ident == Id.__monitor && mt.sym.hasMonitor())
4316 {
4317 /* The handle to the monitor (call it a void*)
4318 * *(cast(void**)e + 1)
4319 */
4320 e = e.castTo(sc, mt.tvoidptr.pointerTo());
4321 e = new AddExp(e.loc, e, IntegerExp.literal!1);
4322 e = new PtrExp(e.loc, e);
4323 e = e.expressionSemantic(sc);
4324 return e;
4325 }
4326
4327 if (ident == Id.outer && mt.sym.vthis)
4328 {
4329 if (mt.sym.vthis.semanticRun == PASS.initial)
4330 mt.sym.vthis.dsymbolSemantic(null);
4331
4332 if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
4333 {
4334 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
4335 dve.type = cdp.type.addMod(e.type.mod);
4336 return dve;
4337 }
4338
4339 /* https://issues.dlang.org/show_bug.cgi?id=15839
4340 * Find closest parent class through nested functions.
4341 */
4342 for (auto p = mt.sym.toParentLocal(); p; p = p.toParentLocal())
4343 {
4344 auto fd = p.isFuncDeclaration();
4345 if (!fd)
4346 break;
4347 auto ad = fd.isThis();
4348 if (!ad && fd.isNested())
4349 continue;
4350 if (!ad)
4351 break;
4352 if (auto cdp = ad.isClassDeclaration())
4353 {
4354 auto ve = new ThisExp(e.loc);
4355
4356 ve.var = fd.vthis;
4357 const nestedError = fd.vthis.checkNestedReference(sc, e.loc);
4358 assert(!nestedError);
4359
4360 ve.type = cdp.type.addMod(fd.vthis.type.mod).addMod(e.type.mod);
4361 return ve;
4362 }
4363 break;
4364 }
4365
4366 // Continue to show enclosing function's frame (stack or closure).
4367 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
4368 dve.type = mt.sym.vthis.type.addMod(e.type.mod);
4369 return dve;
4370 }
4371
4372 return noMember(mt, sc, e, ident, flag & 1);
4373 }
4374 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
4375 {
4376 return noMember(mt, sc, e, ident, flag);
4377 }
4378 if (!s.isFuncDeclaration()) // because of overloading
4379 {
4380 s.checkDeprecated(e.loc, sc);
4381 if (auto d = s.isDeclaration())
4382 d.checkDisabled(e.loc, sc);
4383 }
4384 s = s.toAlias();
4385
4386 if (auto em = s.isEnumMember())
4387 {
4388 return em.getVarExp(e.loc, sc);
4389 }
4390 if (auto v = s.isVarDeclaration())
4391 {
4392 if (!v.type ||
4393 !v.type.deco && v.inuse)
4394 {
4395 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
4396 e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
4397 else
4398 e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
4399 return ErrorExp.get();
4400 }
4401 if (v.type.ty == Terror)
4402 {
4403 return ErrorExp.get();
4404 }
4405
4406 if ((v.storage_class & STC.manifest) && v._init)
4407 {
4408 if (v.inuse)
4409 {
4410 e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
4411 return ErrorExp.get();
4412 }
4413 checkAccess(e.loc, sc, null, v);
4414 Expression ve = new VarExp(e.loc, v);
4415 ve = ve.expressionSemantic(sc);
4416 return ve;
4417 }
4418 }
4419
4420 if (auto t = s.getType())
4421 {
4422 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
4423 }
4424
4425 TemplateMixin tm = s.isTemplateMixin();
4426 if (tm)
4427 {
4428 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
4429 }
4430
4431 TemplateDeclaration td = s.isTemplateDeclaration();
4432
4433 Expression toTemplateExp(TemplateDeclaration td)
4434 {
4435 if (e.op == EXP.type)
4436 e = new TemplateExp(e.loc, td);
4437 else
4438 e = new DotTemplateExp(e.loc, e, td);
4439 e = e.expressionSemantic(sc);
4440 return e;
4441 }
4442
4443 if (td)
4444 {
4445 return toTemplateExp(td);
4446 }
4447
4448 TemplateInstance ti = s.isTemplateInstance();
4449 if (ti)
4450 {
4451 if (!ti.semanticRun)
4452 {
4453 ti.dsymbolSemantic(sc);
4454 if (!ti.inst || ti.errors) // if template failed to expand
4455 {
4456 return ErrorExp.get();
4457 }
4458 }
4459 s = ti.inst.toAlias();
4460 if (!s.isTemplateInstance())
4461 goto L1;
4462 if (e.op == EXP.type)
4463 e = new ScopeExp(e.loc, ti);
4464 else
4465 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
4466 return e.expressionSemantic(sc);
4467 }
4468
4469 if (s.isImport() || s.isModule() || s.isPackage())
4470 {
4471 e = symbolToExp(s, e.loc, sc, false);
4472 return e;
4473 }
4474
4475 OverloadSet o = s.isOverloadSet();
4476 if (o)
4477 {
4478 auto oe = new OverExp(e.loc, o);
4479 if (e.op == EXP.type)
4480 {
4481 return oe;
4482 }
4483 return new DotExp(e.loc, e, oe);
4484 }
4485
4486 Declaration d = s.isDeclaration();
4487 if (!d)
4488 {
4489 e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars());
4490 return ErrorExp.get();
4491 }
4492
4493 if (e.op == EXP.type)
4494 {
4495 /* It's:
4496 * Class.d
4497 */
4498 if (TupleDeclaration tup = d.isTupleDeclaration())
4499 {
4500 e = new TupleExp(e.loc, tup);
4501 e = e.expressionSemantic(sc);
4502 return e;
4503 }
4504
4505 if (mt.sym.classKind == ClassKind.objc
4506 && d.isFuncDeclaration()
4507 && d.isFuncDeclaration().isStatic
4508 && d.isFuncDeclaration().objc.selector)
4509 {
4510 auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
4511 return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
4512 }
4513 else if (d.needThis() && sc.intypeof != 1)
4514 {
4515 /* Rewrite as:
4516 * this.d
4517 */
4518 AggregateDeclaration ad = d.isMemberLocal();
4519 if (auto f = hasThis(sc))
4520 {
4521 // This is almost same as getRightThis() in expressionsem.d
4522 Expression e1;
4523 Type t;
4524 /* returns: true to continue, false to return */
4525 if (f.hasDualContext())
4526 {
4527 if (f.followInstantiationContext(ad))
4528 {
4529 e1 = new VarExp(e.loc, f.vthis);
4530 e1 = new PtrExp(e1.loc, e1);
4531 e1 = new IndexExp(e1.loc, e1, IntegerExp.literal!1);
4532 auto pd = f.toParent2().isDeclaration();
4533 assert(pd);
4534 t = pd.type.toBasetype();
4535 e1 = getThisSkipNestedFuncs(e1.loc, sc, f.toParent2(), ad, e1, t, d, true);
4536 if (!e1)
4537 {
4538 e = new VarExp(e.loc, d);
4539 return e;
4540 }
4541 goto L2;
4542 }
4543 }
4544 e1 = new ThisExp(e.loc);
4545 e1 = e1.expressionSemantic(sc);
4546 L2:
4547 t = e1.type.toBasetype();
4548 ClassDeclaration cd = e.type.isClassHandle();
4549 ClassDeclaration tcd = t.isClassHandle();
4550 if (cd && tcd && (tcd == cd || cd.isBaseOf(tcd, null)))
4551 {
4552 e = new DotTypeExp(e1.loc, e1, cd);
4553 e = new DotVarExp(e.loc, e, d);
4554 e = e.expressionSemantic(sc);
4555 return e;
4556 }
4557 if (tcd && tcd.isNested())
4558 {
4559 /* e1 is the 'this' pointer for an inner class: tcd.
4560 * Rewrite it as the 'this' pointer for the outer class.
4561 */
4562 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
4563 e1 = new DotVarExp(e.loc, e1, vthis);
4564 e1.type = vthis.type;
4565 e1.type = e1.type.addMod(t.mod);
4566 // Do not call ensureStaticLinkTo()
4567 //e1 = e1.expressionSemantic(sc);
4568
4569 // Skip up over nested functions, and get the enclosing
4570 // class type.
4571 e1 = getThisSkipNestedFuncs(e1.loc, sc, tcd.toParentP(ad), ad, e1, t, d, true);
4572 if (!e1)
4573 {
4574 e = new VarExp(e.loc, d);
4575 return e;
4576 }
4577 goto L2;
4578 }
4579 }
4580 }
4581 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
4582 if (d.semanticRun == PASS.initial)
4583 d.dsymbolSemantic(null);
4584
4585 // If static function, get the most visible overload.
4586 // Later on the call is checked for correctness.
4587 // https://issues.dlang.org/show_bug.cgi?id=12511
4588 Dsymbol d2 = d;
4589 if (auto fd = d.isFuncDeclaration())
4590 {
4591 import dmd.access : mostVisibleOverload;
4592 d2 = mostVisibleOverload(fd, sc._module);
4593 }
4594
4595 checkAccess(e.loc, sc, e, d2);
4596 if (d2.isDeclaration())
4597 {
4598 d = cast(Declaration)d2;
4599 auto ve = new VarExp(e.loc, d);
4600 if (d.isVarDeclaration() && d.needThis())
4601 ve.type = d.type.addMod(e.type.mod);
4602 return ve;
4603 }
4604 else if (d2.isTemplateDeclaration())
4605 {
4606 return toTemplateExp(cast(TemplateDeclaration)d2);
4607 }
4608 else
4609 assert(0);
4610 }
4611
4612 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
4613 if (d.isDataseg() || unreal && d.isField())
4614 {
4615 // (e, d)
4616 checkAccess(e.loc, sc, e, d);
4617 Expression ve = new VarExp(e.loc, d);
4618 e = unreal ? ve : new CommaExp(e.loc, e, ve);
4619 e = e.expressionSemantic(sc);
4620 return e;
4621 }
4622
4623 e = new DotVarExp(e.loc, e, d);
4624 e = e.expressionSemantic(sc);
4625 return e;
4626 }
4627
4628 switch (mt.ty)
4629 {
4630 case Tvector: return visitVector (mt.isTypeVector());
4631 case Tsarray: return visitSArray (mt.isTypeSArray());
4632 case Tstruct: return visitStruct (mt.isTypeStruct());
4633 case Tenum: return visitEnum (mt.isTypeEnum());
4634 case Terror: return visitError (mt.isTypeError());
4635 case Tarray: return visitDArray (mt.isTypeDArray());
4636 case Taarray: return visitAArray (mt.isTypeAArray());
4637 case Treference: return visitReference(mt.isTypeReference());
4638 case Tdelegate: return visitDelegate (mt.isTypeDelegate());
4639 case Tclass: return visitClass (mt.isTypeClass());
4640
4641 default: return mt.isTypeBasic()
4642 ? visitBasic(cast(TypeBasic)mt)
4643 : visitType(mt);
4644 }
4645 }
4646
4647
4648 /************************
4649 * Get the the default initialization expression for a type.
4650 * Params:
4651 * mt = the type for which the init expression is returned
4652 * loc = the location where the expression needs to be evaluated
4653 * isCfile = default initializers are different with C
4654 *
4655 * Returns:
4656 * The initialization expression for the type.
4657 */
4658 extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
4659 {
visitBasic(TypeBasic mt)4660 Expression visitBasic(TypeBasic mt)
4661 {
4662 static if (LOGDEFAULTINIT)
4663 {
4664 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
4665 }
4666 dinteger_t value = 0;
4667
4668 switch (mt.ty)
4669 {
4670 case Tchar:
4671 value = isCfile ? 0 : 0xFF;
4672 break;
4673
4674 case Twchar:
4675 case Tdchar:
4676 value = isCfile ? 0 : 0xFFFF;
4677 break;
4678
4679 case Timaginary32:
4680 case Timaginary64:
4681 case Timaginary80:
4682 case Tfloat32:
4683 case Tfloat64:
4684 case Tfloat80:
4685 return new RealExp(loc, isCfile ? CTFloat.zero : target.RealProperties.nan, mt);
4686
4687 case Tcomplex32:
4688 case Tcomplex64:
4689 case Tcomplex80:
4690 {
4691 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
4692 const cvalue = isCfile ? complex_t(CTFloat.zero, CTFloat.zero)
4693 : complex_t(target.RealProperties.nan, target.RealProperties.nan);
4694 return new ComplexExp(loc, cvalue, mt);
4695 }
4696
4697 case Tvoid:
4698 error(loc, "`void` does not have a default initializer");
4699 return ErrorExp.get();
4700
4701 default:
4702 break;
4703 }
4704 return new IntegerExp(loc, value, mt);
4705 }
4706
visitVector(TypeVector mt)4707 Expression visitVector(TypeVector mt)
4708 {
4709 //printf("TypeVector::defaultInit()\n");
4710 assert(mt.basetype.ty == Tsarray);
4711 Expression e = mt.basetype.defaultInit(loc, isCfile);
4712 auto ve = new VectorExp(loc, e, mt);
4713 ve.type = mt;
4714 ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc));
4715 return ve;
4716 }
4717
visitSArray(TypeSArray mt)4718 Expression visitSArray(TypeSArray mt)
4719 {
4720 static if (LOGDEFAULTINIT)
4721 {
4722 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
4723 }
4724 if (mt.next.ty == Tvoid)
4725 return mt.tuns8.defaultInit(loc, isCfile);
4726 else
4727 return mt.next.defaultInit(loc, isCfile);
4728 }
4729
visitFunction(TypeFunction mt)4730 Expression visitFunction(TypeFunction mt)
4731 {
4732 error(loc, "`function` does not have a default initializer");
4733 return ErrorExp.get();
4734 }
4735
visitStruct(TypeStruct mt)4736 Expression visitStruct(TypeStruct mt)
4737 {
4738 static if (LOGDEFAULTINIT)
4739 {
4740 printf("TypeStruct::defaultInit() '%s'\n", mt.toChars());
4741 }
4742 Declaration d = new SymbolDeclaration(mt.sym.loc, mt.sym);
4743 assert(d);
4744 d.type = mt;
4745 d.storage_class |= STC.rvalue; // https://issues.dlang.org/show_bug.cgi?id=14398
4746 return new VarExp(mt.sym.loc, d);
4747 }
4748
visitEnum(TypeEnum mt)4749 Expression visitEnum(TypeEnum mt)
4750 {
4751 static if (LOGDEFAULTINIT)
4752 {
4753 printf("TypeEnum::defaultInit() '%s'\n", mt.toChars());
4754 }
4755 // Initialize to first member of enum
4756 Expression e = mt.sym.getDefaultValue(loc);
4757 e = e.copy();
4758 e.loc = loc;
4759 e.type = mt; // to deal with const, immutable, etc., variants
4760 return e;
4761 }
4762
visitTuple(TypeTuple mt)4763 Expression visitTuple(TypeTuple mt)
4764 {
4765 static if (LOGDEFAULTINIT)
4766 {
4767 printf("TypeTuple::defaultInit() '%s'\n", mt.toChars());
4768 }
4769 auto exps = new Expressions(mt.arguments.dim);
4770 for (size_t i = 0; i < mt.arguments.dim; i++)
4771 {
4772 Parameter p = (*mt.arguments)[i];
4773 assert(p.type);
4774 Expression e = p.type.defaultInitLiteral(loc);
4775 if (e.op == EXP.error)
4776 {
4777 return e;
4778 }
4779 (*exps)[i] = e;
4780 }
4781 return new TupleExp(loc, exps);
4782 }
4783
visitNoreturn(TypeNoreturn mt)4784 Expression visitNoreturn(TypeNoreturn mt)
4785 {
4786 static if (LOGDEFAULTINIT)
4787 {
4788 printf("TypeNoreturn::defaultInit() '%s'\n", mt.toChars());
4789 }
4790 auto cond = IntegerExp.createBool(false);
4791 auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
4792 msg.type = Type.tstring;
4793 auto ae = new AssertExp(loc, cond, msg);
4794 ae.type = mt;
4795 return ae;
4796 }
4797
4798 switch (mt.ty)
4799 {
4800 case Tvector: return visitVector (mt.isTypeVector());
4801 case Tsarray: return visitSArray (mt.isTypeSArray());
4802 case Tfunction: return visitFunction(mt.isTypeFunction());
4803 case Tstruct: return visitStruct (mt.isTypeStruct());
4804 case Tenum: return visitEnum (mt.isTypeEnum());
4805 case Ttuple: return visitTuple (mt.isTypeTuple());
4806
4807 case Tnull: return new NullExp(Loc.initial, Type.tnull);
4808
4809 case Terror: return ErrorExp.get();
4810
4811 case Tarray:
4812 case Taarray:
4813 case Tpointer:
4814 case Treference:
4815 case Tdelegate:
4816 case Tclass: return new NullExp(loc, mt);
4817 case Tnoreturn: return visitNoreturn(mt.isTypeNoreturn());
4818
4819 default: return mt.isTypeBasic() ?
4820 visitBasic(cast(TypeBasic)mt) :
4821 null;
4822 }
4823 }
4824
4825
4826 /******************************
4827 * Get the value of the .max/.min property of `ed` as an Expression.
4828 * Lazily computes the value and caches it in maxval/minval.
4829 * Reports any errors.
4830 * Params:
4831 * ed = the EnumDeclaration being examined
4832 * loc = location to use for error messages
4833 * id = Id::max or Id::min
4834 * Returns:
4835 * corresponding value of .max/.min
4836 */
getMaxMinValue(EnumDeclaration ed,const ref Loc loc,Identifier id)4837 private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
4838 {
4839 //printf("EnumDeclaration::getMaxValue()\n");
4840
4841 static Expression pvalToResult(Expression e, const ref Loc loc)
4842 {
4843 if (e.op != EXP.error)
4844 {
4845 e = e.copy();
4846 e.loc = loc;
4847 }
4848 return e;
4849 }
4850
4851 Expression* pval = (id == Id.max) ? &ed.maxval : &ed.minval;
4852
4853 Expression errorReturn()
4854 {
4855 *pval = ErrorExp.get();
4856 return *pval;
4857 }
4858
4859 if (ed.inuse)
4860 {
4861 ed.error(loc, "recursive definition of `.%s` property", id.toChars());
4862 return errorReturn();
4863 }
4864 if (*pval)
4865 return pvalToResult(*pval, loc);
4866
4867 if (ed._scope)
4868 dsymbolSemantic(ed, ed._scope);
4869 if (ed.errors)
4870 return errorReturn();
4871 if (!ed.members)
4872 {
4873 if (ed.isSpecial())
4874 {
4875 /* Allow these special enums to not need a member list
4876 */
4877 return ed.memtype.getProperty(ed._scope, loc, id, 0);
4878 }
4879
4880 ed.error(loc, "is opaque and has no `.%s`", id.toChars());
4881 return errorReturn();
4882 }
4883 if (!(ed.memtype && ed.memtype.isintegral()))
4884 {
4885 ed.error(loc, "has no `.%s` property because base type `%s` is not an integral type",
4886 id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
4887 return errorReturn();
4888 }
4889
4890 bool first = true;
4891 for (size_t i = 0; i < ed.members.dim; i++)
4892 {
4893 EnumMember em = (*ed.members)[i].isEnumMember();
4894 if (!em)
4895 continue;
4896 if (em.errors)
4897 {
4898 ed.errors = true;
4899 continue;
4900 }
4901
4902 if (em.semanticRun < PASS.semanticdone)
4903 {
4904 em.error("is forward referenced looking for `.%s`", id.toChars());
4905 ed.errors = true;
4906 continue;
4907 }
4908
4909 if (first)
4910 {
4911 *pval = em.value;
4912 first = false;
4913 }
4914 else
4915 {
4916 /* In order to work successfully with UDTs,
4917 * build expressions to do the comparisons,
4918 * and let the semantic analyzer and constant
4919 * folder give us the result.
4920 */
4921
4922 /* Compute:
4923 * if (e > maxval)
4924 * maxval = e;
4925 */
4926 Expression e = em.value;
4927 Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval);
4928 ed.inuse++;
4929 ec = ec.expressionSemantic(em._scope);
4930 ed.inuse--;
4931 ec = ec.ctfeInterpret();
4932 if (ec.op == EXP.error)
4933 {
4934 ed.errors = true;
4935 continue;
4936 }
4937 if (ec.toInteger())
4938 *pval = e;
4939 }
4940 }
4941 return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
4942 }
4943