2 * Semantic analysis for D types.
4 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d)
8 * Documentation: https://dlang.org/phobos/dmd_typesem.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d
14 import core
.checkedint
;
15 import core
.stdc
.string
;
16 import core
.stdc
.stdio
;
22 import dmd
.arraytypes
;
23 import dmd
.astcodegen
;
27 import dmd
.declaration
;
30 import dmd
.dinterpret
;
36 import dmd
.dsymbolsem
;
41 import dmd
.expression
;
42 import dmd
.expressionsem
;
48 import dmd
.identifier
;
60 import dmd
.root
.complex
;
61 import dmd
.root
.ctfloat
;
63 import dmd
.common
.outbuffer
;
64 import dmd
.rootobject
;
65 import dmd
.root
.string
;
66 import dmd
.root
.stringtable
;
69 import dmd
.sideeffect
;
73 /*************************************
74 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
75 * Setting one of pe/pt/ps.
77 * loc = location for error messages
79 * s = symbol being indexed - could be a tuple, could be an expression
80 * pe = set if s[oindex] is an Expression, otherwise null
81 * pt = set if s[oindex] is a Type, otherwise null
82 * ps = set if s[oindex] is a Dsymbol, otherwise null
83 * oindex = index into s
85 private void resolveTupleIndex(const ref Loc loc
, Scope
* sc
, Dsymbol s
, out Expression pe
, out Type pt
, out Dsymbol ps
, RootObject oindex
)
87 auto tup
= s
.isTupleDeclaration();
89 auto eindex
= isExpression(oindex
);
90 auto tindex
= isType(oindex
);
91 auto sindex
= isDsymbol(oindex
);
95 // It's really an index expression
97 eindex
= new TypeExp(loc
, tindex
);
99 eindex
= symbolToExp(sindex
, loc
, sc
, false);
100 Expression e
= new IndexExp(loc
, symbolToExp(s
, loc
, sc
, false), eindex
);
101 e
= e
.expressionSemantic(sc
);
102 resolveExp(e
, pt
, pe
, ps
);
106 // Convert oindex to Expression, then try to resolve to constant.
108 tindex
.resolve(loc
, sc
, eindex
, tindex
, sindex
);
110 eindex
= symbolToExp(sindex
, loc
, sc
, false);
113 .error(loc
, "index `%s` is not an expression", oindex
.toChars());
118 eindex
= semanticLength(sc
, tup
, eindex
);
119 eindex
= eindex
.ctfeInterpret();
120 if (eindex
.op
== EXP
.error
)
125 const(uinteger_t
) d
= eindex
.toUInteger();
126 if (d
>= tup
.objects
.length
)
128 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", d
, cast(ulong)tup
.objects
.length
);
133 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
135 if (auto t
= isType(o
))
136 pt
= t
.typeSemantic(loc
, sc
);
137 if (auto e
= isExpression(o
))
138 resolveExp(e
, pt
, pe
, ps
);
141 /*************************************
142 * Takes an array of Identifiers and figures out if
143 * it represents a Type, Expression, or Dsymbol.
145 * mt = array of identifiers
146 * loc = location for error messages
148 * s = symbol to start search at
150 * pe = set if expression otherwise null
151 * pt = set if type otherwise null
152 * ps = set if symbol otherwise null
153 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
155 private void resolveHelper(TypeQualified mt
, const ref Loc loc
, Scope
* sc
, Dsymbol s
, Dsymbol scopesym
,
156 out Expression pe
, out Type pt
, out Dsymbol ps
, bool intypeid
= false)
160 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc
, mt
.toChars());
162 printf("\tscopesym = '%s'\n", scopesym
.toChars());
167 /* Look for what user might have intended
169 const p
= mt
.mutableOf().unSharedOf().toChars();
170 auto id
= Identifier
.idPool(p
[0 .. strlen(p
)]);
171 if (const n
= importHint(id
.toString()))
172 error(loc
, "`%s` is not defined, perhaps `import %.*s;` ?", p
, cast(int)n
.length
, n
.ptr
);
173 else if (auto s2
= sc
.search_correct(id
))
174 error(loc
, "undefined identifier `%s`, did you mean %s `%s`?", p
, s2
.kind(), s2
.toChars());
175 else if (const q
= Scope
.search_correct_C(id
))
176 error(loc
, "undefined identifier `%s`, did you mean `%s`?", p
, q
);
177 else if ((id
== Id
.This
&& sc
.getStructClassScope()) ||
178 (id
== Id
._super
&& sc
.getClassScope()))
179 error(loc
, "undefined identifier `%s`, did you mean `typeof(%s)`?", p
, p
);
181 error(loc
, "undefined identifier `%s`", p
);
187 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
188 Declaration d
= s
.isDeclaration();
189 if (d
&& (d
.storage_class
& STC
.templateparameter
))
193 // check for deprecated or disabled aliases
194 // functions are checked after overloading
195 // templates are checked after matching constraints
196 if (!s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
197 s
.checkDeprecated(loc
, sc
);
199 d
.checkDisabled(loc
, sc
, true);
202 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
203 for (size_t i
= 0; i
< mt
.idents
.length
; i
++)
205 RootObject id
= mt
.idents
[i
];
206 switch (id
.dyncast()) with (DYNCAST
)
213 resolveTupleIndex(loc
, sc
, s
, ex
, tx
, sx
, id
);
220 ex
= new TypeExp(loc
, tx
);
223 ex
= typeToExpressionHelper(mt
, ex
, i
+ 1);
224 ex
= ex
.expressionSemantic(sc
);
225 resolveExp(ex
, pt
, pe
, ps
);
231 Type t
= s
.getType(); // type symbol, type alias, or type tuple?
232 uint errorsave
= global
.errors
;
233 SearchOptFlags flags
= t
is null ? SearchOpt
.localsOnly
: SearchOpt
.ignorePrivateImports
;
235 Dsymbol sm
= s
.searchX(loc
, sc
, id
, flags
);
238 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, sm
))
240 .error(loc
, "`%s` is not visible from module `%s`", sm
.toPrettyChars(), sc
._module
.toChars());
243 // Same check as in dotIdSemanticProp(DotIdExp)
244 else if (sm
.isPackage() && checkAccess(sc
, sm
.isPackage()))
246 // @@@DEPRECATED_2.106@@@
247 // Should be an error in 2.106. Just remove the deprecation call
248 // and uncomment the null assignment
249 deprecation(loc
, "%s %s is not accessible here, perhaps add 'static import %s;'", sm
.kind(), sm
.toPrettyChars(), sm
.toPrettyChars());
253 if (global
.errors
!= errorsave
)
262 VarDeclaration v
= s
.isVarDeclaration();
263 FuncDeclaration f
= s
.isFuncDeclaration();
264 if (intypeid ||
!v
&& !f
)
265 e
= symbolToExp(s
, loc
, sc
, true);
267 e
= new VarExp(loc
, s
.isDeclaration(), true);
269 e
= typeToExpressionHelper(mt
, e
, i
);
270 e
= e
.expressionSemantic(sc
);
271 resolveExp(e
, pt
, pe
, ps
);
274 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
275 if (intypeid
&& !t
&& sm
&& sm
.needThis())
278 if (VarDeclaration v
= s
.isVarDeclaration())
280 // https://issues.dlang.org/show_bug.cgi?id=19913
281 // v.type would be null if it is a forward referenced member.
283 v
.dsymbolSemantic(sc
);
284 if (v
.storage_class
& (STC
.const_ | STC
.immutable_ | STC
.manifest
) ||
285 v
.type
.isConst() || v
.type
.isImmutable())
287 // https://issues.dlang.org/show_bug.cgi?id=13087
288 // this.field is not constant always
289 if (!v
.isThisDeclaration())
297 if (sm
.isAliasDeclaration
)
298 sm
.checkDeprecated(loc
, sc
);
302 if (auto em
= s
.isEnumMember())
304 // It's not a type, it's an expression
305 pe
= em
.getVarExp(loc
, sc
);
308 if (auto v
= s
.isVarDeclaration())
310 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
311 * because some variables used in type context need to prevent lowering
312 * to a literal or contextful expression. For example:
314 * enum a = 1; alias b = a;
315 * template X(alias e){ alias v = e; } alias x = X!(1);
316 * struct S { int v; alias w = v; }
317 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
318 * // because getDsymbol() need to work in AliasDeclaration::semantic().
321 !v
.type
.deco
&& v
.inuse
)
323 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
324 error(loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
326 error(loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
330 if (v
.type
.ty
== Terror
)
333 pe
= new VarExp(loc
, v
);
336 if (auto fld = s
.isFuncLiteralDeclaration())
338 //printf("'%s' is a function literal\n", fld.toChars());
339 auto e
= new FuncExp(loc
, fld);
340 pe
= e
.expressionSemantic(sc
);
345 if (FuncDeclaration fd
= s
.isFuncDeclaration())
347 pe
= new DsymbolExp(loc
, fd
);
362 if (auto ti
= t
.isTypeInstance())
363 if (ti
!= mt
&& !ti
.deco
)
365 if (!ti
.tempinst
.errors
)
366 error(loc
, "forward reference to `%s`", ti
.toChars());
377 /***************************************
378 * Search for identifier id as a member of `this`.
379 * `id` may be a template instance.
382 * loc = location to print the error messages
383 * sc = the scope where the symbol is located
384 * id = the id of the symbol
385 * flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports`
388 * symbol found, NULL if not
390 private Dsymbol
searchX(Dsymbol dsym
, const ref Loc loc
, Scope
* sc
, RootObject id
, SearchOptFlags flags
)
392 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
393 Dsymbol s
= dsym
.toAlias();
395 if (Declaration d
= s
.isDeclaration())
399 .error(loc
, "circular reference to `%s`", d
.toPrettyChars());
403 switch (id
.dyncast())
405 case DYNCAST
.identifier
:
406 sm
= s
.search(loc
, cast(Identifier
)id
, flags
);
408 case DYNCAST
.dsymbol
:
410 // It's a template instance
411 //printf("\ttemplate instance id\n");
412 Dsymbol st
= cast(Dsymbol
)id
;
413 TemplateInstance ti
= st
.isTemplateInstance();
414 sm
= s
.search(loc
, ti
.name
);
418 TemplateDeclaration td
= sm
.isTemplateDeclaration();
420 return null; // error but handled later
423 ti
.dsymbolSemantic(sc
);
428 case DYNCAST
.expression
:
435 /***************************************************
436 * Determine if type t is copyable.
440 * true if we can copy it
442 bool isCopyable(Type t
)
444 //printf("isCopyable() %s\n", t.toChars());
445 if (auto ts
= t
.isTypeStruct())
447 if (ts
.sym
.postblit
&&
448 ts
.sym
.postblit
.storage_class
& STC
.disable
)
450 if (ts
.sym
.hasCopyCtor
)
452 // check if there is a matching overload of the copy constructor and whether it is disabled or not
453 // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
454 Dsymbol ctor
= search_function(ts
.sym
, Id
.ctor
);
456 scope el
= new IdentifierExp(Loc
.initial
, Id
.p
); // dummy lvalue
458 Expressions
* args
= new Expressions();
460 FuncDeclaration f
= resolveFuncCall(Loc
.initial
, null, ctor
, null, cast()ts
, ArgumentList(args
), FuncResolveFlag
.quiet
);
461 if (!f || f
.storage_class
& STC
.disable
)
468 /************************************
469 * Determine mutability of indirections in (ref) t.
471 * Returns: When the type has any mutable indirections, returns 0.
472 * When all indirections are immutable, returns 2.
473 * Otherwise, when the type has const/inout indirections, returns 1.
476 * isref = if true, check `ref t`; otherwise, check just `t`
477 * t = the type that is being checked
479 int mutabilityOfType(bool isref
, Type t
)
483 if (t
.mod
& MODFlags
.immutable_
)
485 if (t
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
492 if (!t
.hasPointers() || t
.mod
& MODFlags
.immutable_
)
495 /* Accept immutable(T)[] and immutable(T)* as being strongly pure
497 if (t
.ty
== Tarray || t
.ty
== Tpointer
)
499 Type tn
= t
.nextOf().toBasetype();
500 if (tn
.mod
& MODFlags
.immutable_
)
502 if (tn
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
506 /* The rest of this is too strict; fix later.
507 * For example, the only pointer members of a struct may be immutable,
508 * which would maintain strong purity.
509 * (Just like for dynamic arrays and pointers above.)
511 if (t
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
514 /* Should catch delegates and function pointers, and fold in their purity
519 /********************************************
520 * Set 'purity' field of 'typeFunction'.
521 * Do this lazily, as the parameter types might be forward referenced.
523 void purityLevel(TypeFunction typeFunction
)
525 TypeFunction tf
= typeFunction
;
526 if (tf
.purity
!= PURE
.fwdref
)
529 typeFunction
.purity
= PURE
.const_
; // assume strong until something weakens it
531 /* Evaluate what kind of purity based on the modifiers for the parameters
533 foreach (i
, fparam
; tf
.parameterList
)
535 Type t
= fparam
.type
;
539 if (fparam
.storageClass
& (STC
.lazy_ | STC
.out_
))
541 typeFunction
.purity
= PURE
.weak
;
544 const pref
= (fparam
.storageClass
& STC
.ref_
) != 0;
545 if (mutabilityOfType(pref
, t
) == 0)
546 typeFunction
.purity
= PURE
.weak
;
549 tf
.purity
= typeFunction
.purity
;
552 /******************************************
553 * We've mistakenly parsed `t` as a type.
554 * Redo `t` as an Expression only if there are no type modifiers.
558 * t redone as Expression, null if cannot
560 Expression
typeToExpression(Type t
)
562 static Expression
visitSArray(TypeSArray t
)
564 if (auto e
= t
.next
.typeToExpression())
565 return new ArrayExp(t
.dim
.loc
, e
, t
.dim
);
569 static Expression
visitAArray(TypeAArray t
)
571 if (auto e
= t
.next
.typeToExpression())
573 if (auto ei
= t
.index
.typeToExpression())
574 return new ArrayExp(t
.loc
, e
, ei
);
579 static Expression
visitIdentifier(TypeIdentifier t
)
581 return typeToExpressionHelper(t
, new IdentifierExp(t
.loc
, t
.ident
));
584 static Expression
visitInstance(TypeInstance t
)
586 return typeToExpressionHelper(t
, new ScopeExp(t
.loc
, t
.tempinst
));
589 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
590 static Expression
visitMixin(TypeMixin t
)
592 return new TypeExp(t
.loc
, t
);
599 case Tsarray
: return visitSArray(t
.isTypeSArray());
600 case Taarray
: return visitAArray(t
.isTypeAArray());
601 case Tident
: return visitIdentifier(t
.isTypeIdentifier());
602 case Tinstance
: return visitInstance(t
.isTypeInstance());
603 case Tmixin
: return visitMixin(t
.isTypeMixin());
604 default: return null;
608 /*************************************
609 * https://issues.dlang.org/show_bug.cgi?id=14488
610 * Check if the inner most base type is complex or imaginary.
611 * Should only give alerts when set to emit transitional messages.
613 * type = type to check
614 * loc = The source location.
615 * sc = scope of the type
617 extern (D
) bool checkComplexTransition(Type type
, const ref Loc loc
, Scope
* sc
)
619 if (sc
.isDeprecated())
621 // Don't complain if we're inside a template constraint
622 // https://issues.dlang.org/show_bug.cgi?id=21831
623 if (sc
.flags
& SCOPE
.constraint
)
626 Type t
= type
.baseElemOf();
627 while (t
.ty
== Tpointer || t
.ty
== Tarray
)
628 t
= t
.nextOf().baseElemOf();
630 // Basetype is an opaque enum, nothing to check.
631 if (t
.ty
== Tenum
&& !(cast(TypeEnum
)t
).sym
.memtype
)
634 if (t
.isimaginary() || t
.iscomplex())
636 if (sc
.flags
& SCOPE
.Cfile
)
637 return true; // complex/imaginary not deprecated in C code
659 // @@@DEPRECATED_2.117@@@
660 // Deprecated in 2.097 - Can be made an error from 2.117.
661 // The deprecation period is longer than usual as `cfloat`,
662 // `cdouble`, and `creal` were quite widely used.
665 deprecation(loc
, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
666 type
.toChars(), rt
.toChars());
671 deprecation(loc
, "use of imaginary type `%s` is deprecated, use `%s` instead",
672 type
.toChars(), rt
.toChars());
679 /********************************
680 * 'args' are being matched to function type 'tf'
681 * Determine match level.
684 * tthis = type of `this` pointer, null if not member function
685 * argumentList = arguments to function call
686 * flag = 1: performing a partial ordering match
687 * errorHelper = delegate to call for error messages
692 extern (D
) MATCH
callMatch(TypeFunction tf
, Type tthis
, ArgumentList argumentList
, int flag
= 0, void delegate(const(char)*) scope errorHelper
= null, Scope
* sc
= null)
694 //printf("TypeFunction::callMatch() %s\n", tf.toChars());
695 MATCH match
= MATCH
.exact
; // assume exact match
701 if (t
.toBasetype().ty
== Tpointer
)
702 t
= t
.toBasetype().nextOf(); // change struct* to struct
705 if (MODimplicitConv(t
.mod
, tf
.mod
))
706 match
= MATCH
.constant
;
707 else if ((tf
.mod
& MODFlags
.wild
) && MODimplicitConv(t
.mod
, (tf
.mod
& ~MODFlags
.wild
) | MODFlags
.const_
))
709 match
= MATCH
.constant
;
712 return MATCH
.nomatch
;
717 wildmatch |
= MODFlags
.wild
;
718 else if (t
.isConst())
719 wildmatch |
= MODFlags
.const_
;
720 else if (t
.isImmutable())
721 wildmatch |
= MODFlags
.immutable_
;
723 wildmatch |
= MODFlags
.mutable
;
727 ParameterList
* parameterList
= &tf
.parameterList
;
728 const nparams
= parameterList
.length
;
729 if (argumentList
.length
> nparams
)
731 if (parameterList
.varargs
== VarArg
.none
)
733 // suppress early exit if an error message is wanted,
734 // so we can check any matching args are valid
736 return MATCH
.nomatch
;
738 // too many args; no match
739 match
= MATCH
.convert
; // match ... with a "conversion" match level
742 // https://issues.dlang.org/show_bug.cgi?id=22997
743 if (parameterList
.varargs
== VarArg
.none
&& nparams
> argumentList
.length
&& !parameterList
.hasDefaultArgs
)
748 buf
.printf("too few arguments, expected %d, got %d", cast(int)nparams
, cast(int)argumentList
.length
);
749 errorHelper(buf
.peekChars());
751 return MATCH
.nomatch
;
753 const(char)* failMessage
;
754 const(char)** pMessage
= errorHelper ?
&failMessage
: null;
755 auto resolvedArgs
= tf
.resolveNamedArgs(argumentList
, pMessage
);
761 errorHelper(failMessage
);
762 return MATCH
.nomatch
;
765 // if no message was provided, it was because of overflow which will be diagnosed below
766 match
= MATCH
.nomatch
;
767 args
= argumentList
.arguments ?
(*argumentList
.arguments
)[] : null;
771 args
= (*resolvedArgs
)[];
774 foreach (u
, p
; *parameterList
)
776 if (u
>= args
.length
)
779 Expression arg
= args
[u
];
781 continue; // default argument
784 Type targ
= arg
.type
;
786 if (!(p
.isLazy() && tprm
.ty
== Tvoid
&& targ
.ty
!= Tvoid
))
788 const isRef
= p
.isReference();
789 wildmatch |
= targ
.deduceWild(tprm
, isRef
);
794 /* Calculate wild matching modifier
796 if (wildmatch
& MODFlags
.const_ || wildmatch
& (wildmatch
- 1))
797 wildmatch
= MODFlags
.const_
;
798 else if (wildmatch
& MODFlags
.immutable_
)
799 wildmatch
= MODFlags
.immutable_
;
800 else if (wildmatch
& MODFlags
.wild
)
801 wildmatch
= MODFlags
.wild
;
804 assert(wildmatch
& MODFlags
.mutable
);
805 wildmatch
= MODFlags
.mutable
;
809 foreach (u
, p
; *parameterList
)
815 // One or more arguments remain
818 Expression arg
= args
[u
];
820 continue; // default argument
821 m
= argumentMatchParameter(tf
, p
, arg
, wildmatch
, flag
, sc
, pMessage
);
823 else if (p
.defaultArg
)
826 /* prefer matching the element type rather than the array
827 * type when more arguments are present with T[]...
829 if (parameterList
.varargs
== VarArg
.typesafe
&& u
+ 1 == nparams
&& args
.length
> nparams
)
832 //printf("\tm = %d\n", m);
833 if (m
== MATCH
.nomatch
) // if no match
836 if (parameterList
.varargs
== VarArg
.typesafe
&& u
+ 1 == nparams
) // if last varargs param
838 auto trailingArgs
= args
[u
.. $];
839 if (auto vmatch
= matchTypeSafeVarArgs(tf
, p
, trailingArgs
, pMessage
))
840 return vmatch
< match ? vmatch
: match
;
841 // Error message was already generated in `matchTypeSafeVarArgs`
843 errorHelper(failMessage
);
844 return MATCH
.nomatch
;
846 if (pMessage
&& u
>= args
.length
)
847 *pMessage
= tf
.getMatchError("missing argument for parameter #%d: `%s`",
848 u
+ 1, parameterToChars(p
, tf
, false));
849 // If an error happened previously, `pMessage` was already filled
850 else if (pMessage
&& !*pMessage
)
851 *pMessage
= tf
.getParamError(args
[u
], p
);
854 errorHelper(*pMessage
);
855 return MATCH
.nomatch
;
858 match
= m
; // pick worst match
861 if (errorHelper
&& !parameterList
.varargs
&& args
.length
> nparams
)
863 // all parameters had a match, but there are surplus args
864 errorHelper(tf
.getMatchError("expected %d argument(s), not %d", nparams
, args
.length
));
865 return MATCH
.nomatch
;
867 //printf("match = %d\n", match);
872 * Used by `callMatch` to check if the copy constructor may be called to
875 * This is done by seeing if a call to the copy constructor can be made:
877 * typeof(tprm) __copytmp;
878 * copytmp.__copyCtor(arg);
881 private extern(D
) bool isCopyConstructorCallable (StructDeclaration argStruct
,
882 Expression arg
, Type tprm
, Scope
* sc
, const(char)** pMessage
)
884 auto tmp
= new VarDeclaration(arg
.loc
, tprm
, Identifier
.generateId("__copytmp"), null);
885 tmp
.storage_class
= STC
.rvalue | STC
.temp | STC
.ctfe
;
886 tmp
.dsymbolSemantic(sc
);
887 Expression ve
= new VarExp(arg
.loc
, tmp
);
888 Expression e
= new DotIdExp(arg
.loc
, ve
, Id
.ctor
);
889 e
= new CallExp(arg
.loc
, e
, arg
);
890 //printf("e = %s\n", e.toChars());
891 if (dmd
.expressionsem
.trySemantic(e
, sc
))
896 /* https://issues.dlang.org/show_bug.cgi?id=22202
898 * If a function was deduced by semantic on the CallExp,
899 * it means that resolveFuncCall completed succesfully.
900 * Therefore, there exists a callable copy constructor,
901 * however, it cannot be called because scope constraints
902 * such as purity, safety or nogc.
905 auto callExp
= e
.isCallExp();
906 if (auto f
= callExp
.f
)
909 if (!f
.isPure
&& sc
.func
.setImpure())
911 if (!f
.isSafe() && !f
.isTrusted() && sc
.setUnsafe())
913 if (!f
.isNogc
&& sc
.func
.setGC(arg
.loc
, null))
915 if (f
.isDisabled() && !f
.isGenerated())
917 /* https://issues.dlang.org/show_bug.cgi?id=24301
918 * Copy constructor is explicitly disabled
920 buf
.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`",
926 buf
.printf("`%s` copy constructor cannot be called from a `%s` context", f
.type
.toChars(), s
.ptr
);
928 else if (f
.isGenerated() && f
.isDisabled())
930 /* https://issues.dlang.org/show_bug.cgi?id=23097
931 * Compiler generated copy constructor failed.
933 buf
.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
934 argStruct
.toChars());
938 /* Although a copy constructor may exist, no suitable match was found.
939 * i.e: `inout` constructor creates `const` object, not mutable.
940 * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
948 buf
.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
949 argStruct
.toChars(), arg
.type
.toChars(), tprm
.toChars());
952 *pMessage
= buf
.extractChars();
958 * Match a single parameter to an argument.
960 * This function is called by `TypeFunction.callMatch` while iterating over
961 * the list of parameter. Here we check if `arg` is a match for `p`,
962 * which is mostly about checking if `arg.type` converts to `p`'s type
963 * and some check about value reference.
966 * tf = The `TypeFunction`, only used for error reporting
967 * p = The parameter of `tf` being matched
968 * arg = Argument being passed (bound) to `p`
969 * wildmatch = Wild (`inout`) matching level, derived from the full argument list
970 * flag = A non-zero value means we're doing a partial ordering check
971 * (no value semantic check)
972 * sc = Scope we are in
973 * pMessage = A buffer to write the error in, or `null`
975 * Returns: Whether `trailingArgs` match `p`.
977 private extern(D
) MATCH
argumentMatchParameter (TypeFunction tf
, Parameter p
,
978 Expression arg
, ubyte wildmatch
, int flag
, Scope
* sc
, const(char)** pMessage
)
980 //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
982 Type targ
= arg
.type
;
983 Type tprm
= wildmatch ? p
.type
.substWildTo(wildmatch
) : p
.type
;
985 if (p
.isLazy() && tprm
.ty
== Tvoid
&& targ
.ty
!= Tvoid
)
989 // for partial ordering, value is an irrelevant mockup, just look at the type
990 m
= targ
.implicitConvTo(tprm
);
994 const isRef
= p
.isReference();
995 StructDeclaration argStruct
, prmStruct
;
997 // first look for a copy constructor
998 if (arg
.isLvalue() && !isRef
&& targ
.ty
== Tstruct
&& tprm
.ty
== Tstruct
)
1000 // if the argument and the parameter are of the same unqualified struct type
1001 argStruct
= (cast(TypeStruct
)targ
).sym
;
1002 prmStruct
= (cast(TypeStruct
)tprm
).sym
;
1005 // check if the copy constructor may be called to copy the argument
1006 if (argStruct
&& argStruct
== prmStruct
&& argStruct
.hasCopyCtor
)
1008 if (!isCopyConstructorCallable(argStruct
, arg
, tprm
, sc
, pMessage
))
1009 return MATCH
.nomatch
;
1014 import dmd
.dcast
: cimplicitConvTo
;
1015 m
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? arg
.cimplicitConvTo(tprm
) : arg
.implicitConvTo(tprm
);
1019 // Non-lvalues do not match ref or out parameters
1020 if (p
.isReference())
1022 // https://issues.dlang.org/show_bug.cgi?id=13783
1023 // Don't use toBasetype() to handle enum types.
1026 //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
1028 if (m
&& !arg
.isLvalue())
1030 if (p
.storageClass
& STC
.out_
)
1032 if (pMessage
) *pMessage
= tf
.getParamError(arg
, p
);
1033 return MATCH
.nomatch
;
1036 if (arg
.op
== EXP
.string_
&& tp
.ty
== Tsarray
)
1038 if (ta
.ty
!= Tsarray
)
1040 Type tn
= tp
.nextOf().castMod(ta
.nextOf().mod
);
1041 dinteger_t dim
= (cast(StringExp
)arg
).len
;
1042 ta
= tn
.sarrayOf(dim
);
1045 else if (arg
.op
== EXP
.slice
&& tp
.ty
== Tsarray
)
1047 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1048 if (ta
.ty
!= Tsarray
)
1050 Type tn
= ta
.nextOf();
1051 dinteger_t dim
= (cast(TypeSArray
)tp
).dim
.toUInteger();
1052 ta
= tn
.sarrayOf(dim
);
1055 else if (p
.storageClass
& STC
.constscoperef
)
1057 // Allow converting a literal to an `in` which is `ref`
1058 if (arg
.op
== EXP
.arrayLiteral
&& tp
.ty
== Tsarray
)
1060 Type tn
= tp
.nextOf();
1061 dinteger_t dim
= (cast(TypeSArray
)tp
).dim
.toUInteger();
1062 ta
= tn
.sarrayOf(dim
);
1065 // Need to make this a rvalue through a temporary
1068 else if (global
.params
.rvalueRefParam
!= FeatureState
.enabled ||
1069 p
.storageClass
& STC
.out_ ||
1070 !arg
.type
.isCopyable()) // can't copy to temp for ref parameter
1072 if (pMessage
) *pMessage
= tf
.getParamError(arg
, p
);
1073 return MATCH
.nomatch
;
1077 /* in functionParameters() we'll convert this
1078 * rvalue into a temporary
1084 /* If the match is not already perfect or if the arg
1085 is not a lvalue then try the `alias this` chain
1086 see https://issues.dlang.org/show_bug.cgi?id=15674
1087 and https://issues.dlang.org/show_bug.cgi?id=21905
1089 if (ta
!= tp ||
!arg
.isLvalue())
1091 Type firsttab
= ta
.toBasetype();
1094 Type tab
= ta
.toBasetype();
1095 Type tat
= tab
.aliasthisOf();
1096 if (!tat ||
!tat
.implicitConvTo(tprm
))
1098 if (tat
== tab || tat
== firsttab
)
1104 /* A ref variable should work like a head-const reference.
1106 * ref T <- an lvalue of const(T) argument
1107 * ref T[dim] <- an lvalue of const(T[dim]) argument
1109 if (!ta
.constConv(tp
))
1111 if (pMessage
) *pMessage
= tf
.getParamError(arg
, p
);
1112 return MATCH
.nomatch
;
1118 // arguments get specially formatted
1119 private const(char)* getParamError(TypeFunction tf
, Expression arg
, Parameter par
)
1121 if (global
.gag
&& !global
.params
.v
.showGaggedErrors
)
1123 // show qualification when toChars() is the same but types are different
1124 // https://issues.dlang.org/show_bug.cgi?id=19948
1125 // when comparing the type with strcmp, we need to drop the qualifier
1126 bool qual
= !arg
.type
.mutableOf().equals(par
.type
.mutableOf()) &&
1127 strcmp(arg
.type
.mutableOf().toChars(), par
.type
.mutableOf().toChars()) == 0;
1128 auto at
= qual ? arg
.type
.toPrettyChars(true) : arg
.type
.toChars();
1130 // only mention rvalue if it's relevant
1131 const rv
= !arg
.isLvalue() && par
.isReference();
1132 buf
.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
1133 rv ?
"rvalue ".ptr
: "".ptr
, arg
.toChars(), at
,
1134 parameterToChars(par
, tf
, qual
));
1135 return buf
.extractChars();
1139 * Match the remaining arguments `trailingArgs` with parameter `p`.
1141 * Assume we already checked that `p` is the last parameter of `tf`,
1142 * and we want to know whether the arguments would match `p`.
1145 * tf = The `TypeFunction`, only used for error reporting
1146 * p = The last parameter of `tf` which is variadic
1147 * trailingArgs = The remaining arguments that should match `p`
1148 * pMessage = A buffer to write the error in, or `null`
1150 * Returns: Whether `trailingArgs` match `p`.
1152 private extern(D
) MATCH
matchTypeSafeVarArgs(TypeFunction tf
, Parameter p
,
1153 Expression
[] trailingArgs
, const(char)** pMessage
)
1155 Type tb
= p
.type
.toBasetype();
1160 TypeSArray tsa
= cast(TypeSArray
)tb
;
1161 dinteger_t sz
= tsa
.dim
.toInteger();
1162 if (sz
!= trailingArgs
.length
)
1165 *pMessage
= tf
.getMatchError("expected %llu variadic argument(s), not %zu",
1166 sz
, trailingArgs
.length
);
1167 return MATCH
.nomatch
;
1172 MATCH match
= MATCH
.exact
;
1173 TypeArray ta
= cast(TypeArray
)tb
;
1174 foreach (arg
; trailingArgs
)
1179 /* If lazy array of delegates,
1180 * convert arg(s) to delegate(s)
1182 Type tret
= p
.isLazyArray();
1185 if (ta
.next
.equals(arg
.type
))
1187 else if (tret
.toBasetype().ty
== Tvoid
)
1191 m
= arg
.implicitConvTo(tret
);
1192 if (m
== MATCH
.nomatch
)
1193 m
= arg
.implicitConvTo(ta
.next
);
1197 m
= arg
.implicitConvTo(ta
.next
);
1199 if (m
== MATCH
.nomatch
)
1201 if (pMessage
) *pMessage
= tf
.getParamError(arg
, p
);
1202 return MATCH
.nomatch
;
1210 // We leave it up to the actual constructor call to do the matching.
1214 // We can have things as `foo(int[int] wat...)` but they only match
1215 // with an associative array proper.
1216 if (pMessage
&& trailingArgs
.length
) *pMessage
= tf
.getParamError(trailingArgs
[0], p
);
1217 return MATCH
.nomatch
;
1221 /***************************************
1222 * Return !=0 if type has pointers that need to
1223 * be scanned by the GC during a collection cycle.
1225 bool hasPointers(Type t
)
1227 bool visitType(Type _
) { return false; }
1228 bool visitDArray(TypeDArray _
) { return true; }
1229 bool visitAArray(TypeAArray _
) { return true; }
1230 bool visitPointer(TypePointer _
) { return true; }
1231 bool visitDelegate(TypeDelegate _
) { return true; }
1232 bool visitClass(TypeClass _
) { return true; }
1233 bool visitEnum(TypeEnum t
) { return t
.memType().hasPointers(); }
1235 /* Although null isn't dereferencable, treat it as a pointer type for
1236 * attribute inference, generic code, etc.
1238 bool visitNull(TypeNull _
) { return true; }
1240 bool visitSArray(TypeSArray t
)
1242 /* Don't want to do this, because:
1243 * struct S { T* array[0]; }
1244 * may be a variable length struct.
1246 //if (dim.toInteger() == 0)
1249 if (t
.next
.ty
== Tvoid
)
1251 // Arrays of void contain arbitrary data, which may include pointers
1255 return t
.next
.hasPointers();
1258 bool visitStruct(TypeStruct t
)
1260 StructDeclaration sym
= t
.sym
;
1262 if (sym
.members
&& !sym
.determineFields() && sym
.type
!= Type
.terror
)
1263 error(sym
.loc
, "no size because of forward references");
1265 sym
.determineTypeProperties();
1266 return sym
.hasPointerField
;
1272 default: return visitType(t
);
1273 case Tsarray
: return visitSArray(t
.isTypeSArray());
1274 case Tarray
: return visitDArray(t
.isTypeDArray());
1275 case Taarray
: return visitAArray(t
.isTypeAArray());
1276 case Tpointer
: return visitPointer(t
.isTypePointer());
1277 case Tdelegate
: return visitDelegate(t
.isTypeDelegate());
1278 case Tstruct
: return visitStruct(t
.isTypeStruct());
1279 case Tenum
: return visitEnum(t
.isTypeEnum());
1280 case Tclass
: return visitClass(t
.isTypeClass());
1281 case Tnull
: return visitNull(t
.isTypeNull());
1285 /******************************************
1286 * Perform semantic analysis on a type.
1288 * type = Type AST node
1289 * loc = the location of the type
1292 * `Type` with completed semantic analysis, `Terror` if errors
1295 Type
typeSemantic(Type type
, const ref Loc loc
, Scope
* sc
)
1302 Type
visitType(Type t
)
1304 // @@@DEPRECATED_2.110@@@
1305 // Use of `cent` and `ucent` has always been an error.
1306 // Starting from 2.100, recommend core.int128 as a replace for the
1307 // lack of compiler support.
1308 if (t
.ty
== Tint128 || t
.ty
== Tuns128
)
1310 .error(loc
, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
1317 Type
visitComplex(TypeBasic t
)
1319 if (!(sc
.flags
& SCOPE
.Cfile
))
1320 return visitType(t
);
1322 auto tc
= getComplexLibraryType(loc
, sc
, t
.ty
);
1323 if (tc
.ty
== Terror
)
1325 return tc
.addMod(t
.mod
).merge();
1328 Type
visitVector(TypeVector mtype
)
1330 const errors
= global
.errors
;
1331 mtype
.basetype
= mtype
.basetype
.typeSemantic(loc
, sc
);
1332 if (errors
!= global
.errors
)
1334 mtype
.basetype
= mtype
.basetype
.toBasetype().mutableOf();
1335 if (mtype
.basetype
.ty
!= Tsarray
)
1337 .error(loc
, "T in __vector(T) must be a static array, not `%s`", mtype
.basetype
.toChars());
1340 TypeSArray t
= mtype
.basetype
.isTypeSArray();
1341 const sz
= cast(int)t
.size(loc
);
1342 final switch (target
.isVectorTypeSupported(sz
, t
.nextOf()))
1349 // no support at all
1350 .error(loc
, "SIMD vector types not supported on this platform");
1354 // invalid base type
1355 .error(loc
, "vector type `%s` is not supported on this platform", mtype
.toChars());
1360 .error(loc
, "%d byte vector type `%s` is not supported on this platform", sz
, mtype
.toChars());
1363 return merge(mtype
);
1366 Type
visitSArray(TypeSArray mtype
)
1368 //printf("TypeSArray::semantic() %s\n", toChars());
1372 mtype
.next
.resolve(loc
, sc
, e
, t
, s
);
1374 if (auto tup
= s ? s
.isTupleDeclaration() : null)
1376 mtype
.dim
= semanticLength(sc
, tup
, mtype
.dim
);
1377 mtype
.dim
= mtype
.dim
.ctfeInterpret();
1378 if (mtype
.dim
.op
== EXP
.error
)
1381 uinteger_t d
= mtype
.dim
.toUInteger();
1382 if (d
>= tup
.objects
.length
)
1384 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d
, cast(ulong)tup
.objects
.length
);
1388 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
1389 if (auto tt
= o
.isType())
1390 return tt
.addMod(mtype
.mod
);
1391 .error(loc
, "`%s` is not a type", mtype
.toChars());
1395 if (t
&& t
.ty
== Terror
)
1398 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
1399 if (tn
.ty
== Terror
)
1402 Type tbn
= tn
.toBasetype();
1405 auto errors
= global
.errors
;
1406 mtype
.dim
= semanticLength(sc
, tbn
, mtype
.dim
);
1407 mtype
.dim
= mtype
.dim
.implicitCastTo(sc
, Type
.tsize_t
);
1408 if (errors
!= global
.errors
)
1411 mtype
.dim
= mtype
.dim
.optimize(WANTvalue
);
1412 mtype
.dim
= mtype
.dim
.ctfeInterpret();
1413 if (mtype
.dim
.op
== EXP
.error
)
1416 errors
= global
.errors
;
1417 dinteger_t d1
= mtype
.dim
.toInteger();
1418 if (errors
!= global
.errors
)
1421 mtype
.dim
= mtype
.dim
.implicitCastTo(sc
, Type
.tsize_t
);
1422 mtype
.dim
= mtype
.dim
.optimize(WANTvalue
);
1423 if (mtype
.dim
.op
== EXP
.error
)
1426 errors
= global
.errors
;
1427 dinteger_t d2
= mtype
.dim
.toInteger();
1428 if (errors
!= global
.errors
)
1431 if (mtype
.dim
.op
== EXP
.error
)
1434 Type
overflowError()
1436 .error(loc
, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
1437 mtype
.toChars(), cast(ulong)tbn
.size(loc
), cast(ulong)d1
, target
.maxStaticDataSize
);
1442 return overflowError();
1444 Type tbx
= tbn
.baseElemOf();
1445 if (tbx
.ty
== Tstruct
&& !tbx
.isTypeStruct().sym
.members ||
1446 tbx
.ty
== Tenum
&& !tbx
.isTypeEnum().sym
.members
)
1448 /* To avoid meaningless error message, skip the total size limit check
1449 * when the bottom of element type is opaque.
1452 else if (tbn
.isTypeBasic() ||
1453 tbn
.ty
== Tpointer ||
1455 tbn
.ty
== Tsarray ||
1456 tbn
.ty
== Taarray ||
1457 (tbn
.ty
== Tstruct
&& tbn
.isTypeStruct().sym
.sizeok
== Sizeok
.done
) ||
1460 /* Only do this for types that don't need to have semantic()
1461 * run on them for the size, since they may be forward referenced.
1463 bool overflow
= false;
1464 if (mulu(tbn
.size(loc
), d2
, overflow
) > target
.maxStaticDataSize || overflow
)
1465 return overflowError();
1472 // Index the tuple to get the type
1474 TypeTuple tt
= tbn
.isTypeTuple();
1475 uinteger_t d
= mtype
.dim
.toUInteger();
1476 if (d
>= tt
.arguments
.length
)
1478 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d
, cast(ulong)tt
.arguments
.length
);
1481 Type telem
= (*tt
.arguments
)[cast(size_t
)d
].type
;
1482 return telem
.addMod(mtype
.mod
);
1487 .error(loc
, "cannot have array of `%s`", tbn
.toChars());
1495 .error(loc
, "cannot have array of scope `%s`", tbn
.toChars());
1499 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
1500 * and const(T)[3] become const(T[3])
1504 return mtype
.addMod(tn
.mod
).merge();
1507 Type
visitDArray(TypeDArray mtype
)
1509 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
1510 Type tbn
= tn
.toBasetype();
1518 .error(loc
, "cannot have array of `%s`", tbn
.toChars());
1529 .error(loc
, "cannot have array of scope `%s`", tn
.toChars());
1534 return merge(mtype
);
1537 Type
visitAArray(TypeAArray mtype
)
1539 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
1549 // Deal with the case where we thought the index was a type, but
1550 // in reality it was an expression.
1551 if (mtype
.index
.ty
== Tident || mtype
.index
.ty
== Tinstance || mtype
.index
.ty
== Tsarray || mtype
.index
.ty
== Ttypeof || mtype
.index
.ty
== Treturn || mtype
.index
.ty
== Tmixin
)
1556 mtype
.index
.resolve(loc
, sc
, e
, t
, s
);
1558 // https://issues.dlang.org/show_bug.cgi?id=15478
1560 e
= symbolToExp(s
, loc
, sc
, false);
1564 // It was an expression -
1565 // Rewrite as a static array
1566 auto tsa
= new TypeSArray(mtype
.next
, e
);
1567 return tsa
.typeSemantic(loc
, sc
);
1570 mtype
.index
= t
.typeSemantic(loc
, sc
);
1573 .error(loc
, "index is not a type or an expression");
1578 mtype
.index
= mtype
.index
.typeSemantic(loc
, sc
);
1579 mtype
.index
= mtype
.index
.merge2();
1581 if (mtype
.index
.nextOf() && !mtype
.index
.nextOf().isImmutable())
1583 mtype
.index
= mtype
.index
.constOf().mutableOf();
1586 printf("index is %p %s\n", mtype
.index
, mtype
.index
.toChars());
1587 mtype
.index
.check();
1588 printf("index.mod = x%x\n", mtype
.index
.mod
);
1589 printf("index.ito = x%p\n", mtype
.index
.getMcache().ito
);
1590 if (mtype
.index
.getMcache().ito
)
1592 printf("index.ito.mod = x%x\n", mtype
.index
.getMcache().ito
.mod
);
1593 printf("index.ito.ito = x%p\n", mtype
.index
.getMcache().ito
.getMcache().ito
);
1598 switch (mtype
.index
.toBasetype().ty
)
1604 .error(loc
, "cannot have associative array key of `%s`", mtype
.index
.toBasetype().toChars());
1612 Type tbase
= mtype
.index
.baseElemOf();
1613 while (tbase
.ty
== Tarray
)
1614 tbase
= tbase
.nextOf().baseElemOf();
1615 if (auto ts
= tbase
.isTypeStruct())
1617 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
1619 StructDeclaration sd
= ts
.sym
;
1620 if (sd
.semanticRun
< PASS
.semanticdone
)
1621 sd
.dsymbolSemantic(null);
1623 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
1624 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
1626 if (sd
.xeq
&& sd
.xeq
.isGenerated() && sd
.xeq
._scope
&& sd
.xeq
.semanticRun
< PASS
.semantic3done
)
1628 uint errors
= global
.startGagging();
1629 sd
.xeq
.semantic3(sd
.xeq
._scope
);
1630 if (global
.endGagging(errors
))
1635 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
1636 const(char)* s
= (mtype
.index
.toBasetype().ty
!= Tstruct
) ?
"bottom of " : "";
1639 // If sd.xhash != NULL:
1640 // sd or its fields have user-defined toHash.
1641 // AA assumes that its result is consistent with bitwise equality.
1643 // bitwise equality & hashing
1645 else if (sd
.xeq
== sd
.xerreq
)
1647 if (search_function(sd
, Id
.eq
))
1649 .error(loc
, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s
, sd
.toChars(), sd
.toChars());
1653 .error(loc
, "%sAA key type `%s` does not support const equality", s
, sd
.toChars());
1659 if (search_function(sd
, Id
.eq
))
1661 .error(loc
, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s
, sd
.toChars());
1665 .error(loc
, "%sAA key type `%s` supports const equality but doesn't support const hashing", s
, sd
.toChars());
1671 // defined equality & hashing
1672 assert(sd
.xeq
&& sd
.xhash
);
1674 /* xeq and xhash may be implicitly defined by compiler. For example:
1675 * struct S { int[] arr; }
1676 * With 'arr' field equality and hashing, compiler will implicitly
1677 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
1681 else if (tbase
.ty
== Tclass
&& !tbase
.isTypeClass().sym
.isInterfaceDeclaration())
1683 ClassDeclaration cd
= tbase
.isTypeClass().sym
;
1684 if (cd
.semanticRun
< PASS
.semanticdone
)
1685 cd
.dsymbolSemantic(null);
1687 if (!ClassDeclaration
.object
)
1689 .error(Loc
.initial
, "missing or corrupt object.d");
1693 __gshared FuncDeclaration feq
= null;
1694 __gshared FuncDeclaration fcmp
= null;
1695 __gshared FuncDeclaration fhash
= null;
1697 feq
= search_function(ClassDeclaration
.object
, Id
.eq
).isFuncDeclaration();
1699 fcmp
= search_function(ClassDeclaration
.object
, Id
.cmp).isFuncDeclaration();
1701 fhash
= search_function(ClassDeclaration
.object
, Id
.tohash
).isFuncDeclaration();
1702 assert(fcmp
&& feq
&& fhash
);
1704 if (feq
.vtblIndex
< cd
.vtbl
.length
&& cd
.vtbl
[feq
.vtblIndex
] == feq
)
1708 if (fcmp
.vtblIndex
< cd
.vtbl
.length
&& cd
.vtbl
[fcmp
.vtblIndex
] != fcmp
)
1710 const(char)* s
= (mtype
.index
.toBasetype().ty
!= Tclass
) ?
"bottom of " : "";
1711 .error(loc
, "%sAA key type `%s` now requires equality rather than comparison", s
, cd
.toChars());
1712 errorSupplemental(loc
, "Please override `Object.opEquals` and `Object.toHash`.");
1717 mtype
.next
= mtype
.next
.typeSemantic(loc
, sc
).merge2();
1720 switch (mtype
.next
.toBasetype().ty
)
1726 .error(loc
, "cannot have associative array of `%s`", mtype
.next
.toChars());
1733 if (mtype
.next
.isscope())
1735 .error(loc
, "cannot have array of scope `%s`", mtype
.next
.toChars());
1738 return merge(mtype
);
1741 Type
visitPointer(TypePointer mtype
)
1743 //printf("TypePointer::semantic() %s\n", toChars());
1748 Type n
= mtype
.next
.typeSemantic(loc
, sc
);
1749 switch (n
.toBasetype().ty
)
1752 .error(loc
, "cannot have pointer to `%s`", n
.toChars());
1759 if (n
!= mtype
.next
)
1764 if (mtype
.next
.ty
!= Tfunction
)
1767 return merge(mtype
);
1771 return merge(mtype
);
1775 mtype
.deco
= merge(mtype
).deco
;
1776 /* Don't return merge(), because arg identifiers and default args
1778 * even though the types match
1784 Type
visitReference(TypeReference mtype
)
1786 //printf("TypeReference::semantic()\n");
1787 Type n
= mtype
.next
.typeSemantic(loc
, sc
);
1788 if (n
!= mtype
.next
)
1792 return merge(mtype
);
1795 Type
visitFunction(TypeFunction mtype
)
1797 if (mtype
.deco
) // if semantic() already run
1799 //printf("already done\n");
1802 //printf("TypeFunction::semantic() this = %p\n", mtype);
1803 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
1805 bool errors
= false;
1807 if (mtype
.inuse
> global
.recursionLimit
)
1810 .error(loc
, "recursive type");
1814 /* Copy in order to not mess up original.
1815 * This can produce redundant copies if inferring return type,
1816 * as semantic() will get called again on this.
1818 TypeFunction tf
= mtype
.copy().toTypeFunction();
1819 if (mtype
.parameterList
.parameters
)
1821 tf
.parameterList
.parameters
= mtype
.parameterList
.parameters
.copy();
1822 for (size_t i
= 0; i
< mtype
.parameterList
.parameters
.length
; i
++)
1824 Parameter p
= cast(Parameter
)mem
.xmalloc(__traits(classInstanceSize
, Parameter
));
1825 memcpy(cast(void*)p
, cast(void*)(*mtype
.parameterList
.parameters
)[i
], __traits(classInstanceSize
, Parameter
));
1826 (*tf
.parameterList
.parameters
)[i
] = p
;
1830 if (sc
.stc & STC
.pure_
)
1831 tf
.purity
= PURE
.fwdref
;
1832 if (sc
.stc & STC
.nothrow_
)
1833 tf
.isnothrow
= true;
1834 if (sc
.stc & STC
.nogc
)
1836 if (sc
.stc & STC
.ref_
)
1838 if (sc
.stc & STC
.return_
)
1840 if (sc
.stc & STC
.returnScope
)
1841 tf
.isreturnscope
= true;
1842 if (sc
.stc & STC
.returninferred
)
1843 tf
.isreturninferred
= true;
1844 if (sc
.stc & STC
.scope_
)
1845 tf
.isScopeQual
= true;
1846 if (sc
.stc & STC
.scopeinferred
)
1847 tf
.isscopeinferred
= true;
1849 // if (tf.isreturn && !tf.isref)
1850 // tf.isScopeQual = true; // return by itself means 'return scope'
1852 if (tf
.trust
== TRUST
.default_
)
1854 if (sc
.stc & STC
.safe
)
1855 tf
.trust
= TRUST
.safe
;
1856 else if (sc
.stc & STC
.system
)
1857 tf
.trust
= TRUST
.system
;
1858 else if (sc
.stc & STC
.trusted
)
1859 tf
.trust
= TRUST
.trusted
;
1862 if (sc
.stc & STC
.property
)
1863 tf
.isproperty
= true;
1864 if (sc
.stc & STC
.live
)
1867 tf
.linkage
= sc
.linkage
;
1868 if (tf
.linkage
== LINK
.system
)
1869 tf
.linkage
= target
.systemLinkage();
1873 /* If the parent is @safe, then this function defaults to safe
1875 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1876 * to be inferred first.
1878 if (tf
.trust
== TRUST
.default_
)
1879 for (Dsymbol p
= sc
.func
; p
; p
= p
.toParent2())
1881 FuncDeclaration fd
= p
.isFuncDeclaration();
1884 if (fd
.isSafeBypassingInference())
1885 tf
.trust
= TRUST
.safe
; // default to @safe
1891 bool wildreturn
= false;
1895 sc
.stc &= ~(STC
.TYPECTOR | STC
.FUNCATTR
);
1896 tf
.next
= tf
.next
.typeSemantic(loc
, sc
);
1898 errors |
= tf
.checkRetType(loc
);
1899 if (tf
.next
.isscope() && !tf
.isctor
)
1901 .error(loc
, "functions cannot return `scope %s`", tf
.next
.toChars());
1904 if (tf
.next
.hasWild())
1907 if (tf
.isreturn
&& !tf
.isref
&& !tf
.next
.hasPointers())
1909 tf
.isreturn
= false;
1913 /// Perform semantic on the default argument to a parameter
1914 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1915 /// Returns `false` whether an error was encountered.
1916 static bool defaultArgSemantic (ref Parameter fparam
, Scope
* sc
)
1918 Expression e
= fparam
.defaultArg
;
1919 const isRefOrOut
= fparam
.isReference();
1920 const isAuto
= fparam
.storageClass
& (STC
.auto_ | STC
.autoref
);
1921 if (isRefOrOut
&& !isAuto
)
1923 e
= e
.expressionSemantic(sc
);
1924 e
= resolveProperties(sc
, e
);
1928 e
= inferType(e
, fparam
.type
);
1929 Scope
* sc2
= sc
.push();
1930 sc2
.inDefaultArg
= true;
1931 Initializer iz
= new ExpInitializer(e
.loc
, e
);
1932 iz
= iz
.initializerSemantic(sc2
, fparam
.type
, INITnointerpret
);
1933 e
= iz
.initializerToExpression();
1936 if (e
.op
== EXP
.function_
) // https://issues.dlang.org/show_bug.cgi?id=4820
1938 FuncExp fe
= e
.isFuncExp();
1939 // Replace function literal with a function symbol,
1940 // since default arg expression must be copied when used
1941 // and copying the literal itself is wrong.
1942 e
= new VarExp(e
.loc
, fe
.fd
, false);
1943 e
= new AddrExp(e
.loc
, e
);
1944 e
= e
.expressionSemantic(sc
);
1946 if (isRefOrOut
&& (!isAuto || e
.isLvalue())
1947 && !MODimplicitConv(e
.type
.mod
, fparam
.type
.mod
))
1949 const(char)* errTxt
= fparam
.storageClass
& STC
.ref_ ?
"ref" : "out";
1950 .error(e
.loc
, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1951 e
.toChars(), e
.type
.toChars(), errTxt
, fparam
.type
.toChars(), fparam
.toChars());
1953 e
= e
.implicitCastTo(sc
, fparam
.type
);
1955 // default arg must be an lvalue
1956 if (isRefOrOut
&& !isAuto
&&
1957 !(fparam
.storageClass
& STC
.constscoperef
) &&
1958 global
.params
.rvalueRefParam
!= FeatureState
.enabled
)
1959 e
= e
.toLvalue(sc
, "create default argument for `ref` / `out` parameter from");
1961 fparam
.defaultArg
= e
;
1962 return (e
.op
!= EXP
.error
);
1965 ubyte wildparams
= 0;
1966 if (tf
.parameterList
.parameters
)
1968 /* Create a scope for evaluating the default arguments for the parameters
1970 Scope
* argsc
= sc
.push();
1971 argsc
.stc = 0; // don't inherit storage class
1972 argsc
.visibility
= Visibility(Visibility
.Kind
.public_
);
1975 size_t dim
= tf
.parameterList
.length
;
1976 for (size_t i
= 0; i
< dim
; i
++)
1978 Parameter fparam
= tf
.parameterList
[i
];
1979 fparam
.storageClass |
= STC
.parameter
;
1981 fparam
.type
= fparam
.type
.typeSemantic(loc
, argsc
);
1984 if (fparam
.type
.ty
== Terror
)
1990 fparam
.type
= fparam
.type
.addStorageClass(fparam
.storageClass
);
1992 if (fparam
.storageClass
& (STC
.auto_ | STC
.alias_ | STC
.static_
))
1998 fparam
.type
= fparam
.type
.cAdjustParamType(sc
); // adjust C array and function parameter types
2000 Type t
= fparam
.type
.toBasetype();
2002 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
2005 if (auto tt
= t
.isTypeTuple())
2007 /* TypeFunction::parameter also is used as the storage of
2008 * Parameter objects for FuncDeclaration. So we should copy
2009 * the elements of TypeTuple::arguments to avoid unintended
2010 * sharing of Parameter object among other functions.
2012 if (tt
.arguments
&& tt
.arguments
.length
)
2014 /* Propagate additional storage class from tuple parameters to their
2015 * element-parameters.
2016 * Make a copy, as original may be referenced elsewhere.
2018 size_t tdim
= tt
.arguments
.length
;
2019 auto newparams
= new Parameters(tdim
);
2020 for (size_t j
= 0; j
< tdim
; j
++)
2022 Parameter narg
= (*tt
.arguments
)[j
];
2024 // https://issues.dlang.org/show_bug.cgi?id=12744
2025 // If the storage classes of narg
2026 // conflict with the ones in fparam, it's ignored.
2027 StorageClass
stc = fparam
.storageClass | narg
.storageClass
;
2028 StorageClass stc1
= fparam
.storageClass
& (STC
.ref_ | STC
.out_ | STC
.lazy_
);
2029 StorageClass stc2
= narg
.storageClass
& (STC
.ref_ | STC
.out_ | STC
.lazy_
);
2030 if (stc1
&& stc2
&& stc1
!= stc2
)
2032 OutBuffer buf1
; stcToBuffer(buf1
, stc1 |
((stc1
& STC
.ref_
) ?
(fparam
.storageClass
& STC
.auto_
) : 0));
2033 OutBuffer buf2
; stcToBuffer(buf2
, stc2
);
2035 .error(loc
, "incompatible parameter storage classes `%s` and `%s`",
2036 buf1
.peekChars(), buf2
.peekChars());
2038 stc = stc1 |
(stc & ~(STC
.ref_ | STC
.out_ | STC
.lazy_
));
2040 (*newparams
)[j
] = new Parameter(
2041 loc
, stc, narg
.type
, narg
.ident
, narg
.defaultArg
, narg
.userAttribDecl
);
2043 fparam
.type
= new TypeTuple(newparams
);
2044 fparam
.type
= fparam
.type
.typeSemantic(loc
, argsc
);
2046 fparam
.storageClass
= STC
.parameter
;
2048 /* Reset number of parameters, and back up one to do this fparam again,
2049 * now that it is a tuple
2051 dim
= tf
.parameterList
.length
;
2056 // -preview=in: Always add `ref` when used with `extern(C++)` functions
2057 // Done here to allow passing opaque types with `in`
2058 if ((fparam
.storageClass
& (STC
.in_ | STC
.ref_
)) == STC
.in_
)
2063 if (fparam
.storageClass
& STC
.constscoperef
)
2064 fparam
.storageClass |
= STC
.ref_
;
2066 case LINK
.default_
, LINK
.d
:
2069 if (fparam
.storageClass
& STC
.constscoperef
)
2071 .error(loc
, "cannot use `in` parameters with `extern(%s)` functions",
2072 linkageToChars(tf
.linkage
));
2073 .errorSupplemental(loc
, "parameter `%s` declared as `in` here", fparam
.toChars());
2077 // Note that this deprecation will not trigger on `in ref` / `ref in`
2078 // parameters, however the parser will trigger a deprecation on them.
2079 .deprecation(loc
, "using `in` parameters with `extern(%s)` functions is deprecated",
2080 linkageToChars(tf
.linkage
));
2081 .deprecationSupplemental(loc
, "parameter `%s` declared as `in` here", fparam
.toChars());
2087 if (t
.ty
== Tfunction
)
2089 .error(loc
, "cannot have parameter of function type `%s`", fparam
.type
.toChars());
2092 else if (!fparam
.isReference() &&
2093 (t
.ty
== Tstruct || t
.ty
== Tsarray || t
.ty
== Tenum
))
2095 Type tb2
= t
.baseElemOf();
2096 if (tb2
.ty
== Tstruct
&& !tb2
.isTypeStruct().sym
.members ||
2097 tb2
.ty
== Tenum
&& !tb2
.isTypeEnum().sym
.memtype
)
2099 if (fparam
.storageClass
& STC
.constscoperef
)
2101 .error(loc
, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
2102 fparam
.toChars(), fparam
.type
.toChars());
2105 .error(loc
, "cannot have parameter of opaque type `%s` by value",
2106 fparam
.type
.toChars());
2110 else if (!fparam
.isLazy() && t
.ty
== Tvoid
)
2112 .error(loc
, "cannot have parameter of type `%s`", fparam
.type
.toChars());
2116 const bool isTypesafeVariadic
= i
+ 1 == dim
&&
2117 tf
.parameterList
.varargs
== VarArg
.typesafe
&&
2118 (t
.isTypeDArray() || t
.isTypeClass());
2119 if (isTypesafeVariadic
)
2121 /* typesafe variadic arguments are constructed on the stack, so must be `scope`
2123 fparam
.storageClass |
= STC
.scope_ | STC
.scopeinferred
;
2126 if (fparam
.storageClass
& STC
.return_
)
2128 if (!fparam
.isReference())
2130 if (!(fparam
.storageClass
& STC
.scope_
))
2131 fparam
.storageClass |
= STC
.scope_ | STC
.scopeinferred
; // 'return' implies 'scope'
2135 else if (tf
.next
&& !tf
.next
.hasPointers() && tf
.next
.toBasetype().ty
!= Tvoid
)
2137 fparam
.storageClass
&= ~STC
.return_
; // https://issues.dlang.org/show_bug.cgi?id=18963
2141 if (isTypesafeVariadic
)
2143 /* This is because they can be constructed on the stack
2144 * https://dlang.org/spec/function.html#typesafe_variadic_functions
2146 .error(loc
, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
2147 fparam
.ident ? fparam
.ident
.toChars() : "", t
.toChars());
2152 if (fparam
.storageClass
& STC
.out_
)
2154 if (ubyte m
= fparam
.type
.mod
& (MODFlags
.immutable_ | MODFlags
.const_ | MODFlags
.wild
))
2156 .error(loc
, "cannot have `%s out` parameter of type `%s`", MODtoChars(m
), t
.toChars());
2161 Type tv
= t
.baseElemOf();
2162 if (tv
.ty
== Tstruct
&& tv
.isTypeStruct().sym
.noDefaultCtor
)
2164 .error(loc
, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam
.type
.toChars());
2173 //if (tf.next && !wildreturn)
2174 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
2177 // Remove redundant storage classes for type, they are already applied
2178 fparam
.storageClass
&= ~(STC
.TYPECTOR
);
2180 // -preview=in: add `ref` storage class to suited `in` params
2181 if ((fparam
.storageClass
& (STC
.constscoperef | STC
.ref_
)) == STC
.constscoperef
)
2183 auto ts
= t
.baseElemOf().isTypeStruct();
2184 const isPOD
= !ts || ts
.sym
.isPOD();
2185 if (!isPOD || target
.preferPassByRef(t
))
2186 fparam
.storageClass |
= STC
.ref_
;
2190 Expressions
* fargs
= mtype
.inferenceArguments
.arguments
;
2192 // mtype.argumentList only provided for Implicit Function Template Instantiation
2193 if (mtype
.inferenceArguments
.length
> 0)
2194 fargs
= tf
.resolveNamedArgs(mtype
.inferenceArguments
, null);
2196 // Now that we completed semantic for the argument types,
2197 // run semantic on their default values,
2198 // bearing in mind tuples have been expanded.
2199 // We need to keep a pair of [oidx, eidx] (original index,
2200 // extended index), as we need to run semantic when `oidx` changes.
2201 size_t tupleOrigIdx
= size_t
.max
;
2202 size_t tupleExtIdx
= size_t
.max
;
2203 foreach (oidx
, oparam
, eidx
, eparam
; tf
.parameterList
)
2205 // oparam (original param) will always have the default arg
2206 // if there's one, but `eparam` will not if it's an expanded
2207 // tuple. When we see an expanded tuple, we need to save its
2208 // position to get the offset in it later on.
2209 if (oparam
.defaultArg
)
2211 // Get the obvious case out of the way
2212 if (oparam
is eparam
)
2213 errors |
= !defaultArgSemantic(eparam
, argsc
);
2214 // We're seeing a new tuple
2215 else if (tupleOrigIdx
== size_t
.max || tupleOrigIdx
< oidx
)
2217 /* https://issues.dlang.org/show_bug.cgi?id=18572
2219 * If a tuple parameter has a default argument, when expanding the parameter
2220 * tuple the default argument tuple must also be expanded.
2222 tupleOrigIdx
= oidx
;
2224 errors |
= !defaultArgSemantic(oparam
, argsc
);
2225 TupleExp te
= oparam
.defaultArg
.isTupleExp();
2226 if (te
&& te
.exps
&& te
.exps
.length
)
2227 eparam
.defaultArg
= (*te
.exps
)[0];
2229 // Processing an already-seen tuple
2232 TupleExp te
= oparam
.defaultArg
.isTupleExp();
2233 if (te
&& te
.exps
&& te
.exps
.length
)
2234 eparam
.defaultArg
= (*te
.exps
)[eidx
- tupleExtIdx
];
2238 // We need to know the default argument to resolve `auto ref`,
2239 // hence why this has to take place as the very last step.
2240 /* Resolve "auto ref" storage class to be either ref or value,
2241 * based on the argument matching the parameter
2243 if (eparam
.storageClass
& STC
.auto_
)
2245 Expression farg
= (fargs
&& eidx
< fargs
.length
) ?
(*fargs
)[eidx
] : null;
2247 farg
= eparam
.defaultArg
;
2249 if (farg
&& (eparam
.storageClass
& STC
.ref_
))
2251 if (!farg
.isLvalue())
2252 eparam
.storageClass
&= ~STC
.ref_
; // value parameter
2253 eparam
.storageClass
&= ~STC
.auto_
; // https://issues.dlang.org/show_bug.cgi?id=14656
2254 eparam
.storageClass |
= STC
.autoref
;
2256 else if (mtype
.incomplete
&& (eparam
.storageClass
& STC
.ref_
))
2258 // the default argument may have been temporarily removed,
2259 // see usage of `TypeFunction.incomplete`.
2260 // https://issues.dlang.org/show_bug.cgi?id=19891
2261 eparam
.storageClass
&= ~STC
.auto_
;
2262 eparam
.storageClass |
= STC
.autoref
;
2264 else if (eparam
.storageClass
& STC
.ref_
)
2266 .error(loc
, "cannot explicitly instantiate template function with `auto ref` parameter");
2271 .error(loc
, "`auto` can only be used as part of `auto ref` for template function parameters");
2282 if (wildreturn
&& !wildparams
)
2284 .error(loc
, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype
.toChars());
2287 tf
.isInOutParam
= (wildparams
& 1) != 0;
2288 tf
.isInOutQual
= (wildparams
& 2) != 0;
2290 if (tf
.isproperty
&& (tf
.parameterList
.varargs
!= VarArg
.none || tf
.parameterList
.length
> 2))
2292 .error(loc
, "properties can only have zero, one, or two parameter");
2296 if (tf
.parameterList
.varargs
== VarArg
.variadic
&& tf
.linkage
!= LINK
.d
&& tf
.parameterList
.length
== 0 &&
2297 !(sc
.flags
& SCOPE
.Cfile
))
2299 .error(loc
, "variadic functions with non-D linkage must have at least one parameter");
2307 tf
.deco
= tf
.merge().deco
;
2309 /* Don't return merge(), because arg identifiers and default args
2311 * even though the types match
2316 Type
visitDelegate(TypeDelegate mtype
)
2318 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
2319 if (mtype
.deco
) // if semantic() already run
2321 //printf("already done\n");
2324 mtype
.next
= mtype
.next
.typeSemantic(loc
, sc
);
2325 if (mtype
.next
.ty
!= Tfunction
)
2328 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
2329 * perhaps default arguments should
2330 * be removed from next before the merge.
2334 return mtype
.merge();
2338 /* Don't return merge(), because arg identifiers and default args
2340 * even though the types match
2342 mtype
.deco
= mtype
.merge().deco
;
2347 Type
visitIdentifier(TypeIdentifier mtype
)
2352 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
2353 mtype
.resolve(loc
, sc
, e
, t
, s
);
2356 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
2357 return t
.addMod(mtype
.mod
);
2363 auto td
= s
.isTemplateDeclaration
;
2364 if (td
&& td
.onemember
&& td
.onemember
.isAggregateDeclaration
)
2365 .error(loc
, "template %s `%s` is used as a type without instantiation"
2366 ~ "; to instantiate it use `%s!(arguments)`",
2367 s
.kind
, s
.toPrettyChars
, s
.ident
.toChars
);
2369 .error(loc
, "%s `%s` is used as a type", s
.kind
, s
.toPrettyChars
);
2372 else if (e
.op
== EXP
.variable
) // special case: variable is used as a type
2375 N.B. This branch currently triggers for the following code
2380 i.e. the compiler prints "variable x is used as a type"
2381 which isn't a particularly good error message (x is a variable?).
2383 Dsymbol varDecl
= mtype
.toDsymbol(sc
);
2384 const(Loc
) varDeclLoc
= varDecl
.getLoc();
2385 Module varDeclModule
= varDecl
.getModule(); //This can be null
2387 .error(loc
, "variable `%s` is used as a type", mtype
.toChars());
2388 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
2389 if ((varDeclModule
!is null) && varDeclModule
!= sc
._module
) // variable is imported
2391 const(Loc
) varDeclModuleImportLoc
= varDeclModule
.getLoc();
2393 varDeclModuleImportLoc
,
2394 "variable `%s` is imported here from: `%s`",
2396 varDeclModule
.toPrettyChars
,
2400 .errorSupplemental(varDeclLoc
, "variable `%s` is declared here", varDecl
.toChars
);
2403 .error(loc
, "`%s` is used as a type", mtype
.toChars());
2408 Type
visitInstance(TypeInstance mtype
)
2414 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
2416 const errors
= global
.errors
;
2417 mtype
.resolve(loc
, sc
, e
, t
, s
);
2418 // if we had an error evaluating the symbol, suppress further errors
2419 if (!t
&& errors
!= global
.errors
)
2425 if (!e
&& s
&& s
.errors
)
2427 // if there was an error evaluating the symbol, it might actually
2428 // be a type. Avoid misleading error messages.
2429 .error(loc
, "`%s` had previous errors", mtype
.toChars());
2432 .error(loc
, "`%s` is used as a type", mtype
.toChars());
2438 Type
visitTypeof(TypeTypeof mtype
)
2440 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
2444 mtype
.resolve(loc
, sc
, e
, t
, s
);
2445 if (s
&& (t
= s
.getType()) !is null)
2446 t
= t
.addMod(mtype
.mod
);
2449 .error(loc
, "`%s` is used as a type", mtype
.toChars());
2455 Type
visitTraits(TypeTraits mtype
)
2460 mtype
.resolve(loc
, sc
, e
, t
, s
);
2465 .error(mtype
.loc
, "`%s` does not give a valid type", mtype
.toChars
);
2471 Type
visitReturn(TypeReturn mtype
)
2473 //printf("TypeReturn::semantic() %s\n", toChars());
2477 mtype
.resolve(loc
, sc
, e
, t
, s
);
2478 if (s
&& (t
= s
.getType()) !is null)
2479 t
= t
.addMod(mtype
.mod
);
2482 .error(loc
, "`%s` is used as a type", mtype
.toChars());
2488 Type
visitStruct(TypeStruct mtype
)
2490 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
2494 /* Don't semantic for sym because it should be deferred until
2495 * sizeof needed or its members accessed.
2497 // instead, parent should be set correctly
2498 assert(mtype
.sym
.parent
);
2500 if (mtype
.sym
.type
.ty
== Terror
)
2503 return merge(mtype
);
2506 Type
visitEnum(TypeEnum mtype
)
2508 //printf("TypeEnum::semantic() %s\n", toChars());
2509 return mtype
.deco ? mtype
: merge(mtype
);
2512 Type
visitClass(TypeClass mtype
)
2514 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
2518 /* Don't semantic for sym because it should be deferred until
2519 * sizeof needed or its members accessed.
2521 // instead, parent should be set correctly
2522 assert(mtype
.sym
.parent
);
2524 if (mtype
.sym
.type
.ty
== Terror
)
2527 return merge(mtype
);
2530 Type
visitTuple(TypeTuple mtype
)
2532 //printf("TypeTuple::semantic(this = %p)\n", this);
2533 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
2535 mtype
.deco
= merge(mtype
).deco
;
2537 /* Don't return merge(), because a tuple with one type has the
2538 * same deco as that type.
2543 Type
visitSlice(TypeSlice mtype
)
2545 //printf("TypeSlice::semantic() %s\n", toChars());
2546 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
2547 //printf("next: %s\n", tn.toChars());
2549 Type tbn
= tn
.toBasetype();
2550 if (tbn
.ty
!= Ttuple
)
2552 .error(loc
, "can only slice type sequences, not `%s`", tbn
.toChars());
2555 TypeTuple tt
= cast(TypeTuple
)tbn
;
2557 mtype
.lwr
= semanticLength(sc
, tbn
, mtype
.lwr
);
2558 mtype
.upr
= semanticLength(sc
, tbn
, mtype
.upr
);
2559 mtype
.lwr
= mtype
.lwr
.ctfeInterpret();
2560 mtype
.upr
= mtype
.upr
.ctfeInterpret();
2561 if (mtype
.lwr
.op
== EXP
.error || mtype
.upr
.op
== EXP
.error
)
2564 uinteger_t i1
= mtype
.lwr
.toUInteger();
2565 uinteger_t i2
= mtype
.upr
.toUInteger();
2566 if (!(i1
<= i2
&& i2
<= tt
.arguments
.length
))
2568 .error(loc
, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
2569 cast(ulong)i1
, cast(ulong)i2
, cast(ulong)tt
.arguments
.length
);
2576 auto args
= new Parameters();
2577 args
.reserve(cast(size_t
)(i2
- i1
));
2578 foreach (arg
; (*tt
.arguments
)[cast(size_t
)i1
.. cast(size_t
)i2
])
2582 Type t
= new TypeTuple(args
);
2583 return t
.typeSemantic(loc
, sc
);
2586 Type
visitMixin(TypeMixin mtype
)
2588 //printf("TypeMixin::semantic() %s\n", toChars());
2593 mtype
.resolve(loc
, sc
, e
, t
, s
);
2595 if (t
&& t
.ty
!= Terror
)
2598 .error(mtype
.loc
, "`mixin(%s)` does not give a valid type", mtype
.obj
.toChars
);
2602 Type
visitTag(TypeTag mtype
)
2604 //printf("TypeTag.semantic() %s\n", mtype.toChars());
2605 Type
returnType(Type t
)
2607 return t
.deco ? t
: t
.merge();
2614 return returnType(mtype
.resolved
.addSTC(mtype
.mod
));
2617 /* Find the current scope by skipping tag scopes.
2618 * In C, tag scopes aren't considered scopes.
2624 auto scopesym
= sc2
.scopesym
;
2625 if (scopesym
.isStructDeclaration())
2627 sc2
= sc2
.enclosing
;
2633 /* Declare mtype as a struct/union/enum declaration
2637 void declare(ScopeDsymbol sd
)
2639 sd
.members
= mtype
.members
;
2640 auto scopesym
= sc2
.inner().scopesym
;
2641 if (scopesym
.members
)
2642 scopesym
.members
.push(sd
);
2643 if (scopesym
.symtab
&& !scopesym
.symtabInsert(sd
))
2645 Dsymbol s2
= scopesym
.symtabLookup(sd
, mtype
.id
);
2646 handleTagSymbols(*sc2
, sd
, s2
, scopesym
);
2648 sd
.parent
= sc2
.parent
;
2649 sd
.dsymbolSemantic(sc2
);
2655 auto ed
= new EnumDeclaration(mtype
.loc
, mtype
.id
, mtype
.base
);
2657 mtype
.resolved
= visitEnum(new TypeEnum(ed
));
2661 auto sd
= new StructDeclaration(mtype
.loc
, mtype
.id
, false);
2662 sd
.alignment
= mtype
.packalign
;
2664 mtype
.resolved
= visitStruct(new TypeStruct(sd
));
2668 auto ud
= new UnionDeclaration(mtype
.loc
, mtype
.id
);
2669 ud
.alignment
= mtype
.packalign
;
2671 mtype
.resolved
= visitStruct(new TypeStruct(ud
));
2679 /* If it doesn't have a tag by now, supply one.
2680 * It'll be unique, and therefore introducing.
2681 * Declare it, and done.
2685 mtype
.id
= Identifier
.generateId("__tag"[]);
2687 return returnType(mtype
.resolved
.addSTC(mtype
.mod
));
2690 /* look for pre-existing declaration
2693 auto s
= sc2
.search(mtype
.loc
, mtype
.id
, scopesym
, SearchOpt
.ignoreErrors | SearchOpt
.tagNameSpace
);
2694 if (!s || s
.isModule())
2696 // no pre-existing declaration, so declare it
2697 if (mtype
.tok
== TOK
.enum_
&& !mtype
.members
)
2698 .error(mtype
.loc
, "`enum %s` is incomplete without members", mtype
.id
.toChars()); // C11 6.7.2.3-3
2700 return returnType(mtype
.resolved
.addSTC(mtype
.mod
));
2703 /* A redeclaration only happens if both declarations are in
2706 const bool redeclar
= (scopesym
== sc2
.inner().scopesym
);
2710 if (mtype
.tok
== TOK
.enum_
&& s
.isEnumDeclaration())
2712 auto ed
= s
.isEnumDeclaration();
2713 if (mtype
.members
&& ed
.members
)
2714 .error(mtype
.loc
, "`%s` already has members", mtype
.id
.toChars());
2715 else if (!ed
.members
)
2717 ed
.members
= mtype
.members
;
2722 mtype
.resolved
= ed
.type
;
2724 else if (mtype
.tok
== TOK
.union_
&& s
.isUnionDeclaration() ||
2725 mtype
.tok
== TOK
.struct_
&& s
.isStructDeclaration())
2727 // Add members to original declaration
2728 auto sd
= s
.isStructDeclaration();
2729 if (mtype
.members
&& sd
.members
)
2731 /* struct S { int b; };
2732 * struct S { int a; } *s;
2734 .error(mtype
.loc
, "`%s` already has members", mtype
.id
.toChars());
2736 else if (!sd
.members
)
2739 * struct S { int a; } *s;
2741 sd
.members
= mtype
.members
;
2742 if (sd
.semanticRun
== PASS
.semanticdone
)
2744 /* The first semantic pass marked `sd` as an opaque struct.
2745 * Re-run semantic so that all newly assigned members are
2746 * picked up and added to the symtab.
2748 sd
.semanticRun
= PASS
.semantic
;
2749 sd
.dsymbolSemantic(sc2
);
2754 /* struct S { int a; };
2758 mtype
.resolved
= sd
.type
;
2763 * struct S { int a; } *s;
2765 .error(mtype
.loc
, "redeclaration of `%s`", mtype
.id
.toChars());
2766 mtype
.resolved
= error();
2769 else if (mtype
.members
)
2772 * { struct S { int a; } *s; }
2778 if (mtype
.tok
== TOK
.enum_
&& s
.isEnumDeclaration())
2780 mtype
.resolved
= s
.isEnumDeclaration().type
;
2782 else if (mtype
.tok
== TOK
.union_
&& s
.isUnionDeclaration() ||
2783 mtype
.tok
== TOK
.struct_
&& s
.isStructDeclaration())
2788 mtype
.resolved
= s
.isStructDeclaration().type
;
2795 .error(mtype
.loc
, "redeclaring `%s %s` as `%s %s`",
2796 s
.kind(), s
.toChars(), Token
.toChars(mtype
.tok
), mtype
.id
.toChars());
2800 return returnType(mtype
.resolved
.addSTC(mtype
.mod
));
2805 default: return visitType(type
);
2808 case Tcomplex80
: return visitComplex(type
.isTypeBasic());
2809 case Tvector
: return visitVector(type
.isTypeVector());
2810 case Tsarray
: return visitSArray(type
.isTypeSArray());
2811 case Tarray
: return visitDArray(type
.isTypeDArray());
2812 case Taarray
: return visitAArray(type
.isTypeAArray());
2813 case Tpointer
: return visitPointer(type
.isTypePointer());
2814 case Treference
: return visitReference(type
.isTypeReference());
2815 case Tfunction
: return visitFunction(type
.isTypeFunction());
2816 case Tdelegate
: return visitDelegate(type
.isTypeDelegate());
2817 case Tident
: return visitIdentifier(type
.isTypeIdentifier());
2818 case Tinstance
: return visitInstance(type
.isTypeInstance());
2819 case Ttypeof
: return visitTypeof(type
.isTypeTypeof());
2820 case Ttraits
: return visitTraits(type
.isTypeTraits());
2821 case Treturn
: return visitReturn(type
.isTypeReturn());
2822 case Tstruct
: return visitStruct(type
.isTypeStruct());
2823 case Tenum
: return visitEnum(type
.isTypeEnum());
2824 case Tclass
: return visitClass(type
.isTypeClass());
2825 case Ttuple
: return visitTuple(type
.isTypeTuple());
2826 case Tslice
: return visitSlice(type
.isTypeSlice());
2827 case Tmixin
: return visitMixin(type
.isTypeMixin());
2828 case Ttag
: return visitTag(type
.isTypeTag());
2832 Type
trySemantic(Type type
, const ref Loc loc
, Scope
* sc
)
2834 //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
2836 // Needed to display any deprecations that were gagged
2837 auto tcopy
= type
.syntaxCopy();
2839 const errors
= global
.startGagging();
2840 Type t
= typeSemantic(type
, loc
, sc
);
2841 if (global
.endGagging(errors
) || t
.ty
== Terror
) // if any errors happened
2847 // If `typeSemantic` succeeded, there may have been deprecations that
2848 // were gagged due the `startGagging` above. Run again to display
2849 // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
2850 if (global
.gaggedWarnings
> 0)
2851 typeSemantic(tcopy
, loc
, sc
);
2853 //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
2857 /************************************
2858 * If an identical type to `type` is in `type.stringtable`, return
2859 * the latter one. Otherwise, add it to `type.stringtable`.
2860 * Some types don't get merged and are returned as-is.
2862 * type = Type to check against existing types
2864 * the type that was merged
2866 Type
merge(Type type
)
2876 return type
; // don't merge placeholder types
2879 // prevents generating the mangle if the array dim is not yet known
2880 if (!type
.isTypeSArray().dim
.isIntegerExp())
2888 if (!type
.isTypeAArray().index
.merge().deco
)
2893 if (type
.nextOf() && !type
.nextOf().deco
)
2898 //printf("merge(%s)\n", toChars());
2904 mangleToBuffer(type
, buf
);
2906 auto sv
= type
.stringtable
.update(buf
[]);
2912 import core
.stdc
.stdio
;
2914 printf("t = %s\n", t
.toChars());
2917 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2922 Type t
= stripDefaultArgs(type
);
2924 type
.deco
= t
.deco
= cast(char*)sv
.toDchars();
2925 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2932 /*************************************
2933 * This version does a merge even if the deco is already computed.
2934 * Necessary for types that have a deco, but are not merged.
2936 Type
merge2(Type type
)
2938 //printf("merge2(%s)\n", toChars());
2944 auto sv
= Type
.stringtable
.lookup(t
.deco
, strlen(t
.deco
));
2955 /***************************************
2956 * Calculate built-in properties which just the type is necessary.
2959 * t = the type for which the property is calculated
2960 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2961 * loc = the location where the property is encountered
2962 * ident = the identifier of the property
2963 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2964 * src = expression for type `t` or null.
2966 * expression representing the property, or null if not a property and (flag & 1)
2968 Expression
getProperty(Type t
, Scope
* scope_
, const ref Loc loc
, Identifier ident
, int flag
,
2969 Expression src
= null)
2971 Expression
visitType(Type mt
)
2974 static if (LOGDOTEXP
)
2976 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt
.toChars(), ident
.toChars());
2978 if (ident
== Id
.__sizeof
)
2980 const sz
= mt
.size(loc
);
2981 if (sz
== SIZE_INVALID
)
2982 return ErrorExp
.get();
2983 e
= new IntegerExp(loc
, sz
, Type
.tsize_t
);
2985 else if (ident
== Id
.__xalignof
)
2987 const explicitAlignment
= mt
.alignment();
2988 const naturalAlignment
= mt
.alignsize();
2989 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
2990 e
= new IntegerExp(loc
, actualAlignment
, Type
.tsize_t
);
2992 else if (ident
== Id
._init
)
2994 Type tb
= mt
.toBasetype();
2995 e
= mt
.defaultInitLiteral(loc
);
2996 if (tb
.ty
== Tstruct
&& tb
.needsNested())
2998 e
.isStructLiteralExp().useStaticInit
= true;
3001 else if (ident
== Id
._mangleof
)
3005 error(loc
, "forward reference of type `%s.mangleof`", mt
.toChars());
3010 e
= new StringExp(loc
, mt
.deco
.toDString());
3012 sc
.eSink
= global
.errorSink
;
3013 e
= e
.expressionSemantic(&sc
);
3016 else if (ident
== Id
.stringof
)
3018 const s
= mt
.toChars();
3019 e
= new StringExp(loc
, s
.toDString());
3021 sc
.eSink
= global
.errorSink
;
3022 e
= e
.expressionSemantic(&sc
);
3024 else if (flag
&& mt
!= Type
.terror
)
3031 if (mt
.ty
== Tstruct || mt
.ty
== Tclass || mt
.ty
== Tenum
)
3032 s
= mt
.toDsymbol(null);
3034 s
= s
.search_correct(ident
);
3035 if (s
&& !symbolIsVisible(scope_
, s
))
3037 if (mt
!= Type
.terror
)
3040 error(loc
, "no property `%s` for type `%s`, did you mean `%s`?", ident
.toChars(), mt
.toChars(), s
.toPrettyChars());
3041 else if (ident
== Id
.call && mt
.ty
== Tclass
)
3042 error(loc
, "no property `%s` for type `%s`, did you mean `new %s`?", ident
.toChars(), mt
.toChars(), mt
.toPrettyChars());
3044 else if (const n
= importHint(ident
.toString()))
3045 error(loc
, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident
.toChars(), mt
.toChars(), cast(int)n
.length
, n
.ptr
);
3049 error(loc
, "no property `%s` for `%s` of type `%s`", ident
.toChars(), src
.toChars(), mt
.toPrettyChars(true));
3051 error(loc
, "no property `%s` for type `%s`", ident
.toChars(), mt
.toPrettyChars(true));
3053 if (auto dsym
= mt
.toDsymbol(scope_
))
3055 if (auto sym
= dsym
.isAggregateDeclaration())
3057 if (auto fd
= search_function(sym
, Id
.opDispatch
))
3058 errorSupplemental(loc
, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
3059 else if (!sym
.members
)
3060 errorSupplemental(sym
.loc
, "`%s %s` is opaque and has no members.", sym
.kind
, mt
.toPrettyChars(true));
3062 errorSupplemental(dsym
.loc
, "%s `%s` defined here",
3063 dsym
.kind
, dsym
.toChars());
3072 Expression
visitError(TypeError
)
3074 return ErrorExp
.get();
3077 Expression
visitBasic(TypeBasic mt
)
3079 Expression
integerValue(dinteger_t i
)
3081 return new IntegerExp(loc
, i
, mt
);
3084 Expression
intValue(dinteger_t i
)
3086 return new IntegerExp(loc
, i
, Type
.tint32
);
3089 Expression
floatValue(real_t r
)
3091 if (mt
.isreal() || mt
.isimaginary())
3092 return new RealExp(loc
, r
, mt
);
3095 return new ComplexExp(loc
, complex_t(r
, r
), mt
);
3099 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
3100 if (ident
== Id
.max
)
3104 case Tint8
: return integerValue(byte.max
);
3105 case Tuns8
: return integerValue(ubyte.max
);
3106 case Tint16
: return integerValue(short.max
);
3107 case Tuns16
: return integerValue(ushort.max
);
3108 case Tint32
: return integerValue(int.max
);
3109 case Tuns32
: return integerValue(uint.max
);
3110 case Tint64
: return integerValue(long.max
);
3111 case Tuns64
: return integerValue(ulong.max
);
3112 case Tbool
: return integerValue(bool.max
);
3113 case Tchar
: return integerValue(char.max
);
3114 case Twchar
: return integerValue(wchar.max
);
3115 case Tdchar
: return integerValue(dchar.max
);
3118 case Tfloat32
: return floatValue(target
.FloatProperties
.max
);
3121 case Tfloat64
: return floatValue(target
.DoubleProperties
.max
);
3124 case Tfloat80
: return floatValue(target
.RealProperties
.max
);
3128 else if (ident
== Id
.min
)
3132 case Tint8
: return integerValue(byte.min
);
3140 case Tdchar
: return integerValue(0);
3141 case Tint16
: return integerValue(short.min
);
3142 case Tint32
: return integerValue(int.min
);
3143 case Tint64
: return integerValue(long.min
);
3147 else if (ident
== Id
.min_normal
)
3153 case Tfloat32
: return floatValue(target
.FloatProperties
.min_normal
);
3156 case Tfloat64
: return floatValue(target
.DoubleProperties
.min_normal
);
3159 case Tfloat80
: return floatValue(target
.RealProperties
.min_normal
);
3163 else if (ident
== Id
.nan
)
3175 case Tfloat80
: return floatValue(target
.RealProperties
.nan
);
3179 else if (ident
== Id
.infinity
)
3191 case Tfloat80
: return floatValue(target
.RealProperties
.infinity
);
3195 else if (ident
== Id
.dig
)
3201 case Tfloat32
: return intValue(target
.FloatProperties
.dig
);
3204 case Tfloat64
: return intValue(target
.DoubleProperties
.dig
);
3207 case Tfloat80
: return intValue(target
.RealProperties
.dig
);
3211 else if (ident
== Id
.epsilon
)
3217 case Tfloat32
: return floatValue(target
.FloatProperties
.epsilon
);
3220 case Tfloat64
: return floatValue(target
.DoubleProperties
.epsilon
);
3223 case Tfloat80
: return floatValue(target
.RealProperties
.epsilon
);
3227 else if (ident
== Id
.mant_dig
)
3233 case Tfloat32
: return intValue(target
.FloatProperties
.mant_dig
);
3236 case Tfloat64
: return intValue(target
.DoubleProperties
.mant_dig
);
3239 case Tfloat80
: return intValue(target
.RealProperties
.mant_dig
);
3243 else if (ident
== Id
.max_10_exp
)
3249 case Tfloat32
: return intValue(target
.FloatProperties
.max_10_exp
);
3252 case Tfloat64
: return intValue(target
.DoubleProperties
.max_10_exp
);
3255 case Tfloat80
: return intValue(target
.RealProperties
.max_10_exp
);
3259 else if (ident
== Id
.max_exp
)
3265 case Tfloat32
: return intValue(target
.FloatProperties
.max_exp
);
3268 case Tfloat64
: return intValue(target
.DoubleProperties
.max_exp
);
3271 case Tfloat80
: return intValue(target
.RealProperties
.max_exp
);
3275 else if (ident
== Id
.min_10_exp
)
3281 case Tfloat32
: return intValue(target
.FloatProperties
.min_10_exp
);
3284 case Tfloat64
: return intValue(target
.DoubleProperties
.min_10_exp
);
3287 case Tfloat80
: return intValue(target
.RealProperties
.min_10_exp
);
3291 else if (ident
== Id
.min_exp
)
3297 case Tfloat32
: return intValue(target
.FloatProperties
.min_exp
);
3300 case Tfloat64
: return intValue(target
.DoubleProperties
.min_exp
);
3303 case Tfloat80
: return intValue(target
.RealProperties
.min_exp
);
3307 return visitType(mt
);
3310 Expression
visitVector(TypeVector mt
)
3312 return visitType(mt
);
3315 Expression
visitEnum(TypeEnum mt
)
3318 if (ident
== Id
.max || ident
== Id
.min
)
3320 return mt
.sym
.getMaxMinValue(loc
, ident
);
3322 else if (ident
== Id
._init
)
3324 e
= mt
.defaultInitLiteral(loc
);
3326 else if (ident
== Id
.stringof
)
3328 e
= new StringExp(loc
, mt
.toString());
3330 e
= e
.expressionSemantic(&sc
);
3332 else if (ident
== Id
._mangleof
)
3338 e
= mt
.toBasetype().getProperty(scope_
, loc
, ident
, flag
);
3343 Expression
visitTuple(TypeTuple mt
)
3346 static if (LOGDOTEXP
)
3348 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt
.toChars(), ident
.toChars());
3350 if (ident
== Id
.length
)
3352 e
= new IntegerExp(loc
, mt
.arguments
.length
, Type
.tsize_t
);
3354 else if (ident
== Id
._init
)
3356 e
= mt
.defaultInitLiteral(loc
);
3364 error(loc
, "no property `%s` for sequence `%s`", ident
.toChars(), mt
.toChars());
3372 default: return t
.isTypeBasic() ?
3373 visitBasic(cast(TypeBasic
)t
) :
3376 case Terror
: return visitError (t
.isTypeError());
3377 case Tvector
: return visitVector(t
.isTypeVector());
3378 case Tenum
: return visitEnum (t
.isTypeEnum());
3379 case Ttuple
: return visitTuple (t
.isTypeTuple());
3383 /***************************************
3384 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
3386 * exp = Expression to look at
3387 * t = if exp should be a Type, set t to that Type else null
3388 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
3389 * e = if exp should remain an Expression, set e to that Expression else null
3392 private void resolveExp(Expression exp
, out Type t
, out Expression e
, out Dsymbol s
)
3394 if (exp
.isTypeExp())
3396 else if (auto ve
= exp
.isVarExp())
3398 if (auto v
= ve
.var
.isVarDeclaration())
3403 else if (auto te
= exp
.isTemplateExp())
3405 else if (auto se
= exp
.isScopeExp())
3407 else if (exp
.isFuncExp())
3408 s
= getDsymbol(exp
);
3409 else if (auto dte
= exp
.isDotTemplateExp())
3411 else if (exp
.isErrorExp())
3417 /************************************
3418 * Resolve type 'mt' to either type, symbol, or expression.
3419 * If errors happened, resolved to Type.terror.
3422 * mt = type to be resolved
3423 * loc = the location where the type is encountered
3424 * sc = the scope of the type
3425 * pe = is set if t is an expression
3426 * pt = is set if t is a type
3427 * ps = is set if t is a symbol
3428 * intypeid = true if in type id
3430 void resolve(Type mt
, const ref Loc loc
, Scope
* sc
, out Expression pe
, out Type pt
, out Dsymbol ps
, bool intypeid
= false)
3432 void returnExp(Expression e
)
3439 void returnType(Type t
)
3446 void returnSymbol(Dsymbol s
)
3455 returnType(Type
.terror
);
3458 void visitType(Type mt
)
3460 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
3461 Type t
= typeSemantic(mt
, loc
, sc
);
3466 void visitSArray(TypeSArray mt
)
3468 //printf("TypeSArray::resolve() %s\n", mt.toChars());
3469 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
3470 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
3473 // It's really an index expression
3474 if (Dsymbol s
= getDsymbol(pe
))
3475 pe
= new DsymbolExp(loc
, s
);
3476 returnExp(new ArrayExp(loc
, pe
, mt
.dim
));
3481 if (auto tup
= s
.isTupleDeclaration())
3483 mt
.dim
= semanticLength(sc
, tup
, mt
.dim
);
3484 mt
.dim
= mt
.dim
.ctfeInterpret();
3485 if (mt
.dim
.op
== EXP
.error
)
3486 return returnError();
3488 const d
= mt
.dim
.toUInteger();
3489 if (d
>= tup
.objects
.length
)
3491 error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", d
, cast(ulong) tup
.objects
.length
);
3492 return returnError();
3495 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
3496 switch (o
.dyncast()) with (DYNCAST
)
3499 return returnSymbol(cast(Dsymbol
)o
);
3501 Expression e
= cast(Expression
)o
;
3502 if (e
.op
== EXP
.dSymbol
)
3503 return returnSymbol(e
.isDsymbolExp().s
);
3505 return returnExp(e
);
3507 return returnType((cast(Type
)o
).addMod(mt
.mod
));
3512 /* Create a new TupleDeclaration which
3513 * is a slice [d..d+1] out of the old one.
3514 * Do it this way because TemplateInstance::semanticTiargs()
3515 * can handle unresolved Objects this way.
3517 auto objects
= new Objects(1);
3519 return returnSymbol(new TupleDeclaration(loc
, tup
.ident
, objects
));
3522 return visitType(mt
);
3526 if (pt
.ty
!= Terror
)
3527 mt
.next
= pt
; // prevent re-running semantic() on 'next'
3533 void visitDArray(TypeDArray mt
)
3535 //printf("TypeDArray::resolve() %s\n", mt.toChars());
3536 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
3537 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
3540 // It's really a slice expression
3541 if (Dsymbol s
= getDsymbol(pe
))
3542 pe
= new DsymbolExp(loc
, s
);
3543 returnExp(new ArrayExp(loc
, pe
));
3547 if (auto tup
= ps
.isTupleDeclaration())
3556 if (pt
.ty
!= Terror
)
3557 mt
.next
= pt
; // prevent re-running semantic() on 'next'
3562 void visitAArray(TypeAArray mt
)
3564 //printf("TypeAArray::resolve() %s\n", mt.toChars());
3565 // Deal with the case where we thought the index was a type, but
3566 // in reality it was an expression.
3567 if (mt
.index
.ty
== Tident || mt
.index
.ty
== Tinstance || mt
.index
.ty
== Tsarray
)
3572 mt
.index
.resolve(loc
, sc
, e
, t
, s
, intypeid
);
3575 // It was an expression -
3576 // Rewrite as a static array
3577 auto tsa
= new TypeSArray(mt
.next
, e
);
3578 tsa
.mod
= mt
.mod
; // just copy mod field so tsa's semantic is not yet done
3579 return tsa
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
3584 .error(loc
, "index is not a type or an expression");
3589 /*************************************
3590 * Takes an array of Identifiers and figures out if
3591 * it represents a Type or an Expression.
3593 * if expression, pe is set
3594 * if type, pt is set
3596 void visitIdentifier(TypeIdentifier mt
)
3598 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3599 if (mt
.ident
== Id
.ctfe
)
3601 error(loc
, "variable `__ctfe` cannot be read at compile time");
3602 return returnError();
3604 if (mt
.ident
== Id
.builtin_va_list
) // gcc has __builtin_va_xxxx for stdarg.h
3606 /* Since we don't support __builtin_va_start, -arg, -end, we don't
3607 * have to actually care what -list is. A void* will do.
3608 * If we ever do care, import core.stdc.stdarg and pull
3609 * the definition out of that, similarly to how std.math is handled for PowExp
3611 pt
= target
.va_listType(loc
, sc
);
3616 Dsymbol s
= sc
.search(loc
, mt
.ident
, scopesym
);
3618 * https://issues.dlang.org/show_bug.cgi?id=1170
3619 * https://issues.dlang.org/show_bug.cgi?id=10739
3621 * If a symbol is not found, it might be declared in
3622 * a mixin-ed string or a mixin-ed template, so before
3623 * issuing an error semantically analyze all string/template
3624 * mixins that are members of the current ScopeDsymbol.
3626 if (!s
&& sc
.enclosing
)
3628 ScopeDsymbol sds
= sc
.enclosing
.scopesym
;
3629 if (sds
&& sds
.members
)
3631 void semanticOnMixin(Dsymbol member
)
3633 if (auto compileDecl
= member
.isMixinDeclaration())
3634 compileDecl
.dsymbolSemantic(sc
);
3635 else if (auto mixinTempl
= member
.isTemplateMixin())
3636 mixinTempl
.dsymbolSemantic(sc
);
3638 sds
.members
.foreachDsymbol( s
=> semanticOnMixin(s
) );
3639 s
= sc
.search(loc
, mt
.ident
, scopesym
);
3645 // https://issues.dlang.org/show_bug.cgi?id=16042
3646 // If `f` is really a function template, then replace `f`
3647 // with the function template declaration.
3648 if (auto f
= s
.isFuncDeclaration())
3650 if (auto td
= getFuncTemplateDecl(f
))
3652 // If not at the beginning of the overloaded list of
3653 // `TemplateDeclaration`s, then get the beginning
3661 mt
.resolveHelper(loc
, sc
, s
, scopesym
, pe
, pt
, ps
, intypeid
);
3663 pt
= pt
.addMod(mt
.mod
);
3666 void visitInstance(TypeInstance mt
)
3668 // Note close similarity to TypeIdentifier::resolve()
3670 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
3671 mt
.tempinst
.dsymbolSemantic(sc
);
3672 if (!global
.gag
&& mt
.tempinst
.errors
)
3673 return returnError();
3675 mt
.resolveHelper(loc
, sc
, mt
.tempinst
, null, pe
, pt
, ps
, intypeid
);
3677 pt
= pt
.addMod(mt
.mod
);
3678 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
3681 void visitTypeof(TypeTypeof mt
)
3683 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
3684 //static int nest; if (++nest == 50) *(char*)0=0;
3687 error(loc
, "invalid scope");
3688 return returnError();
3693 error(loc
, "circular `typeof` definition");
3696 return returnError();
3700 /* Currently we cannot evaluate 'exp' in speculative context, because
3701 * the type implementation may leak to the final execution. Consider:
3704 * string toString() const { return "x"; }
3707 * alias X = typeof(S!int());
3708 * assert(typeid(X).toString() == "x");
3711 Scope
* sc2
= sc
.push();
3713 if (!mt
.exp
.isTypeidExp())
3714 /* Treat typeof(typeid(exp)) as needing
3715 * the full semantic analysis of the typeid.
3716 * https://issues.dlang.org/show_bug.cgi?id=20958
3720 auto exp2
= mt
.exp
.expressionSemantic(sc2
);
3721 exp2
= resolvePropertiesOnly(sc2
, exp2
);
3724 if (exp2
.op
== EXP
.error
)
3732 if ((mt
.exp
.op
== EXP
.type || mt
.exp
.op
== EXP
.scope_
) &&
3733 // https://issues.dlang.org/show_bug.cgi?id=23863
3734 // compile time sequences are valid types
3735 !mt
.exp
.type
.isTypeTuple())
3737 if (!(sc
.flags
& SCOPE
.Cfile
) && // in (extended) C typeof may be used on types as with sizeof
3741 /* Today, 'typeof(func)' returns void if func is a
3742 * function template (TemplateExp), or
3743 * template lambda (FuncExp).
3744 * It's actually used in Phobos as an idiom, to branch code for
3745 * template functions.
3748 if (auto f
= mt
.exp
.op
== EXP
.variable ? mt
.exp
.isVarExp().var
.isFuncDeclaration()
3749 : mt
.exp
.op
== EXP
.dotVariable ? mt
.exp
.isDotVarExp().var
.isFuncDeclaration() : null)
3751 // f might be a unittest declaration which is incomplete when compiled
3752 // without -unittest. That causes a segfault in checkForwardRef, see
3753 // https://issues.dlang.org/show_bug.cgi?id=20626
3754 if ((!f
.isUnitTestDeclaration() || global
.params
.useUnitTests
) && checkForwardRef(f
, loc
))
3757 if (auto f
= isFuncAddress(mt
.exp
))
3759 if (checkForwardRef(f
, loc
))
3763 Type t
= mt
.exp
.type
;
3766 error(loc
, "expression `%s` has no type", mt
.exp
.toChars());
3769 if (t
.ty
== Ttypeof
)
3771 error(loc
, "forward reference to `%s`", mt
.toChars());
3774 if (mt
.idents
.length
== 0)
3776 returnType(t
.addMod(mt
.mod
));
3780 if (Dsymbol s
= t
.toDsymbol(sc
))
3781 mt
.resolveHelper(loc
, sc
, s
, null, pe
, pt
, ps
, intypeid
);
3784 auto e
= typeToExpressionHelper(mt
, new TypeExp(loc
, t
));
3785 e
= e
.expressionSemantic(sc
);
3786 resolveExp(e
, pt
, pe
, ps
);
3789 pt
= pt
.addMod(mt
.mod
);
3794 void visitReturn(TypeReturn mt
)
3796 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3799 FuncDeclaration func
= sc
.func
;
3802 error(loc
, "`typeof(return)` must be inside function");
3803 return returnError();
3806 func
= func
.fes
.func
;
3807 t
= func
.type
.nextOf();
3810 error(loc
, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc
.func
.toChars());
3811 return returnError();
3814 if (mt
.idents
.length
== 0)
3816 return returnType(t
.addMod(mt
.mod
));
3820 if (Dsymbol s
= t
.toDsymbol(sc
))
3821 mt
.resolveHelper(loc
, sc
, s
, null, pe
, pt
, ps
, intypeid
);
3824 auto e
= typeToExpressionHelper(mt
, new TypeExp(loc
, t
));
3825 e
= e
.expressionSemantic(sc
);
3826 resolveExp(e
, pt
, pe
, ps
);
3829 pt
= pt
.addMod(mt
.mod
);
3833 void visitSlice(TypeSlice mt
)
3835 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
3838 // It's really a slice expression
3839 if (Dsymbol s
= getDsymbol(pe
))
3840 pe
= new DsymbolExp(loc
, s
);
3841 return returnExp(new ArrayExp(loc
, pe
, new IntervalExp(loc
, mt
.lwr
, mt
.upr
)));
3846 TupleDeclaration td
= s
.isTupleDeclaration();
3849 /* It's a slice of a TupleDeclaration
3851 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, td
);
3852 sym
.parent
= sc
.scopesym
;
3854 sc
= sc
.startCTFE();
3855 mt
.lwr
= mt
.lwr
.expressionSemantic(sc
);
3856 mt
.upr
= mt
.upr
.expressionSemantic(sc
);
3860 mt
.lwr
= mt
.lwr
.ctfeInterpret();
3861 mt
.upr
= mt
.upr
.ctfeInterpret();
3862 const i1
= mt
.lwr
.toUInteger();
3863 const i2
= mt
.upr
.toUInteger();
3864 if (!(i1
<= i2
&& i2
<= td
.objects
.length
))
3866 error(loc
, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1
, i2
, cast(ulong) td
.objects
.length
);
3867 return returnError();
3870 if (i1
== 0 && i2
== td
.objects
.length
)
3872 return returnSymbol(td
);
3875 /* Create a new TupleDeclaration which
3876 * is a slice [i1..i2] out of the old one.
3878 auto objects
= new Objects(cast(size_t
)(i2
- i1
));
3879 for (size_t i
= 0; i
< objects
.length
; i
++)
3881 (*objects
)[i
] = (*td
.objects
)[cast(size_t
)i1
+ i
];
3884 return returnSymbol(new TupleDeclaration(loc
, td
.ident
, objects
));
3891 if (pt
.ty
!= Terror
)
3892 mt
.next
= pt
; // prevent re-running semantic() on 'next'
3897 void visitMixin(TypeMixin mt
)
3899 RootObject o
= mt
.obj
;
3901 // if already resolved just set pe/pt/ps and return.
3904 pe
= o
.isExpression();
3910 o
= mt
.compileTypeMixin(loc
, sc
);
3911 if (auto t
= o
.isType())
3913 resolve(t
, loc
, sc
, pe
, pt
, ps
, intypeid
);
3915 pt
= pt
.addMod(mt
.mod
);
3917 else if (auto e
= o
.isExpression())
3919 e
= e
.expressionSemantic(sc
);
3920 if (auto et
= e
.isTypeExp())
3921 returnType(et
.type
.addMod(mt
.mod
));
3929 mt
.obj
= pe ? pe
: (pt ? pt
: ps
);
3932 void visitTraits(TypeTraits mt
)
3934 // if already resolved just return the cached object.
3937 pt
= mt
.obj
.isType();
3938 ps
= mt
.obj
.isDsymbol();
3939 pe
= mt
.obj
.isExpression();
3943 import dmd
.traits
: semanticTraits
;
3945 if (Expression e
= semanticTraits(mt
.exp
, sc
))
3949 case EXP
.dotVariable
:
3950 mt
.obj
= e
.isDotVarExp().var
;
3953 mt
.obj
= e
.isVarExp().var
;
3956 auto fe
= e
.isFuncExp();
3957 mt
.obj
= fe
.td ? fe
.td
: fe
.fd
;
3959 case EXP
.dotTemplateDeclaration
:
3960 mt
.obj
= e
.isDotTemplateExp().td
;
3963 mt
.obj
= e
.isDsymbolExp().s
;
3966 mt
.obj
= e
.isTemplateExp().td
;
3969 mt
.obj
= e
.isScopeExp().sds
;
3972 TupleExp te
= e
.isTupleExp();
3973 Objects
* elems
= new Objects(te
.exps
.length
);
3974 foreach (i
; 0 .. elems
.length
)
3976 auto src
= (*te
.exps
)[i
];
3980 (*elems
)[i
] = src
.isTypeExp().type
;
3983 (*elems
)[i
] = src
.isDotTypeExp().sym
.isType();
3985 case EXP
.overloadSet
:
3986 (*elems
)[i
] = src
.isOverExp().type
;
3989 if (auto sym
= isDsymbol(src
))
3995 TupleDeclaration td
= new TupleDeclaration(e
.loc
, Identifier
.generateId("__aliastup"), elems
);
3999 mt
.obj
= e
.isDotTypeExp().sym
.isType();
4002 mt
.obj
= e
.isTypeExp().type
;
4004 case EXP
.overloadSet
:
4005 mt
.obj
= e
.isOverExp().type
;
4017 if (auto t
= mt
.obj
.isType())
4019 t
= t
.addMod(mt
.mod
);
4023 else if (auto s
= mt
.obj
.isDsymbol())
4025 else if (auto e
= mt
.obj
.isExpression())
4030 assert(global
.errors
);
4031 mt
.obj
= Type
.terror
;
4032 return returnError();
4038 default: visitType (mt
); break;
4039 case Tsarray
: visitSArray (mt
.isTypeSArray()); break;
4040 case Tarray
: visitDArray (mt
.isTypeDArray()); break;
4041 case Taarray
: visitAArray (mt
.isTypeAArray()); break;
4042 case Tident
: visitIdentifier(mt
.isTypeIdentifier()); break;
4043 case Tinstance
: visitInstance (mt
.isTypeInstance()); break;
4044 case Ttypeof
: visitTypeof (mt
.isTypeTypeof()); break;
4045 case Treturn
: visitReturn (mt
.isTypeReturn()); break;
4046 case Tslice
: visitSlice (mt
.isTypeSlice()); break;
4047 case Tmixin
: visitMixin (mt
.isTypeMixin()); break;
4048 case Ttraits
: visitTraits (mt
.isTypeTraits()); break;
4052 /************************
4053 * Access the members of the object e. This type is same as e.type.
4055 * mt = type for which the dot expression is used
4056 * sc = instantiating scope
4057 * e = expression to convert
4058 * ident = identifier being used
4059 * flag = DotExpFlag bit flags
4062 * resulting expression with e.ident resolved
4064 Expression
dotExp(Type mt
, Scope
* sc
, Expression e
, Identifier ident
, DotExpFlag flag
)
4066 Expression
visitType(Type mt
)
4068 VarDeclaration v
= null;
4069 static if (LOGDOTEXP
)
4071 printf("Type::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4073 Expression ex
= e
.lastComma();
4074 if (ex
.op
== EXP
.dotVariable
)
4076 DotVarExp dv
= cast(DotVarExp
)ex
;
4077 v
= dv
.var
.isVarDeclaration();
4079 else if (ex
.op
== EXP
.variable
)
4081 VarExp ve
= cast(VarExp
)ex
;
4082 v
= ve
.var
.isVarDeclaration();
4086 if (ident
== Id
.offsetof
)
4088 v
.dsymbolSemantic(null);
4091 auto ad
= v
.isMember();
4092 objc
.checkOffsetof(e
, ad
);
4094 if (ad
.sizeok
!= Sizeok
.done
)
4095 return ErrorExp
.get();
4096 return new IntegerExp(e
.loc
, v
.offset
, Type
.tsize_t
);
4099 else if (ident
== Id
._init
)
4101 Type tb
= mt
.toBasetype();
4102 e
= mt
.defaultInitLiteral(e
.loc
);
4103 if (tb
.ty
== Tstruct
&& tb
.needsNested())
4105 e
.isStructLiteralExp().useStaticInit
= true;
4110 if (ident
== Id
.stringof
)
4112 /* https://issues.dlang.org/show_bug.cgi?id=3796
4113 * this should demangle e.type.deco rather than
4114 * pretty-printing the type.
4116 e
= new StringExp(e
.loc
, e
.toString());
4119 e
= mt
.getProperty(sc
, e
.loc
, ident
, flag
& DotExpFlag
.gag
);
4123 e
= e
.expressionSemantic(sc
);
4127 Expression
visitError(TypeError
)
4129 return ErrorExp
.get();
4132 Expression
visitBasic(TypeBasic mt
)
4134 static if (LOGDOTEXP
)
4136 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4155 e
= e
.castTo(sc
, t
);
4175 e
= new RealExp(e
.loc
, CTFloat
.zero
, t
);
4179 e
= mt
.Type
.getProperty(sc
, e
.loc
, ident
, flag
);
4183 else if (ident
== Id
.im
)
4189 t
= mt
.timaginary32
;
4194 t
= mt
.timaginary64
;
4199 t
= mt
.timaginary80
;
4203 e
= e
.castTo(sc
, t
);
4226 e
= new RealExp(e
.loc
, CTFloat
.zero
, mt
);
4230 e
= mt
.Type
.getProperty(sc
, e
.loc
, ident
, flag
);
4236 return visitType(mt
);
4238 if (!(flag
& 1) || e
)
4239 e
= e
.expressionSemantic(sc
);
4243 Expression
visitVector(TypeVector mt
)
4245 static if (LOGDOTEXP
)
4247 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4249 if (ident
== Id
.ptr
&& e
.op
== EXP
.call)
4251 /* The trouble with EXP.call is the return ABI for float[4] is different from
4252 * __vector(float[4]), and a type paint won't do.
4254 e
= new AddrExp(e
.loc
, e
);
4255 e
= e
.expressionSemantic(sc
);
4256 return e
.castTo(sc
, mt
.basetype
.nextOf().pointerTo());
4258 if (ident
== Id
.array
)
4260 //e = e.castTo(sc, basetype);
4262 e
= new VectorArrayExp(e
.loc
, e
);
4263 e
= e
.expressionSemantic(sc
);
4266 if (ident
== Id
._init || ident
== Id
.offsetof || ident
== Id
.stringof || ident
== Id
.__xalignof
)
4268 // init should return a new VectorExp
4269 // https://issues.dlang.org/show_bug.cgi?id=12776
4270 // offsetof does not work on a cast expression, so use e directly
4271 // stringof should not add a cast to the output
4272 return visitType(mt
);
4275 // Properties based on the vector element type and are values of the element type
4276 if (ident
== Id
.max || ident
== Id
.min || ident
== Id
.min_normal ||
4277 ident
== Id
.nan || ident
== Id
.infinity || ident
== Id
.epsilon
)
4279 auto vet
= mt
.basetype
.isTypeSArray().next
; // vector element type
4280 if (auto ev
= getProperty(vet
, sc
, e
.loc
, ident
, DotExpFlag
.gag
))
4281 return ev
.castTo(sc
, mt
); // 'broadcast' ev to the vector elements
4284 return mt
.basetype
.dotExp(sc
, e
.castTo(sc
, mt
.basetype
), ident
, flag
);
4287 Expression
visitArray(TypeArray mt
)
4289 static if (LOGDOTEXP
)
4291 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4296 if (!(flag
& 1) || e
)
4297 e
= e
.expressionSemantic(sc
);
4301 Expression
visitSArray(TypeSArray mt
)
4303 static if (LOGDOTEXP
)
4305 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4307 if (ident
== Id
.length
)
4313 else if (ident
== Id
.ptr
)
4315 if (e
.op
== EXP
.type
)
4317 error(e
.loc
, "`%s` is not an expression", e
.toChars());
4318 return ErrorExp
.get();
4320 else if (mt
.dim
.toUInteger() < 1 && checkUnsafeDotExp(sc
, e
, ident
, flag
))
4322 // .ptr on static array is @safe unless size is 0
4323 // https://issues.dlang.org/show_bug.cgi?id=20853
4324 return ErrorExp
.get();
4326 e
= e
.castTo(sc
, e
.type
.nextOf().pointerTo());
4328 else if (ident
== Id
._tupleof
)
4332 error(e
.loc
, "`.tupleof` cannot be used on type `%s`", mt
.toChars
);
4333 return ErrorExp
.get();
4339 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
4341 const length
= cast(size_t
)mt
.dim
.toUInteger();
4342 auto exps
= new Expressions();
4343 exps
.reserve(length
);
4344 foreach (i
; 0 .. length
)
4345 exps
.push(new IndexExp(e
.loc
, ev
, new IntegerExp(e
.loc
, i
, Type
.tsize_t
)));
4346 e
= new TupleExp(e
.loc
, e0
, exps
);
4353 if (!(flag
& 1) || e
)
4354 e
= e
.expressionSemantic(sc
);
4358 Expression
visitDArray(TypeDArray mt
)
4360 static if (LOGDOTEXP
)
4362 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4364 if (e
.op
== EXP
.type
&& (ident
== Id
.length || ident
== Id
.ptr
))
4366 error(e
.loc
, "`%s` is not an expression", e
.toChars());
4367 return ErrorExp
.get();
4369 if (ident
== Id
.length
)
4371 if (e
.op
== EXP
.string_
)
4373 StringExp se
= cast(StringExp
)e
;
4374 return new IntegerExp(se
.loc
, se
.len
, Type
.tsize_t
);
4376 if (e
.op
== EXP
.null_
)
4378 return new IntegerExp(e
.loc
, 0, Type
.tsize_t
);
4380 if (checkNonAssignmentArrayOp(e
))
4382 return ErrorExp
.get();
4384 e
= new ArrayLengthExp(e
.loc
, e
);
4385 e
.type
= Type
.tsize_t
;
4388 else if (ident
== Id
.ptr
)
4390 if (checkUnsafeDotExp(sc
, e
, ident
, flag
))
4391 return ErrorExp
.get();
4392 return e
.castTo(sc
, mt
.next
.pointerTo());
4396 return visitArray(mt
);
4400 Expression
visitAArray(TypeAArray mt
)
4402 static if (LOGDOTEXP
)
4404 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4406 if (ident
== Id
.length
)
4408 __gshared FuncDeclaration fd_aaLen
= null;
4409 if (fd_aaLen
is null)
4411 auto fparams
= new Parameters();
4412 fparams
.push(new Parameter(Loc
.initial
, STC
.const_ | STC
.scope_
, mt
, null, null, null));
4413 fd_aaLen
= FuncDeclaration
.genCfunc(fparams
, Type
.tsize_t
, Id
.aaLen
);
4414 TypeFunction tf
= fd_aaLen
.type
.toTypeFunction();
4415 tf
.purity
= PURE
.const_
;
4416 tf
.isnothrow
= true;
4419 Expression ev
= new VarExp(e
.loc
, fd_aaLen
, false);
4420 e
= new CallExp(e
.loc
, ev
, e
);
4421 e
.type
= fd_aaLen
.type
.toTypeFunction().next
;
4426 return visitType(mt
);
4430 Expression
visitReference(TypeReference mt
)
4432 static if (LOGDOTEXP
)
4434 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4436 // References just forward things along
4437 return mt
.next
.dotExp(sc
, e
, ident
, flag
);
4440 Expression
visitDelegate(TypeDelegate mt
)
4442 static if (LOGDOTEXP
)
4444 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4446 if (ident
== Id
.ptr
)
4448 e
= new DelegatePtrExp(e
.loc
, e
);
4449 e
= e
.expressionSemantic(sc
);
4451 else if (ident
== Id
.funcptr
)
4453 if (checkUnsafeDotExp(sc
, e
, ident
, flag
))
4455 return ErrorExp
.get();
4457 e
= new DelegateFuncptrExp(e
.loc
, e
);
4458 e
= e
.expressionSemantic(sc
);
4462 return visitType(mt
);
4467 /***************************************
4468 * `ident` was not found as a member of `mt`.
4469 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
4470 * If that fails, forward to visitType().
4472 * mt = class or struct
4474 * e = `this` for `ident`
4475 * ident = name of member
4476 * flag = flag & 1, don't report "not a property" error and just return NULL.
4477 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
4479 * resolved expression if found, otherwise null
4481 Expression
noMember(Type mt
, Scope
* sc
, Expression e
, Identifier ident
, int flag
)
4483 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
4485 bool gagError
= flag
& 1;
4487 __gshared
int nest
; // https://issues.dlang.org/show_bug.cgi?id=17380
4489 static Expression
returnExp(Expression e
)
4495 if (++nest
> global
.recursionLimit
)
4497 .error(e
.loc
, "cannot resolve identifier `%s`", ident
.toChars());
4498 return returnExp(gagError ?
null : ErrorExp
.get());
4502 assert(mt
.ty
== Tstruct || mt
.ty
== Tclass
);
4503 auto sym
= mt
.toDsymbol(sc
).isAggregateDeclaration();
4505 if (// https://issues.dlang.org/show_bug.cgi?id=22054
4506 // if a class or struct does not have a body
4507 // there is no point in searching for its members
4509 ident
!= Id
.__sizeof
&&
4510 ident
!= Id
.__xalignof
&&
4511 ident
!= Id
._init
&&
4512 ident
!= Id
._mangleof
&&
4513 ident
!= Id
.stringof
&&
4514 ident
!= Id
.offsetof
&&
4515 // https://issues.dlang.org/show_bug.cgi?id=15045
4516 // Don't forward special built-in member functions.
4519 ident
!= Id
.__xdtor
&&
4520 ident
!= Id
.postblit
&&
4521 ident
!= Id
.__xpostblit
)
4523 /* Look for overloaded opDot() to see if we should forward request
4526 if (auto fd
= search_function(sym
, Id
.opDot
))
4528 /* Rewrite e.ident as:
4531 e
= build_overload(e
.loc
, sc
, e
, null, fd
);
4532 // @@@DEPRECATED_2.110@@@.
4533 // Deprecated in 2.082, made an error in 2.100.
4534 error(e
.loc
, "`opDot` is obsolete. Use `alias this`");
4535 return ErrorExp
.get();
4538 /* Look for overloaded opDispatch to see if we should forward request
4541 if (auto fd
= search_function(sym
, Id
.opDispatch
))
4543 /* Rewrite e.ident as:
4544 * e.opDispatch!("ident")
4546 TemplateDeclaration td
= fd
.isTemplateDeclaration();
4549 .error(fd
.loc
, "%s `%s` must be a template `opDispatch(string s)`, not a %s", fd
.kind
, fd
.toPrettyChars
, fd
.kind());
4550 return returnExp(ErrorExp
.get());
4552 auto se
= new StringExp(e
.loc
, ident
.toString());
4553 auto tiargs
= new Objects();
4555 auto dti
= new DotTemplateInstanceExp(e
.loc
, e
, Id
.opDispatch
, tiargs
);
4556 dti
.ti
.tempdecl
= td
;
4557 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
4559 * template opDispatch(name) if (isValid!name) { ... }
4561 uint errors
= gagError ? global
.startGagging() : 0;
4562 e
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.none
);
4563 if (gagError
&& global
.endGagging(errors
))
4565 return returnExp(e
);
4568 /* See if we should forward to the alias this.
4570 auto alias_e
= flag
& DotExpFlag
.noAliasThis ?
null
4571 : resolveAliasThis(sc
, e
, gagError
);
4572 if (alias_e
&& alias_e
!= e
)
4574 /* Rewrite e.ident as:
4577 auto die
= new DotIdExp(e
.loc
, alias_e
, ident
);
4579 auto errors
= gagError ?
0 : global
.startGagging();
4580 auto exp
= die
.dotIdSemanticProp(sc
, gagError
);
4583 global
.endGagging(errors
);
4584 if (exp
&& exp
.op
== EXP
.error
)
4588 if (exp
&& gagError
)
4589 // now that we know that the alias this leads somewhere useful,
4590 // go back and print deprecations/warnings that we skipped earlier due to the gag
4591 resolveAliasThis(sc
, e
, false);
4593 return returnExp(exp
);
4596 return returnExp(visitType(mt
));
4599 Expression
visitStruct(TypeStruct mt
)
4602 static if (LOGDOTEXP
)
4604 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4606 assert(e
.op
!= EXP
.dot
);
4608 // https://issues.dlang.org/show_bug.cgi?id=14010
4609 if (!(sc
.flags
& SCOPE
.Cfile
) && ident
== Id
._mangleof
)
4611 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
4616 if (ident
== Id
._tupleof
)
4618 /* Create a TupleExp out of the fields of the struct e:
4619 * (e.field0, e.field1, e.field2, ...)
4621 e
= e
.expressionSemantic(sc
); // do this before turning on noaccesscheck
4623 if (!mt
.sym
.determineFields())
4625 error(e
.loc
, "unable to determine fields of `%s` because of forward references", mt
.toChars());
4629 Expression ev
= e
.op
== EXP
.type ?
null : e
;
4631 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
4633 auto exps
= new Expressions();
4634 exps
.reserve(mt
.sym
.fields
.length
);
4635 for (size_t i
= 0; i
< mt
.sym
.fields
.length
; i
++)
4637 VarDeclaration v
= mt
.sym
.fields
[i
];
4640 ex
= new DotVarExp(e
.loc
, ev
, v
);
4643 ex
= new VarExp(e
.loc
, v
);
4644 ex
.type
= ex
.type
.addMod(e
.type
.mod
);
4649 e
= new TupleExp(e
.loc
, e0
, exps
);
4650 Scope
* sc2
= sc
.push();
4651 sc2
.flags |
= SCOPE
.noaccesscheck
;
4652 e
= e
.expressionSemantic(sc2
);
4657 immutable flags
= sc
.flags
& SCOPE
.ignoresymbolvisibility ? SearchOpt
.ignoreVisibility
: 0;
4658 s
= mt
.sym
.search(e
.loc
, ident
, flags | SearchOpt
.ignorePrivateImports
);
4662 return noMember(mt
, sc
, e
, ident
, flag
);
4664 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, s
))
4666 return noMember(mt
, sc
, e
, ident
, flag
);
4668 // check before alias resolution; the alias itself might be deprecated!
4669 if (s
.isAliasDeclaration
)
4670 s
.checkDeprecated(e
.loc
, sc
);
4673 if (auto em
= s
.isEnumMember())
4675 return em
.getVarExp(e
.loc
, sc
);
4677 if (auto v
= s
.isVarDeclaration())
4679 v
.checkDeprecated(e
.loc
, sc
);
4680 v
.checkDisabled(e
.loc
, sc
);
4682 !v
.type
.deco
&& v
.inuse
)
4684 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
4685 error(e
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
4687 error(e
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
4688 return ErrorExp
.get();
4690 if (v
.type
.ty
== Terror
)
4692 return ErrorExp
.get();
4695 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
4699 error(e
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
4700 return ErrorExp
.get();
4702 checkAccess(e
.loc
, sc
, null, v
);
4703 Expression ve
= new VarExp(e
.loc
, v
);
4704 if (!isTrivialExp(e
))
4706 ve
= new CommaExp(e
.loc
, e
, ve
);
4708 return ve
.expressionSemantic(sc
);
4712 if (auto t
= s
.getType())
4714 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
4717 TemplateMixin tm
= s
.isTemplateMixin();
4720 return new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, tm
)).expressionSemantic(sc
);
4723 TemplateDeclaration td
= s
.isTemplateDeclaration();
4726 if (e
.op
== EXP
.type
)
4727 e
= new TemplateExp(e
.loc
, td
);
4729 e
= new DotTemplateExp(e
.loc
, e
, td
);
4730 return e
.expressionSemantic(sc
);
4733 TemplateInstance ti
= s
.isTemplateInstance();
4736 if (!ti
.semanticRun
)
4738 ti
.dsymbolSemantic(sc
);
4739 if (!ti
.inst || ti
.errors
) // if template failed to expand
4741 return ErrorExp
.get();
4744 s
= ti
.inst
.toAlias();
4745 if (!s
.isTemplateInstance())
4747 if (e
.op
== EXP
.type
)
4748 e
= new ScopeExp(e
.loc
, ti
);
4750 e
= new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, ti
));
4751 return e
.expressionSemantic(sc
);
4754 if (s
.isImport() || s
.isModule() || s
.isPackage())
4756 return symbolToExp(s
, e
.loc
, sc
, false);
4759 OverloadSet o
= s
.isOverloadSet();
4762 auto oe
= new OverExp(e
.loc
, o
);
4763 if (e
.op
== EXP
.type
)
4767 return new DotExp(e
.loc
, e
, oe
);
4770 Declaration d
= s
.isDeclaration();
4773 error(e
.loc
, "`%s.%s` is not a declaration", e
.toChars(), ident
.toChars());
4774 return ErrorExp
.get();
4777 if (e
.op
== EXP
.type
)
4782 if (TupleDeclaration tup
= d
.isTupleDeclaration())
4784 e
= new TupleExp(e
.loc
, tup
);
4785 return e
.expressionSemantic(sc
);
4787 if (d
.needThis() && sc
.intypeof
!= 1)
4792 * only if the scope in which we are
4793 * has a `this` that matches the type
4794 * of the lhs of the dot expression.
4796 * https://issues.dlang.org/show_bug.cgi?id=23617
4798 auto fd
= hasThis(sc
);
4799 if (fd
&& fd
.isThis() == mt
.sym
)
4801 e
= new DotVarExp(e
.loc
, new ThisExp(e
.loc
), d
);
4802 return e
.expressionSemantic(sc
);
4805 if (d
.semanticRun
== PASS
.initial
)
4806 d
.dsymbolSemantic(null);
4807 checkAccess(e
.loc
, sc
, e
, d
);
4808 auto ve
= new VarExp(e
.loc
, d
);
4809 if (d
.isVarDeclaration() && d
.needThis())
4810 ve
.type
= d
.type
.addMod(e
.type
.mod
);
4814 bool unreal
= e
.op
== EXP
.variable
&& (cast(VarExp
)e
).var
.isField();
4815 if (d
.isDataseg() || unreal
&& d
.isField())
4818 checkAccess(e
.loc
, sc
, e
, d
);
4819 Expression ve
= new VarExp(e
.loc
, d
);
4820 e
= unreal ? ve
: new CommaExp(e
.loc
, e
, ve
);
4821 return e
.expressionSemantic(sc
);
4824 e
= new DotVarExp(e
.loc
, e
, d
);
4825 return e
.expressionSemantic(sc
);
4828 Expression
visitEnum(TypeEnum mt
)
4830 static if (LOGDOTEXP
)
4832 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e
.toChars(), ident
.toChars(), mt
.toChars());
4834 // https://issues.dlang.org/show_bug.cgi?id=14010
4835 if (ident
== Id
._mangleof
)
4837 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
4840 if (mt
.sym
.semanticRun
< PASS
.semanticdone
)
4841 mt
.sym
.dsymbolSemantic(null);
4843 Dsymbol s
= mt
.sym
.search(e
.loc
, ident
);
4846 if (ident
== Id
._init
)
4848 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
4851 /* Allow special enums to not need a member list
4853 if ((ident
== Id
.max || ident
== Id
.min
) && (mt
.sym
.members ||
!mt
.sym
.isSpecial()))
4855 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
4858 Expression res
= mt
.sym
.getMemtype(Loc
.initial
).dotExp(sc
, e
, ident
, DotExpFlag
.gag
);
4859 if (!(flag
& 1) && !res
)
4861 if (auto ns
= mt
.sym
.search_correct(ident
))
4862 error(e
.loc
, "no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident
.toChars(), mt
.toChars(), mt
.toChars(),
4865 error(e
.loc
, "no property `%s` for type `%s`", ident
.toChars(),
4868 errorSupplemental(mt
.sym
.loc
, "%s `%s` defined here",
4869 mt
.sym
.kind
, mt
.toChars());
4870 return ErrorExp
.get();
4874 EnumMember m
= s
.isEnumMember();
4875 return m
.getVarExp(e
.loc
, sc
);
4878 Expression
visitClass(TypeClass mt
)
4881 static if (LOGDOTEXP
)
4883 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4885 assert(e
.op
!= EXP
.dot
);
4887 // https://issues.dlang.org/show_bug.cgi?id=12543
4888 if (ident
== Id
.__sizeof || ident
== Id
.__xalignof || ident
== Id
._mangleof
)
4890 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4895 if (ident
== Id
._tupleof
)
4897 objc
.checkTupleof(e
, mt
);
4899 /* Create a TupleExp
4901 e
= e
.expressionSemantic(sc
); // do this before turning on noaccesscheck
4903 mt
.sym
.size(e
.loc
); // do semantic of type
4906 Expression ev
= e
.op
== EXP
.type ?
null : e
;
4908 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
4910 auto exps
= new Expressions();
4911 exps
.reserve(mt
.sym
.fields
.length
);
4912 for (size_t i
= 0; i
< mt
.sym
.fields
.length
; i
++)
4914 VarDeclaration v
= mt
.sym
.fields
[i
];
4915 // Don't include hidden 'this' pointer
4916 if (v
.isThisDeclaration())
4920 ex
= new DotVarExp(e
.loc
, ev
, v
);
4923 ex
= new VarExp(e
.loc
, v
);
4924 ex
.type
= ex
.type
.addMod(e
.type
.mod
);
4929 e
= new TupleExp(e
.loc
, e0
, exps
);
4930 Scope
* sc2
= sc
.push();
4931 sc2
.flags |
= SCOPE
.noaccesscheck
;
4932 e
= e
.expressionSemantic(sc2
);
4937 SearchOptFlags flags
= sc
.flags
& SCOPE
.ignoresymbolvisibility ? SearchOpt
.ignoreVisibility
: SearchOpt
.all
;
4938 s
= mt
.sym
.search(e
.loc
, ident
, flags | SearchOpt
.ignorePrivateImports
);
4943 // See if it's a 'this' class or a base class
4944 if (mt
.sym
.ident
== ident
)
4946 if (e
.op
== EXP
.type
)
4948 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4950 e
= new DotTypeExp(e
.loc
, e
, mt
.sym
);
4951 e
= e
.expressionSemantic(sc
);
4954 if (auto cbase
= mt
.sym
.searchBase(ident
))
4956 if (e
.op
== EXP
.type
)
4958 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4960 if (auto ifbase
= cbase
.isInterfaceDeclaration())
4961 e
= new CastExp(e
.loc
, e
, ifbase
.type
);
4963 e
= new DotTypeExp(e
.loc
, e
, cbase
);
4964 e
= e
.expressionSemantic(sc
);
4968 if (ident
== Id
.classinfo
)
4970 if (!Type
.typeinfoclass
)
4972 error(e
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4973 return ErrorExp
.get();
4976 Type t
= Type
.typeinfoclass
.type
;
4977 if (e
.op
== EXP
.type || e
.op
== EXP
.dotType
)
4979 /* For type.classinfo, we know the classinfo
4982 if (!mt
.sym
.vclassinfo
)
4983 mt
.sym
.vclassinfo
= new TypeInfoClassDeclaration(mt
.sym
.type
);
4984 e
= new VarExp(e
.loc
, mt
.sym
.vclassinfo
);
4986 e
.type
= t
; // do this so we don't get redundant dereference
4990 /* For class objects, the classinfo reference is the first
4991 * entry in the vtbl[]
4993 e
= new PtrExp(e
.loc
, e
);
4994 e
.type
= t
.pointerTo();
4995 if (mt
.sym
.isInterfaceDeclaration())
4997 if (mt
.sym
.isCPPinterface())
4999 /* C++ interface vtbl[]s are different in that the
5000 * first entry is always pointer to the first virtual
5001 * function, not classinfo.
5002 * We can't get a .classinfo for it.
5004 error(e
.loc
, "no `.classinfo` for C++ interface objects");
5006 /* For an interface, the first entry in the vtbl[]
5007 * is actually a pointer to an instance of struct Interface.
5008 * The first member of Interface is the .classinfo,
5009 * so add an extra pointer indirection.
5011 e
.type
= e
.type
.pointerTo();
5012 e
= new PtrExp(e
.loc
, e
);
5013 e
.type
= t
.pointerTo();
5015 e
= new PtrExp(e
.loc
, e
, t
);
5020 if (ident
== Id
.__vptr
)
5022 /* The pointer to the vtbl[]
5023 * *cast(immutable(void*)**)e
5025 e
= e
.castTo(sc
, mt
.tvoidptr
.immutableOf().pointerTo().pointerTo());
5026 e
= new PtrExp(e
.loc
, e
);
5027 e
= e
.expressionSemantic(sc
);
5031 if (ident
== Id
.__monitor
&& mt
.sym
.hasMonitor())
5033 /* The handle to the monitor (call it a void*)
5034 * *(cast(void**)e + 1)
5036 e
= e
.castTo(sc
, mt
.tvoidptr
.pointerTo());
5037 e
= new AddExp(e
.loc
, e
, IntegerExp
.literal
!1);
5038 e
= new PtrExp(e
.loc
, e
);
5039 e
= e
.expressionSemantic(sc
);
5043 if (ident
== Id
.outer
&& mt
.sym
.vthis
)
5045 if (mt
.sym
.vthis
.semanticRun
== PASS
.initial
)
5046 mt
.sym
.vthis
.dsymbolSemantic(null);
5048 if (auto cdp
= mt
.sym
.toParentLocal().isClassDeclaration())
5050 auto dve
= new DotVarExp(e
.loc
, e
, mt
.sym
.vthis
);
5051 dve
.type
= cdp
.type
.addMod(e
.type
.mod
);
5055 /* https://issues.dlang.org/show_bug.cgi?id=15839
5056 * Find closest parent class through nested functions.
5058 for (auto p
= mt
.sym
.toParentLocal(); p
; p
= p
.toParentLocal())
5060 auto fd
= p
.isFuncDeclaration();
5063 auto ad
= fd
.isThis();
5064 if (!ad
&& fd
.isNested())
5068 if (auto cdp
= ad
.isClassDeclaration())
5070 auto ve
= new ThisExp(e
.loc
);
5073 const nestedError
= fd
.vthis
.checkNestedReference(sc
, e
.loc
);
5074 assert(!nestedError
);
5076 ve
.type
= cdp
.type
.addMod(fd
.vthis
.type
.mod
).addMod(e
.type
.mod
);
5082 // Continue to show enclosing function's frame (stack or closure).
5083 auto dve
= new DotVarExp(e
.loc
, e
, mt
.sym
.vthis
);
5084 dve
.type
= mt
.sym
.vthis
.type
.addMod(e
.type
.mod
);
5088 return noMember(mt
, sc
, e
, ident
, flag
& 1);
5090 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, s
))
5092 return noMember(mt
, sc
, e
, ident
, flag
);
5094 if (!s
.isFuncDeclaration()) // because of overloading
5096 s
.checkDeprecated(e
.loc
, sc
);
5097 if (auto d
= s
.isDeclaration())
5098 d
.checkDisabled(e
.loc
, sc
);
5102 if (auto em
= s
.isEnumMember())
5104 return em
.getVarExp(e
.loc
, sc
);
5106 if (auto v
= s
.isVarDeclaration())
5109 !v
.type
.deco
&& v
.inuse
)
5111 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
5112 error(e
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
5114 error(e
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
5115 return ErrorExp
.get();
5117 if (v
.type
.ty
== Terror
)
5119 error(e
.loc
, "type of variable `%s` has errors", v
.toPrettyChars
);
5120 return ErrorExp
.get();
5123 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
5127 error(e
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
5128 return ErrorExp
.get();
5130 checkAccess(e
.loc
, sc
, null, v
);
5131 Expression ve
= new VarExp(e
.loc
, v
);
5132 ve
= ve
.expressionSemantic(sc
);
5137 if (auto t
= s
.getType())
5139 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
5142 TemplateMixin tm
= s
.isTemplateMixin();
5145 return new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, tm
)).expressionSemantic(sc
);
5148 TemplateDeclaration td
= s
.isTemplateDeclaration();
5150 Expression
toTemplateExp(TemplateDeclaration td
)
5152 if (e
.op
== EXP
.type
)
5153 e
= new TemplateExp(e
.loc
, td
);
5155 e
= new DotTemplateExp(e
.loc
, e
, td
);
5156 e
= e
.expressionSemantic(sc
);
5162 return toTemplateExp(td
);
5165 TemplateInstance ti
= s
.isTemplateInstance();
5168 if (!ti
.semanticRun
)
5170 ti
.dsymbolSemantic(sc
);
5171 if (!ti
.inst || ti
.errors
) // if template failed to expand
5173 return ErrorExp
.get();
5176 s
= ti
.inst
.toAlias();
5177 if (!s
.isTemplateInstance())
5179 if (e
.op
== EXP
.type
)
5180 e
= new ScopeExp(e
.loc
, ti
);
5182 e
= new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, ti
));
5183 return e
.expressionSemantic(sc
);
5186 if (s
.isImport() || s
.isModule() || s
.isPackage())
5188 e
= symbolToExp(s
, e
.loc
, sc
, false);
5192 OverloadSet o
= s
.isOverloadSet();
5195 auto oe
= new OverExp(e
.loc
, o
);
5196 if (e
.op
== EXP
.type
)
5200 return new DotExp(e
.loc
, e
, oe
);
5203 Declaration d
= s
.isDeclaration();
5206 error(e
.loc
, "`%s.%s` is not a declaration", e
.toChars(), ident
.toChars());
5207 return ErrorExp
.get();
5210 if (e
.op
== EXP
.type
)
5215 if (TupleDeclaration tup
= d
.isTupleDeclaration())
5217 e
= new TupleExp(e
.loc
, tup
);
5218 e
= e
.expressionSemantic(sc
);
5222 if (mt
.sym
.classKind
== ClassKind
.objc
5223 && d
.isFuncDeclaration()
5224 && d
.isFuncDeclaration().isStatic
5225 && d
.isFuncDeclaration().objc
.selector
)
5227 auto classRef
= new ObjcClassReferenceExp(e
.loc
, mt
.sym
);
5228 classRef
.type
= objc
.getRuntimeMetaclass(mt
.sym
).getType();
5229 return new DotVarExp(e
.loc
, classRef
, d
).expressionSemantic(sc
);
5231 else if (d
.needThis() && sc
.intypeof
!= 1)
5236 AggregateDeclaration ad
= d
.isMemberLocal();
5237 if (auto f
= hasThis(sc
))
5239 // This is almost same as getRightThis() in expressionsem.d
5242 /* returns: true to continue, false to return */
5243 if (f
.hasDualContext())
5245 if (f
.followInstantiationContext(ad
))
5247 e1
= new VarExp(e
.loc
, f
.vthis
);
5248 e1
= new PtrExp(e1
.loc
, e1
);
5249 e1
= new IndexExp(e1
.loc
, e1
, IntegerExp
.literal
!1);
5250 auto pd
= f
.toParent2().isDeclaration();
5252 t
= pd
.type
.toBasetype();
5253 e1
= getThisSkipNestedFuncs(e1
.loc
, sc
, f
.toParent2(), ad
, e1
, t
, d
, true);
5256 e
= new VarExp(e
.loc
, d
);
5262 e1
= new ThisExp(e
.loc
);
5263 e1
= e1
.expressionSemantic(sc
);
5265 t
= e1
.type
.toBasetype();
5266 ClassDeclaration cd
= e
.type
.isClassHandle();
5267 ClassDeclaration tcd
= t
.isClassHandle();
5268 if (cd
&& tcd
&& (tcd
== cd || cd
.isBaseOf(tcd
, null)))
5270 e
= new DotTypeExp(e1
.loc
, e1
, cd
);
5271 e
= new DotVarExp(e
.loc
, e
, d
);
5272 e
= e
.expressionSemantic(sc
);
5275 if (tcd
&& tcd
.isNested())
5277 /* e1 is the 'this' pointer for an inner class: tcd.
5278 * Rewrite it as the 'this' pointer for the outer class.
5280 auto vthis
= tcd
.followInstantiationContext(ad
) ? tcd
.vthis2
: tcd
.vthis
;
5281 e1
= new DotVarExp(e
.loc
, e1
, vthis
);
5282 e1
.type
= vthis
.type
;
5283 e1
.type
= e1
.type
.addMod(t
.mod
);
5284 // Do not call ensureStaticLinkTo()
5285 //e1 = e1.expressionSemantic(sc);
5287 // Skip up over nested functions, and get the enclosing
5289 e1
= getThisSkipNestedFuncs(e1
.loc
, sc
, tcd
.toParentP(ad
), ad
, e1
, t
, d
, true);
5292 e
= new VarExp(e
.loc
, d
);
5299 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
5300 if (d
.semanticRun
== PASS
.initial
)
5301 d
.dsymbolSemantic(null);
5303 // If static function, get the most visible overload.
5304 // Later on the call is checked for correctness.
5305 // https://issues.dlang.org/show_bug.cgi?id=12511
5307 if (auto fd
= d
.isFuncDeclaration())
5309 import dmd
.access
: mostVisibleOverload
;
5310 d2
= mostVisibleOverload(fd
, sc
._module
);
5313 checkAccess(e
.loc
, sc
, e
, d2
);
5314 if (d2
.isDeclaration())
5316 d
= cast(Declaration
)d2
;
5317 auto ve
= new VarExp(e
.loc
, d
);
5318 if (d
.isVarDeclaration() && d
.needThis())
5319 ve
.type
= d
.type
.addMod(e
.type
.mod
);
5322 else if (d2
.isTemplateDeclaration())
5324 return toTemplateExp(cast(TemplateDeclaration
)d2
);
5330 bool unreal
= e
.op
== EXP
.variable
&& (cast(VarExp
)e
).var
.isField();
5331 if (d
.isDataseg() || unreal
&& d
.isField())
5334 checkAccess(e
.loc
, sc
, e
, d
);
5335 Expression ve
= new VarExp(e
.loc
, d
);
5336 e
= unreal ? ve
: new CommaExp(e
.loc
, e
, ve
);
5337 e
= e
.expressionSemantic(sc
);
5341 e
= new DotVarExp(e
.loc
, e
, d
);
5342 e
= e
.expressionSemantic(sc
);
5348 case Tvector
: return visitVector (mt
.isTypeVector());
5349 case Tsarray
: return visitSArray (mt
.isTypeSArray());
5350 case Tstruct
: return visitStruct (mt
.isTypeStruct());
5351 case Tenum
: return visitEnum (mt
.isTypeEnum());
5352 case Terror
: return visitError (mt
.isTypeError());
5353 case Tarray
: return visitDArray (mt
.isTypeDArray());
5354 case Taarray
: return visitAArray (mt
.isTypeAArray());
5355 case Treference
: return visitReference(mt
.isTypeReference());
5356 case Tdelegate
: return visitDelegate (mt
.isTypeDelegate());
5357 case Tclass
: return visitClass (mt
.isTypeClass());
5359 default: return mt
.isTypeBasic()
5360 ?
visitBasic(cast(TypeBasic
)mt
)
5366 /************************
5367 * Get the default initialization expression for a type.
5369 * mt = the type for which the init expression is returned
5370 * loc = the location where the expression needs to be evaluated
5371 * isCfile = default initializers are different with C
5374 * The initialization expression for the type.
5376 Expression
defaultInit(Type mt
, const ref Loc loc
, const bool isCfile
= false)
5378 Expression
visitBasic(TypeBasic mt
)
5380 static if (LOGDEFAULTINIT
)
5382 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt
.toChars(), isCfile
);
5384 dinteger_t value
= 0;
5389 value
= isCfile ?
0 : 0xFF;
5394 value
= isCfile ?
0 : 0xFFFF;
5403 return new RealExp(loc
, isCfile ? CTFloat
.zero
: target
.RealProperties
.nan
, mt
);
5409 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
5410 const cvalue
= isCfile ?
complex_t(CTFloat
.zero
, CTFloat
.zero
)
5411 : complex_t(target
.RealProperties
.nan
, target
.RealProperties
.nan
);
5412 return new ComplexExp(loc
, cvalue
, mt
);
5416 error(loc
, "`void` does not have a default initializer");
5417 return ErrorExp
.get();
5422 return new IntegerExp(loc
, value
, mt
);
5425 Expression
visitVector(TypeVector mt
)
5427 //printf("TypeVector::defaultInit()\n");
5428 assert(mt
.basetype
.ty
== Tsarray
);
5429 Expression e
= mt
.basetype
.defaultInit(loc
, isCfile
);
5430 auto ve
= new VectorExp(loc
, e
, mt
);
5432 ve
.dim
= cast(int)(mt
.basetype
.size(loc
) / mt
.elementType().size(loc
));
5436 Expression
visitSArray(TypeSArray mt
)
5438 static if (LOGDEFAULTINIT
)
5440 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt
.toChars(), isCfile
);
5442 if (mt
.next
.ty
== Tvoid
)
5443 return mt
.tuns8
.defaultInit(loc
, isCfile
);
5445 return mt
.next
.defaultInit(loc
, isCfile
);
5448 Expression
visitFunction(TypeFunction mt
)
5450 error(loc
, "`function` does not have a default initializer");
5451 return ErrorExp
.get();
5454 Expression
visitStruct(TypeStruct mt
)
5456 static if (LOGDEFAULTINIT
)
5458 printf("TypeStruct::defaultInit() '%s'\n", mt
.toChars());
5460 Declaration d
= new SymbolDeclaration(mt
.sym
.loc
, mt
.sym
);
5463 d
.storage_class |
= STC
.rvalue
; // https://issues.dlang.org/show_bug.cgi?id=14398
5464 return new VarExp(mt
.sym
.loc
, d
);
5467 Expression
visitEnum(TypeEnum mt
)
5469 static if (LOGDEFAULTINIT
)
5471 printf("TypeEnum::defaultInit() '%s'\n", mt
.toChars());
5473 // Initialize to first member of enum
5474 Expression e
= mt
.sym
.getDefaultValue(loc
);
5477 e
.type
= mt
; // to deal with const, immutable, etc., variants
5481 Expression
visitTuple(TypeTuple mt
)
5483 static if (LOGDEFAULTINIT
)
5485 printf("TypeTuple::defaultInit() '%s'\n", mt
.toChars());
5487 auto exps
= new Expressions(mt
.arguments
.length
);
5488 for (size_t i
= 0; i
< mt
.arguments
.length
; i
++)
5490 Parameter p
= (*mt
.arguments
)[i
];
5492 Expression e
= p
.type
.defaultInitLiteral(loc
);
5493 if (e
.op
== EXP
.error
)
5499 return new TupleExp(loc
, exps
);
5502 Expression
visitNoreturn(TypeNoreturn mt
)
5504 static if (LOGDEFAULTINIT
)
5506 printf("TypeNoreturn::defaultInit() '%s'\n", mt
.toChars());
5508 auto cond
= IntegerExp
.createBool(false);
5509 auto msg
= new StringExp(loc
, "Accessed expression of type `noreturn`");
5510 msg
.type
= Type
.tstring
;
5511 auto ae
= new AssertExp(loc
, cond
, msg
);
5518 case Tvector
: return visitVector (mt
.isTypeVector());
5519 case Tsarray
: return visitSArray (mt
.isTypeSArray());
5520 case Tfunction
: return visitFunction(mt
.isTypeFunction());
5521 case Tstruct
: return visitStruct (mt
.isTypeStruct());
5522 case Tenum
: return visitEnum (mt
.isTypeEnum());
5523 case Ttuple
: return visitTuple (mt
.isTypeTuple());
5525 case Tnull
: return new NullExp(Loc
.initial
, Type
.tnull
);
5527 case Terror
: return ErrorExp
.get();
5534 case Tclass
: return new NullExp(loc
, mt
);
5535 case Tnoreturn
: return visitNoreturn(mt
.isTypeNoreturn());
5537 default: return mt
.isTypeBasic() ?
5538 visitBasic(cast(TypeBasic
)mt
) :
5544 If `type` resolves to a dsymbol, then that
5545 dsymbol is returned.
5548 type = the type that is checked
5549 sc = the scope where the type is used
5552 The dsymbol to which the type resolve or `null`
5553 if the type does resolve to any symbol (for example,
5554 in the case of basic types).
5556 Dsymbol
toDsymbol(Type type
, Scope
* sc
)
5558 Dsymbol
visitType(Type _
) { return null; }
5559 Dsymbol
visitStruct(TypeStruct type
) { return type
.sym
; }
5560 Dsymbol
visitEnum(TypeEnum type
) { return type
.sym
; }
5561 Dsymbol
visitClass(TypeClass type
) { return type
.sym
; }
5563 Dsymbol
visitTraits(TypeTraits type
)
5568 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5569 if (t
&& t
.ty
!= Terror
)
5570 s
= t
.toDsymbol(sc
);
5577 Dsymbol
visitMixin(TypeMixin type
)
5582 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5584 s
= t
.toDsymbol(sc
);
5591 Dsymbol
visitIdentifier(TypeIdentifier type
)
5593 //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
5600 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5601 if (t
&& t
.ty
!= Tident
)
5602 s
= t
.toDsymbol(sc
);
5609 Dsymbol
visitInstance(TypeInstance type
)
5614 //printf("TypeInstance::semantic(%s)\n", toChars());
5615 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5616 if (t
&& t
.ty
!= Tinstance
)
5617 s
= t
.toDsymbol(sc
);
5621 Dsymbol
visitTypeof(TypeTypeof type
)
5623 //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
5627 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5631 Dsymbol
visitReturn(TypeReturn type
)
5636 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5642 default: return visitType(type
);
5643 case Ttraits
: return visitTraits(type
.isTypeTraits());
5644 case Tmixin
: return visitMixin(type
.isTypeMixin());
5645 case Tident
: return visitIdentifier(type
.isTypeIdentifier());
5646 case Tinstance
: return visitInstance(type
.isTypeInstance());
5647 case Ttypeof
: return visitTypeof(type
.isTypeTypeof());
5648 case Treturn
: return visitReturn(type
.isTypeReturn());
5649 case Tstruct
: return visitStruct(type
.isTypeStruct());
5650 case Tenum
: return visitEnum(type
.isTypeEnum());
5651 case Tclass
: return visitClass(type
.isTypeClass());
5655 /************************************
5656 * Add storage class modifiers to type.
5658 Type
addStorageClass(Type type
, StorageClass
stc)
5660 Type
visitType(Type t
)
5662 /* Just translate to MOD bits and let addMod() do the work
5665 if (stc & STC
.immutable_
)
5666 mod
= MODFlags
.immutable_
;
5669 if (stc & (STC
.const_ | STC
.in_
))
5670 mod |
= MODFlags
.const_
;
5672 mod |
= MODFlags
.wild
;
5673 if (stc & STC
.shared_
)
5674 mod |
= MODFlags
.shared_
;
5676 return t
.addMod(mod
);
5679 Type
visitFunction(TypeFunction tf_src
)
5681 //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
5682 TypeFunction t
= visitType(tf_src
).toTypeFunction();
5683 if ((stc & STC
.pure_
&& !t
.purity
) ||
5684 (stc & STC
.nothrow_
&& !t
.isnothrow
) ||
5685 (stc & STC
.nogc
&& !t
.isnogc
) ||
5686 (stc & STC
.scope_
&& !t
.isScopeQual
) ||
5687 (stc & STC
.safe
&& t
.trust
< TRUST
.trusted
))
5689 // Klunky to change these
5690 auto tf
= new TypeFunction(t
.parameterList
, t
.next
, t
.linkage
, 0);
5692 tf
.inferenceArguments
= tf_src
.inferenceArguments
;
5693 tf
.purity
= t
.purity
;
5694 tf
.isnothrow
= t
.isnothrow
;
5695 tf
.isnogc
= t
.isnogc
;
5696 tf
.isproperty
= t
.isproperty
;
5698 tf
.isreturn
= t
.isreturn
;
5699 tf
.isreturnscope
= t
.isreturnscope
;
5700 tf
.isScopeQual
= t
.isScopeQual
;
5701 tf
.isreturninferred
= t
.isreturninferred
;
5702 tf
.isscopeinferred
= t
.isscopeinferred
;
5704 tf
.isInOutParam
= t
.isInOutParam
;
5705 tf
.isInOutQual
= t
.isInOutQual
;
5706 tf
.isctor
= t
.isctor
;
5708 if (stc & STC
.pure_
)
5709 tf
.purity
= PURE
.fwdref
;
5710 if (stc & STC
.nothrow_
)
5711 tf
.isnothrow
= true;
5715 tf
.trust
= TRUST
.safe
;
5716 if (stc & STC
.scope_
)
5718 tf
.isScopeQual
= true;
5719 if (stc & STC
.scopeinferred
)
5720 tf
.isscopeinferred
= true;
5723 tf
.deco
= tf
.merge().deco
;
5729 Type
visitDelegate(TypeDelegate tdg
)
5731 TypeDelegate t
= visitType(tdg
).isTypeDelegate();
5737 default: return visitType(type
);
5738 case Tfunction
: return visitFunction(type
.isTypeFunction());
5739 case Tdelegate
: return visitDelegate(type
.isTypeDelegate());
5743 /**********************************************
5744 * Extract complex type from core.stdc.config
5746 * loc = for error messages
5748 * ty = a complex or imaginary type
5750 * Complex!float, Complex!double, Complex!real or null for error
5753 Type
getComplexLibraryType(const ref Loc loc
, Scope
* sc
, TY ty
)
5756 __gshared Type complex_float
;
5757 __gshared Type complex_double
;
5758 __gshared Type complex_real
;
5765 case Tcomplex32
: id
= Id
.c_complex_float
; pt
= &complex_float
; break;
5767 case Tcomplex64
: id
= Id
.c_complex_double
; pt
= &complex_double
; break;
5769 case Tcomplex80
: id
= Id
.c_complex_real
; pt
= &complex_real
; break;
5778 Module mConfig
= Module
.loadCoreStdcConfig();
5781 error(loc
, "`core.stdc.config` is required for complex numbers");
5785 Dsymbol s
= mConfig
.searchX(Loc
.initial
, sc
, id
, SearchOpt
.ignorePrivateImports
);
5788 error(loc
, "`%s` not found in core.stdc.config", id
.toChars());
5792 if (auto t
= s
.getType())
5794 if (auto ts
= t
.toBasetype().isTypeStruct())
5800 if (auto sd
= s
.isStructDeclaration())
5806 error(loc
, "`%s` must be an alias for a complex struct", s
.toChars());
5810 /*******************************
5811 * Covariant means that 'src' can substitute for 't',
5812 * i.e. a pure function is a match for an impure type.
5815 * t = type 'src' is covariant with
5816 * pstc = if not null, store STCxxxx which would make it covariant
5817 * cppCovariant = true if extern(C++) function types should follow C++ covariant rules
5819 * An enum value of either `Covariant.yes` or a reason it's not covariant.
5821 Covariant
covariant(Type src
, Type t
, StorageClass
* pstc
= null, bool cppCovariant
= false)
5825 printf("Type::covariant(t = %s) %s\n", t
.toChars(), src
.toChars());
5826 printf("deco = %p, %p\n", src
.deco
, t
.deco
);
5827 // printf("ty = %d\n", next.ty);
5828 printf("mod = %x, %x\n", src
.mod
, t
.mod
);
5832 StorageClass
stc = 0;
5834 bool notcovariant
= false;
5837 return Covariant
.yes
;
5839 TypeFunction t1
= src
.isTypeFunction();
5840 TypeFunction t2
= t
.isTypeFunction();
5845 if (t1
.parameterList
.varargs
!= t2
.parameterList
.varargs
)
5848 if (t1
.parameterList
.parameters
&& t2
.parameterList
.parameters
)
5850 if (t1
.parameterList
.length
!= t2
.parameterList
.length
)
5853 foreach (i
, fparam1
; t1
.parameterList
)
5855 Parameter fparam2
= t2
.parameterList
[i
];
5856 Type tp1
= fparam1
.type
;
5857 Type tp2
= fparam2
.type
;
5859 if (!tp1
.equals(tp2
))
5861 if (tp1
.ty
== tp2
.ty
)
5863 if (auto tc1
= tp1
.isTypeClass())
5865 if (tc1
.sym
== (cast(TypeClass
)tp2
).sym
&& MODimplicitConv(tp2
.mod
, tp1
.mod
))
5868 else if (auto ts1
= tp1
.isTypeStruct())
5870 if (ts1
.sym
== (cast(TypeStruct
)tp2
).sym
&& MODimplicitConv(tp2
.mod
, tp1
.mod
))
5873 else if (tp1
.ty
== Tpointer
)
5875 if (tp2
.implicitConvTo(tp1
))
5878 else if (tp1
.ty
== Tarray
)
5880 if (tp2
.implicitConvTo(tp1
))
5883 else if (tp1
.ty
== Tdelegate
)
5885 if (tp2
.implicitConvTo(tp1
))
5892 notcovariant |
= !fparam1
.isCovariant(t1
.isref
, fparam2
);
5894 /* https://issues.dlang.org/show_bug.cgi?id=23135
5895 * extern(C++) mutable parameters are not covariant with const.
5897 if (t1
.linkage
== LINK
.cpp
&& cppCovariant
)
5899 notcovariant |
= tp1
.isNaked() != tp2
.isNaked();
5900 if (auto tpn1
= tp1
.nextOf())
5901 notcovariant |
= tpn1
.isNaked() != tp2
.nextOf().isNaked();
5905 else if (t1
.parameterList
.parameters
!= t2
.parameterList
.parameters
)
5907 if (t1
.parameterList
.length || t2
.parameterList
.length
)
5911 // The argument lists match
5914 if (t1
.linkage
!= t2
.linkage
)
5922 if (!t1n ||
!t2n
) // happens with return type inference
5925 if (t1n
.equals(t2n
))
5927 if (t1n
.ty
== Tclass
&& t2n
.ty
== Tclass
)
5929 /* If same class type, but t2n is const, then it's
5930 * covariant. Do this test first because it can work on
5931 * forward references.
5933 if ((cast(TypeClass
)t1n
).sym
== (cast(TypeClass
)t2n
).sym
&& MODimplicitConv(t1n
.mod
, t2n
.mod
))
5936 // If t1n is forward referenced:
5937 ClassDeclaration cd
= (cast(TypeClass
)t1n
).sym
;
5938 if (cd
.semanticRun
< PASS
.semanticdone
&& !cd
.isBaseInfoComplete())
5939 cd
.dsymbolSemantic(null);
5940 if (!cd
.isBaseInfoComplete())
5942 return Covariant
.fwdref
;
5945 if (t1n
.ty
== Tstruct
&& t2n
.ty
== Tstruct
)
5947 if ((cast(TypeStruct
)t1n
).sym
== (cast(TypeStruct
)t2n
).sym
&& MODimplicitConv(t1n
.mod
, t2n
.mod
))
5950 else if (t1n
.ty
== t2n
.ty
&& t1n
.implicitConvTo(t2n
))
5952 if (t1
.isref
&& t2
.isref
)
5954 // Treat like pointers to t1n and t2n
5955 if (t1n
.constConv(t2n
) < MATCH
.constant
)
5960 else if (t1n
.ty
== Tnull
)
5962 // NULL is covariant with any pointer type, but not with any
5963 // dynamic arrays, associative arrays or delegates.
5964 // https://issues.dlang.org/show_bug.cgi?id=8589
5965 // https://issues.dlang.org/show_bug.cgi?id=19618
5966 Type t2bn
= t2n
.toBasetype();
5967 if (t2bn
.ty
== Tnull || t2bn
.ty
== Tpointer || t2bn
.ty
== Tclass
)
5970 // bottom type is covariant to any type
5971 else if (t1n
.ty
== Tnoreturn
)
5977 if (t1
.isref
!= t2
.isref
)
5980 if (!t1
.isref
&& (t1
.isScopeQual || t2
.isScopeQual
))
5982 StorageClass stc1
= t1
.isScopeQual ? STC
.scope_
: 0;
5983 StorageClass stc2
= t2
.isScopeQual ? STC
.scope_
: 0;
5986 stc1 |
= STC
.return_
;
5987 if (!t1
.isScopeQual
)
5992 stc2 |
= STC
.return_
;
5993 if (!t2
.isScopeQual
)
5996 if (!Parameter
.isCovariantScope(t1
.isref
, stc1
, stc2
))
6000 // We can subtract 'return ref' from 'this', but cannot add it
6001 else if (t1
.isreturn
&& !t2
.isreturn
)
6004 /* https://issues.dlang.org/show_bug.cgi?id=23135
6005 * extern(C++) mutable member functions are not covariant with const.
6007 if (t1
.linkage
== LINK
.cpp
&& cppCovariant
&& t1
.isNaked() != t2
.isNaked())
6010 /* Can convert mutable to const
6012 if (!MODimplicitConv(t2
.mod
, t1
.mod
))
6016 //stop attribute inference with const
6017 // If adding 'const' will make it covariant
6018 if (MODimplicitConv(t2
.mod
, MODmerge(t1
.mod
, MODFlags
.const_
)))
6029 /* Can convert pure to impure, nothrow to throw, and nogc to gc
6031 if (!t1
.purity
&& t2
.purity
)
6034 if (!t1
.isnothrow
&& t2
.isnothrow
)
6035 stc |
= STC
.nothrow_
;
6037 if (!t1
.isnogc
&& t2
.isnogc
)
6040 /* Can convert safe/trusted to system
6042 if (t1
.trust
<= TRUST
.system
&& t2
.trust
>= TRUST
.trusted
)
6044 // Should we infer trusted or safe? Go with safe.
6055 //printf("\tcovaraint: 1\n");
6056 return Covariant
.yes
;
6059 //printf("\tcovaraint: 0\n");
6060 return Covariant
.distinct
;
6063 //printf("\tcovaraint: 2\n");
6064 return Covariant
.no
;
6067 /************************************
6068 * Take the specified storage class for p,
6069 * and use the function signature to infer whether
6070 * STC.scope_ and STC.return_ should be OR'd in.
6071 * (This will not affect the name mangling.)
6073 * tf = TypeFunction to use to get the signature from
6074 * tthis = type of `this` parameter, null if none
6075 * p = parameter to this function
6076 * outerVars = context variables p could escape into, if any
6077 * indirect = is this for an indirect or virtual function call?
6079 * storage class with STC.scope_ or STC.return_ OR'd in
6081 StorageClass
parameterStorageClass(TypeFunction tf
, Type tthis
, Parameter p
, VarDeclarations
* outerVars
= null,
6082 bool indirect
= false)
6084 //printf("parameterStorageClass(p: %s)\n", p.toChars());
6085 auto stc = p
.storageClass
;
6087 // When the preview switch is enable, `in` parameters are `scope`
6088 if (stc & STC
.constscoperef
)
6089 return stc | STC
.scope_
;
6091 if (stc & (STC
.scope_ | STC
.return_ | STC
.lazy_
) || tf
.purity
== PURE
.impure
)
6094 /* If haven't inferred the return type yet, can't infer storage classes
6096 if (!tf
.nextOf() ||
!tf
.isnothrow())
6101 static bool mayHavePointers(Type t
)
6103 if (auto ts
= t
.isTypeStruct())
6106 if (sym
.members
&& !sym
.determineFields() && sym
.type
!= Type
.terror
)
6107 // struct is forward referenced, so "may have" pointers
6110 return t
.hasPointers();
6113 // See if p can escape via any of the other parameters
6114 if (tf
.purity
== PURE
.weak
)
6117 * Indirect calls may escape p through a nested context
6119 * https://issues.dlang.org/show_bug.cgi?id=24212
6120 * https://issues.dlang.org/show_bug.cgi?id=24213
6125 // Check escaping through parameters
6126 foreach (i
, fparam
; tf
.parameterList
)
6128 Type t
= fparam
.type
;
6131 t
= t
.baseElemOf(); // punch thru static arrays
6132 if (t
.isMutable() && t
.hasPointers())
6134 if (fparam
.isReference() && fparam
!= p
)
6137 if (t
.ty
== Tdelegate
)
6138 return stc; // could escape thru delegate
6143 /* if t is a pointer to mutable pointer
6145 if (auto tn
= t
.nextOf())
6147 if (tn
.isMutable() && mayHavePointers(tn
))
6148 return stc; // escape through pointers
6153 // Check escaping through `this`
6154 if (tthis
&& tthis
.isMutable())
6156 foreach (VarDeclaration v
; isAggregate(tthis
).fields
)
6158 if (v
.hasPointers())
6163 // Check escaping through nested context
6164 if (outerVars
&& tf
.isMutable())
6166 foreach (VarDeclaration v
; *outerVars
)
6168 if (v
.hasPointers())
6174 // Check escaping through return value
6175 Type tret
= tf
.nextOf().toBasetype();
6176 if (tf
.isref || tret
.hasPointers())
6178 return stc | STC
.scope_ | STC
.return_ | STC
.returnScope
;
6181 return stc | STC
.scope_
;
6184 bool isBaseOf(Type tthis
, Type t
, int* poffset
)
6186 auto tc
= tthis
.isTypeClass();
6190 if (!t || t
.ty
!= Tclass
)
6193 ClassDeclaration cd
= t
.isTypeClass().sym
;
6194 if (cd
.semanticRun
< PASS
.semanticdone
&& !cd
.isBaseInfoComplete())
6195 cd
.dsymbolSemantic(null);
6196 if (tc
.sym
.semanticRun
< PASS
.semanticdone
&& !tc
.sym
.isBaseInfoComplete())
6197 tc
.sym
.dsymbolSemantic(null);
6199 if (tc
.sym
.isBaseOf(cd
, poffset
))
6205 bool equivalent(Type src
, Type t
)
6207 return immutableOf(src
).equals(t
.immutableOf());
6210 Type
pointerTo(Type type
)
6212 if (type
.ty
== Terror
)
6216 Type t
= new TypePointer(type
);
6217 if (type
.ty
== Tfunction
)
6219 t
.deco
= t
.merge().deco
;
6223 type
.pto
= t
.merge();
6228 Type
referenceTo(Type type
)
6230 if (type
.ty
== Terror
)
6234 Type t
= new TypeReference(type
);
6235 type
.rto
= t
.merge();
6240 // Make corresponding static array type without semantic
6241 Type
sarrayOf(Type type
, dinteger_t dim
)
6244 Type t
= new TypeSArray(type
, new IntegerExp(Loc
.initial
, dim
, Type
.tsize_t
));
6245 // according to TypeSArray.semantic()
6246 t
= t
.addMod(type
.mod
);
6251 Type
arrayOf(Type type
)
6253 if (type
.ty
== Terror
)
6257 Type t
= new TypeDArray(type
);
6258 type
.arrayof
= t
.merge();
6260 return type
.arrayof
;
6263 /********************************
6264 * Convert to 'const'.
6266 Type
constOf(Type type
)
6268 //printf("Type::constOf() %p %s\n", type, type.toChars());
6269 if (type
.mod
== MODFlags
.const_
)
6271 if (type
.mcache
&& type
.mcache
.cto
)
6273 assert(type
.mcache
.cto
.mod
== MODFlags
.const_
);
6274 return type
.mcache
.cto
;
6276 Type t
= type
.makeConst();
6279 //printf("-Type::constOf() %p %s\n", t, t.toChars());
6283 /********************************
6284 * Convert to 'immutable'.
6286 Type
immutableOf(Type type
)
6288 //printf("Type::immutableOf() %p %s\n", this, toChars());
6289 if (type
.isImmutable())
6291 if (type
.mcache
&& type
.mcache
.ito
)
6293 assert(type
.mcache
.ito
.isImmutable());
6294 return type
.mcache
.ito
;
6296 Type t
= type
.makeImmutable();
6299 //printf("\t%p\n", t);
6303 /********************************
6304 * Make type mutable.
6306 Type
mutableOf(Type type
)
6308 //printf("Type::mutableOf() %p, %s\n", type, type.toChars());
6310 if (type
.isImmutable())
6313 t
= type
.mcache
.ito
; // immutable => naked
6314 assert(!t ||
(t
.isMutable() && !t
.isShared()));
6316 else if (type
.isConst())
6319 if (type
.isShared())
6322 t
= type
.mcache
.swcto
; // shared wild const -> shared
6324 t
= type
.mcache
.sto
; // shared const => shared
6329 t
= type
.mcache
.wcto
; // wild const -> naked
6331 t
= type
.mcache
.cto
; // const => naked
6333 assert(!t || t
.isMutable());
6335 else if (type
.isWild())
6338 if (type
.isShared())
6339 t
= type
.mcache
.sto
; // shared wild => shared
6341 t
= type
.mcache
.wto
; // wild => naked
6342 assert(!t || t
.isMutable());
6346 t
= type
.makeMutable();
6352 assert(t
.isMutable());
6356 Type
sharedOf(Type type
)
6358 //printf("Type::sharedOf() %p, %s\n", type, type.toChars());
6359 if (type
.mod
== MODFlags
.shared_
)
6361 if (type
.mcache
&& type
.mcache
.sto
)
6363 assert(type
.mcache
.sto
.mod
== MODFlags
.shared_
);
6364 return type
.mcache
.sto
;
6366 Type t
= type
.makeShared();
6369 //printf("\t%p\n", t);
6373 Type
sharedConstOf(Type type
)
6375 //printf("Type::sharedConstOf() %p, %s\n", type, type.toChars());
6376 if (type
.mod
== (MODFlags
.shared_ | MODFlags
.const_
))
6378 if (type
.mcache
&& type
.mcache
.scto
)
6380 assert(type
.mcache
.scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
6381 return type
.mcache
.scto
;
6383 Type t
= type
.makeSharedConst();
6386 //printf("\t%p\n", t);
6390 /********************************
6391 * Make type unshared.
6394 * immutable => immutable
6396 * shared const => const
6398 * wild const => wild const
6399 * shared wild => wild
6400 * shared wild const => wild const
6402 Type
unSharedOf(Type type
)
6404 //printf("Type::unSharedOf() %p, %s\n", type, type.toChars());
6407 if (type
.isShared())
6413 t
= type
.mcache
.wcto
; // shared wild const => wild const
6415 t
= type
.mcache
.wto
; // shared wild => wild
6420 t
= type
.mcache
.cto
; // shared const => const
6422 t
= type
.mcache
.sto
; // shared => naked
6424 assert(!t ||
!t
.isShared());
6429 t
= type
.nullAttributes();
6430 t
.mod
= type
.mod
& ~MODFlags
.shared_
;
6431 t
.ctype
= type
.ctype
;
6437 assert(!t
.isShared());
6441 /********************************
6442 * Convert to 'wild'.
6444 Type
wildOf(Type type
)
6446 //printf("Type::wildOf() %p %s\n", type, type.toChars());
6447 if (type
.mod
== MODFlags
.wild
)
6449 if (type
.mcache
&& type
.mcache
.wto
)
6451 assert(type
.mcache
.wto
.mod
== MODFlags
.wild
);
6452 return type
.mcache
.wto
;
6454 Type t
= type
.makeWild();
6457 //printf("\t%p %s\n", t, t.toChars());
6461 Type
wildConstOf(Type type
)
6463 //printf("Type::wildConstOf() %p %s\n", type, type.toChars());
6464 if (type
.mod
== MODFlags
.wildconst
)
6466 if (type
.mcache
&& type
.mcache
.wcto
)
6468 assert(type
.mcache
.wcto
.mod
== MODFlags
.wildconst
);
6469 return type
.mcache
.wcto
;
6471 Type t
= type
.makeWildConst();
6474 //printf("\t%p %s\n", t, t.toChars());
6478 Type
sharedWildOf(Type type
)
6480 //printf("Type::sharedWildOf() %p, %s\n", type, type.toChars());
6481 if (type
.mod
== (MODFlags
.shared_ | MODFlags
.wild
))
6483 if (type
.mcache
&& type
.mcache
.swto
)
6485 assert(type
.mcache
.swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
6486 return type
.mcache
.swto
;
6488 Type t
= type
.makeSharedWild();
6491 //printf("\t%p %s\n", t, t.toChars());
6495 Type
sharedWildConstOf(Type type
)
6497 //printf("Type::sharedWildConstOf() %p, %s\n", type, type.toChars());
6498 if (type
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
))
6500 if (type
.mcache
&& type
.mcache
.swcto
)
6502 assert(type
.mcache
.swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
6503 return type
.mcache
.swcto
;
6505 Type t
= type
.makeSharedWildConst();
6508 //printf("\t%p %s\n", t, t.toChars());
6512 Type
unqualify(Type type
, uint m
)
6514 Type t
= type
.mutableOf().unSharedOf();
6516 Type tn
= type
.ty
== Tenum ?
null : type
.nextOf();
6517 if (tn
&& tn
.ty
!= Tfunction
)
6519 Type utn
= tn
.unqualify(m
);
6522 if (type
.ty
== Tpointer
)
6523 t
= utn
.pointerTo();
6524 else if (type
.ty
== Tarray
)
6526 else if (type
.ty
== Tsarray
)
6527 t
= new TypeSArray(utn
, (cast(TypeSArray
)type
).dim
);
6528 else if (type
.ty
== Taarray
)
6530 t
= new TypeAArray(utn
, (cast(TypeAArray
)type
).index
);
6538 t
= t
.addMod(type
.mod
& ~m
);
6542 /**************************
6543 * Return type with the top level of it being mutable.
6546 * t = type for which the top level mutable version is being returned
6549 * type version with mutable top level
6551 Type
toHeadMutable(const Type t
)
6553 Type unqualType
= cast(Type
) t
;
6554 if (t
.isTypeStruct() || t
.isTypeClass())
6559 return unqualType
.mutableOf();
6562 Type
aliasthisOf(Type type
)
6564 auto ad
= isAggregate(type
);
6565 if (!ad ||
!ad
.aliasthis
)
6568 auto s
= ad
.aliasthis
.sym
;
6569 if (s
.isAliasDeclaration())
6572 if (s
.isTupleDeclaration())
6575 if (auto vd
= s
.isVarDeclaration())
6579 t
= t
.addMod(type
.mod
);
6582 Dsymbol callable
= s
.isFuncDeclaration();
6583 callable
= callable ? callable
: s
.isTemplateDeclaration();
6586 auto fd
= resolveFuncCall(Loc
.initial
, null, callable
, null, type
, ArgumentList(), FuncResolveFlag
.quiet
);
6587 if (!fd || fd
.errors ||
!functionSemantic(fd
))
6590 auto t
= fd
.type
.nextOf();
6591 if (!t
) // https://issues.dlang.org/show_bug.cgi?id=14185
6593 t
= t
.substWildTo(type
.mod
== 0 ? MODFlags
.mutable
: type
.mod
);
6596 if (auto d
= s
.isDeclaration())
6601 if (auto ed
= s
.isEnumDeclaration())
6606 //printf("%s\n", s.kind());
6610 /************************************
6611 * Apply MODxxxx bits to existing type.
6613 Type
castMod(Type type
, MOD mod
)
6619 t
= type
.unSharedOf().mutableOf();
6622 case MODFlags
.const_
:
6623 t
= type
.unSharedOf().constOf();
6627 t
= type
.unSharedOf().wildOf();
6630 case MODFlags
.wildconst
:
6631 t
= type
.unSharedOf().wildConstOf();
6634 case MODFlags
.shared_
:
6635 t
= type
.mutableOf().sharedOf();
6638 case MODFlags
.shared_ | MODFlags
.const_
:
6639 t
= type
.sharedConstOf();
6642 case MODFlags
.shared_ | MODFlags
.wild
:
6643 t
= type
.sharedWildOf();
6646 case MODFlags
.shared_ | MODFlags
.wildconst
:
6647 t
= type
.sharedWildConstOf();
6650 case MODFlags
.immutable_
:
6651 t
= type
.immutableOf();
6660 Type
substWildTo(Type type
, uint mod
)
6662 auto tf
= type
.isTypeFunction();
6665 //printf("+Type.substWildTo this = %s, mod = x%x\n", toChars(), mod);
6668 if (Type tn
= type
.nextOf())
6670 // substitution has no effect on function pointer type.
6671 if (type
.ty
== Tpointer
&& tn
.ty
== Tfunction
)
6677 t
= tn
.substWildTo(mod
);
6682 if (type
.ty
== Tpointer
)
6684 else if (type
.ty
== Tarray
)
6686 else if (type
.ty
== Tsarray
)
6687 t
= new TypeSArray(t
, (cast(TypeSArray
)type
).dim
.syntaxCopy());
6688 else if (type
.ty
== Taarray
)
6690 t
= new TypeAArray(t
, (cast(TypeAArray
)type
).index
.syntaxCopy());
6692 else if (type
.ty
== Tdelegate
)
6694 t
= new TypeDelegate(t
.isTypeFunction());
6708 if (mod
== MODFlags
.immutable_
)
6710 t
= t
.immutableOf();
6712 else if (mod
== MODFlags
.wildconst
)
6714 t
= t
.wildConstOf();
6716 else if (mod
== MODFlags
.wild
)
6718 if (type
.isWildConst())
6719 t
= t
.wildConstOf();
6723 else if (mod
== MODFlags
.const_
)
6729 if (type
.isWildConst())
6736 t
= t
.addMod(MODFlags
.const_
);
6737 if (type
.isShared())
6738 t
= t
.addMod(MODFlags
.shared_
);
6740 //printf("-Type.substWildTo t = %s\n", t.toChars());
6744 if (!tf
.iswild
&& !(tf
.mod
& MODFlags
.wild
))
6747 // Substitude inout qualifier of function type to mutable or immutable
6748 // would break type system. Instead substitude inout to the most weak
6749 // qualifer - const.
6750 uint m
= MODFlags
.const_
;
6753 Type tret
= tf
.next
.substWildTo(m
);
6754 Parameters
* params
= tf
.parameterList
.parameters
;
6755 if (tf
.mod
& MODFlags
.wild
)
6756 params
= tf
.parameterList
.parameters
.copy();
6757 for (size_t i
= 0; i
< params
.length
; i
++)
6759 Parameter p
= (*params
)[i
];
6760 Type t
= p
.type
.substWildTo(m
);
6763 if (params
== tf
.parameterList
.parameters
)
6764 params
= tf
.parameterList
.parameters
.copy();
6765 (*params
)[i
] = new Parameter(p
.loc
, p
.storageClass
, t
, null, null, null);
6767 if (tf
.next
== tret
&& params
== tf
.parameterList
.parameters
)
6770 // Similar to TypeFunction.syntaxCopy;
6771 auto t
= new TypeFunction(ParameterList(params
, tf
.parameterList
.varargs
), tret
, tf
.linkage
);
6772 t
.mod
= ((tf
.mod
& MODFlags
.wild
) ?
(tf
.mod
& ~MODFlags
.wild
) | MODFlags
.const_
: tf
.mod
);
6773 t
.isnothrow
= tf
.isnothrow
;
6774 t
.isnogc
= tf
.isnogc
;
6775 t
.purity
= tf
.purity
;
6776 t
.isproperty
= tf
.isproperty
;
6778 t
.isreturn
= tf
.isreturn
;
6779 t
.isreturnscope
= tf
.isreturnscope
;
6780 t
.isScopeQual
= tf
.isScopeQual
;
6781 t
.isreturninferred
= tf
.isreturninferred
;
6782 t
.isscopeinferred
= tf
.isscopeinferred
;
6783 t
.isInOutParam
= false;
6784 t
.isInOutQual
= false;
6786 t
.inferenceArguments
= tf
.inferenceArguments
;
6787 t
.isctor
= tf
.isctor
;
6791 /************************************
6792 * Add MODxxxx bits to existing type.
6793 * We're adding, not replacing, so adding const to
6794 * a shared type => "shared const"
6796 Type
addMod(Type type
, MOD mod
)
6798 /* Add anything to immutable, and it remains immutable
6801 if (!t
.isImmutable())
6803 //printf("addMod(%x) %s\n", mod, toChars());
6809 case MODFlags
.const_
:
6810 if (type
.isShared())
6813 t
= type
.sharedWildConstOf();
6815 t
= type
.sharedConstOf();
6820 t
= type
.wildConstOf();
6827 if (type
.isShared())
6830 t
= type
.sharedWildConstOf();
6832 t
= type
.sharedWildOf();
6837 t
= type
.wildConstOf();
6843 case MODFlags
.wildconst
:
6844 if (type
.isShared())
6845 t
= type
.sharedWildConstOf();
6847 t
= type
.wildConstOf();
6850 case MODFlags
.shared_
:
6854 t
= type
.sharedWildConstOf();
6856 t
= type
.sharedWildOf();
6861 t
= type
.sharedConstOf();
6863 t
= type
.sharedOf();
6867 case MODFlags
.shared_ | MODFlags
.const_
:
6869 t
= type
.sharedWildConstOf();
6871 t
= type
.sharedConstOf();
6874 case MODFlags
.shared_ | MODFlags
.wild
:
6876 t
= type
.sharedWildConstOf();
6878 t
= type
.sharedWildOf();
6881 case MODFlags
.shared_ | MODFlags
.wildconst
:
6882 t
= type
.sharedWildConstOf();
6885 case MODFlags
.immutable_
:
6886 t
= type
.immutableOf();
6897 * Check whether this type has endless `alias this` recursion.
6900 * t = type to check whether it has a recursive alias this
6902 * `true` if `t` has an `alias this` that can be implicitly
6903 * converted back to `t` itself.
6905 private bool checkAliasThisRec(Type t
)
6907 Type tb
= t
.toBasetype();
6908 AliasThisRec
* pflag
;
6909 if (tb
.ty
== Tstruct
)
6910 pflag
= &(cast(TypeStruct
)tb
).att
;
6911 else if (tb
.ty
== Tclass
)
6912 pflag
= &(cast(TypeClass
)tb
).att
;
6916 AliasThisRec flag
= cast(AliasThisRec
)(*pflag
& AliasThisRec
.typeMask
);
6917 if (flag
== AliasThisRec
.fwdref
)
6919 Type att
= aliasthisOf(t
);
6920 flag
= att
&& att
.implicitConvTo(t
) ? AliasThisRec
.yes
: AliasThisRec
.no
;
6922 *pflag
= cast(AliasThisRec
)(flag |
(*pflag
& ~AliasThisRec
.typeMask
));
6923 return flag
== AliasThisRec
.yes
;
6926 /**************************************
6927 * Check and set 'att' if 't' is a recursive 'alias this' type
6929 * The goal is to prevent endless loops when there is a cycle in the alias this chain.
6930 * Since there is no multiple `alias this`, the chain either ends in a leaf,
6931 * or it loops back on itself as some point.
6933 * Example: S0 -> (S1 -> S2 -> S3 -> S1)
6935 * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
6936 * `S1` is a recursive alias this type, but since `att` is initialized to `null`,
6937 * this still returns `false`, but `att1` is set to `S1`.
6938 * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
6939 * we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
6942 * att = type reference used to detect recursion. Should be initialized to `null`.
6943 * t = type of 'alias this' rewrite to attempt
6946 * `false` if the rewrite is safe, `true` if it would loop back around
6948 bool isRecursiveAliasThis(ref Type att
, Type t
)
6950 //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
6951 auto tb
= t
.toBasetype();
6952 if (att
&& tb
.equivalent(att
))
6954 else if (!att
&& tb
.checkAliasThisRec())
6959 /******************************* Private *****************************************/
6963 /* Helper function for `typeToExpression`. Contains common code
6964 * for TypeQualified derived classes.
6966 Expression
typeToExpressionHelper(TypeQualified t
, Expression e
, size_t i
= 0)
6968 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
6969 foreach (id
; t
.idents
[i
.. t
.idents
.length
])
6971 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
6973 final switch (id
.dyncast())
6976 case DYNCAST
.identifier
:
6977 e
= new DotIdExp(e
.loc
, e
, cast(Identifier
)id
);
6980 // ... '. name!(tiargs)'
6981 case DYNCAST
.dsymbol
:
6982 auto ti
= (cast(Dsymbol
)id
).isTemplateInstance();
6984 e
= new DotTemplateInstanceExp(e
.loc
, e
, ti
.name
, ti
.tiargs
);
6988 case DYNCAST
.type
: // https://issues.dlang.org/show_bug.cgi?id=1215
6989 e
= new ArrayExp(t
.loc
, e
, new TypeExp(t
.loc
, cast(Type
)id
));
6993 case DYNCAST
.expression
: // https://issues.dlang.org/show_bug.cgi?id=1215
6994 e
= new ArrayExp(t
.loc
, e
, cast(Expression
)id
);
6997 case DYNCAST
.object
:
6999 case DYNCAST
.parameter
:
7000 case DYNCAST
.statement
:
7001 case DYNCAST
.condition
:
7002 case DYNCAST
.templateparameter
:
7003 case DYNCAST
.initializer
:
7010 /**************************
7011 * This evaluates exp while setting length to be the number
7012 * of elements in the tuple t.
7014 Expression
semanticLength(Scope
* sc
, Type t
, Expression exp
)
7016 if (auto tt
= t
.isTypeTuple())
7018 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, tt
);
7019 sym
.parent
= sc
.scopesym
;
7021 sc
= sc
.startCTFE();
7022 exp
= exp
.expressionSemantic(sc
);
7023 exp
= resolveProperties(sc
, exp
);
7029 sc
= sc
.startCTFE();
7030 exp
= exp
.expressionSemantic(sc
);
7031 exp
= resolveProperties(sc
, exp
);
7037 Expression
semanticLength(Scope
* sc
, TupleDeclaration tup
, Expression exp
)
7039 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, tup
);
7040 sym
.parent
= sc
.scopesym
;
7043 sc
= sc
.startCTFE();
7044 exp
= exp
.expressionSemantic(sc
);
7045 exp
= resolveProperties(sc
, exp
);
7052 /************************************
7053 * Transitively search a type for all function types.
7054 * If any function types with parameters are found that have parameter identifiers
7055 * or default arguments, remove those and create a new type stripped of those.
7056 * This is used to determine the "canonical" version of a type which is useful for
7061 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
7062 * the same as t but with no parameter identifiers or default arguments.
7064 Type
stripDefaultArgs(Type t
)
7066 static Parameters
* stripParams(Parameters
* parameters
)
7068 static Parameter
stripParameter(Parameter p
)
7070 Type t
= stripDefaultArgs(p
.type
);
7071 return (t
!= p
.type || p
.defaultArg || p
.ident || p
.userAttribDecl
)
7072 ?
new Parameter(p
.loc
, p
.storageClass
, t
, null, null, null)
7078 foreach (i
, p
; *parameters
)
7080 Parameter ps
= stripParameter(p
);
7083 // Replace params with a copy we can modify
7084 Parameters
* nparams
= new Parameters(parameters
.length
);
7086 foreach (j
, ref np
; *nparams
)
7088 Parameter pj
= (*parameters
)[j
];
7095 Parameter nps
= stripParameter(pj
);
7096 np
= nps ? nps
: pj
;
7109 if (auto tf
= t
.isTypeFunction())
7111 Type tret
= stripDefaultArgs(tf
.next
);
7112 Parameters
* params
= stripParams(tf
.parameterList
.parameters
);
7113 if (tret
== tf
.next
&& params
== tf
.parameterList
.parameters
)
7115 TypeFunction tr
= tf
.copy().isTypeFunction();
7116 tr
.parameterList
.parameters
= params
;
7118 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
7121 else if (auto tt
= t
.isTypeTuple())
7123 Parameters
* args
= stripParams(tt
.arguments
);
7124 if (args
== tt
.arguments
)
7126 TypeTuple tr
= t
.copy().isTypeTuple();
7127 tr
.arguments
= args
;
7130 else if (t
.ty
== Tenum
)
7132 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
7137 Type tn
= t
.nextOf();
7138 Type n
= stripDefaultArgs(tn
);
7141 TypeNext tr
= cast(TypeNext
)t
.copy();
7147 /******************************
7148 * Get the value of the .max/.min property of `ed` as an Expression.
7149 * Lazily computes the value and caches it in maxval/minval.
7150 * Reports any errors.
7152 * ed = the EnumDeclaration being examined
7153 * loc = location to use for error messages
7154 * id = Id::max or Id::min
7156 * corresponding value of .max/.min
7158 Expression
getMaxMinValue(EnumDeclaration ed
, const ref Loc loc
, Identifier id
)
7160 //printf("EnumDeclaration::getMaxValue()\n");
7162 static Expression
pvalToResult(Expression e
, const ref Loc loc
)
7164 if (e
.op
!= EXP
.error
)
7172 Expression
* pval
= (id
== Id
.max
) ?
&ed
.maxval
: &ed
.minval
;
7174 Expression
errorReturn()
7176 *pval
= ErrorExp
.get();
7182 .error(loc
, "%s `%s` recursive definition of `.%s` property", ed
.kind
, ed
.toPrettyChars
, id
.toChars());
7183 return errorReturn();
7186 return pvalToResult(*pval
, loc
);
7189 dsymbolSemantic(ed
, ed
._scope
);
7191 return errorReturn();
7194 .error(loc
, "%s `%s` is opaque and has no `.%s`", ed
.kind
, ed
.toPrettyChars
, id
.toChars(), id
.toChars());
7195 return errorReturn();
7197 if (!(ed
.memtype
&& ed
.memtype
.isintegral()))
7199 .error(loc
, "%s `%s` has no `.%s` property because base type `%s` is not an integral type", ed
.kind
, ed
.toPrettyChars
, id
.toChars(),
7200 id
.toChars(), ed
.memtype ? ed
.memtype
.toChars() : "");
7201 return errorReturn();
7205 for (size_t i
= 0; i
< ed
.members
.length
; i
++)
7207 EnumMember em
= (*ed
.members
)[i
].isEnumMember();
7216 if (em
.semanticRun
< PASS
.semanticdone
)
7218 .error(em
.loc
, "%s `%s` is forward referenced looking for `.%s`", em
.kind
, em
.toPrettyChars
, id
.toChars());
7230 /* In order to work successfully with UDTs,
7231 * build expressions to do the comparisons,
7232 * and let the semantic analyzer and constant
7233 * folder give us the result.
7240 Expression e
= em
.value
;
7241 Expression ec
= new CmpExp(id
== Id
.max ? EXP
.greaterThan
: EXP
.lessThan
, em
.loc
, e
, *pval
);
7243 ec
= ec
.expressionSemantic(em
._scope
);
7245 ec
= ec
.ctfeInterpret();
7246 if (ec
.op
== EXP
.error
)
7255 return ed
.errors ?
errorReturn() : pvalToResult(*pval
, loc
);
7258 /******************************************
7259 * Compile the MixinType, returning the type or expression AST.
7261 * Doesn't run semantic() on the returned object.
7263 * tm = mixin to compile as a type or expression
7264 * loc = location for error messages
7267 * null if error, else RootObject AST as parsed
7269 RootObject
compileTypeMixin(TypeMixin tm
, ref const Loc loc
, Scope
* sc
)
7272 if (expressionsToString(buf
, sc
, tm
.exps
))
7275 const errors
= global
.errors
;
7276 const len
= buf
.length
;
7278 const str = buf
.extractSlice()[0 .. len
];
7279 const bool doUnittests
= global
.params
.parsingUnittestsRequired();
7280 auto locm
= adjustLocForMixin(str, loc
, global
.params
.mixinOut
);
7281 scope p
= new Parser
!ASTCodegen(locm
, sc
._module
, str, false, global
.errorSink
, &global
.compileEnv
, doUnittests
);
7282 p
.transitionIn
= global
.params
.v
.vin
;
7284 //printf("p.loc.linnum = %d\n", p.loc.linnum);
7286 auto o
= p
.parseTypeOrAssignExp(TOK
.endOfFile
);
7287 if (errors
!= global
.errors
)
7289 assert(global
.errors
!= errors
); // should have caught all these cases
7292 if (p
.token
.value
!= TOK
.endOfFile
)
7294 .error(loc
, "unexpected token `%s` after type `%s`",
7295 p
.token
.toChars(), o
.toChars());
7296 .errorSupplemental(loc
, "while parsing string mixin type `%s`",