d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[official-gcc.git] / gcc / d / dmd / typesem.d
blob84561ac467aa4d14aecebd5ace0bca6fbaca6620
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.dmangle;
31 import dmd.dmodule;
32 import dmd.dscope;
33 import dmd.dstruct;
34 import dmd.dsymbol;
35 import dmd.dsymbolsem;
36 import dmd.dtemplate;
37 import dmd.errors;
38 import dmd.errorsink;
39 import dmd.expression;
40 import dmd.expressionsem;
41 import dmd.func;
42 import dmd.globals;
43 import dmd.hdrgen;
44 import dmd.id;
45 import dmd.identifier;
46 import dmd.imphint;
47 import dmd.importc;
48 import dmd.init;
49 import dmd.initsem;
50 import dmd.location;
51 import dmd.visitor;
52 import dmd.mtype;
53 import dmd.objc;
54 import dmd.opover;
55 import dmd.parse;
56 import dmd.root.complex;
57 import dmd.root.ctfloat;
58 import dmd.root.rmem;
59 import dmd.common.outbuffer;
60 import dmd.root.rootobject;
61 import dmd.root.string;
62 import dmd.root.stringtable;
63 import dmd.safe;
64 import dmd.semantic3;
65 import dmd.sideeffect;
66 import dmd.target;
67 import dmd.tokens;
69 /*************************************
70 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
71 * Setting one of pe/pt/ps.
72 * Params:
73 * loc = location for error messages
74 * sc = context
75 * s = symbol being indexed - could be a tuple, could be an expression
76 * pe = set if s[oindex] is an Expression, otherwise null
77 * pt = set if s[oindex] is a Type, otherwise null
78 * ps = set if s[oindex] is a Dsymbol, otherwise null
79 * oindex = index into s
81 private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
83 auto tup = s.isTupleDeclaration();
85 auto eindex = isExpression(oindex);
86 auto tindex = isType(oindex);
87 auto sindex = isDsymbol(oindex);
89 if (!tup)
91 // It's really an index expression
92 if (tindex)
93 eindex = new TypeExp(loc, tindex);
94 else if (sindex)
95 eindex = symbolToExp(sindex, loc, sc, false);
96 Expression e = new IndexExp(loc, symbolToExp(s, loc, sc, false), eindex);
97 e = e.expressionSemantic(sc);
98 resolveExp(e, pt, pe, ps);
99 return;
102 // Convert oindex to Expression, then try to resolve to constant.
103 if (tindex)
104 tindex.resolve(loc, sc, eindex, tindex, sindex);
105 if (sindex)
106 eindex = symbolToExp(sindex, loc, sc, false);
107 if (!eindex)
109 .error(loc, "index `%s` is not an expression", oindex.toChars());
110 pt = Type.terror;
111 return;
114 eindex = semanticLength(sc, tup, eindex);
115 eindex = eindex.ctfeInterpret();
116 if (eindex.op == EXP.error)
118 pt = Type.terror;
119 return;
121 const(uinteger_t) d = eindex.toUInteger();
122 if (d >= tup.objects.length)
124 .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong)tup.objects.length);
125 pt = Type.terror;
126 return;
129 RootObject o = (*tup.objects)[cast(size_t)d];
130 ps = isDsymbol(o);
131 if (auto t = isType(o))
132 pt = t.typeSemantic(loc, sc);
133 if (auto e = isExpression(o))
134 resolveExp(e, pt, pe, ps);
137 /*************************************
138 * Takes an array of Identifiers and figures out if
139 * it represents a Type, Expression, or Dsymbol.
140 * Params:
141 * mt = array of identifiers
142 * loc = location for error messages
143 * sc = context
144 * s = symbol to start search at
145 * scopesym = unused
146 * pe = set if expression otherwise null
147 * pt = set if type otherwise null
148 * ps = set if symbol otherwise null
149 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
151 private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
152 out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
154 version (none)
156 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars());
157 if (scopesym)
158 printf("\tscopesym = '%s'\n", scopesym.toChars());
161 if (!s)
163 /* Look for what user might have intended
165 const p = mt.mutableOf().unSharedOf().toChars();
166 auto id = Identifier.idPool(p, cast(uint)strlen(p));
167 if (const n = importHint(id.toString()))
168 error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr);
169 else if (auto s2 = sc.search_correct(id))
170 error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
171 else if (const q = Scope.search_correct_C(id))
172 error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
173 else if ((id == Id.This && sc.getStructClassScope()) ||
174 (id == Id._super && sc.getClassScope()))
175 error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p);
176 else
177 error(loc, "undefined identifier `%s`", p);
179 pt = Type.terror;
180 return;
183 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
184 Declaration d = s.isDeclaration();
185 if (d && (d.storage_class & STC.templateparameter))
186 s = s.toAlias();
187 else
189 // check for deprecated or disabled aliases
190 // functions are checked after overloading
191 // templates are checked after matching constraints
192 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
193 s.checkDeprecated(loc, sc);
194 if (d)
195 d.checkDisabled(loc, sc, true);
197 s = s.toAlias();
198 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
199 for (size_t i = 0; i < mt.idents.length; i++)
201 RootObject id = mt.idents[i];
202 switch (id.dyncast()) with (DYNCAST)
204 case expression:
205 case type:
206 Type tx;
207 Expression ex;
208 Dsymbol sx;
209 resolveTupleIndex(loc, sc, s, ex, tx, sx, id);
210 if (sx)
212 s = sx.toAlias();
213 continue;
215 if (tx)
216 ex = new TypeExp(loc, tx);
217 assert(ex);
219 ex = typeToExpressionHelper(mt, ex, i + 1);
220 ex = ex.expressionSemantic(sc);
221 resolveExp(ex, pt, pe, ps);
222 return;
223 default:
224 break;
227 Type t = s.getType(); // type symbol, type alias, or type tuple?
228 uint errorsave = global.errors;
229 int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports;
231 Dsymbol sm = s.searchX(loc, sc, id, flags);
232 if (sm)
234 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
236 .error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
237 sm = null;
239 // Same check as in dotIdSemanticProp(DotIdExp)
240 else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
242 // @@@DEPRECATED_2.106@@@
243 // Should be an error in 2.106. Just remove the deprecation call
244 // and uncomment the null assignment
245 deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
246 //sm = null;
249 if (global.errors != errorsave)
251 pt = Type.terror;
252 return;
255 void helper3()
257 Expression e;
258 VarDeclaration v = s.isVarDeclaration();
259 FuncDeclaration f = s.isFuncDeclaration();
260 if (intypeid || !v && !f)
261 e = symbolToExp(s, loc, sc, true);
262 else
263 e = new VarExp(loc, s.isDeclaration(), true);
265 e = typeToExpressionHelper(mt, e, i);
266 e = e.expressionSemantic(sc);
267 resolveExp(e, pt, pe, ps);
270 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
271 if (intypeid && !t && sm && sm.needThis())
272 return helper3();
274 if (VarDeclaration v = s.isVarDeclaration())
276 // https://issues.dlang.org/show_bug.cgi?id=19913
277 // v.type would be null if it is a forward referenced member.
278 if (v.type is null)
279 v.dsymbolSemantic(sc);
280 if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
281 v.type.isConst() || v.type.isImmutable())
283 // https://issues.dlang.org/show_bug.cgi?id=13087
284 // this.field is not constant always
285 if (!v.isThisDeclaration())
286 return helper3();
290 if (!sm)
291 return helper3();
293 s = sm.toAlias();
296 if (auto em = s.isEnumMember())
298 // It's not a type, it's an expression
299 pe = em.getVarExp(loc, sc);
300 return;
302 if (auto v = s.isVarDeclaration())
304 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
305 * because some variables used in type context need to prevent lowering
306 * to a literal or contextful expression. For example:
308 * enum a = 1; alias b = a;
309 * template X(alias e){ alias v = e; } alias x = X!(1);
310 * struct S { int v; alias w = v; }
311 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
312 * // because getDsymbol() need to work in AliasDeclaration::semantic().
314 if (!v.type ||
315 !v.type.deco && v.inuse)
317 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
318 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
319 else
320 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
321 pt = Type.terror;
322 return;
324 if (v.type.ty == Terror)
325 pt = Type.terror;
326 else
327 pe = new VarExp(loc, v);
328 return;
330 if (auto fld = s.isFuncLiteralDeclaration())
332 //printf("'%s' is a function literal\n", fld.toChars());
333 auto e = new FuncExp(loc, fld);
334 pe = e.expressionSemantic(sc);
335 return;
337 version (none)
339 if (FuncDeclaration fd = s.isFuncDeclaration())
341 pe = new DsymbolExp(loc, fd);
342 return;
346 Type t;
347 while (1)
349 t = s.getType();
350 if (t)
351 break;
352 ps = s;
353 return;
356 if (auto ti = t.isTypeInstance())
357 if (ti != mt && !ti.deco)
359 if (!ti.tempinst.errors)
360 error(loc, "forward reference to `%s`", ti.toChars());
361 pt = Type.terror;
362 return;
365 if (t.ty == Ttuple)
366 pt = t;
367 else
368 pt = t.merge();
371 /******************************************
372 * We've mistakenly parsed `t` as a type.
373 * Redo `t` as an Expression only if there are no type modifiers.
374 * Params:
375 * t = mistaken type
376 * Returns:
377 * t redone as Expression, null if cannot
379 Expression typeToExpression(Type t)
381 static Expression visitSArray(TypeSArray t)
383 if (auto e = t.next.typeToExpression())
384 return new ArrayExp(t.dim.loc, e, t.dim);
385 return null;
388 static Expression visitAArray(TypeAArray t)
390 if (auto e = t.next.typeToExpression())
392 if (auto ei = t.index.typeToExpression())
393 return new ArrayExp(t.loc, e, ei);
395 return null;
398 static Expression visitIdentifier(TypeIdentifier t)
400 return typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident));
403 static Expression visitInstance(TypeInstance t)
405 return typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst));
408 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
409 static Expression visitMixin(TypeMixin t)
411 return new TypeExp(t.loc, t);
414 if (t.mod)
415 return null;
416 switch (t.ty)
418 case Tsarray: return visitSArray(t.isTypeSArray());
419 case Taarray: return visitAArray(t.isTypeAArray());
420 case Tident: return visitIdentifier(t.isTypeIdentifier());
421 case Tinstance: return visitInstance(t.isTypeInstance());
422 case Tmixin: return visitMixin(t.isTypeMixin());
423 default: return null;
427 /******************************************
428 * Perform semantic analysis on a type.
429 * Params:
430 * type = Type AST node
431 * loc = the location of the type
432 * sc = context
433 * Returns:
434 * `Type` with completed semantic analysis, `Terror` if errors
435 * were encountered
437 extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
439 static Type error()
441 return Type.terror;
444 Type visitType(Type t)
446 // @@@DEPRECATED_2.110@@@
447 // Use of `cent` and `ucent` has always been an error.
448 // Starting from 2.100, recommend core.int128 as a replace for the
449 // lack of compiler support.
450 if (t.ty == Tint128 || t.ty == Tuns128)
452 .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
453 return error();
456 return t.merge();
459 Type visitVector(TypeVector mtype)
461 const errors = global.errors;
462 mtype.basetype = mtype.basetype.typeSemantic(loc, sc);
463 if (errors != global.errors)
464 return error();
465 mtype.basetype = mtype.basetype.toBasetype().mutableOf();
466 if (mtype.basetype.ty != Tsarray)
468 .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars());
469 return error();
471 TypeSArray t = mtype.basetype.isTypeSArray();
472 const sz = cast(int)t.size(loc);
473 final switch (target.isVectorTypeSupported(sz, t.nextOf()))
475 case 0:
476 // valid
477 break;
479 case 1:
480 // no support at all
481 .error(loc, "SIMD vector types not supported on this platform");
482 return error();
484 case 2:
485 // invalid base type
486 .error(loc, "vector type `%s` is not supported on this platform", mtype.toChars());
487 return error();
489 case 3:
490 // invalid size
491 .error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars());
492 return error();
494 return merge(mtype);
497 Type visitSArray(TypeSArray mtype)
499 //printf("TypeSArray::semantic() %s\n", toChars());
500 Type t;
501 Expression e;
502 Dsymbol s;
503 mtype.next.resolve(loc, sc, e, t, s);
505 if (auto tup = s ? s.isTupleDeclaration() : null)
507 mtype.dim = semanticLength(sc, tup, mtype.dim);
508 mtype.dim = mtype.dim.ctfeInterpret();
509 if (mtype.dim.op == EXP.error)
510 return error();
512 uinteger_t d = mtype.dim.toUInteger();
513 if (d >= tup.objects.length)
515 .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tup.objects.length);
516 return error();
519 RootObject o = (*tup.objects)[cast(size_t)d];
520 if (o.dyncast() != DYNCAST.type)
522 .error(loc, "`%s` is not a type", mtype.toChars());
523 return error();
525 return (cast(Type)o).addMod(mtype.mod);
528 if (t && t.ty == Terror)
529 return error();
531 Type tn = mtype.next.typeSemantic(loc, sc);
532 if (tn.ty == Terror)
533 return error();
535 Type tbn = tn.toBasetype();
536 if (mtype.dim)
538 auto errors = global.errors;
539 mtype.dim = semanticLength(sc, tbn, mtype.dim);
540 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
541 if (errors != global.errors)
542 return error();
544 mtype.dim = mtype.dim.optimize(WANTvalue);
545 mtype.dim = mtype.dim.ctfeInterpret();
546 if (mtype.dim.op == EXP.error)
547 return error();
549 errors = global.errors;
550 dinteger_t d1 = mtype.dim.toInteger();
551 if (errors != global.errors)
552 return error();
554 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
555 mtype.dim = mtype.dim.optimize(WANTvalue);
556 if (mtype.dim.op == EXP.error)
557 return error();
559 errors = global.errors;
560 dinteger_t d2 = mtype.dim.toInteger();
561 if (errors != global.errors)
562 return error();
564 if (mtype.dim.op == EXP.error)
565 return error();
567 Type overflowError()
569 .error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
570 mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, target.maxStaticDataSize);
571 return error();
574 if (d1 != d2)
575 return overflowError();
577 Type tbx = tbn.baseElemOf();
578 if (tbx.ty == Tstruct && !tbx.isTypeStruct().sym.members ||
579 tbx.ty == Tenum && !tbx.isTypeEnum().sym.members)
581 /* To avoid meaningless error message, skip the total size limit check
582 * when the bottom of element type is opaque.
585 else if (tbn.isTypeBasic() ||
586 tbn.ty == Tpointer ||
587 tbn.ty == Tarray ||
588 tbn.ty == Tsarray ||
589 tbn.ty == Taarray ||
590 (tbn.ty == Tstruct && tbn.isTypeStruct().sym.sizeok == Sizeok.done) ||
591 tbn.ty == Tclass)
593 /* Only do this for types that don't need to have semantic()
594 * run on them for the size, since they may be forward referenced.
596 bool overflow = false;
597 if (mulu(tbn.size(loc), d2, overflow) > target.maxStaticDataSize || overflow)
598 return overflowError();
601 switch (tbn.ty)
603 case Ttuple:
605 // Index the tuple to get the type
606 assert(mtype.dim);
607 TypeTuple tt = tbn.isTypeTuple();
608 uinteger_t d = mtype.dim.toUInteger();
609 if (d >= tt.arguments.length)
611 .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tt.arguments.length);
612 return error();
614 Type telem = (*tt.arguments)[cast(size_t)d].type;
615 return telem.addMod(mtype.mod);
618 case Tfunction:
619 case Tnone:
620 .error(loc, "cannot have array of `%s`", tbn.toChars());
621 return error();
623 default:
624 break;
626 if (tbn.isscope())
628 .error(loc, "cannot have array of scope `%s`", tbn.toChars());
629 return error();
632 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
633 * and const(T)[3] become const(T[3])
635 mtype.next = tn;
636 mtype.transitive();
637 return mtype.addMod(tn.mod).merge();
640 Type visitDArray(TypeDArray mtype)
642 Type tn = mtype.next.typeSemantic(loc, sc);
643 Type tbn = tn.toBasetype();
644 switch (tbn.ty)
646 case Ttuple:
647 return tbn;
649 case Tfunction:
650 case Tnone:
651 .error(loc, "cannot have array of `%s`", tbn.toChars());
652 return error();
654 case Terror:
655 return error();
657 default:
658 break;
660 if (tn.isscope())
662 .error(loc, "cannot have array of scope `%s`", tn.toChars());
663 return error();
665 mtype.next = tn;
666 mtype.transitive();
667 return merge(mtype);
670 Type visitAArray(TypeAArray mtype)
672 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
673 if (mtype.deco)
675 return mtype;
678 mtype.loc = loc;
679 if (sc)
680 sc.setNoFree();
682 // Deal with the case where we thought the index was a type, but
683 // in reality it was an expression.
684 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)
686 Expression e;
687 Type t;
688 Dsymbol s;
689 mtype.index.resolve(loc, sc, e, t, s);
691 // https://issues.dlang.org/show_bug.cgi?id=15478
692 if (s)
693 e = symbolToExp(s, loc, sc, false);
695 if (e)
697 // It was an expression -
698 // Rewrite as a static array
699 auto tsa = new TypeSArray(mtype.next, e);
700 return tsa.typeSemantic(loc, sc);
702 else if (t)
703 mtype.index = t.typeSemantic(loc, sc);
704 else
706 .error(loc, "index is not a type or an expression");
707 return error();
710 else
711 mtype.index = mtype.index.typeSemantic(loc, sc);
712 mtype.index = mtype.index.merge2();
714 if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable())
716 mtype.index = mtype.index.constOf().mutableOf();
717 version (none)
719 printf("index is %p %s\n", mtype.index, mtype.index.toChars());
720 mtype.index.check();
721 printf("index.mod = x%x\n", mtype.index.mod);
722 printf("index.ito = x%p\n", mtype.index.getMcache().ito);
723 if (mtype.index.getMcache().ito)
725 printf("index.ito.mod = x%x\n", mtype.index.getMcache().ito.mod);
726 printf("index.ito.ito = x%p\n", mtype.index.getMcache().ito.getMcache().ito);
731 switch (mtype.index.toBasetype().ty)
733 case Tfunction:
734 case Tvoid:
735 case Tnone:
736 case Ttuple:
737 .error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars());
738 goto case Terror;
739 case Terror:
740 return error();
742 default:
743 break;
745 Type tbase = mtype.index.baseElemOf();
746 while (tbase.ty == Tarray)
747 tbase = tbase.nextOf().baseElemOf();
748 if (auto ts = tbase.isTypeStruct())
750 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
752 StructDeclaration sd = ts.sym;
753 if (sd.semanticRun < PASS.semanticdone)
754 sd.dsymbolSemantic(null);
756 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
757 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
759 if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
761 uint errors = global.startGagging();
762 sd.xeq.semantic3(sd.xeq._scope);
763 if (global.endGagging(errors))
764 sd.xeq = sd.xerreq;
768 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
769 const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : "";
770 if (!sd.xeq)
772 // If sd.xhash != NULL:
773 // sd or its fields have user-defined toHash.
774 // AA assumes that its result is consistent with bitwise equality.
775 // else:
776 // bitwise equality & hashing
778 else if (sd.xeq == sd.xerreq)
780 if (search_function(sd, Id.eq))
782 .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars());
784 else
786 .error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars());
788 return error();
790 else if (!sd.xhash)
792 if (search_function(sd, Id.eq))
794 .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars());
796 else
798 .error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars());
800 return error();
802 else
804 // defined equality & hashing
805 assert(sd.xeq && sd.xhash);
807 /* xeq and xhash may be implicitly defined by compiler. For example:
808 * struct S { int[] arr; }
809 * With 'arr' field equality and hashing, compiler will implicitly
810 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
814 else if (tbase.ty == Tclass && !tbase.isTypeClass().sym.isInterfaceDeclaration())
816 ClassDeclaration cd = tbase.isTypeClass().sym;
817 if (cd.semanticRun < PASS.semanticdone)
818 cd.dsymbolSemantic(null);
820 if (!ClassDeclaration.object)
822 .error(Loc.initial, "missing or corrupt object.d");
823 fatal();
826 __gshared FuncDeclaration feq = null;
827 __gshared FuncDeclaration fcmp = null;
828 __gshared FuncDeclaration fhash = null;
829 if (!feq)
830 feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration();
831 if (!fcmp)
832 fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration();
833 if (!fhash)
834 fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration();
835 assert(fcmp && feq && fhash);
837 if (feq.vtblIndex < cd.vtbl.length && cd.vtbl[feq.vtblIndex] == feq)
839 version (all)
841 if (fcmp.vtblIndex < cd.vtbl.length && cd.vtbl[fcmp.vtblIndex] != fcmp)
843 const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : "";
844 .error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars());
845 errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`.");
850 mtype.next = mtype.next.typeSemantic(loc, sc).merge2();
851 mtype.transitive();
853 switch (mtype.next.toBasetype().ty)
855 case Tfunction:
856 case Tvoid:
857 case Tnone:
858 case Ttuple:
859 .error(loc, "cannot have associative array of `%s`", mtype.next.toChars());
860 goto case Terror;
861 case Terror:
862 return error();
863 default:
864 break;
866 if (mtype.next.isscope())
868 .error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
869 return error();
871 return merge(mtype);
874 Type visitPointer(TypePointer mtype)
876 //printf("TypePointer::semantic() %s\n", toChars());
877 if (mtype.deco)
879 return mtype;
881 Type n = mtype.next.typeSemantic(loc, sc);
882 switch (n.toBasetype().ty)
884 case Ttuple:
885 .error(loc, "cannot have pointer to `%s`", n.toChars());
886 goto case Terror;
887 case Terror:
888 return error();
889 default:
890 break;
892 if (n != mtype.next)
894 mtype.deco = null;
896 mtype.next = n;
897 if (mtype.next.ty != Tfunction)
899 mtype.transitive();
900 return merge(mtype);
902 version (none)
904 return merge(mtype);
906 else
908 mtype.deco = merge(mtype).deco;
909 /* Don't return merge(), because arg identifiers and default args
910 * can be different
911 * even though the types match
913 return mtype;
917 Type visitReference(TypeReference mtype)
919 //printf("TypeReference::semantic()\n");
920 Type n = mtype.next.typeSemantic(loc, sc);
921 if (n != mtype.next)
922 mtype.deco = null;
923 mtype.next = n;
924 mtype.transitive();
925 return merge(mtype);
928 Type visitFunction(TypeFunction mtype)
930 if (mtype.deco) // if semantic() already run
932 //printf("already done\n");
933 return mtype;
935 //printf("TypeFunction::semantic() this = %p\n", mtype);
936 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
938 bool errors = false;
940 if (mtype.inuse > global.recursionLimit)
942 mtype.inuse = 0;
943 .error(loc, "recursive type");
944 return error();
947 /* Copy in order to not mess up original.
948 * This can produce redundant copies if inferring return type,
949 * as semantic() will get called again on this.
951 TypeFunction tf = mtype.copy().toTypeFunction();
952 if (mtype.parameterList.parameters)
954 tf.parameterList.parameters = mtype.parameterList.parameters.copy();
955 for (size_t i = 0; i < mtype.parameterList.parameters.length; i++)
957 Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter));
958 memcpy(cast(void*)p, cast(void*)(*mtype.parameterList.parameters)[i], __traits(classInstanceSize, Parameter));
959 (*tf.parameterList.parameters)[i] = p;
963 if (sc.stc & STC.pure_)
964 tf.purity = PURE.fwdref;
965 if (sc.stc & STC.nothrow_)
966 tf.isnothrow = true;
967 if (sc.stc & STC.nogc)
968 tf.isnogc = true;
969 if (sc.stc & STC.ref_)
970 tf.isref = true;
971 if (sc.stc & STC.return_)
972 tf.isreturn = true;
973 if (sc.stc & STC.returnScope)
974 tf.isreturnscope = true;
975 if (sc.stc & STC.returninferred)
976 tf.isreturninferred = true;
977 if (sc.stc & STC.scope_)
978 tf.isScopeQual = true;
979 if (sc.stc & STC.scopeinferred)
980 tf.isscopeinferred = true;
982 // if (tf.isreturn && !tf.isref)
983 // tf.isScopeQual = true; // return by itself means 'return scope'
985 if (tf.trust == TRUST.default_)
987 if (sc.stc & STC.safe)
988 tf.trust = TRUST.safe;
989 else if (sc.stc & STC.system)
990 tf.trust = TRUST.system;
991 else if (sc.stc & STC.trusted)
992 tf.trust = TRUST.trusted;
995 if (sc.stc & STC.property)
996 tf.isproperty = true;
997 if (sc.stc & STC.live)
998 tf.islive = true;
1000 tf.linkage = sc.linkage;
1001 if (tf.linkage == LINK.system)
1002 tf.linkage = target.systemLinkage();
1004 version (none)
1006 /* If the parent is @safe, then this function defaults to safe
1007 * too.
1008 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1009 * to be inferred first.
1011 if (tf.trust == TRUST.default_)
1012 for (Dsymbol p = sc.func; p; p = p.toParent2())
1014 FuncDeclaration fd = p.isFuncDeclaration();
1015 if (fd)
1017 if (fd.isSafeBypassingInference())
1018 tf.trust = TRUST.safe; // default to @safe
1019 break;
1024 bool wildreturn = false;
1025 if (tf.next)
1027 sc = sc.push();
1028 sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR);
1029 tf.next = tf.next.typeSemantic(loc, sc);
1030 sc = sc.pop();
1031 errors |= tf.checkRetType(loc);
1032 if (tf.next.isscope() && !tf.isctor)
1034 .error(loc, "functions cannot return `scope %s`", tf.next.toChars());
1035 errors = true;
1037 if (tf.next.hasWild())
1038 wildreturn = true;
1040 if (tf.isreturn && !tf.isref && !tf.next.hasPointers())
1042 tf.isreturn = false;
1046 /// Perform semantic on the default argument to a parameter
1047 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1048 /// Returns `false` whether an error was encountered.
1049 static bool defaultArgSemantic (ref Parameter fparam, Scope* sc)
1051 Expression e = fparam.defaultArg;
1052 const isRefOrOut = fparam.isReference();
1053 const isAuto = fparam.storageClass & (STC.auto_ | STC.autoref);
1054 if (isRefOrOut && !isAuto)
1056 e = e.expressionSemantic(sc);
1057 e = resolveProperties(sc, e);
1059 else
1061 e = inferType(e, fparam.type);
1062 Initializer iz = new ExpInitializer(e.loc, e);
1063 iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
1064 e = iz.initializerToExpression();
1066 if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
1068 FuncExp fe = e.isFuncExp();
1069 // Replace function literal with a function symbol,
1070 // since default arg expression must be copied when used
1071 // and copying the literal itself is wrong.
1072 e = new VarExp(e.loc, fe.fd, false);
1073 e = new AddrExp(e.loc, e);
1074 e = e.expressionSemantic(sc);
1076 if (isRefOrOut && (!isAuto || e.isLvalue())
1077 && !MODimplicitConv(e.type.mod, fparam.type.mod))
1079 const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
1080 .error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1081 e.toChars(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
1083 e = e.implicitCastTo(sc, fparam.type);
1085 // default arg must be an lvalue
1086 if (isRefOrOut && !isAuto &&
1087 !(global.params.previewIn && (fparam.storageClass & STC.in_)) &&
1088 global.params.rvalueRefParam != FeatureState.enabled)
1089 e = e.toLvalue(sc, e);
1091 fparam.defaultArg = e;
1092 return (e.op != EXP.error);
1095 ubyte wildparams = 0;
1096 if (tf.parameterList.parameters)
1098 /* Create a scope for evaluating the default arguments for the parameters
1100 Scope* argsc = sc.push();
1101 argsc.stc = 0; // don't inherit storage class
1102 argsc.visibility = Visibility(Visibility.Kind.public_);
1103 argsc.func = null;
1105 size_t dim = tf.parameterList.length;
1106 for (size_t i = 0; i < dim; i++)
1108 Parameter fparam = tf.parameterList[i];
1109 fparam.storageClass |= STC.parameter;
1110 mtype.inuse++;
1111 fparam.type = fparam.type.typeSemantic(loc, argsc);
1112 mtype.inuse--;
1114 if (fparam.type.ty == Terror)
1116 errors = true;
1117 continue;
1120 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
1122 if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_))
1124 if (!fparam.type)
1125 continue;
1128 fparam.type = fparam.type.cAdjustParamType(sc); // adjust C array and function parameter types
1130 Type t = fparam.type.toBasetype();
1132 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
1133 * change.
1135 if (auto tt = t.isTypeTuple())
1137 /* TypeFunction::parameter also is used as the storage of
1138 * Parameter objects for FuncDeclaration. So we should copy
1139 * the elements of TypeTuple::arguments to avoid unintended
1140 * sharing of Parameter object among other functions.
1142 if (tt.arguments && tt.arguments.length)
1144 /* Propagate additional storage class from tuple parameters to their
1145 * element-parameters.
1146 * Make a copy, as original may be referenced elsewhere.
1148 size_t tdim = tt.arguments.length;
1149 auto newparams = new Parameters(tdim);
1150 for (size_t j = 0; j < tdim; j++)
1152 Parameter narg = (*tt.arguments)[j];
1154 // https://issues.dlang.org/show_bug.cgi?id=12744
1155 // If the storage classes of narg
1156 // conflict with the ones in fparam, it's ignored.
1157 StorageClass stc = fparam.storageClass | narg.storageClass;
1158 StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
1159 StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
1160 if (stc1 && stc2 && stc1 != stc2)
1162 OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0));
1163 OutBuffer buf2; stcToBuffer(&buf2, stc2);
1165 .error(loc, "incompatible parameter storage classes `%s` and `%s`",
1166 buf1.peekChars(), buf2.peekChars());
1167 errors = true;
1168 stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_));
1170 (*newparams)[j] = new Parameter(
1171 stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
1173 fparam.type = new TypeTuple(newparams);
1174 fparam.type = fparam.type.typeSemantic(loc, argsc);
1176 fparam.storageClass = STC.parameter;
1178 /* Reset number of parameters, and back up one to do this fparam again,
1179 * now that it is a tuple
1181 dim = tf.parameterList.length;
1182 i--;
1183 continue;
1186 // -preview=in: Always add `ref` when used with `extern(C++)` functions
1187 // Done here to allow passing opaque types with `in`
1188 if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
1190 switch (tf.linkage)
1192 case LINK.cpp:
1193 fparam.storageClass |= STC.ref_;
1194 break;
1195 case LINK.default_, LINK.d:
1196 break;
1197 default:
1198 .error(loc, "cannot use `in` parameters with `extern(%s)` functions",
1199 linkageToChars(tf.linkage));
1200 .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
1201 break;
1205 if (t.ty == Tfunction)
1207 .error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars());
1208 errors = true;
1210 else if (!fparam.isReference() &&
1211 (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum))
1213 Type tb2 = t.baseElemOf();
1214 if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members ||
1215 tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype)
1217 if (global.params.previewIn && (fparam.storageClass & STC.in_))
1219 .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
1220 fparam.toChars(), fparam.type.toChars());
1222 else
1223 .error(loc, "cannot have parameter of opaque type `%s` by value",
1224 fparam.type.toChars());
1225 errors = true;
1228 else if (!fparam.isLazy() && t.ty == Tvoid)
1230 .error(loc, "cannot have parameter of type `%s`", fparam.type.toChars());
1231 errors = true;
1234 const bool isTypesafeVariadic = i + 1 == dim &&
1235 tf.parameterList.varargs == VarArg.typesafe &&
1236 (t.isTypeDArray() || t.isTypeClass());
1237 if (isTypesafeVariadic)
1239 /* typesafe variadic arguments are constructed on the stack, so must be `scope`
1241 fparam.storageClass |= STC.scope_ | STC.scopeinferred;
1244 if (fparam.storageClass & STC.return_)
1246 if (!fparam.isReference())
1248 if (!(fparam.storageClass & STC.scope_))
1249 fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
1250 if (tf.isref)
1253 else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid)
1255 fparam.storageClass &= ~STC.return_; // https://issues.dlang.org/show_bug.cgi?id=18963
1259 if (isTypesafeVariadic)
1261 /* This is because they can be constructed on the stack
1262 * https://dlang.org/spec/function.html#typesafe_variadic_functions
1264 .error(loc, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
1265 fparam.ident ? fparam.ident.toChars() : "", t.toChars());
1266 errors = true;
1270 if (fparam.storageClass & STC.out_)
1272 if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild))
1274 .error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars());
1275 errors = true;
1277 else
1279 Type tv = t.baseElemOf();
1280 if (tv.ty == Tstruct && tv.isTypeStruct().sym.noDefaultCtor)
1282 .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars());
1283 errors = true;
1288 if (t.hasWild())
1290 wildparams |= 1;
1291 //if (tf.next && !wildreturn)
1292 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
1295 /* Scope attribute is not necessary if the parameter type does not have pointers
1297 const sr = buildScopeRef(fparam.storageClass);
1298 switch (sr)
1300 case ScopeRef.Scope:
1301 case ScopeRef.RefScope:
1302 case ScopeRef.ReturnRef_Scope:
1303 if (!fparam.type.hasPointers())
1304 fparam.storageClass &= ~STC.scope_;
1305 break;
1307 case ScopeRef.ReturnScope:
1308 case ScopeRef.Ref_ReturnScope:
1309 if (!fparam.type.hasPointers())
1310 fparam.storageClass &= ~(STC.return_ | STC.scope_ | STC.returnScope);
1311 break;
1313 default:
1314 break;
1317 // Remove redundant storage classes for type, they are already applied
1318 fparam.storageClass &= ~(STC.TYPECTOR);
1320 // -preview=in: add `ref` storage class to suited `in` params
1321 if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
1323 auto ts = t.baseElemOf().isTypeStruct();
1324 const isPOD = !ts || ts.sym.isPOD();
1325 if (!isPOD || target.preferPassByRef(t))
1326 fparam.storageClass |= STC.ref_;
1330 // Now that we completed semantic for the argument types,
1331 // run semantic on their default values,
1332 // bearing in mind tuples have been expanded.
1333 // We need to keep a pair of [oidx, eidx] (original index,
1334 // extended index), as we need to run semantic when `oidx` changes.
1335 size_t tupleOrigIdx = size_t.max;
1336 size_t tupleExtIdx = size_t.max;
1337 foreach (oidx, oparam, eidx, eparam; tf.parameterList)
1339 // oparam (original param) will always have the default arg
1340 // if there's one, but `eparam` will not if it's an expanded
1341 // tuple. When we see an expanded tuple, we need to save its
1342 // position to get the offset in it later on.
1343 if (oparam.defaultArg)
1345 // Get the obvious case out of the way
1346 if (oparam is eparam)
1347 errors |= !defaultArgSemantic(eparam, argsc);
1348 // We're seeing a new tuple
1349 else if (tupleOrigIdx == size_t.max || tupleOrigIdx < oidx)
1351 /* https://issues.dlang.org/show_bug.cgi?id=18572
1353 * If a tuple parameter has a default argument, when expanding the parameter
1354 * tuple the default argument tuple must also be expanded.
1356 tupleOrigIdx = oidx;
1357 tupleExtIdx = eidx;
1358 errors |= !defaultArgSemantic(oparam, argsc);
1359 TupleExp te = oparam.defaultArg.isTupleExp();
1360 if (te && te.exps && te.exps.length)
1361 eparam.defaultArg = (*te.exps)[0];
1363 // Processing an already-seen tuple
1364 else
1366 TupleExp te = oparam.defaultArg.isTupleExp();
1367 if (te && te.exps && te.exps.length)
1368 eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
1372 // We need to know the default argument to resolve `auto ref`,
1373 // hence why this has to take place as the very last step.
1374 /* Resolve "auto ref" storage class to be either ref or value,
1375 * based on the argument matching the parameter
1377 if (eparam.storageClass & STC.auto_)
1379 Expression farg = mtype.fargs && eidx < mtype.fargs.length ?
1380 (*mtype.fargs)[eidx] : eparam.defaultArg;
1381 if (farg && (eparam.storageClass & STC.ref_))
1383 if (!farg.isLvalue())
1384 eparam.storageClass &= ~STC.ref_; // value parameter
1385 eparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656
1386 eparam.storageClass |= STC.autoref;
1388 else if (mtype.incomplete && (eparam.storageClass & STC.ref_))
1390 // the default argument may have been temporarily removed,
1391 // see usage of `TypeFunction.incomplete`.
1392 // https://issues.dlang.org/show_bug.cgi?id=19891
1393 eparam.storageClass &= ~STC.auto_;
1394 eparam.storageClass |= STC.autoref;
1396 else if (eparam.storageClass & STC.ref_)
1398 .error(loc, "cannot explicitly instantiate template function with `auto ref` parameter");
1399 errors = true;
1401 else
1403 .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
1404 errors = true;
1409 argsc.pop();
1411 if (tf.isWild())
1412 wildparams |= 2;
1414 if (wildreturn && !wildparams)
1416 .error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars());
1417 errors = true;
1419 tf.isInOutParam = (wildparams & 1) != 0;
1420 tf.isInOutQual = (wildparams & 2) != 0;
1422 if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
1424 .error(loc, "properties can only have zero, one, or two parameter");
1425 errors = true;
1428 if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
1429 !(sc.flags & SCOPE.Cfile))
1431 .error(loc, "variadic functions with non-D linkage must have at least one parameter");
1432 errors = true;
1435 if (errors)
1436 return error();
1438 if (tf.next)
1439 tf.deco = tf.merge().deco;
1441 /* Don't return merge(), because arg identifiers and default args
1442 * can be different
1443 * even though the types match
1445 return tf;
1448 Type visitDelegate(TypeDelegate mtype)
1450 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
1451 if (mtype.deco) // if semantic() already run
1453 //printf("already done\n");
1454 return mtype;
1456 mtype.next = mtype.next.typeSemantic(loc, sc);
1457 if (mtype.next.ty != Tfunction)
1458 return error();
1460 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
1461 * perhaps default arguments should
1462 * be removed from next before the merge.
1464 version (none)
1466 return mtype.merge();
1468 else
1470 /* Don't return merge(), because arg identifiers and default args
1471 * can be different
1472 * even though the types match
1474 mtype.deco = mtype.merge().deco;
1475 return mtype;
1479 Type visitIdentifier(TypeIdentifier mtype)
1481 Type t;
1482 Expression e;
1483 Dsymbol s;
1484 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
1485 mtype.resolve(loc, sc, e, t, s);
1486 if (t)
1488 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
1489 return t.addMod(mtype.mod);
1491 else
1493 if (s)
1495 auto td = s.isTemplateDeclaration;
1496 if (td && td.onemember && td.onemember.isAggregateDeclaration)
1497 .error(loc, "template %s `%s` is used as a type without instantiation"
1498 ~ "; to instantiate it use `%s!(arguments)`",
1499 s.kind, s.toPrettyChars, s.ident.toChars);
1500 else
1501 .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
1502 //assert(0);
1504 else if (e.op == EXP.variable) // special case: variable is used as a type
1507 N.B. This branch currently triggers for the following code
1508 template test(x* x)
1512 i.e. the compiler prints "variable x is used as a type"
1513 which isn't a particularly good error message (x is a variable?).
1515 Dsymbol varDecl = mtype.toDsymbol(sc);
1516 const(Loc) varDeclLoc = varDecl.getLoc();
1517 Module varDeclModule = varDecl.getModule(); //This can be null
1519 .error(loc, "variable `%s` is used as a type", mtype.toChars());
1520 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
1521 if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
1523 const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
1524 .errorSupplemental(
1525 varDeclModuleImportLoc,
1526 "variable `%s` is imported here from: `%s`",
1527 varDecl.toChars,
1528 varDeclModule.toPrettyChars,
1532 .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
1534 else
1535 .error(loc, "`%s` is used as a type", mtype.toChars());
1536 return error();
1540 Type visitInstance(TypeInstance mtype)
1542 Type t;
1543 Expression e;
1544 Dsymbol s;
1546 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
1548 const errors = global.errors;
1549 mtype.resolve(loc, sc, e, t, s);
1550 // if we had an error evaluating the symbol, suppress further errors
1551 if (!t && errors != global.errors)
1552 return error();
1555 if (!t)
1557 if (!e && s && s.errors)
1559 // if there was an error evaluating the symbol, it might actually
1560 // be a type. Avoid misleading error messages.
1561 .error(loc, "`%s` had previous errors", mtype.toChars());
1563 else
1564 .error(loc, "`%s` is used as a type", mtype.toChars());
1565 return error();
1567 return t;
1570 Type visitTypeof(TypeTypeof mtype)
1572 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
1573 Expression e;
1574 Type t;
1575 Dsymbol s;
1576 mtype.resolve(loc, sc, e, t, s);
1577 if (s && (t = s.getType()) !is null)
1578 t = t.addMod(mtype.mod);
1579 if (!t)
1581 .error(loc, "`%s` is used as a type", mtype.toChars());
1582 return error();
1584 return t;
1587 Type visitTraits(TypeTraits mtype)
1589 Expression e;
1590 Type t;
1591 Dsymbol s;
1592 mtype.resolve(loc, sc, e, t, s);
1594 if (!t)
1596 if (!global.errors)
1597 .error(mtype.loc, "`%s` does not give a valid type", mtype.toChars);
1598 return error();
1600 return t;
1603 Type visitReturn(TypeReturn mtype)
1605 //printf("TypeReturn::semantic() %s\n", toChars());
1606 Expression e;
1607 Type t;
1608 Dsymbol s;
1609 mtype.resolve(loc, sc, e, t, s);
1610 if (s && (t = s.getType()) !is null)
1611 t = t.addMod(mtype.mod);
1612 if (!t)
1614 .error(loc, "`%s` is used as a type", mtype.toChars());
1615 return error();
1617 return t;
1620 Type visitStruct(TypeStruct mtype)
1622 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
1623 if (mtype.deco)
1624 return mtype;
1626 /* Don't semantic for sym because it should be deferred until
1627 * sizeof needed or its members accessed.
1629 // instead, parent should be set correctly
1630 assert(mtype.sym.parent);
1632 if (mtype.sym.type.ty == Terror)
1633 return error();
1635 return merge(mtype);
1638 Type visitEnum(TypeEnum mtype)
1640 //printf("TypeEnum::semantic() %s\n", toChars());
1641 return mtype.deco ? mtype : merge(mtype);
1644 Type visitClass(TypeClass mtype)
1646 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
1647 if (mtype.deco)
1648 return mtype;
1650 /* Don't semantic for sym because it should be deferred until
1651 * sizeof needed or its members accessed.
1653 // instead, parent should be set correctly
1654 assert(mtype.sym.parent);
1656 if (mtype.sym.type.ty == Terror)
1657 return error();
1659 return merge(mtype);
1662 Type visitTuple(TypeTuple mtype)
1664 //printf("TypeTuple::semantic(this = %p)\n", this);
1665 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
1666 if (!mtype.deco)
1667 mtype.deco = merge(mtype).deco;
1669 /* Don't return merge(), because a tuple with one type has the
1670 * same deco as that type.
1672 return mtype;
1675 Type visitSlice(TypeSlice mtype)
1677 //printf("TypeSlice::semantic() %s\n", toChars());
1678 Type tn = mtype.next.typeSemantic(loc, sc);
1679 //printf("next: %s\n", tn.toChars());
1681 Type tbn = tn.toBasetype();
1682 if (tbn.ty != Ttuple)
1684 .error(loc, "can only slice tuple types, not `%s`", tbn.toChars());
1685 return error();
1687 TypeTuple tt = cast(TypeTuple)tbn;
1689 mtype.lwr = semanticLength(sc, tbn, mtype.lwr);
1690 mtype.upr = semanticLength(sc, tbn, mtype.upr);
1691 mtype.lwr = mtype.lwr.ctfeInterpret();
1692 mtype.upr = mtype.upr.ctfeInterpret();
1693 if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error)
1694 return error();
1696 uinteger_t i1 = mtype.lwr.toUInteger();
1697 uinteger_t i2 = mtype.upr.toUInteger();
1698 if (!(i1 <= i2 && i2 <= tt.arguments.length))
1700 .error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
1701 cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.length);
1702 return error();
1705 mtype.next = tn;
1706 mtype.transitive();
1708 auto args = new Parameters();
1709 args.reserve(cast(size_t)(i2 - i1));
1710 foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2])
1712 args.push(arg);
1714 Type t = new TypeTuple(args);
1715 return t.typeSemantic(loc, sc);
1718 Type visitMixin(TypeMixin mtype)
1720 //printf("TypeMixin::semantic() %s\n", toChars());
1722 Expression e;
1723 Type t;
1724 Dsymbol s;
1725 mtype.resolve(loc, sc, e, t, s);
1727 if (t && t.ty != Terror)
1728 return t;
1730 .error(mtype.loc, "`mixin(%s)` does not give a valid type", mtype.obj.toChars);
1731 return error();
1734 Type visitTag(TypeTag mtype)
1736 //printf("TypeTag.semantic() %s\n", mtype.toChars());
1737 if (mtype.resolved)
1739 /* struct S s, *p;
1741 return mtype.resolved.addSTC(mtype.mod);
1744 /* Find the current scope by skipping tag scopes.
1745 * In C, tag scopes aren't considered scopes.
1747 Scope* sc2 = sc;
1748 while (1)
1750 sc2 = sc2.inner();
1751 auto scopesym = sc2.scopesym;
1752 if (scopesym.isStructDeclaration())
1754 sc2 = sc2.enclosing;
1755 continue;
1757 break;
1760 /* Declare mtype as a struct/union/enum declaration
1762 void declareTag()
1764 void declare(ScopeDsymbol sd)
1766 sd.members = mtype.members;
1767 auto scopesym = sc2.inner().scopesym;
1768 if (scopesym.members)
1769 scopesym.members.push(sd);
1770 if (scopesym.symtab && !scopesym.symtabInsert(sd))
1772 Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
1773 handleTagSymbols(*sc2, sd, s2, scopesym);
1775 sd.parent = sc2.parent;
1776 sd.dsymbolSemantic(sc2);
1779 switch (mtype.tok)
1781 case TOK.enum_:
1782 auto ed = new EnumDeclaration(mtype.loc, mtype.id, mtype.base);
1783 declare(ed);
1784 mtype.resolved = visitEnum(new TypeEnum(ed));
1785 break;
1787 case TOK.struct_:
1788 auto sd = new StructDeclaration(mtype.loc, mtype.id, false);
1789 declare(sd);
1790 mtype.resolved = visitStruct(new TypeStruct(sd));
1791 break;
1793 case TOK.union_:
1794 auto ud = new UnionDeclaration(mtype.loc, mtype.id);
1795 declare(ud);
1796 mtype.resolved = visitStruct(new TypeStruct(ud));
1797 break;
1799 default:
1800 assert(0);
1804 /* If it doesn't have a tag by now, supply one.
1805 * It'll be unique, and therefore introducing.
1806 * Declare it, and done.
1808 if (!mtype.id)
1810 mtype.id = Identifier.generateId("__tag"[]);
1811 declareTag();
1812 return mtype.resolved.addSTC(mtype.mod);
1815 /* look for pre-existing declaration
1817 Dsymbol scopesym;
1818 auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
1819 if (!s || s.isModule())
1821 // no pre-existing declaration, so declare it
1822 if (mtype.tok == TOK.enum_ && !mtype.members)
1823 .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
1824 declareTag();
1825 return mtype.resolved.addSTC(mtype.mod);
1828 /* A redeclaration only happens if both declarations are in
1829 * the same scope
1831 const bool redeclar = (scopesym == sc2.inner().scopesym);
1833 if (redeclar)
1835 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
1837 auto ed = s.isEnumDeclaration();
1838 if (mtype.members && ed.members)
1839 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
1840 else if (!ed.members)
1842 ed.members = mtype.members;
1844 else
1847 mtype.resolved = ed.type;
1849 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
1850 mtype.tok == TOK.struct_ && s.isStructDeclaration())
1852 // Add members to original declaration
1853 auto sd = s.isStructDeclaration();
1854 if (mtype.members && sd.members)
1856 /* struct S { int b; };
1857 * struct S { int a; } *s;
1859 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
1861 else if (!sd.members)
1863 /* struct S;
1864 * struct S { int a; } *s;
1866 sd.members = mtype.members;
1867 if (sd.semanticRun == PASS.semanticdone)
1869 /* The first semantic pass marked `sd` as an opaque struct.
1870 * Re-run semantic so that all newly assigned members are
1871 * picked up and added to the symtab.
1873 sd.semanticRun = PASS.semantic;
1874 sd.dsymbolSemantic(sc2);
1877 else
1879 /* struct S { int a; };
1880 * struct S *s;
1883 mtype.resolved = sd.type;
1885 else
1887 /* int S;
1888 * struct S { int a; } *s;
1890 .error(mtype.loc, "redeclaration of `%s`", mtype.id.toChars());
1891 mtype.resolved = error();
1894 else if (mtype.members)
1896 /* struct S;
1897 * { struct S { int a; } *s; }
1899 declareTag();
1901 else
1903 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
1905 mtype.resolved = s.isEnumDeclaration().type;
1907 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
1908 mtype.tok == TOK.struct_ && s.isStructDeclaration())
1910 /* struct S;
1911 * { struct S *s; }
1913 mtype.resolved = s.isStructDeclaration().type;
1915 else
1917 /* union S;
1918 * { struct S *s; }
1920 .error(mtype.loc, "redeclaring `%s %s` as `%s %s`",
1921 s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars());
1922 declareTag();
1925 return mtype.resolved.addSTC(mtype.mod);
1928 switch (type.ty)
1930 default: return visitType(type);
1931 case Tvector: return visitVector(type.isTypeVector());
1932 case Tsarray: return visitSArray(type.isTypeSArray());
1933 case Tarray: return visitDArray(type.isTypeDArray());
1934 case Taarray: return visitAArray(type.isTypeAArray());
1935 case Tpointer: return visitPointer(type.isTypePointer());
1936 case Treference: return visitReference(type.isTypeReference());
1937 case Tfunction: return visitFunction(type.isTypeFunction());
1938 case Tdelegate: return visitDelegate(type.isTypeDelegate());
1939 case Tident: return visitIdentifier(type.isTypeIdentifier());
1940 case Tinstance: return visitInstance(type.isTypeInstance());
1941 case Ttypeof: return visitTypeof(type.isTypeTypeof());
1942 case Ttraits: return visitTraits(type.isTypeTraits());
1943 case Treturn: return visitReturn(type.isTypeReturn());
1944 case Tstruct: return visitStruct(type.isTypeStruct());
1945 case Tenum: return visitEnum(type.isTypeEnum());
1946 case Tclass: return visitClass(type.isTypeClass());
1947 case Ttuple: return visitTuple(type.isTypeTuple());
1948 case Tslice: return visitSlice(type.isTypeSlice());
1949 case Tmixin: return visitMixin(type.isTypeMixin());
1950 case Ttag: return visitTag(type.isTypeTag());
1954 /************************************
1955 * If an identical type to `type` is in `type.stringtable`, return
1956 * the latter one. Otherwise, add it to `type.stringtable`.
1957 * Some types don't get merged and are returned as-is.
1958 * Params:
1959 * type = Type to check against existing types
1960 * Returns:
1961 * the type that was merged
1963 extern (C++) Type merge(Type type)
1965 switch (type.ty)
1967 case Terror:
1968 case Ttypeof:
1969 case Tident:
1970 case Tinstance:
1971 case Tmixin:
1972 case Ttag:
1973 return type; // don't merge placeholder types
1975 case Tsarray:
1976 // prevents generating the mangle if the array dim is not yet known
1977 if (!type.isTypeSArray().dim.isIntegerExp())
1978 return type;
1979 goto default;
1981 case Tenum:
1982 break;
1984 case Taarray:
1985 if (!type.isTypeAArray().index.merge().deco)
1986 return type;
1987 goto default;
1989 default:
1990 if (type.nextOf() && !type.nextOf().deco)
1991 return type;
1992 break;
1995 //printf("merge(%s)\n", toChars());
1996 if (!type.deco)
1998 OutBuffer buf;
1999 buf.reserve(32);
2001 mangleToBuffer(type, &buf);
2003 auto sv = type.stringtable.update(buf[]);
2004 if (sv.value)
2006 Type t = sv.value;
2007 debug
2009 import core.stdc.stdio;
2010 if (!t.deco)
2011 printf("t = %s\n", t.toChars());
2013 assert(t.deco);
2014 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2015 return t;
2017 else
2019 Type t = stripDefaultArgs(type);
2020 sv.value = t;
2021 type.deco = t.deco = cast(char*)sv.toDchars();
2022 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2023 return t;
2026 return type;
2029 /***************************************
2030 * Calculate built-in properties which just the type is necessary.
2032 * Params:
2033 * t = the type for which the property is calculated
2034 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2035 * loc = the location where the property is encountered
2036 * ident = the identifier of the property
2037 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2038 * src = expression for type `t` or null.
2039 * Returns:
2040 * expression representing the property, or null if not a property and (flag & 1)
2042 Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag,
2043 Expression src = null)
2045 Expression visitType(Type mt)
2047 Expression e;
2048 static if (LOGDOTEXP)
2050 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2052 if (ident == Id.__sizeof)
2054 const sz = mt.size(loc);
2055 if (sz == SIZE_INVALID)
2056 return ErrorExp.get();
2057 e = new IntegerExp(loc, sz, Type.tsize_t);
2059 else if (ident == Id.__xalignof)
2061 const explicitAlignment = mt.alignment();
2062 const naturalAlignment = mt.alignsize();
2063 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
2064 e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
2066 else if (ident == Id._init)
2068 Type tb = mt.toBasetype();
2069 e = mt.defaultInitLiteral(loc);
2070 if (tb.ty == Tstruct && tb.needsNested())
2072 e.isStructLiteralExp().useStaticInit = true;
2075 else if (ident == Id._mangleof)
2077 if (!mt.deco)
2079 error(loc, "forward reference of type `%s.mangleof`", mt.toChars());
2080 e = ErrorExp.get();
2082 else
2084 e = new StringExp(loc, mt.deco.toDString());
2085 Scope sc;
2086 e = e.expressionSemantic(&sc);
2089 else if (ident == Id.stringof)
2091 const s = mt.toChars();
2092 e = new StringExp(loc, s.toDString());
2093 Scope sc;
2094 e = e.expressionSemantic(&sc);
2096 else if (flag && mt != Type.terror)
2098 return null;
2100 else
2102 Dsymbol s = null;
2103 if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
2104 s = mt.toDsymbol(null);
2105 if (s)
2106 s = s.search_correct(ident);
2107 if (s && !symbolIsVisible(scope_, s))
2108 s = null;
2109 if (mt != Type.terror)
2111 if (s)
2112 error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
2113 else if (ident == Id.call && mt.ty == Tclass)
2114 error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
2116 else if (const n = importHint(ident.toString()))
2117 error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
2118 else
2120 if (src)
2121 error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true));
2122 else
2123 error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
2124 if (auto dsym = mt.toDsymbol(scope_))
2125 if (auto sym = dsym.isAggregateDeclaration())
2127 if (auto fd = search_function(sym, Id.opDispatch))
2128 errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
2129 else if (!sym.members)
2130 errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
2134 e = ErrorExp.get();
2136 return e;
2139 Expression visitError(TypeError)
2141 return ErrorExp.get();
2144 Expression visitBasic(TypeBasic mt)
2146 Expression integerValue(dinteger_t i)
2148 return new IntegerExp(loc, i, mt);
2151 Expression intValue(dinteger_t i)
2153 return new IntegerExp(loc, i, Type.tint32);
2156 Expression floatValue(real_t r)
2158 if (mt.isreal() || mt.isimaginary())
2159 return new RealExp(loc, r, mt);
2160 else
2162 return new ComplexExp(loc, complex_t(r, r), mt);
2166 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
2167 if (ident == Id.max)
2169 switch (mt.ty)
2171 case Tint8: return integerValue(byte.max);
2172 case Tuns8: return integerValue(ubyte.max);
2173 case Tint16: return integerValue(short.max);
2174 case Tuns16: return integerValue(ushort.max);
2175 case Tint32: return integerValue(int.max);
2176 case Tuns32: return integerValue(uint.max);
2177 case Tint64: return integerValue(long.max);
2178 case Tuns64: return integerValue(ulong.max);
2179 case Tbool: return integerValue(bool.max);
2180 case Tchar: return integerValue(char.max);
2181 case Twchar: return integerValue(wchar.max);
2182 case Tdchar: return integerValue(dchar.max);
2183 case Tcomplex32:
2184 case Timaginary32:
2185 case Tfloat32: return floatValue(target.FloatProperties.max);
2186 case Tcomplex64:
2187 case Timaginary64:
2188 case Tfloat64: return floatValue(target.DoubleProperties.max);
2189 case Tcomplex80:
2190 case Timaginary80:
2191 case Tfloat80: return floatValue(target.RealProperties.max);
2192 default: break;
2195 else if (ident == Id.min)
2197 switch (mt.ty)
2199 case Tint8: return integerValue(byte.min);
2200 case Tuns8:
2201 case Tuns16:
2202 case Tuns32:
2203 case Tuns64:
2204 case Tbool:
2205 case Tchar:
2206 case Twchar:
2207 case Tdchar: return integerValue(0);
2208 case Tint16: return integerValue(short.min);
2209 case Tint32: return integerValue(int.min);
2210 case Tint64: return integerValue(long.min);
2211 default: break;
2214 else if (ident == Id.min_normal)
2216 switch (mt.ty)
2218 case Tcomplex32:
2219 case Timaginary32:
2220 case Tfloat32: return floatValue(target.FloatProperties.min_normal);
2221 case Tcomplex64:
2222 case Timaginary64:
2223 case Tfloat64: return floatValue(target.DoubleProperties.min_normal);
2224 case Tcomplex80:
2225 case Timaginary80:
2226 case Tfloat80: return floatValue(target.RealProperties.min_normal);
2227 default: break;
2230 else if (ident == Id.nan)
2232 switch (mt.ty)
2234 case Tcomplex32:
2235 case Tcomplex64:
2236 case Tcomplex80:
2237 case Timaginary32:
2238 case Timaginary64:
2239 case Timaginary80:
2240 case Tfloat32:
2241 case Tfloat64:
2242 case Tfloat80: return floatValue(target.RealProperties.nan);
2243 default: break;
2246 else if (ident == Id.infinity)
2248 switch (mt.ty)
2250 case Tcomplex32:
2251 case Tcomplex64:
2252 case Tcomplex80:
2253 case Timaginary32:
2254 case Timaginary64:
2255 case Timaginary80:
2256 case Tfloat32:
2257 case Tfloat64:
2258 case Tfloat80: return floatValue(target.RealProperties.infinity);
2259 default: break;
2262 else if (ident == Id.dig)
2264 switch (mt.ty)
2266 case Tcomplex32:
2267 case Timaginary32:
2268 case Tfloat32: return intValue(target.FloatProperties.dig);
2269 case Tcomplex64:
2270 case Timaginary64:
2271 case Tfloat64: return intValue(target.DoubleProperties.dig);
2272 case Tcomplex80:
2273 case Timaginary80:
2274 case Tfloat80: return intValue(target.RealProperties.dig);
2275 default: break;
2278 else if (ident == Id.epsilon)
2280 switch (mt.ty)
2282 case Tcomplex32:
2283 case Timaginary32:
2284 case Tfloat32: return floatValue(target.FloatProperties.epsilon);
2285 case Tcomplex64:
2286 case Timaginary64:
2287 case Tfloat64: return floatValue(target.DoubleProperties.epsilon);
2288 case Tcomplex80:
2289 case Timaginary80:
2290 case Tfloat80: return floatValue(target.RealProperties.epsilon);
2291 default: break;
2294 else if (ident == Id.mant_dig)
2296 switch (mt.ty)
2298 case Tcomplex32:
2299 case Timaginary32:
2300 case Tfloat32: return intValue(target.FloatProperties.mant_dig);
2301 case Tcomplex64:
2302 case Timaginary64:
2303 case Tfloat64: return intValue(target.DoubleProperties.mant_dig);
2304 case Tcomplex80:
2305 case Timaginary80:
2306 case Tfloat80: return intValue(target.RealProperties.mant_dig);
2307 default: break;
2310 else if (ident == Id.max_10_exp)
2312 switch (mt.ty)
2314 case Tcomplex32:
2315 case Timaginary32:
2316 case Tfloat32: return intValue(target.FloatProperties.max_10_exp);
2317 case Tcomplex64:
2318 case Timaginary64:
2319 case Tfloat64: return intValue(target.DoubleProperties.max_10_exp);
2320 case Tcomplex80:
2321 case Timaginary80:
2322 case Tfloat80: return intValue(target.RealProperties.max_10_exp);
2323 default: break;
2326 else if (ident == Id.max_exp)
2328 switch (mt.ty)
2330 case Tcomplex32:
2331 case Timaginary32:
2332 case Tfloat32: return intValue(target.FloatProperties.max_exp);
2333 case Tcomplex64:
2334 case Timaginary64:
2335 case Tfloat64: return intValue(target.DoubleProperties.max_exp);
2336 case Tcomplex80:
2337 case Timaginary80:
2338 case Tfloat80: return intValue(target.RealProperties.max_exp);
2339 default: break;
2342 else if (ident == Id.min_10_exp)
2344 switch (mt.ty)
2346 case Tcomplex32:
2347 case Timaginary32:
2348 case Tfloat32: return intValue(target.FloatProperties.min_10_exp);
2349 case Tcomplex64:
2350 case Timaginary64:
2351 case Tfloat64: return intValue(target.DoubleProperties.min_10_exp);
2352 case Tcomplex80:
2353 case Timaginary80:
2354 case Tfloat80: return intValue(target.RealProperties.min_10_exp);
2355 default: break;
2358 else if (ident == Id.min_exp)
2360 switch (mt.ty)
2362 case Tcomplex32:
2363 case Timaginary32:
2364 case Tfloat32: return intValue(target.FloatProperties.min_exp);
2365 case Tcomplex64:
2366 case Timaginary64:
2367 case Tfloat64: return intValue(target.DoubleProperties.min_exp);
2368 case Tcomplex80:
2369 case Timaginary80:
2370 case Tfloat80: return intValue(target.RealProperties.min_exp);
2371 default: break;
2374 return visitType(mt);
2377 Expression visitVector(TypeVector mt)
2379 return visitType(mt);
2382 Expression visitEnum(TypeEnum mt)
2384 Expression e;
2385 if (ident == Id.max || ident == Id.min)
2387 return mt.sym.getMaxMinValue(loc, ident);
2389 else if (ident == Id._init)
2391 e = mt.defaultInitLiteral(loc);
2393 else if (ident == Id.stringof)
2395 e = new StringExp(loc, mt.toString());
2396 Scope sc;
2397 e = e.expressionSemantic(&sc);
2399 else if (ident == Id._mangleof)
2401 e = visitType(mt);
2403 else
2405 e = mt.toBasetype().getProperty(scope_, loc, ident, flag);
2407 return e;
2410 Expression visitTuple(TypeTuple mt)
2412 Expression e;
2413 static if (LOGDOTEXP)
2415 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2417 if (ident == Id.length)
2419 e = new IntegerExp(loc, mt.arguments.length, Type.tsize_t);
2421 else if (ident == Id._init)
2423 e = mt.defaultInitLiteral(loc);
2425 else if (flag)
2427 e = null;
2429 else
2431 error(loc, "no property `%s` for tuple `%s`", ident.toChars(), mt.toChars());
2432 e = ErrorExp.get();
2434 return e;
2437 switch (t.ty)
2439 default: return t.isTypeBasic() ?
2440 visitBasic(cast(TypeBasic)t) :
2441 visitType(t);
2443 case Terror: return visitError (t.isTypeError());
2444 case Tvector: return visitVector(t.isTypeVector());
2445 case Tenum: return visitEnum (t.isTypeEnum());
2446 case Ttuple: return visitTuple (t.isTypeTuple());
2450 /***************************************
2451 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
2452 * Params:
2453 * exp = Expression to look at
2454 * t = if exp should be a Type, set t to that Type else null
2455 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
2456 * e = if exp should remain an Expression, set e to that Expression else null
2459 private void resolveExp(Expression exp, out Type t, out Expression e, out Dsymbol s)
2461 if (exp.isTypeExp())
2462 t = exp.type;
2463 else if (auto ve = exp.isVarExp())
2465 if (auto v = ve.var.isVarDeclaration())
2466 e = exp;
2467 else
2468 s = ve.var;
2470 else if (auto te = exp.isTemplateExp())
2471 s = te.td;
2472 else if (auto se = exp.isScopeExp())
2473 s = se.sds;
2474 else if (exp.isFuncExp())
2475 s = getDsymbol(exp);
2476 else if (auto dte = exp.isDotTemplateExp())
2477 s = dte.td;
2478 else if (exp.isErrorExp())
2479 t = Type.terror;
2480 else
2481 e = exp;
2484 /************************************
2485 * Resolve type 'mt' to either type, symbol, or expression.
2486 * If errors happened, resolved to Type.terror.
2488 * Params:
2489 * mt = type to be resolved
2490 * loc = the location where the type is encountered
2491 * sc = the scope of the type
2492 * pe = is set if t is an expression
2493 * pt = is set if t is a type
2494 * ps = is set if t is a symbol
2495 * intypeid = true if in type id
2497 void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
2499 void returnExp(Expression e)
2501 pe = e;
2502 pt = null;
2503 ps = null;
2506 void returnType(Type t)
2508 pe = null;
2509 pt = t;
2510 ps = null;
2513 void returnSymbol(Dsymbol s)
2515 pe = null;
2516 pt = null;
2517 ps = s;
2520 void returnError()
2522 returnType(Type.terror);
2525 void visitType(Type mt)
2527 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
2528 Type t = typeSemantic(mt, loc, sc);
2529 assert(t);
2530 returnType(t);
2533 void visitSArray(TypeSArray mt)
2535 //printf("TypeSArray::resolve() %s\n", mt.toChars());
2536 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2537 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2538 if (pe)
2540 // It's really an index expression
2541 if (Dsymbol s = getDsymbol(pe))
2542 pe = new DsymbolExp(loc, s);
2543 returnExp(new ArrayExp(loc, pe, mt.dim));
2545 else if (ps)
2547 Dsymbol s = ps;
2548 if (auto tup = s.isTupleDeclaration())
2550 mt.dim = semanticLength(sc, tup, mt.dim);
2551 mt.dim = mt.dim.ctfeInterpret();
2552 if (mt.dim.op == EXP.error)
2553 return returnError();
2555 const d = mt.dim.toUInteger();
2556 if (d >= tup.objects.length)
2558 error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong) tup.objects.length);
2559 return returnError();
2562 RootObject o = (*tup.objects)[cast(size_t)d];
2563 switch (o.dyncast()) with (DYNCAST)
2565 case dsymbol:
2566 return returnSymbol(cast(Dsymbol)o);
2567 case expression:
2568 Expression e = cast(Expression)o;
2569 if (e.op == EXP.dSymbol)
2570 return returnSymbol(e.isDsymbolExp().s);
2571 else
2572 return returnExp(e);
2573 case type:
2574 return returnType((cast(Type)o).addMod(mt.mod));
2575 default:
2576 break;
2579 /* Create a new TupleDeclaration which
2580 * is a slice [d..d+1] out of the old one.
2581 * Do it this way because TemplateInstance::semanticTiargs()
2582 * can handle unresolved Objects this way.
2584 auto objects = new Objects(1);
2585 (*objects)[0] = o;
2586 return returnSymbol(new TupleDeclaration(loc, tup.ident, objects));
2588 else
2589 return visitType(mt);
2591 else
2593 if (pt.ty != Terror)
2594 mt.next = pt; // prevent re-running semantic() on 'next'
2595 visitType(mt);
2600 void visitDArray(TypeDArray mt)
2602 //printf("TypeDArray::resolve() %s\n", mt.toChars());
2603 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2604 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2605 if (pe)
2607 // It's really a slice expression
2608 if (Dsymbol s = getDsymbol(pe))
2609 pe = new DsymbolExp(loc, s);
2610 returnExp(new ArrayExp(loc, pe));
2612 else if (ps)
2614 if (auto tup = ps.isTupleDeclaration())
2616 // keep ps
2618 else
2619 visitType(mt);
2621 else
2623 if (pt.ty != Terror)
2624 mt.next = pt; // prevent re-running semantic() on 'next'
2625 visitType(mt);
2629 void visitAArray(TypeAArray mt)
2631 //printf("TypeAArray::resolve() %s\n", mt.toChars());
2632 // Deal with the case where we thought the index was a type, but
2633 // in reality it was an expression.
2634 if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray)
2636 Expression e;
2637 Type t;
2638 Dsymbol s;
2639 mt.index.resolve(loc, sc, e, t, s, intypeid);
2640 if (e)
2642 // It was an expression -
2643 // Rewrite as a static array
2644 auto tsa = new TypeSArray(mt.next, e);
2645 tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done
2646 return tsa.resolve(loc, sc, pe, pt, ps, intypeid);
2648 else if (t)
2649 mt.index = t;
2650 else
2651 .error(loc, "index is not a type or an expression");
2653 visitType(mt);
2656 /*************************************
2657 * Takes an array of Identifiers and figures out if
2658 * it represents a Type or an Expression.
2659 * Output:
2660 * if expression, pe is set
2661 * if type, pt is set
2663 void visitIdentifier(TypeIdentifier mt)
2665 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2666 if (mt.ident == Id.ctfe)
2668 error(loc, "variable `__ctfe` cannot be read at compile time");
2669 return returnError();
2671 if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h
2673 /* Since we don't support __builtin_va_start, -arg, -end, we don't
2674 * have to actually care what -list is. A void* will do.
2675 * If we ever do care, import core.stdc.stdarg and pull
2676 * the definition out of that, similarly to how std.math is handled for PowExp
2678 pt = target.va_listType(loc, sc);
2679 return;
2682 Dsymbol scopesym;
2683 Dsymbol s = sc.search(loc, mt.ident, &scopesym);
2685 * https://issues.dlang.org/show_bug.cgi?id=1170
2686 * https://issues.dlang.org/show_bug.cgi?id=10739
2688 * If a symbol is not found, it might be declared in
2689 * a mixin-ed string or a mixin-ed template, so before
2690 * issuing an error semantically analyze all string/template
2691 * mixins that are members of the current ScopeDsymbol.
2693 if (!s && sc.enclosing)
2695 ScopeDsymbol sds = sc.enclosing.scopesym;
2696 if (sds && sds.members)
2698 void semanticOnMixin(Dsymbol member)
2700 if (auto compileDecl = member.isCompileDeclaration())
2701 compileDecl.dsymbolSemantic(sc);
2702 else if (auto mixinTempl = member.isTemplateMixin())
2703 mixinTempl.dsymbolSemantic(sc);
2705 sds.members.foreachDsymbol( s => semanticOnMixin(s) );
2706 s = sc.search(loc, mt.ident, &scopesym);
2710 if (s)
2712 // https://issues.dlang.org/show_bug.cgi?id=16042
2713 // If `f` is really a function template, then replace `f`
2714 // with the function template declaration.
2715 if (auto f = s.isFuncDeclaration())
2717 if (auto td = getFuncTemplateDecl(f))
2719 // If not at the beginning of the overloaded list of
2720 // `TemplateDeclaration`s, then get the beginning
2721 if (td.overroot)
2722 td = td.overroot;
2723 s = td;
2728 mt.resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
2729 if (pt)
2730 pt = pt.addMod(mt.mod);
2733 void visitInstance(TypeInstance mt)
2735 // Note close similarity to TypeIdentifier::resolve()
2737 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
2738 mt.tempinst.dsymbolSemantic(sc);
2739 if (!global.gag && mt.tempinst.errors)
2740 return returnError();
2742 mt.resolveHelper(loc, sc, mt.tempinst, null, pe, pt, ps, intypeid);
2743 if (pt)
2744 pt = pt.addMod(mt.mod);
2745 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
2748 void visitTypeof(TypeTypeof mt)
2750 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
2751 //static int nest; if (++nest == 50) *(char*)0=0;
2752 if (sc is null)
2754 error(loc, "invalid scope");
2755 return returnError();
2757 if (mt.inuse)
2759 mt.inuse = 2;
2760 error(loc, "circular `typeof` definition");
2761 Lerr:
2762 mt.inuse--;
2763 return returnError();
2765 mt.inuse++;
2767 /* Currently we cannot evaluate 'exp' in speculative context, because
2768 * the type implementation may leak to the final execution. Consider:
2770 * struct S(T) {
2771 * string toString() const { return "x"; }
2773 * void main() {
2774 * alias X = typeof(S!int());
2775 * assert(typeid(X).toString() == "x");
2778 Scope* sc2 = sc.push();
2780 if (!mt.exp.isTypeidExp())
2781 /* Treat typeof(typeid(exp)) as needing
2782 * the full semantic analysis of the typeid.
2783 * https://issues.dlang.org/show_bug.cgi?id=20958
2785 sc2.intypeof = 1;
2787 auto exp2 = mt.exp.expressionSemantic(sc2);
2788 exp2 = resolvePropertiesOnly(sc2, exp2);
2789 sc2.pop();
2791 if (exp2.op == EXP.error)
2793 if (!global.gag)
2794 mt.exp = exp2;
2795 goto Lerr;
2797 mt.exp = exp2;
2799 if (mt.exp.op == EXP.type ||
2800 mt.exp.op == EXP.scope_)
2802 if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof
2803 mt.exp.checkType())
2804 goto Lerr;
2806 /* Today, 'typeof(func)' returns void if func is a
2807 * function template (TemplateExp), or
2808 * template lambda (FuncExp).
2809 * It's actually used in Phobos as an idiom, to branch code for
2810 * template functions.
2813 if (auto f = mt.exp.op == EXP.variable ? mt.exp.isVarExp().var.isFuncDeclaration()
2814 : mt.exp.op == EXP.dotVariable ? mt.exp.isDotVarExp().var.isFuncDeclaration() : null)
2816 // f might be a unittest declaration which is incomplete when compiled
2817 // without -unittest. That causes a segfault in checkForwardRef, see
2818 // https://issues.dlang.org/show_bug.cgi?id=20626
2819 if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && f.checkForwardRef(loc))
2820 goto Lerr;
2822 if (auto f = isFuncAddress(mt.exp))
2824 if (f.checkForwardRef(loc))
2825 goto Lerr;
2828 Type t = mt.exp.type;
2829 if (!t)
2831 error(loc, "expression `%s` has no type", mt.exp.toChars());
2832 goto Lerr;
2834 if (t.ty == Ttypeof)
2836 error(loc, "forward reference to `%s`", mt.toChars());
2837 goto Lerr;
2839 if (mt.idents.length == 0)
2841 returnType(t.addMod(mt.mod));
2843 else
2845 if (Dsymbol s = t.toDsymbol(sc))
2846 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
2847 else
2849 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
2850 e = e.expressionSemantic(sc);
2851 resolveExp(e, pt, pe, ps);
2853 if (pt)
2854 pt = pt.addMod(mt.mod);
2856 mt.inuse--;
2859 void visitReturn(TypeReturn mt)
2861 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2862 Type t;
2864 FuncDeclaration func = sc.func;
2865 if (!func)
2867 error(loc, "`typeof(return)` must be inside function");
2868 return returnError();
2870 if (func.fes)
2871 func = func.fes.func;
2872 t = func.type.nextOf();
2873 if (!t)
2875 error(loc, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc.func.toChars());
2876 return returnError();
2879 if (mt.idents.length == 0)
2881 return returnType(t.addMod(mt.mod));
2883 else
2885 if (Dsymbol s = t.toDsymbol(sc))
2886 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
2887 else
2889 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
2890 e = e.expressionSemantic(sc);
2891 resolveExp(e, pt, pe, ps);
2893 if (pt)
2894 pt = pt.addMod(mt.mod);
2898 void visitSlice(TypeSlice mt)
2900 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2901 if (pe)
2903 // It's really a slice expression
2904 if (Dsymbol s = getDsymbol(pe))
2905 pe = new DsymbolExp(loc, s);
2906 return returnExp(new ArrayExp(loc, pe, new IntervalExp(loc, mt.lwr, mt.upr)));
2908 else if (ps)
2910 Dsymbol s = ps;
2911 TupleDeclaration td = s.isTupleDeclaration();
2912 if (td)
2914 /* It's a slice of a TupleDeclaration
2916 ScopeDsymbol sym = new ArrayScopeSymbol(sc, td);
2917 sym.parent = sc.scopesym;
2918 sc = sc.push(sym);
2919 sc = sc.startCTFE();
2920 mt.lwr = mt.lwr.expressionSemantic(sc);
2921 mt.upr = mt.upr.expressionSemantic(sc);
2922 sc = sc.endCTFE();
2923 sc = sc.pop();
2925 mt.lwr = mt.lwr.ctfeInterpret();
2926 mt.upr = mt.upr.ctfeInterpret();
2927 const i1 = mt.lwr.toUInteger();
2928 const i2 = mt.upr.toUInteger();
2929 if (!(i1 <= i2 && i2 <= td.objects.length))
2931 error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1, i2, cast(ulong) td.objects.length);
2932 return returnError();
2935 if (i1 == 0 && i2 == td.objects.length)
2937 return returnSymbol(td);
2940 /* Create a new TupleDeclaration which
2941 * is a slice [i1..i2] out of the old one.
2943 auto objects = new Objects(cast(size_t)(i2 - i1));
2944 for (size_t i = 0; i < objects.length; i++)
2946 (*objects)[i] = (*td.objects)[cast(size_t)i1 + i];
2949 return returnSymbol(new TupleDeclaration(loc, td.ident, objects));
2951 else
2952 visitType(mt);
2954 else
2956 if (pt.ty != Terror)
2957 mt.next = pt; // prevent re-running semantic() on 'next'
2958 visitType(mt);
2962 void visitMixin(TypeMixin mt)
2964 RootObject o = mt.obj;
2966 // if already resolved just set pe/pt/ps and return.
2967 if (o)
2969 pe = o.isExpression();
2970 pt = o.isType();
2971 ps = o.isDsymbol();
2972 return;
2975 o = mt.compileTypeMixin(loc, sc);
2976 if (auto t = o.isType())
2978 resolve(t, loc, sc, pe, pt, ps, intypeid);
2979 if (pt)
2980 pt = pt.addMod(mt.mod);
2982 else if (auto e = o.isExpression())
2984 e = e.expressionSemantic(sc);
2985 if (auto et = e.isTypeExp())
2986 returnType(et.type.addMod(mt.mod));
2987 else
2988 returnExp(e);
2990 else
2991 returnError();
2993 // save the result
2994 mt.obj = pe ? pe : (pt ? pt : ps);
2997 void visitTraits(TypeTraits mt)
2999 // if already resolved just return the cached object.
3000 if (mt.obj)
3002 pt = mt.obj.isType();
3003 ps = mt.obj.isDsymbol();
3004 pe = mt.obj.isExpression();
3005 return;
3008 import dmd.traits : semanticTraits;
3010 if (Expression e = semanticTraits(mt.exp, sc))
3012 switch (e.op)
3014 case EXP.dotVariable:
3015 mt.obj = e.isDotVarExp().var;
3016 break;
3017 case EXP.variable:
3018 mt.obj = e.isVarExp().var;
3019 break;
3020 case EXP.function_:
3021 auto fe = e.isFuncExp();
3022 mt.obj = fe.td ? fe.td : fe.fd;
3023 break;
3024 case EXP.dotTemplateDeclaration:
3025 mt.obj = e.isDotTemplateExp().td;
3026 break;
3027 case EXP.dSymbol:
3028 mt.obj = e.isDsymbolExp().s;
3029 break;
3030 case EXP.template_:
3031 mt.obj = e.isTemplateExp().td;
3032 break;
3033 case EXP.scope_:
3034 mt.obj = e.isScopeExp().sds;
3035 break;
3036 case EXP.tuple:
3037 TupleExp te = e.isTupleExp();
3038 Objects* elems = new Objects(te.exps.length);
3039 foreach (i; 0 .. elems.length)
3041 auto src = (*te.exps)[i];
3042 switch (src.op)
3044 case EXP.type:
3045 (*elems)[i] = src.isTypeExp().type;
3046 break;
3047 case EXP.dotType:
3048 (*elems)[i] = src.isDotTypeExp().sym.isType();
3049 break;
3050 case EXP.overloadSet:
3051 (*elems)[i] = src.isOverExp().type;
3052 break;
3053 default:
3054 if (auto sym = isDsymbol(src))
3055 (*elems)[i] = sym;
3056 else
3057 (*elems)[i] = src;
3060 TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
3061 mt.obj = td;
3062 break;
3063 case EXP.dotType:
3064 mt.obj = e.isDotTypeExp().sym.isType();
3065 break;
3066 case EXP.type:
3067 mt.obj = e.isTypeExp().type;
3068 break;
3069 case EXP.overloadSet:
3070 mt.obj = e.isOverExp().type;
3071 break;
3072 case EXP.error:
3073 break;
3074 default:
3075 mt.obj = e;
3076 break;
3080 if (mt.obj)
3082 if (auto t = mt.obj.isType())
3084 t = t.addMod(mt.mod);
3085 mt.obj = t;
3086 returnType(t);
3088 else if (auto s = mt.obj.isDsymbol())
3089 returnSymbol(s);
3090 else if (auto e = mt.obj.isExpression())
3091 returnExp(e);
3093 else
3095 assert(global.errors);
3096 mt.obj = Type.terror;
3097 return returnError();
3101 switch (mt.ty)
3103 default: visitType (mt); break;
3104 case Tsarray: visitSArray (mt.isTypeSArray()); break;
3105 case Tarray: visitDArray (mt.isTypeDArray()); break;
3106 case Taarray: visitAArray (mt.isTypeAArray()); break;
3107 case Tident: visitIdentifier(mt.isTypeIdentifier()); break;
3108 case Tinstance: visitInstance (mt.isTypeInstance()); break;
3109 case Ttypeof: visitTypeof (mt.isTypeTypeof()); break;
3110 case Treturn: visitReturn (mt.isTypeReturn()); break;
3111 case Tslice: visitSlice (mt.isTypeSlice()); break;
3112 case Tmixin: visitMixin (mt.isTypeMixin()); break;
3113 case Ttraits: visitTraits (mt.isTypeTraits()); break;
3117 /************************
3118 * Access the members of the object e. This type is same as e.type.
3119 * Params:
3120 * mt = type for which the dot expression is used
3121 * sc = instantiating scope
3122 * e = expression to convert
3123 * ident = identifier being used
3124 * flag = DotExpFlag bit flags
3126 * Returns:
3127 * resulting expression with e.ident resolved
3129 Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
3131 Expression visitType(Type mt)
3133 VarDeclaration v = null;
3134 static if (LOGDOTEXP)
3136 printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3138 Expression ex = e.lastComma();
3139 if (ex.op == EXP.dotVariable)
3141 DotVarExp dv = cast(DotVarExp)ex;
3142 v = dv.var.isVarDeclaration();
3144 else if (ex.op == EXP.variable)
3146 VarExp ve = cast(VarExp)ex;
3147 v = ve.var.isVarDeclaration();
3149 if (v)
3151 if (ident == Id.offsetof)
3153 v.dsymbolSemantic(null);
3154 if (v.isField())
3156 auto ad = v.isMember();
3157 objc.checkOffsetof(e, ad);
3158 ad.size(e.loc);
3159 if (ad.sizeok != Sizeok.done)
3160 return ErrorExp.get();
3161 return new IntegerExp(e.loc, v.offset, Type.tsize_t);
3164 else if (ident == Id._init)
3166 Type tb = mt.toBasetype();
3167 e = mt.defaultInitLiteral(e.loc);
3168 if (tb.ty == Tstruct && tb.needsNested())
3170 e.isStructLiteralExp().useStaticInit = true;
3172 goto Lreturn;
3175 if (ident == Id.stringof)
3177 /* https://issues.dlang.org/show_bug.cgi?id=3796
3178 * this should demangle e.type.deco rather than
3179 * pretty-printing the type.
3181 e = new StringExp(e.loc, e.toString());
3183 else
3184 e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag);
3186 Lreturn:
3187 if (e)
3188 e = e.expressionSemantic(sc);
3189 return e;
3192 Expression visitError(TypeError)
3194 return ErrorExp.get();
3197 Expression visitBasic(TypeBasic mt)
3199 static if (LOGDOTEXP)
3201 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3203 Type t;
3204 if (ident == Id.re)
3206 switch (mt.ty)
3208 case Tcomplex32:
3209 t = mt.tfloat32;
3210 goto L1;
3212 case Tcomplex64:
3213 t = mt.tfloat64;
3214 goto L1;
3216 case Tcomplex80:
3217 t = mt.tfloat80;
3218 goto L1;
3220 e = e.castTo(sc, t);
3221 break;
3223 case Tfloat32:
3224 case Tfloat64:
3225 case Tfloat80:
3226 break;
3228 case Timaginary32:
3229 t = mt.tfloat32;
3230 goto L2;
3232 case Timaginary64:
3233 t = mt.tfloat64;
3234 goto L2;
3236 case Timaginary80:
3237 t = mt.tfloat80;
3238 goto L2;
3240 e = new RealExp(e.loc, CTFloat.zero, t);
3241 break;
3243 default:
3244 e = mt.Type.getProperty(sc, e.loc, ident, flag);
3245 break;
3248 else if (ident == Id.im)
3250 Type t2;
3251 switch (mt.ty)
3253 case Tcomplex32:
3254 t = mt.timaginary32;
3255 t2 = mt.tfloat32;
3256 goto L3;
3258 case Tcomplex64:
3259 t = mt.timaginary64;
3260 t2 = mt.tfloat64;
3261 goto L3;
3263 case Tcomplex80:
3264 t = mt.timaginary80;
3265 t2 = mt.tfloat80;
3266 goto L3;
3268 e = e.castTo(sc, t);
3269 e.type = t2;
3270 break;
3272 case Timaginary32:
3273 t = mt.tfloat32;
3274 goto L4;
3276 case Timaginary64:
3277 t = mt.tfloat64;
3278 goto L4;
3280 case Timaginary80:
3281 t = mt.tfloat80;
3282 goto L4;
3284 e = e.copy();
3285 e.type = t;
3286 break;
3288 case Tfloat32:
3289 case Tfloat64:
3290 case Tfloat80:
3291 e = new RealExp(e.loc, CTFloat.zero, mt);
3292 break;
3294 default:
3295 e = mt.Type.getProperty(sc, e.loc, ident, flag);
3296 break;
3299 else
3301 return visitType(mt);
3303 if (!(flag & 1) || e)
3304 e = e.expressionSemantic(sc);
3305 return e;
3308 Expression visitVector(TypeVector mt)
3310 static if (LOGDOTEXP)
3312 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3314 if (ident == Id.ptr && e.op == EXP.call)
3316 /* The trouble with EXP.call is the return ABI for float[4] is different from
3317 * __vector(float[4]), and a type paint won't do.
3319 e = new AddrExp(e.loc, e);
3320 e = e.expressionSemantic(sc);
3321 return e.castTo(sc, mt.basetype.nextOf().pointerTo());
3323 if (ident == Id.array)
3325 //e = e.castTo(sc, basetype);
3326 // Keep lvalue-ness
3327 e = new VectorArrayExp(e.loc, e);
3328 e = e.expressionSemantic(sc);
3329 return e;
3331 if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof)
3333 // init should return a new VectorExp
3334 // https://issues.dlang.org/show_bug.cgi?id=12776
3335 // offsetof does not work on a cast expression, so use e directly
3336 // stringof should not add a cast to the output
3337 return visitType(mt);
3340 // Properties based on the vector element type and are values of the element type
3341 if (ident == Id.max || ident == Id.min || ident == Id.min_normal ||
3342 ident == Id.nan || ident == Id.infinity || ident == Id.epsilon)
3344 auto vet = mt.basetype.isTypeSArray().next; // vector element type
3345 if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag))
3346 return ev.castTo(sc, mt); // 'broadcast' ev to the vector elements
3349 return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag);
3352 Expression visitArray(TypeArray mt)
3354 static if (LOGDOTEXP)
3356 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3359 e = visitType(mt);
3361 if (!(flag & 1) || e)
3362 e = e.expressionSemantic(sc);
3363 return e;
3366 Expression visitSArray(TypeSArray mt)
3368 static if (LOGDOTEXP)
3370 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3372 if (ident == Id.length)
3374 Loc oldLoc = e.loc;
3375 e = mt.dim.copy();
3376 e.loc = oldLoc;
3378 else if (ident == Id.ptr)
3380 if (e.op == EXP.type)
3382 e.error("`%s` is not an expression", e.toChars());
3383 return ErrorExp.get();
3385 else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
3387 // .ptr on static array is @safe unless size is 0
3388 // https://issues.dlang.org/show_bug.cgi?id=20853
3389 return ErrorExp.get();
3391 e = e.castTo(sc, e.type.nextOf().pointerTo());
3393 else if (ident == Id._tupleof)
3395 if (e.isTypeExp())
3397 e.error("`.tupleof` cannot be used on type `%s`", mt.toChars);
3398 return ErrorExp.get();
3400 else
3402 Expression e0;
3403 Expression ev = e;
3404 ev = extractSideEffect(sc, "__tup", e0, ev);
3406 const length = cast(size_t)mt.dim.toUInteger();
3407 auto exps = new Expressions();
3408 exps.reserve(length);
3409 foreach (i; 0 .. length)
3410 exps.push(new IndexExp(e.loc, ev, new IntegerExp(e.loc, i, Type.tsize_t)));
3411 e = new TupleExp(e.loc, e0, exps);
3414 else
3416 e = visitArray(mt);
3418 if (!(flag & 1) || e)
3419 e = e.expressionSemantic(sc);
3420 return e;
3423 Expression visitDArray(TypeDArray mt)
3425 static if (LOGDOTEXP)
3427 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3429 if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
3431 e.error("`%s` is not an expression", e.toChars());
3432 return ErrorExp.get();
3434 if (ident == Id.length)
3436 if (e.op == EXP.string_)
3438 StringExp se = cast(StringExp)e;
3439 return new IntegerExp(se.loc, se.len, Type.tsize_t);
3441 if (e.op == EXP.null_)
3443 return new IntegerExp(e.loc, 0, Type.tsize_t);
3445 if (checkNonAssignmentArrayOp(e))
3447 return ErrorExp.get();
3449 e = new ArrayLengthExp(e.loc, e);
3450 e.type = Type.tsize_t;
3451 return e;
3453 else if (ident == Id.ptr)
3455 if (checkUnsafeDotExp(sc, e, ident, flag))
3456 return ErrorExp.get();
3457 return e.castTo(sc, mt.next.pointerTo());
3459 else
3461 return visitArray(mt);
3465 Expression visitAArray(TypeAArray mt)
3467 static if (LOGDOTEXP)
3469 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3471 if (ident == Id.length)
3473 __gshared FuncDeclaration fd_aaLen = null;
3474 if (fd_aaLen is null)
3476 auto fparams = new Parameters();
3477 fparams.push(new Parameter(STC.const_ | STC.scope_, mt, null, null, null));
3478 fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen);
3479 TypeFunction tf = fd_aaLen.type.toTypeFunction();
3480 tf.purity = PURE.const_;
3481 tf.isnothrow = true;
3482 tf.isnogc = false;
3484 Expression ev = new VarExp(e.loc, fd_aaLen, false);
3485 e = new CallExp(e.loc, ev, e);
3486 e.type = fd_aaLen.type.toTypeFunction().next;
3487 return e;
3489 else
3491 return visitType(mt);
3495 Expression visitReference(TypeReference mt)
3497 static if (LOGDOTEXP)
3499 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3501 // References just forward things along
3502 return mt.next.dotExp(sc, e, ident, flag);
3505 Expression visitDelegate(TypeDelegate mt)
3507 static if (LOGDOTEXP)
3509 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3511 if (ident == Id.ptr)
3513 e = new DelegatePtrExp(e.loc, e);
3514 e = e.expressionSemantic(sc);
3516 else if (ident == Id.funcptr)
3518 if (checkUnsafeDotExp(sc, e, ident, flag))
3520 return ErrorExp.get();
3522 e = new DelegateFuncptrExp(e.loc, e);
3523 e = e.expressionSemantic(sc);
3525 else
3527 return visitType(mt);
3529 return e;
3532 /***************************************
3533 * `ident` was not found as a member of `mt`.
3534 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
3535 * If that fails, forward to visitType().
3536 * Params:
3537 * mt = class or struct
3538 * sc = context
3539 * e = `this` for `ident`
3540 * ident = name of member
3541 * flag = flag & 1, don't report "not a property" error and just return NULL.
3542 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
3543 * Returns:
3544 * resolved expression if found, otherwise null
3546 Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
3548 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
3550 bool gagError = flag & 1;
3552 __gshared int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
3554 static Expression returnExp(Expression e)
3556 --nest;
3557 return e;
3560 if (++nest > global.recursionLimit)
3562 .error(e.loc, "cannot resolve identifier `%s`", ident.toChars());
3563 return returnExp(gagError ? null : ErrorExp.get());
3567 assert(mt.ty == Tstruct || mt.ty == Tclass);
3568 auto sym = mt.toDsymbol(sc).isAggregateDeclaration();
3569 assert(sym);
3570 if (// https://issues.dlang.org/show_bug.cgi?id=22054
3571 // if a class or struct does not have a body
3572 // there is no point in searching for its members
3573 sym.members &&
3574 ident != Id.__sizeof &&
3575 ident != Id.__xalignof &&
3576 ident != Id._init &&
3577 ident != Id._mangleof &&
3578 ident != Id.stringof &&
3579 ident != Id.offsetof &&
3580 // https://issues.dlang.org/show_bug.cgi?id=15045
3581 // Don't forward special built-in member functions.
3582 ident != Id.ctor &&
3583 ident != Id.dtor &&
3584 ident != Id.__xdtor &&
3585 ident != Id.postblit &&
3586 ident != Id.__xpostblit)
3588 /* Look for overloaded opDot() to see if we should forward request
3589 * to it.
3591 if (auto fd = search_function(sym, Id.opDot))
3593 /* Rewrite e.ident as:
3594 * e.opDot().ident
3596 e = build_overload(e.loc, sc, e, null, fd);
3597 // @@@DEPRECATED_2.110@@@.
3598 // Deprecated in 2.082, made an error in 2.100.
3599 e.error("`opDot` is obsolete. Use `alias this`");
3600 return ErrorExp.get();
3603 /* Look for overloaded opDispatch to see if we should forward request
3604 * to it.
3606 if (auto fd = search_function(sym, Id.opDispatch))
3608 /* Rewrite e.ident as:
3609 * e.opDispatch!("ident")
3611 TemplateDeclaration td = fd.isTemplateDeclaration();
3612 if (!td)
3614 fd.error("must be a template `opDispatch(string s)`, not a %s", fd.kind());
3615 return returnExp(ErrorExp.get());
3617 auto se = new StringExp(e.loc, ident.toString());
3618 auto tiargs = new Objects();
3619 tiargs.push(se);
3620 auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs);
3621 dti.ti.tempdecl = td;
3622 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
3623 * e.g.
3624 * template opDispatch(name) if (isValid!name) { ... }
3626 uint errors = gagError ? global.startGagging() : 0;
3627 e = dti.dotTemplateSemanticProp(sc, 0);
3628 if (gagError && global.endGagging(errors))
3629 e = null;
3630 return returnExp(e);
3633 /* See if we should forward to the alias this.
3635 auto alias_e = flag & DotExpFlag.noAliasThis ? null
3636 : resolveAliasThis(sc, e, gagError);
3637 if (alias_e && alias_e != e)
3639 /* Rewrite e.ident as:
3640 * e.aliasthis.ident
3642 auto die = new DotIdExp(e.loc, alias_e, ident);
3644 auto errors = gagError ? 0 : global.startGagging();
3645 auto exp = die.dotIdSemanticProp(sc, gagError);
3646 if (!gagError)
3648 global.endGagging(errors);
3649 if (exp && exp.op == EXP.error)
3650 exp = null;
3653 if (exp && gagError)
3654 // now that we know that the alias this leads somewhere useful,
3655 // go back and print deprecations/warnings that we skipped earlier due to the gag
3656 resolveAliasThis(sc, e, false);
3658 return returnExp(exp);
3661 return returnExp(visitType(mt));
3664 Expression visitStruct(TypeStruct mt)
3666 Dsymbol s;
3667 static if (LOGDOTEXP)
3669 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3671 assert(e.op != EXP.dot);
3673 // https://issues.dlang.org/show_bug.cgi?id=14010
3674 if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
3676 return mt.getProperty(sc, e.loc, ident, flag & 1);
3679 /* If e.tupleof
3681 if (ident == Id._tupleof)
3683 /* Create a TupleExp out of the fields of the struct e:
3684 * (e.field0, e.field1, e.field2, ...)
3686 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
3688 if (!mt.sym.determineFields())
3690 error(e.loc, "unable to determine fields of `%s` because of forward references", mt.toChars());
3693 Expression e0;
3694 Expression ev = e.op == EXP.type ? null : e;
3695 if (ev)
3696 ev = extractSideEffect(sc, "__tup", e0, ev);
3698 auto exps = new Expressions();
3699 exps.reserve(mt.sym.fields.length);
3700 for (size_t i = 0; i < mt.sym.fields.length; i++)
3702 VarDeclaration v = mt.sym.fields[i];
3703 Expression ex;
3704 if (ev)
3705 ex = new DotVarExp(e.loc, ev, v);
3706 else
3708 ex = new VarExp(e.loc, v);
3709 ex.type = ex.type.addMod(e.type.mod);
3711 exps.push(ex);
3714 e = new TupleExp(e.loc, e0, exps);
3715 Scope* sc2 = sc.push();
3716 sc2.flags |= SCOPE.noaccesscheck;
3717 e = e.expressionSemantic(sc2);
3718 sc2.pop();
3719 return e;
3722 immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
3723 s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
3725 if (!s)
3727 return noMember(mt, sc, e, ident, flag);
3729 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
3731 return noMember(mt, sc, e, ident, flag);
3733 s = s.toAlias();
3735 if (auto em = s.isEnumMember())
3737 return em.getVarExp(e.loc, sc);
3739 if (auto v = s.isVarDeclaration())
3741 v.checkDeprecated(e.loc, sc);
3742 v.checkDisabled(e.loc, sc);
3743 if (!v.type ||
3744 !v.type.deco && v.inuse)
3746 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
3747 e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
3748 else
3749 e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
3750 return ErrorExp.get();
3752 if (v.type.ty == Terror)
3754 return ErrorExp.get();
3757 if ((v.storage_class & STC.manifest) && v._init)
3759 if (v.inuse)
3761 e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
3762 return ErrorExp.get();
3764 checkAccess(e.loc, sc, null, v);
3765 Expression ve = new VarExp(e.loc, v);
3766 if (!isTrivialExp(e))
3768 ve = new CommaExp(e.loc, e, ve);
3770 return ve.expressionSemantic(sc);
3774 if (auto t = s.getType())
3776 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
3779 TemplateMixin tm = s.isTemplateMixin();
3780 if (tm)
3782 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
3785 TemplateDeclaration td = s.isTemplateDeclaration();
3786 if (td)
3788 if (e.op == EXP.type)
3789 e = new TemplateExp(e.loc, td);
3790 else
3791 e = new DotTemplateExp(e.loc, e, td);
3792 return e.expressionSemantic(sc);
3795 TemplateInstance ti = s.isTemplateInstance();
3796 if (ti)
3798 if (!ti.semanticRun)
3800 ti.dsymbolSemantic(sc);
3801 if (!ti.inst || ti.errors) // if template failed to expand
3803 return ErrorExp.get();
3806 s = ti.inst.toAlias();
3807 if (!s.isTemplateInstance())
3808 goto L1;
3809 if (e.op == EXP.type)
3810 e = new ScopeExp(e.loc, ti);
3811 else
3812 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
3813 return e.expressionSemantic(sc);
3816 if (s.isImport() || s.isModule() || s.isPackage())
3818 return symbolToExp(s, e.loc, sc, false);
3821 OverloadSet o = s.isOverloadSet();
3822 if (o)
3824 auto oe = new OverExp(e.loc, o);
3825 if (e.op == EXP.type)
3827 return oe;
3829 return new DotExp(e.loc, e, oe);
3832 Declaration d = s.isDeclaration();
3833 if (!d)
3835 e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars());
3836 return ErrorExp.get();
3839 if (e.op == EXP.type)
3841 /* It's:
3842 * Struct.d
3844 if (TupleDeclaration tup = d.isTupleDeclaration())
3846 e = new TupleExp(e.loc, tup);
3847 return e.expressionSemantic(sc);
3849 if (d.needThis() && sc.intypeof != 1)
3851 /* Rewrite as:
3852 * this.d
3854 * only if the scope in which we are
3855 * has a `this` that matches the type
3856 * of the lhs of the dot expression.
3858 * https://issues.dlang.org/show_bug.cgi?id=23617
3860 auto fd = hasThis(sc);
3861 if (fd && fd.isThis() == mt.sym)
3863 e = new DotVarExp(e.loc, new ThisExp(e.loc), d);
3864 return e.expressionSemantic(sc);
3867 if (d.semanticRun == PASS.initial)
3868 d.dsymbolSemantic(null);
3869 checkAccess(e.loc, sc, e, d);
3870 auto ve = new VarExp(e.loc, d);
3871 if (d.isVarDeclaration() && d.needThis())
3872 ve.type = d.type.addMod(e.type.mod);
3873 return ve;
3876 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
3877 if (d.isDataseg() || unreal && d.isField())
3879 // (e, d)
3880 checkAccess(e.loc, sc, e, d);
3881 Expression ve = new VarExp(e.loc, d);
3882 e = unreal ? ve : new CommaExp(e.loc, e, ve);
3883 return e.expressionSemantic(sc);
3886 e = new DotVarExp(e.loc, e, d);
3887 return e.expressionSemantic(sc);
3890 Expression visitEnum(TypeEnum mt)
3892 static if (LOGDOTEXP)
3894 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), mt.toChars());
3896 // https://issues.dlang.org/show_bug.cgi?id=14010
3897 if (ident == Id._mangleof)
3899 return mt.getProperty(sc, e.loc, ident, flag & 1);
3902 if (mt.sym.semanticRun < PASS.semanticdone)
3903 mt.sym.dsymbolSemantic(null);
3905 Dsymbol s = mt.sym.search(e.loc, ident);
3906 if (!s)
3908 if (ident == Id._init)
3910 return mt.getProperty(sc, e.loc, ident, flag & 1);
3913 /* Allow special enums to not need a member list
3915 if ((ident == Id.max || ident == Id.min) && (mt.sym.members || !mt.sym.isSpecial()))
3917 return mt.getProperty(sc, e.loc, ident, flag & 1);
3920 Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, 1);
3921 if (!(flag & 1) && !res)
3923 if (auto ns = mt.sym.search_correct(ident))
3924 e.error("no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
3925 ns.toChars());
3926 else
3927 e.error("no property `%s` for type `%s`", ident.toChars(),
3928 mt.toChars());
3930 return ErrorExp.get();
3932 return res;
3934 EnumMember m = s.isEnumMember();
3935 return m.getVarExp(e.loc, sc);
3938 Expression visitClass(TypeClass mt)
3940 Dsymbol s;
3941 static if (LOGDOTEXP)
3943 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3945 assert(e.op != EXP.dot);
3947 // https://issues.dlang.org/show_bug.cgi?id=12543
3948 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
3950 return mt.Type.getProperty(sc, e.loc, ident, 0);
3953 /* If e.tupleof
3955 if (ident == Id._tupleof)
3957 objc.checkTupleof(e, mt);
3959 /* Create a TupleExp
3961 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
3963 mt.sym.size(e.loc); // do semantic of type
3965 Expression e0;
3966 Expression ev = e.op == EXP.type ? null : e;
3967 if (ev)
3968 ev = extractSideEffect(sc, "__tup", e0, ev);
3970 auto exps = new Expressions();
3971 exps.reserve(mt.sym.fields.length);
3972 for (size_t i = 0; i < mt.sym.fields.length; i++)
3974 VarDeclaration v = mt.sym.fields[i];
3975 // Don't include hidden 'this' pointer
3976 if (v.isThisDeclaration())
3977 continue;
3978 Expression ex;
3979 if (ev)
3980 ex = new DotVarExp(e.loc, ev, v);
3981 else
3983 ex = new VarExp(e.loc, v);
3984 ex.type = ex.type.addMod(e.type.mod);
3986 exps.push(ex);
3989 e = new TupleExp(e.loc, e0, exps);
3990 Scope* sc2 = sc.push();
3991 sc2.flags |= SCOPE.noaccesscheck;
3992 e = e.expressionSemantic(sc2);
3993 sc2.pop();
3994 return e;
3997 int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
3998 s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
4001 if (!s)
4003 // See if it's a 'this' class or a base class
4004 if (mt.sym.ident == ident)
4006 if (e.op == EXP.type)
4008 return mt.Type.getProperty(sc, e.loc, ident, 0);
4010 e = new DotTypeExp(e.loc, e, mt.sym);
4011 e = e.expressionSemantic(sc);
4012 return e;
4014 if (auto cbase = mt.sym.searchBase(ident))
4016 if (e.op == EXP.type)
4018 return mt.Type.getProperty(sc, e.loc, ident, 0);
4020 if (auto ifbase = cbase.isInterfaceDeclaration())
4021 e = new CastExp(e.loc, e, ifbase.type);
4022 else
4023 e = new DotTypeExp(e.loc, e, cbase);
4024 e = e.expressionSemantic(sc);
4025 return e;
4028 if (ident == Id.classinfo)
4030 if (!Type.typeinfoclass)
4032 error(e.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4033 return ErrorExp.get();
4036 Type t = Type.typeinfoclass.type;
4037 if (e.op == EXP.type || e.op == EXP.dotType)
4039 /* For type.classinfo, we know the classinfo
4040 * at compile time.
4042 if (!mt.sym.vclassinfo)
4043 mt.sym.vclassinfo = new TypeInfoClassDeclaration(mt.sym.type);
4044 e = new VarExp(e.loc, mt.sym.vclassinfo);
4045 e = e.addressOf();
4046 e.type = t; // do this so we don't get redundant dereference
4048 else
4050 /* For class objects, the classinfo reference is the first
4051 * entry in the vtbl[]
4053 e = new PtrExp(e.loc, e);
4054 e.type = t.pointerTo();
4055 if (mt.sym.isInterfaceDeclaration())
4057 if (mt.sym.isCPPinterface())
4059 /* C++ interface vtbl[]s are different in that the
4060 * first entry is always pointer to the first virtual
4061 * function, not classinfo.
4062 * We can't get a .classinfo for it.
4064 error(e.loc, "no `.classinfo` for C++ interface objects");
4066 /* For an interface, the first entry in the vtbl[]
4067 * is actually a pointer to an instance of struct Interface.
4068 * The first member of Interface is the .classinfo,
4069 * so add an extra pointer indirection.
4071 e.type = e.type.pointerTo();
4072 e = new PtrExp(e.loc, e);
4073 e.type = t.pointerTo();
4075 e = new PtrExp(e.loc, e, t);
4077 return e;
4080 if (ident == Id.__vptr)
4082 /* The pointer to the vtbl[]
4083 * *cast(immutable(void*)**)e
4085 e = e.castTo(sc, mt.tvoidptr.immutableOf().pointerTo().pointerTo());
4086 e = new PtrExp(e.loc, e);
4087 e = e.expressionSemantic(sc);
4088 return e;
4091 if (ident == Id.__monitor && mt.sym.hasMonitor())
4093 /* The handle to the monitor (call it a void*)
4094 * *(cast(void**)e + 1)
4096 e = e.castTo(sc, mt.tvoidptr.pointerTo());
4097 e = new AddExp(e.loc, e, IntegerExp.literal!1);
4098 e = new PtrExp(e.loc, e);
4099 e = e.expressionSemantic(sc);
4100 return e;
4103 if (ident == Id.outer && mt.sym.vthis)
4105 if (mt.sym.vthis.semanticRun == PASS.initial)
4106 mt.sym.vthis.dsymbolSemantic(null);
4108 if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
4110 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
4111 dve.type = cdp.type.addMod(e.type.mod);
4112 return dve;
4115 /* https://issues.dlang.org/show_bug.cgi?id=15839
4116 * Find closest parent class through nested functions.
4118 for (auto p = mt.sym.toParentLocal(); p; p = p.toParentLocal())
4120 auto fd = p.isFuncDeclaration();
4121 if (!fd)
4122 break;
4123 auto ad = fd.isThis();
4124 if (!ad && fd.isNested())
4125 continue;
4126 if (!ad)
4127 break;
4128 if (auto cdp = ad.isClassDeclaration())
4130 auto ve = new ThisExp(e.loc);
4132 ve.var = fd.vthis;
4133 const nestedError = fd.vthis.checkNestedReference(sc, e.loc);
4134 assert(!nestedError);
4136 ve.type = cdp.type.addMod(fd.vthis.type.mod).addMod(e.type.mod);
4137 return ve;
4139 break;
4142 // Continue to show enclosing function's frame (stack or closure).
4143 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
4144 dve.type = mt.sym.vthis.type.addMod(e.type.mod);
4145 return dve;
4148 return noMember(mt, sc, e, ident, flag & 1);
4150 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
4152 return noMember(mt, sc, e, ident, flag);
4154 if (!s.isFuncDeclaration()) // because of overloading
4156 s.checkDeprecated(e.loc, sc);
4157 if (auto d = s.isDeclaration())
4158 d.checkDisabled(e.loc, sc);
4160 s = s.toAlias();
4162 if (auto em = s.isEnumMember())
4164 return em.getVarExp(e.loc, sc);
4166 if (auto v = s.isVarDeclaration())
4168 if (!v.type ||
4169 !v.type.deco && v.inuse)
4171 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
4172 e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
4173 else
4174 e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
4175 return ErrorExp.get();
4177 if (v.type.ty == Terror)
4179 return ErrorExp.get();
4182 if ((v.storage_class & STC.manifest) && v._init)
4184 if (v.inuse)
4186 e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
4187 return ErrorExp.get();
4189 checkAccess(e.loc, sc, null, v);
4190 Expression ve = new VarExp(e.loc, v);
4191 ve = ve.expressionSemantic(sc);
4192 return ve;
4196 if (auto t = s.getType())
4198 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
4201 TemplateMixin tm = s.isTemplateMixin();
4202 if (tm)
4204 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
4207 TemplateDeclaration td = s.isTemplateDeclaration();
4209 Expression toTemplateExp(TemplateDeclaration td)
4211 if (e.op == EXP.type)
4212 e = new TemplateExp(e.loc, td);
4213 else
4214 e = new DotTemplateExp(e.loc, e, td);
4215 e = e.expressionSemantic(sc);
4216 return e;
4219 if (td)
4221 return toTemplateExp(td);
4224 TemplateInstance ti = s.isTemplateInstance();
4225 if (ti)
4227 if (!ti.semanticRun)
4229 ti.dsymbolSemantic(sc);
4230 if (!ti.inst || ti.errors) // if template failed to expand
4232 return ErrorExp.get();
4235 s = ti.inst.toAlias();
4236 if (!s.isTemplateInstance())
4237 goto L1;
4238 if (e.op == EXP.type)
4239 e = new ScopeExp(e.loc, ti);
4240 else
4241 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
4242 return e.expressionSemantic(sc);
4245 if (s.isImport() || s.isModule() || s.isPackage())
4247 e = symbolToExp(s, e.loc, sc, false);
4248 return e;
4251 OverloadSet o = s.isOverloadSet();
4252 if (o)
4254 auto oe = new OverExp(e.loc, o);
4255 if (e.op == EXP.type)
4257 return oe;
4259 return new DotExp(e.loc, e, oe);
4262 Declaration d = s.isDeclaration();
4263 if (!d)
4265 e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars());
4266 return ErrorExp.get();
4269 if (e.op == EXP.type)
4271 /* It's:
4272 * Class.d
4274 if (TupleDeclaration tup = d.isTupleDeclaration())
4276 e = new TupleExp(e.loc, tup);
4277 e = e.expressionSemantic(sc);
4278 return e;
4281 if (mt.sym.classKind == ClassKind.objc
4282 && d.isFuncDeclaration()
4283 && d.isFuncDeclaration().isStatic
4284 && d.isFuncDeclaration().objc.selector)
4286 auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
4287 return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
4289 else if (d.needThis() && sc.intypeof != 1)
4291 /* Rewrite as:
4292 * this.d
4294 AggregateDeclaration ad = d.isMemberLocal();
4295 if (auto f = hasThis(sc))
4297 // This is almost same as getRightThis() in expressionsem.d
4298 Expression e1;
4299 Type t;
4300 /* returns: true to continue, false to return */
4301 if (f.hasDualContext())
4303 if (f.followInstantiationContext(ad))
4305 e1 = new VarExp(e.loc, f.vthis);
4306 e1 = new PtrExp(e1.loc, e1);
4307 e1 = new IndexExp(e1.loc, e1, IntegerExp.literal!1);
4308 auto pd = f.toParent2().isDeclaration();
4309 assert(pd);
4310 t = pd.type.toBasetype();
4311 e1 = getThisSkipNestedFuncs(e1.loc, sc, f.toParent2(), ad, e1, t, d, true);
4312 if (!e1)
4314 e = new VarExp(e.loc, d);
4315 return e;
4317 goto L2;
4320 e1 = new ThisExp(e.loc);
4321 e1 = e1.expressionSemantic(sc);
4323 t = e1.type.toBasetype();
4324 ClassDeclaration cd = e.type.isClassHandle();
4325 ClassDeclaration tcd = t.isClassHandle();
4326 if (cd && tcd && (tcd == cd || cd.isBaseOf(tcd, null)))
4328 e = new DotTypeExp(e1.loc, e1, cd);
4329 e = new DotVarExp(e.loc, e, d);
4330 e = e.expressionSemantic(sc);
4331 return e;
4333 if (tcd && tcd.isNested())
4335 /* e1 is the 'this' pointer for an inner class: tcd.
4336 * Rewrite it as the 'this' pointer for the outer class.
4338 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
4339 e1 = new DotVarExp(e.loc, e1, vthis);
4340 e1.type = vthis.type;
4341 e1.type = e1.type.addMod(t.mod);
4342 // Do not call ensureStaticLinkTo()
4343 //e1 = e1.expressionSemantic(sc);
4345 // Skip up over nested functions, and get the enclosing
4346 // class type.
4347 e1 = getThisSkipNestedFuncs(e1.loc, sc, tcd.toParentP(ad), ad, e1, t, d, true);
4348 if (!e1)
4350 e = new VarExp(e.loc, d);
4351 return e;
4353 goto L2;
4357 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
4358 if (d.semanticRun == PASS.initial)
4359 d.dsymbolSemantic(null);
4361 // If static function, get the most visible overload.
4362 // Later on the call is checked for correctness.
4363 // https://issues.dlang.org/show_bug.cgi?id=12511
4364 Dsymbol d2 = d;
4365 if (auto fd = d.isFuncDeclaration())
4367 import dmd.access : mostVisibleOverload;
4368 d2 = mostVisibleOverload(fd, sc._module);
4371 checkAccess(e.loc, sc, e, d2);
4372 if (d2.isDeclaration())
4374 d = cast(Declaration)d2;
4375 auto ve = new VarExp(e.loc, d);
4376 if (d.isVarDeclaration() && d.needThis())
4377 ve.type = d.type.addMod(e.type.mod);
4378 return ve;
4380 else if (d2.isTemplateDeclaration())
4382 return toTemplateExp(cast(TemplateDeclaration)d2);
4384 else
4385 assert(0);
4388 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
4389 if (d.isDataseg() || unreal && d.isField())
4391 // (e, d)
4392 checkAccess(e.loc, sc, e, d);
4393 Expression ve = new VarExp(e.loc, d);
4394 e = unreal ? ve : new CommaExp(e.loc, e, ve);
4395 e = e.expressionSemantic(sc);
4396 return e;
4399 e = new DotVarExp(e.loc, e, d);
4400 e = e.expressionSemantic(sc);
4401 return e;
4404 switch (mt.ty)
4406 case Tvector: return visitVector (mt.isTypeVector());
4407 case Tsarray: return visitSArray (mt.isTypeSArray());
4408 case Tstruct: return visitStruct (mt.isTypeStruct());
4409 case Tenum: return visitEnum (mt.isTypeEnum());
4410 case Terror: return visitError (mt.isTypeError());
4411 case Tarray: return visitDArray (mt.isTypeDArray());
4412 case Taarray: return visitAArray (mt.isTypeAArray());
4413 case Treference: return visitReference(mt.isTypeReference());
4414 case Tdelegate: return visitDelegate (mt.isTypeDelegate());
4415 case Tclass: return visitClass (mt.isTypeClass());
4417 default: return mt.isTypeBasic()
4418 ? visitBasic(cast(TypeBasic)mt)
4419 : visitType(mt);
4424 /************************
4425 * Get the default initialization expression for a type.
4426 * Params:
4427 * mt = the type for which the init expression is returned
4428 * loc = the location where the expression needs to be evaluated
4429 * isCfile = default initializers are different with C
4431 * Returns:
4432 * The initialization expression for the type.
4434 extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
4436 Expression visitBasic(TypeBasic mt)
4438 static if (LOGDEFAULTINIT)
4440 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
4442 dinteger_t value = 0;
4444 switch (mt.ty)
4446 case Tchar:
4447 value = isCfile ? 0 : 0xFF;
4448 break;
4450 case Twchar:
4451 case Tdchar:
4452 value = isCfile ? 0 : 0xFFFF;
4453 break;
4455 case Timaginary32:
4456 case Timaginary64:
4457 case Timaginary80:
4458 case Tfloat32:
4459 case Tfloat64:
4460 case Tfloat80:
4461 return new RealExp(loc, isCfile ? CTFloat.zero : target.RealProperties.nan, mt);
4463 case Tcomplex32:
4464 case Tcomplex64:
4465 case Tcomplex80:
4467 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
4468 const cvalue = isCfile ? complex_t(CTFloat.zero, CTFloat.zero)
4469 : complex_t(target.RealProperties.nan, target.RealProperties.nan);
4470 return new ComplexExp(loc, cvalue, mt);
4473 case Tvoid:
4474 error(loc, "`void` does not have a default initializer");
4475 return ErrorExp.get();
4477 default:
4478 break;
4480 return new IntegerExp(loc, value, mt);
4483 Expression visitVector(TypeVector mt)
4485 //printf("TypeVector::defaultInit()\n");
4486 assert(mt.basetype.ty == Tsarray);
4487 Expression e = mt.basetype.defaultInit(loc, isCfile);
4488 auto ve = new VectorExp(loc, e, mt);
4489 ve.type = mt;
4490 ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc));
4491 return ve;
4494 Expression visitSArray(TypeSArray mt)
4496 static if (LOGDEFAULTINIT)
4498 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
4500 if (mt.next.ty == Tvoid)
4501 return mt.tuns8.defaultInit(loc, isCfile);
4502 else
4503 return mt.next.defaultInit(loc, isCfile);
4506 Expression visitFunction(TypeFunction mt)
4508 error(loc, "`function` does not have a default initializer");
4509 return ErrorExp.get();
4512 Expression visitStruct(TypeStruct mt)
4514 static if (LOGDEFAULTINIT)
4516 printf("TypeStruct::defaultInit() '%s'\n", mt.toChars());
4518 Declaration d = new SymbolDeclaration(mt.sym.loc, mt.sym);
4519 assert(d);
4520 d.type = mt;
4521 d.storage_class |= STC.rvalue; // https://issues.dlang.org/show_bug.cgi?id=14398
4522 return new VarExp(mt.sym.loc, d);
4525 Expression visitEnum(TypeEnum mt)
4527 static if (LOGDEFAULTINIT)
4529 printf("TypeEnum::defaultInit() '%s'\n", mt.toChars());
4531 // Initialize to first member of enum
4532 Expression e = mt.sym.getDefaultValue(loc);
4533 e = e.copy();
4534 e.loc = loc;
4535 e.type = mt; // to deal with const, immutable, etc., variants
4536 return e;
4539 Expression visitTuple(TypeTuple mt)
4541 static if (LOGDEFAULTINIT)
4543 printf("TypeTuple::defaultInit() '%s'\n", mt.toChars());
4545 auto exps = new Expressions(mt.arguments.length);
4546 for (size_t i = 0; i < mt.arguments.length; i++)
4548 Parameter p = (*mt.arguments)[i];
4549 assert(p.type);
4550 Expression e = p.type.defaultInitLiteral(loc);
4551 if (e.op == EXP.error)
4553 return e;
4555 (*exps)[i] = e;
4557 return new TupleExp(loc, exps);
4560 Expression visitNoreturn(TypeNoreturn mt)
4562 static if (LOGDEFAULTINIT)
4564 printf("TypeNoreturn::defaultInit() '%s'\n", mt.toChars());
4566 auto cond = IntegerExp.createBool(false);
4567 auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
4568 msg.type = Type.tstring;
4569 auto ae = new AssertExp(loc, cond, msg);
4570 ae.type = mt;
4571 return ae;
4574 switch (mt.ty)
4576 case Tvector: return visitVector (mt.isTypeVector());
4577 case Tsarray: return visitSArray (mt.isTypeSArray());
4578 case Tfunction: return visitFunction(mt.isTypeFunction());
4579 case Tstruct: return visitStruct (mt.isTypeStruct());
4580 case Tenum: return visitEnum (mt.isTypeEnum());
4581 case Ttuple: return visitTuple (mt.isTypeTuple());
4583 case Tnull: return new NullExp(Loc.initial, Type.tnull);
4585 case Terror: return ErrorExp.get();
4587 case Tarray:
4588 case Taarray:
4589 case Tpointer:
4590 case Treference:
4591 case Tdelegate:
4592 case Tclass: return new NullExp(loc, mt);
4593 case Tnoreturn: return visitNoreturn(mt.isTypeNoreturn());
4595 default: return mt.isTypeBasic() ?
4596 visitBasic(cast(TypeBasic)mt) :
4597 null;
4601 /******************************* Private *****************************************/
4603 private:
4605 /* Helper function for `typeToExpression`. Contains common code
4606 * for TypeQualified derived classes.
4608 Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
4610 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
4611 foreach (id; t.idents[i .. t.idents.length])
4613 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
4615 final switch (id.dyncast())
4617 // ... '. ident'
4618 case DYNCAST.identifier:
4619 e = new DotIdExp(e.loc, e, cast(Identifier)id);
4620 break;
4622 // ... '. name!(tiargs)'
4623 case DYNCAST.dsymbol:
4624 auto ti = (cast(Dsymbol)id).isTemplateInstance();
4625 assert(ti);
4626 e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
4627 break;
4629 // ... '[type]'
4630 case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215
4631 e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
4632 break;
4634 // ... '[expr]'
4635 case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215
4636 e = new ArrayExp(t.loc, e, cast(Expression)id);
4637 break;
4639 case DYNCAST.object:
4640 case DYNCAST.tuple:
4641 case DYNCAST.parameter:
4642 case DYNCAST.statement:
4643 case DYNCAST.condition:
4644 case DYNCAST.templateparameter:
4645 case DYNCAST.initializer:
4646 assert(0);
4649 return e;
4652 /**************************
4653 * This evaluates exp while setting length to be the number
4654 * of elements in the tuple t.
4656 Expression semanticLength(Scope* sc, Type t, Expression exp)
4658 if (auto tt = t.isTypeTuple())
4660 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
4661 sym.parent = sc.scopesym;
4662 sc = sc.push(sym);
4663 sc = sc.startCTFE();
4664 exp = exp.expressionSemantic(sc);
4665 exp = resolveProperties(sc, exp);
4666 sc = sc.endCTFE();
4667 sc.pop();
4669 else
4671 sc = sc.startCTFE();
4672 exp = exp.expressionSemantic(sc);
4673 exp = resolveProperties(sc, exp);
4674 sc = sc.endCTFE();
4676 return exp;
4679 Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
4681 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
4682 sym.parent = sc.scopesym;
4684 sc = sc.push(sym);
4685 sc = sc.startCTFE();
4686 exp = exp.expressionSemantic(sc);
4687 exp = resolveProperties(sc, exp);
4688 sc = sc.endCTFE();
4689 sc.pop();
4691 return exp;
4694 /************************************
4695 * Transitively search a type for all function types.
4696 * If any function types with parameters are found that have parameter identifiers
4697 * or default arguments, remove those and create a new type stripped of those.
4698 * This is used to determine the "canonical" version of a type which is useful for
4699 * comparisons.
4700 * Params:
4701 * t = type to scan
4702 * Returns:
4703 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
4704 * the same as t but with no parameter identifiers or default arguments.
4706 Type stripDefaultArgs(Type t)
4708 static Parameters* stripParams(Parameters* parameters)
4710 static Parameter stripParameter(Parameter p)
4712 Type t = stripDefaultArgs(p.type);
4713 return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
4714 ? new Parameter(p.storageClass, t, null, null, null)
4715 : null;
4718 if (parameters)
4720 foreach (i, p; *parameters)
4722 Parameter ps = stripParameter(p);
4723 if (ps)
4725 // Replace params with a copy we can modify
4726 Parameters* nparams = new Parameters(parameters.length);
4728 foreach (j, ref np; *nparams)
4730 Parameter pj = (*parameters)[j];
4731 if (j < i)
4732 np = pj;
4733 else if (j == i)
4734 np = ps;
4735 else
4737 Parameter nps = stripParameter(pj);
4738 np = nps ? nps : pj;
4741 return nparams;
4745 return parameters;
4748 if (t is null)
4749 return t;
4751 if (auto tf = t.isTypeFunction())
4753 Type tret = stripDefaultArgs(tf.next);
4754 Parameters* params = stripParams(tf.parameterList.parameters);
4755 if (tret == tf.next && params == tf.parameterList.parameters)
4756 return t;
4757 TypeFunction tr = tf.copy().isTypeFunction();
4758 tr.parameterList.parameters = params;
4759 tr.next = tret;
4760 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
4761 return tr;
4763 else if (auto tt = t.isTypeTuple())
4765 Parameters* args = stripParams(tt.arguments);
4766 if (args == tt.arguments)
4767 return t;
4768 TypeTuple tr = t.copy().isTypeTuple();
4769 tr.arguments = args;
4770 return tr;
4772 else if (t.ty == Tenum)
4774 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
4775 return t;
4777 else
4779 Type tn = t.nextOf();
4780 Type n = stripDefaultArgs(tn);
4781 if (n == tn)
4782 return t;
4783 TypeNext tr = cast(TypeNext)t.copy();
4784 tr.next = n;
4785 return tr;
4789 /******************************
4790 * Get the value of the .max/.min property of `ed` as an Expression.
4791 * Lazily computes the value and caches it in maxval/minval.
4792 * Reports any errors.
4793 * Params:
4794 * ed = the EnumDeclaration being examined
4795 * loc = location to use for error messages
4796 * id = Id::max or Id::min
4797 * Returns:
4798 * corresponding value of .max/.min
4800 Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
4802 //printf("EnumDeclaration::getMaxValue()\n");
4804 static Expression pvalToResult(Expression e, const ref Loc loc)
4806 if (e.op != EXP.error)
4808 e = e.copy();
4809 e.loc = loc;
4811 return e;
4814 Expression* pval = (id == Id.max) ? &ed.maxval : &ed.minval;
4816 Expression errorReturn()
4818 *pval = ErrorExp.get();
4819 return *pval;
4822 if (ed.inuse)
4824 ed.error(loc, "recursive definition of `.%s` property", id.toChars());
4825 return errorReturn();
4827 if (*pval)
4828 return pvalToResult(*pval, loc);
4830 if (ed._scope)
4831 dsymbolSemantic(ed, ed._scope);
4832 if (ed.errors)
4833 return errorReturn();
4834 if (!ed.members)
4836 ed.error(loc, "is opaque and has no `.%s`", id.toChars());
4837 return errorReturn();
4839 if (!(ed.memtype && ed.memtype.isintegral()))
4841 ed.error(loc, "has no `.%s` property because base type `%s` is not an integral type",
4842 id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
4843 return errorReturn();
4846 bool first = true;
4847 for (size_t i = 0; i < ed.members.length; i++)
4849 EnumMember em = (*ed.members)[i].isEnumMember();
4850 if (!em)
4851 continue;
4852 if (em.errors)
4854 ed.errors = true;
4855 continue;
4858 if (em.semanticRun < PASS.semanticdone)
4860 em.error("is forward referenced looking for `.%s`", id.toChars());
4861 ed.errors = true;
4862 continue;
4865 if (first)
4867 *pval = em.value;
4868 first = false;
4870 else
4872 /* In order to work successfully with UDTs,
4873 * build expressions to do the comparisons,
4874 * and let the semantic analyzer and constant
4875 * folder give us the result.
4878 /* Compute:
4879 * if (e > maxval)
4880 * maxval = e;
4882 Expression e = em.value;
4883 Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval);
4884 ed.inuse = true;
4885 ec = ec.expressionSemantic(em._scope);
4886 ed.inuse = false;
4887 ec = ec.ctfeInterpret();
4888 if (ec.op == EXP.error)
4890 ed.errors = true;
4891 continue;
4893 if (ec.toInteger())
4894 *pval = e;
4897 return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
4900 /******************************************
4901 * Compile the MixinType, returning the type or expression AST.
4903 * Doesn't run semantic() on the returned object.
4904 * Params:
4905 * tm = mixin to compile as a type or expression
4906 * loc = location for error messages
4907 * sc = context
4908 * Return:
4909 * null if error, else RootObject AST as parsed
4911 RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
4913 OutBuffer buf;
4914 if (expressionsToString(buf, sc, tm.exps))
4915 return null;
4917 const errors = global.errors;
4918 const len = buf.length;
4919 buf.writeByte(0);
4920 const str = buf.extractSlice()[0 .. len];
4921 scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink);
4922 p.nextToken();
4923 //printf("p.loc.linnum = %d\n", p.loc.linnum);
4925 auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
4926 if (errors != global.errors)
4928 assert(global.errors != errors); // should have caught all these cases
4929 return null;
4931 if (p.token.value != TOK.endOfFile)
4933 .error(loc, "incomplete mixin type `%s`", str.ptr);
4934 return null;
4937 return o;