Internally these would treat the cast same as a normal conversion from int[7] to int[], which allows code at CTFE to erroneously succeed where it would raise a SEGV at run-time.
1 |
/**
|
|
2 |
* Semantic analysis for D types.
|
|
3 |
*
|
|
4 |
* Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
|
|
5 |
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
|
6 |
* License: $(LINK2 http://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
|
|
10 |
*/
|
|
11 |
|
|
12 |
module dmd.typesem; |
|
13 |
|
|
14 |
import core.checkedint; |
|
15 |
import core.stdc.string; |
|
16 |
import core.stdc.stdio; |
|
17 |
|
|
18 |
import dmd.access; |
|
19 |
import dmd.aggregate; |
|
20 |
import dmd.aliasthis; |
|
21 |
import dmd.arrayop; |
|
22 |
import dmd.arraytypes; |
|
23 |
import dmd.astcodegen; |
|
24 |
import dmd.complex; |
|
25 |
import dmd.dcast; |
|
26 |
import dmd.dclass; |
|
27 |
import dmd.declaration; |
|
28 |
import dmd.denum; |
|
29 |
import dmd.dimport; |
|
30 |
import dmd.dmangle; |
|
31 |
import dmd.dmodule : Module; |
|
32 |
import dmd.dscope; |
|
33 |
import dmd.dstruct; |
|
34 |
import dmd.dsymbol; |
|
35 |
import dmd.dsymbolsem; |
|
36 |
import dmd.dtemplate; |
|
37 |
import dmd.errors; |
|
38 |
import dmd.expression; |
|
39 |
import dmd.expressionsem; |
|
40 |
import dmd.func; |
|
41 |
import dmd.globals; |
|
42 |
import dmd.hdrgen; |
|
43 |
import dmd.id; |
|
44 |
import dmd.identifier; |
|
45 |
import dmd.imphint; |
|
46 |
import dmd.init; |
|
47 |
import dmd.initsem; |
|
48 |
import dmd.visitor; |
|
49 |
import dmd.mtype; |
|
50 |
import dmd.objc; |
|
51 |
import dmd.opover; |
|
52 |
import dmd.parse; |
|
53 |
import dmd.root.ctfloat; |
|
54 |
import dmd.root.rmem; |
|
55 |
import dmd.root.outbuffer; |
|
56 |
import dmd.root.rootobject; |
|
57 |
import dmd.root.string; |
|
58 |
import dmd.root.stringtable; |
|
59 |
import dmd.semantic3; |
|
60 |
import dmd.sideeffect; |
|
61 |
import dmd.target; |
|
62 |
import dmd.tokens; |
|
63 |
import dmd.typesem; |
|
64 |
|
|
65 |
/**************************
|
|
66 |
* This evaluates exp while setting length to be the number
|
|
67 |
* of elements in the tuple t.
|
|
68 |
*/
|
|
69 |
private Expression semanticLength(Scope* sc, Type t, Expression exp) |
|
70 |
{
|
|
71 | 1 |
if (auto tt = t.isTypeTuple()) |
72 |
{
|
|
73 | 1 |
ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt); |
74 | 1 |
sym.parent = sc.scopesym; |
75 | 1 |
sc = sc.push(sym); |
76 | 1 |
sc = sc.startCTFE(); |
77 | 1 |
exp = exp.expressionSemantic(sc); |
78 | 1 |
sc = sc.endCTFE(); |
79 | 1 |
sc.pop(); |
80 |
}
|
|
81 |
else
|
|
82 |
{
|
|
83 | 1 |
sc = sc.startCTFE(); |
84 | 1 |
exp = exp.expressionSemantic(sc); |
85 | 1 |
sc = sc.endCTFE(); |
86 |
}
|
|
87 | 1 |
return exp; |
88 |
}
|
|
89 |
|
|
90 |
private Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp) |
|
91 |
{
|
|
92 | 1 |
ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup); |
93 | 1 |
sym.parent = sc.scopesym; |
94 |
|
|
95 | 1 |
sc = sc.push(sym); |
96 | 1 |
sc = sc.startCTFE(); |
97 | 1 |
exp = exp.expressionSemantic(sc); |
98 | 1 |
sc = sc.endCTFE(); |
99 | 1 |
sc.pop(); |
100 |
|
|
101 | 1 |
return exp; |
102 |
}
|
|
103 |
|
|
104 |
/*************************************
|
|
105 |
* Resolve a tuple index.
|
|
106 |
*/
|
|
107 |
private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, Expression* pe, Type* pt, Dsymbol* ps, RootObject oindex) |
|
108 |
{
|
|
109 | 1 |
*pt = null; |
110 | 1 |
*ps = null; |
111 | 1 |
*pe = null; |
112 |
|
|
113 | 1 |
auto tup = s.isTupleDeclaration(); |
114 |
|
|
115 | 1 |
auto eindex = isExpression(oindex); |
116 | 1 |
auto tindex = isType(oindex); |
117 | 1 |
auto sindex = isDsymbol(oindex); |
118 |
|
|
119 | 1 |
if (!tup) |
120 |
{
|
|
121 |
// It's really an index expression
|
|
122 | 1 |
if (tindex) |
123 |
eindex = new TypeExp(loc, tindex); |
|
124 | 1 |
else if (sindex) |
125 |
eindex = symbolToExp(sindex, loc, sc, false); |
|
126 | 1 |
Expression e = new IndexExp(loc, symbolToExp(s, loc, sc, false), eindex); |
127 | 1 |
e = e.expressionSemantic(sc); |
128 | 1 |
resolveExp(e, pt, pe, ps); |
129 | 1 |
return; |
130 |
}
|
|
131 |
|
|
132 |
// Convert oindex to Expression, then try to resolve to constant.
|
|
133 | 1 |
if (tindex) |
134 | 1 |
tindex.resolve(loc, sc, &eindex, &tindex, &sindex); |
135 | 1 |
if (sindex) |
136 |
eindex = symbolToExp(sindex, loc, sc, false); |
|
137 | 1 |
if (!eindex) |
138 |
{
|
|
139 |
.error(loc, "index `%s` is not an expression", oindex.toChars()); |
|
140 |
*pt = Type.terror; |
|
141 |
return; |
|
142 |
}
|
|
143 |
|
|
144 | 1 |
eindex = semanticLength(sc, tup, eindex); |
145 | 1 |
eindex = eindex.ctfeInterpret(); |
146 | 1 |
if (eindex.op == TOK.error) |
147 |
{
|
|
148 |
*pt = Type.terror; |
|
149 |
return; |
|
150 |
}
|
|
151 | 1 |
const(uinteger_t) d = eindex.toUInteger(); |
152 | 1 |
if (d >= tup.objects.dim) |
153 |
{
|
|
154 |
.error(loc, "tuple index `%llu` exceeds length %llu", d, cast(ulong) tup.objects.dim); |
|
155 |
*pt = Type.terror; |
|
156 |
return; |
|
157 |
}
|
|
158 |
|
|
159 | 1 |
RootObject o = (*tup.objects)[cast(size_t)d]; |
160 | 1 |
*pt = isType(o); |
161 | 1 |
*ps = isDsymbol(o); |
162 | 1 |
*pe = isExpression(o); |
163 | 1 |
if (*pt) |
164 | 1 |
*pt = (*pt).typeSemantic(loc, sc); |
165 | 1 |
if (*pe) |
166 | 1 |
resolveExp(*pe, pt, pe, ps); |
167 |
}
|
|
168 |
|
|
169 |
/*************************************
|
|
170 |
* Takes an array of Identifiers and figures out if
|
|
171 |
* it represents a Type, Expression, or Dsymbol.
|
|
172 |
* Params:
|
|
173 |
* mt = array of identifiers
|
|
174 |
* loc = location for error messages
|
|
175 |
* sc = context
|
|
176 |
* s = symbol to start search at
|
|
177 |
* scopesym = unused
|
|
178 |
* pe = set if expression
|
|
179 |
* pt = set if type
|
|
180 |
* ps = set if symbol
|
|
181 |
* typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
|
|
182 |
*/
|
|
183 |
private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym, |
|
184 |
Expression* pe, Type* pt, Dsymbol* ps, bool intypeid = false) |
|
185 |
{
|
|
186 |
version (none) |
|
187 |
{
|
|
188 |
printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars()); |
|
189 |
if (scopesym) |
|
190 |
printf("\tscopesym = '%s'\n", scopesym.toChars()); |
|
191 |
}
|
|
192 | 1 |
*pe = null; |
193 | 1 |
*pt = null; |
194 | 1 |
*ps = null; |
195 |
|
|
196 | 1 |
if (!s) |
197 |
{
|
|
198 |
/* Look for what user might have intended
|
|
199 |
*/
|
|
200 | 1 |
const p = mt.mutableOf().unSharedOf().toChars(); |
201 | 1 |
auto id = Identifier.idPool(p, cast(uint)strlen(p)); |
202 | 1 |
if (const n = importHint(id.toString())) |
203 | 1 |
error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr); |
204 | 1 |
else if (auto s2 = sc.search_correct(id)) |
205 | 1 |
error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars()); |
206 | 1 |
else if (const q = Scope.search_correct_C(id)) |
207 | 1 |
error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q); |
208 |
else
|
|
209 | 1 |
error(loc, "undefined identifier `%s`", p); |
210 |
|
|
211 | 1 |
*pt = Type.terror; |
212 | 1 |
return; |
213 |
}
|
|
214 |
|
|
215 |
//printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
|
|
216 | 1 |
Declaration d = s.isDeclaration(); |
217 | 1 |
if (d && (d.storage_class & STC.templateparameter)) |
218 | 1 |
s = s.toAlias(); |
219 |
else
|
|
220 |
{
|
|
221 |
// check for deprecated or disabled aliases
|
|
222 | 1 |
s.checkDeprecated(loc, sc); |
223 | 1 |
if (d) |
224 | 1 |
d.checkDisabled(loc, sc, true); |
225 |
}
|
|
226 | 1 |
s = s.toAlias(); |
227 |
//printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
|
|
228 | 1 |
for (size_t i = 0; i < mt.idents.dim; i++) |
229 |
{
|
|
230 | 1 |
RootObject id = mt.idents[i]; |
231 | 1 |
if (id.dyncast() == DYNCAST.expression || |
232 | 1 |
id.dyncast() == DYNCAST.type) |
233 |
{
|
|
234 | 1 |
Type tx; |
235 | 1 |
Expression ex; |
236 | 1 |
Dsymbol sx; |
237 | 1 |
resolveTupleIndex(loc, sc, s, &ex, &tx, &sx, id); |
238 | 1 |
if (sx) |
239 |
{
|
|
240 | 1 |
s = sx.toAlias(); |
241 | 1 |
continue; |
242 |
}
|
|
243 | 1 |
if (tx) |
244 | 1 |
ex = new TypeExp(loc, tx); |
245 | 1 |
assert(ex); |
246 |
|
|
247 | 1 |
ex = typeToExpressionHelper(mt, ex, i + 1); |
248 | 1 |
ex = ex.expressionSemantic(sc); |
249 | 1 |
resolveExp(ex, pt, pe, ps); |
250 | 1 |
return; |
251 |
}
|
|
252 |
|
|
253 | 1 |
Type t = s.getType(); // type symbol, type alias, or type tuple? |
254 | 1 |
uint errorsave = global.errors; |
255 | 1 |
int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports; |
256 |
|
|
257 | 1 |
Dsymbol sm = s.searchX(loc, sc, id, flags); |
258 | 1 |
if (sm && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm)) |
259 |
{
|
|
260 | 1 |
.error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars()); |
261 | 1 |
sm = null; |
262 |
}
|
|
263 | 1 |
if (global.errors != errorsave) |
264 |
{
|
|
265 | 1 |
*pt = Type.terror; |
266 | 1 |
return; |
267 |
}
|
|
268 |
|
|
269 |
void helper3() |
|
270 |
{
|
|
271 | 1 |
Expression e; |
272 | 1 |
VarDeclaration v = s.isVarDeclaration(); |
273 | 1 |
FuncDeclaration f = s.isFuncDeclaration(); |
274 | 1 |
if (intypeid || !v && !f) |
275 | 1 |
e = symbolToExp(s, loc, sc, true); |
276 |
else
|
|
277 | 1 |
e = new VarExp(loc, s.isDeclaration(), true); |
278 |
|
|
279 | 1 |
e = typeToExpressionHelper(mt, e, i); |
280 | 1 |
e = e.expressionSemantic(sc); |
281 | 1 |
resolveExp(e, pt, pe, ps); |
282 |
}
|
|
283 |
|
|
284 |
//printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
|
|
285 | 1 |
if (intypeid && !t && sm && sm.needThis()) |
286 | 1 |
return helper3(); |
287 |
|
|
288 | 1 |
if (VarDeclaration v = s.isVarDeclaration()) |
289 |
{
|
|
290 |
// https://issues.dlang.org/show_bug.cgi?id=19913
|
|
291 |
// v.type would be null if it is a forward referenced member.
|
|
292 | 1 |
if (v.type is null) |
293 | 1 |
v.dsymbolSemantic(sc); |
294 | 1 |
if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) || |
295 | 1 |
v.type.isConst() || v.type.isImmutable()) |
296 |
{
|
|
297 |
// https://issues.dlang.org/show_bug.cgi?id=13087
|
|
298 |
// this.field is not constant always
|
|
299 | 1 |
if (!v.isThisDeclaration()) |
300 | 1 |
return helper3(); |
301 |
}
|
|
302 |
}
|
|
303 | 1 |
if (!sm) |
304 |
{
|
|
305 | 1 |
if (!t) |
306 |
{
|
|
307 | 1 |
if (s.isDeclaration()) // var, func, or tuple declaration? |
308 |
{
|
|
309 | 1 |
t = s.isDeclaration().type; |
310 | 1 |
if (!t && s.isTupleDeclaration()) // expression tuple? |
311 | 1 |
return helper3(); |
312 |
}
|
|
313 | 1 |
else if (s.isTemplateInstance() || |
314 | 1 |
s.isImport() || s.isPackage() || s.isModule()) |
315 |
{
|
|
316 | 1 |
return helper3(); |
317 |
}
|
|
318 |
}
|
|
319 | 1 |
if (t) |
320 |
{
|
|
321 | 1 |
sm = t.toDsymbol(sc); |
322 | 1 |
if (sm && id.dyncast() == DYNCAST.identifier) |
323 |
{
|
|
324 | 1 |
sm = sm.search(loc, cast(Identifier)id, IgnorePrivateImports); |
325 | 1 |
if (!sm) |
326 | 1 |
return helper3(); |
327 |
}
|
|
328 |
else
|
|
329 | 1 |
return helper3(); |
330 |
}
|
|
331 |
else
|
|
332 |
{
|
|
333 | 1 |
if (id.dyncast() == DYNCAST.dsymbol) |
334 |
{
|
|
335 |
// searchX already handles errors for template instances
|
|
336 |
assert(global.errors); |
|
337 |
}
|
|
338 |
else
|
|
339 |
{
|
|
340 | 1 |
assert(id.dyncast() == DYNCAST.identifier); |
341 | 1 |
sm = s.search_correct(cast(Identifier)id); |
342 | 1 |
if (sm) |
343 |
error(loc, "identifier `%s` of `%s` is not defined, did you mean %s `%s`?", id.toChars(), mt.toChars(), sm.kind(), sm.toChars()); |
|
344 |
else
|
|
345 | 1 |
error(loc, "identifier `%s` of `%s` is not defined", id.toChars(), mt.toChars()); |
346 |
}
|
|
347 | 1 |
*pe = ErrorExp.get(); |
348 | 1 |
return; |
349 |
}
|
|
350 |
}
|
|
351 | 1 |
s = sm.toAlias(); |
352 |
}
|
|
353 |
|
|
354 | 1 |
if (auto em = s.isEnumMember()) |
355 |
{
|
|
356 |
// It's not a type, it's an expression
|
|
357 | 1 |
*pe = em.getVarExp(loc, sc); |
358 | 1 |
return; |
359 |
}
|
|
360 | 1 |
if (auto v = s.isVarDeclaration()) |
361 |
{
|
|
362 |
/* This is mostly same with DsymbolExp::semantic(), but we cannot use it
|
|
363 |
* because some variables used in type context need to prevent lowering
|
|
364 |
* to a literal or contextful expression. For example:
|
|
365 |
*
|
|
366 |
* enum a = 1; alias b = a;
|
|
367 |
* template X(alias e){ alias v = e; } alias x = X!(1);
|
|
368 |
* struct S { int v; alias w = v; }
|
|
369 |
* // TypeIdentifier 'a', 'e', and 'v' should be TOK.variable,
|
|
370 |
* // because getDsymbol() need to work in AliasDeclaration::semantic().
|
|
371 |
*/
|
|
372 | 1 |
if (!v.type || |
373 | 1 |
!v.type.deco && v.inuse) |
374 |
{
|
|
375 | 1 |
if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494 |
376 | 1 |
error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars()); |
377 |
else
|
|
378 |
error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars()); |
|
379 | 1 |
*pt = Type.terror; |
380 | 1 |
return; |
381 |
}
|
|
382 | 1 |
if (v.type.ty == Terror) |
383 | 1 |
*pt = Type.terror; |
384 |
else
|
|
385 | 1 |
*pe = new VarExp(loc, v); |
386 | 1 |
return; |
387 |
}
|
|
388 | 1 |
if (auto fld = s.isFuncLiteralDeclaration()) |
389 |
{
|
|
390 |
//printf("'%s' is a function literal\n", fld.toChars());
|
|
391 | 1 |
*pe = new FuncExp(loc, fld); |
392 | 1 |
*pe = (*pe).expressionSemantic(sc); |
393 | 1 |
return; |
394 |
}
|
|
395 |
version (none) |
|
396 |
{
|
|
397 |
if (FuncDeclaration fd = s.isFuncDeclaration()) |
|
398 |
{
|
|
399 |
*pe = new DsymbolExp(loc, fd); |
|
400 |
return; |
|
401 |
}
|
|
402 |
}
|
|
403 |
|
|
404 | 1 |
Type t; |
405 | 1 |
while (1) |
406 |
{
|
|
407 | 1 |
t = s.getType(); |
408 | 1 |
if (t) |
409 | 1 |
break; |
410 |
// If the symbol is an import, try looking inside the import
|
|
411 | 1 |
if (Import si = s.isImport()) |
412 |
{
|
|
413 | 1 |
s = si.search(loc, s.ident); |
414 | 1 |
if (s && s != si) |
415 | 1 |
continue; |
416 | 1 |
s = si; |
417 |
}
|
|
418 | 1 |
*ps = s; |
419 | 1 |
return; |
420 |
}
|
|
421 |
|
|
422 | 1 |
if (auto ti = t.isTypeInstance()) |
423 | 1 |
if (ti != mt && !ti.deco) |
424 |
{
|
|
425 | 1 |
if (!ti.tempinst.errors) |
426 |
error(loc, "forward reference to `%s`", ti.toChars()); |
|
427 | 1 |
*pt = Type.terror; |
428 | 1 |
return; |
429 |
}
|
|
430 |
|
|
431 | 1 |
if (t.ty == Ttuple) |
432 | 1 |
*pt = t; |
433 |
else
|
|
434 | 1 |
*pt = t.merge(); |
435 |
}
|
|
436 |
|
|
437 |
/************************************
|
|
438 |
* Transitively search a type for all function types.
|
|
439 |
* If any function types with parameters are found that have parameter identifiers
|
|
440 |
* or default arguments, remove those and create a new type stripped of those.
|
|
441 |
* This is used to determine the "canonical" version of a type which is useful for
|
|
442 |
* comparisons.
|
|
443 |
* Params:
|
|
444 |
* t = type to scan
|
|
445 |
* Returns:
|
|
446 |
* `t` if no parameter identifiers or default arguments found, otherwise a new type that is
|
|
447 |
* the same as t but with no parameter identifiers or default arguments.
|
|
448 |
*/
|
|
449 |
private Type stripDefaultArgs(Type t) |
|
450 |
{
|
|
451 |
static Parameters* stripParams(Parameters* parameters) |
|
452 |
{
|
|
453 |
static Parameter stripParameter(Parameter p) |
|
454 |
{
|
|
455 | 1 |
Type t = stripDefaultArgs(p.type); |
456 | 1 |
return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl) |
457 | 1 |
? new Parameter(p.storageClass, t, null, null, null) |
458 | 1 |
: null; |
459 |
}
|
|
460 |
|
|
461 | 1 |
if (parameters) |
462 |
{
|
|
463 | 1 |
foreach (i, p; *parameters) |
464 |
{
|
|
465 | 1 |
Parameter ps = stripParameter(p); |
466 | 1 |
if (ps) |
467 |
{
|
|
468 |
// Replace params with a copy we can modify
|
|
469 | 1 |
Parameters* nparams = new Parameters(parameters.dim); |
470 |
|
|
471 | 1 |
foreach (j, ref np; *nparams) |
472 |
{
|
|
473 | 1 |
Parameter pj = (*parameters)[j]; |
474 | 1 |
if (j < i) |
475 | 1 |
np = pj; |
476 | 1 |
else if (j == i) |
477 | 1 |
np = ps; |
478 |
else
|
|
479 |
{
|
|
480 | 1 |
Parameter nps = stripParameter(pj); |
481 | 1 |
np = nps ? nps : pj; |
482 |
}
|
|
483 |
}
|
|
484 | 1 |
return nparams; |
485 |
}
|
|
486 |
}
|
|
487 |
}
|
|
488 | 1 |
return parameters; |
489 |
}
|
|
490 |
|
|
491 | 1 |
if (t is null) |
492 | 1 |
return t; |
493 |
|
|
494 | 1 |
if (auto tf = t.isTypeFunction()) |
495 |
{
|
|
496 | 1 |
Type tret = stripDefaultArgs(tf.next); |
497 | 1 |
Parameters* params = stripParams(tf.parameterList.parameters); |
498 | 1 |
if (tret == tf.next && params == tf.parameterList.parameters) |
499 | 1 |
return t; |
500 | 1 |
TypeFunction tr = cast(TypeFunction)tf.copy(); |
501 | 1 |
tr.parameterList.parameters = params; |
502 | 1 |
tr.next = tret; |
503 |
//printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
|
|
504 | 1 |
return tr; |
505 |
}
|
|
506 | 1 |
else if (auto tt = t.isTypeTuple()) |
507 |
{
|
|
508 | 1 |
Parameters* args = stripParams(tt.arguments); |
509 | 1 |
if (args == tt.arguments) |
510 | 1 |
return t; |
511 | 1 |
TypeTuple tr = cast(TypeTuple)t.copy(); |
512 | 1 |
tr.arguments = args; |
513 | 1 |
return tr; |
514 |
}
|
|
515 | 1 |
else if (t.ty == Tenum) |
516 |
{
|
|
517 |
// TypeEnum::nextOf() may be != NULL, but it's not necessary here.
|
|
518 | 1 |
return t; |
519 |
}
|
|
520 |
else
|
|
521 |
{
|
|
522 | 1 |
Type tn = t.nextOf(); |
523 | 1 |
Type n = stripDefaultArgs(tn); |
524 | 1 |
if (n == tn) |
525 | 1 |
return t; |
526 | 1 |
TypeNext tr = cast(TypeNext)t.copy(); |
527 | 1 |
tr.next = n; |
528 | 1 |
return tr; |
529 |
}
|
|
530 |
}
|
|
531 |
|
|
532 |
/******************************************
|
|
533 |
* We've mistakenly parsed `t` as a type.
|
|
534 |
* Redo `t` as an Expression only if there are no type modifiers.
|
|
535 |
* Params:
|
|
536 |
* t = mistaken type
|
|
537 |
* Returns:
|
|
538 |
* t redone as Expression, null if cannot
|
|
539 |
*/
|
|
540 |
Expression typeToExpression(Type t) |
|
541 |
{
|
|
542 |
static Expression visitSArray(TypeSArray t) |
|
543 |
{
|
|
544 | 1 |
if (auto e = t.next.typeToExpression()) |
545 | 1 |
return new ArrayExp(t.dim.loc, e, t.dim); |
546 |
return null; |
|
547 |
}
|
|
548 |
|
|
549 |
static Expression visitAArray(TypeAArray t) |
|
550 |
{
|
|
551 | 1 |
if (auto e = t.next.typeToExpression()) |
552 |
{
|
|
553 | 1 |
if (auto ei = t.index.typeToExpression()) |
554 | 1 |
return new ArrayExp(t.loc, e, ei); |
555 |
}
|
|
556 | 1 |
return null; |
557 |
}
|
|
558 |
|
|
559 |
static Expression visitIdentifier(TypeIdentifier t) |
|
560 |
{
|
|
561 | 1 |
return typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident)); |
562 |
}
|
|
563 |
|
|
564 |
static Expression visitInstance(TypeInstance t) |
|
565 |
{
|
|
566 | 1 |
return typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst)); |
567 |
}
|
|
568 |
|
|
569 |
// easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
|
|
570 |
static Expression visitMixin(TypeMixin t) |
|
571 |
{
|
|
572 | 1 |
return new TypeExp(t.loc, t); |
573 |
}
|
|
574 |
|
|
575 | 1 |
if (t.mod) |
576 | 1 |
return null; |
577 | 1 |
switch (t.ty) |
578 |
{
|
|
579 | 1 |
case Tsarray: return visitSArray(cast(TypeSArray) t); |
580 | 1 |
case Taarray: return visitAArray(cast(TypeAArray) t); |
581 | 1 |
case Tident: return visitIdentifier(cast(TypeIdentifier) t); |
582 | 1 |
case Tinstance: return visitInstance(cast(TypeInstance) t); |
583 | 1 |
case Tmixin: return visitMixin(cast(TypeMixin) t); |
584 | 1 |
default: return null; |
585 |
}
|
|
586 |
}
|
|
587 |
|
|
588 |
/* Helper function for `typeToExpression`. Contains common code
|
|
589 |
* for TypeQualified derived classes.
|
|
590 |
*/
|
|
591 |
Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0) |
|
592 |
{
|
|
593 |
//printf("toExpressionHelper(e = %s %s)\n", Token.toChars(e.op), e.toChars());
|
|
594 | 1 |
foreach (id; t.idents[i .. t.idents.dim]) |
595 |
{
|
|
596 |
//printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
|
|
597 |
|
|
598 | 1 |
final switch (id.dyncast()) |
599 |
{
|
|
600 |
// ... '. ident'
|
|
601 | 1 |
case DYNCAST.identifier: |
602 | 1 |
e = new DotIdExp(e.loc, e, cast(Identifier)id); |
603 | 1 |
break; |
604 |
|
|
605 |
// ... '. name!(tiargs)'
|
|
606 | 1 |
case DYNCAST.dsymbol: |
607 | 1 |
auto ti = (cast(Dsymbol)id).isTemplateInstance(); |
608 | 1 |
assert(ti); |
609 | 1 |
e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs); |
610 | 1 |
break; |
611 |
|
|
612 |
// ... '[type]'
|
|
613 |
case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215 |
|
614 |
e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id)); |
|
615 |
break; |
|
616 |
|
|
617 |
// ... '[expr]'
|
|
618 | 1 |
case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215 |
619 | 1 |
e = new ArrayExp(t.loc, e, cast(Expression)id); |
620 | 1 |
break; |
621 |
|
|
622 |
case DYNCAST.object: |
|
623 |
case DYNCAST.tuple: |
|
624 |
case DYNCAST.parameter: |
|
625 |
case DYNCAST.statement: |
|
626 |
case DYNCAST.condition: |
|
627 |
case DYNCAST.templateparameter: |
|
628 |
assert(0); |
|
629 |
}
|
|
630 |
}
|
|
631 | 1 |
return e; |
632 |
}
|
|
633 |
|
|
634 |
/******************************************
|
|
635 |
* Perform semantic analysis on a type.
|
|
636 |
* Params:
|
|
637 |
* t = Type AST node
|
|
638 |
* loc = the location of the type
|
|
639 |
* sc = context
|
|
640 |
* Returns:
|
|
641 |
* `Type` with completed semantic analysis, `Terror` if errors
|
|
642 |
* were encountered
|
|
643 |
*/
|
|
644 |
extern(C++) Type typeSemantic(Type t, const ref Loc loc, Scope* sc) |
|
645 |
{
|
|
646 |
static Type error() |
|
647 |
{
|
|
648 | 1 |
return Type.terror; |
649 |
}
|
|
650 |
|
|
651 |
Type visitType(Type t) |
|
652 |
{
|
|
653 | 1 |
if (t.ty == Tint128 || t.ty == Tuns128) |
654 |
{
|
|
655 | 1 |
.error(loc, "`cent` and `ucent` types not implemented"); |
656 | 1 |
return error(); |
657 |
}
|
|
658 |
|
|
659 | 1 |
return t.merge(); |
660 |
}
|
|
661 |
|
|
662 |
Type visitVector(TypeVector mtype) |
|
663 |
{
|
|
664 | 1 |
const errors = global.errors; |
665 | 1 |
mtype.basetype = mtype.basetype.typeSemantic(loc, sc); |
666 | 1 |
if (errors != global.errors) |
667 |
return error(); |
|
668 | 1 |
mtype.basetype = mtype.basetype.toBasetype().mutableOf(); |
669 | 1 |
if (mtype.basetype.ty != Tsarray) |
670 |
{
|
|
671 | 1 |
.error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars()); |
672 | 1 |
return error(); |
673 |
}
|
|
674 | 1 |
TypeSArray t = cast(TypeSArray)mtype.basetype; |
675 | 1 |
const sz = cast(int)t.size(loc); |
676 | 1 |
final switch (target.isVectorTypeSupported(sz, t.nextOf())) |
677 |
{
|
|
678 | 1 |
case 0: |
679 |
// valid
|
|
680 | 1 |
break; |
681 |
|
|
682 |
case 1: |
|
683 |
// no support at all
|
|
684 |
.error(loc, "SIMD vector types not supported on this platform"); |
|
685 |
return error(); |
|
686 |
|
|
687 | 1 |
case 2: |
688 |
// invalid base type
|
|
689 | 1 |
.error(loc, "vector type `%s` is not supported on this platform", mtype.toChars()); |
690 | 1 |
return error(); |
691 |
|
|
692 | 1 |
case 3: |
693 |
// invalid size
|
|
694 | 1 |
.error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars()); |
695 | 1 |
return error(); |
696 |
}
|
|
697 | 1 |
return merge(mtype); |
698 |
}
|
|
699 |
|
|
700 |
Type visitSArray(TypeSArray mtype) |
|
701 |
{
|
|
702 |
//printf("TypeSArray::semantic() %s\n", toChars());
|
|
703 | 1 |
Type t; |
704 | 1 |
Expression e; |
705 | 1 |
Dsymbol s; |
706 | 1 |
mtype.next.resolve(loc, sc, &e, &t, &s); |
707 |
|
|
708 | 1 |
if (auto tup = s ? s.isTupleDeclaration() : null) |
709 |
{
|
|
710 | 1 |
mtype.dim = semanticLength(sc, tup, mtype.dim); |
711 | 1 |
mtype.dim = mtype.dim.ctfeInterpret(); |
712 | 1 |
if (mtype.dim.op == TOK.error) |
713 | 1 |
return error(); |
714 |
|
|
715 | 1 |
uinteger_t d = mtype.dim.toUInteger(); |
716 | 1 |
if (d >= tup.objects.dim) |
717 |
{
|
|
718 | 1 |
.error(loc, "tuple index %llu exceeds %llu", cast(ulong)d, cast(ulong)tup.objects.dim); |
719 | 1 |
return error(); |
720 |
}
|
|
721 |
|
|
722 | 1 |
RootObject o = (*tup.objects)[cast(size_t)d]; |
723 | 1 |
if (o.dyncast() != DYNCAST.type) |
724 |
{
|
|
725 | 1 |
.error(loc, "`%s` is not a type", mtype.toChars()); |
726 | 1 |
return error(); |
727 |
}
|
|
728 | 1 |
return (cast(Type)o).addMod(mtype.mod); |
729 |
}
|
|
730 |
|
|
731 | 1 |
Type tn = mtype.next.typeSemantic(loc, sc); |
732 | 1 |
if (tn.ty == Terror) |
733 | 1 |
return error(); |
734 |
|
|
735 | 1 |
Type tbn = tn.toBasetype(); |
736 | 1 |
if (mtype.dim) |
737 |
{
|
|
738 |
//https://issues.dlang.org/show_bug.cgi?id=15478
|
|
739 | 1 |
if (mtype.dim.isDotVarExp()) |
740 |
{
|
|
741 | 1 |
if (Declaration vd = mtype.dim.isDotVarExp().var) |
742 |
{
|
|
743 | 1 |
FuncDeclaration fd = vd.toAlias().isFuncDeclaration(); |
744 | 1 |
if (fd) |
745 | 1 |
mtype.dim = new CallExp(loc, fd, null); |
746 |
}
|
|
747 |
}
|
|
748 |
|
|
749 | 1 |
auto errors = global.errors; |
750 | 1 |
mtype.dim = semanticLength(sc, tbn, mtype.dim); |
751 | 1 |
if (errors != global.errors) |
752 | 1 |
return error(); |
753 |
|
|
754 | 1 |
mtype.dim = mtype.dim.optimize(WANTvalue); |
755 | 1 |
mtype.dim = mtype.dim.ctfeInterpret(); |
756 | 1 |
if (mtype.dim.op == TOK.error) |
757 | 1 |
return error(); |
758 |
|
|
759 | 1 |
errors = global.errors; |
760 | 1 |
dinteger_t d1 = mtype.dim.toInteger(); |
761 | 1 |
if (errors != global.errors) |
762 |
return error(); |
|
763 |
|
|
764 | 1 |
mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t); |
765 | 1 |
mtype.dim = mtype.dim.optimize(WANTvalue); |
766 | 1 |
if (mtype.dim.op == TOK.error) |
767 |
return error(); |
|
768 |
|
|
769 | 1 |
errors = global.errors; |
770 | 1 |
dinteger_t d2 = mtype.dim.toInteger(); |
771 | 1 |
if (errors != global.errors) |
772 |
return error(); |
|
773 |
|
|
774 | 1 |
if (mtype.dim.op == TOK.error) |
775 |
return error(); |
|
776 |
|
|
777 |
Type overflowError() |
|
778 |
{
|
|
779 | 1 |
.error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array", |
780 |
mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, target.maxStaticDataSize); |
|
781 | 1 |
return error(); |
782 |
}
|
|
783 |
|
|
784 | 1 |
if (d1 != d2) |
785 |
return overflowError(); |
|
786 |
|
|
787 | 1 |
Type tbx = tbn.baseElemOf(); |
788 | 1 |
if (tbx.ty == Tstruct && !(cast(TypeStruct)tbx).sym.members || |
789 | 1 |
tbx.ty == Tenum && !(cast(TypeEnum)tbx).sym.members) |
790 |
{
|
|
791 |
/* To avoid meaningless error message, skip the total size limit check
|
|
792 |
* when the bottom of element type is opaque.
|
|
793 |
*/
|
|
794 |
}
|
|
795 | 1 |
else if (tbn.isTypeBasic() || |
796 | 1 |
tbn.ty == Tpointer || |
797 | 1 |
tbn.ty == Tarray || |
798 | 1 |
tbn.ty == Tsarray || |
799 | 1 |
tbn.ty == Taarray || |
800 | 1 |
(tbn.ty == Tstruct && ((cast(TypeStruct)tbn).sym.sizeok == Sizeok.done)) || |
801 | 1 |
tbn.ty == Tclass) |
802 |
{
|
|
803 |
/* Only do this for types that don't need to have semantic()
|
|
804 |
* run on them for the size, since they may be forward referenced.
|
|
805 |
*/
|
|
806 | 1 |
bool overflow = false; |
807 | 1 |
if (mulu(tbn.size(loc), d2, overflow) >= target.maxStaticDataSize || overflow) |
808 | 1 |
return overflowError(); |
809 |
}
|
|
810 |
}
|
|
811 | 1 |
switch (tbn.ty) |
812 |
{
|
|
813 | 1 |
case Ttuple: |
814 |
{
|
|
815 |
// Index the tuple to get the type
|
|
816 | 1 |
assert(mtype.dim); |
817 | 1 |
TypeTuple tt = cast(TypeTuple)tbn; |
818 | 1 |
uinteger_t d = mtype.dim.toUInteger(); |
819 | 1 |
if (d >= tt.arguments.dim) |
820 |
{
|
|
821 | 1 |
.error(loc, "tuple index %llu exceeds %llu", cast(ulong)d, cast(ulong)tt.arguments.dim); |
822 | 1 |
return error(); |
823 |
}
|
|
824 | 1 |
Type telem = (*tt.arguments)[cast(size_t)d].type; |
825 | 1 |
return telem.addMod(mtype.mod); |
826 |
}
|
|
827 |
|
|
828 | 1 |
case Tfunction: |
829 | 1 |
case Tnone: |
830 | 1 |
.error(loc, "cannot have array of `%s`", tbn.toChars()); |
831 | 1 |
return error(); |
832 |
|
|
833 | 1 |
default: |
834 | 1 |
break; |
835 |
}
|
|
836 | 1 |
if (tbn.isscope()) |
837 |
{
|
|
838 | 1 |
.error(loc, "cannot have array of scope `%s`", tbn.toChars()); |
839 | 1 |
return error(); |
840 |
}
|
|
841 |
|
|
842 |
/* Ensure things like const(immutable(T)[3]) become immutable(T[3])
|
|
843 |
* and const(T)[3] become const(T[3])
|
|
844 |
*/
|
|
845 | 1 |
mtype.next = tn; |
846 | 1 |
mtype.transitive(); |
847 | 1 |
return mtype.addMod(tn.mod).merge(); |
848 |
}
|
|
849 |
|
|
850 |
Type visitDArray(TypeDArray mtype) |
|
851 |
{
|
|
852 | 1 |
Type tn = mtype.next.typeSemantic(loc, sc); |
853 | 1 |
Type tbn = tn.toBasetype(); |
854 | 1 |
switch (tbn.ty) |
855 |
{
|
|
856 | 1 |
case Ttuple: |
857 | 1 |
return tbn; |
858 |
|
|
859 | 1 |
case Tfunction: |
860 | 1 |
case Tnone: |
861 | 1 |
.error(loc, "cannot have array of `%s`", tbn.toChars()); |
862 | 1 |
return error(); |
863 |
|
|
864 | 1 |
case Terror: |
865 | 1 |
return error(); |
866 |
|
|
867 | 1 |
default: |
868 | 1 |
break; |
869 |
}
|
|
870 | 1 |
if (tn.isscope()) |
871 |
{
|
|
872 | 1 |
.error(loc, "cannot have array of scope `%s`", tn.toChars()); |
873 | 1 |
return error(); |
874 |
}
|
|
875 | 1 |
mtype.next = tn; |
876 | 1 |
mtype.transitive(); |
877 | 1 |
return merge(mtype); |
878 |
}
|
|
879 |
|
|
880 |
Type visitAArray(TypeAArray mtype) |
|
881 |
{
|
|
882 |
//printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
|
|
883 | 1 |
if (mtype.deco) |
884 |
{
|
|
885 | 1 |
return mtype; |
886 |
}
|
|
887 |
|
|
888 | 1 |
mtype.loc = loc; |
889 | 1 |
if (sc) |
890 | 1 |
sc.setNoFree(); |
891 |
|
|
892 |
// Deal with the case where we thought the index was a type, but
|
|
893 |
// in reality it was an expression.
|
|
894 | 1 |
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) |
895 |
{
|
|
896 | 1 |
Expression e; |
897 | 1 |
Type t; |
898 | 1 |
Dsymbol s; |
899 | 1 |
mtype.index.resolve(loc, sc, &e, &t, &s); |
900 |
|
|
901 |
//https://issues.dlang.org/show_bug.cgi?id=15478
|
|
902 | 1 |
if (s) |
903 |
{
|
|
904 | 1 |
if (FuncDeclaration fd = s.toAlias().isFuncDeclaration()) |
905 | 1 |
e = new CallExp(loc, fd, null); |
906 |
}
|
|
907 |
|
|
908 | 1 |
if (e) |
909 |
{
|
|
910 |
// It was an expression -
|
|
911 |
// Rewrite as a static array
|
|
912 | 1 |
auto tsa = new TypeSArray(mtype.next, e); |
913 | 1 |
return tsa.typeSemantic(loc, sc); |
914 |
}
|
|
915 | 1 |
else if (t) |
916 | 1 |
mtype.index = t.typeSemantic(loc, sc); |
917 |
else
|
|
918 |
{
|
|
919 |
.error(loc, "index is not a type or an expression"); |
|
920 |
return error(); |
|
921 |
}
|
|
922 |
}
|
|
923 |
else
|
|
924 | 1 |
mtype.index = mtype.index.typeSemantic(loc, sc); |
925 | 1 |
mtype.index = mtype.index.merge2(); |
926 |
|
|
927 | 1 |
if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable()) |
928 |
{
|
|
929 | 1 |
mtype.index = mtype.index.constOf().mutableOf(); |
930 |
version (none) |
|
931 |
{
|
|
932 |
printf("index is %p %s\n", mtype.index, mtype.index.toChars()); |
|
933 |
mtype.index.check(); |
|
934 |
printf("index.mod = x%x\n", mtype.index.mod); |
|
935 |
printf("index.ito = x%x\n", mtype.index.ito); |
|
936 |
if (mtype.index.ito) |
|
937 |
{
|
|
938 |
printf("index.ito.mod = x%x\n", mtype.index.ito.mod); |
|
939 |
printf("index.ito.ito = x%x\n", mtype.index.ito.ito); |
|
940 |
}
|
|
941 |
}
|
|
942 |
}
|
|
943 |
|
|
944 | 1 |
switch (mtype.index.toBasetype().ty) |
945 |
{
|
|
946 | 1 |
case Tfunction: |
947 | 1 |
case Tvoid: |
948 | 1 |
case Tnone: |
949 | 1 |
case Ttuple: |
950 | 1 |
.error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars()); |
951 | 1 |
goto case Terror; |
952 | 1 |
case Terror: |
953 | 1 |
return error(); |
954 |
|
|
955 | 1 |
default: |
956 | 1 |
break; |
957 |
}
|
|
958 | 1 |
Type tbase = mtype.index.baseElemOf(); |
959 | 1 |
while (tbase.ty == Tarray) |
960 | 1 |
tbase = tbase.nextOf().baseElemOf(); |
961 | 1 |
if (auto ts = tbase.isTypeStruct()) |
962 |
{
|
|
963 |
/* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
|
|
964 |
*/
|
|
965 | 1 |
StructDeclaration sd = ts.sym; |
966 | 1 |
if (sd.semanticRun < PASS.semanticdone) |
967 | 1 |
sd.dsymbolSemantic(null); |
968 |
|
|
969 |
// duplicate a part of StructDeclaration::semanticTypeInfoMembers
|
|
970 |
//printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
|
|
971 | 1 |
if (sd.xeq && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done) |
972 |
{
|
|
973 | 1 |
uint errors = global.startGagging(); |
974 | 1 |
sd.xeq.semantic3(sd.xeq._scope); |
975 | 1 |
if (global.endGagging(errors)) |
976 | 1 |
sd.xeq = sd.xerreq; |
977 |
}
|
|
978 |
|
|
979 |
//printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
|
|
980 | 1 |
const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : ""; |
981 | 1 |
if (!sd.xeq) |
982 |
{
|
|
983 |
// If sd.xhash != NULL:
|
|
984 |
// sd or its fields have user-defined toHash.
|
|
985 |
// AA assumes that its result is consistent with bitwise equality.
|
|
986 |
// else:
|
|
987 |
// bitwise equality & hashing
|
|
988 |
}
|
|
989 | 1 |
else if (sd.xeq == sd.xerreq) |
990 |
{
|
|
991 | 1 |
if (search_function(sd, Id.eq)) |
992 |
{
|
|
993 | 1 |
.error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars()); |
994 |
}
|
|
995 |
else
|
|
996 |
{
|
|
997 | 1 |
.error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars()); |
998 |
}
|
|
999 | 1 |
return error(); |
1000 |
}
|
|
1001 | 1 |
else if (!sd.xhash) |
1002 |
{
|
|
1003 | 1 |
if (search_function(sd, Id.eq)) |
1004 |
{
|
|
1005 | 1 |
.error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars()); |
1006 |
}
|
|
1007 |
else
|
|
1008 |
{
|
|
1009 | 1 |
.error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars()); |
1010 |
}
|
|
1011 | 1 |
return error(); |
1012 |
}
|
|
1013 |
else
|
|
1014 |
{
|
|
1015 |
// defined equality & hashing
|
|
1016 | 1 |
assert(sd.xeq && sd.xhash); |
1017 |
|
|
1018 |
/* xeq and xhash may be implicitly defined by compiler. For example:
|
|
1019 |
* struct S { int[] arr; }
|
|
1020 |
* With 'arr' field equality and hashing, compiler will implicitly
|
|
1021 |
* generate functions for xopEquals and xtoHash in TypeInfo_Struct.
|
|
1022 |
*/
|
|
1023 |
}
|
|
1024 |
}
|
|
1025 | 1 |
else if (tbase.ty == Tclass && !(cast(TypeClass)tbase).sym.isInterfaceDeclaration()) |
1026 |
{
|
|
1027 | 1 |
ClassDeclaration cd = (cast(TypeClass)tbase).sym; |
1028 | 1 |
if (cd.semanticRun < PASS.semanticdone) |
1029 | 1 |
cd.dsymbolSemantic(null); |
1030 |
|
|
1031 | 1 |
if (!ClassDeclaration.object) |
1032 |
{
|
|
1033 |
.error(Loc.initial, "missing or corrupt object.d"); |
|
1034 |
fatal(); |
|
1035 |
}
|
|
1036 |
|
|
1037 | 1 |
__gshared FuncDeclaration feq = null; |
1038 | 1 |
__gshared FuncDeclaration fcmp = null; |
1039 | 1 |
__gshared FuncDeclaration fhash = null; |
1040 | 1 |
if (!feq) |
1041 | 1 |
feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration(); |
1042 | 1 |
if (!fcmp) |
1043 | 1 |
fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration(); |
1044 | 1 |
if (!fhash) |
1045 | 1 |
fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration(); |
1046 | 1 |
assert(fcmp && feq && fhash); |
1047 |
|
|
1048 | 1 |
if (feq.vtblIndex < cd.vtbl.dim && cd.vtbl[feq.vtblIndex] == feq) |
1049 |
{
|
|
1050 |
version (all) |
|
1051 |
{
|
|
1052 | 1 |
if (fcmp.vtblIndex < cd.vtbl.dim && cd.vtbl[fcmp.vtblIndex] != fcmp) |
1053 |
{
|
|
1054 |
const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : ""; |
|
1055 |
.error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars()); |
|
1056 |
errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`."); |
|
1057 |
}
|
|
1058 |
}
|
|
1059 |
}
|
|
1060 |
}
|
|
1061 | 1 |
mtype.next = mtype.next.typeSemantic(loc, sc).merge2(); |
1062 | 1 |
mtype.transitive(); |
1063 |
|
|
1064 | 1 |
switch (mtype.next.toBasetype().ty) |
1065 |
{
|
|
1066 | 1 |
case Tfunction: |
1067 | 1 |
case Tvoid: |
1068 | 1 |
case Tnone: |
1069 | 1 |
case Ttuple: |
1070 | 1 |
.error(loc, "cannot have associative array of `%s`", mtype.next.toChars()); |
1071 | 1 |
goto case Terror; |
1072 | 1 |
case Terror: |
1073 | 1 |
return error(); |
1074 | 1 |
default: |
1075 | 1 |
break; |
1076 |
}
|
|
1077 | 1 |
if (mtype.next.isscope()) |
1078 |
{
|
|
1079 | 1 |
.error(loc, "cannot have array of scope `%s`", mtype.next.toChars()); |
1080 | 1 |
return error(); |
1081 |
}
|
|
1082 | 1 |
return merge(mtype); |
1083 |
}
|
|
1084 |
|
|
1085 |
Type visitPointer(TypePointer mtype) |
|
1086 |
{
|
|
1087 |
//printf("TypePointer::semantic() %s\n", toChars());
|
|
1088 | 1 |
if (mtype.deco) |
1089 |
{
|
|
1090 | 1 |
return mtype; |
1091 |
}
|
|
1092 | 1 |
Type n = mtype.next.typeSemantic(loc, sc); |
1093 | 1 |
switch (n.toBasetype().ty) |
1094 |
{
|
|
1095 | 1 |
case Ttuple: |
1096 | 1 |
.error(loc, "cannot have pointer to `%s`", n.toChars()); |
1097 | 1 |
goto case Terror; |
1098 | 1 |
case Terror: |
1099 | 1 |
return error(); |
1100 | 1 |
default: |
1101 | 1 |
break; |
1102 |
}
|
|
1103 | 1 |
if (n != mtype.next) |
1104 |
{
|
|
1105 | 1 |
mtype.deco = null; |
1106 |
}
|
|
1107 | 1 |
mtype.next = n; |
1108 | 1 |
if (mtype.next.ty != Tfunction) |
1109 |
{
|
|
1110 | 1 |
mtype.transitive(); |
1111 | 1 |
return merge(mtype); |
1112 |
}
|
|
1113 |
version (none) |
|
1114 |
{
|
|
1115 |
return merge(mtype); |
|
1116 |
}
|
|
1117 |
else
|
|
1118 |
{
|
|
1119 | 1 |
mtype.deco = merge(mtype).deco; |
1120 |
/* Don't return merge(), because arg identifiers and default args
|
|
1121 |
* can be different
|
|
1122 |
* even though the types match
|
|
1123 |
*/
|
|
1124 | 1 |
return mtype; |
1125 |
}
|
|
1126 |
}
|
|
1127 |
|
|
1128 |
Type visitReference(TypeReference mtype) |
|
1129 |
{
|
|
1130 |
//printf("TypeReference::semantic()\n");
|
|
1131 |
Type n = mtype.next.typeSemantic(loc, sc); |
|
1132 |
if (n != mtype.next) |
|
1133 |
mtype.deco = null; |
|
1134 |
mtype.next = n; |
|
1135 |
mtype.transitive(); |
|
1136 |
return merge(mtype); |
|
1137 |
}
|
|
1138 |
|
|
1139 |
Type visitFunction(TypeFunction mtype) |
|
1140 |
{
|
|
1141 | 1 |
if (mtype.deco) // if semantic() already run |
1142 |
{
|
|
1143 |
//printf("already done\n");
|
|
1144 | 1 |
return mtype; |
1145 |
}
|
|
1146 |
//printf("TypeFunction::semantic() this = %p\n", this);
|
|
1147 |
//printf("TypeFunction::semantic() %s, sc.stc = %llx, fargs = %p\n", toChars(), sc.stc, fargs);
|
|
1148 |
|
|
1149 | 1 |
bool errors = false; |
1150 |
|
|
1151 | 1 |
if (mtype.inuse > global.recursionLimit) |
1152 |
{
|
|
1153 |
mtype.inuse = 0; |
|
1154 |
.error(loc, "recursive type"); |
|
1155 |
return error(); |
|
1156 |
}
|
|
1157 |
|
|
1158 |
/* Copy in order to not mess up original.
|
|
1159 |
* This can produce redundant copies if inferring return type,
|
|
1160 |
* as semantic() will get called again on this.
|
|
1161 |
*/
|
|
1162 | 1 |
TypeFunction tf = mtype.copy().toTypeFunction(); |
1163 | 1 |
if (mtype.parameterList.parameters) |
1164 |
{
|
|
1165 | 1 |
tf.parameterList.parameters = mtype.parameterList.parameters.copy(); |
1166 | 1 |
for (size_t i = 0; i < mtype.parameterList.parameters.dim; i++) |
1167 |
{
|
|
1168 | 1 |
Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter)); |
1169 | 1 |
memcpy(cast(void*)p, cast(void*)(*mtype.parameterList.parameters)[i], __traits(classInstanceSize, Parameter)); |
1170 | 1 |
(*tf.parameterList.parameters)[i] = p; |
1171 |
}
|
|
1172 |
}
|
|
1173 |
|
|
1174 | 1 |
if (sc.stc & STC.pure_) |
1175 | 1 |
tf.purity = PURE.fwdref; |
1176 | 1 |
if (sc.stc & STC.nothrow_) |
1177 | 1 |
tf.isnothrow = true; |
1178 | 1 |
if (sc.stc & STC.nogc) |
1179 | 1 |
tf.isnogc = true; |
1180 | 1 |
if (sc.stc & STC.ref_) |
1181 | 1 |
tf.isref = true; |
1182 | 1 |
if (sc.stc & STC.return_) |
1183 |
tf.isreturn = true; |
|
1184 | 1 |
if (sc.stc & STC.returninferred) |
1185 |
tf.isreturninferred = true; |
|
1186 | 1 |
if (sc.stc & STC.scope_) |
1187 | 1 |
tf.isScopeQual = true; |
1188 | 1 |
if (sc.stc & STC.scopeinferred) |
1189 |
tf.isscopeinferred = true; |
|
1190 |
|
|
1191 |
// if (tf.isreturn && !tf.isref)
|
|
1192 |
// tf.isScopeQual = true; // return by itself means 'return scope'
|
|
1193 |
|
|
1194 | 1 |
if (tf.trust == TRUST.default_) |
1195 |
{
|
|
1196 | 1 |
if (sc.stc & STC.safe) |
1197 | 1 |
tf.trust = TRUST.safe; |
1198 | 1 |
else if (sc.stc & STC.system) |
1199 | 1 |
tf.trust = TRUST.system; |
1200 | 1 |
else if (sc.stc & STC.trusted) |
1201 | 1 |
tf.trust = TRUST.trusted; |
1202 |
}
|
|
1203 |
|
|
1204 | 1 |
if (sc.stc & STC.property) |
1205 | 1 |
tf.isproperty = true; |
1206 | 1 |
if (sc.stc & STC.live) |
1207 | 1 |
tf.islive = true; |
1208 |
|
|
1209 | 1 |
tf.linkage = sc.linkage; |
1210 |
version (none) |
|
1211 |
{
|
|
1212 |
/* If the parent is @safe, then this function defaults to safe
|
|
1213 |
* too.
|
|
1214 |
* If the parent's @safe-ty is inferred, then this function's @safe-ty needs
|
|
1215 |
* to be inferred first.
|
|
1216 |
*/
|
|
1217 |
if (tf.trust == TRUST.default_) |
|
1218 |
for (Dsymbol p = sc.func; p; p = p.toParent2()) |
|
1219 |
{
|
|
1220 |
FuncDeclaration fd = p.isFuncDeclaration(); |
|
1221 |
if (fd) |
|
1222 |
{
|
|
1223 |
if (fd.isSafeBypassingInference()) |
|
1224 |
tf.trust = TRUST.safe; // default to @safe |
|
1225 |
break; |
|
1226 |
}
|
|
1227 |
}
|
|
1228 |
}
|
|
1229 |
|
|
1230 | 1 |
bool wildreturn = false; |
1231 | 1 |
if (tf.next) |
1232 |
{
|
|
1233 | 1 |
sc = sc.push(); |
1234 | 1 |
sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR); |
1235 | 1 |
tf.next = tf.next.typeSemantic(loc, sc); |
1236 | 1 |
sc = sc.pop(); |
1237 | 1 |
errors |= tf.checkRetType(loc); |
1238 | 1 |
if (tf.next.isscope() && !(sc.flags & SCOPE.ctor)) |
1239 |
{
|
|
1240 | 1 |
.error(loc, "functions cannot return `scope %s`", tf.next.toChars()); |
1241 | 1 |
errors = true; |
1242 |
}
|
|
1243 | 1 |
if (tf.next.hasWild()) |
1244 | 1 |
wildreturn = true; |
1245 |
|
|
1246 | 1 |
if (tf.isreturn && !tf.isref && !tf.next.hasPointers()) |
1247 |
{
|
|
1248 | 1 |
tf.isreturn = false; |
1249 |
}
|
|
1250 |
}
|
|
1251 |
|
|
1252 | 1 |
ubyte wildparams = 0; |
1253 | 1 |
if (tf.parameterList.parameters) |
1254 |
{
|
|
1255 |
/* Create a scope for evaluating the default arguments for the parameters
|
|
1256 |
*/
|
|
1257 | 1 |
Scope* argsc = sc.push(); |
1258 | 1 |
argsc.stc = 0; // don't inherit storage class |
1259 | 1 |
argsc.protection = Prot(Prot.Kind.public_); |
1260 | 1 |
argsc.func = null; |
1261 |
|
|
1262 | 1 |
size_t dim = tf.parameterList.length; |
1263 | 1 |
for (size_t i = 0; i < dim; i++) |
1264 |
{
|
|
1265 | 1 |
Parameter fparam = tf.parameterList[i]; |
1266 | 1 |
fparam.storageClass |= STC.parameter; |
1267 | 1 |
mtype.inuse++; |
1268 | 1 |
fparam.type = fparam.type.typeSemantic(loc, argsc); |
1269 | 1 |
mtype.inuse--; |
1270 |
|
|
1271 | 1 |
if (fparam.type.ty == Terror) |
1272 |
{
|
|
1273 | 1 |
errors = true; |
1274 | 1 |
continue; |
1275 |
}
|
|
1276 |
|
|
1277 | 1 |
fparam.type = fparam.type.addStorageClass(fparam.storageClass); |
1278 |
|
|
1279 | 1 |
if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_)) |
1280 |
{
|
|
1281 | 1 |
if (!fparam.type) |
1282 |
continue; |
|
1283 |
}
|
|
1284 |
|
|
1285 | 1 |
Type t = fparam.type.toBasetype(); |
1286 |
|
|
1287 | 1 |
if (t.ty == Tfunction) |
1288 |
{
|
|
1289 | 1 |
.error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars()); |
1290 | 1 |
errors = true; |
1291 |
}
|
|
1292 | 1 |
else if (!fparam.isReference() && |
1293 | 1 |
(t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum)) |
1294 |
{
|
|
1295 | 1 |
Type tb2 = t.baseElemOf(); |
1296 | 1 |
if (tb2.ty == Tstruct && !(cast(TypeStruct)tb2).sym.members || |
1297 | 1 |
tb2.ty == Tenum && !(cast(TypeEnum)tb2).sym.memtype) |
1298 |
{
|
|
1299 | 1 |
.error(loc, "cannot have parameter of opaque type `%s` by value", fparam.type.toChars()); |
1300 | 1 |
errors = true; |
1301 |
}
|
|
1302 |
}
|
|
1303 | 1 |
else if (!(fparam.storageClass & STC.lazy_) && t.ty == Tvoid) |
1304 |
{
|
|
1305 | 1 |
.error(loc, "cannot have parameter of type `%s`", fparam.type.toChars()); |
1306 | 1 |
errors = true; |
1307 |
}
|
|
1308 |
|
|
1309 | 1 |
if ((fparam.storageClass & (STC.ref_ | STC.wild)) == (STC.ref_ | STC.wild)) |
1310 |
{
|
|
1311 |
// 'ref inout' implies 'return'
|
|
1312 | 1 |
fparam.storageClass |= STC.return_; |
1313 |
}
|
|
1314 |
|
|
1315 | 1 |
if (fparam.storageClass & STC.return_) |
1316 |
{
|
|
1317 | 1 |
if (fparam.isReference()) |
1318 |
{
|
|
1319 |
// Disabled for the moment awaiting improvement to allow return by ref
|
|
1320 |
// to be transformed into return by scope.
|
|
1321 | 1 |
if (0 && !tf.isref) |
1322 |
{
|
|
1323 |
auto stc = fparam.storageClass & (STC.ref_ | STC.out_); |
|
1324 |
.error(loc, "parameter `%s` is `return %s` but function does not return by `ref`", |
|
1325 |
fparam.ident ? fparam.ident.toChars() : "", |
|
1326 |
stcToChars(stc)); |
|
1327 |
errors = true; |
|
1328 |
}
|
|
1329 |
}
|
|
1330 |
else
|
|
1331 |
{
|
|
1332 | 1 |
if (!(fparam.storageClass & STC.scope_)) |
1333 | 1 |
fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope' |
1334 | 1 |
if (tf.isref) |
1335 |
{
|
|
1336 |
}
|
|
1337 | 1 |
else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid) |
1338 |
{
|
|
1339 |
fparam.storageClass &= ~STC.return_; // https://issues.dlang.org/show_bug.cgi?id=18963 |
|
1340 |
}
|
|
1341 |
}
|
|
1342 |
}
|
|
1343 |
|
|
1344 | 1 |
if (fparam.storageClass & (STC.ref_ | STC.lazy_)) |
1345 |
{
|
|
1346 |
}
|
|
1347 | 1 |
else if (fparam.storageClass & STC.out_) |
1348 |
{
|
|
1349 | 1 |
if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild)) |
1350 |
{
|
|
1351 | 1 |
.error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars()); |
1352 | 1 |
errors = true; |
1353 |
}
|
|
1354 |
else
|
|
1355 |
{
|
|
1356 | 1 |
Type tv = t.baseElemOf(); |
1357 | 1 |
if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.noDefaultCtor) |
1358 |
{
|
|
1359 | 1 |
.error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars()); |
1360 | 1 |
errors = true; |
1361 |
}
|
|
1362 |
}
|
|
1363 |
}
|
|
1364 |
|
|
1365 | 1 |
if (t.hasWild()) |
1366 |
{
|
|
1367 | 1 |
wildparams |= 1; |
1368 |
//if (tf.next && !wildreturn)
|
|
1369 |
// error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
|
|
1370 |
}
|
|
1371 |
|
|
1372 | 1 |
if (fparam.defaultArg) |
1373 |
{
|
|
1374 | 1 |
Expression e = fparam.defaultArg; |
1375 | 1 |
const isRefOrOut = fparam.isReference(); |
1376 | 1 |
const isAuto = fparam.storageClass & (STC.auto_ | STC.autoref); |
1377 | 1 |
if (isRefOrOut && !isAuto) |
1378 |
{
|
|
1379 | 1 |
e = e.expressionSemantic(argsc); |
1380 | 1 |
e = resolveProperties(argsc, e); |
1381 |
}
|
|
1382 |
else
|
|
1383 |
{
|
|
1384 | 1 |
e = inferType(e, fparam.type); |
1385 | 1 |
Initializer iz = new ExpInitializer(e.loc, e); |
1386 | 1 |
iz = iz.initializerSemantic(argsc, fparam.type, INITnointerpret); |
1387 | 1 |
e = iz.initializerToExpression(); |
1388 |
}
|
|
1389 | 1 |
if (e.op == TOK.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 |
1390 |
{
|
|
1391 | 1 |
FuncExp fe = cast(FuncExp)e; |
1392 |
// Replace function literal with a function symbol,
|
|
1393 |
// since default arg expression must be copied when used
|
|
1394 |
// and copying the literal itself is wrong.
|
|
1395 | 1 |
e = new VarExp(e.loc, fe.fd, false); |
1396 | 1 |
e = new AddrExp(e.loc, e); |
1397 | 1 |
e = e.expressionSemantic(argsc); |
1398 |
}
|
|
1399 | 1 |
e = e.implicitCastTo(argsc, fparam.type); |
1400 |
|
|
1401 |
// default arg must be an lvalue
|
|
1402 | 1 |
if (isRefOrOut && !isAuto) |
1403 | 1 |
e = e.toLvalue(argsc, e); |
1404 |
|
|
1405 | 1 |
fparam.defaultArg = e; |
1406 | 1 |
if (e.op == TOK.error) |
1407 | 1 |
errors = true; |
1408 |
}
|
|
1409 |
|
|
1410 |
/* If fparam after semantic() turns out to be a tuple, the number of parameters may
|
|
1411 |
* change.
|
|
1412 |
*/
|
|
1413 | 1 |
if (auto tt = t.isTypeTuple()) |
1414 |
{
|
|
1415 |
/* TypeFunction::parameter also is used as the storage of
|
|
1416 |
* Parameter objects for FuncDeclaration. So we should copy
|
|
1417 |
* the elements of TypeTuple::arguments to avoid unintended
|
|
1418 |
* sharing of Parameter object among other functions.
|
|
1419 |
*/
|
|
1420 | 1 |
if (tt.arguments && tt.arguments.dim) |
1421 |
{
|
|
1422 |
/* Propagate additional storage class from tuple parameters to their
|
|
1423 |
* element-parameters.
|
|
1424 |
* Make a copy, as original may be referenced elsewhere.
|
|
1425 |
*/
|
|
1426 | 1 |
size_t tdim = tt.arguments.dim; |
1427 | 1 |
auto newparams = new Parameters(tdim); |
1428 | 1 |
for (size_t j = 0; j < tdim; j++) |
1429 |
{
|
|
1430 | 1 |
Parameter narg = (*tt.arguments)[j]; |
1431 |
|
|
1432 |
// https://issues.dlang.org/show_bug.cgi?id=12744
|
|
1433 |
// If the storage classes of narg
|
|
1434 |
// conflict with the ones in fparam, it's ignored.
|
|
1435 | 1 |
StorageClass stc = fparam.storageClass | narg.storageClass; |
1436 | 1 |
StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_); |
1437 | 1 |
StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_); |
1438 | 1 |
if (stc1 && stc2 && stc1 != stc2) |
1439 |
{
|
|
1440 | 1 |
OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0)); |
1441 | 1 |
OutBuffer buf2; stcToBuffer(&buf2, stc2); |
1442 |
|
|
1443 | 1 |
.error(loc, "incompatible parameter storage classes `%s` and `%s`", |
1444 |
buf1.peekChars(), buf2.peekChars()); |
|
1445 | 1 |
errors = true; |
1446 | 1 |
stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_)); |
1447 |
}
|
|
1448 |
|
|
1449 |
/* https://issues.dlang.org/show_bug.cgi?id=18572
|
|
1450 |
*
|
|
1451 |
* If a tuple parameter has a default argument, when expanding the parameter
|
|
1452 |
* tuple the default argument tuple must also be expanded.
|
|
1453 |
*/
|
|
1454 | 1 |
Expression paramDefaultArg = narg.defaultArg; |
1455 | 1 |
TupleExp te = fparam.defaultArg ? fparam.defaultArg.isTupleExp() : null; |
1456 | 1 |
if (te && te.exps && te.exps.length) |
1457 | 1 |
paramDefaultArg = (*te.exps)[j]; |
1458 |
|
|
1459 | 1 |
(*newparams)[j] = new Parameter( |
1460 |
stc, narg.type, narg.ident, paramDefaultArg, narg.userAttribDecl); |
|
1461 |
}
|
|
1462 | 1 |
fparam.type = new TypeTuple(newparams); |
1463 |
}
|
|
1464 | 1 |
fparam.storageClass = STC.parameter; |
1465 |
|
|
1466 |
/* Reset number of parameters, and back up one to do this fparam again,
|
|
1467 |
* now that it is a tuple
|
|
1468 |
*/
|
|
1469 | 1 |
dim = tf.parameterList.length; |
1470 | 1 |
i--; |
1471 | 1 |
continue; |
1472 |
}
|
|
1473 |
|
|
1474 | 1 |
if (fparam.storageClass & STC.scope_ && !fparam.type.hasPointers()) |
1475 |
{
|
|
1476 |
/* X foo(ref return scope X) => Ref-ReturnScope
|
|
1477 |
* ref X foo(ref return scope X) => ReturnRef-Scope
|
|
1478 |
* But X has no pointers, we don't need the scope part, so:
|
|
1479 |
* X foo(ref return scope X) => Ref
|
|
1480 |
* ref X foo(ref return scope X) => ReturnRef
|
|
1481 |
* Constructors are treated as if they are being returned through the hidden parameter,
|
|
1482 |
* which is by ref, and the ref there is ignored.
|
|
1483 |
*/
|
|
1484 | 1 |
fparam.storageClass &= ~STC.scope_; |
1485 | 1 |
if (!tf.isref || (sc.flags & SCOPE.ctor)) |
1486 | 1 |
fparam.storageClass &= ~STC.return_; |
1487 |
}
|
|
1488 |
|
|
1489 |
/* Resolve "auto ref" storage class to be either ref or value,
|
|
1490 |
* based on the argument matching the parameter
|
|
1491 |
*/
|
|
1492 | 1 |
if (fparam.storageClass & STC.auto_) |
1493 |
{
|
|
1494 | 1 |
Expression farg = mtype.fargs && i < mtype.fargs.dim ? (*mtype.fargs)[i] : fparam.defaultArg; |
1495 | 1 |
if (farg && (fparam.storageClass & STC.ref_)) |
1496 |
{
|
|
1497 | 1 |
if (farg.isLvalue()) |
1498 |
{
|
|
1499 |
// ref parameter
|
|
1500 |
}
|
|
1501 |
else
|
|
1502 | 1 |
fparam.storageClass &= ~STC.ref_; // value parameter |
1503 | 1 |
fparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656 |
1504 | 1 |
fparam.storageClass |= STC.autoref; |
1505 |
}
|
|
1506 | 1 |
else if (mtype.incomplete && (fparam.storageClass & STC.ref_)) |
1507 |
{
|
|
1508 |
// the default argument may have been temporarily removed,
|
|
1509 |
// see usage of `TypeFunction.incomplete`.
|
|
1510 |
// https://issues.dlang.org/show_bug.cgi?id=19891
|
|
1511 | 1 |
fparam.storageClass &= ~STC.auto_; |
1512 | 1 |
fparam.storageClass |= STC.autoref; |
1513 |
}
|
|
1514 |
else
|
|
1515 |
{
|
|
1516 | 1 |
.error(loc, "`auto` can only be used as part of `auto ref` for template function parameters"); |
1517 | 1 |
errors = true; |
1518 |
}
|
|
1519 |
}
|
|
1520 |
|
|
1521 |
// Remove redundant storage classes for type, they are already applied
|
|
1522 | 1 |
fparam.storageClass &= ~(STC.TYPECTOR); |
1523 |
}
|
|
1524 | 1 |
argsc.pop(); |
1525 |
}
|
|
1526 | 1 |
if (tf.isWild()) |
1527 | 1 |
wildparams |= 2; |
1528 |
|
|
1529 | 1 |
if (wildreturn && !wildparams) |
1530 |
{
|
|
1531 | 1 |
.error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars()); |
1532 | 1 |
errors = true; |
1533 |
}
|
|
1534 | 1 |
tf.isInOutParam = (wildparams & 1) != 0; |
1535 | 1 |
tf.isInOutQual = (wildparams & 2) != 0; |
1536 |
|
|
1537 | 1 |
if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2)) |
1538 |
{
|
|
1539 | 1 |
.error(loc, "properties can only have zero, one, or two parameter"); |
1540 | 1 |
errors = true; |
1541 |
}
|
|
1542 |
|
|
1543 | 1 |
if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0) |
1544 |
{
|
|
1545 |
.error(loc, "variadic functions with non-D linkage must have at least one parameter"); |
|
1546 |
errors = true; |
|
1547 |
}
|
|
1548 |
|
|
1549 | 1 |
if (errors) |
1550 | 1 |
return error(); |
1551 |
|
|
1552 | 1 |
if (tf.next) |
1553 | 1 |
tf.deco = tf.merge().deco; |
1554 |
|
|
1555 |
/* Don't return merge(), because arg identifiers and default args
|
|
1556 |
* can be different
|
|
1557 |
* even though the types match
|
|
1558 |
*/
|
|
1559 | 1 |
return tf; |
1560 |
}
|
|
1561 |
|
|
1562 |
Type visitDelegate(TypeDelegate mtype) |
|
1563 |
{
|
|
1564 |
//printf("TypeDelegate::semantic() %s\n", toChars());
|
|
1565 | 1 |
if (mtype.deco) // if semantic() already run |
1566 |
{
|
|
1567 |
//printf("already done\n");
|
|
1568 | 1 |
return mtype; |
1569 |
}
|
|
1570 | 1 |
mtype.next = mtype.next.typeSemantic(loc, sc); |
1571 | 1 |
if (mtype.next.ty != Tfunction) |
1572 | 1 |
return error(); |
1573 |
|
|
1574 |
/* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
|
|
1575 |
* perhaps default arguments should
|
|
1576 |
* be removed from next before the merge.
|
|
1577 |
*/
|
|
1578 |
version (none) |
|
1579 |
{
|
|
1580 |
return mtype.merge(); |
|
1581 |
}
|
|
1582 |
else
|
|
1583 |
{
|
|
1584 |
/* Don't return merge(), because arg identifiers and default args
|
|
1585 |
* can be different
|
|
1586 |
* even though the types match
|
|
1587 |
*/
|
|
1588 | 1 |
mtype.deco = mtype.merge().deco; |
1589 | 1 |
return mtype; |
1590 |
}
|
|
1591 |
}
|
|
1592 |
|
|
1593 |
Type visitIdentifier(TypeIdentifier mtype) |
|
1594 |
{
|
|
1595 | 1 |
Type t; |
1596 | 1 |
Expression e; |
1597 | 1 |
Dsymbol s; |
1598 |
//printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
|
|
1599 | 1 |
mtype.resolve(loc, sc, &e, &t, &s); |
1600 | 1 |
if (t) |
1601 |
{
|
|
1602 |
//printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
|
|
1603 | 1 |
return t.addMod(mtype.mod); |
1604 |
}
|
|
1605 |
else
|
|
1606 |
{
|
|
1607 | 1 |
if (s) |
1608 |
{
|
|
1609 | 1 |
auto td = s.isTemplateDeclaration; |
1610 | 1 |
if (td && td.onemember && td.onemember.isAggregateDeclaration) |
1611 | 1 |
.error(loc, "template %s `%s` is used as a type without instantiation" |
1612 |
~ "; to instantiate it use `%s!(arguments)`", |
|
1613 |
s.kind, s.toPrettyChars, s.ident.toChars); |
|
1614 |
else
|
|
1615 | 1 |
.error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars); |
1616 |
//assert(0);
|
|
1617 |
}
|
|
1618 | 1 |
else if (e.op == TOK.variable) // special case: variable is used as a type |
1619 |
{
|
|
1620 | 1 |
Dsymbol varDecl = mtype.toDsymbol(sc); |
1621 | 1 |
const(Loc) varDeclLoc = varDecl.getLoc(); |
1622 | 1 |
Module varDeclModule = varDecl.getModule(); |
1623 |
|
|
1624 | 1 |
.error(loc, "variable `%s` is used as a type", mtype.toChars()); |
1625 |
|
|
1626 | 1 |
if (varDeclModule != sc._module) // variable is imported |
1627 |
{
|
|
1628 | 1 |
const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc(); |
1629 | 1 |
.errorSupplemental( |
1630 |
varDeclModuleImportLoc, |
|
1631 |
"variable `%s` is imported here from: `%s`", |
|
1632 |
varDecl.toChars, |
|
1633 |
varDeclModule.toPrettyChars, |
|
1634 |
);
|
|
1635 |
}
|
|
1636 |
|
|
1637 | 1 |
.errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars); |
1638 |
}
|
|
1639 |
else
|
|
1640 | 1 |
.error(loc, "`%s` is used as a type", mtype.toChars()); |
1641 | 1 |
return error(); |
1642 |
}
|
|
1643 |
}
|
|
1644 |
|
|
1645 |
Type visitInstance(TypeInstance mtype) |
|
1646 |
{
|
|
1647 | 1 |
Type t; |
1648 | 1 |
Expression e; |
1649 | 1 |
Dsymbol s; |
1650 |
|
|
1651 |
//printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
|
|
1652 |
{
|
|
1653 | 1 |
const errors = global.errors; |
1654 | 1 |
mtype.resolve(loc, sc, &e, &t, &s); |
1655 |
// if we had an error evaluating the symbol, suppress further errors
|
|
1656 | 1 |
if (!t && errors != global.errors) |
1657 | 1 |
return error(); |
1658 |
}
|
|
1659 |
|
|
1660 | 1 |
if (!t) |
1661 |
{
|
|
1662 | 1 |
if (!e && s && s.errors) |
1663 |
{
|
|
1664 |
// if there was an error evaluating the symbol, it might actually
|
|
1665 |
// be a type. Avoid misleading error messages.
|
|
1666 |
.error(loc, "`%s` had previous errors", mtype.toChars()); |
|
1667 |
}
|
|
1668 |
else
|
|
1669 | 1 |
.error(loc, "`%s` is used as a type", mtype.toChars()); |
1670 | 1 |
return error(); |
1671 |
}
|
|
1672 | 1 |
return t; |
1673 |
}
|
|
1674 |
|
|
1675 |
Type visitTypeof(TypeTypeof mtype) |
|
1676 |
{
|
|
1677 |
//printf("TypeTypeof::semantic() %s\n", mtype.toChars());
|
|
1678 | 1 |
Expression e; |
1679 | 1 |
Type t; |
1680 | 1 |
Dsymbol s; |
1681 | 1 |
mtype.resolve(loc, sc, &e, &t, &s); |
1682 | 1 |
if (s && (t = s.getType()) !is null) |
1683 |
t = t.addMod(mtype.mod); |
|
1684 | 1 |
if (!t) |
1685 |
{
|
|
1686 |
.error(loc, "`%s` is used as a type", mtype.toChars()); |
|
1687 |
return error(); |
|
1688 |
}
|
|
1689 | 1 |
return t; |
1690 |
}
|
|
1691 |
|
|
1692 |
Type visitTraits(TypeTraits mtype) |
|
1693 |
{
|
|
1694 | 1 |
if (mtype.ty == Terror) |
1695 |
return mtype; |
|
1696 |
|
|
1697 | 1 |
const inAlias = (sc.flags & SCOPE.alias_) != 0; |
1698 | 1 |
if (mtype.exp.ident != Id.allMembers && |
1699 | 1 |
mtype.exp.ident != Id.derivedMembers && |
1700 | 1 |
mtype.exp.ident != Id.getMember && |
1701 | 1 |
mtype.exp.ident != Id.parent && |
1702 | 1 |
mtype.exp.ident != Id.child && |
1703 | 1 |
mtype.exp.ident != Id.getOverloads && |
1704 | 1 |
mtype.exp.ident != Id.getVirtualFunctions && |
1705 | 1 |
mtype.exp.ident != Id.getVirtualMethods && |
1706 | 1 |
mtype.exp.ident != Id.getAttributes && |
1707 | 1 |
mtype.exp.ident != Id.getUnitTests && |
1708 | 1 |
mtype.exp.ident != Id.getAliasThis) |
1709 |
{
|
|
1710 |
static immutable (const(char)*)[2] ctxt = ["as type", "in alias"]; |
|
1711 | 1 |
.error(mtype.loc, "trait `%s` is either invalid or not supported %s", |
1712 |
mtype.exp.ident.toChars, ctxt[inAlias]); |
|
1713 | 1 |
mtype.ty = Terror; |
1714 | 1 |
return mtype; |
1715 |
}
|
|
1716 |
|
|
1717 |
import dmd.traits : semanticTraits; |
|
1718 | 1 |
Type result; |
1719 |
|
|
1720 | 1 |
if (Expression e = semanticTraits(mtype.exp, sc)) |
1721 |
{
|
|
1722 | 1 |
switch (e.op) |
1723 |
{
|
|
1724 | 1 |
case TOK.dotVariable: |
1725 | 1 |
mtype.sym = (cast(DotVarExp)e).var; |
1726 | 1 |
break; |
1727 | 1 |
case TOK.variable: |
1728 | 1 |
mtype.sym = (cast(VarExp)e).var; |
1729 | 1 |
break; |
1730 |
case TOK.function_: |
|
1731 |
auto fe = cast(FuncExp)e; |
|
1732 |
mtype.sym = fe.td ? fe.td : fe.fd; |
|
1733 |
break; |
|
1734 |
case TOK.dotTemplateDeclaration: |
|
1735 |
mtype.sym = (cast(DotTemplateExp)e).td; |
|
1736 |
break; |
|
1737 |
case TOK.dSymbol: |
|
1738 |
mtype.sym = (cast(DsymbolExp)e).s; |
|
1739 |
break; |
|
1740 | 1 |
case TOK.template_: |
1741 | 1 |
mtype.sym = (cast(TemplateExp)e).td; |
1742 | 1 |
break; |
1743 | 1 |
case TOK.scope_: |
1744 | 1 |
mtype.sym = (cast(ScopeExp)e).sds; |
1745 | 1 |
break; |
1746 | 1 |
case TOK.tuple: |
1747 | 1 |
TupleExp te = e.toTupleExp(); |
1748 | 1 |
Objects* elems = new Objects(te.exps.dim); |
1749 | 1 |
foreach (i; 0 .. elems.dim) |
1750 |
{
|
|
1751 | 1 |
auto src = (*te.exps)[i]; |
1752 | 1 |
switch (src.op) |
1753 |
{
|
|
1754 | 1 |
case TOK.type: |
1755 | 1 |
(*elems)[i] = (cast(TypeExp)src).type; |
1756 | 1 |
break; |
1757 |
case TOK.dotType: |
|
1758 |
(*elems)[i] = (cast(DotTypeExp)src).sym.isType(); |
|
1759 |
break; |
|
1760 |
case TOK.overloadSet: |
|
1761 |
(*elems)[i] = (cast(OverExp)src).type; |
|
1762 |
break; |
|
1763 | 1 |
default: |
1764 | 1 |
if (auto sym = isDsymbol(src)) |
1765 |
(*elems)[i] = sym; |
|
1766 |
else
|
|
1767 | 1 |
(*elems)[i] = src; |
1768 |
}
|
|
1769 |
}
|
|
1770 | 1 |
TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems); |
1771 | 1 |
mtype.sym = td; |
1772 | 1 |
break; |
1773 |
case TOK.dotType: |
|
1774 |
result = (cast(DotTypeExp)e).sym.isType(); |
|
1775 |
break; |
|
1776 | 1 |
case TOK.type: |
1777 | 1 |
result = (cast(TypeExp)e).type; |
1778 | 1 |
break; |
1779 | 1 |
case TOK.overloadSet: |
1780 | 1 |
result = (cast(OverExp)e).type; |
1781 | 1 |
break; |
1782 |
default: |
|
1783 |
break; |
|
1784 |
}
|
|
1785 |
}
|
|
1786 |
|
|
1787 | 1 |
if (result) |
1788 | 1 |
result = result.addMod(mtype.mod); |
1789 | 1 |
if (!inAlias && !result) |
1790 |
{
|
|
1791 | 1 |
if (!global.errors) |
1792 | 1 |
.error(mtype.loc, "`%s` does not give a valid type", mtype.toChars); |
1793 | 1 |
return error(); |
1794 |
}
|
|
1795 |
|
|
1796 | 1 |
return result; |
1797 |
}
|
|
1798 |
|
|
1799 |
Type visitReturn(TypeReturn mtype) |
|
1800 |
{
|
|
1801 |
//printf("TypeReturn::semantic() %s\n", toChars());
|
|
1802 | 1 |
Expression e; |
1803 | 1 |
Type t; |
1804 | 1 |
Dsymbol s; |
1805 | 1 |
mtype.resolve(loc, sc, &e, &t, &s); |
1806 | 1 |
if (s && (t = s.getType()) !is null) |
1807 |
t = t.addMod(mtype.mod); |
|
1808 | 1 |
if (!t) |
1809 |
{
|
|
1810 |
.error(loc, "`%s` is used as a type", mtype.toChars()); |
|
1811 |
return error(); |
|
1812 |
}
|
|
1813 | 1 |
return t; |
1814 |
}
|
|
1815 |
|
|
1816 |
Type visitStruct(TypeStruct mtype) |
|
1817 |
{
|
|
1818 |
//printf("TypeStruct::semantic('%s')\n", mtype.toChars());
|
|
1819 | 1 |
if (mtype.deco) |
1820 | 1 |
return mtype; |
1821 |
|
|
1822 |
/* Don't semantic for sym because it should be deferred until
|
|
1823 |
* sizeof needed or its members accessed.
|
|
1824 |
*/
|
|
1825 |
// instead, parent should be set correctly
|
|
1826 | 1 |
assert(mtype.sym.parent); |
1827 |
|
|
1828 | 1 |
if (mtype.sym.type.ty == Terror) |
1829 |
return error(); |
|
1830 |
|
|
1831 | 1 |
return merge(mtype); |
1832 |
}
|
|
1833 |
|
|
1834 |
Type visitEnum(TypeEnum mtype) |
|
1835 |
{
|
|
1836 |
//printf("TypeEnum::semantic() %s\n", toChars());
|
|
1837 | 1 |
return mtype.deco ? mtype : merge(mtype); |
1838 |
}
|
|
1839 |
|
|
1840 |
Type visitClass(TypeClass mtype) |
|
1841 |
{
|
|
1842 |
//printf("TypeClass::semantic(%s)\n", mtype.toChars());
|
|
1843 | 1 |
if (mtype.deco) |
1844 | 1 |
return mtype; |
1845 |
|
|
1846 |
/* Don't semantic for sym because it should be deferred until
|
|
1847 |
* sizeof needed or its members accessed.
|
|
1848 |
*/
|
|
1849 |
// instead, parent should be set correctly
|
|
1850 | 1 |
assert(mtype.sym.parent); |
1851 |
|
|
1852 | 1 |
if (mtype.sym.type.ty == Terror) |
1853 |
return error(); |
|
1854 |
|
|
1855 | 1 |
return merge(mtype); |
1856 |
}
|
|
1857 |
|
|
1858 |
Type visitTuple(TypeTuple mtype) |
|
1859 |
{
|
|
1860 |
//printf("TypeTuple::semantic(this = %p)\n", this);
|
|
1861 |
//printf("TypeTuple::semantic() %p, %s\n", this, toChars());
|
|
1862 | 1 |
if (!mtype.deco) |
1863 | 1 |
mtype.deco = merge(mtype).deco; |
1864 |
|
|
1865 |
/* Don't return merge(), because a tuple with one type has the
|
|
1866 |
* same deco as that type.
|
|
1867 |
*/
|
|
1868 | 1 |
return mtype; |
1869 |
}
|
|
1870 |
|
|
1871 |
Type visitSlice(TypeSlice mtype) |
|
1872 |
{
|
|
1873 |
//printf("TypeSlice::semantic() %s\n", toChars());
|
|
1874 | 1 |
Type tn = mtype.next.typeSemantic(loc, sc); |
1875 |
//printf("next: %s\n", tn.toChars());
|
|
1876 |
|
|
1877 | 1 |
Type tbn = tn.toBasetype(); |
1878 | 1 |
if (tbn.ty != Ttuple) |
1879 |
{
|
|
1880 | 1 |
.error(loc, "can only slice tuple types, not `%s`", tbn.toChars()); |
1881 | 1 |
return error(); |
1882 |
}
|
|
1883 | 1 |
TypeTuple tt = cast(TypeTuple)tbn; |
1884 |
|
|
1885 | 1 |
mtype.lwr = semanticLength(sc, tbn, mtype.lwr); |
1886 | 1 |
mtype.upr = semanticLength(sc, tbn, mtype.upr); |
1887 | 1 |
mtype.lwr = mtype.lwr.ctfeInterpret(); |
1888 | 1 |
mtype.upr = mtype.upr.ctfeInterpret(); |
1889 | 1 |
if (mtype.lwr.op == TOK.error || mtype.upr.op == TOK.error) |
1890 |
return error(); |
|
1891 |
|
|
1892 | 1 |
uinteger_t i1 = mtype.lwr.toUInteger(); |
1893 | 1 |
uinteger_t i2 = mtype.upr.toUInteger(); |
1894 | 1 |
if (!(i1 <= i2 && i2 <= tt.arguments.dim)) |
1895 |
{
|
|
1896 | 1 |
.error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`", |
1897 |
cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.dim); |
|
1898 | 1 |
return error(); |
1899 |
}
|
|
1900 |
|
|
1901 | 1 |
mtype.next = tn; |
1902 | 1 |
mtype.transitive(); |
1903 |
|
|
1904 | 1 |
auto args = new Parameters(); |
1905 | 1 |
args.reserve(cast(size_t)(i2 - i1)); |
1906 | 1 |
foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2]) |
1907 |
{
|
|
1908 | 1 |
args.push(arg); |
1909 |
}
|
|
1910 | 1 |
Type t = new TypeTuple(args); |
1911 | 1 |
return t.typeSemantic(loc, sc); |
1912 |
}
|
|
1913 |
|
|
1914 |
Type visitMixin(TypeMixin mtype) |
|
1915 |
{
|
|
1916 |
//printf("TypeMixin::semantic() %s\n", toChars());
|
|
1917 | 1 |
auto o = mtype.compileTypeMixin(loc, sc); |
1918 | 1 |
if (auto t = o.isType()) |
1919 |
{
|
|
1920 | 1 |
return t.typeSemantic(loc, sc).addMod(mtype.mod); |
1921 |
}
|
|
1922 | 1 |
else if (auto e = o.isExpression()) |
1923 |
{
|
|
1924 | 1 |
e = e.expressionSemantic(sc); |
1925 | 1 |
if (auto et = e.isTypeExp()) |
1926 | 1 |
return et.type.addMod(mtype.mod); |
1927 |
else
|
|
1928 |
{
|
|
1929 |
if (!global.errors) |
|
1930 |
.error(e.loc, "`%s` does not give a valid type", o.toChars); |
|
1931 |
}
|
|
1932 |
}
|
|
1933 |
return error(); |
|
1934 |
}
|
|
1935 |
|
|
1936 | 1 |
switch (t.ty) |
1937 |
{
|
|
1938 | 1 |
default: return visitType(t); |
1939 | 1 |
case Tvector: return visitVector(cast(TypeVector)t); |
1940 | 1 |
case Tsarray: return visitSArray(cast(TypeSArray)t); |
1941 | 1 |
case Tarray: return visitDArray(cast(TypeDArray)t); |
1942 | 1 |
case Taarray: return visitAArray(cast(TypeAArray)t); |
1943 | 1 |
case Tpointer: return visitPointer(cast(TypePointer)t); |
1944 |
case Treference: return visitReference(cast(TypeReference)t); |
|
1945 | 1 |
case Tfunction: return visitFunction(cast(TypeFunction)t); |
1946 | 1 |
case Tdelegate: return visitDelegate(cast(TypeDelegate)t); |
1947 | 1 |
case Tident: return visitIdentifier(cast(TypeIdentifier)t); |
1948 | 1 |
case Tinstance: return visitInstance(cast(TypeInstance)t); |
1949 | 1 |
case Ttypeof: return visitTypeof(cast(TypeTypeof)t); |
1950 | 1 |
case Ttraits: return visitTraits(cast(TypeTraits)t); |
1951 | 1 |
case Treturn: return visitReturn(cast(TypeReturn)t); |
1952 | 1 |
case Tstruct: return visitStruct(cast(TypeStruct)t); |
1953 | 1 |
case Tenum: return visitEnum(cast(TypeEnum)t); |
1954 | 1 |
case Tclass: return visitClass(cast(TypeClass)t); |
1955 | 1 |
case Ttuple: return visitTuple (cast(TypeTuple)t); |
1956 | 1 |
case Tslice: return visitSlice(cast(TypeSlice)t); |
1957 | 1 |
case Tmixin: return visitMixin(cast(TypeMixin)t); |
1958 |
}
|
|
1959 |
}
|
|
1960 |
|
|
1961 |
/******************************************
|
|
1962 |
* Compile the MixinType, returning the type or expression AST.
|
|
1963 |
*
|
|
1964 |
* Doesn't run semantic() on the returned object.
|
|
1965 |
* Params:
|
|
1966 |
* tm = mixin to compile as a type or expression
|
|
1967 |
* loc = location for error messages
|
|
1968 |
* sc = context
|
|
1969 |
* Return:
|
|
1970 |
* null if error, else RootObject AST as parsed
|
|
1971 |
*/
|
|
1972 |
RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc) |
|
1973 |
{
|
|
1974 | 1 |
OutBuffer buf; |
1975 | 1 |
if (expressionsToString(buf, sc, tm.exps)) |
1976 |
return null; |
|
1977 |
|
|
1978 | 1 |
const errors = global.errors; |
1979 | 1 |
const len = buf.length; |
1980 | 1 |
buf.writeByte(0); |
1981 | 1 |
const str = buf.extractSlice()[0 .. len]; |
1982 | 1 |
scope p = new Parser!ASTCodegen(loc, sc._module, str, false); |
1983 | 1 |
p.nextToken(); |
1984 |
//printf("p.loc.linnum = %d\n", p.loc.linnum);
|
|
1985 |
|
|
1986 | 1 |
auto o = p.parseTypeOrAssignExp(TOK.endOfFile); |
1987 | 1 |
if (errors != global.errors) |
1988 |
{
|
|
1989 |
assert(global.errors != errors); // should have caught all these cases |
|
1990 |
return null; |
|
1991 |
}
|
|
1992 | 1 |
if (p.token.value != TOK.endOfFile) |
1993 |
{
|
|
1994 |
.error(loc, "incomplete mixin type `%s`", str.ptr); |
|
1995 |
return null; |
|
1996 |
}
|
|
1997 |
|
|
1998 | 1 |
Type t = o.isType(); |
1999 | 1 |
Expression e = t ? t.typeToExpression() : o.isExpression(); |
2000 |
|
|
2001 | 1 |
return (!e && t) ? t : e; |
2002 |
}
|
|
2003 |
|
|
2004 |
|
|
2005 |
/************************************
|
|
2006 |
* If an identical type to `type` is in `type.stringtable`, return
|
|
2007 |
* the latter one. Otherwise, add it to `type.stringtable`.
|
|
2008 |
* Some types don't get merged and are returned as-is.
|
|
2009 |
* Params:
|
|
2010 |
* type = Type to check against existing types
|
|
2011 |
* Returns:
|
|
2012 |
* the type that was merged
|
|
2013 |
*/
|
|
2014 |
Type merge(Type type) |
|
2015 |
{
|
|
2016 | 1 |
switch (type.ty) |
2017 |
{
|
|
2018 | 1 |
case Terror: |
2019 | 1 |
case Ttypeof: |
2020 | 1 |
case Tident: |
2021 | 1 |
case Tinstance: |
2022 | 1 |
case Tmixin: |
2023 | 1 |
return type; |
2024 |
|
|
2025 | 1 |
case Tsarray: |
2026 |
// prevents generating the mangle if the array dim is not yet known
|
|
2027 | 1 |
if (!(cast(TypeSArray) type).dim.isIntegerExp()) |
2028 | 1 |
return type; |
2029 | 1 |
goto default; |
2030 |
|
|
2031 | 1 |
case Tenum: |
2032 | 1 |
break; |
2033 |
|
|
2034 | 1 |
case Taarray: |
2035 | 1 |
if (!(cast(TypeAArray)type).index.merge().deco) |
2036 | 1 |
return type; |
2037 | 1 |
goto default; |
2038 |
|
|
2039 | 1 |
default: |
2040 | 1 |
if (type.nextOf() && !type.nextOf().deco) |
2041 | 1 |
return type; |
2042 | 1 |
break; |
2043 |
}
|
|
2044 |
|
|
2045 |
//printf("merge(%s)\n", toChars());
|
|
2046 | 1 |
if (!type.deco) |
2047 |
{
|
|
2048 | 1 |
OutBuffer buf; |
2049 | 1 |
buf.reserve(32); |
2050 |
|
|
2051 | 1 |
mangleToBuffer(type, &buf); |
2052 |
|
|
2053 | 1 |
auto sv = type.stringtable.update(buf[]); |
2054 | 1 |
if (sv.value) |
2055 |
{
|
|
2056 | 1 |
Type t = sv.value; |
2057 |
debug
|
|
2058 |
{
|
|
2059 |
import core.stdc.stdio; |
|
2060 | 1 |
if (!t.deco) |
2061 |
printf("t = %s\n", t.toChars()); |
|
2062 |
}
|
|
2063 | 1 |
assert(t.deco); |
2064 |
//printf("old value, deco = '%s' %p\n", t.deco, t.deco);
|
|
2065 | 1 |
return t; |
2066 |
}
|
|
2067 |
else
|
|
2068 |
{
|
|
2069 | 1 |
Type t = stripDefaultArgs(type); |
2070 | 1 |
sv.value = t; |
2071 | 1 |
type.deco = t.deco = cast(char*)sv.toDchars(); |
2072 |
//printf("new value, deco = '%s' %p\n", t.deco, t.deco);
|
|
2073 | 1 |
return t; |
2074 |
}
|
|
2075 |
}
|
|
2076 | 1 |
return type; |
2077 |
}
|
|
2078 |
|
|
2079 |
/***************************************
|
|
2080 |
* Calculate built-in properties which just the type is necessary.
|
|
2081 |
*
|
|
2082 |
* Params:
|
|
2083 |
* t = the type for which the property is calculated
|
|
2084 |
* scope_ = the scope from which the property is being accessed. Used for visibility checks only.
|
|
2085 |
* loc = the location where the property is encountered
|
|
2086 |
* ident = the identifier of the property
|
|
2087 |
* flag = if flag & 1, don't report "not a property" error and just return NULL.
|
|
2088 |
* Returns:
|
|
2089 |
* expression representing the property, or null if not a property and (flag & 1)
|
|
2090 |
*/
|
|
2091 |
Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag) |
|
2092 |
{
|
|
2093 |
Expression visitType(Type mt) |
|
2094 |
{
|
|
2095 | 1 |
Expression e; |
2096 |
static if (LOGDOTEXP) |
|
2097 |
{
|
|
2098 |
printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars()); |
|
2099 |
}
|
|
2100 | 1 |
if (ident == Id.__sizeof) |
2101 |
{
|
|
2102 | 1 |
d_uns64 sz = mt.size(loc); |
2103 | 1 |
if (sz == SIZE_INVALID) |
2104 | 1 |
return ErrorExp.get(); |
2105 | 1 |
e = new IntegerExp(loc, sz, Type.tsize_t); |
2106 |
}
|
|
2107 | 1 |
else if (ident == Id.__xalignof) |
2108 |
{
|
|
2109 | 1 |
const explicitAlignment = mt.alignment(); |
2110 | 1 |
const naturalAlignment = mt.alignsize(); |
2111 | 1 |
const actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment); |
2112 | 1 |
e = new IntegerExp(loc, actualAlignment, Type.tsize_t); |
2113 |
}
|
|
2114 | 1 |
else if (ident == Id._init) |
2115 |
{
|
|
2116 | 1 |
Type tb = mt.toBasetype(); |
2117 | 1 |
e = mt.defaultInitLiteral(loc); |
2118 | 1 |
if (tb.ty == Tstruct && tb.needsNested()) |
2119 |
{
|
|
2120 | 1 |
e.isStructLiteralExp().useStaticInit = true; |
2121 |
}
|
|
2122 |
}
|
|
2123 | 1 |
else if (ident == Id._mangleof) |
2124 |
{
|
|
2125 | 1 |
if (!mt.deco) |
2126 |
{
|
|
2127 |
error(loc, "forward reference of type `%s.mangleof`", mt.toChars()); |
|
2128 |
e = ErrorExp.get(); |
|
2129 |
}
|
|
2130 |
else
|
|
2131 |
{
|
|
2132 | 1 |
e = new StringExp(loc, mt.deco.toDString()); |
2133 | 1 |
Scope sc; |
2134 | 1 |
e = e.expressionSemantic(&sc); |
2135 |
}
|
|
2136 |
}
|
|
2137 | 1 |
else if (ident == Id.stringof) |
2138 |
{
|
|
2139 |
const s = mt.toChars(); |
|
2140 |
e = new StringExp(loc, s.toDString()); |
|
2141 |
Scope sc; |
|
2142 |
e = e.expressionSemantic(&sc); |
|
2143 |
}
|
|
2144 | 1 |
else if (flag && mt != Type.terror) |
2145 |
{
|
|
2146 | 1 |
return null; |
2147 |
}
|
|
2148 |
else
|
|
2149 |
{
|
|
2150 | 1 |
Dsymbol s = null; |
2151 | 1 |
if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum) |
2152 | 1 |
s = mt.toDsymbol(null); |
2153 | 1 |
if (s) |
2154 | 1 |
s = s.search_correct(ident); |
2155 | 1 |
if (s && !symbolIsVisible(scope_, s)) |
2156 | 1 |
s = null; |
2157 | 1 |
if (mt != Type.terror) |
2158 |
{
|
|
2159 | 1 |
if (s) |
2160 | 1 |
error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars()); |
2161 |
else
|
|
2162 |
{
|
|
2163 | 1 |
if (ident == Id.call && mt.ty == Tclass) |
2164 | 1 |
error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars()); |
2165 |
else
|
|
2166 |
{
|
|
2167 | 1 |
if (const n = importHint(ident.toString())) |
2168 | 1 |
error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr); |
2169 |
else
|
|
2170 | 1 |
error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true)); |
2171 |
}
|
|
2172 |
}
|
|
2173 |
}
|
|
2174 | 1 |
e = ErrorExp.get(); |
2175 |
}
|
|
2176 | 1 |
return e; |
2177 |
}
|
|
2178 |
|
|
2179 |
Expression visitError(TypeError) |
|
2180 |
{
|
|
2181 | 1 |
return ErrorExp.get(); |
2182 |
}
|
|
2183 |
|
|
2184 |
Expression visitBasic(TypeBasic mt) |
|
2185 |
{
|
|
2186 |
Expression integerValue(dinteger_t i) |
|
2187 |
{
|
|
2188 | 1 |
return new IntegerExp(loc, i, mt); |
2189 |
}
|
|
2190 |
|
|
2191 |
Expression intValue(dinteger_t i) |
|
2192 |
{
|
|
2193 | 1 |
return new IntegerExp(loc, i, Type.tint32); |
2194 |
}
|
|
2195 |
|
|
2196 |
Expression floatValue(real_t r) |
|
2197 |
{
|
|
2198 | 1 |
if (mt.isreal() || mt.isimaginary()) |
2199 | 1 |
return new RealExp(loc, r, mt); |
2200 |
else
|
|
2201 |
{
|
|
2202 | 1 |
return new ComplexExp(loc, complex_t(r, r), mt); |
2203 |
}
|
|
2204 |
}
|
|
2205 |
|
|
2206 |
//printf("TypeBasic::getProperty('%s')\n", ident.toChars());
|
|
2207 | 1 |
if (ident == Id.max) |
2208 |
{
|
|
2209 | 1 |
switch (mt.ty) |
2210 |
{
|
|
2211 | 1 |
case Tint8: return integerValue(byte.max); |
2212 | 1 |
case Tuns8: return integerValue(ubyte.max); |
2213 | 1 |
case Tint16: return integerValue(short.max); |
2214 | 1 |
case Tuns16: return integerValue(ushort.max); |
2215 | 1 |
case Tint32: return integerValue(int.max); |
2216 | 1 |
case Tuns32: return integerValue(uint.max); |
2217 | 1 |
case Tint64: return integerValue(long.max); |
2218 | 1 |
case Tuns64: return integerValue(ulong.max); |
2219 | 1 |
case Tbool: return integerValue(bool.max); |
2220 | 1 |
case Tchar: return integerValue(char.max); |
2221 | 1 |
case Twchar: return integerValue(wchar.max); |
2222 | 1 |
case Tdchar: return integerValue(dchar.max); |
2223 |
case Tcomplex32: |
|
2224 | 1 |
case Timaginary32: |
2225 | 1 |
case Tfloat32: return floatValue(target.FloatProperties.max); |
2226 |
case Tcomplex64: |
|
2227 |
case Timaginary64: |
|
2228 | 1 |
case Tfloat64: return floatValue(target.DoubleProperties.max); |
2229 |
case Tcomplex80: |
|
2230 |
case Timaginary80: |
|
2231 | 1 |
case Tfloat80: return floatValue(target.RealProperties.max); |
2232 |
default: break; |
|
2233 |
}
|
|
2234 |
}
|
|
2235 | 1 |
else if (ident == Id.min) |
2236 |
{
|
|
2237 | 1 |
switch (mt.ty) |
2238 |
{
|
|
2239 | 1 |
case Tint8: return integerValue(byte.min); |
2240 | 1 |
case Tuns8: |
2241 | 1 |
case Tuns16: |
2242 | 1 |
case Tuns32: |
2243 | 1 |
case Tuns64: |
2244 | 1 |
case Tbool: |
2245 | 1 |
case Tchar: |
2246 | 1 |
case Twchar: |
2247 | 1 |
case Tdchar: return integerValue(0); |
2248 | 1 |
case Tint16: return integerValue(short.min); |
2249 | 1 |
case Tint32: return integerValue(int.min); |
2250 | 1 |
case Tint64: return integerValue(long.min); |
2251 |
default: break; |
|
2252 |
}
|
|
2253 |
}
|
|
2254 | 1 |
else if (ident == Id.min_normal) |
2255 |
{
|
|
2256 | 1 |
switch (mt.ty) |
2257 |
{
|
|
2258 |
case Tcomplex32: |
|
2259 |
case Timaginary32: |
|
2260 | 1 |
case Tfloat32: return floatValue(target.FloatProperties.min_normal); |
2261 |
case Tcomplex64: |
|
2262 |
case Timaginary64: |
|
2263 | 1 |
case Tfloat64: return floatValue(target.DoubleProperties.min_normal); |
2264 |
case Tcomplex80: |
|
2265 |
case Timaginary80: |
|
2266 | 1 |
case Tfloat80: return floatValue(target.RealProperties.min_normal); |
2267 | 1 |
default: break; |
2268 |
}
|
|
2269 |
}
|
|
2270 | 1 |
else if (ident == Id.nan) |
2271 |
{
|
|
2272 | 1 |
switch (mt.ty) |
2273 |
{
|
|
2274 | 1 |
case Tcomplex32: |
2275 | 1 |
case Tcomplex64: |
2276 | 1 |
case Tcomplex80: |
2277 | 1 |
case Timaginary32: |
2278 | 1 |
case Timaginary64: |
2279 | 1 |
case Timaginary80: |
2280 | 1 |
case Tfloat32: |
2281 | 1 |
case Tfloat64: |
2282 | 1 |
case Tfloat80: return floatValue(target.RealProperties.nan); |
2283 | 1 |
default: break; |
2284 |
}
|
|
2285 |
}
|
|
2286 | 1 |
else if (ident == Id.infinity) |
2287 |
{
|
|
2288 | 1 |
switch (mt.ty) |
2289 |
{
|
|
2290 |
case Tcomplex32: |
|
2291 |
case Tcomplex64: |
|
2292 | 1 |
case Tcomplex80: |
2293 | 1 |
case Timaginary32: |
2294 | 1 |
case Timaginary64: |
2295 | 1 |
case Timaginary80: |
2296 | 1 |
case Tfloat32: |
2297 | 1 |
case Tfloat64: |
2298 | 1 |
case Tfloat80: return floatValue(target.RealProperties.infinity); |
2299 |
default: break; |
|
2300 |
}
|
|
2301 |
}
|
|
2302 | 1 |
else if (ident == Id.dig) |
2303 |
{
|
|
2304 | 1 |
switch (mt.ty) |
2305 |
{
|
|
2306 |
case Tcomplex32: |
|
2307 |
case Timaginary32: |
|
2308 | 1 |
case Tfloat32: return intValue(target.FloatProperties.dig); |
2309 |
case Tcomplex64: |
|
2310 |
case Timaginary64: |
|
2311 | 1 |
case Tfloat64: return intValue(target.DoubleProperties.dig); |
2312 |
case Tcomplex80: |
|
2313 |
case Timaginary80: |
|
2314 | 1 |
case Tfloat80: return intValue(target.RealProperties.dig); |
2315 |
default: break; |
|
2316 |
}
|
|
2317 |
}
|
|
2318 | 1 |
else if (ident == Id.epsilon) |
2319 |
{
|
|
2320 | 1 |
switch (mt.ty) |
2321 |
{
|
|
2322 |
case Tcomplex32: |
|
2323 |
case Timaginary32: |
|
2324 | 1 |
case Tfloat32: return floatValue(target.FloatProperties.epsilon); |
2325 |
case Tcomplex64: |
|
2326 |
case Timaginary64: |
|
2327 | 1 |
case Tfloat64: return floatValue(target.DoubleProperties.epsilon); |
2328 |
case Tcomplex80: |
|
2329 |
case Timaginary80: |
|
2330 | 1 |
case Tfloat80: return floatValue(target.RealProperties.epsilon); |
2331 | 1 |
default: break; |
2332 |
}
|
|
2333 |
}
|
|
2334 | 1 |
else if (ident == Id.mant_dig) |
2335 |
{
|
|
2336 | 1 |
switch (mt.ty) |
2337 |
{
|
|
2338 |
case Tcomplex32: |
|
2339 |
case Timaginary32: |
|
2340 | 1 |
case Tfloat32: return intValue(target.FloatProperties.mant_dig); |
2341 |
case Tcomplex64: |
|
2342 |
case Timaginary64: |
|
2343 | 1 |
case Tfloat64: return intValue(target.DoubleProperties.mant_dig); |
2344 |
case Tcomplex80: |
|
2345 |
case Timaginary80: |
|
2346 | 1 |
case Tfloat80: return intValue(target.RealProperties.mant_dig); |
2347 |
default: break; |
|
2348 |
}
|
|
2349 |
}
|
|
2350 | 1 |
else if (ident == Id.max_10_exp) |
2351 |
{
|
|
2352 | 1 |
switch (mt.ty) |
2353 |
{
|
|
2354 |
case Tcomplex32: |
|
2355 |
case Timaginary32: |
|
2356 | 1 |
case Tfloat32: return intValue(target.FloatProperties.max_10_exp); |
2357 |
case Tcomplex64: |
|
2358 |
case Timaginary64: |
|
2359 | 1 |
case Tfloat64: return intValue(target.DoubleProperties.max_10_exp); |
2360 |
case Tcomplex80: |
|
2361 |
case Timaginary80: |
|
2362 | 1 |
case Tfloat80: return intValue(target.RealProperties.max_10_exp); |
2363 |
default: break; |
|
2364 |
}
|
|
2365 |
}
|
|
2366 | 1 |
else if (ident == Id.max_exp) |
2367 |
{
|
|
2368 | 1 |
switch (mt.ty) |
2369 |
{
|
|
2370 |
case Tcomplex32: |
|
2371 |
case Timaginary32: |
|
2372 | 1 |
case Tfloat32: return intValue(target.FloatProperties.max_exp); |
2373 |
case Tcomplex64: |
|
2374 |
case Timaginary64: |
|
2375 | 1 |
case Tfloat64: return intValue(target.DoubleProperties.max_exp); |
2376 |
case Tcomplex80: |
|
2377 |
case Timaginary80: |
|
2378 | 1 |
case Tfloat80: return intValue(target.RealProperties.max_exp); |
2379 |
default: break; |
|
2380 |
}
|
|
2381 |
}
|
|
2382 | 1 |
else if (ident == Id.min_10_exp) |
2383 |
{
|
|
2384 | 1 |
switch (mt.ty) |
2385 |
{
|
|
2386 |
case Tcomplex32: |
|
2387 |
case Timaginary32: |
|
2388 | 1 |
case Tfloat32: return intValue(target.FloatProperties.min_10_exp); |
2389 |
case Tcomplex64: |
|
2390 |
case Timaginary64: |
|
2391 | 1 |
case Tfloat64: return intValue(target.DoubleProperties.min_10_exp); |
2392 |
case Tcomplex80: |
|
2393 |
case Timaginary80: |
|
2394 | 1 |
case Tfloat80: return intValue(target.RealProperties.min_10_exp); |
2395 |
default: break; |
|
2396 |
}
|
|
2397 |
}
|
|
2398 | 1 |
else if (ident == Id.min_exp) |
2399 |
{
|
|
2400 | 1 |
switch (mt.ty) |
2401 |
{
|
|
2402 |
case Tcomplex32: |
|
2403 |
case Timaginary32: |
|
2404 | 1 |
case Tfloat32: return intValue(target.FloatProperties.min_exp); |
2405 |
case Tcomplex64: |
|
2406 |
case Timaginary64: |
|
2407 | 1 |
case Tfloat64: return intValue(target.DoubleProperties.min_exp); |
2408 |
case Tcomplex80: |
|
2409 |
case Timaginary80: |
|
2410 | 1 |
case Tfloat80: return intValue(target.RealProperties.min_exp); |
2411 |
default: break; |
|
2412 |
}
|
|
2413 |
}
|
|
2414 | 1 |
return visitType(mt); |
2415 |
}
|
|
2416 |
|
|
2417 |
Expression visitVector(TypeVector mt) |
|
2418 |
{
|
|
2419 | 1 |
return visitType(mt); |
2420 |
}
|
|
2421 |
|
|
2422 |
Expression visitEnum(TypeEnum mt) |
|
2423 |
{
|
|
2424 | 1 |
Expression e; |
2425 | 1 |
if (ident == Id.max || ident == Id.min) |
2426 |
{
|
|
2427 | 1 |
return mt.sym.getMaxMinValue(loc, ident); |
2428 |
}
|
|
2429 | 1 |
else if (ident == Id._init) |
2430 |
{
|
|
2431 | 1 |
e = mt.defaultInitLiteral(loc); |
2432 |
}
|
|
2433 | 1 |
else if (ident == Id.stringof) |
2434 |
{
|
|
2435 |
e = new StringExp(loc, mt.toString()); |
|
2436 |
Scope sc; |
|
2437 |
e = e.expressionSemantic(&sc); |
|
2438 |
}
|
|
2439 | 1 |
else if (ident == Id._mangleof) |
2440 |
{
|
|
2441 | 1 |
e = visitType(mt); |
2442 |
}
|
|
2443 |
else
|
|
2444 |
{
|
|
2445 | 1 |
e = mt.toBasetype().getProperty(scope_, loc, ident, flag); |
2446 |
}
|
|
2447 | 1 |
return e; |
2448 |
}
|
|
2449 |
|
|
2450 |
Expression visitTuple(TypeTuple mt) |
|
2451 |
{
|
|
2452 | 1 |
Expression e; |
2453 |
static if (LOGDOTEXP) |
|
2454 |
{
|
|
2455 |
printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars()); |
|
2456 |
}
|
|
2457 | 1 |
if (ident == Id.length) |
2458 |
{
|
|
2459 | 1 |
e = new IntegerExp(loc, mt.arguments.dim, Type.tsize_t); |
2460 |
}
|
|
2461 | 1 |
else if (ident == Id._init) |
2462 |
{
|
|
2463 | 1 |
e = mt.defaultInitLiteral(loc); |
2464 |
}
|
|
2465 | 1 |
else if (flag) |
2466 |
{
|
|
2467 | 1 |
e = null; |
2468 |
}
|
|
2469 |
else
|
|
2470 |
{
|
|
2471 | 1 |
error(loc, "no property `%s` for tuple `%s`", ident.toChars(), mt.toChars()); |
2472 | 1 |
e = ErrorExp.get(); |
2473 |
}
|
|
2474 | 1 |
return e; |
2475 |
}
|
|
2476 |
|
|
2477 | 1 |
switch (t.ty) |
2478 |
{
|
|
2479 | 1 |
default: return t.isTypeBasic() ? |
2480 | 1 |
visitBasic(cast(TypeBasic)t) : |
2481 | 1 |
visitType(t); |
2482 |
|
|
2483 | 1 |
case Terror: return visitError (cast(TypeError)t); |
2484 | 1 |
case Tvector: return visitVector(cast(TypeVector)t); |
2485 | 1 |
case Tenum: return visitEnum (cast(TypeEnum)t); |
2486 | 1 |
case Ttuple: return visitTuple (cast(TypeTuple)t); |
2487 |
}
|
|
2488 |
}
|
|
2489 |
|
|
2490 |
/***************************************
|
|
2491 |
* Normalize `e` as the result of resolve() process.
|
|
2492 |
*/
|
|
2493 |
private void resolveExp(Expression e, Type *pt, Expression *pe, Dsymbol* ps) |
|
2494 |
{
|
|
2495 | 1 |
*pt = null; |
2496 | 1 |
*pe = null; |
2497 | 1 |
*ps = null; |
2498 |
|
|
2499 | 1 |
Dsymbol s; |
2500 | 1 |
switch (e.op) |
2501 |
{
|
|
2502 | 1 |
case TOK.error: |
2503 | 1 |
*pt = Type.terror; |
2504 | 1 |
return; |
2505 |
|
|
2506 | 1 |
case TOK.type: |
2507 | 1 |
*pt = e.type; |
2508 | 1 |
return; |
2509 |
|
|
2510 | 1 |
case TOK.variable: |
2511 | 1 |
s = (cast(VarExp)e).var; |
2512 | 1 |
if (s.isVarDeclaration()) |
2513 | 1 |
goto default; |
2514 |
//if (s.isOverDeclaration())
|
|
2515 |
// todo;
|
|
2516 | 1 |
break; |
2517 |
|
|
2518 | 1 |
case TOK.template_: |
2519 |
// TemplateDeclaration
|
|
2520 | 1 |
s = (cast(TemplateExp)e).td; |
2521 | 1 |
break; |
2522 |
|
|
2523 | 1 |
case TOK.scope_: |
2524 | 1 |
s = (cast(ScopeExp)e).sds; |
2525 |
// TemplateDeclaration, TemplateInstance, Import, Package, Module
|
|
2526 | 1 |
break; |
2527 |
|
|
2528 |
case TOK.function_: |
|
2529 |
s = getDsymbol(e); |
|
2530 |
break; |
|
2531 |
|
|
2532 | 1 |
case TOK.dotTemplateDeclaration: |
2533 | 1 |
s = (cast(DotTemplateExp)e).td; |
2534 | 1 |
break; |
2535 |
|
|
2536 |
//case TOK.this_:
|
|
2537 |
//case TOK.super_:
|
|
2538 |
|
|
2539 |
//case TOK.tuple:
|
|
2540 |
|
|
2541 |
//case TOK.overloadSet:
|
|
2542 |
|
|
2543 |
//case TOK.dotVariable:
|
|
2544 |
//case TOK.dotTemplateInstance:
|
|
2545 |
//case TOK.dotType:
|
|
2546 |
//case TOK.dotIdentifier:
|
|
2547 |
|
|
2548 | 1 |
default: |
2549 | 1 |
*pe = e; |
2550 | 1 |
return; |
2551 |
}
|
|
2552 |
|
|
2553 | 1 |
*ps = s; |
2554 |
}
|
|
2555 |
|
|
2556 |
/************************************
|
|
2557 |
* Resolve type 'mt' to either type, symbol, or expression.
|
|
2558 |
* If errors happened, resolved to Type.terror.
|
|
2559 |
*
|
|
2560 |
* Params:
|
|
2561 |
* mt = type to be resolved
|
|
2562 |
* loc = the location where the type is encountered
|
|
2563 |
* sc = the scope of the type
|
|
2564 |
* pe = is set if t is an expression
|
|
2565 |
* pt = is set if t is a type
|
|
2566 |
* ps = is set if t is a symbol
|
|
2567 |
* intypeid = true if in type id
|
|
2568 |
*/
|
|
2569 |
void resolve(Type mt, const ref Loc loc, Scope* sc, Expression* pe, Type* pt, Dsymbol* ps, bool intypeid = false) |
|
2570 |
{
|
|
2571 |
void returnExp(Expression e) |
|
2572 |
{
|
|
2573 | 1 |
*pt = null; |
2574 | 1 |
*pe = e; |
2575 | 1 |
*ps = null; |
2576 |
}
|
|
2577 |
|
|
2578 |
void returnType(Type t) |
|
2579 |
{
|
|
2580 | 1 |
*pt = t; |
2581 | 1 |
*pe = null; |
2582 | 1 |
*ps = null; |
2583 |
}
|
|
2584 |
|
|
2585 |
void returnSymbol(Dsymbol s) |
|
2586 |
{
|
|
2587 | 1 |
*pt = null; |
2588 | 1 |
*pe = null; |
2589 | 1 |
*ps = s; |
2590 |
}
|
|
2591 |
|
|
2592 |
void returnError() |
|
2593 |
{
|
|
2594 | 1 |
returnType(Type.terror); |
2595 |
}
|
|
2596 |
|
|
2597 |
void visitType(Type mt) |
|
2598 |
{
|
|
2599 |
//printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
|
|
2600 | 1 |
Type t = typeSemantic(mt, loc, sc); |
2601 | 1 |
assert(t); |
2602 | 1 |
returnType(t); |
2603 |
}
|
|
2604 |
|
|
2605 |
void visitSArray(TypeSArray mt) |
|
2606 |
{
|
|
2607 |
//printf("TypeSArray::resolve() %s\n", mt.toChars());
|
|
2608 | 1 |
mt.next.resolve(loc, sc, pe, pt, ps, intypeid); |
2609 |
//printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
|
|
2610 | 1 |
if (*pe) |
2611 |
{
|
|
2612 |
// It's really an index expression
|
|
2613 | 1 |
if (Dsymbol s = getDsymbol(*pe)) |
2614 | 1 |
*pe = new DsymbolExp(loc, s); |
2615 | 1 |
returnExp(new ArrayExp(loc, *pe, mt.dim)); |
2616 |
}
|
|
2617 | 1 |
else if (*ps) |
2618 |
{
|
|
2619 | 1 |
Dsymbol s = *ps; |
2620 | 1 |
if (auto tup = s.isTupleDeclaration()) |
2621 |
{
|
|
2622 | 1 |
mt.dim = semanticLength(sc, tup, mt.dim); |
2623 | 1 |
mt.dim = mt.dim.ctfeInterpret(); |
2624 | 1 |
if (mt.dim.op == TOK.error) |
2625 |
return returnError(); |
|
2626 |
|
|
2627 | 1 |
const d = mt.dim.toUInteger(); |
2628 | 1 |
if (d >= tup.objects.dim) |
2629 |
{
|
|
2630 | 1 |
error(loc, "tuple index `%llu` exceeds length %llu", d, cast(ulong) tup.objects.dim); |
2631 | 1 |
return returnError(); |
2632 |
}
|
|
2633 |
|
|
2634 | 1 |
RootObject o = (*tup.objects)[cast(size_t)d]; |
2635 | 1 |
if (o.dyncast() == DYNCAST.dsymbol) |
2636 |
{
|
|
2637 | 1 |
return returnSymbol(cast(Dsymbol)o); |
2638 |
}
|
|
2639 | 1 |
if (o.dyncast() == DYNCAST.expression) |
2640 |
{
|
|
2641 | 1 |
Expression e = cast(Expression)o; |
2642 | 1 |
if (e.op == TOK.dSymbol) |
2643 | 1 |
return returnSymbol((cast(DsymbolExp)e).s); |
2644 |
else
|
|
2645 | 1 |
return returnExp(e); |
2646 |
}
|
|
2647 | 1 |
if (o.dyncast() == DYNCAST.type) |
2648 |
{
|
|
2649 | 1 |
return returnType((cast(Type)o).addMod(mt.mod)); |
2650 |
}
|
|
2651 |
|
|
2652 |
/* Create a new TupleDeclaration which
|
|
2653 |
* is a slice [d..d+1] out of the old one.
|
|
2654 |
* Do it this way because TemplateInstance::semanticTiargs()
|
|
2655 |
* can handle unresolved Objects this way.
|
|
2656 |
*/
|
|
2657 |
auto objects = new Objects(1); |
|
2658 |
(*objects)[0] = o; |
|
2659 |
return returnSymbol(new TupleDeclaration(loc, tup.ident, objects)); |
|
2660 |
}
|
|
2661 |
else
|
|
2662 |
return visitType(mt); |
|
2663 |
}
|
|
2664 |
else
|
|
2665 |
{
|
|
2666 | 1 |
if ((*pt).ty != Terror) |
2667 | 1 |
mt.next = *pt; // prevent re-running semantic() on 'next' |
2668 | 1 |
visitType(mt); |
2669 |
}
|
|
2670 |
|
|
2671 |
}
|
|
2672 |
|
|
2673 |
void visitDArray(TypeDArray mt) |
|
2674 |
{
|
|
2675 |
//printf("TypeDArray::resolve() %s\n", mt.toChars());
|
|
2676 | 1 |
mt.next.resolve(loc, sc, pe, pt, ps, intypeid); |
2677 |
//printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
|
|
2678 | 1 |
if (*pe) |
2679 |
{
|
|
2680 |
// It's really a slice expression
|
|
2681 | 1 |
if (Dsymbol s = getDsymbol(*pe)) |
2682 | 1 |
*pe = new DsymbolExp(loc, s); |
2683 | 1 |
returnExp(new ArrayExp(loc, *pe)); |
2684 |
}
|
|
2685 | 1 |
else if (*ps) |
2686 |
{
|
|
2687 | 1 |
if (auto tup = (*ps).isTupleDeclaration()) |
2688 |
{
|
|
2689 |
// keep *ps
|
|
2690 |
}
|
|
2691 |
else
|
|
2692 |
visitType(mt); |
|
2693 |
}
|
|
2694 |
else
|
|
2695 |
{
|
|
2696 | 1 |
if ((*pt).ty != Terror) |
2697 | 1 |
mt.next = *pt; // prevent re-running semantic() on 'next' |
2698 | 1 |
visitType(mt); |
2699 |
}
|
|
2700 |
}
|
|
2701 |
|
|
2702 |
void visitAArray(TypeAArray mt) |
|
2703 |
{
|
|
2704 |
//printf("TypeAArray::resolve() %s\n", mt.toChars());
|
|
2705 |
// Deal with the case where we thought the index was a type, but
|
|
2706 |
// in reality it was an expression.
|
|
2707 | 1 |
if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray) |
2708 |
{
|
|
2709 | 1 |
Expression e; |
2710 | 1 |
Type t; |
2711 | 1 |
Dsymbol s; |
2712 | 1 |
mt.index.resolve(loc, sc, &e, &t, &s, intypeid); |
2713 | 1 |
if (e) |
2714 |
{
|
|
2715 |
// It was an expression -
|
|
2716 |
// Rewrite as a static array
|
|
2717 | 1 |
auto tsa = new TypeSArray(mt.next, e); |
2718 | 1 |
tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done |
2719 | 1 |
return tsa.resolve(loc, sc, pe, pt, ps, intypeid); |
2720 |
}
|
|
2721 | 1 |
else if (t) |
2722 | 1 |
mt.index = t; |
2723 |
else
|
|
2724 |
.error(loc, "index is not a type or an expression"); |
|
2725 |
}
|
|
2726 | 1 |
visitType(mt); |
2727 |
}
|
|
2728 |
|
|
2729 |
/*************************************
|
|
2730 |
* Takes an array of Identifiers and figures out if
|
|
2731 |
* it represents a Type or an Expression.
|
|
2732 |
* Output:
|
|
2733 |
* if expression, *pe is set
|
|
2734 |
* if type, *pt is set
|
|
2735 |
*/
|
|
2736 |
void visitIdentifier(TypeIdentifier mt) |
|
2737 |
{
|
|
2738 |
//printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
|
|
2739 | 1 |
if ((mt.ident.equals(Id._super) || mt.ident.equals(Id.This)) && !hasThis(sc)) |
2740 |
{
|
|
2741 |
// @@@DEPRECATED_v2.091@@@.
|
|
2742 |
// Made an error in 2.086.
|
|
2743 |
// Eligible for removal in 2.091.
|
|
2744 | 1 |
if (mt.ident.equals(Id._super)) |
2745 |
{
|
|
2746 | 1 |
error(mt.loc, "Using `super` as a type is obsolete. Use `typeof(super)` instead"); |
2747 |
}
|
|
2748 |
// @@@DEPRECATED_v2.091@@@.
|
|
2749 |
// Made an error in 2.086.
|
|
2750 |
// Eligible for removal in 2.091.
|
|
2751 | 1 |
if (mt.ident.equals(Id.This)) |
2752 |
{
|
|
2753 | 1 |
error(mt.loc, "Using `this` as a type is obsolete. Use `typeof(this)` instead"); |
2754 |
}
|
|
2755 | 1 |
if (AggregateDeclaration ad = sc.getStructClassScope()) |
2756 |
{
|
|
2757 | 1 |
if (ClassDeclaration cd = ad.isClassDeclaration()) |
2758 |
{
|
|
2759 | 1 |
if (mt.ident.equals(Id.This)) |
2760 | 1 |
mt.ident = cd.ident; |
2761 | 1 |
else if (cd.baseClass && mt.ident.equals(Id._super)) |
2762 | 1 |
mt.ident = cd.baseClass.ident; |
2763 |
}
|
|
2764 |
else
|
|
2765 |
{
|
|
2766 |