Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { size_t length; const unsigned amax = 0x80000000; bool errors = false; //printf("ArrayInitializer::semantic(%s)\n", t->toChars()); if (sem) // if semantic() already run return this; sem = 1; type = t; Initializer *aa = NULL; t = t->toBasetype(); switch (t->ty) { case Tpointer: case Tsarray: case Tarray: break; case Tvector: t = ((TypeVector *)t)->basetype; break; case Taarray: // was actually an associative array literal aa = new ExpInitializer(loc, toAssocArrayLiteral()); return aa->semantic(sc, t, needInterpret); default: error(loc, "cannot use array to initialize %s", type->toChars()); goto Lerr; } length = 0; for (size_t i = 0; i < index.dim; i++) { Expression *idx = index[i]; if (idx) { idx = idx->ctfeSemantic(sc); idx = idx->ctfeInterpret(); index[i] = idx; length = idx->toInteger(); if (idx->op == TOKerror) errors = true; } Initializer *val = value[i]; ExpInitializer *ei = val->isExpInitializer(); if (ei && !idx) ei->expandTuples = 1; val = val->semantic(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; index.remove(i); value.remove(i); for (size_t j = 0; j < te->exps->dim; ++j) { Expression *e = (*te->exps)[j]; index.insert(i + j, (Expression *)NULL); value.insert(i + j, new ExpInitializer(e->loc, e)); } i--; continue; } else { value[i] = val; } length++; if (length == 0) { error(loc, "array dimension overflow"); goto Lerr; } if (length > dim) dim = length; } if (t->ty == Tsarray) { dinteger_t edim = ((TypeSArray *)t)->dim->toInteger(); if (dim > edim) { error(loc, "array initializer has %u elements, but array length is %lld", dim, edim); goto Lerr; } } if (errors) goto Lerr; if ((uinteger_t) dim * t->nextOf()->size() >= amax) { error(loc, "array dimension %u exceeds max of %u", (unsigned) dim, (unsigned)(amax / t->nextOf()->size())); goto Lerr; } return this; Lerr: return new ErrorInitializer(); }
Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { int errors = 0; //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); vars.setDim(field.dim); t = t->toBasetype(); if (t->ty == Tsarray && t->nextOf()->toBasetype()->ty == Tstruct) t = t->nextOf()->toBasetype(); if (t->ty == Tstruct) { size_t fieldi = 0; TypeStruct *ts = (TypeStruct *)t; ad = ts->sym; if (ad->ctor) error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead", ad->kind(), ad->toChars(), ad->toChars()); StructDeclaration *sd = ad->isStructDeclaration(); assert(sd); sd->size(loc); if (sd->sizeok != SIZEOKdone) { error(loc, "struct %s is forward referenced", sd->toChars()); errors = 1; goto Lerror; } size_t nfields = sd->fields.dim - sd->isNested(); for (size_t i = 0; i < field.dim; i++) { Identifier *id = field[i]; Initializer *val = value[i]; Dsymbol *s; VarDeclaration *v; if (id == NULL) { if (fieldi >= nfields) { error(loc, "too many initializers for %s", ad->toChars()); errors = 1; field.remove(i); i--; continue; } else { s = ad->fields[fieldi]; } } else { //s = ad->symtab->lookup(id); s = ad->search(loc, id, 0); if (!s) { s = ad->search_correct(id); if (s) error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", id->toChars(), t->toChars(), s->kind(), s->toChars()); else error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); errors = 1; continue; } s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { error(loc, "%s.%s is not a per-instance initializable field", t->toChars(), s->toChars()); errors = 1; break; } if (s == ad->fields[fieldi]) break; } } if (s && (v = s->isVarDeclaration()) != NULL) { val = val->semantic(sc, v->type->addMod(t->mod), needInterpret); value[i] = val; vars[i] = v; if (val->isErrorInitializer()) errors = 1; } else { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); errors = 1; } fieldi++; } } else if (t->ty == Tdelegate && value.dim == 0) { /* Rewrite as empty delegate literal { } */ Parameters *arguments = new Parameters; Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, TOKdelegate, NULL); fd->fbody = new CompoundStatement(loc, new Statements()); fd->endloc = loc; Expression *e = new FuncExp(loc, fd); ExpInitializer *ie = new ExpInitializer(loc, e); return ie->semantic(sc, t, needInterpret); } else { error(loc, "a struct is not a valid initializer for a %s", t->toChars()); errors = 1; } Lerror: if (errors) { return new ErrorInitializer(); } return this; }
Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { size_t length; const unsigned amax = 0x80000000; bool errors = false; //printf("ArrayInitializer::semantic(%s)\n", t->toChars()); if (sem) // if semantic() already run return this; 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 || isAssociativeArray()) e = toAssocArrayLiteral(); else e = toExpression(); if (!e) // Bugzilla 13987 { error(loc, "cannot use array to initialize %s", t->toChars()); goto Lerr; } ExpInitializer *ei = new ExpInitializer(e->loc, e); return ei->semantic(sc, t, needInterpret); } case Tpointer: if (t->nextOf()->ty != Tfunction) break; default: error(loc, "cannot use array to initialize %s", t->toChars()); goto Lerr; } type = t; length = 0; for (size_t i = 0; i < index.dim; i++) { Expression *idx = index[i]; if (idx) { sc = sc->startCTFE(); idx = idx->semantic(sc); sc = sc->endCTFE(); idx = idx->ctfeInterpret(); index[i] = idx; length = (size_t)idx->toInteger(); if (idx->op == TOKerror) errors = true; } Initializer *val = value[i]; ExpInitializer *ei = val->isExpInitializer(); if (ei && !idx) ei->expandTuples = true; val = val->semantic(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; index.remove(i); value.remove(i); for (size_t j = 0; j < te->exps->dim; ++j) { Expression *e = (*te->exps)[j]; index.insert(i + j, (Expression *)NULL); value.insert(i + j, new ExpInitializer(e->loc, e)); } i--; continue; } else { value[i] = val; } length++; if (length == 0) { error(loc, "array dimension overflow"); goto Lerr; } if (length > dim) dim = length; } if (t->ty == Tsarray) { dinteger_t edim = ((TypeSArray *)t)->dim->toInteger(); if (dim > edim) { error(loc, "array initializer has %u elements, but array length is %lld", dim, edim); goto Lerr; } } if (errors) goto Lerr; if ((uinteger_t) dim * t->nextOf()->size() >= amax) { error(loc, "array dimension %u exceeds max of %u", (unsigned) dim, (unsigned)(amax / t->nextOf()->size())); goto Lerr; } return this; Lerr: return new ErrorInitializer(); }
Initializer *ArrayInitializer::inferType(Scope *sc) { //printf("ArrayInitializer::inferType() %s\n", toChars()); Expressions *keys = NULL; Expressions *values; if (isAssociativeArray()) { keys = new Expressions(); keys->setDim(value.dim); values = new Expressions(); values->setDim(value.dim); for (size_t i = 0; i < value.dim; i++) { Expression *e = index[i]; if (!e) goto Lno; (*keys)[i] = e; Initializer *iz = value[i]; if (!iz) goto Lno; iz = iz->inferType(sc); if (iz->isErrorInitializer()) return iz; assert(iz->isExpInitializer()); (*values)[i] = ((ExpInitializer *)iz)->exp; assert((*values)[i]->op != TOKerror); } Expression *e = new AssocArrayLiteralExp(loc, keys, values); ExpInitializer *ei = new ExpInitializer(loc, e); return ei->inferType(sc); } else { Expressions *elements = new Expressions(); elements->setDim(value.dim); elements->zero(); for (size_t i = 0; i < value.dim; i++) { assert(!index[i]); // already asserted by isAssociativeArray() Initializer *iz = value[i]; if (!iz) goto Lno; iz = iz->inferType(sc); if (iz->isErrorInitializer()) return iz; assert(iz->isExpInitializer()); (*elements)[i] = ((ExpInitializer *)iz)->exp; assert((*elements)[i]->op != TOKerror); } Expression *e = new ArrayLiteralExp(loc, elements); ExpInitializer *ei = new ExpInitializer(loc, e); return ei->inferType(sc); } Lno: if (keys) { delete keys; delete values; error(loc, "not an associative array initializer"); } else { error(loc, "cannot infer type from array initializer"); } return new ErrorInitializer(); }
Initializer *ArrayInitializer::inferType(Scope *sc, Type *tx) { //printf("ArrayInitializer::inferType() %s\n", toChars()); Expressions *keys = NULL; Expressions *values; if (tx ? (tx->ty == Taarray || tx->ty != Tarray && tx->ty != Tsarray && isAssociativeArray()) : isAssociativeArray()) { Type *tidx = NULL; Type *tval = NULL; if (tx && tx->ty == Taarray) { tidx = ((TypeAArray *)tx)->index; tval = ((TypeAArray *)tx)->next; } keys = new Expressions(); keys->setDim(value.dim); values = new Expressions(); values->setDim(value.dim); for (size_t i = 0; i < value.dim; i++) { Expression *e = index[i]; if (!e) goto Lno; if (tidx) { e = ::inferType(e, tidx); e = e->semantic(sc); e = resolveProperties(sc, e); if (tidx->deco) // tidx may be partial type e = e->implicitCastTo(sc, tidx); } (*keys)[i] = e; Initializer *iz = value[i]; if (!iz) goto Lno; iz = iz->inferType(sc, tval); if (iz->isErrorInitializer()) return iz; assert(iz->isExpInitializer()); (*values)[i] = ((ExpInitializer *)iz)->exp; assert((*values)[i]->op != TOKerror); } Expression *e = new AssocArrayLiteralExp(loc, keys, values); ExpInitializer *ei = new ExpInitializer(loc, e); return ei->inferType(sc, tx); } else { Type *tn = NULL; if (tx && (tx->ty == Tarray || tx->ty == Tsarray)) tn = ((TypeNext *)tx)->next; Expressions *elements = new Expressions(); elements->setDim(value.dim); elements->zero(); for (size_t i = 0; i < value.dim; i++) { assert(!index[i]); // already asserted by isAssociativeArray() Initializer *iz = value[i]; if (!iz) goto Lno; iz = iz->inferType(sc, tn); if (iz->isErrorInitializer()) return iz; assert(iz->isExpInitializer()); (*elements)[i] = ((ExpInitializer *)iz)->exp; assert((*elements)[i]->op != TOKerror); } Expression *e = new ArrayLiteralExp(loc, elements); ExpInitializer *ei = new ExpInitializer(loc, e); return ei->inferType(sc, tx); } Lno: if (keys) { delete keys; delete values; error(loc, "not an associative array initializer"); } else { error(loc, "cannot infer type from array initializer"); } return new ErrorInitializer(); }