expand: Fix up ICE on VCE from _Complex types to _BitInt [PR117458]
[official-gcc.git] / gcc / d / dmd / typesem.d
blobb2b9e38ead4d9a7979ea592452e24f8a8ac89f38
1 /**
2 * Semantic analysis for D types.
4 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d)
8 * Documentation: https://dlang.org/phobos/dmd_typesem.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d
12 module dmd.typesem;
14 import core.checkedint;
15 import core.stdc.string;
16 import core.stdc.stdio;
18 import dmd.access;
19 import dmd.aggregate;
20 import dmd.aliasthis;
21 import dmd.arrayop;
22 import dmd.arraytypes;
23 import dmd.astcodegen;
24 import dmd.astenums;
25 import dmd.dcast;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.denum;
29 import dmd.dimport;
30 import dmd.dinterpret;
31 import dmd.dmangle;
32 import dmd.dmodule;
33 import dmd.dscope;
34 import dmd.dstruct;
35 import dmd.dsymbol;
36 import dmd.dsymbolsem;
37 import dmd.dtemplate;
38 import dmd.enumsem;
39 import dmd.errors;
40 import dmd.errorsink;
41 import dmd.expression;
42 import dmd.expressionsem;
43 import dmd.func;
44 import dmd.funcsem;
45 import dmd.globals;
46 import dmd.hdrgen;
47 import dmd.id;
48 import dmd.identifier;
49 import dmd.imphint;
50 import dmd.importc;
51 import dmd.init;
52 import dmd.initsem;
53 import dmd.location;
54 import dmd.visitor;
55 import dmd.mtype;
56 import dmd.objc;
57 import dmd.opover;
58 import dmd.optimize;
59 import dmd.parse;
60 import dmd.root.complex;
61 import dmd.root.ctfloat;
62 import dmd.root.rmem;
63 import dmd.common.outbuffer;
64 import dmd.rootobject;
65 import dmd.root.string;
66 import dmd.root.stringtable;
67 import dmd.safe;
68 import dmd.semantic3;
69 import dmd.sideeffect;
70 import dmd.target;
71 import dmd.tokens;
73 /*************************************
74 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
75 * Setting one of pe/pt/ps.
76 * Params:
77 * loc = location for error messages
78 * sc = context
79 * s = symbol being indexed - could be a tuple, could be an expression
80 * pe = set if s[oindex] is an Expression, otherwise null
81 * pt = set if s[oindex] is a Type, otherwise null
82 * ps = set if s[oindex] is a Dsymbol, otherwise null
83 * oindex = index into s
85 private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
87 auto tup = s.isTupleDeclaration();
89 auto eindex = isExpression(oindex);
90 auto tindex = isType(oindex);
91 auto sindex = isDsymbol(oindex);
93 if (!tup)
95 // It's really an index expression
96 if (tindex)
97 eindex = new TypeExp(loc, tindex);
98 else if (sindex)
99 eindex = symbolToExp(sindex, loc, sc, false);
100 Expression e = new IndexExp(loc, symbolToExp(s, loc, sc, false), eindex);
101 e = e.expressionSemantic(sc);
102 resolveExp(e, pt, pe, ps);
103 return;
106 // Convert oindex to Expression, then try to resolve to constant.
107 if (tindex)
108 tindex.resolve(loc, sc, eindex, tindex, sindex);
109 if (sindex)
110 eindex = symbolToExp(sindex, loc, sc, false);
111 if (!eindex)
113 .error(loc, "index `%s` is not an expression", oindex.toChars());
114 pt = Type.terror;
115 return;
118 eindex = semanticLength(sc, tup, eindex);
119 eindex = eindex.ctfeInterpret();
120 if (eindex.op == EXP.error)
122 pt = Type.terror;
123 return;
125 const(uinteger_t) d = eindex.toUInteger();
126 if (d >= tup.objects.length)
128 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong)tup.objects.length);
129 pt = Type.terror;
130 return;
133 RootObject o = (*tup.objects)[cast(size_t)d];
134 ps = isDsymbol(o);
135 if (auto t = isType(o))
136 pt = t.typeSemantic(loc, sc);
137 if (auto e = isExpression(o))
138 resolveExp(e, pt, pe, ps);
141 /*************************************
142 * Takes an array of Identifiers and figures out if
143 * it represents a Type, Expression, or Dsymbol.
144 * Params:
145 * mt = array of identifiers
146 * loc = location for error messages
147 * sc = context
148 * s = symbol to start search at
149 * scopesym = unused
150 * pe = set if expression otherwise null
151 * pt = set if type otherwise null
152 * ps = set if symbol otherwise null
153 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
155 private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
156 out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
158 version (none)
160 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars());
161 if (scopesym)
162 printf("\tscopesym = '%s'\n", scopesym.toChars());
165 if (!s)
167 /* Look for what user might have intended
169 const p = mt.mutableOf().unSharedOf().toChars();
170 auto id = Identifier.idPool(p[0 .. strlen(p)]);
171 if (const n = importHint(id.toString()))
172 error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr);
173 else if (auto s2 = sc.search_correct(id))
174 error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
175 else if (const q = Scope.search_correct_C(id))
176 error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
177 else if ((id == Id.This && sc.getStructClassScope()) ||
178 (id == Id._super && sc.getClassScope()))
179 error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p);
180 else
181 error(loc, "undefined identifier `%s`", p);
183 pt = Type.terror;
184 return;
187 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
188 Declaration d = s.isDeclaration();
189 if (d && (d.storage_class & STC.templateparameter))
190 s = s.toAlias();
191 else
193 // check for deprecated or disabled aliases
194 // functions are checked after overloading
195 // templates are checked after matching constraints
196 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
197 s.checkDeprecated(loc, sc);
198 if (d)
199 d.checkDisabled(loc, sc, true);
201 s = s.toAlias();
202 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
203 for (size_t i = 0; i < mt.idents.length; i++)
205 RootObject id = mt.idents[i];
206 switch (id.dyncast()) with (DYNCAST)
208 case expression:
209 case type:
210 Type tx;
211 Expression ex;
212 Dsymbol sx;
213 resolveTupleIndex(loc, sc, s, ex, tx, sx, id);
214 if (sx)
216 s = sx.toAlias();
217 continue;
219 if (tx)
220 ex = new TypeExp(loc, tx);
221 assert(ex);
223 ex = typeToExpressionHelper(mt, ex, i + 1);
224 ex = ex.expressionSemantic(sc);
225 resolveExp(ex, pt, pe, ps);
226 return;
227 default:
228 break;
231 Type t = s.getType(); // type symbol, type alias, or type tuple?
232 uint errorsave = global.errors;
233 SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports;
235 Dsymbol sm = s.searchX(loc, sc, id, flags);
236 if (sm)
238 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
240 .error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
241 sm = null;
243 // Same check as in dotIdSemanticProp(DotIdExp)
244 else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
246 // @@@DEPRECATED_2.106@@@
247 // Should be an error in 2.106. Just remove the deprecation call
248 // and uncomment the null assignment
249 deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
250 //sm = null;
253 if (global.errors != errorsave)
255 pt = Type.terror;
256 return;
259 void helper3()
261 Expression e;
262 VarDeclaration v = s.isVarDeclaration();
263 FuncDeclaration f = s.isFuncDeclaration();
264 if (intypeid || !v && !f)
265 e = symbolToExp(s, loc, sc, true);
266 else
267 e = new VarExp(loc, s.isDeclaration(), true);
269 e = typeToExpressionHelper(mt, e, i);
270 e = e.expressionSemantic(sc);
271 resolveExp(e, pt, pe, ps);
274 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
275 if (intypeid && !t && sm && sm.needThis())
276 return helper3();
278 if (VarDeclaration v = s.isVarDeclaration())
280 // https://issues.dlang.org/show_bug.cgi?id=19913
281 // v.type would be null if it is a forward referenced member.
282 if (v.type is null)
283 v.dsymbolSemantic(sc);
284 if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
285 v.type.isConst() || v.type.isImmutable())
287 // https://issues.dlang.org/show_bug.cgi?id=13087
288 // this.field is not constant always
289 if (!v.isThisDeclaration())
290 return helper3();
294 if (!sm)
295 return helper3();
297 if (sm.isAliasDeclaration)
298 sm.checkDeprecated(loc, sc);
299 s = sm.toAlias();
302 if (auto em = s.isEnumMember())
304 // It's not a type, it's an expression
305 pe = em.getVarExp(loc, sc);
306 return;
308 if (auto v = s.isVarDeclaration())
310 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
311 * because some variables used in type context need to prevent lowering
312 * to a literal or contextful expression. For example:
314 * enum a = 1; alias b = a;
315 * template X(alias e){ alias v = e; } alias x = X!(1);
316 * struct S { int v; alias w = v; }
317 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
318 * // because getDsymbol() need to work in AliasDeclaration::semantic().
320 if (!v.type ||
321 !v.type.deco && v.inuse)
323 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
324 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
325 else
326 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
327 pt = Type.terror;
328 return;
330 if (v.type.ty == Terror)
331 pt = Type.terror;
332 else
333 pe = new VarExp(loc, v);
334 return;
336 if (auto fld = s.isFuncLiteralDeclaration())
338 //printf("'%s' is a function literal\n", fld.toChars());
339 auto e = new FuncExp(loc, fld);
340 pe = e.expressionSemantic(sc);
341 return;
343 version (none)
345 if (FuncDeclaration fd = s.isFuncDeclaration())
347 pe = new DsymbolExp(loc, fd);
348 return;
352 Type t;
353 while (1)
355 t = s.getType();
356 if (t)
357 break;
358 ps = s;
359 return;
362 if (auto ti = t.isTypeInstance())
363 if (ti != mt && !ti.deco)
365 if (!ti.tempinst.errors)
366 error(loc, "forward reference to `%s`", ti.toChars());
367 pt = Type.terror;
368 return;
371 if (t.ty == Ttuple)
372 pt = t;
373 else
374 pt = t.merge();
377 /***************************************
378 * Search for identifier id as a member of `this`.
379 * `id` may be a template instance.
381 * Params:
382 * loc = location to print the error messages
383 * sc = the scope where the symbol is located
384 * id = the id of the symbol
385 * flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports`
387 * Returns:
388 * symbol found, NULL if not
390 private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags)
392 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
393 Dsymbol s = dsym.toAlias();
394 Dsymbol sm;
395 if (Declaration d = s.isDeclaration())
397 if (d.inuse)
399 .error(loc, "circular reference to `%s`", d.toPrettyChars());
400 return null;
403 switch (id.dyncast())
405 case DYNCAST.identifier:
406 sm = s.search(loc, cast(Identifier)id, flags);
407 break;
408 case DYNCAST.dsymbol:
410 // It's a template instance
411 //printf("\ttemplate instance id\n");
412 Dsymbol st = cast(Dsymbol)id;
413 TemplateInstance ti = st.isTemplateInstance();
414 sm = s.search(loc, ti.name);
415 if (!sm)
416 return null;
417 sm = sm.toAlias();
418 TemplateDeclaration td = sm.isTemplateDeclaration();
419 if (!td)
420 return null; // error but handled later
421 ti.tempdecl = td;
422 if (!ti.semanticRun)
423 ti.dsymbolSemantic(sc);
424 sm = ti.toAlias();
425 break;
427 case DYNCAST.type:
428 case DYNCAST.expression:
429 default:
430 assert(0);
432 return sm;
435 /***************************************************
436 * Determine if type t is copyable.
437 * Params:
438 * t = type to check
439 * Returns:
440 * true if we can copy it
442 bool isCopyable(Type t)
444 //printf("isCopyable() %s\n", t.toChars());
445 if (auto ts = t.isTypeStruct())
447 if (ts.sym.postblit &&
448 ts.sym.postblit.storage_class & STC.disable)
449 return false;
450 if (ts.sym.hasCopyCtor)
452 // check if there is a matching overload of the copy constructor and whether it is disabled or not
453 // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
454 Dsymbol ctor = search_function(ts.sym, Id.ctor);
455 assert(ctor);
456 scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
457 el.type = cast() ts;
458 Expressions* args = new Expressions();
459 args.push(el);
460 FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet);
461 if (!f || f.storage_class & STC.disable)
462 return false;
465 return true;
468 /************************************
469 * Determine mutability of indirections in (ref) t.
471 * Returns: When the type has any mutable indirections, returns 0.
472 * When all indirections are immutable, returns 2.
473 * Otherwise, when the type has const/inout indirections, returns 1.
475 * Params:
476 * isref = if true, check `ref t`; otherwise, check just `t`
477 * t = the type that is being checked
479 int mutabilityOfType(bool isref, Type t)
481 if (isref)
483 if (t.mod & MODFlags.immutable_)
484 return 2;
485 if (t.mod & (MODFlags.const_ | MODFlags.wild))
486 return 1;
487 return 0;
490 t = t.baseElemOf();
492 if (!t.hasPointers() || t.mod & MODFlags.immutable_)
493 return 2;
495 /* Accept immutable(T)[] and immutable(T)* as being strongly pure
497 if (t.ty == Tarray || t.ty == Tpointer)
499 Type tn = t.nextOf().toBasetype();
500 if (tn.mod & MODFlags.immutable_)
501 return 2;
502 if (tn.mod & (MODFlags.const_ | MODFlags.wild))
503 return 1;
506 /* The rest of this is too strict; fix later.
507 * For example, the only pointer members of a struct may be immutable,
508 * which would maintain strong purity.
509 * (Just like for dynamic arrays and pointers above.)
511 if (t.mod & (MODFlags.const_ | MODFlags.wild))
512 return 1;
514 /* Should catch delegates and function pointers, and fold in their purity
516 return 0;
519 /********************************************
520 * Set 'purity' field of 'typeFunction'.
521 * Do this lazily, as the parameter types might be forward referenced.
523 void purityLevel(TypeFunction typeFunction)
525 TypeFunction tf = typeFunction;
526 if (tf.purity != PURE.fwdref)
527 return;
529 typeFunction.purity = PURE.const_; // assume strong until something weakens it
531 /* Evaluate what kind of purity based on the modifiers for the parameters
533 foreach (i, fparam; tf.parameterList)
535 Type t = fparam.type;
536 if (!t)
537 continue;
539 if (fparam.storageClass & (STC.lazy_ | STC.out_))
541 typeFunction.purity = PURE.weak;
542 break;
544 const pref = (fparam.storageClass & STC.ref_) != 0;
545 if (mutabilityOfType(pref, t) == 0)
546 typeFunction.purity = PURE.weak;
549 tf.purity = typeFunction.purity;
552 /******************************************
553 * We've mistakenly parsed `t` as a type.
554 * Redo `t` as an Expression only if there are no type modifiers.
555 * Params:
556 * t = mistaken type
557 * Returns:
558 * t redone as Expression, null if cannot
560 Expression typeToExpression(Type t)
562 static Expression visitSArray(TypeSArray t)
564 if (auto e = t.next.typeToExpression())
565 return new ArrayExp(t.dim.loc, e, t.dim);
566 return null;
569 static Expression visitAArray(TypeAArray t)
571 if (auto e = t.next.typeToExpression())
573 if (auto ei = t.index.typeToExpression())
574 return new ArrayExp(t.loc, e, ei);
576 return null;
579 static Expression visitIdentifier(TypeIdentifier t)
581 return typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident));
584 static Expression visitInstance(TypeInstance t)
586 return typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst));
589 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
590 static Expression visitMixin(TypeMixin t)
592 return new TypeExp(t.loc, t);
595 if (t.mod)
596 return null;
597 switch (t.ty)
599 case Tsarray: return visitSArray(t.isTypeSArray());
600 case Taarray: return visitAArray(t.isTypeAArray());
601 case Tident: return visitIdentifier(t.isTypeIdentifier());
602 case Tinstance: return visitInstance(t.isTypeInstance());
603 case Tmixin: return visitMixin(t.isTypeMixin());
604 default: return null;
608 /*************************************
609 * https://issues.dlang.org/show_bug.cgi?id=14488
610 * Check if the inner most base type is complex or imaginary.
611 * Should only give alerts when set to emit transitional messages.
612 * Params:
613 * type = type to check
614 * loc = The source location.
615 * sc = scope of the type
617 extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
619 if (sc.isDeprecated())
620 return false;
621 // Don't complain if we're inside a template constraint
622 // https://issues.dlang.org/show_bug.cgi?id=21831
623 if (sc.flags & SCOPE.constraint)
624 return false;
626 Type t = type.baseElemOf();
627 while (t.ty == Tpointer || t.ty == Tarray)
628 t = t.nextOf().baseElemOf();
630 // Basetype is an opaque enum, nothing to check.
631 if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
632 return false;
634 if (t.isimaginary() || t.iscomplex())
636 if (sc.flags & SCOPE.Cfile)
637 return true; // complex/imaginary not deprecated in C code
638 Type rt;
639 switch (t.ty)
641 case Tcomplex32:
642 case Timaginary32:
643 rt = Type.tfloat32;
644 break;
646 case Tcomplex64:
647 case Timaginary64:
648 rt = Type.tfloat64;
649 break;
651 case Tcomplex80:
652 case Timaginary80:
653 rt = Type.tfloat80;
654 break;
656 default:
657 assert(0);
659 // @@@DEPRECATED_2.117@@@
660 // Deprecated in 2.097 - Can be made an error from 2.117.
661 // The deprecation period is longer than usual as `cfloat`,
662 // `cdouble`, and `creal` were quite widely used.
663 if (t.iscomplex())
665 deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
666 type.toChars(), rt.toChars());
667 return true;
669 else
671 deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead",
672 type.toChars(), rt.toChars());
673 return true;
676 return false;
679 /********************************
680 * 'args' are being matched to function type 'tf'
681 * Determine match level.
682 * Params:
683 * tf = function type
684 * tthis = type of `this` pointer, null if not member function
685 * argumentList = arguments to function call
686 * flag = 1: performing a partial ordering match
687 * errorHelper = delegate to call for error messages
688 * sc = context
689 * Returns:
690 * MATCHxxxx
692 extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null)
694 //printf("TypeFunction::callMatch() %s\n", tf.toChars());
695 MATCH match = MATCH.exact; // assume exact match
696 ubyte wildmatch = 0;
698 if (tthis)
700 Type t = tthis;
701 if (t.toBasetype().ty == Tpointer)
702 t = t.toBasetype().nextOf(); // change struct* to struct
703 if (t.mod != tf.mod)
705 if (MODimplicitConv(t.mod, tf.mod))
706 match = MATCH.constant;
707 else if ((tf.mod & MODFlags.wild) && MODimplicitConv(t.mod, (tf.mod & ~MODFlags.wild) | MODFlags.const_))
709 match = MATCH.constant;
711 else
712 return MATCH.nomatch;
714 if (tf.isWild())
716 if (t.isWild())
717 wildmatch |= MODFlags.wild;
718 else if (t.isConst())
719 wildmatch |= MODFlags.const_;
720 else if (t.isImmutable())
721 wildmatch |= MODFlags.immutable_;
722 else
723 wildmatch |= MODFlags.mutable;
727 ParameterList* parameterList = &tf.parameterList;
728 const nparams = parameterList.length;
729 if (argumentList.length > nparams)
731 if (parameterList.varargs == VarArg.none)
733 // suppress early exit if an error message is wanted,
734 // so we can check any matching args are valid
735 if (!errorHelper)
736 return MATCH.nomatch;
738 // too many args; no match
739 match = MATCH.convert; // match ... with a "conversion" match level
742 // https://issues.dlang.org/show_bug.cgi?id=22997
743 if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
745 if (errorHelper)
747 OutBuffer buf;
748 buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
749 errorHelper(buf.peekChars());
751 return MATCH.nomatch;
753 const(char)* failMessage;
754 const(char)** pMessage = errorHelper ? &failMessage : null;
755 auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
756 Expression[] args;
757 if (!resolvedArgs)
759 if (failMessage)
761 errorHelper(failMessage);
762 return MATCH.nomatch;
765 // if no message was provided, it was because of overflow which will be diagnosed below
766 match = MATCH.nomatch;
767 args = argumentList.arguments ? (*argumentList.arguments)[] : null;
769 else
771 args = (*resolvedArgs)[];
774 foreach (u, p; *parameterList)
776 if (u >= args.length)
777 break;
779 Expression arg = args[u];
780 if (!arg)
781 continue; // default argument
783 Type tprm = p.type;
784 Type targ = arg.type;
786 if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
788 const isRef = p.isReference();
789 wildmatch |= targ.deduceWild(tprm, isRef);
792 if (wildmatch)
794 /* Calculate wild matching modifier
796 if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
797 wildmatch = MODFlags.const_;
798 else if (wildmatch & MODFlags.immutable_)
799 wildmatch = MODFlags.immutable_;
800 else if (wildmatch & MODFlags.wild)
801 wildmatch = MODFlags.wild;
802 else
804 assert(wildmatch & MODFlags.mutable);
805 wildmatch = MODFlags.mutable;
809 foreach (u, p; *parameterList)
811 MATCH m;
813 assert(p);
815 // One or more arguments remain
816 if (u < args.length)
818 Expression arg = args[u];
819 if (!arg)
820 continue; // default argument
821 m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);
823 else if (p.defaultArg)
824 continue;
826 /* prefer matching the element type rather than the array
827 * type when more arguments are present with T[]...
829 if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
830 goto L1;
832 //printf("\tm = %d\n", m);
833 if (m == MATCH.nomatch) // if no match
836 if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
838 auto trailingArgs = args[u .. $];
839 if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
840 return vmatch < match ? vmatch : match;
841 // Error message was already generated in `matchTypeSafeVarArgs`
842 if (failMessage)
843 errorHelper(failMessage);
844 return MATCH.nomatch;
846 if (pMessage && u >= args.length)
847 *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`",
848 u + 1, parameterToChars(p, tf, false));
849 // If an error happened previously, `pMessage` was already filled
850 else if (pMessage && !*pMessage)
851 *pMessage = tf.getParamError(args[u], p);
853 if (errorHelper)
854 errorHelper(*pMessage);
855 return MATCH.nomatch;
857 if (m < match)
858 match = m; // pick worst match
861 if (errorHelper && !parameterList.varargs && args.length > nparams)
863 // all parameters had a match, but there are surplus args
864 errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length));
865 return MATCH.nomatch;
867 //printf("match = %d\n", match);
868 return match;
872 * Used by `callMatch` to check if the copy constructor may be called to
873 * copy the argument
875 * This is done by seeing if a call to the copy constructor can be made:
876 * ```
877 * typeof(tprm) __copytmp;
878 * copytmp.__copyCtor(arg);
879 * ```
881 private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
882 Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
884 auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
885 tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
886 tmp.dsymbolSemantic(sc);
887 Expression ve = new VarExp(arg.loc, tmp);
888 Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
889 e = new CallExp(arg.loc, e, arg);
890 //printf("e = %s\n", e.toChars());
891 if (dmd.expressionsem.trySemantic(e, sc))
892 return true;
894 if (pMessage)
896 /* https://issues.dlang.org/show_bug.cgi?id=22202
898 * If a function was deduced by semantic on the CallExp,
899 * it means that resolveFuncCall completed succesfully.
900 * Therefore, there exists a callable copy constructor,
901 * however, it cannot be called because scope constraints
902 * such as purity, safety or nogc.
904 OutBuffer buf;
905 auto callExp = e.isCallExp();
906 if (auto f = callExp.f)
908 char[] s;
909 if (!f.isPure && sc.func.setImpure())
910 s ~= "pure ";
911 if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
912 s ~= "@safe ";
913 if (!f.isNogc && sc.func.setGC(arg.loc, null))
914 s ~= "nogc ";
915 if (f.isDisabled() && !f.isGenerated())
917 /* https://issues.dlang.org/show_bug.cgi?id=24301
918 * Copy constructor is explicitly disabled
920 buf.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`",
921 f.type.toChars());
923 else if (s)
925 s[$-1] = '\0';
926 buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
928 else if (f.isGenerated() && f.isDisabled())
930 /* https://issues.dlang.org/show_bug.cgi?id=23097
931 * Compiler generated copy constructor failed.
933 buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
934 argStruct.toChars());
936 else
938 /* Although a copy constructor may exist, no suitable match was found.
939 * i.e: `inout` constructor creates `const` object, not mutable.
940 * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
942 goto Lnocpctor;
945 else
947 Lnocpctor:
948 buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
949 argStruct.toChars(), arg.type.toChars(), tprm.toChars());
952 *pMessage = buf.extractChars();
954 return false;
958 * Match a single parameter to an argument.
960 * This function is called by `TypeFunction.callMatch` while iterating over
961 * the list of parameter. Here we check if `arg` is a match for `p`,
962 * which is mostly about checking if `arg.type` converts to `p`'s type
963 * and some check about value reference.
965 * Params:
966 * tf = The `TypeFunction`, only used for error reporting
967 * p = The parameter of `tf` being matched
968 * arg = Argument being passed (bound) to `p`
969 * wildmatch = Wild (`inout`) matching level, derived from the full argument list
970 * flag = A non-zero value means we're doing a partial ordering check
971 * (no value semantic check)
972 * sc = Scope we are in
973 * pMessage = A buffer to write the error in, or `null`
975 * Returns: Whether `trailingArgs` match `p`.
977 private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
978 Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
980 //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
981 MATCH m;
982 Type targ = arg.type;
983 Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
985 if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
986 m = MATCH.convert;
987 else if (flag)
989 // for partial ordering, value is an irrelevant mockup, just look at the type
990 m = targ.implicitConvTo(tprm);
992 else
994 const isRef = p.isReference();
995 StructDeclaration argStruct, prmStruct;
997 // first look for a copy constructor
998 if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
1000 // if the argument and the parameter are of the same unqualified struct type
1001 argStruct = (cast(TypeStruct)targ).sym;
1002 prmStruct = (cast(TypeStruct)tprm).sym;
1005 // check if the copy constructor may be called to copy the argument
1006 if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
1008 if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
1009 return MATCH.nomatch;
1010 m = MATCH.exact;
1012 else
1014 import dmd.dcast : cimplicitConvTo;
1015 m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
1019 // Non-lvalues do not match ref or out parameters
1020 if (p.isReference())
1022 // https://issues.dlang.org/show_bug.cgi?id=13783
1023 // Don't use toBasetype() to handle enum types.
1024 Type ta = targ;
1025 Type tp = tprm;
1026 //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
1028 if (m && !arg.isLvalue())
1030 if (p.storageClass & STC.out_)
1032 if (pMessage) *pMessage = tf.getParamError(arg, p);
1033 return MATCH.nomatch;
1036 if (arg.op == EXP.string_ && tp.ty == Tsarray)
1038 if (ta.ty != Tsarray)
1040 Type tn = tp.nextOf().castMod(ta.nextOf().mod);
1041 dinteger_t dim = (cast(StringExp)arg).len;
1042 ta = tn.sarrayOf(dim);
1045 else if (arg.op == EXP.slice && tp.ty == Tsarray)
1047 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1048 if (ta.ty != Tsarray)
1050 Type tn = ta.nextOf();
1051 dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
1052 ta = tn.sarrayOf(dim);
1055 else if (p.storageClass & STC.constscoperef)
1057 // Allow converting a literal to an `in` which is `ref`
1058 if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
1060 Type tn = tp.nextOf();
1061 dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
1062 ta = tn.sarrayOf(dim);
1065 // Need to make this a rvalue through a temporary
1066 m = MATCH.convert;
1068 else if (global.params.rvalueRefParam != FeatureState.enabled ||
1069 p.storageClass & STC.out_ ||
1070 !arg.type.isCopyable()) // can't copy to temp for ref parameter
1072 if (pMessage) *pMessage = tf.getParamError(arg, p);
1073 return MATCH.nomatch;
1075 else
1077 /* in functionParameters() we'll convert this
1078 * rvalue into a temporary
1080 m = MATCH.convert;
1084 /* If the match is not already perfect or if the arg
1085 is not a lvalue then try the `alias this` chain
1086 see https://issues.dlang.org/show_bug.cgi?id=15674
1087 and https://issues.dlang.org/show_bug.cgi?id=21905
1089 if (ta != tp || !arg.isLvalue())
1091 Type firsttab = ta.toBasetype();
1092 while (1)
1094 Type tab = ta.toBasetype();
1095 Type tat = tab.aliasthisOf();
1096 if (!tat || !tat.implicitConvTo(tprm))
1097 break;
1098 if (tat == tab || tat == firsttab)
1099 break;
1100 ta = tat;
1104 /* A ref variable should work like a head-const reference.
1105 * e.g. disallows:
1106 * ref T <- an lvalue of const(T) argument
1107 * ref T[dim] <- an lvalue of const(T[dim]) argument
1109 if (!ta.constConv(tp))
1111 if (pMessage) *pMessage = tf.getParamError(arg, p);
1112 return MATCH.nomatch;
1115 return m;
1118 // arguments get specially formatted
1119 private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter par)
1121 if (global.gag && !global.params.v.showGaggedErrors)
1122 return null;
1123 // show qualification when toChars() is the same but types are different
1124 // https://issues.dlang.org/show_bug.cgi?id=19948
1125 // when comparing the type with strcmp, we need to drop the qualifier
1126 bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) &&
1127 strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0;
1128 auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars();
1129 OutBuffer buf;
1130 // only mention rvalue if it's relevant
1131 const rv = !arg.isLvalue() && par.isReference();
1132 buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
1133 rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
1134 parameterToChars(par, tf, qual));
1135 return buf.extractChars();
1139 * Match the remaining arguments `trailingArgs` with parameter `p`.
1141 * Assume we already checked that `p` is the last parameter of `tf`,
1142 * and we want to know whether the arguments would match `p`.
1144 * Params:
1145 * tf = The `TypeFunction`, only used for error reporting
1146 * p = The last parameter of `tf` which is variadic
1147 * trailingArgs = The remaining arguments that should match `p`
1148 * pMessage = A buffer to write the error in, or `null`
1150 * Returns: Whether `trailingArgs` match `p`.
1152 private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
1153 Expression[] trailingArgs, const(char)** pMessage)
1155 Type tb = p.type.toBasetype();
1157 switch (tb.ty)
1159 case Tsarray:
1160 TypeSArray tsa = cast(TypeSArray)tb;
1161 dinteger_t sz = tsa.dim.toInteger();
1162 if (sz != trailingArgs.length)
1164 if (pMessage)
1165 *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
1166 sz, trailingArgs.length);
1167 return MATCH.nomatch;
1169 goto case Tarray;
1170 case Tarray:
1172 MATCH match = MATCH.exact;
1173 TypeArray ta = cast(TypeArray)tb;
1174 foreach (arg; trailingArgs)
1176 MATCH m;
1177 assert(arg);
1179 /* If lazy array of delegates,
1180 * convert arg(s) to delegate(s)
1182 Type tret = p.isLazyArray();
1183 if (tret)
1185 if (ta.next.equals(arg.type))
1186 m = MATCH.exact;
1187 else if (tret.toBasetype().ty == Tvoid)
1188 m = MATCH.convert;
1189 else
1191 m = arg.implicitConvTo(tret);
1192 if (m == MATCH.nomatch)
1193 m = arg.implicitConvTo(ta.next);
1196 else
1197 m = arg.implicitConvTo(ta.next);
1199 if (m == MATCH.nomatch)
1201 if (pMessage) *pMessage = tf.getParamError(arg, p);
1202 return MATCH.nomatch;
1204 if (m < match)
1205 match = m;
1207 return match;
1209 case Tclass:
1210 // We leave it up to the actual constructor call to do the matching.
1211 return MATCH.exact;
1213 default:
1214 // We can have things as `foo(int[int] wat...)` but they only match
1215 // with an associative array proper.
1216 if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p);
1217 return MATCH.nomatch;
1221 /***************************************
1222 * Return !=0 if type has pointers that need to
1223 * be scanned by the GC during a collection cycle.
1225 bool hasPointers(Type t)
1227 bool visitType(Type _) { return false; }
1228 bool visitDArray(TypeDArray _) { return true; }
1229 bool visitAArray(TypeAArray _) { return true; }
1230 bool visitPointer(TypePointer _) { return true; }
1231 bool visitDelegate(TypeDelegate _) { return true; }
1232 bool visitClass(TypeClass _) { return true; }
1233 bool visitEnum(TypeEnum t) { return t.memType().hasPointers(); }
1235 /* Although null isn't dereferencable, treat it as a pointer type for
1236 * attribute inference, generic code, etc.
1238 bool visitNull(TypeNull _) { return true; }
1240 bool visitSArray(TypeSArray t)
1242 /* Don't want to do this, because:
1243 * struct S { T* array[0]; }
1244 * may be a variable length struct.
1246 //if (dim.toInteger() == 0)
1247 // return false;
1249 if (t.next.ty == Tvoid)
1251 // Arrays of void contain arbitrary data, which may include pointers
1252 return true;
1254 else
1255 return t.next.hasPointers();
1258 bool visitStruct(TypeStruct t)
1260 StructDeclaration sym = t.sym;
1262 if (sym.members && !sym.determineFields() && sym.type != Type.terror)
1263 error(sym.loc, "no size because of forward references");
1265 sym.determineTypeProperties();
1266 return sym.hasPointerField;
1270 switch(t.ty)
1272 default: return visitType(t);
1273 case Tsarray: return visitSArray(t.isTypeSArray());
1274 case Tarray: return visitDArray(t.isTypeDArray());
1275 case Taarray: return visitAArray(t.isTypeAArray());
1276 case Tpointer: return visitPointer(t.isTypePointer());
1277 case Tdelegate: return visitDelegate(t.isTypeDelegate());
1278 case Tstruct: return visitStruct(t.isTypeStruct());
1279 case Tenum: return visitEnum(t.isTypeEnum());
1280 case Tclass: return visitClass(t.isTypeClass());
1281 case Tnull: return visitNull(t.isTypeNull());
1285 /******************************************
1286 * Perform semantic analysis on a type.
1287 * Params:
1288 * type = Type AST node
1289 * loc = the location of the type
1290 * sc = context
1291 * Returns:
1292 * `Type` with completed semantic analysis, `Terror` if errors
1293 * were encountered
1295 Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
1297 static Type error()
1299 return Type.terror;
1302 Type visitType(Type t)
1304 // @@@DEPRECATED_2.110@@@
1305 // Use of `cent` and `ucent` has always been an error.
1306 // Starting from 2.100, recommend core.int128 as a replace for the
1307 // lack of compiler support.
1308 if (t.ty == Tint128 || t.ty == Tuns128)
1310 .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
1311 return error();
1314 return t.merge();
1317 Type visitComplex(TypeBasic t)
1319 if (!(sc.flags & SCOPE.Cfile))
1320 return visitType(t);
1322 auto tc = getComplexLibraryType(loc, sc, t.ty);
1323 if (tc.ty == Terror)
1324 return tc;
1325 return tc.addMod(t.mod).merge();
1328 Type visitVector(TypeVector mtype)
1330 const errors = global.errors;
1331 mtype.basetype = mtype.basetype.typeSemantic(loc, sc);
1332 if (errors != global.errors)
1333 return error();
1334 mtype.basetype = mtype.basetype.toBasetype().mutableOf();
1335 if (mtype.basetype.ty != Tsarray)
1337 .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars());
1338 return error();
1340 TypeSArray t = mtype.basetype.isTypeSArray();
1341 const sz = cast(int)t.size(loc);
1342 final switch (target.isVectorTypeSupported(sz, t.nextOf()))
1344 case 0:
1345 // valid
1346 break;
1348 case 1:
1349 // no support at all
1350 .error(loc, "SIMD vector types not supported on this platform");
1351 return error();
1353 case 2:
1354 // invalid base type
1355 .error(loc, "vector type `%s` is not supported on this platform", mtype.toChars());
1356 return error();
1358 case 3:
1359 // invalid size
1360 .error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars());
1361 return error();
1363 return merge(mtype);
1366 Type visitSArray(TypeSArray mtype)
1368 //printf("TypeSArray::semantic() %s\n", toChars());
1369 Type t;
1370 Expression e;
1371 Dsymbol s;
1372 mtype.next.resolve(loc, sc, e, t, s);
1374 if (auto tup = s ? s.isTupleDeclaration() : null)
1376 mtype.dim = semanticLength(sc, tup, mtype.dim);
1377 mtype.dim = mtype.dim.ctfeInterpret();
1378 if (mtype.dim.op == EXP.error)
1379 return error();
1381 uinteger_t d = mtype.dim.toUInteger();
1382 if (d >= tup.objects.length)
1384 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tup.objects.length);
1385 return error();
1388 RootObject o = (*tup.objects)[cast(size_t)d];
1389 if (auto tt = o.isType())
1390 return tt.addMod(mtype.mod);
1391 .error(loc, "`%s` is not a type", mtype.toChars());
1392 return error();
1395 if (t && t.ty == Terror)
1396 return error();
1398 Type tn = mtype.next.typeSemantic(loc, sc);
1399 if (tn.ty == Terror)
1400 return error();
1402 Type tbn = tn.toBasetype();
1403 if (mtype.dim)
1405 auto errors = global.errors;
1406 mtype.dim = semanticLength(sc, tbn, mtype.dim);
1407 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
1408 if (errors != global.errors)
1409 return error();
1411 mtype.dim = mtype.dim.optimize(WANTvalue);
1412 mtype.dim = mtype.dim.ctfeInterpret();
1413 if (mtype.dim.op == EXP.error)
1414 return error();
1416 errors = global.errors;
1417 dinteger_t d1 = mtype.dim.toInteger();
1418 if (errors != global.errors)
1419 return error();
1421 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
1422 mtype.dim = mtype.dim.optimize(WANTvalue);
1423 if (mtype.dim.op == EXP.error)
1424 return error();
1426 errors = global.errors;
1427 dinteger_t d2 = mtype.dim.toInteger();
1428 if (errors != global.errors)
1429 return error();
1431 if (mtype.dim.op == EXP.error)
1432 return error();
1434 Type overflowError()
1436 .error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
1437 mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, target.maxStaticDataSize);
1438 return error();
1441 if (d1 != d2)
1442 return overflowError();
1444 Type tbx = tbn.baseElemOf();
1445 if (tbx.ty == Tstruct && !tbx.isTypeStruct().sym.members ||
1446 tbx.ty == Tenum && !tbx.isTypeEnum().sym.members)
1448 /* To avoid meaningless error message, skip the total size limit check
1449 * when the bottom of element type is opaque.
1452 else if (tbn.isTypeBasic() ||
1453 tbn.ty == Tpointer ||
1454 tbn.ty == Tarray ||
1455 tbn.ty == Tsarray ||
1456 tbn.ty == Taarray ||
1457 (tbn.ty == Tstruct && tbn.isTypeStruct().sym.sizeok == Sizeok.done) ||
1458 tbn.ty == Tclass)
1460 /* Only do this for types that don't need to have semantic()
1461 * run on them for the size, since they may be forward referenced.
1463 bool overflow = false;
1464 if (mulu(tbn.size(loc), d2, overflow) > target.maxStaticDataSize || overflow)
1465 return overflowError();
1468 switch (tbn.ty)
1470 case Ttuple:
1472 // Index the tuple to get the type
1473 assert(mtype.dim);
1474 TypeTuple tt = tbn.isTypeTuple();
1475 uinteger_t d = mtype.dim.toUInteger();
1476 if (d >= tt.arguments.length)
1478 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tt.arguments.length);
1479 return error();
1481 Type telem = (*tt.arguments)[cast(size_t)d].type;
1482 return telem.addMod(mtype.mod);
1485 case Tfunction:
1486 case Tnone:
1487 .error(loc, "cannot have array of `%s`", tbn.toChars());
1488 return error();
1490 default:
1491 break;
1493 if (tbn.isscope())
1495 .error(loc, "cannot have array of scope `%s`", tbn.toChars());
1496 return error();
1499 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
1500 * and const(T)[3] become const(T[3])
1502 mtype.next = tn;
1503 mtype.transitive();
1504 return mtype.addMod(tn.mod).merge();
1507 Type visitDArray(TypeDArray mtype)
1509 Type tn = mtype.next.typeSemantic(loc, sc);
1510 Type tbn = tn.toBasetype();
1511 switch (tbn.ty)
1513 case Ttuple:
1514 return tbn;
1516 case Tfunction:
1517 case Tnone:
1518 .error(loc, "cannot have array of `%s`", tbn.toChars());
1519 return error();
1521 case Terror:
1522 return error();
1524 default:
1525 break;
1527 if (tn.isscope())
1529 .error(loc, "cannot have array of scope `%s`", tn.toChars());
1530 return error();
1532 mtype.next = tn;
1533 mtype.transitive();
1534 return merge(mtype);
1537 Type visitAArray(TypeAArray mtype)
1539 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
1540 if (mtype.deco)
1542 return mtype;
1545 mtype.loc = loc;
1546 if (sc)
1547 sc.setNoFree();
1549 // Deal with the case where we thought the index was a type, but
1550 // in reality it was an expression.
1551 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)
1553 Expression e;
1554 Type t;
1555 Dsymbol s;
1556 mtype.index.resolve(loc, sc, e, t, s);
1558 // https://issues.dlang.org/show_bug.cgi?id=15478
1559 if (s)
1560 e = symbolToExp(s, loc, sc, false);
1562 if (e)
1564 // It was an expression -
1565 // Rewrite as a static array
1566 auto tsa = new TypeSArray(mtype.next, e);
1567 return tsa.typeSemantic(loc, sc);
1569 else if (t)
1570 mtype.index = t.typeSemantic(loc, sc);
1571 else
1573 .error(loc, "index is not a type or an expression");
1574 return error();
1577 else
1578 mtype.index = mtype.index.typeSemantic(loc, sc);
1579 mtype.index = mtype.index.merge2();
1581 if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable())
1583 mtype.index = mtype.index.constOf().mutableOf();
1584 version (none)
1586 printf("index is %p %s\n", mtype.index, mtype.index.toChars());
1587 mtype.index.check();
1588 printf("index.mod = x%x\n", mtype.index.mod);
1589 printf("index.ito = x%p\n", mtype.index.getMcache().ito);
1590 if (mtype.index.getMcache().ito)
1592 printf("index.ito.mod = x%x\n", mtype.index.getMcache().ito.mod);
1593 printf("index.ito.ito = x%p\n", mtype.index.getMcache().ito.getMcache().ito);
1598 switch (mtype.index.toBasetype().ty)
1600 case Tfunction:
1601 case Tvoid:
1602 case Tnone:
1603 case Ttuple:
1604 .error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars());
1605 goto case Terror;
1606 case Terror:
1607 return error();
1609 default:
1610 break;
1612 Type tbase = mtype.index.baseElemOf();
1613 while (tbase.ty == Tarray)
1614 tbase = tbase.nextOf().baseElemOf();
1615 if (auto ts = tbase.isTypeStruct())
1617 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
1619 StructDeclaration sd = ts.sym;
1620 if (sd.semanticRun < PASS.semanticdone)
1621 sd.dsymbolSemantic(null);
1623 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
1624 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
1626 if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
1628 uint errors = global.startGagging();
1629 sd.xeq.semantic3(sd.xeq._scope);
1630 if (global.endGagging(errors))
1631 sd.xeq = sd.xerreq;
1635 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
1636 const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : "";
1637 if (!sd.xeq)
1639 // If sd.xhash != NULL:
1640 // sd or its fields have user-defined toHash.
1641 // AA assumes that its result is consistent with bitwise equality.
1642 // else:
1643 // bitwise equality & hashing
1645 else if (sd.xeq == sd.xerreq)
1647 if (search_function(sd, Id.eq))
1649 .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars());
1651 else
1653 .error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars());
1655 return error();
1657 else if (!sd.xhash)
1659 if (search_function(sd, Id.eq))
1661 .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars());
1663 else
1665 .error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars());
1667 return error();
1669 else
1671 // defined equality & hashing
1672 assert(sd.xeq && sd.xhash);
1674 /* xeq and xhash may be implicitly defined by compiler. For example:
1675 * struct S { int[] arr; }
1676 * With 'arr' field equality and hashing, compiler will implicitly
1677 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
1681 else if (tbase.ty == Tclass && !tbase.isTypeClass().sym.isInterfaceDeclaration())
1683 ClassDeclaration cd = tbase.isTypeClass().sym;
1684 if (cd.semanticRun < PASS.semanticdone)
1685 cd.dsymbolSemantic(null);
1687 if (!ClassDeclaration.object)
1689 .error(Loc.initial, "missing or corrupt object.d");
1690 return error();
1693 __gshared FuncDeclaration feq = null;
1694 __gshared FuncDeclaration fcmp = null;
1695 __gshared FuncDeclaration fhash = null;
1696 if (!feq)
1697 feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration();
1698 if (!fcmp)
1699 fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration();
1700 if (!fhash)
1701 fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration();
1702 assert(fcmp && feq && fhash);
1704 if (feq.vtblIndex < cd.vtbl.length && cd.vtbl[feq.vtblIndex] == feq)
1706 version (all)
1708 if (fcmp.vtblIndex < cd.vtbl.length && cd.vtbl[fcmp.vtblIndex] != fcmp)
1710 const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : "";
1711 .error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars());
1712 errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`.");
1717 mtype.next = mtype.next.typeSemantic(loc, sc).merge2();
1718 mtype.transitive();
1720 switch (mtype.next.toBasetype().ty)
1722 case Tfunction:
1723 case Tvoid:
1724 case Tnone:
1725 case Ttuple:
1726 .error(loc, "cannot have associative array of `%s`", mtype.next.toChars());
1727 goto case Terror;
1728 case Terror:
1729 return error();
1730 default:
1731 break;
1733 if (mtype.next.isscope())
1735 .error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
1736 return error();
1738 return merge(mtype);
1741 Type visitPointer(TypePointer mtype)
1743 //printf("TypePointer::semantic() %s\n", toChars());
1744 if (mtype.deco)
1746 return mtype;
1748 Type n = mtype.next.typeSemantic(loc, sc);
1749 switch (n.toBasetype().ty)
1751 case Ttuple:
1752 .error(loc, "cannot have pointer to `%s`", n.toChars());
1753 goto case Terror;
1754 case Terror:
1755 return error();
1756 default:
1757 break;
1759 if (n != mtype.next)
1761 mtype.deco = null;
1763 mtype.next = n;
1764 if (mtype.next.ty != Tfunction)
1766 mtype.transitive();
1767 return merge(mtype);
1769 version (none)
1771 return merge(mtype);
1773 else
1775 mtype.deco = merge(mtype).deco;
1776 /* Don't return merge(), because arg identifiers and default args
1777 * can be different
1778 * even though the types match
1780 return mtype;
1784 Type visitReference(TypeReference mtype)
1786 //printf("TypeReference::semantic()\n");
1787 Type n = mtype.next.typeSemantic(loc, sc);
1788 if (n != mtype.next)
1789 mtype.deco = null;
1790 mtype.next = n;
1791 mtype.transitive();
1792 return merge(mtype);
1795 Type visitFunction(TypeFunction mtype)
1797 if (mtype.deco) // if semantic() already run
1799 //printf("already done\n");
1800 return mtype;
1802 //printf("TypeFunction::semantic() this = %p\n", mtype);
1803 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
1805 bool errors = false;
1807 if (mtype.inuse > global.recursionLimit)
1809 mtype.inuse = 0;
1810 .error(loc, "recursive type");
1811 return error();
1814 /* Copy in order to not mess up original.
1815 * This can produce redundant copies if inferring return type,
1816 * as semantic() will get called again on this.
1818 TypeFunction tf = mtype.copy().toTypeFunction();
1819 if (mtype.parameterList.parameters)
1821 tf.parameterList.parameters = mtype.parameterList.parameters.copy();
1822 for (size_t i = 0; i < mtype.parameterList.parameters.length; i++)
1824 Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter));
1825 memcpy(cast(void*)p, cast(void*)(*mtype.parameterList.parameters)[i], __traits(classInstanceSize, Parameter));
1826 (*tf.parameterList.parameters)[i] = p;
1830 if (sc.stc & STC.pure_)
1831 tf.purity = PURE.fwdref;
1832 if (sc.stc & STC.nothrow_)
1833 tf.isnothrow = true;
1834 if (sc.stc & STC.nogc)
1835 tf.isnogc = true;
1836 if (sc.stc & STC.ref_)
1837 tf.isref = true;
1838 if (sc.stc & STC.return_)
1839 tf.isreturn = true;
1840 if (sc.stc & STC.returnScope)
1841 tf.isreturnscope = true;
1842 if (sc.stc & STC.returninferred)
1843 tf.isreturninferred = true;
1844 if (sc.stc & STC.scope_)
1845 tf.isScopeQual = true;
1846 if (sc.stc & STC.scopeinferred)
1847 tf.isscopeinferred = true;
1849 // if (tf.isreturn && !tf.isref)
1850 // tf.isScopeQual = true; // return by itself means 'return scope'
1852 if (tf.trust == TRUST.default_)
1854 if (sc.stc & STC.safe)
1855 tf.trust = TRUST.safe;
1856 else if (sc.stc & STC.system)
1857 tf.trust = TRUST.system;
1858 else if (sc.stc & STC.trusted)
1859 tf.trust = TRUST.trusted;
1862 if (sc.stc & STC.property)
1863 tf.isproperty = true;
1864 if (sc.stc & STC.live)
1865 tf.islive = true;
1867 tf.linkage = sc.linkage;
1868 if (tf.linkage == LINK.system)
1869 tf.linkage = target.systemLinkage();
1871 version (none)
1873 /* If the parent is @safe, then this function defaults to safe
1874 * too.
1875 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1876 * to be inferred first.
1878 if (tf.trust == TRUST.default_)
1879 for (Dsymbol p = sc.func; p; p = p.toParent2())
1881 FuncDeclaration fd = p.isFuncDeclaration();
1882 if (fd)
1884 if (fd.isSafeBypassingInference())
1885 tf.trust = TRUST.safe; // default to @safe
1886 break;
1891 bool wildreturn = false;
1892 if (tf.next)
1894 sc = sc.push();
1895 sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR);
1896 tf.next = tf.next.typeSemantic(loc, sc);
1897 sc = sc.pop();
1898 errors |= tf.checkRetType(loc);
1899 if (tf.next.isscope() && !tf.isctor)
1901 .error(loc, "functions cannot return `scope %s`", tf.next.toChars());
1902 errors = true;
1904 if (tf.next.hasWild())
1905 wildreturn = true;
1907 if (tf.isreturn && !tf.isref && !tf.next.hasPointers())
1909 tf.isreturn = false;
1913 /// Perform semantic on the default argument to a parameter
1914 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1915 /// Returns `false` whether an error was encountered.
1916 static bool defaultArgSemantic (ref Parameter fparam, Scope* sc)
1918 Expression e = fparam.defaultArg;
1919 const isRefOrOut = fparam.isReference();
1920 const isAuto = fparam.storageClass & (STC.auto_ | STC.autoref);
1921 if (isRefOrOut && !isAuto)
1923 e = e.expressionSemantic(sc);
1924 e = resolveProperties(sc, e);
1926 else
1928 e = inferType(e, fparam.type);
1929 Scope* sc2 = sc.push();
1930 sc2.inDefaultArg = true;
1931 Initializer iz = new ExpInitializer(e.loc, e);
1932 iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret);
1933 e = iz.initializerToExpression();
1934 sc2.pop();
1936 if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
1938 FuncExp fe = e.isFuncExp();
1939 // Replace function literal with a function symbol,
1940 // since default arg expression must be copied when used
1941 // and copying the literal itself is wrong.
1942 e = new VarExp(e.loc, fe.fd, false);
1943 e = new AddrExp(e.loc, e);
1944 e = e.expressionSemantic(sc);
1946 if (isRefOrOut && (!isAuto || e.isLvalue())
1947 && !MODimplicitConv(e.type.mod, fparam.type.mod))
1949 const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
1950 .error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1951 e.toChars(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
1953 e = e.implicitCastTo(sc, fparam.type);
1955 // default arg must be an lvalue
1956 if (isRefOrOut && !isAuto &&
1957 !(fparam.storageClass & STC.constscoperef) &&
1958 global.params.rvalueRefParam != FeatureState.enabled)
1959 e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from");
1961 fparam.defaultArg = e;
1962 return (e.op != EXP.error);
1965 ubyte wildparams = 0;
1966 if (tf.parameterList.parameters)
1968 /* Create a scope for evaluating the default arguments for the parameters
1970 Scope* argsc = sc.push();
1971 argsc.stc = 0; // don't inherit storage class
1972 argsc.visibility = Visibility(Visibility.Kind.public_);
1973 argsc.func = null;
1975 size_t dim = tf.parameterList.length;
1976 for (size_t i = 0; i < dim; i++)
1978 Parameter fparam = tf.parameterList[i];
1979 fparam.storageClass |= STC.parameter;
1980 mtype.inuse++;
1981 fparam.type = fparam.type.typeSemantic(loc, argsc);
1982 mtype.inuse--;
1984 if (fparam.type.ty == Terror)
1986 errors = true;
1987 continue;
1990 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
1992 if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_))
1994 if (!fparam.type)
1995 continue;
1998 fparam.type = fparam.type.cAdjustParamType(sc); // adjust C array and function parameter types
2000 Type t = fparam.type.toBasetype();
2002 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
2003 * change.
2005 if (auto tt = t.isTypeTuple())
2007 /* TypeFunction::parameter also is used as the storage of
2008 * Parameter objects for FuncDeclaration. So we should copy
2009 * the elements of TypeTuple::arguments to avoid unintended
2010 * sharing of Parameter object among other functions.
2012 if (tt.arguments && tt.arguments.length)
2014 /* Propagate additional storage class from tuple parameters to their
2015 * element-parameters.
2016 * Make a copy, as original may be referenced elsewhere.
2018 size_t tdim = tt.arguments.length;
2019 auto newparams = new Parameters(tdim);
2020 for (size_t j = 0; j < tdim; j++)
2022 Parameter narg = (*tt.arguments)[j];
2024 // https://issues.dlang.org/show_bug.cgi?id=12744
2025 // If the storage classes of narg
2026 // conflict with the ones in fparam, it's ignored.
2027 StorageClass stc = fparam.storageClass | narg.storageClass;
2028 StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
2029 StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
2030 if (stc1 && stc2 && stc1 != stc2)
2032 OutBuffer buf1; stcToBuffer(buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0));
2033 OutBuffer buf2; stcToBuffer(buf2, stc2);
2035 .error(loc, "incompatible parameter storage classes `%s` and `%s`",
2036 buf1.peekChars(), buf2.peekChars());
2037 errors = true;
2038 stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_));
2040 (*newparams)[j] = new Parameter(
2041 loc, stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
2043 fparam.type = new TypeTuple(newparams);
2044 fparam.type = fparam.type.typeSemantic(loc, argsc);
2046 fparam.storageClass = STC.parameter;
2048 /* Reset number of parameters, and back up one to do this fparam again,
2049 * now that it is a tuple
2051 dim = tf.parameterList.length;
2052 i--;
2053 continue;
2056 // -preview=in: Always add `ref` when used with `extern(C++)` functions
2057 // Done here to allow passing opaque types with `in`
2058 if ((fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
2060 switch (tf.linkage)
2062 case LINK.cpp:
2063 if (fparam.storageClass & STC.constscoperef)
2064 fparam.storageClass |= STC.ref_;
2065 break;
2066 case LINK.default_, LINK.d:
2067 break;
2068 default:
2069 if (fparam.storageClass & STC.constscoperef)
2071 .error(loc, "cannot use `in` parameters with `extern(%s)` functions",
2072 linkageToChars(tf.linkage));
2073 .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
2075 else
2077 // Note that this deprecation will not trigger on `in ref` / `ref in`
2078 // parameters, however the parser will trigger a deprecation on them.
2079 .deprecation(loc, "using `in` parameters with `extern(%s)` functions is deprecated",
2080 linkageToChars(tf.linkage));
2081 .deprecationSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
2083 break;
2087 if (t.ty == Tfunction)
2089 .error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars());
2090 errors = true;
2092 else if (!fparam.isReference() &&
2093 (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum))
2095 Type tb2 = t.baseElemOf();
2096 if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members ||
2097 tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype)
2099 if (fparam.storageClass & STC.constscoperef)
2101 .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
2102 fparam.toChars(), fparam.type.toChars());
2104 else
2105 .error(loc, "cannot have parameter of opaque type `%s` by value",
2106 fparam.type.toChars());
2107 errors = true;
2110 else if (!fparam.isLazy() && t.ty == Tvoid)
2112 .error(loc, "cannot have parameter of type `%s`", fparam.type.toChars());
2113 errors = true;
2116 const bool isTypesafeVariadic = i + 1 == dim &&
2117 tf.parameterList.varargs == VarArg.typesafe &&
2118 (t.isTypeDArray() || t.isTypeClass());
2119 if (isTypesafeVariadic)
2121 /* typesafe variadic arguments are constructed on the stack, so must be `scope`
2123 fparam.storageClass |= STC.scope_ | STC.scopeinferred;
2126 if (fparam.storageClass & STC.return_)
2128 if (!fparam.isReference())
2130 if (!(fparam.storageClass & STC.scope_))
2131 fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
2132 if (tf.isref)
2135 else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid)
2137 fparam.storageClass &= ~STC.return_; // https://issues.dlang.org/show_bug.cgi?id=18963
2141 if (isTypesafeVariadic)
2143 /* This is because they can be constructed on the stack
2144 * https://dlang.org/spec/function.html#typesafe_variadic_functions
2146 .error(loc, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
2147 fparam.ident ? fparam.ident.toChars() : "", t.toChars());
2148 errors = true;
2152 if (fparam.storageClass & STC.out_)
2154 if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild))
2156 .error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars());
2157 errors = true;
2159 else
2161 Type tv = t.baseElemOf();
2162 if (tv.ty == Tstruct && tv.isTypeStruct().sym.noDefaultCtor)
2164 .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars());
2165 errors = true;
2170 if (t.hasWild())
2172 wildparams |= 1;
2173 //if (tf.next && !wildreturn)
2174 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
2177 // Remove redundant storage classes for type, they are already applied
2178 fparam.storageClass &= ~(STC.TYPECTOR);
2180 // -preview=in: add `ref` storage class to suited `in` params
2181 if ((fparam.storageClass & (STC.constscoperef | STC.ref_)) == STC.constscoperef)
2183 auto ts = t.baseElemOf().isTypeStruct();
2184 const isPOD = !ts || ts.sym.isPOD();
2185 if (!isPOD || target.preferPassByRef(t))
2186 fparam.storageClass |= STC.ref_;
2190 Expressions* fargs = mtype.inferenceArguments.arguments;
2192 // mtype.argumentList only provided for Implicit Function Template Instantiation
2193 if (mtype.inferenceArguments.length > 0)
2194 fargs = tf.resolveNamedArgs(mtype.inferenceArguments, null);
2196 // Now that we completed semantic for the argument types,
2197 // run semantic on their default values,
2198 // bearing in mind tuples have been expanded.
2199 // We need to keep a pair of [oidx, eidx] (original index,
2200 // extended index), as we need to run semantic when `oidx` changes.
2201 size_t tupleOrigIdx = size_t.max;
2202 size_t tupleExtIdx = size_t.max;
2203 foreach (oidx, oparam, eidx, eparam; tf.parameterList)
2205 // oparam (original param) will always have the default arg
2206 // if there's one, but `eparam` will not if it's an expanded
2207 // tuple. When we see an expanded tuple, we need to save its
2208 // position to get the offset in it later on.
2209 if (oparam.defaultArg)
2211 // Get the obvious case out of the way
2212 if (oparam is eparam)
2213 errors |= !defaultArgSemantic(eparam, argsc);
2214 // We're seeing a new tuple
2215 else if (tupleOrigIdx == size_t.max || tupleOrigIdx < oidx)
2217 /* https://issues.dlang.org/show_bug.cgi?id=18572
2219 * If a tuple parameter has a default argument, when expanding the parameter
2220 * tuple the default argument tuple must also be expanded.
2222 tupleOrigIdx = oidx;
2223 tupleExtIdx = eidx;
2224 errors |= !defaultArgSemantic(oparam, argsc);
2225 TupleExp te = oparam.defaultArg.isTupleExp();
2226 if (te && te.exps && te.exps.length)
2227 eparam.defaultArg = (*te.exps)[0];
2229 // Processing an already-seen tuple
2230 else
2232 TupleExp te = oparam.defaultArg.isTupleExp();
2233 if (te && te.exps && te.exps.length)
2234 eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
2238 // We need to know the default argument to resolve `auto ref`,
2239 // hence why this has to take place as the very last step.
2240 /* Resolve "auto ref" storage class to be either ref or value,
2241 * based on the argument matching the parameter
2243 if (eparam.storageClass & STC.auto_)
2245 Expression farg = (fargs && eidx < fargs.length) ? (*fargs)[eidx] : null;
2246 if (!farg)
2247 farg = eparam.defaultArg;
2249 if (farg && (eparam.storageClass & STC.ref_))
2251 if (!farg.isLvalue())
2252 eparam.storageClass &= ~STC.ref_; // value parameter
2253 eparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656
2254 eparam.storageClass |= STC.autoref;
2256 else if (mtype.incomplete && (eparam.storageClass & STC.ref_))
2258 // the default argument may have been temporarily removed,
2259 // see usage of `TypeFunction.incomplete`.
2260 // https://issues.dlang.org/show_bug.cgi?id=19891
2261 eparam.storageClass &= ~STC.auto_;
2262 eparam.storageClass |= STC.autoref;
2264 else if (eparam.storageClass & STC.ref_)
2266 .error(loc, "cannot explicitly instantiate template function with `auto ref` parameter");
2267 errors = true;
2269 else
2271 .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
2272 errors = true;
2277 argsc.pop();
2279 if (tf.isWild())
2280 wildparams |= 2;
2282 if (wildreturn && !wildparams)
2284 .error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars());
2285 errors = true;
2287 tf.isInOutParam = (wildparams & 1) != 0;
2288 tf.isInOutQual = (wildparams & 2) != 0;
2290 if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
2292 .error(loc, "properties can only have zero, one, or two parameter");
2293 errors = true;
2296 if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
2297 !(sc.flags & SCOPE.Cfile))
2299 .error(loc, "variadic functions with non-D linkage must have at least one parameter");
2300 errors = true;
2303 if (errors)
2304 return error();
2306 if (tf.next)
2307 tf.deco = tf.merge().deco;
2309 /* Don't return merge(), because arg identifiers and default args
2310 * can be different
2311 * even though the types match
2313 return tf;
2316 Type visitDelegate(TypeDelegate mtype)
2318 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
2319 if (mtype.deco) // if semantic() already run
2321 //printf("already done\n");
2322 return mtype;
2324 mtype.next = mtype.next.typeSemantic(loc, sc);
2325 if (mtype.next.ty != Tfunction)
2326 return error();
2328 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
2329 * perhaps default arguments should
2330 * be removed from next before the merge.
2332 version (none)
2334 return mtype.merge();
2336 else
2338 /* Don't return merge(), because arg identifiers and default args
2339 * can be different
2340 * even though the types match
2342 mtype.deco = mtype.merge().deco;
2343 return mtype;
2347 Type visitIdentifier(TypeIdentifier mtype)
2349 Type t;
2350 Expression e;
2351 Dsymbol s;
2352 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
2353 mtype.resolve(loc, sc, e, t, s);
2354 if (t)
2356 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
2357 return t.addMod(mtype.mod);
2359 else
2361 if (s)
2363 auto td = s.isTemplateDeclaration;
2364 if (td && td.onemember && td.onemember.isAggregateDeclaration)
2365 .error(loc, "template %s `%s` is used as a type without instantiation"
2366 ~ "; to instantiate it use `%s!(arguments)`",
2367 s.kind, s.toPrettyChars, s.ident.toChars);
2368 else
2369 .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
2370 //assert(0);
2372 else if (e.op == EXP.variable) // special case: variable is used as a type
2375 N.B. This branch currently triggers for the following code
2376 template test(x* x)
2380 i.e. the compiler prints "variable x is used as a type"
2381 which isn't a particularly good error message (x is a variable?).
2383 Dsymbol varDecl = mtype.toDsymbol(sc);
2384 const(Loc) varDeclLoc = varDecl.getLoc();
2385 Module varDeclModule = varDecl.getModule(); //This can be null
2387 .error(loc, "variable `%s` is used as a type", mtype.toChars());
2388 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
2389 if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
2391 const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
2392 .errorSupplemental(
2393 varDeclModuleImportLoc,
2394 "variable `%s` is imported here from: `%s`",
2395 varDecl.toChars,
2396 varDeclModule.toPrettyChars,
2400 .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
2402 else
2403 .error(loc, "`%s` is used as a type", mtype.toChars());
2404 return error();
2408 Type visitInstance(TypeInstance mtype)
2410 Type t;
2411 Expression e;
2412 Dsymbol s;
2414 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
2416 const errors = global.errors;
2417 mtype.resolve(loc, sc, e, t, s);
2418 // if we had an error evaluating the symbol, suppress further errors
2419 if (!t && errors != global.errors)
2420 return error();
2423 if (!t)
2425 if (!e && s && s.errors)
2427 // if there was an error evaluating the symbol, it might actually
2428 // be a type. Avoid misleading error messages.
2429 .error(loc, "`%s` had previous errors", mtype.toChars());
2431 else
2432 .error(loc, "`%s` is used as a type", mtype.toChars());
2433 return error();
2435 return t;
2438 Type visitTypeof(TypeTypeof mtype)
2440 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
2441 Expression e;
2442 Type t;
2443 Dsymbol s;
2444 mtype.resolve(loc, sc, e, t, s);
2445 if (s && (t = s.getType()) !is null)
2446 t = t.addMod(mtype.mod);
2447 if (!t)
2449 .error(loc, "`%s` is used as a type", mtype.toChars());
2450 return error();
2452 return t;
2455 Type visitTraits(TypeTraits mtype)
2457 Expression e;
2458 Type t;
2459 Dsymbol s;
2460 mtype.resolve(loc, sc, e, t, s);
2462 if (!t)
2464 if (!global.errors)
2465 .error(mtype.loc, "`%s` does not give a valid type", mtype.toChars);
2466 return error();
2468 return t;
2471 Type visitReturn(TypeReturn mtype)
2473 //printf("TypeReturn::semantic() %s\n", toChars());
2474 Expression e;
2475 Type t;
2476 Dsymbol s;
2477 mtype.resolve(loc, sc, e, t, s);
2478 if (s && (t = s.getType()) !is null)
2479 t = t.addMod(mtype.mod);
2480 if (!t)
2482 .error(loc, "`%s` is used as a type", mtype.toChars());
2483 return error();
2485 return t;
2488 Type visitStruct(TypeStruct mtype)
2490 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
2491 if (mtype.deco)
2492 return mtype;
2494 /* Don't semantic for sym because it should be deferred until
2495 * sizeof needed or its members accessed.
2497 // instead, parent should be set correctly
2498 assert(mtype.sym.parent);
2500 if (mtype.sym.type.ty == Terror)
2501 return error();
2503 return merge(mtype);
2506 Type visitEnum(TypeEnum mtype)
2508 //printf("TypeEnum::semantic() %s\n", toChars());
2509 return mtype.deco ? mtype : merge(mtype);
2512 Type visitClass(TypeClass mtype)
2514 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
2515 if (mtype.deco)
2516 return mtype;
2518 /* Don't semantic for sym because it should be deferred until
2519 * sizeof needed or its members accessed.
2521 // instead, parent should be set correctly
2522 assert(mtype.sym.parent);
2524 if (mtype.sym.type.ty == Terror)
2525 return error();
2527 return merge(mtype);
2530 Type visitTuple(TypeTuple mtype)
2532 //printf("TypeTuple::semantic(this = %p)\n", this);
2533 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
2534 if (!mtype.deco)
2535 mtype.deco = merge(mtype).deco;
2537 /* Don't return merge(), because a tuple with one type has the
2538 * same deco as that type.
2540 return mtype;
2543 Type visitSlice(TypeSlice mtype)
2545 //printf("TypeSlice::semantic() %s\n", toChars());
2546 Type tn = mtype.next.typeSemantic(loc, sc);
2547 //printf("next: %s\n", tn.toChars());
2549 Type tbn = tn.toBasetype();
2550 if (tbn.ty != Ttuple)
2552 .error(loc, "can only slice type sequences, not `%s`", tbn.toChars());
2553 return error();
2555 TypeTuple tt = cast(TypeTuple)tbn;
2557 mtype.lwr = semanticLength(sc, tbn, mtype.lwr);
2558 mtype.upr = semanticLength(sc, tbn, mtype.upr);
2559 mtype.lwr = mtype.lwr.ctfeInterpret();
2560 mtype.upr = mtype.upr.ctfeInterpret();
2561 if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error)
2562 return error();
2564 uinteger_t i1 = mtype.lwr.toUInteger();
2565 uinteger_t i2 = mtype.upr.toUInteger();
2566 if (!(i1 <= i2 && i2 <= tt.arguments.length))
2568 .error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
2569 cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.length);
2570 return error();
2573 mtype.next = tn;
2574 mtype.transitive();
2576 auto args = new Parameters();
2577 args.reserve(cast(size_t)(i2 - i1));
2578 foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2])
2580 args.push(arg);
2582 Type t = new TypeTuple(args);
2583 return t.typeSemantic(loc, sc);
2586 Type visitMixin(TypeMixin mtype)
2588 //printf("TypeMixin::semantic() %s\n", toChars());
2590 Expression e;
2591 Type t;
2592 Dsymbol s;
2593 mtype.resolve(loc, sc, e, t, s);
2595 if (t && t.ty != Terror)
2596 return t;
2598 .error(mtype.loc, "`mixin(%s)` does not give a valid type", mtype.obj.toChars);
2599 return error();
2602 Type visitTag(TypeTag mtype)
2604 //printf("TypeTag.semantic() %s\n", mtype.toChars());
2605 Type returnType(Type t)
2607 return t.deco ? t : t.merge();
2610 if (mtype.resolved)
2612 /* struct S s, *p;
2614 return returnType(mtype.resolved.addSTC(mtype.mod));
2617 /* Find the current scope by skipping tag scopes.
2618 * In C, tag scopes aren't considered scopes.
2620 Scope* sc2 = sc;
2621 while (1)
2623 sc2 = sc2.inner();
2624 auto scopesym = sc2.scopesym;
2625 if (scopesym.isStructDeclaration())
2627 sc2 = sc2.enclosing;
2628 continue;
2630 break;
2633 /* Declare mtype as a struct/union/enum declaration
2635 void declareTag()
2637 void declare(ScopeDsymbol sd)
2639 sd.members = mtype.members;
2640 auto scopesym = sc2.inner().scopesym;
2641 if (scopesym.members)
2642 scopesym.members.push(sd);
2643 if (scopesym.symtab && !scopesym.symtabInsert(sd))
2645 Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
2646 handleTagSymbols(*sc2, sd, s2, scopesym);
2648 sd.parent = sc2.parent;
2649 sd.dsymbolSemantic(sc2);
2652 switch (mtype.tok)
2654 case TOK.enum_:
2655 auto ed = new EnumDeclaration(mtype.loc, mtype.id, mtype.base);
2656 declare(ed);
2657 mtype.resolved = visitEnum(new TypeEnum(ed));
2658 break;
2660 case TOK.struct_:
2661 auto sd = new StructDeclaration(mtype.loc, mtype.id, false);
2662 sd.alignment = mtype.packalign;
2663 declare(sd);
2664 mtype.resolved = visitStruct(new TypeStruct(sd));
2665 break;
2667 case TOK.union_:
2668 auto ud = new UnionDeclaration(mtype.loc, mtype.id);
2669 ud.alignment = mtype.packalign;
2670 declare(ud);
2671 mtype.resolved = visitStruct(new TypeStruct(ud));
2672 break;
2674 default:
2675 assert(0);
2679 /* If it doesn't have a tag by now, supply one.
2680 * It'll be unique, and therefore introducing.
2681 * Declare it, and done.
2683 if (!mtype.id)
2685 mtype.id = Identifier.generateId("__tag"[]);
2686 declareTag();
2687 return returnType(mtype.resolved.addSTC(mtype.mod));
2690 /* look for pre-existing declaration
2692 Dsymbol scopesym;
2693 auto s = sc2.search(mtype.loc, mtype.id, scopesym, SearchOpt.ignoreErrors | SearchOpt.tagNameSpace);
2694 if (!s || s.isModule())
2696 // no pre-existing declaration, so declare it
2697 if (mtype.tok == TOK.enum_ && !mtype.members)
2698 .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
2699 declareTag();
2700 return returnType(mtype.resolved.addSTC(mtype.mod));
2703 /* A redeclaration only happens if both declarations are in
2704 * the same scope
2706 const bool redeclar = (scopesym == sc2.inner().scopesym);
2708 if (redeclar)
2710 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
2712 auto ed = s.isEnumDeclaration();
2713 if (mtype.members && ed.members)
2714 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
2715 else if (!ed.members)
2717 ed.members = mtype.members;
2719 else
2722 mtype.resolved = ed.type;
2724 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
2725 mtype.tok == TOK.struct_ && s.isStructDeclaration())
2727 // Add members to original declaration
2728 auto sd = s.isStructDeclaration();
2729 if (mtype.members && sd.members)
2731 /* struct S { int b; };
2732 * struct S { int a; } *s;
2734 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
2736 else if (!sd.members)
2738 /* struct S;
2739 * struct S { int a; } *s;
2741 sd.members = mtype.members;
2742 if (sd.semanticRun == PASS.semanticdone)
2744 /* The first semantic pass marked `sd` as an opaque struct.
2745 * Re-run semantic so that all newly assigned members are
2746 * picked up and added to the symtab.
2748 sd.semanticRun = PASS.semantic;
2749 sd.dsymbolSemantic(sc2);
2752 else
2754 /* struct S { int a; };
2755 * struct S *s;
2758 mtype.resolved = sd.type;
2760 else
2762 /* int S;
2763 * struct S { int a; } *s;
2765 .error(mtype.loc, "redeclaration of `%s`", mtype.id.toChars());
2766 mtype.resolved = error();
2769 else if (mtype.members)
2771 /* struct S;
2772 * { struct S { int a; } *s; }
2774 declareTag();
2776 else
2778 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
2780 mtype.resolved = s.isEnumDeclaration().type;
2782 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
2783 mtype.tok == TOK.struct_ && s.isStructDeclaration())
2785 /* struct S;
2786 * { struct S *s; }
2788 mtype.resolved = s.isStructDeclaration().type;
2790 else
2792 /* union S;
2793 * { struct S *s; }
2795 .error(mtype.loc, "redeclaring `%s %s` as `%s %s`",
2796 s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars());
2797 declareTag();
2800 return returnType(mtype.resolved.addSTC(mtype.mod));
2803 switch (type.ty)
2805 default: return visitType(type);
2806 case Tcomplex32:
2807 case Tcomplex64:
2808 case Tcomplex80: return visitComplex(type.isTypeBasic());
2809 case Tvector: return visitVector(type.isTypeVector());
2810 case Tsarray: return visitSArray(type.isTypeSArray());
2811 case Tarray: return visitDArray(type.isTypeDArray());
2812 case Taarray: return visitAArray(type.isTypeAArray());
2813 case Tpointer: return visitPointer(type.isTypePointer());
2814 case Treference: return visitReference(type.isTypeReference());
2815 case Tfunction: return visitFunction(type.isTypeFunction());
2816 case Tdelegate: return visitDelegate(type.isTypeDelegate());
2817 case Tident: return visitIdentifier(type.isTypeIdentifier());
2818 case Tinstance: return visitInstance(type.isTypeInstance());
2819 case Ttypeof: return visitTypeof(type.isTypeTypeof());
2820 case Ttraits: return visitTraits(type.isTypeTraits());
2821 case Treturn: return visitReturn(type.isTypeReturn());
2822 case Tstruct: return visitStruct(type.isTypeStruct());
2823 case Tenum: return visitEnum(type.isTypeEnum());
2824 case Tclass: return visitClass(type.isTypeClass());
2825 case Ttuple: return visitTuple(type.isTypeTuple());
2826 case Tslice: return visitSlice(type.isTypeSlice());
2827 case Tmixin: return visitMixin(type.isTypeMixin());
2828 case Ttag: return visitTag(type.isTypeTag());
2832 Type trySemantic(Type type, const ref Loc loc, Scope* sc)
2834 //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
2836 // Needed to display any deprecations that were gagged
2837 auto tcopy = type.syntaxCopy();
2839 const errors = global.startGagging();
2840 Type t = typeSemantic(type, loc, sc);
2841 if (global.endGagging(errors) || t.ty == Terror) // if any errors happened
2843 t = null;
2845 else
2847 // If `typeSemantic` succeeded, there may have been deprecations that
2848 // were gagged due the `startGagging` above. Run again to display
2849 // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
2850 if (global.gaggedWarnings > 0)
2851 typeSemantic(tcopy, loc, sc);
2853 //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
2854 return t;
2857 /************************************
2858 * If an identical type to `type` is in `type.stringtable`, return
2859 * the latter one. Otherwise, add it to `type.stringtable`.
2860 * Some types don't get merged and are returned as-is.
2861 * Params:
2862 * type = Type to check against existing types
2863 * Returns:
2864 * the type that was merged
2866 Type merge(Type type)
2868 switch (type.ty)
2870 case Terror:
2871 case Ttypeof:
2872 case Tident:
2873 case Tinstance:
2874 case Tmixin:
2875 case Ttag:
2876 return type; // don't merge placeholder types
2878 case Tsarray:
2879 // prevents generating the mangle if the array dim is not yet known
2880 if (!type.isTypeSArray().dim.isIntegerExp())
2881 return type;
2882 goto default;
2884 case Tenum:
2885 break;
2887 case Taarray:
2888 if (!type.isTypeAArray().index.merge().deco)
2889 return type;
2890 goto default;
2892 default:
2893 if (type.nextOf() && !type.nextOf().deco)
2894 return type;
2895 break;
2898 //printf("merge(%s)\n", toChars());
2899 if (!type.deco)
2901 OutBuffer buf;
2902 buf.reserve(32);
2904 mangleToBuffer(type, buf);
2906 auto sv = type.stringtable.update(buf[]);
2907 if (sv.value)
2909 Type t = sv.value;
2910 debug
2912 import core.stdc.stdio;
2913 if (!t.deco)
2914 printf("t = %s\n", t.toChars());
2916 assert(t.deco);
2917 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2918 return t;
2920 else
2922 Type t = stripDefaultArgs(type);
2923 sv.value = t;
2924 type.deco = t.deco = cast(char*)sv.toDchars();
2925 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2926 return t;
2929 return type;
2932 /*************************************
2933 * This version does a merge even if the deco is already computed.
2934 * Necessary for types that have a deco, but are not merged.
2936 Type merge2(Type type)
2938 //printf("merge2(%s)\n", toChars());
2939 Type t = type;
2940 assert(t);
2941 if (!t.deco)
2942 return t.merge();
2944 auto sv = Type.stringtable.lookup(t.deco, strlen(t.deco));
2945 if (sv && sv.value)
2947 t = sv.value;
2948 assert(t.deco);
2950 else
2951 assert(0);
2952 return t;
2955 /***************************************
2956 * Calculate built-in properties which just the type is necessary.
2958 * Params:
2959 * t = the type for which the property is calculated
2960 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2961 * loc = the location where the property is encountered
2962 * ident = the identifier of the property
2963 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2964 * src = expression for type `t` or null.
2965 * Returns:
2966 * expression representing the property, or null if not a property and (flag & 1)
2968 Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag,
2969 Expression src = null)
2971 Expression visitType(Type mt)
2973 Expression e;
2974 static if (LOGDOTEXP)
2976 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2978 if (ident == Id.__sizeof)
2980 const sz = mt.size(loc);
2981 if (sz == SIZE_INVALID)
2982 return ErrorExp.get();
2983 e = new IntegerExp(loc, sz, Type.tsize_t);
2985 else if (ident == Id.__xalignof)
2987 const explicitAlignment = mt.alignment();
2988 const naturalAlignment = mt.alignsize();
2989 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
2990 e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
2992 else if (ident == Id._init)
2994 Type tb = mt.toBasetype();
2995 e = mt.defaultInitLiteral(loc);
2996 if (tb.ty == Tstruct && tb.needsNested())
2998 e.isStructLiteralExp().useStaticInit = true;
3001 else if (ident == Id._mangleof)
3003 if (!mt.deco)
3005 error(loc, "forward reference of type `%s.mangleof`", mt.toChars());
3006 e = ErrorExp.get();
3008 else
3010 e = new StringExp(loc, mt.deco.toDString());
3011 Scope sc;
3012 sc.eSink = global.errorSink;
3013 e = e.expressionSemantic(&sc);
3016 else if (ident == Id.stringof)
3018 const s = mt.toChars();
3019 e = new StringExp(loc, s.toDString());
3020 Scope sc;
3021 sc.eSink = global.errorSink;
3022 e = e.expressionSemantic(&sc);
3024 else if (flag && mt != Type.terror)
3026 return null;
3028 else
3030 Dsymbol s = null;
3031 if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
3032 s = mt.toDsymbol(null);
3033 if (s)
3034 s = s.search_correct(ident);
3035 if (s && !symbolIsVisible(scope_, s))
3036 s = null;
3037 if (mt != Type.terror)
3039 if (s)
3040 error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
3041 else if (ident == Id.call && mt.ty == Tclass)
3042 error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
3044 else if (const n = importHint(ident.toString()))
3045 error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
3046 else
3048 if (src)
3049 error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true));
3050 else
3051 error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
3053 if (auto dsym = mt.toDsymbol(scope_))
3055 if (auto sym = dsym.isAggregateDeclaration())
3057 if (auto fd = search_function(sym, Id.opDispatch))
3058 errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
3059 else if (!sym.members)
3060 errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
3062 errorSupplemental(dsym.loc, "%s `%s` defined here",
3063 dsym.kind, dsym.toChars());
3067 e = ErrorExp.get();
3069 return e;
3072 Expression visitError(TypeError)
3074 return ErrorExp.get();
3077 Expression visitBasic(TypeBasic mt)
3079 Expression integerValue(dinteger_t i)
3081 return new IntegerExp(loc, i, mt);
3084 Expression intValue(dinteger_t i)
3086 return new IntegerExp(loc, i, Type.tint32);
3089 Expression floatValue(real_t r)
3091 if (mt.isreal() || mt.isimaginary())
3092 return new RealExp(loc, r, mt);
3093 else
3095 return new ComplexExp(loc, complex_t(r, r), mt);
3099 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
3100 if (ident == Id.max)
3102 switch (mt.ty)
3104 case Tint8: return integerValue(byte.max);
3105 case Tuns8: return integerValue(ubyte.max);
3106 case Tint16: return integerValue(short.max);
3107 case Tuns16: return integerValue(ushort.max);
3108 case Tint32: return integerValue(int.max);
3109 case Tuns32: return integerValue(uint.max);
3110 case Tint64: return integerValue(long.max);
3111 case Tuns64: return integerValue(ulong.max);
3112 case Tbool: return integerValue(bool.max);
3113 case Tchar: return integerValue(char.max);
3114 case Twchar: return integerValue(wchar.max);
3115 case Tdchar: return integerValue(dchar.max);
3116 case Tcomplex32:
3117 case Timaginary32:
3118 case Tfloat32: return floatValue(target.FloatProperties.max);
3119 case Tcomplex64:
3120 case Timaginary64:
3121 case Tfloat64: return floatValue(target.DoubleProperties.max);
3122 case Tcomplex80:
3123 case Timaginary80:
3124 case Tfloat80: return floatValue(target.RealProperties.max);
3125 default: break;
3128 else if (ident == Id.min)
3130 switch (mt.ty)
3132 case Tint8: return integerValue(byte.min);
3133 case Tuns8:
3134 case Tuns16:
3135 case Tuns32:
3136 case Tuns64:
3137 case Tbool:
3138 case Tchar:
3139 case Twchar:
3140 case Tdchar: return integerValue(0);
3141 case Tint16: return integerValue(short.min);
3142 case Tint32: return integerValue(int.min);
3143 case Tint64: return integerValue(long.min);
3144 default: break;
3147 else if (ident == Id.min_normal)
3149 switch (mt.ty)
3151 case Tcomplex32:
3152 case Timaginary32:
3153 case Tfloat32: return floatValue(target.FloatProperties.min_normal);
3154 case Tcomplex64:
3155 case Timaginary64:
3156 case Tfloat64: return floatValue(target.DoubleProperties.min_normal);
3157 case Tcomplex80:
3158 case Timaginary80:
3159 case Tfloat80: return floatValue(target.RealProperties.min_normal);
3160 default: break;
3163 else if (ident == Id.nan)
3165 switch (mt.ty)
3167 case Tcomplex32:
3168 case Tcomplex64:
3169 case Tcomplex80:
3170 case Timaginary32:
3171 case Timaginary64:
3172 case Timaginary80:
3173 case Tfloat32:
3174 case Tfloat64:
3175 case Tfloat80: return floatValue(target.RealProperties.nan);
3176 default: break;
3179 else if (ident == Id.infinity)
3181 switch (mt.ty)
3183 case Tcomplex32:
3184 case Tcomplex64:
3185 case Tcomplex80:
3186 case Timaginary32:
3187 case Timaginary64:
3188 case Timaginary80:
3189 case Tfloat32:
3190 case Tfloat64:
3191 case Tfloat80: return floatValue(target.RealProperties.infinity);
3192 default: break;
3195 else if (ident == Id.dig)
3197 switch (mt.ty)
3199 case Tcomplex32:
3200 case Timaginary32:
3201 case Tfloat32: return intValue(target.FloatProperties.dig);
3202 case Tcomplex64:
3203 case Timaginary64:
3204 case Tfloat64: return intValue(target.DoubleProperties.dig);
3205 case Tcomplex80:
3206 case Timaginary80:
3207 case Tfloat80: return intValue(target.RealProperties.dig);
3208 default: break;
3211 else if (ident == Id.epsilon)
3213 switch (mt.ty)
3215 case Tcomplex32:
3216 case Timaginary32:
3217 case Tfloat32: return floatValue(target.FloatProperties.epsilon);
3218 case Tcomplex64:
3219 case Timaginary64:
3220 case Tfloat64: return floatValue(target.DoubleProperties.epsilon);
3221 case Tcomplex80:
3222 case Timaginary80:
3223 case Tfloat80: return floatValue(target.RealProperties.epsilon);
3224 default: break;
3227 else if (ident == Id.mant_dig)
3229 switch (mt.ty)
3231 case Tcomplex32:
3232 case Timaginary32:
3233 case Tfloat32: return intValue(target.FloatProperties.mant_dig);
3234 case Tcomplex64:
3235 case Timaginary64:
3236 case Tfloat64: return intValue(target.DoubleProperties.mant_dig);
3237 case Tcomplex80:
3238 case Timaginary80:
3239 case Tfloat80: return intValue(target.RealProperties.mant_dig);
3240 default: break;
3243 else if (ident == Id.max_10_exp)
3245 switch (mt.ty)
3247 case Tcomplex32:
3248 case Timaginary32:
3249 case Tfloat32: return intValue(target.FloatProperties.max_10_exp);
3250 case Tcomplex64:
3251 case Timaginary64:
3252 case Tfloat64: return intValue(target.DoubleProperties.max_10_exp);
3253 case Tcomplex80:
3254 case Timaginary80:
3255 case Tfloat80: return intValue(target.RealProperties.max_10_exp);
3256 default: break;
3259 else if (ident == Id.max_exp)
3261 switch (mt.ty)
3263 case Tcomplex32:
3264 case Timaginary32:
3265 case Tfloat32: return intValue(target.FloatProperties.max_exp);
3266 case Tcomplex64:
3267 case Timaginary64:
3268 case Tfloat64: return intValue(target.DoubleProperties.max_exp);
3269 case Tcomplex80:
3270 case Timaginary80:
3271 case Tfloat80: return intValue(target.RealProperties.max_exp);
3272 default: break;
3275 else if (ident == Id.min_10_exp)
3277 switch (mt.ty)
3279 case Tcomplex32:
3280 case Timaginary32:
3281 case Tfloat32: return intValue(target.FloatProperties.min_10_exp);
3282 case Tcomplex64:
3283 case Timaginary64:
3284 case Tfloat64: return intValue(target.DoubleProperties.min_10_exp);
3285 case Tcomplex80:
3286 case Timaginary80:
3287 case Tfloat80: return intValue(target.RealProperties.min_10_exp);
3288 default: break;
3291 else if (ident == Id.min_exp)
3293 switch (mt.ty)
3295 case Tcomplex32:
3296 case Timaginary32:
3297 case Tfloat32: return intValue(target.FloatProperties.min_exp);
3298 case Tcomplex64:
3299 case Timaginary64:
3300 case Tfloat64: return intValue(target.DoubleProperties.min_exp);
3301 case Tcomplex80:
3302 case Timaginary80:
3303 case Tfloat80: return intValue(target.RealProperties.min_exp);
3304 default: break;
3307 return visitType(mt);
3310 Expression visitVector(TypeVector mt)
3312 return visitType(mt);
3315 Expression visitEnum(TypeEnum mt)
3317 Expression e;
3318 if (ident == Id.max || ident == Id.min)
3320 return mt.sym.getMaxMinValue(loc, ident);
3322 else if (ident == Id._init)
3324 e = mt.defaultInitLiteral(loc);
3326 else if (ident == Id.stringof)
3328 e = new StringExp(loc, mt.toString());
3329 Scope sc;
3330 e = e.expressionSemantic(&sc);
3332 else if (ident == Id._mangleof)
3334 e = visitType(mt);
3336 else
3338 e = mt.toBasetype().getProperty(scope_, loc, ident, flag);
3340 return e;
3343 Expression visitTuple(TypeTuple mt)
3345 Expression e;
3346 static if (LOGDOTEXP)
3348 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
3350 if (ident == Id.length)
3352 e = new IntegerExp(loc, mt.arguments.length, Type.tsize_t);
3354 else if (ident == Id._init)
3356 e = mt.defaultInitLiteral(loc);
3358 else if (flag)
3360 e = null;
3362 else
3364 error(loc, "no property `%s` for sequence `%s`", ident.toChars(), mt.toChars());
3365 e = ErrorExp.get();
3367 return e;
3370 switch (t.ty)
3372 default: return t.isTypeBasic() ?
3373 visitBasic(cast(TypeBasic)t) :
3374 visitType(t);
3376 case Terror: return visitError (t.isTypeError());
3377 case Tvector: return visitVector(t.isTypeVector());
3378 case Tenum: return visitEnum (t.isTypeEnum());
3379 case Ttuple: return visitTuple (t.isTypeTuple());
3383 /***************************************
3384 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
3385 * Params:
3386 * exp = Expression to look at
3387 * t = if exp should be a Type, set t to that Type else null
3388 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
3389 * e = if exp should remain an Expression, set e to that Expression else null
3392 private void resolveExp(Expression exp, out Type t, out Expression e, out Dsymbol s)
3394 if (exp.isTypeExp())
3395 t = exp.type;
3396 else if (auto ve = exp.isVarExp())
3398 if (auto v = ve.var.isVarDeclaration())
3399 e = exp;
3400 else
3401 s = ve.var;
3403 else if (auto te = exp.isTemplateExp())
3404 s = te.td;
3405 else if (auto se = exp.isScopeExp())
3406 s = se.sds;
3407 else if (exp.isFuncExp())
3408 s = getDsymbol(exp);
3409 else if (auto dte = exp.isDotTemplateExp())
3410 s = dte.td;
3411 else if (exp.isErrorExp())
3412 t = Type.terror;
3413 else
3414 e = exp;
3417 /************************************
3418 * Resolve type 'mt' to either type, symbol, or expression.
3419 * If errors happened, resolved to Type.terror.
3421 * Params:
3422 * mt = type to be resolved
3423 * loc = the location where the type is encountered
3424 * sc = the scope of the type
3425 * pe = is set if t is an expression
3426 * pt = is set if t is a type
3427 * ps = is set if t is a symbol
3428 * intypeid = true if in type id
3430 void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
3432 void returnExp(Expression e)
3434 pe = e;
3435 pt = null;
3436 ps = null;
3439 void returnType(Type t)
3441 pe = null;
3442 pt = t;
3443 ps = null;
3446 void returnSymbol(Dsymbol s)
3448 pe = null;
3449 pt = null;
3450 ps = s;
3453 void returnError()
3455 returnType(Type.terror);
3458 void visitType(Type mt)
3460 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
3461 Type t = typeSemantic(mt, loc, sc);
3462 assert(t);
3463 returnType(t);
3466 void visitSArray(TypeSArray mt)
3468 //printf("TypeSArray::resolve() %s\n", mt.toChars());
3469 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
3470 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
3471 if (pe)
3473 // It's really an index expression
3474 if (Dsymbol s = getDsymbol(pe))
3475 pe = new DsymbolExp(loc, s);
3476 returnExp(new ArrayExp(loc, pe, mt.dim));
3478 else if (ps)
3480 Dsymbol s = ps;
3481 if (auto tup = s.isTupleDeclaration())
3483 mt.dim = semanticLength(sc, tup, mt.dim);
3484 mt.dim = mt.dim.ctfeInterpret();
3485 if (mt.dim.op == EXP.error)
3486 return returnError();
3488 const d = mt.dim.toUInteger();
3489 if (d >= tup.objects.length)
3491 error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong) tup.objects.length);
3492 return returnError();
3495 RootObject o = (*tup.objects)[cast(size_t)d];
3496 switch (o.dyncast()) with (DYNCAST)
3498 case dsymbol:
3499 return returnSymbol(cast(Dsymbol)o);
3500 case expression:
3501 Expression e = cast(Expression)o;
3502 if (e.op == EXP.dSymbol)
3503 return returnSymbol(e.isDsymbolExp().s);
3504 else
3505 return returnExp(e);
3506 case type:
3507 return returnType((cast(Type)o).addMod(mt.mod));
3508 default:
3509 break;
3512 /* Create a new TupleDeclaration which
3513 * is a slice [d..d+1] out of the old one.
3514 * Do it this way because TemplateInstance::semanticTiargs()
3515 * can handle unresolved Objects this way.
3517 auto objects = new Objects(1);
3518 (*objects)[0] = o;
3519 return returnSymbol(new TupleDeclaration(loc, tup.ident, objects));
3521 else
3522 return visitType(mt);
3524 else
3526 if (pt.ty != Terror)
3527 mt.next = pt; // prevent re-running semantic() on 'next'
3528 visitType(mt);
3533 void visitDArray(TypeDArray mt)
3535 //printf("TypeDArray::resolve() %s\n", mt.toChars());
3536 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
3537 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
3538 if (pe)
3540 // It's really a slice expression
3541 if (Dsymbol s = getDsymbol(pe))
3542 pe = new DsymbolExp(loc, s);
3543 returnExp(new ArrayExp(loc, pe));
3545 else if (ps)
3547 if (auto tup = ps.isTupleDeclaration())
3549 // keep ps
3551 else
3552 visitType(mt);
3554 else
3556 if (pt.ty != Terror)
3557 mt.next = pt; // prevent re-running semantic() on 'next'
3558 visitType(mt);
3562 void visitAArray(TypeAArray mt)
3564 //printf("TypeAArray::resolve() %s\n", mt.toChars());
3565 // Deal with the case where we thought the index was a type, but
3566 // in reality it was an expression.
3567 if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray)
3569 Expression e;
3570 Type t;
3571 Dsymbol s;
3572 mt.index.resolve(loc, sc, e, t, s, intypeid);
3573 if (e)
3575 // It was an expression -
3576 // Rewrite as a static array
3577 auto tsa = new TypeSArray(mt.next, e);
3578 tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done
3579 return tsa.resolve(loc, sc, pe, pt, ps, intypeid);
3581 else if (t)
3582 mt.index = t;
3583 else
3584 .error(loc, "index is not a type or an expression");
3586 visitType(mt);
3589 /*************************************
3590 * Takes an array of Identifiers and figures out if
3591 * it represents a Type or an Expression.
3592 * Output:
3593 * if expression, pe is set
3594 * if type, pt is set
3596 void visitIdentifier(TypeIdentifier mt)
3598 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3599 if (mt.ident == Id.ctfe)
3601 error(loc, "variable `__ctfe` cannot be read at compile time");
3602 return returnError();
3604 if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h
3606 /* Since we don't support __builtin_va_start, -arg, -end, we don't
3607 * have to actually care what -list is. A void* will do.
3608 * If we ever do care, import core.stdc.stdarg and pull
3609 * the definition out of that, similarly to how std.math is handled for PowExp
3611 pt = target.va_listType(loc, sc);
3612 return;
3615 Dsymbol scopesym;
3616 Dsymbol s = sc.search(loc, mt.ident, scopesym);
3618 * https://issues.dlang.org/show_bug.cgi?id=1170
3619 * https://issues.dlang.org/show_bug.cgi?id=10739
3621 * If a symbol is not found, it might be declared in
3622 * a mixin-ed string or a mixin-ed template, so before
3623 * issuing an error semantically analyze all string/template
3624 * mixins that are members of the current ScopeDsymbol.
3626 if (!s && sc.enclosing)
3628 ScopeDsymbol sds = sc.enclosing.scopesym;
3629 if (sds && sds.members)
3631 void semanticOnMixin(Dsymbol member)
3633 if (auto compileDecl = member.isMixinDeclaration())
3634 compileDecl.dsymbolSemantic(sc);
3635 else if (auto mixinTempl = member.isTemplateMixin())
3636 mixinTempl.dsymbolSemantic(sc);
3638 sds.members.foreachDsymbol( s => semanticOnMixin(s) );
3639 s = sc.search(loc, mt.ident, scopesym);
3643 if (s)
3645 // https://issues.dlang.org/show_bug.cgi?id=16042
3646 // If `f` is really a function template, then replace `f`
3647 // with the function template declaration.
3648 if (auto f = s.isFuncDeclaration())
3650 if (auto td = getFuncTemplateDecl(f))
3652 // If not at the beginning of the overloaded list of
3653 // `TemplateDeclaration`s, then get the beginning
3654 if (td.overroot)
3655 td = td.overroot;
3656 s = td;
3661 mt.resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
3662 if (pt)
3663 pt = pt.addMod(mt.mod);
3666 void visitInstance(TypeInstance mt)
3668 // Note close similarity to TypeIdentifier::resolve()
3670 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
3671 mt.tempinst.dsymbolSemantic(sc);
3672 if (!global.gag && mt.tempinst.errors)
3673 return returnError();
3675 mt.resolveHelper(loc, sc, mt.tempinst, null, pe, pt, ps, intypeid);
3676 if (pt)
3677 pt = pt.addMod(mt.mod);
3678 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
3681 void visitTypeof(TypeTypeof mt)
3683 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
3684 //static int nest; if (++nest == 50) *(char*)0=0;
3685 if (sc is null)
3687 error(loc, "invalid scope");
3688 return returnError();
3690 if (mt.inuse)
3692 mt.inuse = 2;
3693 error(loc, "circular `typeof` definition");
3694 Lerr:
3695 mt.inuse--;
3696 return returnError();
3698 mt.inuse++;
3700 /* Currently we cannot evaluate 'exp' in speculative context, because
3701 * the type implementation may leak to the final execution. Consider:
3703 * struct S(T) {
3704 * string toString() const { return "x"; }
3706 * void main() {
3707 * alias X = typeof(S!int());
3708 * assert(typeid(X).toString() == "x");
3711 Scope* sc2 = sc.push();
3713 if (!mt.exp.isTypeidExp())
3714 /* Treat typeof(typeid(exp)) as needing
3715 * the full semantic analysis of the typeid.
3716 * https://issues.dlang.org/show_bug.cgi?id=20958
3718 sc2.intypeof = 1;
3720 auto exp2 = mt.exp.expressionSemantic(sc2);
3721 exp2 = resolvePropertiesOnly(sc2, exp2);
3722 sc2.pop();
3724 if (exp2.op == EXP.error)
3726 if (!global.gag)
3727 mt.exp = exp2;
3728 goto Lerr;
3730 mt.exp = exp2;
3732 if ((mt.exp.op == EXP.type || mt.exp.op == EXP.scope_) &&
3733 // https://issues.dlang.org/show_bug.cgi?id=23863
3734 // compile time sequences are valid types
3735 !mt.exp.type.isTypeTuple())
3737 if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof
3738 mt.exp.checkType())
3739 goto Lerr;
3741 /* Today, 'typeof(func)' returns void if func is a
3742 * function template (TemplateExp), or
3743 * template lambda (FuncExp).
3744 * It's actually used in Phobos as an idiom, to branch code for
3745 * template functions.
3748 if (auto f = mt.exp.op == EXP.variable ? mt.exp.isVarExp().var.isFuncDeclaration()
3749 : mt.exp.op == EXP.dotVariable ? mt.exp.isDotVarExp().var.isFuncDeclaration() : null)
3751 // f might be a unittest declaration which is incomplete when compiled
3752 // without -unittest. That causes a segfault in checkForwardRef, see
3753 // https://issues.dlang.org/show_bug.cgi?id=20626
3754 if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && checkForwardRef(f, loc))
3755 goto Lerr;
3757 if (auto f = isFuncAddress(mt.exp))
3759 if (checkForwardRef(f, loc))
3760 goto Lerr;
3763 Type t = mt.exp.type;
3764 if (!t)
3766 error(loc, "expression `%s` has no type", mt.exp.toChars());
3767 goto Lerr;
3769 if (t.ty == Ttypeof)
3771 error(loc, "forward reference to `%s`", mt.toChars());
3772 goto Lerr;
3774 if (mt.idents.length == 0)
3776 returnType(t.addMod(mt.mod));
3778 else
3780 if (Dsymbol s = t.toDsymbol(sc))
3781 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
3782 else
3784 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
3785 e = e.expressionSemantic(sc);
3786 resolveExp(e, pt, pe, ps);
3788 if (pt)
3789 pt = pt.addMod(mt.mod);
3791 mt.inuse--;
3794 void visitReturn(TypeReturn mt)
3796 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3797 Type t;
3799 FuncDeclaration func = sc.func;
3800 if (!func)
3802 error(loc, "`typeof(return)` must be inside function");
3803 return returnError();
3805 if (func.fes)
3806 func = func.fes.func;
3807 t = func.type.nextOf();
3808 if (!t)
3810 error(loc, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc.func.toChars());
3811 return returnError();
3814 if (mt.idents.length == 0)
3816 return returnType(t.addMod(mt.mod));
3818 else
3820 if (Dsymbol s = t.toDsymbol(sc))
3821 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
3822 else
3824 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
3825 e = e.expressionSemantic(sc);
3826 resolveExp(e, pt, pe, ps);
3828 if (pt)
3829 pt = pt.addMod(mt.mod);
3833 void visitSlice(TypeSlice mt)
3835 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
3836 if (pe)
3838 // It's really a slice expression
3839 if (Dsymbol s = getDsymbol(pe))
3840 pe = new DsymbolExp(loc, s);
3841 return returnExp(new ArrayExp(loc, pe, new IntervalExp(loc, mt.lwr, mt.upr)));
3843 else if (ps)
3845 Dsymbol s = ps;
3846 TupleDeclaration td = s.isTupleDeclaration();
3847 if (td)
3849 /* It's a slice of a TupleDeclaration
3851 ScopeDsymbol sym = new ArrayScopeSymbol(sc, td);
3852 sym.parent = sc.scopesym;
3853 sc = sc.push(sym);
3854 sc = sc.startCTFE();
3855 mt.lwr = mt.lwr.expressionSemantic(sc);
3856 mt.upr = mt.upr.expressionSemantic(sc);
3857 sc = sc.endCTFE();
3858 sc = sc.pop();
3860 mt.lwr = mt.lwr.ctfeInterpret();
3861 mt.upr = mt.upr.ctfeInterpret();
3862 const i1 = mt.lwr.toUInteger();
3863 const i2 = mt.upr.toUInteger();
3864 if (!(i1 <= i2 && i2 <= td.objects.length))
3866 error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1, i2, cast(ulong) td.objects.length);
3867 return returnError();
3870 if (i1 == 0 && i2 == td.objects.length)
3872 return returnSymbol(td);
3875 /* Create a new TupleDeclaration which
3876 * is a slice [i1..i2] out of the old one.
3878 auto objects = new Objects(cast(size_t)(i2 - i1));
3879 for (size_t i = 0; i < objects.length; i++)
3881 (*objects)[i] = (*td.objects)[cast(size_t)i1 + i];
3884 return returnSymbol(new TupleDeclaration(loc, td.ident, objects));
3886 else
3887 visitType(mt);
3889 else
3891 if (pt.ty != Terror)
3892 mt.next = pt; // prevent re-running semantic() on 'next'
3893 visitType(mt);
3897 void visitMixin(TypeMixin mt)
3899 RootObject o = mt.obj;
3901 // if already resolved just set pe/pt/ps and return.
3902 if (o)
3904 pe = o.isExpression();
3905 pt = o.isType();
3906 ps = o.isDsymbol();
3907 return;
3910 o = mt.compileTypeMixin(loc, sc);
3911 if (auto t = o.isType())
3913 resolve(t, loc, sc, pe, pt, ps, intypeid);
3914 if (pt)
3915 pt = pt.addMod(mt.mod);
3917 else if (auto e = o.isExpression())
3919 e = e.expressionSemantic(sc);
3920 if (auto et = e.isTypeExp())
3921 returnType(et.type.addMod(mt.mod));
3922 else
3923 returnExp(e);
3925 else
3926 returnError();
3928 // save the result
3929 mt.obj = pe ? pe : (pt ? pt : ps);
3932 void visitTraits(TypeTraits mt)
3934 // if already resolved just return the cached object.
3935 if (mt.obj)
3937 pt = mt.obj.isType();
3938 ps = mt.obj.isDsymbol();
3939 pe = mt.obj.isExpression();
3940 return;
3943 import dmd.traits : semanticTraits;
3945 if (Expression e = semanticTraits(mt.exp, sc))
3947 switch (e.op)
3949 case EXP.dotVariable:
3950 mt.obj = e.isDotVarExp().var;
3951 break;
3952 case EXP.variable:
3953 mt.obj = e.isVarExp().var;
3954 break;
3955 case EXP.function_:
3956 auto fe = e.isFuncExp();
3957 mt.obj = fe.td ? fe.td : fe.fd;
3958 break;
3959 case EXP.dotTemplateDeclaration:
3960 mt.obj = e.isDotTemplateExp().td;
3961 break;
3962 case EXP.dSymbol:
3963 mt.obj = e.isDsymbolExp().s;
3964 break;
3965 case EXP.template_:
3966 mt.obj = e.isTemplateExp().td;
3967 break;
3968 case EXP.scope_:
3969 mt.obj = e.isScopeExp().sds;
3970 break;
3971 case EXP.tuple:
3972 TupleExp te = e.isTupleExp();
3973 Objects* elems = new Objects(te.exps.length);
3974 foreach (i; 0 .. elems.length)
3976 auto src = (*te.exps)[i];
3977 switch (src.op)
3979 case EXP.type:
3980 (*elems)[i] = src.isTypeExp().type;
3981 break;
3982 case EXP.dotType:
3983 (*elems)[i] = src.isDotTypeExp().sym.isType();
3984 break;
3985 case EXP.overloadSet:
3986 (*elems)[i] = src.isOverExp().type;
3987 break;
3988 default:
3989 if (auto sym = isDsymbol(src))
3990 (*elems)[i] = sym;
3991 else
3992 (*elems)[i] = src;
3995 TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
3996 mt.obj = td;
3997 break;
3998 case EXP.dotType:
3999 mt.obj = e.isDotTypeExp().sym.isType();
4000 break;
4001 case EXP.type:
4002 mt.obj = e.isTypeExp().type;
4003 break;
4004 case EXP.overloadSet:
4005 mt.obj = e.isOverExp().type;
4006 break;
4007 case EXP.error:
4008 break;
4009 default:
4010 mt.obj = e;
4011 break;
4015 if (mt.obj)
4017 if (auto t = mt.obj.isType())
4019 t = t.addMod(mt.mod);
4020 mt.obj = t;
4021 returnType(t);
4023 else if (auto s = mt.obj.isDsymbol())
4024 returnSymbol(s);
4025 else if (auto e = mt.obj.isExpression())
4026 returnExp(e);
4028 else
4030 assert(global.errors);
4031 mt.obj = Type.terror;
4032 return returnError();
4036 switch (mt.ty)
4038 default: visitType (mt); break;
4039 case Tsarray: visitSArray (mt.isTypeSArray()); break;
4040 case Tarray: visitDArray (mt.isTypeDArray()); break;
4041 case Taarray: visitAArray (mt.isTypeAArray()); break;
4042 case Tident: visitIdentifier(mt.isTypeIdentifier()); break;
4043 case Tinstance: visitInstance (mt.isTypeInstance()); break;
4044 case Ttypeof: visitTypeof (mt.isTypeTypeof()); break;
4045 case Treturn: visitReturn (mt.isTypeReturn()); break;
4046 case Tslice: visitSlice (mt.isTypeSlice()); break;
4047 case Tmixin: visitMixin (mt.isTypeMixin()); break;
4048 case Ttraits: visitTraits (mt.isTypeTraits()); break;
4052 /************************
4053 * Access the members of the object e. This type is same as e.type.
4054 * Params:
4055 * mt = type for which the dot expression is used
4056 * sc = instantiating scope
4057 * e = expression to convert
4058 * ident = identifier being used
4059 * flag = DotExpFlag bit flags
4061 * Returns:
4062 * resulting expression with e.ident resolved
4064 Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag)
4066 Expression visitType(Type mt)
4068 VarDeclaration v = null;
4069 static if (LOGDOTEXP)
4071 printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4073 Expression ex = e.lastComma();
4074 if (ex.op == EXP.dotVariable)
4076 DotVarExp dv = cast(DotVarExp)ex;
4077 v = dv.var.isVarDeclaration();
4079 else if (ex.op == EXP.variable)
4081 VarExp ve = cast(VarExp)ex;
4082 v = ve.var.isVarDeclaration();
4084 if (v)
4086 if (ident == Id.offsetof)
4088 v.dsymbolSemantic(null);
4089 if (v.isField())
4091 auto ad = v.isMember();
4092 objc.checkOffsetof(e, ad);
4093 ad.size(e.loc);
4094 if (ad.sizeok != Sizeok.done)
4095 return ErrorExp.get();
4096 return new IntegerExp(e.loc, v.offset, Type.tsize_t);
4099 else if (ident == Id._init)
4101 Type tb = mt.toBasetype();
4102 e = mt.defaultInitLiteral(e.loc);
4103 if (tb.ty == Tstruct && tb.needsNested())
4105 e.isStructLiteralExp().useStaticInit = true;
4107 goto Lreturn;
4110 if (ident == Id.stringof)
4112 /* https://issues.dlang.org/show_bug.cgi?id=3796
4113 * this should demangle e.type.deco rather than
4114 * pretty-printing the type.
4116 e = new StringExp(e.loc, e.toString());
4118 else
4119 e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag);
4121 Lreturn:
4122 if (e)
4123 e = e.expressionSemantic(sc);
4124 return e;
4127 Expression visitError(TypeError)
4129 return ErrorExp.get();
4132 Expression visitBasic(TypeBasic mt)
4134 static if (LOGDOTEXP)
4136 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4138 Type t;
4139 if (ident == Id.re)
4141 switch (mt.ty)
4143 case Tcomplex32:
4144 t = mt.tfloat32;
4145 goto L1;
4147 case Tcomplex64:
4148 t = mt.tfloat64;
4149 goto L1;
4151 case Tcomplex80:
4152 t = mt.tfloat80;
4153 goto L1;
4155 e = e.castTo(sc, t);
4156 break;
4158 case Tfloat32:
4159 case Tfloat64:
4160 case Tfloat80:
4161 break;
4163 case Timaginary32:
4164 t = mt.tfloat32;
4165 goto L2;
4167 case Timaginary64:
4168 t = mt.tfloat64;
4169 goto L2;
4171 case Timaginary80:
4172 t = mt.tfloat80;
4173 goto L2;
4175 e = new RealExp(e.loc, CTFloat.zero, t);
4176 break;
4178 default:
4179 e = mt.Type.getProperty(sc, e.loc, ident, flag);
4180 break;
4183 else if (ident == Id.im)
4185 Type t2;
4186 switch (mt.ty)
4188 case Tcomplex32:
4189 t = mt.timaginary32;
4190 t2 = mt.tfloat32;
4191 goto L3;
4193 case Tcomplex64:
4194 t = mt.timaginary64;
4195 t2 = mt.tfloat64;
4196 goto L3;
4198 case Tcomplex80:
4199 t = mt.timaginary80;
4200 t2 = mt.tfloat80;
4201 goto L3;
4203 e = e.castTo(sc, t);
4204 e.type = t2;
4205 break;
4207 case Timaginary32:
4208 t = mt.tfloat32;
4209 goto L4;
4211 case Timaginary64:
4212 t = mt.tfloat64;
4213 goto L4;
4215 case Timaginary80:
4216 t = mt.tfloat80;
4217 goto L4;
4219 e = e.copy();
4220 e.type = t;
4221 break;
4223 case Tfloat32:
4224 case Tfloat64:
4225 case Tfloat80:
4226 e = new RealExp(e.loc, CTFloat.zero, mt);
4227 break;
4229 default:
4230 e = mt.Type.getProperty(sc, e.loc, ident, flag);
4231 break;
4234 else
4236 return visitType(mt);
4238 if (!(flag & 1) || e)
4239 e = e.expressionSemantic(sc);
4240 return e;
4243 Expression visitVector(TypeVector mt)
4245 static if (LOGDOTEXP)
4247 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4249 if (ident == Id.ptr && e.op == EXP.call)
4251 /* The trouble with EXP.call is the return ABI for float[4] is different from
4252 * __vector(float[4]), and a type paint won't do.
4254 e = new AddrExp(e.loc, e);
4255 e = e.expressionSemantic(sc);
4256 return e.castTo(sc, mt.basetype.nextOf().pointerTo());
4258 if (ident == Id.array)
4260 //e = e.castTo(sc, basetype);
4261 // Keep lvalue-ness
4262 e = new VectorArrayExp(e.loc, e);
4263 e = e.expressionSemantic(sc);
4264 return e;
4266 if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof)
4268 // init should return a new VectorExp
4269 // https://issues.dlang.org/show_bug.cgi?id=12776
4270 // offsetof does not work on a cast expression, so use e directly
4271 // stringof should not add a cast to the output
4272 return visitType(mt);
4275 // Properties based on the vector element type and are values of the element type
4276 if (ident == Id.max || ident == Id.min || ident == Id.min_normal ||
4277 ident == Id.nan || ident == Id.infinity || ident == Id.epsilon)
4279 auto vet = mt.basetype.isTypeSArray().next; // vector element type
4280 if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag))
4281 return ev.castTo(sc, mt); // 'broadcast' ev to the vector elements
4284 return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag);
4287 Expression visitArray(TypeArray mt)
4289 static if (LOGDOTEXP)
4291 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4294 e = visitType(mt);
4296 if (!(flag & 1) || e)
4297 e = e.expressionSemantic(sc);
4298 return e;
4301 Expression visitSArray(TypeSArray mt)
4303 static if (LOGDOTEXP)
4305 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4307 if (ident == Id.length)
4309 Loc oldLoc = e.loc;
4310 e = mt.dim.copy();
4311 e.loc = oldLoc;
4313 else if (ident == Id.ptr)
4315 if (e.op == EXP.type)
4317 error(e.loc, "`%s` is not an expression", e.toChars());
4318 return ErrorExp.get();
4320 else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
4322 // .ptr on static array is @safe unless size is 0
4323 // https://issues.dlang.org/show_bug.cgi?id=20853
4324 return ErrorExp.get();
4326 e = e.castTo(sc, e.type.nextOf().pointerTo());
4328 else if (ident == Id._tupleof)
4330 if (e.isTypeExp())
4332 error(e.loc, "`.tupleof` cannot be used on type `%s`", mt.toChars);
4333 return ErrorExp.get();
4335 else
4337 Expression e0;
4338 Expression ev = e;
4339 ev = extractSideEffect(sc, "__tup", e0, ev);
4341 const length = cast(size_t)mt.dim.toUInteger();
4342 auto exps = new Expressions();
4343 exps.reserve(length);
4344 foreach (i; 0 .. length)
4345 exps.push(new IndexExp(e.loc, ev, new IntegerExp(e.loc, i, Type.tsize_t)));
4346 e = new TupleExp(e.loc, e0, exps);
4349 else
4351 e = visitArray(mt);
4353 if (!(flag & 1) || e)
4354 e = e.expressionSemantic(sc);
4355 return e;
4358 Expression visitDArray(TypeDArray mt)
4360 static if (LOGDOTEXP)
4362 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4364 if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
4366 error(e.loc, "`%s` is not an expression", e.toChars());
4367 return ErrorExp.get();
4369 if (ident == Id.length)
4371 if (e.op == EXP.string_)
4373 StringExp se = cast(StringExp)e;
4374 return new IntegerExp(se.loc, se.len, Type.tsize_t);
4376 if (e.op == EXP.null_)
4378 return new IntegerExp(e.loc, 0, Type.tsize_t);
4380 if (checkNonAssignmentArrayOp(e))
4382 return ErrorExp.get();
4384 e = new ArrayLengthExp(e.loc, e);
4385 e.type = Type.tsize_t;
4386 return e;
4388 else if (ident == Id.ptr)
4390 if (checkUnsafeDotExp(sc, e, ident, flag))
4391 return ErrorExp.get();
4392 return e.castTo(sc, mt.next.pointerTo());
4394 else
4396 return visitArray(mt);
4400 Expression visitAArray(TypeAArray mt)
4402 static if (LOGDOTEXP)
4404 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4406 if (ident == Id.length)
4408 __gshared FuncDeclaration fd_aaLen = null;
4409 if (fd_aaLen is null)
4411 auto fparams = new Parameters();
4412 fparams.push(new Parameter(Loc.initial, STC.const_ | STC.scope_, mt, null, null, null));
4413 fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen);
4414 TypeFunction tf = fd_aaLen.type.toTypeFunction();
4415 tf.purity = PURE.const_;
4416 tf.isnothrow = true;
4417 tf.isnogc = false;
4419 Expression ev = new VarExp(e.loc, fd_aaLen, false);
4420 e = new CallExp(e.loc, ev, e);
4421 e.type = fd_aaLen.type.toTypeFunction().next;
4422 return e;
4424 else
4426 return visitType(mt);
4430 Expression visitReference(TypeReference mt)
4432 static if (LOGDOTEXP)
4434 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4436 // References just forward things along
4437 return mt.next.dotExp(sc, e, ident, flag);
4440 Expression visitDelegate(TypeDelegate mt)
4442 static if (LOGDOTEXP)
4444 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4446 if (ident == Id.ptr)
4448 e = new DelegatePtrExp(e.loc, e);
4449 e = e.expressionSemantic(sc);
4451 else if (ident == Id.funcptr)
4453 if (checkUnsafeDotExp(sc, e, ident, flag))
4455 return ErrorExp.get();
4457 e = new DelegateFuncptrExp(e.loc, e);
4458 e = e.expressionSemantic(sc);
4460 else
4462 return visitType(mt);
4464 return e;
4467 /***************************************
4468 * `ident` was not found as a member of `mt`.
4469 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
4470 * If that fails, forward to visitType().
4471 * Params:
4472 * mt = class or struct
4473 * sc = context
4474 * e = `this` for `ident`
4475 * ident = name of member
4476 * flag = flag & 1, don't report "not a property" error and just return NULL.
4477 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
4478 * Returns:
4479 * resolved expression if found, otherwise null
4481 Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
4483 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
4485 bool gagError = flag & 1;
4487 __gshared int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
4489 static Expression returnExp(Expression e)
4491 --nest;
4492 return e;
4495 if (++nest > global.recursionLimit)
4497 .error(e.loc, "cannot resolve identifier `%s`", ident.toChars());
4498 return returnExp(gagError ? null : ErrorExp.get());
4502 assert(mt.ty == Tstruct || mt.ty == Tclass);
4503 auto sym = mt.toDsymbol(sc).isAggregateDeclaration();
4504 assert(sym);
4505 if (// https://issues.dlang.org/show_bug.cgi?id=22054
4506 // if a class or struct does not have a body
4507 // there is no point in searching for its members
4508 sym.members &&
4509 ident != Id.__sizeof &&
4510 ident != Id.__xalignof &&
4511 ident != Id._init &&
4512 ident != Id._mangleof &&
4513 ident != Id.stringof &&
4514 ident != Id.offsetof &&
4515 // https://issues.dlang.org/show_bug.cgi?id=15045
4516 // Don't forward special built-in member functions.
4517 ident != Id.ctor &&
4518 ident != Id.dtor &&
4519 ident != Id.__xdtor &&
4520 ident != Id.postblit &&
4521 ident != Id.__xpostblit)
4523 /* Look for overloaded opDot() to see if we should forward request
4524 * to it.
4526 if (auto fd = search_function(sym, Id.opDot))
4528 /* Rewrite e.ident as:
4529 * e.opDot().ident
4531 e = build_overload(e.loc, sc, e, null, fd);
4532 // @@@DEPRECATED_2.110@@@.
4533 // Deprecated in 2.082, made an error in 2.100.
4534 error(e.loc, "`opDot` is obsolete. Use `alias this`");
4535 return ErrorExp.get();
4538 /* Look for overloaded opDispatch to see if we should forward request
4539 * to it.
4541 if (auto fd = search_function(sym, Id.opDispatch))
4543 /* Rewrite e.ident as:
4544 * e.opDispatch!("ident")
4546 TemplateDeclaration td = fd.isTemplateDeclaration();
4547 if (!td)
4549 .error(fd.loc, "%s `%s` must be a template `opDispatch(string s)`, not a %s", fd.kind, fd.toPrettyChars, fd.kind());
4550 return returnExp(ErrorExp.get());
4552 auto se = new StringExp(e.loc, ident.toString());
4553 auto tiargs = new Objects();
4554 tiargs.push(se);
4555 auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs);
4556 dti.ti.tempdecl = td;
4557 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
4558 * e.g.
4559 * template opDispatch(name) if (isValid!name) { ... }
4561 uint errors = gagError ? global.startGagging() : 0;
4562 e = dti.dotTemplateSemanticProp(sc, DotExpFlag.none);
4563 if (gagError && global.endGagging(errors))
4564 e = null;
4565 return returnExp(e);
4568 /* See if we should forward to the alias this.
4570 auto alias_e = flag & DotExpFlag.noAliasThis ? null
4571 : resolveAliasThis(sc, e, gagError);
4572 if (alias_e && alias_e != e)
4574 /* Rewrite e.ident as:
4575 * e.aliasthis.ident
4577 auto die = new DotIdExp(e.loc, alias_e, ident);
4579 auto errors = gagError ? 0 : global.startGagging();
4580 auto exp = die.dotIdSemanticProp(sc, gagError);
4581 if (!gagError)
4583 global.endGagging(errors);
4584 if (exp && exp.op == EXP.error)
4585 exp = null;
4588 if (exp && gagError)
4589 // now that we know that the alias this leads somewhere useful,
4590 // go back and print deprecations/warnings that we skipped earlier due to the gag
4591 resolveAliasThis(sc, e, false);
4593 return returnExp(exp);
4596 return returnExp(visitType(mt));
4599 Expression visitStruct(TypeStruct mt)
4601 Dsymbol s;
4602 static if (LOGDOTEXP)
4604 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4606 assert(e.op != EXP.dot);
4608 // https://issues.dlang.org/show_bug.cgi?id=14010
4609 if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
4611 return mt.getProperty(sc, e.loc, ident, flag & 1);
4614 /* If e.tupleof
4616 if (ident == Id._tupleof)
4618 /* Create a TupleExp out of the fields of the struct e:
4619 * (e.field0, e.field1, e.field2, ...)
4621 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
4623 if (!mt.sym.determineFields())
4625 error(e.loc, "unable to determine fields of `%s` because of forward references", mt.toChars());
4628 Expression e0;
4629 Expression ev = e.op == EXP.type ? null : e;
4630 if (ev)
4631 ev = extractSideEffect(sc, "__tup", e0, ev);
4633 auto exps = new Expressions();
4634 exps.reserve(mt.sym.fields.length);
4635 for (size_t i = 0; i < mt.sym.fields.length; i++)
4637 VarDeclaration v = mt.sym.fields[i];
4638 Expression ex;
4639 if (ev)
4640 ex = new DotVarExp(e.loc, ev, v);
4641 else
4643 ex = new VarExp(e.loc, v);
4644 ex.type = ex.type.addMod(e.type.mod);
4646 exps.push(ex);
4649 e = new TupleExp(e.loc, e0, exps);
4650 Scope* sc2 = sc.push();
4651 sc2.flags |= SCOPE.noaccesscheck;
4652 e = e.expressionSemantic(sc2);
4653 sc2.pop();
4654 return e;
4657 immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
4658 s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
4660 if (!s)
4662 return noMember(mt, sc, e, ident, flag);
4664 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
4666 return noMember(mt, sc, e, ident, flag);
4668 // check before alias resolution; the alias itself might be deprecated!
4669 if (s.isAliasDeclaration)
4670 s.checkDeprecated(e.loc, sc);
4671 s = s.toAlias();
4673 if (auto em = s.isEnumMember())
4675 return em.getVarExp(e.loc, sc);
4677 if (auto v = s.isVarDeclaration())
4679 v.checkDeprecated(e.loc, sc);
4680 v.checkDisabled(e.loc, sc);
4681 if (!v.type ||
4682 !v.type.deco && v.inuse)
4684 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
4685 error(e.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
4686 else
4687 error(e.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
4688 return ErrorExp.get();
4690 if (v.type.ty == Terror)
4692 return ErrorExp.get();
4695 if ((v.storage_class & STC.manifest) && v._init)
4697 if (v.inuse)
4699 error(e.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
4700 return ErrorExp.get();
4702 checkAccess(e.loc, sc, null, v);
4703 Expression ve = new VarExp(e.loc, v);
4704 if (!isTrivialExp(e))
4706 ve = new CommaExp(e.loc, e, ve);
4708 return ve.expressionSemantic(sc);
4712 if (auto t = s.getType())
4714 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
4717 TemplateMixin tm = s.isTemplateMixin();
4718 if (tm)
4720 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
4723 TemplateDeclaration td = s.isTemplateDeclaration();
4724 if (td)
4726 if (e.op == EXP.type)
4727 e = new TemplateExp(e.loc, td);
4728 else
4729 e = new DotTemplateExp(e.loc, e, td);
4730 return e.expressionSemantic(sc);
4733 TemplateInstance ti = s.isTemplateInstance();
4734 if (ti)
4736 if (!ti.semanticRun)
4738 ti.dsymbolSemantic(sc);
4739 if (!ti.inst || ti.errors) // if template failed to expand
4741 return ErrorExp.get();
4744 s = ti.inst.toAlias();
4745 if (!s.isTemplateInstance())
4746 goto L1;
4747 if (e.op == EXP.type)
4748 e = new ScopeExp(e.loc, ti);
4749 else
4750 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
4751 return e.expressionSemantic(sc);
4754 if (s.isImport() || s.isModule() || s.isPackage())
4756 return symbolToExp(s, e.loc, sc, false);
4759 OverloadSet o = s.isOverloadSet();
4760 if (o)
4762 auto oe = new OverExp(e.loc, o);
4763 if (e.op == EXP.type)
4765 return oe;
4767 return new DotExp(e.loc, e, oe);
4770 Declaration d = s.isDeclaration();
4771 if (!d)
4773 error(e.loc, "`%s.%s` is not a declaration", e.toChars(), ident.toChars());
4774 return ErrorExp.get();
4777 if (e.op == EXP.type)
4779 /* It's:
4780 * Struct.d
4782 if (TupleDeclaration tup = d.isTupleDeclaration())
4784 e = new TupleExp(e.loc, tup);
4785 return e.expressionSemantic(sc);
4787 if (d.needThis() && sc.intypeof != 1)
4789 /* Rewrite as:
4790 * this.d
4792 * only if the scope in which we are
4793 * has a `this` that matches the type
4794 * of the lhs of the dot expression.
4796 * https://issues.dlang.org/show_bug.cgi?id=23617
4798 auto fd = hasThis(sc);
4799 if (fd && fd.isThis() == mt.sym)
4801 e = new DotVarExp(e.loc, new ThisExp(e.loc), d);
4802 return e.expressionSemantic(sc);
4805 if (d.semanticRun == PASS.initial)
4806 d.dsymbolSemantic(null);
4807 checkAccess(e.loc, sc, e, d);
4808 auto ve = new VarExp(e.loc, d);
4809 if (d.isVarDeclaration() && d.needThis())
4810 ve.type = d.type.addMod(e.type.mod);
4811 return ve;
4814 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
4815 if (d.isDataseg() || unreal && d.isField())
4817 // (e, d)
4818 checkAccess(e.loc, sc, e, d);
4819 Expression ve = new VarExp(e.loc, d);
4820 e = unreal ? ve : new CommaExp(e.loc, e, ve);
4821 return e.expressionSemantic(sc);
4824 e = new DotVarExp(e.loc, e, d);
4825 return e.expressionSemantic(sc);
4828 Expression visitEnum(TypeEnum mt)
4830 static if (LOGDOTEXP)
4832 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), mt.toChars());
4834 // https://issues.dlang.org/show_bug.cgi?id=14010
4835 if (ident == Id._mangleof)
4837 return mt.getProperty(sc, e.loc, ident, flag & 1);
4840 if (mt.sym.semanticRun < PASS.semanticdone)
4841 mt.sym.dsymbolSemantic(null);
4843 Dsymbol s = mt.sym.search(e.loc, ident);
4844 if (!s)
4846 if (ident == Id._init)
4848 return mt.getProperty(sc, e.loc, ident, flag & 1);
4851 /* Allow special enums to not need a member list
4853 if ((ident == Id.max || ident == Id.min) && (mt.sym.members || !mt.sym.isSpecial()))
4855 return mt.getProperty(sc, e.loc, ident, flag & 1);
4858 Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, DotExpFlag.gag);
4859 if (!(flag & 1) && !res)
4861 if (auto ns = mt.sym.search_correct(ident))
4862 error(e.loc, "no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
4863 ns.toChars());
4864 else
4865 error(e.loc, "no property `%s` for type `%s`", ident.toChars(),
4866 mt.toChars());
4868 errorSupplemental(mt.sym.loc, "%s `%s` defined here",
4869 mt.sym.kind, mt.toChars());
4870 return ErrorExp.get();
4872 return res;
4874 EnumMember m = s.isEnumMember();
4875 return m.getVarExp(e.loc, sc);
4878 Expression visitClass(TypeClass mt)
4880 Dsymbol s;
4881 static if (LOGDOTEXP)
4883 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4885 assert(e.op != EXP.dot);
4887 // https://issues.dlang.org/show_bug.cgi?id=12543
4888 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
4890 return mt.Type.getProperty(sc, e.loc, ident, 0);
4893 /* If e.tupleof
4895 if (ident == Id._tupleof)
4897 objc.checkTupleof(e, mt);
4899 /* Create a TupleExp
4901 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
4903 mt.sym.size(e.loc); // do semantic of type
4905 Expression e0;
4906 Expression ev = e.op == EXP.type ? null : e;
4907 if (ev)
4908 ev = extractSideEffect(sc, "__tup", e0, ev);
4910 auto exps = new Expressions();
4911 exps.reserve(mt.sym.fields.length);
4912 for (size_t i = 0; i < mt.sym.fields.length; i++)
4914 VarDeclaration v = mt.sym.fields[i];
4915 // Don't include hidden 'this' pointer
4916 if (v.isThisDeclaration())
4917 continue;
4918 Expression ex;
4919 if (ev)
4920 ex = new DotVarExp(e.loc, ev, v);
4921 else
4923 ex = new VarExp(e.loc, v);
4924 ex.type = ex.type.addMod(e.type.mod);
4926 exps.push(ex);
4929 e = new TupleExp(e.loc, e0, exps);
4930 Scope* sc2 = sc.push();
4931 sc2.flags |= SCOPE.noaccesscheck;
4932 e = e.expressionSemantic(sc2);
4933 sc2.pop();
4934 return e;
4937 SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
4938 s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
4941 if (!s)
4943 // See if it's a 'this' class or a base class
4944 if (mt.sym.ident == ident)
4946 if (e.op == EXP.type)
4948 return mt.Type.getProperty(sc, e.loc, ident, 0);
4950 e = new DotTypeExp(e.loc, e, mt.sym);
4951 e = e.expressionSemantic(sc);
4952 return e;
4954 if (auto cbase = mt.sym.searchBase(ident))
4956 if (e.op == EXP.type)
4958 return mt.Type.getProperty(sc, e.loc, ident, 0);
4960 if (auto ifbase = cbase.isInterfaceDeclaration())
4961 e = new CastExp(e.loc, e, ifbase.type);
4962 else
4963 e = new DotTypeExp(e.loc, e, cbase);
4964 e = e.expressionSemantic(sc);
4965 return e;
4968 if (ident == Id.classinfo)
4970 if (!Type.typeinfoclass)
4972 error(e.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4973 return ErrorExp.get();
4976 Type t = Type.typeinfoclass.type;
4977 if (e.op == EXP.type || e.op == EXP.dotType)
4979 /* For type.classinfo, we know the classinfo
4980 * at compile time.
4982 if (!mt.sym.vclassinfo)
4983 mt.sym.vclassinfo = new TypeInfoClassDeclaration(mt.sym.type);
4984 e = new VarExp(e.loc, mt.sym.vclassinfo);
4985 e = e.addressOf();
4986 e.type = t; // do this so we don't get redundant dereference
4988 else
4990 /* For class objects, the classinfo reference is the first
4991 * entry in the vtbl[]
4993 e = new PtrExp(e.loc, e);
4994 e.type = t.pointerTo();
4995 if (mt.sym.isInterfaceDeclaration())
4997 if (mt.sym.isCPPinterface())
4999 /* C++ interface vtbl[]s are different in that the
5000 * first entry is always pointer to the first virtual
5001 * function, not classinfo.
5002 * We can't get a .classinfo for it.
5004 error(e.loc, "no `.classinfo` for C++ interface objects");
5006 /* For an interface, the first entry in the vtbl[]
5007 * is actually a pointer to an instance of struct Interface.
5008 * The first member of Interface is the .classinfo,
5009 * so add an extra pointer indirection.
5011 e.type = e.type.pointerTo();
5012 e = new PtrExp(e.loc, e);
5013 e.type = t.pointerTo();
5015 e = new PtrExp(e.loc, e, t);
5017 return e;
5020 if (ident == Id.__vptr)
5022 /* The pointer to the vtbl[]
5023 * *cast(immutable(void*)**)e
5025 e = e.castTo(sc, mt.tvoidptr.immutableOf().pointerTo().pointerTo());
5026 e = new PtrExp(e.loc, e);
5027 e = e.expressionSemantic(sc);
5028 return e;
5031 if (ident == Id.__monitor && mt.sym.hasMonitor())
5033 /* The handle to the monitor (call it a void*)
5034 * *(cast(void**)e + 1)
5036 e = e.castTo(sc, mt.tvoidptr.pointerTo());
5037 e = new AddExp(e.loc, e, IntegerExp.literal!1);
5038 e = new PtrExp(e.loc, e);
5039 e = e.expressionSemantic(sc);
5040 return e;
5043 if (ident == Id.outer && mt.sym.vthis)
5045 if (mt.sym.vthis.semanticRun == PASS.initial)
5046 mt.sym.vthis.dsymbolSemantic(null);
5048 if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
5050 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
5051 dve.type = cdp.type.addMod(e.type.mod);
5052 return dve;
5055 /* https://issues.dlang.org/show_bug.cgi?id=15839
5056 * Find closest parent class through nested functions.
5058 for (auto p = mt.sym.toParentLocal(); p; p = p.toParentLocal())
5060 auto fd = p.isFuncDeclaration();
5061 if (!fd)
5062 break;
5063 auto ad = fd.isThis();
5064 if (!ad && fd.isNested())
5065 continue;
5066 if (!ad)
5067 break;
5068 if (auto cdp = ad.isClassDeclaration())
5070 auto ve = new ThisExp(e.loc);
5072 ve.var = fd.vthis;
5073 const nestedError = fd.vthis.checkNestedReference(sc, e.loc);
5074 assert(!nestedError);
5076 ve.type = cdp.type.addMod(fd.vthis.type.mod).addMod(e.type.mod);
5077 return ve;
5079 break;
5082 // Continue to show enclosing function's frame (stack or closure).
5083 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
5084 dve.type = mt.sym.vthis.type.addMod(e.type.mod);
5085 return dve;
5088 return noMember(mt, sc, e, ident, flag & 1);
5090 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
5092 return noMember(mt, sc, e, ident, flag);
5094 if (!s.isFuncDeclaration()) // because of overloading
5096 s.checkDeprecated(e.loc, sc);
5097 if (auto d = s.isDeclaration())
5098 d.checkDisabled(e.loc, sc);
5100 s = s.toAlias();
5102 if (auto em = s.isEnumMember())
5104 return em.getVarExp(e.loc, sc);
5106 if (auto v = s.isVarDeclaration())
5108 if (!v.type ||
5109 !v.type.deco && v.inuse)
5111 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
5112 error(e.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
5113 else
5114 error(e.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
5115 return ErrorExp.get();
5117 if (v.type.ty == Terror)
5119 error(e.loc, "type of variable `%s` has errors", v.toPrettyChars);
5120 return ErrorExp.get();
5123 if ((v.storage_class & STC.manifest) && v._init)
5125 if (v.inuse)
5127 error(e.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
5128 return ErrorExp.get();
5130 checkAccess(e.loc, sc, null, v);
5131 Expression ve = new VarExp(e.loc, v);
5132 ve = ve.expressionSemantic(sc);
5133 return ve;
5137 if (auto t = s.getType())
5139 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
5142 TemplateMixin tm = s.isTemplateMixin();
5143 if (tm)
5145 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
5148 TemplateDeclaration td = s.isTemplateDeclaration();
5150 Expression toTemplateExp(TemplateDeclaration td)
5152 if (e.op == EXP.type)
5153 e = new TemplateExp(e.loc, td);
5154 else
5155 e = new DotTemplateExp(e.loc, e, td);
5156 e = e.expressionSemantic(sc);
5157 return e;
5160 if (td)
5162 return toTemplateExp(td);
5165 TemplateInstance ti = s.isTemplateInstance();
5166 if (ti)
5168 if (!ti.semanticRun)
5170 ti.dsymbolSemantic(sc);
5171 if (!ti.inst || ti.errors) // if template failed to expand
5173 return ErrorExp.get();
5176 s = ti.inst.toAlias();
5177 if (!s.isTemplateInstance())
5178 goto L1;
5179 if (e.op == EXP.type)
5180 e = new ScopeExp(e.loc, ti);
5181 else
5182 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
5183 return e.expressionSemantic(sc);
5186 if (s.isImport() || s.isModule() || s.isPackage())
5188 e = symbolToExp(s, e.loc, sc, false);
5189 return e;
5192 OverloadSet o = s.isOverloadSet();
5193 if (o)
5195 auto oe = new OverExp(e.loc, o);
5196 if (e.op == EXP.type)
5198 return oe;
5200 return new DotExp(e.loc, e, oe);
5203 Declaration d = s.isDeclaration();
5204 if (!d)
5206 error(e.loc, "`%s.%s` is not a declaration", e.toChars(), ident.toChars());
5207 return ErrorExp.get();
5210 if (e.op == EXP.type)
5212 /* It's:
5213 * Class.d
5215 if (TupleDeclaration tup = d.isTupleDeclaration())
5217 e = new TupleExp(e.loc, tup);
5218 e = e.expressionSemantic(sc);
5219 return e;
5222 if (mt.sym.classKind == ClassKind.objc
5223 && d.isFuncDeclaration()
5224 && d.isFuncDeclaration().isStatic
5225 && d.isFuncDeclaration().objc.selector)
5227 auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
5228 classRef.type = objc.getRuntimeMetaclass(mt.sym).getType();
5229 return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
5231 else if (d.needThis() && sc.intypeof != 1)
5233 /* Rewrite as:
5234 * this.d
5236 AggregateDeclaration ad = d.isMemberLocal();
5237 if (auto f = hasThis(sc))
5239 // This is almost same as getRightThis() in expressionsem.d
5240 Expression e1;
5241 Type t;
5242 /* returns: true to continue, false to return */
5243 if (f.hasDualContext())
5245 if (f.followInstantiationContext(ad))
5247 e1 = new VarExp(e.loc, f.vthis);
5248 e1 = new PtrExp(e1.loc, e1);
5249 e1 = new IndexExp(e1.loc, e1, IntegerExp.literal!1);
5250 auto pd = f.toParent2().isDeclaration();
5251 assert(pd);
5252 t = pd.type.toBasetype();
5253 e1 = getThisSkipNestedFuncs(e1.loc, sc, f.toParent2(), ad, e1, t, d, true);
5254 if (!e1)
5256 e = new VarExp(e.loc, d);
5257 return e;
5259 goto L2;
5262 e1 = new ThisExp(e.loc);
5263 e1 = e1.expressionSemantic(sc);
5265 t = e1.type.toBasetype();
5266 ClassDeclaration cd = e.type.isClassHandle();
5267 ClassDeclaration tcd = t.isClassHandle();
5268 if (cd && tcd && (tcd == cd || cd.isBaseOf(tcd, null)))
5270 e = new DotTypeExp(e1.loc, e1, cd);
5271 e = new DotVarExp(e.loc, e, d);
5272 e = e.expressionSemantic(sc);
5273 return e;
5275 if (tcd && tcd.isNested())
5277 /* e1 is the 'this' pointer for an inner class: tcd.
5278 * Rewrite it as the 'this' pointer for the outer class.
5280 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
5281 e1 = new DotVarExp(e.loc, e1, vthis);
5282 e1.type = vthis.type;
5283 e1.type = e1.type.addMod(t.mod);
5284 // Do not call ensureStaticLinkTo()
5285 //e1 = e1.expressionSemantic(sc);
5287 // Skip up over nested functions, and get the enclosing
5288 // class type.
5289 e1 = getThisSkipNestedFuncs(e1.loc, sc, tcd.toParentP(ad), ad, e1, t, d, true);
5290 if (!e1)
5292 e = new VarExp(e.loc, d);
5293 return e;
5295 goto L2;
5299 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
5300 if (d.semanticRun == PASS.initial)
5301 d.dsymbolSemantic(null);
5303 // If static function, get the most visible overload.
5304 // Later on the call is checked for correctness.
5305 // https://issues.dlang.org/show_bug.cgi?id=12511
5306 Dsymbol d2 = d;
5307 if (auto fd = d.isFuncDeclaration())
5309 import dmd.access : mostVisibleOverload;
5310 d2 = mostVisibleOverload(fd, sc._module);
5313 checkAccess(e.loc, sc, e, d2);
5314 if (d2.isDeclaration())
5316 d = cast(Declaration)d2;
5317 auto ve = new VarExp(e.loc, d);
5318 if (d.isVarDeclaration() && d.needThis())
5319 ve.type = d.type.addMod(e.type.mod);
5320 return ve;
5322 else if (d2.isTemplateDeclaration())
5324 return toTemplateExp(cast(TemplateDeclaration)d2);
5326 else
5327 assert(0);
5330 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
5331 if (d.isDataseg() || unreal && d.isField())
5333 // (e, d)
5334 checkAccess(e.loc, sc, e, d);
5335 Expression ve = new VarExp(e.loc, d);
5336 e = unreal ? ve : new CommaExp(e.loc, e, ve);
5337 e = e.expressionSemantic(sc);
5338 return e;
5341 e = new DotVarExp(e.loc, e, d);
5342 e = e.expressionSemantic(sc);
5343 return e;
5346 switch (mt.ty)
5348 case Tvector: return visitVector (mt.isTypeVector());
5349 case Tsarray: return visitSArray (mt.isTypeSArray());
5350 case Tstruct: return visitStruct (mt.isTypeStruct());
5351 case Tenum: return visitEnum (mt.isTypeEnum());
5352 case Terror: return visitError (mt.isTypeError());
5353 case Tarray: return visitDArray (mt.isTypeDArray());
5354 case Taarray: return visitAArray (mt.isTypeAArray());
5355 case Treference: return visitReference(mt.isTypeReference());
5356 case Tdelegate: return visitDelegate (mt.isTypeDelegate());
5357 case Tclass: return visitClass (mt.isTypeClass());
5359 default: return mt.isTypeBasic()
5360 ? visitBasic(cast(TypeBasic)mt)
5361 : visitType(mt);
5366 /************************
5367 * Get the default initialization expression for a type.
5368 * Params:
5369 * mt = the type for which the init expression is returned
5370 * loc = the location where the expression needs to be evaluated
5371 * isCfile = default initializers are different with C
5373 * Returns:
5374 * The initialization expression for the type.
5376 Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
5378 Expression visitBasic(TypeBasic mt)
5380 static if (LOGDEFAULTINIT)
5382 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
5384 dinteger_t value = 0;
5386 switch (mt.ty)
5388 case Tchar:
5389 value = isCfile ? 0 : 0xFF;
5390 break;
5392 case Twchar:
5393 case Tdchar:
5394 value = isCfile ? 0 : 0xFFFF;
5395 break;
5397 case Timaginary32:
5398 case Timaginary64:
5399 case Timaginary80:
5400 case Tfloat32:
5401 case Tfloat64:
5402 case Tfloat80:
5403 return new RealExp(loc, isCfile ? CTFloat.zero : target.RealProperties.nan, mt);
5405 case Tcomplex32:
5406 case Tcomplex64:
5407 case Tcomplex80:
5409 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
5410 const cvalue = isCfile ? complex_t(CTFloat.zero, CTFloat.zero)
5411 : complex_t(target.RealProperties.nan, target.RealProperties.nan);
5412 return new ComplexExp(loc, cvalue, mt);
5415 case Tvoid:
5416 error(loc, "`void` does not have a default initializer");
5417 return ErrorExp.get();
5419 default:
5420 break;
5422 return new IntegerExp(loc, value, mt);
5425 Expression visitVector(TypeVector mt)
5427 //printf("TypeVector::defaultInit()\n");
5428 assert(mt.basetype.ty == Tsarray);
5429 Expression e = mt.basetype.defaultInit(loc, isCfile);
5430 auto ve = new VectorExp(loc, e, mt);
5431 ve.type = mt;
5432 ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc));
5433 return ve;
5436 Expression visitSArray(TypeSArray mt)
5438 static if (LOGDEFAULTINIT)
5440 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
5442 if (mt.next.ty == Tvoid)
5443 return mt.tuns8.defaultInit(loc, isCfile);
5444 else
5445 return mt.next.defaultInit(loc, isCfile);
5448 Expression visitFunction(TypeFunction mt)
5450 error(loc, "`function` does not have a default initializer");
5451 return ErrorExp.get();
5454 Expression visitStruct(TypeStruct mt)
5456 static if (LOGDEFAULTINIT)
5458 printf("TypeStruct::defaultInit() '%s'\n", mt.toChars());
5460 Declaration d = new SymbolDeclaration(mt.sym.loc, mt.sym);
5461 assert(d);
5462 d.type = mt;
5463 d.storage_class |= STC.rvalue; // https://issues.dlang.org/show_bug.cgi?id=14398
5464 return new VarExp(mt.sym.loc, d);
5467 Expression visitEnum(TypeEnum mt)
5469 static if (LOGDEFAULTINIT)
5471 printf("TypeEnum::defaultInit() '%s'\n", mt.toChars());
5473 // Initialize to first member of enum
5474 Expression e = mt.sym.getDefaultValue(loc);
5475 e = e.copy();
5476 e.loc = loc;
5477 e.type = mt; // to deal with const, immutable, etc., variants
5478 return e;
5481 Expression visitTuple(TypeTuple mt)
5483 static if (LOGDEFAULTINIT)
5485 printf("TypeTuple::defaultInit() '%s'\n", mt.toChars());
5487 auto exps = new Expressions(mt.arguments.length);
5488 for (size_t i = 0; i < mt.arguments.length; i++)
5490 Parameter p = (*mt.arguments)[i];
5491 assert(p.type);
5492 Expression e = p.type.defaultInitLiteral(loc);
5493 if (e.op == EXP.error)
5495 return e;
5497 (*exps)[i] = e;
5499 return new TupleExp(loc, exps);
5502 Expression visitNoreturn(TypeNoreturn mt)
5504 static if (LOGDEFAULTINIT)
5506 printf("TypeNoreturn::defaultInit() '%s'\n", mt.toChars());
5508 auto cond = IntegerExp.createBool(false);
5509 auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
5510 msg.type = Type.tstring;
5511 auto ae = new AssertExp(loc, cond, msg);
5512 ae.type = mt;
5513 return ae;
5516 switch (mt.ty)
5518 case Tvector: return visitVector (mt.isTypeVector());
5519 case Tsarray: return visitSArray (mt.isTypeSArray());
5520 case Tfunction: return visitFunction(mt.isTypeFunction());
5521 case Tstruct: return visitStruct (mt.isTypeStruct());
5522 case Tenum: return visitEnum (mt.isTypeEnum());
5523 case Ttuple: return visitTuple (mt.isTypeTuple());
5525 case Tnull: return new NullExp(Loc.initial, Type.tnull);
5527 case Terror: return ErrorExp.get();
5529 case Tarray:
5530 case Taarray:
5531 case Tpointer:
5532 case Treference:
5533 case Tdelegate:
5534 case Tclass: return new NullExp(loc, mt);
5535 case Tnoreturn: return visitNoreturn(mt.isTypeNoreturn());
5537 default: return mt.isTypeBasic() ?
5538 visitBasic(cast(TypeBasic)mt) :
5539 null;
5544 If `type` resolves to a dsymbol, then that
5545 dsymbol is returned.
5547 Params:
5548 type = the type that is checked
5549 sc = the scope where the type is used
5551 Returns:
5552 The dsymbol to which the type resolve or `null`
5553 if the type does resolve to any symbol (for example,
5554 in the case of basic types).
5556 Dsymbol toDsymbol(Type type, Scope* sc)
5558 Dsymbol visitType(Type _) { return null; }
5559 Dsymbol visitStruct(TypeStruct type) { return type.sym; }
5560 Dsymbol visitEnum(TypeEnum type) { return type.sym; }
5561 Dsymbol visitClass(TypeClass type) { return type.sym; }
5563 Dsymbol visitTraits(TypeTraits type)
5565 Type t;
5566 Expression e;
5567 Dsymbol s;
5568 resolve(type, type.loc, sc, e, t, s);
5569 if (t && t.ty != Terror)
5570 s = t.toDsymbol(sc);
5571 else if (e)
5572 s = getDsymbol(e);
5574 return s;
5577 Dsymbol visitMixin(TypeMixin type)
5579 Type t;
5580 Expression e;
5581 Dsymbol s;
5582 resolve(type, type.loc, sc, e, t, s);
5583 if (t)
5584 s = t.toDsymbol(sc);
5585 else if (e)
5586 s = getDsymbol(e);
5588 return s;
5591 Dsymbol visitIdentifier(TypeIdentifier type)
5593 //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
5594 if (!sc)
5595 return null;
5597 Type t;
5598 Expression e;
5599 Dsymbol s;
5600 resolve(type, type.loc, sc, e, t, s);
5601 if (t && t.ty != Tident)
5602 s = t.toDsymbol(sc);
5603 if (e)
5604 s = getDsymbol(e);
5606 return s;
5609 Dsymbol visitInstance(TypeInstance type)
5611 Type t;
5612 Expression e;
5613 Dsymbol s;
5614 //printf("TypeInstance::semantic(%s)\n", toChars());
5615 resolve(type, type.loc, sc, e, t, s);
5616 if (t && t.ty != Tinstance)
5617 s = t.toDsymbol(sc);
5618 return s;
5621 Dsymbol visitTypeof(TypeTypeof type)
5623 //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
5624 Expression e;
5625 Type t;
5626 Dsymbol s;
5627 resolve(type, type.loc, sc, e, t, s);
5628 return s;
5631 Dsymbol visitReturn(TypeReturn type)
5633 Expression e;
5634 Type t;
5635 Dsymbol s;
5636 resolve(type, type.loc, sc, e, t, s);
5637 return s;
5640 switch(type.ty)
5642 default: return visitType(type);
5643 case Ttraits: return visitTraits(type.isTypeTraits());
5644 case Tmixin: return visitMixin(type.isTypeMixin());
5645 case Tident: return visitIdentifier(type.isTypeIdentifier());
5646 case Tinstance: return visitInstance(type.isTypeInstance());
5647 case Ttypeof: return visitTypeof(type.isTypeTypeof());
5648 case Treturn: return visitReturn(type.isTypeReturn());
5649 case Tstruct: return visitStruct(type.isTypeStruct());
5650 case Tenum: return visitEnum(type.isTypeEnum());
5651 case Tclass: return visitClass(type.isTypeClass());
5655 /************************************
5656 * Add storage class modifiers to type.
5658 Type addStorageClass(Type type, StorageClass stc)
5660 Type visitType(Type t)
5662 /* Just translate to MOD bits and let addMod() do the work
5664 MOD mod = 0;
5665 if (stc & STC.immutable_)
5666 mod = MODFlags.immutable_;
5667 else
5669 if (stc & (STC.const_ | STC.in_))
5670 mod |= MODFlags.const_;
5671 if (stc & STC.wild)
5672 mod |= MODFlags.wild;
5673 if (stc & STC.shared_)
5674 mod |= MODFlags.shared_;
5676 return t.addMod(mod);
5679 Type visitFunction(TypeFunction tf_src)
5681 //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
5682 TypeFunction t = visitType(tf_src).toTypeFunction();
5683 if ((stc & STC.pure_ && !t.purity) ||
5684 (stc & STC.nothrow_ && !t.isnothrow) ||
5685 (stc & STC.nogc && !t.isnogc) ||
5686 (stc & STC.scope_ && !t.isScopeQual) ||
5687 (stc & STC.safe && t.trust < TRUST.trusted))
5689 // Klunky to change these
5690 auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0);
5691 tf.mod = t.mod;
5692 tf.inferenceArguments = tf_src.inferenceArguments;
5693 tf.purity = t.purity;
5694 tf.isnothrow = t.isnothrow;
5695 tf.isnogc = t.isnogc;
5696 tf.isproperty = t.isproperty;
5697 tf.isref = t.isref;
5698 tf.isreturn = t.isreturn;
5699 tf.isreturnscope = t.isreturnscope;
5700 tf.isScopeQual = t.isScopeQual;
5701 tf.isreturninferred = t.isreturninferred;
5702 tf.isscopeinferred = t.isscopeinferred;
5703 tf.trust = t.trust;
5704 tf.isInOutParam = t.isInOutParam;
5705 tf.isInOutQual = t.isInOutQual;
5706 tf.isctor = t.isctor;
5708 if (stc & STC.pure_)
5709 tf.purity = PURE.fwdref;
5710 if (stc & STC.nothrow_)
5711 tf.isnothrow = true;
5712 if (stc & STC.nogc)
5713 tf.isnogc = true;
5714 if (stc & STC.safe)
5715 tf.trust = TRUST.safe;
5716 if (stc & STC.scope_)
5718 tf.isScopeQual = true;
5719 if (stc & STC.scopeinferred)
5720 tf.isscopeinferred = true;
5723 tf.deco = tf.merge().deco;
5724 t = tf;
5726 return t;
5729 Type visitDelegate(TypeDelegate tdg)
5731 TypeDelegate t = visitType(tdg).isTypeDelegate();
5732 return t;
5735 switch(type.ty)
5737 default: return visitType(type);
5738 case Tfunction: return visitFunction(type.isTypeFunction());
5739 case Tdelegate: return visitDelegate(type.isTypeDelegate());
5743 /**********************************************
5744 * Extract complex type from core.stdc.config
5745 * Params:
5746 * loc = for error messages
5747 * sc = context
5748 * ty = a complex or imaginary type
5749 * Returns:
5750 * Complex!float, Complex!double, Complex!real or null for error
5753 Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
5755 // singleton
5756 __gshared Type complex_float;
5757 __gshared Type complex_double;
5758 __gshared Type complex_real;
5760 Type* pt;
5761 Identifier id;
5762 switch (ty)
5764 case Timaginary32:
5765 case Tcomplex32: id = Id.c_complex_float; pt = &complex_float; break;
5766 case Timaginary64:
5767 case Tcomplex64: id = Id.c_complex_double; pt = &complex_double; break;
5768 case Timaginary80:
5769 case Tcomplex80: id = Id.c_complex_real; pt = &complex_real; break;
5770 default:
5771 return Type.terror;
5774 if (*pt)
5775 return *pt;
5776 *pt = Type.terror;
5778 Module mConfig = Module.loadCoreStdcConfig();
5779 if (!mConfig)
5781 error(loc, "`core.stdc.config` is required for complex numbers");
5782 return *pt;
5785 Dsymbol s = mConfig.searchX(Loc.initial, sc, id, SearchOpt.ignorePrivateImports);
5786 if (!s)
5788 error(loc, "`%s` not found in core.stdc.config", id.toChars());
5789 return *pt;
5791 s = s.toAlias();
5792 if (auto t = s.getType())
5794 if (auto ts = t.toBasetype().isTypeStruct())
5796 *pt = ts;
5797 return ts;
5800 if (auto sd = s.isStructDeclaration())
5802 *pt = sd.type;
5803 return sd.type;
5806 error(loc, "`%s` must be an alias for a complex struct", s.toChars());
5807 return *pt;
5810 /*******************************
5811 * Covariant means that 'src' can substitute for 't',
5812 * i.e. a pure function is a match for an impure type.
5813 * Params:
5814 * src = source type
5815 * t = type 'src' is covariant with
5816 * pstc = if not null, store STCxxxx which would make it covariant
5817 * cppCovariant = true if extern(C++) function types should follow C++ covariant rules
5818 * Returns:
5819 * An enum value of either `Covariant.yes` or a reason it's not covariant.
5821 Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
5823 version (none)
5825 printf("Type::covariant(t = %s) %s\n", t.toChars(), src.toChars());
5826 printf("deco = %p, %p\n", src.deco, t.deco);
5827 // printf("ty = %d\n", next.ty);
5828 printf("mod = %x, %x\n", src.mod, t.mod);
5830 if (pstc)
5831 *pstc = 0;
5832 StorageClass stc = 0;
5834 bool notcovariant = false;
5836 if (src.equals(t))
5837 return Covariant.yes;
5839 TypeFunction t1 = src.isTypeFunction();
5840 TypeFunction t2 = t.isTypeFunction();
5842 if (!t1 || !t2)
5843 goto Ldistinct;
5845 if (t1.parameterList.varargs != t2.parameterList.varargs)
5846 goto Ldistinct;
5848 if (t1.parameterList.parameters && t2.parameterList.parameters)
5850 if (t1.parameterList.length != t2.parameterList.length)
5851 goto Ldistinct;
5853 foreach (i, fparam1; t1.parameterList)
5855 Parameter fparam2 = t2.parameterList[i];
5856 Type tp1 = fparam1.type;
5857 Type tp2 = fparam2.type;
5859 if (!tp1.equals(tp2))
5861 if (tp1.ty == tp2.ty)
5863 if (auto tc1 = tp1.isTypeClass())
5865 if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
5866 goto Lcov;
5868 else if (auto ts1 = tp1.isTypeStruct())
5870 if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
5871 goto Lcov;
5873 else if (tp1.ty == Tpointer)
5875 if (tp2.implicitConvTo(tp1))
5876 goto Lcov;
5878 else if (tp1.ty == Tarray)
5880 if (tp2.implicitConvTo(tp1))
5881 goto Lcov;
5883 else if (tp1.ty == Tdelegate)
5885 if (tp2.implicitConvTo(tp1))
5886 goto Lcov;
5889 goto Ldistinct;
5891 Lcov:
5892 notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
5894 /* https://issues.dlang.org/show_bug.cgi?id=23135
5895 * extern(C++) mutable parameters are not covariant with const.
5897 if (t1.linkage == LINK.cpp && cppCovariant)
5899 notcovariant |= tp1.isNaked() != tp2.isNaked();
5900 if (auto tpn1 = tp1.nextOf())
5901 notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
5905 else if (t1.parameterList.parameters != t2.parameterList.parameters)
5907 if (t1.parameterList.length || t2.parameterList.length)
5908 goto Ldistinct;
5911 // The argument lists match
5912 if (notcovariant)
5913 goto Lnotcovariant;
5914 if (t1.linkage != t2.linkage)
5915 goto Lnotcovariant;
5918 // Return types
5919 Type t1n = t1.next;
5920 Type t2n = t2.next;
5922 if (!t1n || !t2n) // happens with return type inference
5923 goto Lnotcovariant;
5925 if (t1n.equals(t2n))
5926 goto Lcovariant;
5927 if (t1n.ty == Tclass && t2n.ty == Tclass)
5929 /* If same class type, but t2n is const, then it's
5930 * covariant. Do this test first because it can work on
5931 * forward references.
5933 if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
5934 goto Lcovariant;
5936 // If t1n is forward referenced:
5937 ClassDeclaration cd = (cast(TypeClass)t1n).sym;
5938 if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
5939 cd.dsymbolSemantic(null);
5940 if (!cd.isBaseInfoComplete())
5942 return Covariant.fwdref;
5945 if (t1n.ty == Tstruct && t2n.ty == Tstruct)
5947 if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
5948 goto Lcovariant;
5950 else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
5952 if (t1.isref && t2.isref)
5954 // Treat like pointers to t1n and t2n
5955 if (t1n.constConv(t2n) < MATCH.constant)
5956 goto Lnotcovariant;
5958 goto Lcovariant;
5960 else if (t1n.ty == Tnull)
5962 // NULL is covariant with any pointer type, but not with any
5963 // dynamic arrays, associative arrays or delegates.
5964 // https://issues.dlang.org/show_bug.cgi?id=8589
5965 // https://issues.dlang.org/show_bug.cgi?id=19618
5966 Type t2bn = t2n.toBasetype();
5967 if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
5968 goto Lcovariant;
5970 // bottom type is covariant to any type
5971 else if (t1n.ty == Tnoreturn)
5972 goto Lcovariant;
5974 goto Lnotcovariant;
5976 Lcovariant:
5977 if (t1.isref != t2.isref)
5978 goto Lnotcovariant;
5980 if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
5982 StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
5983 StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
5984 if (t1.isreturn)
5986 stc1 |= STC.return_;
5987 if (!t1.isScopeQual)
5988 stc1 |= STC.ref_;
5990 if (t2.isreturn)
5992 stc2 |= STC.return_;
5993 if (!t2.isScopeQual)
5994 stc2 |= STC.ref_;
5996 if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
5997 goto Lnotcovariant;
6000 // We can subtract 'return ref' from 'this', but cannot add it
6001 else if (t1.isreturn && !t2.isreturn)
6002 goto Lnotcovariant;
6004 /* https://issues.dlang.org/show_bug.cgi?id=23135
6005 * extern(C++) mutable member functions are not covariant with const.
6007 if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
6008 goto Lnotcovariant;
6010 /* Can convert mutable to const
6012 if (!MODimplicitConv(t2.mod, t1.mod))
6014 version (none)
6016 //stop attribute inference with const
6017 // If adding 'const' will make it covariant
6018 if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
6019 stc |= STC.const_;
6020 else
6021 goto Lnotcovariant;
6023 else
6025 goto Ldistinct;
6029 /* Can convert pure to impure, nothrow to throw, and nogc to gc
6031 if (!t1.purity && t2.purity)
6032 stc |= STC.pure_;
6034 if (!t1.isnothrow && t2.isnothrow)
6035 stc |= STC.nothrow_;
6037 if (!t1.isnogc && t2.isnogc)
6038 stc |= STC.nogc;
6040 /* Can convert safe/trusted to system
6042 if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
6044 // Should we infer trusted or safe? Go with safe.
6045 stc |= STC.safe;
6048 if (stc)
6050 if (pstc)
6051 *pstc = stc;
6052 goto Lnotcovariant;
6055 //printf("\tcovaraint: 1\n");
6056 return Covariant.yes;
6058 Ldistinct:
6059 //printf("\tcovaraint: 0\n");
6060 return Covariant.distinct;
6062 Lnotcovariant:
6063 //printf("\tcovaraint: 2\n");
6064 return Covariant.no;
6067 /************************************
6068 * Take the specified storage class for p,
6069 * and use the function signature to infer whether
6070 * STC.scope_ and STC.return_ should be OR'd in.
6071 * (This will not affect the name mangling.)
6072 * Params:
6073 * tf = TypeFunction to use to get the signature from
6074 * tthis = type of `this` parameter, null if none
6075 * p = parameter to this function
6076 * outerVars = context variables p could escape into, if any
6077 * indirect = is this for an indirect or virtual function call?
6078 * Returns:
6079 * storage class with STC.scope_ or STC.return_ OR'd in
6081 StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null,
6082 bool indirect = false)
6084 //printf("parameterStorageClass(p: %s)\n", p.toChars());
6085 auto stc = p.storageClass;
6087 // When the preview switch is enable, `in` parameters are `scope`
6088 if (stc & STC.constscoperef)
6089 return stc | STC.scope_;
6091 if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || tf.purity == PURE.impure)
6092 return stc;
6094 /* If haven't inferred the return type yet, can't infer storage classes
6096 if (!tf.nextOf() || !tf.isnothrow())
6097 return stc;
6099 tf.purityLevel();
6101 static bool mayHavePointers(Type t)
6103 if (auto ts = t.isTypeStruct())
6105 auto sym = ts.sym;
6106 if (sym.members && !sym.determineFields() && sym.type != Type.terror)
6107 // struct is forward referenced, so "may have" pointers
6108 return true;
6110 return t.hasPointers();
6113 // See if p can escape via any of the other parameters
6114 if (tf.purity == PURE.weak)
6117 * Indirect calls may escape p through a nested context
6118 * See:
6119 * https://issues.dlang.org/show_bug.cgi?id=24212
6120 * https://issues.dlang.org/show_bug.cgi?id=24213
6122 if (indirect)
6123 return stc;
6125 // Check escaping through parameters
6126 foreach (i, fparam; tf.parameterList)
6128 Type t = fparam.type;
6129 if (!t)
6130 continue;
6131 t = t.baseElemOf(); // punch thru static arrays
6132 if (t.isMutable() && t.hasPointers())
6134 if (fparam.isReference() && fparam != p)
6135 return stc;
6137 if (t.ty == Tdelegate)
6138 return stc; // could escape thru delegate
6140 if (t.ty == Tclass)
6141 return stc;
6143 /* if t is a pointer to mutable pointer
6145 if (auto tn = t.nextOf())
6147 if (tn.isMutable() && mayHavePointers(tn))
6148 return stc; // escape through pointers
6153 // Check escaping through `this`
6154 if (tthis && tthis.isMutable())
6156 foreach (VarDeclaration v; isAggregate(tthis).fields)
6158 if (v.hasPointers())
6159 return stc;
6163 // Check escaping through nested context
6164 if (outerVars && tf.isMutable())
6166 foreach (VarDeclaration v; *outerVars)
6168 if (v.hasPointers())
6169 return stc;
6174 // Check escaping through return value
6175 Type tret = tf.nextOf().toBasetype();
6176 if (tf.isref || tret.hasPointers())
6178 return stc | STC.scope_ | STC.return_ | STC.returnScope;
6180 else
6181 return stc | STC.scope_;
6184 bool isBaseOf(Type tthis, Type t, int* poffset)
6186 auto tc = tthis.isTypeClass();
6187 if (!tc)
6188 return false;
6190 if (!t || t.ty != Tclass)
6191 return false;
6193 ClassDeclaration cd = t.isTypeClass().sym;
6194 if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
6195 cd.dsymbolSemantic(null);
6196 if (tc.sym.semanticRun < PASS.semanticdone && !tc.sym.isBaseInfoComplete())
6197 tc.sym.dsymbolSemantic(null);
6199 if (tc.sym.isBaseOf(cd, poffset))
6200 return true;
6202 return false;
6205 bool equivalent(Type src, Type t)
6207 return immutableOf(src).equals(t.immutableOf());
6210 Type pointerTo(Type type)
6212 if (type.ty == Terror)
6213 return type;
6214 if (!type.pto)
6216 Type t = new TypePointer(type);
6217 if (type.ty == Tfunction)
6219 t.deco = t.merge().deco;
6220 type.pto = t;
6222 else
6223 type.pto = t.merge();
6225 return type.pto;
6228 Type referenceTo(Type type)
6230 if (type.ty == Terror)
6231 return type;
6232 if (!type.rto)
6234 Type t = new TypeReference(type);
6235 type.rto = t.merge();
6237 return type.rto;
6240 // Make corresponding static array type without semantic
6241 Type sarrayOf(Type type, dinteger_t dim)
6243 assert(type.deco);
6244 Type t = new TypeSArray(type, new IntegerExp(Loc.initial, dim, Type.tsize_t));
6245 // according to TypeSArray.semantic()
6246 t = t.addMod(type.mod);
6247 t = t.merge();
6248 return t;
6251 Type arrayOf(Type type)
6253 if (type.ty == Terror)
6254 return type;
6255 if (!type.arrayof)
6257 Type t = new TypeDArray(type);
6258 type.arrayof = t.merge();
6260 return type.arrayof;
6263 /********************************
6264 * Convert to 'const'.
6266 Type constOf(Type type)
6268 //printf("Type::constOf() %p %s\n", type, type.toChars());
6269 if (type.mod == MODFlags.const_)
6270 return type;
6271 if (type.mcache && type.mcache.cto)
6273 assert(type.mcache.cto.mod == MODFlags.const_);
6274 return type.mcache.cto;
6276 Type t = type.makeConst();
6277 t = t.merge();
6278 t.fixTo(type);
6279 //printf("-Type::constOf() %p %s\n", t, t.toChars());
6280 return t;
6283 /********************************
6284 * Convert to 'immutable'.
6286 Type immutableOf(Type type)
6288 //printf("Type::immutableOf() %p %s\n", this, toChars());
6289 if (type.isImmutable())
6290 return type;
6291 if (type.mcache && type.mcache.ito)
6293 assert(type.mcache.ito.isImmutable());
6294 return type.mcache.ito;
6296 Type t = type.makeImmutable();
6297 t = t.merge();
6298 t.fixTo(type);
6299 //printf("\t%p\n", t);
6300 return t;
6303 /********************************
6304 * Make type mutable.
6306 Type mutableOf(Type type)
6308 //printf("Type::mutableOf() %p, %s\n", type, type.toChars());
6309 Type t = type;
6310 if (type.isImmutable())
6312 type.getMcache();
6313 t = type.mcache.ito; // immutable => naked
6314 assert(!t || (t.isMutable() && !t.isShared()));
6316 else if (type.isConst())
6318 type.getMcache();
6319 if (type.isShared())
6321 if (type.isWild())
6322 t = type.mcache.swcto; // shared wild const -> shared
6323 else
6324 t = type.mcache.sto; // shared const => shared
6326 else
6328 if (type.isWild())
6329 t = type.mcache.wcto; // wild const -> naked
6330 else
6331 t = type.mcache.cto; // const => naked
6333 assert(!t || t.isMutable());
6335 else if (type.isWild())
6337 type.getMcache();
6338 if (type.isShared())
6339 t = type.mcache.sto; // shared wild => shared
6340 else
6341 t = type.mcache.wto; // wild => naked
6342 assert(!t || t.isMutable());
6344 if (!t)
6346 t = type.makeMutable();
6347 t = t.merge();
6348 t.fixTo(type);
6350 else
6351 t = t.merge();
6352 assert(t.isMutable());
6353 return t;
6356 Type sharedOf(Type type)
6358 //printf("Type::sharedOf() %p, %s\n", type, type.toChars());
6359 if (type.mod == MODFlags.shared_)
6360 return type;
6361 if (type.mcache && type.mcache.sto)
6363 assert(type.mcache.sto.mod == MODFlags.shared_);
6364 return type.mcache.sto;
6366 Type t = type.makeShared();
6367 t = t.merge();
6368 t.fixTo(type);
6369 //printf("\t%p\n", t);
6370 return t;
6373 Type sharedConstOf(Type type)
6375 //printf("Type::sharedConstOf() %p, %s\n", type, type.toChars());
6376 if (type.mod == (MODFlags.shared_ | MODFlags.const_))
6377 return type;
6378 if (type.mcache && type.mcache.scto)
6380 assert(type.mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_));
6381 return type.mcache.scto;
6383 Type t = type.makeSharedConst();
6384 t = t.merge();
6385 t.fixTo(type);
6386 //printf("\t%p\n", t);
6387 return t;
6390 /********************************
6391 * Make type unshared.
6392 * 0 => 0
6393 * const => const
6394 * immutable => immutable
6395 * shared => 0
6396 * shared const => const
6397 * wild => wild
6398 * wild const => wild const
6399 * shared wild => wild
6400 * shared wild const => wild const
6402 Type unSharedOf(Type type)
6404 //printf("Type::unSharedOf() %p, %s\n", type, type.toChars());
6405 Type t = type;
6407 if (type.isShared())
6409 type.getMcache();
6410 if (type.isWild())
6412 if (type.isConst())
6413 t = type.mcache.wcto; // shared wild const => wild const
6414 else
6415 t = type.mcache.wto; // shared wild => wild
6417 else
6419 if (type.isConst())
6420 t = type.mcache.cto; // shared const => const
6421 else
6422 t = type.mcache.sto; // shared => naked
6424 assert(!t || !t.isShared());
6427 if (!t)
6429 t = type.nullAttributes();
6430 t.mod = type.mod & ~MODFlags.shared_;
6431 t.ctype = type.ctype;
6432 t = t.merge();
6433 t.fixTo(type);
6435 else
6436 t = t.merge();
6437 assert(!t.isShared());
6438 return t;
6441 /********************************
6442 * Convert to 'wild'.
6444 Type wildOf(Type type)
6446 //printf("Type::wildOf() %p %s\n", type, type.toChars());
6447 if (type.mod == MODFlags.wild)
6448 return type;
6449 if (type.mcache && type.mcache.wto)
6451 assert(type.mcache.wto.mod == MODFlags.wild);
6452 return type.mcache.wto;
6454 Type t = type.makeWild();
6455 t = t.merge();
6456 t.fixTo(type);
6457 //printf("\t%p %s\n", t, t.toChars());
6458 return t;
6461 Type wildConstOf(Type type)
6463 //printf("Type::wildConstOf() %p %s\n", type, type.toChars());
6464 if (type.mod == MODFlags.wildconst)
6465 return type;
6466 if (type.mcache && type.mcache.wcto)
6468 assert(type.mcache.wcto.mod == MODFlags.wildconst);
6469 return type.mcache.wcto;
6471 Type t = type.makeWildConst();
6472 t = t.merge();
6473 t.fixTo(type);
6474 //printf("\t%p %s\n", t, t.toChars());
6475 return t;
6478 Type sharedWildOf(Type type)
6480 //printf("Type::sharedWildOf() %p, %s\n", type, type.toChars());
6481 if (type.mod == (MODFlags.shared_ | MODFlags.wild))
6482 return type;
6483 if (type.mcache && type.mcache.swto)
6485 assert(type.mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild));
6486 return type.mcache.swto;
6488 Type t = type.makeSharedWild();
6489 t = t.merge();
6490 t.fixTo(type);
6491 //printf("\t%p %s\n", t, t.toChars());
6492 return t;
6495 Type sharedWildConstOf(Type type)
6497 //printf("Type::sharedWildConstOf() %p, %s\n", type, type.toChars());
6498 if (type.mod == (MODFlags.shared_ | MODFlags.wildconst))
6499 return type;
6500 if (type.mcache && type.mcache.swcto)
6502 assert(type.mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
6503 return type.mcache.swcto;
6505 Type t = type.makeSharedWildConst();
6506 t = t.merge();
6507 t.fixTo(type);
6508 //printf("\t%p %s\n", t, t.toChars());
6509 return t;
6512 Type unqualify(Type type, uint m)
6514 Type t = type.mutableOf().unSharedOf();
6516 Type tn = type.ty == Tenum ? null : type.nextOf();
6517 if (tn && tn.ty != Tfunction)
6519 Type utn = tn.unqualify(m);
6520 if (utn != tn)
6522 if (type.ty == Tpointer)
6523 t = utn.pointerTo();
6524 else if (type.ty == Tarray)
6525 t = utn.arrayOf();
6526 else if (type.ty == Tsarray)
6527 t = new TypeSArray(utn, (cast(TypeSArray)type).dim);
6528 else if (type.ty == Taarray)
6530 t = new TypeAArray(utn, (cast(TypeAArray)type).index);
6532 else
6533 assert(0);
6535 t = t.merge();
6538 t = t.addMod(type.mod & ~m);
6539 return t;
6542 /**************************
6543 * Return type with the top level of it being mutable.
6545 * Params:
6546 * t = type for which the top level mutable version is being returned
6548 * Returns:
6549 * type version with mutable top level
6551 Type toHeadMutable(const Type t)
6553 Type unqualType = cast(Type) t;
6554 if (t.isTypeStruct() || t.isTypeClass())
6555 return unqualType;
6557 if (!t.mod)
6558 return unqualType;
6559 return unqualType.mutableOf();
6562 Type aliasthisOf(Type type)
6564 auto ad = isAggregate(type);
6565 if (!ad || !ad.aliasthis)
6566 return null;
6568 auto s = ad.aliasthis.sym;
6569 if (s.isAliasDeclaration())
6570 s = s.toAlias();
6572 if (s.isTupleDeclaration())
6573 return null;
6575 if (auto vd = s.isVarDeclaration())
6577 auto t = vd.type;
6578 if (vd.needThis())
6579 t = t.addMod(type.mod);
6580 return t;
6582 Dsymbol callable = s.isFuncDeclaration();
6583 callable = callable ? callable : s.isTemplateDeclaration();
6584 if (callable)
6586 auto fd = resolveFuncCall(Loc.initial, null, callable, null, type, ArgumentList(), FuncResolveFlag.quiet);
6587 if (!fd || fd.errors || !functionSemantic(fd))
6588 return Type.terror;
6590 auto t = fd.type.nextOf();
6591 if (!t) // https://issues.dlang.org/show_bug.cgi?id=14185
6592 return Type.terror;
6593 t = t.substWildTo(type.mod == 0 ? MODFlags.mutable : type.mod);
6594 return t;
6596 if (auto d = s.isDeclaration())
6598 assert(d.type);
6599 return d.type;
6601 if (auto ed = s.isEnumDeclaration())
6603 return ed.type;
6606 //printf("%s\n", s.kind());
6607 return null;
6610 /************************************
6611 * Apply MODxxxx bits to existing type.
6613 Type castMod(Type type, MOD mod)
6615 Type t;
6616 switch (mod)
6618 case 0:
6619 t = type.unSharedOf().mutableOf();
6620 break;
6622 case MODFlags.const_:
6623 t = type.unSharedOf().constOf();
6624 break;
6626 case MODFlags.wild:
6627 t = type.unSharedOf().wildOf();
6628 break;
6630 case MODFlags.wildconst:
6631 t = type.unSharedOf().wildConstOf();
6632 break;
6634 case MODFlags.shared_:
6635 t = type.mutableOf().sharedOf();
6636 break;
6638 case MODFlags.shared_ | MODFlags.const_:
6639 t = type.sharedConstOf();
6640 break;
6642 case MODFlags.shared_ | MODFlags.wild:
6643 t = type.sharedWildOf();
6644 break;
6646 case MODFlags.shared_ | MODFlags.wildconst:
6647 t = type.sharedWildConstOf();
6648 break;
6650 case MODFlags.immutable_:
6651 t = type.immutableOf();
6652 break;
6654 default:
6655 assert(0);
6657 return t;
6660 Type substWildTo(Type type, uint mod)
6662 auto tf = type.isTypeFunction();
6663 if (!tf)
6665 //printf("+Type.substWildTo this = %s, mod = x%x\n", toChars(), mod);
6666 Type t;
6668 if (Type tn = type.nextOf())
6670 // substitution has no effect on function pointer type.
6671 if (type.ty == Tpointer && tn.ty == Tfunction)
6673 t = type;
6674 goto L1;
6677 t = tn.substWildTo(mod);
6678 if (t == tn)
6679 t = type;
6680 else
6682 if (type.ty == Tpointer)
6683 t = t.pointerTo();
6684 else if (type.ty == Tarray)
6685 t = t.arrayOf();
6686 else if (type.ty == Tsarray)
6687 t = new TypeSArray(t, (cast(TypeSArray)type).dim.syntaxCopy());
6688 else if (type.ty == Taarray)
6690 t = new TypeAArray(t, (cast(TypeAArray)type).index.syntaxCopy());
6692 else if (type.ty == Tdelegate)
6694 t = new TypeDelegate(t.isTypeFunction());
6696 else
6697 assert(0);
6699 t = t.merge();
6702 else
6703 t = type;
6706 if (type.isWild())
6708 if (mod == MODFlags.immutable_)
6710 t = t.immutableOf();
6712 else if (mod == MODFlags.wildconst)
6714 t = t.wildConstOf();
6716 else if (mod == MODFlags.wild)
6718 if (type.isWildConst())
6719 t = t.wildConstOf();
6720 else
6721 t = t.wildOf();
6723 else if (mod == MODFlags.const_)
6725 t = t.constOf();
6727 else
6729 if (type.isWildConst())
6730 t = t.constOf();
6731 else
6732 t = t.mutableOf();
6735 if (type.isConst())
6736 t = t.addMod(MODFlags.const_);
6737 if (type.isShared())
6738 t = t.addMod(MODFlags.shared_);
6740 //printf("-Type.substWildTo t = %s\n", t.toChars());
6741 return t;
6744 if (!tf.iswild && !(tf.mod & MODFlags.wild))
6745 return tf;
6747 // Substitude inout qualifier of function type to mutable or immutable
6748 // would break type system. Instead substitude inout to the most weak
6749 // qualifer - const.
6750 uint m = MODFlags.const_;
6752 assert(tf.next);
6753 Type tret = tf.next.substWildTo(m);
6754 Parameters* params = tf.parameterList.parameters;
6755 if (tf.mod & MODFlags.wild)
6756 params = tf.parameterList.parameters.copy();
6757 for (size_t i = 0; i < params.length; i++)
6759 Parameter p = (*params)[i];
6760 Type t = p.type.substWildTo(m);
6761 if (t == p.type)
6762 continue;
6763 if (params == tf.parameterList.parameters)
6764 params = tf.parameterList.parameters.copy();
6765 (*params)[i] = new Parameter(p.loc, p.storageClass, t, null, null, null);
6767 if (tf.next == tret && params == tf.parameterList.parameters)
6768 return tf;
6770 // Similar to TypeFunction.syntaxCopy;
6771 auto t = new TypeFunction(ParameterList(params, tf.parameterList.varargs), tret, tf.linkage);
6772 t.mod = ((tf.mod & MODFlags.wild) ? (tf.mod & ~MODFlags.wild) | MODFlags.const_ : tf.mod);
6773 t.isnothrow = tf.isnothrow;
6774 t.isnogc = tf.isnogc;
6775 t.purity = tf.purity;
6776 t.isproperty = tf.isproperty;
6777 t.isref = tf.isref;
6778 t.isreturn = tf.isreturn;
6779 t.isreturnscope = tf.isreturnscope;
6780 t.isScopeQual = tf.isScopeQual;
6781 t.isreturninferred = tf.isreturninferred;
6782 t.isscopeinferred = tf.isscopeinferred;
6783 t.isInOutParam = false;
6784 t.isInOutQual = false;
6785 t.trust = tf.trust;
6786 t.inferenceArguments = tf.inferenceArguments;
6787 t.isctor = tf.isctor;
6788 return t.merge();
6791 /************************************
6792 * Add MODxxxx bits to existing type.
6793 * We're adding, not replacing, so adding const to
6794 * a shared type => "shared const"
6796 Type addMod(Type type, MOD mod)
6798 /* Add anything to immutable, and it remains immutable
6800 Type t = type;
6801 if (!t.isImmutable())
6803 //printf("addMod(%x) %s\n", mod, toChars());
6804 switch (mod)
6806 case 0:
6807 break;
6809 case MODFlags.const_:
6810 if (type.isShared())
6812 if (type.isWild())
6813 t = type.sharedWildConstOf();
6814 else
6815 t = type.sharedConstOf();
6817 else
6819 if (type.isWild())
6820 t = type.wildConstOf();
6821 else
6822 t = t.constOf();
6824 break;
6826 case MODFlags.wild:
6827 if (type.isShared())
6829 if (type.isConst())
6830 t = type.sharedWildConstOf();
6831 else
6832 t = type.sharedWildOf();
6834 else
6836 if (type.isConst())
6837 t = type.wildConstOf();
6838 else
6839 t = type.wildOf();
6841 break;
6843 case MODFlags.wildconst:
6844 if (type.isShared())
6845 t = type.sharedWildConstOf();
6846 else
6847 t = type.wildConstOf();
6848 break;
6850 case MODFlags.shared_:
6851 if (type.isWild())
6853 if (type.isConst())
6854 t = type.sharedWildConstOf();
6855 else
6856 t = type.sharedWildOf();
6858 else
6860 if (type.isConst())
6861 t = type.sharedConstOf();
6862 else
6863 t = type.sharedOf();
6865 break;
6867 case MODFlags.shared_ | MODFlags.const_:
6868 if (type.isWild())
6869 t = type.sharedWildConstOf();
6870 else
6871 t = type.sharedConstOf();
6872 break;
6874 case MODFlags.shared_ | MODFlags.wild:
6875 if (type.isConst())
6876 t = type.sharedWildConstOf();
6877 else
6878 t = type.sharedWildOf();
6879 break;
6881 case MODFlags.shared_ | MODFlags.wildconst:
6882 t = type.sharedWildConstOf();
6883 break;
6885 case MODFlags.immutable_:
6886 t = type.immutableOf();
6887 break;
6889 default:
6890 assert(0);
6893 return t;
6897 * Check whether this type has endless `alias this` recursion.
6899 * Params:
6900 * t = type to check whether it has a recursive alias this
6901 * Returns:
6902 * `true` if `t` has an `alias this` that can be implicitly
6903 * converted back to `t` itself.
6905 private bool checkAliasThisRec(Type t)
6907 Type tb = t.toBasetype();
6908 AliasThisRec* pflag;
6909 if (tb.ty == Tstruct)
6910 pflag = &(cast(TypeStruct)tb).att;
6911 else if (tb.ty == Tclass)
6912 pflag = &(cast(TypeClass)tb).att;
6913 else
6914 return false;
6916 AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask);
6917 if (flag == AliasThisRec.fwdref)
6919 Type att = aliasthisOf(t);
6920 flag = att && att.implicitConvTo(t) ? AliasThisRec.yes : AliasThisRec.no;
6922 *pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask));
6923 return flag == AliasThisRec.yes;
6926 /**************************************
6927 * Check and set 'att' if 't' is a recursive 'alias this' type
6929 * The goal is to prevent endless loops when there is a cycle in the alias this chain.
6930 * Since there is no multiple `alias this`, the chain either ends in a leaf,
6931 * or it loops back on itself as some point.
6933 * Example: S0 -> (S1 -> S2 -> S3 -> S1)
6935 * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
6936 * `S1` is a recursive alias this type, but since `att` is initialized to `null`,
6937 * this still returns `false`, but `att1` is set to `S1`.
6938 * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
6939 * we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
6941 * Params:
6942 * att = type reference used to detect recursion. Should be initialized to `null`.
6943 * t = type of 'alias this' rewrite to attempt
6945 * Returns:
6946 * `false` if the rewrite is safe, `true` if it would loop back around
6948 bool isRecursiveAliasThis(ref Type att, Type t)
6950 //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
6951 auto tb = t.toBasetype();
6952 if (att && tb.equivalent(att))
6953 return true;
6954 else if (!att && tb.checkAliasThisRec())
6955 att = tb;
6956 return false;
6959 /******************************* Private *****************************************/
6961 private:
6963 /* Helper function for `typeToExpression`. Contains common code
6964 * for TypeQualified derived classes.
6966 Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
6968 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
6969 foreach (id; t.idents[i .. t.idents.length])
6971 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
6973 final switch (id.dyncast())
6975 // ... '. ident'
6976 case DYNCAST.identifier:
6977 e = new DotIdExp(e.loc, e, cast(Identifier)id);
6978 break;
6980 // ... '. name!(tiargs)'
6981 case DYNCAST.dsymbol:
6982 auto ti = (cast(Dsymbol)id).isTemplateInstance();
6983 assert(ti);
6984 e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
6985 break;
6987 // ... '[type]'
6988 case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215
6989 e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
6990 break;
6992 // ... '[expr]'
6993 case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215
6994 e = new ArrayExp(t.loc, e, cast(Expression)id);
6995 break;
6997 case DYNCAST.object:
6998 case DYNCAST.tuple:
6999 case DYNCAST.parameter:
7000 case DYNCAST.statement:
7001 case DYNCAST.condition:
7002 case DYNCAST.templateparameter:
7003 case DYNCAST.initializer:
7004 assert(0);
7007 return e;
7010 /**************************
7011 * This evaluates exp while setting length to be the number
7012 * of elements in the tuple t.
7014 Expression semanticLength(Scope* sc, Type t, Expression exp)
7016 if (auto tt = t.isTypeTuple())
7018 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
7019 sym.parent = sc.scopesym;
7020 sc = sc.push(sym);
7021 sc = sc.startCTFE();
7022 exp = exp.expressionSemantic(sc);
7023 exp = resolveProperties(sc, exp);
7024 sc = sc.endCTFE();
7025 sc.pop();
7027 else
7029 sc = sc.startCTFE();
7030 exp = exp.expressionSemantic(sc);
7031 exp = resolveProperties(sc, exp);
7032 sc = sc.endCTFE();
7034 return exp;
7037 Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
7039 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
7040 sym.parent = sc.scopesym;
7042 sc = sc.push(sym);
7043 sc = sc.startCTFE();
7044 exp = exp.expressionSemantic(sc);
7045 exp = resolveProperties(sc, exp);
7046 sc = sc.endCTFE();
7047 sc.pop();
7049 return exp;
7052 /************************************
7053 * Transitively search a type for all function types.
7054 * If any function types with parameters are found that have parameter identifiers
7055 * or default arguments, remove those and create a new type stripped of those.
7056 * This is used to determine the "canonical" version of a type which is useful for
7057 * comparisons.
7058 * Params:
7059 * t = type to scan
7060 * Returns:
7061 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
7062 * the same as t but with no parameter identifiers or default arguments.
7064 Type stripDefaultArgs(Type t)
7066 static Parameters* stripParams(Parameters* parameters)
7068 static Parameter stripParameter(Parameter p)
7070 Type t = stripDefaultArgs(p.type);
7071 return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
7072 ? new Parameter(p.loc, p.storageClass, t, null, null, null)
7073 : null;
7076 if (parameters)
7078 foreach (i, p; *parameters)
7080 Parameter ps = stripParameter(p);
7081 if (ps)
7083 // Replace params with a copy we can modify
7084 Parameters* nparams = new Parameters(parameters.length);
7086 foreach (j, ref np; *nparams)
7088 Parameter pj = (*parameters)[j];
7089 if (j < i)
7090 np = pj;
7091 else if (j == i)
7092 np = ps;
7093 else
7095 Parameter nps = stripParameter(pj);
7096 np = nps ? nps : pj;
7099 return nparams;
7103 return parameters;
7106 if (t is null)
7107 return t;
7109 if (auto tf = t.isTypeFunction())
7111 Type tret = stripDefaultArgs(tf.next);
7112 Parameters* params = stripParams(tf.parameterList.parameters);
7113 if (tret == tf.next && params == tf.parameterList.parameters)
7114 return t;
7115 TypeFunction tr = tf.copy().isTypeFunction();
7116 tr.parameterList.parameters = params;
7117 tr.next = tret;
7118 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
7119 return tr;
7121 else if (auto tt = t.isTypeTuple())
7123 Parameters* args = stripParams(tt.arguments);
7124 if (args == tt.arguments)
7125 return t;
7126 TypeTuple tr = t.copy().isTypeTuple();
7127 tr.arguments = args;
7128 return tr;
7130 else if (t.ty == Tenum)
7132 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
7133 return t;
7135 else
7137 Type tn = t.nextOf();
7138 Type n = stripDefaultArgs(tn);
7139 if (n == tn)
7140 return t;
7141 TypeNext tr = cast(TypeNext)t.copy();
7142 tr.next = n;
7143 return tr;
7147 /******************************
7148 * Get the value of the .max/.min property of `ed` as an Expression.
7149 * Lazily computes the value and caches it in maxval/minval.
7150 * Reports any errors.
7151 * Params:
7152 * ed = the EnumDeclaration being examined
7153 * loc = location to use for error messages
7154 * id = Id::max or Id::min
7155 * Returns:
7156 * corresponding value of .max/.min
7158 Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
7160 //printf("EnumDeclaration::getMaxValue()\n");
7162 static Expression pvalToResult(Expression e, const ref Loc loc)
7164 if (e.op != EXP.error)
7166 e = e.copy();
7167 e.loc = loc;
7169 return e;
7172 Expression* pval = (id == Id.max) ? &ed.maxval : &ed.minval;
7174 Expression errorReturn()
7176 *pval = ErrorExp.get();
7177 return *pval;
7180 if (ed.inuse)
7182 .error(loc, "%s `%s` recursive definition of `.%s` property", ed.kind, ed.toPrettyChars, id.toChars());
7183 return errorReturn();
7185 if (*pval)
7186 return pvalToResult(*pval, loc);
7188 if (ed._scope)
7189 dsymbolSemantic(ed, ed._scope);
7190 if (ed.errors)
7191 return errorReturn();
7192 if (!ed.members)
7194 .error(loc, "%s `%s` is opaque and has no `.%s`", ed.kind, ed.toPrettyChars, id.toChars(), id.toChars());
7195 return errorReturn();
7197 if (!(ed.memtype && ed.memtype.isintegral()))
7199 .error(loc, "%s `%s` has no `.%s` property because base type `%s` is not an integral type", ed.kind, ed.toPrettyChars, id.toChars(),
7200 id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
7201 return errorReturn();
7204 bool first = true;
7205 for (size_t i = 0; i < ed.members.length; i++)
7207 EnumMember em = (*ed.members)[i].isEnumMember();
7208 if (!em)
7209 continue;
7210 if (em.errors)
7212 ed.errors = true;
7213 continue;
7216 if (em.semanticRun < PASS.semanticdone)
7218 .error(em.loc, "%s `%s` is forward referenced looking for `.%s`", em.kind, em.toPrettyChars, id.toChars());
7219 ed.errors = true;
7220 continue;
7223 if (first)
7225 *pval = em.value;
7226 first = false;
7228 else
7230 /* In order to work successfully with UDTs,
7231 * build expressions to do the comparisons,
7232 * and let the semantic analyzer and constant
7233 * folder give us the result.
7236 /* Compute:
7237 * if (e > maxval)
7238 * maxval = e;
7240 Expression e = em.value;
7241 Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval);
7242 ed.inuse = true;
7243 ec = ec.expressionSemantic(em._scope);
7244 ed.inuse = false;
7245 ec = ec.ctfeInterpret();
7246 if (ec.op == EXP.error)
7248 ed.errors = true;
7249 continue;
7251 if (ec.toInteger())
7252 *pval = e;
7255 return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
7258 /******************************************
7259 * Compile the MixinType, returning the type or expression AST.
7261 * Doesn't run semantic() on the returned object.
7262 * Params:
7263 * tm = mixin to compile as a type or expression
7264 * loc = location for error messages
7265 * sc = context
7266 * Return:
7267 * null if error, else RootObject AST as parsed
7269 RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
7271 OutBuffer buf;
7272 if (expressionsToString(buf, sc, tm.exps))
7273 return null;
7275 const errors = global.errors;
7276 const len = buf.length;
7277 buf.writeByte(0);
7278 const str = buf.extractSlice()[0 .. len];
7279 const bool doUnittests = global.params.parsingUnittestsRequired();
7280 auto locm = adjustLocForMixin(str, loc, global.params.mixinOut);
7281 scope p = new Parser!ASTCodegen(locm, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
7282 p.transitionIn = global.params.v.vin;
7283 p.nextToken();
7284 //printf("p.loc.linnum = %d\n", p.loc.linnum);
7286 auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
7287 if (errors != global.errors)
7289 assert(global.errors != errors); // should have caught all these cases
7290 return null;
7292 if (p.token.value != TOK.endOfFile)
7294 .error(loc, "unexpected token `%s` after type `%s`",
7295 p.token.toChars(), o.toChars());
7296 .errorSupplemental(loc, "while parsing string mixin type `%s`",
7297 str.ptr);
7298 return null;
7301 return o;