diff --git a/compiler/src/dmd/astbase.d b/compiler/src/dmd/astbase.d index 9a2567ceb71f..e261e79ca0ca 100644 --- a/compiler/src/dmd/astbase.d +++ b/compiler/src/dmd/astbase.d @@ -4324,15 +4324,13 @@ struct ASTBase } } - extern (C++) class TypeTraits : Type + extern (C++) class TypeTraits : TypeQualified { TraitsExp exp; - Loc loc; extern (D) this(Loc loc, TraitsExp exp) { - super(Tident); - this.loc = loc; + super(Ttraits, loc); this.exp = exp; } @@ -4345,21 +4343,20 @@ struct ASTBase { TraitsExp te = exp.syntaxCopy(); TypeTraits tt = new TypeTraits(loc, te); + tt.syntaxCopyHelper(this); tt.mod = mod; return tt; } } - extern (C++) final class TypeMixin : Type + extern (C++) final class TypeMixin : TypeQualified { - Loc loc; Expressions* exps; RootObject obj; extern (D) this(Loc loc, Expressions* exps) { - super(Tmixin); - this.loc = loc; + super(Tmixin, loc); this.exps = exps; } @@ -4379,7 +4376,10 @@ struct ASTBase return a; } - return new TypeMixin(loc, arraySyntaxCopy(exps)); + auto tm = new TypeMixin(loc, arraySyntaxCopy(exps)); + tm.syntaxCopyHelper(this); + tm.mod = mod; + return tm; } override void accept(Visitor v) diff --git a/compiler/src/dmd/mtype.d b/compiler/src/dmd/mtype.d index 3dc6871abf80..408cc1138eff 100644 --- a/compiler/src/dmd/mtype.d +++ b/compiler/src/dmd/mtype.d @@ -1535,18 +1535,16 @@ extern (C++) final class TypeDelegate : TypeNext * * The point is to allow AliasDeclarationY to use `__traits()`, see $(LINK https://issues.dlang.org/show_bug.cgi?id=7804). */ -extern (C++) final class TypeTraits : Type +extern (C++) final class TypeTraits : TypeQualified { - Loc loc; /// The expression to resolve as type or symbol. TraitsExp exp; /// Cached type/symbol after semantic analysis. RootObject obj; - final extern (D) this(Loc loc, TraitsExp exp) @safe + final extern (D) this(Loc loc, TraitsExp exp) nothrow @safe { - super(Ttraits); - this.loc = loc; + super(Ttraits, loc); this.exp = exp; } @@ -1559,6 +1557,7 @@ extern (C++) final class TypeTraits : Type { TraitsExp te = exp.syntaxCopy(); TypeTraits tt = new TypeTraits(loc, te); + tt.syntaxCopyHelper(this); tt.mod = mod; return tt; } @@ -1574,16 +1573,14 @@ extern (C++) final class TypeTraits : Type * * Semantic analysis will convert it to a real type. */ -extern (C++) final class TypeMixin : Type +extern (C++) final class TypeMixin : TypeQualified { - Loc loc; Expressions* exps; RootObject obj; // cached result of semantic analysis. - extern (D) this(Loc loc, Expressions* exps) @safe + extern (D) this(Loc loc, Expressions* exps) nothrow @safe { - super(Tmixin); - this.loc = loc; + super(Tmixin, loc); this.exps = exps; } @@ -1594,7 +1591,10 @@ extern (C++) final class TypeMixin : Type override TypeMixin syntaxCopy() { - return new TypeMixin(loc, Expression.arraySyntaxCopy(exps)); + auto tm = new TypeMixin(loc, Expression.arraySyntaxCopy(exps)); + tm.syntaxCopyHelper(this); + tm.mod = mod; + return tm; } override void accept(Visitor v) @@ -1613,7 +1613,7 @@ extern (C++) abstract class TypeQualified : Type // representing ident.ident!tiargs.ident. ... etc. Objects idents; - final extern (D) this(TY ty, Loc loc) + final extern (D) this(TY ty, Loc loc) @safe nothrow { super(ty); this.loc = loc; diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 704c662526a0..604af4080012 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -1817,6 +1817,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * mixin Foo!(args); * mixin a.b.c!(args).Foo!(args); * mixin typeof(expr).identifier!(args); + * mixin typeof(expr)[index]; + * mixin mixin(...); + * mixin __traits(...); * mixin Foo!(args) identifier; * mixin identifier = Foo!(args); */ @@ -1849,8 +1852,61 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.typeof_) { tqual = parseTypeof(); + while (token.value == TOK.leftBracket) + { + nextToken(); + tqual.addIndex(parseAssignExp()); + check(TOK.rightBracket); + } check(TOK.dot); } + else if (token.value == TOK.mixin_) + { + loc = token.loc; + nextToken(); + if (token.value != TOK.leftParenthesis) + error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); + auto exps = parseArguments(); + tqual = new AST.TypeMixin(loc, exps); + while (token.value == TOK.leftBracket) + { + nextToken(); + tqual.addIndex(parseAssignExp()); + check(TOK.rightBracket); + } + if (token.value == TOK.dot) + nextToken(); + else + goto Lmixin; + } + else if (token.value == TOK.traits) + { + if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp()) + { + if (te.ident) + { + tqual = new AST.TypeTraits(token.loc, te); + while (token.value == TOK.leftBracket) + { + nextToken(); + tqual.addIndex(parseAssignExp()); + check(TOK.rightBracket); + } + if (token.value == TOK.dot) + nextToken(); + else + goto Lmixin; + } + } + if (!tqual) + { + error("traits expected"); + id = Id.empty; + nextToken(); + goto Lmixin; + } + } + if (token.value != TOK.identifier) { error("identifier expected, not `%s`", token.toChars()); @@ -1861,6 +1917,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); } + Lmixin: while (1) { tiargs = null; @@ -1878,7 +1935,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer tqual.addInst(tempinst); tiargs = null; } - else + else if (id) { if (!tqual) tqual = new AST.TypeIdentifier(loc, id); @@ -1886,6 +1943,18 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer tqual.addIdent(id); } + while (token.value == TOK.leftBracket) + { + nextToken(); + if (!tqual) + { + error("identifier expected before `[`"); + tqual = new AST.TypeIdentifier(loc, Id.empty); + } + tqual.addIndex(parseAssignExp()); + check(TOK.rightBracket); + } + if (token.value != TOK.dot) break; diff --git a/compiler/test/compilable/test21356.d b/compiler/test/compilable/test21356.d new file mode 100644 index 000000000000..b6fe72359905 --- /dev/null +++ b/compiler/test/compilable/test21356.d @@ -0,0 +1,15 @@ +struct A +{ + mixin template Foo() {} +} + +alias AliasSeq(A...) = A; + +alias thing = AliasSeq!(A); + +mixin thing[0].Foo; +mixin typeof(thing)[0].Foo; + +mixin template M() {} +mixin mixin("M"); +mixin __traits(getMember, A, "Foo");