Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix Issue 20053 - add mixin types #10215

Merged
merged 1 commit into from Jul 29, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/dmd/astbase.d
Expand Up @@ -188,6 +188,7 @@ struct ASTBase
Tvector,
Tint128,
Tuns128,
Tmixin,
TMAX
}

Expand Down Expand Up @@ -235,6 +236,7 @@ struct ASTBase
alias Tvector = ENUMTY.Tvector;
alias Tint128 = ENUMTY.Tint128;
alias Tuns128 = ENUMTY.Tuns128;
alias Tmixin = ENUMTY.Tmixin;
alias TMAX = ENUMTY.TMAX;

alias TY = ubyte;
Expand Down Expand Up @@ -2758,6 +2760,7 @@ struct ASTBase
sizeTy[Terror] = __traits(classInstanceSize, TypeError);
sizeTy[Tnull] = __traits(classInstanceSize, TypeNull);
sizeTy[Tvector] = __traits(classInstanceSize, TypeVector);
sizeTy[Tmixin] = __traits(classInstanceSize, TypeMixin);
return sizeTy;
}();

Expand Down Expand Up @@ -4243,6 +4246,41 @@ struct ASTBase
}
}

extern (C++) final class TypeMixin : Type
{
Expressions* exps;

extern (D) this(Expressions* exps)
{
super(Tmixin);
this.exps = exps;
}

override Type syntaxCopy()
{
static Expressions* arraySyntaxCopy(Expressions* exps)
{
Expressions* a = null;
if (exps)
{
a = new Expressions(exps.dim);
foreach (i, e; *exps)
{
(*a)[i] = e ? e.syntaxCopy() : null;
}
}
return a;
}

return new TypeMixin(arraySyntaxCopy(exps));
Copy link
Member

Choose a reason for hiding this comment

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

I'm confused as to why this idiom was used here. It's just a more complicated way of saying... this:

override Type syntaxCopy()
{
    Expressions* a = null;
    if (exps)
    {
        a = new Expressions(exps.dim);
        foreach (i, e; *exps)
        {
            (*a)[i] = e ? e.syntaxCopy() : null;
        }
    }
    return new TypeMixin(a);
}

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 arraySyntaxCopy is used all over dmd, but is not available in astbase.d

}

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
Expand Up @@ -103,6 +103,7 @@ private immutable char[TMAX] mangleChar =
Treturn : '@',
Tvector : '@',
Ttraits : '@',
Tmixin : '@',
];

unittest
Expand Down
1 change: 1 addition & 0 deletions src/dmd/dtemplate.d
Expand Up @@ -6413,6 +6413,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
if (ta)
{
//printf("type %s\n", ta.toChars());

Copy link
Member

Choose a reason for hiding this comment

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

Unrelated

// It might really be an Expression or an Alias
ta.resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0);
if (ea)
Expand Down
1 change: 1 addition & 0 deletions src/dmd/glue.d
Expand Up @@ -1465,6 +1465,7 @@ tym_t totym(Type tx)

case Tident:
case Ttypeof:
case Tmixin:
//printf("ty = %d, '%s'\n", tx.ty, tx.toChars());
error(Loc.initial, "forward reference of `%s`", tx.toChars());
t = TYint;
Expand Down
8 changes: 8 additions & 0 deletions src/dmd/hdrgen.d
Expand Up @@ -3727,6 +3727,13 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
buf.writestring("typeof(null)");
}

void visitMixin(TypeMixin t)
{
buf.writestring("mixin(");
argsToBuffer(t.exps, buf, hgs, null);
buf.writeByte(')');
}

switch (t.ty)
{
default: return t.isTypeBasic() ?
Expand All @@ -3753,5 +3760,6 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
case Ttuple: return visitTuple (cast(TypeTuple)t);
case Tslice: return visitSlice(cast(TypeSlice)t);
case Tnull: return visitNull(cast(TypeNull)t);
case Tmixin: return visitMixin(cast(TypeMixin)t);
}
}
36 changes: 36 additions & 0 deletions src/dmd/mtype.d
Expand Up @@ -286,6 +286,7 @@ enum ENUMTY : int
Tint128,
Tuns128,
TTraits,
Tmixin,
TMAX,
}

