d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / gcc / d / dmd / typesem.d
blob6721fa6544a7e4b6f8ceaaea7e36655d9c623607
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.globals;
45 import dmd.hdrgen;
46 import dmd.id;
47 import dmd.identifier;
48 import dmd.imphint;
49 import dmd.importc;
50 import dmd.init;
51 import dmd.initsem;
52 import dmd.location;
53 import dmd.visitor;
54 import dmd.mtype;
55 import dmd.objc;
56 import dmd.opover;
57 import dmd.optimize;
58 import dmd.parse;
59 import dmd.root.complex;
60 import dmd.root.ctfloat;
61 import dmd.root.rmem;
62 import dmd.common.outbuffer;
63 import dmd.rootobject;
64 import dmd.root.string;
65 import dmd.root.stringtable;
66 import dmd.safe;
67 import dmd.semantic3;
68 import dmd.sideeffect;
69 import dmd.target;
70 import dmd.tokens;
72 /*************************************
73 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
74 * Setting one of pe/pt/ps.
75 * Params:
76 * loc = location for error messages
77 * sc = context
78 * s = symbol being indexed - could be a tuple, could be an expression
79 * pe = set if s[oindex] is an Expression, otherwise null
80 * pt = set if s[oindex] is a Type, otherwise null
81 * ps = set if s[oindex] is a Dsymbol, otherwise null
82 * oindex = index into s
84 private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
86 auto tup = s.isTupleDeclaration();
88 auto eindex = isExpression(oindex);
89 auto tindex = isType(oindex);
90 auto sindex = isDsymbol(oindex);
92 if (!tup)
94 // It's really an index expression
95 if (tindex)
96 eindex = new TypeExp(loc, tindex);
97 else if (sindex)
98 eindex = symbolToExp(sindex, loc, sc, false);
99 Expression e = new IndexExp(loc, symbolToExp(s, loc, sc, false), eindex);
100 e = e.expressionSemantic(sc);
101 resolveExp(e, pt, pe, ps);
102 return;
105 // Convert oindex to Expression, then try to resolve to constant.
106 if (tindex)
107 tindex.resolve(loc, sc, eindex, tindex, sindex);
108 if (sindex)
109 eindex = symbolToExp(sindex, loc, sc, false);
110 if (!eindex)
112 .error(loc, "index `%s` is not an expression", oindex.toChars());
113 pt = Type.terror;
114 return;
117 eindex = semanticLength(sc, tup, eindex);
118 eindex = eindex.ctfeInterpret();
119 if (eindex.op == EXP.error)
121 pt = Type.terror;
122 return;
124 const(uinteger_t) d = eindex.toUInteger();
125 if (d >= tup.objects.length)
127 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong)tup.objects.length);
128 pt = Type.terror;
129 return;
132 RootObject o = (*tup.objects)[cast(size_t)d];
133 ps = isDsymbol(o);
134 if (auto t = isType(o))
135 pt = t.typeSemantic(loc, sc);
136 if (auto e = isExpression(o))
137 resolveExp(e, pt, pe, ps);
140 /*************************************
141 * Takes an array of Identifiers and figures out if
142 * it represents a Type, Expression, or Dsymbol.
143 * Params:
144 * mt = array of identifiers
145 * loc = location for error messages
146 * sc = context
147 * s = symbol to start search at
148 * scopesym = unused
149 * pe = set if expression otherwise null
150 * pt = set if type otherwise null
151 * ps = set if symbol otherwise null
152 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
154 private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
155 out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
157 version (none)
159 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars());
160 if (scopesym)
161 printf("\tscopesym = '%s'\n", scopesym.toChars());
164 if (!s)
166 /* Look for what user might have intended
168 const p = mt.mutableOf().unSharedOf().toChars();
169 auto id = Identifier.idPool(p[0 .. strlen(p)]);
170 if (const n = importHint(id.toString()))
171 error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr);
172 else if (auto s2 = sc.search_correct(id))
173 error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
174 else if (const q = Scope.search_correct_C(id))
175 error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
176 else if ((id == Id.This && sc.getStructClassScope()) ||
177 (id == Id._super && sc.getClassScope()))
178 error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p);
179 else
180 error(loc, "undefined identifier `%s`", p);
182 pt = Type.terror;
183 return;
186 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
187 Declaration d = s.isDeclaration();
188 if (d && (d.storage_class & STC.templateparameter))
189 s = s.toAlias();
190 else
192 // check for deprecated or disabled aliases
193 // functions are checked after overloading
194 // templates are checked after matching constraints
195 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
196 s.checkDeprecated(loc, sc);
197 if (d)
198 d.checkDisabled(loc, sc, true);
200 s = s.toAlias();
201 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
202 for (size_t i = 0; i < mt.idents.length; i++)
204 RootObject id = mt.idents[i];
205 switch (id.dyncast()) with (DYNCAST)
207 case expression:
208 case type:
209 Type tx;
210 Expression ex;
211 Dsymbol sx;
212 resolveTupleIndex(loc, sc, s, ex, tx, sx, id);
213 if (sx)
215 s = sx.toAlias();
216 continue;
218 if (tx)
219 ex = new TypeExp(loc, tx);
220 assert(ex);
222 ex = typeToExpressionHelper(mt, ex, i + 1);
223 ex = ex.expressionSemantic(sc);
224 resolveExp(ex, pt, pe, ps);
225 return;
226 default:
227 break;
230 Type t = s.getType(); // type symbol, type alias, or type tuple?
231 uint errorsave = global.errors;
232 SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports;
234 Dsymbol sm = s.searchX(loc, sc, id, flags);
235 if (sm)
237 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
239 .error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
240 sm = null;
242 // Same check as in dotIdSemanticProp(DotIdExp)
243 else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
245 // @@@DEPRECATED_2.106@@@
246 // Should be an error in 2.106. Just remove the deprecation call
247 // and uncomment the null assignment
248 deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
249 //sm = null;
252 if (global.errors != errorsave)
254 pt = Type.terror;
255 return;
258 void helper3()
260 Expression e;
261 VarDeclaration v = s.isVarDeclaration();
262 FuncDeclaration f = s.isFuncDeclaration();
263 if (intypeid || !v && !f)
264 e = symbolToExp(s, loc, sc, true);
265 else
266 e = new VarExp(loc, s.isDeclaration(), true);
268 e = typeToExpressionHelper(mt, e, i);
269 e = e.expressionSemantic(sc);
270 resolveExp(e, pt, pe, ps);
273 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
274 if (intypeid && !t && sm && sm.needThis())
275 return helper3();
277 if (VarDeclaration v = s.isVarDeclaration())
279 // https://issues.dlang.org/show_bug.cgi?id=19913
280 // v.type would be null if it is a forward referenced member.
281 if (v.type is null)
282 v.dsymbolSemantic(sc);
283 if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
284 v.type.isConst() || v.type.isImmutable())
286 // https://issues.dlang.org/show_bug.cgi?id=13087
287 // this.field is not constant always
288 if (!v.isThisDeclaration())
289 return helper3();
293 if (!sm)
294 return helper3();
296 if (sm.isAliasDeclaration)
297 sm.checkDeprecated(loc, sc);
298 s = sm.toAlias();
301 if (auto em = s.isEnumMember())
303 // It's not a type, it's an expression
304 pe = em.getVarExp(loc, sc);
305 return;
307 if (auto v = s.isVarDeclaration())
309 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
310 * because some variables used in type context need to prevent lowering
311 * to a literal or contextful expression. For example:
313 * enum a = 1; alias b = a;
314 * template X(alias e){ alias v = e; } alias x = X!(1);
315 * struct S { int v; alias w = v; }
316 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
317 * // because getDsymbol() need to work in AliasDeclaration::semantic().
319 if (!v.type ||
320 !v.type.deco && v.inuse)
322 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
323 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
324 else
325 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
326 pt = Type.terror;
327 return;
329 if (v.type.ty == Terror)
330 pt = Type.terror;
331 else
332 pe = new VarExp(loc, v);
333 return;
335 if (auto fld = s.isFuncLiteralDeclaration())
337 //printf("'%s' is a function literal\n", fld.toChars());
338 auto e = new FuncExp(loc, fld);
339 pe = e.expressionSemantic(sc);
340 return;
342 version (none)
344 if (FuncDeclaration fd = s.isFuncDeclaration())
346 pe = new DsymbolExp(loc, fd);
347 return;
351 Type t;
352 while (1)
354 t = s.getType();
355 if (t)
356 break;
357 ps = s;
358 return;
361 if (auto ti = t.isTypeInstance())
362 if (ti != mt && !ti.deco)
364 if (!ti.tempinst.errors)
365 error(loc, "forward reference to `%s`", ti.toChars());
366 pt = Type.terror;
367 return;
370 if (t.ty == Ttuple)
371 pt = t;
372 else
373 pt = t.merge();
376 /***************************************
377 * Search for identifier id as a member of `this`.
378 * `id` may be a template instance.
380 * Params:
381 * loc = location to print the error messages
382 * sc = the scope where the symbol is located
383 * id = the id of the symbol
384 * flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports`
386 * Returns:
387 * symbol found, NULL if not
389 private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags)
391 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
392 Dsymbol s = dsym.toAlias();
393 Dsymbol sm;
394 if (Declaration d = s.isDeclaration())
396 if (d.inuse)
398 .error(loc, "circular reference to `%s`", d.toPrettyChars());
399 return null;
402 switch (id.dyncast())
404 case DYNCAST.identifier:
405 sm = s.search(loc, cast(Identifier)id, flags);
406 break;
407 case DYNCAST.dsymbol:
409 // It's a template instance
410 //printf("\ttemplate instance id\n");
411 Dsymbol st = cast(Dsymbol)id;
412 TemplateInstance ti = st.isTemplateInstance();
413 sm = s.search(loc, ti.name);
414 if (!sm)
415 return null;
416 sm = sm.toAlias();
417 TemplateDeclaration td = sm.isTemplateDeclaration();
418 if (!td)
419 return null; // error but handled later
420 ti.tempdecl = td;
421 if (!ti.semanticRun)
422 ti.dsymbolSemantic(sc);
423 sm = ti.toAlias();
424 break;
426 case DYNCAST.type:
427 case DYNCAST.expression:
428 default:
429 assert(0);
431 return sm;
434 /***************************************************
435 * Determine if type t is copyable.
436 * Params:
437 * t = type to check
438 * Returns:
439 * true if we can copy it
441 bool isCopyable(Type t)
443 //printf("isCopyable() %s\n", t.toChars());
444 if (auto ts = t.isTypeStruct())
446 if (ts.sym.postblit &&
447 ts.sym.postblit.storage_class & STC.disable)
448 return false;
449 if (ts.sym.hasCopyCtor)
451 // check if there is a matching overload of the copy constructor and whether it is disabled or not
452 // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
453 Dsymbol ctor = search_function(ts.sym, Id.ctor);
454 assert(ctor);
455 scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
456 el.type = cast() ts;
457 Expressions* args = new Expressions();
458 args.push(el);
459 FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet);
460 if (!f || f.storage_class & STC.disable)
461 return false;
464 return true;
467 /************************************
468 * Determine mutability of indirections in (ref) t.
470 * Returns: When the type has any mutable indirections, returns 0.
471 * When all indirections are immutable, returns 2.
472 * Otherwise, when the type has const/inout indirections, returns 1.
474 * Params:
475 * isref = if true, check `ref t`; otherwise, check just `t`
476 * t = the type that is being checked
478 int mutabilityOfType(bool isref, Type t)
480 if (isref)
482 if (t.mod & MODFlags.immutable_)
483 return 2;
484 if (t.mod & (MODFlags.const_ | MODFlags.wild))
485 return 1;
486 return 0;
489 t = t.baseElemOf();
491 if (!t.hasPointers() || t.mod & MODFlags.immutable_)
492 return 2;
494 /* Accept immutable(T)[] and immutable(T)* as being strongly pure
496 if (t.ty == Tarray || t.ty == Tpointer)
498 Type tn = t.nextOf().toBasetype();
499 if (tn.mod & MODFlags.immutable_)
500 return 2;
501 if (tn.mod & (MODFlags.const_ | MODFlags.wild))
502 return 1;
505 /* The rest of this is too strict; fix later.
506 * For example, the only pointer members of a struct may be immutable,
507 * which would maintain strong purity.
508 * (Just like for dynamic arrays and pointers above.)
510 if (t.mod & (MODFlags.const_ | MODFlags.wild))
511 return 1;
513 /* Should catch delegates and function pointers, and fold in their purity
515 return 0;
518 /********************************************
519 * Set 'purity' field of 'typeFunction'.
520 * Do this lazily, as the parameter types might be forward referenced.
522 extern(C++) void purityLevel(TypeFunction typeFunction)
524 TypeFunction tf = typeFunction;
525 if (tf.purity != PURE.fwdref)
526 return;
528 typeFunction.purity = PURE.const_; // assume strong until something weakens it
530 /* Evaluate what kind of purity based on the modifiers for the parameters
532 foreach (i, fparam; tf.parameterList)
534 Type t = fparam.type;
535 if (!t)
536 continue;
538 if (fparam.storageClass & (STC.lazy_ | STC.out_))
540 typeFunction.purity = PURE.weak;
541 break;
543 const pref = (fparam.storageClass & STC.ref_) != 0;
544 if (mutabilityOfType(pref, t) == 0)
545 typeFunction.purity = PURE.weak;
548 tf.purity = typeFunction.purity;
551 /******************************************
552 * We've mistakenly parsed `t` as a type.
553 * Redo `t` as an Expression only if there are no type modifiers.
554 * Params:
555 * t = mistaken type
556 * Returns:
557 * t redone as Expression, null if cannot
559 Expression typeToExpression(Type t)
561 static Expression visitSArray(TypeSArray t)
563 if (auto e = t.next.typeToExpression())
564 return new ArrayExp(t.dim.loc, e, t.dim);
565 return null;
568 static Expression visitAArray(TypeAArray t)
570 if (auto e = t.next.typeToExpression())
572 if (auto ei = t.index.typeToExpression())
573 return new ArrayExp(t.loc, e, ei);
575 return null;
578 static Expression visitIdentifier(TypeIdentifier t)
580 return typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident));
583 static Expression visitInstance(TypeInstance t)
585 return typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst));
588 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
589 static Expression visitMixin(TypeMixin t)
591 return new TypeExp(t.loc, t);
594 if (t.mod)
595 return null;
596 switch (t.ty)
598 case Tsarray: return visitSArray(t.isTypeSArray());
599 case Taarray: return visitAArray(t.isTypeAArray());
600 case Tident: return visitIdentifier(t.isTypeIdentifier());
601 case Tinstance: return visitInstance(t.isTypeInstance());
602 case Tmixin: return visitMixin(t.isTypeMixin());
603 default: return null;
607 /*************************************
608 * https://issues.dlang.org/show_bug.cgi?id=14488
609 * Check if the inner most base type is complex or imaginary.
610 * Should only give alerts when set to emit transitional messages.
611 * Params:
612 * type = type to check
613 * loc = The source location.
614 * sc = scope of the type
616 extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
618 if (sc.isDeprecated())
619 return false;
620 // Don't complain if we're inside a template constraint
621 // https://issues.dlang.org/show_bug.cgi?id=21831
622 if (sc.flags & SCOPE.constraint)
623 return false;
625 Type t = type.baseElemOf();
626 while (t.ty == Tpointer || t.ty == Tarray)
627 t = t.nextOf().baseElemOf();
629 // Basetype is an opaque enum, nothing to check.
630 if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
631 return false;
633 if (t.isimaginary() || t.iscomplex())
635 if (sc.flags & SCOPE.Cfile)
636 return true; // complex/imaginary not deprecated in C code
637 Type rt;
638 switch (t.ty)
640 case Tcomplex32:
641 case Timaginary32:
642 rt = Type.tfloat32;
643 break;
645 case Tcomplex64:
646 case Timaginary64:
647 rt = Type.tfloat64;
648 break;
650 case Tcomplex80:
651 case Timaginary80:
652 rt = Type.tfloat80;
653 break;
655 default:
656 assert(0);
658 // @@@DEPRECATED_2.117@@@
659 // Deprecated in 2.097 - Can be made an error from 2.117.
660 // The deprecation period is longer than usual as `cfloat`,
661 // `cdouble`, and `creal` were quite widely used.
662 if (t.iscomplex())
664 deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
665 type.toChars(), rt.toChars());
666 return true;
668 else
670 deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead",
671 type.toChars(), rt.toChars());
672 return true;
675 return false;
678 /********************************
679 * 'args' are being matched to function type 'tf'
680 * Determine match level.
681 * Params:
682 * tf = function type
683 * tthis = type of `this` pointer, null if not member function
684 * argumentList = arguments to function call
685 * flag = 1: performing a partial ordering match
686 * errorHelper = delegate to call for error messages
687 * sc = context
688 * Returns:
689 * MATCHxxxx
691 extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null)
693 //printf("TypeFunction::callMatch() %s\n", tf.toChars());
694 MATCH match = MATCH.exact; // assume exact match
695 ubyte wildmatch = 0;
697 if (tthis)
699 Type t = tthis;
700 if (t.toBasetype().ty == Tpointer)
701 t = t.toBasetype().nextOf(); // change struct* to struct
702 if (t.mod != tf.mod)
704 if (MODimplicitConv(t.mod, tf.mod))
705 match = MATCH.constant;
706 else if ((tf.mod & MODFlags.wild) && MODimplicitConv(t.mod, (tf.mod & ~MODFlags.wild) | MODFlags.const_))
708 match = MATCH.constant;
710 else
711 return MATCH.nomatch;
713 if (tf.isWild())
715 if (t.isWild())
716 wildmatch |= MODFlags.wild;
717 else if (t.isConst())
718 wildmatch |= MODFlags.const_;
719 else if (t.isImmutable())
720 wildmatch |= MODFlags.immutable_;
721 else
722 wildmatch |= MODFlags.mutable;
726 ParameterList* parameterList = &tf.parameterList;
727 const nparams = parameterList.length;
728 if (argumentList.length > nparams)
730 if (parameterList.varargs == VarArg.none)
732 // suppress early exit if an error message is wanted,
733 // so we can check any matching args are valid
734 if (!errorHelper)
735 return MATCH.nomatch;
737 // too many args; no match
738 match = MATCH.convert; // match ... with a "conversion" match level
741 // https://issues.dlang.org/show_bug.cgi?id=22997
742 if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
744 if (errorHelper)
746 OutBuffer buf;
747 buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
748 errorHelper(buf.peekChars());
750 return MATCH.nomatch;
752 const(char)* failMessage;
753 const(char)** pMessage = errorHelper ? &failMessage : null;
754 auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
755 Expression[] args;
756 if (!resolvedArgs)
758 if (failMessage)
760 errorHelper(failMessage);
761 return MATCH.nomatch;
764 // if no message was provided, it was because of overflow which will be diagnosed below
765 match = MATCH.nomatch;
766 args = argumentList.arguments ? (*argumentList.arguments)[] : null;
768 else
770 args = (*resolvedArgs)[];
773 foreach (u, p; *parameterList)
775 if (u >= args.length)
776 break;
778 Expression arg = args[u];
779 if (!arg)
780 continue; // default argument
782 Type tprm = p.type;
783 Type targ = arg.type;
785 if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
787 const isRef = p.isReference();
788 wildmatch |= targ.deduceWild(tprm, isRef);
791 if (wildmatch)
793 /* Calculate wild matching modifier
795 if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
796 wildmatch = MODFlags.const_;
797 else if (wildmatch & MODFlags.immutable_)
798 wildmatch = MODFlags.immutable_;
799 else if (wildmatch & MODFlags.wild)
800 wildmatch = MODFlags.wild;
801 else
803 assert(wildmatch & MODFlags.mutable);
804 wildmatch = MODFlags.mutable;
808 foreach (u, p; *parameterList)
810 MATCH m;
812 assert(p);
814 // One or more arguments remain
815 if (u < args.length)
817 Expression arg = args[u];
818 if (!arg)
819 continue; // default argument
820 m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);
822 else if (p.defaultArg)
823 continue;
825 /* prefer matching the element type rather than the array
826 * type when more arguments are present with T[]...
828 if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
829 goto L1;
831 //printf("\tm = %d\n", m);
832 if (m == MATCH.nomatch) // if no match
835 if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
837 auto trailingArgs = args[u .. $];
838 if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
839 return vmatch < match ? vmatch : match;
840 // Error message was already generated in `matchTypeSafeVarArgs`
841 if (failMessage)
842 errorHelper(failMessage);
843 return MATCH.nomatch;
845 if (pMessage && u >= args.length)
846 *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`",
847 u + 1, parameterToChars(p, tf, false));
848 // If an error happened previously, `pMessage` was already filled
849 else if (pMessage && !*pMessage)
850 *pMessage = tf.getParamError(args[u], p);
852 if (errorHelper)
853 errorHelper(*pMessage);
854 return MATCH.nomatch;
856 if (m < match)
857 match = m; // pick worst match
860 if (errorHelper && !parameterList.varargs && args.length > nparams)
862 // all parameters had a match, but there are surplus args
863 errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length));
864 return MATCH.nomatch;
866 //printf("match = %d\n", match);
867 return match;
871 * Used by `callMatch` to check if the copy constructor may be called to
872 * copy the argument
874 * This is done by seeing if a call to the copy constructor can be made:
875 * ```
876 * typeof(tprm) __copytmp;
877 * copytmp.__copyCtor(arg);
878 * ```
880 private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
881 Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
883 auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
884 tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
885 tmp.dsymbolSemantic(sc);
886 Expression ve = new VarExp(arg.loc, tmp);
887 Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
888 e = new CallExp(arg.loc, e, arg);
889 //printf("e = %s\n", e.toChars());
890 if (dmd.expressionsem.trySemantic(e, sc))
891 return true;
893 if (pMessage)
895 /* https://issues.dlang.org/show_bug.cgi?id=22202
897 * If a function was deduced by semantic on the CallExp,
898 * it means that resolveFuncCall completed succesfully.
899 * Therefore, there exists a callable copy constructor,
900 * however, it cannot be called because scope constraints
901 * such as purity, safety or nogc.
903 OutBuffer buf;
904 auto callExp = e.isCallExp();
905 if (auto f = callExp.f)
907 char[] s;
908 if (!f.isPure && sc.func.setImpure())
909 s ~= "pure ";
910 if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
911 s ~= "@safe ";
912 if (!f.isNogc && sc.func.setGC(arg.loc, null))
913 s ~= "nogc ";
914 if (f.isDisabled() && !f.isGenerated())
916 /* https://issues.dlang.org/show_bug.cgi?id=24301
917 * Copy constructor is explicitly disabled
919 buf.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`",
920 f.type.toChars());
922 else if (s)
924 s[$-1] = '\0';
925 buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
927 else if (f.isGenerated() && f.isDisabled())
929 /* https://issues.dlang.org/show_bug.cgi?id=23097
930 * Compiler generated copy constructor failed.
932 buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
933 argStruct.toChars());
935 else
937 /* Although a copy constructor may exist, no suitable match was found.
938 * i.e: `inout` constructor creates `const` object, not mutable.
939 * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
941 goto Lnocpctor;
944 else
946 Lnocpctor:
947 buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
948 argStruct.toChars(), arg.type.toChars(), tprm.toChars());
951 *pMessage = buf.extractChars();
953 return false;
957 * Match a single parameter to an argument.
959 * This function is called by `TypeFunction.callMatch` while iterating over
960 * the list of parameter. Here we check if `arg` is a match for `p`,
961 * which is mostly about checking if `arg.type` converts to `p`'s type
962 * and some check about value reference.
964 * Params:
965 * tf = The `TypeFunction`, only used for error reporting
966 * p = The parameter of `tf` being matched
967 * arg = Argument being passed (bound) to `p`
968 * wildmatch = Wild (`inout`) matching level, derived from the full argument list
969 * flag = A non-zero value means we're doing a partial ordering check
970 * (no value semantic check)
971 * sc = Scope we are in
972 * pMessage = A buffer to write the error in, or `null`
974 * Returns: Whether `trailingArgs` match `p`.
976 private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
977 Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
979 //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
980 MATCH m;
981 Type targ = arg.type;
982 Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
984 if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
985 m = MATCH.convert;
986 else if (flag)
988 // for partial ordering, value is an irrelevant mockup, just look at the type
989 m = targ.implicitConvTo(tprm);
991 else
993 const isRef = p.isReference();
994 StructDeclaration argStruct, prmStruct;
996 // first look for a copy constructor
997 if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
999 // if the argument and the parameter are of the same unqualified struct type
1000 argStruct = (cast(TypeStruct)targ).sym;
1001 prmStruct = (cast(TypeStruct)tprm).sym;
1004 // check if the copy constructor may be called to copy the argument
1005 if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
1007 if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
1008 return MATCH.nomatch;
1009 m = MATCH.exact;
1011 else
1013 import dmd.dcast : cimplicitConvTo;
1014 m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
1018 // Non-lvalues do not match ref or out parameters
1019 if (p.isReference())
1021 // https://issues.dlang.org/show_bug.cgi?id=13783
1022 // Don't use toBasetype() to handle enum types.
1023 Type ta = targ;
1024 Type tp = tprm;
1025 //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
1027 if (m && !arg.isLvalue())
1029 if (p.storageClass & STC.out_)
1031 if (pMessage) *pMessage = tf.getParamError(arg, p);
1032 return MATCH.nomatch;
1035 if (arg.op == EXP.string_ && tp.ty == Tsarray)
1037 if (ta.ty != Tsarray)
1039 Type tn = tp.nextOf().castMod(ta.nextOf().mod);
1040 dinteger_t dim = (cast(StringExp)arg).len;
1041 ta = tn.sarrayOf(dim);
1044 else if (arg.op == EXP.slice && tp.ty == Tsarray)
1046 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1047 if (ta.ty != Tsarray)
1049 Type tn = ta.nextOf();
1050 dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
1051 ta = tn.sarrayOf(dim);
1054 else if (p.storageClass & STC.constscoperef)
1056 // Allow converting a literal to an `in` which is `ref`
1057 if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
1059 Type tn = tp.nextOf();
1060 dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
1061 ta = tn.sarrayOf(dim);
1064 // Need to make this a rvalue through a temporary
1065 m = MATCH.convert;
1067 else if (global.params.rvalueRefParam != FeatureState.enabled ||
1068 p.storageClass & STC.out_ ||
1069 !arg.type.isCopyable()) // can't copy to temp for ref parameter
1071 if (pMessage) *pMessage = tf.getParamError(arg, p);
1072 return MATCH.nomatch;
1074 else
1076 /* in functionParameters() we'll convert this
1077 * rvalue into a temporary
1079 m = MATCH.convert;
1083 /* If the match is not already perfect or if the arg
1084 is not a lvalue then try the `alias this` chain
1085 see https://issues.dlang.org/show_bug.cgi?id=15674
1086 and https://issues.dlang.org/show_bug.cgi?id=21905
1088 if (ta != tp || !arg.isLvalue())
1090 Type firsttab = ta.toBasetype();
1091 while (1)
1093 Type tab = ta.toBasetype();
1094 Type tat = tab.aliasthisOf();
1095 if (!tat || !tat.implicitConvTo(tprm))
1096 break;
1097 if (tat == tab || tat == firsttab)
1098 break;
1099 ta = tat;
1103 /* A ref variable should work like a head-const reference.
1104 * e.g. disallows:
1105 * ref T <- an lvalue of const(T) argument
1106 * ref T[dim] <- an lvalue of const(T[dim]) argument
1108 if (!ta.constConv(tp))
1110 if (pMessage) *pMessage = tf.getParamError(arg, p);
1111 return MATCH.nomatch;
1114 return m;
1117 // arguments get specially formatted
1118 private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter par)
1120 if (global.gag && !global.params.v.showGaggedErrors)
1121 return null;
1122 // show qualification when toChars() is the same but types are different
1123 // https://issues.dlang.org/show_bug.cgi?id=19948
1124 // when comparing the type with strcmp, we need to drop the qualifier
1125 bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) &&
1126 strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0;
1127 auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars();
1128 OutBuffer buf;
1129 // only mention rvalue if it's relevant
1130 const rv = !arg.isLvalue() && par.isReference();
1131 buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
1132 rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
1133 parameterToChars(par, tf, qual));
1134 return buf.extractChars();
1138 * Match the remaining arguments `trailingArgs` with parameter `p`.
1140 * Assume we already checked that `p` is the last parameter of `tf`,
1141 * and we want to know whether the arguments would match `p`.
1143 * Params:
1144 * tf = The `TypeFunction`, only used for error reporting
1145 * p = The last parameter of `tf` which is variadic
1146 * trailingArgs = The remaining arguments that should match `p`
1147 * pMessage = A buffer to write the error in, or `null`
1149 * Returns: Whether `trailingArgs` match `p`.
1151 private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
1152 Expression[] trailingArgs, const(char)** pMessage)
1154 Type tb = p.type.toBasetype();
1156 switch (tb.ty)
1158 case Tsarray:
1159 TypeSArray tsa = cast(TypeSArray)tb;
1160 dinteger_t sz = tsa.dim.toInteger();
1161 if (sz != trailingArgs.length)
1163 if (pMessage)
1164 *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
1165 sz, trailingArgs.length);
1166 return MATCH.nomatch;
1168 goto case Tarray;
1169 case Tarray:
1171 MATCH match = MATCH.exact;
1172 TypeArray ta = cast(TypeArray)tb;
1173 foreach (arg; trailingArgs)
1175 MATCH m;
1176 assert(arg);
1178 /* If lazy array of delegates,
1179 * convert arg(s) to delegate(s)
1181 Type tret = p.isLazyArray();
1182 if (tret)
1184 if (ta.next.equals(arg.type))
1185 m = MATCH.exact;
1186 else if (tret.toBasetype().ty == Tvoid)
1187 m = MATCH.convert;
1188 else
1190 m = arg.implicitConvTo(tret);
1191 if (m == MATCH.nomatch)
1192 m = arg.implicitConvTo(ta.next);
1195 else
1196 m = arg.implicitConvTo(ta.next);
1198 if (m == MATCH.nomatch)
1200 if (pMessage) *pMessage = tf.getParamError(arg, p);
1201 return MATCH.nomatch;
1203 if (m < match)
1204 match = m;
1206 return match;
1208 case Tclass:
1209 // We leave it up to the actual constructor call to do the matching.
1210 return MATCH.exact;
1212 default:
1213 // We can have things as `foo(int[int] wat...)` but they only match
1214 // with an associative array proper.
1215 if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p);
1216 return MATCH.nomatch;
1220 /***************************************
1221 * Return !=0 if type has pointers that need to
1222 * be scanned by the GC during a collection cycle.
1224 extern(C++) bool hasPointers(Type t)
1226 bool visitType(Type _) { return false; }
1227 bool visitDArray(TypeDArray _) { return true; }
1228 bool visitAArray(TypeAArray _) { return true; }
1229 bool visitPointer(TypePointer _) { return true; }
1230 bool visitDelegate(TypeDelegate _) { return true; }
1231 bool visitClass(TypeClass _) { return true; }
1232 bool visitEnum(TypeEnum t) { return t.memType().hasPointers(); }
1234 /* Although null isn't dereferencable, treat it as a pointer type for
1235 * attribute inference, generic code, etc.
1237 bool visitNull(TypeNull _) { return true; }
1239 bool visitSArray(TypeSArray t)
1241 /* Don't want to do this, because:
1242 * struct S { T* array[0]; }
1243 * may be a variable length struct.
1245 //if (dim.toInteger() == 0)
1246 // return false;
1248 if (t.next.ty == Tvoid)
1250 // Arrays of void contain arbitrary data, which may include pointers
1251 return true;
1253 else
1254 return t.next.hasPointers();
1257 bool visitStruct(TypeStruct t)
1259 StructDeclaration sym = t.sym;
1261 if (sym.members && !sym.determineFields() && sym.type != Type.terror)
1262 error(sym.loc, "no size because of forward references");
1264 sym.determineTypeProperties();
1265 return sym.hasPointerField;
1269 switch(t.ty)
1271 default: return visitType(t);
1272 case Tsarray: return visitSArray(t.isTypeSArray());
1273 case Tarray: return visitDArray(t.isTypeDArray());
1274 case Taarray: return visitAArray(t.isTypeAArray());
1275 case Tpointer: return visitPointer(t.isTypePointer());
1276 case Tdelegate: return visitDelegate(t.isTypeDelegate());
1277 case Tstruct: return visitStruct(t.isTypeStruct());
1278 case Tenum: return visitEnum(t.isTypeEnum());
1279 case Tclass: return visitClass(t.isTypeClass());
1280 case Tnull: return visitNull(t.isTypeNull());
1284 /******************************************
1285 * Perform semantic analysis on a type.
1286 * Params:
1287 * type = Type AST node
1288 * loc = the location of the type
1289 * sc = context
1290 * Returns:
1291 * `Type` with completed semantic analysis, `Terror` if errors
1292 * were encountered
1294 extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
1296 static Type error()
1298 return Type.terror;
1301 Type visitType(Type t)
1303 // @@@DEPRECATED_2.110@@@
1304 // Use of `cent` and `ucent` has always been an error.
1305 // Starting from 2.100, recommend core.int128 as a replace for the
1306 // lack of compiler support.
1307 if (t.ty == Tint128 || t.ty == Tuns128)
1309 .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
1310 return error();
1313 return t.merge();
1316 Type visitComplex(TypeBasic t)
1318 if (!(sc.flags & SCOPE.Cfile))
1319 return visitType(t);
1321 auto tc = getComplexLibraryType(loc, sc, t.ty);
1322 if (tc.ty == Terror)
1323 return tc;
1324 return tc.addMod(t.mod).merge();
1327 Type visitVector(TypeVector mtype)
1329 const errors = global.errors;
1330 mtype.basetype = mtype.basetype.typeSemantic(loc, sc);
1331 if (errors != global.errors)
1332 return error();
1333 mtype.basetype = mtype.basetype.toBasetype().mutableOf();
1334 if (mtype.basetype.ty != Tsarray)
1336 .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars());
1337 return error();
1339 TypeSArray t = mtype.basetype.isTypeSArray();
1340 const sz = cast(int)t.size(loc);
1341 final switch (target.isVectorTypeSupported(sz, t.nextOf()))
1343 case 0:
1344 // valid
1345 break;
1347 case 1:
1348 // no support at all
1349 .error(loc, "SIMD vector types not supported on this platform");
1350 return error();
1352 case 2:
1353 // invalid base type
1354 .error(loc, "vector type `%s` is not supported on this platform", mtype.toChars());
1355 return error();
1357 case 3:
1358 // invalid size
1359 .error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars());
1360 return error();
1362 return merge(mtype);
1365 Type visitSArray(TypeSArray mtype)
1367 //printf("TypeSArray::semantic() %s\n", toChars());
1368 Type t;
1369 Expression e;
1370 Dsymbol s;
1371 mtype.next.resolve(loc, sc, e, t, s);
1373 if (auto tup = s ? s.isTupleDeclaration() : null)
1375 mtype.dim = semanticLength(sc, tup, mtype.dim);
1376 mtype.dim = mtype.dim.ctfeInterpret();
1377 if (mtype.dim.op == EXP.error)
1378 return error();
1380 uinteger_t d = mtype.dim.toUInteger();
1381 if (d >= tup.objects.length)
1383 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tup.objects.length);
1384 return error();
1387 RootObject o = (*tup.objects)[cast(size_t)d];
1388 if (auto tt = o.isType())
1389 return tt.addMod(mtype.mod);
1390 .error(loc, "`%s` is not a type", mtype.toChars());
1391 return error();
1394 if (t && t.ty == Terror)
1395 return error();
1397 Type tn = mtype.next.typeSemantic(loc, sc);
1398 if (tn.ty == Terror)
1399 return error();
1401 Type tbn = tn.toBasetype();
1402 if (mtype.dim)
1404 auto errors = global.errors;
1405 mtype.dim = semanticLength(sc, tbn, mtype.dim);
1406 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
1407 if (errors != global.errors)
1408 return error();
1410 mtype.dim = mtype.dim.optimize(WANTvalue);
1411 mtype.dim = mtype.dim.ctfeInterpret();
1412 if (mtype.dim.op == EXP.error)
1413 return error();
1415 errors = global.errors;
1416 dinteger_t d1 = mtype.dim.toInteger();
1417 if (errors != global.errors)
1418 return error();
1420 mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
1421 mtype.dim = mtype.dim.optimize(WANTvalue);
1422 if (mtype.dim.op == EXP.error)
1423 return error();
1425 errors = global.errors;
1426 dinteger_t d2 = mtype.dim.toInteger();
1427 if (errors != global.errors)
1428 return error();
1430 if (mtype.dim.op == EXP.error)
1431 return error();
1433 Type overflowError()
1435 .error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
1436 mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, target.maxStaticDataSize);
1437 return error();
1440 if (d1 != d2)
1441 return overflowError();
1443 Type tbx = tbn.baseElemOf();
1444 if (tbx.ty == Tstruct && !tbx.isTypeStruct().sym.members ||
1445 tbx.ty == Tenum && !tbx.isTypeEnum().sym.members)
1447 /* To avoid meaningless error message, skip the total size limit check
1448 * when the bottom of element type is opaque.
1451 else if (tbn.isTypeBasic() ||
1452 tbn.ty == Tpointer ||
1453 tbn.ty == Tarray ||
1454 tbn.ty == Tsarray ||
1455 tbn.ty == Taarray ||
1456 (tbn.ty == Tstruct && tbn.isTypeStruct().sym.sizeok == Sizeok.done) ||
1457 tbn.ty == Tclass)
1459 /* Only do this for types that don't need to have semantic()
1460 * run on them for the size, since they may be forward referenced.
1462 bool overflow = false;
1463 if (mulu(tbn.size(loc), d2, overflow) > target.maxStaticDataSize || overflow)
1464 return overflowError();
1467 switch (tbn.ty)
1469 case Ttuple:
1471 // Index the tuple to get the type
1472 assert(mtype.dim);
1473 TypeTuple tt = tbn.isTypeTuple();
1474 uinteger_t d = mtype.dim.toUInteger();
1475 if (d >= tt.arguments.length)
1477 .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tt.arguments.length);
1478 return error();
1480 Type telem = (*tt.arguments)[cast(size_t)d].type;
1481 return telem.addMod(mtype.mod);
1484 case Tfunction:
1485 case Tnone:
1486 .error(loc, "cannot have array of `%s`", tbn.toChars());
1487 return error();
1489 default:
1490 break;
1492 if (tbn.isscope())
1494 .error(loc, "cannot have array of scope `%s`", tbn.toChars());
1495 return error();
1498 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
1499 * and const(T)[3] become const(T[3])
1501 mtype.next = tn;
1502 mtype.transitive();
1503 return mtype.addMod(tn.mod).merge();
1506 Type visitDArray(TypeDArray mtype)
1508 Type tn = mtype.next.typeSemantic(loc, sc);
1509 Type tbn = tn.toBasetype();
1510 switch (tbn.ty)
1512 case Ttuple:
1513 return tbn;
1515 case Tfunction:
1516 case Tnone:
1517 .error(loc, "cannot have array of `%s`", tbn.toChars());
1518 return error();
1520 case Terror:
1521 return error();
1523 default:
1524 break;
1526 if (tn.isscope())
1528 .error(loc, "cannot have array of scope `%s`", tn.toChars());
1529 return error();
1531 mtype.next = tn;
1532 mtype.transitive();
1533 return merge(mtype);
1536 Type visitAArray(TypeAArray mtype)
1538 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
1539 if (mtype.deco)
1541 return mtype;
1544 mtype.loc = loc;
1545 if (sc)
1546 sc.setNoFree();
1548 // Deal with the case where we thought the index was a type, but
1549 // in reality it was an expression.
1550 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)
1552 Expression e;
1553 Type t;
1554 Dsymbol s;
1555 mtype.index.resolve(loc, sc, e, t, s);
1557 // https://issues.dlang.org/show_bug.cgi?id=15478
1558 if (s)
1559 e = symbolToExp(s, loc, sc, false);
1561 if (e)
1563 // It was an expression -
1564 // Rewrite as a static array
1565 auto tsa = new TypeSArray(mtype.next, e);
1566 return tsa.typeSemantic(loc, sc);
1568 else if (t)
1569 mtype.index = t.typeSemantic(loc, sc);
1570 else
1572 .error(loc, "index is not a type or an expression");
1573 return error();
1576 else
1577 mtype.index = mtype.index.typeSemantic(loc, sc);
1578 mtype.index = mtype.index.merge2();
1580 if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable())
1582 mtype.index = mtype.index.constOf().mutableOf();
1583 version (none)
1585 printf("index is %p %s\n", mtype.index, mtype.index.toChars());
1586 mtype.index.check();
1587 printf("index.mod = x%x\n", mtype.index.mod);
1588 printf("index.ito = x%p\n", mtype.index.getMcache().ito);
1589 if (mtype.index.getMcache().ito)
1591 printf("index.ito.mod = x%x\n", mtype.index.getMcache().ito.mod);
1592 printf("index.ito.ito = x%p\n", mtype.index.getMcache().ito.getMcache().ito);
1597 switch (mtype.index.toBasetype().ty)
1599 case Tfunction:
1600 case Tvoid:
1601 case Tnone:
1602 case Ttuple:
1603 .error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars());
1604 goto case Terror;
1605 case Terror:
1606 return error();
1608 default:
1609 break;
1611 Type tbase = mtype.index.baseElemOf();
1612 while (tbase.ty == Tarray)
1613 tbase = tbase.nextOf().baseElemOf();
1614 if (auto ts = tbase.isTypeStruct())
1616 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
1618 StructDeclaration sd = ts.sym;
1619 if (sd.semanticRun < PASS.semanticdone)
1620 sd.dsymbolSemantic(null);
1622 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
1623 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
1625 if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
1627 uint errors = global.startGagging();
1628 sd.xeq.semantic3(sd.xeq._scope);
1629 if (global.endGagging(errors))
1630 sd.xeq = sd.xerreq;
1634 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
1635 const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : "";
1636 if (!sd.xeq)
1638 // If sd.xhash != NULL:
1639 // sd or its fields have user-defined toHash.
1640 // AA assumes that its result is consistent with bitwise equality.
1641 // else:
1642 // bitwise equality & hashing
1644 else if (sd.xeq == sd.xerreq)
1646 if (search_function(sd, Id.eq))
1648 .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars());
1650 else
1652 .error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars());
1654 return error();
1656 else if (!sd.xhash)
1658 if (search_function(sd, Id.eq))
1660 .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars());
1662 else
1664 .error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars());
1666 return error();
1668 else
1670 // defined equality & hashing
1671 assert(sd.xeq && sd.xhash);
1673 /* xeq and xhash may be implicitly defined by compiler. For example:
1674 * struct S { int[] arr; }
1675 * With 'arr' field equality and hashing, compiler will implicitly
1676 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
1680 else if (tbase.ty == Tclass && !tbase.isTypeClass().sym.isInterfaceDeclaration())
1682 ClassDeclaration cd = tbase.isTypeClass().sym;
1683 if (cd.semanticRun < PASS.semanticdone)
1684 cd.dsymbolSemantic(null);
1686 if (!ClassDeclaration.object)
1688 .error(Loc.initial, "missing or corrupt object.d");
1689 fatal();
1692 __gshared FuncDeclaration feq = null;
1693 __gshared FuncDeclaration fcmp = null;
1694 __gshared FuncDeclaration fhash = null;
1695 if (!feq)
1696 feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration();
1697 if (!fcmp)
1698 fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration();
1699 if (!fhash)
1700 fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration();
1701 assert(fcmp && feq && fhash);
1703 if (feq.vtblIndex < cd.vtbl.length && cd.vtbl[feq.vtblIndex] == feq)
1705 version (all)
1707 if (fcmp.vtblIndex < cd.vtbl.length && cd.vtbl[fcmp.vtblIndex] != fcmp)
1709 const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : "";
1710 .error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars());
1711 errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`.");
1716 mtype.next = mtype.next.typeSemantic(loc, sc).merge2();
1717 mtype.transitive();
1719 switch (mtype.next.toBasetype().ty)
1721 case Tfunction:
1722 case Tvoid:
1723 case Tnone:
1724 case Ttuple:
1725 .error(loc, "cannot have associative array of `%s`", mtype.next.toChars());
1726 goto case Terror;
1727 case Terror:
1728 return error();
1729 default:
1730 break;
1732 if (mtype.next.isscope())
1734 .error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
1735 return error();
1737 return merge(mtype);
1740 Type visitPointer(TypePointer mtype)
1742 //printf("TypePointer::semantic() %s\n", toChars());
1743 if (mtype.deco)
1745 return mtype;
1747 Type n = mtype.next.typeSemantic(loc, sc);
1748 switch (n.toBasetype().ty)
1750 case Ttuple:
1751 .error(loc, "cannot have pointer to `%s`", n.toChars());
1752 goto case Terror;
1753 case Terror:
1754 return error();
1755 default:
1756 break;
1758 if (n != mtype.next)
1760 mtype.deco = null;
1762 mtype.next = n;
1763 if (mtype.next.ty != Tfunction)
1765 mtype.transitive();
1766 return merge(mtype);
1768 version (none)
1770 return merge(mtype);
1772 else
1774 mtype.deco = merge(mtype).deco;
1775 /* Don't return merge(), because arg identifiers and default args
1776 * can be different
1777 * even though the types match
1779 return mtype;
1783 Type visitReference(TypeReference mtype)
1785 //printf("TypeReference::semantic()\n");
1786 Type n = mtype.next.typeSemantic(loc, sc);
1787 if (n != mtype.next)
1788 mtype.deco = null;
1789 mtype.next = n;
1790 mtype.transitive();
1791 return merge(mtype);
1794 Type visitFunction(TypeFunction mtype)
1796 if (mtype.deco) // if semantic() already run
1798 //printf("already done\n");
1799 return mtype;
1801 //printf("TypeFunction::semantic() this = %p\n", mtype);
1802 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
1804 bool errors = false;
1806 if (mtype.inuse > global.recursionLimit)
1808 mtype.inuse = 0;
1809 .error(loc, "recursive type");
1810 return error();
1813 /* Copy in order to not mess up original.
1814 * This can produce redundant copies if inferring return type,
1815 * as semantic() will get called again on this.
1817 TypeFunction tf = mtype.copy().toTypeFunction();
1818 if (mtype.parameterList.parameters)
1820 tf.parameterList.parameters = mtype.parameterList.parameters.copy();
1821 for (size_t i = 0; i < mtype.parameterList.parameters.length; i++)
1823 Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter));
1824 memcpy(cast(void*)p, cast(void*)(*mtype.parameterList.parameters)[i], __traits(classInstanceSize, Parameter));
1825 (*tf.parameterList.parameters)[i] = p;
1829 if (sc.stc & STC.pure_)
1830 tf.purity = PURE.fwdref;
1831 if (sc.stc & STC.nothrow_)
1832 tf.isnothrow = true;
1833 if (sc.stc & STC.nogc)
1834 tf.isnogc = true;
1835 if (sc.stc & STC.ref_)
1836 tf.isref = true;
1837 if (sc.stc & STC.return_)
1838 tf.isreturn = true;
1839 if (sc.stc & STC.returnScope)
1840 tf.isreturnscope = true;
1841 if (sc.stc & STC.returninferred)
1842 tf.isreturninferred = true;
1843 if (sc.stc & STC.scope_)
1844 tf.isScopeQual = true;
1845 if (sc.stc & STC.scopeinferred)
1846 tf.isscopeinferred = true;
1848 // if (tf.isreturn && !tf.isref)
1849 // tf.isScopeQual = true; // return by itself means 'return scope'
1851 if (tf.trust == TRUST.default_)
1853 if (sc.stc & STC.safe)
1854 tf.trust = TRUST.safe;
1855 else if (sc.stc & STC.system)
1856 tf.trust = TRUST.system;
1857 else if (sc.stc & STC.trusted)
1858 tf.trust = TRUST.trusted;
1861 if (sc.stc & STC.property)
1862 tf.isproperty = true;
1863 if (sc.stc & STC.live)
1864 tf.islive = true;
1866 tf.linkage = sc.linkage;
1867 if (tf.linkage == LINK.system)
1868 tf.linkage = target.systemLinkage();
1870 version (none)
1872 /* If the parent is @safe, then this function defaults to safe
1873 * too.
1874 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1875 * to be inferred first.
1877 if (tf.trust == TRUST.default_)
1878 for (Dsymbol p = sc.func; p; p = p.toParent2())
1880 FuncDeclaration fd = p.isFuncDeclaration();
1881 if (fd)
1883 if (fd.isSafeBypassingInference())
1884 tf.trust = TRUST.safe; // default to @safe
1885 break;
1890 bool wildreturn = false;
1891 if (tf.next)
1893 sc = sc.push();
1894 sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR);
1895 tf.next = tf.next.typeSemantic(loc, sc);
1896 sc = sc.pop();
1897 errors |= tf.checkRetType(loc);
1898 if (tf.next.isscope() && !tf.isctor)
1900 .error(loc, "functions cannot return `scope %s`", tf.next.toChars());
1901 errors = true;
1903 if (tf.next.hasWild())
1904 wildreturn = true;
1906 if (tf.isreturn && !tf.isref && !tf.next.hasPointers())
1908 tf.isreturn = false;
1912 /// Perform semantic on the default argument to a parameter
1913 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1914 /// Returns `false` whether an error was encountered.
1915 static bool defaultArgSemantic (ref Parameter fparam, Scope* sc)
1917 Expression e = fparam.defaultArg;
1918 const isRefOrOut = fparam.isReference();
1919 const isAuto = fparam.storageClass & (STC.auto_ | STC.autoref);
1920 if (isRefOrOut && !isAuto)
1922 e = e.expressionSemantic(sc);
1923 e = resolveProperties(sc, e);
1925 else
1927 e = inferType(e, fparam.type);
1928 Scope* sc2 = sc.push();
1929 sc2.inDefaultArg = true;
1930 Initializer iz = new ExpInitializer(e.loc, e);
1931 iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret);
1932 e = iz.initializerToExpression();
1933 sc2.pop();
1935 if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
1937 FuncExp fe = e.isFuncExp();
1938 // Replace function literal with a function symbol,
1939 // since default arg expression must be copied when used
1940 // and copying the literal itself is wrong.
1941 e = new VarExp(e.loc, fe.fd, false);
1942 e = new AddrExp(e.loc, e);
1943 e = e.expressionSemantic(sc);
1945 if (isRefOrOut && (!isAuto || e.isLvalue())
1946 && !MODimplicitConv(e.type.mod, fparam.type.mod))
1948 const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
1949 .error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1950 e.toChars(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
1952 e = e.implicitCastTo(sc, fparam.type);
1954 // default arg must be an lvalue
1955 if (isRefOrOut && !isAuto &&
1956 !(fparam.storageClass & STC.constscoperef) &&
1957 global.params.rvalueRefParam != FeatureState.enabled)
1958 e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from");
1960 fparam.defaultArg = e;
1961 return (e.op != EXP.error);
1964 ubyte wildparams = 0;
1965 if (tf.parameterList.parameters)
1967 /* Create a scope for evaluating the default arguments for the parameters
1969 Scope* argsc = sc.push();
1970 argsc.stc = 0; // don't inherit storage class
1971 argsc.visibility = Visibility(Visibility.Kind.public_);
1972 argsc.func = null;
1974 size_t dim = tf.parameterList.length;
1975 for (size_t i = 0; i < dim; i++)
1977 Parameter fparam = tf.parameterList[i];
1978 fparam.storageClass |= STC.parameter;
1979 mtype.inuse++;
1980 fparam.type = fparam.type.typeSemantic(loc, argsc);
1981 mtype.inuse--;
1983 if (fparam.type.ty == Terror)
1985 errors = true;
1986 continue;
1989 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
1991 if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_))
1993 if (!fparam.type)
1994 continue;
1997 fparam.type = fparam.type.cAdjustParamType(sc); // adjust C array and function parameter types
1999 Type t = fparam.type.toBasetype();
2001 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
2002 * change.
2004 if (auto tt = t.isTypeTuple())
2006 /* TypeFunction::parameter also is used as the storage of
2007 * Parameter objects for FuncDeclaration. So we should copy
2008 * the elements of TypeTuple::arguments to avoid unintended
2009 * sharing of Parameter object among other functions.
2011 if (tt.arguments && tt.arguments.length)
2013 /* Propagate additional storage class from tuple parameters to their
2014 * element-parameters.
2015 * Make a copy, as original may be referenced elsewhere.
2017 size_t tdim = tt.arguments.length;
2018 auto newparams = new Parameters(tdim);
2019 for (size_t j = 0; j < tdim; j++)
2021 Parameter narg = (*tt.arguments)[j];
2023 // https://issues.dlang.org/show_bug.cgi?id=12744
2024 // If the storage classes of narg
2025 // conflict with the ones in fparam, it's ignored.
2026 StorageClass stc = fparam.storageClass | narg.storageClass;
2027 StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
2028 StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
2029 if (stc1 && stc2 && stc1 != stc2)
2031 OutBuffer buf1; stcToBuffer(buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0));
2032 OutBuffer buf2; stcToBuffer(buf2, stc2);
2034 .error(loc, "incompatible parameter storage classes `%s` and `%s`",
2035 buf1.peekChars(), buf2.peekChars());
2036 errors = true;
2037 stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_));
2039 (*newparams)[j] = new Parameter(
2040 loc, stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
2042 fparam.type = new TypeTuple(newparams);
2043 fparam.type = fparam.type.typeSemantic(loc, argsc);
2045 fparam.storageClass = STC.parameter;
2047 /* Reset number of parameters, and back up one to do this fparam again,
2048 * now that it is a tuple
2050 dim = tf.parameterList.length;
2051 i--;
2052 continue;
2055 // -preview=in: Always add `ref` when used with `extern(C++)` functions
2056 // Done here to allow passing opaque types with `in`
2057 if ((fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
2059 switch (tf.linkage)
2061 case LINK.cpp:
2062 if (fparam.storageClass & STC.constscoperef)
2063 fparam.storageClass |= STC.ref_;
2064 break;
2065 case LINK.default_, LINK.d:
2066 break;
2067 default:
2068 if (fparam.storageClass & STC.constscoperef)
2070 .error(loc, "cannot use `in` parameters with `extern(%s)` functions",
2071 linkageToChars(tf.linkage));
2072 .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
2074 else
2076 // Note that this deprecation will not trigger on `in ref` / `ref in`
2077 // parameters, however the parser will trigger a deprecation on them.
2078 .deprecation(loc, "using `in` parameters with `extern(%s)` functions is deprecated",
2079 linkageToChars(tf.linkage));
2080 .deprecationSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
2082 break;
2086 if (t.ty == Tfunction)
2088 .error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars());
2089 errors = true;
2091 else if (!fparam.isReference() &&
2092 (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum))
2094 Type tb2 = t.baseElemOf();
2095 if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members ||
2096 tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype)
2098 if (fparam.storageClass & STC.constscoperef)
2100 .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
2101 fparam.toChars(), fparam.type.toChars());
2103 else
2104 .error(loc, "cannot have parameter of opaque type `%s` by value",
2105 fparam.type.toChars());
2106 errors = true;
2109 else if (!fparam.isLazy() && t.ty == Tvoid)
2111 .error(loc, "cannot have parameter of type `%s`", fparam.type.toChars());
2112 errors = true;
2115 const bool isTypesafeVariadic = i + 1 == dim &&
2116 tf.parameterList.varargs == VarArg.typesafe &&
2117 (t.isTypeDArray() || t.isTypeClass());
2118 if (isTypesafeVariadic)
2120 /* typesafe variadic arguments are constructed on the stack, so must be `scope`
2122 fparam.storageClass |= STC.scope_ | STC.scopeinferred;
2125 if (fparam.storageClass & STC.return_)
2127 if (!fparam.isReference())
2129 if (!(fparam.storageClass & STC.scope_))
2130 fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
2131 if (tf.isref)
2134 else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid)
2136 fparam.storageClass &= ~STC.return_; // https://issues.dlang.org/show_bug.cgi?id=18963
2140 if (isTypesafeVariadic)
2142 /* This is because they can be constructed on the stack
2143 * https://dlang.org/spec/function.html#typesafe_variadic_functions
2145 .error(loc, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
2146 fparam.ident ? fparam.ident.toChars() : "", t.toChars());
2147 errors = true;
2151 if (fparam.storageClass & STC.out_)
2153 if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild))
2155 .error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars());
2156 errors = true;
2158 else
2160 Type tv = t.baseElemOf();
2161 if (tv.ty == Tstruct && tv.isTypeStruct().sym.noDefaultCtor)
2163 .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars());
2164 errors = true;
2169 if (t.hasWild())
2171 wildparams |= 1;
2172 //if (tf.next && !wildreturn)
2173 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
2176 // Remove redundant storage classes for type, they are already applied
2177 fparam.storageClass &= ~(STC.TYPECTOR);
2179 // -preview=in: add `ref` storage class to suited `in` params
2180 if ((fparam.storageClass & (STC.constscoperef | STC.ref_)) == STC.constscoperef)
2182 auto ts = t.baseElemOf().isTypeStruct();
2183 const isPOD = !ts || ts.sym.isPOD();
2184 if (!isPOD || target.preferPassByRef(t))
2185 fparam.storageClass |= STC.ref_;
2189 // Now that we completed semantic for the argument types,
2190 // run semantic on their default values,
2191 // bearing in mind tuples have been expanded.
2192 // We need to keep a pair of [oidx, eidx] (original index,
2193 // extended index), as we need to run semantic when `oidx` changes.
2194 size_t tupleOrigIdx = size_t.max;
2195 size_t tupleExtIdx = size_t.max;
2196 foreach (oidx, oparam, eidx, eparam; tf.parameterList)
2198 // oparam (original param) will always have the default arg
2199 // if there's one, but `eparam` will not if it's an expanded
2200 // tuple. When we see an expanded tuple, we need to save its
2201 // position to get the offset in it later on.
2202 if (oparam.defaultArg)
2204 // Get the obvious case out of the way
2205 if (oparam is eparam)
2206 errors |= !defaultArgSemantic(eparam, argsc);
2207 // We're seeing a new tuple
2208 else if (tupleOrigIdx == size_t.max || tupleOrigIdx < oidx)
2210 /* https://issues.dlang.org/show_bug.cgi?id=18572
2212 * If a tuple parameter has a default argument, when expanding the parameter
2213 * tuple the default argument tuple must also be expanded.
2215 tupleOrigIdx = oidx;
2216 tupleExtIdx = eidx;
2217 errors |= !defaultArgSemantic(oparam, argsc);
2218 TupleExp te = oparam.defaultArg.isTupleExp();
2219 if (te && te.exps && te.exps.length)
2220 eparam.defaultArg = (*te.exps)[0];
2222 // Processing an already-seen tuple
2223 else
2225 TupleExp te = oparam.defaultArg.isTupleExp();
2226 if (te && te.exps && te.exps.length)
2227 eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
2231 // We need to know the default argument to resolve `auto ref`,
2232 // hence why this has to take place as the very last step.
2233 /* Resolve "auto ref" storage class to be either ref or value,
2234 * based on the argument matching the parameter
2236 if (eparam.storageClass & STC.auto_)
2238 Expression farg = mtype.fargs && eidx < mtype.fargs.length ?
2239 (*mtype.fargs)[eidx] : eparam.defaultArg;
2240 if (farg && (eparam.storageClass & STC.ref_))
2242 if (!farg.isLvalue())
2243 eparam.storageClass &= ~STC.ref_; // value parameter
2244 eparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656
2245 eparam.storageClass |= STC.autoref;
2247 else if (mtype.incomplete && (eparam.storageClass & STC.ref_))
2249 // the default argument may have been temporarily removed,
2250 // see usage of `TypeFunction.incomplete`.
2251 // https://issues.dlang.org/show_bug.cgi?id=19891
2252 eparam.storageClass &= ~STC.auto_;
2253 eparam.storageClass |= STC.autoref;
2255 else if (eparam.storageClass & STC.ref_)
2257 .error(loc, "cannot explicitly instantiate template function with `auto ref` parameter");
2258 errors = true;
2260 else
2262 .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
2263 errors = true;
2268 argsc.pop();
2270 if (tf.isWild())
2271 wildparams |= 2;
2273 if (wildreturn && !wildparams)
2275 .error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars());
2276 errors = true;
2278 tf.isInOutParam = (wildparams & 1) != 0;
2279 tf.isInOutQual = (wildparams & 2) != 0;
2281 if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
2283 .error(loc, "properties can only have zero, one, or two parameter");
2284 errors = true;
2287 if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
2288 !(sc.flags & SCOPE.Cfile))
2290 .error(loc, "variadic functions with non-D linkage must have at least one parameter");
2291 errors = true;
2294 if (errors)
2295 return error();
2297 if (tf.next)
2298 tf.deco = tf.merge().deco;
2300 /* Don't return merge(), because arg identifiers and default args
2301 * can be different
2302 * even though the types match
2304 return tf;
2307 Type visitDelegate(TypeDelegate mtype)
2309 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
2310 if (mtype.deco) // if semantic() already run
2312 //printf("already done\n");
2313 return mtype;
2315 mtype.next = mtype.next.typeSemantic(loc, sc);
2316 if (mtype.next.ty != Tfunction)
2317 return error();
2319 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
2320 * perhaps default arguments should
2321 * be removed from next before the merge.
2323 version (none)
2325 return mtype.merge();
2327 else
2329 /* Don't return merge(), because arg identifiers and default args
2330 * can be different
2331 * even though the types match
2333 mtype.deco = mtype.merge().deco;
2334 return mtype;
2338 Type visitIdentifier(TypeIdentifier mtype)
2340 Type t;
2341 Expression e;
2342 Dsymbol s;
2343 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
2344 mtype.resolve(loc, sc, e, t, s);
2345 if (t)
2347 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
2348 return t.addMod(mtype.mod);
2350 else
2352 if (s)
2354 auto td = s.isTemplateDeclaration;
2355 if (td && td.onemember && td.onemember.isAggregateDeclaration)
2356 .error(loc, "template %s `%s` is used as a type without instantiation"
2357 ~ "; to instantiate it use `%s!(arguments)`",
2358 s.kind, s.toPrettyChars, s.ident.toChars);
2359 else
2360 .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
2361 //assert(0);
2363 else if (e.op == EXP.variable) // special case: variable is used as a type
2366 N.B. This branch currently triggers for the following code
2367 template test(x* x)
2371 i.e. the compiler prints "variable x is used as a type"
2372 which isn't a particularly good error message (x is a variable?).
2374 Dsymbol varDecl = mtype.toDsymbol(sc);
2375 const(Loc) varDeclLoc = varDecl.getLoc();
2376 Module varDeclModule = varDecl.getModule(); //This can be null
2378 .error(loc, "variable `%s` is used as a type", mtype.toChars());
2379 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
2380 if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
2382 const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
2383 .errorSupplemental(
2384 varDeclModuleImportLoc,
2385 "variable `%s` is imported here from: `%s`",
2386 varDecl.toChars,
2387 varDeclModule.toPrettyChars,
2391 .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
2393 else
2394 .error(loc, "`%s` is used as a type", mtype.toChars());
2395 return error();
2399 Type visitInstance(TypeInstance mtype)
2401 Type t;
2402 Expression e;
2403 Dsymbol s;
2405 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
2407 const errors = global.errors;
2408 mtype.resolve(loc, sc, e, t, s);
2409 // if we had an error evaluating the symbol, suppress further errors
2410 if (!t && errors != global.errors)
2411 return error();
2414 if (!t)
2416 if (!e && s && s.errors)
2418 // if there was an error evaluating the symbol, it might actually
2419 // be a type. Avoid misleading error messages.
2420 .error(loc, "`%s` had previous errors", mtype.toChars());
2422 else
2423 .error(loc, "`%s` is used as a type", mtype.toChars());
2424 return error();
2426 return t;
2429 Type visitTypeof(TypeTypeof mtype)
2431 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
2432 Expression e;
2433 Type t;
2434 Dsymbol s;
2435 mtype.resolve(loc, sc, e, t, s);
2436 if (s && (t = s.getType()) !is null)
2437 t = t.addMod(mtype.mod);
2438 if (!t)
2440 .error(loc, "`%s` is used as a type", mtype.toChars());
2441 return error();
2443 return t;
2446 Type visitTraits(TypeTraits mtype)
2448 Expression e;
2449 Type t;
2450 Dsymbol s;
2451 mtype.resolve(loc, sc, e, t, s);
2453 if (!t)
2455 if (!global.errors)
2456 .error(mtype.loc, "`%s` does not give a valid type", mtype.toChars);
2457 return error();
2459 return t;
2462 Type visitReturn(TypeReturn mtype)
2464 //printf("TypeReturn::semantic() %s\n", toChars());
2465 Expression e;
2466 Type t;
2467 Dsymbol s;
2468 mtype.resolve(loc, sc, e, t, s);
2469 if (s && (t = s.getType()) !is null)
2470 t = t.addMod(mtype.mod);
2471 if (!t)
2473 .error(loc, "`%s` is used as a type", mtype.toChars());
2474 return error();
2476 return t;
2479 Type visitStruct(TypeStruct mtype)
2481 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
2482 if (mtype.deco)
2483 return mtype;
2485 /* Don't semantic for sym because it should be deferred until
2486 * sizeof needed or its members accessed.
2488 // instead, parent should be set correctly
2489 assert(mtype.sym.parent);
2491 if (mtype.sym.type.ty == Terror)
2492 return error();
2494 return merge(mtype);
2497 Type visitEnum(TypeEnum mtype)
2499 //printf("TypeEnum::semantic() %s\n", toChars());
2500 return mtype.deco ? mtype : merge(mtype);
2503 Type visitClass(TypeClass mtype)
2505 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
2506 if (mtype.deco)
2507 return mtype;
2509 /* Don't semantic for sym because it should be deferred until
2510 * sizeof needed or its members accessed.
2512 // instead, parent should be set correctly
2513 assert(mtype.sym.parent);
2515 if (mtype.sym.type.ty == Terror)
2516 return error();
2518 return merge(mtype);
2521 Type visitTuple(TypeTuple mtype)
2523 //printf("TypeTuple::semantic(this = %p)\n", this);
2524 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
2525 if (!mtype.deco)
2526 mtype.deco = merge(mtype).deco;
2528 /* Don't return merge(), because a tuple with one type has the
2529 * same deco as that type.
2531 return mtype;
2534 Type visitSlice(TypeSlice mtype)
2536 //printf("TypeSlice::semantic() %s\n", toChars());
2537 Type tn = mtype.next.typeSemantic(loc, sc);
2538 //printf("next: %s\n", tn.toChars());
2540 Type tbn = tn.toBasetype();
2541 if (tbn.ty != Ttuple)
2543 .error(loc, "can only slice type sequences, not `%s`", tbn.toChars());
2544 return error();
2546 TypeTuple tt = cast(TypeTuple)tbn;
2548 mtype.lwr = semanticLength(sc, tbn, mtype.lwr);
2549 mtype.upr = semanticLength(sc, tbn, mtype.upr);
2550 mtype.lwr = mtype.lwr.ctfeInterpret();
2551 mtype.upr = mtype.upr.ctfeInterpret();
2552 if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error)
2553 return error();
2555 uinteger_t i1 = mtype.lwr.toUInteger();
2556 uinteger_t i2 = mtype.upr.toUInteger();
2557 if (!(i1 <= i2 && i2 <= tt.arguments.length))
2559 .error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
2560 cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.length);
2561 return error();
2564 mtype.next = tn;
2565 mtype.transitive();
2567 auto args = new Parameters();
2568 args.reserve(cast(size_t)(i2 - i1));
2569 foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2])
2571 args.push(arg);
2573 Type t = new TypeTuple(args);
2574 return t.typeSemantic(loc, sc);
2577 Type visitMixin(TypeMixin mtype)
2579 //printf("TypeMixin::semantic() %s\n", toChars());
2581 Expression e;
2582 Type t;
2583 Dsymbol s;
2584 mtype.resolve(loc, sc, e, t, s);
2586 if (t && t.ty != Terror)
2587 return t;
2589 .error(mtype.loc, "`mixin(%s)` does not give a valid type", mtype.obj.toChars);
2590 return error();
2593 Type visitTag(TypeTag mtype)
2595 //printf("TypeTag.semantic() %s\n", mtype.toChars());
2596 Type returnType(Type t)
2598 return t.deco ? t : t.merge();
2601 if (mtype.resolved)
2603 /* struct S s, *p;
2605 return returnType(mtype.resolved.addSTC(mtype.mod));
2608 /* Find the current scope by skipping tag scopes.
2609 * In C, tag scopes aren't considered scopes.
2611 Scope* sc2 = sc;
2612 while (1)
2614 sc2 = sc2.inner();
2615 auto scopesym = sc2.scopesym;
2616 if (scopesym.isStructDeclaration())
2618 sc2 = sc2.enclosing;
2619 continue;
2621 break;
2624 /* Declare mtype as a struct/union/enum declaration
2626 void declareTag()
2628 void declare(ScopeDsymbol sd)
2630 sd.members = mtype.members;
2631 auto scopesym = sc2.inner().scopesym;
2632 if (scopesym.members)
2633 scopesym.members.push(sd);
2634 if (scopesym.symtab && !scopesym.symtabInsert(sd))
2636 Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
2637 handleTagSymbols(*sc2, sd, s2, scopesym);
2639 sd.parent = sc2.parent;
2640 sd.dsymbolSemantic(sc2);
2643 switch (mtype.tok)
2645 case TOK.enum_:
2646 auto ed = new EnumDeclaration(mtype.loc, mtype.id, mtype.base);
2647 declare(ed);
2648 mtype.resolved = visitEnum(new TypeEnum(ed));
2649 break;
2651 case TOK.struct_:
2652 auto sd = new StructDeclaration(mtype.loc, mtype.id, false);
2653 sd.alignment = mtype.packalign;
2654 declare(sd);
2655 mtype.resolved = visitStruct(new TypeStruct(sd));
2656 break;
2658 case TOK.union_:
2659 auto ud = new UnionDeclaration(mtype.loc, mtype.id);
2660 ud.alignment = mtype.packalign;
2661 declare(ud);
2662 mtype.resolved = visitStruct(new TypeStruct(ud));
2663 break;
2665 default:
2666 assert(0);
2670 /* If it doesn't have a tag by now, supply one.
2671 * It'll be unique, and therefore introducing.
2672 * Declare it, and done.
2674 if (!mtype.id)
2676 mtype.id = Identifier.generateId("__tag"[]);
2677 declareTag();
2678 return returnType(mtype.resolved.addSTC(mtype.mod));
2681 /* look for pre-existing declaration
2683 Dsymbol scopesym;
2684 auto s = sc2.search(mtype.loc, mtype.id, scopesym, SearchOpt.ignoreErrors | SearchOpt.tagNameSpace);
2685 if (!s || s.isModule())
2687 // no pre-existing declaration, so declare it
2688 if (mtype.tok == TOK.enum_ && !mtype.members)
2689 .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
2690 declareTag();
2691 return returnType(mtype.resolved.addSTC(mtype.mod));
2694 /* A redeclaration only happens if both declarations are in
2695 * the same scope
2697 const bool redeclar = (scopesym == sc2.inner().scopesym);
2699 if (redeclar)
2701 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
2703 auto ed = s.isEnumDeclaration();
2704 if (mtype.members && ed.members)
2705 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
2706 else if (!ed.members)
2708 ed.members = mtype.members;
2710 else
2713 mtype.resolved = ed.type;
2715 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
2716 mtype.tok == TOK.struct_ && s.isStructDeclaration())
2718 // Add members to original declaration
2719 auto sd = s.isStructDeclaration();
2720 if (mtype.members && sd.members)
2722 /* struct S { int b; };
2723 * struct S { int a; } *s;
2725 .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
2727 else if (!sd.members)
2729 /* struct S;
2730 * struct S { int a; } *s;
2732 sd.members = mtype.members;
2733 if (sd.semanticRun == PASS.semanticdone)
2735 /* The first semantic pass marked `sd` as an opaque struct.
2736 * Re-run semantic so that all newly assigned members are
2737 * picked up and added to the symtab.
2739 sd.semanticRun = PASS.semantic;
2740 sd.dsymbolSemantic(sc2);
2743 else
2745 /* struct S { int a; };
2746 * struct S *s;
2749 mtype.resolved = sd.type;
2751 else
2753 /* int S;
2754 * struct S { int a; } *s;
2756 .error(mtype.loc, "redeclaration of `%s`", mtype.id.toChars());
2757 mtype.resolved = error();
2760 else if (mtype.members)
2762 /* struct S;
2763 * { struct S { int a; } *s; }
2765 declareTag();
2767 else
2769 if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
2771 mtype.resolved = s.isEnumDeclaration().type;
2773 else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
2774 mtype.tok == TOK.struct_ && s.isStructDeclaration())
2776 /* struct S;
2777 * { struct S *s; }
2779 mtype.resolved = s.isStructDeclaration().type;
2781 else
2783 /* union S;
2784 * { struct S *s; }
2786 .error(mtype.loc, "redeclaring `%s %s` as `%s %s`",
2787 s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars());
2788 declareTag();
2791 return returnType(mtype.resolved.addSTC(mtype.mod));
2794 switch (type.ty)
2796 default: return visitType(type);
2797 case Tcomplex32:
2798 case Tcomplex64:
2799 case Tcomplex80: return visitComplex(type.isTypeBasic());
2800 case Tvector: return visitVector(type.isTypeVector());
2801 case Tsarray: return visitSArray(type.isTypeSArray());
2802 case Tarray: return visitDArray(type.isTypeDArray());
2803 case Taarray: return visitAArray(type.isTypeAArray());
2804 case Tpointer: return visitPointer(type.isTypePointer());
2805 case Treference: return visitReference(type.isTypeReference());
2806 case Tfunction: return visitFunction(type.isTypeFunction());
2807 case Tdelegate: return visitDelegate(type.isTypeDelegate());
2808 case Tident: return visitIdentifier(type.isTypeIdentifier());
2809 case Tinstance: return visitInstance(type.isTypeInstance());
2810 case Ttypeof: return visitTypeof(type.isTypeTypeof());
2811 case Ttraits: return visitTraits(type.isTypeTraits());
2812 case Treturn: return visitReturn(type.isTypeReturn());
2813 case Tstruct: return visitStruct(type.isTypeStruct());
2814 case Tenum: return visitEnum(type.isTypeEnum());
2815 case Tclass: return visitClass(type.isTypeClass());
2816 case Ttuple: return visitTuple(type.isTypeTuple());
2817 case Tslice: return visitSlice(type.isTypeSlice());
2818 case Tmixin: return visitMixin(type.isTypeMixin());
2819 case Ttag: return visitTag(type.isTypeTag());
2823 extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc)
2825 //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
2827 // Needed to display any deprecations that were gagged
2828 auto tcopy = type.syntaxCopy();
2830 const errors = global.startGagging();
2831 Type t = typeSemantic(type, loc, sc);
2832 if (global.endGagging(errors) || t.ty == Terror) // if any errors happened
2834 t = null;
2836 else
2838 // If `typeSemantic` succeeded, there may have been deprecations that
2839 // were gagged due the `startGagging` above. Run again to display
2840 // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
2841 if (global.gaggedWarnings > 0)
2842 typeSemantic(tcopy, loc, sc);
2844 //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
2845 return t;
2848 /************************************
2849 * If an identical type to `type` is in `type.stringtable`, return
2850 * the latter one. Otherwise, add it to `type.stringtable`.
2851 * Some types don't get merged and are returned as-is.
2852 * Params:
2853 * type = Type to check against existing types
2854 * Returns:
2855 * the type that was merged
2857 extern (C++) Type merge(Type type)
2859 switch (type.ty)
2861 case Terror:
2862 case Ttypeof:
2863 case Tident:
2864 case Tinstance:
2865 case Tmixin:
2866 case Ttag:
2867 return type; // don't merge placeholder types
2869 case Tsarray:
2870 // prevents generating the mangle if the array dim is not yet known
2871 if (!type.isTypeSArray().dim.isIntegerExp())
2872 return type;
2873 goto default;
2875 case Tenum:
2876 break;
2878 case Taarray:
2879 if (!type.isTypeAArray().index.merge().deco)
2880 return type;
2881 goto default;
2883 default:
2884 if (type.nextOf() && !type.nextOf().deco)
2885 return type;
2886 break;
2889 //printf("merge(%s)\n", toChars());
2890 if (!type.deco)
2892 OutBuffer buf;
2893 buf.reserve(32);
2895 mangleToBuffer(type, buf);
2897 auto sv = type.stringtable.update(buf[]);
2898 if (sv.value)
2900 Type t = sv.value;
2901 debug
2903 import core.stdc.stdio;
2904 if (!t.deco)
2905 printf("t = %s\n", t.toChars());
2907 assert(t.deco);
2908 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2909 return t;
2911 else
2913 Type t = stripDefaultArgs(type);
2914 sv.value = t;
2915 type.deco = t.deco = cast(char*)sv.toDchars();
2916 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2917 return t;
2920 return type;
2923 /*************************************
2924 * This version does a merge even if the deco is already computed.
2925 * Necessary for types that have a deco, but are not merged.
2927 extern(C++) Type merge2(Type type)
2929 //printf("merge2(%s)\n", toChars());
2930 Type t = type;
2931 assert(t);
2932 if (!t.deco)
2933 return t.merge();
2935 auto sv = Type.stringtable.lookup(t.deco, strlen(t.deco));
2936 if (sv && sv.value)
2938 t = sv.value;
2939 assert(t.deco);
2941 else
2942 assert(0);
2943 return t;
2946 /***************************************
2947 * Calculate built-in properties which just the type is necessary.
2949 * Params:
2950 * t = the type for which the property is calculated
2951 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2952 * loc = the location where the property is encountered
2953 * ident = the identifier of the property
2954 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2955 * src = expression for type `t` or null.
2956 * Returns:
2957 * expression representing the property, or null if not a property and (flag & 1)
2959 Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag,
2960 Expression src = null)
2962 Expression visitType(Type mt)
2964 Expression e;
2965 static if (LOGDOTEXP)
2967 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2969 if (ident == Id.__sizeof)
2971 const sz = mt.size(loc);
2972 if (sz == SIZE_INVALID)
2973 return ErrorExp.get();
2974 e = new IntegerExp(loc, sz, Type.tsize_t);
2976 else if (ident == Id.__xalignof)
2978 const explicitAlignment = mt.alignment();
2979 const naturalAlignment = mt.alignsize();
2980 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
2981 e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
2983 else if (ident == Id._init)
2985 Type tb = mt.toBasetype();
2986 e = mt.defaultInitLiteral(loc);
2987 if (tb.ty == Tstruct && tb.needsNested())
2989 e.isStructLiteralExp().useStaticInit = true;
2992 else if (ident == Id._mangleof)
2994 if (!mt.deco)
2996 error(loc, "forward reference of type `%s.mangleof`", mt.toChars());
2997 e = ErrorExp.get();
2999 else
3001 e = new StringExp(loc, mt.deco.toDString());
3002 Scope sc;
3003 sc.eSink = global.errorSink;
3004 e = e.expressionSemantic(&sc);
3007 else if (ident == Id.stringof)
3009 const s = mt.toChars();
3010 e = new StringExp(loc, s.toDString());
3011 Scope sc;
3012 sc.eSink = global.errorSink;
3013 e = e.expressionSemantic(&sc);
3015 else if (flag && mt != Type.terror)
3017 return null;
3019 else
3021 Dsymbol s = null;
3022 if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
3023 s = mt.toDsymbol(null);
3024 if (s)
3025 s = s.search_correct(ident);
3026 if (s && !symbolIsVisible(scope_, s))
3027 s = null;
3028 if (mt != Type.terror)
3030 if (s)
3031 error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
3032 else if (ident == Id.call && mt.ty == Tclass)
3033 error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
3035 else if (const n = importHint(ident.toString()))
3036 error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
3037 else
3039 if (src)
3040 error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true));
3041 else
3042 error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
3044 if (auto dsym = mt.toDsymbol(scope_))
3046 if (auto sym = dsym.isAggregateDeclaration())
3048 if (auto fd = search_function(sym, Id.opDispatch))
3049 errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
3050 else if (!sym.members)
3051 errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
3053 errorSupplemental(dsym.loc, "%s `%s` defined here",
3054 dsym.kind, dsym.toChars());
3058 e = ErrorExp.get();
3060 return e;
3063 Expression visitError(TypeError)
3065 return ErrorExp.get();
3068 Expression visitBasic(TypeBasic mt)
3070 Expression integerValue(dinteger_t i)
3072 return new IntegerExp(loc, i, mt);
3075 Expression intValue(dinteger_t i)
3077 return new IntegerExp(loc, i, Type.tint32);
3080 Expression floatValue(real_t r)
3082 if (mt.isreal() || mt.isimaginary())
3083 return new RealExp(loc, r, mt);
3084 else
3086 return new ComplexExp(loc, complex_t(r, r), mt);
3090 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
3091 if (ident == Id.max)
3093 switch (mt.ty)
3095 case Tint8: return integerValue(byte.max);
3096 case Tuns8: return integerValue(ubyte.max);
3097 case Tint16: return integerValue(short.max);
3098 case Tuns16: return integerValue(ushort.max);
3099 case Tint32: return integerValue(int.max);
3100 case Tuns32: return integerValue(uint.max);
3101 case Tint64: return integerValue(long.max);
3102 case Tuns64: return integerValue(ulong.max);
3103 case Tbool: return integerValue(bool.max);
3104 case Tchar: return integerValue(char.max);
3105 case Twchar: return integerValue(wchar.max);
3106 case Tdchar: return integerValue(dchar.max);
3107 case Tcomplex32:
3108 case Timaginary32:
3109 case Tfloat32: return floatValue(target.FloatProperties.max);
3110 case Tcomplex64:
3111 case Timaginary64:
3112 case Tfloat64: return floatValue(target.DoubleProperties.max);
3113 case Tcomplex80:
3114 case Timaginary80:
3115 case Tfloat80: return floatValue(target.RealProperties.max);
3116 default: break;
3119 else if (ident == Id.min)
3121 switch (mt.ty)
3123 case Tint8: return integerValue(byte.min);
3124 case Tuns8:
3125 case Tuns16:
3126 case Tuns32:
3127 case Tuns64:
3128 case Tbool:
3129 case Tchar:
3130 case Twchar:
3131 case Tdchar: return integerValue(0);
3132 case Tint16: return integerValue(short.min);
3133 case Tint32: return integerValue(int.min);
3134 case Tint64: return integerValue(long.min);
3135 default: break;
3138 else if (ident == Id.min_normal)
3140 switch (mt.ty)
3142 case Tcomplex32:
3143 case Timaginary32:
3144 case Tfloat32: return floatValue(target.FloatProperties.min_normal);
3145 case Tcomplex64:
3146 case Timaginary64:
3147 case Tfloat64: return floatValue(target.DoubleProperties.min_normal);
3148 case Tcomplex80:
3149 case Timaginary80:
3150 case Tfloat80: return floatValue(target.RealProperties.min_normal);
3151 default: break;
3154 else if (ident == Id.nan)
3156 switch (mt.ty)
3158 case Tcomplex32:
3159 case Tcomplex64:
3160 case Tcomplex80:
3161 case Timaginary32:
3162 case Timaginary64:
3163 case Timaginary80:
3164 case Tfloat32:
3165 case Tfloat64:
3166 case Tfloat80: return floatValue(target.RealProperties.nan);
3167 default: break;
3170 else if (ident == Id.infinity)
3172 switch (mt.ty)
3174 case Tcomplex32:
3175 case Tcomplex64:
3176 case Tcomplex80:
3177 case Timaginary32:
3178 case Timaginary64:
3179 case Timaginary80:
3180 case Tfloat32:
3181 case Tfloat64:
3182 case Tfloat80: return floatValue(target.RealProperties.infinity);
3183 default: break;
3186 else if (ident == Id.dig)
3188 switch (mt.ty)
3190 case Tcomplex32:
3191 case Timaginary32:
3192 case Tfloat32: return intValue(target.FloatProperties.dig);
3193 case Tcomplex64:
3194 case Timaginary64:
3195 case Tfloat64: return intValue(target.DoubleProperties.dig);
3196 case Tcomplex80:
3197 case Timaginary80:
3198 case Tfloat80: return intValue(target.RealProperties.dig);
3199 default: break;
3202 else if (ident == Id.epsilon)
3204 switch (mt.ty)
3206 case Tcomplex32:
3207 case Timaginary32:
3208 case Tfloat32: return floatValue(target.FloatProperties.epsilon);
3209 case Tcomplex64:
3210 case Timaginary64:
3211 case Tfloat64: return floatValue(target.DoubleProperties.epsilon);
3212 case Tcomplex80:
3213 case Timaginary80:
3214 case Tfloat80: return floatValue(target.RealProperties.epsilon);
3215 default: break;
3218 else if (ident == Id.mant_dig)
3220 switch (mt.ty)
3222 case Tcomplex32:
3223 case Timaginary32:
3224 case Tfloat32: return intValue(target.FloatProperties.mant_dig);
3225 case Tcomplex64:
3226 case Timaginary64:
3227 case Tfloat64: return intValue(target.DoubleProperties.mant_dig);
3228 case Tcomplex80:
3229 case Timaginary80:
3230 case Tfloat80: return intValue(target.RealProperties.mant_dig);
3231 default: break;
3234 else if (ident == Id.max_10_exp)
3236 switch (mt.ty)
3238 case Tcomplex32:
3239 case Timaginary32:
3240 case Tfloat32: return intValue(target.FloatProperties.max_10_exp);
3241 case Tcomplex64:
3242 case Timaginary64:
3243 case Tfloat64: return intValue(target.DoubleProperties.max_10_exp);
3244 case Tcomplex80:
3245 case Timaginary80:
3246 case Tfloat80: return intValue(target.RealProperties.max_10_exp);
3247 default: break;
3250 else if (ident == Id.max_exp)
3252 switch (mt.ty)
3254 case Tcomplex32:
3255 case Timaginary32:
3256 case Tfloat32: return intValue(target.FloatProperties.max_exp);
3257 case Tcomplex64:
3258 case Timaginary64:
3259 case Tfloat64: return intValue(target.DoubleProperties.max_exp);
3260 case Tcomplex80:
3261 case Timaginary80:
3262 case Tfloat80: return intValue(target.RealProperties.max_exp);
3263 default: break;
3266 else if (ident == Id.min_10_exp)
3268 switch (mt.ty)
3270 case Tcomplex32:
3271 case Timaginary32:
3272 case Tfloat32: return intValue(target.FloatProperties.min_10_exp);
3273 case Tcomplex64:
3274 case Timaginary64:
3275 case Tfloat64: return intValue(target.DoubleProperties.min_10_exp);
3276 case Tcomplex80:
3277 case Timaginary80:
3278 case Tfloat80: return intValue(target.RealProperties.min_10_exp);
3279 default: break;
3282 else if (ident == Id.min_exp)
3284 switch (mt.ty)
3286 case Tcomplex32:
3287 case Timaginary32:
3288 case Tfloat32: return intValue(target.FloatProperties.min_exp);
3289 case Tcomplex64:
3290 case Timaginary64:
3291 case Tfloat64: return intValue(target.DoubleProperties.min_exp);
3292 case Tcomplex80:
3293 case Timaginary80:
3294 case Tfloat80: return intValue(target.RealProperties.min_exp);
3295 default: break;
3298 return visitType(mt);
3301 Expression visitVector(TypeVector mt)
3303 return visitType(mt);
3306 Expression visitEnum(TypeEnum mt)
3308 Expression e;
3309 if (ident == Id.max || ident == Id.min)
3311 return mt.sym.getMaxMinValue(loc, ident);
3313 else if (ident == Id._init)
3315 e = mt.defaultInitLiteral(loc);
3317 else if (ident == Id.stringof)
3319 e = new StringExp(loc, mt.toString());
3320 Scope sc;
3321 e = e.expressionSemantic(&sc);
3323 else if (ident == Id._mangleof)
3325 e = visitType(mt);
3327 else
3329 e = mt.toBasetype().getProperty(scope_, loc, ident, flag);
3331 return e;
3334 Expression visitTuple(TypeTuple mt)
3336 Expression e;
3337 static if (LOGDOTEXP)
3339 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
3341 if (ident == Id.length)
3343 e = new IntegerExp(loc, mt.arguments.length, Type.tsize_t);
3345 else if (ident == Id._init)
3347 e = mt.defaultInitLiteral(loc);
3349 else if (flag)
3351 e = null;
3353 else
3355 error(loc, "no property `%s` for sequence `%s`", ident.toChars(), mt.toChars());
3356 e = ErrorExp.get();
3358 return e;
3361 switch (t.ty)
3363 default: return t.isTypeBasic() ?
3364 visitBasic(cast(TypeBasic)t) :
3365 visitType(t);
3367 case Terror: return visitError (t.isTypeError());
3368 case Tvector: return visitVector(t.isTypeVector());
3369 case Tenum: return visitEnum (t.isTypeEnum());
3370 case Ttuple: return visitTuple (t.isTypeTuple());
3374 /***************************************
3375 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
3376 * Params:
3377 * exp = Expression to look at
3378 * t = if exp should be a Type, set t to that Type else null
3379 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
3380 * e = if exp should remain an Expression, set e to that Expression else null
3383 private void resolveExp(Expression exp, out Type t, out Expression e, out Dsymbol s)
3385 if (exp.isTypeExp())
3386 t = exp.type;
3387 else if (auto ve = exp.isVarExp())
3389 if (auto v = ve.var.isVarDeclaration())
3390 e = exp;
3391 else
3392 s = ve.var;
3394 else if (auto te = exp.isTemplateExp())
3395 s = te.td;
3396 else if (auto se = exp.isScopeExp())
3397 s = se.sds;
3398 else if (exp.isFuncExp())
3399 s = getDsymbol(exp);
3400 else if (auto dte = exp.isDotTemplateExp())
3401 s = dte.td;
3402 else if (exp.isErrorExp())
3403 t = Type.terror;
3404 else
3405 e = exp;
3408 /************************************
3409 * Resolve type 'mt' to either type, symbol, or expression.
3410 * If errors happened, resolved to Type.terror.
3412 * Params:
3413 * mt = type to be resolved
3414 * loc = the location where the type is encountered
3415 * sc = the scope of the type
3416 * pe = is set if t is an expression
3417 * pt = is set if t is a type
3418 * ps = is set if t is a symbol
3419 * intypeid = true if in type id
3421 void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
3423 void returnExp(Expression e)
3425 pe = e;
3426 pt = null;
3427 ps = null;
3430 void returnType(Type t)
3432 pe = null;
3433 pt = t;
3434 ps = null;
3437 void returnSymbol(Dsymbol s)
3439 pe = null;
3440 pt = null;
3441 ps = s;
3444 void returnError()
3446 returnType(Type.terror);
3449 void visitType(Type mt)
3451 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
3452 Type t = typeSemantic(mt, loc, sc);
3453 assert(t);
3454 returnType(t);
3457 void visitSArray(TypeSArray mt)
3459 //printf("TypeSArray::resolve() %s\n", mt.toChars());
3460 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
3461 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
3462 if (pe)
3464 // It's really an index expression
3465 if (Dsymbol s = getDsymbol(pe))
3466 pe = new DsymbolExp(loc, s);
3467 returnExp(new ArrayExp(loc, pe, mt.dim));
3469 else if (ps)
3471 Dsymbol s = ps;
3472 if (auto tup = s.isTupleDeclaration())
3474 mt.dim = semanticLength(sc, tup, mt.dim);
3475 mt.dim = mt.dim.ctfeInterpret();
3476 if (mt.dim.op == EXP.error)
3477 return returnError();
3479 const d = mt.dim.toUInteger();
3480 if (d >= tup.objects.length)
3482 error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong) tup.objects.length);
3483 return returnError();
3486 RootObject o = (*tup.objects)[cast(size_t)d];
3487 switch (o.dyncast()) with (DYNCAST)
3489 case dsymbol:
3490 return returnSymbol(cast(Dsymbol)o);
3491 case expression:
3492 Expression e = cast(Expression)o;
3493 if (e.op == EXP.dSymbol)
3494 return returnSymbol(e.isDsymbolExp().s);
3495 else
3496 return returnExp(e);
3497 case type:
3498 return returnType((cast(Type)o).addMod(mt.mod));
3499 default:
3500 break;
3503 /* Create a new TupleDeclaration which
3504 * is a slice [d..d+1] out of the old one.
3505 * Do it this way because TemplateInstance::semanticTiargs()
3506 * can handle unresolved Objects this way.
3508 auto objects = new Objects(1);
3509 (*objects)[0] = o;
3510 return returnSymbol(new TupleDeclaration(loc, tup.ident, objects));
3512 else
3513 return visitType(mt);
3515 else
3517 if (pt.ty != Terror)
3518 mt.next = pt; // prevent re-running semantic() on 'next'
3519 visitType(mt);
3524 void visitDArray(TypeDArray mt)
3526 //printf("TypeDArray::resolve() %s\n", mt.toChars());
3527 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
3528 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
3529 if (pe)
3531 // It's really a slice expression
3532 if (Dsymbol s = getDsymbol(pe))
3533 pe = new DsymbolExp(loc, s);
3534 returnExp(new ArrayExp(loc, pe));
3536 else if (ps)
3538 if (auto tup = ps.isTupleDeclaration())
3540 // keep ps
3542 else
3543 visitType(mt);
3545 else
3547 if (pt.ty != Terror)
3548 mt.next = pt; // prevent re-running semantic() on 'next'
3549 visitType(mt);
3553 void visitAArray(TypeAArray mt)
3555 //printf("TypeAArray::resolve() %s\n", mt.toChars());
3556 // Deal with the case where we thought the index was a type, but
3557 // in reality it was an expression.
3558 if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray)
3560 Expression e;
3561 Type t;
3562 Dsymbol s;
3563 mt.index.resolve(loc, sc, e, t, s, intypeid);
3564 if (e)
3566 // It was an expression -
3567 // Rewrite as a static array
3568 auto tsa = new TypeSArray(mt.next, e);
3569 tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done
3570 return tsa.resolve(loc, sc, pe, pt, ps, intypeid);
3572 else if (t)
3573 mt.index = t;
3574 else
3575 .error(loc, "index is not a type or an expression");
3577 visitType(mt);
3580 /*************************************
3581 * Takes an array of Identifiers and figures out if
3582 * it represents a Type or an Expression.
3583 * Output:
3584 * if expression, pe is set
3585 * if type, pt is set
3587 void visitIdentifier(TypeIdentifier mt)
3589 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3590 if (mt.ident == Id.ctfe)
3592 error(loc, "variable `__ctfe` cannot be read at compile time");
3593 return returnError();
3595 if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h
3597 /* Since we don't support __builtin_va_start, -arg, -end, we don't
3598 * have to actually care what -list is. A void* will do.
3599 * If we ever do care, import core.stdc.stdarg and pull
3600 * the definition out of that, similarly to how std.math is handled for PowExp
3602 pt = target.va_listType(loc, sc);
3603 return;
3606 Dsymbol scopesym;
3607 Dsymbol s = sc.search(loc, mt.ident, scopesym);
3609 * https://issues.dlang.org/show_bug.cgi?id=1170
3610 * https://issues.dlang.org/show_bug.cgi?id=10739
3612 * If a symbol is not found, it might be declared in
3613 * a mixin-ed string or a mixin-ed template, so before
3614 * issuing an error semantically analyze all string/template
3615 * mixins that are members of the current ScopeDsymbol.
3617 if (!s && sc.enclosing)
3619 ScopeDsymbol sds = sc.enclosing.scopesym;
3620 if (sds && sds.members)
3622 void semanticOnMixin(Dsymbol member)
3624 if (auto compileDecl = member.isMixinDeclaration())
3625 compileDecl.dsymbolSemantic(sc);
3626 else if (auto mixinTempl = member.isTemplateMixin())
3627 mixinTempl.dsymbolSemantic(sc);
3629 sds.members.foreachDsymbol( s => semanticOnMixin(s) );
3630 s = sc.search(loc, mt.ident, scopesym);
3634 if (s)
3636 // https://issues.dlang.org/show_bug.cgi?id=16042
3637 // If `f` is really a function template, then replace `f`
3638 // with the function template declaration.
3639 if (auto f = s.isFuncDeclaration())
3641 if (auto td = getFuncTemplateDecl(f))
3643 // If not at the beginning of the overloaded list of
3644 // `TemplateDeclaration`s, then get the beginning
3645 if (td.overroot)
3646 td = td.overroot;
3647 s = td;
3652 mt.resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
3653 if (pt)
3654 pt = pt.addMod(mt.mod);
3657 void visitInstance(TypeInstance mt)
3659 // Note close similarity to TypeIdentifier::resolve()
3661 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
3662 mt.tempinst.dsymbolSemantic(sc);
3663 if (!global.gag && mt.tempinst.errors)
3664 return returnError();
3666 mt.resolveHelper(loc, sc, mt.tempinst, null, pe, pt, ps, intypeid);
3667 if (pt)
3668 pt = pt.addMod(mt.mod);
3669 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
3672 void visitTypeof(TypeTypeof mt)
3674 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
3675 //static int nest; if (++nest == 50) *(char*)0=0;
3676 if (sc is null)
3678 error(loc, "invalid scope");
3679 return returnError();
3681 if (mt.inuse)
3683 mt.inuse = 2;
3684 error(loc, "circular `typeof` definition");
3685 Lerr:
3686 mt.inuse--;
3687 return returnError();
3689 mt.inuse++;
3691 /* Currently we cannot evaluate 'exp' in speculative context, because
3692 * the type implementation may leak to the final execution. Consider:
3694 * struct S(T) {
3695 * string toString() const { return "x"; }
3697 * void main() {
3698 * alias X = typeof(S!int());
3699 * assert(typeid(X).toString() == "x");
3702 Scope* sc2 = sc.push();
3704 if (!mt.exp.isTypeidExp())
3705 /* Treat typeof(typeid(exp)) as needing
3706 * the full semantic analysis of the typeid.
3707 * https://issues.dlang.org/show_bug.cgi?id=20958
3709 sc2.intypeof = 1;
3711 auto exp2 = mt.exp.expressionSemantic(sc2);
3712 exp2 = resolvePropertiesOnly(sc2, exp2);
3713 sc2.pop();
3715 if (exp2.op == EXP.error)
3717 if (!global.gag)
3718 mt.exp = exp2;
3719 goto Lerr;
3721 mt.exp = exp2;
3723 if ((mt.exp.op == EXP.type || mt.exp.op == EXP.scope_) &&
3724 // https://issues.dlang.org/show_bug.cgi?id=23863
3725 // compile time sequences are valid types
3726 !mt.exp.type.isTypeTuple())
3728 if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof
3729 mt.exp.checkType())
3730 goto Lerr;
3732 /* Today, 'typeof(func)' returns void if func is a
3733 * function template (TemplateExp), or
3734 * template lambda (FuncExp).
3735 * It's actually used in Phobos as an idiom, to branch code for
3736 * template functions.
3739 if (auto f = mt.exp.op == EXP.variable ? mt.exp.isVarExp().var.isFuncDeclaration()
3740 : mt.exp.op == EXP.dotVariable ? mt.exp.isDotVarExp().var.isFuncDeclaration() : null)
3742 // f might be a unittest declaration which is incomplete when compiled
3743 // without -unittest. That causes a segfault in checkForwardRef, see
3744 // https://issues.dlang.org/show_bug.cgi?id=20626
3745 if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && f.checkForwardRef(loc))
3746 goto Lerr;
3748 if (auto f = isFuncAddress(mt.exp))
3750 if (f.checkForwardRef(loc))
3751 goto Lerr;
3754 Type t = mt.exp.type;
3755 if (!t)
3757 error(loc, "expression `%s` has no type", mt.exp.toChars());
3758 goto Lerr;
3760 if (t.ty == Ttypeof)
3762 error(loc, "forward reference to `%s`", mt.toChars());
3763 goto Lerr;
3765 if (mt.idents.length == 0)
3767 returnType(t.addMod(mt.mod));
3769 else
3771 if (Dsymbol s = t.toDsymbol(sc))
3772 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
3773 else
3775 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
3776 e = e.expressionSemantic(sc);
3777 resolveExp(e, pt, pe, ps);
3779 if (pt)
3780 pt = pt.addMod(mt.mod);
3782 mt.inuse--;
3785 void visitReturn(TypeReturn mt)
3787 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3788 Type t;
3790 FuncDeclaration func = sc.func;
3791 if (!func)
3793 error(loc, "`typeof(return)` must be inside function");
3794 return returnError();
3796 if (func.fes)
3797 func = func.fes.func;
3798 t = func.type.nextOf();
3799 if (!t)
3801 error(loc, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc.func.toChars());
3802 return returnError();
3805 if (mt.idents.length == 0)
3807 return returnType(t.addMod(mt.mod));
3809 else
3811 if (Dsymbol s = t.toDsymbol(sc))
3812 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
3813 else
3815 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
3816 e = e.expressionSemantic(sc);
3817 resolveExp(e, pt, pe, ps);
3819 if (pt)
3820 pt = pt.addMod(mt.mod);
3824 void visitSlice(TypeSlice mt)
3826 mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
3827 if (pe)
3829 // It's really a slice expression
3830 if (Dsymbol s = getDsymbol(pe))
3831 pe = new DsymbolExp(loc, s);
3832 return returnExp(new ArrayExp(loc, pe, new IntervalExp(loc, mt.lwr, mt.upr)));
3834 else if (ps)
3836 Dsymbol s = ps;
3837 TupleDeclaration td = s.isTupleDeclaration();
3838 if (td)
3840 /* It's a slice of a TupleDeclaration
3842 ScopeDsymbol sym = new ArrayScopeSymbol(sc, td);
3843 sym.parent = sc.scopesym;
3844 sc = sc.push(sym);
3845 sc = sc.startCTFE();
3846 mt.lwr = mt.lwr.expressionSemantic(sc);
3847 mt.upr = mt.upr.expressionSemantic(sc);
3848 sc = sc.endCTFE();
3849 sc = sc.pop();
3851 mt.lwr = mt.lwr.ctfeInterpret();
3852 mt.upr = mt.upr.ctfeInterpret();
3853 const i1 = mt.lwr.toUInteger();
3854 const i2 = mt.upr.toUInteger();
3855 if (!(i1 <= i2 && i2 <= td.objects.length))
3857 error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1, i2, cast(ulong) td.objects.length);
3858 return returnError();
3861 if (i1 == 0 && i2 == td.objects.length)
3863 return returnSymbol(td);
3866 /* Create a new TupleDeclaration which
3867 * is a slice [i1..i2] out of the old one.
3869 auto objects = new Objects(cast(size_t)(i2 - i1));
3870 for (size_t i = 0; i < objects.length; i++)
3872 (*objects)[i] = (*td.objects)[cast(size_t)i1 + i];
3875 return returnSymbol(new TupleDeclaration(loc, td.ident, objects));
3877 else
3878 visitType(mt);
3880 else
3882 if (pt.ty != Terror)
3883 mt.next = pt; // prevent re-running semantic() on 'next'
3884 visitType(mt);
3888 void visitMixin(TypeMixin mt)
3890 RootObject o = mt.obj;
3892 // if already resolved just set pe/pt/ps and return.
3893 if (o)
3895 pe = o.isExpression();
3896 pt = o.isType();
3897 ps = o.isDsymbol();
3898 return;
3901 o = mt.compileTypeMixin(loc, sc);
3902 if (auto t = o.isType())
3904 resolve(t, loc, sc, pe, pt, ps, intypeid);
3905 if (pt)
3906 pt = pt.addMod(mt.mod);
3908 else if (auto e = o.isExpression())
3910 e = e.expressionSemantic(sc);
3911 if (auto et = e.isTypeExp())
3912 returnType(et.type.addMod(mt.mod));
3913 else
3914 returnExp(e);
3916 else
3917 returnError();
3919 // save the result
3920 mt.obj = pe ? pe : (pt ? pt : ps);
3923 void visitTraits(TypeTraits mt)
3925 // if already resolved just return the cached object.
3926 if (mt.obj)
3928 pt = mt.obj.isType();
3929 ps = mt.obj.isDsymbol();
3930 pe = mt.obj.isExpression();
3931 return;
3934 import dmd.traits : semanticTraits;
3936 if (Expression e = semanticTraits(mt.exp, sc))
3938 switch (e.op)
3940 case EXP.dotVariable:
3941 mt.obj = e.isDotVarExp().var;
3942 break;
3943 case EXP.variable:
3944 mt.obj = e.isVarExp().var;
3945 break;
3946 case EXP.function_:
3947 auto fe = e.isFuncExp();
3948 mt.obj = fe.td ? fe.td : fe.fd;
3949 break;
3950 case EXP.dotTemplateDeclaration:
3951 mt.obj = e.isDotTemplateExp().td;
3952 break;
3953 case EXP.dSymbol:
3954 mt.obj = e.isDsymbolExp().s;
3955 break;
3956 case EXP.template_:
3957 mt.obj = e.isTemplateExp().td;
3958 break;
3959 case EXP.scope_:
3960 mt.obj = e.isScopeExp().sds;
3961 break;
3962 case EXP.tuple:
3963 TupleExp te = e.isTupleExp();
3964 Objects* elems = new Objects(te.exps.length);
3965 foreach (i; 0 .. elems.length)
3967 auto src = (*te.exps)[i];
3968 switch (src.op)
3970 case EXP.type:
3971 (*elems)[i] = src.isTypeExp().type;
3972 break;
3973 case EXP.dotType:
3974 (*elems)[i] = src.isDotTypeExp().sym.isType();
3975 break;
3976 case EXP.overloadSet:
3977 (*elems)[i] = src.isOverExp().type;
3978 break;
3979 default:
3980 if (auto sym = isDsymbol(src))
3981 (*elems)[i] = sym;
3982 else
3983 (*elems)[i] = src;
3986 TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
3987 mt.obj = td;
3988 break;
3989 case EXP.dotType:
3990 mt.obj = e.isDotTypeExp().sym.isType();
3991 break;
3992 case EXP.type:
3993 mt.obj = e.isTypeExp().type;
3994 break;
3995 case EXP.overloadSet:
3996 mt.obj = e.isOverExp().type;
3997 break;
3998 case EXP.error:
3999 break;
4000 default:
4001 mt.obj = e;
4002 break;
4006 if (mt.obj)
4008 if (auto t = mt.obj.isType())
4010 t = t.addMod(mt.mod);
4011 mt.obj = t;
4012 returnType(t);
4014 else if (auto s = mt.obj.isDsymbol())
4015 returnSymbol(s);
4016 else if (auto e = mt.obj.isExpression())
4017 returnExp(e);
4019 else
4021 assert(global.errors);
4022 mt.obj = Type.terror;
4023 return returnError();
4027 switch (mt.ty)
4029 default: visitType (mt); break;
4030 case Tsarray: visitSArray (mt.isTypeSArray()); break;
4031 case Tarray: visitDArray (mt.isTypeDArray()); break;
4032 case Taarray: visitAArray (mt.isTypeAArray()); break;
4033 case Tident: visitIdentifier(mt.isTypeIdentifier()); break;
4034 case Tinstance: visitInstance (mt.isTypeInstance()); break;
4035 case Ttypeof: visitTypeof (mt.isTypeTypeof()); break;
4036 case Treturn: visitReturn (mt.isTypeReturn()); break;
4037 case Tslice: visitSlice (mt.isTypeSlice()); break;
4038 case Tmixin: visitMixin (mt.isTypeMixin()); break;
4039 case Ttraits: visitTraits (mt.isTypeTraits()); break;
4043 /************************
4044 * Access the members of the object e. This type is same as e.type.
4045 * Params:
4046 * mt = type for which the dot expression is used
4047 * sc = instantiating scope
4048 * e = expression to convert
4049 * ident = identifier being used
4050 * flag = DotExpFlag bit flags
4052 * Returns:
4053 * resulting expression with e.ident resolved
4055 Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag)
4057 Expression visitType(Type mt)
4059 VarDeclaration v = null;
4060 static if (LOGDOTEXP)
4062 printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4064 Expression ex = e.lastComma();
4065 if (ex.op == EXP.dotVariable)
4067 DotVarExp dv = cast(DotVarExp)ex;
4068 v = dv.var.isVarDeclaration();
4070 else if (ex.op == EXP.variable)
4072 VarExp ve = cast(VarExp)ex;
4073 v = ve.var.isVarDeclaration();
4075 if (v)
4077 if (ident == Id.offsetof)
4079 v.dsymbolSemantic(null);
4080 if (v.isField())
4082 auto ad = v.isMember();
4083 objc.checkOffsetof(e, ad);
4084 ad.size(e.loc);
4085 if (ad.sizeok != Sizeok.done)
4086 return ErrorExp.get();
4087 return new IntegerExp(e.loc, v.offset, Type.tsize_t);
4090 else if (ident == Id._init)
4092 Type tb = mt.toBasetype();
4093 e = mt.defaultInitLiteral(e.loc);
4094 if (tb.ty == Tstruct && tb.needsNested())
4096 e.isStructLiteralExp().useStaticInit = true;
4098 goto Lreturn;
4101 if (ident == Id.stringof)
4103 /* https://issues.dlang.org/show_bug.cgi?id=3796
4104 * this should demangle e.type.deco rather than
4105 * pretty-printing the type.
4107 e = new StringExp(e.loc, e.toString());
4109 else
4110 e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag);
4112 Lreturn:
4113 if (e)
4114 e = e.expressionSemantic(sc);
4115 return e;
4118 Expression visitError(TypeError)
4120 return ErrorExp.get();
4123 Expression visitBasic(TypeBasic mt)
4125 static if (LOGDOTEXP)
4127 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4129 Type t;
4130 if (ident == Id.re)
4132 switch (mt.ty)
4134 case Tcomplex32:
4135 t = mt.tfloat32;
4136 goto L1;
4138 case Tcomplex64:
4139 t = mt.tfloat64;
4140 goto L1;
4142 case Tcomplex80:
4143 t = mt.tfloat80;
4144 goto L1;
4146 e = e.castTo(sc, t);
4147 break;
4149 case Tfloat32:
4150 case Tfloat64:
4151 case Tfloat80:
4152 break;
4154 case Timaginary32:
4155 t = mt.tfloat32;
4156 goto L2;
4158 case Timaginary64:
4159 t = mt.tfloat64;
4160 goto L2;
4162 case Timaginary80:
4163 t = mt.tfloat80;
4164 goto L2;
4166 e = new RealExp(e.loc, CTFloat.zero, t);
4167 break;
4169 default:
4170 e = mt.Type.getProperty(sc, e.loc, ident, flag);
4171 break;
4174 else if (ident == Id.im)
4176 Type t2;
4177 switch (mt.ty)
4179 case Tcomplex32:
4180 t = mt.timaginary32;
4181 t2 = mt.tfloat32;
4182 goto L3;
4184 case Tcomplex64:
4185 t = mt.timaginary64;
4186 t2 = mt.tfloat64;
4187 goto L3;
4189 case Tcomplex80:
4190 t = mt.timaginary80;
4191 t2 = mt.tfloat80;
4192 goto L3;
4194 e = e.castTo(sc, t);
4195 e.type = t2;
4196 break;
4198 case Timaginary32:
4199 t = mt.tfloat32;
4200 goto L4;
4202 case Timaginary64:
4203 t = mt.tfloat64;
4204 goto L4;
4206 case Timaginary80:
4207 t = mt.tfloat80;
4208 goto L4;
4210 e = e.copy();
4211 e.type = t;
4212 break;
4214 case Tfloat32:
4215 case Tfloat64:
4216 case Tfloat80:
4217 e = new RealExp(e.loc, CTFloat.zero, mt);
4218 break;
4220 default:
4221 e = mt.Type.getProperty(sc, e.loc, ident, flag);
4222 break;
4225 else
4227 return visitType(mt);
4229 if (!(flag & 1) || e)
4230 e = e.expressionSemantic(sc);
4231 return e;
4234 Expression visitVector(TypeVector mt)
4236 static if (LOGDOTEXP)
4238 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4240 if (ident == Id.ptr && e.op == EXP.call)
4242 /* The trouble with EXP.call is the return ABI for float[4] is different from
4243 * __vector(float[4]), and a type paint won't do.
4245 e = new AddrExp(e.loc, e);
4246 e = e.expressionSemantic(sc);
4247 return e.castTo(sc, mt.basetype.nextOf().pointerTo());
4249 if (ident == Id.array)
4251 //e = e.castTo(sc, basetype);
4252 // Keep lvalue-ness
4253 e = new VectorArrayExp(e.loc, e);
4254 e = e.expressionSemantic(sc);
4255 return e;
4257 if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof)
4259 // init should return a new VectorExp
4260 // https://issues.dlang.org/show_bug.cgi?id=12776
4261 // offsetof does not work on a cast expression, so use e directly
4262 // stringof should not add a cast to the output
4263 return visitType(mt);
4266 // Properties based on the vector element type and are values of the element type
4267 if (ident == Id.max || ident == Id.min || ident == Id.min_normal ||
4268 ident == Id.nan || ident == Id.infinity || ident == Id.epsilon)
4270 auto vet = mt.basetype.isTypeSArray().next; // vector element type
4271 if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag))
4272 return ev.castTo(sc, mt); // 'broadcast' ev to the vector elements
4275 return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag);
4278 Expression visitArray(TypeArray mt)
4280 static if (LOGDOTEXP)
4282 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4285 e = visitType(mt);
4287 if (!(flag & 1) || e)
4288 e = e.expressionSemantic(sc);
4289 return e;
4292 Expression visitSArray(TypeSArray mt)
4294 static if (LOGDOTEXP)
4296 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4298 if (ident == Id.length)
4300 Loc oldLoc = e.loc;
4301 e = mt.dim.copy();
4302 e.loc = oldLoc;
4304 else if (ident == Id.ptr)
4306 if (e.op == EXP.type)
4308 error(e.loc, "`%s` is not an expression", e.toChars());
4309 return ErrorExp.get();
4311 else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
4313 // .ptr on static array is @safe unless size is 0
4314 // https://issues.dlang.org/show_bug.cgi?id=20853
4315 return ErrorExp.get();
4317 e = e.castTo(sc, e.type.nextOf().pointerTo());
4319 else if (ident == Id._tupleof)
4321 if (e.isTypeExp())
4323 error(e.loc, "`.tupleof` cannot be used on type `%s`", mt.toChars);
4324 return ErrorExp.get();
4326 else
4328 Expression e0;
4329 Expression ev = e;
4330 ev = extractSideEffect(sc, "__tup", e0, ev);
4332 const length = cast(size_t)mt.dim.toUInteger();
4333 auto exps = new Expressions();
4334 exps.reserve(length);
4335 foreach (i; 0 .. length)
4336 exps.push(new IndexExp(e.loc, ev, new IntegerExp(e.loc, i, Type.tsize_t)));
4337 e = new TupleExp(e.loc, e0, exps);
4340 else
4342 e = visitArray(mt);
4344 if (!(flag & 1) || e)
4345 e = e.expressionSemantic(sc);
4346 return e;
4349 Expression visitDArray(TypeDArray mt)
4351 static if (LOGDOTEXP)
4353 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4355 if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
4357 error(e.loc, "`%s` is not an expression", e.toChars());
4358 return ErrorExp.get();
4360 if (ident == Id.length)
4362 if (e.op == EXP.string_)
4364 StringExp se = cast(StringExp)e;
4365 return new IntegerExp(se.loc, se.len, Type.tsize_t);
4367 if (e.op == EXP.null_)
4369 return new IntegerExp(e.loc, 0, Type.tsize_t);
4371 if (checkNonAssignmentArrayOp(e))
4373 return ErrorExp.get();
4375 e = new ArrayLengthExp(e.loc, e);
4376 e.type = Type.tsize_t;
4377 return e;
4379 else if (ident == Id.ptr)
4381 if (checkUnsafeDotExp(sc, e, ident, flag))
4382 return ErrorExp.get();
4383 return e.castTo(sc, mt.next.pointerTo());
4385 else
4387 return visitArray(mt);
4391 Expression visitAArray(TypeAArray mt)
4393 static if (LOGDOTEXP)
4395 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4397 if (ident == Id.length)
4399 __gshared FuncDeclaration fd_aaLen = null;
4400 if (fd_aaLen is null)
4402 auto fparams = new Parameters();
4403 fparams.push(new Parameter(Loc.initial, STC.const_ | STC.scope_, mt, null, null, null));
4404 fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen);
4405 TypeFunction tf = fd_aaLen.type.toTypeFunction();
4406 tf.purity = PURE.const_;
4407 tf.isnothrow = true;
4408 tf.isnogc = false;
4410 Expression ev = new VarExp(e.loc, fd_aaLen, false);
4411 e = new CallExp(e.loc, ev, e);
4412 e.type = fd_aaLen.type.toTypeFunction().next;
4413 return e;
4415 else
4417 return visitType(mt);
4421 Expression visitReference(TypeReference mt)
4423 static if (LOGDOTEXP)
4425 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4427 // References just forward things along
4428 return mt.next.dotExp(sc, e, ident, flag);
4431 Expression visitDelegate(TypeDelegate mt)
4433 static if (LOGDOTEXP)
4435 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4437 if (ident == Id.ptr)
4439 e = new DelegatePtrExp(e.loc, e);
4440 e = e.expressionSemantic(sc);
4442 else if (ident == Id.funcptr)
4444 if (checkUnsafeDotExp(sc, e, ident, flag))
4446 return ErrorExp.get();
4448 e = new DelegateFuncptrExp(e.loc, e);
4449 e = e.expressionSemantic(sc);
4451 else
4453 return visitType(mt);
4455 return e;
4458 /***************************************
4459 * `ident` was not found as a member of `mt`.
4460 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
4461 * If that fails, forward to visitType().
4462 * Params:
4463 * mt = class or struct
4464 * sc = context
4465 * e = `this` for `ident`
4466 * ident = name of member
4467 * flag = flag & 1, don't report "not a property" error and just return NULL.
4468 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
4469 * Returns:
4470 * resolved expression if found, otherwise null
4472 Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
4474 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
4476 bool gagError = flag & 1;
4478 __gshared int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
4480 static Expression returnExp(Expression e)
4482 --nest;
4483 return e;
4486 if (++nest > global.recursionLimit)
4488 .error(e.loc, "cannot resolve identifier `%s`", ident.toChars());
4489 return returnExp(gagError ? null : ErrorExp.get());
4493 assert(mt.ty == Tstruct || mt.ty == Tclass);
4494 auto sym = mt.toDsymbol(sc).isAggregateDeclaration();
4495 assert(sym);
4496 if (// https://issues.dlang.org/show_bug.cgi?id=22054
4497 // if a class or struct does not have a body
4498 // there is no point in searching for its members
4499 sym.members &&
4500 ident != Id.__sizeof &&
4501 ident != Id.__xalignof &&
4502 ident != Id._init &&
4503 ident != Id._mangleof &&
4504 ident != Id.stringof &&
4505 ident != Id.offsetof &&
4506 // https://issues.dlang.org/show_bug.cgi?id=15045
4507 // Don't forward special built-in member functions.
4508 ident != Id.ctor &&
4509 ident != Id.dtor &&
4510 ident != Id.__xdtor &&
4511 ident != Id.postblit &&
4512 ident != Id.__xpostblit)
4514 /* Look for overloaded opDot() to see if we should forward request
4515 * to it.
4517 if (auto fd = search_function(sym, Id.opDot))
4519 /* Rewrite e.ident as:
4520 * e.opDot().ident
4522 e = build_overload(e.loc, sc, e, null, fd);
4523 // @@@DEPRECATED_2.110@@@.
4524 // Deprecated in 2.082, made an error in 2.100.
4525 error(e.loc, "`opDot` is obsolete. Use `alias this`");
4526 return ErrorExp.get();
4529 /* Look for overloaded opDispatch to see if we should forward request
4530 * to it.
4532 if (auto fd = search_function(sym, Id.opDispatch))
4534 /* Rewrite e.ident as:
4535 * e.opDispatch!("ident")
4537 TemplateDeclaration td = fd.isTemplateDeclaration();
4538 if (!td)
4540 .error(fd.loc, "%s `%s` must be a template `opDispatch(string s)`, not a %s", fd.kind, fd.toPrettyChars, fd.kind());
4541 return returnExp(ErrorExp.get());
4543 auto se = new StringExp(e.loc, ident.toString());
4544 auto tiargs = new Objects();
4545 tiargs.push(se);
4546 auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs);
4547 dti.ti.tempdecl = td;
4548 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
4549 * e.g.
4550 * template opDispatch(name) if (isValid!name) { ... }
4552 uint errors = gagError ? global.startGagging() : 0;
4553 e = dti.dotTemplateSemanticProp(sc, DotExpFlag.none);
4554 if (gagError && global.endGagging(errors))
4555 e = null;
4556 return returnExp(e);
4559 /* See if we should forward to the alias this.
4561 auto alias_e = flag & DotExpFlag.noAliasThis ? null
4562 : resolveAliasThis(sc, e, gagError);
4563 if (alias_e && alias_e != e)
4565 /* Rewrite e.ident as:
4566 * e.aliasthis.ident
4568 auto die = new DotIdExp(e.loc, alias_e, ident);
4570 auto errors = gagError ? 0 : global.startGagging();
4571 auto exp = die.dotIdSemanticProp(sc, gagError);
4572 if (!gagError)
4574 global.endGagging(errors);
4575 if (exp && exp.op == EXP.error)
4576 exp = null;
4579 if (exp && gagError)
4580 // now that we know that the alias this leads somewhere useful,
4581 // go back and print deprecations/warnings that we skipped earlier due to the gag
4582 resolveAliasThis(sc, e, false);
4584 return returnExp(exp);
4587 return returnExp(visitType(mt));
4590 Expression visitStruct(TypeStruct mt)
4592 Dsymbol s;
4593 static if (LOGDOTEXP)
4595 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4597 assert(e.op != EXP.dot);
4599 // https://issues.dlang.org/show_bug.cgi?id=14010
4600 if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
4602 return mt.getProperty(sc, e.loc, ident, flag & 1);
4605 /* If e.tupleof
4607 if (ident == Id._tupleof)
4609 /* Create a TupleExp out of the fields of the struct e:
4610 * (e.field0, e.field1, e.field2, ...)
4612 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
4614 if (!mt.sym.determineFields())
4616 error(e.loc, "unable to determine fields of `%s` because of forward references", mt.toChars());
4619 Expression e0;
4620 Expression ev = e.op == EXP.type ? null : e;
4621 if (ev)
4622 ev = extractSideEffect(sc, "__tup", e0, ev);
4624 auto exps = new Expressions();
4625 exps.reserve(mt.sym.fields.length);
4626 for (size_t i = 0; i < mt.sym.fields.length; i++)
4628 VarDeclaration v = mt.sym.fields[i];
4629 Expression ex;
4630 if (ev)
4631 ex = new DotVarExp(e.loc, ev, v);
4632 else
4634 ex = new VarExp(e.loc, v);
4635 ex.type = ex.type.addMod(e.type.mod);
4637 exps.push(ex);
4640 e = new TupleExp(e.loc, e0, exps);
4641 Scope* sc2 = sc.push();
4642 sc2.flags |= SCOPE.noaccesscheck;
4643 e = e.expressionSemantic(sc2);
4644 sc2.pop();
4645 return e;
4648 immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
4649 s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
4651 if (!s)
4653 return noMember(mt, sc, e, ident, flag);
4655 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
4657 return noMember(mt, sc, e, ident, flag);
4659 // check before alias resolution; the alias itself might be deprecated!
4660 if (s.isAliasDeclaration)
4661 s.checkDeprecated(e.loc, sc);
4662 s = s.toAlias();
4664 if (auto em = s.isEnumMember())
4666 return em.getVarExp(e.loc, sc);
4668 if (auto v = s.isVarDeclaration())
4670 v.checkDeprecated(e.loc, sc);
4671 v.checkDisabled(e.loc, sc);
4672 if (!v.type ||
4673 !v.type.deco && v.inuse)
4675 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
4676 error(e.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
4677 else
4678 error(e.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
4679 return ErrorExp.get();
4681 if (v.type.ty == Terror)
4683 return ErrorExp.get();
4686 if ((v.storage_class & STC.manifest) && v._init)
4688 if (v.inuse)
4690 error(e.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
4691 return ErrorExp.get();
4693 checkAccess(e.loc, sc, null, v);
4694 Expression ve = new VarExp(e.loc, v);
4695 if (!isTrivialExp(e))
4697 ve = new CommaExp(e.loc, e, ve);
4699 return ve.expressionSemantic(sc);
4703 if (auto t = s.getType())
4705 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
4708 TemplateMixin tm = s.isTemplateMixin();
4709 if (tm)
4711 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
4714 TemplateDeclaration td = s.isTemplateDeclaration();
4715 if (td)
4717 if (e.op == EXP.type)
4718 e = new TemplateExp(e.loc, td);
4719 else
4720 e = new DotTemplateExp(e.loc, e, td);
4721 return e.expressionSemantic(sc);
4724 TemplateInstance ti = s.isTemplateInstance();
4725 if (ti)
4727 if (!ti.semanticRun)
4729 ti.dsymbolSemantic(sc);
4730 if (!ti.inst || ti.errors) // if template failed to expand
4732 return ErrorExp.get();
4735 s = ti.inst.toAlias();
4736 if (!s.isTemplateInstance())
4737 goto L1;
4738 if (e.op == EXP.type)
4739 e = new ScopeExp(e.loc, ti);
4740 else
4741 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
4742 return e.expressionSemantic(sc);
4745 if (s.isImport() || s.isModule() || s.isPackage())
4747 return symbolToExp(s, e.loc, sc, false);
4750 OverloadSet o = s.isOverloadSet();
4751 if (o)
4753 auto oe = new OverExp(e.loc, o);
4754 if (e.op == EXP.type)
4756 return oe;
4758 return new DotExp(e.loc, e, oe);
4761 Declaration d = s.isDeclaration();
4762 if (!d)
4764 error(e.loc, "`%s.%s` is not a declaration", e.toChars(), ident.toChars());
4765 return ErrorExp.get();
4768 if (e.op == EXP.type)
4770 /* It's:
4771 * Struct.d
4773 if (TupleDeclaration tup = d.isTupleDeclaration())
4775 e = new TupleExp(e.loc, tup);
4776 return e.expressionSemantic(sc);
4778 if (d.needThis() && sc.intypeof != 1)
4780 /* Rewrite as:
4781 * this.d
4783 * only if the scope in which we are
4784 * has a `this` that matches the type
4785 * of the lhs of the dot expression.
4787 * https://issues.dlang.org/show_bug.cgi?id=23617
4789 auto fd = hasThis(sc);
4790 if (fd && fd.isThis() == mt.sym)
4792 e = new DotVarExp(e.loc, new ThisExp(e.loc), d);
4793 return e.expressionSemantic(sc);
4796 if (d.semanticRun == PASS.initial)
4797 d.dsymbolSemantic(null);
4798 checkAccess(e.loc, sc, e, d);
4799 auto ve = new VarExp(e.loc, d);
4800 if (d.isVarDeclaration() && d.needThis())
4801 ve.type = d.type.addMod(e.type.mod);
4802 return ve;
4805 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
4806 if (d.isDataseg() || unreal && d.isField())
4808 // (e, d)
4809 checkAccess(e.loc, sc, e, d);
4810 Expression ve = new VarExp(e.loc, d);
4811 e = unreal ? ve : new CommaExp(e.loc, e, ve);
4812 return e.expressionSemantic(sc);
4815 e = new DotVarExp(e.loc, e, d);
4816 return e.expressionSemantic(sc);
4819 Expression visitEnum(TypeEnum mt)
4821 static if (LOGDOTEXP)
4823 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), mt.toChars());
4825 // https://issues.dlang.org/show_bug.cgi?id=14010
4826 if (ident == Id._mangleof)
4828 return mt.getProperty(sc, e.loc, ident, flag & 1);
4831 if (mt.sym.semanticRun < PASS.semanticdone)
4832 mt.sym.dsymbolSemantic(null);
4834 Dsymbol s = mt.sym.search(e.loc, ident);
4835 if (!s)
4837 if (ident == Id._init)
4839 return mt.getProperty(sc, e.loc, ident, flag & 1);
4842 /* Allow special enums to not need a member list
4844 if ((ident == Id.max || ident == Id.min) && (mt.sym.members || !mt.sym.isSpecial()))
4846 return mt.getProperty(sc, e.loc, ident, flag & 1);
4849 Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, DotExpFlag.gag);
4850 if (!(flag & 1) && !res)
4852 if (auto ns = mt.sym.search_correct(ident))
4853 error(e.loc, "no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
4854 ns.toChars());
4855 else
4856 error(e.loc, "no property `%s` for type `%s`", ident.toChars(),
4857 mt.toChars());
4859 errorSupplemental(mt.sym.loc, "%s `%s` defined here",
4860 mt.sym.kind, mt.toChars());
4861 return ErrorExp.get();
4863 return res;
4865 EnumMember m = s.isEnumMember();
4866 return m.getVarExp(e.loc, sc);
4869 Expression visitClass(TypeClass mt)
4871 Dsymbol s;
4872 static if (LOGDOTEXP)
4874 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
4876 assert(e.op != EXP.dot);
4878 // https://issues.dlang.org/show_bug.cgi?id=12543
4879 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
4881 return mt.Type.getProperty(sc, e.loc, ident, 0);
4884 /* If e.tupleof
4886 if (ident == Id._tupleof)
4888 objc.checkTupleof(e, mt);
4890 /* Create a TupleExp
4892 e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
4894 mt.sym.size(e.loc); // do semantic of type
4896 Expression e0;
4897 Expression ev = e.op == EXP.type ? null : e;
4898 if (ev)
4899 ev = extractSideEffect(sc, "__tup", e0, ev);
4901 auto exps = new Expressions();
4902 exps.reserve(mt.sym.fields.length);
4903 for (size_t i = 0; i < mt.sym.fields.length; i++)
4905 VarDeclaration v = mt.sym.fields[i];
4906 // Don't include hidden 'this' pointer
4907 if (v.isThisDeclaration())
4908 continue;
4909 Expression ex;
4910 if (ev)
4911 ex = new DotVarExp(e.loc, ev, v);
4912 else
4914 ex = new VarExp(e.loc, v);
4915 ex.type = ex.type.addMod(e.type.mod);
4917 exps.push(ex);
4920 e = new TupleExp(e.loc, e0, exps);
4921 Scope* sc2 = sc.push();
4922 sc2.flags |= SCOPE.noaccesscheck;
4923 e = e.expressionSemantic(sc2);
4924 sc2.pop();
4925 return e;
4928 SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
4929 s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
4932 if (!s)
4934 // See if it's a 'this' class or a base class
4935 if (mt.sym.ident == ident)
4937 if (e.op == EXP.type)
4939 return mt.Type.getProperty(sc, e.loc, ident, 0);
4941 e = new DotTypeExp(e.loc, e, mt.sym);
4942 e = e.expressionSemantic(sc);
4943 return e;
4945 if (auto cbase = mt.sym.searchBase(ident))
4947 if (e.op == EXP.type)
4949 return mt.Type.getProperty(sc, e.loc, ident, 0);
4951 if (auto ifbase = cbase.isInterfaceDeclaration())
4952 e = new CastExp(e.loc, e, ifbase.type);
4953 else
4954 e = new DotTypeExp(e.loc, e, cbase);
4955 e = e.expressionSemantic(sc);
4956 return e;
4959 if (ident == Id.classinfo)
4961 if (!Type.typeinfoclass)
4963 error(e.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4964 return ErrorExp.get();
4967 Type t = Type.typeinfoclass.type;
4968 if (e.op == EXP.type || e.op == EXP.dotType)
4970 /* For type.classinfo, we know the classinfo
4971 * at compile time.
4973 if (!mt.sym.vclassinfo)
4974 mt.sym.vclassinfo = new TypeInfoClassDeclaration(mt.sym.type);
4975 e = new VarExp(e.loc, mt.sym.vclassinfo);
4976 e = e.addressOf();
4977 e.type = t; // do this so we don't get redundant dereference
4979 else
4981 /* For class objects, the classinfo reference is the first
4982 * entry in the vtbl[]
4984 e = new PtrExp(e.loc, e);
4985 e.type = t.pointerTo();
4986 if (mt.sym.isInterfaceDeclaration())
4988 if (mt.sym.isCPPinterface())
4990 /* C++ interface vtbl[]s are different in that the
4991 * first entry is always pointer to the first virtual
4992 * function, not classinfo.
4993 * We can't get a .classinfo for it.
4995 error(e.loc, "no `.classinfo` for C++ interface objects");
4997 /* For an interface, the first entry in the vtbl[]
4998 * is actually a pointer to an instance of struct Interface.
4999 * The first member of Interface is the .classinfo,
5000 * so add an extra pointer indirection.
5002 e.type = e.type.pointerTo();
5003 e = new PtrExp(e.loc, e);
5004 e.type = t.pointerTo();
5006 e = new PtrExp(e.loc, e, t);
5008 return e;
5011 if (ident == Id.__vptr)
5013 /* The pointer to the vtbl[]
5014 * *cast(immutable(void*)**)e
5016 e = e.castTo(sc, mt.tvoidptr.immutableOf().pointerTo().pointerTo());
5017 e = new PtrExp(e.loc, e);
5018 e = e.expressionSemantic(sc);
5019 return e;
5022 if (ident == Id.__monitor && mt.sym.hasMonitor())
5024 /* The handle to the monitor (call it a void*)
5025 * *(cast(void**)e + 1)
5027 e = e.castTo(sc, mt.tvoidptr.pointerTo());
5028 e = new AddExp(e.loc, e, IntegerExp.literal!1);
5029 e = new PtrExp(e.loc, e);
5030 e = e.expressionSemantic(sc);
5031 return e;
5034 if (ident == Id.outer && mt.sym.vthis)
5036 if (mt.sym.vthis.semanticRun == PASS.initial)
5037 mt.sym.vthis.dsymbolSemantic(null);
5039 if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
5041 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
5042 dve.type = cdp.type.addMod(e.type.mod);
5043 return dve;
5046 /* https://issues.dlang.org/show_bug.cgi?id=15839
5047 * Find closest parent class through nested functions.
5049 for (auto p = mt.sym.toParentLocal(); p; p = p.toParentLocal())
5051 auto fd = p.isFuncDeclaration();
5052 if (!fd)
5053 break;
5054 auto ad = fd.isThis();
5055 if (!ad && fd.isNested())
5056 continue;
5057 if (!ad)
5058 break;
5059 if (auto cdp = ad.isClassDeclaration())
5061 auto ve = new ThisExp(e.loc);
5063 ve.var = fd.vthis;
5064 const nestedError = fd.vthis.checkNestedReference(sc, e.loc);
5065 assert(!nestedError);
5067 ve.type = cdp.type.addMod(fd.vthis.type.mod).addMod(e.type.mod);
5068 return ve;
5070 break;
5073 // Continue to show enclosing function's frame (stack or closure).
5074 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
5075 dve.type = mt.sym.vthis.type.addMod(e.type.mod);
5076 return dve;
5079 return noMember(mt, sc, e, ident, flag & 1);
5081 if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
5083 return noMember(mt, sc, e, ident, flag);
5085 if (!s.isFuncDeclaration()) // because of overloading
5087 s.checkDeprecated(e.loc, sc);
5088 if (auto d = s.isDeclaration())
5089 d.checkDisabled(e.loc, sc);
5091 s = s.toAlias();
5093 if (auto em = s.isEnumMember())
5095 return em.getVarExp(e.loc, sc);
5097 if (auto v = s.isVarDeclaration())
5099 if (!v.type ||
5100 !v.type.deco && v.inuse)
5102 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
5103 error(e.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
5104 else
5105 error(e.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
5106 return ErrorExp.get();
5108 if (v.type.ty == Terror)
5110 error(e.loc, "type of variable `%s` has errors", v.toPrettyChars);
5111 return ErrorExp.get();
5114 if ((v.storage_class & STC.manifest) && v._init)
5116 if (v.inuse)
5118 error(e.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
5119 return ErrorExp.get();
5121 checkAccess(e.loc, sc, null, v);
5122 Expression ve = new VarExp(e.loc, v);
5123 ve = ve.expressionSemantic(sc);
5124 return ve;
5128 if (auto t = s.getType())
5130 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
5133 TemplateMixin tm = s.isTemplateMixin();
5134 if (tm)
5136 return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
5139 TemplateDeclaration td = s.isTemplateDeclaration();
5141 Expression toTemplateExp(TemplateDeclaration td)
5143 if (e.op == EXP.type)
5144 e = new TemplateExp(e.loc, td);
5145 else
5146 e = new DotTemplateExp(e.loc, e, td);
5147 e = e.expressionSemantic(sc);
5148 return e;
5151 if (td)
5153 return toTemplateExp(td);
5156 TemplateInstance ti = s.isTemplateInstance();
5157 if (ti)
5159 if (!ti.semanticRun)
5161 ti.dsymbolSemantic(sc);
5162 if (!ti.inst || ti.errors) // if template failed to expand
5164 return ErrorExp.get();
5167 s = ti.inst.toAlias();
5168 if (!s.isTemplateInstance())
5169 goto L1;
5170 if (e.op == EXP.type)
5171 e = new ScopeExp(e.loc, ti);
5172 else
5173 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
5174 return e.expressionSemantic(sc);
5177 if (s.isImport() || s.isModule() || s.isPackage())
5179 e = symbolToExp(s, e.loc, sc, false);
5180 return e;
5183 OverloadSet o = s.isOverloadSet();
5184 if (o)
5186 auto oe = new OverExp(e.loc, o);
5187 if (e.op == EXP.type)
5189 return oe;
5191 return new DotExp(e.loc, e, oe);
5194 Declaration d = s.isDeclaration();
5195 if (!d)
5197 error(e.loc, "`%s.%s` is not a declaration", e.toChars(), ident.toChars());
5198 return ErrorExp.get();
5201 if (e.op == EXP.type)
5203 /* It's:
5204 * Class.d
5206 if (TupleDeclaration tup = d.isTupleDeclaration())
5208 e = new TupleExp(e.loc, tup);
5209 e = e.expressionSemantic(sc);
5210 return e;
5213 if (mt.sym.classKind == ClassKind.objc
5214 && d.isFuncDeclaration()
5215 && d.isFuncDeclaration().isStatic
5216 && d.isFuncDeclaration().objc.selector)
5218 auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
5219 classRef.type = objc.getRuntimeMetaclass(mt.sym).getType();
5220 return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
5222 else if (d.needThis() && sc.intypeof != 1)
5224 /* Rewrite as:
5225 * this.d
5227 AggregateDeclaration ad = d.isMemberLocal();
5228 if (auto f = hasThis(sc))
5230 // This is almost same as getRightThis() in expressionsem.d
5231 Expression e1;
5232 Type t;
5233 /* returns: true to continue, false to return */
5234 if (f.hasDualContext())
5236 if (f.followInstantiationContext(ad))
5238 e1 = new VarExp(e.loc, f.vthis);
5239 e1 = new PtrExp(e1.loc, e1);
5240 e1 = new IndexExp(e1.loc, e1, IntegerExp.literal!1);
5241 auto pd = f.toParent2().isDeclaration();
5242 assert(pd);
5243 t = pd.type.toBasetype();
5244 e1 = getThisSkipNestedFuncs(e1.loc, sc, f.toParent2(), ad, e1, t, d, true);
5245 if (!e1)
5247 e = new VarExp(e.loc, d);
5248 return e;
5250 goto L2;
5253 e1 = new ThisExp(e.loc);
5254 e1 = e1.expressionSemantic(sc);
5256 t = e1.type.toBasetype();
5257 ClassDeclaration cd = e.type.isClassHandle();
5258 ClassDeclaration tcd = t.isClassHandle();
5259 if (cd && tcd && (tcd == cd || cd.isBaseOf(tcd, null)))
5261 e = new DotTypeExp(e1.loc, e1, cd);
5262 e = new DotVarExp(e.loc, e, d);
5263 e = e.expressionSemantic(sc);
5264 return e;
5266 if (tcd && tcd.isNested())
5268 /* e1 is the 'this' pointer for an inner class: tcd.
5269 * Rewrite it as the 'this' pointer for the outer class.
5271 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
5272 e1 = new DotVarExp(e.loc, e1, vthis);
5273 e1.type = vthis.type;
5274 e1.type = e1.type.addMod(t.mod);
5275 // Do not call ensureStaticLinkTo()
5276 //e1 = e1.expressionSemantic(sc);
5278 // Skip up over nested functions, and get the enclosing
5279 // class type.
5280 e1 = getThisSkipNestedFuncs(e1.loc, sc, tcd.toParentP(ad), ad, e1, t, d, true);
5281 if (!e1)
5283 e = new VarExp(e.loc, d);
5284 return e;
5286 goto L2;
5290 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
5291 if (d.semanticRun == PASS.initial)
5292 d.dsymbolSemantic(null);
5294 // If static function, get the most visible overload.
5295 // Later on the call is checked for correctness.
5296 // https://issues.dlang.org/show_bug.cgi?id=12511
5297 Dsymbol d2 = d;
5298 if (auto fd = d.isFuncDeclaration())
5300 import dmd.access : mostVisibleOverload;
5301 d2 = mostVisibleOverload(fd, sc._module);
5304 checkAccess(e.loc, sc, e, d2);
5305 if (d2.isDeclaration())
5307 d = cast(Declaration)d2;
5308 auto ve = new VarExp(e.loc, d);
5309 if (d.isVarDeclaration() && d.needThis())
5310 ve.type = d.type.addMod(e.type.mod);
5311 return ve;
5313 else if (d2.isTemplateDeclaration())
5315 return toTemplateExp(cast(TemplateDeclaration)d2);
5317 else
5318 assert(0);
5321 bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
5322 if (d.isDataseg() || unreal && d.isField())
5324 // (e, d)
5325 checkAccess(e.loc, sc, e, d);
5326 Expression ve = new VarExp(e.loc, d);
5327 e = unreal ? ve : new CommaExp(e.loc, e, ve);
5328 e = e.expressionSemantic(sc);
5329 return e;
5332 e = new DotVarExp(e.loc, e, d);
5333 e = e.expressionSemantic(sc);
5334 return e;
5337 switch (mt.ty)
5339 case Tvector: return visitVector (mt.isTypeVector());
5340 case Tsarray: return visitSArray (mt.isTypeSArray());
5341 case Tstruct: return visitStruct (mt.isTypeStruct());
5342 case Tenum: return visitEnum (mt.isTypeEnum());
5343 case Terror: return visitError (mt.isTypeError());
5344 case Tarray: return visitDArray (mt.isTypeDArray());
5345 case Taarray: return visitAArray (mt.isTypeAArray());
5346 case Treference: return visitReference(mt.isTypeReference());
5347 case Tdelegate: return visitDelegate (mt.isTypeDelegate());
5348 case Tclass: return visitClass (mt.isTypeClass());
5350 default: return mt.isTypeBasic()
5351 ? visitBasic(cast(TypeBasic)mt)
5352 : visitType(mt);
5357 /************************
5358 * Get the default initialization expression for a type.
5359 * Params:
5360 * mt = the type for which the init expression is returned
5361 * loc = the location where the expression needs to be evaluated
5362 * isCfile = default initializers are different with C
5364 * Returns:
5365 * The initialization expression for the type.
5367 extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
5369 Expression visitBasic(TypeBasic mt)
5371 static if (LOGDEFAULTINIT)
5373 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
5375 dinteger_t value = 0;
5377 switch (mt.ty)
5379 case Tchar:
5380 value = isCfile ? 0 : 0xFF;
5381 break;
5383 case Twchar:
5384 case Tdchar:
5385 value = isCfile ? 0 : 0xFFFF;
5386 break;
5388 case Timaginary32:
5389 case Timaginary64:
5390 case Timaginary80:
5391 case Tfloat32:
5392 case Tfloat64:
5393 case Tfloat80:
5394 return new RealExp(loc, isCfile ? CTFloat.zero : target.RealProperties.nan, mt);
5396 case Tcomplex32:
5397 case Tcomplex64:
5398 case Tcomplex80:
5400 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
5401 const cvalue = isCfile ? complex_t(CTFloat.zero, CTFloat.zero)
5402 : complex_t(target.RealProperties.nan, target.RealProperties.nan);
5403 return new ComplexExp(loc, cvalue, mt);
5406 case Tvoid:
5407 error(loc, "`void` does not have a default initializer");
5408 return ErrorExp.get();
5410 default:
5411 break;
5413 return new IntegerExp(loc, value, mt);
5416 Expression visitVector(TypeVector mt)
5418 //printf("TypeVector::defaultInit()\n");
5419 assert(mt.basetype.ty == Tsarray);
5420 Expression e = mt.basetype.defaultInit(loc, isCfile);
5421 auto ve = new VectorExp(loc, e, mt);
5422 ve.type = mt;
5423 ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc));
5424 return ve;
5427 Expression visitSArray(TypeSArray mt)
5429 static if (LOGDEFAULTINIT)
5431 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
5433 if (mt.next.ty == Tvoid)
5434 return mt.tuns8.defaultInit(loc, isCfile);
5435 else
5436 return mt.next.defaultInit(loc, isCfile);
5439 Expression visitFunction(TypeFunction mt)
5441 error(loc, "`function` does not have a default initializer");
5442 return ErrorExp.get();
5445 Expression visitStruct(TypeStruct mt)
5447 static if (LOGDEFAULTINIT)
5449 printf("TypeStruct::defaultInit() '%s'\n", mt.toChars());
5451 Declaration d = new SymbolDeclaration(mt.sym.loc, mt.sym);
5452 assert(d);
5453 d.type = mt;
5454 d.storage_class |= STC.rvalue; // https://issues.dlang.org/show_bug.cgi?id=14398
5455 return new VarExp(mt.sym.loc, d);
5458 Expression visitEnum(TypeEnum mt)
5460 static if (LOGDEFAULTINIT)
5462 printf("TypeEnum::defaultInit() '%s'\n", mt.toChars());
5464 // Initialize to first member of enum
5465 Expression e = mt.sym.getDefaultValue(loc);
5466 e = e.copy();
5467 e.loc = loc;
5468 e.type = mt; // to deal with const, immutable, etc., variants
5469 return e;
5472 Expression visitTuple(TypeTuple mt)
5474 static if (LOGDEFAULTINIT)
5476 printf("TypeTuple::defaultInit() '%s'\n", mt.toChars());
5478 auto exps = new Expressions(mt.arguments.length);
5479 for (size_t i = 0; i < mt.arguments.length; i++)
5481 Parameter p = (*mt.arguments)[i];
5482 assert(p.type);
5483 Expression e = p.type.defaultInitLiteral(loc);
5484 if (e.op == EXP.error)
5486 return e;
5488 (*exps)[i] = e;
5490 return new TupleExp(loc, exps);
5493 Expression visitNoreturn(TypeNoreturn mt)
5495 static if (LOGDEFAULTINIT)
5497 printf("TypeNoreturn::defaultInit() '%s'\n", mt.toChars());
5499 auto cond = IntegerExp.createBool(false);
5500 auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
5501 msg.type = Type.tstring;
5502 auto ae = new AssertExp(loc, cond, msg);
5503 ae.type = mt;
5504 return ae;
5507 switch (mt.ty)
5509 case Tvector: return visitVector (mt.isTypeVector());
5510 case Tsarray: return visitSArray (mt.isTypeSArray());
5511 case Tfunction: return visitFunction(mt.isTypeFunction());
5512 case Tstruct: return visitStruct (mt.isTypeStruct());
5513 case Tenum: return visitEnum (mt.isTypeEnum());
5514 case Ttuple: return visitTuple (mt.isTypeTuple());
5516 case Tnull: return new NullExp(Loc.initial, Type.tnull);
5518 case Terror: return ErrorExp.get();
5520 case Tarray:
5521 case Taarray:
5522 case Tpointer:
5523 case Treference:
5524 case Tdelegate:
5525 case Tclass: return new NullExp(loc, mt);
5526 case Tnoreturn: return visitNoreturn(mt.isTypeNoreturn());
5528 default: return mt.isTypeBasic() ?
5529 visitBasic(cast(TypeBasic)mt) :
5530 null;
5535 If `type` resolves to a dsymbol, then that
5536 dsymbol is returned.
5538 Params:
5539 type = the type that is checked
5540 sc = the scope where the type is used
5542 Returns:
5543 The dsymbol to which the type resolve or `null`
5544 if the type does resolve to any symbol (for example,
5545 in the case of basic types).
5547 extern(C++) Dsymbol toDsymbol(Type type, Scope* sc)
5549 Dsymbol visitType(Type _) { return null; }
5550 Dsymbol visitStruct(TypeStruct type) { return type.sym; }
5551 Dsymbol visitEnum(TypeEnum type) { return type.sym; }
5552 Dsymbol visitClass(TypeClass type) { return type.sym; }
5554 Dsymbol visitTraits(TypeTraits type)
5556 Type t;
5557 Expression e;
5558 Dsymbol s;
5559 resolve(type, type.loc, sc, e, t, s);
5560 if (t && t.ty != Terror)
5561 s = t.toDsymbol(sc);
5562 else if (e)
5563 s = getDsymbol(e);
5565 return s;
5568 Dsymbol visitMixin(TypeMixin type)
5570 Type t;
5571 Expression e;
5572 Dsymbol s;
5573 resolve(type, type.loc, sc, e, t, s);
5574 if (t)
5575 s = t.toDsymbol(sc);
5576 else if (e)
5577 s = getDsymbol(e);
5579 return s;
5582 Dsymbol visitIdentifier(TypeIdentifier type)
5584 //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
5585 if (!sc)
5586 return null;
5588 Type t;
5589 Expression e;
5590 Dsymbol s;
5591 resolve(type, type.loc, sc, e, t, s);
5592 if (t && t.ty != Tident)
5593 s = t.toDsymbol(sc);
5594 if (e)
5595 s = getDsymbol(e);
5597 return s;
5600 Dsymbol visitInstance(TypeInstance type)
5602 Type t;
5603 Expression e;
5604 Dsymbol s;
5605 //printf("TypeInstance::semantic(%s)\n", toChars());
5606 resolve(type, type.loc, sc, e, t, s);
5607 if (t && t.ty != Tinstance)
5608 s = t.toDsymbol(sc);
5609 return s;
5612 Dsymbol visitTypeof(TypeTypeof type)
5614 //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
5615 Expression e;
5616 Type t;
5617 Dsymbol s;
5618 resolve(type, type.loc, sc, e, t, s);
5619 return s;
5622 Dsymbol visitReturn(TypeReturn type)
5624 Expression e;
5625 Type t;
5626 Dsymbol s;
5627 resolve(type, type.loc, sc, e, t, s);
5628 return s;
5631 switch(type.ty)
5633 default: return visitType(type);
5634 case Ttraits: return visitTraits(type.isTypeTraits());
5635 case Tmixin: return visitMixin(type.isTypeMixin());
5636 case Tident: return visitIdentifier(type.isTypeIdentifier());
5637 case Tinstance: return visitInstance(type.isTypeInstance());
5638 case Ttypeof: return visitTypeof(type.isTypeTypeof());
5639 case Treturn: return visitReturn(type.isTypeReturn());
5640 case Tstruct: return visitStruct(type.isTypeStruct());
5641 case Tenum: return visitEnum(type.isTypeEnum());
5642 case Tclass: return visitClass(type.isTypeClass());
5646 /**********************************************
5647 * Extract complex type from core.stdc.config
5648 * Params:
5649 * loc = for error messages
5650 * sc = context
5651 * ty = a complex or imaginary type
5652 * Returns:
5653 * Complex!float, Complex!double, Complex!real or null for error
5656 Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
5658 // singleton
5659 __gshared Type complex_float;
5660 __gshared Type complex_double;
5661 __gshared Type complex_real;
5663 Type* pt;
5664 Identifier id;
5665 switch (ty)
5667 case Timaginary32:
5668 case Tcomplex32: id = Id.c_complex_float; pt = &complex_float; break;
5669 case Timaginary64:
5670 case Tcomplex64: id = Id.c_complex_double; pt = &complex_double; break;
5671 case Timaginary80:
5672 case Tcomplex80: id = Id.c_complex_real; pt = &complex_real; break;
5673 default:
5674 return Type.terror;
5677 if (*pt)
5678 return *pt;
5679 *pt = Type.terror;
5681 Module mConfig = Module.loadCoreStdcConfig();
5682 if (!mConfig)
5684 error(loc, "`core.stdc.config` is required for complex numbers");
5685 return *pt;
5688 Dsymbol s = mConfig.searchX(Loc.initial, sc, id, SearchOpt.ignorePrivateImports);
5689 if (!s)
5691 error(loc, "`%s` not found in core.stdc.config", id.toChars());
5692 return *pt;
5694 s = s.toAlias();
5695 if (auto t = s.getType())
5697 if (auto ts = t.toBasetype().isTypeStruct())
5699 *pt = ts;
5700 return ts;
5703 if (auto sd = s.isStructDeclaration())
5705 *pt = sd.type;
5706 return sd.type;
5709 error(loc, "`%s` must be an alias for a complex struct", s.toChars());
5710 return *pt;
5713 /*******************************
5714 * Covariant means that 'src' can substitute for 't',
5715 * i.e. a pure function is a match for an impure type.
5716 * Params:
5717 * src = source type
5718 * t = type 'src' is covariant with
5719 * pstc = if not null, store STCxxxx which would make it covariant
5720 * cppCovariant = true if extern(C++) function types should follow C++ covariant rules
5721 * Returns:
5722 * An enum value of either `Covariant.yes` or a reason it's not covariant.
5724 extern(C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
5726 version (none)
5728 printf("Type::covariant(t = %s) %s\n", t.toChars(), src.toChars());
5729 printf("deco = %p, %p\n", src.deco, t.deco);
5730 // printf("ty = %d\n", next.ty);
5731 printf("mod = %x, %x\n", src.mod, t.mod);
5733 if (pstc)
5734 *pstc = 0;
5735 StorageClass stc = 0;
5737 bool notcovariant = false;
5739 if (src.equals(t))
5740 return Covariant.yes;
5742 TypeFunction t1 = src.isTypeFunction();
5743 TypeFunction t2 = t.isTypeFunction();
5745 if (!t1 || !t2)
5746 goto Ldistinct;
5748 if (t1.parameterList.varargs != t2.parameterList.varargs)
5749 goto Ldistinct;
5751 if (t1.parameterList.parameters && t2.parameterList.parameters)
5753 if (t1.parameterList.length != t2.parameterList.length)
5754 goto Ldistinct;
5756 foreach (i, fparam1; t1.parameterList)
5758 Parameter fparam2 = t2.parameterList[i];
5759 Type tp1 = fparam1.type;
5760 Type tp2 = fparam2.type;
5762 if (!tp1.equals(tp2))
5764 if (tp1.ty == tp2.ty)
5766 if (auto tc1 = tp1.isTypeClass())
5768 if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
5769 goto Lcov;
5771 else if (auto ts1 = tp1.isTypeStruct())
5773 if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
5774 goto Lcov;
5776 else if (tp1.ty == Tpointer)
5778 if (tp2.implicitConvTo(tp1))
5779 goto Lcov;
5781 else if (tp1.ty == Tarray)
5783 if (tp2.implicitConvTo(tp1))
5784 goto Lcov;
5786 else if (tp1.ty == Tdelegate)
5788 if (tp2.implicitConvTo(tp1))
5789 goto Lcov;
5792 goto Ldistinct;
5794 Lcov:
5795 notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
5797 /* https://issues.dlang.org/show_bug.cgi?id=23135
5798 * extern(C++) mutable parameters are not covariant with const.
5800 if (t1.linkage == LINK.cpp && cppCovariant)
5802 notcovariant |= tp1.isNaked() != tp2.isNaked();
5803 if (auto tpn1 = tp1.nextOf())
5804 notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
5808 else if (t1.parameterList.parameters != t2.parameterList.parameters)
5810 if (t1.parameterList.length || t2.parameterList.length)
5811 goto Ldistinct;
5814 // The argument lists match
5815 if (notcovariant)
5816 goto Lnotcovariant;
5817 if (t1.linkage != t2.linkage)
5818 goto Lnotcovariant;
5821 // Return types
5822 Type t1n = t1.next;
5823 Type t2n = t2.next;
5825 if (!t1n || !t2n) // happens with return type inference
5826 goto Lnotcovariant;
5828 if (t1n.equals(t2n))
5829 goto Lcovariant;
5830 if (t1n.ty == Tclass && t2n.ty == Tclass)
5832 /* If same class type, but t2n is const, then it's
5833 * covariant. Do this test first because it can work on
5834 * forward references.
5836 if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
5837 goto Lcovariant;
5839 // If t1n is forward referenced:
5840 ClassDeclaration cd = (cast(TypeClass)t1n).sym;
5841 if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
5842 cd.dsymbolSemantic(null);
5843 if (!cd.isBaseInfoComplete())
5845 return Covariant.fwdref;
5848 if (t1n.ty == Tstruct && t2n.ty == Tstruct)
5850 if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
5851 goto Lcovariant;
5853 else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
5855 if (t1.isref && t2.isref)
5857 // Treat like pointers to t1n and t2n
5858 if (t1n.constConv(t2n) < MATCH.constant)
5859 goto Lnotcovariant;
5861 goto Lcovariant;
5863 else if (t1n.ty == Tnull)
5865 // NULL is covariant with any pointer type, but not with any
5866 // dynamic arrays, associative arrays or delegates.
5867 // https://issues.dlang.org/show_bug.cgi?id=8589
5868 // https://issues.dlang.org/show_bug.cgi?id=19618
5869 Type t2bn = t2n.toBasetype();
5870 if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
5871 goto Lcovariant;
5873 // bottom type is covariant to any type
5874 else if (t1n.ty == Tnoreturn)
5875 goto Lcovariant;
5877 goto Lnotcovariant;
5879 Lcovariant:
5880 if (t1.isref != t2.isref)
5881 goto Lnotcovariant;
5883 if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
5885 StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
5886 StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
5887 if (t1.isreturn)
5889 stc1 |= STC.return_;
5890 if (!t1.isScopeQual)
5891 stc1 |= STC.ref_;
5893 if (t2.isreturn)
5895 stc2 |= STC.return_;
5896 if (!t2.isScopeQual)
5897 stc2 |= STC.ref_;
5899 if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
5900 goto Lnotcovariant;
5903 // We can subtract 'return ref' from 'this', but cannot add it
5904 else if (t1.isreturn && !t2.isreturn)
5905 goto Lnotcovariant;
5907 /* https://issues.dlang.org/show_bug.cgi?id=23135
5908 * extern(C++) mutable member functions are not covariant with const.
5910 if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
5911 goto Lnotcovariant;
5913 /* Can convert mutable to const
5915 if (!MODimplicitConv(t2.mod, t1.mod))
5917 version (none)
5919 //stop attribute inference with const
5920 // If adding 'const' will make it covariant
5921 if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
5922 stc |= STC.const_;
5923 else
5924 goto Lnotcovariant;
5926 else
5928 goto Ldistinct;
5932 /* Can convert pure to impure, nothrow to throw, and nogc to gc
5934 if (!t1.purity && t2.purity)
5935 stc |= STC.pure_;
5937 if (!t1.isnothrow && t2.isnothrow)
5938 stc |= STC.nothrow_;
5940 if (!t1.isnogc && t2.isnogc)
5941 stc |= STC.nogc;
5943 /* Can convert safe/trusted to system
5945 if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
5947 // Should we infer trusted or safe? Go with safe.
5948 stc |= STC.safe;
5951 if (stc)
5953 if (pstc)
5954 *pstc = stc;
5955 goto Lnotcovariant;
5958 //printf("\tcovaraint: 1\n");
5959 return Covariant.yes;
5961 Ldistinct:
5962 //printf("\tcovaraint: 0\n");
5963 return Covariant.distinct;
5965 Lnotcovariant:
5966 //printf("\tcovaraint: 2\n");
5967 return Covariant.no;
5970 /************************************
5971 * Take the specified storage class for p,
5972 * and use the function signature to infer whether
5973 * STC.scope_ and STC.return_ should be OR'd in.
5974 * (This will not affect the name mangling.)
5975 * Params:
5976 * tf = TypeFunction to use to get the signature from
5977 * tthis = type of `this` parameter, null if none
5978 * p = parameter to this function
5979 * outerVars = context variables p could escape into, if any
5980 * indirect = is this for an indirect or virtual function call?
5981 * Returns:
5982 * storage class with STC.scope_ or STC.return_ OR'd in
5984 StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null,
5985 bool indirect = false)
5987 //printf("parameterStorageClass(p: %s)\n", p.toChars());
5988 auto stc = p.storageClass;
5990 // When the preview switch is enable, `in` parameters are `scope`
5991 if (stc & STC.constscoperef)
5992 return stc | STC.scope_;
5994 if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || tf.purity == PURE.impure)
5995 return stc;
5997 /* If haven't inferred the return type yet, can't infer storage classes
5999 if (!tf.nextOf() || !tf.isnothrow())
6000 return stc;
6002 tf.purityLevel();
6004 static bool mayHavePointers(Type t)
6006 if (auto ts = t.isTypeStruct())
6008 auto sym = ts.sym;
6009 if (sym.members && !sym.determineFields() && sym.type != Type.terror)
6010 // struct is forward referenced, so "may have" pointers
6011 return true;
6013 return t.hasPointers();
6016 // See if p can escape via any of the other parameters
6017 if (tf.purity == PURE.weak)
6020 * Indirect calls may escape p through a nested context
6021 * See:
6022 * https://issues.dlang.org/show_bug.cgi?id=24212
6023 * https://issues.dlang.org/show_bug.cgi?id=24213
6025 if (indirect)
6026 return stc;
6028 // Check escaping through parameters
6029 foreach (i, fparam; tf.parameterList)
6031 Type t = fparam.type;
6032 if (!t)
6033 continue;
6034 t = t.baseElemOf(); // punch thru static arrays
6035 if (t.isMutable() && t.hasPointers())
6037 if (fparam.isReference() && fparam != p)
6038 return stc;
6040 if (t.ty == Tdelegate)
6041 return stc; // could escape thru delegate
6043 if (t.ty == Tclass)
6044 return stc;
6046 /* if t is a pointer to mutable pointer
6048 if (auto tn = t.nextOf())
6050 if (tn.isMutable() && mayHavePointers(tn))
6051 return stc; // escape through pointers
6056 // Check escaping through `this`
6057 if (tthis && tthis.isMutable())
6059 foreach (VarDeclaration v; isAggregate(tthis).fields)
6061 if (v.hasPointers())
6062 return stc;
6066 // Check escaping through nested context
6067 if (outerVars && tf.isMutable())
6069 foreach (VarDeclaration v; *outerVars)
6071 if (v.hasPointers())
6072 return stc;
6077 // Check escaping through return value
6078 Type tret = tf.nextOf().toBasetype();
6079 if (tf.isref || tret.hasPointers())
6081 return stc | STC.scope_ | STC.return_ | STC.returnScope;
6083 else
6084 return stc | STC.scope_;
6087 extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset)
6089 auto tc = tthis.isTypeClass();
6090 if (!tc)
6091 return false;
6093 if (!t || t.ty != Tclass)
6094 return false;
6096 ClassDeclaration cd = t.isTypeClass().sym;
6097 if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
6098 cd.dsymbolSemantic(null);
6099 if (tc.sym.semanticRun < PASS.semanticdone && !tc.sym.isBaseInfoComplete())
6100 tc.sym.dsymbolSemantic(null);
6102 if (tc.sym.isBaseOf(cd, poffset))
6103 return true;
6105 return false;
6108 /******************************* Private *****************************************/
6110 private:
6112 /* Helper function for `typeToExpression`. Contains common code
6113 * for TypeQualified derived classes.
6115 Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
6117 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
6118 foreach (id; t.idents[i .. t.idents.length])
6120 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
6122 final switch (id.dyncast())
6124 // ... '. ident'
6125 case DYNCAST.identifier:
6126 e = new DotIdExp(e.loc, e, cast(Identifier)id);
6127 break;
6129 // ... '. name!(tiargs)'
6130 case DYNCAST.dsymbol:
6131 auto ti = (cast(Dsymbol)id).isTemplateInstance();
6132 assert(ti);
6133 e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
6134 break;
6136 // ... '[type]'
6137 case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215
6138 e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
6139 break;
6141 // ... '[expr]'
6142 case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215
6143 e = new ArrayExp(t.loc, e, cast(Expression)id);
6144 break;
6146 case DYNCAST.object:
6147 case DYNCAST.tuple:
6148 case DYNCAST.parameter:
6149 case DYNCAST.statement:
6150 case DYNCAST.condition:
6151 case DYNCAST.templateparameter:
6152 case DYNCAST.initializer:
6153 assert(0);
6156 return e;
6159 /**************************
6160 * This evaluates exp while setting length to be the number
6161 * of elements in the tuple t.
6163 Expression semanticLength(Scope* sc, Type t, Expression exp)
6165 if (auto tt = t.isTypeTuple())
6167 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
6168 sym.parent = sc.scopesym;
6169 sc = sc.push(sym);
6170 sc = sc.startCTFE();
6171 exp = exp.expressionSemantic(sc);
6172 exp = resolveProperties(sc, exp);
6173 sc = sc.endCTFE();
6174 sc.pop();
6176 else
6178 sc = sc.startCTFE();
6179 exp = exp.expressionSemantic(sc);
6180 exp = resolveProperties(sc, exp);
6181 sc = sc.endCTFE();
6183 return exp;
6186 Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
6188 ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
6189 sym.parent = sc.scopesym;
6191 sc = sc.push(sym);
6192 sc = sc.startCTFE();
6193 exp = exp.expressionSemantic(sc);
6194 exp = resolveProperties(sc, exp);
6195 sc = sc.endCTFE();
6196 sc.pop();
6198 return exp;
6201 /************************************
6202 * Transitively search a type for all function types.
6203 * If any function types with parameters are found that have parameter identifiers
6204 * or default arguments, remove those and create a new type stripped of those.
6205 * This is used to determine the "canonical" version of a type which is useful for
6206 * comparisons.
6207 * Params:
6208 * t = type to scan
6209 * Returns:
6210 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
6211 * the same as t but with no parameter identifiers or default arguments.
6213 Type stripDefaultArgs(Type t)
6215 static Parameters* stripParams(Parameters* parameters)
6217 static Parameter stripParameter(Parameter p)
6219 Type t = stripDefaultArgs(p.type);
6220 return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
6221 ? new Parameter(p.loc, p.storageClass, t, null, null, null)
6222 : null;
6225 if (parameters)
6227 foreach (i, p; *parameters)
6229 Parameter ps = stripParameter(p);
6230 if (ps)
6232 // Replace params with a copy we can modify
6233 Parameters* nparams = new Parameters(parameters.length);
6235 foreach (j, ref np; *nparams)
6237 Parameter pj = (*parameters)[j];
6238 if (j < i)
6239 np = pj;
6240 else if (j == i)
6241 np = ps;
6242 else
6244 Parameter nps = stripParameter(pj);
6245 np = nps ? nps : pj;
6248 return nparams;
6252 return parameters;
6255 if (t is null)
6256 return t;
6258 if (auto tf = t.isTypeFunction())
6260 Type tret = stripDefaultArgs(tf.next);
6261 Parameters* params = stripParams(tf.parameterList.parameters);
6262 if (tret == tf.next && params == tf.parameterList.parameters)
6263 return t;
6264 TypeFunction tr = tf.copy().isTypeFunction();
6265 tr.parameterList.parameters = params;
6266 tr.next = tret;
6267 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
6268 return tr;
6270 else if (auto tt = t.isTypeTuple())
6272 Parameters* args = stripParams(tt.arguments);
6273 if (args == tt.arguments)
6274 return t;
6275 TypeTuple tr = t.copy().isTypeTuple();
6276 tr.arguments = args;
6277 return tr;
6279 else if (t.ty == Tenum)
6281 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
6282 return t;
6284 else
6286 Type tn = t.nextOf();
6287 Type n = stripDefaultArgs(tn);
6288 if (n == tn)
6289 return t;
6290 TypeNext tr = cast(TypeNext)t.copy();
6291 tr.next = n;
6292 return tr;
6296 /******************************
6297 * Get the value of the .max/.min property of `ed` as an Expression.
6298 * Lazily computes the value and caches it in maxval/minval.
6299 * Reports any errors.
6300 * Params:
6301 * ed = the EnumDeclaration being examined
6302 * loc = location to use for error messages
6303 * id = Id::max or Id::min
6304 * Returns:
6305 * corresponding value of .max/.min
6307 Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
6309 //printf("EnumDeclaration::getMaxValue()\n");
6311 static Expression pvalToResult(Expression e, const ref Loc loc)
6313 if (e.op != EXP.error)
6315 e = e.copy();
6316 e.loc = loc;
6318 return e;
6321 Expression* pval = (id == Id.max) ? &ed.maxval : &ed.minval;
6323 Expression errorReturn()
6325 *pval = ErrorExp.get();
6326 return *pval;
6329 if (ed.inuse)
6331 .error(loc, "%s `%s` recursive definition of `.%s` property", ed.kind, ed.toPrettyChars, id.toChars());
6332 return errorReturn();
6334 if (*pval)
6335 return pvalToResult(*pval, loc);
6337 if (ed._scope)
6338 dsymbolSemantic(ed, ed._scope);
6339 if (ed.errors)
6340 return errorReturn();
6341 if (!ed.members)
6343 .error(loc, "%s `%s` is opaque and has no `.%s`", ed.kind, ed.toPrettyChars, id.toChars(), id.toChars());
6344 return errorReturn();
6346 if (!(ed.memtype && ed.memtype.isintegral()))
6348 .error(loc, "%s `%s` has no `.%s` property because base type `%s` is not an integral type", ed.kind, ed.toPrettyChars, id.toChars(),
6349 id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
6350 return errorReturn();
6353 bool first = true;
6354 for (size_t i = 0; i < ed.members.length; i++)
6356 EnumMember em = (*ed.members)[i].isEnumMember();
6357 if (!em)
6358 continue;
6359 if (em.errors)
6361 ed.errors = true;
6362 continue;
6365 if (em.semanticRun < PASS.semanticdone)
6367 .error(em.loc, "%s `%s` is forward referenced looking for `.%s`", em.kind, em.toPrettyChars, id.toChars());
6368 ed.errors = true;
6369 continue;
6372 if (first)
6374 *pval = em.value;
6375 first = false;
6377 else
6379 /* In order to work successfully with UDTs,
6380 * build expressions to do the comparisons,
6381 * and let the semantic analyzer and constant
6382 * folder give us the result.
6385 /* Compute:
6386 * if (e > maxval)
6387 * maxval = e;
6389 Expression e = em.value;
6390 Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval);
6391 ed.inuse = true;
6392 ec = ec.expressionSemantic(em._scope);
6393 ed.inuse = false;
6394 ec = ec.ctfeInterpret();
6395 if (ec.op == EXP.error)
6397 ed.errors = true;
6398 continue;
6400 if (ec.toInteger())
6401 *pval = e;
6404 return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
6407 /******************************************
6408 * Compile the MixinType, returning the type or expression AST.
6410 * Doesn't run semantic() on the returned object.
6411 * Params:
6412 * tm = mixin to compile as a type or expression
6413 * loc = location for error messages
6414 * sc = context
6415 * Return:
6416 * null if error, else RootObject AST as parsed
6418 RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
6420 OutBuffer buf;
6421 if (expressionsToString(buf, sc, tm.exps))
6422 return null;
6424 const errors = global.errors;
6425 const len = buf.length;
6426 buf.writeByte(0);
6427 const str = buf.extractSlice()[0 .. len];
6428 const bool doUnittests = global.params.parsingUnittestsRequired();
6429 auto locm = adjustLocForMixin(str, loc, global.params.mixinOut);
6430 scope p = new Parser!ASTCodegen(locm, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
6431 p.transitionIn = global.params.v.vin;
6432 p.nextToken();
6433 //printf("p.loc.linnum = %d\n", p.loc.linnum);
6435 auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
6436 if (errors != global.errors)
6438 assert(global.errors != errors); // should have caught all these cases
6439 return null;
6441 if (p.token.value != TOK.endOfFile)
6443 .error(loc, "unexpected token `%s` after type `%s`",
6444 p.token.toChars(), o.toChars());
6445 .errorSupplemental(loc, "while parsing string mixin type `%s`",
6446 str.ptr);
6447 return null;
6450 return o;