Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
Mono organizations on
GitHub to continue tracking issues. Bugzilla will remain
available for reference in read-only mode. We will continue to work
on open Bugzilla bugs, copy them to the new locations
as needed for follow-up, and add the new items under Related
Our sincere thanks to everyone who has contributed on this bug
tracker over the years. Thanks also for your understanding as we
make these adjustments and improvements for the future.
Please create a new report on
GitHub or Developer Community with
your current version information, steps to reproduce, and relevant error
messages or log files if you are hitting an issue that looks similar to
this resolved bug and you do not yet see a matching new report.
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 22.214.171.124 (2017-04/ef39d08) as well as on .NET.
I can reproduce with Mono 126.96.36.199 (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