d: Merge upstream dmd ff57fec515, druntime ff57fec515, phobos 17bafda79.
[official-gcc.git] / gcc / d / dmd / typesem.d
blob8795002cd154daff2b36435d1a595a60bf32ac39
1 /**
2 * Semantic analysis for D types.
4 * Copyright: Copyright (C) 1999-2023 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
12 module dmd.typesem;
14 import core.checkedint;
15 import core.stdc.string;
16 import core.stdc.stdio;
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.dinterpret;
31 import dmd.dmangle;
32 import dmd.dmodule;
33 import dmd.dscope;
34 import dmd.dstruct;
35 import dmd.dsymbol;
36 import dmd.dsymbolsem;
37 import dmd.dtemplate;
38 import dmd.errors;
39 import dmd.errorsink;
40 import dmd.expression;
41 import dmd.expressionsem;
42 import dmd.func;
43 import dmd.globals;
44 import dmd.hdrgen;
45 import dmd.id;
46 import dmd.identifier;
47 import dmd.imphint;
48 import dmd.importc;
49 import dmd.init;
50 import dmd.initsem;
51 import dmd.location;
52 import dmd.visitor;
53 import dmd.mtype;
54 import dmd.objc;
55 import dmd.opover;
56 import dmd.optimize;
57 import dmd.parse;
58 import dmd.root.complex;
59 import dmd.root.ctfloat;
60 import dmd.root.rmem;
61 import dmd.common.outbuffer;
62 import dmd.rootobject;
63 import dmd.root.string;
64 import dmd.root.stringtable;
65 import dmd.safe;
66 import dmd.semantic3;
67 import dmd.sideeffect;
68 import dmd.target;
69 import dmd.tokens;
71 /*************************************
72 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
73 * Setting one of pe/pt/ps.
74 * Params:
75 * loc = location for error messages
76 * sc = context
77 * s = symbol being indexed - could be a tuple, could be an expression
78 * pe = set if s[oindex] is an Expression, otherwise null
79 * pt = set if s[oindex] is a Type, otherwise null
80 * ps = set if s[oindex] is a Dsymbol, otherwise null
81 * oindex = index into s
83 private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
85 auto tup = s.isTupleDeclaration();
87 auto eindex = isExpression(oindex);
88 auto tindex = isType(oindex);
89 auto sindex = isDsymbol(oindex);
91 if (!tup)
93 // It's really an index expression
94 if (tindex)
95 eindex = new TypeExp(loc, tindex);
96 else if (sindex)
97 eindex = symbolToExp(sindex, loc, sc, false);
98 Expression e = new IndexExp(loc, symbolToExp(s, loc, sc, false), eindex);
99 e = e.expressionSemantic(sc);
100 resolveExp(e, pt, pe, ps);
101 return;
104 // Convert oindex to Expression, then try to resolve to constant.
105 if (tindex)
106 tindex.resolve(loc, sc, eindex, tindex, sindex);
107 if (sindex)
108 eindex = symbolToExp(sindex, loc, sc, false);
109 if (!eindex)
111 .error(loc, "index `%s` is not an expression", oindex.toChars());
112 pt = Type.terror;
113 return;
116 eindex = semanticLength(sc, tup, eindex);
117 eindex = eindex.ctfeInterpret();
118 if (eindex.op == EXP.error)
120 pt = Type.terror;
121 return;
123 const(uinteger_t) d = eindex.toUInteger();
124 if (d >= tup.objects.length)
126 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong)tup.objects.length);
127 pt = Type.terror;
128 return;
131 RootObject o = (*tup.objects)[cast(size_t)d];
132 ps = isDsymbol(o);
133 if (auto t = isType(o))
134 pt = t.typeSemantic(loc, sc);
135 if (auto e = isExpression(o))
136 resolveExp(e, pt, pe, ps);
139 /*************************************
140 * Takes an array of Identifiers and figures out if
141 * it represents a Type, Expression, or Dsymbol.
142 * Params:
143 * mt = array of identifiers
144 * loc = location for error messages
145 * sc = context
146 * s = symbol to start search at
147 * scopesym = unused
148 * pe = set if expression otherwise null
149 * pt = set if type otherwise null
150 * ps = set if symbol otherwise null
151 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
153 private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
154 out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
156 version (none)
158 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars());
159 if (scopesym)
160 printf("\tscopesym = '%s'\n", scopesym.toChars());
163 if (!s)
165 /* Look for what user might have intended
167 const p = mt.mutableOf().unSharedOf().toChars();
168 auto id = Identifier.idPool(p[0 .. strlen(p)]);
169 if (const n = importHint(id.toString()))
170 error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr);
171 else if (auto s2 = sc.search_correct(id))
172 error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
173 else if (const q = Scope.search_correct_C(id))
174 error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
175 else if ((id == Id.This && sc.getStructClassScope()) ||
176 (id == Id._super && sc.getClassScope()))
177 error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p);
178 else
179 error(loc, "undefined identifier `%s`", p);
181 pt = Type.terror;
182 return;
185 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
186 Declaration d = s.isDeclaration();
187 if (d && (d.storage_class & STC.templateparameter))
188 s = s.toAlias();
189 else
191 // check for deprecated or disabled aliases
192 // functions are checked after overloading
193 // templates are checked after matching constraints
194 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
195 s.checkDeprecated(loc, sc);
196 if (d)
197 d.checkDisabled(loc, sc, true);
199 s = s.toAlias();
200 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
201 for (size_t i = 0; i < mt.idents.length; i++)
203 RootObject id = mt.idents[i];
204 switch (id.dyncast()) with (DYNCAST)
206 case expression:
207 case type:
208 Type tx;
209 Expression ex;
210 Dsymbol sx;
211 resolveTupleIndex(loc, sc, s, ex, tx, sx, id);
212 if (sx)
214 s = sx.toAlias();
215 continue;
217 if (tx)
218 ex = new TypeExp(loc, tx);
219 assert(ex);
221 ex = typeToExpressionHelper(mt, ex, i + 1);
222 ex = ex.expressionSemantic(sc);
223 resolveExp(ex, pt, pe, ps);
224 return;
225 default:
226 break;
229 Type t = s.getType(); // type symbol, type alias, or type tuple?
230 uint errorsave = global.errors;
231 int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports;
233 Dsymbol sm = s.searchX(loc, sc, id, flags);
234 if (sm)
236 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
238 .error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
239 sm = null;
241 // Same check as in dotIdSemanticProp(DotIdExp)
242 else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
244 // @@@DEPRECATED_2.106@@@
245 // Should be an error in 2.106. Just remove the deprecation call
246 // and uncomment the null assignment
247 deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
248 //sm = null;
251 if (global.errors != errorsave)
253 pt = Type.terror;
254 return;
257 void helper3()
259 Expression e;
260 VarDeclaration v = s.isVarDeclaration();
261 FuncDeclaration f = s.isFuncDeclaration();
262 if (intypeid || !v && !f)
263 e = symbolToExp(s, loc, sc, true);
264 else
265 e = new VarExp(loc, s.isDeclaration(), true);
267 e = typeToExpressionHelper(mt, e, i);
268 e = e.expressionSemantic(sc);
269 resolveExp(e, pt, pe, ps);
272 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
273 if (intypeid && !t && sm && sm.needThis())
274 return helper3();
276 if (VarDeclaration v = s.isVarDeclaration())
278 // https://issues.dlang.org/show_bug.cgi?id=19913
279 // v.type would be null if it is a forward referenced member.
280 if (v.type is null)
281 v.dsymbolSemantic(sc);
282 if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
283 v.type.isConst() || v.type.isImmutable())
285 // https://issues.dlang.org/show_bug.cgi?id=13087
286 // this.field is not constant always
287 if (!v.isThisDeclaration())
288 return helper3();
292 if (!sm)
293 return helper3();
295 if (sm.isAliasDeclaration)
296 sm.checkDeprecated(loc, sc);
297 s = sm.toAlias();
300 if (auto em = s.isEnumMember())
302 // It's not a type, it's an expression
303 pe = em.getVarExp(loc, sc);
304 return;
306 if (auto v = s.isVarDeclaration())
308 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
309 * because some variables used in type context need to prevent lowering
310 * to a literal or contextful expression. For example:
312 * enum a = 1; alias b = a;
313 * template X(alias e){ alias v = e; } alias x = X!(1);
314 * struct S { int v; alias w = v; }
315 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
316 * // because getDsymbol() need to work in AliasDeclaration::semantic().
318 if (!v.type ||
319 !v.type.deco && v.inuse)
321 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
322 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
323 else
324 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
325 pt = Type.terror;
326 return;
328 if (v.type.ty == Terror)
329 pt = Type.terror;
330 else
331 pe = new VarExp(loc, v);
332 return;
334 if (auto fld = s.isFuncLiteralDeclaration())
336 //printf("'%s' is a function literal\n", fld.toChars());
337 auto e = new FuncExp(loc, fld);
338 pe = e.expressionSemantic(sc);
339 return;
341 version (none)
343 if (FuncDeclaration fd = s.isFuncDeclaration())
345 pe = new DsymbolExp(loc, fd);
346 return;
350 Type t;
351 while (1)
353 t = s.getType();
354 if (t)
355 break;
356 ps = s;
357 return;
360 if (auto ti = t.isTypeInstance())
361 if (ti != mt && !ti.deco)
363 if (!ti.tempinst.errors)
364 error(loc, "forward reference to `%s`", ti.toChars());
365 pt = Type.terror;
366 return;
369 if (t.ty == Ttuple)
370 pt = t;
371 else
372 pt = t.merge();
375 /******************************************
376 * We've mistakenly parsed `t` as a type.
377 * Redo `t` as an Expression only if there are no type modifiers.
378 * Params:
379 * t = mistaken type
380 * Returns:
381 * t redone as Expression, null if cannot
383 Expression typeToExpression(Type t)
385 static Expression visitSArray(TypeSArray t)
387 if (auto e = t.next.typeToExpression())
388 return new ArrayExp(t.dim.loc, e, t.dim);
389 return null;
392 static Expression visitAArray(TypeAArray t)
394 if (auto e = t.next.typeToExpression())
396 if (auto ei = t.index.typeToExpression())
397 return new ArrayExp(t.loc, e, ei);
399 return null;
402 static Expression visitIdentifier(TypeIdentifier t)
404 return typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident));
407 static Expression visitInstance(TypeInstance t)
409 return typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst));
412 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
413 static Expression visitMixin(TypeMixin t)
415 return new TypeExp(t.loc, t);
418 if (t.mod)
419 return null;
420 switch (t.ty)
422 case Tsarray: return visitSArray(t.isTypeSArray());
423 case Taarray: return visitAArray(t.isTypeAArray());
424 case Tident: return visitIdentifier(t.isTypeIdentifier());
425 case Tinstance: return visitInstance(t.isTypeInstance());
426 case Tmixin: return visitMixin(t.isTypeMixin());
427 default: return null;
431 /******************************************
432 * Perform semantic analysis on a type.
433 * Params:
434 * type = Type AST node
435 * loc = the location of the type
436 * sc = context
437 * Returns:
438 * `Type` with completed semantic analysis, `Terror` if errors
439 * were encountered
441 extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
443 static Type error()
445 return Type.terror;
448 Type visitType(Type t)
450 // @@@DEPRECATED_2.110@@@
451 // Use of `cent` and `ucent` has always been an error.
452 // Starting from 2.100, recommend core.int128 as a replace for the
453 // lack of compiler support.
454 if (t.ty == Tint128 || t.ty == Tuns128)
456 .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
457 return error();
460 return t.merge();
463 Type visitComplex(TypeBasic t)
465 if (!(sc.flags & SCOPE.Cfile))
466 return visitType(t);
468 auto tc = getComplexLibraryType(loc, sc, t.ty);
469 if (tc.ty == Terror)
470 return tc;
471 return tc.addMod(t.mod).merge();
474 Type visitVector(TypeVector mtype)
476 const errors = global.errors;
477 mtype.basetype = mtype.basetype.typeSemantic(loc, sc);
478 if (errors != global.errors)
479 return error();
480 mtype.basetype = mtype.basetype.toBasetype().mutableOf();
481 if (mtype.basetype.ty != Tsarray)
483 .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars());
484 return error();
486 TypeSArray t = mtype.basetype.isTypeSArray();
487 const sz = cast(int)t.size(loc);
488 final switch (target.isVectorTypeSupported(sz, t.nextOf()))
490 case 0:
491 // valid
492 break;
494 case 1:
495 // no support at all
496 .error(loc, "SIMD vector types not supported on this platform");
497 return error();
499 case 2:
500 // invalid base type
501 .error(loc, "vector type `%s` is not supported on this platform", mtype.toChars());
502 return error();
504 case 3:
505 // invalid size
506 .error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars());
507 return error();
509 return merge(mtype);
512 Type visitSArray(TypeSArray mtype)
514 //printf("TypeSArray::semantic() %s\n", toChars());
515 Type t;
516 Expression e;
517 Dsymbol s;
518 mtype.next.resolve(loc, sc, e, t, s);
520 if (auto tup = s ? s.isTupleDeclaration() : null)
522 mtype.dim = semanticLength(sc, tup, mtype.dim);
523 mtype.dim = mtype.dim.ctfeInterpret();
524 if (mtype.dim.op == EXP.error)
525 return error();
527 uinteger_t d = mtype.dim.toUInteger();
528 if (d >= tup.objects.length)
530 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tup.objects.length);
531 return error();
534 RootObject o = (*tup.objects)[cast(size_t)d];
535 if (auto tt = o.isType())
536 return tt.addMod(mtype.mod);
537 .error(loc, "`%s` is not a type", mtype.toChars());
538 return error();
541 if (t && t.ty == Terror)
542 return error();
544 Type tn = mtype.next.typeSemantic(loc, sc);
545 if (tn.ty == Terror)
546 return error();
548 Type tbn = tn.toBasetype();
549 if (mtype.dim)
551 auto errors = global.errors;
552 mtype.dim = semanticLength(sc, tbn, mtype.dim);
553 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
554 if (errors != global.errors)
555 return error();
557 mtype.dim = mtype.dim.optimize(WANTvalue);
558 mtype.dim = mtype.dim.ctfeInterpret();
559 if (mtype.dim.op == EXP.error)
560 return error();
562 errors = global.errors;
563 dinteger_t d1 = mtype.dim.toInteger();
564 if (errors != global.errors)
565 return error();
567 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
568 mtype.dim = mtype.dim.optimize(WANTvalue);
569 if (mtype.dim.op == EXP.error)
570 return error();
572 errors = global.errors;
573 dinteger_t d2 = mtype.dim.toInteger();
574 if (errors != global.errors)
575 return error();
577 if (mtype.dim.op == EXP.error)
578 return error();
580 Type overflowError()
582 .error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
583 mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, target.maxStaticDataSize);
584 return error();
587 if (d1 != d2)
588 return overflowError();
590 Type tbx = tbn.baseElemOf();
591 if (tbx.ty == Tstruct && !tbx.isTypeStruct().sym.members ||
592 tbx.ty == Tenum && !tbx.isTypeEnum().sym.members)
594 /* To avoid meaningless error message, skip the total size limit check
595 * when the bottom of element type is opaque.
598 else if (tbn.isTypeBasic() ||
599 tbn.ty == Tpointer ||
600 tbn.ty == Tarray ||
601 tbn.ty == Tsarray ||
602 tbn.ty == Taarray ||
603 (tbn.ty == Tstruct && tbn.isTypeStruct().sym.sizeok == Sizeok.done) ||
604 tbn.ty == Tclass)
606 /* Only do this for types that don't need to have semantic()
607 * run on them for the size, since they may be forward referenced.
609 bool overflow = false;
610 if (mulu(tbn.size(loc), d2, overflow) > target.maxStaticDataSize || overflow)
611 return overflowError();
614 switch (tbn.ty)
616 case Ttuple:
618 // Index the tuple to get the type
619 assert(mtype.dim);
620 TypeTuple tt = tbn.isTypeTuple();
621 uinteger_t d = mtype.dim.toUInteger();
622 if (d >= tt.arguments.length)
624 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tt.arguments.length);
625 return error();
627 Type telem = (*tt.arguments)[cast(size_t)d].type;
628 return telem.addMod(mtype.mod);
631 case Tfunction:
632 case Tnone:
633 .error(loc, "cannot have array of `%s`", tbn.toChars());
634 return error();
636 default:
637 break;
639 if (tbn.isscope())
641 .error(loc, "cannot have array of scope `%s`", tbn.toChars());
642 return error();
645 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
646 * and const(T)[3] become const(T[3])
648 mtype.next = tn;
649 mtype.transitive();
650 return mtype.addMod(tn.mod).merge();
653 Type visitDArray(TypeDArray mtype)
655 Type tn = mtype.next.typeSemantic(loc, sc);
656 Type tbn = tn.toBasetype();
657 switch (tbn.ty)
659 case Ttuple:
660 return tbn;
662 case Tfunction:
663 case Tnone:
664 .error(loc, "cannot have array of `%s`", tbn.toChars());
665 return error();
667 case Terror:
668 return error();
670 default:
671 break;
673 if (tn.isscope())
675 .error(loc, "cannot have array of scope `%s`", tn.toChars());
676 return error();
678 mtype.next = tn;
679 mtype.transitive();
680 return merge(mtype);
683 Type visitAArray(TypeAArray mtype)
685 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
686 if (mtype.deco)
688 return mtype;
691 mtype.loc = loc;
692 if (sc)
693 sc.setNoFree();
695 // Deal with the case where we thought the index was a type, but
696 // in reality it was an expression.
697 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)
699 Expression e;
700 Type t;
701 Dsymbol s;
702 mtype.index.resolve(loc, sc, e, t, s);
704 // https://issues.dlang.org/show_bug.cgi?id=15478
705 if (s)
706 e = symbolToExp(s, loc, sc, false);
708 if (e)
710 // It was an expression -
711 // Rewrite as a static array
712 auto tsa = new TypeSArray(mtype.next, e);
713 return tsa.typeSemantic(loc, sc);
715 else if (t)
716 mtype.index = t.typeSemantic(loc, sc);
717 else
719 .error(loc, "index is not a type or an expression");
720 return error();
723 else
724 mtype.index = mtype.index.typeSemantic(loc, sc);
725 mtype.index = mtype.index.merge2();
727 if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable())
729 mtype.index = mtype.index.constOf().mutableOf();
730 version (none)
732 printf("index is %p %s\n", mtype.index, mtype.index.toChars());
733 mtype.index.check();
734 printf("index.mod = x%x\n", mtype.index.mod);
735 printf("index.ito = x%p\n", mtype.index.getMcache().ito);
736 if (mtype.index.getMcache().ito)
738 printf("index.ito.mod = x%x\n", mtype.index.getMcache().ito.mod);
739 printf("index.ito.ito = x%p\n", mtype.index.getMcache().ito.getMcache().ito);
744 switch (mtype.index.toBasetype().ty)
746 case Tfunction:
747 case Tvoid:
748 case Tnone:
749 case Ttuple:
750 .error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars());
751 goto case Terror;
752 case Terror:
753 return error();
755 default:
756 break;
758 Type tbase = mtype.index.baseElemOf();
759 while (tbase.ty == Tarray)
760 tbase = tbase.nextOf().baseElemOf();
761 if (auto ts = tbase.isTypeStruct())
763 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
765 StructDeclaration sd = ts.sym;
766 if (sd.semanticRun < PASS.semanticdone)
767 sd.dsymbolSemantic(null);
769 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
770 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
772 if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
774 uint errors = global.startGagging();
775 sd.xeq.semantic3(sd.xeq._scope);
776 if (global.endGagging(errors))
777 sd.xeq = sd.xerreq;
781 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
782 const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : "";
783 if (!sd.xeq)
785 // If sd.xhash != NULL:
786 // sd or its fields have user-defined toHash.
787 // AA assumes that its result is consistent with bitwise equality.
788 // else:
789 // bitwise equality & hashing
791 else if (sd.xeq == sd.xerreq)
793 if (search_function(sd, Id.eq))
795 .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars());
797 else
799 .error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars());
801 return error();
803 else if (!sd.xhash)
805 if (search_function(sd, Id.eq))
807 .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars());
809 else
811 .error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars());
813 return error();
815 else
817 // defined equality & hashing
818 assert(sd.xeq && sd.xhash);
820 /* xeq and xhash may be implicitly defined by compiler. For example:
821 * struct S { int[] arr; }
822 * With 'arr' field equality and hashing, compiler will implicitly
823 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
827 else if (tbase.ty == Tclass && !tbase.isTypeClass().sym.isInterfaceDeclaration())
829 ClassDeclaration cd = tbase.isTypeClass().sym;
830 if (cd.semanticRun < PASS.semanticdone)
831 cd.dsymbolSemantic(null);
833 if (!ClassDeclaration.object)
835 .error(Loc.initial, "missing or corrupt object.d");
836 fatal();
839 __gshared FuncDeclaration feq = null;
840 __gshared FuncDeclaration fcmp = null;
841 __gshared FuncDeclaration fhash = null;
842 if (!feq)
843 feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration();
844 if (!fcmp)
845 fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration();
846 if (!fhash)
847 fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration();
848 assert(fcmp && feq && fhash);
850 if (feq.vtblIndex < cd.vtbl.length && cd.vtbl[feq.vtblIndex] == feq)
852 version (all)
854 if (fcmp.vtblIndex < cd.vtbl.length && cd.vtbl[fcmp.vtblIndex] != fcmp)
856 const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : "";
857 .error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars());
858 errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`.");
863 mtype.next = mtype.next.typeSemantic(loc, sc).merge2();
864 mtype.transitive();
866 switch (mtype.next.toBasetype().ty)
868 case Tfunction:
869 case Tvoid:
870 case Tnone:
871 case Ttuple:
872 .error(loc, "cannot have associative array of `%s`", mtype.next.toChars());
873 goto case Terror;
874 case Terror:
875 return error();
876 default:
877 break;
879 if (mtype.next.isscope())
881 .error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
882 return error();
884 return merge(mtype);
887 Type visitPointer(TypePointer mtype)
889 //printf("TypePointer::semantic() %s\n", toChars());
890 if (mtype.deco)
892 return mtype;
894 Type n = mtype.next.typeSemantic(loc, sc);
895 switch (n.toBasetype().ty)
897 case Ttuple:
898 .error(loc, "cannot have pointer to `%s`", n.toChars());
899 goto case Terror;
900 case Terror:
901 return error();
902 default:
903 break;
905 if (n != mtype.next)
907 mtype.deco = null;
909 mtype.next = n;
910 if (mtype.next.ty != Tfunction)
912 mtype.transitive();
913 return merge(mtype);
915 version (none)
917 return merge(mtype);
919 else
921 mtype.deco = merge(mtype).deco;
922 /* Don't return merge(), because arg identifiers and default args
923 * can be different
924 * even though the types match
926 return mtype;
930 Type visitReference(TypeReference mtype)
932 //printf("TypeReference::semantic()\n");
933 Type n = mtype.next.typeSemantic(loc, sc);
934 if (n != mtype.next)
935 mtype.deco = null;
936 mtype.next = n;
937 mtype.transitive();
938 return merge(mtype);
941 Type visitFunction(TypeFunction mtype)
943 if (mtype.deco) // if semantic() already run
945 //printf("already done\n");
946 return mtype;
948 //printf("TypeFunction::semantic() this = %p\n", mtype);
949 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
951 bool errors = false;
953 if (mtype.inuse > global.recursionLimit)
955 mtype.inuse = 0;
956 .error(loc, "recursive type");
957 return error();
960 /* Copy in order to not mess up original.
961 * This can produce redundant copies if inferring return type,
962 * as semantic() will get called again on this.
964 TypeFunction tf = mtype.copy().toTypeFunction();
965 if (mtype.parameterList.parameters)
967 tf.parameterList.parameters = mtype.parameterList.parameters.copy();
968 for (size_t i = 0; i < mtype.parameterList.parameters.length; i++)
970 Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter));
971 memcpy(cast(void*)p, cast(void*)(*mtype.parameterList.parameters)[i], __traits(classInstanceSize, Parameter));
972 (*tf.parameterList.parameters)[i] = p;
976 if (sc.stc & STC.pure_)
977 tf.purity = PURE.fwdref;
978 if (sc.stc & STC.nothrow_)
979 tf.isnothrow = true;
980 if (sc.stc & STC.nogc)
981 tf.isnogc = true;
982 if (sc.stc & STC.ref_)
983 tf.isref = true;
984 if (sc.stc & STC.return_)
985 tf.isreturn = true;
986 if (sc.stc & STC.returnScope)
987 tf.isreturnscope = true;
988 if (sc.stc & STC.returninferred)
989 tf.isreturninferred = true;
990 if (sc.stc & STC.scope_)
991 tf.isScopeQual = true;
992 if (sc.stc & STC.scopeinferred)
993 tf.isscopeinferred = true;
995 // if (tf.isreturn && !tf.isref)
996 // tf.isScopeQual = true; // return by itself means 'return scope'
998 if (tf.trust == TRUST.default_)
1000 if (sc.stc & STC.safe)
1001 tf.trust = TRUST.safe;
1002 else if (sc.stc & STC.system)
1003 tf.trust = TRUST.system;
1004 else if (sc.stc & STC.trusted)
1005 tf.trust = TRUST.trusted;
1008 if (sc.stc & STC.property)
1009 tf.isproperty = true;
1010 if (sc.stc & STC.live)
1011 tf.islive = true;
1013 tf.linkage = sc.linkage;
1014 if (tf.linkage == LINK.system)
1015 tf.linkage = target.systemLinkage();
1017 version (none)
1019 /* If the parent is @safe, then this function defaults to safe
1020 * too.
1021 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1022 * to be inferred first.
1024 if (tf.trust == TRUST.default_)
1025 for (Dsymbol p = sc.func; p; p = p.toParent2())
1027 FuncDeclaration fd = p.isFuncDeclaration();
1028 if (fd)
1030 if (fd.isSafeBypassingInference())
1031 tf.trust = TRUST.safe; // default to @safe
1032 break;
1037 bool wildreturn = false;
1038 if (tf.next)
1040 sc = sc.push();
1041 sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR);
1042 tf.next = tf.next.typeSemantic(loc, sc);
1043 sc = sc.pop();
1044 errors |= tf.checkRetType(loc);
1045 if (tf.next.isscope() && !tf.isctor)
1047 .error(loc, "functions cannot return `scope %s`", tf.next.toChars());
1048 errors = true;
1050 if (tf.next.hasWild())
1051 wildreturn = true;
1053 if (tf.isreturn && !tf.isref && !tf.next.hasPointers())
1055 tf.isreturn = false;
1059 /// Perform semantic on the default argument to a parameter
1060 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1061 /// Returns `false` whether an error was encountered.
1062 static bool defaultArgSemantic (ref Parameter fparam, Scope* sc)
1064 Expression e = fparam.defaultArg;
1065 const isRefOrOut = fparam.isReference();
1066 const isAuto = fparam.storageClass & (STC.auto_ | STC.autoref);
1067 if (isRefOrOut && !isAuto)
1069 e = e.expressionSemantic(sc);
1070 e = resolveProperties(sc, e);
1072 else
1074 e = inferType(e, fparam.type);
1075 Initializer iz = new ExpInitializer(e.loc, e);
1076 iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
1077 e = iz.initializerToExpression();
1079 if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
1081 FuncExp fe = e.isFuncExp();
1082 // Replace function literal with a function symbol,
1083 // since default arg expression must be copied when used
1084 // and copying the literal itself is wrong.
1085 e = new VarExp(e.loc, fe.fd, false);
1086 e = new AddrExp(e.loc, e);
1087 e = e.expressionSemantic(sc);
1089 if (isRefOrOut && (!isAuto || e.isLvalue())
1090 && !MODimplicitConv(e.type.mod, fparam.type.mod))
1092 const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
1093 .error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1094 e.toChars(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
1096 e = e.implicitCastTo(sc, fparam.type);
1098 // default arg must be an lvalue
1099 if (isRefOrOut && !isAuto &&
1100 !(global.params.previewIn && (fparam.storageClass & STC.in_)) &&
1101 global.params.rvalueRefParam != FeatureState.enabled)
1102 e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from");
1104 fparam.defaultArg = e;
1105 return (e.op != EXP.error);
1108 ubyte wildparams = 0;
1109 if (tf.parameterList.parameters)
1111 /* Create a scope for evaluating the default arguments for the parameters
1113 Scope* argsc = sc.push();
1114 argsc.stc = 0; // don't inherit storage class
1115 argsc.visibility = Visibility(Visibility.Kind.public_);
1116 argsc.func = null;
1118 size_t dim = tf.parameterList.length;
1119 for (size_t i = 0; i < dim; i++)
1121 Parameter fparam = tf.parameterList[i];
1122 fparam.storageClass |= STC.parameter;
1123 mtype.inuse++;
1124 fparam.type = fparam.type.typeSemantic(loc, argsc);
1125 mtype.inuse--;
1127 if (fparam.type.ty == Terror)
1129 errors = true;
1130 continue;
1133 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
1135 if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_))
1137 if (!fparam.type)
1138 continue;
1141 fparam.type = fparam.type.cAdjustParamType(sc); // adjust C array and function parameter types
1143 Type t = fparam.type.toBasetype();
1145 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
1146 * change.
1148 if (auto tt = t.isTypeTuple())
1150 /* TypeFunction::parameter also is used as the storage of
1151 * Parameter objects for FuncDeclaration. So we should copy
1152 * the elements of TypeTuple::arguments to avoid unintended
1153 * sharing of Parameter object among other functions.
1155 if (tt.arguments && tt.arguments.length)
1157 /* Propagate additional storage class from tuple parameters to their
1158 * element-parameters.
1159 * Make a copy, as original may be referenced elsewhere.
1161 size_t tdim = tt.arguments.length;
1162 auto newparams = new Parameters(tdim);
1163 for (size_t j = 0; j < tdim; j++)
1165 Parameter narg = (*tt.arguments)[j];
1167 // https://issues.dlang.org/show_bug.cgi?id=12744
1168 // If the storage classes of narg
1169 // conflict with the ones in fparam, it's ignored.
1170 StorageClass stc = fparam.storageClass | narg.storageClass;
1171 StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
1172 StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
1173 if (stc1 && stc2 && stc1 != stc2)
1175 OutBuffer buf1; stcToBuffer(buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0));
1176 OutBuffer buf2; stcToBuffer(buf2, stc2);
1178 .error(loc, "incompatible parameter storage classes `%s` and `%s`",
1179 buf1.peekChars(), buf2.peekChars());
1180 errors = true;
1181 stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_));
1183 (*newparams)[j] = new Parameter(
1184 loc, stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
1186 fparam.type = new TypeTuple(newparams);
1187 fparam.type = fparam.type.typeSemantic(loc, argsc);
1189 fparam.storageClass = STC.parameter;
1191 /* Reset number of parameters, and back up one to do this fparam again,
1192 * now that it is a tuple
1194 dim = tf.parameterList.length;
1195 i--;
1196 continue;
1199 // -preview=in: Always add `ref` when used with `extern(C++)` functions
1200 // Done here to allow passing opaque types with `in`
1201 if ((fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
1203 switch (tf.linkage)
1205 case LINK.cpp:
1206 if (global.params.previewIn)
1207 fparam.storageClass |= STC.ref_;
1208 break;
1209 case LINK.default_, LINK.d:
1210 break;
1211 default:
1212 if (global.params.previewIn)
1214 .error(loc, "cannot use `in` parameters with `extern(%s)` functions",
1215 linkageToChars(tf.linkage));
1216 .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
1218 else
1220 // Note that this deprecation will not trigger on `in ref` / `ref in`
1221 // parameters, however the parser will trigger a deprecation on them.
1222 .deprecation(loc, "using `in` parameters with `extern(%s)` functions is deprecated",
1223 linkageToChars(tf.linkage));
1224 .deprecationSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
1226 break;
1230 if (t.ty == Tfunction)
1232 .error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars());
1233 errors = true;
1235 else if (!fparam.isReference() &&
1236 (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum))
1238 Type tb2 = t.baseElemOf();
1239 if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members ||
1240 tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype)
1242 if (global.params.previewIn && (fparam.storageClass & STC.in_))
1244 .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
1245 fparam.toChars(), fparam.type.toChars());
1247 else
1248 .error(loc, "cannot have parameter of opaque type `%s` by value",
1249 fparam.type.toChars());
1250 errors = true;
1253 else if (!fparam.isLazy() && t.ty == Tvoid)
1255 .error(loc, "cannot have parameter of type `%s`", fparam.type.toChars());
1256 errors = true;
1259 const bool isTypesafeVariadic = i + 1 == dim &&
1260 tf.parameterList.varargs == VarArg.typesafe &&
1261 (t.isTypeDArray() || t.isTypeClass());
1262 if (isTypesafeVariadic)
1264 /* typesafe variadic arguments are constructed on the stack, so must be `scope`
1266 fparam.storageClass |= STC.scope_ | STC.scopeinferred;
1269 if (fparam.storageClass & STC.return_)
1271 if (!fparam.isReference())
1273 if (!(fparam.storageClass & STC.scope_))
1274 fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
1275 if (tf.isref)
1278 else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid)
1280 fparam.storageClass &= ~STC.return_; // https://issues.dlang.org/show_bug.cgi?id=18963
1284 if (isTypesafeVariadic)
1286 /* This is because they can be constructed on the stack
1287 * https://dlang.org/spec/function.html#typesafe_variadic_functions
1289 .error(loc, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
1290 fparam.ident ? fparam.ident.toChars() : "", t.toChars());
1291 errors = true;
1295 if (fparam.storageClass & STC.out_)
1297 if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild))
1299 .error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars());
1300 errors = true;
1302 else
1304 Type tv = t.baseElemOf();
1305 if (tv.ty == Tstruct && tv.isTypeStruct().sym.noDefaultCtor)
1307 .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars());
1308 errors = true;
1313 if (t.hasWild())
1315 wildparams |= 1;
1316 //if (tf.next && !wildreturn)
1317 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
1320 // Remove redundant storage classes for type, they are already applied
1321 fparam.storageClass &= ~(STC.TYPECTOR);
1323 // -preview=in: add `ref` storage class to suited `in` params
1324 if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
1326 auto ts = t.baseElemOf().isTypeStruct();
1327 const isPOD = !ts || ts.sym.isPOD();
1328 if (!isPOD || target.preferPassByRef(t))
1329 fparam.storageClass |= STC.ref_;
1333 // Now that we completed semantic for the argument types,
1334 // run semantic on their default values,
1335 // bearing in mind tuples have been expanded.
1336 // We need to keep a pair of [oidx, eidx] (original index,
1337 // extended index), as we need to run semantic when `oidx` changes.
1338 size_t tupleOrigIdx = size_t.max;
1339 size_t tupleExtIdx = size_t.max;
1340 foreach (oidx, oparam, eidx, eparam; tf.parameterList)
1342 // oparam (original param) will always have the default arg
1343 // if there's one, but `eparam` will not if it's an expanded
1344 // tuple. When we see an expanded tuple, we need to save its
1345 // position to get the offset in it later on.
1346 if (oparam.defaultArg)
1348 // Get the obvious case out of the way
1349 if (oparam is eparam)
1350 errors |= !defaultArgSemantic(eparam, argsc);
1351 // We're seeing a new tuple
1352 else if (tupleOrigIdx == size_t.max || tupleOrigIdx < oidx)
1354 /* https://issues.dlang.org/show_bug.cgi?id=18572
1356 * If a tuple parameter has a default argument, when expanding the parameter
1357 * tuple the default argument tuple must also be expanded.
1359 tupleOrigIdx = oidx;
1360 tupleExtIdx = eidx;
1361 errors |= !defaultArgSemantic(oparam, argsc);
1362 TupleExp te = oparam.defaultArg.isTupleExp();
1363 if (te && te.exps && te.exps.length)
1364 eparam.defaultArg = (*te.exps)[0];
1366 // Processing an already-seen tuple
1367 else
1369 TupleExp te = oparam.defaultArg.isTupleExp();
1370 if (te && te.exps && te.exps.length)
1371 eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
1375 // We need to know the default argument to resolve `auto ref`,
1376 // hence why this has to take place as the very last step.
1377 /* Resolve "auto ref" storage class to be either ref or value,
1378 * based on the argument matching the parameter
1380 if (eparam.storageClass & STC.auto_)
1382 Expression farg = mtype.fargs && eidx < mtype.fargs.length ?
1383 (*mtype.fargs)[eidx] : eparam.defaultArg;
1384 if (farg && (eparam.storageClass & STC.ref_))
1386 if (!farg.isLvalue())
1387 eparam.storageClass &= ~STC.ref_; // value parameter
1388 eparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656
1389 eparam.storageClass |= STC.autoref;
1391 else if (mtype.incomplete && (eparam.storageClass & STC.ref_))
1393 // the default argument may have been temporarily removed,
1394 // see usage of `TypeFunction.incomplete`.
1395 // https://issues.dlang.org/show_bug.cgi?id=19891
1396 eparam.storageClass &= ~STC.auto_;
1397 eparam.storageClass |= STC.autoref;
1399 else if (eparam.storageClass & STC.ref_)
1401 .error(loc, "cannot explicitly instantiate template function with `auto ref` parameter");
1402 errors = true;
1404 else
1406 .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
1407 errors = true;
1412 argsc.pop();
1414 if (tf.isWild())
1415 wildparams |= 2;
1417 if (wildreturn && !wildparams)
1419 .error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars());
1420 errors = true;
1422 tf.isInOutParam = (wildparams & 1) != 0;
1423 tf.isInOutQual = (wildparams & 2) != 0;
1425 if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
1427 .error(loc, "properties can only have zero, one, or two parameter");
1428 errors = true;
1431 if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
1432 !(sc.flags & SCOPE.Cfile))
1434 .error(loc, "variadic functions with non-D linkage must have at least one parameter");
1435 errors = true;
1438 if (errors)
1439 return error();
1441 if (tf.next)
1442 tf.deco = tf.merge().deco;
1444 /* Don't return merge(), because arg identifiers and default args
1445 * can be different
1446 * even though the types match
1448 return tf;
1451 Type visitDelegate(TypeDelegate mtype)
1453 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
1454 if (mtype.deco) // if semantic() already run
1456 //printf("already done\n");
1457 return mtype;
1459 mtype.next = mtype.next.typeSemantic(loc, sc);
1460 if (mtype.next.ty != Tfunction)
1461 return error();
1463 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
1464 * perhaps default arguments should
1465 * be removed from next before the merge.
1467 version (none)
1469 return mtype.merge();
1471 else
1473 /* Don't return merge(), because arg identifiers and default args
1474 * can be different
1475 * even though the types match
1477 mtype.deco = mtype.merge().deco;
1478 return mtype;
1482 Type visitIdentifier(TypeIdentifier mtype)
1484 Type t;
1485 Expression e;
1486 Dsymbol s;
1487 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
1488 mtype.resolve(loc, sc, e, t, s);
1489 if (t)
1491 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
1492 return t.addMod(mtype.mod);
1494 else
1496 if (s)
1498 auto td = s.isTemplateDeclaration;
1499 if (td && td.onemember && td.onemember.isAggregateDeclaration)
1500 .error(loc, "template %s `%s` is used as a type without instantiation"
1501 ~ "; to instantiate it use `%s!(arguments)`",
1502 s.kind, s.toPrettyChars, s.ident.toChars);
1503 else
1504 .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
1505 //assert(0);
1507 else if (e.op == EXP.variable) // special case: variable is used as a type
1510 N.B. This branch currently triggers for the following code
1511 template test(x* x)
1515 i.e. the compiler prints "variable x is used as a type"
1516 which isn't a particularly good error message (x is a variable?).
1518 Dsymbol varDecl = mtype.toDsymbol(sc);
1519 const(Loc) varDeclLoc = varDecl.getLoc();
1520 Module varDeclModule = varDecl.getModule(); //This can be null
1522 .error(loc, "variable `%s` is used as a type", mtype.toChars());
1523 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
1524 if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
1526 const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
1527 .errorSupplemental(
1528 varDeclModuleImportLoc,
1529 "variable `%s` is imported here from: `%s`",
1530 varDecl.toChars,
1531 varDeclModule.toPrettyChars,
1535 .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
1537 else
1538 .error(loc, "`%s` is used as a type", mtype.toChars());
1539 return error();
1543 Type visitInstance(TypeInstance mtype)
1545 Type t;
1546 Expression e;
1547 Dsymbol s;
1549 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
1551 const errors = global.errors;
1552 mtype.resolve(loc, sc, e, t, s);
1553 // if we had an error evaluating the symbol, suppress further errors
1554 if (!t && errors != global.errors)
1555 return error();
1558 if (!t)
1560 if (!e && s && s.errors)
1562 // if there was an error evaluating the symbol, it might actually
1563 // be a type. Avoid misleading error messages.
1564 .error(loc, "`%s` had previous errors", mtype.toChars());
1566 else
1567 .error(loc, "`%s` is used as a type", mtype.toChars());
1568 return error();
1570 return t;
1573 Type visitTypeof(TypeTypeof mtype)
1575 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
1576 Expression e;
1577 Type t;
1578 Dsymbol s;
1579 mtype.resolve(loc, sc, e, t, s);
1580 if (s && (t = s.getType()) !is null)
1581 t = t.addMod(mtype.mod);
1582 if (!t)
1584 .error(loc, "`%s` is used as a type", mtype.toChars());
1585 return error();
1587 return t;
1590 Type visitTraits(TypeTraits mtype)
1592 Expression e;
1593 Type t;
1594 Dsymbol s;
1595 mtype.resolve(loc, sc, e, t, s);
1597 if (!t)
1599 if (!global.errors)
1600 .error(mtype.loc, "`%s` does not give a valid type", mtype.toChars);
1601 return error();
1603 return t;
1606 Type visitReturn(TypeReturn mtype)
1608 //printf("TypeReturn::semantic() %s\n", toChars());
1609 Expression e;
1610 Type t;
1611 Dsymbol s;
1612 mtype.resolve(loc, sc, e, t, s);
1613 if (s && (t = s.getType()) !is null)
1614 t = t.addMod(mtype.mod);
1615 if (!t)
1617 .error(loc, "`%s` is used as a type", mtype.toChars());
1618 return error();
1620 return t;
1623 Type visitStruct(TypeStruct mtype)
1625 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
1626 if (mtype.deco)
1627 return mtype;
1629 /* Don't semantic for sym because it should be deferred until
1630 * sizeof needed or its members accessed.
1632 // instead, parent should be set correctly
1633 assert(mtype.sym.parent);
1635 if (mtype.sym.type.ty == Terror)
1636 return error();
1638 return merge(mtype);
1641 Type visitEnum(TypeEnum mtype)
1643 //printf("TypeEnum::semantic() %s\n", toChars());
1644 return mtype.deco ? mtype : merge(mtype);
1647 Type visitClass(TypeClass mtype)
1649 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
1650 if (mtype.deco)
1651 return mtype;
1653 /* Don't semantic for sym because it should be deferred until
1654 * sizeof needed or its members accessed.
1656 // instead, parent should be set correctly
1657 assert(mtype.sym.parent);
1659 if (mtype.sym.type.ty == Terror)
1660 return error();
1662 return merge(mtype);
1665 Type visitTuple(TypeTuple mtype)
1667 //printf("TypeTuple::semantic(this = %p)\n", this);
1668 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
1669 if (!mtype.deco)
1670 mtype.deco = merge(mtype).deco;
1672 /* Don't return merge(), because a tuple with one type has the
1673 * same deco as that type.
1675 return mtype;
1678 Type visitSlice(TypeSlice mtype)
1680 //printf("TypeSlice::semantic() %s\n", toChars());
1681 Type tn = mtype.next.typeSemantic(loc, sc);
1682 //printf("next: %s\n", tn.toChars());
1684 Type tbn = tn.toBasetype();
1685 if (tbn.ty != Ttuple)
1687 .error(loc, "can only slice type sequences, not `%s`", tbn.toChars());
1688 return error();
1690 TypeTuple tt = cast(TypeTuple)tbn;
1692 mtype.lwr = semanticLength(sc, tbn, mtype.lwr);
1693 mtype.upr = semanticLength(sc, tbn, mtype.upr);
1694 mtype.lwr = mtype.lwr.ctfeInterpret();
1695 mtype.upr = mtype.upr.ctfeInterpret();
1696 if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error)
1697 return error();
1699 uinteger_t i1 = mtype.lwr.toUInteger();
1700 uinteger_t i2 = mtype.upr.toUInteger();
1701 if (!(i1 <= i2 && i2 <= tt.arguments.length))
1703 .error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
1704 cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.length);
1705 return error();
1708 mtype.next = tn;
1709 mtype.transitive();
1711 auto args = new Parameters();
1712 args.reserve(cast(size_t)(i2 - i1));
1713 foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2])
1715 args.push(arg);
1717 Type t = new TypeTuple(args);
1718 return t.typeSemantic(loc, sc);
1721 Type visitMixin(TypeMixin mtype)
1723 //printf("TypeMixin::semantic() %s\n", toChars());
1725 Expression e;
1726 Type t;
1727 Dsymbol s;
1728 mtype.resolve(loc, sc, e, t, s);
1730 if (t && t.ty != Terror)
1731 return t;
1733 .error(mtype.loc, "`mixin(%s)` does not give a valid type", mtype.obj.toChars);
1734 return error();
1737 Type visitTag(TypeTag mtype)
1739 //printf("TypeTag.semantic() %s\n", mtype.toChars());
1740 if (mtype.resolved)
1742 /* struct S s, *p;
1744 return mtype.resolved.addSTC(mtype.mod);
1747 /* Find the current scope by skipping tag scopes.
1748 * In C, tag scopes aren't considered scopes.
1750 Scope* sc2 = sc;
1751 while (1)
1753 sc2 = sc2.inner();
1754 auto scopesym = sc2.scopesym;
1755 if (scopesym.isStructDeclaration())
1757 sc2 = sc2.enclosing;
1758 continue;
1760 break;
1763 /* Declare mtype as a struct/union/enum declaration
1765 void declareTag()
1767 void declare(ScopeDsymbol sd)
1769 sd.members = mtype.members;
1770 auto scopesym = sc2.inner().scopesym;
1771 if (scopesym.members)
1772 scopesym.members.push(sd);
1773 if (scopesym.symtab && !scopesym.symtabInsert(sd))
1775 Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
1776 handleTagSymbols(*sc2, sd, s2, scopesym);
1778 sd.parent = sc2.parent;
1779 sd.dsymbolSemantic(sc2);
1782 switch (mtype.tok)
1784 case TOK.enum_:
1785 auto ed = new EnumDeclaration(mtype.loc, mtype.id, mtype.base);
1786 declare(ed);
1787 mtype.resolved = visitEnum(new TypeEnum(ed));
1788 break;
1790 case TOK.struct_:
1791 auto sd = new StructDeclaration(mtype.loc, mtype.id, false);
1792 sd.alignment = mtype.packalign;
1793 declare(sd);
1794 mtype.resolved = visitStruct(new TypeStruct(sd));
1795 break;
1797 case TOK.union_:
1798 auto ud = new UnionDeclaration(mtype.loc, mtype.id);
1799 ud.alignment = mtype.packalign;
1800 declare(ud);
1801 mtype.resolved = visitStruct(new TypeStruct(ud));
1802 break;
1804 default:
1805 assert(0);
1809 /* If it doesn't have a tag by now, supply one.
1810 * It'll be unique, and therefore introducing.
1811 * Declare it, and done.
1813 if (!mtype.id)
1815 mtype.id = Identifier.generateId("__tag"[]);
1816 declareTag();
1817 return mtype.resolved.addSTC(mtype.mod);
1820 /* look for pre-existing declaration
1822 Dsymbol scopesym;
1823 auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
1824 if (!s || s.isModule())
1826 // no pre-existing declaration, so declare it
1827 if (mtype.tok == TOK.enum_ && !mtype.members)
1828 .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
1829 declareTag();
1830 return mtype.resolved.addSTC(mtype.mod);
1833 /* A redeclaration only happens if both declarations are in
1834 * the same scope
1836 const bool redeclar = (scopesym == sc2.inner().scopesym);
1838 if (redeclar)
1840 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
1842 auto ed = s.isEnumDeclaration();
1843 if (mtype.members && ed.members)
1844 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
1845 else if (!ed.members)
1847 ed.members = mtype.members;
1849 else
1852 mtype.resolved = ed.type;
1854 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
1855 mtype.tok == TOK.struct_ && s.isStructDeclaration())
1857 // Add members to original declaration
1858 auto sd = s.isStructDeclaration();
1859 if (mtype.members && sd.members)
1861 /* struct S { int b; };
1862 * struct S { int a; } *s;
1864 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
1866 else if (!sd.members)
1868 /* struct S;
1869 * struct S { int a; } *s;
1871 sd.members = mtype.members;
1872 if (sd.semanticRun == PASS.semanticdone)
1874 /* The first semantic pass marked `sd` as an opaque struct.
1875 * Re-run semantic so that all newly assigned members are
1876 * picked up and added to the symtab.
1878 sd.semanticRun = PASS.semantic;
1879 sd.dsymbolSemantic(sc2);
1882 else
1884 /* struct S { int a; };
1885 * struct S *s;
1888 mtype.resolved = sd.type;
1890 else
1892 /* int S;
1893 * struct S { int a; } *s;
1895 .error(mtype.loc, "redeclaration of `%s`", mtype.id.toChars());
1896 mtype.resolved = error();
1899 else if (mtype.members)
1901 /* struct S;
1902 * { struct S { int a; } *s; }
1904 declareTag();
1906 else
1908 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
1910 mtype.resolved = s.isEnumDeclaration().type;
1912 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
1913 mtype.tok == TOK.struct_ && s.isStructDeclaration())
1915 /* struct S;
1916 * { struct S *s; }
1918 mtype.resolved = s.isStructDeclaration().type;
1920 else
1922 /* union S;
1923 * { struct S *s; }
1925 .error(mtype.loc, "redeclaring `%s %s` as `%s %s`",
1926 s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars());
1927 declareTag();
1930 return mtype.resolved.addSTC(mtype.mod);
1933 switch (type.ty)
1935 default: return visitType(type);
1936 case Tcomplex32:
1937 case Tcomplex64:
1938 case Tcomplex80: return visitComplex(type.isTypeBasic());
1939 case Tvector: return visitVector(type.isTypeVector());
1940 case Tsarray: return visitSArray(type.isTypeSArray());
1941 case Tarray: return visitDArray(type.isTypeDArray());
1942 case Taarray: return visitAArray(type.isTypeAArray());
1943 case Tpointer: return visitPointer(type.isTypePointer());
1944 case Treference: return visitReference(type.isTypeReference());
1945 case Tfunction: return visitFunction(type.isTypeFunction());
1946 case Tdelegate: return visitDelegate(type.isTypeDelegate());
1947 case Tident: return visitIdentifier(type.isTypeIdentifier());
1948 case Tinstance: return visitInstance(type.isTypeInstance());
1949 case Ttypeof: return visitTypeof(type.isTypeTypeof());
1950 case Ttraits: return visitTraits(type.isTypeTraits());
1951 case Treturn: return visitReturn(type.isTypeReturn());
1952 case Tstruct: return visitStruct(type.isTypeStruct());
1953 case Tenum: return visitEnum(type.isTypeEnum());
1954 case Tclass: return visitClass(type.isTypeClass());
1955 case Ttuple: return visitTuple(type.isTypeTuple());
1956 case Tslice: return visitSlice(type.isTypeSlice());
1957 case Tmixin: return visitMixin(type.isTypeMixin());
1958 case Ttag: return visitTag(type.isTypeTag());
1962 /************************************
1963 * If an identical type to `type` is in `type.stringtable`, return
1964 * the latter one. Otherwise, add it to `type.stringtable`.
1965 * Some types don't get merged and are returned as-is.
1966 * Params:
1967 * type = Type to check against existing types
1968 * Returns:
1969 * the type that was merged
1971 extern (C++) Type merge(Type type)
1973 switch (type.ty)
1975 case Terror:
1976 case Ttypeof:
1977 case Tident:
1978 case Tinstance:
1979 case Tmixin:
1980 case Ttag:
1981 return type; // don't merge placeholder types
1983 case Tsarray:
1984 // prevents generating the mangle if the array dim is not yet known
1985 if (!type.isTypeSArray().dim.isIntegerExp())
1986 return type;
1987 goto default;
1989 case Tenum:
1990 break;
1992 case Taarray:
1993 if (!type.isTypeAArray().index.merge().deco)
1994 return type;
1995 goto default;
1997 default:
1998 if (type.nextOf() && !type.nextOf().deco)
1999 return type;
2000 break;
2003 //printf("merge(%s)\n", toChars());
2004 if (!type.deco)
2006 OutBuffer buf;
2007 buf.reserve(32);
2009 mangleToBuffer(type, buf);
2011 auto sv = type.stringtable.update(buf[]);
2012 if (sv.value)
2014 Type t = sv.value;
2015 debug
2017 import core.stdc.stdio;
2018 if (!t.deco)
2019 printf("t = %s\n", t.toChars());
2021 assert(t.deco);
2022 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2023 return t;
2025 else
2027 Type t = stripDefaultArgs(type);
2028 sv.value = t;
2029 type.deco = t.deco = cast(char*)sv.toDchars();
2030 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2031 return t;
2034 return type;
2037 /***************************************
2038 * Calculate built-in properties which just the type is necessary.
2040 * Params:
2041 * t = the type for which the property is calculated
2042 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2043 * loc = the location where the property is encountered
2044 * ident = the identifier of the property
2045 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2046 * src = expression for type `t` or null.
2047 * Returns:
2048 * expression representing the property, or null if not a property and (flag & 1)
2050 Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag,
2051 Expression src = null)
2053 Expression visitType(Type mt)
2055 Expression e;
2056 static if (LOGDOTEXP)
2058 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2060 if (ident == Id.__sizeof)
2062 const sz = mt.size(loc);
2063 if (sz == SIZE_INVALID)
2064 return ErrorExp.get();
2065 e = new IntegerExp(loc, sz, Type.tsize_t);
2067 else if (ident == Id.__xalignof)
2069 const explicitAlignment = mt.alignment();
2070 const naturalAlignment = mt.alignsize();
2071 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
2072 e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
2074 else if (ident == Id._init)
2076 Type tb = mt.toBasetype();
2077 e = mt.defaultInitLiteral(loc);
2078 if (tb.ty == Tstruct && tb.needsNested())
2080 e.isStructLiteralExp().useStaticInit = true;
2083 else if (ident == Id._mangleof)
2085 if (!mt.deco)
2087 error(loc, "forward reference of type `%s.mangleof`", mt.toChars());
2088 e = ErrorExp.get();
2090 else
2092 e = new StringExp(loc, mt.deco.toDString());
2093 Scope sc;
2094 sc.eSink = global.errorSink;
2095 e = e.expressionSemantic(&sc);
2098 else if (ident == Id.stringof)
2100 const s = mt.toChars();
2101 e = new StringExp(loc, s.toDString());
2102 Scope sc;
2103 sc.eSink = global.errorSink;
2104 e = e.expressionSemantic(&sc);
2106 else if (flag && mt != Type.terror)
2108 return null;
2110 else
2112 Dsymbol s = null;
2113 if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
2114 s = mt.toDsymbol(null);
2115 if (s)
2116 s = s.search_correct(ident);
2117 if (s && !symbolIsVisible(scope_, s))
2118 s = null;
2119 if (mt != Type.terror)
2121 if (s)
2122 error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
2123 else if (ident == Id.call && mt.ty == Tclass)
2124 error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
2126 else if (const n = importHint(ident.toString()))
2127 error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
2128 else
2130 if (src)
2131 error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true));
2132 else
2133 error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
2135 if (auto dsym = mt.toDsymbol(scope_))
2137 if (auto sym = dsym.isAggregateDeclaration())
2139 if (auto fd = search_function(sym, Id.opDispatch))
2140 errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
2141 else if (!sym.members)
2142 errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
2144 errorSupplemental(dsym.loc, "%s `%s` defined here",
2145 dsym.kind, dsym.toChars());
2149 e = ErrorExp.get();
2151 return e;
2154 Expression visitError(TypeError)
2156 return ErrorExp.get();
2159 Expression visitBasic(TypeBasic mt)
2161 Expression integerValue(dinteger_t i)
2163 return new IntegerExp(loc, i, mt);
2166 Expression intValue(dinteger_t i)
2168 return new IntegerExp(loc, i, Type.tint32);
2171 Expression floatValue(real_t r)
2173 if (mt.isreal() || mt.isimaginary())
2174 return new RealExp(loc, r, mt);
2175 else
2177 return new ComplexExp(loc, complex_t(r, r), mt);
2181 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
2182 if (ident == Id.max)
2184 switch (mt.ty)
2186 case Tint8: return integerValue(byte.max);
2187 case Tuns8: return integerValue(ubyte.max);
2188 case Tint16: return integerValue(short.max);
2189 case Tuns16: return integerValue(ushort.max);
2190 case Tint32: return integerValue(int.max);
2191 case Tuns32: return integerValue(uint.max);
2192 case Tint64: return integerValue(long.max);
2193 case Tuns64: return integerValue(ulong.max);
2194 case Tbool: return integerValue(bool.max);
2195 case Tchar: return integerValue(char.max);
2196 case Twchar: return integerValue(wchar.max);
2197 case Tdchar: return integerValue(dchar.max);
2198 case Tcomplex32:
2199 case Timaginary32:
2200 case Tfloat32: return floatValue(target.FloatProperties.max);
2201 case Tcomplex64:
2202 case Timaginary64:
2203 case Tfloat64: return floatValue(target.DoubleProperties.max);
2204 case Tcomplex80:
2205 case Timaginary80:
2206 case Tfloat80: return floatValue(target.RealProperties.max);
2207 default: break;
2210 else if (ident == Id.min)
2212 switch (mt.ty)
2214 case Tint8: return integerValue(byte.min);
2215 case Tuns8:
2216 case Tuns16:
2217 case Tuns32:
2218 case Tuns64:
2219 case Tbool:
2220 case Tchar:
2221 case Twchar:
2222 case Tdchar: return integerValue(0);
2223 case Tint16: return integerValue(short.min);
2224 case Tint32: return integerValue(int.min);
2225 case Tint64: return integerValue(long.min);
2226 default: break;
2229 else if (ident == Id.min_normal)
2231 switch (mt.ty)
2233 case Tcomplex32:
2234 case Timaginary32:
2235 case Tfloat32: return floatValue(target.FloatProperties.min_normal);
2236 case Tcomplex64:
2237 case Timaginary64:
2238 case Tfloat64: return floatValue(target.DoubleProperties.min_normal);
2239 case Tcomplex80:
2240 case Timaginary80:
2241 case Tfloat80: return floatValue(target.RealProperties.min_normal);
2242 default: break;
2245 else if (ident == Id.nan)
2247 switch (mt.ty)
2249 case Tcomplex32:
2250 case Tcomplex64:
2251 case Tcomplex80:
2252 case Timaginary32:
2253 case Timaginary64:
2254 case Timaginary80:
2255 case Tfloat32:
2256 case Tfloat64:
2257 case Tfloat80: return floatValue(target.RealProperties.nan);
2258 default: break;
2261 else if (ident == Id.infinity)
2263 switch (mt.ty)
2265 case Tcomplex32:
2266 case Tcomplex64:
2267 case Tcomplex80:
2268 case Timaginary32:
2269 case Timaginary64:
2270 case Timaginary80:
2271 case Tfloat32:
2272 case Tfloat64:
2273 case Tfloat80: return floatValue(target.RealProperties.infinity);
2274 default: break;
2277 else if (ident == Id.dig)
2279 switch (mt.ty)
2281 case Tcomplex32:
2282 case Timaginary32:
2283 case Tfloat32: return intValue(target.FloatProperties.dig);
2284 case Tcomplex64:
2285 case Timaginary64:
2286 case Tfloat64: return intValue(target.DoubleProperties.dig);
2287 case Tcomplex80:
2288 case Timaginary80:
2289 case Tfloat80: return intValue(target.RealProperties.dig);
2290 default: break;
2293 else if (ident == Id.epsilon)
2295 switch (mt.ty)
2297 case Tcomplex32:
2298 case Timaginary32:
2299 case Tfloat32: return floatValue(target.FloatProperties.epsilon);
2300 case Tcomplex64:
2301 case Timaginary64:
2302 case Tfloat64: return floatValue(target.DoubleProperties.epsilon);
2303 case Tcomplex80:
2304 case Timaginary80:
2305 case Tfloat80: return floatValue(target.RealProperties.epsilon);
2306 default: break;
2309 else if (ident == Id.mant_dig)
2311 switch (mt.ty)
2313 case Tcomplex32:
2314 case Timaginary32:
2315 case Tfloat32: return intValue(target.FloatProperties.mant_dig);
2316 case Tcomplex64:
2317 case Timaginary64:
2318 case Tfloat64: return intValue(target.DoubleProperties.mant_dig);
2319 case Tcomplex80:
2320 case Timaginary80:
2321 case Tfloat80: return intValue(target.RealProperties.mant_dig);
2322 default: break;
2325 else if (ident == Id.max_10_exp)
2327 switch (mt.ty)
2329 case Tcomplex32:
2330 case Timaginary32:
2331 case Tfloat32: return intValue(target.FloatProperties.max_10_exp);
2332 case Tcomplex64:
2333 case Timaginary64:
2334 case Tfloat64: return intValue(target.DoubleProperties.max_10_exp);
2335 case Tcomplex80:
2336 case Timaginary80:
2337 case Tfloat80: return intValue(target.RealProperties.max_10_exp);
2338 default: break;
2341 else if (ident == Id.max_exp)
2343 switch (mt.ty)
2345 case Tcomplex32:
2346 case Timaginary32:
2347 case Tfloat32: return intValue(target.FloatProperties.max_exp);
2348 case Tcomplex64:
2349 case Timaginary64:
2350 case Tfloat64: return intValue(target.DoubleProperties.max_exp);
2351 case Tcomplex80:
2352 case Timaginary80:
2353 case Tfloat80: return intValue(target.RealProperties.max_exp);
2354 default: break;
2357 else if (ident == Id.min_10_exp)
2359 switch (mt.ty)
2361 case Tcomplex32:
2362 case Timaginary32:
2363 case Tfloat32: return intValue(target.FloatProperties.min_10_exp);
2364 case Tcomplex64:
2365 case Timaginary64:
2366 case Tfloat64: return intValue(target.DoubleProperties.min_10_exp);
2367 case Tcomplex80:
2368 case Timaginary80:
2369 case Tfloat80: return intValue(target.RealProperties.min_10_exp);
2370 default: break;
2373 else if (ident == Id.min_exp)
2375 switch (mt.ty)
2377 case Tcomplex32:
2378 case Timaginary32:
2379 case Tfloat32: return intValue(target.FloatProperties.min_exp);
2380 case Tcomplex64:
2381 case Timaginary64:
2382 case Tfloat64: return intValue(target.DoubleProperties.min_exp);
2383 case Tcomplex80:
2384 case Timaginary80:
2385 case Tfloat80: return intValue(target.RealProperties.min_exp);
2386 default: break;
2389 return visitType(mt);
2392 Expression visitVector(TypeVector mt)
2394 return visitType(mt);
2397 Expression visitEnum(TypeEnum mt)
2399 Expression e;
2400 if (ident == Id.max || ident == Id.min)
2402 return mt.sym.getMaxMinValue(loc, ident);
2404 else if (ident == Id._init)
2406 e = mt.defaultInitLiteral(loc);
2408 else if (ident == Id.stringof)
2410 e = new StringExp(loc, mt.toString());
2411 Scope sc;
2412 e = e.expressionSemantic(&sc);
2414 else if (ident == Id._mangleof)
2416 e = visitType(mt);
2418 else
2420 e = mt.toBasetype().getProperty(scope_, loc, ident, flag);
2422 return e;
2425 Expression visitTuple(TypeTuple mt)
2427 Expression e;
2428 static if (LOGDOTEXP)
2430 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2432 if (ident == Id.length)
2434 e = new IntegerExp(loc, mt.arguments.length, Type.tsize_t);
2436 else if (ident == Id._init)
2438 e = mt.defaultInitLiteral(loc);
2440 else if (flag)
2442 e = null;
2444 else
2446 error(loc, "no property `%s` for sequence `%s`", ident.toChars(), mt.toChars());
2447 e = ErrorExp.get();
2449 return e;
2452 switch (t.ty)
2454 default: return t.isTypeBasic() ?
2455 visitBasic(cast(TypeBasic)t) :
2456 visitType(t);
2458 case Terror: return visitError (t.isTypeError());
2459 case Tvector: return visitVector(t.isTypeVector());
2460 case Tenum: return visitEnum (t.isTypeEnum());
2461 case Ttuple: return visitTuple (t.isTypeTuple());
2465 /***************************************
2466 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
2467 * Params:
2468 * exp = Expression to look at
2469 * t = if exp should be a Type, set t to that Type else null
2470 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
2471 * e = if exp should remain an Expression, set e to that Expression else null
2474 private void resolveExp(Expression exp, out Type t, out Expression e, out Dsymbol s)
2476 if (exp.isTypeExp())
2477 t = exp.type;
2478 else if (auto ve = exp.isVarExp())
2480 if (auto v = ve.var.isVarDeclaration())
2481 e = exp;
2482 else
2483 s = ve.var;
2485 else if (auto te = exp.isTemplateExp())
2486 s = te.td;
2487 else if (auto se = exp.isScopeExp())
2488 s = se.sds;
2489 else if (exp.isFuncExp())
2490 s = getDsymbol(exp);
2491 else if (auto dte = exp.isDotTemplateExp())
2492 s = dte.td;
2493 else if (exp.isErrorExp())
2494 t = Type.terror;
2495 else
2496 e = exp;
2499 /************************************
2500 * Resolve type 'mt' to either type, symbol, or expression.
2501 * If errors happened, resolved to Type.terror.
2503 * Params:
2504 * mt = type to be resolved
2505 * loc = the location where the type is encountered
2506 * sc = the scope of the type
2507 * pe = is set if t is an expression
2508 * pt = is set if t is a type
2509 * ps = is set if t is a symbol
2510 * intypeid = true if in type id
2512 void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
2514 void returnExp(Expression e)
2516 pe = e;
2517 pt = null;
2518 ps = null;
2521 void returnType(Type t)
2523 pe = null;
2524 pt = t;
2525 ps = null;
2528 void returnSymbol(Dsymbol s)
2530 pe = null;
2531 pt = null;
2532 ps = s;
2535 void returnError()
2537 returnType(Type.terror);
2540 void visitType(Type mt)
2542 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
2543 Type t = typeSemantic(mt, loc, sc);
2544 assert(t);
2545 returnType(t);
2548 void visitSArray(TypeSArray mt)
2550 //printf("TypeSArray::resolve() %s\n", mt.toChars());
2551 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2552 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2553 if (pe)
2555 // It's really an index expression
2556 if (Dsymbol s = getDsymbol(pe))
2557 pe = new DsymbolExp(loc, s);
2558 returnExp(new ArrayExp(loc, pe, mt.dim));
2560 else if (ps)
2562 Dsymbol s = ps;
2563 if (auto tup = s.isTupleDeclaration())
2565 mt.dim = semanticLength(sc, tup, mt.dim);
2566 mt.dim = mt.dim.ctfeInterpret();
2567 if (mt.dim.op == EXP.error)
2568 return returnError();
2570 const d = mt.dim.toUInteger();
2571 if (d >= tup.objects.length)
2573 error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong) tup.objects.length);
2574 return returnError();
2577 RootObject o = (*tup.objects)[cast(size_t)d];
2578 switch (o.dyncast()) with (DYNCAST)
2580 case dsymbol:
2581 return returnSymbol(cast(Dsymbol)o);
2582 case expression:
2583 Expression e = cast(Expression)o;
2584 if (e.op == EXP.dSymbol)
2585 return returnSymbol(e.isDsymbolExp().s);
2586 else
2587 return returnExp(e);
2588 case type:
2589 return returnType((cast(Type)o).addMod(mt.mod));
2590 default:
2591 break;
2594 /* Create a new TupleDeclaration which
2595 * is a slice [d..d+1] out of the old one.
2596 * Do it this way because TemplateInstance::semanticTiargs()
2597 * can handle unresolved Objects this way.
2599 auto objects = new Objects(1);
2600 (*objects)[0] = o;
2601 return returnSymbol(new TupleDeclaration(loc, tup.ident, objects));
2603 else
2604 return visitType(mt);
2606 else
2608 if (pt.ty != Terror)
2609 mt.next = pt; // prevent re-running semantic() on 'next'
2610 visitType(mt);
2615 void visitDArray(TypeDArray mt)
2617 //printf("TypeDArray::resolve() %s\n", mt.toChars());
2618 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2619 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2620 if (pe)
2622 // It's really a slice expression
2623 if (Dsymbol s = getDsymbol(pe))
2624 pe = new DsymbolExp(loc, s);
2625 returnExp(new ArrayExp(loc, pe));
2627 else if (ps)
2629 if (auto tup = ps.isTupleDeclaration())
2631 // keep ps
2633 else
2634 visitType(mt);
2636 else
2638 if (pt.ty != Terror)
2639 mt.next = pt; // prevent re-running semantic() on 'next'
2640 visitType(mt);
2644 void visitAArray(TypeAArray mt)
2646 //printf("TypeAArray::resolve() %s\n", mt.toChars());
2647 // Deal with the case where we thought the index was a type, but
2648 // in reality it was an expression.
2649 if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray)
2651 Expression e;
2652 Type t;
2653 Dsymbol s;
2654 mt.index.resolve(loc, sc, e, t, s, intypeid);
2655 if (e)
2657 // It was an expression -
2658 // Rewrite as a static array
2659 auto tsa = new TypeSArray(mt.next, e);
2660 tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done
2661 return tsa.resolve(loc, sc, pe, pt, ps, intypeid);
2663 else if (t)
2664 mt.index = t;
2665 else
2666 .error(loc, "index is not a type or an expression");
2668 visitType(mt);
2671 /*************************************
2672 * Takes an array of Identifiers and figures out if
2673 * it represents a Type or an Expression.
2674 * Output:
2675 * if expression, pe is set
2676 * if type, pt is set
2678 void visitIdentifier(TypeIdentifier mt)
2680 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2681 if (mt.ident == Id.ctfe)
2683 error(loc, "variable `__ctfe` cannot be read at compile time");
2684 return returnError();
2686 if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h
2688 /* Since we don't support __builtin_va_start, -arg, -end, we don't
2689 * have to actually care what -list is. A void* will do.
2690 * If we ever do care, import core.stdc.stdarg and pull
2691 * the definition out of that, similarly to how std.math is handled for PowExp
2693 pt = target.va_listType(loc, sc);
2694 return;
2697 Dsymbol scopesym;
2698 Dsymbol s = sc.search(loc, mt.ident, &scopesym);
2700 * https://issues.dlang.org/show_bug.cgi?id=1170
2701 * https://issues.dlang.org/show_bug.cgi?id=10739
2703 * If a symbol is not found, it might be declared in
2704 * a mixin-ed string or a mixin-ed template, so before
2705 * issuing an error semantically analyze all string/template
2706 * mixins that are members of the current ScopeDsymbol.
2708 if (!s && sc.enclosing)
2710 ScopeDsymbol sds = sc.enclosing.scopesym;
2711 if (sds && sds.members)
2713 void semanticOnMixin(Dsymbol member)
2715 if (auto compileDecl = member.isMixinDeclaration())
2716 compileDecl.dsymbolSemantic(sc);
2717 else if (auto mixinTempl = member.isTemplateMixin())
2718 mixinTempl.dsymbolSemantic(sc);
2720 sds.members.foreachDsymbol( s => semanticOnMixin(s) );
2721 s = sc.search(loc, mt.ident, &scopesym);
2725 if (s)
2727 // https://issues.dlang.org/show_bug.cgi?id=16042
2728 // If `f` is really a function template, then replace `f`
2729 // with the function template declaration.
2730 if (auto f = s.isFuncDeclaration())
2732 if (auto td = getFuncTemplateDecl(f))
2734 // If not at the beginning of the overloaded list of
2735 // `TemplateDeclaration`s, then get the beginning
2736 if (td.overroot)
2737 td = td.overroot;
2738 s = td;
2743 mt.resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
2744 if (pt)
2745 pt = pt.addMod(mt.mod);
2748 void visitInstance(TypeInstance mt)
2750 // Note close similarity to TypeIdentifier::resolve()
2752 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
2753 mt.tempinst.dsymbolSemantic(sc);
2754 if (!global.gag && mt.tempinst.errors)
2755 return returnError();
2757 mt.resolveHelper(loc, sc, mt.tempinst, null, pe, pt, ps, intypeid);
2758 if (pt)
2759 pt = pt.addMod(mt.mod);
2760 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
2763 void visitTypeof(TypeTypeof mt)
2765 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
2766 //static int nest; if (++nest == 50) *(char*)0=0;
2767 if (sc is null)
2769 error(loc, "invalid scope");
2770 return returnError();
2772 if (mt.inuse)
2774 mt.inuse = 2;
2775 error(loc, "circular `typeof` definition");
2776 Lerr:
2777 mt.inuse--;
2778 return returnError();
2780 mt.inuse++;
2782 /* Currently we cannot evaluate 'exp' in speculative context, because
2783 * the type implementation may leak to the final execution. Consider:
2785 * struct S(T) {
2786 * string toString() const { return "x"; }
2788 * void main() {
2789 * alias X = typeof(S!int());
2790 * assert(typeid(X).toString() == "x");
2793 Scope* sc2 = sc.push();
2795 if (!mt.exp.isTypeidExp())
2796 /* Treat typeof(typeid(exp)) as needing
2797 * the full semantic analysis of the typeid.
2798 * https://issues.dlang.org/show_bug.cgi?id=20958
2800 sc2.intypeof = 1;
2802 auto exp2 = mt.exp.expressionSemantic(sc2);
2803 exp2 = resolvePropertiesOnly(sc2, exp2);
2804 sc2.pop();
2806 if (exp2.op == EXP.error)
2808 if (!global.gag)
2809 mt.exp = exp2;
2810 goto Lerr;
2812 mt.exp = exp2;
2814 if ((mt.exp.op == EXP.type || mt.exp.op == EXP.scope_) &&
2815 // https://issues.dlang.org/show_bug.cgi?id=23863
2816 // compile time sequences are valid types
2817 !mt.exp.type.isTypeTuple())
2819 if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof
2820 mt.exp.checkType())
2821 goto Lerr;
2823 /* Today, 'typeof(func)' returns void if func is a
2824 * function template (TemplateExp), or
2825 * template lambda (FuncExp).
2826 * It's actually used in Phobos as an idiom, to branch code for
2827 * template functions.
2830 if (auto f = mt.exp.op == EXP.variable ? mt.exp.isVarExp().var.isFuncDeclaration()
2831 : mt.exp.op == EXP.dotVariable ? mt.exp.isDotVarExp().var.isFuncDeclaration() : null)
2833 // f might be a unittest declaration which is incomplete when compiled
2834 // without -unittest. That causes a segfault in checkForwardRef, see
2835 // https://issues.dlang.org/show_bug.cgi?id=20626
2836 if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && f.checkForwardRef(loc))
2837 goto Lerr;
2839 if (auto f = isFuncAddress(mt.exp))
2841 if (f.checkForwardRef(loc))
2842 goto Lerr;
2845 Type t = mt.exp.type;
2846 if (!t)
2848 error(loc, "expression `%s` has no type", mt.exp.toChars());
2849 goto Lerr;
2851 if (t.ty == Ttypeof)
2853 error(loc, "forward reference to `%s`", mt.toChars());
2854 goto Lerr;
2856 if (mt.idents.length == 0)
2858 returnType(t.addMod(mt.mod));
2860 else
2862 if (Dsymbol s = t.toDsymbol(sc))
2863 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
2864 else
2866 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
2867 e = e.expressionSemantic(sc);
2868 resolveExp(e, pt, pe, ps);
2870 if (pt)
2871 pt = pt.addMod(mt.mod);
2873 mt.inuse--;
2876 void visitReturn(TypeReturn mt)
2878 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2879 Type t;
2881 FuncDeclaration func = sc.func;
2882 if (!func)
2884 error(loc, "`typeof(return)` must be inside function");
2885 return returnError();
2887 if (func.fes)
2888 func = func.fes.func;
2889 t = func.type.nextOf();
2890 if (!t)
2892 error(loc, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc.func.toChars());
2893 return returnError();
2896 if (mt.idents.length == 0)
2898 return returnType(t.addMod(mt.mod));
2900 else
2902 if (Dsymbol s = t.toDsymbol(sc))
2903 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
2904 else
2906 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
2907 e = e.expressionSemantic(sc);
2908 resolveExp(e, pt, pe, ps);
2910 if (pt)
2911 pt = pt.addMod(mt.mod);
2915 void visitSlice(TypeSlice mt)
2917 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2918 if (pe)
2920 // It's really a slice expression
2921 if (Dsymbol s = getDsymbol(pe))
2922 pe = new DsymbolExp(loc, s);
2923 return returnExp(new ArrayExp(loc, pe, new IntervalExp(loc, mt.lwr, mt.upr)));
2925 else if (ps)
2927 Dsymbol s = ps;
2928 TupleDeclaration td = s.isTupleDeclaration();
2929 if (td)
2931 /* It's a slice of a TupleDeclaration
2933 ScopeDsymbol sym = new ArrayScopeSymbol(sc, td);
2934 sym.parent = sc.scopesym;
2935 sc = sc.push(sym);
2936 sc = sc.startCTFE();
2937 mt.lwr = mt.lwr.expressionSemantic(sc);
2938 mt.upr = mt.upr.expressionSemantic(sc);
2939 sc = sc.endCTFE();
2940 sc = sc.pop();
2942 mt.lwr = mt.lwr.ctfeInterpret();
2943 mt.upr = mt.upr.ctfeInterpret();
2944 const i1 = mt.lwr.toUInteger();
2945 const i2 = mt.upr.toUInteger();
2946 if (!(i1 <= i2 && i2 <= td.objects.length))
2948 error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1, i2, cast(ulong) td.objects.length);
2949 return returnError();
2952 if (i1 == 0 && i2 == td.objects.length)
2954 return returnSymbol(td);
2957 /* Create a new TupleDeclaration which
2958 * is a slice [i1..i2] out of the old one.
2960 auto objects = new Objects(cast(size_t)(i2 - i1));
2961 for (size_t i = 0; i < objects.length; i++)
2963 (*objects)[i] = (*td.objects)[cast(size_t)i1 + i];
2966 return returnSymbol(new TupleDeclaration(loc, td.ident, objects));
2968 else
2969 visitType(mt);
2971 else
2973 if (pt.ty != Terror)
2974 mt.next = pt; // prevent re-running semantic() on 'next'
2975 visitType(mt);
2979 void visitMixin(TypeMixin mt)
2981 RootObject o = mt.obj;
2983 // if already resolved just set pe/pt/ps and return.
2984 if (o)
2986 pe = o.isExpression();
2987 pt = o.isType();
2988 ps = o.isDsymbol();
2989 return;
2992 o = mt.compileTypeMixin(loc, sc);
2993 if (auto t = o.isType())
2995 resolve(t, loc, sc, pe, pt, ps, intypeid);
2996 if (pt)
2997 pt = pt.addMod(mt.mod);
2999 else if (auto e = o.isExpression())
3001 e = e.expressionSemantic(sc);
3002 if (auto et = e.isTypeExp())
3003 returnType(et.type.addMod(mt.mod));
3004 else
3005 returnExp(e);
3007 else
3008 returnError();
3010 // save the result
3011 mt.obj = pe ? pe : (pt ? pt : ps);
3014 void visitTraits(TypeTraits mt)
3016 // if already resolved just return the cached object.
3017 if (mt.obj)
3019 pt = mt.obj.isType();
3020 ps = mt.obj.isDsymbol();
3021 pe = mt.obj.isExpression();
3022 return;
3025 import dmd.traits : semanticTraits;
3027 if (Expression e = semanticTraits(mt.exp, sc))
3029 switch (e.op)
3031 case EXP.dotVariable:
3032 mt.obj = e.isDotVarExp().var;
3033 break;
3034 case EXP.variable:
3035 mt.obj = e.isVarExp().var;
3036 break;
3037 case EXP.function_:
3038 auto fe = e.isFuncExp();
3039 mt.obj = fe.td ? fe.td : fe.fd;
3040 break;
3041 case EXP.dotTemplateDeclaration:
3042 mt.obj = e.isDotTemplateExp().td;
3043 break;
3044 case EXP.dSymbol:
3045 mt.obj = e.isDsymbolExp().s;
3046 break;
3047 case EXP.template_:
3048 mt.obj = e.isTemplateExp().td;
3049 break;
3050 case EXP.scope_:
3051 mt.obj = e.isScopeExp().sds;
3052 break;
3053 case EXP.tuple:
3054 TupleExp te = e.isTupleExp();
3055 Objects* elems = new Objects(te.exps.length);
3056 foreach (i; 0 .. elems.length)
3058 auto src = (*te.exps)[i];
3059 switch (src.op)
3061 case EXP.type:
3062 (*elems)[i] = src.isTypeExp().type;
3063 break;
3064 case EXP.dotType:
3065 (*elems)[i] = src.isDotTypeExp().sym.isType();
3066 break;
3067 case EXP.overloadSet:
3068 (*elems)[i] = src.isOverExp().type;
3069 break;
3070 default:
3071 if (auto sym = isDsymbol(src))
3072 (*elems)[i] = sym;
3073 else
3074 (*elems)[i] = src;
3077 TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
3078 mt.obj = td;
3079 break;
3080 case EXP.dotType:
3081 mt.obj = e.isDotTypeExp().sym.isType();
3082 break;
3083 case EXP.type:
3084 mt.obj = e.isTypeExp().type;
3085 break;
3086 case EXP.overloadSet:
3087 mt.obj = e.isOverExp().type;
3088 break;
3089 case EXP.error:
3090 break;
3091 default:
3092 mt.obj = e;
3093 break;
3097 if (mt.obj)
3099 if (auto t = mt.obj.isType())
3101 t = t.addMod(mt.mod);
3102 mt.obj = t;
3103 returnType(t);
3105 else if (auto s = mt.obj.isDsymbol())
3106 returnSymbol(s);
3107 else if (auto e = mt.obj.isExpression())
3108 returnExp(e);
3110 else
3112 assert(global.errors);
3113 mt.obj = Type.terror;
3114 return returnError();
3118 switch (mt.ty)
3120 default: visitType (mt); break;
3121 case Tsarray: visitSArray (mt.isTypeSArray()); break;
3122 case Tarray: visitDArray (mt.isTypeDArray()); break;
3123 case Taarray: visitAArray (mt.isTypeAArray()); break;
3124 case Tident: visitIdentifier(mt.isTypeIdentifier()); break;
3125 case Tinstance: visitInstance (mt.isTypeInstance()); break;
3126 case Ttypeof: visitTypeof (mt.isTypeTypeof()); break;
3127 case Treturn: visitReturn (mt.isTypeReturn()); break;
3128 case Tslice: visitSlice (mt.isTypeSlice()); break;
3129 case Tmixin: visitMixin (mt.isTypeMixin()); break;
3130 case Ttraits: visitTraits (mt.isTypeTraits()); break;
3134 /************************
3135 * Access the members of the object e. This type is same as e.type.
3136 * Params:
3137 * mt = type for which the dot expression is used
3138 * sc = instantiating scope
3139 * e = expression to convert
3140 * ident = identifier being used
3141 * flag = DotExpFlag bit flags
3143 * Returns:
3144 * resulting expression with e.ident resolved
3146 Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag)
3148 Expression visitType(Type mt)
3150 VarDeclaration v = null;
3151 static if (LOGDOTEXP)
3153 printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3155 Expression ex = e.lastComma();
3156 if (ex.op == EXP.dotVariable)
3158 DotVarExp dv = cast(DotVarExp)ex;
3159 v = dv.var.isVarDeclaration();
3161 else if (ex.op == EXP.variable)
3163 VarExp ve = cast(VarExp)ex;
3164 v = ve.var.isVarDeclaration();
3166 if (v)
3168 if (ident == Id.offsetof)
3170 v.dsymbolSemantic(null);
3171 if (v.isField())
3173 auto ad = v.isMember();
3174 objc.checkOffsetof(e, ad);
3175 ad.size(e.loc);
3176 if (ad.sizeok != Sizeok.done)
3177 return ErrorExp.get();
3178 return new IntegerExp(e.loc, v.offset, Type.tsize_t);
3181 else if (ident == Id._init)
3183 Type tb = mt.toBasetype();
3184 e = mt.defaultInitLiteral(e.loc);
3185 if (tb.ty == Tstruct && tb.needsNested())
3187 e.isStructLiteralExp().useStaticInit = true;
3189 goto Lreturn;
3192 if (ident == Id.stringof)
3194 /* https://issues.dlang.org/show_bug.cgi?id=3796
3195 * this should demangle e.type.deco rather than
3196 * pretty-printing the type.
3198 e = new StringExp(e.loc, e.toString());
3200 else
3201 e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag);
3203 Lreturn:
3204 if (e)
3205 e = e.expressionSemantic(sc);
3206 return e;
3209 Expression visitError(TypeError)
3211 return ErrorExp.get();
3214 Expression visitBasic(TypeBasic mt)
3216 static if (LOGDOTEXP)
3218 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3220 Type t;
3221 if (ident == Id.re)
3223 switch (mt.ty)
3225 case Tcomplex32:
3226 t = mt.tfloat32;
3227 goto L1;
3229 case Tcomplex64:
3230 t = mt.tfloat64;
3231 goto L1;
3233 case Tcomplex80:
3234 t = mt.tfloat80;
3235 goto L1;
3237 e = e.castTo(sc, t);
3238 break;
3240 case Tfloat32:
3241 case Tfloat64:
3242 case Tfloat80:
3243 break;
3245 case Timaginary32:
3246 t = mt.tfloat32;
3247 goto L2;
3249 case Timaginary64:
3250 t = mt.tfloat64;
3251 goto L2;
3253 case Timaginary80:
3254 t = mt.tfloat80;
3255 goto L2;
3257 e = new RealExp(e.loc, CTFloat.zero, t);
3258 break;
3260 default:
3261 e = mt.Type.getProperty(sc, e.loc, ident, flag);
3262 break;
3265 else if (ident == Id.im)
3267 Type t2;
3268 switch (mt.ty)
3270 case Tcomplex32:
3271 t = mt.timaginary32;
3272 t2 = mt.tfloat32;
3273 goto L3;
3275 case Tcomplex64:
3276 t = mt.timaginary64;
3277 t2 = mt.tfloat64;
3278 goto L3;
3280 case Tcomplex80:
3281 t = mt.timaginary80;
3282 t2 = mt.tfloat80;
3283 goto L3;
3285 e = e.castTo(sc, t);
3286 e.type = t2;
3287 break;
3289 case Timaginary32:
3290 t = mt.tfloat32;
3291 goto L4;
3293 case Timaginary64:
3294 t = mt.tfloat64;
3295 goto L4;
3297 case Timaginary80:
3298 t = mt.tfloat80;
3299 goto L4;
3301 e = e.copy();
3302 e.type = t;
3303 break;
3305 case Tfloat32:
3306 case Tfloat64:
3307 case Tfloat80:
3308 e = new RealExp(e.loc, CTFloat.zero, mt);
3309 break;
3311 default:
3312 e = mt.Type.getProperty(sc, e.loc, ident, flag);
3313 break;
3316 else
3318 return visitType(mt);
3320 if (!(flag & 1) || e)
3321 e = e.expressionSemantic(sc);
3322 return e;
3325 Expression visitVector(TypeVector mt)
3327 static if (LOGDOTEXP)
3329 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3331 if (ident == Id.ptr && e.op == EXP.call)
3333 /* The trouble with EXP.call is the return ABI for float[4] is different from
3334 * __vector(float[4]), and a type paint won't do.
3336 e = new AddrExp(e.loc, e);
3337 e = e.expressionSemantic(sc);
3338 return e.castTo(sc, mt.basetype.nextOf().pointerTo());
3340 if (ident == Id.array)
3342 //e = e.castTo(sc, basetype);
3343 // Keep lvalue-ness
3344 e = new VectorArrayExp(e.loc, e);
3345 e = e.expressionSemantic(sc);
3346 return e;
3348 if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof)
3350 // init should return a new VectorExp
3351 // https://issues.dlang.org/show_bug.cgi?id=12776
3352 // offsetof does not work on a cast expression, so use e directly
3353 // stringof should not add a cast to the output
3354 return visitType(mt);
3357 // Properties based on the vector element type and are values of the element type
3358 if (ident == Id.max || ident == Id.min || ident == Id.min_normal ||
3359 ident == Id.nan || ident == Id.infinity || ident == Id.epsilon)
3361 auto vet = mt.basetype.isTypeSArray().next; // vector element type
3362 if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag))
3363 return ev.castTo(sc, mt); // 'broadcast' ev to the vector elements
3366 return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag);
3369 Expression visitArray(TypeArray mt)
3371 static if (LOGDOTEXP)
3373 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3376 e = visitType(mt);
3378 if (!(flag & 1) || e)
3379 e = e.expressionSemantic(sc);
3380 return e;
3383 Expression visitSArray(TypeSArray mt)
3385 static if (LOGDOTEXP)
3387 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3389 if (ident == Id.length)
3391 Loc oldLoc = e.loc;
3392 e = mt.dim.copy();
3393 e.loc = oldLoc;
3395 else if (ident == Id.ptr)
3397 if (e.op == EXP.type)
3399 error(e.loc, "`%s` is not an expression", e.toChars());
3400 return ErrorExp.get();
3402 else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
3404 // .ptr on static array is @safe unless size is 0
3405 // https://issues.dlang.org/show_bug.cgi?id=20853
3406 return ErrorExp.get();
3408 e = e.castTo(sc, e.type.nextOf().pointerTo());
3410 else if (ident == Id._tupleof)
3412 if (e.isTypeExp())
3414 error(e.loc, "`.tupleof` cannot be used on type `%s`", mt.toChars);
3415 return ErrorExp.get();
3417 else
3419 Expression e0;
3420 Expression ev = e;
3421 ev = extractSideEffect(sc, "__tup", e0, ev);
3423 const length = cast(size_t)mt.dim.toUInteger();
3424 auto exps = new Expressions();
3425 exps.reserve(length);
3426 foreach (i; 0 .. length)
3427 exps.push(new IndexExp(e.loc, ev, new IntegerExp(e.loc, i, Type.tsize_t)));
3428 e = new TupleExp(e.loc, e0, exps);
3431 else
3433 e = visitArray(mt);
3435 if (!(flag & 1) || e)
3436 e = e.expressionSemantic(sc);
3437 return e;
3440 Expression visitDArray(TypeDArray mt)
3442 static if (LOGDOTEXP)
3444 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3446 if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
3448 error(e.loc, "`%s` is not an expression", e.toChars());
3449 return ErrorExp.get();
3451 if (ident == Id.length)
3453 if (e.op == EXP.string_)
3455 StringExp se = cast(StringExp)e;
3456 return new IntegerExp(se.loc, se.len, Type.tsize_t);
3458 if (e.op == EXP.null_)
3460 return new IntegerExp(e.loc, 0, Type.tsize_t);
3462 if (checkNonAssignmentArrayOp(e))
3464 return ErrorExp.get();
3466 e = new ArrayLengthExp(e.loc, e);
3467 e.type = Type.tsize_t;
3468 return e;
3470 else if (ident == Id.ptr)
3472 if (checkUnsafeDotExp(sc, e, ident, flag))
3473 return ErrorExp.get();
3474 return e.castTo(sc, mt.next.pointerTo());
3476 else
3478 return visitArray(mt);
3482 Expression visitAArray(TypeAArray mt)
3484 static if (LOGDOTEXP)
3486 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3488 if (ident == Id.length)
3490 __gshared FuncDeclaration fd_aaLen = null;
3491 if (fd_aaLen is null)
3493 auto fparams = new Parameters();
3494 fparams.push(new Parameter(Loc.initial, STC.const_ | STC.scope_, mt, null, null, null));
3495 fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen);
3496 TypeFunction tf = fd_aaLen.type.toTypeFunction();
3497 tf.purity = PURE.const_;
3498 tf.isnothrow = true;
3499 tf.isnogc = false;
3501 Expression ev = new VarExp(e.loc, fd_aaLen, false);
3502 e = new CallExp(e.loc, ev, e);
3503 e.type = fd_aaLen.type.toTypeFunction().next;
3504 return e;
3506 else
3508 return visitType(mt);
3512 Expression visitReference(TypeReference mt)
3514 static if (LOGDOTEXP)
3516 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3518 // References just forward things along
3519 return mt.next.dotExp(sc, e, ident, flag);
3522 Expression visitDelegate(TypeDelegate mt)
3524 static if (LOGDOTEXP)
3526 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3528 if (ident == Id.ptr)
3530 e = new DelegatePtrExp(e.loc, e);
3531 e = e.expressionSemantic(sc);
3533 else if (ident == Id.funcptr)
3535 if (checkUnsafeDotExp(sc, e, ident, flag))
3537 return ErrorExp.get();
3539 e = new DelegateFuncptrExp(e.loc, e);
3540 e = e.expressionSemantic(sc);
3542 else
3544 return visitType(mt);
3546 return e;
3549 /***************************************
3550 * `ident` was not found as a member of `mt`.
3551 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
3552 * If that fails, forward to visitType().
3553 * Params:
3554 * mt = class or struct
3555 * sc = context
3556 * e = `this` for `ident`
3557 * ident = name of member
3558 * flag = flag & 1, don't report "not a property" error and just return NULL.
3559 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
3560 * Returns:
3561 * resolved expression if found, otherwise null
3563 Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
3565 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
3567 bool gagError = flag & 1;
3569 __gshared int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
3571 static Expression returnExp(Expression e)
3573 --nest;
3574 return e;
3577 if (++nest > global.recursionLimit)
3579 .error(e.loc, "cannot resolve identifier `%s`", ident.toChars());
3580 return returnExp(gagError ? null : ErrorExp.get());
3584 assert(mt.ty == Tstruct || mt.ty == Tclass);
3585 auto sym = mt.toDsymbol(sc).isAggregateDeclaration();
3586 assert(sym);
3587 if (// https://issues.dlang.org/show_bug.cgi?id=22054
3588 // if a class or struct does not have a body
3589 // there is no point in searching for its members
3590 sym.members &&
3591 ident != Id.__sizeof &&
3592 ident != Id.__xalignof &&
3593 ident != Id._init &&
3594 ident != Id._mangleof &&
3595 ident != Id.stringof &&
3596 ident != Id.offsetof &&
3597 // https://issues.dlang.org/show_bug.cgi?id=15045
3598 // Don't forward special built-in member functions.
3599 ident != Id.ctor &&
3600 ident != Id.dtor &&
3601 ident != Id.__xdtor &&
3602 ident != Id.postblit &&
3603 ident != Id.__xpostblit)
3605 /* Look for overloaded opDot() to see if we should forward request
3606 * to it.
3608 if (auto fd = search_function(sym, Id.opDot))
3610 /* Rewrite e.ident as:
3611 * e.opDot().ident
3613 e = build_overload(e.loc, sc, e, null, fd);
3614 // @@@DEPRECATED_2.110@@@.
3615 // Deprecated in 2.082, made an error in 2.100.
3616 error(e.loc, "`opDot` is obsolete. Use `alias this`");
3617 return ErrorExp.get();
3620 /* Look for overloaded opDispatch to see if we should forward request
3621 * to it.
3623 if (auto fd = search_function(sym, Id.opDispatch))
3625 /* Rewrite e.ident as:
3626 * e.opDispatch!("ident")
3628 TemplateDeclaration td = fd.isTemplateDeclaration();
3629 if (!td)
3631 .error(fd.loc, "%s `%s` must be a template `opDispatch(string s)`, not a %s", fd.kind, fd.toPrettyChars, fd.kind());
3632 return returnExp(ErrorExp.get());
3634 auto se = new StringExp(e.loc, ident.toString());
3635 auto tiargs = new Objects();
3636 tiargs.push(se);
3637 auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs);
3638 dti.ti.tempdecl = td;
3639 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
3640 * e.g.
3641 * template opDispatch(name) if (isValid!name) { ... }
3643 uint errors = gagError ? global.startGagging() : 0;
3644 e = dti.dotTemplateSemanticProp(sc, DotExpFlag.none);
3645 if (gagError && global.endGagging(errors))
3646 e = null;
3647 return returnExp(e);
3650 /* See if we should forward to the alias this.
3652 auto alias_e = flag & DotExpFlag.noAliasThis ? null
3653 : resolveAliasThis(sc, e, gagError);
3654 if (alias_e && alias_e != e)
3656 /* Rewrite e.ident as:
3657 * e.aliasthis.ident
3659 auto die = new DotIdExp(e.loc, alias_e, ident);
3661 auto errors = gagError ? 0 : global.startGagging();
3662 auto exp = die.dotIdSemanticProp(sc, gagError);
3663 if (!gagError)
3665 global.endGagging(errors);
3666 if (exp && exp.op == EXP.error)
3667 exp = null;
3670 if (exp && gagError)
3671 // now that we know that the alias this leads somewhere useful,
3672 // go back and print deprecations/warnings that we skipped earlier due to the gag
3673 resolveAliasThis(sc, e, false);
3675 return returnExp(exp);
3678 return returnExp(visitType(mt));
3681 Expression visitStruct(TypeStruct mt)
3683 Dsymbol s;
3684 static if (LOGDOTEXP)
3686 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3688 assert(e.op != EXP.dot);
3690 // https://issues.dlang.org/show_bug.cgi?id=14010
3691 if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
3693 return mt.getProperty(sc, e.loc, ident, flag & 1);
3696 /* If e.tupleof
3698 if (ident == Id._tupleof)
3700 /* Create a TupleExp out of the fields of the struct e:
3701 * (e.field0, e.field1, e.field2, ...)
3703 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
3705 if (!mt.sym.determineFields())
3707 error(e.loc, "unable to determine fields of `%s` because of forward references", mt.toChars());
3710 Expression e0;
3711 Expression ev = e.op == EXP.type ? null : e;
3712 if (ev)
3713 ev = extractSideEffect(sc, "__tup", e0, ev);
3715 auto exps = new Expressions();
3716 exps.reserve(mt.sym.fields.length);
3717 for (size_t i = 0; i < mt.sym.fields.length; i++)
3719 VarDeclaration v = mt.sym.fields[i];
3720 Expression ex;
3721 if (ev)
3722 ex = new DotVarExp(e.loc, ev, v);
3723 else
3725 ex = new VarExp(e.loc, v);
3726 ex.type = ex.type.addMod(e.type.mod);
3728 exps.push(ex);
3731 e = new TupleExp(e.loc, e0, exps);
3732 Scope* sc2 = sc.push();
3733 sc2.flags |= SCOPE.noaccesscheck;
3734 e = e.expressionSemantic(sc2);
3735 sc2.pop();
3736 return e;
3739 immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
3740 s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
3742 if (!s)
3744 return noMember(mt, sc, e, ident, flag);
3746 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
3748 return noMember(mt, sc, e, ident, flag);
3750 // check before alias resolution; the alias itself might be deprecated!
3751 if (s.isAliasDeclaration)
3752 s.checkDeprecated(e.loc, sc);
3753 s = s.toAlias();
3755 if (auto em = s.isEnumMember())
3757 return em.getVarExp(e.loc, sc);
3759 if (auto v = s.isVarDeclaration())
3761 v.checkDeprecated(e.loc, sc);
3762 v.checkDisabled(e.loc, sc);
3763 if (!v.type ||
3764 !v.type.deco && v.inuse)
3766 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
3767 error(e.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
3768 else
3769 error(e.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
3770 return ErrorExp.get();
3772 if (v.type.ty == Terror)
3774 return ErrorExp.get();
3777 if ((v.storage_class & STC.manifest) && v._init)
3779 if (v.inuse)
3781 error(e.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
3782 return ErrorExp.get();
3784 checkAccess(e.loc, sc, null, v);
3785 Expression ve = new VarExp(e.loc, v);
3786 if (!isTrivialExp(e))
3788 ve = new CommaExp(e.loc, e, ve);
3790 return ve.expressionSemantic(sc);
3794 if (auto t = s.getType())
3796 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
3799 TemplateMixin tm = s.isTemplateMixin();
3800 if (tm)
3802 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
3805 TemplateDeclaration td = s.isTemplateDeclaration();
3806 if (td)
3808 if (e.op == EXP.type)
3809 e = new TemplateExp(e.loc, td);
3810 else
3811 e = new DotTemplateExp(e.loc, e, td);
3812 return e.expressionSemantic(sc);
3815 TemplateInstance ti = s.isTemplateInstance();
3816 if (ti)
3818 if (!ti.semanticRun)
3820 ti.dsymbolSemantic(sc);
3821 if (!ti.inst || ti.errors) // if template failed to expand
3823 return ErrorExp.get();
3826 s = ti.inst.toAlias();
3827 if (!s.isTemplateInstance())
3828 goto L1;
3829 if (e.op == EXP.type)
3830 e = new ScopeExp(e.loc, ti);
3831 else
3832 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
3833 return e.expressionSemantic(sc);
3836 if (s.isImport() || s.isModule() || s.isPackage())
3838 return symbolToExp(s, e.loc, sc, false);
3841 OverloadSet o = s.isOverloadSet();
3842 if (o)
3844 auto oe = new OverExp(e.loc, o);
3845 if (e.op == EXP.type)
3847 return oe;
3849 return new DotExp(e.loc, e, oe);
3852 Declaration d = s.isDeclaration();
3853 if (!d)
3855 error(e.loc, "`%s.%s` is not a declaration", e.toChars(), ident.toChars());
3856 return ErrorExp.get();
3859 if (e.op == EXP.type)
3861 /* It's:
3862 * Struct.d
3864 if (TupleDeclaration tup = d.isTupleDeclaration())
3866 e = new TupleExp(e.loc, tup);
3867 return e.expressionSemantic(sc);
3869 if (d.needThis() && sc.intypeof != 1)
3871 /* Rewrite as:
3872 * this.d
3874 * only if the scope in which we are
3875 * has a `this` that matches the type
3876 * of the lhs of the dot expression.
3878 * https://issues.dlang.org/show_bug.cgi?id=23617
3880 auto fd = hasThis(sc);
3881 if (fd && fd.isThis() == mt.sym)
3883 e = new DotVarExp(e.loc, new ThisExp(e.loc), d);
3884 return e.expressionSemantic(sc);
3887 if (d.semanticRun == PASS.initial)
3888 d.dsymbolSemantic(null);
3889 checkAccess(e.loc, sc, e, d);
3890 auto ve = new VarExp(e.loc, d);
3891 if (d.isVarDeclaration() && d.needThis())
3892 ve.type = d.type.addMod(e.type.mod);
3893 return ve;
3896 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
3897 if (d.isDataseg() || unreal && d.isField())
3899 // (e, d)
3900 checkAccess(e.loc, sc, e, d);
3901 Expression ve = new VarExp(e.loc, d);
3902 e = unreal ? ve : new CommaExp(e.loc, e, ve);
3903 return e.expressionSemantic(sc);
3906 e = new DotVarExp(e.loc, e, d);
3907 return e.expressionSemantic(sc);
3910 Expression visitEnum(TypeEnum mt)
3912 static if (LOGDOTEXP)
3914 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), mt.toChars());
3916 // https://issues.dlang.org/show_bug.cgi?id=14010
3917 if (ident == Id._mangleof)
3919 return mt.getProperty(sc, e.loc, ident, flag & 1);
3922 if (mt.sym.semanticRun < PASS.semanticdone)
3923 mt.sym.dsymbolSemantic(null);
3925 Dsymbol s = mt.sym.search(e.loc, ident);
3926 if (!s)
3928 if (ident == Id._init)
3930 return mt.getProperty(sc, e.loc, ident, flag & 1);
3933 /* Allow special enums to not need a member list
3935 if ((ident == Id.max || ident == Id.min) && (mt.sym.members || !mt.sym.isSpecial()))
3937 return mt.getProperty(sc, e.loc, ident, flag & 1);
3940 Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, DotExpFlag.gag);
3941 if (!(flag & 1) && !res)
3943 if (auto ns = mt.sym.search_correct(ident))
3944 error(e.loc, "no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
3945 ns.toChars());
3946 else
3947 error(e.loc, "no property `%s` for type `%s`", ident.toChars(),
3948 mt.toChars());
3950 errorSupplemental(mt.sym.loc, "%s `%s` defined here",
3951 mt.sym.kind, mt.toChars());
3952 return ErrorExp.get();
3954 return res;
3956 EnumMember m = s.isEnumMember();
3957 return m.getVarExp(e.loc, sc);
3960 Expression visitClass(TypeClass mt)
3962 Dsymbol s;
3963 static if (LOGDOTEXP)
3965 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3967 assert(e.op != EXP.dot);
3969 // https://issues.dlang.org/show_bug.cgi?id=12543
3970 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
3972 return mt.Type.getProperty(sc, e.loc, ident, 0);
3975 /* If e.tupleof
3977 if (ident == Id._tupleof)
3979 objc.checkTupleof(e, mt);
3981 /* Create a TupleExp
3983 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
3985 mt.sym.size(e.loc); // do semantic of type
3987 Expression e0;
3988 Expression ev = e.op == EXP.type ? null : e;
3989 if (ev)
3990 ev = extractSideEffect(sc, "__tup", e0, ev);
3992 auto exps = new Expressions();
3993 exps.reserve(mt.sym.fields.length);
3994 for (size_t i = 0; i < mt.sym.fields.length; i++)
3996 VarDeclaration v = mt.sym.fields[i];
3997 // Don't include hidden 'this' pointer
3998 if (v.isThisDeclaration())
3999 continue;
4000 Expression ex;
4001 if (ev)
4002 ex = new DotVarExp(e.loc, ev, v);
4003 else
4005 ex = new VarExp(e.loc, v);
4006 ex.type = ex.type.addMod(e.type.mod);
4008 exps.push(ex);
4011 e = new TupleExp(e.loc, e0, exps);
4012 Scope* sc2 = sc.push();
4013 sc2.flags |= SCOPE.noaccesscheck;
4014 e = e.expressionSemantic(sc2);
4015 sc2.pop();
4016 return e;
4019 int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
4020 s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
4023 if (!s)
4025 // See if it's a 'this' class or a base class
4026 if (mt.sym.ident == ident)
4028 if (e.op == EXP.type)
4030 return mt.Type.getProperty(sc, e.loc, ident, 0);
4032 e = new DotTypeExp(e.loc, e, mt.sym);
4033 e = e.expressionSemantic(sc);
4034 return e;
4036 if (auto cbase = mt.sym.searchBase(ident))
4038 if (e.op == EXP.type)
4040 return mt.Type.getProperty(sc, e.loc, ident, 0);
4042 if (auto ifbase = cbase.isInterfaceDeclaration())
4043 e = new CastExp(e.loc, e, ifbase.type);
4044 else
4045 e = new DotTypeExp(e.loc, e, cbase);
4046 e = e.expressionSemantic(sc);
4047 return e;
4050 if (ident == Id.classinfo)
4052 if (!Type.typeinfoclass)
4054 error(e.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4055 return ErrorExp.get();
4058 Type t = Type.typeinfoclass.type;
4059 if (e.op == EXP.type || e.op == EXP.dotType)
4061 /* For type.classinfo, we know the classinfo
4062 * at compile time.
4064 if (!mt.sym.vclassinfo)
4065 mt.sym.vclassinfo = new TypeInfoClassDeclaration(mt.sym.type);
4066 e = new VarExp(e.loc, mt.sym.vclassinfo);
4067 e = e.addressOf();
4068 e.type = t; // do this so we don't get redundant dereference
4070 else
4072 /* For class objects, the classinfo reference is the first
4073 * entry in the vtbl[]
4075 e = new PtrExp(e.loc, e);
4076 e.type = t.pointerTo();
4077 if (mt.sym.isInterfaceDeclaration())
4079 if (mt.sym.isCPPinterface())
4081 /* C++ interface vtbl[]s are different in that the
4082 * first entry is always pointer to the first virtual
4083 * function, not classinfo.
4084 * We can't get a .classinfo for it.
4086 error(e.loc, "no `.classinfo` for C++ interface objects");
4088 /* For an interface, the first entry in the vtbl[]
4089 * is actually a pointer to an instance of struct Interface.
4090 * The first member of Interface is the .classinfo,
4091 * so add an extra pointer indirection.
4093 e.type = e.type.pointerTo();
4094 e = new PtrExp(e.loc, e);
4095 e.type = t.pointerTo();
4097 e = new PtrExp(e.loc, e, t);
4099 return e;
4102 if (ident == Id.__vptr)
4104 /* The pointer to the vtbl[]
4105 * *cast(immutable(void*)**)e
4107 e = e.castTo(sc, mt.tvoidptr.immutableOf().pointerTo().pointerTo());
4108 e = new PtrExp(e.loc, e);
4109 e = e.expressionSemantic(sc);
4110 return e;
4113 if (ident == Id.__monitor && mt.sym.hasMonitor())
4115 /* The handle to the monitor (call it a void*)
4116 * *(cast(void**)e + 1)
4118 e = e.castTo(sc, mt.tvoidptr.pointerTo());
4119 e = new AddExp(e.loc, e, IntegerExp.literal!1);
4120 e = new PtrExp(e.loc, e);
4121 e = e.expressionSemantic(sc);
4122 return e;
4125 if (ident == Id.outer && mt.sym.vthis)
4127 if (mt.sym.vthis.semanticRun == PASS.initial)
4128 mt.sym.vthis.dsymbolSemantic(null);
4130 if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
4132 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
4133 dve.type = cdp.type.addMod(e.type.mod);
4134 return dve;
4137 /* https://issues.dlang.org/show_bug.cgi?id=15839
4138 * Find closest parent class through nested functions.
4140 for (auto p = mt.sym.toParentLocal(); p; p = p.toParentLocal())
4142 auto fd = p.isFuncDeclaration();
4143 if (!fd)
4144 break;
4145 auto ad = fd.isThis();
4146 if (!ad && fd.isNested())
4147 continue;
4148 if (!ad)
4149 break;
4150 if (auto cdp = ad.isClassDeclaration())
4152 auto ve = new ThisExp(e.loc);
4154 ve.var = fd.vthis;
4155 const nestedError = fd.vthis.checkNestedReference(sc, e.loc);
4156 assert(!nestedError);
4158 ve.type = cdp.type.addMod(fd.vthis.type.mod).addMod(e.type.mod);
4159 return ve;
4161 break;
4164 // Continue to show enclosing function's frame (stack or closure).
4165 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
4166 dve.type = mt.sym.vthis.type.addMod(e.type.mod);
4167 return dve;
4170 return noMember(mt, sc, e, ident, flag & 1);
4172 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
4174 return noMember(mt, sc, e, ident, flag);
4176 if (!s.isFuncDeclaration()) // because of overloading
4178 s.checkDeprecated(e.loc, sc);
4179 if (auto d = s.isDeclaration())
4180 d.checkDisabled(e.loc, sc);
4182 s = s.toAlias();
4184 if (auto em = s.isEnumMember())
4186 return em.getVarExp(e.loc, sc);
4188 if (auto v = s.isVarDeclaration())
4190 if (!v.type ||
4191 !v.type.deco && v.inuse)
4193 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
4194 error(e.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
4195 else
4196 error(e.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
4197 return ErrorExp.get();
4199 if (v.type.ty == Terror)
4201 error(e.loc, "type of variable `%s` has errors", v.toPrettyChars);
4202 return ErrorExp.get();
4205 if ((v.storage_class & STC.manifest) && v._init)
4207 if (v.inuse)
4209 error(e.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
4210 return ErrorExp.get();
4212 checkAccess(e.loc, sc, null, v);
4213 Expression ve = new VarExp(e.loc, v);
4214 ve = ve.expressionSemantic(sc);
4215 return ve;
4219 if (auto t = s.getType())
4221 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
4224 TemplateMixin tm = s.isTemplateMixin();
4225 if (tm)
4227 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
4230 TemplateDeclaration td = s.isTemplateDeclaration();
4232 Expression toTemplateExp(TemplateDeclaration td)
4234 if (e.op == EXP.type)
4235 e = new TemplateExp(e.loc, td);
4236 else
4237 e = new DotTemplateExp(e.loc, e, td);
4238 e = e.expressionSemantic(sc);
4239 return e;
4242 if (td)
4244 return toTemplateExp(td);
4247 TemplateInstance ti = s.isTemplateInstance();
4248 if (ti)
4250 if (!ti.semanticRun)
4252 ti.dsymbolSemantic(sc);
4253 if (!ti.inst || ti.errors) // if template failed to expand
4255 return ErrorExp.get();
4258 s = ti.inst.toAlias();
4259 if (!s.isTemplateInstance())
4260 goto L1;
4261 if (e.op == EXP.type)
4262 e = new ScopeExp(e.loc, ti);
4263 else
4264 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
4265 return e.expressionSemantic(sc);
4268 if (s.isImport() || s.isModule() || s.isPackage())
4270 e = symbolToExp(s, e.loc, sc, false);
4271 return e;
4274 OverloadSet o = s.isOverloadSet();
4275 if (o)
4277 auto oe = new OverExp(e.loc, o);
4278 if (e.op == EXP.type)
4280 return oe;
4282 return new DotExp(e.loc, e, oe);
4285 Declaration d = s.isDeclaration();
4286 if (!d)
4288 error(e.loc, "`%s.%s` is not a declaration", e.toChars(), ident.toChars());
4289 return ErrorExp.get();
4292 if (e.op == EXP.type)
4294 /* It's:
4295 * Class.d
4297 if (TupleDeclaration tup = d.isTupleDeclaration())
4299 e = new TupleExp(e.loc, tup);
4300 e = e.expressionSemantic(sc);
4301 return e;
4304 if (mt.sym.classKind == ClassKind.objc
4305 && d.isFuncDeclaration()
4306 && d.isFuncDeclaration().isStatic
4307 && d.isFuncDeclaration().objc.selector)
4309 auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
4310 classRef.type = objc.getRuntimeMetaclass(mt.sym).getType();
4311 return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
4313 else if (d.needThis() && sc.intypeof != 1)
4315 /* Rewrite as:
4316 * this.d
4318 AggregateDeclaration ad = d.isMemberLocal();
4319 if (auto f = hasThis(sc))
4321 // This is almost same as getRightThis() in expressionsem.d
4322 Expression e1;
4323 Type t;
4324 /* returns: true to continue, false to return */
4325 if (f.hasDualContext())
4327 if (f.followInstantiationContext(ad))
4329 e1 = new VarExp(e.loc, f.vthis);
4330 e1 = new PtrExp(e1.loc, e1);
4331 e1 = new IndexExp(e1.loc, e1, IntegerExp.literal!1);
4332 auto pd = f.toParent2().isDeclaration();
4333 assert(pd);
4334 t = pd.type.toBasetype();
4335 e1 = getThisSkipNestedFuncs(e1.loc, sc, f.toParent2(), ad, e1, t, d, true);
4336 if (!e1)
4338 e = new VarExp(e.loc, d);
4339 return e;
4341 goto L2;
4344 e1 = new ThisExp(e.loc);
4345 e1 = e1.expressionSemantic(sc);
4347 t = e1.type.toBasetype();
4348 ClassDeclaration cd = e.type.isClassHandle();
4349 ClassDeclaration tcd = t.isClassHandle();
4350 if (cd && tcd && (tcd == cd || cd.isBaseOf(tcd, null)))
4352 e = new DotTypeExp(e1.loc, e1, cd);
4353 e = new DotVarExp(e.loc, e, d);
4354 e = e.expressionSemantic(sc);
4355 return e;
4357 if (tcd && tcd.isNested())
4359 /* e1 is the 'this' pointer for an inner class: tcd.
4360 * Rewrite it as the 'this' pointer for the outer class.
4362 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
4363 e1 = new DotVarExp(e.loc, e1, vthis);
4364 e1.type = vthis.type;
4365 e1.type = e1.type.addMod(t.mod);
4366 // Do not call ensureStaticLinkTo()
4367 //e1 = e1.expressionSemantic(sc);
4369 // Skip up over nested functions, and get the enclosing
4370 // class type.
4371 e1 = getThisSkipNestedFuncs(e1.loc, sc, tcd.toParentP(ad), ad, e1, t, d, true);
4372 if (!e1)
4374 e = new VarExp(e.loc, d);
4375 return e;
4377 goto L2;
4381 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
4382 if (d.semanticRun == PASS.initial)
4383 d.dsymbolSemantic(null);
4385 // If static function, get the most visible overload.
4386 // Later on the call is checked for correctness.
4387 // https://issues.dlang.org/show_bug.cgi?id=12511
4388 Dsymbol d2 = d;
4389 if (auto fd = d.isFuncDeclaration())
4391 import dmd.access : mostVisibleOverload;
4392 d2 = mostVisibleOverload(fd, sc._module);
4395 checkAccess(e.loc, sc, e, d2);
4396 if (d2.isDeclaration())
4398 d = cast(Declaration)d2;
4399 auto ve = new VarExp(e.loc, d);
4400 if (d.isVarDeclaration() && d.needThis())
4401 ve.type = d.type.addMod(e.type.mod);
4402 return ve;
4404 else if (d2.isTemplateDeclaration())
4406 return toTemplateExp(cast(TemplateDeclaration)d2);
4408 else
4409 assert(0);
4412 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
4413 if (d.isDataseg() || unreal && d.isField())
4415 // (e, d)
4416 checkAccess(e.loc, sc, e, d);
4417 Expression ve = new VarExp(e.loc, d);
4418 e = unreal ? ve : new CommaExp(e.loc, e, ve);
4419 e = e.expressionSemantic(sc);
4420 return e;
4423 e = new DotVarExp(e.loc, e, d);
4424 e = e.expressionSemantic(sc);
4425 return e;
4428 switch (mt.ty)
4430 case Tvector: return visitVector (mt.isTypeVector());
4431 case Tsarray: return visitSArray (mt.isTypeSArray());
4432 case Tstruct: return visitStruct (mt.isTypeStruct());
4433 case Tenum: return visitEnum (mt.isTypeEnum());
4434 case Terror: return visitError (mt.isTypeError());
4435 case Tarray: return visitDArray (mt.isTypeDArray());
4436 case Taarray: return visitAArray (mt.isTypeAArray());
4437 case Treference: return visitReference(mt.isTypeReference());
4438 case Tdelegate: return visitDelegate (mt.isTypeDelegate());
4439 case Tclass: return visitClass (mt.isTypeClass());
4441 default: return mt.isTypeBasic()
4442 ? visitBasic(cast(TypeBasic)mt)
4443 : visitType(mt);
4448 /************************
4449 * Get the default initialization expression for a type.
4450 * Params:
4451 * mt = the type for which the init expression is returned
4452 * loc = the location where the expression needs to be evaluated
4453 * isCfile = default initializers are different with C
4455 * Returns:
4456 * The initialization expression for the type.
4458 extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
4460 Expression visitBasic(TypeBasic mt)
4462 static if (LOGDEFAULTINIT)
4464 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
4466 dinteger_t value = 0;
4468 switch (mt.ty)
4470 case Tchar:
4471 value = isCfile ? 0 : 0xFF;
4472 break;
4474 case Twchar:
4475 case Tdchar:
4476 value = isCfile ? 0 : 0xFFFF;
4477 break;
4479 case Timaginary32:
4480 case Timaginary64:
4481 case Timaginary80:
4482 case Tfloat32:
4483 case Tfloat64:
4484 case Tfloat80:
4485 return new RealExp(loc, isCfile ? CTFloat.zero : target.RealProperties.nan, mt);
4487 case Tcomplex32:
4488 case Tcomplex64:
4489 case Tcomplex80:
4491 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
4492 const cvalue = isCfile ? complex_t(CTFloat.zero, CTFloat.zero)
4493 : complex_t(target.RealProperties.nan, target.RealProperties.nan);
4494 return new ComplexExp(loc, cvalue, mt);
4497 case Tvoid:
4498 error(loc, "`void` does not have a default initializer");
4499 return ErrorExp.get();
4501 default:
4502 break;
4504 return new IntegerExp(loc, value, mt);
4507 Expression visitVector(TypeVector mt)
4509 //printf("TypeVector::defaultInit()\n");
4510 assert(mt.basetype.ty == Tsarray);
4511 Expression e = mt.basetype.defaultInit(loc, isCfile);
4512 auto ve = new VectorExp(loc, e, mt);
4513 ve.type = mt;
4514 ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc));
4515 return ve;
4518 Expression visitSArray(TypeSArray mt)
4520 static if (LOGDEFAULTINIT)
4522 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
4524 if (mt.next.ty == Tvoid)
4525 return mt.tuns8.defaultInit(loc, isCfile);
4526 else
4527 return mt.next.defaultInit(loc, isCfile);
4530 Expression visitFunction(TypeFunction mt)
4532 error(loc, "`function` does not have a default initializer");
4533 return ErrorExp.get();
4536 Expression visitStruct(TypeStruct mt)
4538 static if (LOGDEFAULTINIT)
4540 printf("TypeStruct::defaultInit() '%s'\n", mt.toChars());
4542 Declaration d = new SymbolDeclaration(mt.sym.loc, mt.sym);
4543 assert(d);
4544 d.type = mt;
4545 d.storage_class |= STC.rvalue; // https://issues.dlang.org/show_bug.cgi?id=14398
4546 return new VarExp(mt.sym.loc, d);
4549 Expression visitEnum(TypeEnum mt)
4551 static if (LOGDEFAULTINIT)
4553 printf("TypeEnum::defaultInit() '%s'\n", mt.toChars());
4555 // Initialize to first member of enum
4556 Expression e = mt.sym.getDefaultValue(loc);
4557 e = e.copy();
4558 e.loc = loc;
4559 e.type = mt; // to deal with const, immutable, etc., variants
4560 return e;
4563 Expression visitTuple(TypeTuple mt)
4565 static if (LOGDEFAULTINIT)
4567 printf("TypeTuple::defaultInit() '%s'\n", mt.toChars());
4569 auto exps = new Expressions(mt.arguments.length);
4570 for (size_t i = 0; i < mt.arguments.length; i++)
4572 Parameter p = (*mt.arguments)[i];
4573 assert(p.type);
4574 Expression e = p.type.defaultInitLiteral(loc);
4575 if (e.op == EXP.error)
4577 return e;
4579 (*exps)[i] = e;
4581 return new TupleExp(loc, exps);
4584 Expression visitNoreturn(TypeNoreturn mt)
4586 static if (LOGDEFAULTINIT)
4588 printf("TypeNoreturn::defaultInit() '%s'\n", mt.toChars());
4590 auto cond = IntegerExp.createBool(false);
4591 auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
4592 msg.type = Type.tstring;
4593 auto ae = new AssertExp(loc, cond, msg);
4594 ae.type = mt;
4595 return ae;
4598 switch (mt.ty)
4600 case Tvector: return visitVector (mt.isTypeVector());
4601 case Tsarray: return visitSArray (mt.isTypeSArray());
4602 case Tfunction: return visitFunction(mt.isTypeFunction());
4603 case Tstruct: return visitStruct (mt.isTypeStruct());
4604 case Tenum: return visitEnum (mt.isTypeEnum());
4605 case Ttuple: return visitTuple (mt.isTypeTuple());
4607 case Tnull: return new NullExp(Loc.initial, Type.tnull);
4609 case Terror: return ErrorExp.get();
4611 case Tarray:
4612 case Taarray:
4613 case Tpointer:
4614 case Treference:
4615 case Tdelegate:
4616 case Tclass: return new NullExp(loc, mt);
4617 case Tnoreturn: return visitNoreturn(mt.isTypeNoreturn());
4619 default: return mt.isTypeBasic() ?
4620 visitBasic(cast(TypeBasic)mt) :
4621 null;
4626 /**********************************************
4627 * Extract complex type from core.stdc.config
4628 * Params:
4629 * loc = for error messages
4630 * sc = context
4631 * ty = a complex or imaginary type
4632 * Returns:
4633 * Complex!float, Complex!double, Complex!real or null for error
4636 Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
4638 // singleton
4639 __gshared Type complex_float;
4640 __gshared Type complex_double;
4641 __gshared Type complex_real;
4643 Type* pt;
4644 Identifier id;
4645 switch (ty)
4647 case Timaginary32:
4648 case Tcomplex32: id = Id.c_complex_float; pt = &complex_float; break;
4649 case Timaginary64:
4650 case Tcomplex64: id = Id.c_complex_double; pt = &complex_double; break;
4651 case Timaginary80:
4652 case Tcomplex80: id = Id.c_complex_real; pt = &complex_real; break;
4653 default:
4654 return Type.terror;
4657 if (*pt)
4658 return *pt;
4659 *pt = Type.terror;
4661 Module mConfig = Module.loadCoreStdcConfig();
4662 if (!mConfig)
4664 error(loc, "`core.stdc.config` is required for complex numbers");
4665 return *pt;
4668 Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports);
4669 if (!s)
4671 error(loc, "`%s` not found in core.stdc.config", id.toChars());
4672 return *pt;
4674 s = s.toAlias();
4675 if (auto t = s.getType())
4677 if (auto ts = t.toBasetype().isTypeStruct())
4679 *pt = ts;
4680 return ts;
4683 if (auto sd = s.isStructDeclaration())
4685 *pt = sd.type;
4686 return sd.type;
4689 error(loc, "`%s` must be an alias for a complex struct", s.toChars());
4690 return *pt;
4693 /******************************* Private *****************************************/
4695 private:
4697 /* Helper function for `typeToExpression`. Contains common code
4698 * for TypeQualified derived classes.
4700 Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
4702 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
4703 foreach (id; t.idents[i .. t.idents.length])
4705 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
4707 final switch (id.dyncast())
4709 // ... '. ident'
4710 case DYNCAST.identifier:
4711 e = new DotIdExp(e.loc, e, cast(Identifier)id);
4712 break;
4714 // ... '. name!(tiargs)'
4715 case DYNCAST.dsymbol:
4716 auto ti = (cast(Dsymbol)id).isTemplateInstance();
4717 assert(ti);
4718 e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
4719 break;
4721 // ... '[type]'
4722 case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215
4723 e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
4724 break;
4726 // ... '[expr]'
4727 case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215
4728 e = new ArrayExp(t.loc, e, cast(Expression)id);
4729 break;
4731 case DYNCAST.object:
4732 case DYNCAST.tuple:
4733 case DYNCAST.parameter:
4734 case DYNCAST.statement:
4735 case DYNCAST.condition:
4736 case DYNCAST.templateparameter:
4737 case DYNCAST.initializer:
4738 assert(0);
4741 return e;
4744 /**************************
4745 * This evaluates exp while setting length to be the number
4746 * of elements in the tuple t.
4748 Expression semanticLength(Scope* sc, Type t, Expression exp)
4750 if (auto tt = t.isTypeTuple())
4752 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
4753 sym.parent = sc.scopesym;
4754 sc = sc.push(sym);
4755 sc = sc.startCTFE();
4756 exp = exp.expressionSemantic(sc);
4757 exp = resolveProperties(sc, exp);
4758 sc = sc.endCTFE();
4759 sc.pop();
4761 else
4763 sc = sc.startCTFE();
4764 exp = exp.expressionSemantic(sc);
4765 exp = resolveProperties(sc, exp);
4766 sc = sc.endCTFE();
4768 return exp;
4771 Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
4773 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
4774 sym.parent = sc.scopesym;
4776 sc = sc.push(sym);
4777 sc = sc.startCTFE();
4778 exp = exp.expressionSemantic(sc);
4779 exp = resolveProperties(sc, exp);
4780 sc = sc.endCTFE();
4781 sc.pop();
4783 return exp;
4786 /************************************
4787 * Transitively search a type for all function types.
4788 * If any function types with parameters are found that have parameter identifiers
4789 * or default arguments, remove those and create a new type stripped of those.
4790 * This is used to determine the "canonical" version of a type which is useful for
4791 * comparisons.
4792 * Params:
4793 * t = type to scan
4794 * Returns:
4795 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
4796 * the same as t but with no parameter identifiers or default arguments.
4798 Type stripDefaultArgs(Type t)
4800 static Parameters* stripParams(Parameters* parameters)
4802 static Parameter stripParameter(Parameter p)
4804 Type t = stripDefaultArgs(p.type);
4805 return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
4806 ? new Parameter(p.loc, p.storageClass, t, null, null, null)
4807 : null;
4810 if (parameters)
4812 foreach (i, p; *parameters)
4814 Parameter ps = stripParameter(p);
4815 if (ps)
4817 // Replace params with a copy we can modify
4818 Parameters* nparams = new Parameters(parameters.length);
4820 foreach (j, ref np; *nparams)
4822 Parameter pj = (*parameters)[j];
4823 if (j < i)
4824 np = pj;
4825 else if (j == i)
4826 np = ps;
4827 else
4829 Parameter nps = stripParameter(pj);
4830 np = nps ? nps : pj;
4833 return nparams;
4837 return parameters;
4840 if (t is null)
4841 return t;
4843 if (auto tf = t.isTypeFunction())
4845 Type tret = stripDefaultArgs(tf.next);
4846 Parameters* params = stripParams(tf.parameterList.parameters);
4847 if (tret == tf.next && params == tf.parameterList.parameters)
4848 return t;
4849 TypeFunction tr = tf.copy().isTypeFunction();
4850 tr.parameterList.parameters = params;
4851 tr.next = tret;
4852 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
4853 return tr;
4855 else if (auto tt = t.isTypeTuple())
4857 Parameters* args = stripParams(tt.arguments);
4858 if (args == tt.arguments)
4859 return t;
4860 TypeTuple tr = t.copy().isTypeTuple();
4861 tr.arguments = args;
4862 return tr;
4864 else if (t.ty == Tenum)
4866 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
4867 return t;
4869 else
4871 Type tn = t.nextOf();
4872 Type n = stripDefaultArgs(tn);
4873 if (n == tn)
4874 return t;
4875 TypeNext tr = cast(TypeNext)t.copy();
4876 tr.next = n;
4877 return tr;
4881 /******************************
4882 * Get the value of the .max/.min property of `ed` as an Expression.
4883 * Lazily computes the value and caches it in maxval/minval.
4884 * Reports any errors.
4885 * Params:
4886 * ed = the EnumDeclaration being examined
4887 * loc = location to use for error messages
4888 * id = Id::max or Id::min
4889 * Returns:
4890 * corresponding value of .max/.min
4892 Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
4894 //printf("EnumDeclaration::getMaxValue()\n");
4896 static Expression pvalToResult(Expression e, const ref Loc loc)
4898 if (e.op != EXP.error)
4900 e = e.copy();
4901 e.loc = loc;
4903 return e;
4906 Expression* pval = (id == Id.max) ? &ed.maxval : &ed.minval;
4908 Expression errorReturn()
4910 *pval = ErrorExp.get();
4911 return *pval;
4914 if (ed.inuse)
4916 .error(loc, "%s `%s` recursive definition of `.%s` property", ed.kind, ed.toPrettyChars, id.toChars());
4917 return errorReturn();
4919 if (*pval)
4920 return pvalToResult(*pval, loc);
4922 if (ed._scope)
4923 dsymbolSemantic(ed, ed._scope);
4924 if (ed.errors)
4925 return errorReturn();
4926 if (!ed.members)
4928 .error(loc, "%s `%s` is opaque and has no `.%s`", ed.kind, ed.toPrettyChars, id.toChars(), id.toChars());
4929 return errorReturn();
4931 if (!(ed.memtype && ed.memtype.isintegral()))
4933 .error(loc, "%s `%s` has no `.%s` property because base type `%s` is not an integral type", ed.kind, ed.toPrettyChars, id.toChars(),
4934 id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
4935 return errorReturn();
4938 bool first = true;
4939 for (size_t i = 0; i < ed.members.length; i++)
4941 EnumMember em = (*ed.members)[i].isEnumMember();
4942 if (!em)
4943 continue;
4944 if (em.errors)
4946 ed.errors = true;
4947 continue;
4950 if (em.semanticRun < PASS.semanticdone)
4952 .error(em.loc, "%s `%s` is forward referenced looking for `.%s`", em.kind, em.toPrettyChars, id.toChars());
4953 ed.errors = true;
4954 continue;
4957 if (first)
4959 *pval = em.value;
4960 first = false;
4962 else
4964 /* In order to work successfully with UDTs,
4965 * build expressions to do the comparisons,
4966 * and let the semantic analyzer and constant
4967 * folder give us the result.
4970 /* Compute:
4971 * if (e > maxval)
4972 * maxval = e;
4974 Expression e = em.value;
4975 Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval);
4976 ed.inuse = true;
4977 ec = ec.expressionSemantic(em._scope);
4978 ed.inuse = false;
4979 ec = ec.ctfeInterpret();
4980 if (ec.op == EXP.error)
4982 ed.errors = true;
4983 continue;
4985 if (ec.toInteger())
4986 *pval = e;
4989 return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
4992 /******************************************
4993 * Compile the MixinType, returning the type or expression AST.
4995 * Doesn't run semantic() on the returned object.
4996 * Params:
4997 * tm = mixin to compile as a type or expression
4998 * loc = location for error messages
4999 * sc = context
5000 * Return:
5001 * null if error, else RootObject AST as parsed
5003 RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
5005 OutBuffer buf;
5006 if (expressionsToString(buf, sc, tm.exps))
5007 return null;
5009 const errors = global.errors;
5010 const len = buf.length;
5011 buf.writeByte(0);
5012 const str = buf.extractSlice()[0 .. len];
5013 const bool doUnittests = global.params.parsingUnittestsRequired();
5014 auto locm = adjustLocForMixin(str, loc, global.params.mixinOut);
5015 scope p = new Parser!ASTCodegen(locm, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
5016 p.transitionIn = global.params.v.vin;
5017 p.nextToken();
5018 //printf("p.loc.linnum = %d\n", p.loc.linnum);
5020 auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
5021 if (errors != global.errors)
5023 assert(global.errors != errors); // should have caught all these cases
5024 return null;
5026 if (p.token.value != TOK.endOfFile)
5028 .error(loc, "unexpected token `%s` after type `%s`",
5029 p.token.toChars(), o.toChars());
5030 .errorSupplemental(loc, "while parsing string mixin type `%s`",
5031 str.ptr);
5032 return null;
5035 return o;