From 85af04b5f02277ae8ae49b3a7d11ce20180ce5cd Mon Sep 17 00:00:00 2001 From: Don Clugston Date: Wed, 5 Oct 2011 11:03:11 +0200 Subject: [PATCH 1/3] 6769 [CTFE] AA.keys doesn't compile when -inline is used Undo the transformations which the inliner has done on the built-in AA properties. We really need to clean up the runtime, what it's doing is unnecessarily disgusting. A side-effect of the implementation is that casts from &int[7] to int[]* are now supported in CTFE. --- src/interpret.c | 76 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/src/interpret.c b/src/interpret.c index 41ace30132bd..37626a3511b9 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -1491,12 +1491,22 @@ Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) { // Check for unsupported type painting operations Type *elemtype = ((TypeArray *)(val->type))->next; + + // It's OK to cast from fixed length to dynamic array, eg &int[3] to int[]* + if (val->type->ty == Tsarray && pointee->ty == Tarray + && elemtype->size() == pointee->nextOf()->size()) + { + Expression *e = new AddrExp(loc, val); + e->type = type; + return e; + } if ( #if DMDV2 elemtype->castMod(0) != pointee->castMod(0) #else elemtype != pointee #endif + // It's OK to cast from int[] to uint* && !(elemtype->isintegral() && pointee->isintegral() && elemtype->size() == pointee->size())) { @@ -5215,7 +5225,7 @@ Expression *interpret_length(InterState *istate, Expression *earg) #if DMDV2 -Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration *fd) +Expression *interpret_keys(InterState *istate, Expression *earg, Type *elemType) { #if LOG printf("interpret_keys()\n"); @@ -5230,14 +5240,11 @@ Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration assert(earg->op == TOKassocarrayliteral); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); - assert(fd->type->ty == Tfunction); - assert(fd->type->nextOf()->ty == Tarray); - Type *elemType = ((TypeFunction *)fd->type)->nextOf()->nextOf(); e->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim)); return copyLiteral(e); } -Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd) +Expression *interpret_values(InterState *istate, Expression *earg, Type *elemType) { #if LOG printf("interpret_values()\n"); @@ -5252,9 +5259,6 @@ Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclarati assert(earg->op == TOKassocarrayliteral); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->values); - assert(fd->type->ty == Tfunction); - assert(fd->type->nextOf()->ty == Tarray); - Type *elemType = ((TypeFunction *)fd->type)->nextOf()->nextOf(); e->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim)); //printf("result is %s\n", e->toChars()); return copyLiteral(e); @@ -5276,8 +5280,31 @@ bool isAssocArray(Type *t) return true; return false; } + +// Given a template AA type, extract the corresponding built-in AA type +TypeAArray *toBuiltinAAType(Type *t) +{ + t = t->toBasetype(); + if (t->ty == Taarray) + return (TypeAArray *)t; + assert(t->ty == Tstruct); + StructDeclaration *sym = ((TypeStruct *)t)->sym; + assert(sym->ident == Id::AssociativeArray); + TemplateInstance *tinst = sym->parent->isTemplateInstance(); + assert(tinst); + return new TypeAArray((Type *)(tinst->tiargs->tdata()[1]), (Type *)(tinst->tiargs->tdata()[0])); +} #endif +// Helper function: given a function of type A[] f(...), +// return A. +Type *returnedArrayElementType(FuncDeclaration *fd) +{ + assert(fd->type->ty == Tfunction); + assert(fd->type->nextOf()->ty == Tarray); + return ((TypeFunction *)fd->type)->nextOf()->nextOf(); +} + /* Decoding UTF strings for foreach loops. Duplicates the functionality of * the twelve _aApplyXXn functions in aApply.d in the runtime. */ @@ -5539,9 +5566,9 @@ bool evaluateIfBuiltin(Expression **result, InterState *istate, if (fd->ident == Id::length) e = interpret_length(istate, pthis); else if (fd->ident == Id::keys) - e = interpret_keys(istate, pthis, fd); + e = interpret_keys(istate, pthis, returnedArrayElementType(fd)); else if (fd->ident == Id::values) - e = interpret_values(istate, pthis, fd); + e = interpret_values(istate, pthis, returnedArrayElementType(fd)); else if (fd->ident == Id::rehash) e = pthis; // rehash is a no-op } @@ -5567,6 +5594,35 @@ bool evaluateIfBuiltin(Expression **result, InterState *istate, e = EXP_CANT_INTERPRET; } } + /* Horrid hack to retrieve the builtin AA functions after they've been + * mashed by the inliner. + */ + if (!pthis) + { + Expression *firstarg = nargs > 0 ? (Expression *)(arguments->data[0]) : NULL; + // Check for the first parameter being a templatized AA. Hack: we assume that + // template AA.var is always the AA data itself. + Expression *firstdotvar = (firstarg && firstarg->op == TOKdotvar) + ? ((DotVarExp *)firstarg)->e1 : NULL; + if (firstdotvar && isAssocArray(firstdotvar->type)) + { if (fd->ident == Id::aaLen && nargs == 1) + e = interpret_length(istate, firstdotvar->interpret(istate)); + else if (fd->ident == Id::aaKeys && nargs == 2) + { + Expression *trueAA = firstdotvar->interpret(istate); + e = interpret_keys(istate, trueAA, toBuiltinAAType(trueAA->type)->index); + } + else if (fd->ident == Id::aaValues && nargs == 3) + { + Expression *trueAA = firstdotvar->interpret(istate); + e = interpret_values(istate, trueAA, toBuiltinAAType(trueAA->type)->nextOf()); + } + else if (fd->ident == Id::aaRehash && nargs == 2) + { + return firstdotvar->interpret(istate, ctfeNeedLvalue); + } + } + } #endif #if DMDV1 if (!pthis) From 2d71927e0cfb7e46232f227d825135c2d576d315 Mon Sep 17 00:00:00 2001 From: Don Clugston Date: Wed, 5 Oct 2011 11:16:39 +0200 Subject: [PATCH 2/3] Test case for 6769 --- test/compilable/interpret3.d | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/compilable/interpret3.d b/test/compilable/interpret3.d index 3515455ec720..5eb02fa70f9e 100644 --- a/test/compilable/interpret3.d +++ b/test/compilable/interpret3.d @@ -2599,6 +2599,7 @@ static assert({ assert(s.aa[7][56] == 57); bug6751c(s.aa); assert(s.aa.keys.length==1); + assert(s.aa.values.length==1); return true; }()); @@ -2623,3 +2624,13 @@ static assert({ int[int] w; return w.length; }()==0); + +/************************************************** + 6769 AA.keys, AA.values with -inline +**************************************************/ + +static assert({ + double[char[3]] w = ["abc" : 2.3]; + double[] z = w.values; + return w.keys.length; +}() == 1); From 13431d21af92f622839e958caa7e3eb80f14fa1b Mon Sep 17 00:00:00 2001 From: Don Clugston Date: Wed, 5 Oct 2011 11:41:27 +0200 Subject: [PATCH 3/3] CTFE: Combine D1 and D2 treatment of AAs A couple of minor changes is enough to make the code identical, allowing two functions to be completely removed. Also fixes a D1 bug in the type of .values and .keys. --- src/interpret.c | 75 +++++++++---------------------------------------- 1 file changed, 13 insertions(+), 62 deletions(-) diff --git a/src/interpret.c b/src/interpret.c index 37626a3511b9..69f3888f7699 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -5160,55 +5160,6 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) /******************************* Special Functions ***************************/ -#if DMDV1 - -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) -{ -#if LOG - printf("interpret_aaKeys()\n"); -#endif - if (!arguments || arguments->dim != 2) - return NULL; - Expression *earg = arguments->tdata()[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op == TOKnull) - return new NullExp(earg->loc); - if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); - Type *elemType = ((TypeAArray *)aae->type)->index; - e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); - return copyLiteral(e); -} - -Expression *interpret_aaValues(InterState *istate, Expressions *arguments) -{ -#if LOG - printf("interpret_aaValues()\n"); -#endif - if (!arguments || arguments->dim != 3) - return NULL; - Expression *earg = arguments->tdata()[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op == TOKnull) - return new NullExp(earg->loc); - if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->values); - Type *elemType = ((TypeAArray *)aae->type)->next; - e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); - //printf("result is %s\n", e->toChars()); - return copyLiteral(e); -} - -#endif - Expression *interpret_length(InterState *istate, Expression *earg) { //printf("interpret_length()\n"); @@ -5223,8 +5174,6 @@ Expression *interpret_length(InterState *istate, Expression *earg) return e; } -#if DMDV2 - Expression *interpret_keys(InterState *istate, Expression *earg, Type *elemType) { #if LOG @@ -5264,8 +5213,6 @@ Expression *interpret_values(InterState *istate, Expression *earg, Type *elemTyp return copyLiteral(e); } -#endif - #if DMDV2 // Return true if t is an AA, or AssociativeArray!(key, value) bool isAssocArray(Type *t) @@ -5628,15 +5575,19 @@ bool evaluateIfBuiltin(Expression **result, InterState *istate, if (!pthis) { Expression *firstarg = nargs > 0 ? (Expression *)(arguments->data[0]) : NULL; - if (fd->ident == Id::aaLen && nargs == 1 && firstarg->type->toBasetype()->ty == Taarray) - e = interpret_length(istate, firstarg); - else if (fd->ident == Id::aaKeys) - e = interpret_aaKeys(istate, arguments); - else if (fd->ident == Id::aaValues) - e = interpret_aaValues(istate, arguments); - else if (fd->ident == Id::aaRehash && nargs == 2) - { // rehash is a no-op - return firstarg->interpret(istate, ctfeNeedLvalue); + if (firstarg && firstarg->type->toBasetype()->ty == Taarray) + { + TypeAArray *firstAAtype = (TypeAArray *)firstarg->type; + if (fd->ident == Id::aaLen && nargs == 1) + e = interpret_length(istate, firstarg); + else if (fd->ident == Id::aaKeys) + e = interpret_keys(istate, firstarg, firstAAtype->index); + else if (fd->ident == Id::aaValues) + e = interpret_values(istate, firstarg, firstAAtype->nextOf()); + else if (fd->ident == Id::aaRehash && nargs == 2) + { // rehash is a no-op + return firstarg->interpret(istate, ctfeNeedLvalue); + } } } #endif