Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions changelog/alias_from_trait.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Aliases can be created directly from a `__trait`.

Previously an `AliasSeq` was necessary in order to declare an alias based on a `__trait`.
Now the grammar allows to write shorter declarations:

---
struct Foo
{
int a;
}

alias oldWay = AliasSeq!(__traits(getMember, Foo, "a"))[0];
alias newWay = __traits(getMember, Foo, "a");
---

To permit this it was more interesting to include `__trait` in the basic types
instead of just changing the alias syntax, so as bonus,
a new way of declaring the variables exists:

---
struct Foo { static struct Bar {} }
const(__traits(getMember, Foo, "Bar")) fooBar;
static assert(is(typeof(fooBar) == const(Foo.Bar)));
---

Despite of being a type from the syntax point of view and when used specifically for an `alias`
the `getMember` trait can also represent symbols or even imports.
This does not change the alias semantic since for example the same distinction
was already done in case of an identifier chain.
18 changes: 18 additions & 0 deletions src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -4138,6 +4138,24 @@ struct ASTBase
}
}

extern (C++) class TypeTraits : Type
{
TraitsExp exp;
Loc loc;

extern (D) this(Loc loc, TraitsExp exp)
{
super(Tident);
this.loc = loc;
this.exp = exp;
}

override void accept(Visitor v)
{
v.visit(this);
}
}

extern (C++) final class TypeIdentifier : TypeQualified
{
Identifier ident;
Expand Down
1 change: 1 addition & 0 deletions src/dmd/dmangle.d
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ private immutable char[TMAX] mangleChar =
Tslice : '@',
Treturn : '@',
Tvector : '@',
Ttraits : '@',
];

unittest
Expand Down
15 changes: 15 additions & 0 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -5976,6 +5976,21 @@ Laftersemantic:
void aliasSemantic(AliasDeclaration ds, Scope* sc)
{
//printf("AliasDeclaration::semantic() %s\n", ds.toChars());
if (ds.type && ds.type.ty == Ttraits)
{
TypeTraits tt = cast(TypeTraits) ds.type;
if (auto t = typeSemantic(tt, tt.loc, sc))
{
ds.type = t;
}
else
{
if (tt.sym)
ds.aliassym = tt.sym;
// __trait(getMember) always returns alias-able stuff
// so at this point either we're good or traits sem has emitted an error
}
}
if (ds.aliassym)
{
auto fd = ds.aliassym.isFuncLiteralDeclaration();
Expand Down
6 changes: 6 additions & 0 deletions src/dmd/hdrgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,12 @@ public:
buf.writestring(t.dstring);
}

override void visit(TypeTraits t)
{
//printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
visit(t.exp);
}

override void visit(TypeVector t)
{
//printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod);
Expand Down
40 changes: 40 additions & 0 deletions src/dmd/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ enum ENUMTY : int
Tvector,
Tint128,
Tuns128,
TTraits,
TMAX,
}

Expand Down Expand Up @@ -332,6 +333,7 @@ alias Tnull = ENUMTY.Tnull;
alias Tvector = ENUMTY.Tvector;
alias Tint128 = ENUMTY.Tint128;
alias Tuns128 = ENUMTY.Tuns128;
alias Ttraits = ENUMTY.TTraits;
alias TMAX = ENUMTY.TMAX;

alias TY = ubyte;
Expand Down Expand Up @@ -472,6 +474,7 @@ extern (C++) abstract class Type : RootObject
sizeTy[Terror] = __traits(classInstanceSize, TypeError);
sizeTy[Tnull] = __traits(classInstanceSize, TypeNull);
sizeTy[Tvector] = __traits(classInstanceSize, TypeVector);
sizeTy[Ttraits] = __traits(classInstanceSize, TypeTraits);
return sizeTy;
}();

Expand Down Expand Up @@ -5017,6 +5020,43 @@ extern (C++) final class TypeDelegate : TypeNext
}
}

/**
* This is a shell containing a TraitsExp that can be
* either resolved to a type or to a symbol.
*
* The point is to allow AliasDeclarationY to use `__traits(getMember)`
* directly (VS using a library helper in the past).
*/
extern (C++) final class TypeTraits : Type
{
Loc loc;

/// The expression to resolve as type or symbol.
TraitsExp exp;
/// The symbol when exp doesn't represent a type.
Dsymbol sym;

final extern (D) this(Loc loc, TraitsExp exp)
{
super(Ttraits);
this.loc = loc;
this.exp = exp;
}

override Type syntaxCopy()
{
TraitsExp te = cast(TraitsExp) exp.syntaxCopy();
TypeTraits tt = new TypeTraits(loc, te);
tt.mod = mod;
return tt;
}

override void accept(Visitor v)
{
v.visit(this);
}
}

/***********************************************************
*/
extern (C++) abstract class TypeQualified : Type
Expand Down
12 changes: 12 additions & 0 deletions src/dmd/mtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ enum ENUMTY
Tvector,
Tint128,
Tuns128,
TTraits,
TMAX
};
typedef unsigned char TY; // ENUMTY
Expand Down Expand Up @@ -580,6 +581,17 @@ class TypeDelegate : public TypeNext
void accept(Visitor *v) { v->visit(this); }
};

class TypeTraits : public Type
{
Loc loc;
/// The expression to resolve as type or symbol.
TraitsExp *exp;
/// The symbol when exp doesn't represent a type.
Dsymbol *sym;
Type *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};

