www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Typeinfo inconsistencies

reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
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)[]?


 T

It 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
prev sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
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)[]?


 T

OK --- 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