Bugzilla – Bug 319585
[GMCS] CS0508 not reported for generic property override causing looped unification
Last modified: 2010-05-18 18:34:08 UTC
---- Reported by nazgul@omega.pl 2005-11-19 17:35:05 MST ---- Please fill in this template when reporting a bug, unless you know what you are doing. Description of Problem: The example below is quite strange. It should be rejected by gmcs, just like by csc, because B returned by B getT() is in full signature A<T>.B, but T getT() from A<T> resolves to A<A<T>.B> getT(), so A<T>.B getT() is not a correct override of A<A<T>.B> getT() Steps to reproduce the problem: 1. Compile following program abstract class A<T> { public abstract T getT(); class B : A<B> { public override B getT() { throw new System.Exception("The method or operation is not implemented."); } } } Actual Results: error No Main Expected Results: t.cs(7,26): error CS0508: 'A<T>.B.getT()': return type must be 'A<T>.B' to match overridden member 'A<A<T>.B>.getT()' t.cs(3,22): (Location of symbol related to previous error) ---- Additional Comments From rharinath@novell.com 2005-12-17 02:33:33 MST ---- Hmm, I'm not sure I follow. I think these hold: (a) A<T>.getT() has a return type T (from the text) (a') A<A<T>.B>.getT() has return type A<T>.B (subtitution T -> A<T>.B) (b) A<T>.B.getT() overrides A<A<T>.B>.getT() (base type of A<T>.B) (c) A<T>.B.getT() has return type A<T>.B (from the text) So, they should unify fine? IIUC, you disagree with (a'). Also, IIUC, the CSC error message is saying (c) doesn't hold. ---- Additional Comments From nazgul@omega.pl 2005-12-17 10:18:07 MST ---- I did a more detailed analysis playing with csc and now I know the problem. It is illustrated with following snippet of code: class A<T> { public class B : A<B> { public void getTT() { System.Console.WriteLine(typeof (B)); System.Console.WriteLine(this.GetType()); } } } class M { static void Main () { A<int>.B b = new A<int>.B(); b.getTT(); System.Console.WriteLine (b.GetType()); } } The core of the problem is how C# resolves visibility of types. In above example B means different things depending on context: - in class declaration signature class B : A <B> { } both B's refere to the current type B (that is A<T>.B) - inside the class B no longer referes to current type, but to type derived from base type (that is A<A<T>.B>.B) So my original example expands to abstract class A<T> { public abstract T getT(); } class A<T>.B : A<A<T>.B> { public override A<A<T>.B>.B getT() { throw new System.Exception("The method or operation is not implemented."); } } Which we can now easily see why is rejected. ---- Additional Comments From rharinath@novell.com 2005-12-17 13:57:32 MST ---- Thanks for the analysis. So, the deduction '(c)' above appears to be wrong. Essentially this is a horrible interaction between generics and the type-lookup rules. In non-generic code, I don't think this distinction matters -- it'd be the same type however you slice it. I'm stealing the bug from Martin :-) I think we have to ensure that (1) a type name is not injected into its contained declaration space (2) a name lookup first travels the inheritance hierarchy before looking at any enclosing declaration spaces Together, this would match the behaviour you see. I'm fairly sure that (2) is implemented. So, I'll have to track down where it's not satisfying (1). This bug depended on bug(s) 77403. Unknown operating system unknown. Setting to default OS "Other".
Expected output A`1+B[A`1+B[System.Int32]] A`1+B[System.Int32] A`1+B[System.Int32]
> I think we have to ensure that > > (1) a type name is not injected into its contained declaration space > > (2) a name lookup first travels the inheritance hierarchy before > looking at any enclosing declaration spaces > > Together, this would match the behaviour you see. I'm fairly sure > that (2) is implemented. So, I'll have to track down where it's not > satisfying (1). Hmm, my two conditions above hide the subtle assumption that the name lookup inflates the result of the lookup, which we probably don't. So, (2) is not correctly implemented.
Fixed in trunk.