blob: 52e26bccd858881cabd7b98590845c8ef093dabf [file] [log] [blame]
/* 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
*/
#include "root/checkedint.h"
#include "mars.h"
#include "init.h"
#include "expression.h"
#include "statement.h"
#include "declaration.h"
#include "aggregate.h"
#include "scope.h"
#include "mtype.h"
#include "template.h"
#include "id.h"
FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
Expression *semantic(Expression *e, Scope *sc);
Initializer *inferType(Initializer *init, Scope *sc);
Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
bool hasNonConstPointers(Expression *e);
class InitializerSemanticVisitor : public Visitor
{
public:
Initializer *result;
Scope *sc;
Type *t;
NeedInterpret needInterpret;
InitializerSemanticVisitor(Scope *sc, Type *t, NeedInterpret needInterpret)
{
this->result = NULL;
this->sc = sc;
this->t = t;
this->needInterpret = needInterpret;
}
void visit(ErrorInitializer *i)
{
//printf("ErrorInitializer::semantic(t = %p)\n", t);
result = i;
}
void visit(VoidInitializer *i)
{
//printf("VoidInitializer::semantic(t = %p)\n", t);
i->type = t;
result = i;
}
void visit(StructInitializer *i)
{
//printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
t = t->toBasetype();
if (t->ty == Tsarray && t->nextOf()->toBasetype()->ty == Tstruct)
t = t->nextOf()->toBasetype();
if (t->ty == Tstruct)
{
StructDeclaration *sd = ((TypeStruct *)t)->sym;
if (sd->ctor)
{
error(i->loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead",
sd->kind(), sd->toChars(), sd->toChars());
result = new ErrorInitializer();
return;
}
sd->size(i->loc);
if (sd->sizeok != SIZEOKdone)
{
result = new ErrorInitializer();
return;
}
size_t nfields = sd->fields.dim - sd->isNested();
//expandTuples for non-identity arguments?
Expressions *elements = new Expressions();
elements->setDim(nfields);
for (size_t j = 0; j < elements->dim; j++)
(*elements)[j] = NULL;
// Run semantic for explicitly given initializers
// TODO: this part is slightly different from StructLiteralExp::semantic.
bool errors = false;
for (size_t fieldi = 0, j = 0; j < i->field.dim; j++)
{
if (Identifier *id = i->field[j])
{
Dsymbol *s = sd->search(i->loc, id);
if (!s)
{
s = sd->search_correct(id);
if (s)
error(i->loc, "'%s' is not a member of '%s', did you mean %s '%s'?",
id->toChars(), sd->toChars(), s->kind(), s->toChars());
else
error(i->loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
result = new ErrorInitializer();
return;
}
s = s->toAlias();
// Find out which field index it is
for (fieldi = 0; 1; fieldi++)
{
if (fieldi >= nfields)
{
error(i->loc, "%s.%s is not a per-instance initializable field",
sd->toChars(), s->toChars());
result = new ErrorInitializer();
return;
}
if (s == sd->fields[fieldi])
break;
}
}
else if (fieldi >= nfields)
{
error(i->loc, "too many initializers for %s", sd->toChars());
result = new ErrorInitializer();
return;
}
VarDeclaration *vd = sd->fields[fieldi];
if ((*elements)[fieldi])
{
error(i->loc, "duplicate initializer for field '%s'", vd->toChars());
errors = true;
continue;
}
for (size_t k = 0; k < nfields; k++)
{
VarDeclaration *v2 = sd->fields[k];
if (vd->isOverlappedWith(v2) && (*elements)[k])
{
error(i->loc, "overlapping initialization for field %s and %s",
v2->toChars(), vd->toChars());
errors = true;
continue;
}
}
assert(sc);
Initializer *iz = i->value[j];
iz = ::semantic(iz, sc, vd->type->addMod(t->mod), needInterpret);
Expression *ex = initializerToExpression(iz);
if (ex->op == TOKerror)
{
errors = true;
continue;
}
i->value[j] = iz;
(*elements)[fieldi] = doCopyOrMove(sc, ex);
++fieldi;
}
if (errors)
{
result = new ErrorInitializer();
return;
}
StructLiteralExp *sle = new StructLiteralExp(i->loc, sd, elements, t);
if (!sd->fill(i->loc, elements, false))
{
result = new ErrorInitializer();
return;
}
sle->type = t;
ExpInitializer *ie = new ExpInitializer(i->loc, sle);
result = ::semantic(ie, sc, t, needInterpret);
return;
}
else if ((t->ty == Tdelegate || (t->ty == Tpointer && t->nextOf()->ty == Tfunction)) && i->value.dim == 0)
{
TOK tok = (t->ty == Tdelegate) ? TOKdelegate : TOKfunction;
/* Rewrite as empty delegate literal { }
*/
Parameters *parameters = new Parameters;
Type *tf = new TypeFunction(parameters, NULL, 0, LINKd);
FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(i->loc, Loc(), tf, tok, NULL);
fd->fbody = new CompoundStatement(i->loc, new Statements());
fd->endloc = i->loc;
Expression *e = new FuncExp(i->loc, fd);
ExpInitializer *ie = new ExpInitializer(i->loc, e);
result = ::semantic(ie, sc, t, needInterpret);
return;
}
error(i->loc, "a struct is not a valid initializer for a %s", t->toChars());
result = new ErrorInitializer();
}
void visit(ArrayInitializer *i)
{
unsigned length;
const unsigned amax = 0x80000000;
bool errors = false;
//printf("ArrayInitializer::semantic(%s)\n", t->toChars());
if (i->sem) // if semantic() already run
{
result = i;
return;
}
i->sem = true;
t = t->toBasetype();
switch (t->ty)
{
case Tsarray:
case Tarray:
break;
case Tvector:
t = ((TypeVector *)t)->basetype;
break;
case Taarray:
case Tstruct: // consider implicit constructor call
{
Expression *e;
// note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
if (t->ty == Taarray || i->isAssociativeArray())
e = i->toAssocArrayLiteral();
else
e = initializerToExpression(i);
if (!e) // Bugzilla 13987
{
error(i->loc, "cannot use array to initialize %s", t->toChars());
goto Lerr;
}
ExpInitializer *ei = new ExpInitializer(e->loc, e);
result = ::semantic(ei, sc, t, needInterpret);
return;
}
case Tpointer:
if (t->nextOf()->ty != Tfunction)
break;
/* fall through */
default:
error(i->loc, "cannot use array to initialize %s", t->toChars());
goto Lerr;
}
i->type = t;
length = 0;
for (size_t j = 0; j < i->index.dim; j++)
{
Expression *idx = i->index[j];
if (idx)
{
sc = sc->startCTFE();
idx = ::semantic(idx, sc);
sc = sc->endCTFE();
idx = idx->ctfeInterpret();
i->index[j] = idx;
const uinteger_t idxvalue = idx->toInteger();
if (idxvalue >= amax)
{
error(i->loc, "array index %llu overflow", (ulonglong)idxvalue);
errors = true;
}
length = (unsigned)idx->toInteger();
if (idx->op == TOKerror)
errors = true;
}
Initializer *val = i->value[j];
ExpInitializer *ei = val->isExpInitializer();
if (ei && !idx)
ei->expandTuples = true;
val = ::semantic(val, sc, t->nextOf(), needInterpret);
if (val->isErrorInitializer())
errors = true;
ei = val->isExpInitializer();
// found a tuple, expand it
if (ei && ei->exp->op == TOKtuple)
{
TupleExp *te = (TupleExp *)ei->exp;
i->index.remove(j);
i->value.remove(j);
for (size_t k = 0; k < te->exps->dim; ++k)
{
Expression *e = (*te->exps)[k];
i->index.insert(j + k, (Expression *)NULL);
i->value.insert(j + k, new ExpInitializer(e->loc, e));
}
j--;
continue;
}
else
{
i->value[j] = val;
}
length++;
if (length == 0)
{
error(i->loc, "array dimension overflow");
goto Lerr;
}
if (length > i->dim)
i->dim = length;
}
if (t->ty == Tsarray)
{
uinteger_t edim = ((TypeSArray *)t)->dim->toInteger();
if (i->dim > edim)
{
error(i->loc, "array initializer has %u elements, but array length is %llu", i->dim, (ulonglong)edim);
goto Lerr;
}
}
if (errors)
goto Lerr;
else
{
d_uns64 sz = t->nextOf()->size();
bool overflow = false;
const d_uns64 max = mulu((d_uns64)i->dim, sz, overflow);
if (overflow || max > amax)
{
error(i->loc, "array dimension %llu exceeds max of %llu", (ulonglong)i->dim, (ulonglong)(amax / sz));
goto Lerr;
}
result = i;
return;
}
Lerr:
result = new ErrorInitializer();
}
void visit(ExpInitializer *i)
{
//printf("ExpInitializer::semantic(%s), type = %s\n", i->exp->toChars(), t->toChars());
if (needInterpret) sc = sc->startCTFE();
i->exp = ::semantic(i->exp, sc);
i->exp = resolveProperties(sc, i->exp);
if (needInterpret) sc = sc->endCTFE();
if (i->exp->op == TOKerror)
{
result = new ErrorInitializer();
return;
}
unsigned int olderrors = global.errors;
if (needInterpret)
{
// If the result will be implicitly cast, move the cast into CTFE
// to avoid premature truncation of polysemous types.
// eg real [] x = [1.1, 2.2]; should use real precision.
if (i->exp->implicitConvTo(t))
{
i->exp = i->exp->implicitCastTo(sc, t);
}
if (!global.gag && olderrors != global.errors)
{
result = i;
return;
}
i->exp = i->exp->ctfeInterpret();
}
else
{
i->exp = i->exp->optimize(WANTvalue);
}
if (!global.gag && olderrors != global.errors)
{
result = i; // Failed, suppress duplicate error messages
return;
}
if (i->exp->type->ty == Ttuple && ((TypeTuple *)i->exp->type)->arguments->dim == 0)
{
Type *et = i->exp->type;
i->exp = new TupleExp(i->exp->loc, new Expressions());
i->exp->type = et;
}
if (i->exp->op == TOKtype)
{
i->exp->error("initializer must be an expression, not '%s'", i->exp->toChars());
result = new ErrorInitializer();
return;
}
// Make sure all pointers are constants
if (needInterpret && hasNonConstPointers(i->exp))
{
i->exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", i->exp->toChars());
result = new ErrorInitializer();
return;
}
Type *tb = t->toBasetype();
Type *ti = i->exp->type->toBasetype();
if (i->exp->op == TOKtuple && i->expandTuples && !i->exp->implicitConvTo(t))
{
result = new ExpInitializer(i->loc, i->exp);
return;
}
/* Look for case of initializing a static array with a too-short
* string literal, such as:
* char[5] foo = "abc";
* Allow this by doing an explicit cast, which will lengthen the string
* literal.
*/
if (i->exp->op == TOKstring && tb->ty == Tsarray)
{
StringExp *se = (StringExp *)i->exp;
Type *typeb = se->type->toBasetype();
TY tynto = tb->nextOf()->ty;
if (!se->committed &&
(typeb->ty == Tarray || typeb->ty == Tsarray) &&
(tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
{
i->exp = se->castTo(sc, t);
goto L1;
}
}
// Look for implicit constructor call
if (tb->ty == Tstruct &&
!(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) &&
!i->exp->implicitConvTo(t))
{
StructDeclaration *sd = ((TypeStruct *)tb)->sym;
if (sd->ctor)
{
// Rewrite as S().ctor(exp)
Expression *e;
e = new StructLiteralExp(i->loc, sd, NULL);
e = new DotIdExp(i->loc, e, Id::ctor);
e = new CallExp(i->loc, e, i->exp);
e = ::semantic(e, sc);
if (needInterpret)
i->exp = e->ctfeInterpret();
else
i->exp = e->optimize(WANTvalue);
}
}
// Look for the case of statically initializing an array
// with a single member.
if (tb->ty == Tsarray &&
!tb->nextOf()->equals(ti->toBasetype()->nextOf()) &&
i->exp->implicitConvTo(tb->nextOf())
)
{
/* If the variable is not actually used in compile time, array creation is
* redundant. So delay it until invocation of toExpression() or toDt().
*/
t = tb->nextOf();
}
if (i->exp->implicitConvTo(t))
{
i->exp = i->exp->implicitCastTo(sc, t);
}
else
{
// Look for mismatch of compile-time known length to emit
// better diagnostic message, as same as AssignExp::semantic.
if (tb->ty == Tsarray &&
i->exp->implicitConvTo(tb->nextOf()->arrayOf()) > MATCHnomatch)
{
uinteger_t dim1 = ((TypeSArray *)tb)->dim->toInteger();
uinteger_t dim2 = dim1;
if (i->exp->op == TOKarrayliteral)
{
ArrayLiteralExp *ale = (ArrayLiteralExp *)i->exp;
dim2 = ale->elements ? ale->elements->dim : 0;
}
else if (i->exp->op == TOKslice)
{
Type *tx = toStaticArrayType((SliceExp *)i->exp);
if (tx)
dim2 = ((TypeSArray *)tx)->dim->toInteger();
}
if (dim1 != dim2)
{
i->exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
i->exp = new ErrorExp();
}
}
i->exp = i->exp->implicitCastTo(sc, t);
}
L1:
if (i->exp->op == TOKerror)
{
result = i;
return;
}
if (needInterpret)
i->exp = i->exp->ctfeInterpret();
else
i->exp = i->exp->optimize(WANTvalue);
//printf("-ExpInitializer::semantic(): "); i->exp->print();
result = i;
}
};
// Performs semantic analisys on Initializer AST nodes
Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret)
{
InitializerSemanticVisitor v = InitializerSemanticVisitor(sc, t, needInterpret);
init->accept(&v);
return v.result;
}
class InferTypeVisitor : public Visitor
{
public:
Initializer *result;
Scope *sc;
InferTypeVisitor(Scope *sc)
{
this->result = NULL;
this->sc = sc;
}
void visit(ErrorInitializer *i)
{
result = i;
}
void visit(VoidInitializer *i)
{
error(i->loc, "cannot infer type from void initializer");
result = new ErrorInitializer();
}
void visit(StructInitializer *i)
{
error(i->loc, "cannot infer type from struct initializer");
result = new ErrorInitializer();
}
void visit(ArrayInitializer *init)
{
//printf("ArrayInitializer::inferType() %s\n", init->toChars());
Expressions *keys = NULL;
Expressions *values;
if (init->isAssociativeArray())
{
keys = new Expressions();
keys->setDim(init->value.dim);
values = new Expressions();
values->setDim(init->value.dim);
for (size_t i = 0; i < init->value.dim; i++)
{
Expression *e = init->index[i];
if (!e)
goto Lno;
(*keys)[i] = e;
Initializer *iz = init->value[i];
if (!iz)
goto Lno;
iz = inferType(iz, sc);
if (iz->isErrorInitializer())
{
result = iz;
return;
}
assert(iz->isExpInitializer());
(*values)[i] = ((ExpInitializer *)iz)->exp;
assert((*values)[i]->op != TOKerror);
}
Expression *e = new AssocArrayLiteralExp(init->loc, keys, values);
ExpInitializer *ei = new ExpInitializer(init->loc, e);
result = inferType(ei, sc);
return;
}
else
{
Expressions *elements = new Expressions();
elements->setDim(init->value.dim);
elements->zero();
for (size_t i = 0; i < init->value.dim; i++)
{
assert(!init->index[i]); // already asserted by isAssociativeArray()
Initializer *iz = init->value[i];
if (!iz)
goto Lno;
iz = inferType(iz, sc);
if (iz->isErrorInitializer())
{
result = iz;
return;
}
assert(iz->isExpInitializer());
(*elements)[i] = ((ExpInitializer *)iz)->exp;
assert((*elements)[i]->op != TOKerror);
}
Expression *e = new ArrayLiteralExp(init->loc, NULL, elements);
ExpInitializer *ei = new ExpInitializer(init->loc, e);
result = inferType(ei, sc);
return;
}
Lno:
if (keys)
{
delete keys;
delete values;
error(init->loc, "not an associative array initializer");
}
else
{
error(init->loc, "cannot infer type from array initializer");
}
result = new ErrorInitializer();
}
void visit(ExpInitializer *init)
{
//printf("ExpInitializer::inferType() %s\n", init->toChars());
init->exp = ::semantic(init->exp, sc);
init->exp = resolveProperties(sc, init->exp);
if (init->exp->op == TOKscope)
{
ScopeExp *se = (ScopeExp *)init->exp;
TemplateInstance *ti = se->sds->isTemplateInstance();
if (ti && ti->semanticRun == PASSsemantic && !ti->aliasdecl)
se->error("cannot infer type from %s %s, possible circular dependency", se->sds->kind(), se->toChars());
else
se->error("cannot infer type from %s %s", se->sds->kind(), se->toChars());
result = new ErrorInitializer();
return;
}
// Give error for overloaded function addresses
bool hasOverloads = false;
if (FuncDeclaration *f = isFuncAddress(init->exp, &hasOverloads))
{
if (f->checkForwardRef(init->loc))
{
result = new ErrorInitializer();
return;
}
if (hasOverloads && !f->isUnique())
{
init->exp->error("cannot infer type from overloaded function symbol %s", init->exp->toChars());
result = new ErrorInitializer();
return;
}
}
if (init->exp->op == TOKaddress)
{
AddrExp *ae = (AddrExp *)init->exp;
if (ae->e1->op == TOKoverloadset)
{
init->exp->error("cannot infer type from overloaded function symbol %s", init->exp->toChars());
result = new ErrorInitializer();
return;
}
}
if (init->exp->op == TOKerror)
{
result = new ErrorInitializer();
return;
}
if (!init->exp->type)
{
result = new ErrorInitializer();
return;
}
result = init;
}
};
/* Translates to an expression to infer type.
* Returns ExpInitializer or ErrorInitializer.
*/
Initializer *inferType(Initializer *init, Scope *sc)
{
InferTypeVisitor v = InferTypeVisitor(sc);
init->accept(&v);
return v.result;
}
class InitToExpressionVisitor : public Visitor
{
public:
Expression *result;
Type *itype;
InitToExpressionVisitor(Type *itype)
{
this->result = NULL;
this->itype = itype;
}
void visit(ErrorInitializer *)
{
result = new ErrorExp();
}
void visit(VoidInitializer *)
{
result = NULL;
}
/***************************************
* This works by transforming a struct initializer into
* a struct literal. In the future, the two should be the
* same thing.
*/
void visit(StructInitializer *)
{
// cannot convert to an expression without target 'ad'
result = NULL;
}
/********************************
* If possible, convert array initializer to array literal.
* Otherwise return NULL.
*/
void visit(ArrayInitializer *init)
{
//printf("ArrayInitializer::toExpression(), dim = %d\n", init->dim);
//static int i; if (++i == 2) halt();
Expressions *elements;
unsigned edim;
const unsigned amax = 0x80000000;
Type *t = NULL;
if (init->type)
{
if (init->type == Type::terror)
{
result = new ErrorExp();
return;
}
t = init->type->toBasetype();
switch (t->ty)
{
case Tvector:
t = ((TypeVector *)t)->basetype;
/* fall through */
case Tsarray:
{
uinteger_t adim = ((TypeSArray *)t)->dim->toInteger();
if (adim >= amax)
goto Lno;
edim = (unsigned)adim;
break;
}
case Tpointer:
case Tarray:
edim = init->dim;
break;
default:
assert(0);
}
}
else
{
edim = (unsigned)init->value.dim;
for (size_t i = 0, j = 0; i < init->value.dim; i++, j++)
{
if (init->index[i])
{
if (init->index[i]->op == TOKint64)
{
const uinteger_t idxval = init->index[i]->toInteger();
if (idxval >= amax)
goto Lno;
j = (size_t)idxval;
}
else
goto Lno;
}
if (j >= edim)
edim = (unsigned)(j + 1);
}
}
elements = new Expressions();
elements->setDim(edim);
elements->zero();
for (size_t i = 0, j = 0; i < init->value.dim; i++, j++)
{
if (init->index[i])
j = (size_t)(init->index[i])->toInteger();
assert(j < edim);
Initializer *iz = init->value[i];
if (!iz)
goto Lno;
Expression *ex = initializerToExpression(iz);
if (!ex)
{
goto Lno;
}
(*elements)[j] = ex;
}
/* Fill in any missing elements with the default initializer
*/
{
Expression *_init = NULL;
for (size_t i = 0; i < edim; i++)
{
if (!(*elements)[i])
{
if (!init->type)
goto Lno;
if (!_init)
_init = ((TypeNext *)t)->next->defaultInit();
(*elements)[i] = _init;
}
}
/* Expand any static array initializers that are a single expression
* into an array of them
*/
if (t)
{
Type *tn = t->nextOf()->toBasetype();
if (tn->ty == Tsarray)
{
size_t dim = ((TypeSArray *)tn)->dim->toInteger();
Type *te = tn->nextOf()->toBasetype();
for (size_t i = 0; i < elements->dim; i++)
{
Expression *e = (*elements)[i];
if (te->equals(e->type))
{
Expressions *elements2 = new Expressions();
elements2->setDim(dim);
for (size_t j = 0; j < dim; j++)
(*elements2)[j] = e;
e = new ArrayLiteralExp(e->loc, tn, elements2);
(*elements)[i] = e;
}
}
}
}
/* If any elements are errors, then the whole thing is an error
*/
for (size_t i = 0; i < edim; i++)
{
Expression *e = (*elements)[i];
if (e->op == TOKerror)
{
result = e;
return;
}
}
Expression *e = new ArrayLiteralExp(init->loc, init->type, elements);
result = e;
return;
}
Lno:
result = NULL;
}
void visit(ExpInitializer *i)
{
if (itype)
{
//printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype->toChars(), i->exp->toChars());
Type *tb = itype->toBasetype();
Expression *e = (i->exp->op == TOKconstruct || i->exp->op == TOKblit) ? ((AssignExp *)i->exp)->e2 : i->exp;
if (tb->ty == Tsarray && e->implicitConvTo(tb->nextOf()))
{
TypeSArray *tsa = (TypeSArray *)tb;
size_t d = (size_t)tsa->dim->toInteger();
Expressions *elements = new Expressions();
elements->setDim(d);
for (size_t i = 0; i < d; i++)
(*elements)[i] = e;
ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, itype, elements);
result = ae;
return;
}
}
result = i->exp;
}
};
Expression *initializerToExpression(Initializer *i, Type *t)
{
InitToExpressionVisitor v = InitToExpressionVisitor(t);
i->accept(&v);
return v.result;
}