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
8 changes: 0 additions & 8 deletions src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
104 changes: 88 additions & 16 deletions src/dmd/lambdacomp.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,6 +35,8 @@ import dmd.statement;
import dmd.tokens;
import dmd.visitor;

enum LOG = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Out of interest: why not version= LOG? This is commonly used pattern in DRuntime.

@RazvanN7 RazvanN7 Feb 14, 2018 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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


/**
* The type of the visited expression.
*/
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -122,6 +125,8 @@ public:

override void visit(DotIdExp exp)
{
static if (LOG)
printf("DotIdExp: %s\n", exp.toChars());
if (buf.offset == 0)
return;

Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -224,6 +271,9 @@ public:

override void visit(BinExp exp)
{
static if (LOG)
printf("BinExp: %s\n", exp.toChars());

if (buf.offset == 0)
return;

Expand All @@ -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);
Expand All @@ -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)
Expand Down
18 changes: 17 additions & 1 deletion src/dmd/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -1453,8 +1453,24 @@ extern (C++) Expression semanticTraits(TraitsExp e, Scope* sc)

if (l1 && l2)
{
import core.stdc.string;
const(char)* getSerialization(FuncLiteralDeclaration fld)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why don't you return string here? Comparing D strings is more efficient (no \0 checking)
You already know the length of the buffer - no need to throw this valuable information away.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I know it's easier with strings, but the serialization field is is const(char)* and I really haven't seen AST members declared as strings. All of them are const(char)*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Quoting a conversation with Walter here:

On 12/5/2017 11:20 AM, Andrei Alexandrescu wrote:
Hi Walter, Seb noticed that the dmd code is going through unpleasant hoops caused by C-style strings. Do you think incrementally switching to D-style strings would improve the compiler? -- Andrei

Yes, but we have to be mindful of gdc and ldc both relying on the C++ interface to use dmd, and D strings don't work on that interface.
I've already converted a bunch of internal stuff to D strings where the interface to the back end was not involved.

(we can even convert the C++ interfaces, but that's significantly more effort)

@RazvanN7 RazvanN7 Feb 14, 2018 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

So how do we proceed here? That was my problem also: I may turn the field into a string, but what should I do regarding the header file?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Well, as its a new field and not used by GDC or LDC at the moment, you could do sth. like:

struct DString
{
  size_t length;
  char* head;
}

CC @ibuclaw @redstar @klickverbot

We have to start somewhere, but I don't want to block your PR with this. Sorry.

@timotheecour timotheecour Feb 14, 2018 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

how about this:

extern(C++) Dstring funLib(Dstring input);

see full working example here showing using such API from C++ with the function defined in D.

https://github.com/timotheecour/dtools/blob/master/tests/d01_dmd_string/

EDIT: see #7893

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@timotheecour #7893 is a good step in the right direction, we need to start using D strings in the compiler. That would be an effort separated from this.

{
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)
{
Expand Down
60 changes: 53 additions & 7 deletions test/compilable/testlambdacomp.d
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

void test1()
{
static assert(__traits(isSame, (a, b) => a + b, (c, d) => c + d));
Expand All @@ -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()
{

Expand All @@ -17,8 +42,8 @@ void test2()

class A
{
int a;
this(int a)
Y a;
this(Y a)
{
this.a = a;
}
Expand All @@ -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()
Expand Down