Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Issue 3382 - [tdpl] Implement uniform function call syntax #582

Merged
merged 2 commits into from

4 participants

@9rnsr
Collaborator

http://d.puremagic.com/issues/show_bug.cgi?id=3382

This pull contains a small lexer fix.
To allow 1.prop syntax, short floating point syntax (e.g. 1.f, 1.Li) are disallowed.

Supplemental change of Phobos: phobos/pull/#378

@WalterBright WalterBright commented on the diff
src/expression.c
@@ -6595,6 +6595,25 @@ void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
e = e->semantic(sc);
return e;
}
+ else if ((t1b->isTypeBasic() && t1b->ty != Tvoid) ||
+ t1b->ty == Tenum || t1b->ty == Tnull)
+ { /* If ident is not a valid property, rewrite:
+ * e1.ident
+ * as:
+ * .ident(e1)
+ */
@WalterBright Owner

I'm not sure what the justification is for this rewrite. And, of course, anything that uses gagging I'm very nervous about and want to avoid as much as possible.

@9rnsr Collaborator
9rnsr added a note

I thought that "uniform" means all types of objects, not only array + user-defined types. Is it my mistake?
And yes, use gagging is ugly, but at least it works for array UFCS. I'd also like to reduce use of them in the future, but today it's difficult.

@andralex Owner

What does gagging mean?

Anyway, Kenji is right: uniform call syntax must apply to all types as a last resort. This has been agreed upon and consequently is part of TDPL.

It saves a lot of boilerplate, see D-Programming-Language/phobos#365. Also a lot of code in std.container consists of forwarding and aliasing that implement a rich interface in terms of a simpler one.

To recap: if all attempts to resolve a.b(c) fail, the call should be rewritten as b(a, c) and retried. The symbol "b" is looked up with the normal rules, i.e. it could be found in a different module than a's, which allows a module to extend functionality of a type defined by another module.

@9rnsr Collaborator
9rnsr added a note

In dmd source, "gagging" means that suppress any errors that raised in compilation.
In this case with x.prop, compiler will replace it to prop(x) with gagging errors that the fail of searching prop function/property from typeof(x), instead of raising them.

Thanks for comment, Andrei. Issue 662 is the report of UFCS with basic types.
I think you should write comment in both 3382 and 662.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@WalterBright

Is there any way to just pull ff7e522?

@9rnsr
Collaborator

Is there any way to just pull ff7e522?

Opened a pull request contains just only ff7e522.
#583

@braddr
Owner

This pull request seems to cause dmd to go into an infinite loop. Every platform stalls when it gets to this pull request. I'm going to put in a quick hack to the auto-tester to skip it until it's been fixed.

@9rnsr
Collaborator

Sorry, I close this pull temporary.

@9rnsr 9rnsr closed this
@9rnsr 9rnsr reopened this
@9rnsr
Collaborator

Fixed.

@WalterBright WalterBright merged commit b7742f7 into from
@braddr braddr referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@ghost Unknown referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@ghost Unknown referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@ghost Unknown referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@AlexeyProkhin AlexeyProkhin referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 6, 2012
  1. @9rnsr
Commits on Mar 7, 2012
  1. @9rnsr
This page is out of date. Refresh to see the latest.
Showing with 147 additions and 24 deletions.
  1. +70 −24 src/expression.c
  2. +77 −0 test/runnable/ufcs.d
View
94 src/expression.c
@@ -6562,6 +6562,25 @@ Expression *DotIdExp::semantic(Scope *sc, int flag)
e = e->semantic(sc);
return e;
}
+ else if ((t1b->isTypeBasic() && t1b->ty != Tvoid) ||
+ t1b->ty == Tenum || t1b->ty == Tnull)
+ { /* If ident is not a valid property, rewrite:
+ * e1.ident
+ * as:
+ * .ident(e1)
+ */
@WalterBright Owner

I'm not sure what the justification is for this rewrite. And, of course, anything that uses gagging I'm very nervous about and want to avoid as much as possible.

@9rnsr Collaborator
9rnsr added a note

I thought that "uniform" means all types of objects, not only array + user-defined types. Is it my mistake?
And yes, use gagging is ugly, but at least it works for array UFCS. I'd also like to reduce use of them in the future, but today it's difficult.

@andralex Owner

What does gagging mean?

Anyway, Kenji is right: uniform call syntax must apply to all types as a last resort. This has been agreed upon and consequently is part of TDPL.

It saves a lot of boilerplate, see D-Programming-Language/phobos#365. Also a lot of code in std.container consists of forwarding and aliasing that implement a rich interface in terms of a simpler one.

To recap: if all attempts to resolve a.b(c) fail, the call should be rewritten as b(a, c) and retried. The symbol "b" is looked up with the normal rules, i.e. it could be found in a different module than a's, which allows a module to extend functionality of a type defined by another module.

@9rnsr Collaborator
9rnsr added a note

In dmd source, "gagging" means that suppress any errors that raised in compilation.
In this case with x.prop, compiler will replace it to prop(x) with gagging errors that the fail of searching prop function/property from typeof(x), instead of raising them.

Thanks for comment, Andrei. Issue 662 is the report of UFCS with basic types.
I think you should write comment in both 3382 and 662.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ unsigned errors = global.startGagging();
+ Type *t1 = e1->type;
+ e = e1->type->dotExp(sc, e1, ident);
+ if (global.endGagging(errors)) // if failed to find the property
+ {
+ e1->type = t1; // kludge to restore type
+ e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident);
+ e = new CallExp(loc, e, e1);
+ }
+ e = e->semantic(sc);
+ return e;
+ }
#endif
else
{
@@ -7069,7 +7088,7 @@ Expression *CallExp::syntaxCopy()
Expression *CallExp::resolveUFCS(Scope *sc)
{
- Expression *ethis = NULL;
+ Expression *e = NULL;
DotIdExp *dotid;
DotTemplateInstanceExp *dotti;
Identifier *ident;
@@ -7078,46 +7097,73 @@ Expression *CallExp::resolveUFCS(Scope *sc)
{
dotid = (DotIdExp *)e1;
ident = dotid->ident;
- ethis = dotid->e1 = dotid->e1->semantic(sc);
- if (ethis->op == TOKdotexp)
+ e = dotid->e1 = dotid->e1->semantic(sc);
+ if (e->op == TOKdotexp)
return NULL;
- ethis = resolveProperties(sc, ethis);
+ e = resolveProperties(sc, e);
}
else if (e1->op == TOKdotti)
{
dotti = (DotTemplateInstanceExp *)e1;
ident = dotti->ti->name;
- ethis = dotti->e1 = dotti->e1->semantic(sc);
- if (ethis->op == TOKdotexp)
+ e = dotti->e1 = dotti->e1->semantic(sc);
+ if (e->op == TOKdotexp)
return NULL;
- ethis = resolveProperties(sc, ethis);
+ e = resolveProperties(sc, e);
}
- if (ethis && ethis->type)
+ if (e && e->type)
{
+ if (e->op == TOKtype || e->op == TOKimport)
+ return NULL;
+ //printf("resolveUCSS %s, e->op = %s\n", toChars(), Token::toChars(e->op));
AggregateDeclaration *ad;
+ Expression *esave = e;
Lagain:
- Type *tthis = ethis->type->toBasetype();
- if (tthis->ty == Tclass)
+ Type *t = e->type->toBasetype();
+ if (t->ty == Tpointer)
+ { Type *tn = t->nextOf();
+ if (tn->ty == Tclass || tn->ty == Tstruct)
+ {
+ e = new PtrExp(e->loc, e);
+ e = e->semantic(sc);
+ t = e->type->toBasetype();
+ }
+ }
+ if (t->ty == Tclass)
{
- ad = ((TypeClass *)tthis)->sym;
- if (search_function(ad, ident))
- return NULL;
+ ad = ((TypeClass *)t)->sym;
goto L1;
}
- else if (tthis->ty == Tstruct)
+ else if (t->ty == Tstruct)
{
- ad = ((TypeStruct *)tthis)->sym;
- if (search_function(ad, ident))
- return NULL;
+ ad = ((TypeStruct *)t)->sym;
L1:
+ if (ad->search(loc, ident, 0))
+ return NULL;
if (ad->aliasthis)
{
- ethis = resolveAliasThis(sc, ethis);
+ e = resolveAliasThis(sc, e);
goto Lagain;
}
+ if (ad->search(loc, Id::opDot, 0))
+ {
+ e = new DotIdExp(e->loc, e, Id::opDot);
+ e = e->semantic(sc);
+ e = resolveProperties(sc, e);
+ goto Lagain;
+ }
+ if (ad->search(loc, Id::opDispatch, 0))
+ return NULL;
+ e = esave;
+ goto Lshift;
+ }
+ else if ((t->isTypeBasic() && t->ty != Tvoid) ||
+ t->ty == Tenum || t->ty == Tnull)
+ {
+ goto Lshift;
}
- else if (tthis->ty == Taarray && e1->op == TOKdot)
+ else if (t->ty == Taarray && e1->op == TOKdot)
{
if (ident == Id::remove)
{
@@ -7132,20 +7178,20 @@ Expression *CallExp::resolveUFCS(Scope *sc)
key = key->semantic(sc);
key = resolveProperties(sc, key);
- TypeAArray *taa = (TypeAArray *)tthis;
+ TypeAArray *taa = (TypeAArray *)t;
key = key->implicitCastTo(sc, taa->index);
if (!key->rvalue())
return new ErrorExp();
- return new RemoveExp(loc, ethis, key);
+ return new RemoveExp(loc, e, key);
}
else if (ident == Id::apply || ident == Id::applyReverse)
{
return NULL;
}
else
- { TypeAArray *taa = (TypeAArray *)tthis;
+ { TypeAArray *taa = (TypeAArray *)t;
assert(taa->ty == Taarray);
StructDeclaration *sd = taa->getImpl();
Dsymbol *s = sd->search(0, ident, 2);
@@ -7154,12 +7200,12 @@ Expression *CallExp::resolveUFCS(Scope *sc)
goto Lshift;
}
}
- else if (tthis->ty == Tarray || tthis->ty == Tsarray)
+ else if (t->ty == Tarray || t->ty == Tsarray)
{
Lshift:
if (!arguments)
arguments = new Expressions();
- arguments->shift(ethis);
+ arguments->shift(e);
if (e1->op == TOKdot)
{
/* Transform:
View
77 test/runnable/ufcs.d
@@ -0,0 +1,77 @@
+module ufcs;
+
+extern (C) int printf(const char*, ...);
+
+/*******************************************/
+// 662
+
+import std.stdio,std.string, std.conv;
+
+enum Etest
+{
+ a,b,c,d
+}
+
+//typedef int testi = 10;
+//typedef Test Test2;
+
+int test() { return 33; }
+
+class Test
+{
+ static int test(int i) { return i; }
+}
+
+int test(Etest test)
+{
+ return cast(int)test;
+}
+
+//int test(testi i)
+//{
+// return cast(int)i;
+//}
+
+void test682()
+{
+ assert(22.to!string() == "22");
+ assert((new Test).test(11) == 11);
+ assert(Test.test(11) == 11);
+ //assert(Test2.test(11) == 11);
+ assert(test() == 33);
+ assert(ufcs.test() == 33);
+ assert(Etest.d.test() == Etest.d);
+ //testi i;
+ //assert(i.test() == i.init);
+}
+
+/*******************************************/
+// 3382
+
+import std.range, std.algorithm;
+
+@property T twice(T)(T x){ return x * x; }
+real toreal(ireal x){ return x.im; }
+char toupper(char c){ return ('a'<=c && c<='z') ? cast(char)(c - 'a' + 'A') : c; }
+
+@property ref T setter(T)(ref T x, T v){ x = v; return x; }
+
+void test3382()
+{
+ auto r = iota(0, 10).map!"a*3"().filter!"a%2 != 0"();
+ foreach (e; r)
+ printf("e = %d\n", e);
+
+ assert(10.twice == 100);
+ assert(0.5.twice == 0.25);
+ assert(1.4i.toreal() == 1.4);
+ assert('c'.toupper() == 'C');
+}
+
+/*******************************************/
+
+void main()
+{
+ test682();
+ test3382();
+}
Something went wrong with that request. Please try again.