74 changes: 73 additions & 1 deletion src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import dmd.aggregate;
import dmd.aliasthis;
import dmd.arrayop;
import dmd.arraytypes;
import dmd.astcodegen;
import dmd.complex;
import dmd.dcast;
import dmd.dclass;
Expand Down Expand Up @@ -48,6 +49,7 @@ import dmd.visitor;
import dmd.mtype;
import dmd.objc;
import dmd.opover;
import dmd.parse;
import dmd.root.ctfloat;
import dmd.root.rmem;
import dmd.root.outbuffer;
Expand Down Expand Up @@ -1586,7 +1588,7 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc)
Type t;
Expression e;
Dsymbol s;
//printf("TypeIdentifier::semantic(%s)\n", toChars());
//printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
mtype.resolve(loc, sc, &e, &t, &s);
if (t)
{
Expand Down Expand Up @@ -1880,6 +1882,16 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc)
return t.typeSemantic(loc, sc);
}

Type visitMixin(TypeMixin mtype)
{
//printf("TypeMixin::semantic() %s\n", toChars());
Type t = mtype.compileTypeMixin(loc, sc);
if (!t)
return error();

return t.typeSemantic(loc, sc);
}

switch (t.ty)
{
default: return visitType(t);
Expand All @@ -1901,9 +1913,50 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc)
case Tclass: return visitClass(cast(TypeClass)t);
case Ttuple: return visitTuple (cast(TypeTuple)t);
case Tslice: return visitSlice(cast(TypeSlice)t);
case Tmixin: return visitMixin(cast(TypeMixin)t);
}
}

/******************************************
* Compile the MixinType, returning the type AST.
*
* Doesn't run semantic() on the returned type.
* Params:
* tm = mixin to compile as a type
* loc = location for error messages
* sc = context
* Return:
* null if error, else type AST as parsed
*/
Type compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
{
OutBuffer buf;
if (expressionsToString(buf, sc, tm.exps))
return null;

const errors = global.errors;
const len = buf.offset;
const str = buf.extractChars()[0 .. len];
scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated);
scope p = new Parser!ASTCodegen(loc, sc._module, str, false, diagnosticReporter);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);

Type t = p.parseType();
if (p.errors)
{
assert(global.errors != errors); // should have caught all these cases
return null;
}
if (p.token.value != TOK.endOfFile)
{
.error(loc, "incomplete mixin type `%s`", str.ptr);
return null;
}
return t;
}


/************************************
* If an identical type to `type` is in `type.stringtable`, return
* the latter one. Otherwise, add it to `type.stringtable`.
Expand All @@ -1921,6 +1974,7 @@ Type merge(Type type)
case Ttypeof:
case Tident:
case Tinstance:
case Tmixin:
return type;

case Tenum:
Expand Down Expand Up @@ -2932,6 +2986,23 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, Expression* pe, Type* pt, Ds
}
}

void visitMixin(TypeMixin mt)
{
auto ta = mt.compileTypeMixin(loc, sc);
if (ta)
{
auto tt = ta.isTypeTraits();
if (tt && tt.exp)
{
*pe = tt.exp;
}
else
resolve(ta, loc, sc, pe, pt, ps, intypeid);
}
else
returnError();
}

switch (mt.ty)
{
default: visitType (mt); break;
Expand All @@ -2943,6 +3014,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, Expression* pe, Type* pt, Ds
case Ttypeof: visitTypeof (cast(TypeTypeof)mt); break;
case Treturn: visitReturn (cast(TypeReturn)mt); break;
case Tslice: visitSlice (cast(TypeSlice)mt); break;
case Tmixin: visitMixin (cast(TypeMixin)mt); break;
}
}

Expand Down
55 changes: 55 additions & 0 deletions test/compilable/mixintype.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

alias Int = mixin("int");
alias Lint = mixin("Int");

int test1(mixin("int")* p)
{
mixin("int")[] a;
mixin("int[]") b;
mixin("int[] c;");
mixin("*p = c[0];");
*p = mixin("c[0]");
return *p + a[0] + b[0] + c[0];
}

/******************************************/

void test2()
{
auto a = __traits(allMembers, mixin(__MODULE__));
}

/*****************************************/

void test3()
{
char val;
int mod;
enum b = __traits(compiles, mixin("*cast(int*)&val + mod"));
static assert(b == true);
}

/********************************************/


struct S
{
int fielda;
int fieldb;
}

template Foo4(alias T)
{
enum Foo4 = true;
}

void test4()
{
S sa;
auto a = Foo4!( __traits(getMember,sa,"fielda") );

S sb;
enum getStuff = q{ __traits(getMember,sb,"fieldb") };
auto b = Foo4!(mixin(getStuff));
}

13 changes: 13 additions & 0 deletions test/fail_compilation/mixintype2.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

/* TEST_OUTPUT:
---
fail_compilation/mixintype2.d(9): Error: alias `mixintype2.Foo.T` recursive alias declaration
---
*/

struct Foo {
alias T = mixin("T2");
}
alias T1 = mixin("Foo.T");
alias T2 = mixin("T1");
void func (T2 p) {}