digitalmars.D - Typeinfo inconsistencies
- H. S. Teoh (24/24) Aug 13 2013 So, I got some free time today and decided to look into issue 6210, and
- Maxim Fomin (18/48) Aug 13 2013 It seems that important path is taken here:
- Maxim Fomin (46/76) Aug 13 2013 OK
- H. S. Teoh (7/75) Aug 13 2013 Thanks!! Will you submit a pull request? You can reference bug 6210. I'm
So, I got some free time today and decided to look into issue 6210, and found out that the problem was caused by this: char[] a = "h".dup; const(char)[] b = "h"; string c = "h"; writeln(typeid(a).getHash(&a)); // prints 104 writeln(typeid(b).getHash(&b)); // prints 703014434222502 writeln(typeid(c).getHash(&c)); // prints 104 This is completely b0rken, because it causes the following code to fail: int[char[]] aa; aa["h"] = 1; assert(aa.dup == aa); // fails The reason for this inconsistency is that char[] and immutable(char)[] (aka string) have their getHash functions overridden in druntime's src/rt/typeinfo/ti_Ag.d, but there is no such override for const(char)[]. I tried adding another subclass for const(char)[]'s typeid that inherits the correct version of getHash, but it didn't work because presumably this stuff is hardcoded into the compiler somewhere. So my question is, where in the compiler decides to use the specific typeinfos for char[] and immutable(char)[], but not const(char)[]? T -- That's not a bug; that's a feature!
Aug 13 2013
On Tuesday, 13 August 2013 at 17:42:31 UTC, H. S. Teoh wrote:So, I got some free time today and decided to look into issue 6210, and found out that the problem was caused by this: char[] a = "h".dup; const(char)[] b = "h"; string c = "h"; writeln(typeid(a).getHash(&a)); // prints 104 writeln(typeid(b).getHash(&b)); // prints 703014434222502 writeln(typeid(c).getHash(&c)); // prints 104 This is completely b0rken, because it causes the following code to fail: int[char[]] aa; aa["h"] = 1; assert(aa.dup == aa); // fails The reason for this inconsistency is that char[] and immutable(char)[] (aka string) have their getHash functions overridden in druntime's src/rt/typeinfo/ti_Ag.d, but there is no such override for const(char)[]. I tried adding another subclass for const(char)[]'s typeid that inherits the correct version of getHash, but it didn't work because presumably this stuff is hardcoded into the compiler somewhere. So my question is, where in the compiler decides to use the specific typeinfos for char[] and immutable(char)[], but not const(char)[]? TIt seems that important path is taken here: https://github.com/D-Programming-Language/dmd/blob/master/src/typinf.c#L138 And root of the issue maybe here: https://github.com/D-Programming-Language/dmd/blob/master/src/typinf.c#L793 (essentially if(char && immutable)) Based on ad-hoc dmd debug: If type is "AssociativeArray!(const(char)[], int)" Type::builtinTypeInfo returns 0. If type is "char[]" !t->vtinfo is false, so entire branch is skipped. If type is "const(char)[]" then !t->builtinTypeInfo() is true and dmd executes COMDAT generation branch. If type is "const(char)" then !t->builtinTypeInfo() is true and dmd executes COMDAT generation branch (also if (t->isConst()) is also true). If type is "char" then "!t->builtinTypeInfo()" is false. It seems that it is consistent with your observations.
Aug 13 2013
On Tuesday, 13 August 2013 at 17:42:31 UTC, H. S. Teoh wrote:So, I got some free time today and decided to look into issue 6210, and found out that the problem was caused by this: char[] a = "h".dup; const(char)[] b = "h"; string c = "h"; writeln(typeid(a).getHash(&a)); // prints 104 writeln(typeid(b).getHash(&b)); // prints 703014434222502 writeln(typeid(c).getHash(&c)); // prints 104 This is completely b0rken, because it causes the following code to fail: int[char[]] aa; aa["h"] = 1; assert(aa.dup == aa); // fails The reason for this inconsistency is that char[] and immutable(char)[] (aka string) have their getHash functions overridden in druntime's src/rt/typeinfo/ti_Ag.d, but there is no such override for const(char)[]. I tried adding another subclass for const(char)[]'s typeid that inherits the correct version of getHash, but it didn't work because presumably this stuff is hardcoded into the compiler somewhere. So my question is, where in the compiler decides to use the specific typeinfos for char[] and immutable(char)[], but not const(char)[]? TOK --- a/src/typinf.c +++ b/src/typinf.c -790,7 +790,8 int TypeDArray::builtinTypeInfo() #if DMDV2 return !mod && (next->isTypeBasic() != NULL && !next->mod || // strings are so common, make them builtin - next->ty == Tchar && next->mod == MODimmutable); + next->ty == Tchar && next->mod == MODimmutable || + next->ty == Tchar && next->mod == MODconst); #else return next->isTypeBasic() != NULL; #endif --- a/src/rt/typeinfo/ti_Ag.d +++ b/src/rt/typeinfo/ti_Ag.d -186,3 +186,15 class TypeInfo_Aya : TypeInfo_Aa } } +// const(char)[] + +class TypeInfo_Axa : TypeInfo_Aa +{ + override string toString() const { return "const(char)[]"; } + + override property inout(TypeInfo) next() inout + { + return cast(inout)typeid(const(char)); + } +} + and this program runs fine and prints 104 for three cases import std.stdio; void main() { int[char[]] aa; aa["h"] = 1; assert(aa.dup == aa); // fails, now ok char[] a = "h".dup; const(char)[] b = "h"; string c = "h"; writeln(typeid(a).getHash(&a)); // prints 104 writeln(typeid(b).getHash(&b)); // prints 703014434222502, now 104 writeln(typeid(c).getHash(&c)); // prints 104 }
Aug 13 2013
On Tue, Aug 13, 2013 at 09:48:10PM +0200, Maxim Fomin wrote:On Tuesday, 13 August 2013 at 17:42:31 UTC, H. S. Teoh wrote:Thanks!! Will you submit a pull request? You can reference bug 6210. I'm guessing that this will probably also fix one or two other AA-related bugs that have been around for a while. T -- It's amazing how careful choice of punctuation can leave you hanging:So, I got some free time today and decided to look into issue 6210, and found out that the problem was caused by this: char[] a = "h".dup; const(char)[] b = "h"; string c = "h"; writeln(typeid(a).getHash(&a)); // prints 104 writeln(typeid(b).getHash(&b)); // prints 703014434222502 writeln(typeid(c).getHash(&c)); // prints 104 This is completely b0rken, because it causes the following code to fail: int[char[]] aa; aa["h"] = 1; assert(aa.dup == aa); // fails The reason for this inconsistency is that char[] and immutable(char)[] (aka string) have their getHash functions overridden in druntime's src/rt/typeinfo/ti_Ag.d, but there is no such override for const(char)[]. I tried adding another subclass for const(char)[]'s typeid that inherits the correct version of getHash, but it didn't work because presumably this stuff is hardcoded into the compiler somewhere. So my question is, where in the compiler decides to use the specific typeinfos for char[] and immutable(char)[], but not const(char)[]? TOK --- a/src/typinf.c +++ b/src/typinf.c -790,7 +790,8 int TypeDArray::builtinTypeInfo() #if DMDV2 return !mod && (next->isTypeBasic() != NULL && !next->mod || // strings are so common, make them builtin - next->ty == Tchar && next->mod == MODimmutable); + next->ty == Tchar && next->mod == MODimmutable || + next->ty == Tchar && next->mod == MODconst); #else return next->isTypeBasic() != NULL; #endif --- a/src/rt/typeinfo/ti_Ag.d +++ b/src/rt/typeinfo/ti_Ag.d -186,3 +186,15 class TypeInfo_Aya : TypeInfo_Aa } } +// const(char)[] + +class TypeInfo_Axa : TypeInfo_Aa +{ + override string toString() const { return "const(char)[]"; } + + override property inout(TypeInfo) next() inout + { + return cast(inout)typeid(const(char)); + } +} +
Aug 13 2013