Expand Down Expand Up @@ -334,6 +335,7 @@ alias Tvector = ENUMTY.Tvector;
alias Tint128 = ENUMTY.Tint128;
alias Tuns128 = ENUMTY.Tuns128;
alias Ttraits = ENUMTY.TTraits;
alias Tmixin = ENUMTY.Tmixin;
alias TMAX = ENUMTY.TMAX;

alias TY = ubyte;
Expand Down Expand Up @@ -488,6 +490,7 @@ extern (C++) abstract class Type : ASTNode
sizeTy[Tnull] = __traits(classInstanceSize, TypeNull);
sizeTy[Tvector] = __traits(classInstanceSize, TypeVector);
sizeTy[Ttraits] = __traits(classInstanceSize, TypeTraits);
sizeTy[Tmixin] = __traits(classInstanceSize, TypeMixin);
return sizeTy;
}();

Expand Down Expand Up @@ -2663,6 +2666,8 @@ extern (C++) abstract class Type : ASTNode
inout(TypeTuple) isTypeTuple() { return ty == Ttuple ? cast(typeof(return))this : null; }
inout(TypeSlice) isTypeSlice() { return ty == Tslice ? cast(typeof(return))this : null; }
inout(TypeNull) isTypeNull() { return ty == Tnull ? cast(typeof(return))this : null; }
inout(TypeMixin) isTypeMixin() { return ty == Tmixin ? cast(typeof(return))this : null; }
inout(TypeTraits) isTypeTraits() { return ty == Ttraits ? cast(typeof(return))this : null; }
}

override void accept(Visitor v)
Expand Down Expand Up @@ -5132,6 +5137,37 @@ extern (C++) final class TypeTraits : Type
}
}

/******
* Implements mixin types.
*
* Semantic analysis will convert it to a real type.
*/
extern (C++) final class TypeMixin : Type
{
Expressions* exps;

extern (D) this(Expressions* exps)
{
super(Tmixin);
this.exps = exps;
}

override const(char)* kind() const
{
return "mixin";
}

override Type syntaxCopy()
{
return new TypeMixin(Expression.arraySyntaxCopy(exps));
}

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

/***********************************************************
*/
extern (C++) abstract class TypeQualified : Type
Expand Down
52 changes: 27 additions & 25 deletions src/dmd/parse.d
Expand Up @@ -1929,19 +1929,7 @@ final class Parser(AST) : Lexer
// Get TemplateArgumentList
while (token.value != endtok)
{
// See if it is an Expression or a Type
if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null))
{
// Template argument is a type
AST.Type ta = parseType();
tiargs.push(ta);
}
else
{
// Template argument is an expression
AST.Expression ea = parseAssignExp();
tiargs.push(ea);
}
tiargs.push(parseTypeOrAssignExp());
if (token.value != TOK.comma)
break;
nextToken();
Expand All @@ -1950,6 +1938,18 @@ final class Parser(AST) : Lexer
return tiargs;
}

/***************************************
* Parse a Type or an Expression
* Returns:
* RootObject representing the AST
*/
RootObject parseTypeOrAssignExp()
{
return isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null)
? parseType() // argument is a type
: parseAssignExp(); // argument is an expression
Copy link
Member

Choose a reason for hiding this comment

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

Would have been better if this refactoring was in another PR

}

