Bug 3285 - Generic methods crashing - CRISIS
Summary: Generic methods crashing - CRISIS
Alias: None
Product: iOS
Classification: Xamarin
Component: General ()
Version: 5.2
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Sebastien Pouliot
: 3449 ()
Depends on:
Reported: 2012-02-09 03:43 UTC by Amanda
Modified: 2012-02-24 11:57 UTC (History)
2 users (show)

Is this bug a regression?: ---
Last known good build:

Monotouch version screen (61.50 KB, image/png)
2012-02-09 03:45 UTC, Amanda

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and 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 Links.

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 Developer Community or GitHub 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.

Related Links:

Description Amanda 2012-02-09 03:43:59 UTC

My app has started crashing on generic methods when debugging to the iPhone. It does not happen on the simulator. It also never used to happen on previous versions. The code has not changed

An example of where it happens:

public Employees GetEmployees(Employee employeeTemplate)
 return this.Get<Employees>(this.Process, "GetEmployees", employeeTemplate);

and then it never gets here:

 protected B Get<B>(BusinessObject owner, string methodName, params object[] args)

return GetImpl<B>(XmlCompressionMethod.GZip, methodName,  ref args);
 etc, etc....

I have attached the version screen
Comment 1 Amanda 2012-02-09 03:45:07 UTC
Created attachment 1328 [details]
Monotouch version screen
Comment 2 Sebastien Pouliot 2012-02-14 21:42:24 UTC
*** Bug 3449 has been marked as a duplicate of this bug. ***
Comment 3 Sebastien Pouliot 2012-02-14 21:46:54 UTC
You're likely hitting a limitation of the AOT compiler [1]. These do not occur on the simulator where the JIT (x86) is being used. OTOH the version of MonoTouch you're using should not influence the issue.

It's difficult to know which one (or if it could be something else) without more context about the code you're executing. Please attach a test case we can compile and duplicate the issue and we'll be able to pinpoint the issue and, often, suggest a simple workaround for it.

[1] http://docs.xamarin.com/ios/about/limitations#Limited_Generics_Support
Comment 4 Amanda 2012-02-15 12:30:45 UTC
Hi Sebastian

Thank you for your prompt reply. On further investigation we found that the actual cause is in this code below.
We have resolved the issue. It seems that a yield break within an IEnumerable method, called by a lamba statement, confuses the compiler

 // NOTE: This is the code that caused the problem
 // return GetInterfaces(type, interfaceType).Select(interf => interf != null).FirstOrDefault();
 // NOTE: When changed to this it works:

                   foreach (Type interf in GetInterfaces(type, interfaceType))
                       return interf != null;
                   return false;

public static IEnumerable<Type> GetInterfaces(this Type type, Type interfaceType)
			Type[] interfaces = type.GetInterfaces();
			foreach (Type t in interfaces)
				Type typeToCheck = t;
				if (t.IsGenericType)
					typeToCheck = t.GetGenericTypeDefinition();
				if (typeToCheck == interfaceType)
					yield return t;
			yield break;
Comment 5 Sebastien Pouliot 2012-02-23 14:13:09 UTC
Amanda, thanks for providing the test case. LINQ introduce it's own generic code which makes it difficult for the AOT compiler to predict the final usage.

So while this did not work:
return GetInterfaces(type, interfaceType).Select(interf => interf != null).FirstOrDefault();

the following is working:
return GetInterfaces(type, interfaceType).Select(interf => interf !=null).FirstOrDefault(delegate { return true; });

which is identical, execution wise, but the later is clear enough for the AOT compiler to produce the required code. 

I already made a similar fix in the past, but it did not cover this case. I'll try to generalize it so it cover more (including this) case(s).
Comment 6 Sebastien Pouliot 2012-02-23 15:12:06 UTC
Fixed in master (for MonoTouch 5.3)
Comment 7 Amanda 2012-02-24 11:57:49 UTC
Hi Sebastian

I made the change as per your suggestion, and everything  works fine - thanks for your help