Bug 3131 – Disambiguate symbol lookup based on if it's a type or identifier that is required

Status
NEW
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2009-07-03T07:16:33Z
Last change time
2024-12-13T17:50:28Z
Keywords
spec
Assigned to
No Owner
Creator
david
Moved to GitHub: dmd#18048 →

Comments

Comment #0 by davidl — 2009-07-03T07:16:33Z
class c{ } c c; c = new c; Jarrett mentioned that it doesn't compile in bug 3125. This can alleviate the pain of porting C# code. I patched this in my own box when I tried to port some C# code.
Comment #1 by jarrett.billingsley — 2009-07-03T08:42:11Z
No. This is working as intended. What you're doing here is shadowing the global 'c' with a local 'c'. Symbol lookup in D is simple: it looks in enclosing scopes until it finds a symbol of the given name, no matter how you're using that name. If you're porting code from another language, you're going to have to expect some translation work. And besides, what's so difficult about "c c = new c;", or better yet, _not doing it in the first place_?
Comment #2 by davidl — 2009-07-03T16:33:30Z
(In reply to comment #1) > No. This is working as intended. What you're doing here is shadowing the > global 'c' with a local 'c'. Symbol lookup in D is simple: it looks in > enclosing scopes until it finds a symbol of the given name, no matter how > you're using that name. If you're porting code from another language, you're > going to have to expect some translation work. And besides, what's so > difficult about "c c = new c;", or better yet, _not doing it in the first > place_? c c = new c; <-- this is the only 1 case that trigger this issue. Sometimes you can have class ClassType1 { } class ClassType2 { ClassType1 ClassType1; void func(ClassType1 t){} // this ClassType1 is clearly referring to the type of "ClassType1" } And it's not hard to make this work. I see no reason to ignore this one. My own dmd gets several other features patched. So it's somewhat troublesome to isolate the patch to this particular bug. The idea is pretty simple, when you try to tell the user the error, firstly try to resolve the type upper scope A roughly patch: Type *TypeIdentifier::semantic(Loc loc, Scope *sc) { Type *t; Expression *e; Dsymbol *s; +++ bool tried = false; +++ Scope *sce = sc -> enclosing; //printf("TypeIdentifier::semantic(%s)\n", toChars()); resolve(loc, sc, &e, &t, &s); +++ L1: if (t) { //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco); if (t->ty == Ttypedef) { TypeTypedef *tt = (TypeTypedef *)t; if (tt->sym->sem == 1) error(loc, "circular reference of typedef %s", tt->toChars()); } t = t->addMod(mod); } else { +++ if ( sce != NULL) +++ { +++ resolve(loc, sce, &e, &t, &s); +++ sce = sce -> enclosing; +++ goto L1; +++ } #ifdef DEBUG if (!global.gag) printf("1: "); #endif if (s) { s->error(loc, "is used as a type"); //halt(); } else error(loc, "%s is used as a type", toChars()); t = tvoid; } //t->print(); return t; } You see, it's simple. I think it should be enhanced.
Comment #3 by davidl — 2009-07-03T16:43:39Z
Umm, this time I review the patch, that bool tried is some legacy way to solve the issue. It didn't work correctly if it requires to resolve the symbol in upper-upper scope. I changed it to the current one, but the bool tried left forgotten. I won't try to hack the compiler, if hacking it is relatively simple, the issue is hard to bypass. The original C# code uses duplication name of var and type everywhere.
Comment #4 by jarrett.billingsley — 2009-07-03T16:59:11Z
(In reply to comment #2) > Sometimes you can have > > class ClassType1 > { > } > > class ClassType2 > { > ClassType1 ClassType1; > void func(ClassType1 t){} // this ClassType1 is clearly referring to the type > of "ClassType1" > } > > And it's not hard to make this work. I see no reason to ignore this one. I do. It's stupid and pointless. Just name your local variable _something else_. > You see, it's simple. I think it should be enhanced. Just because it's simple doesn't mean it should be done.
Comment #5 by ddparnell — 2009-07-03T20:33:36Z
Regardless of whether it is a good idea or not, I see a related problem in that there is a bit of apparent inconsistency. Look at this program ... // ------------ struct X { } struct Y { X X; // Disallowed } void main() { X X; // Allowed. } // ------------ Either both instances should be disallowed or both allowed, IMO.
Comment #6 by jarrett.billingsley — 2009-07-03T21:43:33Z
(In reply to comment #5) > Regardless of whether it is a good idea or not, I see a related problem in that > there is a bit of apparent inconsistency. > > Look at this program ... > > // ------------ > struct X > { > } > struct Y > { > X X; // Disallowed > } > void main() > { > X X; // Allowed. > } > // ------------ > > Either both instances should be disallowed or both allowed, IMO. I would say they should both be allowed. The declaration of the struct member should happen semantically after the type lookup, just like with the variable.
Comment #7 by andrej.mitrovich — 2012-12-21T10:46:48Z
(In reply to comment #6) > I would say they should both be allowed. The declaration of the struct member > should happen semantically after the type lookup, just like with the variable. This kind of code is just asking for trouble.
Comment #8 by robert.schadek — 2024-12-13T17:50:28Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18048 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB