From badb47e14740f7ff336a7bac05145809f3261706 Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Mon, 12 Feb 2018 11:06:08 +0200 Subject: [PATCH] Compute lazy lambda serialization --- src/dmd/expression.d | 8 --- src/dmd/lambdacomp.d | 104 ++++++++++++++++++++++++++----- src/dmd/traits.d | 18 +++++- test/compilable/testlambdacomp.d | 60 +++++++++++++++--- 4 files changed, 158 insertions(+), 32 deletions(-) diff --git a/src/dmd/expression.d b/src/dmd/expression.d index d52aa08e1bf3..deeea405a09c 100644 --- a/src/dmd/expression.d +++ b/src/dmd/expression.d @@ -4342,15 +4342,7 @@ extern (C++) final class FuncExp : Expression if (fd.fes) s = "__foreachbody"; else if (fd.tok == TOK.reserved) - { - import dmd.lambdacomp; - s = "__lambda"; - auto serVisitor = new SerializeVisitor(sc); - fd.accept(serVisitor); - fd.serialization = serVisitor.buf.offset == 0 ? "uncomparable" : serVisitor.buf.extractString(); - //printf("serialization: %s\n", fd.serialization); - } else if (fd.tok == TOK.delegate_) s = "__dgliteral"; else diff --git a/src/dmd/lambdacomp.d b/src/dmd/lambdacomp.d index 39e37657e546..89ab4ec517bd 100644 --- a/src/dmd/lambdacomp.d +++ b/src/dmd/lambdacomp.d @@ -23,6 +23,7 @@ import core.stdc.string; import dmd.declaration; import dmd.denum; import dmd.dsymbol; +import dmd.dtemplate; import dmd.expression; import dmd.func; import dmd.dmangle; @@ -34,6 +35,8 @@ import dmd.statement; import dmd.tokens; import dmd.visitor; +enum LOG = false; + /** * The type of the visited expression. */ @@ -83,6 +86,8 @@ public: override void visit(FuncLiteralDeclaration fld) { assert(fld.type.ty != Terror); + static if (LOG) + printf("FuncLiteralDeclaration: %s\n", fld.toChars()); TypeFunction tf = cast(TypeFunction)fld.type; uint dim = cast(uint)Parameter.dim(tf.parameters); @@ -111,9 +116,7 @@ public: } // Now the function body can be serialized. - CompoundStatement cs = fld.fbody.isCompoundStatement(); - Statement s = !cs ? fld.fbody : null; - ReturnStatement rs = s ? s.isReturnStatement() : null; + ReturnStatement rs = fld.fbody.isReturnStatement(); if (rs && rs.exp) { rs.exp.accept(this); @@ -122,6 +125,8 @@ public: override void visit(DotIdExp exp) { + static if (LOG) + printf("DotIdExp: %s\n", exp.toChars()); if (buf.offset == 0) return; @@ -156,13 +161,9 @@ public: } } - override void visit(IdentifierExp exp) + bool checkArgument(const(char)* id) { - if (buf.offset == 0) - return; - // The identifier may be an argument - auto id = exp.ident.toChars; auto stringtable_value = arg_hash.lookup(id, strlen(id)); if (stringtable_value) { @@ -171,10 +172,25 @@ public: buf.writestring(gen_id); buf.writeByte('_'); et = ExpType.Arg; + return true; } - else + return false; + } + + override void visit(IdentifierExp exp) + { + static if (LOG) + printf("IdentifierExp: %s\n", exp.toChars()); + + if (buf.offset == 0) + return; + + auto id = exp.ident.toChars(); + + // If it's not an argument + if (!checkArgument(id)) { - // Or it may be something else + // we must check what the identifier expression is. Dsymbol scopesym; Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); if (s) @@ -199,6 +215,37 @@ public: } } + override void visit(DotVarExp exp) + { + static if (LOG) + printf("DotVarExp: %s, var: %s, e1: %s\n", exp.toChars(), + exp.var.toChars(), exp.e1.toChars()); + + exp.e1.accept(this); + if (buf.offset == 0) + return; + + buf.setsize(buf.offset -1); + buf.writeByte('.'); + buf.writestring(exp.var.toChars()); + buf.writeByte('_'); + } + + override void visit(VarExp exp) + { + static if (LOG) + printf("VarExp: %s, var: %s\n", exp.toChars(), exp.var.toChars()); + + if (buf.offset == 0) + return; + + auto id = exp.var.ident.toChars(); + if (!checkArgument(id)) + { + buf.offset = 0; + } + } + override void visit(UnaExp exp) { if (buf.offset == 0) @@ -224,6 +271,9 @@ public: override void visit(BinExp exp) { + static if (LOG) + printf("BinExp: %s\n", exp.toChars()); + if (buf.offset == 0) return; @@ -247,11 +297,9 @@ public: buf.writeByte('_'); } - override void visit(TypeIdentifier t) + void writeMangledName(Dsymbol s) { - Dsymbol scopesym; - Dsymbol s = sc.search(t.loc, t.ident, &scopesym); - if (s && s.semanticRun == PASS.semantic3done) + if (s) { OutBuffer mangledName; mangleToBuffer(s, &mangledName); @@ -262,9 +310,33 @@ public: buf.reset(); } - override void visit(TypeInstance t) + private bool checkTemplateInstance(T)(T t) + if (is(T == TypeStruct) || is(T == TypeClass)) { - buf.reset(); + if (t.sym.parent && t.sym.parent.isTemplateInstance()) + { + buf.reset(); + return true; + } + return false; + } + + override void visit(TypeStruct t) + { + static if (LOG) + printf("TypeStruct: %s\n", t.toChars); + + if (!checkTemplateInstance!TypeStruct(t)) + writeMangledName(t.sym); + } + + override void visit(TypeClass t) + { + static if (LOG) + printf("TypeClass: %s\n", t.toChars()); + + if (!checkTemplateInstance!TypeClass(t)) + writeMangledName(t.sym); } override void visit(Parameter p) diff --git a/src/dmd/traits.d b/src/dmd/traits.d index a37d3b1b081d..2f2b06dbac35 100644 --- a/src/dmd/traits.d +++ b/src/dmd/traits.d @@ -1453,8 +1453,24 @@ extern (C++) Expression semanticTraits(TraitsExp e, Scope* sc) if (l1 && l2) { - import core.stdc.string; + const(char)* getSerialization(FuncLiteralDeclaration fld) + { + import dmd.lambdacomp : SerializeVisitor; + auto serVisitor = new SerializeVisitor(sc); + fld.accept(serVisitor); + if (serVisitor.buf.offset == 0) + return "uncomparable"; + else + return serVisitor.buf.extractString(); + } + + if (!l1.serialization) + l1.serialization = getSerialization(l1); + if (!l2.serialization) + l2.serialization = getSerialization(l2); + //printf("serialization1: %s\n", l1.serialization); + //printf("serialization2: %s\n", l2.serialization); if (strcmp(l1.serialization, l2.serialization) == 0 && strcmp(l1.serialization, "uncomparable") != 0) { diff --git a/test/compilable/testlambdacomp.d b/test/compilable/testlambdacomp.d index 8337baadee24..e74ce44baeb3 100644 --- a/test/compilable/testlambdacomp.d +++ b/test/compilable/testlambdacomp.d @@ -1,3 +1,4 @@ + void test1() { static assert(__traits(isSame, (a, b) => a + b, (c, d) => c + d)); @@ -6,6 +7,30 @@ void test1() static assert(__traits(isSame, (a, b) => a + b + 10, (c, d) => c + d + 10)); } +class Y +{ + static int r = 5; + int x; + this(int x) + { + this.x = x; + } +} + +class A +{ + Y a; + this(Y a) + { + this.a = a; + } +} + +void foo3(alias pred)() +{ + static assert(!__traits(isSame, pred, (A x, A y) => ++x.a.x + (--y.a.x))); +} + void test2() { @@ -17,8 +42,8 @@ void test2() class A { - int a; - this(int a) + Y a; + this(Y a) { this.a = a; } @@ -33,18 +58,39 @@ void test2() } } - static assert(__traits(isSame, (A a) => ++a.a, (A b) => ++b.a)); - static assert(!__traits(isSame, (A a) => ++a.a, (B a) => ++a.a)); + B q = new B(7); + alias pred = (A a, A b) => ++a.a.x + (--b.a.x); + foo3!pred(); + static assert(!__traits(isSame, (A a) => ++a.a.x + 2, (A b) => ++b.a.x + 3)); + static assert(__traits(isSame, pred, (A x, A y) => ++x.a.x + (--y.a.x))); + static assert(!__traits(isSame, (B a) => ++a.a + 2, (B b) => ++b.a + 3)); + static assert(__traits(isSame, (B a) => ++a.a, (B a) => ++a.a)); - A cl = new A(7); - static assert(!__traits(isSame, a => a + cl.a, c => c + cl.a)); + B cl = new B(7); + static assert(!__traits(isSame, a => a + q.a, c => c + cl.a)); - struct T(G) + class C(G) { G a; + this(int a) + { + this.a = a; + } } + static assert(!__traits(isSame, (C!int a) => ++a.a, (C!int a) => ++a.a)); + struct X + { + int a; + } + static assert(__traits(isSame, (X a) => a.a + 2, (X b) => b.a + 2)); + + struct T(G) + { + G a; + } static assert(!__traits(isSame, (T!int a) => ++a.a, (T!int a) => ++a.a)); + } void test3()