2 * Semantic analysis for D types.
4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d)
8 * Documentation: https://dlang.org/phobos/dmd_typesem.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d
14 import core
.checkedint
;
15 import core
.stdc
.string
;
16 import core
.stdc
.stdio
;
22 import dmd
.arraytypes
;
23 import dmd
.astcodegen
;
27 import dmd
.declaration
;
30 import dmd
.dinterpret
;
36 import dmd
.dsymbolsem
;
40 import dmd
.expression
;
41 import dmd
.expressionsem
;
46 import dmd
.identifier
;
58 import dmd
.root
.complex
;
59 import dmd
.root
.ctfloat
;
61 import dmd
.common
.outbuffer
;
62 import dmd
.rootobject
;
63 import dmd
.root
.string
;
64 import dmd
.root
.stringtable
;
67 import dmd
.sideeffect
;
71 /*************************************
72 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
73 * Setting one of pe/pt/ps.
75 * loc = location for error messages
77 * s = symbol being indexed - could be a tuple, could be an expression
78 * pe = set if s[oindex] is an Expression, otherwise null
79 * pt = set if s[oindex] is a Type, otherwise null
80 * ps = set if s[oindex] is a Dsymbol, otherwise null
81 * oindex = index into s
83 private void resolveTupleIndex(const ref Loc loc
, Scope
* sc
, Dsymbol s
, out Expression pe
, out Type pt
, out Dsymbol ps
, RootObject oindex
)
85 auto tup
= s
.isTupleDeclaration();
87 auto eindex
= isExpression(oindex
);
88 auto tindex
= isType(oindex
);
89 auto sindex
= isDsymbol(oindex
);
93 // It's really an index expression
95 eindex
= new TypeExp(loc
, tindex
);
97 eindex
= symbolToExp(sindex
, loc
, sc
, false);
98 Expression e
= new IndexExp(loc
, symbolToExp(s
, loc
, sc
, false), eindex
);
99 e
= e
.expressionSemantic(sc
);
100 resolveExp(e
, pt
, pe
, ps
);
104 // Convert oindex to Expression, then try to resolve to constant.
106 tindex
.resolve(loc
, sc
, eindex
, tindex
, sindex
);
108 eindex
= symbolToExp(sindex
, loc
, sc
, false);
111 .error(loc
, "index `%s` is not an expression", oindex
.toChars());
116 eindex
= semanticLength(sc
, tup
, eindex
);
117 eindex
= eindex
.ctfeInterpret();
118 if (eindex
.op
== EXP
.error
)
123 const(uinteger_t
) d
= eindex
.toUInteger();
124 if (d
>= tup
.objects
.length
)
126 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", d
, cast(ulong)tup
.objects
.length
);
131 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
133 if (auto t
= isType(o
))
134 pt
= t
.typeSemantic(loc
, sc
);
135 if (auto e
= isExpression(o
))
136 resolveExp(e
, pt
, pe
, ps
);
139 /*************************************
140 * Takes an array of Identifiers and figures out if
141 * it represents a Type, Expression, or Dsymbol.
143 * mt = array of identifiers
144 * loc = location for error messages
146 * s = symbol to start search at
148 * pe = set if expression otherwise null
149 * pt = set if type otherwise null
150 * ps = set if symbol otherwise null
151 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
153 private void resolveHelper(TypeQualified mt
, const ref Loc loc
, Scope
* sc
, Dsymbol s
, Dsymbol scopesym
,
154 out Expression pe
, out Type pt
, out Dsymbol ps
, bool intypeid
= false)
158 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc
, mt
.toChars());
160 printf("\tscopesym = '%s'\n", scopesym
.toChars());
165 /* Look for what user might have intended
167 const p
= mt
.mutableOf().unSharedOf().toChars();
168 auto id
= Identifier
.idPool(p
[0 .. strlen(p
)]);
169 if (const n
= importHint(id
.toString()))
170 error(loc
, "`%s` is not defined, perhaps `import %.*s;` ?", p
, cast(int)n
.length
, n
.ptr
);
171 else if (auto s2
= sc
.search_correct(id
))
172 error(loc
, "undefined identifier `%s`, did you mean %s `%s`?", p
, s2
.kind(), s2
.toChars());
173 else if (const q
= Scope
.search_correct_C(id
))
174 error(loc
, "undefined identifier `%s`, did you mean `%s`?", p
, q
);
175 else if ((id
== Id
.This
&& sc
.getStructClassScope()) ||
176 (id
== Id
._super
&& sc
.getClassScope()))
177 error(loc
, "undefined identifier `%s`, did you mean `typeof(%s)`?", p
, p
);
179 error(loc
, "undefined identifier `%s`", p
);
185 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
186 Declaration d
= s
.isDeclaration();
187 if (d
&& (d
.storage_class
& STC
.templateparameter
))
191 // check for deprecated or disabled aliases
192 // functions are checked after overloading
193 // templates are checked after matching constraints
194 if (!s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
195 s
.checkDeprecated(loc
, sc
);
197 d
.checkDisabled(loc
, sc
, true);
200 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
201 for (size_t i
= 0; i
< mt
.idents
.length
; i
++)
203 RootObject id
= mt
.idents
[i
];
204 switch (id
.dyncast()) with (DYNCAST
)
211 resolveTupleIndex(loc
, sc
, s
, ex
, tx
, sx
, id
);
218 ex
= new TypeExp(loc
, tx
);
221 ex
= typeToExpressionHelper(mt
, ex
, i
+ 1);
222 ex
= ex
.expressionSemantic(sc
);
223 resolveExp(ex
, pt
, pe
, ps
);
229 Type t
= s
.getType(); // type symbol, type alias, or type tuple?
230 uint errorsave
= global
.errors
;
231 int flags
= t
is null ? SearchLocalsOnly
: IgnorePrivateImports
;
233 Dsymbol sm
= s
.searchX(loc
, sc
, id
, flags
);
236 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, sm
))
238 .error(loc
, "`%s` is not visible from module `%s`", sm
.toPrettyChars(), sc
._module
.toChars());
241 // Same check as in dotIdSemanticProp(DotIdExp)
242 else if (sm
.isPackage() && checkAccess(sc
, sm
.isPackage()))
244 // @@@DEPRECATED_2.106@@@
245 // Should be an error in 2.106. Just remove the deprecation call
246 // and uncomment the null assignment
247 deprecation(loc
, "%s %s is not accessible here, perhaps add 'static import %s;'", sm
.kind(), sm
.toPrettyChars(), sm
.toPrettyChars());
251 if (global
.errors
!= errorsave
)
260 VarDeclaration v
= s
.isVarDeclaration();
261 FuncDeclaration f
= s
.isFuncDeclaration();
262 if (intypeid ||
!v
&& !f
)
263 e
= symbolToExp(s
, loc
, sc
, true);
265 e
= new VarExp(loc
, s
.isDeclaration(), true);
267 e
= typeToExpressionHelper(mt
, e
, i
);
268 e
= e
.expressionSemantic(sc
);
269 resolveExp(e
, pt
, pe
, ps
);
272 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
273 if (intypeid
&& !t
&& sm
&& sm
.needThis())
276 if (VarDeclaration v
= s
.isVarDeclaration())
278 // https://issues.dlang.org/show_bug.cgi?id=19913
279 // v.type would be null if it is a forward referenced member.
281 v
.dsymbolSemantic(sc
);
282 if (v
.storage_class
& (STC
.const_ | STC
.immutable_ | STC
.manifest
) ||
283 v
.type
.isConst() || v
.type
.isImmutable())
285 // https://issues.dlang.org/show_bug.cgi?id=13087
286 // this.field is not constant always
287 if (!v
.isThisDeclaration())
295 if (sm
.isAliasDeclaration
)
296 sm
.checkDeprecated(loc
, sc
);
300 if (auto em
= s
.isEnumMember())
302 // It's not a type, it's an expression
303 pe
= em
.getVarExp(loc
, sc
);
306 if (auto v
= s
.isVarDeclaration())
308 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
309 * because some variables used in type context need to prevent lowering
310 * to a literal or contextful expression. For example:
312 * enum a = 1; alias b = a;
313 * template X(alias e){ alias v = e; } alias x = X!(1);
314 * struct S { int v; alias w = v; }
315 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
316 * // because getDsymbol() need to work in AliasDeclaration::semantic().
319 !v
.type
.deco
&& v
.inuse
)
321 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
322 error(loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
324 error(loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
328 if (v
.type
.ty
== Terror
)
331 pe
= new VarExp(loc
, v
);
334 if (auto fld = s
.isFuncLiteralDeclaration())
336 //printf("'%s' is a function literal\n", fld.toChars());
337 auto e
= new FuncExp(loc
, fld);
338 pe
= e
.expressionSemantic(sc
);
343 if (FuncDeclaration fd
= s
.isFuncDeclaration())
345 pe
= new DsymbolExp(loc
, fd
);
360 if (auto ti
= t
.isTypeInstance())
361 if (ti
!= mt
&& !ti
.deco
)
363 if (!ti
.tempinst
.errors
)
364 error(loc
, "forward reference to `%s`", ti
.toChars());
375 /******************************************
376 * We've mistakenly parsed `t` as a type.
377 * Redo `t` as an Expression only if there are no type modifiers.
381 * t redone as Expression, null if cannot
383 Expression
typeToExpression(Type t
)
385 static Expression
visitSArray(TypeSArray t
)
387 if (auto e
= t
.next
.typeToExpression())
388 return new ArrayExp(t
.dim
.loc
, e
, t
.dim
);
392 static Expression
visitAArray(TypeAArray t
)
394 if (auto e
= t
.next
.typeToExpression())
396 if (auto ei
= t
.index
.typeToExpression())
397 return new ArrayExp(t
.loc
, e
, ei
);
402 static Expression
visitIdentifier(TypeIdentifier t
)
404 return typeToExpressionHelper(t
, new IdentifierExp(t
.loc
, t
.ident
));
407 static Expression
visitInstance(TypeInstance t
)
409 return typeToExpressionHelper(t
, new ScopeExp(t
.loc
, t
.tempinst
));
412 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
413 static Expression
visitMixin(TypeMixin t
)
415 return new TypeExp(t
.loc
, t
);
422 case Tsarray
: return visitSArray(t
.isTypeSArray());
423 case Taarray
: return visitAArray(t
.isTypeAArray());
424 case Tident
: return visitIdentifier(t
.isTypeIdentifier());
425 case Tinstance
: return visitInstance(t
.isTypeInstance());
426 case Tmixin
: return visitMixin(t
.isTypeMixin());
427 default: return null;
431 /******************************************
432 * Perform semantic analysis on a type.
434 * type = Type AST node
435 * loc = the location of the type
438 * `Type` with completed semantic analysis, `Terror` if errors
441 extern(C
++) Type
typeSemantic(Type type
, const ref Loc loc
, Scope
* sc
)
448 Type
visitType(Type t
)
450 // @@@DEPRECATED_2.110@@@
451 // Use of `cent` and `ucent` has always been an error.
452 // Starting from 2.100, recommend core.int128 as a replace for the
453 // lack of compiler support.
454 if (t
.ty
== Tint128 || t
.ty
== Tuns128
)
456 .error(loc
, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
463 Type
visitComplex(TypeBasic t
)
465 if (!(sc
.flags
& SCOPE
.Cfile
))
468 auto tc
= getComplexLibraryType(loc
, sc
, t
.ty
);
471 return tc
.addMod(t
.mod
).merge();
474 Type
visitVector(TypeVector mtype
)
476 const errors
= global
.errors
;
477 mtype
.basetype
= mtype
.basetype
.typeSemantic(loc
, sc
);
478 if (errors
!= global
.errors
)
480 mtype
.basetype
= mtype
.basetype
.toBasetype().mutableOf();
481 if (mtype
.basetype
.ty
!= Tsarray
)
483 .error(loc
, "T in __vector(T) must be a static array, not `%s`", mtype
.basetype
.toChars());
486 TypeSArray t
= mtype
.basetype
.isTypeSArray();
487 const sz
= cast(int)t
.size(loc
);
488 final switch (target
.isVectorTypeSupported(sz
, t
.nextOf()))
496 .error(loc
, "SIMD vector types not supported on this platform");
501 .error(loc
, "vector type `%s` is not supported on this platform", mtype
.toChars());
506 .error(loc
, "%d byte vector type `%s` is not supported on this platform", sz
, mtype
.toChars());
512 Type
visitSArray(TypeSArray mtype
)
514 //printf("TypeSArray::semantic() %s\n", toChars());
518 mtype
.next
.resolve(loc
, sc
, e
, t
, s
);
520 if (auto tup
= s ? s
.isTupleDeclaration() : null)
522 mtype
.dim
= semanticLength(sc
, tup
, mtype
.dim
);
523 mtype
.dim
= mtype
.dim
.ctfeInterpret();
524 if (mtype
.dim
.op
== EXP
.error
)
527 uinteger_t d
= mtype
.dim
.toUInteger();
528 if (d
>= tup
.objects
.length
)
530 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d
, cast(ulong)tup
.objects
.length
);
534 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
535 if (auto tt
= o
.isType())
536 return tt
.addMod(mtype
.mod
);
537 .error(loc
, "`%s` is not a type", mtype
.toChars());
541 if (t
&& t
.ty
== Terror
)
544 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
548 Type tbn
= tn
.toBasetype();
551 auto errors
= global
.errors
;
552 mtype
.dim
= semanticLength(sc
, tbn
, mtype
.dim
);
553 mtype
.dim
= mtype
.dim
.implicitCastTo(sc
, Type
.tsize_t
);
554 if (errors
!= global
.errors
)
557 mtype
.dim
= mtype
.dim
.optimize(WANTvalue
);
558 mtype
.dim
= mtype
.dim
.ctfeInterpret();
559 if (mtype
.dim
.op
== EXP
.error
)
562 errors
= global
.errors
;
563 dinteger_t d1
= mtype
.dim
.toInteger();
564 if (errors
!= global
.errors
)
567 mtype
.dim
= mtype
.dim
.implicitCastTo(sc
, Type
.tsize_t
);
568 mtype
.dim
= mtype
.dim
.optimize(WANTvalue
);
569 if (mtype
.dim
.op
== EXP
.error
)
572 errors
= global
.errors
;
573 dinteger_t d2
= mtype
.dim
.toInteger();
574 if (errors
!= global
.errors
)
577 if (mtype
.dim
.op
== EXP
.error
)
582 .error(loc
, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
583 mtype
.toChars(), cast(ulong)tbn
.size(loc
), cast(ulong)d1
, target
.maxStaticDataSize
);
588 return overflowError();
590 Type tbx
= tbn
.baseElemOf();
591 if (tbx
.ty
== Tstruct
&& !tbx
.isTypeStruct().sym
.members ||
592 tbx
.ty
== Tenum
&& !tbx
.isTypeEnum().sym
.members
)
594 /* To avoid meaningless error message, skip the total size limit check
595 * when the bottom of element type is opaque.
598 else if (tbn
.isTypeBasic() ||
599 tbn
.ty
== Tpointer ||
603 (tbn
.ty
== Tstruct
&& tbn
.isTypeStruct().sym
.sizeok
== Sizeok
.done
) ||
606 /* Only do this for types that don't need to have semantic()
607 * run on them for the size, since they may be forward referenced.
609 bool overflow
= false;
610 if (mulu(tbn
.size(loc
), d2
, overflow
) > target
.maxStaticDataSize || overflow
)
611 return overflowError();
618 // Index the tuple to get the type
620 TypeTuple tt
= tbn
.isTypeTuple();
621 uinteger_t d
= mtype
.dim
.toUInteger();
622 if (d
>= tt
.arguments
.length
)
624 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d
, cast(ulong)tt
.arguments
.length
);
627 Type telem
= (*tt
.arguments
)[cast(size_t
)d
].type
;
628 return telem
.addMod(mtype
.mod
);
633 .error(loc
, "cannot have array of `%s`", tbn
.toChars());
641 .error(loc
, "cannot have array of scope `%s`", tbn
.toChars());
645 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
646 * and const(T)[3] become const(T[3])
650 return mtype
.addMod(tn
.mod
).merge();
653 Type
visitDArray(TypeDArray mtype
)
655 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
656 Type tbn
= tn
.toBasetype();
664 .error(loc
, "cannot have array of `%s`", tbn
.toChars());
675 .error(loc
, "cannot have array of scope `%s`", tn
.toChars());
683 Type
visitAArray(TypeAArray mtype
)
685 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
695 // Deal with the case where we thought the index was a type, but
696 // in reality it was an expression.
697 if (mtype
.index
.ty
== Tident || mtype
.index
.ty
== Tinstance || mtype
.index
.ty
== Tsarray || mtype
.index
.ty
== Ttypeof || mtype
.index
.ty
== Treturn || mtype
.index
.ty
== Tmixin
)
702 mtype
.index
.resolve(loc
, sc
, e
, t
, s
);
704 // https://issues.dlang.org/show_bug.cgi?id=15478
706 e
= symbolToExp(s
, loc
, sc
, false);
710 // It was an expression -
711 // Rewrite as a static array
712 auto tsa
= new TypeSArray(mtype
.next
, e
);
713 return tsa
.typeSemantic(loc
, sc
);
716 mtype
.index
= t
.typeSemantic(loc
, sc
);
719 .error(loc
, "index is not a type or an expression");
724 mtype
.index
= mtype
.index
.typeSemantic(loc
, sc
);
725 mtype
.index
= mtype
.index
.merge2();
727 if (mtype
.index
.nextOf() && !mtype
.index
.nextOf().isImmutable())
729 mtype
.index
= mtype
.index
.constOf().mutableOf();
732 printf("index is %p %s\n", mtype
.index
, mtype
.index
.toChars());
734 printf("index.mod = x%x\n", mtype
.index
.mod
);
735 printf("index.ito = x%p\n", mtype
.index
.getMcache().ito
);
736 if (mtype
.index
.getMcache().ito
)
738 printf("index.ito.mod = x%x\n", mtype
.index
.getMcache().ito
.mod
);
739 printf("index.ito.ito = x%p\n", mtype
.index
.getMcache().ito
.getMcache().ito
);
744 switch (mtype
.index
.toBasetype().ty
)
750 .error(loc
, "cannot have associative array key of `%s`", mtype
.index
.toBasetype().toChars());
758 Type tbase
= mtype
.index
.baseElemOf();
759 while (tbase
.ty
== Tarray
)
760 tbase
= tbase
.nextOf().baseElemOf();
761 if (auto ts
= tbase
.isTypeStruct())
763 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
765 StructDeclaration sd
= ts
.sym
;
766 if (sd
.semanticRun
< PASS
.semanticdone
)
767 sd
.dsymbolSemantic(null);
769 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
770 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
772 if (sd
.xeq
&& sd
.xeq
.isGenerated() && sd
.xeq
._scope
&& sd
.xeq
.semanticRun
< PASS
.semantic3done
)
774 uint errors
= global
.startGagging();
775 sd
.xeq
.semantic3(sd
.xeq
._scope
);
776 if (global
.endGagging(errors
))
781 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
782 const(char)* s
= (mtype
.index
.toBasetype().ty
!= Tstruct
) ?
"bottom of " : "";
785 // If sd.xhash != NULL:
786 // sd or its fields have user-defined toHash.
787 // AA assumes that its result is consistent with bitwise equality.
789 // bitwise equality & hashing
791 else if (sd
.xeq
== sd
.xerreq
)
793 if (search_function(sd
, Id
.eq
))
795 .error(loc
, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s
, sd
.toChars(), sd
.toChars());
799 .error(loc
, "%sAA key type `%s` does not support const equality", s
, sd
.toChars());
805 if (search_function(sd
, Id
.eq
))
807 .error(loc
, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s
, sd
.toChars());
811 .error(loc
, "%sAA key type `%s` supports const equality but doesn't support const hashing", s
, sd
.toChars());
817 // defined equality & hashing
818 assert(sd
.xeq
&& sd
.xhash
);
820 /* xeq and xhash may be implicitly defined by compiler. For example:
821 * struct S { int[] arr; }
822 * With 'arr' field equality and hashing, compiler will implicitly
823 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
827 else if (tbase
.ty
== Tclass
&& !tbase
.isTypeClass().sym
.isInterfaceDeclaration())
829 ClassDeclaration cd
= tbase
.isTypeClass().sym
;
830 if (cd
.semanticRun
< PASS
.semanticdone
)
831 cd
.dsymbolSemantic(null);
833 if (!ClassDeclaration
.object
)
835 .error(Loc
.initial
, "missing or corrupt object.d");
839 __gshared FuncDeclaration feq
= null;
840 __gshared FuncDeclaration fcmp
= null;
841 __gshared FuncDeclaration fhash
= null;
843 feq
= search_function(ClassDeclaration
.object
, Id
.eq
).isFuncDeclaration();
845 fcmp
= search_function(ClassDeclaration
.object
, Id
.cmp).isFuncDeclaration();
847 fhash
= search_function(ClassDeclaration
.object
, Id
.tohash
).isFuncDeclaration();
848 assert(fcmp
&& feq
&& fhash
);
850 if (feq
.vtblIndex
< cd
.vtbl
.length
&& cd
.vtbl
[feq
.vtblIndex
] == feq
)
854 if (fcmp
.vtblIndex
< cd
.vtbl
.length
&& cd
.vtbl
[fcmp
.vtblIndex
] != fcmp
)
856 const(char)* s
= (mtype
.index
.toBasetype().ty
!= Tclass
) ?
"bottom of " : "";
857 .error(loc
, "%sAA key type `%s` now requires equality rather than comparison", s
, cd
.toChars());
858 errorSupplemental(loc
, "Please override `Object.opEquals` and `Object.toHash`.");
863 mtype
.next
= mtype
.next
.typeSemantic(loc
, sc
).merge2();
866 switch (mtype
.next
.toBasetype().ty
)
872 .error(loc
, "cannot have associative array of `%s`", mtype
.next
.toChars());
879 if (mtype
.next
.isscope())
881 .error(loc
, "cannot have array of scope `%s`", mtype
.next
.toChars());
887 Type
visitPointer(TypePointer mtype
)
889 //printf("TypePointer::semantic() %s\n", toChars());
894 Type n
= mtype
.next
.typeSemantic(loc
, sc
);
895 switch (n
.toBasetype().ty
)
898 .error(loc
, "cannot have pointer to `%s`", n
.toChars());
910 if (mtype
.next
.ty
!= Tfunction
)
921 mtype
.deco
= merge(mtype
).deco
;
922 /* Don't return merge(), because arg identifiers and default args
924 * even though the types match
930 Type
visitReference(TypeReference mtype
)
932 //printf("TypeReference::semantic()\n");
933 Type n
= mtype
.next
.typeSemantic(loc
, sc
);
941 Type
visitFunction(TypeFunction mtype
)
943 if (mtype
.deco
) // if semantic() already run
945 //printf("already done\n");
948 //printf("TypeFunction::semantic() this = %p\n", mtype);
949 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
953 if (mtype
.inuse
> global
.recursionLimit
)
956 .error(loc
, "recursive type");
960 /* Copy in order to not mess up original.
961 * This can produce redundant copies if inferring return type,
962 * as semantic() will get called again on this.
964 TypeFunction tf
= mtype
.copy().toTypeFunction();
965 if (mtype
.parameterList
.parameters
)
967 tf
.parameterList
.parameters
= mtype
.parameterList
.parameters
.copy();
968 for (size_t i
= 0; i
< mtype
.parameterList
.parameters
.length
; i
++)
970 Parameter p
= cast(Parameter
)mem
.xmalloc(__traits(classInstanceSize
, Parameter
));
971 memcpy(cast(void*)p
, cast(void*)(*mtype
.parameterList
.parameters
)[i
], __traits(classInstanceSize
, Parameter
));
972 (*tf
.parameterList
.parameters
)[i
] = p
;
976 if (sc
.stc & STC
.pure_
)
977 tf
.purity
= PURE
.fwdref
;
978 if (sc
.stc & STC
.nothrow_
)
980 if (sc
.stc & STC
.nogc
)
982 if (sc
.stc & STC
.ref_
)
984 if (sc
.stc & STC
.return_
)
986 if (sc
.stc & STC
.returnScope
)
987 tf
.isreturnscope
= true;
988 if (sc
.stc & STC
.returninferred
)
989 tf
.isreturninferred
= true;
990 if (sc
.stc & STC
.scope_
)
991 tf
.isScopeQual
= true;
992 if (sc
.stc & STC
.scopeinferred
)
993 tf
.isscopeinferred
= true;
995 // if (tf.isreturn && !tf.isref)
996 // tf.isScopeQual = true; // return by itself means 'return scope'
998 if (tf
.trust
== TRUST
.default_
)
1000 if (sc
.stc & STC
.safe
)
1001 tf
.trust
= TRUST
.safe
;
1002 else if (sc
.stc & STC
.system
)
1003 tf
.trust
= TRUST
.system
;
1004 else if (sc
.stc & STC
.trusted
)
1005 tf
.trust
= TRUST
.trusted
;
1008 if (sc
.stc & STC
.property
)
1009 tf
.isproperty
= true;
1010 if (sc
.stc & STC
.live
)
1013 tf
.linkage
= sc
.linkage
;
1014 if (tf
.linkage
== LINK
.system
)
1015 tf
.linkage
= target
.systemLinkage();
1019 /* If the parent is @safe, then this function defaults to safe
1021 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1022 * to be inferred first.
1024 if (tf
.trust
== TRUST
.default_
)
1025 for (Dsymbol p
= sc
.func
; p
; p
= p
.toParent2())
1027 FuncDeclaration fd
= p
.isFuncDeclaration();
1030 if (fd
.isSafeBypassingInference())
1031 tf
.trust
= TRUST
.safe
; // default to @safe
1037 bool wildreturn
= false;
1041 sc
.stc &= ~(STC
.TYPECTOR | STC
.FUNCATTR
);
1042 tf
.next
= tf
.next
.typeSemantic(loc
, sc
);
1044 errors |
= tf
.checkRetType(loc
);
1045 if (tf
.next
.isscope() && !tf
.isctor
)
1047 .error(loc
, "functions cannot return `scope %s`", tf
.next
.toChars());
1050 if (tf
.next
.hasWild())
1053 if (tf
.isreturn
&& !tf
.isref
&& !tf
.next
.hasPointers())
1055 tf
.isreturn
= false;
1059 /// Perform semantic on the default argument to a parameter
1060 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1061 /// Returns `false` whether an error was encountered.
1062 static bool defaultArgSemantic (ref Parameter fparam
, Scope
* sc
)
1064 Expression e
= fparam
.defaultArg
;
1065 const isRefOrOut
= fparam
.isReference();
1066 const isAuto
= fparam
.storageClass
& (STC
.auto_ | STC
.autoref
);
1067 if (isRefOrOut
&& !isAuto
)
1069 e
= e
.expressionSemantic(sc
);
1070 e
= resolveProperties(sc
, e
);
1074 e
= inferType(e
, fparam
.type
);
1075 Initializer iz
= new ExpInitializer(e
.loc
, e
);
1076 iz
= iz
.initializerSemantic(sc
, fparam
.type
, INITnointerpret
);
1077 e
= iz
.initializerToExpression();
1079 if (e
.op
== EXP
.function_
) // https://issues.dlang.org/show_bug.cgi?id=4820
1081 FuncExp fe
= e
.isFuncExp();
1082 // Replace function literal with a function symbol,
1083 // since default arg expression must be copied when used
1084 // and copying the literal itself is wrong.
1085 e
= new VarExp(e
.loc
, fe
.fd
, false);
1086 e
= new AddrExp(e
.loc
, e
);
1087 e
= e
.expressionSemantic(sc
);
1089 if (isRefOrOut
&& (!isAuto || e
.isLvalue())
1090 && !MODimplicitConv(e
.type
.mod
, fparam
.type
.mod
))
1092 const(char)* errTxt
= fparam
.storageClass
& STC
.ref_ ?
"ref" : "out";
1093 .error(e
.loc
, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1094 e
.toChars(), e
.type
.toChars(), errTxt
, fparam
.type
.toChars(), fparam
.toChars());
1096 e
= e
.implicitCastTo(sc
, fparam
.type
);
1098 // default arg must be an lvalue
1099 if (isRefOrOut
&& !isAuto
&&
1100 !(global
.params
.previewIn
&& (fparam
.storageClass
& STC
.in_
)) &&
1101 global
.params
.rvalueRefParam
!= FeatureState
.enabled
)
1102 e
= e
.toLvalue(sc
, "create default argument for `ref` / `out` parameter from");
1104 fparam
.defaultArg
= e
;
1105 return (e
.op
!= EXP
.error
);
1108 ubyte wildparams
= 0;
1109 if (tf
.parameterList
.parameters
)
1111 /* Create a scope for evaluating the default arguments for the parameters
1113 Scope
* argsc
= sc
.push();
1114 argsc
.stc = 0; // don't inherit storage class
1115 argsc
.visibility
= Visibility(Visibility
.Kind
.public_
);
1118 size_t dim
= tf
.parameterList
.length
;
1119 for (size_t i
= 0; i
< dim
; i
++)
1121 Parameter fparam
= tf
.parameterList
[i
];
1122 fparam
.storageClass |
= STC
.parameter
;
1124 fparam
.type
= fparam
.type
.typeSemantic(loc
, argsc
);
1127 if (fparam
.type
.ty
== Terror
)
1133 fparam
.type
= fparam
.type
.addStorageClass(fparam
.storageClass
);
1135 if (fparam
.storageClass
& (STC
.auto_ | STC
.alias_ | STC
.static_
))
1141 fparam
.type
= fparam
.type
.cAdjustParamType(sc
); // adjust C array and function parameter types
1143 Type t
= fparam
.type
.toBasetype();
1145 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
1148 if (auto tt
= t
.isTypeTuple())
1150 /* TypeFunction::parameter also is used as the storage of
1151 * Parameter objects for FuncDeclaration. So we should copy
1152 * the elements of TypeTuple::arguments to avoid unintended
1153 * sharing of Parameter object among other functions.
1155 if (tt
.arguments
&& tt
.arguments
.length
)
1157 /* Propagate additional storage class from tuple parameters to their
1158 * element-parameters.
1159 * Make a copy, as original may be referenced elsewhere.
1161 size_t tdim
= tt
.arguments
.length
;
1162 auto newparams
= new Parameters(tdim
);
1163 for (size_t j
= 0; j
< tdim
; j
++)
1165 Parameter narg
= (*tt
.arguments
)[j
];
1167 // https://issues.dlang.org/show_bug.cgi?id=12744
1168 // If the storage classes of narg
1169 // conflict with the ones in fparam, it's ignored.
1170 StorageClass
stc = fparam
.storageClass | narg
.storageClass
;
1171 StorageClass stc1
= fparam
.storageClass
& (STC
.ref_ | STC
.out_ | STC
.lazy_
);
1172 StorageClass stc2
= narg
.storageClass
& (STC
.ref_ | STC
.out_ | STC
.lazy_
);
1173 if (stc1
&& stc2
&& stc1
!= stc2
)
1175 OutBuffer buf1
; stcToBuffer(buf1
, stc1 |
((stc1
& STC
.ref_
) ?
(fparam
.storageClass
& STC
.auto_
) : 0));
1176 OutBuffer buf2
; stcToBuffer(buf2
, stc2
);
1178 .error(loc
, "incompatible parameter storage classes `%s` and `%s`",
1179 buf1
.peekChars(), buf2
.peekChars());
1181 stc = stc1 |
(stc & ~(STC
.ref_ | STC
.out_ | STC
.lazy_
));
1183 (*newparams
)[j
] = new Parameter(
1184 loc
, stc, narg
.type
, narg
.ident
, narg
.defaultArg
, narg
.userAttribDecl
);
1186 fparam
.type
= new TypeTuple(newparams
);
1187 fparam
.type
= fparam
.type
.typeSemantic(loc
, argsc
);
1189 fparam
.storageClass
= STC
.parameter
;
1191 /* Reset number of parameters, and back up one to do this fparam again,
1192 * now that it is a tuple
1194 dim
= tf
.parameterList
.length
;
1199 // -preview=in: Always add `ref` when used with `extern(C++)` functions
1200 // Done here to allow passing opaque types with `in`
1201 if ((fparam
.storageClass
& (STC
.in_ | STC
.ref_
)) == STC
.in_
)
1206 if (global
.params
.previewIn
)
1207 fparam
.storageClass |
= STC
.ref_
;
1209 case LINK
.default_
, LINK
.d
:
1212 if (global
.params
.previewIn
)
1214 .error(loc
, "cannot use `in` parameters with `extern(%s)` functions",
1215 linkageToChars(tf
.linkage
));
1216 .errorSupplemental(loc
, "parameter `%s` declared as `in` here", fparam
.toChars());
1220 // Note that this deprecation will not trigger on `in ref` / `ref in`
1221 // parameters, however the parser will trigger a deprecation on them.
1222 .deprecation(loc
, "using `in` parameters with `extern(%s)` functions is deprecated",
1223 linkageToChars(tf
.linkage
));
1224 .deprecationSupplemental(loc
, "parameter `%s` declared as `in` here", fparam
.toChars());
1230 if (t
.ty
== Tfunction
)
1232 .error(loc
, "cannot have parameter of function type `%s`", fparam
.type
.toChars());
1235 else if (!fparam
.isReference() &&
1236 (t
.ty
== Tstruct || t
.ty
== Tsarray || t
.ty
== Tenum
))
1238 Type tb2
= t
.baseElemOf();
1239 if (tb2
.ty
== Tstruct
&& !tb2
.isTypeStruct().sym
.members ||
1240 tb2
.ty
== Tenum
&& !tb2
.isTypeEnum().sym
.memtype
)
1242 if (global
.params
.previewIn
&& (fparam
.storageClass
& STC
.in_
))
1244 .error(loc
, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
1245 fparam
.toChars(), fparam
.type
.toChars());
1248 .error(loc
, "cannot have parameter of opaque type `%s` by value",
1249 fparam
.type
.toChars());
1253 else if (!fparam
.isLazy() && t
.ty
== Tvoid
)
1255 .error(loc
, "cannot have parameter of type `%s`", fparam
.type
.toChars());
1259 const bool isTypesafeVariadic
= i
+ 1 == dim
&&
1260 tf
.parameterList
.varargs
== VarArg
.typesafe
&&
1261 (t
.isTypeDArray() || t
.isTypeClass());
1262 if (isTypesafeVariadic
)
1264 /* typesafe variadic arguments are constructed on the stack, so must be `scope`
1266 fparam
.storageClass |
= STC
.scope_ | STC
.scopeinferred
;
1269 if (fparam
.storageClass
& STC
.return_
)
1271 if (!fparam
.isReference())
1273 if (!(fparam
.storageClass
& STC
.scope_
))
1274 fparam
.storageClass |
= STC
.scope_ | STC
.scopeinferred
; // 'return' implies 'scope'
1278 else if (tf
.next
&& !tf
.next
.hasPointers() && tf
.next
.toBasetype().ty
!= Tvoid
)
1280 fparam
.storageClass
&= ~STC
.return_
; // https://issues.dlang.org/show_bug.cgi?id=18963
1284 if (isTypesafeVariadic
)
1286 /* This is because they can be constructed on the stack
1287 * https://dlang.org/spec/function.html#typesafe_variadic_functions
1289 .error(loc
, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
1290 fparam
.ident ? fparam
.ident
.toChars() : "", t
.toChars());
1295 if (fparam
.storageClass
& STC
.out_
)
1297 if (ubyte m
= fparam
.type
.mod
& (MODFlags
.immutable_ | MODFlags
.const_ | MODFlags
.wild
))
1299 .error(loc
, "cannot have `%s out` parameter of type `%s`", MODtoChars(m
), t
.toChars());
1304 Type tv
= t
.baseElemOf();
1305 if (tv
.ty
== Tstruct
&& tv
.isTypeStruct().sym
.noDefaultCtor
)
1307 .error(loc
, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam
.type
.toChars());
1316 //if (tf.next && !wildreturn)
1317 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
1320 // Remove redundant storage classes for type, they are already applied
1321 fparam
.storageClass
&= ~(STC
.TYPECTOR
);
1323 // -preview=in: add `ref` storage class to suited `in` params
1324 if (global
.params
.previewIn
&& (fparam
.storageClass
& (STC
.in_ | STC
.ref_
)) == STC
.in_
)
1326 auto ts
= t
.baseElemOf().isTypeStruct();
1327 const isPOD
= !ts || ts
.sym
.isPOD();
1328 if (!isPOD || target
.preferPassByRef(t
))
1329 fparam
.storageClass |
= STC
.ref_
;
1333 // Now that we completed semantic for the argument types,
1334 // run semantic on their default values,
1335 // bearing in mind tuples have been expanded.
1336 // We need to keep a pair of [oidx, eidx] (original index,
1337 // extended index), as we need to run semantic when `oidx` changes.
1338 size_t tupleOrigIdx
= size_t
.max
;
1339 size_t tupleExtIdx
= size_t
.max
;
1340 foreach (oidx
, oparam
, eidx
, eparam
; tf
.parameterList
)
1342 // oparam (original param) will always have the default arg
1343 // if there's one, but `eparam` will not if it's an expanded
1344 // tuple. When we see an expanded tuple, we need to save its
1345 // position to get the offset in it later on.
1346 if (oparam
.defaultArg
)
1348 // Get the obvious case out of the way
1349 if (oparam
is eparam
)
1350 errors |
= !defaultArgSemantic(eparam
, argsc
);
1351 // We're seeing a new tuple
1352 else if (tupleOrigIdx
== size_t
.max || tupleOrigIdx
< oidx
)
1354 /* https://issues.dlang.org/show_bug.cgi?id=18572
1356 * If a tuple parameter has a default argument, when expanding the parameter
1357 * tuple the default argument tuple must also be expanded.
1359 tupleOrigIdx
= oidx
;
1361 errors |
= !defaultArgSemantic(oparam
, argsc
);
1362 TupleExp te
= oparam
.defaultArg
.isTupleExp();
1363 if (te
&& te
.exps
&& te
.exps
.length
)
1364 eparam
.defaultArg
= (*te
.exps
)[0];
1366 // Processing an already-seen tuple
1369 TupleExp te
= oparam
.defaultArg
.isTupleExp();
1370 if (te
&& te
.exps
&& te
.exps
.length
)
1371 eparam
.defaultArg
= (*te
.exps
)[eidx
- tupleExtIdx
];
1375 // We need to know the default argument to resolve `auto ref`,
1376 // hence why this has to take place as the very last step.
1377 /* Resolve "auto ref" storage class to be either ref or value,
1378 * based on the argument matching the parameter
1380 if (eparam
.storageClass
& STC
.auto_
)
1382 Expression farg
= mtype
.fargs
&& eidx
< mtype
.fargs
.length ?
1383 (*mtype
.fargs
)[eidx
] : eparam
.defaultArg
;
1384 if (farg
&& (eparam
.storageClass
& STC
.ref_
))
1386 if (!farg
.isLvalue())
1387 eparam
.storageClass
&= ~STC
.ref_
; // value parameter
1388 eparam
.storageClass
&= ~STC
.auto_
; // https://issues.dlang.org/show_bug.cgi?id=14656
1389 eparam
.storageClass |
= STC
.autoref
;
1391 else if (mtype
.incomplete
&& (eparam
.storageClass
& STC
.ref_
))
1393 // the default argument may have been temporarily removed,
1394 // see usage of `TypeFunction.incomplete`.
1395 // https://issues.dlang.org/show_bug.cgi?id=19891
1396 eparam
.storageClass
&= ~STC
.auto_
;
1397 eparam
.storageClass |
= STC
.autoref
;
1399 else if (eparam
.storageClass
& STC
.ref_
)
1401 .error(loc
, "cannot explicitly instantiate template function with `auto ref` parameter");
1406 .error(loc
, "`auto` can only be used as part of `auto ref` for template function parameters");
1417 if (wildreturn
&& !wildparams
)
1419 .error(loc
, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype
.toChars());
1422 tf
.isInOutParam
= (wildparams
& 1) != 0;
1423 tf
.isInOutQual
= (wildparams
& 2) != 0;
1425 if (tf
.isproperty
&& (tf
.parameterList
.varargs
!= VarArg
.none || tf
.parameterList
.length
> 2))
1427 .error(loc
, "properties can only have zero, one, or two parameter");
1431 if (tf
.parameterList
.varargs
== VarArg
.variadic
&& tf
.linkage
!= LINK
.d
&& tf
.parameterList
.length
== 0 &&
1432 !(sc
.flags
& SCOPE
.Cfile
))
1434 .error(loc
, "variadic functions with non-D linkage must have at least one parameter");
1442 tf
.deco
= tf
.merge().deco
;
1444 /* Don't return merge(), because arg identifiers and default args
1446 * even though the types match
1451 Type
visitDelegate(TypeDelegate mtype
)
1453 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
1454 if (mtype
.deco
) // if semantic() already run
1456 //printf("already done\n");
1459 mtype
.next
= mtype
.next
.typeSemantic(loc
, sc
);
1460 if (mtype
.next
.ty
!= Tfunction
)
1463 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
1464 * perhaps default arguments should
1465 * be removed from next before the merge.
1469 return mtype
.merge();
1473 /* Don't return merge(), because arg identifiers and default args
1475 * even though the types match
1477 mtype
.deco
= mtype
.merge().deco
;
1482 Type
visitIdentifier(TypeIdentifier mtype
)
1487 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
1488 mtype
.resolve(loc
, sc
, e
, t
, s
);
1491 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
1492 return t
.addMod(mtype
.mod
);
1498 auto td
= s
.isTemplateDeclaration
;
1499 if (td
&& td
.onemember
&& td
.onemember
.isAggregateDeclaration
)
1500 .error(loc
, "template %s `%s` is used as a type without instantiation"
1501 ~ "; to instantiate it use `%s!(arguments)`",
1502 s
.kind
, s
.toPrettyChars
, s
.ident
.toChars
);
1504 .error(loc
, "%s `%s` is used as a type", s
.kind
, s
.toPrettyChars
);
1507 else if (e
.op
== EXP
.variable
) // special case: variable is used as a type
1510 N.B. This branch currently triggers for the following code
1515 i.e. the compiler prints "variable x is used as a type"
1516 which isn't a particularly good error message (x is a variable?).
1518 Dsymbol varDecl
= mtype
.toDsymbol(sc
);
1519 const(Loc
) varDeclLoc
= varDecl
.getLoc();
1520 Module varDeclModule
= varDecl
.getModule(); //This can be null
1522 .error(loc
, "variable `%s` is used as a type", mtype
.toChars());
1523 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
1524 if ((varDeclModule
!is null) && varDeclModule
!= sc
._module
) // variable is imported
1526 const(Loc
) varDeclModuleImportLoc
= varDeclModule
.getLoc();
1528 varDeclModuleImportLoc
,
1529 "variable `%s` is imported here from: `%s`",
1531 varDeclModule
.toPrettyChars
,
1535 .errorSupplemental(varDeclLoc
, "variable `%s` is declared here", varDecl
.toChars
);
1538 .error(loc
, "`%s` is used as a type", mtype
.toChars());
1543 Type
visitInstance(TypeInstance mtype
)
1549 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
1551 const errors
= global
.errors
;
1552 mtype
.resolve(loc
, sc
, e
, t
, s
);
1553 // if we had an error evaluating the symbol, suppress further errors
1554 if (!t
&& errors
!= global
.errors
)
1560 if (!e
&& s
&& s
.errors
)
1562 // if there was an error evaluating the symbol, it might actually
1563 // be a type. Avoid misleading error messages.
1564 .error(loc
, "`%s` had previous errors", mtype
.toChars());
1567 .error(loc
, "`%s` is used as a type", mtype
.toChars());
1573 Type
visitTypeof(TypeTypeof mtype
)
1575 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
1579 mtype
.resolve(loc
, sc
, e
, t
, s
);
1580 if (s
&& (t
= s
.getType()) !is null)
1581 t
= t
.addMod(mtype
.mod
);
1584 .error(loc
, "`%s` is used as a type", mtype
.toChars());
1590 Type
visitTraits(TypeTraits mtype
)
1595 mtype
.resolve(loc
, sc
, e
, t
, s
);
1600 .error(mtype
.loc
, "`%s` does not give a valid type", mtype
.toChars
);
1606 Type
visitReturn(TypeReturn mtype
)
1608 //printf("TypeReturn::semantic() %s\n", toChars());
1612 mtype
.resolve(loc
, sc
, e
, t
, s
);
1613 if (s
&& (t
= s
.getType()) !is null)
1614 t
= t
.addMod(mtype
.mod
);
1617 .error(loc
, "`%s` is used as a type", mtype
.toChars());
1623 Type
visitStruct(TypeStruct mtype
)
1625 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
1629 /* Don't semantic for sym because it should be deferred until
1630 * sizeof needed or its members accessed.
1632 // instead, parent should be set correctly
1633 assert(mtype
.sym
.parent
);
1635 if (mtype
.sym
.type
.ty
== Terror
)
1638 return merge(mtype
);
1641 Type
visitEnum(TypeEnum mtype
)
1643 //printf("TypeEnum::semantic() %s\n", toChars());
1644 return mtype
.deco ? mtype
: merge(mtype
);
1647 Type
visitClass(TypeClass mtype
)
1649 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
1653 /* Don't semantic for sym because it should be deferred until
1654 * sizeof needed or its members accessed.
1656 // instead, parent should be set correctly
1657 assert(mtype
.sym
.parent
);
1659 if (mtype
.sym
.type
.ty
== Terror
)
1662 return merge(mtype
);
1665 Type
visitTuple(TypeTuple mtype
)
1667 //printf("TypeTuple::semantic(this = %p)\n", this);
1668 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
1670 mtype
.deco
= merge(mtype
).deco
;
1672 /* Don't return merge(), because a tuple with one type has the
1673 * same deco as that type.
1678 Type
visitSlice(TypeSlice mtype
)
1680 //printf("TypeSlice::semantic() %s\n", toChars());
1681 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
1682 //printf("next: %s\n", tn.toChars());
1684 Type tbn
= tn
.toBasetype();
1685 if (tbn
.ty
!= Ttuple
)
1687 .error(loc
, "can only slice type sequences, not `%s`", tbn
.toChars());
1690 TypeTuple tt
= cast(TypeTuple
)tbn
;
1692 mtype
.lwr
= semanticLength(sc
, tbn
, mtype
.lwr
);
1693 mtype
.upr
= semanticLength(sc
, tbn
, mtype
.upr
);
1694 mtype
.lwr
= mtype
.lwr
.ctfeInterpret();
1695 mtype
.upr
= mtype
.upr
.ctfeInterpret();
1696 if (mtype
.lwr
.op
== EXP
.error || mtype
.upr
.op
== EXP
.error
)
1699 uinteger_t i1
= mtype
.lwr
.toUInteger();
1700 uinteger_t i2
= mtype
.upr
.toUInteger();
1701 if (!(i1
<= i2
&& i2
<= tt
.arguments
.length
))
1703 .error(loc
, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
1704 cast(ulong)i1
, cast(ulong)i2
, cast(ulong)tt
.arguments
.length
);
1711 auto args
= new Parameters();
1712 args
.reserve(cast(size_t
)(i2
- i1
));
1713 foreach (arg
; (*tt
.arguments
)[cast(size_t
)i1
.. cast(size_t
)i2
])
1717 Type t
= new TypeTuple(args
);
1718 return t
.typeSemantic(loc
, sc
);
1721 Type
visitMixin(TypeMixin mtype
)
1723 //printf("TypeMixin::semantic() %s\n", toChars());
1728 mtype
.resolve(loc
, sc
, e
, t
, s
);
1730 if (t
&& t
.ty
!= Terror
)
1733 .error(mtype
.loc
, "`mixin(%s)` does not give a valid type", mtype
.obj
.toChars
);
1737 Type
visitTag(TypeTag mtype
)
1739 //printf("TypeTag.semantic() %s\n", mtype.toChars());
1744 return mtype
.resolved
.addSTC(mtype
.mod
);
1747 /* Find the current scope by skipping tag scopes.
1748 * In C, tag scopes aren't considered scopes.
1754 auto scopesym
= sc2
.scopesym
;
1755 if (scopesym
.isStructDeclaration())
1757 sc2
= sc2
.enclosing
;
1763 /* Declare mtype as a struct/union/enum declaration
1767 void declare(ScopeDsymbol sd
)
1769 sd
.members
= mtype
.members
;
1770 auto scopesym
= sc2
.inner().scopesym
;
1771 if (scopesym
.members
)
1772 scopesym
.members
.push(sd
);
1773 if (scopesym
.symtab
&& !scopesym
.symtabInsert(sd
))
1775 Dsymbol s2
= scopesym
.symtabLookup(sd
, mtype
.id
);
1776 handleTagSymbols(*sc2
, sd
, s2
, scopesym
);
1778 sd
.parent
= sc2
.parent
;
1779 sd
.dsymbolSemantic(sc2
);
1785 auto ed
= new EnumDeclaration(mtype
.loc
, mtype
.id
, mtype
.base
);
1787 mtype
.resolved
= visitEnum(new TypeEnum(ed
));
1791 auto sd
= new StructDeclaration(mtype
.loc
, mtype
.id
, false);
1792 sd
.alignment
= mtype
.packalign
;
1794 mtype
.resolved
= visitStruct(new TypeStruct(sd
));
1798 auto ud
= new UnionDeclaration(mtype
.loc
, mtype
.id
);
1799 ud
.alignment
= mtype
.packalign
;
1801 mtype
.resolved
= visitStruct(new TypeStruct(ud
));
1809 /* If it doesn't have a tag by now, supply one.
1810 * It'll be unique, and therefore introducing.
1811 * Declare it, and done.
1815 mtype
.id
= Identifier
.generateId("__tag"[]);
1817 return mtype
.resolved
.addSTC(mtype
.mod
);
1820 /* look for pre-existing declaration
1823 auto s
= sc2
.search(mtype
.loc
, mtype
.id
, &scopesym
, IgnoreErrors | TagNameSpace
);
1824 if (!s || s
.isModule())
1826 // no pre-existing declaration, so declare it
1827 if (mtype
.tok
== TOK
.enum_
&& !mtype
.members
)
1828 .error(mtype
.loc
, "`enum %s` is incomplete without members", mtype
.id
.toChars()); // C11 6.7.2.3-3
1830 return mtype
.resolved
.addSTC(mtype
.mod
);
1833 /* A redeclaration only happens if both declarations are in
1836 const bool redeclar
= (scopesym
== sc2
.inner().scopesym
);
1840 if (mtype
.tok
== TOK
.enum_
&& s
.isEnumDeclaration())
1842 auto ed
= s
.isEnumDeclaration();
1843 if (mtype
.members
&& ed
.members
)
1844 .error(mtype
.loc
, "`%s` already has members", mtype
.id
.toChars());
1845 else if (!ed
.members
)
1847 ed
.members
= mtype
.members
;
1852 mtype
.resolved
= ed
.type
;
1854 else if (mtype
.tok
== TOK
.union_
&& s
.isUnionDeclaration() ||
1855 mtype
.tok
== TOK
.struct_
&& s
.isStructDeclaration())
1857 // Add members to original declaration
1858 auto sd
= s
.isStructDeclaration();
1859 if (mtype
.members
&& sd
.members
)
1861 /* struct S { int b; };
1862 * struct S { int a; } *s;
1864 .error(mtype
.loc
, "`%s` already has members", mtype
.id
.toChars());
1866 else if (!sd
.members
)
1869 * struct S { int a; } *s;
1871 sd
.members
= mtype
.members
;
1872 if (sd
.semanticRun
== PASS
.semanticdone
)
1874 /* The first semantic pass marked `sd` as an opaque struct.
1875 * Re-run semantic so that all newly assigned members are
1876 * picked up and added to the symtab.
1878 sd
.semanticRun
= PASS
.semantic
;
1879 sd
.dsymbolSemantic(sc2
);
1884 /* struct S { int a; };
1888 mtype
.resolved
= sd
.type
;
1893 * struct S { int a; } *s;
1895 .error(mtype
.loc
, "redeclaration of `%s`", mtype
.id
.toChars());
1896 mtype
.resolved
= error();
1899 else if (mtype
.members
)
1902 * { struct S { int a; } *s; }
1908 if (mtype
.tok
== TOK
.enum_
&& s
.isEnumDeclaration())
1910 mtype
.resolved
= s
.isEnumDeclaration().type
;
1912 else if (mtype
.tok
== TOK
.union_
&& s
.isUnionDeclaration() ||
1913 mtype
.tok
== TOK
.struct_
&& s
.isStructDeclaration())
1918 mtype
.resolved
= s
.isStructDeclaration().type
;
1925 .error(mtype
.loc
, "redeclaring `%s %s` as `%s %s`",
1926 s
.kind(), s
.toChars(), Token
.toChars(mtype
.tok
), mtype
.id
.toChars());
1930 return mtype
.resolved
.addSTC(mtype
.mod
);
1935 default: return visitType(type
);
1938 case Tcomplex80
: return visitComplex(type
.isTypeBasic());
1939 case Tvector
: return visitVector(type
.isTypeVector());
1940 case Tsarray
: return visitSArray(type
.isTypeSArray());
1941 case Tarray
: return visitDArray(type
.isTypeDArray());
1942 case Taarray
: return visitAArray(type
.isTypeAArray());
1943 case Tpointer
: return visitPointer(type
.isTypePointer());
1944 case Treference
: return visitReference(type
.isTypeReference());
1945 case Tfunction
: return visitFunction(type
.isTypeFunction());
1946 case Tdelegate
: return visitDelegate(type
.isTypeDelegate());
1947 case Tident
: return visitIdentifier(type
.isTypeIdentifier());
1948 case Tinstance
: return visitInstance(type
.isTypeInstance());
1949 case Ttypeof
: return visitTypeof(type
.isTypeTypeof());
1950 case Ttraits
: return visitTraits(type
.isTypeTraits());
1951 case Treturn
: return visitReturn(type
.isTypeReturn());
1952 case Tstruct
: return visitStruct(type
.isTypeStruct());
1953 case Tenum
: return visitEnum(type
.isTypeEnum());
1954 case Tclass
: return visitClass(type
.isTypeClass());
1955 case Ttuple
: return visitTuple(type
.isTypeTuple());
1956 case Tslice
: return visitSlice(type
.isTypeSlice());
1957 case Tmixin
: return visitMixin(type
.isTypeMixin());
1958 case Ttag
: return visitTag(type
.isTypeTag());
1962 /************************************
1963 * If an identical type to `type` is in `type.stringtable`, return
1964 * the latter one. Otherwise, add it to `type.stringtable`.
1965 * Some types don't get merged and are returned as-is.
1967 * type = Type to check against existing types
1969 * the type that was merged
1971 extern (C
++) Type
merge(Type type
)
1981 return type
; // don't merge placeholder types
1984 // prevents generating the mangle if the array dim is not yet known
1985 if (!type
.isTypeSArray().dim
.isIntegerExp())
1993 if (!type
.isTypeAArray().index
.merge().deco
)
1998 if (type
.nextOf() && !type
.nextOf().deco
)
2003 //printf("merge(%s)\n", toChars());
2009 mangleToBuffer(type
, buf
);
2011 auto sv
= type
.stringtable
.update(buf
[]);
2017 import core
.stdc
.stdio
;
2019 printf("t = %s\n", t
.toChars());
2022 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2027 Type t
= stripDefaultArgs(type
);
2029 type
.deco
= t
.deco
= cast(char*)sv
.toDchars();
2030 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2037 /***************************************
2038 * Calculate built-in properties which just the type is necessary.
2041 * t = the type for which the property is calculated
2042 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2043 * loc = the location where the property is encountered
2044 * ident = the identifier of the property
2045 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2046 * src = expression for type `t` or null.
2048 * expression representing the property, or null if not a property and (flag & 1)
2050 Expression
getProperty(Type t
, Scope
* scope_
, const ref Loc loc
, Identifier ident
, int flag
,
2051 Expression src
= null)
2053 Expression
visitType(Type mt
)
2056 static if (LOGDOTEXP
)
2058 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt
.toChars(), ident
.toChars());
2060 if (ident
== Id
.__sizeof
)
2062 const sz
= mt
.size(loc
);
2063 if (sz
== SIZE_INVALID
)
2064 return ErrorExp
.get();
2065 e
= new IntegerExp(loc
, sz
, Type
.tsize_t
);
2067 else if (ident
== Id
.__xalignof
)
2069 const explicitAlignment
= mt
.alignment();
2070 const naturalAlignment
= mt
.alignsize();
2071 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
2072 e
= new IntegerExp(loc
, actualAlignment
, Type
.tsize_t
);
2074 else if (ident
== Id
._init
)
2076 Type tb
= mt
.toBasetype();
2077 e
= mt
.defaultInitLiteral(loc
);
2078 if (tb
.ty
== Tstruct
&& tb
.needsNested())
2080 e
.isStructLiteralExp().useStaticInit
= true;
2083 else if (ident
== Id
._mangleof
)
2087 error(loc
, "forward reference of type `%s.mangleof`", mt
.toChars());
2092 e
= new StringExp(loc
, mt
.deco
.toDString());
2094 sc
.eSink
= global
.errorSink
;
2095 e
= e
.expressionSemantic(&sc
);
2098 else if (ident
== Id
.stringof
)
2100 const s
= mt
.toChars();
2101 e
= new StringExp(loc
, s
.toDString());
2103 sc
.eSink
= global
.errorSink
;
2104 e
= e
.expressionSemantic(&sc
);
2106 else if (flag
&& mt
!= Type
.terror
)
2113 if (mt
.ty
== Tstruct || mt
.ty
== Tclass || mt
.ty
== Tenum
)
2114 s
= mt
.toDsymbol(null);
2116 s
= s
.search_correct(ident
);
2117 if (s
&& !symbolIsVisible(scope_
, s
))
2119 if (mt
!= Type
.terror
)
2122 error(loc
, "no property `%s` for type `%s`, did you mean `%s`?", ident
.toChars(), mt
.toChars(), s
.toPrettyChars());
2123 else if (ident
== Id
.call && mt
.ty
== Tclass
)
2124 error(loc
, "no property `%s` for type `%s`, did you mean `new %s`?", ident
.toChars(), mt
.toChars(), mt
.toPrettyChars());
2126 else if (const n
= importHint(ident
.toString()))
2127 error(loc
, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident
.toChars(), mt
.toChars(), cast(int)n
.length
, n
.ptr
);
2131 error(loc
, "no property `%s` for `%s` of type `%s`", ident
.toChars(), src
.toChars(), mt
.toPrettyChars(true));
2133 error(loc
, "no property `%s` for type `%s`", ident
.toChars(), mt
.toPrettyChars(true));
2135 if (auto dsym
= mt
.toDsymbol(scope_
))
2137 if (auto sym
= dsym
.isAggregateDeclaration())
2139 if (auto fd
= search_function(sym
, Id
.opDispatch
))
2140 errorSupplemental(loc
, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
2141 else if (!sym
.members
)
2142 errorSupplemental(sym
.loc
, "`%s %s` is opaque and has no members.", sym
.kind
, mt
.toPrettyChars(true));
2144 errorSupplemental(dsym
.loc
, "%s `%s` defined here",
2145 dsym
.kind
, dsym
.toChars());
2154 Expression
visitError(TypeError
)
2156 return ErrorExp
.get();
2159 Expression
visitBasic(TypeBasic mt
)
2161 Expression
integerValue(dinteger_t i
)
2163 return new IntegerExp(loc
, i
, mt
);
2166 Expression
intValue(dinteger_t i
)
2168 return new IntegerExp(loc
, i
, Type
.tint32
);
2171 Expression
floatValue(real_t r
)
2173 if (mt
.isreal() || mt
.isimaginary())
2174 return new RealExp(loc
, r
, mt
);
2177 return new ComplexExp(loc
, complex_t(r
, r
), mt
);
2181 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
2182 if (ident
== Id
.max
)
2186 case Tint8
: return integerValue(byte.max
);
2187 case Tuns8
: return integerValue(ubyte.max
);
2188 case Tint16
: return integerValue(short.max
);
2189 case Tuns16
: return integerValue(ushort.max
);
2190 case Tint32
: return integerValue(int.max
);
2191 case Tuns32
: return integerValue(uint.max
);
2192 case Tint64
: return integerValue(long.max
);
2193 case Tuns64
: return integerValue(ulong.max
);
2194 case Tbool
: return integerValue(bool.max
);
2195 case Tchar
: return integerValue(char.max
);
2196 case Twchar
: return integerValue(wchar.max
);
2197 case Tdchar
: return integerValue(dchar.max
);
2200 case Tfloat32
: return floatValue(target
.FloatProperties
.max
);
2203 case Tfloat64
: return floatValue(target
.DoubleProperties
.max
);
2206 case Tfloat80
: return floatValue(target
.RealProperties
.max
);
2210 else if (ident
== Id
.min
)
2214 case Tint8
: return integerValue(byte.min
);
2222 case Tdchar
: return integerValue(0);
2223 case Tint16
: return integerValue(short.min
);
2224 case Tint32
: return integerValue(int.min
);
2225 case Tint64
: return integerValue(long.min
);
2229 else if (ident
== Id
.min_normal
)
2235 case Tfloat32
: return floatValue(target
.FloatProperties
.min_normal
);
2238 case Tfloat64
: return floatValue(target
.DoubleProperties
.min_normal
);
2241 case Tfloat80
: return floatValue(target
.RealProperties
.min_normal
);
2245 else if (ident
== Id
.nan
)
2257 case Tfloat80
: return floatValue(target
.RealProperties
.nan
);
2261 else if (ident
== Id
.infinity
)
2273 case Tfloat80
: return floatValue(target
.RealProperties
.infinity
);
2277 else if (ident
== Id
.dig
)
2283 case Tfloat32
: return intValue(target
.FloatProperties
.dig
);
2286 case Tfloat64
: return intValue(target
.DoubleProperties
.dig
);
2289 case Tfloat80
: return intValue(target
.RealProperties
.dig
);
2293 else if (ident
== Id
.epsilon
)
2299 case Tfloat32
: return floatValue(target
.FloatProperties
.epsilon
);
2302 case Tfloat64
: return floatValue(target
.DoubleProperties
.epsilon
);
2305 case Tfloat80
: return floatValue(target
.RealProperties
.epsilon
);
2309 else if (ident
== Id
.mant_dig
)
2315 case Tfloat32
: return intValue(target
.FloatProperties
.mant_dig
);
2318 case Tfloat64
: return intValue(target
.DoubleProperties
.mant_dig
);
2321 case Tfloat80
: return intValue(target
.RealProperties
.mant_dig
);
2325 else if (ident
== Id
.max_10_exp
)
2331 case Tfloat32
: return intValue(target
.FloatProperties
.max_10_exp
);
2334 case Tfloat64
: return intValue(target
.DoubleProperties
.max_10_exp
);
2337 case Tfloat80
: return intValue(target
.RealProperties
.max_10_exp
);
2341 else if (ident
== Id
.max_exp
)
2347 case Tfloat32
: return intValue(target
.FloatProperties
.max_exp
);
2350 case Tfloat64
: return intValue(target
.DoubleProperties
.max_exp
);
2353 case Tfloat80
: return intValue(target
.RealProperties
.max_exp
);
2357 else if (ident
== Id
.min_10_exp
)
2363 case Tfloat32
: return intValue(target
.FloatProperties
.min_10_exp
);
2366 case Tfloat64
: return intValue(target
.DoubleProperties
.min_10_exp
);
2369 case Tfloat80
: return intValue(target
.RealProperties
.min_10_exp
);
2373 else if (ident
== Id
.min_exp
)
2379 case Tfloat32
: return intValue(target
.FloatProperties
.min_exp
);
2382 case Tfloat64
: return intValue(target
.DoubleProperties
.min_exp
);
2385 case Tfloat80
: return intValue(target
.RealProperties
.min_exp
);
2389 return visitType(mt
);
2392 Expression
visitVector(TypeVector mt
)
2394 return visitType(mt
);
2397 Expression
visitEnum(TypeEnum mt
)
2400 if (ident
== Id
.max || ident
== Id
.min
)
2402 return mt
.sym
.getMaxMinValue(loc
, ident
);
2404 else if (ident
== Id
._init
)
2406 e
= mt
.defaultInitLiteral(loc
);
2408 else if (ident
== Id
.stringof
)
2410 e
= new StringExp(loc
, mt
.toString());
2412 e
= e
.expressionSemantic(&sc
);
2414 else if (ident
== Id
._mangleof
)
2420 e
= mt
.toBasetype().getProperty(scope_
, loc
, ident
, flag
);
2425 Expression
visitTuple(TypeTuple mt
)
2428 static if (LOGDOTEXP
)
2430 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt
.toChars(), ident
.toChars());
2432 if (ident
== Id
.length
)
2434 e
= new IntegerExp(loc
, mt
.arguments
.length
, Type
.tsize_t
);
2436 else if (ident
== Id
._init
)
2438 e
= mt
.defaultInitLiteral(loc
);
2446 error(loc
, "no property `%s` for sequence `%s`", ident
.toChars(), mt
.toChars());
2454 default: return t
.isTypeBasic() ?
2455 visitBasic(cast(TypeBasic
)t
) :
2458 case Terror
: return visitError (t
.isTypeError());
2459 case Tvector
: return visitVector(t
.isTypeVector());
2460 case Tenum
: return visitEnum (t
.isTypeEnum());
2461 case Ttuple
: return visitTuple (t
.isTypeTuple());
2465 /***************************************
2466 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
2468 * exp = Expression to look at
2469 * t = if exp should be a Type, set t to that Type else null
2470 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
2471 * e = if exp should remain an Expression, set e to that Expression else null
2474 private void resolveExp(Expression exp
, out Type t
, out Expression e
, out Dsymbol s
)
2476 if (exp
.isTypeExp())
2478 else if (auto ve
= exp
.isVarExp())
2480 if (auto v
= ve
.var
.isVarDeclaration())
2485 else if (auto te
= exp
.isTemplateExp())
2487 else if (auto se
= exp
.isScopeExp())
2489 else if (exp
.isFuncExp())
2490 s
= getDsymbol(exp
);
2491 else if (auto dte
= exp
.isDotTemplateExp())
2493 else if (exp
.isErrorExp())
2499 /************************************
2500 * Resolve type 'mt' to either type, symbol, or expression.
2501 * If errors happened, resolved to Type.terror.
2504 * mt = type to be resolved
2505 * loc = the location where the type is encountered
2506 * sc = the scope of the type
2507 * pe = is set if t is an expression
2508 * pt = is set if t is a type
2509 * ps = is set if t is a symbol
2510 * intypeid = true if in type id
2512 void resolve(Type mt
, const ref Loc loc
, Scope
* sc
, out Expression pe
, out Type pt
, out Dsymbol ps
, bool intypeid
= false)
2514 void returnExp(Expression e
)
2521 void returnType(Type t
)
2528 void returnSymbol(Dsymbol s
)
2537 returnType(Type
.terror
);
2540 void visitType(Type mt
)
2542 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
2543 Type t
= typeSemantic(mt
, loc
, sc
);
2548 void visitSArray(TypeSArray mt
)
2550 //printf("TypeSArray::resolve() %s\n", mt.toChars());
2551 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
2552 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2555 // It's really an index expression
2556 if (Dsymbol s
= getDsymbol(pe
))
2557 pe
= new DsymbolExp(loc
, s
);
2558 returnExp(new ArrayExp(loc
, pe
, mt
.dim
));
2563 if (auto tup
= s
.isTupleDeclaration())
2565 mt
.dim
= semanticLength(sc
, tup
, mt
.dim
);
2566 mt
.dim
= mt
.dim
.ctfeInterpret();
2567 if (mt
.dim
.op
== EXP
.error
)
2568 return returnError();
2570 const d
= mt
.dim
.toUInteger();
2571 if (d
>= tup
.objects
.length
)
2573 error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", d
, cast(ulong) tup
.objects
.length
);
2574 return returnError();
2577 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
2578 switch (o
.dyncast()) with (DYNCAST
)
2581 return returnSymbol(cast(Dsymbol
)o
);
2583 Expression e
= cast(Expression
)o
;
2584 if (e
.op
== EXP
.dSymbol
)
2585 return returnSymbol(e
.isDsymbolExp().s
);
2587 return returnExp(e
);
2589 return returnType((cast(Type
)o
).addMod(mt
.mod
));
2594 /* Create a new TupleDeclaration which
2595 * is a slice [d..d+1] out of the old one.
2596 * Do it this way because TemplateInstance::semanticTiargs()
2597 * can handle unresolved Objects this way.
2599 auto objects
= new Objects(1);
2601 return returnSymbol(new TupleDeclaration(loc
, tup
.ident
, objects
));
2604 return visitType(mt
);
2608 if (pt
.ty
!= Terror
)
2609 mt
.next
= pt
; // prevent re-running semantic() on 'next'
2615 void visitDArray(TypeDArray mt
)
2617 //printf("TypeDArray::resolve() %s\n", mt.toChars());
2618 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
2619 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2622 // It's really a slice expression
2623 if (Dsymbol s
= getDsymbol(pe
))
2624 pe
= new DsymbolExp(loc
, s
);
2625 returnExp(new ArrayExp(loc
, pe
));
2629 if (auto tup
= ps
.isTupleDeclaration())
2638 if (pt
.ty
!= Terror
)
2639 mt
.next
= pt
; // prevent re-running semantic() on 'next'
2644 void visitAArray(TypeAArray mt
)
2646 //printf("TypeAArray::resolve() %s\n", mt.toChars());
2647 // Deal with the case where we thought the index was a type, but
2648 // in reality it was an expression.
2649 if (mt
.index
.ty
== Tident || mt
.index
.ty
== Tinstance || mt
.index
.ty
== Tsarray
)
2654 mt
.index
.resolve(loc
, sc
, e
, t
, s
, intypeid
);
2657 // It was an expression -
2658 // Rewrite as a static array
2659 auto tsa
= new TypeSArray(mt
.next
, e
);
2660 tsa
.mod
= mt
.mod
; // just copy mod field so tsa's semantic is not yet done
2661 return tsa
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
2666 .error(loc
, "index is not a type or an expression");
2671 /*************************************
2672 * Takes an array of Identifiers and figures out if
2673 * it represents a Type or an Expression.
2675 * if expression, pe is set
2676 * if type, pt is set
2678 void visitIdentifier(TypeIdentifier mt
)
2680 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2681 if (mt
.ident
== Id
.ctfe
)
2683 error(loc
, "variable `__ctfe` cannot be read at compile time");
2684 return returnError();
2686 if (mt
.ident
== Id
.builtin_va_list
) // gcc has __builtin_va_xxxx for stdarg.h
2688 /* Since we don't support __builtin_va_start, -arg, -end, we don't
2689 * have to actually care what -list is. A void* will do.
2690 * If we ever do care, import core.stdc.stdarg and pull
2691 * the definition out of that, similarly to how std.math is handled for PowExp
2693 pt
= target
.va_listType(loc
, sc
);
2698 Dsymbol s
= sc
.search(loc
, mt
.ident
, &scopesym
);
2700 * https://issues.dlang.org/show_bug.cgi?id=1170
2701 * https://issues.dlang.org/show_bug.cgi?id=10739
2703 * If a symbol is not found, it might be declared in
2704 * a mixin-ed string or a mixin-ed template, so before
2705 * issuing an error semantically analyze all string/template
2706 * mixins that are members of the current ScopeDsymbol.
2708 if (!s
&& sc
.enclosing
)
2710 ScopeDsymbol sds
= sc
.enclosing
.scopesym
;
2711 if (sds
&& sds
.members
)
2713 void semanticOnMixin(Dsymbol member
)
2715 if (auto compileDecl
= member
.isMixinDeclaration())
2716 compileDecl
.dsymbolSemantic(sc
);
2717 else if (auto mixinTempl
= member
.isTemplateMixin())
2718 mixinTempl
.dsymbolSemantic(sc
);
2720 sds
.members
.foreachDsymbol( s
=> semanticOnMixin(s
) );
2721 s
= sc
.search(loc
, mt
.ident
, &scopesym
);
2727 // https://issues.dlang.org/show_bug.cgi?id=16042
2728 // If `f` is really a function template, then replace `f`
2729 // with the function template declaration.
2730 if (auto f
= s
.isFuncDeclaration())
2732 if (auto td
= getFuncTemplateDecl(f
))
2734 // If not at the beginning of the overloaded list of
2735 // `TemplateDeclaration`s, then get the beginning
2743 mt
.resolveHelper(loc
, sc
, s
, scopesym
, pe
, pt
, ps
, intypeid
);
2745 pt
= pt
.addMod(mt
.mod
);
2748 void visitInstance(TypeInstance mt
)
2750 // Note close similarity to TypeIdentifier::resolve()
2752 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
2753 mt
.tempinst
.dsymbolSemantic(sc
);
2754 if (!global
.gag
&& mt
.tempinst
.errors
)
2755 return returnError();
2757 mt
.resolveHelper(loc
, sc
, mt
.tempinst
, null, pe
, pt
, ps
, intypeid
);
2759 pt
= pt
.addMod(mt
.mod
);
2760 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
2763 void visitTypeof(TypeTypeof mt
)
2765 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
2766 //static int nest; if (++nest == 50) *(char*)0=0;
2769 error(loc
, "invalid scope");
2770 return returnError();
2775 error(loc
, "circular `typeof` definition");
2778 return returnError();
2782 /* Currently we cannot evaluate 'exp' in speculative context, because
2783 * the type implementation may leak to the final execution. Consider:
2786 * string toString() const { return "x"; }
2789 * alias X = typeof(S!int());
2790 * assert(typeid(X).toString() == "x");
2793 Scope
* sc2
= sc
.push();
2795 if (!mt
.exp
.isTypeidExp())
2796 /* Treat typeof(typeid(exp)) as needing
2797 * the full semantic analysis of the typeid.
2798 * https://issues.dlang.org/show_bug.cgi?id=20958
2802 auto exp2
= mt
.exp
.expressionSemantic(sc2
);
2803 exp2
= resolvePropertiesOnly(sc2
, exp2
);
2806 if (exp2
.op
== EXP
.error
)
2814 if ((mt
.exp
.op
== EXP
.type || mt
.exp
.op
== EXP
.scope_
) &&
2815 // https://issues.dlang.org/show_bug.cgi?id=23863
2816 // compile time sequences are valid types
2817 !mt
.exp
.type
.isTypeTuple())
2819 if (!(sc
.flags
& SCOPE
.Cfile
) && // in (extended) C typeof may be used on types as with sizeof
2823 /* Today, 'typeof(func)' returns void if func is a
2824 * function template (TemplateExp), or
2825 * template lambda (FuncExp).
2826 * It's actually used in Phobos as an idiom, to branch code for
2827 * template functions.
2830 if (auto f
= mt
.exp
.op
== EXP
.variable ? mt
.exp
.isVarExp().var
.isFuncDeclaration()
2831 : mt
.exp
.op
== EXP
.dotVariable ? mt
.exp
.isDotVarExp().var
.isFuncDeclaration() : null)
2833 // f might be a unittest declaration which is incomplete when compiled
2834 // without -unittest. That causes a segfault in checkForwardRef, see
2835 // https://issues.dlang.org/show_bug.cgi?id=20626
2836 if ((!f
.isUnitTestDeclaration() || global
.params
.useUnitTests
) && f
.checkForwardRef(loc
))
2839 if (auto f
= isFuncAddress(mt
.exp
))
2841 if (f
.checkForwardRef(loc
))
2845 Type t
= mt
.exp
.type
;
2848 error(loc
, "expression `%s` has no type", mt
.exp
.toChars());
2851 if (t
.ty
== Ttypeof
)
2853 error(loc
, "forward reference to `%s`", mt
.toChars());
2856 if (mt
.idents
.length
== 0)
2858 returnType(t
.addMod(mt
.mod
));
2862 if (Dsymbol s
= t
.toDsymbol(sc
))
2863 mt
.resolveHelper(loc
, sc
, s
, null, pe
, pt
, ps
, intypeid
);
2866 auto e
= typeToExpressionHelper(mt
, new TypeExp(loc
, t
));
2867 e
= e
.expressionSemantic(sc
);
2868 resolveExp(e
, pt
, pe
, ps
);
2871 pt
= pt
.addMod(mt
.mod
);
2876 void visitReturn(TypeReturn mt
)
2878 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2881 FuncDeclaration func
= sc
.func
;
2884 error(loc
, "`typeof(return)` must be inside function");
2885 return returnError();
2888 func
= func
.fes
.func
;
2889 t
= func
.type
.nextOf();
2892 error(loc
, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc
.func
.toChars());
2893 return returnError();
2896 if (mt
.idents
.length
== 0)
2898 return returnType(t
.addMod(mt
.mod
));
2902 if (Dsymbol s
= t
.toDsymbol(sc
))
2903 mt
.resolveHelper(loc
, sc
, s
, null, pe
, pt
, ps
, intypeid
);
2906 auto e
= typeToExpressionHelper(mt
, new TypeExp(loc
, t
));
2907 e
= e
.expressionSemantic(sc
);
2908 resolveExp(e
, pt
, pe
, ps
);
2911 pt
= pt
.addMod(mt
.mod
);
2915 void visitSlice(TypeSlice mt
)
2917 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
2920 // It's really a slice expression
2921 if (Dsymbol s
= getDsymbol(pe
))
2922 pe
= new DsymbolExp(loc
, s
);
2923 return returnExp(new ArrayExp(loc
, pe
, new IntervalExp(loc
, mt
.lwr
, mt
.upr
)));
2928 TupleDeclaration td
= s
.isTupleDeclaration();
2931 /* It's a slice of a TupleDeclaration
2933 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, td
);
2934 sym
.parent
= sc
.scopesym
;
2936 sc
= sc
.startCTFE();
2937 mt
.lwr
= mt
.lwr
.expressionSemantic(sc
);
2938 mt
.upr
= mt
.upr
.expressionSemantic(sc
);
2942 mt
.lwr
= mt
.lwr
.ctfeInterpret();
2943 mt
.upr
= mt
.upr
.ctfeInterpret();
2944 const i1
= mt
.lwr
.toUInteger();
2945 const i2
= mt
.upr
.toUInteger();
2946 if (!(i1
<= i2
&& i2
<= td
.objects
.length
))
2948 error(loc
, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1
, i2
, cast(ulong) td
.objects
.length
);
2949 return returnError();
2952 if (i1
== 0 && i2
== td
.objects
.length
)
2954 return returnSymbol(td
);
2957 /* Create a new TupleDeclaration which
2958 * is a slice [i1..i2] out of the old one.
2960 auto objects
= new Objects(cast(size_t
)(i2
- i1
));
2961 for (size_t i
= 0; i
< objects
.length
; i
++)
2963 (*objects
)[i
] = (*td
.objects
)[cast(size_t
)i1
+ i
];
2966 return returnSymbol(new TupleDeclaration(loc
, td
.ident
, objects
));
2973 if (pt
.ty
!= Terror
)
2974 mt
.next
= pt
; // prevent re-running semantic() on 'next'
2979 void visitMixin(TypeMixin mt
)
2981 RootObject o
= mt
.obj
;
2983 // if already resolved just set pe/pt/ps and return.
2986 pe
= o
.isExpression();
2992 o
= mt
.compileTypeMixin(loc
, sc
);
2993 if (auto t
= o
.isType())
2995 resolve(t
, loc
, sc
, pe
, pt
, ps
, intypeid
);
2997 pt
= pt
.addMod(mt
.mod
);
2999 else if (auto e
= o
.isExpression())
3001 e
= e
.expressionSemantic(sc
);
3002 if (auto et
= e
.isTypeExp())
3003 returnType(et
.type
.addMod(mt
.mod
));
3011 mt
.obj
= pe ? pe
: (pt ? pt
: ps
);
3014 void visitTraits(TypeTraits mt
)
3016 // if already resolved just return the cached object.
3019 pt
= mt
.obj
.isType();
3020 ps
= mt
.obj
.isDsymbol();
3021 pe
= mt
.obj
.isExpression();
3025 import dmd
.traits
: semanticTraits
;
3027 if (Expression e
= semanticTraits(mt
.exp
, sc
))
3031 case EXP
.dotVariable
:
3032 mt
.obj
= e
.isDotVarExp().var
;
3035 mt
.obj
= e
.isVarExp().var
;
3038 auto fe
= e
.isFuncExp();
3039 mt
.obj
= fe
.td ? fe
.td
: fe
.fd
;
3041 case EXP
.dotTemplateDeclaration
:
3042 mt
.obj
= e
.isDotTemplateExp().td
;
3045 mt
.obj
= e
.isDsymbolExp().s
;
3048 mt
.obj
= e
.isTemplateExp().td
;
3051 mt
.obj
= e
.isScopeExp().sds
;
3054 TupleExp te
= e
.isTupleExp();
3055 Objects
* elems
= new Objects(te
.exps
.length
);
3056 foreach (i
; 0 .. elems
.length
)
3058 auto src
= (*te
.exps
)[i
];
3062 (*elems
)[i
] = src
.isTypeExp().type
;
3065 (*elems
)[i
] = src
.isDotTypeExp().sym
.isType();
3067 case EXP
.overloadSet
:
3068 (*elems
)[i
] = src
.isOverExp().type
;
3071 if (auto sym
= isDsymbol(src
))
3077 TupleDeclaration td
= new TupleDeclaration(e
.loc
, Identifier
.generateId("__aliastup"), elems
);
3081 mt
.obj
= e
.isDotTypeExp().sym
.isType();
3084 mt
.obj
= e
.isTypeExp().type
;
3086 case EXP
.overloadSet
:
3087 mt
.obj
= e
.isOverExp().type
;
3099 if (auto t
= mt
.obj
.isType())
3101 t
= t
.addMod(mt
.mod
);
3105 else if (auto s
= mt
.obj
.isDsymbol())
3107 else if (auto e
= mt
.obj
.isExpression())
3112 assert(global
.errors
);
3113 mt
.obj
= Type
.terror
;
3114 return returnError();
3120 default: visitType (mt
); break;
3121 case Tsarray
: visitSArray (mt
.isTypeSArray()); break;
3122 case Tarray
: visitDArray (mt
.isTypeDArray()); break;
3123 case Taarray
: visitAArray (mt
.isTypeAArray()); break;
3124 case Tident
: visitIdentifier(mt
.isTypeIdentifier()); break;
3125 case Tinstance
: visitInstance (mt
.isTypeInstance()); break;
3126 case Ttypeof
: visitTypeof (mt
.isTypeTypeof()); break;
3127 case Treturn
: visitReturn (mt
.isTypeReturn()); break;
3128 case Tslice
: visitSlice (mt
.isTypeSlice()); break;
3129 case Tmixin
: visitMixin (mt
.isTypeMixin()); break;
3130 case Ttraits
: visitTraits (mt
.isTypeTraits()); break;
3134 /************************
3135 * Access the members of the object e. This type is same as e.type.
3137 * mt = type for which the dot expression is used
3138 * sc = instantiating scope
3139 * e = expression to convert
3140 * ident = identifier being used
3141 * flag = DotExpFlag bit flags
3144 * resulting expression with e.ident resolved
3146 Expression
dotExp(Type mt
, Scope
* sc
, Expression e
, Identifier ident
, DotExpFlag flag
)
3148 Expression
visitType(Type mt
)
3150 VarDeclaration v
= null;
3151 static if (LOGDOTEXP
)
3153 printf("Type::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3155 Expression ex
= e
.lastComma();
3156 if (ex
.op
== EXP
.dotVariable
)
3158 DotVarExp dv
= cast(DotVarExp
)ex
;
3159 v
= dv
.var
.isVarDeclaration();
3161 else if (ex
.op
== EXP
.variable
)
3163 VarExp ve
= cast(VarExp
)ex
;
3164 v
= ve
.var
.isVarDeclaration();
3168 if (ident
== Id
.offsetof
)
3170 v
.dsymbolSemantic(null);
3173 auto ad
= v
.isMember();
3174 objc
.checkOffsetof(e
, ad
);
3176 if (ad
.sizeok
!= Sizeok
.done
)
3177 return ErrorExp
.get();
3178 return new IntegerExp(e
.loc
, v
.offset
, Type
.tsize_t
);
3181 else if (ident
== Id
._init
)
3183 Type tb
= mt
.toBasetype();
3184 e
= mt
.defaultInitLiteral(e
.loc
);
3185 if (tb
.ty
== Tstruct
&& tb
.needsNested())
3187 e
.isStructLiteralExp().useStaticInit
= true;
3192 if (ident
== Id
.stringof
)
3194 /* https://issues.dlang.org/show_bug.cgi?id=3796
3195 * this should demangle e.type.deco rather than
3196 * pretty-printing the type.
3198 e
= new StringExp(e
.loc
, e
.toString());
3201 e
= mt
.getProperty(sc
, e
.loc
, ident
, flag
& DotExpFlag
.gag
);
3205 e
= e
.expressionSemantic(sc
);
3209 Expression
visitError(TypeError
)
3211 return ErrorExp
.get();
3214 Expression
visitBasic(TypeBasic mt
)
3216 static if (LOGDOTEXP
)
3218 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3237 e
= e
.castTo(sc
, t
);
3257 e
= new RealExp(e
.loc
, CTFloat
.zero
, t
);
3261 e
= mt
.Type
.getProperty(sc
, e
.loc
, ident
, flag
);
3265 else if (ident
== Id
.im
)
3271 t
= mt
.timaginary32
;
3276 t
= mt
.timaginary64
;
3281 t
= mt
.timaginary80
;
3285 e
= e
.castTo(sc
, t
);
3308 e
= new RealExp(e
.loc
, CTFloat
.zero
, mt
);
3312 e
= mt
.Type
.getProperty(sc
, e
.loc
, ident
, flag
);
3318 return visitType(mt
);
3320 if (!(flag
& 1) || e
)
3321 e
= e
.expressionSemantic(sc
);
3325 Expression
visitVector(TypeVector mt
)
3327 static if (LOGDOTEXP
)
3329 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3331 if (ident
== Id
.ptr
&& e
.op
== EXP
.call)
3333 /* The trouble with EXP.call is the return ABI for float[4] is different from
3334 * __vector(float[4]), and a type paint won't do.
3336 e
= new AddrExp(e
.loc
, e
);
3337 e
= e
.expressionSemantic(sc
);
3338 return e
.castTo(sc
, mt
.basetype
.nextOf().pointerTo());
3340 if (ident
== Id
.array
)
3342 //e = e.castTo(sc, basetype);
3344 e
= new VectorArrayExp(e
.loc
, e
);
3345 e
= e
.expressionSemantic(sc
);
3348 if (ident
== Id
._init || ident
== Id
.offsetof || ident
== Id
.stringof || ident
== Id
.__xalignof
)
3350 // init should return a new VectorExp
3351 // https://issues.dlang.org/show_bug.cgi?id=12776
3352 // offsetof does not work on a cast expression, so use e directly
3353 // stringof should not add a cast to the output
3354 return visitType(mt
);
3357 // Properties based on the vector element type and are values of the element type
3358 if (ident
== Id
.max || ident
== Id
.min || ident
== Id
.min_normal ||
3359 ident
== Id
.nan || ident
== Id
.infinity || ident
== Id
.epsilon
)
3361 auto vet
= mt
.basetype
.isTypeSArray().next
; // vector element type
3362 if (auto ev
= getProperty(vet
, sc
, e
.loc
, ident
, DotExpFlag
.gag
))
3363 return ev
.castTo(sc
, mt
); // 'broadcast' ev to the vector elements
3366 return mt
.basetype
.dotExp(sc
, e
.castTo(sc
, mt
.basetype
), ident
, flag
);
3369 Expression
visitArray(TypeArray mt
)
3371 static if (LOGDOTEXP
)
3373 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3378 if (!(flag
& 1) || e
)
3379 e
= e
.expressionSemantic(sc
);
3383 Expression
visitSArray(TypeSArray mt
)
3385 static if (LOGDOTEXP
)
3387 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3389 if (ident
== Id
.length
)
3395 else if (ident
== Id
.ptr
)
3397 if (e
.op
== EXP
.type
)
3399 error(e
.loc
, "`%s` is not an expression", e
.toChars());
3400 return ErrorExp
.get();
3402 else if (mt
.dim
.toUInteger() < 1 && checkUnsafeDotExp(sc
, e
, ident
, flag
))
3404 // .ptr on static array is @safe unless size is 0
3405 // https://issues.dlang.org/show_bug.cgi?id=20853
3406 return ErrorExp
.get();
3408 e
= e
.castTo(sc
, e
.type
.nextOf().pointerTo());
3410 else if (ident
== Id
._tupleof
)
3414 error(e
.loc
, "`.tupleof` cannot be used on type `%s`", mt
.toChars
);
3415 return ErrorExp
.get();
3421 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
3423 const length
= cast(size_t
)mt
.dim
.toUInteger();
3424 auto exps
= new Expressions();
3425 exps
.reserve(length
);
3426 foreach (i
; 0 .. length
)
3427 exps
.push(new IndexExp(e
.loc
, ev
, new IntegerExp(e
.loc
, i
, Type
.tsize_t
)));
3428 e
= new TupleExp(e
.loc
, e0
, exps
);
3435 if (!(flag
& 1) || e
)
3436 e
= e
.expressionSemantic(sc
);
3440 Expression
visitDArray(TypeDArray mt
)
3442 static if (LOGDOTEXP
)
3444 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3446 if (e
.op
== EXP
.type
&& (ident
== Id
.length || ident
== Id
.ptr
))
3448 error(e
.loc
, "`%s` is not an expression", e
.toChars());
3449 return ErrorExp
.get();
3451 if (ident
== Id
.length
)
3453 if (e
.op
== EXP
.string_
)
3455 StringExp se
= cast(StringExp
)e
;
3456 return new IntegerExp(se
.loc
, se
.len
, Type
.tsize_t
);
3458 if (e
.op
== EXP
.null_
)
3460 return new IntegerExp(e
.loc
, 0, Type
.tsize_t
);
3462 if (checkNonAssignmentArrayOp(e
))
3464 return ErrorExp
.get();
3466 e
= new ArrayLengthExp(e
.loc
, e
);
3467 e
.type
= Type
.tsize_t
;
3470 else if (ident
== Id
.ptr
)
3472 if (checkUnsafeDotExp(sc
, e
, ident
, flag
))
3473 return ErrorExp
.get();
3474 return e
.castTo(sc
, mt
.next
.pointerTo());
3478 return visitArray(mt
);
3482 Expression
visitAArray(TypeAArray mt
)
3484 static if (LOGDOTEXP
)
3486 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3488 if (ident
== Id
.length
)
3490 __gshared FuncDeclaration fd_aaLen
= null;
3491 if (fd_aaLen
is null)
3493 auto fparams
= new Parameters();
3494 fparams
.push(new Parameter(Loc
.initial
, STC
.const_ | STC
.scope_
, mt
, null, null, null));
3495 fd_aaLen
= FuncDeclaration
.genCfunc(fparams
, Type
.tsize_t
, Id
.aaLen
);
3496 TypeFunction tf
= fd_aaLen
.type
.toTypeFunction();
3497 tf
.purity
= PURE
.const_
;
3498 tf
.isnothrow
= true;
3501 Expression ev
= new VarExp(e
.loc
, fd_aaLen
, false);
3502 e
= new CallExp(e
.loc
, ev
, e
);
3503 e
.type
= fd_aaLen
.type
.toTypeFunction().next
;
3508 return visitType(mt
);
3512 Expression
visitReference(TypeReference mt
)
3514 static if (LOGDOTEXP
)
3516 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3518 // References just forward things along
3519 return mt
.next
.dotExp(sc
, e
, ident
, flag
);
3522 Expression
visitDelegate(TypeDelegate mt
)
3524 static if (LOGDOTEXP
)
3526 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3528 if (ident
== Id
.ptr
)
3530 e
= new DelegatePtrExp(e
.loc
, e
);
3531 e
= e
.expressionSemantic(sc
);
3533 else if (ident
== Id
.funcptr
)
3535 if (checkUnsafeDotExp(sc
, e
, ident
, flag
))
3537 return ErrorExp
.get();
3539 e
= new DelegateFuncptrExp(e
.loc
, e
);
3540 e
= e
.expressionSemantic(sc
);
3544 return visitType(mt
);
3549 /***************************************
3550 * `ident` was not found as a member of `mt`.
3551 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
3552 * If that fails, forward to visitType().
3554 * mt = class or struct
3556 * e = `this` for `ident`
3557 * ident = name of member
3558 * flag = flag & 1, don't report "not a property" error and just return NULL.
3559 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
3561 * resolved expression if found, otherwise null
3563 Expression
noMember(Type mt
, Scope
* sc
, Expression e
, Identifier ident
, int flag
)
3565 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
3567 bool gagError
= flag
& 1;
3569 __gshared
int nest
; // https://issues.dlang.org/show_bug.cgi?id=17380
3571 static Expression
returnExp(Expression e
)
3577 if (++nest
> global
.recursionLimit
)
3579 .error(e
.loc
, "cannot resolve identifier `%s`", ident
.toChars());
3580 return returnExp(gagError ?
null : ErrorExp
.get());
3584 assert(mt
.ty
== Tstruct || mt
.ty
== Tclass
);
3585 auto sym
= mt
.toDsymbol(sc
).isAggregateDeclaration();
3587 if (// https://issues.dlang.org/show_bug.cgi?id=22054
3588 // if a class or struct does not have a body
3589 // there is no point in searching for its members
3591 ident
!= Id
.__sizeof
&&
3592 ident
!= Id
.__xalignof
&&
3593 ident
!= Id
._init
&&
3594 ident
!= Id
._mangleof
&&
3595 ident
!= Id
.stringof
&&
3596 ident
!= Id
.offsetof
&&
3597 // https://issues.dlang.org/show_bug.cgi?id=15045
3598 // Don't forward special built-in member functions.
3601 ident
!= Id
.__xdtor
&&
3602 ident
!= Id
.postblit
&&
3603 ident
!= Id
.__xpostblit
)
3605 /* Look for overloaded opDot() to see if we should forward request
3608 if (auto fd
= search_function(sym
, Id
.opDot
))
3610 /* Rewrite e.ident as:
3613 e
= build_overload(e
.loc
, sc
, e
, null, fd
);
3614 // @@@DEPRECATED_2.110@@@.
3615 // Deprecated in 2.082, made an error in 2.100.
3616 error(e
.loc
, "`opDot` is obsolete. Use `alias this`");
3617 return ErrorExp
.get();
3620 /* Look for overloaded opDispatch to see if we should forward request
3623 if (auto fd
= search_function(sym
, Id
.opDispatch
))
3625 /* Rewrite e.ident as:
3626 * e.opDispatch!("ident")
3628 TemplateDeclaration td
= fd
.isTemplateDeclaration();
3631 .error(fd
.loc
, "%s `%s` must be a template `opDispatch(string s)`, not a %s", fd
.kind
, fd
.toPrettyChars
, fd
.kind());
3632 return returnExp(ErrorExp
.get());
3634 auto se
= new StringExp(e
.loc
, ident
.toString());
3635 auto tiargs
= new Objects();
3637 auto dti
= new DotTemplateInstanceExp(e
.loc
, e
, Id
.opDispatch
, tiargs
);
3638 dti
.ti
.tempdecl
= td
;
3639 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
3641 * template opDispatch(name) if (isValid!name) { ... }
3643 uint errors
= gagError ? global
.startGagging() : 0;
3644 e
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.none
);
3645 if (gagError
&& global
.endGagging(errors
))
3647 return returnExp(e
);
3650 /* See if we should forward to the alias this.
3652 auto alias_e
= flag
& DotExpFlag
.noAliasThis ?
null
3653 : resolveAliasThis(sc
, e
, gagError
);
3654 if (alias_e
&& alias_e
!= e
)
3656 /* Rewrite e.ident as:
3659 auto die
= new DotIdExp(e
.loc
, alias_e
, ident
);
3661 auto errors
= gagError ?
0 : global
.startGagging();
3662 auto exp
= die
.dotIdSemanticProp(sc
, gagError
);
3665 global
.endGagging(errors
);
3666 if (exp
&& exp
.op
== EXP
.error
)
3670 if (exp
&& gagError
)
3671 // now that we know that the alias this leads somewhere useful,
3672 // go back and print deprecations/warnings that we skipped earlier due to the gag
3673 resolveAliasThis(sc
, e
, false);
3675 return returnExp(exp
);
3678 return returnExp(visitType(mt
));
3681 Expression
visitStruct(TypeStruct mt
)
3684 static if (LOGDOTEXP
)
3686 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3688 assert(e
.op
!= EXP
.dot
);
3690 // https://issues.dlang.org/show_bug.cgi?id=14010
3691 if (!(sc
.flags
& SCOPE
.Cfile
) && ident
== Id
._mangleof
)
3693 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
3698 if (ident
== Id
._tupleof
)
3700 /* Create a TupleExp out of the fields of the struct e:
3701 * (e.field0, e.field1, e.field2, ...)
3703 e
= e
.expressionSemantic(sc
); // do this before turning on noaccesscheck
3705 if (!mt
.sym
.determineFields())
3707 error(e
.loc
, "unable to determine fields of `%s` because of forward references", mt
.toChars());
3711 Expression ev
= e
.op
== EXP
.type ?
null : e
;
3713 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
3715 auto exps
= new Expressions();
3716 exps
.reserve(mt
.sym
.fields
.length
);
3717 for (size_t i
= 0; i
< mt
.sym
.fields
.length
; i
++)
3719 VarDeclaration v
= mt
.sym
.fields
[i
];
3722 ex
= new DotVarExp(e
.loc
, ev
, v
);
3725 ex
= new VarExp(e
.loc
, v
);
3726 ex
.type
= ex
.type
.addMod(e
.type
.mod
);
3731 e
= new TupleExp(e
.loc
, e0
, exps
);
3732 Scope
* sc2
= sc
.push();
3733 sc2
.flags |
= SCOPE
.noaccesscheck
;
3734 e
= e
.expressionSemantic(sc2
);
3739 immutable flags
= sc
.flags
& SCOPE
.ignoresymbolvisibility ? IgnoreSymbolVisibility
: 0;
3740 s
= mt
.sym
.search(e
.loc
, ident
, flags | IgnorePrivateImports
);
3744 return noMember(mt
, sc
, e
, ident
, flag
);
3746 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, s
))
3748 return noMember(mt
, sc
, e
, ident
, flag
);
3750 // check before alias resolution; the alias itself might be deprecated!
3751 if (s
.isAliasDeclaration
)
3752 s
.checkDeprecated(e
.loc
, sc
);
3755 if (auto em
= s
.isEnumMember())
3757 return em
.getVarExp(e
.loc
, sc
);
3759 if (auto v
= s
.isVarDeclaration())
3761 v
.checkDeprecated(e
.loc
, sc
);
3762 v
.checkDisabled(e
.loc
, sc
);
3764 !v
.type
.deco
&& v
.inuse
)
3766 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
3767 error(e
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
3769 error(e
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
3770 return ErrorExp
.get();
3772 if (v
.type
.ty
== Terror
)
3774 return ErrorExp
.get();
3777 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
3781 error(e
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
3782 return ErrorExp
.get();
3784 checkAccess(e
.loc
, sc
, null, v
);
3785 Expression ve
= new VarExp(e
.loc
, v
);
3786 if (!isTrivialExp(e
))
3788 ve
= new CommaExp(e
.loc
, e
, ve
);
3790 return ve
.expressionSemantic(sc
);
3794 if (auto t
= s
.getType())
3796 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
3799 TemplateMixin tm
= s
.isTemplateMixin();
3802 return new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, tm
)).expressionSemantic(sc
);
3805 TemplateDeclaration td
= s
.isTemplateDeclaration();
3808 if (e
.op
== EXP
.type
)
3809 e
= new TemplateExp(e
.loc
, td
);
3811 e
= new DotTemplateExp(e
.loc
, e
, td
);
3812 return e
.expressionSemantic(sc
);
3815 TemplateInstance ti
= s
.isTemplateInstance();
3818 if (!ti
.semanticRun
)
3820 ti
.dsymbolSemantic(sc
);
3821 if (!ti
.inst || ti
.errors
) // if template failed to expand
3823 return ErrorExp
.get();
3826 s
= ti
.inst
.toAlias();
3827 if (!s
.isTemplateInstance())
3829 if (e
.op
== EXP
.type
)
3830 e
= new ScopeExp(e
.loc
, ti
);
3832 e
= new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, ti
));
3833 return e
.expressionSemantic(sc
);
3836 if (s
.isImport() || s
.isModule() || s
.isPackage())
3838 return symbolToExp(s
, e
.loc
, sc
, false);
3841 OverloadSet o
= s
.isOverloadSet();
3844 auto oe
= new OverExp(e
.loc
, o
);
3845 if (e
.op
== EXP
.type
)
3849 return new DotExp(e
.loc
, e
, oe
);
3852 Declaration d
= s
.isDeclaration();
3855 error(e
.loc
, "`%s.%s` is not a declaration", e
.toChars(), ident
.toChars());
3856 return ErrorExp
.get();
3859 if (e
.op
== EXP
.type
)
3864 if (TupleDeclaration tup
= d
.isTupleDeclaration())
3866 e
= new TupleExp(e
.loc
, tup
);
3867 return e
.expressionSemantic(sc
);
3869 if (d
.needThis() && sc
.intypeof
!= 1)
3874 * only if the scope in which we are
3875 * has a `this` that matches the type
3876 * of the lhs of the dot expression.
3878 * https://issues.dlang.org/show_bug.cgi?id=23617
3880 auto fd
= hasThis(sc
);
3881 if (fd
&& fd
.isThis() == mt
.sym
)
3883 e
= new DotVarExp(e
.loc
, new ThisExp(e
.loc
), d
);
3884 return e
.expressionSemantic(sc
);
3887 if (d
.semanticRun
== PASS
.initial
)
3888 d
.dsymbolSemantic(null);
3889 checkAccess(e
.loc
, sc
, e
, d
);
3890 auto ve
= new VarExp(e
.loc
, d
);
3891 if (d
.isVarDeclaration() && d
.needThis())
3892 ve
.type
= d
.type
.addMod(e
.type
.mod
);
3896 bool unreal
= e
.op
== EXP
.variable
&& (cast(VarExp
)e
).var
.isField();
3897 if (d
.isDataseg() || unreal
&& d
.isField())
3900 checkAccess(e
.loc
, sc
, e
, d
);
3901 Expression ve
= new VarExp(e
.loc
, d
);
3902 e
= unreal ? ve
: new CommaExp(e
.loc
, e
, ve
);
3903 return e
.expressionSemantic(sc
);
3906 e
= new DotVarExp(e
.loc
, e
, d
);
3907 return e
.expressionSemantic(sc
);
3910 Expression
visitEnum(TypeEnum mt
)
3912 static if (LOGDOTEXP
)
3914 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e
.toChars(), ident
.toChars(), mt
.toChars());
3916 // https://issues.dlang.org/show_bug.cgi?id=14010
3917 if (ident
== Id
._mangleof
)
3919 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
3922 if (mt
.sym
.semanticRun
< PASS
.semanticdone
)
3923 mt
.sym
.dsymbolSemantic(null);
3925 Dsymbol s
= mt
.sym
.search(e
.loc
, ident
);
3928 if (ident
== Id
._init
)
3930 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
3933 /* Allow special enums to not need a member list
3935 if ((ident
== Id
.max || ident
== Id
.min
) && (mt
.sym
.members ||
!mt
.sym
.isSpecial()))
3937 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
3940 Expression res
= mt
.sym
.getMemtype(Loc
.initial
).dotExp(sc
, e
, ident
, DotExpFlag
.gag
);
3941 if (!(flag
& 1) && !res
)
3943 if (auto ns
= mt
.sym
.search_correct(ident
))
3944 error(e
.loc
, "no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident
.toChars(), mt
.toChars(), mt
.toChars(),
3947 error(e
.loc
, "no property `%s` for type `%s`", ident
.toChars(),
3950 errorSupplemental(mt
.sym
.loc
, "%s `%s` defined here",
3951 mt
.sym
.kind
, mt
.toChars());
3952 return ErrorExp
.get();
3956 EnumMember m
= s
.isEnumMember();
3957 return m
.getVarExp(e
.loc
, sc
);
3960 Expression
visitClass(TypeClass mt
)
3963 static if (LOGDOTEXP
)
3965 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3967 assert(e
.op
!= EXP
.dot
);
3969 // https://issues.dlang.org/show_bug.cgi?id=12543
3970 if (ident
== Id
.__sizeof || ident
== Id
.__xalignof || ident
== Id
._mangleof
)
3972 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
3977 if (ident
== Id
._tupleof
)
3979 objc
.checkTupleof(e
, mt
);
3981 /* Create a TupleExp
3983 e
= e
.expressionSemantic(sc
); // do this before turning on noaccesscheck
3985 mt
.sym
.size(e
.loc
); // do semantic of type
3988 Expression ev
= e
.op
== EXP
.type ?
null : e
;
3990 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
3992 auto exps
= new Expressions();
3993 exps
.reserve(mt
.sym
.fields
.length
);
3994 for (size_t i
= 0; i
< mt
.sym
.fields
.length
; i
++)
3996 VarDeclaration v
= mt
.sym
.fields
[i
];
3997 // Don't include hidden 'this' pointer
3998 if (v
.isThisDeclaration())
4002 ex
= new DotVarExp(e
.loc
, ev
, v
);
4005 ex
= new VarExp(e
.loc
, v
);
4006 ex
.type
= ex
.type
.addMod(e
.type
.mod
);
4011 e
= new TupleExp(e
.loc
, e0
, exps
);
4012 Scope
* sc2
= sc
.push();
4013 sc2
.flags |
= SCOPE
.noaccesscheck
;
4014 e
= e
.expressionSemantic(sc2
);
4019 int flags
= sc
.flags
& SCOPE
.ignoresymbolvisibility ? IgnoreSymbolVisibility
: 0;
4020 s
= mt
.sym
.search(e
.loc
, ident
, flags | IgnorePrivateImports
);
4025 // See if it's a 'this' class or a base class
4026 if (mt
.sym
.ident
== ident
)
4028 if (e
.op
== EXP
.type
)
4030 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4032 e
= new DotTypeExp(e
.loc
, e
, mt
.sym
);
4033 e
= e
.expressionSemantic(sc
);
4036 if (auto cbase
= mt
.sym
.searchBase(ident
))
4038 if (e
.op
== EXP
.type
)
4040 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4042 if (auto ifbase
= cbase
.isInterfaceDeclaration())
4043 e
= new CastExp(e
.loc
, e
, ifbase
.type
);
4045 e
= new DotTypeExp(e
.loc
, e
, cbase
);
4046 e
= e
.expressionSemantic(sc
);
4050 if (ident
== Id
.classinfo
)
4052 if (!Type
.typeinfoclass
)
4054 error(e
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4055 return ErrorExp
.get();
4058 Type t
= Type
.typeinfoclass
.type
;
4059 if (e
.op
== EXP
.type || e
.op
== EXP
.dotType
)
4061 /* For type.classinfo, we know the classinfo
4064 if (!mt
.sym
.vclassinfo
)
4065 mt
.sym
.vclassinfo
= new TypeInfoClassDeclaration(mt
.sym
.type
);
4066 e
= new VarExp(e
.loc
, mt
.sym
.vclassinfo
);
4068 e
.type
= t
; // do this so we don't get redundant dereference
4072 /* For class objects, the classinfo reference is the first
4073 * entry in the vtbl[]
4075 e
= new PtrExp(e
.loc
, e
);
4076 e
.type
= t
.pointerTo();
4077 if (mt
.sym
.isInterfaceDeclaration())
4079 if (mt
.sym
.isCPPinterface())
4081 /* C++ interface vtbl[]s are different in that the
4082 * first entry is always pointer to the first virtual
4083 * function, not classinfo.
4084 * We can't get a .classinfo for it.
4086 error(e
.loc
, "no `.classinfo` for C++ interface objects");
4088 /* For an interface, the first entry in the vtbl[]
4089 * is actually a pointer to an instance of struct Interface.
4090 * The first member of Interface is the .classinfo,
4091 * so add an extra pointer indirection.
4093 e
.type
= e
.type
.pointerTo();
4094 e
= new PtrExp(e
.loc
, e
);
4095 e
.type
= t
.pointerTo();
4097 e
= new PtrExp(e
.loc
, e
, t
);
4102 if (ident
== Id
.__vptr
)
4104 /* The pointer to the vtbl[]
4105 * *cast(immutable(void*)**)e
4107 e
= e
.castTo(sc
, mt
.tvoidptr
.immutableOf().pointerTo().pointerTo());
4108 e
= new PtrExp(e
.loc
, e
);
4109 e
= e
.expressionSemantic(sc
);
4113 if (ident
== Id
.__monitor
&& mt
.sym
.hasMonitor())
4115 /* The handle to the monitor (call it a void*)
4116 * *(cast(void**)e + 1)
4118 e
= e
.castTo(sc
, mt
.tvoidptr
.pointerTo());
4119 e
= new AddExp(e
.loc
, e
, IntegerExp
.literal
!1);
4120 e
= new PtrExp(e
.loc
, e
);
4121 e
= e
.expressionSemantic(sc
);
4125 if (ident
== Id
.outer
&& mt
.sym
.vthis
)
4127 if (mt
.sym
.vthis
.semanticRun
== PASS
.initial
)
4128 mt
.sym
.vthis
.dsymbolSemantic(null);
4130 if (auto cdp
= mt
.sym
.toParentLocal().isClassDeclaration())
4132 auto dve
= new DotVarExp(e
.loc
, e
, mt
.sym
.vthis
);
4133 dve
.type
= cdp
.type
.addMod(e
.type
.mod
);
4137 /* https://issues.dlang.org/show_bug.cgi?id=15839
4138 * Find closest parent class through nested functions.
4140 for (auto p
= mt
.sym
.toParentLocal(); p
; p
= p
.toParentLocal())
4142 auto fd
= p
.isFuncDeclaration();
4145 auto ad
= fd
.isThis();
4146 if (!ad
&& fd
.isNested())
4150 if (auto cdp
= ad
.isClassDeclaration())
4152 auto ve
= new ThisExp(e
.loc
);
4155 const nestedError
= fd
.vthis
.checkNestedReference(sc
, e
.loc
);
4156 assert(!nestedError
);
4158 ve
.type
= cdp
.type
.addMod(fd
.vthis
.type
.mod
).addMod(e
.type
.mod
);
4164 // Continue to show enclosing function's frame (stack or closure).
4165 auto dve
= new DotVarExp(e
.loc
, e
, mt
.sym
.vthis
);
4166 dve
.type
= mt
.sym
.vthis
.type
.addMod(e
.type
.mod
);
4170 return noMember(mt
, sc
, e
, ident
, flag
& 1);
4172 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, s
))
4174 return noMember(mt
, sc
, e
, ident
, flag
);
4176 if (!s
.isFuncDeclaration()) // because of overloading
4178 s
.checkDeprecated(e
.loc
, sc
);
4179 if (auto d
= s
.isDeclaration())
4180 d
.checkDisabled(e
.loc
, sc
);
4184 if (auto em
= s
.isEnumMember())
4186 return em
.getVarExp(e
.loc
, sc
);
4188 if (auto v
= s
.isVarDeclaration())
4191 !v
.type
.deco
&& v
.inuse
)
4193 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
4194 error(e
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
4196 error(e
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
4197 return ErrorExp
.get();
4199 if (v
.type
.ty
== Terror
)
4201 error(e
.loc
, "type of variable `%s` has errors", v
.toPrettyChars
);
4202 return ErrorExp
.get();
4205 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
4209 error(e
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
4210 return ErrorExp
.get();
4212 checkAccess(e
.loc
, sc
, null, v
);
4213 Expression ve
= new VarExp(e
.loc
, v
);
4214 ve
= ve
.expressionSemantic(sc
);
4219 if (auto t
= s
.getType())
4221 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
4224 TemplateMixin tm
= s
.isTemplateMixin();
4227 return new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, tm
)).expressionSemantic(sc
);
4230 TemplateDeclaration td
= s
.isTemplateDeclaration();
4232 Expression
toTemplateExp(TemplateDeclaration td
)
4234 if (e
.op
== EXP
.type
)
4235 e
= new TemplateExp(e
.loc
, td
);
4237 e
= new DotTemplateExp(e
.loc
, e
, td
);
4238 e
= e
.expressionSemantic(sc
);
4244 return toTemplateExp(td
);
4247 TemplateInstance ti
= s
.isTemplateInstance();
4250 if (!ti
.semanticRun
)
4252 ti
.dsymbolSemantic(sc
);
4253 if (!ti
.inst || ti
.errors
) // if template failed to expand
4255 return ErrorExp
.get();
4258 s
= ti
.inst
.toAlias();
4259 if (!s
.isTemplateInstance())
4261 if (e
.op
== EXP
.type
)
4262 e
= new ScopeExp(e
.loc
, ti
);
4264 e
= new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, ti
));
4265 return e
.expressionSemantic(sc
);
4268 if (s
.isImport() || s
.isModule() || s
.isPackage())
4270 e
= symbolToExp(s
, e
.loc
, sc
, false);
4274 OverloadSet o
= s
.isOverloadSet();
4277 auto oe
= new OverExp(e
.loc
, o
);
4278 if (e
.op
== EXP
.type
)
4282 return new DotExp(e
.loc
, e
, oe
);
4285 Declaration d
= s
.isDeclaration();
4288 error(e
.loc
, "`%s.%s` is not a declaration", e
.toChars(), ident
.toChars());
4289 return ErrorExp
.get();
4292 if (e
.op
== EXP
.type
)
4297 if (TupleDeclaration tup
= d
.isTupleDeclaration())
4299 e
= new TupleExp(e
.loc
, tup
);
4300 e
= e
.expressionSemantic(sc
);
4304 if (mt
.sym
.classKind
== ClassKind
.objc
4305 && d
.isFuncDeclaration()
4306 && d
.isFuncDeclaration().isStatic
4307 && d
.isFuncDeclaration().objc
.selector
)
4309 auto classRef
= new ObjcClassReferenceExp(e
.loc
, mt
.sym
);
4310 classRef
.type
= objc
.getRuntimeMetaclass(mt
.sym
).getType();
4311 return new DotVarExp(e
.loc
, classRef
, d
).expressionSemantic(sc
);
4313 else if (d
.needThis() && sc
.intypeof
!= 1)
4318 AggregateDeclaration ad
= d
.isMemberLocal();
4319 if (auto f
= hasThis(sc
))
4321 // This is almost same as getRightThis() in expressionsem.d
4324 /* returns: true to continue, false to return */
4325 if (f
.hasDualContext())
4327 if (f
.followInstantiationContext(ad
))
4329 e1
= new VarExp(e
.loc
, f
.vthis
);
4330 e1
= new PtrExp(e1
.loc
, e1
);
4331 e1
= new IndexExp(e1
.loc
, e1
, IntegerExp
.literal
!1);
4332 auto pd
= f
.toParent2().isDeclaration();
4334 t
= pd
.type
.toBasetype();
4335 e1
= getThisSkipNestedFuncs(e1
.loc
, sc
, f
.toParent2(), ad
, e1
, t
, d
, true);
4338 e
= new VarExp(e
.loc
, d
);
4344 e1
= new ThisExp(e
.loc
);
4345 e1
= e1
.expressionSemantic(sc
);
4347 t
= e1
.type
.toBasetype();
4348 ClassDeclaration cd
= e
.type
.isClassHandle();
4349 ClassDeclaration tcd
= t
.isClassHandle();
4350 if (cd
&& tcd
&& (tcd
== cd || cd
.isBaseOf(tcd
, null)))
4352 e
= new DotTypeExp(e1
.loc
, e1
, cd
);
4353 e
= new DotVarExp(e
.loc
, e
, d
);
4354 e
= e
.expressionSemantic(sc
);
4357 if (tcd
&& tcd
.isNested())
4359 /* e1 is the 'this' pointer for an inner class: tcd.
4360 * Rewrite it as the 'this' pointer for the outer class.
4362 auto vthis
= tcd
.followInstantiationContext(ad
) ? tcd
.vthis2
: tcd
.vthis
;
4363 e1
= new DotVarExp(e
.loc
, e1
, vthis
);
4364 e1
.type
= vthis
.type
;
4365 e1
.type
= e1
.type
.addMod(t
.mod
);
4366 // Do not call ensureStaticLinkTo()
4367 //e1 = e1.expressionSemantic(sc);
4369 // Skip up over nested functions, and get the enclosing
4371 e1
= getThisSkipNestedFuncs(e1
.loc
, sc
, tcd
.toParentP(ad
), ad
, e1
, t
, d
, true);
4374 e
= new VarExp(e
.loc
, d
);
4381 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
4382 if (d
.semanticRun
== PASS
.initial
)
4383 d
.dsymbolSemantic(null);
4385 // If static function, get the most visible overload.
4386 // Later on the call is checked for correctness.
4387 // https://issues.dlang.org/show_bug.cgi?id=12511
4389 if (auto fd
= d
.isFuncDeclaration())
4391 import dmd
.access
: mostVisibleOverload
;
4392 d2
= mostVisibleOverload(fd
, sc
._module
);
4395 checkAccess(e
.loc
, sc
, e
, d2
);
4396 if (d2
.isDeclaration())
4398 d
= cast(Declaration
)d2
;
4399 auto ve
= new VarExp(e
.loc
, d
);
4400 if (d
.isVarDeclaration() && d
.needThis())
4401 ve
.type
= d
.type
.addMod(e
.type
.mod
);
4404 else if (d2
.isTemplateDeclaration())
4406 return toTemplateExp(cast(TemplateDeclaration
)d2
);
4412 bool unreal
= e
.op
== EXP
.variable
&& (cast(VarExp
)e
).var
.isField();
4413 if (d
.isDataseg() || unreal
&& d
.isField())
4416 checkAccess(e
.loc
, sc
, e
, d
);
4417 Expression ve
= new VarExp(e
.loc
, d
);
4418 e
= unreal ? ve
: new CommaExp(e
.loc
, e
, ve
);
4419 e
= e
.expressionSemantic(sc
);
4423 e
= new DotVarExp(e
.loc
, e
, d
);
4424 e
= e
.expressionSemantic(sc
);
4430 case Tvector
: return visitVector (mt
.isTypeVector());
4431 case Tsarray
: return visitSArray (mt
.isTypeSArray());
4432 case Tstruct
: return visitStruct (mt
.isTypeStruct());
4433 case Tenum
: return visitEnum (mt
.isTypeEnum());
4434 case Terror
: return visitError (mt
.isTypeError());
4435 case Tarray
: return visitDArray (mt
.isTypeDArray());
4436 case Taarray
: return visitAArray (mt
.isTypeAArray());
4437 case Treference
: return visitReference(mt
.isTypeReference());
4438 case Tdelegate
: return visitDelegate (mt
.isTypeDelegate());
4439 case Tclass
: return visitClass (mt
.isTypeClass());
4441 default: return mt
.isTypeBasic()
4442 ?
visitBasic(cast(TypeBasic
)mt
)
4448 /************************
4449 * Get the default initialization expression for a type.
4451 * mt = the type for which the init expression is returned
4452 * loc = the location where the expression needs to be evaluated
4453 * isCfile = default initializers are different with C
4456 * The initialization expression for the type.
4458 extern (C
++) Expression
defaultInit(Type mt
, const ref Loc loc
, const bool isCfile
= false)
4460 Expression
visitBasic(TypeBasic mt
)
4462 static if (LOGDEFAULTINIT
)
4464 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt
.toChars(), isCfile
);
4466 dinteger_t value
= 0;
4471 value
= isCfile ?
0 : 0xFF;
4476 value
= isCfile ?
0 : 0xFFFF;
4485 return new RealExp(loc
, isCfile ? CTFloat
.zero
: target
.RealProperties
.nan
, mt
);
4491 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
4492 const cvalue
= isCfile ?
complex_t(CTFloat
.zero
, CTFloat
.zero
)
4493 : complex_t(target
.RealProperties
.nan
, target
.RealProperties
.nan
);
4494 return new ComplexExp(loc
, cvalue
, mt
);
4498 error(loc
, "`void` does not have a default initializer");
4499 return ErrorExp
.get();
4504 return new IntegerExp(loc
, value
, mt
);
4507 Expression
visitVector(TypeVector mt
)
4509 //printf("TypeVector::defaultInit()\n");
4510 assert(mt
.basetype
.ty
== Tsarray
);
4511 Expression e
= mt
.basetype
.defaultInit(loc
, isCfile
);
4512 auto ve
= new VectorExp(loc
, e
, mt
);
4514 ve
.dim
= cast(int)(mt
.basetype
.size(loc
) / mt
.elementType().size(loc
));
4518 Expression
visitSArray(TypeSArray mt
)
4520 static if (LOGDEFAULTINIT
)
4522 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt
.toChars(), isCfile
);
4524 if (mt
.next
.ty
== Tvoid
)
4525 return mt
.tuns8
.defaultInit(loc
, isCfile
);
4527 return mt
.next
.defaultInit(loc
, isCfile
);
4530 Expression
visitFunction(TypeFunction mt
)
4532 error(loc
, "`function` does not have a default initializer");
4533 return ErrorExp
.get();
4536 Expression
visitStruct(TypeStruct mt
)
4538 static if (LOGDEFAULTINIT
)
4540 printf("TypeStruct::defaultInit() '%s'\n", mt
.toChars());
4542 Declaration d
= new SymbolDeclaration(mt
.sym
.loc
, mt
.sym
);
4545 d
.storage_class |
= STC
.rvalue
; // https://issues.dlang.org/show_bug.cgi?id=14398
4546 return new VarExp(mt
.sym
.loc
, d
);
4549 Expression
visitEnum(TypeEnum mt
)
4551 static if (LOGDEFAULTINIT
)
4553 printf("TypeEnum::defaultInit() '%s'\n", mt
.toChars());
4555 // Initialize to first member of enum
4556 Expression e
= mt
.sym
.getDefaultValue(loc
);
4559 e
.type
= mt
; // to deal with const, immutable, etc., variants
4563 Expression
visitTuple(TypeTuple mt
)
4565 static if (LOGDEFAULTINIT
)
4567 printf("TypeTuple::defaultInit() '%s'\n", mt
.toChars());
4569 auto exps
= new Expressions(mt
.arguments
.length
);
4570 for (size_t i
= 0; i
< mt
.arguments
.length
; i
++)
4572 Parameter p
= (*mt
.arguments
)[i
];
4574 Expression e
= p
.type
.defaultInitLiteral(loc
);
4575 if (e
.op
== EXP
.error
)
4581 return new TupleExp(loc
, exps
);
4584 Expression
visitNoreturn(TypeNoreturn mt
)
4586 static if (LOGDEFAULTINIT
)
4588 printf("TypeNoreturn::defaultInit() '%s'\n", mt
.toChars());
4590 auto cond
= IntegerExp
.createBool(false);
4591 auto msg
= new StringExp(loc
, "Accessed expression of type `noreturn`");
4592 msg
.type
= Type
.tstring
;
4593 auto ae
= new AssertExp(loc
, cond
, msg
);
4600 case Tvector
: return visitVector (mt
.isTypeVector());
4601 case Tsarray
: return visitSArray (mt
.isTypeSArray());
4602 case Tfunction
: return visitFunction(mt
.isTypeFunction());
4603 case Tstruct
: return visitStruct (mt
.isTypeStruct());
4604 case Tenum
: return visitEnum (mt
.isTypeEnum());
4605 case Ttuple
: return visitTuple (mt
.isTypeTuple());
4607 case Tnull
: return new NullExp(Loc
.initial
, Type
.tnull
);
4609 case Terror
: return ErrorExp
.get();
4616 case Tclass
: return new NullExp(loc
, mt
);
4617 case Tnoreturn
: return visitNoreturn(mt
.isTypeNoreturn());
4619 default: return mt
.isTypeBasic() ?
4620 visitBasic(cast(TypeBasic
)mt
) :
4626 /**********************************************
4627 * Extract complex type from core.stdc.config
4629 * loc = for error messages
4631 * ty = a complex or imaginary type
4633 * Complex!float, Complex!double, Complex!real or null for error
4636 Type
getComplexLibraryType(const ref Loc loc
, Scope
* sc
, TY ty
)
4639 __gshared Type complex_float
;
4640 __gshared Type complex_double
;
4641 __gshared Type complex_real
;
4648 case Tcomplex32
: id
= Id
.c_complex_float
; pt
= &complex_float
; break;
4650 case Tcomplex64
: id
= Id
.c_complex_double
; pt
= &complex_double
; break;
4652 case Tcomplex80
: id
= Id
.c_complex_real
; pt
= &complex_real
; break;
4661 Module mConfig
= Module
.loadCoreStdcConfig();
4664 error(loc
, "`core.stdc.config` is required for complex numbers");
4668 Dsymbol s
= mConfig
.searchX(Loc
.initial
, sc
, id
, IgnorePrivateImports
);
4671 error(loc
, "`%s` not found in core.stdc.config", id
.toChars());
4675 if (auto t
= s
.getType())
4677 if (auto ts
= t
.toBasetype().isTypeStruct())
4683 if (auto sd
= s
.isStructDeclaration())
4689 error(loc
, "`%s` must be an alias for a complex struct", s
.toChars());
4693 /******************************* Private *****************************************/
4697 /* Helper function for `typeToExpression`. Contains common code
4698 * for TypeQualified derived classes.
4700 Expression
typeToExpressionHelper(TypeQualified t
, Expression e
, size_t i
= 0)
4702 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
4703 foreach (id
; t
.idents
[i
.. t
.idents
.length
])
4705 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
4707 final switch (id
.dyncast())
4710 case DYNCAST
.identifier
:
4711 e
= new DotIdExp(e
.loc
, e
, cast(Identifier
)id
);
4714 // ... '. name!(tiargs)'
4715 case DYNCAST
.dsymbol
:
4716 auto ti
= (cast(Dsymbol
)id
).isTemplateInstance();
4718 e
= new DotTemplateInstanceExp(e
.loc
, e
, ti
.name
, ti
.tiargs
);
4722 case DYNCAST
.type
: // https://issues.dlang.org/show_bug.cgi?id=1215
4723 e
= new ArrayExp(t
.loc
, e
, new TypeExp(t
.loc
, cast(Type
)id
));
4727 case DYNCAST
.expression
: // https://issues.dlang.org/show_bug.cgi?id=1215
4728 e
= new ArrayExp(t
.loc
, e
, cast(Expression
)id
);
4731 case DYNCAST
.object
:
4733 case DYNCAST
.parameter
:
4734 case DYNCAST
.statement
:
4735 case DYNCAST
.condition
:
4736 case DYNCAST
.templateparameter
:
4737 case DYNCAST
.initializer
:
4744 /**************************
4745 * This evaluates exp while setting length to be the number
4746 * of elements in the tuple t.
4748 Expression
semanticLength(Scope
* sc
, Type t
, Expression exp
)
4750 if (auto tt
= t
.isTypeTuple())
4752 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, tt
);
4753 sym
.parent
= sc
.scopesym
;
4755 sc
= sc
.startCTFE();
4756 exp
= exp
.expressionSemantic(sc
);
4757 exp
= resolveProperties(sc
, exp
);
4763 sc
= sc
.startCTFE();
4764 exp
= exp
.expressionSemantic(sc
);
4765 exp
= resolveProperties(sc
, exp
);
4771 Expression
semanticLength(Scope
* sc
, TupleDeclaration tup
, Expression exp
)
4773 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, tup
);
4774 sym
.parent
= sc
.scopesym
;
4777 sc
= sc
.startCTFE();
4778 exp
= exp
.expressionSemantic(sc
);
4779 exp
= resolveProperties(sc
, exp
);
4786 /************************************
4787 * Transitively search a type for all function types.
4788 * If any function types with parameters are found that have parameter identifiers
4789 * or default arguments, remove those and create a new type stripped of those.
4790 * This is used to determine the "canonical" version of a type which is useful for
4795 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
4796 * the same as t but with no parameter identifiers or default arguments.
4798 Type
stripDefaultArgs(Type t
)
4800 static Parameters
* stripParams(Parameters
* parameters
)
4802 static Parameter
stripParameter(Parameter p
)
4804 Type t
= stripDefaultArgs(p
.type
);
4805 return (t
!= p
.type || p
.defaultArg || p
.ident || p
.userAttribDecl
)
4806 ?
new Parameter(p
.loc
, p
.storageClass
, t
, null, null, null)
4812 foreach (i
, p
; *parameters
)
4814 Parameter ps
= stripParameter(p
);
4817 // Replace params with a copy we can modify
4818 Parameters
* nparams
= new Parameters(parameters
.length
);
4820 foreach (j
, ref np
; *nparams
)
4822 Parameter pj
= (*parameters
)[j
];
4829 Parameter nps
= stripParameter(pj
);
4830 np
= nps ? nps
: pj
;
4843 if (auto tf
= t
.isTypeFunction())
4845 Type tret
= stripDefaultArgs(tf
.next
);
4846 Parameters
* params
= stripParams(tf
.parameterList
.parameters
);
4847 if (tret
== tf
.next
&& params
== tf
.parameterList
.parameters
)
4849 TypeFunction tr
= tf
.copy().isTypeFunction();
4850 tr
.parameterList
.parameters
= params
;
4852 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
4855 else if (auto tt
= t
.isTypeTuple())
4857 Parameters
* args
= stripParams(tt
.arguments
);
4858 if (args
== tt
.arguments
)
4860 TypeTuple tr
= t
.copy().isTypeTuple();
4861 tr
.arguments
= args
;
4864 else if (t
.ty
== Tenum
)
4866 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
4871 Type tn
= t
.nextOf();
4872 Type n
= stripDefaultArgs(tn
);
4875 TypeNext tr
= cast(TypeNext
)t
.copy();
4881 /******************************
4882 * Get the value of the .max/.min property of `ed` as an Expression.
4883 * Lazily computes the value and caches it in maxval/minval.
4884 * Reports any errors.
4886 * ed = the EnumDeclaration being examined
4887 * loc = location to use for error messages
4888 * id = Id::max or Id::min
4890 * corresponding value of .max/.min
4892 Expression
getMaxMinValue(EnumDeclaration ed
, const ref Loc loc
, Identifier id
)
4894 //printf("EnumDeclaration::getMaxValue()\n");
4896 static Expression
pvalToResult(Expression e
, const ref Loc loc
)
4898 if (e
.op
!= EXP
.error
)
4906 Expression
* pval
= (id
== Id
.max
) ?
&ed
.maxval
: &ed
.minval
;
4908 Expression
errorReturn()
4910 *pval
= ErrorExp
.get();
4916 .error(loc
, "%s `%s` recursive definition of `.%s` property", ed
.kind
, ed
.toPrettyChars
, id
.toChars());
4917 return errorReturn();
4920 return pvalToResult(*pval
, loc
);
4923 dsymbolSemantic(ed
, ed
._scope
);
4925 return errorReturn();
4928 .error(loc
, "%s `%s` is opaque and has no `.%s`", ed
.kind
, ed
.toPrettyChars
, id
.toChars(), id
.toChars());
4929 return errorReturn();
4931 if (!(ed
.memtype
&& ed
.memtype
.isintegral()))
4933 .error(loc
, "%s `%s` has no `.%s` property because base type `%s` is not an integral type", ed
.kind
, ed
.toPrettyChars
, id
.toChars(),
4934 id
.toChars(), ed
.memtype ? ed
.memtype
.toChars() : "");
4935 return errorReturn();
4939 for (size_t i
= 0; i
< ed
.members
.length
; i
++)
4941 EnumMember em
= (*ed
.members
)[i
].isEnumMember();
4950 if (em
.semanticRun
< PASS
.semanticdone
)
4952 .error(em
.loc
, "%s `%s` is forward referenced looking for `.%s`", em
.kind
, em
.toPrettyChars
, id
.toChars());
4964 /* In order to work successfully with UDTs,
4965 * build expressions to do the comparisons,
4966 * and let the semantic analyzer and constant
4967 * folder give us the result.
4974 Expression e
= em
.value
;
4975 Expression ec
= new CmpExp(id
== Id
.max ? EXP
.greaterThan
: EXP
.lessThan
, em
.loc
, e
, *pval
);
4977 ec
= ec
.expressionSemantic(em
._scope
);
4979 ec
= ec
.ctfeInterpret();
4980 if (ec
.op
== EXP
.error
)
4989 return ed
.errors ?
errorReturn() : pvalToResult(*pval
, loc
);
4992 /******************************************
4993 * Compile the MixinType, returning the type or expression AST.
4995 * Doesn't run semantic() on the returned object.
4997 * tm = mixin to compile as a type or expression
4998 * loc = location for error messages
5001 * null if error, else RootObject AST as parsed
5003 RootObject
compileTypeMixin(TypeMixin tm
, ref const Loc loc
, Scope
* sc
)
5006 if (expressionsToString(buf
, sc
, tm
.exps
))
5009 const errors
= global
.errors
;
5010 const len
= buf
.length
;
5012 const str = buf
.extractSlice()[0 .. len
];
5013 const bool doUnittests
= global
.params
.parsingUnittestsRequired();
5014 auto locm
= adjustLocForMixin(str, loc
, global
.params
.mixinOut
);
5015 scope p
= new Parser
!ASTCodegen(locm
, sc
._module
, str, false, global
.errorSink
, &global
.compileEnv
, doUnittests
);
5016 p
.transitionIn
= global
.params
.v
.vin
;
5018 //printf("p.loc.linnum = %d\n", p.loc.linnum);
5020 auto o
= p
.parseTypeOrAssignExp(TOK
.endOfFile
);
5021 if (errors
!= global
.errors
)
5023 assert(global
.errors
!= errors
); // should have caught all these cases
5026 if (p
.token
.value
!= TOK
.endOfFile
)
5028 .error(loc
, "unexpected token `%s` after type `%s`",
5029 p
.token
.toChars(), o
.toChars());
5030 .errorSupplemental(loc
, "while parsing string mixin type `%s`",