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
53 changes: 53 additions & 0 deletions changelog/AliasAssign.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Add Alias Assignment

This adds the ability for an alias declaration inside a template to be
assigned a new value. For example, the recursive template:

---
template staticMap(alias F, T...)
{
static if (T.length == 0)
alias staticMap = AliasSym!();
else
alias staticMap = AliasSym!(F!(T[0]), staticMap!(T[0 .. T.length]));
}
---

can now be reworked into an iterative template:

---
template staticMap(alias F, T...)
{
alias A = AliasSeq!();
static foreach (t; T)
A = AliasSeq!(A, F!t); // alias assignment here
alias staticMap = A;
}
---

Using the iterative approach will eliminate the combinatorial explosion of recursive
template instantiations, eliminating the associated high memory and runtime costs,
as well as eliminating the issues with limits on the nesting depth of templates.
It will eliminate the obtuse error messages generated when deep in recursion.

The grammar:

---
AliasAssign:
Identifier = Type;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is reassignment limited to types? What about aliases for other symbols?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because if this doesn't work, it isn't worth the effort to extend it.

---

is added to the expansion of DeclDef. The Identifier must resolve to a lexically
preceding AliasDeclaration:

---
alias Identifier = Type;
---

where the Identifier's match, and both are members of the same TemplateDeclaration.
Upon semantic processing, when the AliasAssign is encountered the Type in the
AliasAssign replaces the Type from the corresponding AliasDeclaration or any previous matching
AliasAssign.

The AliasAssign grammar was previously rejected by the parser, so adding it
should not break existing code.
31 changes: 31 additions & 0 deletions src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,11 @@ struct ASTBase
return null;
}

inout(AliasAssign) isAliasAssign() inout
{
return null;
}

inout(ClassDeclaration) isClassDeclaration() inout
{
return null;
Expand Down Expand Up @@ -520,12 +525,38 @@ struct ASTBase
}
}

extern (C++) final class AliasAssign : Dsymbol
{
Identifier ident;
Type type;

extern (D) this(const ref Loc loc, Identifier ident, Type type)
{
super(null);
this.loc = loc;
this.ident = ident;
this.type = type;
}

override inout(AliasAssign) isAliasAssign() inout
{
return this;
}

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

extern (C++) abstract class Declaration : Dsymbol
{
StorageClass storage_class;
Prot protection;
LINK linkage;
Type type;
short inuse;
ubyte adFlags;

final extern (D) this(Identifier id)
{
Expand Down
11 changes: 10 additions & 1 deletion src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,11 @@ extern (C++) abstract class Declaration : Dsymbol
StorageClass storage_class = STC.undefined_;
Prot protection;
LINK linkage = LINK.default_;
int inuse; // used to detect cycles
short inuse; // used to detect cycles

ubyte adFlags; // control re-assignment of AliasDeclaration (put here for packing reasons)
enum wasRead = 1; // set if AliasDeclaration was read
enum ignoreRead = 2; // ignore any reads of AliasDeclaration

// overridden symbol with pragma(mangle, "...")
const(char)[] mangleOverride;
Expand Down Expand Up @@ -869,6 +873,11 @@ extern (C++) final class AliasDeclaration : Declaration
// loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym.kind() : "", inuse);
assert(this != aliassym);
//static int count; if (++count == 10) *(char*)0=0;

// Reading the AliasDeclaration
if (!(adFlags & ignoreRead))
adFlags |= wasRead; // can never assign to this AliasDeclaration again

if (inuse == 1 && type && _scope)
{
inuse = 2;
Expand Down
3 changes: 2 additions & 1 deletion src/dmd/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ class Declaration : public Dsymbol
StorageClass storage_class;
Prot protection;
LINK linkage;
int inuse; // used to detect cycles
short inuse; // used to detect cycles
uint8_t adFlags;
DString mangleOverride; // overridden symbol with pragma(mangle, "...")

const char *kind() const;
Expand Down
3 changes: 3 additions & 0 deletions src/dmd/dscope.d
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ struct Scope
uint[void*] anchorCounts; /// lookup duplicate anchor name count
Identifier prevAnchor; /// qualified symbol name of last doc anchor

AliasDeclaration aliasAsg; /// if set, then aliasAsg is being assigned a new value,
/// do not set wasRead for it

extern (D) __gshared Scope* freelist;

extern (D) static Scope* alloc()
Expand Down
42 changes: 41 additions & 1 deletion src/dmd/dsymbol.d
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,7 @@ extern (C++) class Dsymbol : ASTNode
inout(Declaration) isDeclaration() inout { return null; }
inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; }
inout(ExpressionDsymbol) isExpressionDsymbol() inout { return null; }
inout(AliasAssign) isAliasAssign() inout { return null; }
inout(ThisDeclaration) isThisDeclaration() inout { return null; }
inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; }
inout(TupleDeclaration) isTupleDeclaration() inout { return null; }
Expand Down Expand Up @@ -2113,7 +2114,7 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
}

/**
* Class that holds an expression in a Dsymbol wraper.
* Class that holds an expression in a Dsymbol wrapper.
* This is not an AST node, but a class used to pass
* an expression as a function parameter of type Dsymbol.
*/
Expand All @@ -2132,6 +2133,45 @@ extern (C++) final class ExpressionDsymbol : Dsymbol
}
}

/**********************************************
* Encapsulate assigning to an alias:
* `identifier = type;`
* where `identifier` is an AliasDeclaration in scope.
*/
extern (C++) final class AliasAssign : Dsymbol
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see this being added to dsymbol.h

{
Identifier ident; /// Dsymbol's ident will be null, as this class is anonymous
Type type; /// replace previous RHS of AliasDeclaration with `type`

extern (D) this(const ref Loc loc, Identifier ident, Type type)
{
super(loc, null);
this.ident = ident;
this.type = type;
}

override Dsymbol syntaxCopy(Dsymbol s)
{
assert(!s);
AliasAssign aa = new AliasAssign(loc, ident, type.syntaxCopy());
return aa;
}

override inout(AliasAssign) isAliasAssign() inout
{
return this;
}

override const(char)* kind() const
{
return "aliasAssign";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"alias assignment"

}

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

/***********************************************************
* Table of Dsymbol's
Expand Down
2 changes: 2 additions & 0 deletions src/dmd/dsymbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class ArrayScopeSymbol;
class SymbolDeclaration;
class Expression;
class ExpressionDsymbol;
class AliasAssign;
class OverloadSet;
struct AA;
#ifdef IN_GCC
Expand Down Expand Up @@ -238,6 +239,7 @@ class Dsymbol : public ASTNode
virtual Declaration *isDeclaration() { return NULL; }
virtual StorageClassDeclaration *isStorageClassDeclaration(){ return NULL; }
virtual ExpressionDsymbol *isExpressionDsymbol() { return NULL; }
virtual AliasAssign *isAliasAssign() { return NULL; }
virtual ThisDeclaration *isThisDeclaration() { return NULL; }
virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; }
virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
Expand Down
Loading