Thread overview |
---|
September 06, 2008 [Issue 2339] New: Inconsistent behaviour referring to template mixin member at compile time | ||||
---|---|---|---|---|
| ||||
http://d.puremagic.com/issues/show_bug.cgi?id=2339 Summary: Inconsistent behaviour referring to template mixin member at compile time Product: D Version: 1.035 Platform: All OS/Version: All Status: NEW Keywords: rejects-valid Severity: blocker Priority: P2 Component: DMD AssignedTo: bugzilla@digitalmars.com ReportedBy: matti.niemenmaa+dbugzilla@iki.fi All four cases in the code below should not assert, yet the first two do and the fourth doesn't even compile. I'm marking this as "blocker" because there's no workaround that I can find and I really need the fourth case to work. It may be that this is a combination of two bugs: the string mixin apparently mangles the identifier into "this.x", which may explain the fourth case. The first two don't make any sense in light of the third, though. template Check(alias name) { const Check = is(typeof(name)); } template FooTemplate() { int x; } class X { mixin FooTemplate FooMixin; // false: // static assert (is(typeof(FooMixin.x))); // static assert (is(typeof(mixin("FooMixin.x")))); // true: static assert (Check!(FooMixin.x)); // doesn't compile: // asdf.d(20): Error: 'this' is only defined in non-static member functions, not asdf // asdf.d(20): Error: this for x needs to be type X not type int // asdf.d(20): template instance Check!(this.x) does not match any template declaration // asdf.d(20): static assert (Check!(this.x)) is not evaluatable at compile time static assert (Check!(mixin("FooMixin.x"))); } -- |
April 22, 2009 [Issue 2339] Inconsistent behaviour referring to template mixin member at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2339 ------- Comment #1 from matti.niemenmaa+dbugzilla@iki.fi 2009-04-22 03:51 ------- I've been investigating this a bit and the issue seems to be that VarDeclaration::needThis() returns true for x; if I make it return false instead, the code compiles fine. Unfortunately, I can't think of a test that would cause that and related cases to return false without breaking something else. Alternatively, needThis() is correct but some places should be checking for something else as well. Here's another testcase, in case it's any help. In this one, it's FuncDeclaration::needThis() that we don't want returning true. template ReturnTypeOf(alias f) { alias typeof(f()) ReturnTypeOf; } template FooIn(char[] s) { mixin ( `template Run() { const Run = "static if (is(ReturnTypeOf!(mixin(\"`~s~`.foo\")) == void)) `~s~`.foo; else static assert (false); "; }` ); } template Mixin() { void foo() { throw new Exception("Success!"); } } class C { mixin Mixin!() M; void runFoo() { // Works static assert (is(ReturnTypeOf!(M.foo) == void)); // Fails // static assert (is(ReturnTypeOf!(mixin("M.foo")) == void)); // Fails at an incorrect line number // mixin (FooIn!("M").Run!()); // Fails like the 2nd case above // static if (is(ReturnTypeOf!(mixin("M.foo")) == void)) // M.foo; // else // static assert (false); } } void main() { (new C).runFoo(); } I tried returning false from needThis() if scope->parent->isTemplateMixin(), but that breaks code like this (an LDC testcase): extern(C) int printf(char*, ...); template Foo() { void test() { printf("test\n"); typeof(this).whee(); } } class Bar { void whee() { printf("whee\n"); } mixin Foo!(); } void main() { (new Bar).test(); } -- |
April 23, 2009 [Issue 2339] Inconsistent behaviour referring to template mixin member at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2339 ------- Comment #2 from matti.niemenmaa+dbugzilla@iki.fi 2009-04-23 09:53 ------- I think the problem in the fourth case might be in how it gets parsed. Here's a snippet from the frontend's normally-commented-out printf() and logging calls on the first, working case: parseStaticAssert() p = 0xf97c4a, *p = ' ' p = 0xf97c4b, *p = '(' p = 0xf97c4c, *p = 'C' t->value = 120 parsePrimaryExp(): loc = 13 p = 0xf97c51, *p = '!' p = 0xf97c52, *p = '(' Dsymbol::Dsymbol(0xf98df0, ident <NULL>) TemplateInstance(this = 0xf98df0, ident = 'Check') Parser::parseTemplateArgumentList() p = 0xf97c53, *p = 'F' t->value = 120 isDeclaration(needId = 0) p = 0xf97c5b, *p = '.' p = 0xf97c5c, *p = 'x' t->value = 120 p = 0xf97c5d, *p = ')' is Parser::isDeclarator() parseBasicType() parseDeclarator(tpl = (nil)) parseBasicType2() p = 0xf97c5e, *p = ')' Expression::Expression(op = 156) this = 0xf990f0 ObjectToCBuffer() t: FooMixin.x ty = 6 ScopeExp::ScopeExp(pkg = 'Check!(FooMixin.x)') As far as I can tell, when the whole expression is recognized as a template instantiation it goes into parseTemplateArgumentList() and makes it into an expression of type TOKimport (??). The whole thing is then one big ScopeExp. Here's how the contents of the string mixin are parsed: Lexer::Lexer(0xf99430,0,10) lexer.mod = 0xf97770, 0xf97ab0 Parser::Parser() p = 0xf99430, *p = 'F' t->value = 120 p.loc.linnum = 21 Parser::parseExpression() loc = 21 parsePrimaryExp(): loc = 21 p = 0xf99438, *p = '.' Expression::Expression(op = 120) this = 0xfcded0 p = 0xf99439, *p = 'x' t->value = 120 p = 0xf9943a, *p = '^@' Expression::Expression(op = 101) this = 0xfcdf20 DotIdExp::toCBuffer() DotIdExp::semantic(this = 0xfcdf20, 'FooMixin.x') This time, the inner expression becomes a DotIdExp, which I think has something to do with why the semantic phases diverge later on. Here's the working one, starting from just before a Scope::search call: TypeIdentifier::resolve(sc = 0xfca6f0, idents = 'FooMixin.x') Scope::search(0xfca6f0, 'FooMixin') looking in scopesym 'X', kind = 'class' X.ClassDeclaration::search('FooMixin') X->ScopeDsymbol::search(ident='FooMixin', flags=x0) s = 'X.FooTemplate!()' found X.FooTemplate!(), kind = 'mixin' TypeQualified::resolveHelper(sc = 0xfca6f0, idents = 'FooMixin.x') scopesym = 'X' 1: s = 'FooTemplate!()' 0xf98c30, kind = 'mixin' And here's the non-working one: UnaExp::semantic('FooMixin.x') IdentifierExp::semantic('FooMixin') Scope::search(0xfca6f0, 'FooMixin') looking in scopesym 'X', kind = 'class' X.ClassDeclaration::search('FooMixin') X->ScopeDsymbol::search(ident='FooMixin', flags=x0) s = 'X.FooTemplate!()' found X.FooTemplate!(), kind = 'mixin' Expression::Expression(op = 42) this = 0xfce010 DsymbolExp::semantic('FooTemplate!()') DsymbolExp:: 0xfce010 'FooTemplate!()' is a symbol For a solution, I considered setting a flag in TemplateInstance::semanticTiargs, just prior to the latter Expression::semantic call, which would tell CompileExp (the one that handles string mixins) that we're actually looking for template arguments. It would then do something like what Parser::parseTemplateArgumentList does, instead of just looking at the expression in isolation. But I don't actually have any clue whether this would help or not. Also, I think it would require some special handling for comma expressions, or manually wrapping the contents of the mixin'd string in brackets before passing it to the parser. -- |
April 23, 2009 [Issue 2339] Inconsistent behaviour referring to template mixin member at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2339 matti.niemenmaa+dbugzilla@iki.fi changed: What |Removed |Added ---------------------------------------------------------------------------- Severity|blocker |normal ------- Comment #3 from matti.niemenmaa+dbugzilla@iki.fi 2009-04-23 12:38 ------- Well, at least there was some use in spending time on this now: I realized the obvious workaround, which makes it get parsed correctly. While the following doesn't work: static assert (Check!(mixin("FooMixin.x"))); The following does: static assert (mixin("Check!(FooMixin.x"))); Lowered severity to "normal" as this is now no longer a blocker for me. -- |
Copyright © 1999-2021 by the D Language Foundation