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
;
47 import dmd
.identifier
;
59 import dmd
.root
.complex
;
60 import dmd
.root
.ctfloat
;
62 import dmd
.common
.outbuffer
;
63 import dmd
.rootobject
;
64 import dmd
.root
.string
;
65 import dmd
.root
.stringtable
;
68 import dmd
.sideeffect
;
72 /*************************************
73 * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
74 * Setting one of pe/pt/ps.
76 * loc = location for error messages
78 * s = symbol being indexed - could be a tuple, could be an expression
79 * pe = set if s[oindex] is an Expression, otherwise null
80 * pt = set if s[oindex] is a Type, otherwise null
81 * ps = set if s[oindex] is a Dsymbol, otherwise null
82 * oindex = index into s
84 private void resolveTupleIndex(const ref Loc loc
, Scope
* sc
, Dsymbol s
, out Expression pe
, out Type pt
, out Dsymbol ps
, RootObject oindex
)
86 auto tup
= s
.isTupleDeclaration();
88 auto eindex
= isExpression(oindex
);
89 auto tindex
= isType(oindex
);
90 auto sindex
= isDsymbol(oindex
);
94 // It's really an index expression
96 eindex
= new TypeExp(loc
, tindex
);
98 eindex
= symbolToExp(sindex
, loc
, sc
, false);
99 Expression e
= new IndexExp(loc
, symbolToExp(s
, loc
, sc
, false), eindex
);
100 e
= e
.expressionSemantic(sc
);
101 resolveExp(e
, pt
, pe
, ps
);
105 // Convert oindex to Expression, then try to resolve to constant.
107 tindex
.resolve(loc
, sc
, eindex
, tindex
, sindex
);
109 eindex
= symbolToExp(sindex
, loc
, sc
, false);
112 .error(loc
, "index `%s` is not an expression", oindex
.toChars());
117 eindex
= semanticLength(sc
, tup
, eindex
);
118 eindex
= eindex
.ctfeInterpret();
119 if (eindex
.op
== EXP
.error
)
124 const(uinteger_t
) d
= eindex
.toUInteger();
125 if (d
>= tup
.objects
.length
)
127 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", d
, cast(ulong)tup
.objects
.length
);
132 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
134 if (auto t
= isType(o
))
135 pt
= t
.typeSemantic(loc
, sc
);
136 if (auto e
= isExpression(o
))
137 resolveExp(e
, pt
, pe
, ps
);
140 /*************************************
141 * Takes an array of Identifiers and figures out if
142 * it represents a Type, Expression, or Dsymbol.
144 * mt = array of identifiers
145 * loc = location for error messages
147 * s = symbol to start search at
149 * pe = set if expression otherwise null
150 * pt = set if type otherwise null
151 * ps = set if symbol otherwise null
152 * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
154 private void resolveHelper(TypeQualified mt
, const ref Loc loc
, Scope
* sc
, Dsymbol s
, Dsymbol scopesym
,
155 out Expression pe
, out Type pt
, out Dsymbol ps
, bool intypeid
= false)
159 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc
, mt
.toChars());
161 printf("\tscopesym = '%s'\n", scopesym
.toChars());
166 /* Look for what user might have intended
168 const p
= mt
.mutableOf().unSharedOf().toChars();
169 auto id
= Identifier
.idPool(p
[0 .. strlen(p
)]);
170 if (const n
= importHint(id
.toString()))
171 error(loc
, "`%s` is not defined, perhaps `import %.*s;` ?", p
, cast(int)n
.length
, n
.ptr
);
172 else if (auto s2
= sc
.search_correct(id
))
173 error(loc
, "undefined identifier `%s`, did you mean %s `%s`?", p
, s2
.kind(), s2
.toChars());
174 else if (const q
= Scope
.search_correct_C(id
))
175 error(loc
, "undefined identifier `%s`, did you mean `%s`?", p
, q
);
176 else if ((id
== Id
.This
&& sc
.getStructClassScope()) ||
177 (id
== Id
._super
&& sc
.getClassScope()))
178 error(loc
, "undefined identifier `%s`, did you mean `typeof(%s)`?", p
, p
);
180 error(loc
, "undefined identifier `%s`", p
);
186 //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
187 Declaration d
= s
.isDeclaration();
188 if (d
&& (d
.storage_class
& STC
.templateparameter
))
192 // check for deprecated or disabled aliases
193 // functions are checked after overloading
194 // templates are checked after matching constraints
195 if (!s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
196 s
.checkDeprecated(loc
, sc
);
198 d
.checkDisabled(loc
, sc
, true);
201 //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
202 for (size_t i
= 0; i
< mt
.idents
.length
; i
++)
204 RootObject id
= mt
.idents
[i
];
205 switch (id
.dyncast()) with (DYNCAST
)
212 resolveTupleIndex(loc
, sc
, s
, ex
, tx
, sx
, id
);
219 ex
= new TypeExp(loc
, tx
);
222 ex
= typeToExpressionHelper(mt
, ex
, i
+ 1);
223 ex
= ex
.expressionSemantic(sc
);
224 resolveExp(ex
, pt
, pe
, ps
);
230 Type t
= s
.getType(); // type symbol, type alias, or type tuple?
231 uint errorsave
= global
.errors
;
232 SearchOptFlags flags
= t
is null ? SearchOpt
.localsOnly
: SearchOpt
.ignorePrivateImports
;
234 Dsymbol sm
= s
.searchX(loc
, sc
, id
, flags
);
237 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, sm
))
239 .error(loc
, "`%s` is not visible from module `%s`", sm
.toPrettyChars(), sc
._module
.toChars());
242 // Same check as in dotIdSemanticProp(DotIdExp)
243 else if (sm
.isPackage() && checkAccess(sc
, sm
.isPackage()))
245 // @@@DEPRECATED_2.106@@@
246 // Should be an error in 2.106. Just remove the deprecation call
247 // and uncomment the null assignment
248 deprecation(loc
, "%s %s is not accessible here, perhaps add 'static import %s;'", sm
.kind(), sm
.toPrettyChars(), sm
.toPrettyChars());
252 if (global
.errors
!= errorsave
)
261 VarDeclaration v
= s
.isVarDeclaration();
262 FuncDeclaration f
= s
.isFuncDeclaration();
263 if (intypeid ||
!v
&& !f
)
264 e
= symbolToExp(s
, loc
, sc
, true);
266 e
= new VarExp(loc
, s
.isDeclaration(), true);
268 e
= typeToExpressionHelper(mt
, e
, i
);
269 e
= e
.expressionSemantic(sc
);
270 resolveExp(e
, pt
, pe
, ps
);
273 //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
274 if (intypeid
&& !t
&& sm
&& sm
.needThis())
277 if (VarDeclaration v
= s
.isVarDeclaration())
279 // https://issues.dlang.org/show_bug.cgi?id=19913
280 // v.type would be null if it is a forward referenced member.
282 v
.dsymbolSemantic(sc
);
283 if (v
.storage_class
& (STC
.const_ | STC
.immutable_ | STC
.manifest
) ||
284 v
.type
.isConst() || v
.type
.isImmutable())
286 // https://issues.dlang.org/show_bug.cgi?id=13087
287 // this.field is not constant always
288 if (!v
.isThisDeclaration())
296 if (sm
.isAliasDeclaration
)
297 sm
.checkDeprecated(loc
, sc
);
301 if (auto em
= s
.isEnumMember())
303 // It's not a type, it's an expression
304 pe
= em
.getVarExp(loc
, sc
);
307 if (auto v
= s
.isVarDeclaration())
309 /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
310 * because some variables used in type context need to prevent lowering
311 * to a literal or contextful expression. For example:
313 * enum a = 1; alias b = a;
314 * template X(alias e){ alias v = e; } alias x = X!(1);
315 * struct S { int v; alias w = v; }
316 * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
317 * // because getDsymbol() need to work in AliasDeclaration::semantic().
320 !v
.type
.deco
&& v
.inuse
)
322 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
323 error(loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
325 error(loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
329 if (v
.type
.ty
== Terror
)
332 pe
= new VarExp(loc
, v
);
335 if (auto fld = s
.isFuncLiteralDeclaration())
337 //printf("'%s' is a function literal\n", fld.toChars());
338 auto e
= new FuncExp(loc
, fld);
339 pe
= e
.expressionSemantic(sc
);
344 if (FuncDeclaration fd
= s
.isFuncDeclaration())
346 pe
= new DsymbolExp(loc
, fd
);
361 if (auto ti
= t
.isTypeInstance())
362 if (ti
!= mt
&& !ti
.deco
)
364 if (!ti
.tempinst
.errors
)
365 error(loc
, "forward reference to `%s`", ti
.toChars());
376 /***************************************
377 * Search for identifier id as a member of `this`.
378 * `id` may be a template instance.
381 * loc = location to print the error messages
382 * sc = the scope where the symbol is located
383 * id = the id of the symbol
384 * flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports`
387 * symbol found, NULL if not
389 private Dsymbol
searchX(Dsymbol dsym
, const ref Loc loc
, Scope
* sc
, RootObject id
, SearchOptFlags flags
)
391 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
392 Dsymbol s
= dsym
.toAlias();
394 if (Declaration d
= s
.isDeclaration())
398 .error(loc
, "circular reference to `%s`", d
.toPrettyChars());
402 switch (id
.dyncast())
404 case DYNCAST
.identifier
:
405 sm
= s
.search(loc
, cast(Identifier
)id
, flags
);
407 case DYNCAST
.dsymbol
:
409 // It's a template instance
410 //printf("\ttemplate instance id\n");
411 Dsymbol st
= cast(Dsymbol
)id
;
412 TemplateInstance ti
= st
.isTemplateInstance();
413 sm
= s
.search(loc
, ti
.name
);
417 TemplateDeclaration td
= sm
.isTemplateDeclaration();
419 return null; // error but handled later
422 ti
.dsymbolSemantic(sc
);
427 case DYNCAST
.expression
:
434 /***************************************************
435 * Determine if type t is copyable.
439 * true if we can copy it
441 bool isCopyable(Type t
)
443 //printf("isCopyable() %s\n", t.toChars());
444 if (auto ts
= t
.isTypeStruct())
446 if (ts
.sym
.postblit
&&
447 ts
.sym
.postblit
.storage_class
& STC
.disable
)
449 if (ts
.sym
.hasCopyCtor
)
451 // check if there is a matching overload of the copy constructor and whether it is disabled or not
452 // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
453 Dsymbol ctor
= search_function(ts
.sym
, Id
.ctor
);
455 scope el
= new IdentifierExp(Loc
.initial
, Id
.p
); // dummy lvalue
457 Expressions
* args
= new Expressions();
459 FuncDeclaration f
= resolveFuncCall(Loc
.initial
, null, ctor
, null, cast()ts
, ArgumentList(args
), FuncResolveFlag
.quiet
);
460 if (!f || f
.storage_class
& STC
.disable
)
467 /************************************
468 * Determine mutability of indirections in (ref) t.
470 * Returns: When the type has any mutable indirections, returns 0.
471 * When all indirections are immutable, returns 2.
472 * Otherwise, when the type has const/inout indirections, returns 1.
475 * isref = if true, check `ref t`; otherwise, check just `t`
476 * t = the type that is being checked
478 int mutabilityOfType(bool isref
, Type t
)
482 if (t
.mod
& MODFlags
.immutable_
)
484 if (t
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
491 if (!t
.hasPointers() || t
.mod
& MODFlags
.immutable_
)
494 /* Accept immutable(T)[] and immutable(T)* as being strongly pure
496 if (t
.ty
== Tarray || t
.ty
== Tpointer
)
498 Type tn
= t
.nextOf().toBasetype();
499 if (tn
.mod
& MODFlags
.immutable_
)
501 if (tn
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
505 /* The rest of this is too strict; fix later.
506 * For example, the only pointer members of a struct may be immutable,
507 * which would maintain strong purity.
508 * (Just like for dynamic arrays and pointers above.)
510 if (t
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
513 /* Should catch delegates and function pointers, and fold in their purity
518 /********************************************
519 * Set 'purity' field of 'typeFunction'.
520 * Do this lazily, as the parameter types might be forward referenced.
522 extern(C
++) void purityLevel(TypeFunction typeFunction
)
524 TypeFunction tf
= typeFunction
;
525 if (tf
.purity
!= PURE
.fwdref
)
528 typeFunction
.purity
= PURE
.const_
; // assume strong until something weakens it
530 /* Evaluate what kind of purity based on the modifiers for the parameters
532 foreach (i
, fparam
; tf
.parameterList
)
534 Type t
= fparam
.type
;
538 if (fparam
.storageClass
& (STC
.lazy_ | STC
.out_
))
540 typeFunction
.purity
= PURE
.weak
;
543 const pref
= (fparam
.storageClass
& STC
.ref_
) != 0;
544 if (mutabilityOfType(pref
, t
) == 0)
545 typeFunction
.purity
= PURE
.weak
;
548 tf
.purity
= typeFunction
.purity
;
551 /******************************************
552 * We've mistakenly parsed `t` as a type.
553 * Redo `t` as an Expression only if there are no type modifiers.
557 * t redone as Expression, null if cannot
559 Expression
typeToExpression(Type t
)
561 static Expression
visitSArray(TypeSArray t
)
563 if (auto e
= t
.next
.typeToExpression())
564 return new ArrayExp(t
.dim
.loc
, e
, t
.dim
);
568 static Expression
visitAArray(TypeAArray t
)
570 if (auto e
= t
.next
.typeToExpression())
572 if (auto ei
= t
.index
.typeToExpression())
573 return new ArrayExp(t
.loc
, e
, ei
);
578 static Expression
visitIdentifier(TypeIdentifier t
)
580 return typeToExpressionHelper(t
, new IdentifierExp(t
.loc
, t
.ident
));
583 static Expression
visitInstance(TypeInstance t
)
585 return typeToExpressionHelper(t
, new ScopeExp(t
.loc
, t
.tempinst
));
588 // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
589 static Expression
visitMixin(TypeMixin t
)
591 return new TypeExp(t
.loc
, t
);
598 case Tsarray
: return visitSArray(t
.isTypeSArray());
599 case Taarray
: return visitAArray(t
.isTypeAArray());
600 case Tident
: return visitIdentifier(t
.isTypeIdentifier());
601 case Tinstance
: return visitInstance(t
.isTypeInstance());
602 case Tmixin
: return visitMixin(t
.isTypeMixin());
603 default: return null;
607 /*************************************
608 * https://issues.dlang.org/show_bug.cgi?id=14488
609 * Check if the inner most base type is complex or imaginary.
610 * Should only give alerts when set to emit transitional messages.
612 * type = type to check
613 * loc = The source location.
614 * sc = scope of the type
616 extern (D
) bool checkComplexTransition(Type type
, const ref Loc loc
, Scope
* sc
)
618 if (sc
.isDeprecated())
620 // Don't complain if we're inside a template constraint
621 // https://issues.dlang.org/show_bug.cgi?id=21831
622 if (sc
.flags
& SCOPE
.constraint
)
625 Type t
= type
.baseElemOf();
626 while (t
.ty
== Tpointer || t
.ty
== Tarray
)
627 t
= t
.nextOf().baseElemOf();
629 // Basetype is an opaque enum, nothing to check.
630 if (t
.ty
== Tenum
&& !(cast(TypeEnum
)t
).sym
.memtype
)
633 if (t
.isimaginary() || t
.iscomplex())
635 if (sc
.flags
& SCOPE
.Cfile
)
636 return true; // complex/imaginary not deprecated in C code
658 // @@@DEPRECATED_2.117@@@
659 // Deprecated in 2.097 - Can be made an error from 2.117.
660 // The deprecation period is longer than usual as `cfloat`,
661 // `cdouble`, and `creal` were quite widely used.
664 deprecation(loc
, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
665 type
.toChars(), rt
.toChars());
670 deprecation(loc
, "use of imaginary type `%s` is deprecated, use `%s` instead",
671 type
.toChars(), rt
.toChars());
678 /********************************
679 * 'args' are being matched to function type 'tf'
680 * Determine match level.
683 * tthis = type of `this` pointer, null if not member function
684 * argumentList = arguments to function call
685 * flag = 1: performing a partial ordering match
686 * errorHelper = delegate to call for error messages
691 extern (D
) MATCH
callMatch(TypeFunction tf
, Type tthis
, ArgumentList argumentList
, int flag
= 0, void delegate(const(char)*) scope errorHelper
= null, Scope
* sc
= null)
693 //printf("TypeFunction::callMatch() %s\n", tf.toChars());
694 MATCH match
= MATCH
.exact
; // assume exact match
700 if (t
.toBasetype().ty
== Tpointer
)
701 t
= t
.toBasetype().nextOf(); // change struct* to struct
704 if (MODimplicitConv(t
.mod
, tf
.mod
))
705 match
= MATCH
.constant
;
706 else if ((tf
.mod
& MODFlags
.wild
) && MODimplicitConv(t
.mod
, (tf
.mod
& ~MODFlags
.wild
) | MODFlags
.const_
))
708 match
= MATCH
.constant
;
711 return MATCH
.nomatch
;
716 wildmatch |
= MODFlags
.wild
;
717 else if (t
.isConst())
718 wildmatch |
= MODFlags
.const_
;
719 else if (t
.isImmutable())
720 wildmatch |
= MODFlags
.immutable_
;
722 wildmatch |
= MODFlags
.mutable
;
726 ParameterList
* parameterList
= &tf
.parameterList
;
727 const nparams
= parameterList
.length
;
728 if (argumentList
.length
> nparams
)
730 if (parameterList
.varargs
== VarArg
.none
)
732 // suppress early exit if an error message is wanted,
733 // so we can check any matching args are valid
735 return MATCH
.nomatch
;
737 // too many args; no match
738 match
= MATCH
.convert
; // match ... with a "conversion" match level
741 // https://issues.dlang.org/show_bug.cgi?id=22997
742 if (parameterList
.varargs
== VarArg
.none
&& nparams
> argumentList
.length
&& !parameterList
.hasDefaultArgs
)
747 buf
.printf("too few arguments, expected %d, got %d", cast(int)nparams
, cast(int)argumentList
.length
);
748 errorHelper(buf
.peekChars());
750 return MATCH
.nomatch
;
752 const(char)* failMessage
;
753 const(char)** pMessage
= errorHelper ?
&failMessage
: null;
754 auto resolvedArgs
= tf
.resolveNamedArgs(argumentList
, pMessage
);
760 errorHelper(failMessage
);
761 return MATCH
.nomatch
;
764 // if no message was provided, it was because of overflow which will be diagnosed below
765 match
= MATCH
.nomatch
;
766 args
= argumentList
.arguments ?
(*argumentList
.arguments
)[] : null;
770 args
= (*resolvedArgs
)[];
773 foreach (u
, p
; *parameterList
)
775 if (u
>= args
.length
)
778 Expression arg
= args
[u
];
780 continue; // default argument
783 Type targ
= arg
.type
;
785 if (!(p
.isLazy() && tprm
.ty
== Tvoid
&& targ
.ty
!= Tvoid
))
787 const isRef
= p
.isReference();
788 wildmatch |
= targ
.deduceWild(tprm
, isRef
);
793 /* Calculate wild matching modifier
795 if (wildmatch
& MODFlags
.const_ || wildmatch
& (wildmatch
- 1))
796 wildmatch
= MODFlags
.const_
;
797 else if (wildmatch
& MODFlags
.immutable_
)
798 wildmatch
= MODFlags
.immutable_
;
799 else if (wildmatch
& MODFlags
.wild
)
800 wildmatch
= MODFlags
.wild
;
803 assert(wildmatch
& MODFlags
.mutable
);
804 wildmatch
= MODFlags
.mutable
;
808 foreach (u
, p
; *parameterList
)
814 // One or more arguments remain
817 Expression arg
= args
[u
];
819 continue; // default argument
820 m
= argumentMatchParameter(tf
, p
, arg
, wildmatch
, flag
, sc
, pMessage
);
822 else if (p
.defaultArg
)
825 /* prefer matching the element type rather than the array
826 * type when more arguments are present with T[]...
828 if (parameterList
.varargs
== VarArg
.typesafe
&& u
+ 1 == nparams
&& args
.length
> nparams
)
831 //printf("\tm = %d\n", m);
832 if (m
== MATCH
.nomatch
) // if no match
835 if (parameterList
.varargs
== VarArg
.typesafe
&& u
+ 1 == nparams
) // if last varargs param
837 auto trailingArgs
= args
[u
.. $];
838 if (auto vmatch
= matchTypeSafeVarArgs(tf
, p
, trailingArgs
, pMessage
))
839 return vmatch
< match ? vmatch
: match
;
840 // Error message was already generated in `matchTypeSafeVarArgs`
842 errorHelper(failMessage
);
843 return MATCH
.nomatch
;
845 if (pMessage
&& u
>= args
.length
)
846 *pMessage
= tf
.getMatchError("missing argument for parameter #%d: `%s`",
847 u
+ 1, parameterToChars(p
, tf
, false));
848 // If an error happened previously, `pMessage` was already filled
849 else if (pMessage
&& !*pMessage
)
850 *pMessage
= tf
.getParamError(args
[u
], p
);
853 errorHelper(*pMessage
);
854 return MATCH
.nomatch
;
857 match
= m
; // pick worst match
860 if (errorHelper
&& !parameterList
.varargs
&& args
.length
> nparams
)
862 // all parameters had a match, but there are surplus args
863 errorHelper(tf
.getMatchError("expected %d argument(s), not %d", nparams
, args
.length
));
864 return MATCH
.nomatch
;
866 //printf("match = %d\n", match);
871 * Used by `callMatch` to check if the copy constructor may be called to
874 * This is done by seeing if a call to the copy constructor can be made:
876 * typeof(tprm) __copytmp;
877 * copytmp.__copyCtor(arg);
880 private extern(D
) bool isCopyConstructorCallable (StructDeclaration argStruct
,
881 Expression arg
, Type tprm
, Scope
* sc
, const(char)** pMessage
)
883 auto tmp
= new VarDeclaration(arg
.loc
, tprm
, Identifier
.generateId("__copytmp"), null);
884 tmp
.storage_class
= STC
.rvalue | STC
.temp | STC
.ctfe
;
885 tmp
.dsymbolSemantic(sc
);
886 Expression ve
= new VarExp(arg
.loc
, tmp
);
887 Expression e
= new DotIdExp(arg
.loc
, ve
, Id
.ctor
);
888 e
= new CallExp(arg
.loc
, e
, arg
);
889 //printf("e = %s\n", e.toChars());
890 if (dmd
.expressionsem
.trySemantic(e
, sc
))
895 /* https://issues.dlang.org/show_bug.cgi?id=22202
897 * If a function was deduced by semantic on the CallExp,
898 * it means that resolveFuncCall completed succesfully.
899 * Therefore, there exists a callable copy constructor,
900 * however, it cannot be called because scope constraints
901 * such as purity, safety or nogc.
904 auto callExp
= e
.isCallExp();
905 if (auto f
= callExp
.f
)
908 if (!f
.isPure
&& sc
.func
.setImpure())
910 if (!f
.isSafe() && !f
.isTrusted() && sc
.setUnsafe())
912 if (!f
.isNogc
&& sc
.func
.setGC(arg
.loc
, null))
914 if (f
.isDisabled() && !f
.isGenerated())
916 /* https://issues.dlang.org/show_bug.cgi?id=24301
917 * Copy constructor is explicitly disabled
919 buf
.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`",
925 buf
.printf("`%s` copy constructor cannot be called from a `%s` context", f
.type
.toChars(), s
.ptr
);
927 else if (f
.isGenerated() && f
.isDisabled())
929 /* https://issues.dlang.org/show_bug.cgi?id=23097
930 * Compiler generated copy constructor failed.
932 buf
.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
933 argStruct
.toChars());
937 /* Although a copy constructor may exist, no suitable match was found.
938 * i.e: `inout` constructor creates `const` object, not mutable.
939 * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
947 buf
.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
948 argStruct
.toChars(), arg
.type
.toChars(), tprm
.toChars());
951 *pMessage
= buf
.extractChars();
957 * Match a single parameter to an argument.
959 * This function is called by `TypeFunction.callMatch` while iterating over
960 * the list of parameter. Here we check if `arg` is a match for `p`,
961 * which is mostly about checking if `arg.type` converts to `p`'s type
962 * and some check about value reference.
965 * tf = The `TypeFunction`, only used for error reporting
966 * p = The parameter of `tf` being matched
967 * arg = Argument being passed (bound) to `p`
968 * wildmatch = Wild (`inout`) matching level, derived from the full argument list
969 * flag = A non-zero value means we're doing a partial ordering check
970 * (no value semantic check)
971 * sc = Scope we are in
972 * pMessage = A buffer to write the error in, or `null`
974 * Returns: Whether `trailingArgs` match `p`.
976 private extern(D
) MATCH
argumentMatchParameter (TypeFunction tf
, Parameter p
,
977 Expression arg
, ubyte wildmatch
, int flag
, Scope
* sc
, const(char)** pMessage
)
979 //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
981 Type targ
= arg
.type
;
982 Type tprm
= wildmatch ? p
.type
.substWildTo(wildmatch
) : p
.type
;
984 if (p
.isLazy() && tprm
.ty
== Tvoid
&& targ
.ty
!= Tvoid
)
988 // for partial ordering, value is an irrelevant mockup, just look at the type
989 m
= targ
.implicitConvTo(tprm
);
993 const isRef
= p
.isReference();
994 StructDeclaration argStruct
, prmStruct
;
996 // first look for a copy constructor
997 if (arg
.isLvalue() && !isRef
&& targ
.ty
== Tstruct
&& tprm
.ty
== Tstruct
)
999 // if the argument and the parameter are of the same unqualified struct type
1000 argStruct
= (cast(TypeStruct
)targ
).sym
;
1001 prmStruct
= (cast(TypeStruct
)tprm
).sym
;
1004 // check if the copy constructor may be called to copy the argument
1005 if (argStruct
&& argStruct
== prmStruct
&& argStruct
.hasCopyCtor
)
1007 if (!isCopyConstructorCallable(argStruct
, arg
, tprm
, sc
, pMessage
))
1008 return MATCH
.nomatch
;
1013 import dmd
.dcast
: cimplicitConvTo
;
1014 m
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? arg
.cimplicitConvTo(tprm
) : arg
.implicitConvTo(tprm
);
1018 // Non-lvalues do not match ref or out parameters
1019 if (p
.isReference())
1021 // https://issues.dlang.org/show_bug.cgi?id=13783
1022 // Don't use toBasetype() to handle enum types.
1025 //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
1027 if (m
&& !arg
.isLvalue())
1029 if (p
.storageClass
& STC
.out_
)
1031 if (pMessage
) *pMessage
= tf
.getParamError(arg
, p
);
1032 return MATCH
.nomatch
;
1035 if (arg
.op
== EXP
.string_
&& tp
.ty
== Tsarray
)
1037 if (ta
.ty
!= Tsarray
)
1039 Type tn
= tp
.nextOf().castMod(ta
.nextOf().mod
);
1040 dinteger_t dim
= (cast(StringExp
)arg
).len
;
1041 ta
= tn
.sarrayOf(dim
);
1044 else if (arg
.op
== EXP
.slice
&& tp
.ty
== Tsarray
)
1046 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1047 if (ta
.ty
!= Tsarray
)
1049 Type tn
= ta
.nextOf();
1050 dinteger_t dim
= (cast(TypeSArray
)tp
).dim
.toUInteger();
1051 ta
= tn
.sarrayOf(dim
);
1054 else if (p
.storageClass
& STC
.constscoperef
)
1056 // Allow converting a literal to an `in` which is `ref`
1057 if (arg
.op
== EXP
.arrayLiteral
&& tp
.ty
== Tsarray
)
1059 Type tn
= tp
.nextOf();
1060 dinteger_t dim
= (cast(TypeSArray
)tp
).dim
.toUInteger();
1061 ta
= tn
.sarrayOf(dim
);
1064 // Need to make this a rvalue through a temporary
1067 else if (global
.params
.rvalueRefParam
!= FeatureState
.enabled ||
1068 p
.storageClass
& STC
.out_ ||
1069 !arg
.type
.isCopyable()) // can't copy to temp for ref parameter
1071 if (pMessage
) *pMessage
= tf
.getParamError(arg
, p
);
1072 return MATCH
.nomatch
;
1076 /* in functionParameters() we'll convert this
1077 * rvalue into a temporary
1083 /* If the match is not already perfect or if the arg
1084 is not a lvalue then try the `alias this` chain
1085 see https://issues.dlang.org/show_bug.cgi?id=15674
1086 and https://issues.dlang.org/show_bug.cgi?id=21905
1088 if (ta
!= tp ||
!arg
.isLvalue())
1090 Type firsttab
= ta
.toBasetype();
1093 Type tab
= ta
.toBasetype();
1094 Type tat
= tab
.aliasthisOf();
1095 if (!tat ||
!tat
.implicitConvTo(tprm
))
1097 if (tat
== tab || tat
== firsttab
)
1103 /* A ref variable should work like a head-const reference.
1105 * ref T <- an lvalue of const(T) argument
1106 * ref T[dim] <- an lvalue of const(T[dim]) argument
1108 if (!ta
.constConv(tp
))
1110 if (pMessage
) *pMessage
= tf
.getParamError(arg
, p
);
1111 return MATCH
.nomatch
;
1117 // arguments get specially formatted
1118 private const(char)* getParamError(TypeFunction tf
, Expression arg
, Parameter par
)
1120 if (global
.gag
&& !global
.params
.v
.showGaggedErrors
)
1122 // show qualification when toChars() is the same but types are different
1123 // https://issues.dlang.org/show_bug.cgi?id=19948
1124 // when comparing the type with strcmp, we need to drop the qualifier
1125 bool qual
= !arg
.type
.mutableOf().equals(par
.type
.mutableOf()) &&
1126 strcmp(arg
.type
.mutableOf().toChars(), par
.type
.mutableOf().toChars()) == 0;
1127 auto at
= qual ? arg
.type
.toPrettyChars(true) : arg
.type
.toChars();
1129 // only mention rvalue if it's relevant
1130 const rv
= !arg
.isLvalue() && par
.isReference();
1131 buf
.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
1132 rv ?
"rvalue ".ptr
: "".ptr
, arg
.toChars(), at
,
1133 parameterToChars(par
, tf
, qual
));
1134 return buf
.extractChars();
1138 * Match the remaining arguments `trailingArgs` with parameter `p`.
1140 * Assume we already checked that `p` is the last parameter of `tf`,
1141 * and we want to know whether the arguments would match `p`.
1144 * tf = The `TypeFunction`, only used for error reporting
1145 * p = The last parameter of `tf` which is variadic
1146 * trailingArgs = The remaining arguments that should match `p`
1147 * pMessage = A buffer to write the error in, or `null`
1149 * Returns: Whether `trailingArgs` match `p`.
1151 private extern(D
) MATCH
matchTypeSafeVarArgs(TypeFunction tf
, Parameter p
,
1152 Expression
[] trailingArgs
, const(char)** pMessage
)
1154 Type tb
= p
.type
.toBasetype();
1159 TypeSArray tsa
= cast(TypeSArray
)tb
;
1160 dinteger_t sz
= tsa
.dim
.toInteger();
1161 if (sz
!= trailingArgs
.length
)
1164 *pMessage
= tf
.getMatchError("expected %llu variadic argument(s), not %zu",
1165 sz
, trailingArgs
.length
);
1166 return MATCH
.nomatch
;
1171 MATCH match
= MATCH
.exact
;
1172 TypeArray ta
= cast(TypeArray
)tb
;
1173 foreach (arg
; trailingArgs
)
1178 /* If lazy array of delegates,
1179 * convert arg(s) to delegate(s)
1181 Type tret
= p
.isLazyArray();
1184 if (ta
.next
.equals(arg
.type
))
1186 else if (tret
.toBasetype().ty
== Tvoid
)
1190 m
= arg
.implicitConvTo(tret
);
1191 if (m
== MATCH
.nomatch
)
1192 m
= arg
.implicitConvTo(ta
.next
);
1196 m
= arg
.implicitConvTo(ta
.next
);
1198 if (m
== MATCH
.nomatch
)
1200 if (pMessage
) *pMessage
= tf
.getParamError(arg
, p
);
1201 return MATCH
.nomatch
;
1209 // We leave it up to the actual constructor call to do the matching.
1213 // We can have things as `foo(int[int] wat...)` but they only match
1214 // with an associative array proper.
1215 if (pMessage
&& trailingArgs
.length
) *pMessage
= tf
.getParamError(trailingArgs
[0], p
);
1216 return MATCH
.nomatch
;
1220 /***************************************
1221 * Return !=0 if type has pointers that need to
1222 * be scanned by the GC during a collection cycle.
1224 extern(C
++) bool hasPointers(Type t
)
1226 bool visitType(Type _
) { return false; }
1227 bool visitDArray(TypeDArray _
) { return true; }
1228 bool visitAArray(TypeAArray _
) { return true; }
1229 bool visitPointer(TypePointer _
) { return true; }
1230 bool visitDelegate(TypeDelegate _
) { return true; }
1231 bool visitClass(TypeClass _
) { return true; }
1232 bool visitEnum(TypeEnum t
) { return t
.memType().hasPointers(); }
1234 /* Although null isn't dereferencable, treat it as a pointer type for
1235 * attribute inference, generic code, etc.
1237 bool visitNull(TypeNull _
) { return true; }
1239 bool visitSArray(TypeSArray t
)
1241 /* Don't want to do this, because:
1242 * struct S { T* array[0]; }
1243 * may be a variable length struct.
1245 //if (dim.toInteger() == 0)
1248 if (t
.next
.ty
== Tvoid
)
1250 // Arrays of void contain arbitrary data, which may include pointers
1254 return t
.next
.hasPointers();
1257 bool visitStruct(TypeStruct t
)
1259 StructDeclaration sym
= t
.sym
;
1261 if (sym
.members
&& !sym
.determineFields() && sym
.type
!= Type
.terror
)
1262 error(sym
.loc
, "no size because of forward references");
1264 sym
.determineTypeProperties();
1265 return sym
.hasPointerField
;
1271 default: return visitType(t
);
1272 case Tsarray
: return visitSArray(t
.isTypeSArray());
1273 case Tarray
: return visitDArray(t
.isTypeDArray());
1274 case Taarray
: return visitAArray(t
.isTypeAArray());
1275 case Tpointer
: return visitPointer(t
.isTypePointer());
1276 case Tdelegate
: return visitDelegate(t
.isTypeDelegate());
1277 case Tstruct
: return visitStruct(t
.isTypeStruct());
1278 case Tenum
: return visitEnum(t
.isTypeEnum());
1279 case Tclass
: return visitClass(t
.isTypeClass());
1280 case Tnull
: return visitNull(t
.isTypeNull());
1284 /******************************************
1285 * Perform semantic analysis on a type.
1287 * type = Type AST node
1288 * loc = the location of the type
1291 * `Type` with completed semantic analysis, `Terror` if errors
1294 extern(C
++) Type
typeSemantic(Type type
, const ref Loc loc
, Scope
* sc
)
1301 Type
visitType(Type t
)
1303 // @@@DEPRECATED_2.110@@@
1304 // Use of `cent` and `ucent` has always been an error.
1305 // Starting from 2.100, recommend core.int128 as a replace for the
1306 // lack of compiler support.
1307 if (t
.ty
== Tint128 || t
.ty
== Tuns128
)
1309 .error(loc
, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
1316 Type
visitComplex(TypeBasic t
)
1318 if (!(sc
.flags
& SCOPE
.Cfile
))
1319 return visitType(t
);
1321 auto tc
= getComplexLibraryType(loc
, sc
, t
.ty
);
1322 if (tc
.ty
== Terror
)
1324 return tc
.addMod(t
.mod
).merge();
1327 Type
visitVector(TypeVector mtype
)
1329 const errors
= global
.errors
;
1330 mtype
.basetype
= mtype
.basetype
.typeSemantic(loc
, sc
);
1331 if (errors
!= global
.errors
)
1333 mtype
.basetype
= mtype
.basetype
.toBasetype().mutableOf();
1334 if (mtype
.basetype
.ty
!= Tsarray
)
1336 .error(loc
, "T in __vector(T) must be a static array, not `%s`", mtype
.basetype
.toChars());
1339 TypeSArray t
= mtype
.basetype
.isTypeSArray();
1340 const sz
= cast(int)t
.size(loc
);
1341 final switch (target
.isVectorTypeSupported(sz
, t
.nextOf()))
1348 // no support at all
1349 .error(loc
, "SIMD vector types not supported on this platform");
1353 // invalid base type
1354 .error(loc
, "vector type `%s` is not supported on this platform", mtype
.toChars());
1359 .error(loc
, "%d byte vector type `%s` is not supported on this platform", sz
, mtype
.toChars());
1362 return merge(mtype
);
1365 Type
visitSArray(TypeSArray mtype
)
1367 //printf("TypeSArray::semantic() %s\n", toChars());
1371 mtype
.next
.resolve(loc
, sc
, e
, t
, s
);
1373 if (auto tup
= s ? s
.isTupleDeclaration() : null)
1375 mtype
.dim
= semanticLength(sc
, tup
, mtype
.dim
);
1376 mtype
.dim
= mtype
.dim
.ctfeInterpret();
1377 if (mtype
.dim
.op
== EXP
.error
)
1380 uinteger_t d
= mtype
.dim
.toUInteger();
1381 if (d
>= tup
.objects
.length
)
1383 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d
, cast(ulong)tup
.objects
.length
);
1387 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
1388 if (auto tt
= o
.isType())
1389 return tt
.addMod(mtype
.mod
);
1390 .error(loc
, "`%s` is not a type", mtype
.toChars());
1394 if (t
&& t
.ty
== Terror
)
1397 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
1398 if (tn
.ty
== Terror
)
1401 Type tbn
= tn
.toBasetype();
1404 auto errors
= global
.errors
;
1405 mtype
.dim
= semanticLength(sc
, tbn
, mtype
.dim
);
1406 mtype
.dim
= mtype
.dim
.implicitCastTo(sc
, Type
.tsize_t
);
1407 if (errors
!= global
.errors
)
1410 mtype
.dim
= mtype
.dim
.optimize(WANTvalue
);
1411 mtype
.dim
= mtype
.dim
.ctfeInterpret();
1412 if (mtype
.dim
.op
== EXP
.error
)
1415 errors
= global
.errors
;
1416 dinteger_t d1
= mtype
.dim
.toInteger();
1417 if (errors
!= global
.errors
)
1420 mtype
.dim
= mtype
.dim
.implicitCastTo(sc
, Type
.tsize_t
);
1421 mtype
.dim
= mtype
.dim
.optimize(WANTvalue
);
1422 if (mtype
.dim
.op
== EXP
.error
)
1425 errors
= global
.errors
;
1426 dinteger_t d2
= mtype
.dim
.toInteger();
1427 if (errors
!= global
.errors
)
1430 if (mtype
.dim
.op
== EXP
.error
)
1433 Type
overflowError()
1435 .error(loc
, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
1436 mtype
.toChars(), cast(ulong)tbn
.size(loc
), cast(ulong)d1
, target
.maxStaticDataSize
);
1441 return overflowError();
1443 Type tbx
= tbn
.baseElemOf();
1444 if (tbx
.ty
== Tstruct
&& !tbx
.isTypeStruct().sym
.members ||
1445 tbx
.ty
== Tenum
&& !tbx
.isTypeEnum().sym
.members
)
1447 /* To avoid meaningless error message, skip the total size limit check
1448 * when the bottom of element type is opaque.
1451 else if (tbn
.isTypeBasic() ||
1452 tbn
.ty
== Tpointer ||
1454 tbn
.ty
== Tsarray ||
1455 tbn
.ty
== Taarray ||
1456 (tbn
.ty
== Tstruct
&& tbn
.isTypeStruct().sym
.sizeok
== Sizeok
.done
) ||
1459 /* Only do this for types that don't need to have semantic()
1460 * run on them for the size, since they may be forward referenced.
1462 bool overflow
= false;
1463 if (mulu(tbn
.size(loc
), d2
, overflow
) > target
.maxStaticDataSize || overflow
)
1464 return overflowError();
1471 // Index the tuple to get the type
1473 TypeTuple tt
= tbn
.isTypeTuple();
1474 uinteger_t d
= mtype
.dim
.toUInteger();
1475 if (d
>= tt
.arguments
.length
)
1477 .error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d
, cast(ulong)tt
.arguments
.length
);
1480 Type telem
= (*tt
.arguments
)[cast(size_t
)d
].type
;
1481 return telem
.addMod(mtype
.mod
);
1486 .error(loc
, "cannot have array of `%s`", tbn
.toChars());
1494 .error(loc
, "cannot have array of scope `%s`", tbn
.toChars());
1498 /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
1499 * and const(T)[3] become const(T[3])
1503 return mtype
.addMod(tn
.mod
).merge();
1506 Type
visitDArray(TypeDArray mtype
)
1508 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
1509 Type tbn
= tn
.toBasetype();
1517 .error(loc
, "cannot have array of `%s`", tbn
.toChars());
1528 .error(loc
, "cannot have array of scope `%s`", tn
.toChars());
1533 return merge(mtype
);
1536 Type
visitAArray(TypeAArray mtype
)
1538 //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
1548 // Deal with the case where we thought the index was a type, but
1549 // in reality it was an expression.
1550 if (mtype
.index
.ty
== Tident || mtype
.index
.ty
== Tinstance || mtype
.index
.ty
== Tsarray || mtype
.index
.ty
== Ttypeof || mtype
.index
.ty
== Treturn || mtype
.index
.ty
== Tmixin
)
1555 mtype
.index
.resolve(loc
, sc
, e
, t
, s
);
1557 // https://issues.dlang.org/show_bug.cgi?id=15478
1559 e
= symbolToExp(s
, loc
, sc
, false);
1563 // It was an expression -
1564 // Rewrite as a static array
1565 auto tsa
= new TypeSArray(mtype
.next
, e
);
1566 return tsa
.typeSemantic(loc
, sc
);
1569 mtype
.index
= t
.typeSemantic(loc
, sc
);
1572 .error(loc
, "index is not a type or an expression");
1577 mtype
.index
= mtype
.index
.typeSemantic(loc
, sc
);
1578 mtype
.index
= mtype
.index
.merge2();
1580 if (mtype
.index
.nextOf() && !mtype
.index
.nextOf().isImmutable())
1582 mtype
.index
= mtype
.index
.constOf().mutableOf();
1585 printf("index is %p %s\n", mtype
.index
, mtype
.index
.toChars());
1586 mtype
.index
.check();
1587 printf("index.mod = x%x\n", mtype
.index
.mod
);
1588 printf("index.ito = x%p\n", mtype
.index
.getMcache().ito
);
1589 if (mtype
.index
.getMcache().ito
)
1591 printf("index.ito.mod = x%x\n", mtype
.index
.getMcache().ito
.mod
);
1592 printf("index.ito.ito = x%p\n", mtype
.index
.getMcache().ito
.getMcache().ito
);
1597 switch (mtype
.index
.toBasetype().ty
)
1603 .error(loc
, "cannot have associative array key of `%s`", mtype
.index
.toBasetype().toChars());
1611 Type tbase
= mtype
.index
.baseElemOf();
1612 while (tbase
.ty
== Tarray
)
1613 tbase
= tbase
.nextOf().baseElemOf();
1614 if (auto ts
= tbase
.isTypeStruct())
1616 /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
1618 StructDeclaration sd
= ts
.sym
;
1619 if (sd
.semanticRun
< PASS
.semanticdone
)
1620 sd
.dsymbolSemantic(null);
1622 // duplicate a part of StructDeclaration::semanticTypeInfoMembers
1623 //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
1625 if (sd
.xeq
&& sd
.xeq
.isGenerated() && sd
.xeq
._scope
&& sd
.xeq
.semanticRun
< PASS
.semantic3done
)
1627 uint errors
= global
.startGagging();
1628 sd
.xeq
.semantic3(sd
.xeq
._scope
);
1629 if (global
.endGagging(errors
))
1634 //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
1635 const(char)* s
= (mtype
.index
.toBasetype().ty
!= Tstruct
) ?
"bottom of " : "";
1638 // If sd.xhash != NULL:
1639 // sd or its fields have user-defined toHash.
1640 // AA assumes that its result is consistent with bitwise equality.
1642 // bitwise equality & hashing
1644 else if (sd
.xeq
== sd
.xerreq
)
1646 if (search_function(sd
, Id
.eq
))
1648 .error(loc
, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s
, sd
.toChars(), sd
.toChars());
1652 .error(loc
, "%sAA key type `%s` does not support const equality", s
, sd
.toChars());
1658 if (search_function(sd
, Id
.eq
))
1660 .error(loc
, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s
, sd
.toChars());
1664 .error(loc
, "%sAA key type `%s` supports const equality but doesn't support const hashing", s
, sd
.toChars());
1670 // defined equality & hashing
1671 assert(sd
.xeq
&& sd
.xhash
);
1673 /* xeq and xhash may be implicitly defined by compiler. For example:
1674 * struct S { int[] arr; }
1675 * With 'arr' field equality and hashing, compiler will implicitly
1676 * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
1680 else if (tbase
.ty
== Tclass
&& !tbase
.isTypeClass().sym
.isInterfaceDeclaration())
1682 ClassDeclaration cd
= tbase
.isTypeClass().sym
;
1683 if (cd
.semanticRun
< PASS
.semanticdone
)
1684 cd
.dsymbolSemantic(null);
1686 if (!ClassDeclaration
.object
)
1688 .error(Loc
.initial
, "missing or corrupt object.d");
1692 __gshared FuncDeclaration feq
= null;
1693 __gshared FuncDeclaration fcmp
= null;
1694 __gshared FuncDeclaration fhash
= null;
1696 feq
= search_function(ClassDeclaration
.object
, Id
.eq
).isFuncDeclaration();
1698 fcmp
= search_function(ClassDeclaration
.object
, Id
.cmp).isFuncDeclaration();
1700 fhash
= search_function(ClassDeclaration
.object
, Id
.tohash
).isFuncDeclaration();
1701 assert(fcmp
&& feq
&& fhash
);
1703 if (feq
.vtblIndex
< cd
.vtbl
.length
&& cd
.vtbl
[feq
.vtblIndex
] == feq
)
1707 if (fcmp
.vtblIndex
< cd
.vtbl
.length
&& cd
.vtbl
[fcmp
.vtblIndex
] != fcmp
)
1709 const(char)* s
= (mtype
.index
.toBasetype().ty
!= Tclass
) ?
"bottom of " : "";
1710 .error(loc
, "%sAA key type `%s` now requires equality rather than comparison", s
, cd
.toChars());
1711 errorSupplemental(loc
, "Please override `Object.opEquals` and `Object.toHash`.");
1716 mtype
.next
= mtype
.next
.typeSemantic(loc
, sc
).merge2();
1719 switch (mtype
.next
.toBasetype().ty
)
1725 .error(loc
, "cannot have associative array of `%s`", mtype
.next
.toChars());
1732 if (mtype
.next
.isscope())
1734 .error(loc
, "cannot have array of scope `%s`", mtype
.next
.toChars());
1737 return merge(mtype
);
1740 Type
visitPointer(TypePointer mtype
)
1742 //printf("TypePointer::semantic() %s\n", toChars());
1747 Type n
= mtype
.next
.typeSemantic(loc
, sc
);
1748 switch (n
.toBasetype().ty
)
1751 .error(loc
, "cannot have pointer to `%s`", n
.toChars());
1758 if (n
!= mtype
.next
)
1763 if (mtype
.next
.ty
!= Tfunction
)
1766 return merge(mtype
);
1770 return merge(mtype
);
1774 mtype
.deco
= merge(mtype
).deco
;
1775 /* Don't return merge(), because arg identifiers and default args
1777 * even though the types match
1783 Type
visitReference(TypeReference mtype
)
1785 //printf("TypeReference::semantic()\n");
1786 Type n
= mtype
.next
.typeSemantic(loc
, sc
);
1787 if (n
!= mtype
.next
)
1791 return merge(mtype
);
1794 Type
visitFunction(TypeFunction mtype
)
1796 if (mtype
.deco
) // if semantic() already run
1798 //printf("already done\n");
1801 //printf("TypeFunction::semantic() this = %p\n", mtype);
1802 //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
1804 bool errors
= false;
1806 if (mtype
.inuse
> global
.recursionLimit
)
1809 .error(loc
, "recursive type");
1813 /* Copy in order to not mess up original.
1814 * This can produce redundant copies if inferring return type,
1815 * as semantic() will get called again on this.
1817 TypeFunction tf
= mtype
.copy().toTypeFunction();
1818 if (mtype
.parameterList
.parameters
)
1820 tf
.parameterList
.parameters
= mtype
.parameterList
.parameters
.copy();
1821 for (size_t i
= 0; i
< mtype
.parameterList
.parameters
.length
; i
++)
1823 Parameter p
= cast(Parameter
)mem
.xmalloc(__traits(classInstanceSize
, Parameter
));
1824 memcpy(cast(void*)p
, cast(void*)(*mtype
.parameterList
.parameters
)[i
], __traits(classInstanceSize
, Parameter
));
1825 (*tf
.parameterList
.parameters
)[i
] = p
;
1829 if (sc
.stc & STC
.pure_
)
1830 tf
.purity
= PURE
.fwdref
;
1831 if (sc
.stc & STC
.nothrow_
)
1832 tf
.isnothrow
= true;
1833 if (sc
.stc & STC
.nogc
)
1835 if (sc
.stc & STC
.ref_
)
1837 if (sc
.stc & STC
.return_
)
1839 if (sc
.stc & STC
.returnScope
)
1840 tf
.isreturnscope
= true;
1841 if (sc
.stc & STC
.returninferred
)
1842 tf
.isreturninferred
= true;
1843 if (sc
.stc & STC
.scope_
)
1844 tf
.isScopeQual
= true;
1845 if (sc
.stc & STC
.scopeinferred
)
1846 tf
.isscopeinferred
= true;
1848 // if (tf.isreturn && !tf.isref)
1849 // tf.isScopeQual = true; // return by itself means 'return scope'
1851 if (tf
.trust
== TRUST
.default_
)
1853 if (sc
.stc & STC
.safe
)
1854 tf
.trust
= TRUST
.safe
;
1855 else if (sc
.stc & STC
.system
)
1856 tf
.trust
= TRUST
.system
;
1857 else if (sc
.stc & STC
.trusted
)
1858 tf
.trust
= TRUST
.trusted
;
1861 if (sc
.stc & STC
.property
)
1862 tf
.isproperty
= true;
1863 if (sc
.stc & STC
.live
)
1866 tf
.linkage
= sc
.linkage
;
1867 if (tf
.linkage
== LINK
.system
)
1868 tf
.linkage
= target
.systemLinkage();
1872 /* If the parent is @safe, then this function defaults to safe
1874 * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1875 * to be inferred first.
1877 if (tf
.trust
== TRUST
.default_
)
1878 for (Dsymbol p
= sc
.func
; p
; p
= p
.toParent2())
1880 FuncDeclaration fd
= p
.isFuncDeclaration();
1883 if (fd
.isSafeBypassingInference())
1884 tf
.trust
= TRUST
.safe
; // default to @safe
1890 bool wildreturn
= false;
1894 sc
.stc &= ~(STC
.TYPECTOR | STC
.FUNCATTR
);
1895 tf
.next
= tf
.next
.typeSemantic(loc
, sc
);
1897 errors |
= tf
.checkRetType(loc
);
1898 if (tf
.next
.isscope() && !tf
.isctor
)
1900 .error(loc
, "functions cannot return `scope %s`", tf
.next
.toChars());
1903 if (tf
.next
.hasWild())
1906 if (tf
.isreturn
&& !tf
.isref
&& !tf
.next
.hasPointers())
1908 tf
.isreturn
= false;
1912 /// Perform semantic on the default argument to a parameter
1913 /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1914 /// Returns `false` whether an error was encountered.
1915 static bool defaultArgSemantic (ref Parameter fparam
, Scope
* sc
)
1917 Expression e
= fparam
.defaultArg
;
1918 const isRefOrOut
= fparam
.isReference();
1919 const isAuto
= fparam
.storageClass
& (STC
.auto_ | STC
.autoref
);
1920 if (isRefOrOut
&& !isAuto
)
1922 e
= e
.expressionSemantic(sc
);
1923 e
= resolveProperties(sc
, e
);
1927 e
= inferType(e
, fparam
.type
);
1928 Scope
* sc2
= sc
.push();
1929 sc2
.inDefaultArg
= true;
1930 Initializer iz
= new ExpInitializer(e
.loc
, e
);
1931 iz
= iz
.initializerSemantic(sc2
, fparam
.type
, INITnointerpret
);
1932 e
= iz
.initializerToExpression();
1935 if (e
.op
== EXP
.function_
) // https://issues.dlang.org/show_bug.cgi?id=4820
1937 FuncExp fe
= e
.isFuncExp();
1938 // Replace function literal with a function symbol,
1939 // since default arg expression must be copied when used
1940 // and copying the literal itself is wrong.
1941 e
= new VarExp(e
.loc
, fe
.fd
, false);
1942 e
= new AddrExp(e
.loc
, e
);
1943 e
= e
.expressionSemantic(sc
);
1945 if (isRefOrOut
&& (!isAuto || e
.isLvalue())
1946 && !MODimplicitConv(e
.type
.mod
, fparam
.type
.mod
))
1948 const(char)* errTxt
= fparam
.storageClass
& STC
.ref_ ?
"ref" : "out";
1949 .error(e
.loc
, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1950 e
.toChars(), e
.type
.toChars(), errTxt
, fparam
.type
.toChars(), fparam
.toChars());
1952 e
= e
.implicitCastTo(sc
, fparam
.type
);
1954 // default arg must be an lvalue
1955 if (isRefOrOut
&& !isAuto
&&
1956 !(fparam
.storageClass
& STC
.constscoperef
) &&
1957 global
.params
.rvalueRefParam
!= FeatureState
.enabled
)
1958 e
= e
.toLvalue(sc
, "create default argument for `ref` / `out` parameter from");
1960 fparam
.defaultArg
= e
;
1961 return (e
.op
!= EXP
.error
);
1964 ubyte wildparams
= 0;
1965 if (tf
.parameterList
.parameters
)
1967 /* Create a scope for evaluating the default arguments for the parameters
1969 Scope
* argsc
= sc
.push();
1970 argsc
.stc = 0; // don't inherit storage class
1971 argsc
.visibility
= Visibility(Visibility
.Kind
.public_
);
1974 size_t dim
= tf
.parameterList
.length
;
1975 for (size_t i
= 0; i
< dim
; i
++)
1977 Parameter fparam
= tf
.parameterList
[i
];
1978 fparam
.storageClass |
= STC
.parameter
;
1980 fparam
.type
= fparam
.type
.typeSemantic(loc
, argsc
);
1983 if (fparam
.type
.ty
== Terror
)
1989 fparam
.type
= fparam
.type
.addStorageClass(fparam
.storageClass
);
1991 if (fparam
.storageClass
& (STC
.auto_ | STC
.alias_ | STC
.static_
))
1997 fparam
.type
= fparam
.type
.cAdjustParamType(sc
); // adjust C array and function parameter types
1999 Type t
= fparam
.type
.toBasetype();
2001 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
2004 if (auto tt
= t
.isTypeTuple())
2006 /* TypeFunction::parameter also is used as the storage of
2007 * Parameter objects for FuncDeclaration. So we should copy
2008 * the elements of TypeTuple::arguments to avoid unintended
2009 * sharing of Parameter object among other functions.
2011 if (tt
.arguments
&& tt
.arguments
.length
)
2013 /* Propagate additional storage class from tuple parameters to their
2014 * element-parameters.
2015 * Make a copy, as original may be referenced elsewhere.
2017 size_t tdim
= tt
.arguments
.length
;
2018 auto newparams
= new Parameters(tdim
);
2019 for (size_t j
= 0; j
< tdim
; j
++)
2021 Parameter narg
= (*tt
.arguments
)[j
];
2023 // https://issues.dlang.org/show_bug.cgi?id=12744
2024 // If the storage classes of narg
2025 // conflict with the ones in fparam, it's ignored.
2026 StorageClass
stc = fparam
.storageClass | narg
.storageClass
;
2027 StorageClass stc1
= fparam
.storageClass
& (STC
.ref_ | STC
.out_ | STC
.lazy_
);
2028 StorageClass stc2
= narg
.storageClass
& (STC
.ref_ | STC
.out_ | STC
.lazy_
);
2029 if (stc1
&& stc2
&& stc1
!= stc2
)
2031 OutBuffer buf1
; stcToBuffer(buf1
, stc1 |
((stc1
& STC
.ref_
) ?
(fparam
.storageClass
& STC
.auto_
) : 0));
2032 OutBuffer buf2
; stcToBuffer(buf2
, stc2
);
2034 .error(loc
, "incompatible parameter storage classes `%s` and `%s`",
2035 buf1
.peekChars(), buf2
.peekChars());
2037 stc = stc1 |
(stc & ~(STC
.ref_ | STC
.out_ | STC
.lazy_
));
2039 (*newparams
)[j
] = new Parameter(
2040 loc
, stc, narg
.type
, narg
.ident
, narg
.defaultArg
, narg
.userAttribDecl
);
2042 fparam
.type
= new TypeTuple(newparams
);
2043 fparam
.type
= fparam
.type
.typeSemantic(loc
, argsc
);
2045 fparam
.storageClass
= STC
.parameter
;
2047 /* Reset number of parameters, and back up one to do this fparam again,
2048 * now that it is a tuple
2050 dim
= tf
.parameterList
.length
;
2055 // -preview=in: Always add `ref` when used with `extern(C++)` functions
2056 // Done here to allow passing opaque types with `in`
2057 if ((fparam
.storageClass
& (STC
.in_ | STC
.ref_
)) == STC
.in_
)
2062 if (fparam
.storageClass
& STC
.constscoperef
)
2063 fparam
.storageClass |
= STC
.ref_
;
2065 case LINK
.default_
, LINK
.d
:
2068 if (fparam
.storageClass
& STC
.constscoperef
)
2070 .error(loc
, "cannot use `in` parameters with `extern(%s)` functions",
2071 linkageToChars(tf
.linkage
));
2072 .errorSupplemental(loc
, "parameter `%s` declared as `in` here", fparam
.toChars());
2076 // Note that this deprecation will not trigger on `in ref` / `ref in`
2077 // parameters, however the parser will trigger a deprecation on them.
2078 .deprecation(loc
, "using `in` parameters with `extern(%s)` functions is deprecated",
2079 linkageToChars(tf
.linkage
));
2080 .deprecationSupplemental(loc
, "parameter `%s` declared as `in` here", fparam
.toChars());
2086 if (t
.ty
== Tfunction
)
2088 .error(loc
, "cannot have parameter of function type `%s`", fparam
.type
.toChars());
2091 else if (!fparam
.isReference() &&
2092 (t
.ty
== Tstruct || t
.ty
== Tsarray || t
.ty
== Tenum
))
2094 Type tb2
= t
.baseElemOf();
2095 if (tb2
.ty
== Tstruct
&& !tb2
.isTypeStruct().sym
.members ||
2096 tb2
.ty
== Tenum
&& !tb2
.isTypeEnum().sym
.memtype
)
2098 if (fparam
.storageClass
& STC
.constscoperef
)
2100 .error(loc
, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
2101 fparam
.toChars(), fparam
.type
.toChars());
2104 .error(loc
, "cannot have parameter of opaque type `%s` by value",
2105 fparam
.type
.toChars());
2109 else if (!fparam
.isLazy() && t
.ty
== Tvoid
)
2111 .error(loc
, "cannot have parameter of type `%s`", fparam
.type
.toChars());
2115 const bool isTypesafeVariadic
= i
+ 1 == dim
&&
2116 tf
.parameterList
.varargs
== VarArg
.typesafe
&&
2117 (t
.isTypeDArray() || t
.isTypeClass());
2118 if (isTypesafeVariadic
)
2120 /* typesafe variadic arguments are constructed on the stack, so must be `scope`
2122 fparam
.storageClass |
= STC
.scope_ | STC
.scopeinferred
;
2125 if (fparam
.storageClass
& STC
.return_
)
2127 if (!fparam
.isReference())
2129 if (!(fparam
.storageClass
& STC
.scope_
))
2130 fparam
.storageClass |
= STC
.scope_ | STC
.scopeinferred
; // 'return' implies 'scope'
2134 else if (tf
.next
&& !tf
.next
.hasPointers() && tf
.next
.toBasetype().ty
!= Tvoid
)
2136 fparam
.storageClass
&= ~STC
.return_
; // https://issues.dlang.org/show_bug.cgi?id=18963
2140 if (isTypesafeVariadic
)
2142 /* This is because they can be constructed on the stack
2143 * https://dlang.org/spec/function.html#typesafe_variadic_functions
2145 .error(loc
, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
2146 fparam
.ident ? fparam
.ident
.toChars() : "", t
.toChars());
2151 if (fparam
.storageClass
& STC
.out_
)
2153 if (ubyte m
= fparam
.type
.mod
& (MODFlags
.immutable_ | MODFlags
.const_ | MODFlags
.wild
))
2155 .error(loc
, "cannot have `%s out` parameter of type `%s`", MODtoChars(m
), t
.toChars());
2160 Type tv
= t
.baseElemOf();
2161 if (tv
.ty
== Tstruct
&& tv
.isTypeStruct().sym
.noDefaultCtor
)
2163 .error(loc
, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam
.type
.toChars());
2172 //if (tf.next && !wildreturn)
2173 // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
2176 // Remove redundant storage classes for type, they are already applied
2177 fparam
.storageClass
&= ~(STC
.TYPECTOR
);
2179 // -preview=in: add `ref` storage class to suited `in` params
2180 if ((fparam
.storageClass
& (STC
.constscoperef | STC
.ref_
)) == STC
.constscoperef
)
2182 auto ts
= t
.baseElemOf().isTypeStruct();
2183 const isPOD
= !ts || ts
.sym
.isPOD();
2184 if (!isPOD || target
.preferPassByRef(t
))
2185 fparam
.storageClass |
= STC
.ref_
;
2189 // Now that we completed semantic for the argument types,
2190 // run semantic on their default values,
2191 // bearing in mind tuples have been expanded.
2192 // We need to keep a pair of [oidx, eidx] (original index,
2193 // extended index), as we need to run semantic when `oidx` changes.
2194 size_t tupleOrigIdx
= size_t
.max
;
2195 size_t tupleExtIdx
= size_t
.max
;
2196 foreach (oidx
, oparam
, eidx
, eparam
; tf
.parameterList
)
2198 // oparam (original param) will always have the default arg
2199 // if there's one, but `eparam` will not if it's an expanded
2200 // tuple. When we see an expanded tuple, we need to save its
2201 // position to get the offset in it later on.
2202 if (oparam
.defaultArg
)
2204 // Get the obvious case out of the way
2205 if (oparam
is eparam
)
2206 errors |
= !defaultArgSemantic(eparam
, argsc
);
2207 // We're seeing a new tuple
2208 else if (tupleOrigIdx
== size_t
.max || tupleOrigIdx
< oidx
)
2210 /* https://issues.dlang.org/show_bug.cgi?id=18572
2212 * If a tuple parameter has a default argument, when expanding the parameter
2213 * tuple the default argument tuple must also be expanded.
2215 tupleOrigIdx
= oidx
;
2217 errors |
= !defaultArgSemantic(oparam
, argsc
);
2218 TupleExp te
= oparam
.defaultArg
.isTupleExp();
2219 if (te
&& te
.exps
&& te
.exps
.length
)
2220 eparam
.defaultArg
= (*te
.exps
)[0];
2222 // Processing an already-seen tuple
2225 TupleExp te
= oparam
.defaultArg
.isTupleExp();
2226 if (te
&& te
.exps
&& te
.exps
.length
)
2227 eparam
.defaultArg
= (*te
.exps
)[eidx
- tupleExtIdx
];
2231 // We need to know the default argument to resolve `auto ref`,
2232 // hence why this has to take place as the very last step.
2233 /* Resolve "auto ref" storage class to be either ref or value,
2234 * based on the argument matching the parameter
2236 if (eparam
.storageClass
& STC
.auto_
)
2238 Expression farg
= mtype
.fargs
&& eidx
< mtype
.fargs
.length ?
2239 (*mtype
.fargs
)[eidx
] : eparam
.defaultArg
;
2240 if (farg
&& (eparam
.storageClass
& STC
.ref_
))
2242 if (!farg
.isLvalue())
2243 eparam
.storageClass
&= ~STC
.ref_
; // value parameter
2244 eparam
.storageClass
&= ~STC
.auto_
; // https://issues.dlang.org/show_bug.cgi?id=14656
2245 eparam
.storageClass |
= STC
.autoref
;
2247 else if (mtype
.incomplete
&& (eparam
.storageClass
& STC
.ref_
))
2249 // the default argument may have been temporarily removed,
2250 // see usage of `TypeFunction.incomplete`.
2251 // https://issues.dlang.org/show_bug.cgi?id=19891
2252 eparam
.storageClass
&= ~STC
.auto_
;
2253 eparam
.storageClass |
= STC
.autoref
;
2255 else if (eparam
.storageClass
& STC
.ref_
)
2257 .error(loc
, "cannot explicitly instantiate template function with `auto ref` parameter");
2262 .error(loc
, "`auto` can only be used as part of `auto ref` for template function parameters");
2273 if (wildreturn
&& !wildparams
)
2275 .error(loc
, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype
.toChars());
2278 tf
.isInOutParam
= (wildparams
& 1) != 0;
2279 tf
.isInOutQual
= (wildparams
& 2) != 0;
2281 if (tf
.isproperty
&& (tf
.parameterList
.varargs
!= VarArg
.none || tf
.parameterList
.length
> 2))
2283 .error(loc
, "properties can only have zero, one, or two parameter");
2287 if (tf
.parameterList
.varargs
== VarArg
.variadic
&& tf
.linkage
!= LINK
.d
&& tf
.parameterList
.length
== 0 &&
2288 !(sc
.flags
& SCOPE
.Cfile
))
2290 .error(loc
, "variadic functions with non-D linkage must have at least one parameter");
2298 tf
.deco
= tf
.merge().deco
;
2300 /* Don't return merge(), because arg identifiers and default args
2302 * even though the types match
2307 Type
visitDelegate(TypeDelegate mtype
)
2309 //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
2310 if (mtype
.deco
) // if semantic() already run
2312 //printf("already done\n");
2315 mtype
.next
= mtype
.next
.typeSemantic(loc
, sc
);
2316 if (mtype
.next
.ty
!= Tfunction
)
2319 /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
2320 * perhaps default arguments should
2321 * be removed from next before the merge.
2325 return mtype
.merge();
2329 /* Don't return merge(), because arg identifiers and default args
2331 * even though the types match
2333 mtype
.deco
= mtype
.merge().deco
;
2338 Type
visitIdentifier(TypeIdentifier mtype
)
2343 //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
2344 mtype
.resolve(loc
, sc
, e
, t
, s
);
2347 //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
2348 return t
.addMod(mtype
.mod
);
2354 auto td
= s
.isTemplateDeclaration
;
2355 if (td
&& td
.onemember
&& td
.onemember
.isAggregateDeclaration
)
2356 .error(loc
, "template %s `%s` is used as a type without instantiation"
2357 ~ "; to instantiate it use `%s!(arguments)`",
2358 s
.kind
, s
.toPrettyChars
, s
.ident
.toChars
);
2360 .error(loc
, "%s `%s` is used as a type", s
.kind
, s
.toPrettyChars
);
2363 else if (e
.op
== EXP
.variable
) // special case: variable is used as a type
2366 N.B. This branch currently triggers for the following code
2371 i.e. the compiler prints "variable x is used as a type"
2372 which isn't a particularly good error message (x is a variable?).
2374 Dsymbol varDecl
= mtype
.toDsymbol(sc
);
2375 const(Loc
) varDeclLoc
= varDecl
.getLoc();
2376 Module varDeclModule
= varDecl
.getModule(); //This can be null
2378 .error(loc
, "variable `%s` is used as a type", mtype
.toChars());
2379 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
2380 if ((varDeclModule
!is null) && varDeclModule
!= sc
._module
) // variable is imported
2382 const(Loc
) varDeclModuleImportLoc
= varDeclModule
.getLoc();
2384 varDeclModuleImportLoc
,
2385 "variable `%s` is imported here from: `%s`",
2387 varDeclModule
.toPrettyChars
,
2391 .errorSupplemental(varDeclLoc
, "variable `%s` is declared here", varDecl
.toChars
);
2394 .error(loc
, "`%s` is used as a type", mtype
.toChars());
2399 Type
visitInstance(TypeInstance mtype
)
2405 //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
2407 const errors
= global
.errors
;
2408 mtype
.resolve(loc
, sc
, e
, t
, s
);
2409 // if we had an error evaluating the symbol, suppress further errors
2410 if (!t
&& errors
!= global
.errors
)
2416 if (!e
&& s
&& s
.errors
)
2418 // if there was an error evaluating the symbol, it might actually
2419 // be a type. Avoid misleading error messages.
2420 .error(loc
, "`%s` had previous errors", mtype
.toChars());
2423 .error(loc
, "`%s` is used as a type", mtype
.toChars());
2429 Type
visitTypeof(TypeTypeof mtype
)
2431 //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
2435 mtype
.resolve(loc
, sc
, e
, t
, s
);
2436 if (s
&& (t
= s
.getType()) !is null)
2437 t
= t
.addMod(mtype
.mod
);
2440 .error(loc
, "`%s` is used as a type", mtype
.toChars());
2446 Type
visitTraits(TypeTraits mtype
)
2451 mtype
.resolve(loc
, sc
, e
, t
, s
);
2456 .error(mtype
.loc
, "`%s` does not give a valid type", mtype
.toChars
);
2462 Type
visitReturn(TypeReturn mtype
)
2464 //printf("TypeReturn::semantic() %s\n", toChars());
2468 mtype
.resolve(loc
, sc
, e
, t
, s
);
2469 if (s
&& (t
= s
.getType()) !is null)
2470 t
= t
.addMod(mtype
.mod
);
2473 .error(loc
, "`%s` is used as a type", mtype
.toChars());
2479 Type
visitStruct(TypeStruct mtype
)
2481 //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
2485 /* Don't semantic for sym because it should be deferred until
2486 * sizeof needed or its members accessed.
2488 // instead, parent should be set correctly
2489 assert(mtype
.sym
.parent
);
2491 if (mtype
.sym
.type
.ty
== Terror
)
2494 return merge(mtype
);
2497 Type
visitEnum(TypeEnum mtype
)
2499 //printf("TypeEnum::semantic() %s\n", toChars());
2500 return mtype
.deco ? mtype
: merge(mtype
);
2503 Type
visitClass(TypeClass mtype
)
2505 //printf("TypeClass::semantic(%s)\n", mtype.toChars());
2509 /* Don't semantic for sym because it should be deferred until
2510 * sizeof needed or its members accessed.
2512 // instead, parent should be set correctly
2513 assert(mtype
.sym
.parent
);
2515 if (mtype
.sym
.type
.ty
== Terror
)
2518 return merge(mtype
);
2521 Type
visitTuple(TypeTuple mtype
)
2523 //printf("TypeTuple::semantic(this = %p)\n", this);
2524 //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
2526 mtype
.deco
= merge(mtype
).deco
;
2528 /* Don't return merge(), because a tuple with one type has the
2529 * same deco as that type.
2534 Type
visitSlice(TypeSlice mtype
)
2536 //printf("TypeSlice::semantic() %s\n", toChars());
2537 Type tn
= mtype
.next
.typeSemantic(loc
, sc
);
2538 //printf("next: %s\n", tn.toChars());
2540 Type tbn
= tn
.toBasetype();
2541 if (tbn
.ty
!= Ttuple
)
2543 .error(loc
, "can only slice type sequences, not `%s`", tbn
.toChars());
2546 TypeTuple tt
= cast(TypeTuple
)tbn
;
2548 mtype
.lwr
= semanticLength(sc
, tbn
, mtype
.lwr
);
2549 mtype
.upr
= semanticLength(sc
, tbn
, mtype
.upr
);
2550 mtype
.lwr
= mtype
.lwr
.ctfeInterpret();
2551 mtype
.upr
= mtype
.upr
.ctfeInterpret();
2552 if (mtype
.lwr
.op
== EXP
.error || mtype
.upr
.op
== EXP
.error
)
2555 uinteger_t i1
= mtype
.lwr
.toUInteger();
2556 uinteger_t i2
= mtype
.upr
.toUInteger();
2557 if (!(i1
<= i2
&& i2
<= tt
.arguments
.length
))
2559 .error(loc
, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
2560 cast(ulong)i1
, cast(ulong)i2
, cast(ulong)tt
.arguments
.length
);
2567 auto args
= new Parameters();
2568 args
.reserve(cast(size_t
)(i2
- i1
));
2569 foreach (arg
; (*tt
.arguments
)[cast(size_t
)i1
.. cast(size_t
)i2
])
2573 Type t
= new TypeTuple(args
);
2574 return t
.typeSemantic(loc
, sc
);
2577 Type
visitMixin(TypeMixin mtype
)
2579 //printf("TypeMixin::semantic() %s\n", toChars());
2584 mtype
.resolve(loc
, sc
, e
, t
, s
);
2586 if (t
&& t
.ty
!= Terror
)
2589 .error(mtype
.loc
, "`mixin(%s)` does not give a valid type", mtype
.obj
.toChars
);
2593 Type
visitTag(TypeTag mtype
)
2595 //printf("TypeTag.semantic() %s\n", mtype.toChars());
2596 Type
returnType(Type t
)
2598 return t
.deco ? t
: t
.merge();
2605 return returnType(mtype
.resolved
.addSTC(mtype
.mod
));
2608 /* Find the current scope by skipping tag scopes.
2609 * In C, tag scopes aren't considered scopes.
2615 auto scopesym
= sc2
.scopesym
;
2616 if (scopesym
.isStructDeclaration())
2618 sc2
= sc2
.enclosing
;
2624 /* Declare mtype as a struct/union/enum declaration
2628 void declare(ScopeDsymbol sd
)
2630 sd
.members
= mtype
.members
;
2631 auto scopesym
= sc2
.inner().scopesym
;
2632 if (scopesym
.members
)
2633 scopesym
.members
.push(sd
);
2634 if (scopesym
.symtab
&& !scopesym
.symtabInsert(sd
))
2636 Dsymbol s2
= scopesym
.symtabLookup(sd
, mtype
.id
);
2637 handleTagSymbols(*sc2
, sd
, s2
, scopesym
);
2639 sd
.parent
= sc2
.parent
;
2640 sd
.dsymbolSemantic(sc2
);
2646 auto ed
= new EnumDeclaration(mtype
.loc
, mtype
.id
, mtype
.base
);
2648 mtype
.resolved
= visitEnum(new TypeEnum(ed
));
2652 auto sd
= new StructDeclaration(mtype
.loc
, mtype
.id
, false);
2653 sd
.alignment
= mtype
.packalign
;
2655 mtype
.resolved
= visitStruct(new TypeStruct(sd
));
2659 auto ud
= new UnionDeclaration(mtype
.loc
, mtype
.id
);
2660 ud
.alignment
= mtype
.packalign
;
2662 mtype
.resolved
= visitStruct(new TypeStruct(ud
));
2670 /* If it doesn't have a tag by now, supply one.
2671 * It'll be unique, and therefore introducing.
2672 * Declare it, and done.
2676 mtype
.id
= Identifier
.generateId("__tag"[]);
2678 return returnType(mtype
.resolved
.addSTC(mtype
.mod
));
2681 /* look for pre-existing declaration
2684 auto s
= sc2
.search(mtype
.loc
, mtype
.id
, scopesym
, SearchOpt
.ignoreErrors | SearchOpt
.tagNameSpace
);
2685 if (!s || s
.isModule())
2687 // no pre-existing declaration, so declare it
2688 if (mtype
.tok
== TOK
.enum_
&& !mtype
.members
)
2689 .error(mtype
.loc
, "`enum %s` is incomplete without members", mtype
.id
.toChars()); // C11 6.7.2.3-3
2691 return returnType(mtype
.resolved
.addSTC(mtype
.mod
));
2694 /* A redeclaration only happens if both declarations are in
2697 const bool redeclar
= (scopesym
== sc2
.inner().scopesym
);
2701 if (mtype
.tok
== TOK
.enum_
&& s
.isEnumDeclaration())
2703 auto ed
= s
.isEnumDeclaration();
2704 if (mtype
.members
&& ed
.members
)
2705 .error(mtype
.loc
, "`%s` already has members", mtype
.id
.toChars());
2706 else if (!ed
.members
)
2708 ed
.members
= mtype
.members
;
2713 mtype
.resolved
= ed
.type
;
2715 else if (mtype
.tok
== TOK
.union_
&& s
.isUnionDeclaration() ||
2716 mtype
.tok
== TOK
.struct_
&& s
.isStructDeclaration())
2718 // Add members to original declaration
2719 auto sd
= s
.isStructDeclaration();
2720 if (mtype
.members
&& sd
.members
)
2722 /* struct S { int b; };
2723 * struct S { int a; } *s;
2725 .error(mtype
.loc
, "`%s` already has members", mtype
.id
.toChars());
2727 else if (!sd
.members
)
2730 * struct S { int a; } *s;
2732 sd
.members
= mtype
.members
;
2733 if (sd
.semanticRun
== PASS
.semanticdone
)
2735 /* The first semantic pass marked `sd` as an opaque struct.
2736 * Re-run semantic so that all newly assigned members are
2737 * picked up and added to the symtab.
2739 sd
.semanticRun
= PASS
.semantic
;
2740 sd
.dsymbolSemantic(sc2
);
2745 /* struct S { int a; };
2749 mtype
.resolved
= sd
.type
;
2754 * struct S { int a; } *s;
2756 .error(mtype
.loc
, "redeclaration of `%s`", mtype
.id
.toChars());
2757 mtype
.resolved
= error();
2760 else if (mtype
.members
)
2763 * { struct S { int a; } *s; }
2769 if (mtype
.tok
== TOK
.enum_
&& s
.isEnumDeclaration())
2771 mtype
.resolved
= s
.isEnumDeclaration().type
;
2773 else if (mtype
.tok
== TOK
.union_
&& s
.isUnionDeclaration() ||
2774 mtype
.tok
== TOK
.struct_
&& s
.isStructDeclaration())
2779 mtype
.resolved
= s
.isStructDeclaration().type
;
2786 .error(mtype
.loc
, "redeclaring `%s %s` as `%s %s`",
2787 s
.kind(), s
.toChars(), Token
.toChars(mtype
.tok
), mtype
.id
.toChars());
2791 return returnType(mtype
.resolved
.addSTC(mtype
.mod
));
2796 default: return visitType(type
);
2799 case Tcomplex80
: return visitComplex(type
.isTypeBasic());
2800 case Tvector
: return visitVector(type
.isTypeVector());
2801 case Tsarray
: return visitSArray(type
.isTypeSArray());
2802 case Tarray
: return visitDArray(type
.isTypeDArray());
2803 case Taarray
: return visitAArray(type
.isTypeAArray());
2804 case Tpointer
: return visitPointer(type
.isTypePointer());
2805 case Treference
: return visitReference(type
.isTypeReference());
2806 case Tfunction
: return visitFunction(type
.isTypeFunction());
2807 case Tdelegate
: return visitDelegate(type
.isTypeDelegate());
2808 case Tident
: return visitIdentifier(type
.isTypeIdentifier());
2809 case Tinstance
: return visitInstance(type
.isTypeInstance());
2810 case Ttypeof
: return visitTypeof(type
.isTypeTypeof());
2811 case Ttraits
: return visitTraits(type
.isTypeTraits());
2812 case Treturn
: return visitReturn(type
.isTypeReturn());
2813 case Tstruct
: return visitStruct(type
.isTypeStruct());
2814 case Tenum
: return visitEnum(type
.isTypeEnum());
2815 case Tclass
: return visitClass(type
.isTypeClass());
2816 case Ttuple
: return visitTuple(type
.isTypeTuple());
2817 case Tslice
: return visitSlice(type
.isTypeSlice());
2818 case Tmixin
: return visitMixin(type
.isTypeMixin());
2819 case Ttag
: return visitTag(type
.isTypeTag());
2823 extern(C
++) Type
trySemantic(Type type
, const ref Loc loc
, Scope
* sc
)
2825 //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
2827 // Needed to display any deprecations that were gagged
2828 auto tcopy
= type
.syntaxCopy();
2830 const errors
= global
.startGagging();
2831 Type t
= typeSemantic(type
, loc
, sc
);
2832 if (global
.endGagging(errors
) || t
.ty
== Terror
) // if any errors happened
2838 // If `typeSemantic` succeeded, there may have been deprecations that
2839 // were gagged due the `startGagging` above. Run again to display
2840 // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
2841 if (global
.gaggedWarnings
> 0)
2842 typeSemantic(tcopy
, loc
, sc
);
2844 //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
2848 /************************************
2849 * If an identical type to `type` is in `type.stringtable`, return
2850 * the latter one. Otherwise, add it to `type.stringtable`.
2851 * Some types don't get merged and are returned as-is.
2853 * type = Type to check against existing types
2855 * the type that was merged
2857 extern (C
++) Type
merge(Type type
)
2867 return type
; // don't merge placeholder types
2870 // prevents generating the mangle if the array dim is not yet known
2871 if (!type
.isTypeSArray().dim
.isIntegerExp())
2879 if (!type
.isTypeAArray().index
.merge().deco
)
2884 if (type
.nextOf() && !type
.nextOf().deco
)
2889 //printf("merge(%s)\n", toChars());
2895 mangleToBuffer(type
, buf
);
2897 auto sv
= type
.stringtable
.update(buf
[]);
2903 import core
.stdc
.stdio
;
2905 printf("t = %s\n", t
.toChars());
2908 //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2913 Type t
= stripDefaultArgs(type
);
2915 type
.deco
= t
.deco
= cast(char*)sv
.toDchars();
2916 //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2923 /*************************************
2924 * This version does a merge even if the deco is already computed.
2925 * Necessary for types that have a deco, but are not merged.
2927 extern(C
++) Type
merge2(Type type
)
2929 //printf("merge2(%s)\n", toChars());
2935 auto sv
= Type
.stringtable
.lookup(t
.deco
, strlen(t
.deco
));
2946 /***************************************
2947 * Calculate built-in properties which just the type is necessary.
2950 * t = the type for which the property is calculated
2951 * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2952 * loc = the location where the property is encountered
2953 * ident = the identifier of the property
2954 * flag = if flag & 1, don't report "not a property" error and just return NULL.
2955 * src = expression for type `t` or null.
2957 * expression representing the property, or null if not a property and (flag & 1)
2959 Expression
getProperty(Type t
, Scope
* scope_
, const ref Loc loc
, Identifier ident
, int flag
,
2960 Expression src
= null)
2962 Expression
visitType(Type mt
)
2965 static if (LOGDOTEXP
)
2967 printf("Type::getProperty(type = '%s', ident = '%s')\n", mt
.toChars(), ident
.toChars());
2969 if (ident
== Id
.__sizeof
)
2971 const sz
= mt
.size(loc
);
2972 if (sz
== SIZE_INVALID
)
2973 return ErrorExp
.get();
2974 e
= new IntegerExp(loc
, sz
, Type
.tsize_t
);
2976 else if (ident
== Id
.__xalignof
)
2978 const explicitAlignment
= mt
.alignment();
2979 const naturalAlignment
= mt
.alignsize();
2980 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
2981 e
= new IntegerExp(loc
, actualAlignment
, Type
.tsize_t
);
2983 else if (ident
== Id
._init
)
2985 Type tb
= mt
.toBasetype();
2986 e
= mt
.defaultInitLiteral(loc
);
2987 if (tb
.ty
== Tstruct
&& tb
.needsNested())
2989 e
.isStructLiteralExp().useStaticInit
= true;
2992 else if (ident
== Id
._mangleof
)
2996 error(loc
, "forward reference of type `%s.mangleof`", mt
.toChars());
3001 e
= new StringExp(loc
, mt
.deco
.toDString());
3003 sc
.eSink
= global
.errorSink
;
3004 e
= e
.expressionSemantic(&sc
);
3007 else if (ident
== Id
.stringof
)
3009 const s
= mt
.toChars();
3010 e
= new StringExp(loc
, s
.toDString());
3012 sc
.eSink
= global
.errorSink
;
3013 e
= e
.expressionSemantic(&sc
);
3015 else if (flag
&& mt
!= Type
.terror
)
3022 if (mt
.ty
== Tstruct || mt
.ty
== Tclass || mt
.ty
== Tenum
)
3023 s
= mt
.toDsymbol(null);
3025 s
= s
.search_correct(ident
);
3026 if (s
&& !symbolIsVisible(scope_
, s
))
3028 if (mt
!= Type
.terror
)
3031 error(loc
, "no property `%s` for type `%s`, did you mean `%s`?", ident
.toChars(), mt
.toChars(), s
.toPrettyChars());
3032 else if (ident
== Id
.call && mt
.ty
== Tclass
)
3033 error(loc
, "no property `%s` for type `%s`, did you mean `new %s`?", ident
.toChars(), mt
.toChars(), mt
.toPrettyChars());
3035 else if (const n
= importHint(ident
.toString()))
3036 error(loc
, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident
.toChars(), mt
.toChars(), cast(int)n
.length
, n
.ptr
);
3040 error(loc
, "no property `%s` for `%s` of type `%s`", ident
.toChars(), src
.toChars(), mt
.toPrettyChars(true));
3042 error(loc
, "no property `%s` for type `%s`", ident
.toChars(), mt
.toPrettyChars(true));
3044 if (auto dsym
= mt
.toDsymbol(scope_
))
3046 if (auto sym
= dsym
.isAggregateDeclaration())
3048 if (auto fd
= search_function(sym
, Id
.opDispatch
))
3049 errorSupplemental(loc
, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
3050 else if (!sym
.members
)
3051 errorSupplemental(sym
.loc
, "`%s %s` is opaque and has no members.", sym
.kind
, mt
.toPrettyChars(true));
3053 errorSupplemental(dsym
.loc
, "%s `%s` defined here",
3054 dsym
.kind
, dsym
.toChars());
3063 Expression
visitError(TypeError
)
3065 return ErrorExp
.get();
3068 Expression
visitBasic(TypeBasic mt
)
3070 Expression
integerValue(dinteger_t i
)
3072 return new IntegerExp(loc
, i
, mt
);
3075 Expression
intValue(dinteger_t i
)
3077 return new IntegerExp(loc
, i
, Type
.tint32
);
3080 Expression
floatValue(real_t r
)
3082 if (mt
.isreal() || mt
.isimaginary())
3083 return new RealExp(loc
, r
, mt
);
3086 return new ComplexExp(loc
, complex_t(r
, r
), mt
);
3090 //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
3091 if (ident
== Id
.max
)
3095 case Tint8
: return integerValue(byte.max
);
3096 case Tuns8
: return integerValue(ubyte.max
);
3097 case Tint16
: return integerValue(short.max
);
3098 case Tuns16
: return integerValue(ushort.max
);
3099 case Tint32
: return integerValue(int.max
);
3100 case Tuns32
: return integerValue(uint.max
);
3101 case Tint64
: return integerValue(long.max
);
3102 case Tuns64
: return integerValue(ulong.max
);
3103 case Tbool
: return integerValue(bool.max
);
3104 case Tchar
: return integerValue(char.max
);
3105 case Twchar
: return integerValue(wchar.max
);
3106 case Tdchar
: return integerValue(dchar.max
);
3109 case Tfloat32
: return floatValue(target
.FloatProperties
.max
);
3112 case Tfloat64
: return floatValue(target
.DoubleProperties
.max
);
3115 case Tfloat80
: return floatValue(target
.RealProperties
.max
);
3119 else if (ident
== Id
.min
)
3123 case Tint8
: return integerValue(byte.min
);
3131 case Tdchar
: return integerValue(0);
3132 case Tint16
: return integerValue(short.min
);
3133 case Tint32
: return integerValue(int.min
);
3134 case Tint64
: return integerValue(long.min
);
3138 else if (ident
== Id
.min_normal
)
3144 case Tfloat32
: return floatValue(target
.FloatProperties
.min_normal
);
3147 case Tfloat64
: return floatValue(target
.DoubleProperties
.min_normal
);
3150 case Tfloat80
: return floatValue(target
.RealProperties
.min_normal
);
3154 else if (ident
== Id
.nan
)
3166 case Tfloat80
: return floatValue(target
.RealProperties
.nan
);
3170 else if (ident
== Id
.infinity
)
3182 case Tfloat80
: return floatValue(target
.RealProperties
.infinity
);
3186 else if (ident
== Id
.dig
)
3192 case Tfloat32
: return intValue(target
.FloatProperties
.dig
);
3195 case Tfloat64
: return intValue(target
.DoubleProperties
.dig
);
3198 case Tfloat80
: return intValue(target
.RealProperties
.dig
);
3202 else if (ident
== Id
.epsilon
)
3208 case Tfloat32
: return floatValue(target
.FloatProperties
.epsilon
);
3211 case Tfloat64
: return floatValue(target
.DoubleProperties
.epsilon
);
3214 case Tfloat80
: return floatValue(target
.RealProperties
.epsilon
);
3218 else if (ident
== Id
.mant_dig
)
3224 case Tfloat32
: return intValue(target
.FloatProperties
.mant_dig
);
3227 case Tfloat64
: return intValue(target
.DoubleProperties
.mant_dig
);
3230 case Tfloat80
: return intValue(target
.RealProperties
.mant_dig
);
3234 else if (ident
== Id
.max_10_exp
)
3240 case Tfloat32
: return intValue(target
.FloatProperties
.max_10_exp
);
3243 case Tfloat64
: return intValue(target
.DoubleProperties
.max_10_exp
);
3246 case Tfloat80
: return intValue(target
.RealProperties
.max_10_exp
);
3250 else if (ident
== Id
.max_exp
)
3256 case Tfloat32
: return intValue(target
.FloatProperties
.max_exp
);
3259 case Tfloat64
: return intValue(target
.DoubleProperties
.max_exp
);
3262 case Tfloat80
: return intValue(target
.RealProperties
.max_exp
);
3266 else if (ident
== Id
.min_10_exp
)
3272 case Tfloat32
: return intValue(target
.FloatProperties
.min_10_exp
);
3275 case Tfloat64
: return intValue(target
.DoubleProperties
.min_10_exp
);
3278 case Tfloat80
: return intValue(target
.RealProperties
.min_10_exp
);
3282 else if (ident
== Id
.min_exp
)
3288 case Tfloat32
: return intValue(target
.FloatProperties
.min_exp
);
3291 case Tfloat64
: return intValue(target
.DoubleProperties
.min_exp
);
3294 case Tfloat80
: return intValue(target
.RealProperties
.min_exp
);
3298 return visitType(mt
);
3301 Expression
visitVector(TypeVector mt
)
3303 return visitType(mt
);
3306 Expression
visitEnum(TypeEnum mt
)
3309 if (ident
== Id
.max || ident
== Id
.min
)
3311 return mt
.sym
.getMaxMinValue(loc
, ident
);
3313 else if (ident
== Id
._init
)
3315 e
= mt
.defaultInitLiteral(loc
);
3317 else if (ident
== Id
.stringof
)
3319 e
= new StringExp(loc
, mt
.toString());
3321 e
= e
.expressionSemantic(&sc
);
3323 else if (ident
== Id
._mangleof
)
3329 e
= mt
.toBasetype().getProperty(scope_
, loc
, ident
, flag
);
3334 Expression
visitTuple(TypeTuple mt
)
3337 static if (LOGDOTEXP
)
3339 printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt
.toChars(), ident
.toChars());
3341 if (ident
== Id
.length
)
3343 e
= new IntegerExp(loc
, mt
.arguments
.length
, Type
.tsize_t
);
3345 else if (ident
== Id
._init
)
3347 e
= mt
.defaultInitLiteral(loc
);
3355 error(loc
, "no property `%s` for sequence `%s`", ident
.toChars(), mt
.toChars());
3363 default: return t
.isTypeBasic() ?
3364 visitBasic(cast(TypeBasic
)t
) :
3367 case Terror
: return visitError (t
.isTypeError());
3368 case Tvector
: return visitVector(t
.isTypeVector());
3369 case Tenum
: return visitEnum (t
.isTypeEnum());
3370 case Ttuple
: return visitTuple (t
.isTypeTuple());
3374 /***************************************
3375 * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
3377 * exp = Expression to look at
3378 * t = if exp should be a Type, set t to that Type else null
3379 * s = if exp should be a Dsymbol, set s to that Dsymbol else null
3380 * e = if exp should remain an Expression, set e to that Expression else null
3383 private void resolveExp(Expression exp
, out Type t
, out Expression e
, out Dsymbol s
)
3385 if (exp
.isTypeExp())
3387 else if (auto ve
= exp
.isVarExp())
3389 if (auto v
= ve
.var
.isVarDeclaration())
3394 else if (auto te
= exp
.isTemplateExp())
3396 else if (auto se
= exp
.isScopeExp())
3398 else if (exp
.isFuncExp())
3399 s
= getDsymbol(exp
);
3400 else if (auto dte
= exp
.isDotTemplateExp())
3402 else if (exp
.isErrorExp())
3408 /************************************
3409 * Resolve type 'mt' to either type, symbol, or expression.
3410 * If errors happened, resolved to Type.terror.
3413 * mt = type to be resolved
3414 * loc = the location where the type is encountered
3415 * sc = the scope of the type
3416 * pe = is set if t is an expression
3417 * pt = is set if t is a type
3418 * ps = is set if t is a symbol
3419 * intypeid = true if in type id
3421 void resolve(Type mt
, const ref Loc loc
, Scope
* sc
, out Expression pe
, out Type pt
, out Dsymbol ps
, bool intypeid
= false)
3423 void returnExp(Expression e
)
3430 void returnType(Type t
)
3437 void returnSymbol(Dsymbol s
)
3446 returnType(Type
.terror
);
3449 void visitType(Type mt
)
3451 //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
3452 Type t
= typeSemantic(mt
, loc
, sc
);
3457 void visitSArray(TypeSArray mt
)
3459 //printf("TypeSArray::resolve() %s\n", mt.toChars());
3460 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
3461 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
3464 // It's really an index expression
3465 if (Dsymbol s
= getDsymbol(pe
))
3466 pe
= new DsymbolExp(loc
, s
);
3467 returnExp(new ArrayExp(loc
, pe
, mt
.dim
));
3472 if (auto tup
= s
.isTupleDeclaration())
3474 mt
.dim
= semanticLength(sc
, tup
, mt
.dim
);
3475 mt
.dim
= mt
.dim
.ctfeInterpret();
3476 if (mt
.dim
.op
== EXP
.error
)
3477 return returnError();
3479 const d
= mt
.dim
.toUInteger();
3480 if (d
>= tup
.objects
.length
)
3482 error(loc
, "sequence index `%llu` out of bounds `[0 .. %llu]`", d
, cast(ulong) tup
.objects
.length
);
3483 return returnError();
3486 RootObject o
= (*tup
.objects
)[cast(size_t
)d
];
3487 switch (o
.dyncast()) with (DYNCAST
)
3490 return returnSymbol(cast(Dsymbol
)o
);
3492 Expression e
= cast(Expression
)o
;
3493 if (e
.op
== EXP
.dSymbol
)
3494 return returnSymbol(e
.isDsymbolExp().s
);
3496 return returnExp(e
);
3498 return returnType((cast(Type
)o
).addMod(mt
.mod
));
3503 /* Create a new TupleDeclaration which
3504 * is a slice [d..d+1] out of the old one.
3505 * Do it this way because TemplateInstance::semanticTiargs()
3506 * can handle unresolved Objects this way.
3508 auto objects
= new Objects(1);
3510 return returnSymbol(new TupleDeclaration(loc
, tup
.ident
, objects
));
3513 return visitType(mt
);
3517 if (pt
.ty
!= Terror
)
3518 mt
.next
= pt
; // prevent re-running semantic() on 'next'
3524 void visitDArray(TypeDArray mt
)
3526 //printf("TypeDArray::resolve() %s\n", mt.toChars());
3527 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
3528 //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
3531 // It's really a slice expression
3532 if (Dsymbol s
= getDsymbol(pe
))
3533 pe
= new DsymbolExp(loc
, s
);
3534 returnExp(new ArrayExp(loc
, pe
));
3538 if (auto tup
= ps
.isTupleDeclaration())
3547 if (pt
.ty
!= Terror
)
3548 mt
.next
= pt
; // prevent re-running semantic() on 'next'
3553 void visitAArray(TypeAArray mt
)
3555 //printf("TypeAArray::resolve() %s\n", mt.toChars());
3556 // Deal with the case where we thought the index was a type, but
3557 // in reality it was an expression.
3558 if (mt
.index
.ty
== Tident || mt
.index
.ty
== Tinstance || mt
.index
.ty
== Tsarray
)
3563 mt
.index
.resolve(loc
, sc
, e
, t
, s
, intypeid
);
3566 // It was an expression -
3567 // Rewrite as a static array
3568 auto tsa
= new TypeSArray(mt
.next
, e
);
3569 tsa
.mod
= mt
.mod
; // just copy mod field so tsa's semantic is not yet done
3570 return tsa
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
3575 .error(loc
, "index is not a type or an expression");
3580 /*************************************
3581 * Takes an array of Identifiers and figures out if
3582 * it represents a Type or an Expression.
3584 * if expression, pe is set
3585 * if type, pt is set
3587 void visitIdentifier(TypeIdentifier mt
)
3589 //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3590 if (mt
.ident
== Id
.ctfe
)
3592 error(loc
, "variable `__ctfe` cannot be read at compile time");
3593 return returnError();
3595 if (mt
.ident
== Id
.builtin_va_list
) // gcc has __builtin_va_xxxx for stdarg.h
3597 /* Since we don't support __builtin_va_start, -arg, -end, we don't
3598 * have to actually care what -list is. A void* will do.
3599 * If we ever do care, import core.stdc.stdarg and pull
3600 * the definition out of that, similarly to how std.math is handled for PowExp
3602 pt
= target
.va_listType(loc
, sc
);
3607 Dsymbol s
= sc
.search(loc
, mt
.ident
, scopesym
);
3609 * https://issues.dlang.org/show_bug.cgi?id=1170
3610 * https://issues.dlang.org/show_bug.cgi?id=10739
3612 * If a symbol is not found, it might be declared in
3613 * a mixin-ed string or a mixin-ed template, so before
3614 * issuing an error semantically analyze all string/template
3615 * mixins that are members of the current ScopeDsymbol.
3617 if (!s
&& sc
.enclosing
)
3619 ScopeDsymbol sds
= sc
.enclosing
.scopesym
;
3620 if (sds
&& sds
.members
)
3622 void semanticOnMixin(Dsymbol member
)
3624 if (auto compileDecl
= member
.isMixinDeclaration())
3625 compileDecl
.dsymbolSemantic(sc
);
3626 else if (auto mixinTempl
= member
.isTemplateMixin())
3627 mixinTempl
.dsymbolSemantic(sc
);
3629 sds
.members
.foreachDsymbol( s
=> semanticOnMixin(s
) );
3630 s
= sc
.search(loc
, mt
.ident
, scopesym
);
3636 // https://issues.dlang.org/show_bug.cgi?id=16042
3637 // If `f` is really a function template, then replace `f`
3638 // with the function template declaration.
3639 if (auto f
= s
.isFuncDeclaration())
3641 if (auto td
= getFuncTemplateDecl(f
))
3643 // If not at the beginning of the overloaded list of
3644 // `TemplateDeclaration`s, then get the beginning
3652 mt
.resolveHelper(loc
, sc
, s
, scopesym
, pe
, pt
, ps
, intypeid
);
3654 pt
= pt
.addMod(mt
.mod
);
3657 void visitInstance(TypeInstance mt
)
3659 // Note close similarity to TypeIdentifier::resolve()
3661 //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
3662 mt
.tempinst
.dsymbolSemantic(sc
);
3663 if (!global
.gag
&& mt
.tempinst
.errors
)
3664 return returnError();
3666 mt
.resolveHelper(loc
, sc
, mt
.tempinst
, null, pe
, pt
, ps
, intypeid
);
3668 pt
= pt
.addMod(mt
.mod
);
3669 //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
3672 void visitTypeof(TypeTypeof mt
)
3674 //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
3675 //static int nest; if (++nest == 50) *(char*)0=0;
3678 error(loc
, "invalid scope");
3679 return returnError();
3684 error(loc
, "circular `typeof` definition");
3687 return returnError();
3691 /* Currently we cannot evaluate 'exp' in speculative context, because
3692 * the type implementation may leak to the final execution. Consider:
3695 * string toString() const { return "x"; }
3698 * alias X = typeof(S!int());
3699 * assert(typeid(X).toString() == "x");
3702 Scope
* sc2
= sc
.push();
3704 if (!mt
.exp
.isTypeidExp())
3705 /* Treat typeof(typeid(exp)) as needing
3706 * the full semantic analysis of the typeid.
3707 * https://issues.dlang.org/show_bug.cgi?id=20958
3711 auto exp2
= mt
.exp
.expressionSemantic(sc2
);
3712 exp2
= resolvePropertiesOnly(sc2
, exp2
);
3715 if (exp2
.op
== EXP
.error
)
3723 if ((mt
.exp
.op
== EXP
.type || mt
.exp
.op
== EXP
.scope_
) &&
3724 // https://issues.dlang.org/show_bug.cgi?id=23863
3725 // compile time sequences are valid types
3726 !mt
.exp
.type
.isTypeTuple())
3728 if (!(sc
.flags
& SCOPE
.Cfile
) && // in (extended) C typeof may be used on types as with sizeof
3732 /* Today, 'typeof(func)' returns void if func is a
3733 * function template (TemplateExp), or
3734 * template lambda (FuncExp).
3735 * It's actually used in Phobos as an idiom, to branch code for
3736 * template functions.
3739 if (auto f
= mt
.exp
.op
== EXP
.variable ? mt
.exp
.isVarExp().var
.isFuncDeclaration()
3740 : mt
.exp
.op
== EXP
.dotVariable ? mt
.exp
.isDotVarExp().var
.isFuncDeclaration() : null)
3742 // f might be a unittest declaration which is incomplete when compiled
3743 // without -unittest. That causes a segfault in checkForwardRef, see
3744 // https://issues.dlang.org/show_bug.cgi?id=20626
3745 if ((!f
.isUnitTestDeclaration() || global
.params
.useUnitTests
) && f
.checkForwardRef(loc
))
3748 if (auto f
= isFuncAddress(mt
.exp
))
3750 if (f
.checkForwardRef(loc
))
3754 Type t
= mt
.exp
.type
;
3757 error(loc
, "expression `%s` has no type", mt
.exp
.toChars());
3760 if (t
.ty
== Ttypeof
)
3762 error(loc
, "forward reference to `%s`", mt
.toChars());
3765 if (mt
.idents
.length
== 0)
3767 returnType(t
.addMod(mt
.mod
));
3771 if (Dsymbol s
= t
.toDsymbol(sc
))
3772 mt
.resolveHelper(loc
, sc
, s
, null, pe
, pt
, ps
, intypeid
);
3775 auto e
= typeToExpressionHelper(mt
, new TypeExp(loc
, t
));
3776 e
= e
.expressionSemantic(sc
);
3777 resolveExp(e
, pt
, pe
, ps
);
3780 pt
= pt
.addMod(mt
.mod
);
3785 void visitReturn(TypeReturn mt
)
3787 //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
3790 FuncDeclaration func
= sc
.func
;
3793 error(loc
, "`typeof(return)` must be inside function");
3794 return returnError();
3797 func
= func
.fes
.func
;
3798 t
= func
.type
.nextOf();
3801 error(loc
, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc
.func
.toChars());
3802 return returnError();
3805 if (mt
.idents
.length
== 0)
3807 return returnType(t
.addMod(mt
.mod
));
3811 if (Dsymbol s
= t
.toDsymbol(sc
))
3812 mt
.resolveHelper(loc
, sc
, s
, null, pe
, pt
, ps
, intypeid
);
3815 auto e
= typeToExpressionHelper(mt
, new TypeExp(loc
, t
));
3816 e
= e
.expressionSemantic(sc
);
3817 resolveExp(e
, pt
, pe
, ps
);
3820 pt
= pt
.addMod(mt
.mod
);
3824 void visitSlice(TypeSlice mt
)
3826 mt
.next
.resolve(loc
, sc
, pe
, pt
, ps
, intypeid
);
3829 // It's really a slice expression
3830 if (Dsymbol s
= getDsymbol(pe
))
3831 pe
= new DsymbolExp(loc
, s
);
3832 return returnExp(new ArrayExp(loc
, pe
, new IntervalExp(loc
, mt
.lwr
, mt
.upr
)));
3837 TupleDeclaration td
= s
.isTupleDeclaration();
3840 /* It's a slice of a TupleDeclaration
3842 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, td
);
3843 sym
.parent
= sc
.scopesym
;
3845 sc
= sc
.startCTFE();
3846 mt
.lwr
= mt
.lwr
.expressionSemantic(sc
);
3847 mt
.upr
= mt
.upr
.expressionSemantic(sc
);
3851 mt
.lwr
= mt
.lwr
.ctfeInterpret();
3852 mt
.upr
= mt
.upr
.ctfeInterpret();
3853 const i1
= mt
.lwr
.toUInteger();
3854 const i2
= mt
.upr
.toUInteger();
3855 if (!(i1
<= i2
&& i2
<= td
.objects
.length
))
3857 error(loc
, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1
, i2
, cast(ulong) td
.objects
.length
);
3858 return returnError();
3861 if (i1
== 0 && i2
== td
.objects
.length
)
3863 return returnSymbol(td
);
3866 /* Create a new TupleDeclaration which
3867 * is a slice [i1..i2] out of the old one.
3869 auto objects
= new Objects(cast(size_t
)(i2
- i1
));
3870 for (size_t i
= 0; i
< objects
.length
; i
++)
3872 (*objects
)[i
] = (*td
.objects
)[cast(size_t
)i1
+ i
];
3875 return returnSymbol(new TupleDeclaration(loc
, td
.ident
, objects
));
3882 if (pt
.ty
!= Terror
)
3883 mt
.next
= pt
; // prevent re-running semantic() on 'next'
3888 void visitMixin(TypeMixin mt
)
3890 RootObject o
= mt
.obj
;
3892 // if already resolved just set pe/pt/ps and return.
3895 pe
= o
.isExpression();
3901 o
= mt
.compileTypeMixin(loc
, sc
);
3902 if (auto t
= o
.isType())
3904 resolve(t
, loc
, sc
, pe
, pt
, ps
, intypeid
);
3906 pt
= pt
.addMod(mt
.mod
);
3908 else if (auto e
= o
.isExpression())
3910 e
= e
.expressionSemantic(sc
);
3911 if (auto et
= e
.isTypeExp())
3912 returnType(et
.type
.addMod(mt
.mod
));
3920 mt
.obj
= pe ? pe
: (pt ? pt
: ps
);
3923 void visitTraits(TypeTraits mt
)
3925 // if already resolved just return the cached object.
3928 pt
= mt
.obj
.isType();
3929 ps
= mt
.obj
.isDsymbol();
3930 pe
= mt
.obj
.isExpression();
3934 import dmd
.traits
: semanticTraits
;
3936 if (Expression e
= semanticTraits(mt
.exp
, sc
))
3940 case EXP
.dotVariable
:
3941 mt
.obj
= e
.isDotVarExp().var
;
3944 mt
.obj
= e
.isVarExp().var
;
3947 auto fe
= e
.isFuncExp();
3948 mt
.obj
= fe
.td ? fe
.td
: fe
.fd
;
3950 case EXP
.dotTemplateDeclaration
:
3951 mt
.obj
= e
.isDotTemplateExp().td
;
3954 mt
.obj
= e
.isDsymbolExp().s
;
3957 mt
.obj
= e
.isTemplateExp().td
;
3960 mt
.obj
= e
.isScopeExp().sds
;
3963 TupleExp te
= e
.isTupleExp();
3964 Objects
* elems
= new Objects(te
.exps
.length
);
3965 foreach (i
; 0 .. elems
.length
)
3967 auto src
= (*te
.exps
)[i
];
3971 (*elems
)[i
] = src
.isTypeExp().type
;
3974 (*elems
)[i
] = src
.isDotTypeExp().sym
.isType();
3976 case EXP
.overloadSet
:
3977 (*elems
)[i
] = src
.isOverExp().type
;
3980 if (auto sym
= isDsymbol(src
))
3986 TupleDeclaration td
= new TupleDeclaration(e
.loc
, Identifier
.generateId("__aliastup"), elems
);
3990 mt
.obj
= e
.isDotTypeExp().sym
.isType();
3993 mt
.obj
= e
.isTypeExp().type
;
3995 case EXP
.overloadSet
:
3996 mt
.obj
= e
.isOverExp().type
;
4008 if (auto t
= mt
.obj
.isType())
4010 t
= t
.addMod(mt
.mod
);
4014 else if (auto s
= mt
.obj
.isDsymbol())
4016 else if (auto e
= mt
.obj
.isExpression())
4021 assert(global
.errors
);
4022 mt
.obj
= Type
.terror
;
4023 return returnError();
4029 default: visitType (mt
); break;
4030 case Tsarray
: visitSArray (mt
.isTypeSArray()); break;
4031 case Tarray
: visitDArray (mt
.isTypeDArray()); break;
4032 case Taarray
: visitAArray (mt
.isTypeAArray()); break;
4033 case Tident
: visitIdentifier(mt
.isTypeIdentifier()); break;
4034 case Tinstance
: visitInstance (mt
.isTypeInstance()); break;
4035 case Ttypeof
: visitTypeof (mt
.isTypeTypeof()); break;
4036 case Treturn
: visitReturn (mt
.isTypeReturn()); break;
4037 case Tslice
: visitSlice (mt
.isTypeSlice()); break;
4038 case Tmixin
: visitMixin (mt
.isTypeMixin()); break;
4039 case Ttraits
: visitTraits (mt
.isTypeTraits()); break;
4043 /************************
4044 * Access the members of the object e. This type is same as e.type.
4046 * mt = type for which the dot expression is used
4047 * sc = instantiating scope
4048 * e = expression to convert
4049 * ident = identifier being used
4050 * flag = DotExpFlag bit flags
4053 * resulting expression with e.ident resolved
4055 Expression
dotExp(Type mt
, Scope
* sc
, Expression e
, Identifier ident
, DotExpFlag flag
)
4057 Expression
visitType(Type mt
)
4059 VarDeclaration v
= null;
4060 static if (LOGDOTEXP
)
4062 printf("Type::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4064 Expression ex
= e
.lastComma();
4065 if (ex
.op
== EXP
.dotVariable
)
4067 DotVarExp dv
= cast(DotVarExp
)ex
;
4068 v
= dv
.var
.isVarDeclaration();
4070 else if (ex
.op
== EXP
.variable
)
4072 VarExp ve
= cast(VarExp
)ex
;
4073 v
= ve
.var
.isVarDeclaration();
4077 if (ident
== Id
.offsetof
)
4079 v
.dsymbolSemantic(null);
4082 auto ad
= v
.isMember();
4083 objc
.checkOffsetof(e
, ad
);
4085 if (ad
.sizeok
!= Sizeok
.done
)
4086 return ErrorExp
.get();
4087 return new IntegerExp(e
.loc
, v
.offset
, Type
.tsize_t
);
4090 else if (ident
== Id
._init
)
4092 Type tb
= mt
.toBasetype();
4093 e
= mt
.defaultInitLiteral(e
.loc
);
4094 if (tb
.ty
== Tstruct
&& tb
.needsNested())
4096 e
.isStructLiteralExp().useStaticInit
= true;
4101 if (ident
== Id
.stringof
)
4103 /* https://issues.dlang.org/show_bug.cgi?id=3796
4104 * this should demangle e.type.deco rather than
4105 * pretty-printing the type.
4107 e
= new StringExp(e
.loc
, e
.toString());
4110 e
= mt
.getProperty(sc
, e
.loc
, ident
, flag
& DotExpFlag
.gag
);
4114 e
= e
.expressionSemantic(sc
);
4118 Expression
visitError(TypeError
)
4120 return ErrorExp
.get();
4123 Expression
visitBasic(TypeBasic mt
)
4125 static if (LOGDOTEXP
)
4127 printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4146 e
= e
.castTo(sc
, t
);
4166 e
= new RealExp(e
.loc
, CTFloat
.zero
, t
);
4170 e
= mt
.Type
.getProperty(sc
, e
.loc
, ident
, flag
);
4174 else if (ident
== Id
.im
)
4180 t
= mt
.timaginary32
;
4185 t
= mt
.timaginary64
;
4190 t
= mt
.timaginary80
;
4194 e
= e
.castTo(sc
, t
);
4217 e
= new RealExp(e
.loc
, CTFloat
.zero
, mt
);
4221 e
= mt
.Type
.getProperty(sc
, e
.loc
, ident
, flag
);
4227 return visitType(mt
);
4229 if (!(flag
& 1) || e
)
4230 e
= e
.expressionSemantic(sc
);
4234 Expression
visitVector(TypeVector mt
)
4236 static if (LOGDOTEXP
)
4238 printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4240 if (ident
== Id
.ptr
&& e
.op
== EXP
.call)
4242 /* The trouble with EXP.call is the return ABI for float[4] is different from
4243 * __vector(float[4]), and a type paint won't do.
4245 e
= new AddrExp(e
.loc
, e
);
4246 e
= e
.expressionSemantic(sc
);
4247 return e
.castTo(sc
, mt
.basetype
.nextOf().pointerTo());
4249 if (ident
== Id
.array
)
4251 //e = e.castTo(sc, basetype);
4253 e
= new VectorArrayExp(e
.loc
, e
);
4254 e
= e
.expressionSemantic(sc
);
4257 if (ident
== Id
._init || ident
== Id
.offsetof || ident
== Id
.stringof || ident
== Id
.__xalignof
)
4259 // init should return a new VectorExp
4260 // https://issues.dlang.org/show_bug.cgi?id=12776
4261 // offsetof does not work on a cast expression, so use e directly
4262 // stringof should not add a cast to the output
4263 return visitType(mt
);
4266 // Properties based on the vector element type and are values of the element type
4267 if (ident
== Id
.max || ident
== Id
.min || ident
== Id
.min_normal ||
4268 ident
== Id
.nan || ident
== Id
.infinity || ident
== Id
.epsilon
)
4270 auto vet
= mt
.basetype
.isTypeSArray().next
; // vector element type
4271 if (auto ev
= getProperty(vet
, sc
, e
.loc
, ident
, DotExpFlag
.gag
))
4272 return ev
.castTo(sc
, mt
); // 'broadcast' ev to the vector elements
4275 return mt
.basetype
.dotExp(sc
, e
.castTo(sc
, mt
.basetype
), ident
, flag
);
4278 Expression
visitArray(TypeArray mt
)
4280 static if (LOGDOTEXP
)
4282 printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4287 if (!(flag
& 1) || e
)
4288 e
= e
.expressionSemantic(sc
);
4292 Expression
visitSArray(TypeSArray mt
)
4294 static if (LOGDOTEXP
)
4296 printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4298 if (ident
== Id
.length
)
4304 else if (ident
== Id
.ptr
)
4306 if (e
.op
== EXP
.type
)
4308 error(e
.loc
, "`%s` is not an expression", e
.toChars());
4309 return ErrorExp
.get();
4311 else if (mt
.dim
.toUInteger() < 1 && checkUnsafeDotExp(sc
, e
, ident
, flag
))
4313 // .ptr on static array is @safe unless size is 0
4314 // https://issues.dlang.org/show_bug.cgi?id=20853
4315 return ErrorExp
.get();
4317 e
= e
.castTo(sc
, e
.type
.nextOf().pointerTo());
4319 else if (ident
== Id
._tupleof
)
4323 error(e
.loc
, "`.tupleof` cannot be used on type `%s`", mt
.toChars
);
4324 return ErrorExp
.get();
4330 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
4332 const length
= cast(size_t
)mt
.dim
.toUInteger();
4333 auto exps
= new Expressions();
4334 exps
.reserve(length
);
4335 foreach (i
; 0 .. length
)
4336 exps
.push(new IndexExp(e
.loc
, ev
, new IntegerExp(e
.loc
, i
, Type
.tsize_t
)));
4337 e
= new TupleExp(e
.loc
, e0
, exps
);
4344 if (!(flag
& 1) || e
)
4345 e
= e
.expressionSemantic(sc
);
4349 Expression
visitDArray(TypeDArray mt
)
4351 static if (LOGDOTEXP
)
4353 printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4355 if (e
.op
== EXP
.type
&& (ident
== Id
.length || ident
== Id
.ptr
))
4357 error(e
.loc
, "`%s` is not an expression", e
.toChars());
4358 return ErrorExp
.get();
4360 if (ident
== Id
.length
)
4362 if (e
.op
== EXP
.string_
)
4364 StringExp se
= cast(StringExp
)e
;
4365 return new IntegerExp(se
.loc
, se
.len
, Type
.tsize_t
);
4367 if (e
.op
== EXP
.null_
)
4369 return new IntegerExp(e
.loc
, 0, Type
.tsize_t
);
4371 if (checkNonAssignmentArrayOp(e
))
4373 return ErrorExp
.get();
4375 e
= new ArrayLengthExp(e
.loc
, e
);
4376 e
.type
= Type
.tsize_t
;
4379 else if (ident
== Id
.ptr
)
4381 if (checkUnsafeDotExp(sc
, e
, ident
, flag
))
4382 return ErrorExp
.get();
4383 return e
.castTo(sc
, mt
.next
.pointerTo());
4387 return visitArray(mt
);
4391 Expression
visitAArray(TypeAArray mt
)
4393 static if (LOGDOTEXP
)
4395 printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4397 if (ident
== Id
.length
)
4399 __gshared FuncDeclaration fd_aaLen
= null;
4400 if (fd_aaLen
is null)
4402 auto fparams
= new Parameters();
4403 fparams
.push(new Parameter(Loc
.initial
, STC
.const_ | STC
.scope_
, mt
, null, null, null));
4404 fd_aaLen
= FuncDeclaration
.genCfunc(fparams
, Type
.tsize_t
, Id
.aaLen
);
4405 TypeFunction tf
= fd_aaLen
.type
.toTypeFunction();
4406 tf
.purity
= PURE
.const_
;
4407 tf
.isnothrow
= true;
4410 Expression ev
= new VarExp(e
.loc
, fd_aaLen
, false);
4411 e
= new CallExp(e
.loc
, ev
, e
);
4412 e
.type
= fd_aaLen
.type
.toTypeFunction().next
;
4417 return visitType(mt
);
4421 Expression
visitReference(TypeReference mt
)
4423 static if (LOGDOTEXP
)
4425 printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4427 // References just forward things along
4428 return mt
.next
.dotExp(sc
, e
, ident
, flag
);
4431 Expression
visitDelegate(TypeDelegate mt
)
4433 static if (LOGDOTEXP
)
4435 printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4437 if (ident
== Id
.ptr
)
4439 e
= new DelegatePtrExp(e
.loc
, e
);
4440 e
= e
.expressionSemantic(sc
);
4442 else if (ident
== Id
.funcptr
)
4444 if (checkUnsafeDotExp(sc
, e
, ident
, flag
))
4446 return ErrorExp
.get();
4448 e
= new DelegateFuncptrExp(e
.loc
, e
);
4449 e
= e
.expressionSemantic(sc
);
4453 return visitType(mt
);
4458 /***************************************
4459 * `ident` was not found as a member of `mt`.
4460 * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
4461 * If that fails, forward to visitType().
4463 * mt = class or struct
4465 * e = `this` for `ident`
4466 * ident = name of member
4467 * flag = flag & 1, don't report "not a property" error and just return NULL.
4468 * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
4470 * resolved expression if found, otherwise null
4472 Expression
noMember(Type mt
, Scope
* sc
, Expression e
, Identifier ident
, int flag
)
4474 //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
4476 bool gagError
= flag
& 1;
4478 __gshared
int nest
; // https://issues.dlang.org/show_bug.cgi?id=17380
4480 static Expression
returnExp(Expression e
)
4486 if (++nest
> global
.recursionLimit
)
4488 .error(e
.loc
, "cannot resolve identifier `%s`", ident
.toChars());
4489 return returnExp(gagError ?
null : ErrorExp
.get());
4493 assert(mt
.ty
== Tstruct || mt
.ty
== Tclass
);
4494 auto sym
= mt
.toDsymbol(sc
).isAggregateDeclaration();
4496 if (// https://issues.dlang.org/show_bug.cgi?id=22054
4497 // if a class or struct does not have a body
4498 // there is no point in searching for its members
4500 ident
!= Id
.__sizeof
&&
4501 ident
!= Id
.__xalignof
&&
4502 ident
!= Id
._init
&&
4503 ident
!= Id
._mangleof
&&
4504 ident
!= Id
.stringof
&&
4505 ident
!= Id
.offsetof
&&
4506 // https://issues.dlang.org/show_bug.cgi?id=15045
4507 // Don't forward special built-in member functions.
4510 ident
!= Id
.__xdtor
&&
4511 ident
!= Id
.postblit
&&
4512 ident
!= Id
.__xpostblit
)
4514 /* Look for overloaded opDot() to see if we should forward request
4517 if (auto fd
= search_function(sym
, Id
.opDot
))
4519 /* Rewrite e.ident as:
4522 e
= build_overload(e
.loc
, sc
, e
, null, fd
);
4523 // @@@DEPRECATED_2.110@@@.
4524 // Deprecated in 2.082, made an error in 2.100.
4525 error(e
.loc
, "`opDot` is obsolete. Use `alias this`");
4526 return ErrorExp
.get();
4529 /* Look for overloaded opDispatch to see if we should forward request
4532 if (auto fd
= search_function(sym
, Id
.opDispatch
))
4534 /* Rewrite e.ident as:
4535 * e.opDispatch!("ident")
4537 TemplateDeclaration td
= fd
.isTemplateDeclaration();
4540 .error(fd
.loc
, "%s `%s` must be a template `opDispatch(string s)`, not a %s", fd
.kind
, fd
.toPrettyChars
, fd
.kind());
4541 return returnExp(ErrorExp
.get());
4543 auto se
= new StringExp(e
.loc
, ident
.toString());
4544 auto tiargs
= new Objects();
4546 auto dti
= new DotTemplateInstanceExp(e
.loc
, e
, Id
.opDispatch
, tiargs
);
4547 dti
.ti
.tempdecl
= td
;
4548 /* opDispatch, which doesn't need IFTI, may occur instantiate error.
4550 * template opDispatch(name) if (isValid!name) { ... }
4552 uint errors
= gagError ? global
.startGagging() : 0;
4553 e
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.none
);
4554 if (gagError
&& global
.endGagging(errors
))
4556 return returnExp(e
);
4559 /* See if we should forward to the alias this.
4561 auto alias_e
= flag
& DotExpFlag
.noAliasThis ?
null
4562 : resolveAliasThis(sc
, e
, gagError
);
4563 if (alias_e
&& alias_e
!= e
)
4565 /* Rewrite e.ident as:
4568 auto die
= new DotIdExp(e
.loc
, alias_e
, ident
);
4570 auto errors
= gagError ?
0 : global
.startGagging();
4571 auto exp
= die
.dotIdSemanticProp(sc
, gagError
);
4574 global
.endGagging(errors
);
4575 if (exp
&& exp
.op
== EXP
.error
)
4579 if (exp
&& gagError
)
4580 // now that we know that the alias this leads somewhere useful,
4581 // go back and print deprecations/warnings that we skipped earlier due to the gag
4582 resolveAliasThis(sc
, e
, false);
4584 return returnExp(exp
);
4587 return returnExp(visitType(mt
));
4590 Expression
visitStruct(TypeStruct mt
)
4593 static if (LOGDOTEXP
)
4595 printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4597 assert(e
.op
!= EXP
.dot
);
4599 // https://issues.dlang.org/show_bug.cgi?id=14010
4600 if (!(sc
.flags
& SCOPE
.Cfile
) && ident
== Id
._mangleof
)
4602 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
4607 if (ident
== Id
._tupleof
)
4609 /* Create a TupleExp out of the fields of the struct e:
4610 * (e.field0, e.field1, e.field2, ...)
4612 e
= e
.expressionSemantic(sc
); // do this before turning on noaccesscheck
4614 if (!mt
.sym
.determineFields())
4616 error(e
.loc
, "unable to determine fields of `%s` because of forward references", mt
.toChars());
4620 Expression ev
= e
.op
== EXP
.type ?
null : e
;
4622 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
4624 auto exps
= new Expressions();
4625 exps
.reserve(mt
.sym
.fields
.length
);
4626 for (size_t i
= 0; i
< mt
.sym
.fields
.length
; i
++)
4628 VarDeclaration v
= mt
.sym
.fields
[i
];
4631 ex
= new DotVarExp(e
.loc
, ev
, v
);
4634 ex
= new VarExp(e
.loc
, v
);
4635 ex
.type
= ex
.type
.addMod(e
.type
.mod
);
4640 e
= new TupleExp(e
.loc
, e0
, exps
);
4641 Scope
* sc2
= sc
.push();
4642 sc2
.flags |
= SCOPE
.noaccesscheck
;
4643 e
= e
.expressionSemantic(sc2
);
4648 immutable flags
= sc
.flags
& SCOPE
.ignoresymbolvisibility ? SearchOpt
.ignoreVisibility
: 0;
4649 s
= mt
.sym
.search(e
.loc
, ident
, flags | SearchOpt
.ignorePrivateImports
);
4653 return noMember(mt
, sc
, e
, ident
, flag
);
4655 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, s
))
4657 return noMember(mt
, sc
, e
, ident
, flag
);
4659 // check before alias resolution; the alias itself might be deprecated!
4660 if (s
.isAliasDeclaration
)
4661 s
.checkDeprecated(e
.loc
, sc
);
4664 if (auto em
= s
.isEnumMember())
4666 return em
.getVarExp(e
.loc
, sc
);
4668 if (auto v
= s
.isVarDeclaration())
4670 v
.checkDeprecated(e
.loc
, sc
);
4671 v
.checkDisabled(e
.loc
, sc
);
4673 !v
.type
.deco
&& v
.inuse
)
4675 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
4676 error(e
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
4678 error(e
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
4679 return ErrorExp
.get();
4681 if (v
.type
.ty
== Terror
)
4683 return ErrorExp
.get();
4686 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
4690 error(e
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
4691 return ErrorExp
.get();
4693 checkAccess(e
.loc
, sc
, null, v
);
4694 Expression ve
= new VarExp(e
.loc
, v
);
4695 if (!isTrivialExp(e
))
4697 ve
= new CommaExp(e
.loc
, e
, ve
);
4699 return ve
.expressionSemantic(sc
);
4703 if (auto t
= s
.getType())
4705 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
4708 TemplateMixin tm
= s
.isTemplateMixin();
4711 return new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, tm
)).expressionSemantic(sc
);
4714 TemplateDeclaration td
= s
.isTemplateDeclaration();
4717 if (e
.op
== EXP
.type
)
4718 e
= new TemplateExp(e
.loc
, td
);
4720 e
= new DotTemplateExp(e
.loc
, e
, td
);
4721 return e
.expressionSemantic(sc
);
4724 TemplateInstance ti
= s
.isTemplateInstance();
4727 if (!ti
.semanticRun
)
4729 ti
.dsymbolSemantic(sc
);
4730 if (!ti
.inst || ti
.errors
) // if template failed to expand
4732 return ErrorExp
.get();
4735 s
= ti
.inst
.toAlias();
4736 if (!s
.isTemplateInstance())
4738 if (e
.op
== EXP
.type
)
4739 e
= new ScopeExp(e
.loc
, ti
);
4741 e
= new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, ti
));
4742 return e
.expressionSemantic(sc
);
4745 if (s
.isImport() || s
.isModule() || s
.isPackage())
4747 return symbolToExp(s
, e
.loc
, sc
, false);
4750 OverloadSet o
= s
.isOverloadSet();
4753 auto oe
= new OverExp(e
.loc
, o
);
4754 if (e
.op
== EXP
.type
)
4758 return new DotExp(e
.loc
, e
, oe
);
4761 Declaration d
= s
.isDeclaration();
4764 error(e
.loc
, "`%s.%s` is not a declaration", e
.toChars(), ident
.toChars());
4765 return ErrorExp
.get();
4768 if (e
.op
== EXP
.type
)
4773 if (TupleDeclaration tup
= d
.isTupleDeclaration())
4775 e
= new TupleExp(e
.loc
, tup
);
4776 return e
.expressionSemantic(sc
);
4778 if (d
.needThis() && sc
.intypeof
!= 1)
4783 * only if the scope in which we are
4784 * has a `this` that matches the type
4785 * of the lhs of the dot expression.
4787 * https://issues.dlang.org/show_bug.cgi?id=23617
4789 auto fd
= hasThis(sc
);
4790 if (fd
&& fd
.isThis() == mt
.sym
)
4792 e
= new DotVarExp(e
.loc
, new ThisExp(e
.loc
), d
);
4793 return e
.expressionSemantic(sc
);
4796 if (d
.semanticRun
== PASS
.initial
)
4797 d
.dsymbolSemantic(null);
4798 checkAccess(e
.loc
, sc
, e
, d
);
4799 auto ve
= new VarExp(e
.loc
, d
);
4800 if (d
.isVarDeclaration() && d
.needThis())
4801 ve
.type
= d
.type
.addMod(e
.type
.mod
);
4805 bool unreal
= e
.op
== EXP
.variable
&& (cast(VarExp
)e
).var
.isField();
4806 if (d
.isDataseg() || unreal
&& d
.isField())
4809 checkAccess(e
.loc
, sc
, e
, d
);
4810 Expression ve
= new VarExp(e
.loc
, d
);
4811 e
= unreal ? ve
: new CommaExp(e
.loc
, e
, ve
);
4812 return e
.expressionSemantic(sc
);
4815 e
= new DotVarExp(e
.loc
, e
, d
);
4816 return e
.expressionSemantic(sc
);
4819 Expression
visitEnum(TypeEnum mt
)
4821 static if (LOGDOTEXP
)
4823 printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e
.toChars(), ident
.toChars(), mt
.toChars());
4825 // https://issues.dlang.org/show_bug.cgi?id=14010
4826 if (ident
== Id
._mangleof
)
4828 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
4831 if (mt
.sym
.semanticRun
< PASS
.semanticdone
)
4832 mt
.sym
.dsymbolSemantic(null);
4834 Dsymbol s
= mt
.sym
.search(e
.loc
, ident
);
4837 if (ident
== Id
._init
)
4839 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
4842 /* Allow special enums to not need a member list
4844 if ((ident
== Id
.max || ident
== Id
.min
) && (mt
.sym
.members ||
!mt
.sym
.isSpecial()))
4846 return mt
.getProperty(sc
, e
.loc
, ident
, flag
& 1);
4849 Expression res
= mt
.sym
.getMemtype(Loc
.initial
).dotExp(sc
, e
, ident
, DotExpFlag
.gag
);
4850 if (!(flag
& 1) && !res
)
4852 if (auto ns
= mt
.sym
.search_correct(ident
))
4853 error(e
.loc
, "no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident
.toChars(), mt
.toChars(), mt
.toChars(),
4856 error(e
.loc
, "no property `%s` for type `%s`", ident
.toChars(),
4859 errorSupplemental(mt
.sym
.loc
, "%s `%s` defined here",
4860 mt
.sym
.kind
, mt
.toChars());
4861 return ErrorExp
.get();
4865 EnumMember m
= s
.isEnumMember();
4866 return m
.getVarExp(e
.loc
, sc
);
4869 Expression
visitClass(TypeClass mt
)
4872 static if (LOGDOTEXP
)
4874 printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e
.toChars(), ident
.toChars());
4876 assert(e
.op
!= EXP
.dot
);
4878 // https://issues.dlang.org/show_bug.cgi?id=12543
4879 if (ident
== Id
.__sizeof || ident
== Id
.__xalignof || ident
== Id
._mangleof
)
4881 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4886 if (ident
== Id
._tupleof
)
4888 objc
.checkTupleof(e
, mt
);
4890 /* Create a TupleExp
4892 e
= e
.expressionSemantic(sc
); // do this before turning on noaccesscheck
4894 mt
.sym
.size(e
.loc
); // do semantic of type
4897 Expression ev
= e
.op
== EXP
.type ?
null : e
;
4899 ev
= extractSideEffect(sc
, "__tup", e0
, ev
);
4901 auto exps
= new Expressions();
4902 exps
.reserve(mt
.sym
.fields
.length
);
4903 for (size_t i
= 0; i
< mt
.sym
.fields
.length
; i
++)
4905 VarDeclaration v
= mt
.sym
.fields
[i
];
4906 // Don't include hidden 'this' pointer
4907 if (v
.isThisDeclaration())
4911 ex
= new DotVarExp(e
.loc
, ev
, v
);
4914 ex
= new VarExp(e
.loc
, v
);
4915 ex
.type
= ex
.type
.addMod(e
.type
.mod
);
4920 e
= new TupleExp(e
.loc
, e0
, exps
);
4921 Scope
* sc2
= sc
.push();
4922 sc2
.flags |
= SCOPE
.noaccesscheck
;
4923 e
= e
.expressionSemantic(sc2
);
4928 SearchOptFlags flags
= sc
.flags
& SCOPE
.ignoresymbolvisibility ? SearchOpt
.ignoreVisibility
: SearchOpt
.all
;
4929 s
= mt
.sym
.search(e
.loc
, ident
, flags | SearchOpt
.ignorePrivateImports
);
4934 // See if it's a 'this' class or a base class
4935 if (mt
.sym
.ident
== ident
)
4937 if (e
.op
== EXP
.type
)
4939 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4941 e
= new DotTypeExp(e
.loc
, e
, mt
.sym
);
4942 e
= e
.expressionSemantic(sc
);
4945 if (auto cbase
= mt
.sym
.searchBase(ident
))
4947 if (e
.op
== EXP
.type
)
4949 return mt
.Type
.getProperty(sc
, e
.loc
, ident
, 0);
4951 if (auto ifbase
= cbase
.isInterfaceDeclaration())
4952 e
= new CastExp(e
.loc
, e
, ifbase
.type
);
4954 e
= new DotTypeExp(e
.loc
, e
, cbase
);
4955 e
= e
.expressionSemantic(sc
);
4959 if (ident
== Id
.classinfo
)
4961 if (!Type
.typeinfoclass
)
4963 error(e
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4964 return ErrorExp
.get();
4967 Type t
= Type
.typeinfoclass
.type
;
4968 if (e
.op
== EXP
.type || e
.op
== EXP
.dotType
)
4970 /* For type.classinfo, we know the classinfo
4973 if (!mt
.sym
.vclassinfo
)
4974 mt
.sym
.vclassinfo
= new TypeInfoClassDeclaration(mt
.sym
.type
);
4975 e
= new VarExp(e
.loc
, mt
.sym
.vclassinfo
);
4977 e
.type
= t
; // do this so we don't get redundant dereference
4981 /* For class objects, the classinfo reference is the first
4982 * entry in the vtbl[]
4984 e
= new PtrExp(e
.loc
, e
);
4985 e
.type
= t
.pointerTo();
4986 if (mt
.sym
.isInterfaceDeclaration())
4988 if (mt
.sym
.isCPPinterface())
4990 /* C++ interface vtbl[]s are different in that the
4991 * first entry is always pointer to the first virtual
4992 * function, not classinfo.
4993 * We can't get a .classinfo for it.
4995 error(e
.loc
, "no `.classinfo` for C++ interface objects");
4997 /* For an interface, the first entry in the vtbl[]
4998 * is actually a pointer to an instance of struct Interface.
4999 * The first member of Interface is the .classinfo,
5000 * so add an extra pointer indirection.
5002 e
.type
= e
.type
.pointerTo();
5003 e
= new PtrExp(e
.loc
, e
);
5004 e
.type
= t
.pointerTo();
5006 e
= new PtrExp(e
.loc
, e
, t
);
5011 if (ident
== Id
.__vptr
)
5013 /* The pointer to the vtbl[]
5014 * *cast(immutable(void*)**)e
5016 e
= e
.castTo(sc
, mt
.tvoidptr
.immutableOf().pointerTo().pointerTo());
5017 e
= new PtrExp(e
.loc
, e
);
5018 e
= e
.expressionSemantic(sc
);
5022 if (ident
== Id
.__monitor
&& mt
.sym
.hasMonitor())
5024 /* The handle to the monitor (call it a void*)
5025 * *(cast(void**)e + 1)
5027 e
= e
.castTo(sc
, mt
.tvoidptr
.pointerTo());
5028 e
= new AddExp(e
.loc
, e
, IntegerExp
.literal
!1);
5029 e
= new PtrExp(e
.loc
, e
);
5030 e
= e
.expressionSemantic(sc
);
5034 if (ident
== Id
.outer
&& mt
.sym
.vthis
)
5036 if (mt
.sym
.vthis
.semanticRun
== PASS
.initial
)
5037 mt
.sym
.vthis
.dsymbolSemantic(null);
5039 if (auto cdp
= mt
.sym
.toParentLocal().isClassDeclaration())
5041 auto dve
= new DotVarExp(e
.loc
, e
, mt
.sym
.vthis
);
5042 dve
.type
= cdp
.type
.addMod(e
.type
.mod
);
5046 /* https://issues.dlang.org/show_bug.cgi?id=15839
5047 * Find closest parent class through nested functions.
5049 for (auto p
= mt
.sym
.toParentLocal(); p
; p
= p
.toParentLocal())
5051 auto fd
= p
.isFuncDeclaration();
5054 auto ad
= fd
.isThis();
5055 if (!ad
&& fd
.isNested())
5059 if (auto cdp
= ad
.isClassDeclaration())
5061 auto ve
= new ThisExp(e
.loc
);
5064 const nestedError
= fd
.vthis
.checkNestedReference(sc
, e
.loc
);
5065 assert(!nestedError
);
5067 ve
.type
= cdp
.type
.addMod(fd
.vthis
.type
.mod
).addMod(e
.type
.mod
);
5073 // Continue to show enclosing function's frame (stack or closure).
5074 auto dve
= new DotVarExp(e
.loc
, e
, mt
.sym
.vthis
);
5075 dve
.type
= mt
.sym
.vthis
.type
.addMod(e
.type
.mod
);
5079 return noMember(mt
, sc
, e
, ident
, flag
& 1);
5081 if (!(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
, s
))
5083 return noMember(mt
, sc
, e
, ident
, flag
);
5085 if (!s
.isFuncDeclaration()) // because of overloading
5087 s
.checkDeprecated(e
.loc
, sc
);
5088 if (auto d
= s
.isDeclaration())
5089 d
.checkDisabled(e
.loc
, sc
);
5093 if (auto em
= s
.isEnumMember())
5095 return em
.getVarExp(e
.loc
, sc
);
5097 if (auto v
= s
.isVarDeclaration())
5100 !v
.type
.deco
&& v
.inuse
)
5102 if (v
.inuse
) // https://issues.dlang.org/show_bug.cgi?id=9494
5103 error(e
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
5105 error(e
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
5106 return ErrorExp
.get();
5108 if (v
.type
.ty
== Terror
)
5110 error(e
.loc
, "type of variable `%s` has errors", v
.toPrettyChars
);
5111 return ErrorExp
.get();
5114 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
5118 error(e
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
5119 return ErrorExp
.get();
5121 checkAccess(e
.loc
, sc
, null, v
);
5122 Expression ve
= new VarExp(e
.loc
, v
);
5123 ve
= ve
.expressionSemantic(sc
);
5128 if (auto t
= s
.getType())
5130 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
5133 TemplateMixin tm
= s
.isTemplateMixin();
5136 return new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, tm
)).expressionSemantic(sc
);
5139 TemplateDeclaration td
= s
.isTemplateDeclaration();
5141 Expression
toTemplateExp(TemplateDeclaration td
)
5143 if (e
.op
== EXP
.type
)
5144 e
= new TemplateExp(e
.loc
, td
);
5146 e
= new DotTemplateExp(e
.loc
, e
, td
);
5147 e
= e
.expressionSemantic(sc
);
5153 return toTemplateExp(td
);
5156 TemplateInstance ti
= s
.isTemplateInstance();
5159 if (!ti
.semanticRun
)
5161 ti
.dsymbolSemantic(sc
);
5162 if (!ti
.inst || ti
.errors
) // if template failed to expand
5164 return ErrorExp
.get();
5167 s
= ti
.inst
.toAlias();
5168 if (!s
.isTemplateInstance())
5170 if (e
.op
== EXP
.type
)
5171 e
= new ScopeExp(e
.loc
, ti
);
5173 e
= new DotExp(e
.loc
, e
, new ScopeExp(e
.loc
, ti
));
5174 return e
.expressionSemantic(sc
);
5177 if (s
.isImport() || s
.isModule() || s
.isPackage())
5179 e
= symbolToExp(s
, e
.loc
, sc
, false);
5183 OverloadSet o
= s
.isOverloadSet();
5186 auto oe
= new OverExp(e
.loc
, o
);
5187 if (e
.op
== EXP
.type
)
5191 return new DotExp(e
.loc
, e
, oe
);
5194 Declaration d
= s
.isDeclaration();
5197 error(e
.loc
, "`%s.%s` is not a declaration", e
.toChars(), ident
.toChars());
5198 return ErrorExp
.get();
5201 if (e
.op
== EXP
.type
)
5206 if (TupleDeclaration tup
= d
.isTupleDeclaration())
5208 e
= new TupleExp(e
.loc
, tup
);
5209 e
= e
.expressionSemantic(sc
);
5213 if (mt
.sym
.classKind
== ClassKind
.objc
5214 && d
.isFuncDeclaration()
5215 && d
.isFuncDeclaration().isStatic
5216 && d
.isFuncDeclaration().objc
.selector
)
5218 auto classRef
= new ObjcClassReferenceExp(e
.loc
, mt
.sym
);
5219 classRef
.type
= objc
.getRuntimeMetaclass(mt
.sym
).getType();
5220 return new DotVarExp(e
.loc
, classRef
, d
).expressionSemantic(sc
);
5222 else if (d
.needThis() && sc
.intypeof
!= 1)
5227 AggregateDeclaration ad
= d
.isMemberLocal();
5228 if (auto f
= hasThis(sc
))
5230 // This is almost same as getRightThis() in expressionsem.d
5233 /* returns: true to continue, false to return */
5234 if (f
.hasDualContext())
5236 if (f
.followInstantiationContext(ad
))
5238 e1
= new VarExp(e
.loc
, f
.vthis
);
5239 e1
= new PtrExp(e1
.loc
, e1
);
5240 e1
= new IndexExp(e1
.loc
, e1
, IntegerExp
.literal
!1);
5241 auto pd
= f
.toParent2().isDeclaration();
5243 t
= pd
.type
.toBasetype();
5244 e1
= getThisSkipNestedFuncs(e1
.loc
, sc
, f
.toParent2(), ad
, e1
, t
, d
, true);
5247 e
= new VarExp(e
.loc
, d
);
5253 e1
= new ThisExp(e
.loc
);
5254 e1
= e1
.expressionSemantic(sc
);
5256 t
= e1
.type
.toBasetype();
5257 ClassDeclaration cd
= e
.type
.isClassHandle();
5258 ClassDeclaration tcd
= t
.isClassHandle();
5259 if (cd
&& tcd
&& (tcd
== cd || cd
.isBaseOf(tcd
, null)))
5261 e
= new DotTypeExp(e1
.loc
, e1
, cd
);
5262 e
= new DotVarExp(e
.loc
, e
, d
);
5263 e
= e
.expressionSemantic(sc
);
5266 if (tcd
&& tcd
.isNested())
5268 /* e1 is the 'this' pointer for an inner class: tcd.
5269 * Rewrite it as the 'this' pointer for the outer class.
5271 auto vthis
= tcd
.followInstantiationContext(ad
) ? tcd
.vthis2
: tcd
.vthis
;
5272 e1
= new DotVarExp(e
.loc
, e1
, vthis
);
5273 e1
.type
= vthis
.type
;
5274 e1
.type
= e1
.type
.addMod(t
.mod
);
5275 // Do not call ensureStaticLinkTo()
5276 //e1 = e1.expressionSemantic(sc);
5278 // Skip up over nested functions, and get the enclosing
5280 e1
= getThisSkipNestedFuncs(e1
.loc
, sc
, tcd
.toParentP(ad
), ad
, e1
, t
, d
, true);
5283 e
= new VarExp(e
.loc
, d
);
5290 //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
5291 if (d
.semanticRun
== PASS
.initial
)
5292 d
.dsymbolSemantic(null);
5294 // If static function, get the most visible overload.
5295 // Later on the call is checked for correctness.
5296 // https://issues.dlang.org/show_bug.cgi?id=12511
5298 if (auto fd
= d
.isFuncDeclaration())
5300 import dmd
.access
: mostVisibleOverload
;
5301 d2
= mostVisibleOverload(fd
, sc
._module
);
5304 checkAccess(e
.loc
, sc
, e
, d2
);
5305 if (d2
.isDeclaration())
5307 d
= cast(Declaration
)d2
;
5308 auto ve
= new VarExp(e
.loc
, d
);
5309 if (d
.isVarDeclaration() && d
.needThis())
5310 ve
.type
= d
.type
.addMod(e
.type
.mod
);
5313 else if (d2
.isTemplateDeclaration())
5315 return toTemplateExp(cast(TemplateDeclaration
)d2
);
5321 bool unreal
= e
.op
== EXP
.variable
&& (cast(VarExp
)e
).var
.isField();
5322 if (d
.isDataseg() || unreal
&& d
.isField())
5325 checkAccess(e
.loc
, sc
, e
, d
);
5326 Expression ve
= new VarExp(e
.loc
, d
);
5327 e
= unreal ? ve
: new CommaExp(e
.loc
, e
, ve
);
5328 e
= e
.expressionSemantic(sc
);
5332 e
= new DotVarExp(e
.loc
, e
, d
);
5333 e
= e
.expressionSemantic(sc
);
5339 case Tvector
: return visitVector (mt
.isTypeVector());
5340 case Tsarray
: return visitSArray (mt
.isTypeSArray());
5341 case Tstruct
: return visitStruct (mt
.isTypeStruct());
5342 case Tenum
: return visitEnum (mt
.isTypeEnum());
5343 case Terror
: return visitError (mt
.isTypeError());
5344 case Tarray
: return visitDArray (mt
.isTypeDArray());
5345 case Taarray
: return visitAArray (mt
.isTypeAArray());
5346 case Treference
: return visitReference(mt
.isTypeReference());
5347 case Tdelegate
: return visitDelegate (mt
.isTypeDelegate());
5348 case Tclass
: return visitClass (mt
.isTypeClass());
5350 default: return mt
.isTypeBasic()
5351 ?
visitBasic(cast(TypeBasic
)mt
)
5357 /************************
5358 * Get the default initialization expression for a type.
5360 * mt = the type for which the init expression is returned
5361 * loc = the location where the expression needs to be evaluated
5362 * isCfile = default initializers are different with C
5365 * The initialization expression for the type.
5367 extern (C
++) Expression
defaultInit(Type mt
, const ref Loc loc
, const bool isCfile
= false)
5369 Expression
visitBasic(TypeBasic mt
)
5371 static if (LOGDEFAULTINIT
)
5373 printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt
.toChars(), isCfile
);
5375 dinteger_t value
= 0;
5380 value
= isCfile ?
0 : 0xFF;
5385 value
= isCfile ?
0 : 0xFFFF;
5394 return new RealExp(loc
, isCfile ? CTFloat
.zero
: target
.RealProperties
.nan
, mt
);
5400 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
5401 const cvalue
= isCfile ?
complex_t(CTFloat
.zero
, CTFloat
.zero
)
5402 : complex_t(target
.RealProperties
.nan
, target
.RealProperties
.nan
);
5403 return new ComplexExp(loc
, cvalue
, mt
);
5407 error(loc
, "`void` does not have a default initializer");
5408 return ErrorExp
.get();
5413 return new IntegerExp(loc
, value
, mt
);
5416 Expression
visitVector(TypeVector mt
)
5418 //printf("TypeVector::defaultInit()\n");
5419 assert(mt
.basetype
.ty
== Tsarray
);
5420 Expression e
= mt
.basetype
.defaultInit(loc
, isCfile
);
5421 auto ve
= new VectorExp(loc
, e
, mt
);
5423 ve
.dim
= cast(int)(mt
.basetype
.size(loc
) / mt
.elementType().size(loc
));
5427 Expression
visitSArray(TypeSArray mt
)
5429 static if (LOGDEFAULTINIT
)
5431 printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt
.toChars(), isCfile
);
5433 if (mt
.next
.ty
== Tvoid
)
5434 return mt
.tuns8
.defaultInit(loc
, isCfile
);
5436 return mt
.next
.defaultInit(loc
, isCfile
);
5439 Expression
visitFunction(TypeFunction mt
)
5441 error(loc
, "`function` does not have a default initializer");
5442 return ErrorExp
.get();
5445 Expression
visitStruct(TypeStruct mt
)
5447 static if (LOGDEFAULTINIT
)
5449 printf("TypeStruct::defaultInit() '%s'\n", mt
.toChars());
5451 Declaration d
= new SymbolDeclaration(mt
.sym
.loc
, mt
.sym
);
5454 d
.storage_class |
= STC
.rvalue
; // https://issues.dlang.org/show_bug.cgi?id=14398
5455 return new VarExp(mt
.sym
.loc
, d
);
5458 Expression
visitEnum(TypeEnum mt
)
5460 static if (LOGDEFAULTINIT
)
5462 printf("TypeEnum::defaultInit() '%s'\n", mt
.toChars());
5464 // Initialize to first member of enum
5465 Expression e
= mt
.sym
.getDefaultValue(loc
);
5468 e
.type
= mt
; // to deal with const, immutable, etc., variants
5472 Expression
visitTuple(TypeTuple mt
)
5474 static if (LOGDEFAULTINIT
)
5476 printf("TypeTuple::defaultInit() '%s'\n", mt
.toChars());
5478 auto exps
= new Expressions(mt
.arguments
.length
);
5479 for (size_t i
= 0; i
< mt
.arguments
.length
; i
++)
5481 Parameter p
= (*mt
.arguments
)[i
];
5483 Expression e
= p
.type
.defaultInitLiteral(loc
);
5484 if (e
.op
== EXP
.error
)
5490 return new TupleExp(loc
, exps
);
5493 Expression
visitNoreturn(TypeNoreturn mt
)
5495 static if (LOGDEFAULTINIT
)
5497 printf("TypeNoreturn::defaultInit() '%s'\n", mt
.toChars());
5499 auto cond
= IntegerExp
.createBool(false);
5500 auto msg
= new StringExp(loc
, "Accessed expression of type `noreturn`");
5501 msg
.type
= Type
.tstring
;
5502 auto ae
= new AssertExp(loc
, cond
, msg
);
5509 case Tvector
: return visitVector (mt
.isTypeVector());
5510 case Tsarray
: return visitSArray (mt
.isTypeSArray());
5511 case Tfunction
: return visitFunction(mt
.isTypeFunction());
5512 case Tstruct
: return visitStruct (mt
.isTypeStruct());
5513 case Tenum
: return visitEnum (mt
.isTypeEnum());
5514 case Ttuple
: return visitTuple (mt
.isTypeTuple());
5516 case Tnull
: return new NullExp(Loc
.initial
, Type
.tnull
);
5518 case Terror
: return ErrorExp
.get();
5525 case Tclass
: return new NullExp(loc
, mt
);
5526 case Tnoreturn
: return visitNoreturn(mt
.isTypeNoreturn());
5528 default: return mt
.isTypeBasic() ?
5529 visitBasic(cast(TypeBasic
)mt
) :
5535 If `type` resolves to a dsymbol, then that
5536 dsymbol is returned.
5539 type = the type that is checked
5540 sc = the scope where the type is used
5543 The dsymbol to which the type resolve or `null`
5544 if the type does resolve to any symbol (for example,
5545 in the case of basic types).
5547 extern(C
++) Dsymbol
toDsymbol(Type type
, Scope
* sc
)
5549 Dsymbol
visitType(Type _
) { return null; }
5550 Dsymbol
visitStruct(TypeStruct type
) { return type
.sym
; }
5551 Dsymbol
visitEnum(TypeEnum type
) { return type
.sym
; }
5552 Dsymbol
visitClass(TypeClass type
) { return type
.sym
; }
5554 Dsymbol
visitTraits(TypeTraits type
)
5559 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5560 if (t
&& t
.ty
!= Terror
)
5561 s
= t
.toDsymbol(sc
);
5568 Dsymbol
visitMixin(TypeMixin type
)
5573 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5575 s
= t
.toDsymbol(sc
);
5582 Dsymbol
visitIdentifier(TypeIdentifier type
)
5584 //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
5591 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5592 if (t
&& t
.ty
!= Tident
)
5593 s
= t
.toDsymbol(sc
);
5600 Dsymbol
visitInstance(TypeInstance type
)
5605 //printf("TypeInstance::semantic(%s)\n", toChars());
5606 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5607 if (t
&& t
.ty
!= Tinstance
)
5608 s
= t
.toDsymbol(sc
);
5612 Dsymbol
visitTypeof(TypeTypeof type
)
5614 //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
5618 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5622 Dsymbol
visitReturn(TypeReturn type
)
5627 resolve(type
, type
.loc
, sc
, e
, t
, s
);
5633 default: return visitType(type
);
5634 case Ttraits
: return visitTraits(type
.isTypeTraits());
5635 case Tmixin
: return visitMixin(type
.isTypeMixin());
5636 case Tident
: return visitIdentifier(type
.isTypeIdentifier());
5637 case Tinstance
: return visitInstance(type
.isTypeInstance());
5638 case Ttypeof
: return visitTypeof(type
.isTypeTypeof());
5639 case Treturn
: return visitReturn(type
.isTypeReturn());
5640 case Tstruct
: return visitStruct(type
.isTypeStruct());
5641 case Tenum
: return visitEnum(type
.isTypeEnum());
5642 case Tclass
: return visitClass(type
.isTypeClass());
5646 /**********************************************
5647 * Extract complex type from core.stdc.config
5649 * loc = for error messages
5651 * ty = a complex or imaginary type
5653 * Complex!float, Complex!double, Complex!real or null for error
5656 Type
getComplexLibraryType(const ref Loc loc
, Scope
* sc
, TY ty
)
5659 __gshared Type complex_float
;
5660 __gshared Type complex_double
;
5661 __gshared Type complex_real
;
5668 case Tcomplex32
: id
= Id
.c_complex_float
; pt
= &complex_float
; break;
5670 case Tcomplex64
: id
= Id
.c_complex_double
; pt
= &complex_double
; break;
5672 case Tcomplex80
: id
= Id
.c_complex_real
; pt
= &complex_real
; break;
5681 Module mConfig
= Module
.loadCoreStdcConfig();
5684 error(loc
, "`core.stdc.config` is required for complex numbers");
5688 Dsymbol s
= mConfig
.searchX(Loc
.initial
, sc
, id
, SearchOpt
.ignorePrivateImports
);
5691 error(loc
, "`%s` not found in core.stdc.config", id
.toChars());
5695 if (auto t
= s
.getType())
5697 if (auto ts
= t
.toBasetype().isTypeStruct())
5703 if (auto sd
= s
.isStructDeclaration())
5709 error(loc
, "`%s` must be an alias for a complex struct", s
.toChars());
5713 /*******************************
5714 * Covariant means that 'src' can substitute for 't',
5715 * i.e. a pure function is a match for an impure type.
5718 * t = type 'src' is covariant with
5719 * pstc = if not null, store STCxxxx which would make it covariant
5720 * cppCovariant = true if extern(C++) function types should follow C++ covariant rules
5722 * An enum value of either `Covariant.yes` or a reason it's not covariant.
5724 extern(C
++) Covariant
covariant(Type src
, Type t
, StorageClass
* pstc
= null, bool cppCovariant
= false)
5728 printf("Type::covariant(t = %s) %s\n", t
.toChars(), src
.toChars());
5729 printf("deco = %p, %p\n", src
.deco
, t
.deco
);
5730 // printf("ty = %d\n", next.ty);
5731 printf("mod = %x, %x\n", src
.mod
, t
.mod
);
5735 StorageClass
stc = 0;
5737 bool notcovariant
= false;
5740 return Covariant
.yes
;
5742 TypeFunction t1
= src
.isTypeFunction();
5743 TypeFunction t2
= t
.isTypeFunction();
5748 if (t1
.parameterList
.varargs
!= t2
.parameterList
.varargs
)
5751 if (t1
.parameterList
.parameters
&& t2
.parameterList
.parameters
)
5753 if (t1
.parameterList
.length
!= t2
.parameterList
.length
)
5756 foreach (i
, fparam1
; t1
.parameterList
)
5758 Parameter fparam2
= t2
.parameterList
[i
];
5759 Type tp1
= fparam1
.type
;
5760 Type tp2
= fparam2
.type
;
5762 if (!tp1
.equals(tp2
))
5764 if (tp1
.ty
== tp2
.ty
)
5766 if (auto tc1
= tp1
.isTypeClass())
5768 if (tc1
.sym
== (cast(TypeClass
)tp2
).sym
&& MODimplicitConv(tp2
.mod
, tp1
.mod
))
5771 else if (auto ts1
= tp1
.isTypeStruct())
5773 if (ts1
.sym
== (cast(TypeStruct
)tp2
).sym
&& MODimplicitConv(tp2
.mod
, tp1
.mod
))
5776 else if (tp1
.ty
== Tpointer
)
5778 if (tp2
.implicitConvTo(tp1
))
5781 else if (tp1
.ty
== Tarray
)
5783 if (tp2
.implicitConvTo(tp1
))
5786 else if (tp1
.ty
== Tdelegate
)
5788 if (tp2
.implicitConvTo(tp1
))
5795 notcovariant |
= !fparam1
.isCovariant(t1
.isref
, fparam2
);
5797 /* https://issues.dlang.org/show_bug.cgi?id=23135
5798 * extern(C++) mutable parameters are not covariant with const.
5800 if (t1
.linkage
== LINK
.cpp
&& cppCovariant
)
5802 notcovariant |
= tp1
.isNaked() != tp2
.isNaked();
5803 if (auto tpn1
= tp1
.nextOf())
5804 notcovariant |
= tpn1
.isNaked() != tp2
.nextOf().isNaked();
5808 else if (t1
.parameterList
.parameters
!= t2
.parameterList
.parameters
)
5810 if (t1
.parameterList
.length || t2
.parameterList
.length
)
5814 // The argument lists match
5817 if (t1
.linkage
!= t2
.linkage
)
5825 if (!t1n ||
!t2n
) // happens with return type inference
5828 if (t1n
.equals(t2n
))
5830 if (t1n
.ty
== Tclass
&& t2n
.ty
== Tclass
)
5832 /* If same class type, but t2n is const, then it's
5833 * covariant. Do this test first because it can work on
5834 * forward references.
5836 if ((cast(TypeClass
)t1n
).sym
== (cast(TypeClass
)t2n
).sym
&& MODimplicitConv(t1n
.mod
, t2n
.mod
))
5839 // If t1n is forward referenced:
5840 ClassDeclaration cd
= (cast(TypeClass
)t1n
).sym
;
5841 if (cd
.semanticRun
< PASS
.semanticdone
&& !cd
.isBaseInfoComplete())
5842 cd
.dsymbolSemantic(null);
5843 if (!cd
.isBaseInfoComplete())
5845 return Covariant
.fwdref
;
5848 if (t1n
.ty
== Tstruct
&& t2n
.ty
== Tstruct
)
5850 if ((cast(TypeStruct
)t1n
).sym
== (cast(TypeStruct
)t2n
).sym
&& MODimplicitConv(t1n
.mod
, t2n
.mod
))
5853 else if (t1n
.ty
== t2n
.ty
&& t1n
.implicitConvTo(t2n
))
5855 if (t1
.isref
&& t2
.isref
)
5857 // Treat like pointers to t1n and t2n
5858 if (t1n
.constConv(t2n
) < MATCH
.constant
)
5863 else if (t1n
.ty
== Tnull
)
5865 // NULL is covariant with any pointer type, but not with any
5866 // dynamic arrays, associative arrays or delegates.
5867 // https://issues.dlang.org/show_bug.cgi?id=8589
5868 // https://issues.dlang.org/show_bug.cgi?id=19618
5869 Type t2bn
= t2n
.toBasetype();
5870 if (t2bn
.ty
== Tnull || t2bn
.ty
== Tpointer || t2bn
.ty
== Tclass
)
5873 // bottom type is covariant to any type
5874 else if (t1n
.ty
== Tnoreturn
)
5880 if (t1
.isref
!= t2
.isref
)
5883 if (!t1
.isref
&& (t1
.isScopeQual || t2
.isScopeQual
))
5885 StorageClass stc1
= t1
.isScopeQual ? STC
.scope_
: 0;
5886 StorageClass stc2
= t2
.isScopeQual ? STC
.scope_
: 0;
5889 stc1 |
= STC
.return_
;
5890 if (!t1
.isScopeQual
)
5895 stc2 |
= STC
.return_
;
5896 if (!t2
.isScopeQual
)
5899 if (!Parameter
.isCovariantScope(t1
.isref
, stc1
, stc2
))
5903 // We can subtract 'return ref' from 'this', but cannot add it
5904 else if (t1
.isreturn
&& !t2
.isreturn
)
5907 /* https://issues.dlang.org/show_bug.cgi?id=23135
5908 * extern(C++) mutable member functions are not covariant with const.
5910 if (t1
.linkage
== LINK
.cpp
&& cppCovariant
&& t1
.isNaked() != t2
.isNaked())
5913 /* Can convert mutable to const
5915 if (!MODimplicitConv(t2
.mod
, t1
.mod
))
5919 //stop attribute inference with const
5920 // If adding 'const' will make it covariant
5921 if (MODimplicitConv(t2
.mod
, MODmerge(t1
.mod
, MODFlags
.const_
)))
5932 /* Can convert pure to impure, nothrow to throw, and nogc to gc
5934 if (!t1
.purity
&& t2
.purity
)
5937 if (!t1
.isnothrow
&& t2
.isnothrow
)
5938 stc |
= STC
.nothrow_
;
5940 if (!t1
.isnogc
&& t2
.isnogc
)
5943 /* Can convert safe/trusted to system
5945 if (t1
.trust
<= TRUST
.system
&& t2
.trust
>= TRUST
.trusted
)
5947 // Should we infer trusted or safe? Go with safe.
5958 //printf("\tcovaraint: 1\n");
5959 return Covariant
.yes
;
5962 //printf("\tcovaraint: 0\n");
5963 return Covariant
.distinct
;
5966 //printf("\tcovaraint: 2\n");
5967 return Covariant
.no
;
5970 /************************************
5971 * Take the specified storage class for p,
5972 * and use the function signature to infer whether
5973 * STC.scope_ and STC.return_ should be OR'd in.
5974 * (This will not affect the name mangling.)
5976 * tf = TypeFunction to use to get the signature from
5977 * tthis = type of `this` parameter, null if none
5978 * p = parameter to this function
5979 * outerVars = context variables p could escape into, if any
5980 * indirect = is this for an indirect or virtual function call?
5982 * storage class with STC.scope_ or STC.return_ OR'd in
5984 StorageClass
parameterStorageClass(TypeFunction tf
, Type tthis
, Parameter p
, VarDeclarations
* outerVars
= null,
5985 bool indirect
= false)
5987 //printf("parameterStorageClass(p: %s)\n", p.toChars());
5988 auto stc = p
.storageClass
;
5990 // When the preview switch is enable, `in` parameters are `scope`
5991 if (stc & STC
.constscoperef
)
5992 return stc | STC
.scope_
;
5994 if (stc & (STC
.scope_ | STC
.return_ | STC
.lazy_
) || tf
.purity
== PURE
.impure
)
5997 /* If haven't inferred the return type yet, can't infer storage classes
5999 if (!tf
.nextOf() ||
!tf
.isnothrow())
6004 static bool mayHavePointers(Type t
)
6006 if (auto ts
= t
.isTypeStruct())
6009 if (sym
.members
&& !sym
.determineFields() && sym
.type
!= Type
.terror
)
6010 // struct is forward referenced, so "may have" pointers
6013 return t
.hasPointers();
6016 // See if p can escape via any of the other parameters
6017 if (tf
.purity
== PURE
.weak
)
6020 * Indirect calls may escape p through a nested context
6022 * https://issues.dlang.org/show_bug.cgi?id=24212
6023 * https://issues.dlang.org/show_bug.cgi?id=24213
6028 // Check escaping through parameters
6029 foreach (i
, fparam
; tf
.parameterList
)
6031 Type t
= fparam
.type
;
6034 t
= t
.baseElemOf(); // punch thru static arrays
6035 if (t
.isMutable() && t
.hasPointers())
6037 if (fparam
.isReference() && fparam
!= p
)
6040 if (t
.ty
== Tdelegate
)
6041 return stc; // could escape thru delegate
6046 /* if t is a pointer to mutable pointer
6048 if (auto tn
= t
.nextOf())
6050 if (tn
.isMutable() && mayHavePointers(tn
))
6051 return stc; // escape through pointers
6056 // Check escaping through `this`
6057 if (tthis
&& tthis
.isMutable())
6059 foreach (VarDeclaration v
; isAggregate(tthis
).fields
)
6061 if (v
.hasPointers())
6066 // Check escaping through nested context
6067 if (outerVars
&& tf
.isMutable())
6069 foreach (VarDeclaration v
; *outerVars
)
6071 if (v
.hasPointers())
6077 // Check escaping through return value
6078 Type tret
= tf
.nextOf().toBasetype();
6079 if (tf
.isref || tret
.hasPointers())
6081 return stc | STC
.scope_ | STC
.return_ | STC
.returnScope
;
6084 return stc | STC
.scope_
;
6087 extern(C
++) bool isBaseOf(Type tthis
, Type t
, int* poffset
)
6089 auto tc
= tthis
.isTypeClass();
6093 if (!t || t
.ty
!= Tclass
)
6096 ClassDeclaration cd
= t
.isTypeClass().sym
;
6097 if (cd
.semanticRun
< PASS
.semanticdone
&& !cd
.isBaseInfoComplete())
6098 cd
.dsymbolSemantic(null);
6099 if (tc
.sym
.semanticRun
< PASS
.semanticdone
&& !tc
.sym
.isBaseInfoComplete())
6100 tc
.sym
.dsymbolSemantic(null);
6102 if (tc
.sym
.isBaseOf(cd
, poffset
))
6108 /******************************* Private *****************************************/
6112 /* Helper function for `typeToExpression`. Contains common code
6113 * for TypeQualified derived classes.
6115 Expression
typeToExpressionHelper(TypeQualified t
, Expression e
, size_t i
= 0)
6117 //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
6118 foreach (id
; t
.idents
[i
.. t
.idents
.length
])
6120 //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
6122 final switch (id
.dyncast())
6125 case DYNCAST
.identifier
:
6126 e
= new DotIdExp(e
.loc
, e
, cast(Identifier
)id
);
6129 // ... '. name!(tiargs)'
6130 case DYNCAST
.dsymbol
:
6131 auto ti
= (cast(Dsymbol
)id
).isTemplateInstance();
6133 e
= new DotTemplateInstanceExp(e
.loc
, e
, ti
.name
, ti
.tiargs
);
6137 case DYNCAST
.type
: // https://issues.dlang.org/show_bug.cgi?id=1215
6138 e
= new ArrayExp(t
.loc
, e
, new TypeExp(t
.loc
, cast(Type
)id
));
6142 case DYNCAST
.expression
: // https://issues.dlang.org/show_bug.cgi?id=1215
6143 e
= new ArrayExp(t
.loc
, e
, cast(Expression
)id
);
6146 case DYNCAST
.object
:
6148 case DYNCAST
.parameter
:
6149 case DYNCAST
.statement
:
6150 case DYNCAST
.condition
:
6151 case DYNCAST
.templateparameter
:
6152 case DYNCAST
.initializer
:
6159 /**************************
6160 * This evaluates exp while setting length to be the number
6161 * of elements in the tuple t.
6163 Expression
semanticLength(Scope
* sc
, Type t
, Expression exp
)
6165 if (auto tt
= t
.isTypeTuple())
6167 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, tt
);
6168 sym
.parent
= sc
.scopesym
;
6170 sc
= sc
.startCTFE();
6171 exp
= exp
.expressionSemantic(sc
);
6172 exp
= resolveProperties(sc
, exp
);
6178 sc
= sc
.startCTFE();
6179 exp
= exp
.expressionSemantic(sc
);
6180 exp
= resolveProperties(sc
, exp
);
6186 Expression
semanticLength(Scope
* sc
, TupleDeclaration tup
, Expression exp
)
6188 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, tup
);
6189 sym
.parent
= sc
.scopesym
;
6192 sc
= sc
.startCTFE();
6193 exp
= exp
.expressionSemantic(sc
);
6194 exp
= resolveProperties(sc
, exp
);
6201 /************************************
6202 * Transitively search a type for all function types.
6203 * If any function types with parameters are found that have parameter identifiers
6204 * or default arguments, remove those and create a new type stripped of those.
6205 * This is used to determine the "canonical" version of a type which is useful for
6210 * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
6211 * the same as t but with no parameter identifiers or default arguments.
6213 Type
stripDefaultArgs(Type t
)
6215 static Parameters
* stripParams(Parameters
* parameters
)
6217 static Parameter
stripParameter(Parameter p
)
6219 Type t
= stripDefaultArgs(p
.type
);
6220 return (t
!= p
.type || p
.defaultArg || p
.ident || p
.userAttribDecl
)
6221 ?
new Parameter(p
.loc
, p
.storageClass
, t
, null, null, null)
6227 foreach (i
, p
; *parameters
)
6229 Parameter ps
= stripParameter(p
);
6232 // Replace params with a copy we can modify
6233 Parameters
* nparams
= new Parameters(parameters
.length
);
6235 foreach (j
, ref np
; *nparams
)
6237 Parameter pj
= (*parameters
)[j
];
6244 Parameter nps
= stripParameter(pj
);
6245 np
= nps ? nps
: pj
;
6258 if (auto tf
= t
.isTypeFunction())
6260 Type tret
= stripDefaultArgs(tf
.next
);
6261 Parameters
* params
= stripParams(tf
.parameterList
.parameters
);
6262 if (tret
== tf
.next
&& params
== tf
.parameterList
.parameters
)
6264 TypeFunction tr
= tf
.copy().isTypeFunction();
6265 tr
.parameterList
.parameters
= params
;
6267 //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
6270 else if (auto tt
= t
.isTypeTuple())
6272 Parameters
* args
= stripParams(tt
.arguments
);
6273 if (args
== tt
.arguments
)
6275 TypeTuple tr
= t
.copy().isTypeTuple();
6276 tr
.arguments
= args
;
6279 else if (t
.ty
== Tenum
)
6281 // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
6286 Type tn
= t
.nextOf();
6287 Type n
= stripDefaultArgs(tn
);
6290 TypeNext tr
= cast(TypeNext
)t
.copy();
6296 /******************************
6297 * Get the value of the .max/.min property of `ed` as an Expression.
6298 * Lazily computes the value and caches it in maxval/minval.
6299 * Reports any errors.
6301 * ed = the EnumDeclaration being examined
6302 * loc = location to use for error messages
6303 * id = Id::max or Id::min
6305 * corresponding value of .max/.min
6307 Expression
getMaxMinValue(EnumDeclaration ed
, const ref Loc loc
, Identifier id
)
6309 //printf("EnumDeclaration::getMaxValue()\n");
6311 static Expression
pvalToResult(Expression e
, const ref Loc loc
)
6313 if (e
.op
!= EXP
.error
)
6321 Expression
* pval
= (id
== Id
.max
) ?
&ed
.maxval
: &ed
.minval
;
6323 Expression
errorReturn()
6325 *pval
= ErrorExp
.get();
6331 .error(loc
, "%s `%s` recursive definition of `.%s` property", ed
.kind
, ed
.toPrettyChars
, id
.toChars());
6332 return errorReturn();
6335 return pvalToResult(*pval
, loc
);
6338 dsymbolSemantic(ed
, ed
._scope
);
6340 return errorReturn();
6343 .error(loc
, "%s `%s` is opaque and has no `.%s`", ed
.kind
, ed
.toPrettyChars
, id
.toChars(), id
.toChars());
6344 return errorReturn();
6346 if (!(ed
.memtype
&& ed
.memtype
.isintegral()))
6348 .error(loc
, "%s `%s` has no `.%s` property because base type `%s` is not an integral type", ed
.kind
, ed
.toPrettyChars
, id
.toChars(),
6349 id
.toChars(), ed
.memtype ? ed
.memtype
.toChars() : "");
6350 return errorReturn();
6354 for (size_t i
= 0; i
< ed
.members
.length
; i
++)
6356 EnumMember em
= (*ed
.members
)[i
].isEnumMember();
6365 if (em
.semanticRun
< PASS
.semanticdone
)
6367 .error(em
.loc
, "%s `%s` is forward referenced looking for `.%s`", em
.kind
, em
.toPrettyChars
, id
.toChars());
6379 /* In order to work successfully with UDTs,
6380 * build expressions to do the comparisons,
6381 * and let the semantic analyzer and constant
6382 * folder give us the result.
6389 Expression e
= em
.value
;
6390 Expression ec
= new CmpExp(id
== Id
.max ? EXP
.greaterThan
: EXP
.lessThan
, em
.loc
, e
, *pval
);
6392 ec
= ec
.expressionSemantic(em
._scope
);
6394 ec
= ec
.ctfeInterpret();
6395 if (ec
.op
== EXP
.error
)
6404 return ed
.errors ?
errorReturn() : pvalToResult(*pval
, loc
);
6407 /******************************************
6408 * Compile the MixinType, returning the type or expression AST.
6410 * Doesn't run semantic() on the returned object.
6412 * tm = mixin to compile as a type or expression
6413 * loc = location for error messages
6416 * null if error, else RootObject AST as parsed
6418 RootObject
compileTypeMixin(TypeMixin tm
, ref const Loc loc
, Scope
* sc
)
6421 if (expressionsToString(buf
, sc
, tm
.exps
))
6424 const errors
= global
.errors
;
6425 const len
= buf
.length
;
6427 const str = buf
.extractSlice()[0 .. len
];
6428 const bool doUnittests
= global
.params
.parsingUnittestsRequired();
6429 auto locm
= adjustLocForMixin(str, loc
, global
.params
.mixinOut
);
6430 scope p
= new Parser
!ASTCodegen(locm
, sc
._module
, str, false, global
.errorSink
, &global
.compileEnv
, doUnittests
);
6431 p
.transitionIn
= global
.params
.v
.vin
;
6433 //printf("p.loc.linnum = %d\n", p.loc.linnum);
6435 auto o
= p
.parseTypeOrAssignExp(TOK
.endOfFile
);
6436 if (errors
!= global
.errors
)
6438 assert(global
.errors
!= errors
); // should have caught all these cases
6441 if (p
.token
.value
!= TOK
.endOfFile
)
6443 .error(loc
, "unexpected token `%s` after type `%s`",
6444 p
.token
.toChars(), o
.toChars());
6445 .errorSupplemental(loc
, "while parsing string mixin type `%s`",