diff --git a/changelog/new-aa.dd b/changelog/new-aa.dd new file mode 100644 index 000000000000..b48e9f12dfba --- /dev/null +++ b/changelog/new-aa.dd @@ -0,0 +1,16 @@ +`new` can now allocate an associative array + +This allows two associative array references to point to the same +associative array instance before any keys have been inserted. + +--- +int[string] a = new int[string]; +auto b = a; +... +a["seven"] = 7; +assert(b["seven"] == 7); +--- + +Note: Calling `new` is not needed before inserting keys on a null +associative array reference - the instance will be allocated if it +doesn't exist. diff --git a/compiler/src/dmd/e2ir.d b/compiler/src/dmd/e2ir.d index c81f12411e7c..30290413c8c4 100644 --- a/compiler/src/dmd/e2ir.d +++ b/compiler/src/dmd/e2ir.d @@ -1301,6 +1301,16 @@ elem* toElem(Expression e, IRState *irs) } e = el_combine(ezprefix, e); } + else if (auto taa = t.isTypeAArray()) + { + Symbol *s = aaGetSymbol(taa, "New", 0); + elem *ti = getTypeInfo(ne, t, irs); + // aaNew(ti) + elem *ep = el_params(ti, null); + e = el_bin(OPcall, TYnptr, el_var(s), ep); + elem_setLoc(e, ne.loc); + return e; + } else { ne.error("internal compiler error: cannot new type `%s`\n", t.toChars()); diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index b3633eba9d7d..ca97cd89f0a9 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -3463,8 +3463,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!exp.arguments && exp.newtype.isTypeSArray()) { auto ts = exp.newtype.isTypeSArray(); - edim = ts.dim; - exp.newtype = ts.next; + // check `new Value[Key]` + ts.dim = ts.dim.expressionSemantic(sc); + if (ts.dim.op == EXP.type) + { + exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type); + } + else + { + edim = ts.dim; + exp.newtype = ts.next; + } } ClassDeclaration cdthis = null; @@ -3518,18 +3527,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { return setError(); } - //https://issues.dlang.org/show_bug.cgi?id=20547 - //exp.arguments are the "parameters" to [], not to a real function - //so the errors that come from preFunctionParameters are misleading - if (originalNewtype.ty == Tsarray) - { - if (preFunctionParameters(sc, exp.arguments, false)) - { - exp.error("cannot create a `%s` with `new`", originalNewtype.toChars()); - return setError(); - } - } - else if (preFunctionParameters(sc, exp.arguments)) + if (preFunctionParameters(sc, exp.arguments)) { return setError(); } @@ -3885,6 +3883,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.type.pointerTo(); } + else if (tb.ty == Taarray) + { + // e.g. `new Alias(args)` + if (nargs) + { + exp.error("`new` cannot take arguments for an associative array"); + return setError(); + } + } else { exp.error("cannot create a `%s` with `new`", exp.type.toChars()); diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 4e3fd533c18e..7fa2d074131f 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -9312,13 +9312,10 @@ LagainStc: { AST.TypeAArray taa = cast(AST.TypeAArray)t; AST.Type index = taa.index; + // `new Type[expr]` is a static array auto edim = AST.typeToExpression(index); - if (!edim) - { - error("cannot create a `%s` with `new`", t.toChars); - return new AST.NullExp(loc); - } - t = new AST.TypeSArray(taa.next, edim); + if (edim) + t = new AST.TypeSArray(taa.next, edim); } else if (token.value == TOK.leftParenthesis && t.ty != Tsarray) { diff --git a/compiler/test/fail_compilation/fail20547.d b/compiler/test/fail_compilation/fail20547.d deleted file mode 100644 index c14977d0f124..000000000000 --- a/compiler/test/fail_compilation/fail20547.d +++ /dev/null @@ -1,15 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail20547.d(12): Error: cannot create a `string[string]` with `new` -fail_compilation/fail20547.d(14): Error: cannot create a `string[string]` with `new` ---- -*/ - -void main() -{ - //https://issues.dlang.org/show_bug.cgi?id=11790 - string[string] crash = new string[string]; - //https://issues.dlang.org/show_bug.cgi?id=20547 - int[string] c = new typeof(crash); -} diff --git a/compiler/test/fail_compilation/misc_parser_err_cov1.d b/compiler/test/fail_compilation/misc_parser_err_cov1.d index 22cf39241f88..b50a616ac974 100644 --- a/compiler/test/fail_compilation/misc_parser_err_cov1.d +++ b/compiler/test/fail_compilation/misc_parser_err_cov1.d @@ -10,7 +10,6 @@ fail_compilation/misc_parser_err_cov1.d(31): Error: expression expected, not `)` fail_compilation/misc_parser_err_cov1.d(32): Error: `type identifier : specialization` expected following `is` fail_compilation/misc_parser_err_cov1.d(33): Error: semicolon expected following auto declaration, not `auto` fail_compilation/misc_parser_err_cov1.d(33): Error: found `+` when expecting `(` following `mixin` -fail_compilation/misc_parser_err_cov1.d(34): Error: cannot create a `char[float]` with `new` fail_compilation/misc_parser_err_cov1.d(35): Error: `key:value` expected for associative array literal fail_compilation/misc_parser_err_cov1.d(36): Error: basic type expected, not `;` fail_compilation/misc_parser_err_cov1.d(36): Error: `{ members }` expected for anonymous class @@ -44,7 +43,7 @@ void main() auto tt = __traits(