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
;
35 import dmd
.dsymbolsem
;
39 import dmd
.expression
;
40 import dmd
.expressionsem
;
45 import dmd
.identifier
;
56 import dmd
.root
.complex
;
57 import dmd
.root
.ctfloat
;
59 import dmd
.common
.outbuffer
;
60 import dmd
.root
.rootobject
;
61 import dmd
.root
.string
;
62 import dmd
.root
.stringtable
;
65 import dmd
.sideeffect
;
69 /*************************************
70 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
71 * Setting one of pe/pt/ps.
73 * loc = location for error messages
75 * s = symbol being indexed - could be a tuple, could be an expression
76 * pe = set if s[oindex] is an Expression, otherwise null
77 * pt = set if s[oindex] is a Type, otherwise null
78 * ps = set if s[oindex] is a Dsymbol, otherwise null
79 * oindex = index into s
81 private void resolveTupleIndex(const ref Loc loc
, Scope
* sc
, Dsymbol s
, out Expression pe
, out Type pt
, out Dsymbol ps
, RootObject oindex
)
83 auto tup
= s
.isTupleDeclaration();
85 auto eindex
= isExpression(oindex
);
86 auto tindex
= isType(oindex
);
87 auto sindex
= isDsymbol(oindex
);
91 // It's really an index expression
93 eindex
= new TypeExp(loc
, tindex
);
95 eindex
= symbolToExp(sindex
, loc
, sc
, false);
96 Expression e
= new IndexExp(loc
, symbolToExp(s
, loc
, sc
, false), eindex
);
97 e
= e
.expressionSemantic(sc
);
98 resolveExp(e
, pt
, pe
, ps
);
102 // Convert oindex to Expression, then try to resolve to constant.
104 tindex
.resolve(loc
, sc
, eindex
, tindex
, sindex
);
106 eindex
= symbolToExp(sindex
, loc
, sc
, false);
109 .error(loc
, "index `%s` is not an expression", oindex
.toChars());
114 eindex
= semanticLength(sc
, tup
, eindex
);
115 eindex
= eindex
.ctfeInterpret();
116 if (eindex
.op
== EXP
.error
)
121 const(uinteger_t
) d
= eindex
.toUInteger();
122 if (d
>= tup
.objects
.length
)
124 .error(loc
, "tuple index `%llu` out of bounds `[0 .. %llu]`", d
, cast(ulong)tup
.objects
.length
);
129 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
131 if (auto t
= isType(o
))
132 pt
= t
.typeSemantic(loc
, sc
);
133 if (auto e
= isExpression(o
))
134 resolveExp(e
, pt
, pe
, ps
);
137 /*************************************
138 * Takes an array of Identifiers and figures out if
139 * it represents a Type, Expression, or Dsymbol.
141 * mt = array of identifiers
142 * loc = location for error messages
144 * s = symbol to start search at
146 * pe = set if expression otherwise null
147 * pt = set if type otherwise null
148 * ps = set if symbol otherwise null
149 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
151 private void resolveHelper(TypeQualified mt
, const ref Loc loc
, Scope
* sc
, Dsymbol s
, Dsymbol scopesym
,
152 out Expression pe
, out Type pt
, out Dsymbol ps
, bool intypeid
= false)
156 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc
, mt
.toChars());
158 printf("\tscopesym = '%s'\n", scopesym
.toChars());
163 /* Look for what user might have intended
165 const p
= mt
.mutableOf().unSharedOf().toChars();
166 auto id
= Identifier
.idPool(p
, cast(uint)strlen(p
));
167 if (const n
= importHint(id
.toString()))
168 error(loc
, "`%s` is not defined, perhaps `import %.*s;` ?", p
, cast(int)n
.length
, n
.ptr
);
169 else if (auto s2
= sc
.search_correct(id
))
170 error(loc
, "undefined identifier `%s`, did you mean %s `%s`?", p
, s2
.kind(), s2
.toChars());
171 else if (const q
= Scope
.search_correct_C(id
))
172 error(loc
, "undefined identifier `%s`, did you mean `%s`?", p
, q
);
173 else if ((id
== Id
.This
&& sc
.getStructClassScope()) ||
174 (id
== Id
._super
&& sc
.getClassScope()))
175 error(loc
, "undefined identifier `%s`, did you mean `typeof(%s)`?", p
, p
);
177 error(loc
, "undefined identifier `%s`", p
);
183 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
184 Declaration d
= s
.isDeclaration();
185 if (d
&& (d
.storage_class
& STC
.templateparameter
))
189 // check for deprecated or disabled aliases
190 // functions are checked after overloading
191 // templates are checked after matching constraints
192 if (!s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
193 s
.checkDeprecated(loc
, sc
);
195 d
.checkDisabled(loc
, sc
, true);
198 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
199 for (size_t i
= 0; i
< mt
.idents
.length
; i
++)
201 RootObject id
= mt
.idents
[i
];
202 switch (id
.dyncast()) with (DYNCAST
)
209 resolveTupleIndex(loc
, sc
, s
, ex
, tx
, sx
, id
);
216 ex
= new TypeExp(loc
, tx
);
219 ex
= typeToExpressionHelper(mt
, ex
, i
+ 1);
220 ex
= ex
.expressionSemantic(sc
);
221 resolveExp(ex
, pt
, pe
, ps
);
227 Type t
= s
.getType(); // type symbol, type alias, or type tuple?
228 uint errorsave
= global
.errors
;
229 int flags
= t
is null ? SearchLocalsOnly
: IgnorePrivateImports
;
231 Dsymbol sm
= s
.searchX(loc
, sc
, id
, flags
);
234 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, sm
))
236 .error(loc
, "`%s` is not visible from module `%s`", sm
.toPrettyChars(), sc
._module
.toChars());
239 // Same check as in dotIdSemanticProp(DotIdExp)
240 else if (sm
.isPackage() && checkAccess(sc
, sm
.isPackage()))
242 // @@@DEPRECATED_2.106@@@
243 // Should be an error in 2.106. Just remove the deprecation call
244 // and uncomment the null assignment
245 deprecation(loc
, "%s %s is not accessible here, perhaps add 'static import %s;'", sm
.kind(), sm
.toPrettyChars(), sm
.toPrettyChars());
249 if (global
.errors
!= errorsave
)
258 VarDeclaration v
= s
.isVarDeclaration();
259 FuncDeclaration f
= s
.isFuncDeclaration();
260 if (intypeid ||
!v
&& !f
)
261 e
= symbolToExp(s
, loc
, sc
, true);
263 e
= new VarExp(loc
, s
.isDeclaration(), true);
265 e
= typeToExpressionHelper(mt
, e
, i
);
266 e
= e
.expressionSemantic(sc
);
267 resolveExp(e
, pt
, pe
, ps
);
270 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
271 if (intypeid
&& !t
&& sm
&& sm
.needThis())
274 if (VarDeclaration v
= s
.isVarDeclaration())
276 // https://issues.dlang.org/show_bug.cgi?id=19913
277 // v.type would be null if it is a forward referenced member.
279 v
.dsymbolSemantic(sc
);
280 if (v
.storage_class
& (STC
.const_ | STC
.immutable_ | STC
.manifest
) ||
281 v
.type
.isConst() || v
.type
.isImmutable())
283 // https://issues.dlang.org/show_bug.cgi?id=13087
284 // this.field is not constant always
285 if (!v
.isThisDeclaration())
296 if (auto em
= s
.isEnumMember())
298 // It's not a type, it's an expression
299 pe
= em
.getVarExp(loc
, sc
);
302 if (auto v
= s
.isVarDeclaration())
304 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
305 * because some variables used in type context need to prevent lowering
306 * to a literal or contextful expression. For example:
308 * enum a = 1; alias b = a;
309 * template X(alias e){ alias v = e; } alias x = X!(1);
310 * struct S { int v; alias w = v; }
311 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
312 * // because getDsymbol() need to work in AliasDeclaration::semantic().
315 !v
.type
.deco
&& v
.inuse
)
317 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
318 error(loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
320 error(loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
324 if (v
.type
.ty
== Terror
)
327 pe
= new VarExp(loc
, v
);
330 if (auto fld = s
.isFuncLiteralDeclaration())
332 //printf("'%s' is a function literal\n", fld.toChars());
333 auto e
= new FuncExp(loc
, fld);
334 pe
= e
.expressionSemantic(sc
);
339 if (FuncDeclaration fd
= s
.isFuncDeclaration())
341 pe
= new DsymbolExp(loc
, fd
);
356 if (auto ti
= t
.isTypeInstance())
357 if (ti
!= mt
&& !ti
.deco
)
359 if (!ti
.tempinst
.errors
)
360 error(loc
, "forward reference to `%s`", ti
.toChars());
371 /******************************************
372 * We've mistakenly parsed `t` as a type.
373 * Redo `t` as an Expression only if there are no type modifiers.
377 * t redone as Expression, null if cannot
379 Expression
typeToExpression(Type t
)
381 static Expression
visitSArray(TypeSArray t
)
383 if (auto e
= t
.next
.typeToExpression())
384 return new ArrayExp(t
.dim
.loc
, e
, t
.dim
);
388 static Expression
visitAArray(TypeAArray t
)
390 if (auto e
= t
.next
.typeToExpression())
392 if (auto ei
= t
.index
.typeToExpression())
393 return new ArrayExp(t
.loc
, e
, ei
);
398 static Expression
visitIdentifier(TypeIdentifier t
)
400 return typeToExpressionHelper(t
, new IdentifierExp(t
.loc
, t
.ident
));
403 static Expression
visitInstance(TypeInstance t
)
405 return typeToExpressionHelper(t
, new ScopeExp(t
.loc
, t
.tempinst
));
408 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
409 static Expression
visitMixin(TypeMixin t
)
411 return new TypeExp(t
.loc
, t
);
418 case Tsarray
: return visitSArray(t
.isTypeSArray());
419 case Taarray
: return visitAArray(t
.isTypeAArray());
420 case Tident
: return visitIdentifier(t
.isTypeIdentifier());
421 case Tinstance
: return visitInstance(t
.isTypeInstance());
422 case Tmixin
: return visitMixin(t
.isTypeMixin());
423 default: return null;
427 /******************************************
428 * Perform semantic analysis on a type.
430 * type = Type AST node
431 * loc = the location of the type
434 * `Type` with completed semantic analysis, `Terror` if errors
437 extern(C
++) Type
typeSemantic(Type type
, const ref Loc loc
, Scope
* sc
)
444 Type
visitType(Type t
)
446 // @@@DEPRECATED_2.110@@@
447 // Use of `cent` and `ucent` has always been an error.
448 // Starting from 2.100, recommend core.int128 as a replace for the
449 // lack of compiler support.
450 if (t
.ty
== Tint128 || t
.ty
== Tuns128
)
452 .error(loc
, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
459 Type
visitVector(TypeVector mtype
)
461 const errors
= global
.errors
;
462 mtype
.basetype
= mtype
.basetype
.typeSemantic(loc
, sc
);
463 if (errors
!= global
.errors
)
465 mtype
.basetype
= mtype
.basetype
.toBasetype().mutableOf();
466 if (mtype
.basetype
.ty
!= Tsarray
)
468 .error(loc
, "T in __vector(T) must be a static array, not `%s`", mtype
.basetype
.toChars());
471 TypeSArray t
= mtype
.basetype
.isTypeSArray();
472 const sz
= cast(int)t
.size(loc
);
473 final switch (target
.isVectorTypeSupported(sz
, t
.nextOf()))
481 .error(loc
, "SIMD vector types not supported on this platform");
486 .error(loc
, "vector type `%s` is not supported on this platform", mtype
.toChars());
491 .error(loc
, "%d byte vector type `%s` is not supported on this platform", sz
, mtype
.toChars());
497 Type
visitSArray(TypeSArray mtype
)
499 //printf("TypeSArray::semantic() %s\n", toChars());
503 mtype
.next
.resolve(loc
, sc
, e
, t
, s
);
505 if (auto tup
= s ? s
.isTupleDeclaration() : null)
507 mtype
.dim
= semanticLength(sc
, tup
, mtype
.dim
);
508 mtype
.dim
= mtype
.dim
.ctfeInterpret();
509 if (mtype
.dim
.op
== EXP
.error
)
512 uinteger_t d
= mtype
.dim
.toUInteger();
513 if (d
>= tup
.objects
.length
)
515 .error(loc
, "tuple index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d
, cast(ulong)tup
.objects
.length
);
519 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
520 if (o
.dyncast() != DYNCAST
.type
)
522 .error(loc
, "`%s` is not a type", mtype
.toChars());
525 return (cast(Type
)o
).addMod(mtype
.mod
);
528 if (t
&& t
.ty
== Terror
)
531 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
535 Type tbn
= tn
.toBasetype();
538 auto errors
= global
.errors
;
539 mtype
.dim
= semanticLength(sc
, tbn
, mtype
.dim
);
540 mtype
.dim
= mtype
.dim
.implicitCastTo(sc
, Type
.tsize_t
);
541 if (errors
!= global
.errors
)
544 mtype
.dim
= mtype
.dim
.optimize(WANTvalue
);
545 mtype
.dim
= mtype
.dim
.ctfeInterpret();
546 if (mtype
.dim
.op
== EXP
.error
)
549 errors
= global
.errors
;
550 dinteger_t d1
= mtype
.dim
.toInteger();
551 if (errors
!= global
.errors
)
554 mtype
.dim
= mtype
.dim
.implicitCastTo(sc
, Type
.tsize_t
);
555 mtype
.dim
= mtype
.dim
.optimize(WANTvalue
);
556 if (mtype
.dim
.op
== EXP
.error
)
559 errors
= global
.errors
;
560 dinteger_t d2
= mtype
.dim
.toInteger();
561 if (errors
!= global
.errors
)
564 if (mtype
.dim
.op
== EXP
.error
)
569 .error(loc
, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
570 mtype
.toChars(), cast(ulong)tbn
.size(loc
), cast(ulong)d1
, target
.maxStaticDataSize
);
575 return overflowError();
577 Type tbx
= tbn
.baseElemOf();
578 if (tbx
.ty
== Tstruct
&& !tbx
.isTypeStruct().sym
.members ||
579 tbx
.ty
== Tenum
&& !tbx
.isTypeEnum().sym
.members
)
581 /* To avoid meaningless error message, skip the total size limit check
582 * when the bottom of element type is opaque.
585 else if (tbn
.isTypeBasic() ||
586 tbn
.ty
== Tpointer ||
590 (tbn
.ty
== Tstruct
&& tbn
.isTypeStruct().sym
.sizeok
== Sizeok
.done
) ||
593 /* Only do this for types that don't need to have semantic()
594 * run on them for the size, since they may be forward referenced.
596 bool overflow
= false;
597 if (mulu(tbn
.size(loc
), d2
, overflow
) > target
.maxStaticDataSize || overflow
)
598 return overflowError();
605 // Index the tuple to get the type
607 TypeTuple tt
= tbn
.isTypeTuple();
608 uinteger_t d
= mtype
.dim
.toUInteger();
609 if (d
>= tt
.arguments
.length
)
611 .error(loc
, "tuple index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d
, cast(ulong)tt
.arguments
.length
);
614 Type telem
= (*tt
.arguments
)[cast(size_t
)d
].type
;
615 return telem
.addMod(mtype
.mod
);
620 .error(loc
, "cannot have array of `%s`", tbn
.toChars());
628 .error(loc
, "cannot have array of scope `%s`", tbn
.toChars());
632 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
633 * and const(T)[3] become const(T[3])
637 return mtype
.addMod(tn
.mod
).merge();
640 Type
visitDArray(TypeDArray mtype
)
642 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
643 Type tbn
= tn
.toBasetype();
651 .error(loc
, "cannot have array of `%s`", tbn
.toChars());
662 .error(loc
, "cannot have array of scope `%s`", tn
.toChars());
670 Type
visitAArray(TypeAArray mtype
)
672 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
682 // Deal with the case where we thought the index was a type, but
683 // in reality it was an expression.
684 if (mtype
.index
.ty
== Tident || mtype
.index
.ty
== Tinstance || mtype
.index
.ty
== Tsarray || mtype
.index
.ty
== Ttypeof || mtype
.index
.ty
== Treturn || mtype
.index
.ty
== Tmixin
)
689 mtype
.index
.resolve(loc
, sc
, e
, t
, s
);
691 // https://issues.dlang.org/show_bug.cgi?id=15478
693 e
= symbolToExp(s
, loc
, sc
, false);
697 // It was an expression -
698 // Rewrite as a static array
699 auto tsa
= new TypeSArray(mtype
.next
, e
);
700 return tsa
.typeSemantic(loc
, sc
);
703 mtype
.index
= t
.typeSemantic(loc
, sc
);
706 .error(loc
, "index is not a type or an expression");
711 mtype
.index
= mtype
.index
.typeSemantic(loc
, sc
);
712 mtype
.index
= mtype
.index
.merge2();
714 if (mtype
.index
.nextOf() && !mtype
.index
.nextOf().isImmutable())
716 mtype
.index
= mtype
.index
.constOf().mutableOf();
719 printf("index is %p %s\n", mtype
.index
, mtype
.index
.toChars());
721 printf("index.mod = x%x\n", mtype
.index
.mod
);
722 printf("index.ito = x%p\n", mtype
.index
.getMcache().ito
);
723 if (mtype
.index
.getMcache().ito
)
725 printf("index.ito.mod = x%x\n", mtype
.index
.getMcache().ito
.mod
);
726 printf("index.ito.ito = x%p\n", mtype
.index
.getMcache().ito
.getMcache().ito
);
731 switch (mtype
.index
.toBasetype().ty
)
737 .error(loc
, "cannot have associative array key of `%s`", mtype
.index
.toBasetype().toChars());
745 Type tbase
= mtype
.index
.baseElemOf();
746 while (tbase
.ty
== Tarray
)
747 tbase
= tbase
.nextOf().baseElemOf();
748 if (auto ts
= tbase
.isTypeStruct())
750 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
752 StructDeclaration sd
= ts
.sym
;
753 if (sd
.semanticRun
< PASS
.semanticdone
)
754 sd
.dsymbolSemantic(null);
756 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
757 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
759 if (sd
.xeq
&& sd
.xeq
.isGenerated() && sd
.xeq
._scope
&& sd
.xeq
.semanticRun
< PASS
.semantic3done
)
761 uint errors
= global
.startGagging();
762 sd
.xeq
.semantic3(sd
.xeq
._scope
);
763 if (global
.endGagging(errors
))
768 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
769 const(char)* s
= (mtype
.index
.toBasetype().ty
!= Tstruct
) ?
"bottom of " : "";
772 // If sd.xhash != NULL:
773 // sd or its fields have user-defined toHash.
774 // AA assumes that its result is consistent with bitwise equality.
776 // bitwise equality & hashing
778 else if (sd
.xeq
== sd
.xerreq
)
780 if (search_function(sd
, Id
.eq
))
782 .error(loc
, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s
, sd
.toChars(), sd
.toChars());
786 .error(loc
, "%sAA key type `%s` does not support const equality", s
, sd
.toChars());
792 if (search_function(sd
, Id
.eq
))
794 .error(loc
, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s
, sd
.toChars());
798 .error(loc
, "%sAA key type `%s` supports const equality but doesn't support const hashing", s
, sd
.toChars());
804 // defined equality & hashing
805 assert(sd
.xeq
&& sd
.xhash
);
807 /* xeq and xhash may be implicitly defined by compiler. For example:
808 * struct S { int[] arr; }
809 * With 'arr' field equality and hashing, compiler will implicitly
810 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
814 else if (tbase
.ty
== Tclass
&& !tbase
.isTypeClass().sym
.isInterfaceDeclaration())
816 ClassDeclaration cd
= tbase
.isTypeClass().sym
;
817 if (cd
.semanticRun
< PASS
.semanticdone
)
818 cd
.dsymbolSemantic(null);
820 if (!ClassDeclaration
.object
)
822 .error(Loc
.initial
, "missing or corrupt object.d");
826 __gshared FuncDeclaration feq
= null;
827 __gshared FuncDeclaration fcmp
= null;
828 __gshared FuncDeclaration fhash
= null;
830 feq
= search_function(ClassDeclaration
.object
, Id
.eq
).isFuncDeclaration();
832 fcmp
= search_function(ClassDeclaration
.object
, Id
.cmp).isFuncDeclaration();
834 fhash
= search_function(ClassDeclaration
.object
, Id
.tohash
).isFuncDeclaration();
835 assert(fcmp
&& feq
&& fhash
);
837 if (feq
.vtblIndex
< cd
.vtbl
.length
&& cd
.vtbl
[feq
.vtblIndex
] == feq
)
841 if (fcmp
.vtblIndex
< cd
.vtbl
.length
&& cd
.vtbl
[fcmp
.vtblIndex
] != fcmp
)
843 const(char)* s
= (mtype
.index
.toBasetype().ty
!= Tclass
) ?
"bottom of " : "";
844 .error(loc
, "%sAA key type `%s` now requires equality rather than comparison", s
, cd
.toChars());
845 errorSupplemental(loc
, "Please override `Object.opEquals` and `Object.toHash`.");
850 mtype
.next
= mtype
.next
.typeSemantic(loc
, sc
).merge2();
853 switch (mtype
.next
.toBasetype().ty
)
859 .error(loc
, "cannot have associative array of `%s`", mtype
.next
.toChars());
866 if (mtype
.next
.isscope())
868 .error(loc
, "cannot have array of scope `%s`", mtype
.next
.toChars());
874 Type
visitPointer(TypePointer mtype
)
876 //printf("TypePointer::semantic() %s\n", toChars());
881 Type n
= mtype
.next
.typeSemantic(loc
, sc
);
882 switch (n
.toBasetype().ty
)
885 .error(loc
, "cannot have pointer to `%s`", n
.toChars());
897 if (mtype
.next
.ty
!= Tfunction
)
908 mtype
.deco
= merge(mtype
).deco
;
909 /* Don't return merge(), because arg identifiers and default args
911 * even though the types match
917 Type
visitReference(TypeReference mtype
)
919 //printf("TypeReference::semantic()\n");
920 Type n
= mtype
.next
.typeSemantic(loc
, sc
);
928 Type
visitFunction(TypeFunction mtype
)
930 if (mtype
.deco
) // if semantic() already run
932 //printf("already done\n");
935 //printf("TypeFunction::semantic() this = %p\n", mtype);
936 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
940 if (mtype
.inuse
> global
.recursionLimit
)
943 .error(loc
, "recursive type");
947 /* Copy in order to not mess up original.
948 * This can produce redundant copies if inferring return type,
949 * as semantic() will get called again on this.
951 TypeFunction tf
= mtype
.copy().toTypeFunction();
952 if (mtype
.parameterList
.parameters
)
954 tf
.parameterList
.parameters
= mtype
.parameterList
.parameters
.copy();
955 for (size_t i
= 0; i
< mtype
.parameterList
.parameters
.length
; i
++)
957 Parameter p
= cast(Parameter
)mem
.xmalloc(__traits(classInstanceSize
, Parameter
));
958 memcpy(cast(void*)p
, cast(void*)(*mtype
.parameterList
.parameters
)[i
], __traits(classInstanceSize
, Parameter
));
959 (*tf
.parameterList
.parameters
)[i
] = p
;
963 if (sc
.stc & STC
.pure_
)
964 tf
.purity
= PURE
.fwdref
;
965 if (sc
.stc & STC
.nothrow_
)
967 if (sc
.stc & STC
.nogc
)
969 if (sc
.stc & STC
.ref_
)
971 if (sc
.stc & STC
.return_
)
973 if (sc
.stc & STC
.returnScope
)
974 tf
.isreturnscope
= true;
975 if (sc
.stc & STC
.returninferred
)
976 tf
.isreturninferred
= true;
977 if (sc
.stc & STC
.scope_
)
978 tf
.isScopeQual
= true;
979 if (sc
.stc & STC
.scopeinferred
)
980 tf
.isscopeinferred
= true;
982 // if (tf.isreturn && !tf.isref)
983 // tf.isScopeQual = true; // return by itself means 'return scope'
985 if (tf
.trust
== TRUST
.default_
)
987 if (sc
.stc & STC
.safe
)
988 tf
.trust
= TRUST
.safe
;
989 else if (sc
.stc & STC
.system
)
990 tf
.trust
= TRUST
.system
;
991 else if (sc
.stc & STC
.trusted
)
992 tf
.trust
= TRUST
.trusted
;
995 if (sc
.stc & STC
.property
)
996 tf
.isproperty
= true;
997 if (sc
.stc & STC
.live
)
1000 tf
.linkage
= sc
.linkage
;
1001 if (tf
.linkage
== LINK
.system
)
1002 tf
.linkage
= target
.systemLinkage();
1006 /* If the parent is @safe, then this function defaults to safe
1008 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1009 * to be inferred first.
1011 if (tf
.trust
== TRUST
.default_
)
1012 for (Dsymbol p
= sc
.func
; p
; p
= p
.toParent2())
1014 FuncDeclaration fd
= p
.isFuncDeclaration();
1017 if (fd
.isSafeBypassingInference())
1018 tf
.trust
= TRUST
.safe
; // default to @safe
1024 bool wildreturn
= false;
1028 sc
.stc &= ~(STC
.TYPECTOR | STC
.FUNCATTR
);
1029 tf
.next
= tf
.next
.typeSemantic(loc
, sc
);
1031 errors |
= tf
.checkRetType(loc
);
1032 if (tf
.next
.isscope() && !tf
.isctor
)
1034 .error(loc
, "functions cannot return `scope %s`", tf
.next
.toChars());
1037 if (tf
.next
.hasWild())
1040 if (tf
.isreturn
&& !tf
.isref
&& !tf
.next
.hasPointers())
1042 tf
.isreturn
= false;
1046 /// Perform semantic on the default argument to a parameter
1047 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1048 /// Returns `false` whether an error was encountered.
1049 static bool defaultArgSemantic (ref Parameter fparam
, Scope
* sc
)
1051 Expression e
= fparam
.defaultArg
;
1052 const isRefOrOut
= fparam
.isReference();
1053 const isAuto
= fparam
.storageClass
& (STC
.auto_ | STC
.autoref
);
1054 if (isRefOrOut
&& !isAuto
)
1056 e
= e
.expressionSemantic(sc
);
1057 e
= resolveProperties(sc
, e
);
1061 e
= inferType(e
, fparam
.type
);
1062 Initializer iz
= new ExpInitializer(e
.loc
, e
);
1063 iz
= iz
.initializerSemantic(sc
, fparam
.type
, INITnointerpret
);
1064 e
= iz
.initializerToExpression();
1066 if (e
.op
== EXP
.function_
) // https://issues.dlang.org/show_bug.cgi?id=4820
1068 FuncExp fe
= e
.isFuncExp();
1069 // Replace function literal with a function symbol,
1070 // since default arg expression must be copied when used
1071 // and copying the literal itself is wrong.
1072 e
= new VarExp(e
.loc
, fe
.fd
, false);
1073 e
= new AddrExp(e
.loc
, e
);
1074 e
= e
.expressionSemantic(sc
);
1076 if (isRefOrOut
&& (!isAuto || e
.isLvalue())
1077 && !MODimplicitConv(e
.type
.mod
, fparam
.type
.mod
))
1079 const(char)* errTxt
= fparam
.storageClass
& STC
.ref_ ?
"ref" : "out";
1080 .error(e
.loc
, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1081 e
.toChars(), e
.type
.toChars(), errTxt
, fparam
.type
.toChars(), fparam
.toChars());
1083 e
= e
.implicitCastTo(sc
, fparam
.type
);
1085 // default arg must be an lvalue
1086 if (isRefOrOut
&& !isAuto
&&
1087 !(global
.params
.previewIn
&& (fparam
.storageClass
& STC
.in_
)) &&
1088 global
.params
.rvalueRefParam
!= FeatureState
.enabled
)
1089 e
= e
.toLvalue(sc
, e
);
1091 fparam
.defaultArg
= e
;
1092 return (e
.op
!= EXP
.error
);
1095 ubyte wildparams
= 0;
1096 if (tf
.parameterList
.parameters
)
1098 /* Create a scope for evaluating the default arguments for the parameters
1100 Scope
* argsc
= sc
.push();
1101 argsc
.stc = 0; // don't inherit storage class
1102 argsc
.visibility
= Visibility(Visibility
.Kind
.public_
);
1105 size_t dim
= tf
.parameterList
.length
;
1106 for (size_t i
= 0; i
< dim
; i
++)
1108 Parameter fparam
= tf
.parameterList
[i
];
1109 fparam
.storageClass |
= STC
.parameter
;
1111 fparam
.type
= fparam
.type
.typeSemantic(loc
, argsc
);
1114 if (fparam
.type
.ty
== Terror
)
1120 fparam
.type
= fparam
.type
.addStorageClass(fparam
.storageClass
);
1122 if (fparam
.storageClass
& (STC
.auto_ | STC
.alias_ | STC
.static_
))
1128 fparam
.type
= fparam
.type
.cAdjustParamType(sc
); // adjust C array and function parameter types
1130 Type t
= fparam
.type
.toBasetype();
1132 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
1135 if (auto tt
= t
.isTypeTuple())
1137 /* TypeFunction::parameter also is used as the storage of
1138 * Parameter objects for FuncDeclaration. So we should copy
1139 * the elements of TypeTuple::arguments to avoid unintended
1140 * sharing of Parameter object among other functions.
1142 if (tt
.arguments
&& tt
.arguments
.length
)
1144 /* Propagate additional storage class from tuple parameters to their
1145 * element-parameters.
1146 * Make a copy, as original may be referenced elsewhere.
1148 size_t tdim
= tt
.arguments
.length
;
1149 auto newparams
= new Parameters(tdim
);
1150 for (size_t j
= 0; j
< tdim
; j
++)
1152 Parameter narg
= (*tt
.arguments
)[j
];
1154 // https://issues.dlang.org/show_bug.cgi?id=12744
1155 // If the storage classes of narg
1156 // conflict with the ones in fparam, it's ignored.
1157 StorageClass
stc = fparam
.storageClass | narg
.storageClass
;
1158 StorageClass stc1
= fparam
.storageClass
& (STC
.ref_ | STC
.out_ | STC
.lazy_
);
1159 StorageClass stc2
= narg
.storageClass
& (STC
.ref_ | STC
.out_ | STC
.lazy_
);
1160 if (stc1
&& stc2
&& stc1
!= stc2
)
1162 OutBuffer buf1
; stcToBuffer(&buf1
, stc1 |
((stc1
& STC
.ref_
) ?
(fparam
.storageClass
& STC
.auto_
) : 0));
1163 OutBuffer buf2
; stcToBuffer(&buf2
, stc2
);
1165 .error(loc
, "incompatible parameter storage classes `%s` and `%s`",
1166 buf1
.peekChars(), buf2
.peekChars());
1168 stc = stc1 |
(stc & ~(STC
.ref_ | STC
.out_ | STC
.lazy_
));
1170 (*newparams
)[j
] = new Parameter(
1171 stc, narg
.type
, narg
.ident
, narg
.defaultArg
, narg
.userAttribDecl
);
1173 fparam
.type
= new TypeTuple(newparams
);
1174 fparam
.type
= fparam
.type
.typeSemantic(loc
, argsc
);
1176 fparam
.storageClass
= STC
.parameter
;
1178 /* Reset number of parameters, and back up one to do this fparam again,
1179 * now that it is a tuple
1181 dim
= tf
.parameterList
.length
;
1186 // -preview=in: Always add `ref` when used with `extern(C++)` functions
1187 // Done here to allow passing opaque types with `in`
1188 if (global
.params
.previewIn
&& (fparam
.storageClass
& (STC
.in_ | STC
.ref_
)) == STC
.in_
)
1193 fparam
.storageClass |
= STC
.ref_
;
1195 case LINK
.default_
, LINK
.d
:
1198 .error(loc
, "cannot use `in` parameters with `extern(%s)` functions",
1199 linkageToChars(tf
.linkage
));
1200 .errorSupplemental(loc
, "parameter `%s` declared as `in` here", fparam
.toChars());
1205 if (t
.ty
== Tfunction
)
1207 .error(loc
, "cannot have parameter of function type `%s`", fparam
.type
.toChars());
1210 else if (!fparam
.isReference() &&
1211 (t
.ty
== Tstruct || t
.ty
== Tsarray || t
.ty
== Tenum
))
1213 Type tb2
= t
.baseElemOf();
1214 if (tb2
.ty
== Tstruct
&& !tb2
.isTypeStruct().sym
.members ||
1215 tb2
.ty
== Tenum
&& !tb2
.isTypeEnum().sym
.memtype
)
1217 if (global
.params
.previewIn
&& (fparam
.storageClass
& STC
.in_
))
1219 .error(loc
, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
1220 fparam
.toChars(), fparam
.type
.toChars());
1223 .error(loc
, "cannot have parameter of opaque type `%s` by value",
1224 fparam
.type
.toChars());
1228 else if (!fparam
.isLazy() && t
.ty
== Tvoid
)
1230 .error(loc
, "cannot have parameter of type `%s`", fparam
.type
.toChars());
1234 const bool isTypesafeVariadic
= i
+ 1 == dim
&&
1235 tf
.parameterList
.varargs
== VarArg
.typesafe
&&
1236 (t
.isTypeDArray() || t
.isTypeClass());
1237 if (isTypesafeVariadic
)
1239 /* typesafe variadic arguments are constructed on the stack, so must be `scope`
1241 fparam
.storageClass |
= STC
.scope_ | STC
.scopeinferred
;
1244 if (fparam
.storageClass
& STC
.return_
)
1246 if (!fparam
.isReference())
1248 if (!(fparam
.storageClass
& STC
.scope_
))
1249 fparam
.storageClass |
= STC
.scope_ | STC
.scopeinferred
; // 'return' implies 'scope'
1253 else if (tf
.next
&& !tf
.next
.hasPointers() && tf
.next
.toBasetype().ty
!= Tvoid
)
1255 fparam
.storageClass
&= ~STC
.return_
; // https://issues.dlang.org/show_bug.cgi?id=18963
1259 if (isTypesafeVariadic
)
1261 /* This is because they can be constructed on the stack
1262 * https://dlang.org/spec/function.html#typesafe_variadic_functions
1264 .error(loc
, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
1265 fparam
.ident ? fparam
.ident
.toChars() : "", t
.toChars());
1270 if (fparam
.storageClass
& STC
.out_
)
1272 if (ubyte m
= fparam
.type
.mod
& (MODFlags
.immutable_ | MODFlags
.const_ | MODFlags
.wild
))
1274 .error(loc
, "cannot have `%s out` parameter of type `%s`", MODtoChars(m
), t
.toChars());
1279 Type tv
= t
.baseElemOf();
1280 if (tv
.ty
== Tstruct
&& tv
.isTypeStruct().sym
.noDefaultCtor
)
1282 .error(loc
, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam
.type
.toChars());
1291 //if (tf.next && !wildreturn)
1292 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
1295 /* Scope attribute is not necessary if the parameter type does not have pointers
1297 const sr
= buildScopeRef(fparam
.storageClass
);
1300 case ScopeRef
.Scope
:
1301 case ScopeRef
.RefScope
:
1302 case ScopeRef
.ReturnRef_Scope
:
1303 if (!fparam
.type
.hasPointers())
1304 fparam
.storageClass
&= ~STC
.scope_
;
1307 case ScopeRef
.ReturnScope
:
1308 case ScopeRef
.Ref_ReturnScope
:
1309 if (!fparam
.type
.hasPointers())
1310 fparam
.storageClass
&= ~(STC
.return_ | STC
.scope_ | STC
.returnScope
);
1317 // Remove redundant storage classes for type, they are already applied
1318 fparam
.storageClass
&= ~(STC
.TYPECTOR
);
1320 // -preview=in: add `ref` storage class to suited `in` params
1321 if (global
.params
.previewIn
&& (fparam
.storageClass
& (STC
.in_ | STC
.ref_
)) == STC
.in_
)
1323 auto ts
= t
.baseElemOf().isTypeStruct();
1324 const isPOD
= !ts || ts
.sym
.isPOD();
1325 if (!isPOD || target
.preferPassByRef(t
))
1326 fparam
.storageClass |
= STC
.ref_
;
1330 // Now that we completed semantic for the argument types,
1331 // run semantic on their default values,
1332 // bearing in mind tuples have been expanded.
1333 // We need to keep a pair of [oidx, eidx] (original index,
1334 // extended index), as we need to run semantic when `oidx` changes.
1335 size_t tupleOrigIdx
= size_t
.max
;
1336 size_t tupleExtIdx
= size_t
.max
;
1337 foreach (oidx
, oparam
, eidx
, eparam
; tf
.parameterList
)
1339 // oparam (original param) will always have the default arg
1340 // if there's one, but `eparam` will not if it's an expanded
1341 // tuple. When we see an expanded tuple, we need to save its
1342 // position to get the offset in it later on.
1343 if (oparam
.defaultArg
)
1345 // Get the obvious case out of the way
1346 if (oparam
is eparam
)
1347 errors |
= !defaultArgSemantic(eparam
, argsc
);
1348 // We're seeing a new tuple
1349 else if (tupleOrigIdx
== size_t
.max || tupleOrigIdx
< oidx
)
1351 /* https://issues.dlang.org/show_bug.cgi?id=18572
1353 * If a tuple parameter has a default argument, when expanding the parameter
1354 * tuple the default argument tuple must also be expanded.
1356 tupleOrigIdx
= oidx
;
1358 errors |
= !defaultArgSemantic(oparam
, argsc
);
1359 TupleExp te
= oparam
.defaultArg
.isTupleExp();
1360 if (te
&& te
.exps
&& te
.exps
.length
)
1361 eparam
.defaultArg
= (*te
.exps
)[0];
1363 // Processing an already-seen tuple
1366 TupleExp te
= oparam
.defaultArg
.isTupleExp();
1367 if (te
&& te
.exps
&& te
.exps
.length
)
1368 eparam
.defaultArg
= (*te
.exps
)[eidx
- tupleExtIdx
];
1372 // We need to know the default argument to resolve `auto ref`,
1373 // hence why this has to take place as the very last step.
1374 /* Resolve "auto ref" storage class to be either ref or value,
1375 * based on the argument matching the parameter
1377 if (eparam
.storageClass
& STC
.auto_
)
1379 Expression farg
= mtype
.fargs
&& eidx
< mtype
.fargs
.length ?
1380 (*mtype
.fargs
)[eidx
] : eparam
.defaultArg
;
1381 if (farg
&& (eparam
.storageClass
& STC
.ref_
))
1383 if (!farg
.isLvalue())
1384 eparam
.storageClass
&= ~STC
.ref_
; // value parameter
1385 eparam
.storageClass
&= ~STC
.auto_
; // https://issues.dlang.org/show_bug.cgi?id=14656
1386 eparam
.storageClass |
= STC
.autoref
;
1388 else if (mtype
.incomplete
&& (eparam
.storageClass
& STC
.ref_
))
1390 // the default argument may have been temporarily removed,
1391 // see usage of `TypeFunction.incomplete`.
1392 // https://issues.dlang.org/show_bug.cgi?id=19891
1393 eparam
.storageClass
&= ~STC
.auto_
;
1394 eparam
.storageClass |
= STC
.autoref
;
1396 else if (eparam
.storageClass
& STC
.ref_
)
1398 .error(loc
, "cannot explicitly instantiate template function with `auto ref` parameter");
1403 .error(loc
, "`auto` can only be used as part of `auto ref` for template function parameters");
1414 if (wildreturn
&& !wildparams
)
1416 .error(loc
, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype
.toChars());
1419 tf
.isInOutParam
= (wildparams
& 1) != 0;
1420 tf
.isInOutQual
= (wildparams
& 2) != 0;
1422 if (tf
.isproperty
&& (tf
.parameterList
.varargs
!= VarArg
.none || tf
.parameterList
.length
> 2))
1424 .error(loc
, "properties can only have zero, one, or two parameter");
1428 if (tf
.parameterList
.varargs
== VarArg
.variadic
&& tf
.linkage
!= LINK
.d
&& tf
.parameterList
.length
== 0 &&
1429 !(sc
.flags
& SCOPE
.Cfile
))
1431 .error(loc
, "variadic functions with non-D linkage must have at least one parameter");
1439 tf
.deco
= tf
.merge().deco
;
1441 /* Don't return merge(), because arg identifiers and default args
1443 * even though the types match
1448 Type
visitDelegate(TypeDelegate mtype
)
1450 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
1451 if (mtype
.deco
) // if semantic() already run
1453 //printf("already done\n");
1456 mtype
.next
= mtype
.next
.typeSemantic(loc
, sc
);
1457 if (mtype
.next
.ty
!= Tfunction
)
1460 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
1461 * perhaps default arguments should
1462 * be removed from next before the merge.
1466 return mtype
.merge();
1470 /* Don't return merge(), because arg identifiers and default args
1472 * even though the types match
1474 mtype
.deco
= mtype
.merge().deco
;
1479 Type
visitIdentifier(TypeIdentifier mtype
)
1484 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
1485 mtype
.resolve(loc
, sc
, e
, t
, s
);
1488 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
1489 return t
.addMod(mtype
.mod
);
1495 auto td
= s
.isTemplateDeclaration
;
1496 if (td
&& td
.onemember
&& td
.onemember
.isAggregateDeclaration
)
1497 .error(loc
, "template %s `%s` is used as a type without instantiation"
1498 ~ "; to instantiate it use `%s!(arguments)`",
1499 s
.kind
, s
.toPrettyChars
, s
.ident
.toChars
);
1501 .error(loc
, "%s `%s` is used as a type", s
.kind
, s
.toPrettyChars
);
1504 else if (e
.op
== EXP
.variable
) // special case: variable is used as a type
1507 N.B. This branch currently triggers for the following code
1512 i.e. the compiler prints "variable x is used as a type"
1513 which isn't a particularly good error message (x is a variable?).
1515 Dsymbol varDecl
= mtype
.toDsymbol(sc
);
1516 const(Loc
) varDeclLoc
= varDecl
.getLoc();
1517 Module varDeclModule
= varDecl
.getModule(); //This can be null
1519 .error(loc
, "variable `%s` is used as a type", mtype
.toChars());
1520 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
1521 if ((varDeclModule
!is null) && varDeclModule
!= sc
._module
) // variable is imported
1523 const(Loc
) varDeclModuleImportLoc
= varDeclModule
.getLoc();
1525 varDeclModuleImportLoc
,
1526 "variable `%s` is imported here from: `%s`",
1528 varDeclModule
.toPrettyChars
,
1532 .errorSupplemental(varDeclLoc
, "variable `%s` is declared here", varDecl
.toChars
);
1535 .error(loc
, "`%s` is used as a type", mtype
.toChars());
1540 Type
visitInstance(TypeInstance mtype
)
1546 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
1548 const errors
= global
.errors
;
1549 mtype
.resolve(loc
, sc
, e
, t
, s
);
1550 // if we had an error evaluating the symbol, suppress further errors
1551 if (!t
&& errors
!= global
.errors
)
1557 if (!e
&& s
&& s
.errors
)
1559 // if there was an error evaluating the symbol, it might actually
1560 // be a type. Avoid misleading error messages.
1561 .error(loc
, "`%s` had previous errors", mtype
.toChars());
1564 .error(loc
, "`%s` is used as a type", mtype
.toChars());
1570 Type
visitTypeof(TypeTypeof mtype
)
1572 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
1576 mtype
.resolve(loc
, sc
, e
, t
, s
);
1577 if (s
&& (t
= s
.getType()) !is null)
1578 t
= t
.addMod(mtype
.mod
);
1581 .error(loc
, "`%s` is used as a type", mtype
.toChars());
1587 Type
visitTraits(TypeTraits mtype
)
1592 mtype
.resolve(loc
, sc
, e
, t
, s
);
1597 .error(mtype
.loc
, "`%s` does not give a valid type", mtype
.toChars
);
1603 Type
visitReturn(TypeReturn mtype
)
1605 //printf("TypeReturn::semantic() %s\n", toChars());
1609 mtype
.resolve(loc
, sc
, e
, t
, s
);
1610 if (s
&& (t
= s
.getType()) !is null)
1611 t
= t
.addMod(mtype
.mod
);
1614 .error(loc
, "`%s` is used as a type", mtype
.toChars());
1620 Type
visitStruct(TypeStruct mtype
)
1622 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
1626 /* Don't semantic for sym because it should be deferred until
1627 * sizeof needed or its members accessed.
1629 // instead, parent should be set correctly
1630 assert(mtype
.sym
.parent
);
1632 if (mtype
.sym
.type
.ty
== Terror
)
1635 return merge(mtype
);
1638 Type
visitEnum(TypeEnum mtype
)
1640 //printf("TypeEnum::semantic() %s\n", toChars());
1641 return mtype
.deco ? mtype
: merge(mtype
);
1644 Type
visitClass(TypeClass mtype
)
1646 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
1650 /* Don't semantic for sym because it should be deferred until
1651 * sizeof needed or its members accessed.
1653 // instead, parent should be set correctly
1654 assert(mtype
.sym
.parent
);
1656 if (mtype
.sym
.type
.ty
== Terror
)
1659 return merge(mtype
);
1662 Type
visitTuple(TypeTuple mtype
)
1664 //printf("TypeTuple::semantic(this = %p)\n", this);
1665 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
1667 mtype
.deco
= merge(mtype
).deco
;
1669 /* Don't return merge(), because a tuple with one type has the
1670 * same deco as that type.
1675 Type
visitSlice(TypeSlice mtype
)
1677 //printf("TypeSlice::semantic() %s\n", toChars());
1678 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
1679 //printf("next: %s\n", tn.toChars());
1681 Type tbn
= tn
.toBasetype();
1682 if (tbn
.ty
!= Ttuple
)
1684 .error(loc
, "can only slice tuple types, not `%s`", tbn
.toChars());
1687 TypeTuple tt
= cast(TypeTuple
)tbn
;
1689 mtype
.lwr
= semanticLength(sc
, tbn
, mtype
.lwr
);
1690 mtype
.upr
= semanticLength(sc
, tbn
, mtype
.upr
);
1691 mtype
.lwr
= mtype
.lwr
.ctfeInterpret();
1692 mtype
.upr
= mtype
.upr
.ctfeInterpret();
1693 if (mtype
.lwr
.op
== EXP
.error || mtype
.upr
.op
== EXP
.error
)
1696 uinteger_t i1
= mtype
.lwr
.toUInteger();
1697 uinteger_t i2
= mtype
.upr
.toUInteger();
1698 if (!(i1
<= i2
&& i2
<= tt
.arguments
.length
))
1700 .error(loc
, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
1701 cast(ulong)i1
, cast(ulong)i2
, cast(ulong)tt
.arguments
.length
);
1708 auto args
= new Parameters();
1709 args
.reserve(cast(size_t
)(i2
- i1
));
1710 foreach (arg
; (*tt
.arguments
)[cast(size_t
)i1
.. cast(size_t
)i2
])
1714 Type t
= new TypeTuple(args
);
1715 return t
.typeSemantic(loc
, sc
);
1718 Type
visitMixin(TypeMixin mtype
)
1720 //printf("TypeMixin::semantic() %s\n", toChars());
1725 mtype
.resolve(loc
, sc
, e
, t
, s
);
1727 if (t
&& t
.ty
!= Terror
)
1730 .error(mtype
.loc
, "`mixin(%s)` does not give a valid type", mtype
.obj
.toChars
);
1734 Type
visitTag(TypeTag mtype
)
1736 //printf("TypeTag.semantic() %s\n", mtype.toChars());
1741 return mtype
.resolved
.addSTC(mtype
.mod
);
1744 /* Find the current scope by skipping tag scopes.
1745 * In C, tag scopes aren't considered scopes.
1751 auto scopesym
= sc2
.scopesym
;
1752 if (scopesym
.isStructDeclaration())
1754 sc2
= sc2
.enclosing
;
1760 /* Declare mtype as a struct/union/enum declaration
1764 void declare(ScopeDsymbol sd
)
1766 sd
.members
= mtype
.members
;
1767 auto scopesym
= sc2
.inner().scopesym
;
1768 if (scopesym
.members
)
1769 scopesym
.members
.push(sd
);
1770 if (scopesym
.symtab
&& !scopesym
.symtabInsert(sd
))
1772 Dsymbol s2
= scopesym
.symtabLookup(sd
, mtype
.id
);
1773 handleTagSymbols(*sc2
, sd
, s2
, scopesym
);
1775 sd
.parent
= sc2
.parent
;
1776 sd
.dsymbolSemantic(sc2
);
1782 auto ed
= new EnumDeclaration(mtype
.loc
, mtype
.id
, mtype
.base
);
1784 mtype
.resolved
= visitEnum(new TypeEnum(ed
));
1788 auto sd
= new StructDeclaration(mtype
.loc
, mtype
.id
, false);
1790 mtype
.resolved
= visitStruct(new TypeStruct(sd
));
1794 auto ud
= new UnionDeclaration(mtype
.loc
, mtype
.id
);
1796 mtype
.resolved
= visitStruct(new TypeStruct(ud
));
1804 /* If it doesn't have a tag by now, supply one.
1805 * It'll be unique, and therefore introducing.
1806 * Declare it, and done.
1810 mtype
.id
= Identifier
.generateId("__tag"[]);
1812 return mtype
.resolved
.addSTC(mtype
.mod
);
1815 /* look for pre-existing declaration
1818 auto s
= sc2
.search(mtype
.loc
, mtype
.id
, &scopesym
, IgnoreErrors | TagNameSpace
);
1819 if (!s || s
.isModule())
1821 // no pre-existing declaration, so declare it
1822 if (mtype
.tok
== TOK
.enum_
&& !mtype
.members
)
1823 .error(mtype
.loc
, "`enum %s` is incomplete without members", mtype
.id
.toChars()); // C11 6.7.2.3-3
1825 return mtype
.resolved
.addSTC(mtype
.mod
);
1828 /* A redeclaration only happens if both declarations are in
1831 const bool redeclar
= (scopesym
== sc2
.inner().scopesym
);
1835 if (mtype
.tok
== TOK
.enum_
&& s
.isEnumDeclaration())
1837 auto ed
= s
.isEnumDeclaration();
1838 if (mtype
.members
&& ed
.members
)
1839 .error(mtype
.loc
, "`%s` already has members", mtype
.id
.toChars());
1840 else if (!ed
.members
)
1842 ed
.members
= mtype
.members
;
1847 mtype
.resolved
= ed
.type
;
1849 else if (mtype
.tok
== TOK
.union_
&& s
.isUnionDeclaration() ||
1850 mtype
.tok
== TOK
.struct_
&& s
.isStructDeclaration())
1852 // Add members to original declaration
1853 auto sd
= s
.isStructDeclaration();
1854 if (mtype
.members
&& sd
.members
)
1856 /* struct S { int b; };
1857 * struct S { int a; } *s;
1859 .error(mtype
.loc
, "`%s` already has members", mtype
.id
.toChars());
1861 else if (!sd
.members
)
1864 * struct S { int a; } *s;
1866 sd
.members
= mtype
.members
;
1867 if (sd
.semanticRun
== PASS
.semanticdone
)
1869 /* The first semantic pass marked `sd` as an opaque struct.
1870 * Re-run semantic so that all newly assigned members are
1871 * picked up and added to the symtab.
1873 sd
.semanticRun
= PASS
.semantic
;
1874 sd
.dsymbolSemantic(sc2
);
1879 /* struct S { int a; };
1883 mtype
.resolved
= sd
.type
;
1888 * struct S { int a; } *s;
1890 .error(mtype
.loc
, "redeclaration of `%s`", mtype
.id
.toChars());
1891 mtype
.resolved
= error();
1894 else if (mtype
.members
)
1897 * { struct S { int a; } *s; }
1903 if (mtype
.tok
== TOK
.enum_
&& s
.isEnumDeclaration())
1905 mtype
.resolved
= s
.isEnumDeclaration().type
;
1907 else if (mtype
.tok
== TOK
.union_
&& s
.isUnionDeclaration() ||
1908 mtype
.tok
== TOK
.struct_
&& s
.isStructDeclaration())
1913 mtype
.resolved
= s
.isStructDeclaration().type
;
1920 .error(mtype
.loc
, "redeclaring `%s %s` as `%s %s`",
1921 s
.kind(), s
.toChars(), Token
.toChars(mtype
.tok
), mtype
.id
.toChars());
1925 return mtype
.resolved
.addSTC(mtype
.mod
);
1930 default: return visitType(type
);
1931 case Tvector
: return visitVector(type
.isTypeVector());
1932 case Tsarray
: return visitSArray(type
.isTypeSArray());
1933 case Tarray
: return visitDArray(type
.isTypeDArray());
1934 case Taarray
: return visitAArray(type
.isTypeAArray());
1935 case Tpointer
: return visitPointer(type
.isTypePointer());
1936 case Treference
: return visitReference(type
.isTypeReference());
1937 case Tfunction
: return visitFunction(type
.isTypeFunction());
1938 case Tdelegate
: return visitDelegate(type
.isTypeDelegate());
1939 case Tident
: return visitIdentifier(type
.isTypeIdentifier());
1940 case Tinstance
: return visitInstance(type
.isTypeInstance());
1941 case Ttypeof
: return visitTypeof(type
.isTypeTypeof());
1942 case Ttraits
: return visitTraits(type
.isTypeTraits());
1943 case Treturn
: return visitReturn(type
.isTypeReturn());
1944 case Tstruct
: return visitStruct(type
.isTypeStruct());
1945 case Tenum
: return visitEnum(type
.isTypeEnum());
1946 case Tclass
: return visitClass(type
.isTypeClass());
1947 case Ttuple
: return visitTuple(type
.isTypeTuple());
1948 case Tslice
: return visitSlice(type
.isTypeSlice());
1949 case Tmixin
: return visitMixin(type
.isTypeMixin());
1950 case Ttag
: return visitTag(type
.isTypeTag());
1954 /************************************
1955 * If an identical type to `type` is in `type.stringtable`, return
1956 * the latter one. Otherwise, add it to `type.stringtable`.
1957 * Some types don't get merged and are returned as-is.
1959 * type = Type to check against existing types
1961 * the type that was merged
1963 extern (C
++) Type
merge(Type type
)
1973 return type
; // don't merge placeholder types
1976 // prevents generating the mangle if the array dim is not yet known
1977 if (!type
.isTypeSArray().dim
.isIntegerExp())
1985 if (!type
.isTypeAArray().index
.merge().deco
)
1990 if (type
.nextOf() && !type
.nextOf().deco
)
1995 //printf("merge(%s)\n", toChars());
2001 mangleToBuffer(type
, &buf
);
2003 auto sv
= type
.stringtable
.update(buf
[]);
2009 import core
.stdc
.stdio
;
2011 printf("t = %s\n", t
.toChars());
2014 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2019 Type t
= stripDefaultArgs(type
);
2021 type
.deco
= t
.deco
= cast(char*)sv
.toDchars();
2022 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2029 /***************************************
2030 * Calculate built-in properties which just the type is necessary.
2033 * t = the type for which the property is calculated
2034 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2035 * loc = the location where the property is encountered
2036 * ident = the identifier of the property
2037 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2038 * src = expression for type `t` or null.
2040 * expression representing the property, or null if not a property and (flag & 1)
2042 Expression
getProperty(Type t
, Scope
* scope_
, const ref Loc loc
, Identifier ident
, int flag
,
2043 Expression src
= null)
2045 Expression
visitType(Type mt
)
2048 static if (LOGDOTEXP
)
2050 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt
.toChars(), ident
.toChars());
2052 if (ident
== Id
.__sizeof
)
2054 const sz
= mt
.size(loc
);
2055 if (sz
== SIZE_INVALID
)
2056 return ErrorExp
.get();
2057 e
= new IntegerExp(loc
, sz
, Type
.tsize_t
);
2059 else if (ident
== Id
.__xalignof
)
2061 const explicitAlignment
= mt
.alignment();
2062 const naturalAlignment
= mt
.alignsize();
2063 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
2064 e
= new IntegerExp(loc
, actualAlignment
, Type
.tsize_t
);
2066 else if (ident
== Id
._init
)
2068 Type tb
= mt
.toBasetype();
2069 e
= mt
.defaultInitLiteral(loc
);
2070 if (tb
.ty
== Tstruct
&& tb
.needsNested())
2072 e
.isStructLiteralExp().useStaticInit
= true;
2075 else if (ident
== Id
._mangleof
)
2079 error(loc
, "forward reference of type `%s.mangleof`", mt
.toChars());
2084 e
= new StringExp(loc
, mt
.deco
.toDString());
2086 e
= e
.expressionSemantic(&sc
);
2089 else if (ident
== Id
.stringof
)
2091 const s
= mt
.toChars();
2092 e
= new StringExp(loc
, s
.toDString());
2094 e
= e
.expressionSemantic(&sc
);
2096 else if (flag
&& mt
!= Type
.terror
)
2103 if (mt
.ty
== Tstruct || mt
.ty
== Tclass || mt
.ty
== Tenum
)
2104 s
= mt
.toDsymbol(null);
2106 s
= s
.search_correct(ident
);
2107 if (s
&& !symbolIsVisible(scope_
, s
))
2109 if (mt
!= Type
.terror
)
2112 error(loc
, "no property `%s` for type `%s`, did you mean `%s`?", ident
.toChars(), mt
.toChars(), s
.toPrettyChars());
2113 else if (ident
== Id
.call && mt
.ty
== Tclass
)
2114 error(loc
, "no property `%s` for type `%s`, did you mean `new %s`?", ident
.toChars(), mt
.toChars(), mt
.toPrettyChars());
2116 else if (const n
= importHint(ident
.toString()))
2117 error(loc
, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident
.toChars(), mt
.toChars(), cast(int)n
.length
, n
.ptr
);
2121 error(loc
, "no property `%s` for `%s` of type `%s`", ident
.toChars(), src
.toChars(), mt
.toPrettyChars(true));
2123 error(loc
, "no property `%s` for type `%s`", ident
.toChars(), mt
.toPrettyChars(true));
2124 if (auto dsym
= mt
.toDsymbol(scope_
))
2125 if (auto sym
= dsym
.isAggregateDeclaration())
2127 if (auto fd
= search_function(sym
, Id
.opDispatch
))
2128 errorSupplemental(loc
, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
2129 else if (!sym
.members
)
2130 errorSupplemental(sym
.loc
, "`%s %s` is opaque and has no members.", sym
.kind
, mt
.toPrettyChars(true));
2139 Expression
visitError(TypeError
)
2141 return ErrorExp
.get();
2144 Expression
visitBasic(TypeBasic mt
)
2146 Expression
integerValue(dinteger_t i
)
2148 return new IntegerExp(loc
, i
, mt
);
2151 Expression
intValue(dinteger_t i
)
2153 return new IntegerExp(loc
, i
, Type
.tint32
);
2156 Expression
floatValue(real_t r
)
2158 if (mt
.isreal() || mt
.isimaginary())
2159 return new RealExp(loc
, r
, mt
);
2162 return new ComplexExp(loc
, complex_t(r
, r
), mt
);
2166 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
2167 if (ident
== Id
.max
)
2171 case Tint8
: return integerValue(byte.max
);
2172 case Tuns8
: return integerValue(ubyte.max
);
2173 case Tint16
: return integerValue(short.max
);
2174 case Tuns16
: return integerValue(ushort.max
);
2175 case Tint32
: return integerValue(int.max
);
2176 case Tuns32
: return integerValue(uint.max
);
2177 case Tint64
: return integerValue(long.max
);
2178 case Tuns64
: return integerValue(ulong.max
);
2179 case Tbool
: return integerValue(bool.max
);
2180 case Tchar
: return integerValue(char.max
);
2181 case Twchar
: return integerValue(wchar.max
);
2182 case Tdchar
: return integerValue(dchar.max
);
2185 case Tfloat32
: return floatValue(target
.FloatProperties
.max
);
2188 case Tfloat64
: return floatValue(target
.DoubleProperties
.max
);
2191 case Tfloat80
: return floatValue(target
.RealProperties
.max
);
2195 else if (ident
== Id
.min
)
2199 case Tint8
: return integerValue(byte.min
);
2207 case Tdchar
: return integerValue(0);
2208 case Tint16
: return integerValue(short.min
);
2209 case Tint32
: return integerValue(int.min
);
2210 case Tint64
: return integerValue(long.min
);
2214 else if (ident
== Id
.min_normal
)
2220 case Tfloat32
: return floatValue(target
.FloatProperties
.min_normal
);
2223 case Tfloat64
: return floatValue(target
.DoubleProperties
.min_normal
);
2226 case Tfloat80
: return floatValue(target
.RealProperties
.min_normal
);
2230 else if (ident
== Id
.nan
)
2242 case Tfloat80
: return floatValue(target
.RealProperties
.nan
);
2246 else if (ident
== Id
.infinity
)
2258 case Tfloat80
: return floatValue(target
.RealProperties
.infinity
);
2262 else if (ident
== Id
.dig
)
2268 case Tfloat32
: return intValue(target
.FloatProperties
.dig
);
2271 case Tfloat64
: return intValue(target
.DoubleProperties
.dig
);
2274 case Tfloat80
: return intValue(target
.RealProperties
.dig
);
2278 else if (ident
== Id
.epsilon
)
2284 case Tfloat32
: return floatValue(target
.FloatProperties
.epsilon
);
2287 case Tfloat64
: return floatValue(target
.DoubleProperties
.epsilon
);
2290 case Tfloat80
: return floatValue(target
.RealProperties
.epsilon
);
2294 else if (ident
== Id
.mant_dig
)
2300 case Tfloat32
: return intValue(target
.FloatProperties
.mant_dig
);
2303 case Tfloat64
: return intValue(target
.DoubleProperties
.mant_dig
);
2306 case Tfloat80
: return intValue(target
.RealProperties
.mant_dig
);
2310 else if (ident
== Id
.max_10_exp
)
2316 case Tfloat32
: return intValue(target
.FloatProperties
.max_10_exp
);
2319 case Tfloat64
: return intValue(target
.DoubleProperties
.max_10_exp
);
2322 case Tfloat80
: return intValue(target
.RealProperties
.max_10_exp
);
2326 else if (ident
== Id
.max_exp
)
2332 case Tfloat32
: return intValue(target
.FloatProperties
.max_exp
);
2335 case Tfloat64
: return intValue(target
.DoubleProperties
.max_exp
);
2338 case Tfloat80
: return intValue(target
.RealProperties
.max_exp
);
2342 else if (ident
== Id
.min_10_exp
)
2348 case Tfloat32
: return intValue(target
.FloatProperties
.min_10_exp
);
2351 case Tfloat64
: return intValue(target
.DoubleProperties
.min_10_exp
);
2354 case Tfloat80
: return intValue(target
.RealProperties
.min_10_exp
);
2358 else if (ident
== Id
.min_exp
)
2364 case Tfloat32
: return intValue(target
.FloatProperties
.min_exp
);
2367 case Tfloat64
: return intValue(target
.DoubleProperties
.min_exp
);
2370 case Tfloat80
: return intValue(target
.RealProperties
.min_exp
);
2374 return visitType(mt
);
2377 Expression
visitVector(TypeVector mt
)
2379 return visitType(mt
);
2382 Expression
visitEnum(TypeEnum mt
)
2385 if (ident
== Id
.max || ident
== Id
.min
)
2387 return mt
.sym
.getMaxMinValue(loc
, ident
);
2389 else if (ident
== Id
._init
)
2391 e
= mt
.defaultInitLiteral(loc
);
2393 else if (ident
== Id
.stringof
)
2395 e
= new StringExp(loc
, mt
.toString());
2397 e
= e
.expressionSemantic(&sc
);
2399 else if (ident
== Id
._mangleof
)
2405 e
= mt
.toBasetype().getProperty(scope_
, loc
, ident
, flag
);
2410 Expression
visitTuple(TypeTuple mt
)
2413 static if (LOGDOTEXP
)
2415 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt
.toChars(), ident
.toChars());
2417 if (ident
== Id
.length
)
2419 e
= new IntegerExp(loc
, mt
.arguments
.length
, Type
.tsize_t
);
2421 else if (ident
== Id
._init
)
2423 e
= mt
.defaultInitLiteral(loc
);
2431 error(loc
, "no property `%s` for tuple `%s`", ident
.toChars(), mt
.toChars());
2439 default: return t
.isTypeBasic() ?
2440 visitBasic(cast(TypeBasic
)t
) :
2443 case Terror
: return visitError (t
.isTypeError());
2444 case Tvector
: return visitVector(t
.isTypeVector());
2445 case Tenum
: return visitEnum (t
.isTypeEnum());
2446 case Ttuple
: return visitTuple (t
.isTypeTuple());
2450 /***************************************
2451 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
2453 * exp = Expression to look at
2454 * t = if exp should be a Type, set t to that Type else null
2455 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
2456 * e = if exp should remain an Expression, set e to that Expression else null
2459 private void resolveExp(Expression exp
, out Type t
, out Expression e
, out Dsymbol s
)
2461 if (exp
.isTypeExp())
2463 else if (auto ve
= exp
.isVarExp())
2465 if (auto v
= ve
.var
.isVarDeclaration())
2470 else if (auto te
= exp
.isTemplateExp())
2472 else if (auto se
= exp
.isScopeExp())
2474 else if (exp
.isFuncExp())
2475 s
= getDsymbol(exp
);
2476 else if (auto dte
= exp
.isDotTemplateExp())
2478 else if (exp
.isErrorExp())
2484 /************************************
2485 * Resolve type 'mt' to either type, symbol, or expression.
2486 * If errors happened, resolved to Type.terror.
2489 * mt = type to be resolved
2490 * loc = the location where the type is encountered
2491 * sc = the scope of the type
2492 * pe = is set if t is an expression
2493 * pt = is set if t is a type
2494 * ps = is set if t is a symbol
2495 * intypeid = true if in type id
2497 void resolve(Type mt
, const ref Loc loc
, Scope
* sc
, out Expression pe
, out Type pt
, out Dsymbol ps
, bool intypeid
= false)
2499 void returnExp(Expression e
)
2506 void returnType(Type t
)
2513 void returnSymbol(Dsymbol s
)
2522 returnType(Type
.terror
);
2525 void visitType(Type mt
)
2527 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
2528 Type t
= typeSemantic(mt
, loc
, sc
);
2533 void visitSArray(TypeSArray mt
)
2535 //printf("TypeSArray::resolve() %s\n", mt.toChars());
2536 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
2537 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2540 // It's really an index expression
2541 if (Dsymbol s
= getDsymbol(pe
))
2542 pe
= new DsymbolExp(loc
, s
);
2543 returnExp(new ArrayExp(loc
, pe
, mt
.dim
));
2548 if (auto tup
= s
.isTupleDeclaration())
2550 mt
.dim
= semanticLength(sc
, tup
, mt
.dim
);
2551 mt
.dim
= mt
.dim
.ctfeInterpret();
2552 if (mt
.dim
.op
== EXP
.error
)
2553 return returnError();
2555 const d
= mt
.dim
.toUInteger();
2556 if (d
>= tup
.objects
.length
)
2558 error(loc
, "tuple index `%llu` out of bounds `[0 .. %llu]`", d
, cast(ulong) tup
.objects
.length
);
2559 return returnError();
2562 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
2563 switch (o
.dyncast()) with (DYNCAST
)
2566 return returnSymbol(cast(Dsymbol
)o
);
2568 Expression e
= cast(Expression
)o
;
2569 if (e
.op
== EXP
.dSymbol
)
2570 return returnSymbol(e
.isDsymbolExp().s
);
2572 return returnExp(e
);
2574 return returnType((cast(Type
)o
).addMod(mt
.mod
));
2579 /* Create a new TupleDeclaration which
2580 * is a slice [d..d+1] out of the old one.
2581 * Do it this way because TemplateInstance::semanticTiargs()
2582 * can handle unresolved Objects this way.
2584 auto objects
= new Objects(1);
2586 return returnSymbol(new TupleDeclaration(loc
, tup
.ident
, objects
));
2589 return visitType(mt
);
2593 if (pt
.ty
!= Terror
)
2594 mt
.next
= pt
; // prevent re-running semantic() on 'next'
2600 void visitDArray(TypeDArray mt
)
2602 //printf("TypeDArray::resolve() %s\n", mt.toChars());
2603 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
2604 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2607 // It's really a slice expression
2608 if (Dsymbol s
= getDsymbol(pe
))
2609 pe
= new DsymbolExp(loc
, s
);
2610 returnExp(new ArrayExp(loc
, pe
));
2614 if (auto tup
= ps
.isTupleDeclaration())
2623 if (pt
.ty
!= Terror
)
2624 mt
.next
= pt
; // prevent re-running semantic() on 'next'
2629 void visitAArray(TypeAArray mt
)
2631 //printf("TypeAArray::resolve() %s\n", mt.toChars());
2632 // Deal with the case where we thought the index was a type, but
2633 // in reality it was an expression.
2634 if (mt
.index
.ty
== Tident || mt
.index
.ty
== Tinstance || mt
.index
.ty
== Tsarray
)
2639 mt
.index
.resolve(loc
, sc
, e
, t
, s
, intypeid
);
2642 // It was an expression -
2643 // Rewrite as a static array
2644 auto tsa
= new TypeSArray(mt
.next
, e
);
2645 tsa
.mod
= mt
.mod
; // just copy mod field so tsa's semantic is not yet done
2646 return tsa
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
2651 .error(loc
, "index is not a type or an expression");
2656 /*************************************
2657 * Takes an array of Identifiers and figures out if
2658 * it represents a Type or an Expression.
2660 * if expression, pe is set
2661 * if type, pt is set
2663 void visitIdentifier(TypeIdentifier mt
)
2665 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2666 if (mt
.ident
== Id
.ctfe
)
2668 error(loc
, "variable `__ctfe` cannot be read at compile time");
2669 return returnError();
2671 if (mt
.ident
== Id
.builtin_va_list
) // gcc has __builtin_va_xxxx for stdarg.h
2673 /* Since we don't support __builtin_va_start, -arg, -end, we don't
2674 * have to actually care what -list is. A void* will do.
2675 * If we ever do care, import core.stdc.stdarg and pull
2676 * the definition out of that, similarly to how std.math is handled for PowExp
2678 pt
= target
.va_listType(loc
, sc
);
2683 Dsymbol s
= sc
.search(loc
, mt
.ident
, &scopesym
);
2685 * https://issues.dlang.org/show_bug.cgi?id=1170
2686 * https://issues.dlang.org/show_bug.cgi?id=10739
2688 * If a symbol is not found, it might be declared in
2689 * a mixin-ed string or a mixin-ed template, so before
2690 * issuing an error semantically analyze all string/template
2691 * mixins that are members of the current ScopeDsymbol.
2693 if (!s
&& sc
.enclosing
)
2695 ScopeDsymbol sds
= sc
.enclosing
.scopesym
;
2696 if (sds
&& sds
.members
)
2698 void semanticOnMixin(Dsymbol member
)
2700 if (auto compileDecl
= member
.isCompileDeclaration())
2701 compileDecl
.dsymbolSemantic(sc
);
2702 else if (auto mixinTempl
= member
.isTemplateMixin())
2703 mixinTempl
.dsymbolSemantic(sc
);
2705 sds
.members
.foreachDsymbol( s
=> semanticOnMixin(s
) );
2706 s
= sc
.search(loc
, mt
.ident
, &scopesym
);
2712 // https://issues.dlang.org/show_bug.cgi?id=16042
2713 // If `f` is really a function template, then replace `f`
2714 // with the function template declaration.
2715 if (auto f
= s
.isFuncDeclaration())
2717 if (auto td
= getFuncTemplateDecl(f
))
2719 // If not at the beginning of the overloaded list of
2720 // `TemplateDeclaration`s, then get the beginning
2728 mt
.resolveHelper(loc
, sc
, s
, scopesym
, pe
, pt
, ps
, intypeid
);
2730 pt
= pt
.addMod(mt
.mod
);
2733 void visitInstance(TypeInstance mt
)
2735 // Note close similarity to TypeIdentifier::resolve()
2737 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
2738 mt
.tempinst
.dsymbolSemantic(sc
);
2739 if (!global
.gag
&& mt
.tempinst
.errors
)
2740 return returnError();
2742 mt
.resolveHelper(loc
, sc
, mt
.tempinst
, null, pe
, pt
, ps
, intypeid
);
2744 pt
= pt
.addMod(mt
.mod
);
2745 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
2748 void visitTypeof(TypeTypeof mt
)
2750 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
2751 //static int nest; if (++nest == 50) *(char*)0=0;
2754 error(loc
, "invalid scope");
2755 return returnError();
2760 error(loc
, "circular `typeof` definition");
2763 return returnError();
2767 /* Currently we cannot evaluate 'exp' in speculative context, because
2768 * the type implementation may leak to the final execution. Consider:
2771 * string toString() const { return "x"; }
2774 * alias X = typeof(S!int());
2775 * assert(typeid(X).toString() == "x");
2778 Scope
* sc2
= sc
.push();
2780 if (!mt
.exp
.isTypeidExp())
2781 /* Treat typeof(typeid(exp)) as needing
2782 * the full semantic analysis of the typeid.
2783 * https://issues.dlang.org/show_bug.cgi?id=20958
2787 auto exp2
= mt
.exp
.expressionSemantic(sc2
);
2788 exp2
= resolvePropertiesOnly(sc2
, exp2
);
2791 if (exp2
.op
== EXP
.error
)
2799 if (mt
.exp
.op
== EXP
.type ||
2800 mt
.exp
.op
== EXP
.scope_
)
2802 if (!(sc
.flags
& SCOPE
.Cfile
) && // in (extended) C typeof may be used on types as with sizeof
2806 /* Today, 'typeof(func)' returns void if func is a
2807 * function template (TemplateExp), or
2808 * template lambda (FuncExp).
2809 * It's actually used in Phobos as an idiom, to branch code for
2810 * template functions.
2813 if (auto f
= mt
.exp
.op
== EXP
.variable ? mt
.exp
.isVarExp().var
.isFuncDeclaration()
2814 : mt
.exp
.op
== EXP
.dotVariable ? mt
.exp
.isDotVarExp().var
.isFuncDeclaration() : null)
2816 // f might be a unittest declaration which is incomplete when compiled
2817 // without -unittest. That causes a segfault in checkForwardRef, see
2818 // https://issues.dlang.org/show_bug.cgi?id=20626
2819 if ((!f
.isUnitTestDeclaration() || global
.params
.useUnitTests
) && f
.checkForwardRef(loc
))
2822 if (auto f
= isFuncAddress(mt
.exp
))
2824 if (f
.checkForwardRef(loc
))
2828 Type t
= mt
.exp
.type
;
2831 error(loc
, "expression `%s` has no type", mt
.exp
.toChars());
2834 if (t
.ty
== Ttypeof
)
2836 error(loc
, "forward reference to `%s`", mt
.toChars());
2839 if (mt
.idents
.length
== 0)
2841 returnType(t
.addMod(mt
.mod
));
2845 if (Dsymbol s
= t
.toDsymbol(sc
))
2846 mt
.resolveHelper(loc
, sc
, s
, null, pe
, pt
, ps
, intypeid
);
2849 auto e
= typeToExpressionHelper(mt
, new TypeExp(loc
, t
));
2850 e
= e
.expressionSemantic(sc
);
2851 resolveExp(e
, pt
, pe
, ps
);
2854 pt
= pt
.addMod(mt
.mod
);
2859 void visitReturn(TypeReturn mt
)
2861 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2864 FuncDeclaration func
= sc
.func
;
2867 error(loc
, "`typeof(return)` must be inside function");
2868 return returnError();
2871 func
= func
.fes
.func
;
2872 t
= func
.type
.nextOf();
2875 error(loc
, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc
.func
.toChars());
2876 return returnError();
2879 if (mt
.idents
.length
== 0)
2881 return returnType(t
.addMod(mt
.mod
));
2885 if (Dsymbol s
= t
.toDsymbol(sc
))
2886 mt
.resolveHelper(loc
, sc
, s
, null, pe
, pt
, ps
, intypeid
);
2889 auto e
= typeToExpressionHelper(mt
, new TypeExp(loc
, t
));
2890 e
= e
.expressionSemantic(sc
);
2891 resolveExp(e
, pt
, pe
, ps
);
2894 pt
= pt
.addMod(mt
.mod
);
2898 void visitSlice(TypeSlice mt
)
2900 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
2903 // It's really a slice expression
2904 if (Dsymbol s
= getDsymbol(pe
))
2905 pe
= new DsymbolExp(loc
, s
);
2906 return returnExp(new ArrayExp(loc
, pe
, new IntervalExp(loc
, mt
.lwr
, mt
.upr
)));
2911 TupleDeclaration td
= s
.isTupleDeclaration();
2914 /* It's a slice of a TupleDeclaration
2916 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, td
);
2917 sym
.parent
= sc
.scopesym
;
2919 sc
= sc
.startCTFE();
2920 mt
.lwr
= mt
.lwr
.expressionSemantic(sc
);
2921 mt
.upr
= mt
.upr
.expressionSemantic(sc
);
2925 mt
.lwr
= mt
.lwr
.ctfeInterpret();
2926 mt
.upr
= mt
.upr
.ctfeInterpret();
2927 const i1
= mt
.lwr
.toUInteger();
2928 const i2
= mt
.upr
.toUInteger();
2929 if (!(i1
<= i2
&& i2
<= td
.objects
.length
))
2931 error(loc
, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1
, i2
, cast(ulong) td
.objects
.length
);
2932 return returnError();
2935 if (i1
== 0 && i2
== td
.objects
.length
)
2937 return returnSymbol(td
);
2940 /* Create a new TupleDeclaration which
2941 * is a slice [i1..i2] out of the old one.
2943 auto objects
= new Objects(cast(size_t
)(i2
- i1
));
2944 for (size_t i
= 0; i
< objects
.length
; i
++)
2946 (*objects
)[i
] = (*td
.objects
)[cast(size_t
)i1
+ i
];
2949 return returnSymbol(new TupleDeclaration(loc
, td
.ident
, objects
));
2956 if (pt
.ty
!= Terror
)
2957 mt
.next
= pt
; // prevent re-running semantic() on 'next'
2962 void visitMixin(TypeMixin mt
)
2964 RootObject o
= mt
.obj
;
2966 // if already resolved just set pe/pt/ps and return.
2969 pe
= o
.isExpression();
2975 o
= mt
.compileTypeMixin(loc
, sc
);
2976 if (auto t
= o
.isType())
2978 resolve(t
, loc
, sc
, pe
, pt
, ps
, intypeid
);
2980 pt
= pt
.addMod(mt
.mod
);
2982 else if (auto e
= o
.isExpression())
2984 e
= e
.expressionSemantic(sc
);
2985 if (auto et
= e
.isTypeExp())
2986 returnType(et
.type
.addMod(mt
.mod
));
2994 mt
.obj
= pe ? pe
: (pt ? pt
: ps
);
2997 void visitTraits(TypeTraits mt
)
2999 // if already resolved just return the cached object.
3002 pt
= mt
.obj
.isType();
3003 ps
= mt
.obj
.isDsymbol();
3004 pe
= mt
.obj
.isExpression();
3008 import dmd
.traits
: semanticTraits
;
3010 if (Expression e
= semanticTraits(mt
.exp
, sc
))
3014 case EXP
.dotVariable
:
3015 mt
.obj
= e
.isDotVarExp().var
;
3018 mt
.obj
= e
.isVarExp().var
;
3021 auto fe
= e
.isFuncExp();
3022 mt
.obj
= fe
.td ? fe
.td
: fe
.fd
;
3024 case EXP
.dotTemplateDeclaration
:
3025 mt
.obj
= e
.isDotTemplateExp().td
;
3028 mt
.obj
= e
.isDsymbolExp().s
;
3031 mt
.obj
= e
.isTemplateExp().td
;
3034 mt
.obj
= e
.isScopeExp().sds
;
3037 TupleExp te
= e
.isTupleExp();
3038 Objects
* elems
= new Objects(te
.exps
.length
);
3039 foreach (i
; 0 .. elems
.length
)
3041 auto src
= (*te
.exps
)[i
];
3045 (*elems
)[i
] = src
.isTypeExp().type
;
3048 (*elems
)[i
] = src
.isDotTypeExp().sym
.isType();
3050 case EXP
.overloadSet
:
3051 (*elems
)[i
] = src
.isOverExp().type
;
3054 if (auto sym
= isDsymbol(src
))
3060 TupleDeclaration td
= new TupleDeclaration(e
.loc
, Identifier
.generateId("__aliastup"), elems
);
3064 mt
.obj
= e
.isDotTypeExp().sym
.isType();
3067 mt
.obj
= e
.isTypeExp().type
;
3069 case EXP
.overloadSet
:
3070 mt
.obj
= e
.isOverExp().type
;
3082 if (auto t
= mt
.obj
.isType())
3084 t
= t
.addMod(mt
.mod
);
3088 else if (auto s
= mt
.obj
.isDsymbol())
3090 else if (auto e
= mt
.obj
.isExpression())
3095 assert(global
.errors
);
3096 mt
.obj
= Type
.terror
;
3097 return returnError();
3103 default: visitType (mt
); break;
3104 case Tsarray
: visitSArray (mt
.isTypeSArray()); break;
3105 case Tarray
: visitDArray (mt
.isTypeDArray()); break;
3106 case Taarray
: visitAArray (mt
.isTypeAArray()); break;
3107 case Tident
: visitIdentifier(mt
.isTypeIdentifier()); break;
3108 case Tinstance
: visitInstance (mt
.isTypeInstance()); break;
3109 case Ttypeof
: visitTypeof (mt
.isTypeTypeof()); break;
3110 case Treturn
: visitReturn (mt
.isTypeReturn()); break;
3111 case Tslice
: visitSlice (mt
.isTypeSlice()); break;
3112 case Tmixin
: visitMixin (mt
.isTypeMixin()); break;
3113 case Ttraits
: visitTraits (mt
.isTypeTraits()); break;
3117 /************************
3118 * Access the members of the object e. This type is same as e.type.
3120 * mt = type for which the dot expression is used
3121 * sc = instantiating scope
3122 * e = expression to convert
3123 * ident = identifier being used
3124 * flag = DotExpFlag bit flags
3127 * resulting expression with e.ident resolved
3129 Expression
dotExp(Type mt
, Scope
* sc
, Expression e
, Identifier ident
, int flag
)
3131 Expression
visitType(Type mt
)
3133 VarDeclaration v
= null;
3134 static if (LOGDOTEXP
)
3136 printf("Type::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3138 Expression ex
= e
.lastComma();
3139 if (ex
.op
== EXP
.dotVariable
)
3141 DotVarExp dv
= cast(DotVarExp
)ex
;
3142 v
= dv
.var
.isVarDeclaration();
3144 else if (ex
.op
== EXP
.variable
)
3146 VarExp ve
= cast(VarExp
)ex
;
3147 v
= ve
.var
.isVarDeclaration();
3151 if (ident
== Id
.offsetof
)
3153 v
.dsymbolSemantic(null);
3156 auto ad
= v
.isMember();
3157 objc
.checkOffsetof(e
, ad
);
3159 if (ad
.sizeok
!= Sizeok
.done
)
3160 return ErrorExp
.get();
3161 return new IntegerExp(e
.loc
, v
.offset
, Type
.tsize_t
);
3164 else if (ident
== Id
._init
)
3166 Type tb
= mt
.toBasetype();
3167 e
= mt
.defaultInitLiteral(e
.loc
);
3168 if (tb
.ty
== Tstruct
&& tb
.needsNested())
3170 e
.isStructLiteralExp().useStaticInit
= true;
3175 if (ident
== Id
.stringof
)
3177 /* https://issues.dlang.org/show_bug.cgi?id=3796
3178 * this should demangle e.type.deco rather than
3179 * pretty-printing the type.
3181 e
= new StringExp(e
.loc
, e
.toString());
3184 e
= mt
.getProperty(sc
, e
.loc
, ident
, flag
& DotExpFlag
.gag
);
3188 e
= e
.expressionSemantic(sc
);
3192 Expression
visitError(TypeError
)
3194 return ErrorExp
.get();
3197 Expression
visitBasic(TypeBasic mt
)
3199 static if (LOGDOTEXP
)
3201 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3220 e
= e
.castTo(sc
, t
);
3240 e
= new RealExp(e
.loc
, CTFloat
.zero
, t
);
3244 e
= mt
.Type
.getProperty(sc
, e
.loc
, ident
, flag
);
3248 else if (ident
== Id
.im
)
3254 t
= mt
.timaginary32
;
3259 t
= mt
.timaginary64
;
3264 t
= mt
.timaginary80
;
3268 e
= e
.castTo(sc
, t
);
3291 e
= new RealExp(e
.loc
, CTFloat
.zero
, mt
);
3295 e
= mt
.Type
.getProperty(sc
, e
.loc
, ident
, flag
);
3301 return visitType(mt
);
3303 if (!(flag
& 1) || e
)
3304 e
= e
.expressionSemantic(sc
);
3308 Expression
visitVector(TypeVector mt
)
3310 static if (LOGDOTEXP
)
3312 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3314 if (ident
== Id
.ptr
&& e
.op
== EXP
.call)
3316 /* The trouble with EXP.call is the return ABI for float[4] is different from
3317 * __vector(float[4]), and a type paint won't do.
3319 e
= new AddrExp(e
.loc
, e
);
3320 e
= e
.expressionSemantic(sc
);
3321 return e
.castTo(sc
, mt
.basetype
.nextOf().pointerTo());
3323 if (ident
== Id
.array
)
3325 //e = e.castTo(sc, basetype);
3327 e
= new VectorArrayExp(e
.loc
, e
);
3328 e
= e
.expressionSemantic(sc
);
3331 if (ident
== Id
._init || ident
== Id
.offsetof || ident
== Id
.stringof || ident
== Id
.__xalignof
)
3333 // init should return a new VectorExp
3334 // https://issues.dlang.org/show_bug.cgi?id=12776
3335 // offsetof does not work on a cast expression, so use e directly
3336 // stringof should not add a cast to the output
3337 return visitType(mt
);
3340 // Properties based on the vector element type and are values of the element type
3341 if (ident
== Id
.max || ident
== Id
.min || ident
== Id
.min_normal ||
3342 ident
== Id
.nan || ident
== Id
.infinity || ident
== Id
.epsilon
)
3344 auto vet
= mt
.basetype
.isTypeSArray().next
; // vector element type
3345 if (auto ev
= getProperty(vet
, sc
, e
.loc
, ident
, DotExpFlag
.gag
))
3346 return ev
.castTo(sc
, mt
); // 'broadcast' ev to the vector elements
3349 return mt
.basetype
.dotExp(sc
, e
.castTo(sc
, mt
.basetype
), ident
, flag
);
3352 Expression
visitArray(TypeArray mt
)
3354 static if (LOGDOTEXP
)
3356 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3361 if (!(flag
& 1) || e
)
3362 e
= e
.expressionSemantic(sc
);
3366 Expression
visitSArray(TypeSArray mt
)
3368 static if (LOGDOTEXP
)
3370 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3372 if (ident
== Id
.length
)
3378 else if (ident
== Id
.ptr
)
3380 if (e
.op
== EXP
.type
)
3382 e
.error("`%s` is not an expression", e
.toChars());
3383 return ErrorExp
.get();
3385 else if (mt
.dim
.toUInteger() < 1 && checkUnsafeDotExp(sc
, e
, ident
, flag
))
3387 // .ptr on static array is @safe unless size is 0
3388 // https://issues.dlang.org/show_bug.cgi?id=20853
3389 return ErrorExp
.get();
3391 e
= e
.castTo(sc
, e
.type
.nextOf().pointerTo());
3393 else if (ident
== Id
._tupleof
)
3397 e
.error("`.tupleof` cannot be used on type `%s`", mt
.toChars
);
3398 return ErrorExp
.get();
3404 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
3406 const length
= cast(size_t
)mt
.dim
.toUInteger();
3407 auto exps
= new Expressions();
3408 exps
.reserve(length
);
3409 foreach (i
; 0 .. length
)
3410 exps
.push(new IndexExp(e
.loc
, ev
, new IntegerExp(e
.loc
, i
, Type
.tsize_t
)));
3411 e
= new TupleExp(e
.loc
, e0
, exps
);
3418 if (!(flag
& 1) || e
)
3419 e
= e
.expressionSemantic(sc
);
3423 Expression
visitDArray(TypeDArray mt
)
3425 static if (LOGDOTEXP
)
3427 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3429 if (e
.op
== EXP
.type
&& (ident
== Id
.length || ident
== Id
.ptr
))
3431 e
.error("`%s` is not an expression", e
.toChars());
3432 return ErrorExp
.get();
3434 if (ident
== Id
.length
)
3436 if (e
.op
== EXP
.string_
)
3438 StringExp se
= cast(StringExp
)e
;
3439 return new IntegerExp(se
.loc
, se
.len
, Type
.tsize_t
);
3441 if (e
.op
== EXP
.null_
)
3443 return new IntegerExp(e
.loc
, 0, Type
.tsize_t
);
3445 if (checkNonAssignmentArrayOp(e
))
3447 return ErrorExp
.get();
3449 e
= new ArrayLengthExp(e
.loc
, e
);
3450 e
.type
= Type
.tsize_t
;
3453 else if (ident
== Id
.ptr
)
3455 if (checkUnsafeDotExp(sc
, e
, ident
, flag
))
3456 return ErrorExp
.get();
3457 return e
.castTo(sc
, mt
.next
.pointerTo());
3461 return visitArray(mt
);
3465 Expression
visitAArray(TypeAArray mt
)
3467 static if (LOGDOTEXP
)
3469 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3471 if (ident
== Id
.length
)
3473 __gshared FuncDeclaration fd_aaLen
= null;
3474 if (fd_aaLen
is null)
3476 auto fparams
= new Parameters();
3477 fparams
.push(new Parameter(STC
.const_ | STC
.scope_
, mt
, null, null, null));
3478 fd_aaLen
= FuncDeclaration
.genCfunc(fparams
, Type
.tsize_t
, Id
.aaLen
);
3479 TypeFunction tf
= fd_aaLen
.type
.toTypeFunction();
3480 tf
.purity
= PURE
.const_
;
3481 tf
.isnothrow
= true;
3484 Expression ev
= new VarExp(e
.loc
, fd_aaLen
, false);
3485 e
= new CallExp(e
.loc
, ev
, e
);
3486 e
.type
= fd_aaLen
.type
.toTypeFunction().next
;
3491 return visitType(mt
);
3495 Expression
visitReference(TypeReference mt
)
3497 static if (LOGDOTEXP
)
3499 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3501 // References just forward things along
3502 return mt
.next
.dotExp(sc
, e
, ident
, flag
);
3505 Expression
visitDelegate(TypeDelegate mt
)
3507 static if (LOGDOTEXP
)
3509 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3511 if (ident
== Id
.ptr
)
3513 e
= new DelegatePtrExp(e
.loc
, e
);
3514 e
= e
.expressionSemantic(sc
);
3516 else if (ident
== Id
.funcptr
)
3518 if (checkUnsafeDotExp(sc
, e
, ident
, flag
))
3520 return ErrorExp
.get();
3522 e
= new DelegateFuncptrExp(e
.loc
, e
);
3523 e
= e
.expressionSemantic(sc
);
3527 return visitType(mt
);
3532 /***************************************
3533 * `ident` was not found as a member of `mt`.
3534 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
3535 * If that fails, forward to visitType().
3537 * mt = class or struct
3539 * e = `this` for `ident`
3540 * ident = name of member
3541 * flag = flag & 1, don't report "not a property" error and just return NULL.
3542 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
3544 * resolved expression if found, otherwise null
3546 Expression
noMember(Type mt
, Scope
* sc
, Expression e
, Identifier ident
, int flag
)
3548 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
3550 bool gagError
= flag
& 1;
3552 __gshared
int nest
; // https://issues.dlang.org/show_bug.cgi?id=17380
3554 static Expression
returnExp(Expression e
)
3560 if (++nest
> global
.recursionLimit
)
3562 .error(e
.loc
, "cannot resolve identifier `%s`", ident
.toChars());
3563 return returnExp(gagError ?
null : ErrorExp
.get());
3567 assert(mt
.ty
== Tstruct || mt
.ty
== Tclass
);
3568 auto sym
= mt
.toDsymbol(sc
).isAggregateDeclaration();
3570 if (// https://issues.dlang.org/show_bug.cgi?id=22054
3571 // if a class or struct does not have a body
3572 // there is no point in searching for its members
3574 ident
!= Id
.__sizeof
&&
3575 ident
!= Id
.__xalignof
&&
3576 ident
!= Id
._init
&&
3577 ident
!= Id
._mangleof
&&
3578 ident
!= Id
.stringof
&&
3579 ident
!= Id
.offsetof
&&
3580 // https://issues.dlang.org/show_bug.cgi?id=15045
3581 // Don't forward special built-in member functions.
3584 ident
!= Id
.__xdtor
&&
3585 ident
!= Id
.postblit
&&
3586 ident
!= Id
.__xpostblit
)
3588 /* Look for overloaded opDot() to see if we should forward request
3591 if (auto fd
= search_function(sym
, Id
.opDot
))
3593 /* Rewrite e.ident as:
3596 e
= build_overload(e
.loc
, sc
, e
, null, fd
);
3597 // @@@DEPRECATED_2.110@@@.
3598 // Deprecated in 2.082, made an error in 2.100.
3599 e
.error("`opDot` is obsolete. Use `alias this`");
3600 return ErrorExp
.get();
3603 /* Look for overloaded opDispatch to see if we should forward request
3606 if (auto fd
= search_function(sym
, Id
.opDispatch
))
3608 /* Rewrite e.ident as:
3609 * e.opDispatch!("ident")
3611 TemplateDeclaration td
= fd
.isTemplateDeclaration();
3614 fd
.error("must be a template `opDispatch(string s)`, not a %s", fd
.kind());
3615 return returnExp(ErrorExp
.get());
3617 auto se
= new StringExp(e
.loc
, ident
.toString());
3618 auto tiargs
= new Objects();
3620 auto dti
= new DotTemplateInstanceExp(e
.loc
, e
, Id
.opDispatch
, tiargs
);
3621 dti
.ti
.tempdecl
= td
;
3622 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
3624 * template opDispatch(name) if (isValid!name) { ... }
3626 uint errors
= gagError ? global
.startGagging() : 0;
3627 e
= dti
.dotTemplateSemanticProp(sc
, 0);
3628 if (gagError
&& global
.endGagging(errors
))
3630 return returnExp(e
);
3633 /* See if we should forward to the alias this.
3635 auto alias_e
= flag
& DotExpFlag
.noAliasThis ?
null
3636 : resolveAliasThis(sc
, e
, gagError
);
3637 if (alias_e
&& alias_e
!= e
)
3639 /* Rewrite e.ident as:
3642 auto die
= new DotIdExp(e
.loc
, alias_e
, ident
);
3644 auto errors
= gagError ?
0 : global
.startGagging();
3645 auto exp
= die
.dotIdSemanticProp(sc
, gagError
);
3648 global
.endGagging(errors
);
3649 if (exp
&& exp
.op
== EXP
.error
)
3653 if (exp
&& gagError
)
3654 // now that we know that the alias this leads somewhere useful,
3655 // go back and print deprecations/warnings that we skipped earlier due to the gag
3656 resolveAliasThis(sc
, e
, false);
3658 return returnExp(exp
);
3661 return returnExp(visitType(mt
));
3664 Expression
visitStruct(TypeStruct mt
)
3667 static if (LOGDOTEXP
)
3669 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3671 assert(e
.op
!= EXP
.dot
);
3673 // https://issues.dlang.org/show_bug.cgi?id=14010
3674 if (!(sc
.flags
& SCOPE
.Cfile
) && ident
== Id
._mangleof
)
3676 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
3681 if (ident
== Id
._tupleof
)
3683 /* Create a TupleExp out of the fields of the struct e:
3684 * (e.field0, e.field1, e.field2, ...)
3686 e
= e
.expressionSemantic(sc
); // do this before turning on noaccesscheck
3688 if (!mt
.sym
.determineFields())
3690 error(e
.loc
, "unable to determine fields of `%s` because of forward references", mt
.toChars());
3694 Expression ev
= e
.op
== EXP
.type ?
null : e
;
3696 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
3698 auto exps
= new Expressions();
3699 exps
.reserve(mt
.sym
.fields
.length
);
3700 for (size_t i
= 0; i
< mt
.sym
.fields
.length
; i
++)
3702 VarDeclaration v
= mt
.sym
.fields
[i
];
3705 ex
= new DotVarExp(e
.loc
, ev
, v
);
3708 ex
= new VarExp(e
.loc
, v
);
3709 ex
.type
= ex
.type
.addMod(e
.type
.mod
);
3714 e
= new TupleExp(e
.loc
, e0
, exps
);
3715 Scope
* sc2
= sc
.push();
3716 sc2
.flags |
= SCOPE
.noaccesscheck
;
3717 e
= e
.expressionSemantic(sc2
);
3722 immutable flags
= sc
.flags
& SCOPE
.ignoresymbolvisibility ? IgnoreSymbolVisibility
: 0;
3723 s
= mt
.sym
.search(e
.loc
, ident
, flags | IgnorePrivateImports
);
3727 return noMember(mt
, sc
, e
, ident
, flag
);
3729 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, s
))
3731 return noMember(mt
, sc
, e
, ident
, flag
);
3735 if (auto em
= s
.isEnumMember())
3737 return em
.getVarExp(e
.loc
, sc
);
3739 if (auto v
= s
.isVarDeclaration())
3741 v
.checkDeprecated(e
.loc
, sc
);
3742 v
.checkDisabled(e
.loc
, sc
);
3744 !v
.type
.deco
&& v
.inuse
)
3746 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
3747 e
.error("circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
3749 e
.error("forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
3750 return ErrorExp
.get();
3752 if (v
.type
.ty
== Terror
)
3754 return ErrorExp
.get();
3757 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
3761 e
.error("circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
3762 return ErrorExp
.get();
3764 checkAccess(e
.loc
, sc
, null, v
);
3765 Expression ve
= new VarExp(e
.loc
, v
);
3766 if (!isTrivialExp(e
))
3768 ve
= new CommaExp(e
.loc
, e
, ve
);
3770 return ve
.expressionSemantic(sc
);
3774 if (auto t
= s
.getType())
3776 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
3779 TemplateMixin tm
= s
.isTemplateMixin();
3782 return new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, tm
)).expressionSemantic(sc
);
3785 TemplateDeclaration td
= s
.isTemplateDeclaration();
3788 if (e
.op
== EXP
.type
)
3789 e
= new TemplateExp(e
.loc
, td
);
3791 e
= new DotTemplateExp(e
.loc
, e
, td
);
3792 return e
.expressionSemantic(sc
);
3795 TemplateInstance ti
= s
.isTemplateInstance();
3798 if (!ti
.semanticRun
)
3800 ti
.dsymbolSemantic(sc
);
3801 if (!ti
.inst || ti
.errors
) // if template failed to expand
3803 return ErrorExp
.get();
3806 s
= ti
.inst
.toAlias();
3807 if (!s
.isTemplateInstance())
3809 if (e
.op
== EXP
.type
)
3810 e
= new ScopeExp(e
.loc
, ti
);
3812 e
= new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, ti
));
3813 return e
.expressionSemantic(sc
);
3816 if (s
.isImport() || s
.isModule() || s
.isPackage())
3818 return symbolToExp(s
, e
.loc
, sc
, false);
3821 OverloadSet o
= s
.isOverloadSet();
3824 auto oe
= new OverExp(e
.loc
, o
);
3825 if (e
.op
== EXP
.type
)
3829 return new DotExp(e
.loc
, e
, oe
);
3832 Declaration d
= s
.isDeclaration();
3835 e
.error("`%s.%s` is not a declaration", e
.toChars(), ident
.toChars());
3836 return ErrorExp
.get();
3839 if (e
.op
== EXP
.type
)
3844 if (TupleDeclaration tup
= d
.isTupleDeclaration())
3846 e
= new TupleExp(e
.loc
, tup
);
3847 return e
.expressionSemantic(sc
);
3849 if (d
.needThis() && sc
.intypeof
!= 1)
3854 * only if the scope in which we are
3855 * has a `this` that matches the type
3856 * of the lhs of the dot expression.
3858 * https://issues.dlang.org/show_bug.cgi?id=23617
3860 auto fd
= hasThis(sc
);
3861 if (fd
&& fd
.isThis() == mt
.sym
)
3863 e
= new DotVarExp(e
.loc
, new ThisExp(e
.loc
), d
);
3864 return e
.expressionSemantic(sc
);
3867 if (d
.semanticRun
== PASS
.initial
)
3868 d
.dsymbolSemantic(null);
3869 checkAccess(e
.loc
, sc
, e
, d
);
3870 auto ve
= new VarExp(e
.loc
, d
);
3871 if (d
.isVarDeclaration() && d
.needThis())
3872 ve
.type
= d
.type
.addMod(e
.type
.mod
);
3876 bool unreal
= e
.op
== EXP
.variable
&& (cast(VarExp
)e
).var
.isField();
3877 if (d
.isDataseg() || unreal
&& d
.isField())
3880 checkAccess(e
.loc
, sc
, e
, d
);
3881 Expression ve
= new VarExp(e
.loc
, d
);
3882 e
= unreal ? ve
: new CommaExp(e
.loc
, e
, ve
);
3883 return e
.expressionSemantic(sc
);
3886 e
= new DotVarExp(e
.loc
, e
, d
);
3887 return e
.expressionSemantic(sc
);
3890 Expression
visitEnum(TypeEnum mt
)
3892 static if (LOGDOTEXP
)
3894 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e
.toChars(), ident
.toChars(), mt
.toChars());
3896 // https://issues.dlang.org/show_bug.cgi?id=14010
3897 if (ident
== Id
._mangleof
)
3899 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
3902 if (mt
.sym
.semanticRun
< PASS
.semanticdone
)
3903 mt
.sym
.dsymbolSemantic(null);
3905 Dsymbol s
= mt
.sym
.search(e
.loc
, ident
);
3908 if (ident
== Id
._init
)
3910 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
3913 /* Allow special enums to not need a member list
3915 if ((ident
== Id
.max || ident
== Id
.min
) && (mt
.sym
.members ||
!mt
.sym
.isSpecial()))
3917 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
3920 Expression res
= mt
.sym
.getMemtype(Loc
.initial
).dotExp(sc
, e
, ident
, 1);
3921 if (!(flag
& 1) && !res
)
3923 if (auto ns
= mt
.sym
.search_correct(ident
))
3924 e
.error("no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident
.toChars(), mt
.toChars(), mt
.toChars(),
3927 e
.error("no property `%s` for type `%s`", ident
.toChars(),
3930 return ErrorExp
.get();
3934 EnumMember m
= s
.isEnumMember();
3935 return m
.getVarExp(e
.loc
, sc
);
3938 Expression
visitClass(TypeClass mt
)
3941 static if (LOGDOTEXP
)
3943 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
3945 assert(e
.op
!= EXP
.dot
);
3947 // https://issues.dlang.org/show_bug.cgi?id=12543
3948 if (ident
== Id
.__sizeof || ident
== Id
.__xalignof || ident
== Id
._mangleof
)
3950 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
3955 if (ident
== Id
._tupleof
)
3957 objc
.checkTupleof(e
, mt
);
3959 /* Create a TupleExp
3961 e
= e
.expressionSemantic(sc
); // do this before turning on noaccesscheck
3963 mt
.sym
.size(e
.loc
); // do semantic of type
3966 Expression ev
= e
.op
== EXP
.type ?
null : e
;
3968 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
3970 auto exps
= new Expressions();
3971 exps
.reserve(mt
.sym
.fields
.length
);
3972 for (size_t i
= 0; i
< mt
.sym
.fields
.length
; i
++)
3974 VarDeclaration v
= mt
.sym
.fields
[i
];
3975 // Don't include hidden 'this' pointer
3976 if (v
.isThisDeclaration())
3980 ex
= new DotVarExp(e
.loc
, ev
, v
);
3983 ex
= new VarExp(e
.loc
, v
);
3984 ex
.type
= ex
.type
.addMod(e
.type
.mod
);
3989 e
= new TupleExp(e
.loc
, e0
, exps
);
3990 Scope
* sc2
= sc
.push();
3991 sc2
.flags |
= SCOPE
.noaccesscheck
;
3992 e
= e
.expressionSemantic(sc2
);
3997 int flags
= sc
.flags
& SCOPE
.ignoresymbolvisibility ? IgnoreSymbolVisibility
: 0;
3998 s
= mt
.sym
.search(e
.loc
, ident
, flags | IgnorePrivateImports
);
4003 // See if it's a 'this' class or a base class
4004 if (mt
.sym
.ident
== ident
)
4006 if (e
.op
== EXP
.type
)
4008 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4010 e
= new DotTypeExp(e
.loc
, e
, mt
.sym
);
4011 e
= e
.expressionSemantic(sc
);
4014 if (auto cbase
= mt
.sym
.searchBase(ident
))
4016 if (e
.op
== EXP
.type
)
4018 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4020 if (auto ifbase
= cbase
.isInterfaceDeclaration())
4021 e
= new CastExp(e
.loc
, e
, ifbase
.type
);
4023 e
= new DotTypeExp(e
.loc
, e
, cbase
);
4024 e
= e
.expressionSemantic(sc
);
4028 if (ident
== Id
.classinfo
)
4030 if (!Type
.typeinfoclass
)
4032 error(e
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4033 return ErrorExp
.get();
4036 Type t
= Type
.typeinfoclass
.type
;
4037 if (e
.op
== EXP
.type || e
.op
== EXP
.dotType
)
4039 /* For type.classinfo, we know the classinfo
4042 if (!mt
.sym
.vclassinfo
)
4043 mt
.sym
.vclassinfo
= new TypeInfoClassDeclaration(mt
.sym
.type
);
4044 e
= new VarExp(e
.loc
, mt
.sym
.vclassinfo
);
4046 e
.type
= t
; // do this so we don't get redundant dereference
4050 /* For class objects, the classinfo reference is the first
4051 * entry in the vtbl[]
4053 e
= new PtrExp(e
.loc
, e
);
4054 e
.type
= t
.pointerTo();
4055 if (mt
.sym
.isInterfaceDeclaration())
4057 if (mt
.sym
.isCPPinterface())
4059 /* C++ interface vtbl[]s are different in that the
4060 * first entry is always pointer to the first virtual
4061 * function, not classinfo.
4062 * We can't get a .classinfo for it.
4064 error(e
.loc
, "no `.classinfo` for C++ interface objects");
4066 /* For an interface, the first entry in the vtbl[]
4067 * is actually a pointer to an instance of struct Interface.
4068 * The first member of Interface is the .classinfo,
4069 * so add an extra pointer indirection.
4071 e
.type
= e
.type
.pointerTo();
4072 e
= new PtrExp(e
.loc
, e
);
4073 e
.type
= t
.pointerTo();
4075 e
= new PtrExp(e
.loc
, e
, t
);
4080 if (ident
== Id
.__vptr
)
4082 /* The pointer to the vtbl[]
4083 * *cast(immutable(void*)**)e
4085 e
= e
.castTo(sc
, mt
.tvoidptr
.immutableOf().pointerTo().pointerTo());
4086 e
= new PtrExp(e
.loc
, e
);
4087 e
= e
.expressionSemantic(sc
);
4091 if (ident
== Id
.__monitor
&& mt
.sym
.hasMonitor())
4093 /* The handle to the monitor (call it a void*)
4094 * *(cast(void**)e + 1)
4096 e
= e
.castTo(sc
, mt
.tvoidptr
.pointerTo());
4097 e
= new AddExp(e
.loc
, e
, IntegerExp
.literal
!1);
4098 e
= new PtrExp(e
.loc
, e
);
4099 e
= e
.expressionSemantic(sc
);
4103 if (ident
== Id
.outer
&& mt
.sym
.vthis
)
4105 if (mt
.sym
.vthis
.semanticRun
== PASS
.initial
)
4106 mt
.sym
.vthis
.dsymbolSemantic(null);
4108 if (auto cdp
= mt
.sym
.toParentLocal().isClassDeclaration())
4110 auto dve
= new DotVarExp(e
.loc
, e
, mt
.sym
.vthis
);
4111 dve
.type
= cdp
.type
.addMod(e
.type
.mod
);
4115 /* https://issues.dlang.org/show_bug.cgi?id=15839
4116 * Find closest parent class through nested functions.
4118 for (auto p
= mt
.sym
.toParentLocal(); p
; p
= p
.toParentLocal())
4120 auto fd
= p
.isFuncDeclaration();
4123 auto ad
= fd
.isThis();
4124 if (!ad
&& fd
.isNested())
4128 if (auto cdp
= ad
.isClassDeclaration())
4130 auto ve
= new ThisExp(e
.loc
);
4133 const nestedError
= fd
.vthis
.checkNestedReference(sc
, e
.loc
);
4134 assert(!nestedError
);
4136 ve
.type
= cdp
.type
.addMod(fd
.vthis
.type
.mod
).addMod(e
.type
.mod
);
4142 // Continue to show enclosing function's frame (stack or closure).
4143 auto dve
= new DotVarExp(e
.loc
, e
, mt
.sym
.vthis
);
4144 dve
.type
= mt
.sym
.vthis
.type
.addMod(e
.type
.mod
);
4148 return noMember(mt
, sc
, e
, ident
, flag
& 1);
4150 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, s
))
4152 return noMember(mt
, sc
, e
, ident
, flag
);
4154 if (!s
.isFuncDeclaration()) // because of overloading
4156 s
.checkDeprecated(e
.loc
, sc
);
4157 if (auto d
= s
.isDeclaration())
4158 d
.checkDisabled(e
.loc
, sc
);
4162 if (auto em
= s
.isEnumMember())
4164 return em
.getVarExp(e
.loc
, sc
);
4166 if (auto v
= s
.isVarDeclaration())
4169 !v
.type
.deco
&& v
.inuse
)
4171 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
4172 e
.error("circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
4174 e
.error("forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
4175 return ErrorExp
.get();
4177 if (v
.type
.ty
== Terror
)
4179 e
.error("type of variable `%s` has errors", v
.toPrettyChars
);
4180 return ErrorExp
.get();
4183 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
4187 e
.error("circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
4188 return ErrorExp
.get();
4190 checkAccess(e
.loc
, sc
, null, v
);
4191 Expression ve
= new VarExp(e
.loc
, v
);
4192 ve
= ve
.expressionSemantic(sc
);
4197 if (auto t
= s
.getType())
4199 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
4202 TemplateMixin tm
= s
.isTemplateMixin();
4205 return new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, tm
)).expressionSemantic(sc
);
4208 TemplateDeclaration td
= s
.isTemplateDeclaration();
4210 Expression
toTemplateExp(TemplateDeclaration td
)
4212 if (e
.op
== EXP
.type
)
4213 e
= new TemplateExp(e
.loc
, td
);
4215 e
= new DotTemplateExp(e
.loc
, e
, td
);
4216 e
= e
.expressionSemantic(sc
);
4222 return toTemplateExp(td
);
4225 TemplateInstance ti
= s
.isTemplateInstance();
4228 if (!ti
.semanticRun
)
4230 ti
.dsymbolSemantic(sc
);
4231 if (!ti
.inst || ti
.errors
) // if template failed to expand
4233 return ErrorExp
.get();
4236 s
= ti
.inst
.toAlias();
4237 if (!s
.isTemplateInstance())
4239 if (e
.op
== EXP
.type
)
4240 e
= new ScopeExp(e
.loc
, ti
);
4242 e
= new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, ti
));
4243 return e
.expressionSemantic(sc
);
4246 if (s
.isImport() || s
.isModule() || s
.isPackage())
4248 e
= symbolToExp(s
, e
.loc
, sc
, false);
4252 OverloadSet o
= s
.isOverloadSet();
4255 auto oe
= new OverExp(e
.loc
, o
);
4256 if (e
.op
== EXP
.type
)
4260 return new DotExp(e
.loc
, e
, oe
);
4263 Declaration d
= s
.isDeclaration();
4266 e
.error("`%s.%s` is not a declaration", e
.toChars(), ident
.toChars());
4267 return ErrorExp
.get();
4270 if (e
.op
== EXP
.type
)
4275 if (TupleDeclaration tup
= d
.isTupleDeclaration())
4277 e
= new TupleExp(e
.loc
, tup
);
4278 e
= e
.expressionSemantic(sc
);
4282 if (mt
.sym
.classKind
== ClassKind
.objc
4283 && d
.isFuncDeclaration()
4284 && d
.isFuncDeclaration().isStatic
4285 && d
.isFuncDeclaration().objc
.selector
)
4287 auto classRef
= new ObjcClassReferenceExp(e
.loc
, mt
.sym
);
4288 return new DotVarExp(e
.loc
, classRef
, d
).expressionSemantic(sc
);
4290 else if (d
.needThis() && sc
.intypeof
!= 1)
4295 AggregateDeclaration ad
= d
.isMemberLocal();
4296 if (auto f
= hasThis(sc
))
4298 // This is almost same as getRightThis() in expressionsem.d
4301 /* returns: true to continue, false to return */
4302 if (f
.hasDualContext())
4304 if (f
.followInstantiationContext(ad
))
4306 e1
= new VarExp(e
.loc
, f
.vthis
);
4307 e1
= new PtrExp(e1
.loc
, e1
);
4308 e1
= new IndexExp(e1
.loc
, e1
, IntegerExp
.literal
!1);
4309 auto pd
= f
.toParent2().isDeclaration();
4311 t
= pd
.type
.toBasetype();
4312 e1
= getThisSkipNestedFuncs(e1
.loc
, sc
, f
.toParent2(), ad
, e1
, t
, d
, true);
4315 e
= new VarExp(e
.loc
, d
);
4321 e1
= new ThisExp(e
.loc
);
4322 e1
= e1
.expressionSemantic(sc
);
4324 t
= e1
.type
.toBasetype();
4325 ClassDeclaration cd
= e
.type
.isClassHandle();
4326 ClassDeclaration tcd
= t
.isClassHandle();
4327 if (cd
&& tcd
&& (tcd
== cd || cd
.isBaseOf(tcd
, null)))
4329 e
= new DotTypeExp(e1
.loc
, e1
, cd
);
4330 e
= new DotVarExp(e
.loc
, e
, d
);
4331 e
= e
.expressionSemantic(sc
);
4334 if (tcd
&& tcd
.isNested())
4336 /* e1 is the 'this' pointer for an inner class: tcd.
4337 * Rewrite it as the 'this' pointer for the outer class.
4339 auto vthis
= tcd
.followInstantiationContext(ad
) ? tcd
.vthis2
: tcd
.vthis
;
4340 e1
= new DotVarExp(e
.loc
, e1
, vthis
);
4341 e1
.type
= vthis
.type
;
4342 e1
.type
= e1
.type
.addMod(t
.mod
);
4343 // Do not call ensureStaticLinkTo()
4344 //e1 = e1.expressionSemantic(sc);
4346 // Skip up over nested functions, and get the enclosing
4348 e1
= getThisSkipNestedFuncs(e1
.loc
, sc
, tcd
.toParentP(ad
), ad
, e1
, t
, d
, true);
4351 e
= new VarExp(e
.loc
, d
);
4358 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
4359 if (d
.semanticRun
== PASS
.initial
)
4360 d
.dsymbolSemantic(null);
4362 // If static function, get the most visible overload.
4363 // Later on the call is checked for correctness.
4364 // https://issues.dlang.org/show_bug.cgi?id=12511
4366 if (auto fd
= d
.isFuncDeclaration())
4368 import dmd
.access
: mostVisibleOverload
;
4369 d2
= mostVisibleOverload(fd
, sc
._module
);
4372 checkAccess(e
.loc
, sc
, e
, d2
);
4373 if (d2
.isDeclaration())
4375 d
= cast(Declaration
)d2
;
4376 auto ve
= new VarExp(e
.loc
, d
);
4377 if (d
.isVarDeclaration() && d
.needThis())
4378 ve
.type
= d
.type
.addMod(e
.type
.mod
);
4381 else if (d2
.isTemplateDeclaration())
4383 return toTemplateExp(cast(TemplateDeclaration
)d2
);
4389 bool unreal
= e
.op
== EXP
.variable
&& (cast(VarExp
)e
).var
.isField();
4390 if (d
.isDataseg() || unreal
&& d
.isField())
4393 checkAccess(e
.loc
, sc
, e
, d
);
4394 Expression ve
= new VarExp(e
.loc
, d
);
4395 e
= unreal ? ve
: new CommaExp(e
.loc
, e
, ve
);
4396 e
= e
.expressionSemantic(sc
);
4400 e
= new DotVarExp(e
.loc
, e
, d
);
4401 e
= e
.expressionSemantic(sc
);
4407 case Tvector
: return visitVector (mt
.isTypeVector());
4408 case Tsarray
: return visitSArray (mt
.isTypeSArray());
4409 case Tstruct
: return visitStruct (mt
.isTypeStruct());
4410 case Tenum
: return visitEnum (mt
.isTypeEnum());
4411 case Terror
: return visitError (mt
.isTypeError());
4412 case Tarray
: return visitDArray (mt
.isTypeDArray());
4413 case Taarray
: return visitAArray (mt
.isTypeAArray());
4414 case Treference
: return visitReference(mt
.isTypeReference());
4415 case Tdelegate
: return visitDelegate (mt
.isTypeDelegate());
4416 case Tclass
: return visitClass (mt
.isTypeClass());
4418 default: return mt
.isTypeBasic()
4419 ?
visitBasic(cast(TypeBasic
)mt
)
4425 /************************
4426 * Get the default initialization expression for a type.
4428 * mt = the type for which the init expression is returned
4429 * loc = the location where the expression needs to be evaluated
4430 * isCfile = default initializers are different with C
4433 * The initialization expression for the type.
4435 extern (C
++) Expression
defaultInit(Type mt
, const ref Loc loc
, const bool isCfile
= false)
4437 Expression
visitBasic(TypeBasic mt
)
4439 static if (LOGDEFAULTINIT
)
4441 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt
.toChars(), isCfile
);
4443 dinteger_t value
= 0;
4448 value
= isCfile ?
0 : 0xFF;
4453 value
= isCfile ?
0 : 0xFFFF;
4462 return new RealExp(loc
, isCfile ? CTFloat
.zero
: target
.RealProperties
.nan
, mt
);
4468 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
4469 const cvalue
= isCfile ?
complex_t(CTFloat
.zero
, CTFloat
.zero
)
4470 : complex_t(target
.RealProperties
.nan
, target
.RealProperties
.nan
);
4471 return new ComplexExp(loc
, cvalue
, mt
);
4475 error(loc
, "`void` does not have a default initializer");
4476 return ErrorExp
.get();
4481 return new IntegerExp(loc
, value
, mt
);
4484 Expression
visitVector(TypeVector mt
)
4486 //printf("TypeVector::defaultInit()\n");
4487 assert(mt
.basetype
.ty
== Tsarray
);
4488 Expression e
= mt
.basetype
.defaultInit(loc
, isCfile
);
4489 auto ve
= new VectorExp(loc
, e
, mt
);
4491 ve
.dim
= cast(int)(mt
.basetype
.size(loc
) / mt
.elementType().size(loc
));
4495 Expression
visitSArray(TypeSArray mt
)
4497 static if (LOGDEFAULTINIT
)
4499 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt
.toChars(), isCfile
);
4501 if (mt
.next
.ty
== Tvoid
)
4502 return mt
.tuns8
.defaultInit(loc
, isCfile
);
4504 return mt
.next
.defaultInit(loc
, isCfile
);
4507 Expression
visitFunction(TypeFunction mt
)
4509 error(loc
, "`function` does not have a default initializer");
4510 return ErrorExp
.get();
4513 Expression
visitStruct(TypeStruct mt
)
4515 static if (LOGDEFAULTINIT
)
4517 printf("TypeStruct::defaultInit() '%s'\n", mt
.toChars());
4519 Declaration d
= new SymbolDeclaration(mt
.sym
.loc
, mt
.sym
);
4522 d
.storage_class |
= STC
.rvalue
; // https://issues.dlang.org/show_bug.cgi?id=14398
4523 return new VarExp(mt
.sym
.loc
, d
);
4526 Expression
visitEnum(TypeEnum mt
)
4528 static if (LOGDEFAULTINIT
)
4530 printf("TypeEnum::defaultInit() '%s'\n", mt
.toChars());
4532 // Initialize to first member of enum
4533 Expression e
= mt
.sym
.getDefaultValue(loc
);
4536 e
.type
= mt
; // to deal with const, immutable, etc., variants
4540 Expression
visitTuple(TypeTuple mt
)
4542 static if (LOGDEFAULTINIT
)
4544 printf("TypeTuple::defaultInit() '%s'\n", mt
.toChars());
4546 auto exps
= new Expressions(mt
.arguments
.length
);
4547 for (size_t i
= 0; i
< mt
.arguments
.length
; i
++)
4549 Parameter p
= (*mt
.arguments
)[i
];
4551 Expression e
= p
.type
.defaultInitLiteral(loc
);
4552 if (e
.op
== EXP
.error
)
4558 return new TupleExp(loc
, exps
);
4561 Expression
visitNoreturn(TypeNoreturn mt
)
4563 static if (LOGDEFAULTINIT
)
4565 printf("TypeNoreturn::defaultInit() '%s'\n", mt
.toChars());
4567 auto cond
= IntegerExp
.createBool(false);
4568 auto msg
= new StringExp(loc
, "Accessed expression of type `noreturn`");
4569 msg
.type
= Type
.tstring
;
4570 auto ae
= new AssertExp(loc
, cond
, msg
);
4577 case Tvector
: return visitVector (mt
.isTypeVector());
4578 case Tsarray
: return visitSArray (mt
.isTypeSArray());
4579 case Tfunction
: return visitFunction(mt
.isTypeFunction());
4580 case Tstruct
: return visitStruct (mt
.isTypeStruct());
4581 case Tenum
: return visitEnum (mt
.isTypeEnum());
4582 case Ttuple
: return visitTuple (mt
.isTypeTuple());
4584 case Tnull
: return new NullExp(Loc
.initial
, Type
.tnull
);
4586 case Terror
: return ErrorExp
.get();
4593 case Tclass
: return new NullExp(loc
, mt
);
4594 case Tnoreturn
: return visitNoreturn(mt
.isTypeNoreturn());
4596 default: return mt
.isTypeBasic() ?
4597 visitBasic(cast(TypeBasic
)mt
) :
4602 /******************************* Private *****************************************/
4606 /* Helper function for `typeToExpression`. Contains common code
4607 * for TypeQualified derived classes.
4609 Expression
typeToExpressionHelper(TypeQualified t
, Expression e
, size_t i
= 0)
4611 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
4612 foreach (id
; t
.idents
[i
.. t
.idents
.length
])
4614 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
4616 final switch (id
.dyncast())
4619 case DYNCAST
.identifier
:
4620 e
= new DotIdExp(e
.loc
, e
, cast(Identifier
)id
);
4623 // ... '. name!(tiargs)'
4624 case DYNCAST
.dsymbol
:
4625 auto ti
= (cast(Dsymbol
)id
).isTemplateInstance();
4627 e
= new DotTemplateInstanceExp(e
.loc
, e
, ti
.name
, ti
.tiargs
);
4631 case DYNCAST
.type
: // https://issues.dlang.org/show_bug.cgi?id=1215
4632 e
= new ArrayExp(t
.loc
, e
, new TypeExp(t
.loc
, cast(Type
)id
));
4636 case DYNCAST
.expression
: // https://issues.dlang.org/show_bug.cgi?id=1215
4637 e
= new ArrayExp(t
.loc
, e
, cast(Expression
)id
);
4640 case DYNCAST
.object
:
4642 case DYNCAST
.parameter
:
4643 case DYNCAST
.statement
:
4644 case DYNCAST
.condition
:
4645 case DYNCAST
.templateparameter
:
4646 case DYNCAST
.initializer
:
4653 /**************************
4654 * This evaluates exp while setting length to be the number
4655 * of elements in the tuple t.
4657 Expression
semanticLength(Scope
* sc
, Type t
, Expression exp
)
4659 if (auto tt
= t
.isTypeTuple())
4661 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, tt
);
4662 sym
.parent
= sc
.scopesym
;
4664 sc
= sc
.startCTFE();
4665 exp
= exp
.expressionSemantic(sc
);
4666 exp
= resolveProperties(sc
, exp
);
4672 sc
= sc
.startCTFE();
4673 exp
= exp
.expressionSemantic(sc
);
4674 exp
= resolveProperties(sc
, exp
);
4680 Expression
semanticLength(Scope
* sc
, TupleDeclaration tup
, Expression exp
)
4682 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, tup
);
4683 sym
.parent
= sc
.scopesym
;
4686 sc
= sc
.startCTFE();
4687 exp
= exp
.expressionSemantic(sc
);
4688 exp
= resolveProperties(sc
, exp
);
4695 /************************************
4696 * Transitively search a type for all function types.
4697 * If any function types with parameters are found that have parameter identifiers
4698 * or default arguments, remove those and create a new type stripped of those.
4699 * This is used to determine the "canonical" version of a type which is useful for
4704 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
4705 * the same as t but with no parameter identifiers or default arguments.
4707 Type
stripDefaultArgs(Type t
)
4709 static Parameters
* stripParams(Parameters
* parameters
)
4711 static Parameter
stripParameter(Parameter p
)
4713 Type t
= stripDefaultArgs(p
.type
);
4714 return (t
!= p
.type || p
.defaultArg || p
.ident || p
.userAttribDecl
)
4715 ?
new Parameter(p
.storageClass
, t
, null, null, null)
4721 foreach (i
, p
; *parameters
)
4723 Parameter ps
= stripParameter(p
);
4726 // Replace params with a copy we can modify
4727 Parameters
* nparams
= new Parameters(parameters
.length
);
4729 foreach (j
, ref np
; *nparams
)
4731 Parameter pj
= (*parameters
)[j
];
4738 Parameter nps
= stripParameter(pj
);
4739 np
= nps ? nps
: pj
;
4752 if (auto tf
= t
.isTypeFunction())
4754 Type tret
= stripDefaultArgs(tf
.next
);
4755 Parameters
* params
= stripParams(tf
.parameterList
.parameters
);
4756 if (tret
== tf
.next
&& params
== tf
.parameterList
.parameters
)
4758 TypeFunction tr
= tf
.copy().isTypeFunction();
4759 tr
.parameterList
.parameters
= params
;
4761 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
4764 else if (auto tt
= t
.isTypeTuple())
4766 Parameters
* args
= stripParams(tt
.arguments
);
4767 if (args
== tt
.arguments
)
4769 TypeTuple tr
= t
.copy().isTypeTuple();
4770 tr
.arguments
= args
;
4773 else if (t
.ty
== Tenum
)
4775 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
4780 Type tn
= t
.nextOf();
4781 Type n
= stripDefaultArgs(tn
);
4784 TypeNext tr
= cast(TypeNext
)t
.copy();
4790 /******************************
4791 * Get the value of the .max/.min property of `ed` as an Expression.
4792 * Lazily computes the value and caches it in maxval/minval.
4793 * Reports any errors.
4795 * ed = the EnumDeclaration being examined
4796 * loc = location to use for error messages
4797 * id = Id::max or Id::min
4799 * corresponding value of .max/.min
4801 Expression
getMaxMinValue(EnumDeclaration ed
, const ref Loc loc
, Identifier id
)
4803 //printf("EnumDeclaration::getMaxValue()\n");
4805 static Expression
pvalToResult(Expression e
, const ref Loc loc
)
4807 if (e
.op
!= EXP
.error
)
4815 Expression
* pval
= (id
== Id
.max
) ?
&ed
.maxval
: &ed
.minval
;
4817 Expression
errorReturn()
4819 *pval
= ErrorExp
.get();
4825 ed
.error(loc
, "recursive definition of `.%s` property", id
.toChars());
4826 return errorReturn();
4829 return pvalToResult(*pval
, loc
);
4832 dsymbolSemantic(ed
, ed
._scope
);
4834 return errorReturn();
4837 ed
.error(loc
, "is opaque and has no `.%s`", id
.toChars());
4838 return errorReturn();
4840 if (!(ed
.memtype
&& ed
.memtype
.isintegral()))
4842 ed
.error(loc
, "has no `.%s` property because base type `%s` is not an integral type",
4843 id
.toChars(), ed
.memtype ? ed
.memtype
.toChars() : "");
4844 return errorReturn();
4848 for (size_t i
= 0; i
< ed
.members
.length
; i
++)
4850 EnumMember em
= (*ed
.members
)[i
].isEnumMember();
4859 if (em
.semanticRun
< PASS
.semanticdone
)
4861 em
.error("is forward referenced looking for `.%s`", id
.toChars());
4873 /* In order to work successfully with UDTs,
4874 * build expressions to do the comparisons,
4875 * and let the semantic analyzer and constant
4876 * folder give us the result.
4883 Expression e
= em
.value
;
4884 Expression ec
= new CmpExp(id
== Id
.max ? EXP
.greaterThan
: EXP
.lessThan
, em
.loc
, e
, *pval
);
4886 ec
= ec
.expressionSemantic(em
._scope
);
4888 ec
= ec
.ctfeInterpret();
4889 if (ec
.op
== EXP
.error
)
4898 return ed
.errors ?
errorReturn() : pvalToResult(*pval
, loc
);
4901 /******************************************
4902 * Compile the MixinType, returning the type or expression AST.
4904 * Doesn't run semantic() on the returned object.
4906 * tm = mixin to compile as a type or expression
4907 * loc = location for error messages
4910 * null if error, else RootObject AST as parsed
4912 RootObject
compileTypeMixin(TypeMixin tm
, Loc loc
, Scope
* sc
)
4915 if (expressionsToString(buf
, sc
, tm
.exps
))
4918 const errors
= global
.errors
;
4919 const len
= buf
.length
;
4921 const str = buf
.extractSlice()[0 .. len
];
4922 scope p
= new Parser
!ASTCodegen(loc
, sc
._module
, str, false, global
.errorSink
);
4924 //printf("p.loc.linnum = %d\n", p.loc.linnum);
4926 auto o
= p
.parseTypeOrAssignExp(TOK
.endOfFile
);
4927 if (errors
!= global
.errors
)
4929 assert(global
.errors
!= errors
); // should have caught all these cases
4932 if (p
.token
.value
!= TOK
.endOfFile
)
4934 .error(loc
, "incomplete mixin type `%s`", str.ptr
);