/*****************************
* Parse single template argument, to support the syntax:
* foo!arg
Expand Down Expand Up @@ -3510,7 +3510,7 @@ final class Parser(AST) : Lexer
return decldefs;
}

private AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null)
AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null)
{
/* Take care of the storage class prefixes that
* serve as type attributes:
Expand Down Expand Up @@ -3712,6 +3712,15 @@ final class Parser(AST) : Lexer
}
break;

case TOK.mixin_:
// https://dlang.org/spec/expression.html#mixin_types
nextToken();
if (token.value != TOK.leftParentheses)
error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(TOK.leftParentheses), "`mixin`".ptr);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(TOK.leftParentheses), "`mixin`".ptr);
error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParentheses));

auto exps = parseArguments();
t = new AST.TypeMixin(exps);
break;

case TOK.dot:
// Leading . as in .foo
t = parseBasicTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents);
Expand Down Expand Up @@ -5630,6 +5639,8 @@ final class Parser(AST) : Lexer
}
case TOK.mixin_:
{
if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
goto Ldeclaration;
Token* t = peek(&token);
if (t.value == TOK.leftParentheses)
{
Expand Down Expand Up @@ -6921,6 +6932,7 @@ final class Parser(AST) : Lexer

case TOK.typeof_:
case TOK.vector:
case TOK.mixin_:
/* typeof(exp).identifier...
*/
t = peek(t);
Expand Down Expand Up @@ -7923,17 +7935,7 @@ final class Parser(AST) : Lexer
{
nextToken();
check(TOK.leftParentheses, "`typeid`");
RootObject o;
if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null))
{
// argument is a type
o = parseType();
}
else
{
// argument is an expression
o = parseAssignExp();
}
RootObject o = parseTypeOrAssignExp();
check(TOK.rightParentheses);
e = new AST.TypeidExp(loc, o);
break;
Expand Down
77 changes: 58 additions & 19 deletions src/dmd/traits.d
Expand Up @@ -17,6 +17,7 @@ import core.stdc.string;

import dmd.aggregate;
import dmd.arraytypes;
import dmd.astcodegen;
import dmd.attrib;
import dmd.canthrow;
import dmd.dclass;
Expand All @@ -38,6 +39,7 @@ import dmd.id;
import dmd.identifier;
import dmd.mtype;
import dmd.nogc;
import dmd.parse;
import dmd.root.array;
import dmd.root.speller;
import dmd.root.stringtable;
Expand All @@ -46,6 +48,7 @@ import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
import dmd.root.rootobject;
import dmd.root.outbuffer;

enum LOGSEMANTIC = false;

Expand Down Expand Up @@ -1518,33 +1521,69 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
bool err = false;

auto t = isType(o);
auto ex = t ? t.typeToExpression() : isExpression(o);
if (!ex && t)
while (t)
{
Dsymbol s;
t.resolve(e.loc, sc2, &ex, &t, &s);
if (t)
if (auto tm = t.isTypeMixin())
{
t.typeSemantic(e.loc, sc2);
if (t.ty == Terror)
/* The mixin string could be a type or an expression.
* Have to try compiling it to see.
*/
OutBuffer buf;
if (expressionsToString(buf, sc, tm.exps))
{
err = true;
break;
}
const len = buf.offset;
const str = buf.extractChars()[0 .. len];
scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated);
scope p = new Parser!ASTCodegen(e.loc, sc._module, str, false, diagnosticReporter);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);

o = p.parseTypeOrAssignExp();
if (p.errors ||
p.token.value != TOK.endOfFile)
{
err = true;
break;
}
t = o.isType();
}
else if (s && s.errors)
err = true;
else
break;
}
if (ex)

if (!err)
{
ex = ex.expressionSemantic(sc2);
ex = resolvePropertiesOnly(sc2, ex);
ex = ex.optimize(WANTvalue);
if (sc2.func && sc2.func.type.ty == Tfunction)
auto ex = t ? t.typeToExpression() : isExpression(o);
if (!ex && t)
{
const tf = cast(TypeFunction)sc2.func.type;
err |= tf.isnothrow && canThrow(ex, sc2.func, false);
Dsymbol s;
t.resolve(e.loc, sc2, &ex, &t, &s);
if (t)
{
t.typeSemantic(e.loc, sc2);
if (t.ty == Terror)
err = true;
}
else if (s && s.errors)
err = true;
}
if (ex)
{
ex = ex.expressionSemantic(sc2);
ex = resolvePropertiesOnly(sc2, ex);
ex = ex.optimize(WANTvalue);
if (sc2.func && sc2.func.type.ty == Tfunction)
{
const tf = cast(TypeFunction)sc2.func.type;
err |= tf.isnothrow && canThrow(ex, sc2.func, false);
}
ex = checkGC(sc2, ex);
if (ex.op == TOK.error)
err = true;
}
ex = checkGC(sc2, ex);
if (ex.op == TOK.error)
err = true;
}

// Carefully detach the scope from the parent and throw it away as
Expand Down