Files
ldc/dmd2/cast.c
2013-01-04 06:22:57 +01:00

3030 lines
88 KiB
C

// Copyright (c) 1999-2012 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include <string.h> // mem{set|cpy}()
#include "rmem.h"
#include "expression.h"
#include "mtype.h"
#include "utf.h"
#include "declaration.h"
#include "aggregate.h"
#include "template.h"
#include "scope.h"
//#define DUMP .dump(__PRETTY_FUNCTION__, this)
#define DUMP
/* ==================== implicitCast ====================== */
/**************************************
* Do an implicit cast.
* Issue error if it can't be done.
*/
Expression *Expression::implicitCastTo(Scope *sc, Type *t)
{
//printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars());
MATCH match = implicitConvTo(t);
if (match)
{
#if DMDV1
TY tyfrom = type->toBasetype()->ty;
TY tyto = t->toBasetype()->ty;
if (global.params.warnings &&
Type::impcnvWarn[tyfrom][tyto] &&
op != TOKint64)
{
Expression *e = optimize(WANTflags | WANTvalue);
if (e->op == TOKint64)
return e->implicitCastTo(sc, t);
if (tyfrom == Tint32 &&
(op == TOKadd || op == TOKmin ||
op == TOKand || op == TOKor || op == TOKxor)
)
{
/* This is really only a semi-kludge fix,
* we really should look at the operands of op
* and see if they are narrower types.
* For example, b=b|b and b=b|7 and s=b+b should be allowed,
* but b=b|i should be an error.
*/
;
}
else
{
warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data",
toChars(), type->toChars(), t->toChars());
}
}
#endif
#if DMDV2
if (match == MATCHconst && type->constConv(t))
{
Expression *e = copy();
e->type = t;
return e;
}
#endif
return castTo(sc, t);
}
Expression *e = optimize(WANTflags | WANTvalue);
if (e != this)
return e->implicitCastTo(sc, t);
#if 0
printf("ty = %d\n", type->ty);
print();
type->print();
printf("to:\n");
t->print();
printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco);
//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t);
fflush(stdout);
#endif
if (t->ty != Terror && type->ty != Terror)
{
if (!t->deco)
{ /* Can happen with:
* enum E { One }
* class A
* { static void fork(EDG dg) { dg(E.One); }
* alias void delegate(E) EDG;
* }
* Should eventually make it work.
*/
error("forward reference to type %s", t->toChars());
}
else if (t->reliesOnTident())
error("forward reference to type %s", t->reliesOnTident()->toChars());
//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);
error("cannot implicitly convert expression (%s) of type %s to %s",
toChars(), type->toChars(), t->toChars());
}
return new ErrorExp();
}
Expression *StringExp::implicitCastTo(Scope *sc, Type *t)
{
//printf("StringExp::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars());
unsigned char committed = this->committed;
Expression *e = Expression::implicitCastTo(sc, t);
if (e->op == TOKstring)
{
// Retain polysemous nature if it started out that way
((StringExp *)e)->committed = committed;
}
return e;
}
Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t)
{
return this;
}
Expression *FuncExp::implicitCastTo(Scope *sc, Type *t)
{
//printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars());
return inferType(t)->Expression::implicitCastTo(sc, t);
}
/*******************************************
* Return !=0 if we can implicitly convert this to type t.
* Don't do the actual cast.
*/
MATCH Expression::implicitConvTo(Type *t)
{
#if 0
printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
//static int nest; if (++nest == 10) halt();
if (t == Type::terror)
return MATCHnomatch;
if (!type)
{ error("%s is not an expression", toChars());
type = Type::terror;
}
Expression *e = optimize(WANTvalue | WANTflags);
if (e->type == t)
return MATCHexact;
if (e != this)
{ //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars());
return e->implicitConvTo(t);
}
MATCH match = type->implicitConvTo(t);
if (match != MATCHnomatch)
return match;
/* See if we can do integral narrowing conversions
*/
if (type->isintegral() && t->isintegral() &&
type->isTypeBasic() && t->isTypeBasic())
{ IntRange src = this->getIntRange() DUMP;
IntRange targetUnsigned = IntRange::fromType(t, /*isUnsigned*/true) DUMP;
IntRange targetSigned = IntRange::fromType(t, /*isUnsigned*/false) DUMP;
if (targetUnsigned.contains(src) || targetSigned.contains(src))
return MATCHconvert;
}
#if 0
Type *tb = t->toBasetype();
if (tb->ty == Tdelegate)
{ TypeDelegate *td = (TypeDelegate *)tb;
TypeFunction *tf = (TypeFunction *)td->nextOf();
if (!tf->varargs &&
!(tf->arguments && tf->arguments->dim)
)
{
match = type->implicitConvTo(tf->nextOf());
if (match)
return match;
if (tf->nextOf()->toBasetype()->ty == Tvoid)
return MATCHconvert;
}
}
#endif
return MATCHnomatch;
}
MATCH IntegerExp::implicitConvTo(Type *t)
{
#if 0
printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH m = type->implicitConvTo(t);
if (m >= MATCHconst)
return m;
TY ty = type->toBasetype()->ty;
TY toty = t->toBasetype()->ty;
TY oldty = ty;
if (m == MATCHnomatch && t->ty == Tenum)
goto Lno;
if (t->ty == Tvector)
{ TypeVector *tv = (TypeVector *)t;
TypeBasic *tb = tv->elementType();
toty = tb->ty;
}
switch (ty)
{
case Tbool:
value &= 1;
ty = Tint32;
break;
case Tint8:
value = (signed char)value;
ty = Tint32;
break;
case Tchar:
case Tuns8:
value &= 0xFF;
ty = Tint32;
break;
case Tint16:
value = (short)value;
ty = Tint32;
break;
case Tuns16:
case Twchar:
value &= 0xFFFF;
ty = Tint32;
break;
case Tint32:
value = (int)value;
break;
case Tuns32:
case Tdchar:
value &= 0xFFFFFFFF;
ty = Tuns32;
break;
default:
break;
}
// Only allow conversion if no change in value
switch (toty)
{
case Tbool:
if ((value & 1) != value)
goto Lno;
goto Lyes;
case Tint8:
if ((signed char)value != value)
goto Lno;
goto Lyes;
case Tchar:
if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
goto Lno;
case Tuns8:
//printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
if ((unsigned char)value != value)
goto Lno;
goto Lyes;
case Tint16:
if ((short)value != value)
goto Lno;
goto Lyes;
case Twchar:
if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
goto Lno;
case Tuns16:
if ((unsigned short)value != value)
goto Lno;
goto Lyes;
case Tint32:
if (ty == Tuns32)
{
}
else if ((int)value != value)
goto Lno;
goto Lyes;
case Tuns32:
if (ty == Tint32)
{
}
else if ((unsigned)value != value)
goto Lno;
goto Lyes;
case Tdchar:
if (value > 0x10FFFFUL)
goto Lno;
goto Lyes;
case Tfloat32:
{
volatile float f;
if (type->isunsigned())
{
f = (float)value;
if (f != value)
goto Lno;
}
else
{
f = (float)(long long)value;
if (f != (long long)value)
goto Lno;
}
goto Lyes;
}
case Tfloat64:
{
volatile double f;
if (type->isunsigned())
{
f = (double)value;
if (f != value)
goto Lno;
}
else
{
f = (double)(long long)value;
if (f != (long long)value)
goto Lno;
}
goto Lyes;
}
case Tfloat80:
{
volatile_longdouble f;
if (type->isunsigned())
{
f = ldouble(value);
if (f != value) // isn't this a noop, because the compiler prefers ld
goto Lno;
}
else
{
f = ldouble((long long)value);
if (f != (long long)value)
goto Lno;
}
goto Lyes;
}
case Tpointer:
//printf("type = %s\n", type->toBasetype()->toChars());
//printf("t = %s\n", t->toBasetype()->toChars());
if (ty == Tpointer &&
type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty)
{ /* Allow things like:
* const char* P = cast(char *)3;
* char* q = P;
*/
goto Lyes;
}
break;
}
return Expression::implicitConvTo(t);
Lyes:
//printf("MATCHconvert\n");
return MATCHconvert;
Lno:
//printf("MATCHnomatch\n");
return MATCHnomatch;
}
MATCH NullExp::implicitConvTo(Type *t)
{
#if 0
printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n",
toChars(), type->toChars(), t->toChars(), committed);
#endif
if (this->type->equals(t))
return MATCHexact;
/* 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->invariantOf()->equals(type->invariantOf()))
return MATCHconst;
return Expression::implicitConvTo(t);
}
#if DMDV2
MATCH StructLiteralExp::implicitConvTo(Type *t)
{
#if 0
printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH m = Expression::implicitConvTo(t);
if (m != MATCHnomatch)
return m;
if (type->ty == t->ty && type->ty == Tstruct &&
((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym)
{
m = MATCHconst;
for (size_t i = 0; i < elements->dim; i++)
{ Expression *e = (*elements)[i];
Type *te = e->type;
te = te->castMod(t->mod);
MATCH m2 = e->implicitConvTo(te);
//printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2);
if (m2 < m)
m = m2;
}
}
return m;
}
#endif
MATCH StringExp::implicitConvTo(Type *t)
{
#if 0
printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
toChars(), committed, type->toChars(), t->toChars());
#endif
if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
{
return MATCHnomatch;
}
if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer)
{
TY tyn = type->nextOf()->ty;
if (tyn == Tchar || tyn == Twchar || tyn == Tdchar)
{ Type *tn;
MATCH m;
switch (t->ty)
{
case Tsarray:
if (type->ty == Tsarray)
{
if (((TypeSArray *)type)->dim->toInteger() !=
((TypeSArray *)t)->dim->toInteger())
return MATCHnomatch;
TY tynto = t->nextOf()->ty;
if (tynto == tyn)
return MATCHexact;
if (!committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
return MATCHexact;
}
else if (type->ty == Tarray)
{
if (length() >
((TypeSArray *)t)->dim->toInteger())
return MATCHnomatch;
TY tynto = t->nextOf()->ty;
if (tynto == tyn)
return MATCHexact;
if (!committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
return MATCHexact;
}
case Tarray:
case Tpointer:
tn = t->nextOf();
m = MATCHexact;
if (type->nextOf()->mod != tn->mod)
{ if (!tn->isConst())
return MATCHnomatch;
m = MATCHconst;
}
if (!committed)
{
switch (tn->ty)
{
case Tchar:
return (postfix != 'w' && postfix != 'd' ? m : MATCHconvert);
case Twchar:
return (postfix == 'w' ? m : MATCHconvert);
case Tdchar:
return (postfix == 'd' ? m : MATCHconvert);
}
}
break;
}
}
}
return Expression::implicitConvTo(t);
#if 0
m = (MATCH)type->implicitConvTo(t);
if (m)
{
return m;
}
return MATCHnomatch;
#endif
}
MATCH ArrayLiteralExp::implicitConvTo(Type *t)
{ MATCH result = MATCHexact;
#if 0
printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
Type *typeb = type->toBasetype();
Type *tb = t->toBasetype();
if ((tb->ty == Tarray || tb->ty == Tsarray) &&
(typeb->ty == Tarray || typeb->ty == Tsarray))
{
Type *typen = typeb->nextOf()->toBasetype();
if (tb->ty == Tsarray)
{ TypeSArray *tsa = (TypeSArray *)tb;
if (elements->dim != tsa->dim->toInteger())
result = MATCHnomatch;
}
Type *telement = tb->nextOf();
if (!elements->dim)
{ if (typen->ty != Tvoid)
result = typen->implicitConvTo(telement);
}
else
{ for (size_t i = 0; i < elements->dim; i++)
{ Expression *e = (*elements)[i];
if (result == MATCHnomatch)
break; // no need to check for worse
MATCH m = (MATCH)e->implicitConvTo(telement);
if (m < result)
result = m; // remember worst match
}
}
if (!result)
result = type->implicitConvTo(t);
return result;
}
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);
if (elements->dim != tbase->dim->toInteger())
return MATCHnomatch;
Type *telement = tv->elementType();
for (size_t i = 0; i < elements->dim; i++)
{ Expression *e = (*elements)[i];
MATCH m = (MATCH)e->implicitConvTo(telement);
if (m < result)
result = m; // remember worst match
if (result == MATCHnomatch)
break; // no need to check for worse
}
return result;
}
else
return Expression::implicitConvTo(t);
}
MATCH AssocArrayLiteralExp::implicitConvTo(Type *t)
{
Type *typeb = type->toBasetype();
Type *tb = t->toBasetype();
if (tb->ty == Taarray && typeb->ty == Taarray)
{
MATCH result = MATCHexact;
for (size_t i = 0; i < keys->dim; i++)
{ Expression *e = (*keys)[i];
MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index);
if (m < result)
result = m; // remember worst match
if (result == MATCHnomatch)
break; // no need to check for worse
e = (*values)[i];
m = (MATCH)e->implicitConvTo(tb->nextOf());
if (m < result)
result = m; // remember worst match
if (result == MATCHnomatch)
break; // no need to check for worse
}
return result;
}
else
return Expression::implicitConvTo(t);
}
MATCH CallExp::implicitConvTo(Type *t)
{
#if 0
printf("CalLExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH m = Expression::implicitConvTo(t);
if (m)
return m;
/* Allow the result of strongly pure functions to
* convert to immutable
*/
if (f && f->isPure() == PUREstrong && !f->type->hasWild())
return type->invariantOf()->implicitConvTo(t);
return MATCHnomatch;
}
MATCH AddrExp::implicitConvTo(Type *t)
{
#if 0
printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH result;
result = type->implicitConvTo(t);
//printf("\tresult = %d\n", result);
if (result == MATCHnomatch)
{
// Look for pointers to functions where the functions are overloaded.
t = t->toBasetype();
if (e1->op == TOKoverloadset &&
(t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
{ OverExp *eo = (OverExp *)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(), m))
{ if (f)
/* Error if match in more than one overload set,
* even if one is a 'better' match than the other.
*/
ScopeDsymbol::multiplyDefined(loc, f, f2);
else
f = f2;
result = MATCHexact;
}
}
}
if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
e1->op == TOKvar)
{
#if !IN_LLVM
/* I don't think this can ever happen -
* it should have been
* converted to a SymOffExp.
*/
assert(0);
#endif
VarExp *ve = (VarExp *)e1;
FuncDeclaration *f = ve->var->isFuncDeclaration();
if (f && f->overloadExactMatch(t->nextOf(), m))
result = MATCHexact;
}
}
//printf("\tresult = %d\n", result);
return result;
}
MATCH SymOffExp::implicitConvTo(Type *t)
{
#if 0
printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH result;
result = type->implicitConvTo(t);
//printf("\tresult = %d\n", result);
if (result == MATCHnomatch)
{
// Look for pointers to functions where the functions are overloaded.
FuncDeclaration *f;
t = t->toBasetype();
if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
(t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
{
f = var->isFuncDeclaration();
if (f)
{ f = f->overloadExactMatch(t->nextOf(), m);
if (f)
{ if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) ||
(t->ty == Tpointer && !(f->needThis() || f->isNested())))
{
result = MATCHexact;
}
}
}
}
}
//printf("\tresult = %d\n", result);
return result;
}
MATCH DelegateExp::implicitConvTo(Type *t)
{
#if 0
printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH result;
result = type->implicitConvTo(t);
if (result == MATCHnomatch)
{
// Look for pointers to functions where the functions are overloaded.
t = t->toBasetype();
if (type->ty == Tdelegate &&
t->ty == Tdelegate)
{
if (func && func->overloadExactMatch(t->nextOf(), m))
result = MATCHexact;
}
}
return result;
}
MATCH FuncExp::implicitConvTo(Type *t)
{
//printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars());
Expression *e = inferType(t, 1);
if (e &&
(t->ty == Tdelegate ||
t->ty == Tpointer && t->nextOf()->ty == Tfunction))
{
if (e != this)
return e->implicitConvTo(t);
/* MATCHconst: Conversion from implicit to explicit function pointer
* MATCHconvert: Conversion from impliict funciton pointer to delegate
*/
if (fd->tok == TOKreserved && // fbody doesn't have a frame pointer
(type->equals(t) || type->nextOf()->covariant(t->nextOf()) == 1))
{
return t->ty == Tpointer ? MATCHconst : MATCHconvert;
}
}
return Expression::implicitConvTo(t);
}
MATCH OrExp::implicitConvTo(Type *t)
{
MATCH result = Expression::implicitConvTo(t);
if (result == MATCHnomatch)
{
MATCH m1 = e1->implicitConvTo(t);
MATCH m2 = e2->implicitConvTo(t);
// Pick the worst match
result = (m1 < m2) ? m1 : m2;
}
return result;
}
MATCH XorExp::implicitConvTo(Type *t)
{
MATCH result = Expression::implicitConvTo(t);
if (result == MATCHnomatch)
{
MATCH m1 = e1->implicitConvTo(t);
MATCH m2 = e2->implicitConvTo(t);
// Pick the worst match
result = (m1 < m2) ? m1 : m2;
}
return result;
}
MATCH CondExp::implicitConvTo(Type *t)
{
MATCH m1 = e1->implicitConvTo(t);
MATCH m2 = e2->implicitConvTo(t);
//printf("CondExp: m1 %d m2 %d\n", m1, m2);
// Pick the worst match
return (m1 < m2) ? m1 : m2;
}
MATCH CommaExp::implicitConvTo(Type *t)
{
return e2->implicitConvTo(t);
}
MATCH CastExp::implicitConvTo(Type *t)
{
#if 0
printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH result;
result = type->implicitConvTo(t);
if (result == MATCHnomatch)
{
if (t->isintegral() &&
e1->type->isintegral() &&
e1->implicitConvTo(t) != MATCHnomatch)
result = MATCHconvert;
else
result = Expression::implicitConvTo(t);
}
return result;
}
MATCH NewExp::implicitConvTo(Type *t)
{
#if 0
printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH match = Expression::implicitConvTo(t);
if (match != MATCHnomatch)
return match;
/* The return from new() is special in that it might be a unique pointer.
* If we can prove it is, allow the following implicit conversions:
* mutable => immutable
* non-shared => shared
* shared => non-shared
*/
Type *typeb = type->toBasetype();
Type *tb = t->toBasetype();
if (tb->ty == Tclass)
{
//printf("%s => %s\n", type->castMod(0)->toChars(), t->castMod(0)->toChars());
match = type->castMod(0)->implicitConvTo(t->castMod(0));
if (!match)
goto Lnomatch;
// Regardless, don't allow immutable to be implicitly converted to mutable
if (tb->isMutable() && !typeb->isMutable())
goto Lnomatch;
// All the fields must be convertible as well
ClassDeclaration *cd = ((TypeClass *)tb)->sym;
cd->size(loc); // resolve any forward references
/* The following is excessively conservative, but be very
* careful in loosening them up.
*/
if (cd->isNested() ||
cd->isInterfaceDeclaration() ||
cd->ctor ||
cd->baseClass != ClassDeclaration::object)
goto Lnomatch;
for (size_t i = 0; i < cd->fields.dim; i++)
{ Dsymbol *sm = cd->fields[i];
Declaration *d = sm->isDeclaration();
if (d->storage_class & STCref || d->hasPointers())
goto Lnomatch;
}
return (match == MATCHexact) ? MATCHconst : match;
}
else if ((tb->ty == Tpointer || tb->ty == Tarray) &&
(typeb->ty == Tpointer || typeb->ty == Tarray))
{
Type *typen = type->nextOf()->toBasetype();
Type *tn = tb->nextOf()->toBasetype();
//printf("%s => %s\n", typen->castMod(0)->toChars(), tn->castMod(0)->toChars());
{
/* Determine if the match failure was solely due to a difference
* in the mod bits, by rebuilding type and t without mod bits and
* retrying the implicit conversion.
*/
Type *tn2 = tn->castMod(0); // cast off mod bits
Type *typen2 = typen->castMod(0);
Type *t2 = (tb->ty == Tpointer) ? tn2->pointerTo() : tn2->arrayOf();
Type *type2 = (typeb->ty == Tpointer) ? typen2->pointerTo() : typen2->arrayOf();
match = type2->implicitConvTo(t2);
if (!match)
goto Lnomatch;
}
// Regardless, don't allow immutable to be implicitly converted to mutable
if (tn->isMutable() && !typen->isMutable())
goto Lnomatch;
if (tn->isTypeBasic())
;
else if (tn->ty == Tstruct)
{
// All the fields must be convertible as well
StructDeclaration *sd = ((TypeStruct *)tn)->sym;
sd->size(loc); // resolve any forward references
/* The following is excessively conservative, but be very
* careful in loosening them up.
*/
if (sd->isNested() ||
sd->ctor)
goto Lnomatch;
for (size_t i = 0; i < sd->fields.dim; i++)
{ Dsymbol *sm = sd->fields[i];
Declaration *d = sm->isDeclaration();
if (d->storage_class & STCref || d->hasPointers())
goto Lnomatch;
}
}
else
{
/* More fruit left on the table, such as pointers to immutable.
*/
goto Lnomatch;
}
return (match == MATCHexact) ? MATCHconst : match;
}
Lnomatch:
return MATCHnomatch;
}
/* ==================== castTo ====================== */
/**************************************
* Do an explicit cast.
*/
Expression *Expression::castTo(Scope *sc, Type *t)
{
//printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
#if 0
printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
if (type == t)
return this;
Expression *e = this;
Type *tb = t->toBasetype();
Type *typeb = type->toBasetype();
if (tb != typeb)
{
#if !IN_LLVM
// Do (type *) cast of (type [dim])
if (tb->ty == Tpointer &&
typeb->ty == Tsarray
)
{
//printf("Converting [dim] to *\n");
if (typeb->size(loc) == 0)
e = new NullExp(loc);
else
e = new AddrExp(loc, e);
}
else
#endif
#if 0
if (tb->ty == Tdelegate && type->ty != Tdelegate)
{
TypeDelegate *td = (TypeDelegate *)tb;
TypeFunction *tf = (TypeFunction *)td->nextOf();
return toDelegate(sc, tf->nextOf());
}
else
#endif
{
if (typeb->ty == Tstruct)
{ TypeStruct *ts = (TypeStruct *)typeb;
if (!(tb->ty == Tstruct && ts->sym == ((TypeStruct *)tb)->sym) &&
ts->sym->aliasthis)
{ /* Forward the cast to our alias this member, rewrite to:
* cast(to)e1.aliasthis
*/
Expression *e1 = resolveAliasThis(sc, this);
Expression *e2 = new CastExp(loc, e1, tb);
e2 = e2->semantic(sc);
return e2;
}
}
else if (typeb->ty == Tclass)
{ TypeClass *ts = (TypeClass *)typeb;
if (ts->sym->aliasthis)
{
if (tb->ty == Tclass)
{
ClassDeclaration *cdfrom = typeb->isClassHandle();
ClassDeclaration *cdto = tb->isClassHandle();
int offset;
if (cdto->isBaseOf(cdfrom, &offset))
goto L1;
}
/* Forward the cast to our alias this member, rewrite to:
* cast(to)e1.aliasthis
*/
Expression *e1 = resolveAliasThis(sc, this);
Expression *e2 = new CastExp(loc, e1, tb);
e2 = e2->semantic(sc);
return e2;
}
L1: ;
}
else if (tb->ty == Tvector && typeb->ty != Tvector)
{
//printf("test1 e = %s, e->type = %s, tb = %s\n", e->toChars(), e->type->toChars(), tb->toChars());
TypeVector *tv = (TypeVector *)tb;
e = new CastExp(loc, e, tv->elementType());
e = new VectorExp(loc, e, tb);
e = e->semantic(sc);
return e;
}
else if (typeb->implicitConvTo(tb) == MATCHconst && t == type->constOf())
{
Expression *e = copy();
e->type = t;
return e;
}
e = new CastExp(loc, e, tb);
}
}
else
{
e = e->copy(); // because of COW for assignment to e->type
}
assert(e != this);
e->type = t;
//printf("Returning: %s\n", e->toChars());
return e;
}
Expression *ErrorExp::castTo(Scope *sc, Type *t)
{
return this;
}
Expression *RealExp::castTo(Scope *sc, Type *t)
{ Expression *e = this;
if (type != t)
{
if ((type->isreal() && t->isreal()) ||
(type->isimaginary() && t->isimaginary())
)
{ e = copy();
e->type = t;
}
else
e = Expression::castTo(sc, t);
}
return e;
}
Expression *ComplexExp::castTo(Scope *sc, Type *t)
{ Expression *e = this;
if (type != t)
{
if (type->iscomplex() && t->iscomplex())
{ e = copy();
e->type = t;
}
else
e = Expression::castTo(sc, t);
}
return e;
}
Expression *NullExp::castTo(Scope *sc, Type *t)
{
//printf("NullExp::castTo(t = %p)\n", t);
if (type == t)
{
committed = 1;
return this;
}
NullExp *e = (NullExp *)copy();
e->committed = 1;
Type *tb = t->toBasetype();
#if 0
e->type = type->toBasetype();
if (tb != e->type)
{
// NULL implicitly converts to any pointer type or dynamic array
if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid &&
(tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
tb->ty == Tdelegate))
{
if (tb->ty == Tdelegate)
{ TypeDelegate *td = (TypeDelegate *)tb;
TypeFunction *tf = (TypeFunction *)td->nextOf();
if (!tf->varargs &&
!(tf->arguments && tf->arguments->dim)
)
{
return Expression::castTo(sc, t);
}
}
}
else
{
//return e->Expression::castTo(sc, t);
}
}
#else
if (tb->ty == Tvoid)
{
e->type = type->toBasetype();
return e->Expression::castTo(sc, t);
}
#endif
e->type = t;
return e;
}
Expression *StringExp::castTo(Scope *sc, Type *t)
{
/* 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(), toChars(), committed);
if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
{
error("cannot convert string literal to void*");
return new ErrorExp();
}
StringExp *se = this;
if (!committed)
{ se = (StringExp *)copy();
se->committed = 1;
copied = 1;
}
if (type == t)
{
return se;
}
Type *tb = t->toBasetype();
//printf("\ttype = %s\n", type->toChars());
if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate)
return Expression::castTo(sc, t);
Type *typeb = type->toBasetype();
if (typeb == tb)
{
if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
se->type = t;
return se;
}
if (committed && tb->ty == Tsarray && typeb->ty == Tarray)
{
se = (StringExp *)copy();
d_uns64 szx = tb->nextOf()->size();
assert(szx <= 255);
se->sz = (unsigned char)szx;
se->len = (len * sz) / se->sz;
se->committed = 1;
se->type = t;
return se;
}
if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
{ if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
goto Lcast;
}
if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
{ if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
goto Lcast;
}
if (typeb->nextOf()->size() == tb->nextOf()->size())
{
if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
if (tb->ty == Tsarray)
goto L2; // handle possible change in static array dimension
se->type = t;
return se;
}
if (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 < len;)
{ unsigned c;
const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
if (p)
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 < len;)
{ unsigned c;
const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
if (p)
error("%s", p);
buffer.write4(c);
newlen++;
}
buffer.write4(0);
goto L1;
case X(Twchar,Tchar):
for (size_t u = 0; u < len;)
{ unsigned c;
const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
if (p)
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 < len;)
{ unsigned c;
const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
if (p)
error("%s", p);
buffer.write4(c);
newlen++;
}
buffer.write4(0);
goto L1;
case X(Tdchar,Tchar):
for (size_t u = 0; u < len; u++)
{
unsigned c = ((unsigned *)se->string)[u];
if (!utf_isValidDchar(c))
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 < len; u++)
{
unsigned c = ((unsigned *)se->string)[u];
if (!utf_isValidDchar(c))
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 *)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)
{
dinteger_t dim2 = ((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 = (unsigned char *)mem.malloc((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;
return se;
Lcast:
Expression *e = new CastExp(loc, se, t);
e->type = t; // so semantic() won't be run on e
return e;
}
Expression *AddrExp::castTo(Scope *sc, Type *t)
{
Type *tb;
#if 0
printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
Expression *e = this;
tb = t->toBasetype();
type = type->toBasetype();
if (tb != type)
{
// Look for pointers to functions where the functions are overloaded.
if (e1->op == TOKoverloadset &&
(t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
{ OverExp *eo = (OverExp *)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(), m))
{ if (f)
/* Error if match in more than one overload set,
* even if one is a 'better' match than the other.
*/
ScopeDsymbol::multiplyDefined(loc, f, f2);
else
f = f2;
}
}
#if IN_LLVM
if (f)
{
f = f->overloadExactMatch(tb->nextOf(), m);
if (f)
{
if (tb->ty == Tdelegate)
{
if (f->needThis() && hasThis(sc))
{
e = new DelegateExp(loc, new ThisExp(loc), f);
e = e->semantic(sc);
}
else if (f->isNested())
{
e = new DelegateExp(loc, new IntegerExp(0), f);
e = e->semantic(sc);
}
else if (f->needThis())
{ error("no 'this' to create delegate for %s", f->toChars());
return new ErrorExp();
}
else
{ error("cannot cast from function pointer to delegate");
return new ErrorExp();
}
}
else
{
e = new VarExp(loc, f);
e->type = f->type;
e = new AddrExp(loc, e);
e->type = t;
return e;
}
#if DMDV2
f->tookAddressOf++;
#endif
return e;
}
}
#else
if (f)
{ f->tookAddressOf++;
SymOffExp *se = new SymOffExp(loc, f, 0, 0);
se->semantic(sc);
// Let SymOffExp::castTo() do the heavy lifting
return se->castTo(sc, t);
}
#endif
}
if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
e1->op == TOKvar)
{
VarExp *ve = (VarExp *)e1;
FuncDeclaration *f = ve->var->isFuncDeclaration();
if (f)
{
#if !IN_LLVM
assert(0); // should be SymOffExp instead
#endif
f = f->overloadExactMatch(tb->nextOf(), m);
if (f)
{
e = new VarExp(loc, f);
e->type = f->type;
e = new AddrExp(loc, e);
e->type = t;
return e;
}
}
}
e = Expression::castTo(sc, t);
}
#if IN_LLVM
else if (e1->op == TOKvar)
{
VarExp *ve = (VarExp*)e1->copy();
ve->hasOverloads = 0;
e1 = ve;
}
#endif
e->type = t;
return e;
}
Expression *TupleExp::castTo(Scope *sc, Type *t)
{ TupleExp *e = (TupleExp *)copy();
e->exps = (Expressions *)exps->copy();
for (size_t i = 0; i < e->exps->dim; i++)
{ Expression *ex = (*e->exps)[i];
ex = ex->castTo(sc, t);
(*e->exps)[i] = ex;
}
return e;
}
Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
{
#if 0
printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n",
toChars(), type->toChars(), t->toChars());
#endif
if (type == t)
return this;
ArrayLiteralExp *e = this;
Type *typeb = type->toBasetype();
Type *tb = t->toBasetype();
if ((tb->ty == Tarray || tb->ty == Tsarray) &&
(typeb->ty == Tarray || typeb->ty == Tsarray) &&
// Not trying to convert non-void[] to void[]
!(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid))
{
if (tb->ty == Tsarray)
{ TypeSArray *tsa = (TypeSArray *)tb;
if (elements->dim != tsa->dim->toInteger())
goto L1;
}
e = (ArrayLiteralExp *)copy();
e->elements = (Expressions *)elements->copy();
for (size_t i = 0; i < elements->dim; i++)
{ Expression *ex = (*elements)[i];
ex = ex->castTo(sc, tb->nextOf());
(*e->elements)[i] = ex;
}
e->type = t;
return e;
}
if (tb->ty == Tpointer && typeb->ty == Tsarray)
{
Type *tp = typeb->nextOf()->pointerTo();
if (!tp->equals(e->type))
{ e = (ArrayLiteralExp *)copy();
e->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);
if (elements->dim != tbase->dim->toInteger())
goto L1;
e = (ArrayLiteralExp *)copy();
e->elements = (Expressions *)elements->copy();
Type *telement = tv->elementType();
for (size_t i = 0; i < elements->dim; i++)
{ Expression *ex = (*elements)[i];
ex = ex->castTo(sc, telement);
(*e->elements)[i] = ex;
}
Expression *ev = new VectorExp(loc, e, tb);
ev = ev->semantic(sc);
return ev;
}
L1:
return e->Expression::castTo(sc, t);
}
Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
{
if (type == t)
return this;
AssocArrayLiteralExp *e = this;
Type *typeb = type->toBasetype();
Type *tb = t->toBasetype();
if (tb->ty == Taarray && typeb->ty == Taarray &&
tb->nextOf()->toBasetype()->ty != Tvoid)
{
e = (AssocArrayLiteralExp *)copy();
e->keys = (Expressions *)keys->copy();
e->values = (Expressions *)values->copy();
assert(keys->dim == values->dim);
for (size_t i = 0; i < keys->dim; i++)
{ Expression *ex = (*values)[i];
ex = ex->castTo(sc, tb->nextOf());
(*e->values)[i] = ex;
ex = (*keys)[i];
ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
(*e->keys)[i] = ex;
}
e->type = t;
return e;
}
return e->Expression::castTo(sc, t);
}
Expression *SymOffExp::castTo(Scope *sc, Type *t)
{
#if 0
printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
if (type == t && hasOverloads == 0)
return this;
Expression *e;
Type *tb = t->toBasetype();
Type *typeb = type->toBasetype();
if (tb != typeb)
{
// Look for pointers to functions where the functions are overloaded.
FuncDeclaration *f;
if (hasOverloads &&
typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction &&
(tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction)
{
f = var->isFuncDeclaration();
if (f)
{
f = f->overloadExactMatch(tb->nextOf(), m);
if (f)
{
if (tb->ty == Tdelegate)
{
if (f->needThis() && hasThis(sc))
{
e = new DelegateExp(loc, new ThisExp(loc), f);
e = e->semantic(sc);
}
else if (f->isNested())
{
e = new DelegateExp(loc, new IntegerExp(0), f);
e = e->semantic(sc);
}
else if (f->needThis())
{ error("no 'this' to create delegate for %s", f->toChars());
return new ErrorExp();
}
else
{ error("cannot cast from function pointer to delegate");
return new ErrorExp();
}
}
else
{
e = new SymOffExp(loc, f, 0);
e->type = t;
}
#if DMDV2
f->tookAddressOf++;
#endif
return e;
}
}
}
e = Expression::castTo(sc, t);
}
else
{ e = copy();
e->type = t;
((SymOffExp *)e)->hasOverloads = 0;
}
return e;
}
Expression *DelegateExp::castTo(Scope *sc, Type *t)
{
#if 0
printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
static char msg[] = "cannot form delegate due to covariant return type";
Expression *e = this;
Type *tb = t->toBasetype();
Type *typeb = type->toBasetype();
if (tb != typeb || hasOverloads)
{
// Look for delegates to functions where the functions are overloaded.
FuncDeclaration *f;
if (typeb->ty == Tdelegate &&
tb->ty == Tdelegate)
{
if (func)
{
f = func->overloadExactMatch(tb->nextOf(), m);
if (f)
{ int offset;
if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset)
error("%s", msg);
f->tookAddressOf++;
e = new DelegateExp(loc, e1, f);
e->type = t;
return e;
}
if (func->tintro)
error("%s", msg);
}
}
e = Expression::castTo(sc, t);
}
else
{ int offset;
func->tookAddressOf++;
if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset)
error("%s", msg);
e = copy();
e->type = t;
}
return e;
}
Expression *FuncExp::castTo(Scope *sc, Type *t)
{
//printf("FuncExp::castTo type = %s, t = %s\n", type->toChars(), t->toChars());
Expression *e = inferType(t, 1);
if (e)
{
if (e != this)
e = e->castTo(sc, t);
else if (!e->type->equals(t))
{
assert(e->type->nextOf()->covariant(t->nextOf()) == 1);
e = e->copy();
e->type = t;
}
return e;
}
return Expression::castTo(sc, t);
}
Expression *CondExp::castTo(Scope *sc, Type *t)
{
Expression *e = this;
if (type != t)
{
if (1 || e1->op == TOKstring || e2->op == TOKstring)
{ e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t));
e->type = t;
}
else
e = Expression::castTo(sc, t);
}
return e;
}
Expression *CommaExp::castTo(Scope *sc, Type *t)
{
Expression *e2c = e2->castTo(sc, t);
Expression *e;
if (e2c != e2)
{
e = new CommaExp(loc, e1, e2c);
e->type = e2c->type;
}
else
{ e = this;
e->type = e2->type;
}
return e;
}
/* ==================== inferType ====================== */
/****************************************
* Set type inference target
* flag 1: don't put an error when inference fails
*/
Expression *Expression::inferType(Type *t, int flag, TemplateParameters *tparams)
{
return this;
}
Expression *ArrayLiteralExp::inferType(Type *t, int flag, TemplateParameters *tparams)
{
if (t)
{
t = t->toBasetype();
if (t->ty == Tarray || t->ty == Tsarray)
{
Type *tn = t->nextOf();
for (size_t i = 0; i < elements->dim; i++)
{ Expression *e = (*elements)[i];
if (e)
{ e = e->inferType(tn, flag, tparams);
(*elements)[i] = e;
}
}
}
}
return this;
}
Expression *AssocArrayLiteralExp::inferType(Type *t, int flag, TemplateParameters *tparams)
{
if (t)
{
t = t->toBasetype();
if (t->ty == Taarray)
{ TypeAArray *taa = (TypeAArray *)t;
Type *ti = taa->index;
Type *tv = taa->nextOf();
for (size_t i = 0; i < keys->dim; i++)
{ Expression *e = (*keys)[i];
if (e)
{ e = e->inferType(ti, flag, tparams);
(*keys)[i] = e;
}
}
for (size_t i = 0; i < values->dim; i++)
{ Expression *e = (*values)[i];
if (e)
{ e = e->inferType(tv, flag, tparams);
(*values)[i] = e;
}
}
}
}
return this;
}
Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams)
{
if (!to)
return this;
//printf("FuncExp::interType('%s'), to=%s\n", type?type->toChars():"null", to->toChars());
if (!type) // semantic is not yet done
{
if (to->ty == Tdelegate ||
to->ty == Tpointer && to->nextOf()->ty == Tfunction)
{ fd->treq = to;
}
return this;
}
Expression *e = NULL;
Type *t = to;
if (t->ty == Tdelegate)
{ if (tok == TOKfunction)
goto L1;
t = t->nextOf();
}
else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
{ if (tok == TOKdelegate)
goto L1;
t = t->nextOf();
}
if (td)
{ /// Parameter types inference from
assert(td->scope);
if (t->ty == Tfunction)
{
TypeFunction *tfv = (TypeFunction *)t;
TypeFunction *tfl = (TypeFunction *)fd->type;
//printf("\ttfv = %s\n", tfv->toChars());
//printf("\ttfl = %s\n", tfl->toChars());
size_t dim = Parameter::dim(tfl->parameters);
if (Parameter::dim(tfv->parameters) == dim &&
tfv->varargs == tfl->varargs)
{
Objects *tiargs = new Objects();
tiargs->reserve(td->parameters->dim);
for (size_t i = 0; i < td->parameters->dim; i++)
{
TemplateParameter *tp = (*td->parameters)[i];
for (size_t u = 0; u < dim; u++)
{ Parameter *p = Parameter::getNth(tfl->parameters, u);
if (p->type->ty == Tident &&
((TypeIdentifier *)p->type)->ident == tp->ident)
{ p = Parameter::getNth(tfv->parameters, u);
Type *tprm = p->type;
if (tprm->reliesOnTident(tparams))
goto L1;
tprm = tprm->semantic(loc, td->scope);
tiargs->push(tprm);
u = dim; // break inner loop
}
}
}
// Set target of return type inference
assert(td->onemember);
FuncLiteralDeclaration *fld = td->onemember->isFuncLiteralDeclaration();
assert(fld);
if (!fld->type->nextOf() && tfv->next)
fld->treq = to;
TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
e = (new ScopeExp(loc, ti))->semantic(td->scope);
// Reset inference target for the later re-semantic
fld->treq = NULL;
if (e->op == TOKfunction)
{ FuncExp *fe = (FuncExp *)e;
assert(fe->td == NULL);
e = fe->inferType(to, flag);
}
}
}
}
else if (type)
{
assert(type != Type::tvoid); // semantic is already done
// Allow conversion from implicit function pointer to delegate
if (tok == TOKreserved && type->ty == Tpointer &&
to->ty == Tdelegate)
{
Type *typen = type->nextOf();
if (typen->deco)
{
FuncExp *fe = (FuncExp *)copy();
fe->tok = TOKdelegate;
fe->type = (new TypeDelegate(typen))->merge();
e = fe;
}
}
else
e = this;
}
L1:
if (!flag && !e)
{ error("cannot infer function literal type from %s", to->toChars());
e = new ErrorExp();
}
return e;
}
Expression *CondExp::inferType(Type *t, int flag, TemplateParameters *tparams)
{
if (t)
{
t = t->toBasetype();
e1 = e1->inferType(t, flag, tparams);
e2 = e2->inferType(t, flag, tparams);
}
return this;
}
/* ==================== ====================== */
/****************************************
* Scale addition/subtraction to/from pointer.
*/
Expression *BinExp::scaleFactor(Scope *sc)
{
if (sc->func && !sc->intypeof)
{
if (sc->func->setUnsafe())
{
error("pointer arithmetic not allowed in @safe functions");
return new ErrorExp();
}
}
d_uns64 stride;
Type *t1b = e1->type->toBasetype();
Type *t2b = e2->type->toBasetype();
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;
stride = t1b->nextOf()->size(loc);
if (!t->equals(t2b))
e2 = e2->castTo(sc, t);
// LDC: llvm uses typesafe pointer arithmetic
#if !IN_LLVM
e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t));
#endif
e2->type = t;
type = 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;
stride = t2b->nextOf()->size(loc);
if (!t->equals(t1b))
e = e1->castTo(sc, t);
else
e = e1;
#if !IN_LLVM
e = new MulExp(loc, e, new IntegerExp(0, stride, t));
#endif
e->type = t;
type = e2->type;
e1 = e2;
e2 = e;
}
return this;
}
/**************************************
* 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))
{
e = (*((ArrayLiteralExp *)e)->elements)[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);
}
/**************************************
* Combine types.
* Output:
* *pt merged type, if *pt is not NULL
* *pe1 rewritten e1
* *pe2 rewritten e2
* Returns:
* !=0 success
* 0 failed
*/
int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2)
{
//printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
//e->dump(0);
MATCH m;
Expression *e1 = *pe1;
Expression *e2 = *pe2;
if (e->op != TOKquestion ||
e1->type->toBasetype()->ty != e2->type->toBasetype()->ty)
{
e1 = e1->integralPromotions(sc);
e2 = e2->integralPromotions(sc);
}
Type *t1 = e1->type;
Type *t2 = e2->type;
assert(t1);
Type *t = t1;
//if (t1) printf("\tt1 = %s\n", t1->toChars());
//if (t2) printf("\tt2 = %s\n", t2->toChars());
#ifdef DEBUG
if (!t2) printf("\te2 = '%s'\n", e2->toChars());
#endif
assert(t2);
Lagain:
Type *t1b = t1->toBasetype();
Type *t2b = t2->toBasetype();
TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
if (ty != Terror)
{
TY ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
TY ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
if (t1b->ty == ty1) // if no promotions
{
if (t1 == t2)
{
t = t1;
goto Lret;
}
if (t1b == 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");
//dump(0);
//printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
goto Lret;
}
t1 = t1b;
t2 = t2b;
if (t1 == t2)
{
}
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 == t2n)
;
#if IN_LLVM
else if (t1n->equals(t2n))
;
#endif
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;
TypeFunction *d = (TypeFunction *)tf1->syntaxCopy();
if (tf1->purity != tf2->purity)
d->purity = PUREimpure;
assert(d->purity != PUREfwdref);
d->isnothrow = (tf1->isnothrow && tf2->isnothrow);
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);
tx = tx->merge();
}
else
tx = d->pointerTo();
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;
}
goto Lincompatible;
}
}
else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
(e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid ||
// if e2 is void[]
e2->op == TOKarrayliteral && t2->ty == Tsarray && t2->nextOf()->ty == Tvoid && ((TypeSArray *)t2)->dim->toInteger() == 0 ||
isVoidArrayLiteral(e2, t1))
)
{ /* (T[n] op void*) => T[]
* (T[] op void*) => T[]
* (T[n] op void[0]) => T[]
* (T[] op void[0]) => T[]
* (T[n] op void[]) => T[]
* (T[] op void[]) => T[]
*/
goto Lx1;
}
else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
(e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid ||
e1->op == TOKarrayliteral && t1->ty == Tsarray && t1->nextOf()->ty == Tvoid && ((TypeSArray *)t1)->dim->toInteger() == 0 ||
isVoidArrayLiteral(e1, t2))
)
{ /* (void* op T[n]) => T[]
* (void* op T[]) => T[]
* (void[0] op T[n]) => T[]
* (void[0] op T[]) => T[]
* (void[] op T[n]) => T[]
* (void[] op T[]) => T[]
*/
goto Lx2;
}
else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
(m = t1->implicitConvTo(t2)) != MATCHnomatch)
{
if (t1->ty == Tsarray && e2->op == TOKarrayliteral)
goto Lt1;
if (m == MATCHconst &&
(e->op == TOKaddass || e->op == TOKminass || e->op == TOKmulass ||
e->op == TOKdivass || e->op == TOKmodass || e->op == TOKpowass ||
e->op == TOKandass || e->op == TOKorass || e->op == TOKxorass)
)
{ // Don't make the lvalue const
t = t2;
goto Lret;
}
goto Lt2;
}
else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
{
if (t2->ty == Tsarray && e1->op == TOKarrayliteral)
goto Lt2;
goto Lt1;
}
/* If one is mutable and the other invariant, then retry
* with both of them as const
*/
else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) &&
(t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) &&
t1->nextOf()->mod != t2->nextOf()->mod
)
{
Type *t1n = t1->nextOf();
Type *t2n = t2->nextOf();
unsigned char mod;
if (e1->op == TOKnull && e2->op != TOKnull)
mod = t2n->mod;
else if (e1->op != TOKnull && e2->op == TOKnull)
mod = t1n->mod;
else if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
goto Lincompatible;
else
mod = MODmerge(t1n->mod, t2n->mod);
if (t1->ty == Tpointer)
t1 = t1n->castMod(mod)->pointerTo();
else
t1 = t1n->castMod(mod)->arrayOf();
if (t2->ty == Tpointer)
t2 = t2n->castMod(mod)->pointerTo();
else
t2 = t2n->castMod(mod)->arrayOf();
t = t1;
goto Lagain;
}
else if (t1->ty == Tclass && t2->ty == Tclass)
{
if (t1->mod != t2->mod)
{
unsigned char mod;
if (e1->op == TOKnull && e2->op != TOKnull)
mod = t2->mod;
else if (e1->op != TOKnull && e2->op == TOKnull)
mod = t1->mod;
else if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
goto Lincompatible;
else
mod = MODmerge(t1->mod, t2->mod);
t1 = t1->castMod(mod);
t2 = t2->castMod(mod);
t = t1;
goto Lagain;
}
goto Lcc;
}
else if (t1->ty == Tclass || t2->ty == Tclass)
{
Lcc:
while (1)
{
MATCH i1 = e2->implicitConvTo(t1);
MATCH i2 = e1->implicitConvTo(t2);
if (i1 && i2)
{
// We have the case of class vs. void*, so pick class
if (t1->ty == Tpointer)
i1 = MATCHnomatch;
else if (t2->ty == Tpointer)
i2 = MATCHnomatch;
}
if (i2)
{
goto Lt2;
}
else if (i1)
{
goto Lt1;
}
else if (t1->ty == Tclass && t2->ty == Tclass)
{ TypeClass *tc1 = (TypeClass *)t1;
TypeClass *tc2 = (TypeClass *)t2;
/* Pick 'tightest' type
*/
ClassDeclaration *cd1 = tc1->sym->baseClass;
ClassDeclaration *cd2 = tc2->sym->baseClass;
if (cd1 && cd2)
{ t1 = cd1->type;
t2 = cd2->type;
}
else if (cd1)
t1 = cd1->type;
else if (cd2)
t2 = cd2->type;
else
goto Lincompatible;
}
else if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
{
e1 = resolveAliasThis(sc, e1);
t1 = e1->type;
continue;
}
else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
{
e2 = resolveAliasThis(sc, e2);
t2 = e2->type;
continue;
}
else
goto Lincompatible;
}
}
else if (t1->ty == Tstruct && t2->ty == Tstruct)
{
if (t1->mod != t2->mod)
{
if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
goto Lincompatible;
unsigned char mod = MODmerge(t1->mod, t2->mod);
t1 = t1->castMod(mod);
t2 = t2->castMod(mod);
t = t1;
goto Lagain;
}
TypeStruct *ts1 = (TypeStruct *)t1;
TypeStruct *ts2 = (TypeStruct *)t2;
if (ts1->sym != ts2->sym)
{
if (!ts1->sym->aliasthis && !ts2->sym->aliasthis)
goto Lincompatible;
MATCH i1 = MATCHnomatch;
MATCH i2 = MATCHnomatch;
Expression *e1b = NULL;
Expression *e2b = NULL;
if (ts2->sym->aliasthis)
{
e2b = resolveAliasThis(sc, e2);
i1 = e2b->implicitConvTo(t1);
}
if (ts1->sym->aliasthis)
{
e1b = resolveAliasThis(sc, e1);
i2 = e1b->implicitConvTo(t2);
}
if (i1 && i2)
goto Lincompatible;
if (i1)
goto Lt1;
else if (i2)
goto Lt2;
if (e1b)
{ e1 = e1b;
t1 = e1b->type->toBasetype();
}
if (e2b)
{ e2 = e2b;
t2 = e2b->type->toBasetype();
}
t = t1;
goto Lagain;
}
}
else if (t1->ty == Tstruct || t2->ty == Tstruct)
{
if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
{
e1 = resolveAliasThis(sc, e1);
t1 = e1->type;
t = t1;
goto Lagain;
}
if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
{
e2 = resolveAliasThis(sc, e2);
t2 = e2->type;
t = t2;
goto Lagain;
}
goto Lincompatible;
}
else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
{
goto Lt2;
}
else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
{
goto Lt1;
}
else if (t1->ty == Tsarray && t2->ty == Tsarray &&
e2->implicitConvTo(t1->nextOf()->arrayOf()))
{
Lx1:
t = t1->nextOf()->arrayOf(); // T[]
e1 = e1->castTo(sc, t);
e2 = e2->castTo(sc, t);
}
else if (t1->ty == Tsarray && t2->ty == Tsarray &&
e1->implicitConvTo(t2->nextOf()->arrayOf()))
{
Lx2:
t = t2->nextOf()->arrayOf();
e1 = e1->castTo(sc, t);
e2 = e2->castTo(sc, t);
}
else if (t1->ty == Tvector && t2->ty != Tvector &&
e2->implicitConvTo(t1))
{
e2 = e2->castTo(sc, t1);
t2 = t1;
goto Lagain;
}
else if (t2->ty == Tvector && t1->ty != Tvector &&
e1->implicitConvTo(t2))
{
e1 = e1->castTo(sc, t2);
t1 = t2;
goto Lagain;
}
else if (t1->isintegral() && t2->isintegral())
{
assert(t1->ty == t2->ty);
if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
goto Lincompatible;
unsigned char mod = MODmerge(t1->mod, t2->mod);
t1 = t1->castMod(mod);
t2 = t2->castMod(mod);
t = t1;
e1 = e1->castTo(sc, t);
e2 = e2->castTo(sc, t);
goto Lagain;
}
else if (e1->isArrayOperand() && t1->ty == Tarray &&
e2->implicitConvTo(t1->nextOf()))
{ // T[] op T
e2 = e2->castTo(sc, t1->nextOf());
t = t1->nextOf()->arrayOf();
}
else if (e2->isArrayOperand() && t2->ty == Tarray &&
e1->implicitConvTo(t2->nextOf()))
{ // T op T[]
e1 = e1->castTo(sc, t2->nextOf());
t = t2->nextOf()->arrayOf();
//printf("test %s\n", e->toChars());
e1 = e1->optimize(WANTvalue);
if (e && e->isCommutative() && e1->isConst())
{ /* Swap operands to minimize number of functions generated
*/
//printf("swap %s\n", e->toChars());
Expression *tmp = e1;
e1 = e2;
e2 = tmp;
}
}
else
{
Lincompatible:
return 0;
}
Lret:
if (!*pt)
*pt = t;
*pe1 = e1;
*pe2 = e2;
#if 0
printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars());
if (e1->type) printf("\tt1 = %s\n", e1->type->toChars());
if (e2->type) printf("\tt2 = %s\n", e2->type->toChars());
printf("\ttype = %s\n", t->toChars());
#endif
//dump(0);
return 1;
Lt1:
e2 = e2->castTo(sc, t1);
t = t1;
goto Lret;
Lt2:
e1 = e1->castTo(sc, t2);
t = t2;
goto Lret;
}
/************************************
* Bring leaves to common type.
*/
Expression *BinExp::typeCombine(Scope *sc)
{
Type *t1 = e1->type->toBasetype();
Type *t2 = e2->type->toBasetype();
if (op == TOKmin || op == TOKadd)
{
// struct+struct, and class+class are errors
if (t1->ty == Tstruct && t2->ty == Tstruct)
goto Lerror;
else if (t1->ty == Tclass && t2->ty == Tclass)
goto Lerror;
}
if (!typeMerge(sc, this, &type, &e1, &e2))
goto Lerror;
return this;
Lerror:
incompatibleTypes();
type = Type::terror;
e1 = new ErrorExp();
e2 = new ErrorExp();
return new ErrorExp();
}
/***********************************
* Do integral promotions (convertchk).
* Don't convert <array of> to <pointer to>
*/
Expression *Expression::integralPromotions(Scope *sc)
{
Expression *e = this;
//printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars());
switch (type->toBasetype()->ty)
{
case Tvoid:
error("void has no value");
return new ErrorExp();
case Tint8:
case Tuns8:
case Tint16:
case Tuns16:
case Tbool:
case Tchar:
case Twchar:
e = e->castTo(sc, Type::tint32);
break;
case Tdchar:
e = e->castTo(sc, Type::tuns32);
break;
}
return e;
}
/***********************************
* See if both types are arrays that can be compared
* for equality. Return !=0 if so.
* If they are arrays, but incompatible, issue error.
* This is to enable comparing things like an immutable
* array with a mutable one.
*/
int arrayTypeCompatible(Loc loc, Type *t1, Type *t2)
{
t1 = t1->toBasetype();
t2 = t2->toBasetype();
if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
(t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
{
if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst &&
t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst &&
(t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid))
{
error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars());
}
return 1;
}
return 0;
}
/***********************************
* See if both types are arrays that can be compared
* for equality without any casting. Return !=0 if so.
* This is to enable comparing things like an immutable
* array with a mutable one.
*/
int arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2)
{
t1 = t1->toBasetype();
t2 = t2->toBasetype();
if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
t2->ty == t1->ty)
{
if (t1->nextOf()->implicitConvTo(t2->nextOf()) >= MATCHconst ||
t2->nextOf()->implicitConvTo(t1->nextOf()) >= MATCHconst)
return 1;
}
return 0;
}
/******************************************************************/
/* Determine the integral ranges of an expression.
* This is used to determine if implicit narrowing conversions will
* be allowed.
*/
uinteger_t getMask(uinteger_t v)
{
// Ref: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
return v /* | 0xff*/;
}
IntRange Expression::getIntRange()
{
return IntRange::fromType(type) DUMP;
}
IntRange IntegerExp::getIntRange()
{
return IntRange(value).cast(type) DUMP;
}
IntRange CastExp::getIntRange()
{
return e1->getIntRange().cast(type) DUMP;
}
IntRange AddExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
return IntRange(ir1.imin + ir2.imin, ir1.imax + ir2.imax).cast(type) DUMP;
}
IntRange MinExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
return IntRange(ir1.imin - ir2.imax, ir1.imax - ir2.imin).cast(type) DUMP;
}
IntRange DivExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
// Should we ignore the possibility of div-by-0???
if (ir2.containsZero())
return Expression::getIntRange() DUMP;
// [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
SignExtendedNumber bdy[4] = {
ir1.imin / ir2.imin,
ir1.imin / ir2.imax,
ir1.imax / ir2.imin,
ir1.imax / ir2.imax
};
return IntRange::fromNumbers4(bdy).cast(type) DUMP;
}
IntRange MulExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
// [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
SignExtendedNumber bdy[4] = {
ir1.imin * ir2.imin,
ir1.imin * ir2.imax,
ir1.imax * ir2.imin,
ir1.imax * ir2.imax
};
return IntRange::fromNumbers4(bdy).cast(type) DUMP;
}
IntRange ModExp::getIntRange()
{
IntRange irNum = e1->getIntRange();
IntRange irDen = e2->getIntRange().absNeg();
/*
due to the rules of D (C)'s % operator, we need to consider the cases
separately in different range of signs.
case 1. [500, 1700] % [7, 23] (numerator is always positive)
= [0, 22]
case 2. [-500, 1700] % [7, 23] (numerator can be negative)
= [-22, 22]
case 3. [-1700, -500] % [7, 23] (numerator is always negative)
= [-22, 0]
the number 22 is the maximum absolute value in the denomator's range. We
don't care about divide by zero.
*/
// Modding on 0 is invalid anyway.
if (!irDen.imin.negative)
return Expression::getIntRange() DUMP;
++ irDen.imin;
irDen.imax = -irDen.imin;
if (!irNum.imin.negative)
irNum.imin.value = 0;
else if (irNum.imin < irDen.imin)
irNum.imin = irDen.imin;
if (irNum.imax.negative)
{
irNum.imax.negative = false;
irNum.imax.value = 0;
}
else if (irNum.imax > irDen.imax)
irNum.imax = irDen.imax;
return irNum.cast(type) DUMP;
}
// The algorithms for &, |, ^ are not yet the best! Sometimes they will produce
// not the tightest bound. See
// https://github.com/D-Programming-Language/dmd/pull/116
// for detail.
static IntRange unsignedBitwiseAnd(const IntRange& a, const IntRange& b)
{
// the DiffMasks stores the mask of bits which are variable in the range.
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
// Since '&' computes the digitwise-minimum, the we could set all varying
// digits to 0 to get a lower bound, and set all varying digits to 1 to get
// an upper bound.
IntRange result;
result.imin.value = (a.imin.value & ~aDiffMask) & (b.imin.value & ~bDiffMask);
result.imax.value = (a.imax.value | aDiffMask) & (b.imax.value | bDiffMask);
// Sometimes the upper bound is overestimated. The upper bound will never
// exceed the input.
if (result.imax.value > a.imax.value)
result.imax.value = a.imax.value;
if (result.imax.value > b.imax.value)
result.imax.value = b.imax.value;
result.imin.negative = result.imax.negative = a.imin.negative && b.imin.negative;
return result;
}
static IntRange unsignedBitwiseOr(const IntRange& a, const IntRange& b)
{
// the DiffMasks stores the mask of bits which are variable in the range.
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
// The imax algorithm by Adam D. Ruppe.
// http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=108796
IntRange result;
result.imin.value = (a.imin.value & ~aDiffMask) | (b.imin.value & ~bDiffMask);
result.imax.value = a.imax.value | b.imax.value | getMask(a.imax.value & b.imax.value);
// Sometimes the lower bound is underestimated. The lower bound will never
// less than the input.
if (result.imin.value < a.imin.value)
result.imin.value = a.imin.value;
if (result.imin.value < b.imin.value)
result.imin.value = b.imin.value;
result.imin.negative = result.imax.negative = a.imin.negative || b.imin.negative;
return result;
}
static IntRange unsignedBitwiseXor(const IntRange& a, const IntRange& b)
{
// the DiffMasks stores the mask of bits which are variable in the range.
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
IntRange result;
result.imin.value = (a.imin.value ^ b.imin.value) & ~(aDiffMask | bDiffMask);
result.imax.value = (a.imax.value ^ b.imax.value) | (aDiffMask | bDiffMask);
result.imin.negative = result.imax.negative = a.imin.negative != b.imin.negative;
return result;
}
IntRange AndExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
bool has1neg, has1pos, has2neg, has2pos;
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
IntRange result;
bool hasResult = false;
if (has1pos && has2pos)
result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2pos), /*ref*/hasResult);
if (has1pos && has2neg)
result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2neg), /*ref*/hasResult);
if (has1neg && has2pos)
result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2pos), /*ref*/hasResult);
if (has1neg && has2neg)
result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2neg), /*ref*/hasResult);
assert(hasResult);
return result.cast(type) DUMP;
}
IntRange OrExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
bool has1neg, has1pos, has2neg, has2pos;
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
IntRange result;
bool hasResult = false;
if (has1pos && has2pos)
result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2pos), /*ref*/hasResult);
if (has1pos && has2neg)
result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2neg), /*ref*/hasResult);
if (has1neg && has2pos)
result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2pos), /*ref*/hasResult);
if (has1neg && has2neg)
result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2neg), /*ref*/hasResult);
assert(hasResult);
return result.cast(type) DUMP;
}
IntRange XorExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
bool has1neg, has1pos, has2neg, has2pos;
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
IntRange result;
bool hasResult = false;
if (has1pos && has2pos)
result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2pos), /*ref*/hasResult);
if (has1pos && has2neg)
result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2neg), /*ref*/hasResult);
if (has1neg && has2pos)
result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2pos), /*ref*/hasResult);
if (has1neg && has2neg)
result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2neg), /*ref*/hasResult);
assert(hasResult);
return result.cast(type) DUMP;
}
IntRange ShlExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
if (ir2.imin.negative)
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
SignExtendedNumber lower = ir1.imin << (ir1.imin.negative ? ir2.imax : ir2.imin);
SignExtendedNumber upper = ir1.imax << (ir1.imax.negative ? ir2.imin : ir2.imax);
return IntRange(lower, upper).cast(type) DUMP;
}
IntRange ShrExp::getIntRange()
{
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
if (ir2.imin.negative)
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
SignExtendedNumber lower = ir1.imin >> (ir1.imin.negative ? ir2.imin : ir2.imax);
SignExtendedNumber upper = ir1.imax >> (ir1.imax.negative ? ir2.imax : ir2.imin);
return IntRange(lower, upper).cast(type) DUMP;
}
IntRange UshrExp::getIntRange()
{
IntRange ir1 = e1->getIntRange().castUnsigned(e1->type);
IntRange ir2 = e2->getIntRange();
if (ir2.imin.negative)
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
return IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(type) DUMP;
}
IntRange CommaExp::getIntRange()
{
return e2->getIntRange() DUMP;
}
IntRange ComExp::getIntRange()
{
IntRange ir = e1->getIntRange();
return IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative),
SignExtendedNumber(~ir.imin.value, !ir.imin.negative)).cast(type) DUMP;
}
IntRange NegExp::getIntRange()
{
IntRange ir = e1->getIntRange();
return IntRange(-ir.imax, -ir.imin).cast(type) DUMP;
}