Created attachment 24232 [details]
Description of Problem:
In the constraint of the parameter T2 it is written that it must be subclass of Foo<Τ3>. Therefore, the Type.IsAssignableFrom must return true for T2 and Foo<T3>. But it returns false. But if you comment out the tenth line ("where T1 : T2"), then the function returns true. In MS.NET Type.IsAssignableFrom always returns true for T2 and Foo<T3>.
Steps to reproduce the problem:
1. Compile "test.cs"
2. Run "test.exe"
"False" in console.
"True" in console.
How often does this happen?
Thank you very much for the very reproductible test case. I could reproduce as expected on Mono 184.108.40.206 (2017-04/ef39d08) as well as on .NET.
I can reproduce with Mono 220.127.116.11 (2017-06/6425f06)
I think this is happening because make_generic_param_class () calls mono_class_setup_supertypes (). make_generic_param_class () is ultimately called from mono_class_from_mono_type () which is, in turn, called on "T2" when loading the constraint "where T1 : T2". We load constraints in the order of the generic parameter to which they apply (ie "where T1 : C1" before "where T2 : C2"). For example if the reproduction example is modified to
class GenericClass <T1, T2, T3, T4> where T4 : T2 where T2 : Foo<T3>
then typeof(Foo<T3>).IsAssignableFrom(typeof(T4)) does return True as expected.
It's not totally clear to me yet if I can just delay setting up the supertypes array in make_generic_param_class or if we need to be a lot more careful about creating a generic param MonoClass from a MonoType as a side-effect of loading the constraints.
The simple fix doesn't work: just processing the constraints in metadata.c get_constraints() is enough to cause the later type variables to be created before they've had their constraints attached.
I'm now working on two-phase creation of MonoClass-es for type variables: (1) create barebones typevariables; (2) create the constraints; (3) attach the constraints to the type variables and finish initialization.
For the record, we also get typeof (Foo<T3>).IsAssignableFrom(typeof(T1)) wrong, and for a new (but related) reason:
- our code that computes the parent class of a generic param (in mono_class_from_generic_parameter_internal ()) just checks whether the first constraint is not an interface and makes that the parent object, otherwise System.Object is the parent. (This is already wrong an naive, if a gparam has multiple constraints, but even so...)
- MONO_CLASS_IS_INTERFACE() assumes that any type variable is an interface.
- T2 cannot be an interface because it derives from a class (Foo<T3>) that is definitely not an interface.
To get this right we need to set MonoClass:parent to the (at most 1) MonoClass that *must* be a non-interface class. And we must know that gparams like T2 that derive from a class can never be interfaces.
Fixed on mono master https://github.com/mono/mono/commit/fa62f916a3c02931eb6d5f72e07b9aa37b477171
Fixed on mono 2017-08 https://github.com/mono/mono/commit/cfe2428963efce3b5130e9ce70d8b2f0a6410872