class TypeQualified : public Type
{
public:
Expand Down
44 changes: 43 additions & 1 deletion src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ final class Parser(AST) : Lexer
case TOK.union_:
case TOK.class_:
case TOK.interface_:
case TOK.traits:
Ldeclaration:
a = parseDeclarations(false, pAttrs, pAttrs.comment);
if (a && a.dim)
Expand Down Expand Up @@ -3719,6 +3720,27 @@ final class Parser(AST) : Lexer
t = parseVector();
break;

case TOK.traits:
{
AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp();
if (!te)
{
// error already emitted while parsing primary
t = new AST.TypeError;
}
else if (te.ident != Id.getMember)
{
// even if this is not a grammar error, it's not worth continuing.
error("invalid `__traits`, only `getMember` can give types and symbols");
t = new AST.TypeError;
}
else
{
t = new AST.TypeTraits(loc, te);
}
break;
}

case TOK.const_:
// const(type)
nextToken();
Expand Down Expand Up @@ -5394,6 +5416,7 @@ final class Parser(AST) : Lexer
case TOK.dot:
case TOK.typeof_:
case TOK.vector:
case TOK.traits:
/* https://issues.dlang.org/show_bug.cgi?id=15163
* If tokens can be handled as
* old C-style declaration or D expression, prefer the latter.
Expand Down Expand Up @@ -5442,7 +5465,6 @@ final class Parser(AST) : Lexer
case TOK.typeid_:
case TOK.is_:
case TOK.leftBracket:
case TOK.traits:
case TOK.file:
case TOK.fileFullPath:
case TOK.line:
Expand Down Expand Up @@ -6905,6 +6927,25 @@ final class Parser(AST) : Lexer
goto Lfalse;
goto L3;

case TOK.traits:
// __traits(getMember
t = peek(t);
if (t.value != TOK.leftParentheses)
goto Lfalse;
auto lp = t;
t = peek(t);
if (t.value != TOK.identifier || t.ident != Id.getMember)
goto Lfalse;
if (!skipParens(lp, &lp))
goto Lfalse;
// we are in a lookup for decl VS statement
// so we expect a declarator following __trait if it's a type.
// other usages wont be ambiguous (alias, template instance, type qual, etc.)
if (lp.value != TOK.identifier)
goto Lfalse;

break;

case TOK.const_:
case TOK.immutable_:
case TOK.shared_:
Expand Down Expand Up @@ -8303,6 +8344,7 @@ final class Parser(AST) : Lexer
case TOK.function_:
case TOK.delegate_:
case TOK.typeof_:
case TOK.traits:
case TOK.vector:
case TOK.file:
case TOK.fileFullPath:
Expand Down
1 change: 1 addition & 0 deletions src/dmd/parsetimevisitor.d
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ public:
void visit(AST.TypeStruct t) { visit(cast(AST.Type)t); }
void visit(AST.TypeNext t) { visit(cast(AST.Type)t); }
void visit(AST.TypeQualified t) { visit(cast(AST.Type)t); }
void visit(AST.TypeTraits t) { visit(cast(AST.Type)t); }

// TypeNext
void visit(AST.TypeReference t) { visit(cast(AST.TypeNext)t); }
Expand Down
1 change: 1 addition & 0 deletions src/dmd/strictvisitor.d
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ extern(C++) class StrictVisitor(AST) : ParseTimeVisitor!AST
override void visit(AST.TypeAArray) { assert(0); }
override void visit(AST.TypeSArray) { assert(0); }
override void visit(AST.TypeQualified) { assert(0); }
override void visit(AST.TypeTraits) { assert(0); }
override void visit(AST.TypeIdentifier) { assert(0); }
override void visit(AST.TypeReturn) { assert(0); }
override void visit(AST.TypeTypeof) { assert(0); }
Expand Down
5 changes: 5 additions & 0 deletions src/dmd/transitivevisitor.d
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,11 @@ package mixin template ParseVisitMethods(AST)
t.upr.accept(this);
}

override void visit(AST.TypeTraits t)
{
t.exp.accept(this);
}

// Miscellaneous
//========================================================

Expand Down
14 changes: 14 additions & 0 deletions src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,20 @@ private extern (C++) final class TypeSemanticVisitor : Visitor
result = t;
}

override void visit(TypeTraits mtype)
{
import dmd.traits : semanticTraits;

result = null;
if (Expression e = semanticTraits(mtype.exp, sc))
{
if (Dsymbol ds = getDsymbol(e))
mtype.sym = ds;
else if (Type t = getType(e))
result = t.addMod(mtype.mod);
}
}

override void visit(TypeReturn mtype)
{
//printf("TypeReturn::semantic() %s\n", toChars());
Expand Down
2 changes: 2 additions & 0 deletions src/dmd/visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class TypeClass;
class TypeTuple;
class TypeSlice;
class TypeNull;
class TypeTraits;

class Dsymbol;

Expand Down Expand Up @@ -427,6 +428,7 @@ class ParseTimeVisitor
virtual void visit(TypeStruct *t) { visit((Type *)t); }
virtual void visit(TypeNext *t) { visit((Type *)t); }
virtual void visit(TypeQualified *t) { visit((Type *)t); }
virtual void visit(TypeTraits *t) { visit((Type *)t); }

// TypeNext
virtual void visit(TypeReference *t) { visit((TypeNext *)t); }
Expand Down
9 changes: 9 additions & 0 deletions test/fail_compilation/e7804_1.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
TEST_OUTPUT:
---
fail_compilation/e7804_1.d(9): Error: invalid `__traits`, only `getMember` can give types and symbols
---
*/
module e7804_1;

__traits(farfelu, Aggr, "member") a;
Loading