| |
| /* Compiler implementation of the D programming language |
| * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved |
| * written by Walter Bright |
| * http://www.digitalmars.com |
| * Distributed under the Boost Software License, Version 1.0. |
| * http://www.boost.org/LICENSE_1_0.txt |
| * https://github.com/D-Programming-Language/dmd/blob/master/src/cast.c |
| */ |
| |
| #include "root/dsystem.h" // mem{set|cpy}() |
| #include "root/rmem.h" |
| |
| #include "mars.h" |
| #include "expression.h" |
| #include "mtype.h" |
| #include "utf.h" |
| #include "declaration.h" |
| #include "aggregate.h" |
| #include "template.h" |
| #include "scope.h" |
| #include "id.h" |
| #include "init.h" |
| #include "tokens.h" |
| |
| FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL); |
| bool isCommutative(TOK op); |
| MOD MODmerge(MOD mod1, MOD mod2); |
| Expression *semantic(Expression *e, Scope *sc); |
| |
| /* ==================== implicitCast ====================== */ |
| |
| /************************************** |
| * Do an implicit cast. |
| * Issue error if it can't be done. |
| */ |
| |
| |
| Expression *implicitCastTo(Expression *e, Scope *sc, Type *t) |
| { |
| class ImplicitCastTo : public Visitor |
| { |
| public: |
| Type *t; |
| Scope *sc; |
| Expression *result; |
| |
| ImplicitCastTo(Scope *sc, Type *t) |
| : t(t), sc(sc) |
| { |
| result = NULL; |
| } |
| |
| void visit(Expression *e) |
| { |
| //printf("Expression::implicitCastTo(%s of type %s) => %s\n", e->toChars(), e->type->toChars(), t->toChars()); |
| |
| MATCH match = e->implicitConvTo(t); |
| if (match) |
| { |
| if (match == MATCHconst && |
| (e->type->constConv(t) || |
| (!e->isLvalue() && e->type->equivalent(t)))) |
| { |
| /* Do not emit CastExp for const conversions and |
| * unique conversions on rvalue. |
| */ |
| result = e->copy(); |
| result->type = t; |
| return; |
| } |
| result = e->castTo(sc, t); |
| return; |
| } |
| |
| result = e->optimize(WANTvalue); |
| if (result != e) |
| { |
| result->accept(this); |
| return; |
| } |
| |
| if (t->ty != Terror && e->type->ty != Terror) |
| { |
| if (!t->deco) |
| { |
| e->error("forward reference to type %s", t->toChars()); |
| } |
| else |
| { |
| //printf("type %p ty %d deco %p\n", type, type->ty, type->deco); |
| //type = type->semantic(loc, sc); |
| //printf("type %s t %s\n", type->deco, t->deco); |
| e->error("cannot implicitly convert expression (%s) of type %s to %s", |
| e->toChars(), e->type->toChars(), t->toChars()); |
| } |
| } |
| result = new ErrorExp(); |
| } |
| |
| void visit(StringExp *e) |
| { |
| //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e->toChars(), e->type->toChars(), t->toChars()); |
| visit((Expression *)e); |
| if (result->op == TOKstring) |
| { |
| // Retain polysemous nature if it started out that way |
| ((StringExp *)result)->committed = e->committed; |
| } |
| } |
| |
| void visit(ErrorExp *e) |
| { |
| result = e; |
| } |
| |
| void visit(FuncExp *e) |
| { |
| //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars()); |
| FuncExp *fe; |
| if (e->matchType(t, sc, &fe) > MATCHnomatch) |
| { |
| result = fe; |
| return; |
| } |
| visit((Expression *)e); |
| } |
| |
| void visit(ArrayLiteralExp *e) |
| { |
| visit((Expression *)e); |
| |
| Type *tb = result->type->toBasetype(); |
| if (tb->ty == Tarray && global.params.useTypeInfo && Type::dtypeinfo) |
| semanticTypeInfo(sc, ((TypeDArray *)tb)->next); |
| } |
| |
| void visit(SliceExp *e) |
| { |
| visit((Expression *)e); |
| if (result->op != TOKslice) |
| return; |
| |
| e = (SliceExp *)result; |
| if (e->e1->op == TOKarrayliteral) |
| { |
| ArrayLiteralExp *ale = (ArrayLiteralExp *)e->e1; |
| Type *tb = t->toBasetype(); |
| Type *tx; |
| if (tb->ty == Tsarray) |
| tx = tb->nextOf()->sarrayOf(ale->elements ? ale->elements->dim : 0); |
| else |
| tx = tb->nextOf()->arrayOf(); |
| e->e1 = ale->implicitCastTo(sc, tx); |
| } |
| } |
| }; |
| |
| ImplicitCastTo v(sc, t); |
| e->accept(&v); |
| return v.result; |
| } |
| |
| /******************************************* |
| * Return MATCH level of implicitly converting e to type t. |
| * Don't do the actual cast; don't change e. |
| */ |
| |
| MATCH implicitConvTo(Expression *e, Type *t) |
| { |
| class ImplicitConvTo : public Visitor |
| { |
| public: |
| Type *t; |
| MATCH result; |
| |
| ImplicitConvTo(Type *t) |
| : t(t) |
| { |
| result = MATCHnomatch; |
| } |
| |
| void visit(Expression *e) |
| { |
| //static int nest; if (++nest == 10) halt(); |
| if (t == Type::terror) |
| return; |
| if (!e->type) |
| { |
| e->error("%s is not an expression", e->toChars()); |
| e->type = Type::terror; |
| } |
| Expression *ex = e->optimize(WANTvalue); |
| if (ex->type->equals(t)) |
| { |
| result = MATCHexact; |
| return; |
| } |
| if (ex != e) |
| { |
| //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars()); |
| result = ex->implicitConvTo(t); |
| return; |
| } |
| MATCH match = e->type->implicitConvTo(t); |
| if (match != MATCHnomatch) |
| { |
| result = match; |
| return; |
| } |
| |
| /* See if we can do integral narrowing conversions |
| */ |
| if (e->type->isintegral() && t->isintegral() && |
| e->type->isTypeBasic() && t->isTypeBasic()) |
| { |
| IntRange src = getIntRange(e); |
| IntRange target = IntRange::fromType(t); |
| if (target.contains(src)) |
| { |
| result = MATCHconvert; |
| return; |
| } |
| } |
| } |
| |
| /****** |
| * Given expression e of type t, see if we can implicitly convert e |
| * to type tprime, where tprime is type t with mod bits added. |
| * Returns: |
| * match level |
| */ |
| static MATCH implicitMod(Expression *e, Type *t, MOD mod) |
| { |
| Type *tprime; |
| if (t->ty == Tpointer) |
| tprime = t->nextOf()->castMod(mod)->pointerTo(); |
| else if (t->ty == Tarray) |
| tprime = t->nextOf()->castMod(mod)->arrayOf(); |
| else if (t->ty == Tsarray) |
| tprime = t->nextOf()->castMod(mod)->sarrayOf(t->size() / t->nextOf()->size()); |
| else |
| tprime = t->castMod(mod); |
| |
| return e->implicitConvTo(tprime); |
| } |
| |
| static MATCH implicitConvToAddMin(BinExp *e, Type *t) |
| { |
| /* Is this (ptr +- offset)? If so, then ask ptr |
| * if the conversion can be done. |
| * This is to support doing things like implicitly converting a mutable unique |
| * pointer to an immutable pointer. |
| */ |
| |
| Type *typeb = e->type->toBasetype(); |
| Type *tb = t->toBasetype(); |
| if (typeb->ty != Tpointer || tb->ty != Tpointer) |
| return MATCHnomatch; |
| |
| Type *t1b = e->e1->type->toBasetype(); |
| Type *t2b = e->e2->type->toBasetype(); |
| if (t1b->ty == Tpointer && t2b->isintegral() && |
| t1b->equivalent(tb)) |
| { |
| // ptr + offset |
| // ptr - offset |
| MATCH m = e->e1->implicitConvTo(t); |
| return (m > MATCHconst) ? MATCHconst : m; |
| } |
| if (t2b->ty == Tpointer && t1b->isintegral() && |
| t2b->equivalent(tb)) |
| { |
| // offset + ptr |
| MATCH m = e->e2->implicitConvTo(t); |
| return (m > MATCHconst) ? MATCHconst : m; |
| } |
| |
| return MATCHnomatch; |
| } |
| |
| void visit(AddExp *e) |
| { |
| visit((Expression *)e); |
| if (result == MATCHnomatch) |
| result = implicitConvToAddMin(e, t); |
| } |
| |
| void visit(MinExp *e) |
| { |
| visit((Expression *)e); |
| if (result == MATCHnomatch) |
| result = implicitConvToAddMin(e, t); |
| } |
| |
| void visit(IntegerExp *e) |
| { |
| MATCH m = e->type->implicitConvTo(t); |
| if (m >= MATCHconst) |
| { |
| result = m; |
| return; |
| } |
| |
| TY ty = e->type->toBasetype()->ty; |
| TY toty = t->toBasetype()->ty; |
| TY oldty = ty; |
| |
| if (m == MATCHnomatch && t->ty == Tenum) |
| return; |
| |
| if (t->ty == Tvector) |
| { |
| TypeVector *tv = (TypeVector *)t; |
| TypeBasic *tb = tv->elementType(); |
| if (tb->ty == Tvoid) |
| return; |
| toty = tb->ty; |
| } |
| |
| switch (ty) |
| { |
| case Tbool: |
| case Tint8: |
| case Tchar: |
| case Tuns8: |
| case Tint16: |
| case Tuns16: |
| case Twchar: |
| ty = Tint32; |
| break; |
| |
| case Tdchar: |
| ty = Tuns32; |
| break; |
| |
| default: |
| break; |
| } |
| |
| // Only allow conversion if no change in value |
| dinteger_t value = e->toInteger(); |
| switch (toty) |
| { |
| case Tbool: |
| if ((value & 1) != value) |
| return; |
| break; |
| |
| case Tint8: |
| if (ty == Tuns64 && value & ~0x7FUL) |
| return; |
| else if ((signed char)value != (sinteger_t)value) |
| return; |
| break; |
| |
| case Tchar: |
| if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) |
| return; |
| /* fall through */ |
| case Tuns8: |
| //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); |
| if ((unsigned char)value != value) |
| return; |
| break; |
| |
| case Tint16: |
| if (ty == Tuns64 && value & ~0x7FFFUL) |
| return; |
| else if ((short)value != (sinteger_t)value) |
| return; |
| break; |
| |
| case Twchar: |
| if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) |
| return; |
| /* fall through */ |
| case Tuns16: |
| if ((unsigned short)value != value) |
| return; |
| break; |
| |
| case Tint32: |
| if (ty == Tuns32) |
| { |
| } |
| else if (ty == Tuns64 && value & ~0x7FFFFFFFUL) |
| return; |
| else if ((int)value != (sinteger_t)value) |
| return; |
| break; |
| |
| case Tuns32: |
| if (ty == Tint32) |
| { |
| } |
| else if ((unsigned)value != value) |
| return; |
| break; |
| |
| case Tdchar: |
| if (value > 0x10FFFFUL) |
| return; |
| break; |
| |
| case Tfloat32: |
| { |
| volatile float f; |
| if (e->type->isunsigned()) |
| { |
| f = (float)value; |
| if (f != value) |
| return; |
| } |
| else |
| { |
| f = (float)(sinteger_t)value; |
| if (f != (sinteger_t)value) |
| return; |
| } |
| break; |
| } |
| |
| case Tfloat64: |
| { |
| volatile double f; |
| if (e->type->isunsigned()) |
| { |
| f = (double)value; |
| if (f != value) |
| return; |
| } |
| else |
| { |
| f = (double)(sinteger_t)value; |
| if (f != (sinteger_t)value) |
| return; |
| } |
| break; |
| } |
| |
| case Tfloat80: |
| { |
| volatile_longdouble f; |
| if (e->type->isunsigned()) |
| { |
| f = ldouble(value); |
| if ((dinteger_t)f != value) // isn't this a noop, because the compiler prefers ld |
| return; |
| } |
| else |
| { |
| f = ldouble((sinteger_t)value); |
| if ((sinteger_t)f != (sinteger_t)value) |
| return; |
| } |
| break; |
| } |
| |
| case Tpointer: |
| //printf("type = %s\n", type->toBasetype()->toChars()); |
| //printf("t = %s\n", t->toBasetype()->toChars()); |
| if (ty == Tpointer && |
| e->type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty) |
| { |
| /* Allow things like: |
| * const char* P = cast(char *)3; |
| * char* q = P; |
| */ |
| break; |
| } |
| /* fall through */ |
| |
| default: |
| visit((Expression *)e); |
| return; |
| } |
| |
| //printf("MATCHconvert\n"); |
| result = MATCHconvert; |
| } |
| |
| void visit(ErrorExp *) |
| { |
| // no match |
| } |
| |
| void visit(NullExp *e) |
| { |
| if (e->type->equals(t)) |
| { |
| result = MATCHexact; |
| return; |
| } |
| |
| /* Allow implicit conversions from immutable to mutable|const, |
| * and mutable to immutable. It works because, after all, a null |
| * doesn't actually point to anything. |
| */ |
| if (t->equivalent(e->type)) |
| { |
| result = MATCHconst; |
| return; |
| } |
| |
| visit((Expression *)e); |
| } |
| |
| void visit(StructLiteralExp *e) |
| { |
| visit((Expression *)e); |
| if (result != MATCHnomatch) |
| return; |
| if (e->type->ty == t->ty && e->type->ty == Tstruct && |
| ((TypeStruct *)e->type)->sym == ((TypeStruct *)t)->sym) |
| { |
| result = MATCHconst; |
| for (size_t i = 0; i < e->elements->dim; i++) |
| { |
| Expression *el = (*e->elements)[i]; |
| if (!el) |
| continue; |
| Type *te = el->type; |
| te = e->sd->fields[i]->type->addMod(t->mod); |
| MATCH m2 = el->implicitConvTo(te); |
| //printf("\t%s => %s, match = %d\n", el->toChars(), te->toChars(), m2); |
| if (m2 < result) |
| result = m2; |
| } |
| } |
| } |
| |
| void visit(StringExp *e) |
| { |
| if (!e->committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) |
| return; |
| |
| if (e->type->ty == Tsarray || e->type->ty == Tarray || e->type->ty == Tpointer) |
| { |
| TY tyn = e->type->nextOf()->ty; |
| if (tyn == Tchar || tyn == Twchar || tyn == Tdchar) |
| { |
| switch (t->ty) |
| { |
| case Tsarray: |
| if (e->type->ty == Tsarray) |
| { |
| TY tynto = t->nextOf()->ty; |
| if (tynto == tyn) |
| { |
| if (((TypeSArray *)e->type)->dim->toInteger() == |
| ((TypeSArray *)t)->dim->toInteger()) |
| { |
| result = MATCHexact; |
| } |
| return; |
| } |
| if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) |
| { |
| if (e->committed && tynto != tyn) |
| return; |
| size_t fromlen = e->numberOfCodeUnits(tynto); |
| size_t tolen = (size_t)((TypeSArray *)t)->dim->toInteger(); |
| if (tolen < fromlen) |
| return; |
| if (tolen != fromlen) |
| { |
| // implicit length extending |
| result = MATCHconvert; |
| return; |
| } |
| } |
| if (!e->committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar)) |
| { |
| result = MATCHexact; |
| return; |
| } |
| } |
| else if (e->type->ty == Tarray) |
| { |
| TY tynto = t->nextOf()->ty; |
| if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) |
| { |
| if (e->committed && tynto != tyn) |
| return; |
| size_t fromlen = e->numberOfCodeUnits(tynto); |
| size_t tolen = (size_t)((TypeSArray *)t)->dim->toInteger(); |
| if (tolen < fromlen) |
| return; |
| if (tolen != fromlen) |
| { |
| // implicit length extending |
| result = MATCHconvert; |
| return; |
| } |
| } |
| if (tynto == tyn) |
| { |
| result = MATCHexact; |
| return; |
| } |
| if (!e->committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar)) |
| { |
| result = MATCHexact; |
| return; |
| } |
| } |
| /* fall through */ |
| case Tarray: |
| case Tpointer: |
| Type *tn = t->nextOf(); |
| MATCH m = MATCHexact; |
| if (e->type->nextOf()->mod != tn->mod) |
| { |
| if (!tn->isConst()) |
| return; |
| m = MATCHconst; |
| } |
| if (!e->committed) |
| { |
| switch (tn->ty) |
| { |
| case Tchar: |
| if (e->postfix == 'w' || e->postfix == 'd') |
| m = MATCHconvert; |
| result = m; |
| return; |
| case Twchar: |
| if (e->postfix != 'w') |
| m = MATCHconvert; |
| result = m; |
| return; |
| case Tdchar: |
| if (e->postfix != 'd') |
| m = MATCHconvert; |
| result = m; |
| return; |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| visit((Expression *)e); |
| } |
| |
| void visit(ArrayLiteralExp *e) |
| { |
| Type *typeb = e->type->toBasetype(); |
| Type *tb = t->toBasetype(); |
| if ((tb->ty == Tarray || tb->ty == Tsarray) && |
| (typeb->ty == Tarray || typeb->ty == Tsarray)) |
| { |
| result = MATCHexact; |
| Type *typen = typeb->nextOf()->toBasetype(); |
| |
| if (tb->ty == Tsarray) |
| { |
| TypeSArray *tsa = (TypeSArray *)tb; |
| if (e->elements->dim != tsa->dim->toInteger()) |
| result = MATCHnomatch; |
| } |
| |
| Type *telement = tb->nextOf(); |
| if (!e->elements->dim) |
| { |
| if (typen->ty != Tvoid) |
| result = typen->implicitConvTo(telement); |
| } |
| else |
| { |
| if (e->basis) |
| { |
| MATCH m = e->basis->implicitConvTo(telement); |
| if (m < result) |
| result = m; |
| } |
| for (size_t i = 0; i < e->elements->dim; i++) |
| { |
| Expression *el = (*e->elements)[i]; |
| if (result == MATCHnomatch) |
| break; |
| if (!el) |
| continue; |
| MATCH m = el->implicitConvTo(telement); |
| if (m < result) |
| result = m; // remember worst match |
| } |
| } |
| |
| if (!result) |
| result = e->type->implicitConvTo(t); |
| |
| return; |
| } |
| else if (tb->ty == Tvector && |
| (typeb->ty == Tarray || typeb->ty == Tsarray)) |
| { |
| result = MATCHexact; |
| // Convert array literal to vector type |
| TypeVector *tv = (TypeVector *)tb; |
| TypeSArray *tbase = (TypeSArray *)tv->basetype; |
| assert(tbase->ty == Tsarray); |
| const size_t edim = e->elements->dim; |
| const size_t tbasedim = tbase->dim->toInteger(); |
| if (edim > tbasedim) |
| { |
| result = MATCHnomatch; |
| return; |
| } |
| |
| Type *telement = tv->elementType(); |
| if (edim < tbasedim) |
| { |
| Expression *el = typeb->nextOf()->defaultInitLiteral(e->loc); |
| MATCH m = el->implicitConvTo(telement); |
| if (m < result) |
| result = m; // remember worst match |
| } |
| for (size_t i = 0; i < edim; i++) |
| { |
| Expression *el = (*e->elements)[i]; |
| MATCH m = el->implicitConvTo(telement); |
| if (m < result) |
| result = m; // remember worst match |
| if (result == MATCHnomatch) |
| break; // no need to check for worse |
| } |
| return; |
| } |
| |
| visit((Expression *)e); |
| } |
| |
| void visit(AssocArrayLiteralExp *e) |
| { |
| Type *typeb = e->type->toBasetype(); |
| Type *tb = t->toBasetype(); |
| if (tb->ty == Taarray && typeb->ty == Taarray) |
| { |
| result = MATCHexact; |
| for (size_t i = 0; i < e->keys->dim; i++) |
| { |
| Expression *el = (*e->keys)[i]; |
| MATCH m = el->implicitConvTo(((TypeAArray *)tb)->index); |
| if (m < result) |
| result = m; // remember worst match |
| if (result == MATCHnomatch) |
| break; // no need to check for worse |
| el = (*e->values)[i]; |
| m = el->implicitConvTo(tb->nextOf()); |
| if (m < result) |
| result = m; // remember worst match |
| if (result == MATCHnomatch) |
| break; // no need to check for worse |
| } |
| return; |
| } |
| else |
| visit((Expression *)e); |
| } |
| |
| void visit(CallExp *e) |
| { |
| visit((Expression *)e); |
| if (result != MATCHnomatch) |
| return; |
| |
| /* Allow the result of strongly pure functions to |
| * convert to immutable |
| */ |
| if (e->f && e->f->isolateReturn()) |
| { |
| result = e->type->immutableOf()->implicitConvTo(t); |
| if (result > MATCHconst) // Match level is MATCHconst at best. |
| result = MATCHconst; |
| return; |
| } |
| |
| /* Conversion is 'const' conversion if: |
| * 1. function is pure (weakly pure is ok) |
| * 2. implicit conversion only fails because of mod bits |
| * 3. each function parameter can be implicitly converted to the mod bits |
| */ |
| Type *tx = e->f ? e->f->type : e->e1->type; |
| tx = tx->toBasetype(); |
| if (tx->ty != Tfunction) |
| return; |
| TypeFunction *tf = (TypeFunction *)tx; |
| |
| if (tf->purity == PUREimpure) |
| return; |
| if (e->f && e->f->isNested()) |
| return; |
| |
| /* See if fail only because of mod bits. |
| * |
| * Bugzilla 14155: All pure functions can access global immutable data. |
| * So the returned pointer may refer an immutable global data, |
| * and then the returned pointer that points non-mutable object |
| * cannot be unique pointer. |
| * |
| * Example: |
| * immutable g; |
| * static this() { g = 1; } |
| * const(int*) foo() pure { return &g; } |
| * void test() { |
| * immutable(int*) ip = foo(); // OK |
| * int* mp = foo(); // should be disallowed |
| * } |
| */ |
| if (e->type->immutableOf()->implicitConvTo(t) < MATCHconst && |
| e->type->addMod(MODshared)->implicitConvTo(t) < MATCHconst && |
| e->type->implicitConvTo(t->addMod(MODshared)) < MATCHconst) |
| { |
| return; |
| } |
| // Allow a conversion to immutable type, or |
| // conversions of mutable types between thread-local and shared. |
| |
| /* Get mod bits of what we're converting to |
| */ |
| Type *tb = t->toBasetype(); |
| MOD mod = tb->mod; |
| if (tf->isref) |
| ; |
| else |
| { |
| Type *ti = getIndirection(t); |
| if (ti) |
| mod = ti->mod; |
| } |
| if (mod & MODwild) |
| return; // not sure what to do with this |
| |
| /* Apply mod bits to each function parameter, |
| * and see if we can convert the function argument to the modded type |
| */ |
| |
| size_t nparams = Parameter::dim(tf->parameters); |
| size_t j = (tf->linkage == LINKd && tf->varargs == 1); // if TypeInfoArray was prepended |
| if (e->e1->op == TOKdotvar) |
| { |
| /* Treat 'this' as just another function argument |
| */ |
| DotVarExp *dve = (DotVarExp *)e->e1; |
| Type *targ = dve->e1->type; |
| if (targ->constConv(targ->castMod(mod)) == MATCHnomatch) |
| return; |
| } |
| for (size_t i = j; i < e->arguments->dim; ++i) |
| { |
| Expression *earg = (*e->arguments)[i]; |
| Type *targ = earg->type->toBasetype(); |
| if (i - j < nparams) |
| { |
| Parameter *fparam = Parameter::getNth(tf->parameters, i - j); |
| if (fparam->storageClass & STClazy) |
| return; // not sure what to do with this |
| Type *tparam = fparam->type; |
| if (!tparam) |
| continue; |
| if (fparam->storageClass & (STCout | STCref)) |
| { |
| if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch) |
| return; |
| continue; |
| } |
| } |
| |
| if (implicitMod(earg, targ, mod) == MATCHnomatch) |
| return; |
| } |
| |
| /* Success |
| */ |
| result = MATCHconst; |
| } |
| |
| void visit(AddrExp *e) |
| { |
| result = e->type->implicitConvTo(t); |
| //printf("\tresult = %d\n", result); |
| |
| if (result != MATCHnomatch) |
| return; |
| |
| // Look for pointers to functions where the functions are overloaded. |
| |
| t = t->toBasetype(); |
| |
| if (e->e1->op == TOKoverloadset && |
| (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) |
| { |
| OverExp *eo = (OverExp *)e->e1; |
| FuncDeclaration *f = NULL; |
| for (size_t i = 0; i < eo->vars->a.dim; i++) |
| { |
| Dsymbol *s = eo->vars->a[i]; |
| FuncDeclaration *f2 = s->isFuncDeclaration(); |
| assert(f2); |
| if (f2->overloadExactMatch(t->nextOf())) |
| { |
| if (f) |
| { |
| /* Error if match in more than one overload set, |
| * even if one is a 'better' match than the other. |
| */ |
| ScopeDsymbol::multiplyDefined(e->loc, f, f2); |
| } |
| else |
| f = f2; |
| result = MATCHexact; |
| } |
| } |
| } |
| |
| if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction && |
| t->ty == Tpointer && t->nextOf()->ty == Tfunction && |
| e->e1->op == TOKvar) |
| { |
| /* I don't think this can ever happen - |
| * it should have been |
| * converted to a SymOffExp. |
| */ |
| assert(0); |
| } |
| |
| //printf("\tresult = %d\n", result); |
| } |
| |
| void visit(SymOffExp *e) |
| { |
| result = e->type->implicitConvTo(t); |
| //printf("\tresult = %d\n", result); |
| if (result != MATCHnomatch) |
| return; |
| |
| // Look for pointers to functions where the functions are overloaded. |
| t = t->toBasetype(); |
| if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction && |
| (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) |
| { |
| if (FuncDeclaration *f = e->var->isFuncDeclaration()) |
| { |
| f = f->overloadExactMatch(t->nextOf()); |
| if (f) |
| { |
| if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) || |
| (t->ty == Tpointer && !(f->needThis() || f->isNested()))) |
| { |
| result = MATCHexact; |
| } |
| } |
| } |
| } |
| //printf("\tresult = %d\n", result); |
| } |
| |
| void visit(DelegateExp *e) |
| { |
| result = e->type->implicitConvTo(t); |
| if (result != MATCHnomatch) |
| return; |
| |
| // Look for pointers to functions where the functions are overloaded. |
| t = t->toBasetype(); |
| if (e->type->ty == Tdelegate && |
| t->ty == Tdelegate) |
| { |
| if (e->func && e->func->overloadExactMatch(t->nextOf())) |
| result = MATCHexact; |
| } |
| } |
| |
| void visit(FuncExp *e) |
| { |
| //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars()); |
| MATCH m = e->matchType(t, NULL, NULL, 1); |
| if (m > MATCHnomatch) |
| { |
| result = m; |
| return; |
| } |
| visit((Expression *)e); |
| } |
| |
| void visit(AndExp *e) |
| { |
| visit((Expression *)e); |
| if (result != MATCHnomatch) |
| return; |
| |
| MATCH m1 = e->e1->implicitConvTo(t); |
| MATCH m2 = e->e2->implicitConvTo(t); |
| |
| // Pick the worst match |
| result = (m1 < m2) ? m1 : m2; |
| } |
| |
| void visit(OrExp *e) |
| { |
| visit((Expression *)e); |
| if (result != MATCHnomatch) |
| return; |
| |
| MATCH m1 = e->e1->implicitConvTo(t); |
| MATCH m2 = e->e2->implicitConvTo(t); |
| |
| // Pick the worst match |
| result = (m1 < m2) ? m1 : m2; |
| } |
| |
| void visit(XorExp *e) |
| { |
| visit((Expression *)e); |
| if (result != MATCHnomatch) |
| return; |
| |
| MATCH m1 = e->e1->implicitConvTo(t); |
| MATCH m2 = e->e2->implicitConvTo(t); |
| |
| // Pick the worst match |
| result = (m1 < m2) ? m1 : m2; |
| } |
| |
| void visit(CondExp *e) |
| { |
| MATCH m1 = e->e1->implicitConvTo(t); |
| MATCH m2 = e->e2->implicitConvTo(t); |
| //printf("CondExp: m1 %d m2 %d\n", m1, m2); |
| |
| // Pick the worst match |
| result = (m1 < m2) ? m1 : m2; |
| } |
| |
| void visit(CommaExp *e) |
| { |
| e->e2->accept(this); |
| } |
| |
| void visit(CastExp *e) |
| { |
| result = e->type->implicitConvTo(t); |
| if (result != MATCHnomatch) |
| return; |
| |
| if (t->isintegral() && |
| e->e1->type->isintegral() && |
| e->e1->implicitConvTo(t) != MATCHnomatch) |
| result = MATCHconvert; |
| else |
| visit((Expression *)e); |
| } |
| |
| void visit(NewExp *e) |
| { |
| visit((Expression *)e); |
| if (result != MATCHnomatch) |
| return; |
| |
| /* Calling new() is like calling a pure function. We can implicitly convert the |
| * return from new() to t using the same algorithm as in CallExp, with the function |
| * 'arguments' being: |
| * thisexp |
| * newargs |
| * arguments |
| * .init |
| * 'member' and 'allocator' need to be pure. |
| */ |
| |
| /* See if fail only because of mod bits |
| */ |
| if (e->type->immutableOf()->implicitConvTo(t->immutableOf()) == MATCHnomatch) |
| return; |
| |
| /* Get mod bits of what we're converting to |
| */ |
| Type *tb = t->toBasetype(); |
| MOD mod = tb->mod; |
| if (Type *ti = getIndirection(t)) |
| mod = ti->mod; |
| if (mod & MODwild) |
| return; // not sure what to do with this |
| |
| /* Apply mod bits to each argument, |
| * and see if we can convert the argument to the modded type |
| */ |
| |
| if (e->thisexp) |
| { |
| /* Treat 'this' as just another function argument |
| */ |
| Type *targ = e->thisexp->type; |
| if (targ->constConv(targ->castMod(mod)) == MATCHnomatch) |
| return; |
| } |
| |
| /* Check call to 'allocator', then 'member' |
| */ |
| FuncDeclaration *fd = e->allocator; |
| for (int count = 0; count < 2; ++count, (fd = e->member)) |
| { |
| if (!fd) |
| continue; |
| if (fd->errors || fd->type->ty != Tfunction) |
| return; // error |
| TypeFunction *tf = (TypeFunction *)fd->type; |
| if (tf->purity == PUREimpure) |
| return; // impure |
| |
| if (fd == e->member) |
| { |
| if (e->type->immutableOf()->implicitConvTo(t) < MATCHconst && |
| e->type->addMod(MODshared)->implicitConvTo(t) < MATCHconst && |
| e->type->implicitConvTo(t->addMod(MODshared)) < MATCHconst) |
| { |
| return; |
| } |
| // Allow a conversion to immutable type, or |
| // conversions of mutable types between thread-local and shared. |
| } |
| |
| Expressions *args = (fd == e->allocator) ? e->newargs : e->arguments; |
| |
| size_t nparams = Parameter::dim(tf->parameters); |
| size_t j = (tf->linkage == LINKd && tf->varargs == 1); // if TypeInfoArray was prepended |
| for (size_t i = j; i < e->arguments->dim; ++i) |
| { |
| Expression *earg = (*args)[i]; |
| Type *targ = earg->type->toBasetype(); |
| if (i - j < nparams) |
| { |
| Parameter *fparam = Parameter::getNth(tf->parameters, i - j); |
| if (fparam->storageClass & STClazy) |
| return; // not sure what to do with this |
| Type *tparam = fparam->type; |
| if (!tparam) |
| continue; |
| if (fparam->storageClass & (STCout | STCref)) |
| { |
| if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch) |
| return; |
| continue; |
| } |
| } |
| |
| if (implicitMod(earg, targ, mod) == MATCHnomatch) |
| return; |
| } |
| } |
| |
| /* If no 'member', then construction is by simple assignment, |
| * and just straight check 'arguments' |
| */ |
| if (!e->member && e->arguments) |
| { |
| for (size_t i = 0; i < e->arguments->dim; ++i) |
| { |
| Expression *earg = (*e->arguments)[i]; |
| if (!earg) // Bugzilla 14853: if it's on overlapped field |
| continue; |
| Type *targ = earg->type->toBasetype(); |
| if (implicitMod(earg, targ, mod) == MATCHnomatch) |
| return; |
| } |
| } |
| |
| /* Consider the .init expression as an argument |
| */ |
| Type *ntb = e->newtype->toBasetype(); |
| if (ntb->ty == Tarray) |
| ntb = ntb->nextOf()->toBasetype(); |
| if (ntb->ty == Tstruct) |
| { |
| // Don't allow nested structs - uplevel reference may not be convertible |
| StructDeclaration *sd = ((TypeStruct *)ntb)->sym; |
| sd->size(e->loc); // resolve any forward references |
| if (sd->isNested()) |
| return; |
| } |
| if (ntb->isZeroInit(e->loc)) |
| { |
| /* Zeros are implicitly convertible, except for special cases. |
| */ |
| if (ntb->ty == Tclass) |
| { |
| /* With new() must look at the class instance initializer. |
| */ |
| ClassDeclaration *cd = ((TypeClass *)ntb)->sym; |
| |
| cd->size(e->loc); // resolve any forward references |
| |
| if (cd->isNested()) |
| return; // uplevel reference may not be convertible |
| |
| assert(!cd->isInterfaceDeclaration()); |
| |
| struct ClassCheck |
| { |
| static bool convertible(Loc loc, ClassDeclaration *cd, MOD mod) |
| { |
| for (size_t i = 0; i < cd->fields.dim; i++) |
| { |
| VarDeclaration *v = cd->fields[i]; |
| Initializer *init = v->_init; |
| if (init) |
| { |
| if (init->isVoidInitializer()) |
| ; |
| else if (ExpInitializer *ei = init->isExpInitializer()) |
| { |
| Type *tb = v->type->toBasetype(); |
| if (implicitMod(ei->exp, tb, mod) == MATCHnomatch) |
| return false; |
| } |
| else |
| { |
| /* Enhancement: handle StructInitializer and ArrayInitializer |
| */ |
| return false; |
| } |
| } |
| else if (!v->type->isZeroInit(loc)) |
| return false; |
| } |
| return cd->baseClass ? convertible(loc, cd->baseClass, mod) : true; |
| } |
| }; |
| |
| if (!ClassCheck::convertible(e->loc, cd, mod)) |
| return; |
| } |
| } |
| else |
| { |
| Expression *earg = e->newtype->defaultInitLiteral(e->loc); |
| Type *targ = e->newtype->toBasetype(); |
| |
| if (implicitMod(earg, targ, mod) == MATCHnomatch) |
| return; |
| } |
| |
| /* Success |
| */ |
| result = MATCHconst; |
| } |
| |
| void visit(SliceExp *e) |
| { |
| //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e->toChars(), e->type->toChars()); |
| visit((Expression *)e); |
| if (result != MATCHnomatch) |
| return; |
| |
| Type *tb = t->toBasetype(); |
| Type *typeb = e->type->toBasetype(); |
| if (tb->ty == Tsarray && typeb->ty == Tarray) |
| { |
| typeb = toStaticArrayType(e); |
| if (typeb) |
| result = typeb->implicitConvTo(t); |
| return; |
| } |
| |
| /* If the only reason it won't convert is because of the mod bits, |
| * then test for conversion by seeing if e1 can be converted with those |
| * same mod bits. |
| */ |
| Type *t1b = e->e1->type->toBasetype(); |
| if (tb->ty == Tarray && typeb->equivalent(tb)) |
| { |
| Type *tbn = tb->nextOf(); |
| Type *tx = NULL; |
| |
| /* If e->e1 is dynamic array or pointer, the uniqueness of e->e1 |
| * is equivalent with the uniqueness of the referred data. And in here |
| * we can have arbitrary typed reference for that. |
| */ |
| if (t1b->ty == Tarray) |
| tx = tbn->arrayOf(); |
| if (t1b->ty == Tpointer) |
| tx = tbn->pointerTo(); |
| |
| /* If e->e1 is static array, at least it should be an rvalue. |
| * If not, e->e1 is a reference, and its uniqueness does not link |
| * to the uniqueness of the referred data. |
| */ |
| if (t1b->ty == Tsarray && !e->e1->isLvalue()) |
| tx = tbn->sarrayOf(t1b->size() / tbn->size()); |
| |
| if (tx) |
| { |
| result = e->e1->implicitConvTo(tx); |
| if (result > MATCHconst) // Match level is MATCHconst at best. |
| result = MATCHconst; |
| } |
| } |
| |
| // Enhancement 10724 |
| if (tb->ty == Tpointer && e->e1->op == TOKstring) |
| e->e1->accept(this); |
| } |
| }; |
| |
| ImplicitConvTo v(t); |
| e->accept(&v); |
| return v.result; |
| } |
| |
| Type *toStaticArrayType(SliceExp *e) |
| { |
| if (e->lwr && e->upr) |
| { |
| // For the following code to work, e should be optimized beforehand. |
| // (eg. $ in lwr and upr should be already resolved, if possible) |
| Expression *lwr = e->lwr->optimize(WANTvalue); |
| Expression *upr = e->upr->optimize(WANTvalue); |
| if (lwr->isConst() && upr->isConst()) |
| { |
| size_t len = (size_t)(upr->toUInteger() - lwr->toUInteger()); |
| return e->type->toBasetype()->nextOf()->sarrayOf(len); |
| } |
| } |
| else |
| { |
| Type *t1b = e->e1->type->toBasetype(); |
| if (t1b->ty == Tsarray) |
| return t1b; |
| } |
| return NULL; |
| } |
| |
| /* ==================== castTo ====================== */ |
| |
| /************************************** |
| * Do an explicit cast. |
| * Assume that the 'this' expression does not have any indirections. |
| */ |
| |
| Expression *castTo(Expression *e, Scope *sc, Type *t) |
| { |
| class CastTo : public Visitor |
| { |
| public: |
| Type *t; |
| Scope *sc; |
| Expression *result; |
| |
| CastTo(Scope *sc, Type *t) |
| : t(t), sc(sc) |
| { |
| result = NULL; |
| } |
| |
| void visit(Expression *e) |
| { |
| //printf("Expression::castTo(this=%s, t=%s)\n", e->toChars(), t->toChars()); |
| if (e->type->equals(t)) |
| { |
| result = e; |
| return; |
| } |
| if (e->op == TOKvar) |
| { |
| VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); |
| if (v && v->storage_class & STCmanifest) |
| { |
| result = e->ctfeInterpret(); |
| result = result->castTo(sc, t); |
| return; |
| } |
| } |
| |
| Type *tob = t->toBasetype(); |
| Type *t1b = e->type->toBasetype(); |
| if (tob->equals(t1b)) |
| { |
| result = e->copy(); // because of COW for assignment to e->type |
| result->type = t; |
| return; |
| } |
| |
| /* Make semantic error against invalid cast between concrete types. |
| * Assume that 'e' is never be any placeholder expressions. |
| * The result of these checks should be consistent with CastExp::toElem(). |
| */ |
| |
| // Fat Value types |
| const bool tob_isFV = (tob->ty == Tstruct || tob->ty == Tsarray || tob->ty == Tvector); |
| const bool t1b_isFV = (t1b->ty == Tstruct || t1b->ty == Tsarray || t1b->ty == Tvector); |
| |
| // Fat Reference types |
| const bool tob_isFR = (tob->ty == Tarray || tob->ty == Tdelegate); |
| const bool t1b_isFR = (t1b->ty == Tarray || t1b->ty == Tdelegate); |
| |
| // Reference types |
| const bool tob_isR = (tob_isFR || tob->ty == Tpointer || tob->ty == Taarray || tob->ty == Tclass); |
| const bool t1b_isR = (t1b_isFR || t1b->ty == Tpointer || t1b->ty == Taarray || t1b->ty == Tclass); |
| |
| // Arithmetic types (== valueable basic types) |
| const bool tob_isA = ((tob->isintegral() || tob->isfloating()) && tob->ty != Tvector); |
| const bool t1b_isA = ((t1b->isintegral() || t1b->isfloating()) && t1b->ty != Tvector); |
| |
| if (AggregateDeclaration *t1ad = isAggregate(t1b)) |
| { |
| AggregateDeclaration *toad = isAggregate(tob); |
| if (t1ad != toad && t1ad->aliasthis) |
| { |
| if (t1b->ty == Tclass && tob->ty == Tclass) |
| { |
| ClassDeclaration *t1cd = t1b->isClassHandle(); |
| ClassDeclaration *tocd = tob->isClassHandle(); |
| int offset; |
| if (tocd->isBaseOf(t1cd, &offset)) |
| goto Lok; |
| } |
| |
| /* Forward the cast to our alias this member, rewrite to: |
| * cast(to)e1.aliasthis |
| */ |
| result = resolveAliasThis(sc, e); |
| result = result->castTo(sc, t); |
| return; |
| } |
| } |
| else if (tob->ty == Tvector && t1b->ty != Tvector) |
| { |
| //printf("test1 e = %s, e->type = %s, tob = %s\n", e->toChars(), e->type->toChars(), tob->toChars()); |
| TypeVector *tv = (TypeVector *)tob; |
| result = new CastExp(e->loc, e, tv->elementType()); |
| result = new VectorExp(e->loc, result, tob); |
| result = ::semantic(result, sc); |
| return; |
| } |
| else if (tob->ty != Tvector && t1b->ty == Tvector) |
| { |
| // T[n] <-- __vector(U[m]) |
| if (tob->ty == Tsarray) |
| { |
| if (t1b->size(e->loc) == tob->size(e->loc)) |
| goto Lok; |
| } |
| goto Lfail; |
| } |
| else if (t1b->implicitConvTo(tob) == MATCHconst && t->equals(e->type->constOf())) |
| { |
| result = e->copy(); |
| result->type = t; |
| return; |
| } |
| |
| // arithmetic values vs. other arithmetic values |
| // arithmetic values vs. T* |
| if ((tob_isA && (t1b_isA || t1b->ty == Tpointer)) || |
| (t1b_isA && (tob_isA || tob->ty == Tpointer))) |
| { |
| goto Lok; |
| } |
| |
| // arithmetic values vs. references or fat values |
| if ((tob_isA && (t1b_isR || t1b_isFV)) || |
| (t1b_isA && (tob_isR || tob_isFV))) |
| { |
| goto Lfail; |
| } |
| |
| // Bugzlla 3133: A cast between fat values is possible only when the sizes match. |
| if (tob_isFV && t1b_isFV) |
| { |
| if (t1b->size(e->loc) == tob->size(e->loc)) |
| goto Lok; |
| e->error("cannot cast expression %s of type %s to %s because of different sizes", |
| e->toChars(), e->type->toChars(), t->toChars()); |
| result = new ErrorExp(); |
| return; |
| } |
| |
| // Fat values vs. null or references |
| if ((tob_isFV && (t1b->ty == Tnull || t1b_isR)) || |
| (t1b_isFV && (tob->ty == Tnull || tob_isR))) |
| { |
| if (tob->ty == Tpointer && t1b->ty == Tsarray) |
| { |
| // T[n] sa; |
| // cast(U*)sa; // ==> cast(U*)sa.ptr; |
| result = new AddrExp(e->loc, e, t); |
| return; |
| } |
| if (tob->ty == Tarray && t1b->ty == Tsarray) |
| { |
| // T[n] sa; |
| // cast(U[])sa; // ==> cast(U[])sa[]; |
| d_uns64 fsize = t1b->nextOf()->size(); |
| d_uns64 tsize = tob->nextOf()->size(); |
| if (fsize != tsize) |
| { |
| dinteger_t dim = ((TypeSArray *)t1b)->dim->toInteger(); |
| if (tsize == 0 || (dim * fsize) % tsize != 0) |
| { |
| e->error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up", |
| e->toChars(), e->type->toChars(), t->toChars()); |
| result = new ErrorExp(); |
| return; |
| } |
| } |
| goto Lok; |
| } |
| goto Lfail; |
| } |
| |
| /* For references, any reinterpret casts are allowed to same 'ty' type. |
| * T* to U* |
| * R1 function(P1) to R2 function(P2) |
| * R1 delegate(P1) to R2 delegate(P2) |
| * T[] to U[] |
| * V1[K1] to V2[K2] |
| * class/interface A to B (will be a dynamic cast if possible) |
| */ |
| if (tob->ty == t1b->ty && tob_isR && t1b_isR) |
| goto Lok; |
| |
| // typeof(null) <-- non-null references or values |
| if (tob->ty == Tnull && t1b->ty != Tnull) |
| goto Lfail; // Bugzilla 14629 |
| // typeof(null) --> non-null references or arithmetic values |
| if (t1b->ty == Tnull && tob->ty != Tnull) |
| goto Lok; |
| |
| // Check size mismatch of references. |
| // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof. |
| if ((tob_isFR && t1b_isR) || (t1b_isFR && tob_isR)) |
| { |
| if (tob->ty == Tpointer && t1b->ty == Tarray) |
| { |
| // T[] da; |
| // cast(U*)da; // ==> cast(U*)da.ptr; |
| goto Lok; |
| } |
| if (tob->ty == Tpointer && t1b->ty == Tdelegate) |
| { |
| // void delegate() dg; |
| // cast(U*)dg; // ==> cast(U*)dg.ptr; |
| // Note that it happens even when U is a Tfunction! |
| e->deprecation("casting from %s to %s is deprecated", e->type->toChars(), t->toChars()); |
| goto Lok; |
| } |
| goto Lfail; |
| } |
| |
| if (t1b->ty == Tvoid && tob->ty != Tvoid) |
| { |
| Lfail: |
| e->error("cannot cast expression %s of type %s to %s", |
| e->toChars(), e->type->toChars(), t->toChars()); |
| result = new ErrorExp(); |
| return; |
| } |
| |
| Lok: |
| result = new CastExp(e->loc, e, t); |
| result->type = t; // Don't call semantic() |
| //printf("Returning: %s\n", result->toChars()); |
| } |
| |
| void visit(ErrorExp *e) |
| { |
| result = e; |
| } |
| |
| void visit(RealExp *e) |
| { |
| if (!e->type->equals(t)) |
| { |
| if ((e->type->isreal() && t->isreal()) || |
| (e->type->isimaginary() && t->isimaginary()) |
| ) |
| { |
| result = e->copy(); |
| result->type = t; |
| } |
| else |
| visit((Expression *)e); |
| return; |
| } |
| result = e; |
| } |
| |
| void visit(ComplexExp *e) |
| { |
| if (!e->type->equals(t)) |
| { |
| if (e->type->iscomplex() && t->iscomplex()) |
| { |
| result = e->copy(); |
| result->type = t; |
| } |
| else |
| visit((Expression *)e); |
| return; |
| } |
| result = e; |
| } |
| |
| void visit(NullExp *e) |
| { |
| //printf("NullExp::castTo(t = %s) %s\n", t->toChars(), toChars()); |
| visit((Expression *)e); |
| if (result->op == TOKnull) |
| { |
| NullExp *ex = (NullExp *)result; |
| ex->committed = 1; |
| return; |
| } |
| } |
| |
| void visit(StructLiteralExp *e) |
| { |
| visit((Expression *)e); |
| if (result->op == TOKstructliteral) |
| ((StructLiteralExp *)result)->stype = t; // commit type |
| } |
| |
| void visit(StringExp *e) |
| { |
| /* This follows copy-on-write; any changes to 'this' |
| * will result in a copy. |
| * The this->string member is considered immutable. |
| */ |
| int copied = 0; |
| |
| //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), e->toChars(), e->committed); |
| |
| if (!e->committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) |
| { |
| e->error("cannot convert string literal to void*"); |
| result = new ErrorExp(); |
| return; |
| } |
| |
| StringExp *se = e; |
| if (!e->committed) |
| { |
| se = (StringExp *)e->copy(); |
| se->committed = 1; |
| copied = 1; |
| } |
| |
| if (e->type->equals(t)) |
| { |
| result = se; |
| return; |
| } |
| |
| Type *tb = t->toBasetype(); |
| //printf("\ttype = %s\n", e->type->toChars()); |
| if (tb->ty == Tdelegate && e->type->toBasetype()->ty != Tdelegate) |
| { |
| visit((Expression *)e); |
| return; |
| } |
| |
| Type *typeb = e->type->toBasetype(); |
| if (typeb->equals(tb)) |
| { |
| if (!copied) |
| { |
| se = (StringExp *)e->copy(); |
| copied = 1; |
| } |
| se->type = t; |
| result = se; |
| return; |
| } |
| |
| /* Handle reinterpret casts: |
| * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000] |
| * cast(wchar[2])"abcd"c --> [\u6261, \u6463] |
| * cast(wchar[1])"abcd"c --> [\u6261] |
| */ |
| if (e->committed && tb->ty == Tsarray && typeb->ty == Tarray) |
| { |
| se = (StringExp *)e->copy(); |
| d_uns64 szx = tb->nextOf()->size(); |
| assert(szx <= 255); |
| se->sz = (unsigned char)szx; |
| se->len = (size_t)((TypeSArray *)tb)->dim->toInteger(); |
| se->committed = 1; |
| se->type = t; |
| |
| /* Assure space for terminating 0 |
| */ |
| if ((se->len + 1) * se->sz > (e->len + 1) * e->sz) |
| { |
| void *s = (void *)mem.xmalloc((se->len + 1) * se->sz); |
| memcpy(s, se->string, se->len * se->sz); |
| memset((char *)s + se->len * se->sz, 0, se->sz); |
| se->string = s; |
| } |
| result = se; |
| return; |
| } |
| |
| if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer) |
| { |
| if (!copied) |
| { |
| se = (StringExp *)e->copy(); |
| copied = 1; |
| } |
| goto Lcast; |
| } |
| if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer) |
| { |
| if (!copied) |
| { |
| se = (StringExp *)e->copy(); |
| copied = 1; |
| } |
| goto Lcast; |
| } |
| |
| if (typeb->nextOf()->size() == tb->nextOf()->size()) |
| { |
| if (!copied) |
| { |
| se = (StringExp *)e->copy(); |
| copied = 1; |
| } |
| if (tb->ty == Tsarray) |
| goto L2; // handle possible change in static array dimension |
| se->type = t; |
| result = se; |
| return; |
| } |
| |
| if (e->committed) |
| goto Lcast; |
| |
| #define X(tf,tt) ((int)(tf) * 256 + (int)(tt)) |
| { |
| OutBuffer buffer; |
| size_t newlen = 0; |
| int tfty = typeb->nextOf()->toBasetype()->ty; |
| int ttty = tb->nextOf()->toBasetype()->ty; |
| switch (X(tfty, ttty)) |
| { |
| case X(Tchar, Tchar): |
| case X(Twchar,Twchar): |
| case X(Tdchar,Tdchar): |
| break; |
| |
| case X(Tchar, Twchar): |
| for (size_t u = 0; u < e->len;) |
| { |
| unsigned c; |
| const char *p = utf_decodeChar((utf8_t *)se->string, e->len, &u, &c); |
| if (p) |
| e->error("%s", p); |
| else |
| buffer.writeUTF16(c); |
| } |
| newlen = buffer.offset / 2; |
| buffer.writeUTF16(0); |
| goto L1; |
| |
| case X(Tchar, Tdchar): |
| for (size_t u = 0; u < e->len;) |
| { |
| unsigned c; |
| const char *p = utf_decodeChar((utf8_t *)se->string, e->len, &u, &c); |
| if (p) |
| e->error("%s", p); |
| buffer.write4(c); |
| newlen++; |
| } |
| buffer.write4(0); |
| goto L1; |
| |
| case X(Twchar,Tchar): |
| for (size_t u = 0; u < e->len;) |
| { |
| unsigned c; |
| const char *p = utf_decodeWchar((unsigned short *)se->string, e->len, &u, &c); |
| if (p) |
| e->error("%s", p); |
| else |
| buffer.writeUTF8(c); |
| } |
| newlen = buffer.offset; |
| buffer.writeUTF8(0); |
| goto L1; |
| |
| case X(Twchar,Tdchar): |
| for (size_t u = 0; u < e->len;) |
| { |
| unsigned c; |
| const char *p = utf_decodeWchar((unsigned short *)se->string, e->len, &u, &c); |
| if (p) |
| e->error("%s", p); |
| buffer.write4(c); |
| newlen++; |
| } |
| buffer.write4(0); |
| goto L1; |
| |
| case X(Tdchar,Tchar): |
| for (size_t u = 0; u < e->len; u++) |
| { |
| unsigned c = ((unsigned *)se->string)[u]; |
| if (!utf_isValidDchar(c)) |
| e->error("invalid UCS-32 char \\U%08x", c); |
| else |
| buffer.writeUTF8(c); |
| newlen++; |
| } |
| newlen = buffer.offset; |
| buffer.writeUTF8(0); |
| goto L1; |
| |
| case X(Tdchar,Twchar): |
| for (size_t u = 0; u < e->len; u++) |
| { |
| unsigned c = ((unsigned *)se->string)[u]; |
| if (!utf_isValidDchar(c)) |
| e->error("invalid UCS-32 char \\U%08x", c); |
| else |
| buffer.writeUTF16(c); |
| newlen++; |
| } |
| newlen = buffer.offset / 2; |
| buffer.writeUTF16(0); |
| goto L1; |
| |
| L1: |
| if (!copied) |
| { |
| se = (StringExp *)e->copy(); |
| copied = 1; |
| } |
| se->string = buffer.extractData(); |
| se->len = newlen; |
| |
| { |
| d_uns64 szx = tb->nextOf()->size(); |
| assert(szx <= 255); |
| se->sz = (unsigned char)szx; |
| } |
| break; |
| |
| default: |
| assert(typeb->nextOf()->size() != tb->nextOf()->size()); |
| goto Lcast; |
| } |
| } |
| #undef X |
| L2: |
| assert(copied); |
| |
| // See if need to truncate or extend the literal |
| if (tb->ty == Tsarray) |
| { |
| size_t dim2 = (size_t)((TypeSArray *)tb)->dim->toInteger(); |
| |
| //printf("dim from = %d, to = %d\n", (int)se->len, (int)dim2); |
| |
| // Changing dimensions |
| if (dim2 != se->len) |
| { |
| // Copy when changing the string literal |
| size_t newsz = se->sz; |
| size_t d = (dim2 < se->len) ? dim2 : se->len; |
| void *s = (void *)mem.xmalloc((dim2 + 1) * newsz); |
| memcpy(s, se->string, d * newsz); |
| // Extend with 0, add terminating 0 |
| memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); |
| se->string = s; |
| se->len = dim2; |
| } |
| } |
| se->type = t; |
| result = se; |
| return; |
| |
| Lcast: |
| result = new CastExp(e->loc, se, t); |
| result->type = t; // so semantic() won't be run on e |
| } |
| |
| void visit(AddrExp *e) |
| { |
| Type *tb; |
| |
| result = e; |
| |
| tb = t->toBasetype(); |
| e->type = e->type->toBasetype(); |
| if (!tb->equals(e->type)) |
| { |
| // Look for pointers to functions where the functions are overloaded. |
| |
| if (e->e1->op == TOKoverloadset && |
| (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) |
| { |
| OverExp *eo = (OverExp *)e->e1; |
| FuncDeclaration *f = NULL; |
| for (size_t i = 0; i < eo->vars->a.dim; i++) |
| { |
| Dsymbol *s = eo->vars->a[i]; |
| FuncDeclaration *f2 = s->isFuncDeclaration(); |
| assert(f2); |
| if (f2->overloadExactMatch(t->nextOf())) |
| { |
| if (f) |
| { |
| /* Error if match in more than one overload set, |
| * even if one is a 'better' match than the other. |
| */ |
| ScopeDsymbol::multiplyDefined(e->loc, f, f2); |
| } |
| else |
| f = f2; |
| } |
| } |
| if (f) |
| { |
| f->tookAddressOf++; |
| SymOffExp *se = new SymOffExp(e->loc, f, 0, false); |
| ::semantic(se, sc); |
| // Let SymOffExp::castTo() do the heavy lifting |
| visit(se); |
| return; |
| } |
| } |
| |
| if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction && |
| tb->ty == Tpointer && tb->nextOf()->ty == Tfunction && |
| e->e1->op == TOKvar) |
| { |
| VarExp *ve = (VarExp *)e->e1; |
| FuncDeclaration *f = ve->var->isFuncDeclaration(); |
| if (f) |
| { |
| assert(f->isImportedSymbol()); |
| f = f->overloadExactMatch(tb->nextOf()); |
| if (f) |
| { |
| result = new VarExp(e->loc, f, false); |
| result->type = f->type; |
| result = new AddrExp(e->loc, result, t); |
| return; |
| } |
| } |
| } |
| |
| if (FuncDeclaration *f = isFuncAddress(e)) |
| { |
| if (f->checkForwardRef(e->loc)) |
| { |
| result = new ErrorExp(); |
| return; |
| } |
| } |
| |
| visit((Expression *)e); |
| } |
| result->type = t; |
| } |
| |
| void visit(TupleExp *e) |
| { |
| if (e->type->equals(t)) |
| { |
| result = e; |
| return; |
| } |
| |
| TupleExp *te = (TupleExp *)e->copy(); |
| te->e0 = e->e0 ? e->e0->copy() : NULL; |
| te->exps = (Expressions *)e->exps->copy(); |
| for (size_t i = 0; i < te->exps->dim; i++) |
| { |
| Expression *ex = (*te->exps)[i]; |
| ex = ex->castTo(sc, t); |
| (*te->exps)[i] = ex; |
| } |
| result = te; |
| |
| /* Questionable behavior: In here, result->type is not set to t. |
| * Therefoe: |
| * TypeTuple!(int, int) values; |
| * auto values2 = cast(long)values; |
| * // typeof(values2) == TypeTuple!(int, int) !! |
| * |
| * Only when the casted tuple is immediately expanded, it would work. |
| * auto arr = [cast(long)values]; |
| * // typeof(arr) == long[] |
| */ |
| } |
| |
| void visit(ArrayLiteralExp *e) |
| { |
| if (e->type == t) |
| { |
| result = e; |
| return; |
| } |
| ArrayLiteralExp *ae = e; |
| Type *typeb = e->type->toBasetype(); |
| Type *tb = t->toBasetype(); |
| if ((tb->ty == Tarray || tb->ty == Tsarray) && |
| (typeb->ty == Tarray || typeb->ty == Tsarray)) |
| { |
| if (tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid) |
| { |
| // Don't do anything to cast non-void[] to void[] |
| } |
| else if (typeb->ty == Tsarray && typeb->nextOf()->toBasetype()->ty == Tvoid) |
| { |
| // Don't do anything for casting void[n] to others |
| } |
| else |
| { |
| if (tb->ty == Tsarray) |
| { |
| TypeSArray *tsa = (TypeSArray *)tb; |
| if (e->elements->dim != tsa->dim->toInteger()) |
| goto L1; |
| } |
| |
| ae = (ArrayLiteralExp *)e->copy(); |
| if (e->basis) |
| ae->basis = e->basis->castTo(sc, tb->nextOf()); |
| ae->elements = e->elements->copy(); |
| for (size_t i = 0; i < e->elements->dim; i++) |
| { |
| Expression *ex = (*e->elements)[i]; |
| if (!ex) |
| continue; |
| ex = ex->castTo(sc, tb->nextOf()); |
| (*ae->elements)[i] = ex; |
| } |
| ae->type = t; |
| result = ae; |
| return; |
| } |
| } |
| else if (tb->ty == Tpointer && typeb->ty == Tsarray) |
| { |
| Type *tp = typeb->nextOf()->pointerTo(); |
| if (!tp->equals(ae->type)) |
| { |
| ae = (ArrayLiteralExp *)e->copy(); |
| ae->type = tp; |
| } |
| } |
| else if (tb->ty == Tvector && |
| (typeb->ty == Tarray || typeb->ty == Tsarray)) |
| { |
| // Convert array literal to vector type |
| TypeVector *tv = (TypeVector *)tb; |
| TypeSArray *tbase = (TypeSArray *)tv->basetype; |
| assert(tbase->ty == Tsarray); |
| const size_t edim = e->elements->dim; |
| const size_t tbasedim = tbase->dim->toInteger(); |
| if (edim > tbasedim) |
| goto L1; |
| |
| ae = (ArrayLiteralExp *)e->copy(); |
| ae->type = tbase; // Bugzilla 12642 |
| ae->elements = e->elements->copy(); |
| Type *telement = tv->elementType(); |
| for (size_t i = 0; i < edim; i++) |
| { |
| Expression *ex = (*e->elements)[i]; |
| ex = ex->castTo(sc, telement); |
| (*ae->elements)[i] = ex; |
| } |
| // Fill in the rest with the default initializer |
| ae->elements->setDim(tbasedim); |
| for (size_t i = edim; i < tbasedim; i++) |
| { |
| Expression *ex = typeb->nextOf()->defaultInitLiteral(e->loc); |
| ex = ex->castTo(sc, telement); |
| (*ae->elements)[i] = ex; |
| } |
| Expression *ev = new VectorExp(e->loc, ae, tb); |
| ev = ::semantic(ev, sc); |
| result = ev; |
| return; |
| } |
| L1: |
| visit((Expression *)ae); |
| } |
| |
| void visit(AssocArrayLiteralExp *e) |
| { |
| if (e->type == t) |
| { |
| result = e; |
| return; |
| } |
| Type *typeb = e->type->toBasetype(); |
| Type *tb = t->toBasetype(); |
| if (tb->ty == Taarray && typeb->ty == Taarray && |
| tb->nextOf()->toBasetype()->ty != Tvoid) |
| { |
| AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e->copy(); |
| ae->keys = e->keys->copy(); |
| ae->values = e->values->copy(); |
| assert(e->keys->dim == e->values->dim); |
| for (size_t i = 0; i < e->keys->dim; i++) |
| { |
| Expression *ex = (*e->values)[i]; |
| ex = ex->castTo(sc, tb->nextOf()); |
| (*ae->values)[i] = ex; |
| |
| ex = (*e->keys)[i]; |
| ex = ex->castTo(sc, ((TypeAArray *)tb)->index); |
| (*ae->keys)[i] = ex; |
| } |
| ae->type = t; |
| result = ae; |
| return; |
| } |
| visit((Expression *)e); |
| } |
| |
| void visit(SymOffExp *e) |
| { |
| if (e->type == t && !e->hasOverloads) |
| { |
| result = e; |
| return; |
| } |
| Type *tb = t->toBasetype(); |
| Type *typeb = e->type->toBasetype(); |
| |
| if (tb->equals(typeb)) |
| { |
| result = e->copy(); |
| result->type = t; |
| ((SymOffExp *)result)->hasOverloads = false; |
| return; |
| } |
| |
| // Look for pointers to functions where the functions are overloaded. |
| if (e->hasOverloads && |
| typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction && |
| (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction) |
| { |
| FuncDeclaration *f = e->var->isFuncDeclaration(); |
| f = f ? f->overloadExactMatch(tb->nextOf()) : NULL; |
| if (f) |
| { |
| if (tb->ty == Tdelegate) |
| { |
| if (f->needThis() && hasThis(sc)) |
| { |
| result = new DelegateExp(e->loc, new ThisExp(e->loc), f, false); |
| result = ::semantic(result, sc); |
| } |
| else if (f->isNested()) |
| { |
| result = new DelegateExp(e->loc, new IntegerExp(0), f, false); |
| result = ::semantic(result, sc); |
| } |
| else if (f->needThis()) |
| { |
| e->error("no 'this' to create delegate for %s", f->toChars()); |
| result = new ErrorExp(); |
| return; |
| } |
| else |
| { |
| e->error("cannot cast from function pointer to delegate"); |
| result = new ErrorExp(); |
| return; |
| } |
| } |
| else |
| { |
| result = new SymOffExp(e->loc, f, 0, false); |
| result->type = t; |
| } |
| f->tookAddressOf++; |
| return; |
| } |
| } |
| |
| if (FuncDeclaration *f = isFuncAddress(e)) |
| { |
| if (f->checkForwardRef(e->loc)) |
| { |
| result = new ErrorExp(); |
| return; |
| } |
| } |
| |
| visit((Expression *)e); |
| } |
| |
| void visit(DelegateExp *e) |
| { |
| static const char msg[] = "cannot form delegate due to covariant return type"; |
| |
| Type *tb = t->toBasetype(); |
| Type *typeb = e->type->toBasetype(); |
| if (!tb->equals(typeb) || e->hasOverloads) |
| { |
| // Look for delegates to functions where the functions are overloaded. |
| if (typeb->ty == Tdelegate && |
| tb->ty == Tdelegate) |
| { |
| if (e->func) |
| { |
| FuncDeclaration *f = e->func->overloadExactMatch(tb->nextOf()); |
| if (f) |
| { |
| int offset; |
| if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset) |
| e->error("%s", msg); |
| if (f != e->func) // if address not already marked as taken |
| f->tookAddressOf++; |
| result = new DelegateExp(e->loc, e->e1, f, false); |
| result->type = t; |
| return; |
| } |
| if (e->func->tintro) |
| e->error("%s", msg); |
| } |
| } |
| |
| if (FuncDeclaration *f = isFuncAddress(e)) |
| { |
| if (f->checkForwardRef(e->loc)) |
| { |
| result = new ErrorExp(); |
| return; |
| } |
| } |
| |
| visit((Expression *)e); |
| } |
| else |
| { |
| int offset; |
| e->func->tookAddressOf++; |
| if (e->func->tintro && e->func->tintro->nextOf()->isBaseOf(e->func->type->nextOf(), &offset) && offset) |
| e->error("%s", msg); |
| result = e->copy(); |
| result->type = t; |
| } |
| } |
| |
| void visit(FuncExp *e) |
| { |
| //printf("FuncExp::castTo type = %s, t = %s\n", e->type->toChars(), t->toChars()); |
| FuncExp *fe; |
| if (e->matchType(t, sc, &fe, 1) > MATCHnomatch) |
| { |
| result = fe; |
| return; |
| } |
| visit((Expression *)e); |
| } |
| |
| void visit(CondExp *e) |
| { |
| if (!e->type->equals(t)) |
| { |
| result = new CondExp(e->loc, e->econd, e->e1->castTo(sc, t), e->e2->castTo(sc, t)); |
| result->type = t; |
| return; |
| } |
| result = e; |
| } |
| |
| void visit(CommaExp *e) |
| { |
| Expression *e2c = e->e2->castTo(sc, t); |
| |
| if (e2c != e->e2) |
| { |
| result = new CommaExp(e->loc, e->e1, e2c); |
| result->type = e2c->type; |
| } |
| else |
| { |
| result = e; |
| result->type = e->e2->type; |
| } |
| } |
| |
| void visit(SliceExp *e) |
| { |
| //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e->toChars(), e->type->toChars(), t->toChars()); |
| Type *typeb = e->type->toBasetype(); |
| Type *tb = t->toBasetype(); |
| if (e->type->equals(t) || typeb->ty != Tarray || |
| (tb->ty != Tarray && tb->ty != Tsarray)) |
| { |
| visit((Expression *)e); |
| return; |
| } |
| |
| if (tb->ty == Tarray) |
| { |
| if (typeb->nextOf()->equivalent(tb->nextOf())) |
| { |
| // T[] to const(T)[] |
| result = e->copy(); |
| result->type = t; |
| } |
| else |
| { |
| visit((Expression *)e); |
| } |
| return; |
| } |
| |
| // Handle the cast from Tarray to Tsarray with CT-known slicing |
| |
| TypeSArray *tsa = (TypeSArray *)toStaticArrayType(e); |
| if (tsa && tsa->size(e->loc) == tb->size(e->loc)) |
| { |
| /* Match if the sarray sizes are equal: |
| * T[a .. b] to const(T)[b-a] |
| * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim) |
| * |
| * If a SliceExp has Tsarray, it will become lvalue. |
| * That's handled in SliceExp::isLvalue and toLvalue |
| */ |
| result = e->copy(); |
| result->type = t; |
| return; |
| } |
| if (tsa && tsa->dim->equals(((TypeSArray *)tb)->dim)) |
| { |
| /* Match if the dimensions are equal |
| * with the implicit conversion of e->e1: |
| * cast(float[2]) [2.0, 1.0, 0.0][0..2]; |
| */ |
| Type *t1b = e->e1->type->toBasetype(); |
| if (t1b->ty == Tsarray) |
| t1b = tb->nextOf()->sarrayOf(((TypeSArray *)t1b)->dim->toInteger()); |
| else if (t1b->ty == Tarray) |
| t1b = tb->nextOf()->arrayOf(); |
| else if (t1b->ty == Tpointer) |
| t1b = tb->nextOf()->pointerTo(); |
| else |
| assert(0); |
| if (e->e1->implicitConvTo(t1b) > MATCHnomatch) |
| { |
| Expression *e1x = e->e1->implicitCastTo(sc, t1b); |
| assert(e1x->op != TOKerror); |
| e = (SliceExp *)e->copy(); |
| e->e1 = e1x; |
| e->type = t; |
| result = e; |
| return; |
| } |
| } |
| e->error("cannot cast expression %s of type %s to %s", |
| e->toChars(), tsa ? tsa->toChars() : e->type->toChars(), |
| t->toChars()); |
| result = new ErrorExp(); |
| } |
| }; |
| |
| CastTo v(sc, t); |
| e->accept(&v); |
| return v.result; |
| } |
| |
| /* ==================== inferType ====================== */ |
| |
| /**************************************** |
| * Set type inference target |
| * t Target type |
| * flag 1: don't put an error when inference fails |
| */ |
| |
| Expression *inferType(Expression *e, Type *t, int flag) |
| { |
| class InferType : public Visitor |
| { |
| public: |
| Type *t; |
| int flag; |
| Expression *result; |
| |
| InferType(Type *t, int flag) |
| : t(t), flag(flag) |
| { |
| result = NULL; |
| } |
| |
| |
| void visit(Expression *e) |
| { |
| result = e; |
| } |
| |
| void visit(ArrayLiteralExp *ale) |
| { |
| Type *tb = t->toBasetype(); |
| if (tb->ty == Tarray || tb->ty == Tsarray) |
| { |
| Type *tn = tb->nextOf(); |
| if (ale->basis) |
| ale->basis = inferType(ale->basis, tn, flag); |
| for (size_t i = 0; i < ale->elements->dim; i++) |
| { |
| Expression *e = (*ale->elements)[i]; |
| if (e) |
| { |
| e = inferType(e, tn, flag); |
| (*ale->elements)[i] = e; |
| } |
| } |
| } |
| result = ale; |
| } |
| |
| void visit(AssocArrayLiteralExp *aale) |
| { |
| Type *tb = t->toBasetype(); |
| if (tb->ty == Taarray) |
| { |
| TypeAArray *taa = (TypeAArray *)tb; |
| Type *ti = taa->index; |
| Type *tv = taa->nextOf(); |
| for (size_t i = 0; i < aale->keys->dim; i++) |
| { |
| Expression *e = (*aale->keys)[i]; |
| if (e) |
| { |
| e = inferType(e, ti, flag); |
| (*aale->keys)[i] = e; |
| } |
| } |
| for (size_t i = 0; i < aale->values->dim; i++) |
| { |
| Expression *e = (*aale->values)[i]; |
| if (e) |
| { |
| e = inferType(e, tv, flag); |
| (*aale->values)[i] = e; |
| } |
| } |
| } |
| result = aale; |
| } |
| |
| void visit(FuncExp *fe) |
| { |
| //printf("FuncExp::inferType('%s'), to=%s\n", fe->type ? fe->type->toChars() : "null", t->toChars()); |
| if (t->ty == Tdelegate || |
| (t->ty == Tpointer && t->nextOf()->ty == Tfunction)) |
| { |
| fe->fd->treq = t; |
| } |
| result = fe; |
| } |
| |
| void visit(CondExp *ce) |
| { |
| Type *tb = t->toBasetype(); |
| ce->e1 = inferType(ce->e1, tb, flag); |
| ce->e2 = inferType(ce->e2, tb, flag); |
| result = ce; |
| } |
| }; |
| |
| if (!t) |
| return e; |
| |
| InferType v(t, flag); |
| e->accept(&v); |
| return v.result; |
| } |
| |
| /* ==================== ====================== */ |
| |
| /**************************************** |
| * Scale addition/subtraction to/from pointer. |
| */ |
| |
| Expression *scaleFactor(BinExp *be, Scope *sc) |
| { |
| Type *t1b = be->e1->type->toBasetype(); |
| Type *t2b = be->e2->type->toBasetype(); |
| Expression *eoff; |
| |
| if (t1b->ty == Tpointer && t2b->isintegral()) |
| { |
| // Need to adjust operator by the stride |
| // Replace (ptr + int) with (ptr + (int * stride)) |
| Type *t = Type::tptrdiff_t; |
| |
| d_uns64 stride = t1b->nextOf()->size(be->loc); |
| if (!t->equals(t2b)) |
| be->e2 = be->e2->castTo(sc, t); |
| eoff = be->e2; |
| be->e2 = new MulExp(be->loc, be->e2, new IntegerExp(Loc(), stride, t)); |
| be->e2->type = t; |
| be->type = be->e1->type; |
| } |
| else if (t2b->ty == Tpointer && t1b->isintegral()) |
| { |
| // Need to adjust operator by the stride |
| // Replace (int + ptr) with (ptr + (int * stride)) |
| Type *t = Type::tptrdiff_t; |
| Expression *e; |
| |
| d_uns64 stride = t2b->nextOf()->size(be->loc); |
| if (!t->equals(t1b)) |
| e = be->e1->castTo(sc, t); |
| else |
| e = be->e1; |
| eoff = e; |
| e = new MulExp(be->loc, e, new IntegerExp(Loc(), stride, t)); |
| e->type = t; |
| be->type = be->e2->type; |
| be->e1 = be->e2; |
| be->e2 = e; |
| } |
| else |
| assert(0); |
| |
| if (sc->func && !sc->intypeof) |
| { |
| eoff = eoff->optimize(WANTvalue); |
| if (eoff->op == TOKint64 && eoff->toInteger() == 0) |
| ; |
| else if (sc->func->setUnsafe()) |
| { |
| be->error("pointer arithmetic not allowed in @safe functions"); |
| return new ErrorExp(); |
| } |
| } |
| |
| return be; |
| } |
| |
| /************************************** |
| * Return true if e is an empty array literal with dimensionality |
| * equal to or less than type of other array. |
| * [], [[]], [[[]]], etc. |
| * I.e., make sure that [1,2] is compatible with [], |
| * [[1,2]] is compatible with [[]], etc. |
| */ |
| bool isVoidArrayLiteral(Expression *e, Type *other) |
| { |
| while (e->op == TOKarrayliteral && e->type->ty == Tarray |
| && (((ArrayLiteralExp *)e)->elements->dim == 1)) |
| { |
| ArrayLiteralExp *ale = (ArrayLiteralExp *)e; |
| e = ale->getElement(0); |
| if (other->ty == Tsarray || other->ty == Tarray) |
| other = other->nextOf(); |
| else |
| return false; |
| } |
| if (other->ty != Tsarray && other->ty != Tarray) |
| return false; |
| Type *t = e->type; |
| return (e->op == TOKarrayliteral && t->ty == Tarray && |
| t->nextOf()->ty == Tvoid && |
| ((ArrayLiteralExp *)e)->elements->dim == 0); |
| } |
| |
| // used by deduceType() |
| Type *rawTypeMerge(Type *t1, Type *t2) |
| { |
| if (t1->equals(t2)) |
| return t1; |
| if (t1->equivalent(t2)) |
| return t1->castMod(MODmerge(t1->mod, t2->mod)); |
| |
| Type *t1b = t1->toBasetype(); |
| Type *t2b = t2->toBasetype(); |
| if (t1b->equals(t2b)) |
| return t1b; |
| if (t1b->equivalent(t2b)) |
| return t1b->castMod(MODmerge(t1b->mod, t2b->mod)); |
| |
| TY ty = (TY)impcnvResult[t1b->ty][t2b->ty]; |
| if (ty != Terror) |
| return Type::basic[ty]; |
| |
| return NULL; |
| } |
| |
| /************************************** |
| * Combine types. |
| * Output: |
| * *pt merged type, if *pt is not NULL |
| * *pe1 rewritten e1 |
| * *pe2 rewritten e2 |
| * Returns: |
| * true success |
| * false failed |
| */ |
| |
| bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2) |
| { |
| //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars()); |
| |
| MATCH m; |
| Expression *e1 = *pe1; |
| Expression *e2 = *pe2; |
| Type *t1b = e1->type->toBasetype(); |
| Type *t2b = e2->type->toBasetype(); |
| |
| if (op != TOKquestion || |
| (t1b->ty != t2b->ty && (t1b->isTypeBasic() && t2b->isTypeBasic()))) |
| { |
| e1 = integralPromotions(e1, sc); |
| e2 = integralPromotions(e2, sc); |
| } |
| |
| Type *t1 = e1->type; |
| Type *t2 = e2->type; |
| assert(t1); |
| Type *t = t1; |
| |
| /* The start type of alias this type recursion. |
| * In following case, we should save A, and stop recursion |
| * if it appears again. |
| * X -> Y -> [A] -> B -> A -> B -> ... |
| */ |
| Type *att1 = NULL; |
| Type *att2 = NULL; |
| |
| //if (t1) printf("\tt1 = %s\n", t1->toChars()); |
| //if (t2) printf("\tt2 = %s\n", t2->toChars()); |
| assert(t2); |
| |
| if (t1->mod != t2->mod && |
| t1->ty == Tenum && t2->ty == Tenum && |
| ((TypeEnum *)t1)->sym == ((TypeEnum *)t2)->sym) |
| { |
| unsigned char mod = MODmerge(t1->mod, t2->mod); |
| t1 = t1->castMod(mod); |
| t2 = t2->castMod(mod); |
| } |
| |
| Lagain: |
| t1b = t1->toBasetype(); |
| t2b = t2->toBasetype(); |
| |
| TY ty = (TY)impcnvResult[t1b->ty][t2b->ty]; |
| if (ty != Terror) |
| { |
| TY ty1 = (TY)impcnvType1[t1b->ty][t2b->ty]; |
| TY ty2 = (TY)impcnvType2[t1b->ty][t2b->ty]; |
| |
| if (t1b->ty == ty1) // if no promotions |
| { |
| if (t1->equals(t2)) |
| { |
| t = t1; |
| goto Lret; |
| } |
| |
| if (t1b->equals(t2b)) |
| { |
| t = t1b; |
| goto Lret; |
| } |
| } |
| |
| t = Type::basic[ty]; |
| |
| t1 = Type::basic[ty1]; |
| t2 = Type::basic[ty2]; |
| e1 = e1->castTo(sc, t1); |
| e2 = e2->castTo(sc, t2); |
| //printf("after typeCombine():\n"); |
| //print(); |
| //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); |
| goto Lret; |
| } |
| |
| t1 = t1b; |
| t2 = t2b; |
| |
| if (t1->ty == Ttuple || t2->ty == Ttuple) |
| goto Lincompatible; |
| |
| if (t1->equals(t2)) |
| { |
| // merging can not result in new enum type |
| if (t->ty == Tenum) |
| t = t1b; |
| } |
| else if ((t1->ty == Tpointer && t2->ty == Tpointer) || |
| (t1->ty == Tdelegate && t2->ty == Tdelegate)) |
| { |
| // Bring pointers to compatible type |
| Type *t1n = t1->nextOf(); |
| Type *t2n = t2->nextOf(); |
| |
| if (t1n->equals(t2n)) |
| ; |
| else if (t1n->ty == Tvoid) // pointers to void are always compatible |
| t = t2; |
| else if (t2n->ty == Tvoid) |
| ; |
| else if (t1->implicitConvTo(t2)) |
| { |
| goto Lt2; |
| } |
| else if (t2->implicitConvTo(t1)) |
| { |
| goto Lt1; |
| } |
| else if (t1n->ty == Tfunction && t2n->ty == Tfunction) |
| { |
| TypeFunction *tf1 = (TypeFunction *)t1n; |
| TypeFunction *tf2 = (TypeFunction *)t2n; |
| tf1->purityLevel(); |
| tf2->purityLevel(); |
| |
| TypeFunction *d = (TypeFunction *)tf1->syntaxCopy(); |
| |
| if (tf1->purity != tf2->purity) |
| d->purity = PUREimpure; |
| assert(d->purity != PUREfwdref); |
| |
| d->isnothrow = (tf1->isnothrow && tf2->isnothrow); |
| d->isnogc = (tf1->isnogc && tf2->isnogc); |
| |
| if (tf1->trust == tf2->trust) |
| d->trust = tf1->trust; |
| else if (tf1->trust <= TRUSTsystem || tf2->trust <= TRUSTsystem) |
| d->trust = TRUSTsystem; |
| else |
| d->trust = TRUSTtrusted; |
| |
| Type *tx = NULL; |
| if (t1->ty == Tdelegate) |
| { |
| tx = new TypeDelegate(d); |
| } |
| else |
| tx = d->pointerTo(); |
| |
| tx = tx->semantic(e1->loc, sc); |
| |
| if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx)) |
| { |
| t = tx; |
| e1 = e1->castTo(sc, t); |
| e2 = e2->castTo(sc, t); |
| goto Lret; |
| } |
| goto Lincompatible; |
| } |
| else if (t1n->mod != t2n->mod) |
| { |
| if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared()) |
| goto Lincompatible; |
| unsigned char mod = MODmerge(t1n->mod, t2n->mod); |
| t1 = t1n->castMod(mod)->pointerTo(); |
| t2 = t2n->castMod(mod)->pointerTo(); |
| t = t1; |
| goto Lagain; |
| } |
| else if (t1n->ty == Tclass && t2n->ty == Tclass) |
| { |
| ClassDeclaration *cd1 = t1n->isClassHandle(); |
| ClassDeclaration *cd2 = t2n->isClassHandle(); |
| int offset; |
| |
| if (cd1->isBaseOf(cd2, &offset)) |
| { |
| if (offset) |
| e2 = e2->castTo(sc, t); |
| } |
| else if (cd2->isBaseOf(cd1, &offset)) |
| { |
| t = t2; |
| if (offset) |
| e1 = e1->castTo(sc, t); |
| } |
| else |
| goto Lincompatible; |
| } |
| else |
| { |
| t1 = t1n->constOf()->pointerTo(); |
| t2 = t2n->constOf()->pointerTo(); |
| if (t1->implicitConvTo(t2)) |
| { |
| goto Lt2; |
| } |
| else if (t2->implicitConvTo(t1)) |
| { |
| goto Lt1; |
| } |
|