Bug 322941 (MONO80249) - [GMCS] incorrect compilation of foreach
Summary: [GMCS] incorrect compilation of foreach
Status: RESOLVED FIXED
Alias: MONO80249
Product: Mono: Compilers
Classification: Mono
Component: C# (show other bugs)
Version: 1.2
Hardware: Other Other
: P3 - Medium : Major
Target Milestone: ---
Assignee: Raja R Harinath
QA Contact: Mono Bugs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-12-13 15:27 UTC by Paolo Molaro
Modified: 2007-09-15 21:24 UTC (History)
0 users

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Wiest 2007-09-15 20:19:35 UTC


---- Reported by lupus@ximian.com 2006-12-13 08:27:29 MST ----

Given the following test:
using System;
using System.Collections;
using System.Collections.Generic;

class MyEnum : IEnumerator {
	int count = 0;
	public object Current {
		get {return "";}
	}
	public bool MoveNext () {
		if (count > 0)
			return false;
		count++;
		return true;
	}
	public void Reset () {
	}
}
class MyDict : IEnumerable<KeyValuePair<object,object>> {
	IEnumerator<KeyValuePair<object, object>> IEnumerable<KeyValuePair<object,
object>>.GetEnumerator() {
		KeyValuePair<object, object> o = new KeyValuePair<object, object>
("hello", "world");
		yield return o;
	}
	public IEnumerator GetEnumerator() {
		return new MyEnum ();
	}
}
class T {
	static void Main () {
		MyDict dict = new MyDict ();
		foreach (KeyValuePair<object, object> o in dict) {
			Console.WriteLine ("{0} {1}", o.Key, o.Value);
		}
	}
}

Compiling with gmcs yields a cast exception. This is because gmcs
calls the non-generic GetEnumerator() instead of the proper generic
implementation that returns KeyValuePair<object, object values.
This is a reduced test case from ironpython code. This bug makes a
gmcs-compiled ironpython (1.1) unusable.



---- Additional Comments From miguel@ximian.com 2006-12-13 12:32:52 MST ----

Am going to CC Marek and Martin for good measure, as he has been
looking at some of these bits recently.  Marek, do you know what is
going on?





---- Additional Comments From marek.safar@seznam.cz 2006-12-13 15:34:39 MST ----

Here is little bit simplified version

using System;
using System.Collections;
using System.Collections.Generic;

class MyDict : IEnumerable<KeyValuePair<object,object>> {
	IEnumerator<KeyValuePair<object, object>>
IEnumerable<KeyValuePair<object,object>>.GetEnumerator() {
		KeyValuePair<object, object> o = new KeyValuePair<object,
object>("hello", "world");
		yield return o;
	}

	public IEnumerator GetEnumerator() {
		throw new NotImplementedException();
	}
}
class T {
	static void Main () {
		MyDict dict = new MyDict ();
		foreach (KeyValuePair<object, object> o in dict) {
			Console.WriteLine ("{0} {1}", o.Key, o.Value);
		}
	}
}



---- Additional Comments From marek.safar@seznam.cz 2006-12-13 15:37:11 MST ----

Unfortunately it looks like not a bug because when you try to compile
the code with csc you will get exactly same result in the both cases.

InvalidCast or NotImplemented

So, we can fix it but that we will be incompatible with csc.





---- Additional Comments From lupus@ximian.com 2006-12-13 15:51:39 MST ----

Marek, thanks for checking. I reduced the test from similar code in
ironpython. Please download version 1.1 alpha 1 from
http://www.codeplex.com/IronPython. Compile with gmcs (in Src make
CSC=gmcs, change mkdir to mkdir -p in the makefile). Run mono ipy.exe
and get the crash. Take the Bin package and it will work.
The issue is in the IronPython.Runtime.Types.DynamicType.GetAttrNames
method. The sample code matches that method and the generated code in
the csc-compiled bin calls the generic method.



---- Additional Comments From rhowell@novell.com 2006-12-13 20:59:00 MST ----

Does this bug have anything to do with https://bugzilla.novell.com/show_bug.cgi?id=MONO79561 ? They both deal with
IEnumerable, Generics, and foreach loops.



---- Additional Comments From rharinath@novell.com 2006-12-13 23:27:19 MST ----

IIRC, 'foreach' prefers direct calls to GetEnumerator rather than
going through the IEnumerable interface.



---- Additional Comments From rharinath@novell.com 2006-12-13 23:47:51 MST ----

... and after a quick scan of the IronPython source code, I think the
testcase above doesn't reflect the code (and we seem to be doing the
right thing wrt the testcase).

I think the operative declaration is

  public IAttributesDictionary dict;

so, there may be some other issue.  Perhaps we are checking 'is
IEnumerable' too early somewhere.



---- Additional Comments From lupus@ximian.com 2006-12-14 07:16:46 MST ----

*** https://bugzilla.novell.com/show_bug.cgi?id=MONO80259 has been marked as a duplicate of this bug. ***



---- Additional Comments From miguel@ximian.com 2007-01-10 01:05:51 MST ----

Hello,

This seems to have regressed.  Now instead of an exception, this is
what I get from running ipy.exe:


** ERROR **: file class.c: line 574 (mono_generic_class_get_context):
assertion failed: (context->class_inst == gclass->inst)
aborting...
Stacktrace:

  at IronPython.Runtime.SystemState.Initialize () <0xffffffff>
  at IronPython.Runtime.SystemState.Initialize () <0x00043>
  at IronPython.Runtime.SystemState..ctor
(IronPython.Hosting.EngineOptions) <0x00013>
  at IronPython.Hosting.PythonEngine.Initialize
(IronPython.Hosting.EngineOptions) <0x00040>
  at IronPython.Hosting.PythonEngine..ctor
(IronPython.Hosting.EngineOptions) <0x00025>
  at IronPythonConsole.PythonCommandLine.Main (string[]) <0x00088>
  at (wrapper runtime-invoke)
System.Object.runtime_invoke_int_string[]
(object,intptr,intptr,intptr) <0xffffffff>


Paolo's original test case produces an InvalidCastException on both
gmcs and .NET 2.0.

Marek's reduced test case produces a NotImplementedException on both
gmcs and .NET 2.0.

But the new IronPython alpha still fails to start up.

The issue is in the initialization of the EmptyTypeOps`1 class:
#5  0xb7f37286 in g_assert_warning () from /opt/gnome/lib/libglib-2.0.so.0
(gdb) up
#6  0x080f41f0 in mono_generic_class_get_context (gclass=0x81eac40) at
class.c:574
574                    g_assert (context->class_inst == gclass->inst);
(gdb)
#7  0x080fa051 in mono_class_init (class=0x8333850) at class.c:2414
2414                                    gklass->methods [i], class,
mono_generic_class_get_context ((MonoGenericClass *) gclass));
(gdb) p *class
$4 = {image = 0x826a480, enum_basetype = 0x0, element_class =
0x8333850, cast_class = 0x8333850, rank = 0 '\0', inited = 0,
  init_pending = 1, size_inited = 0, valuetype = 0, enumtype = 0,
blittable = 0, unicode = 0, wastypebuilder = 0, min_align = 0,
  packing_size = 0, ghcimpl = 0, has_finalize = 0, marshalbyref = 0,
contextbound = 0, delegate = 0, gc_descr_inited = 0,
  has_cctor = 0, has_references = 0, has_static_refs = 0,
no_special_static_fields = 0, is_com_object = 0, exception_type = 0 '\0',
  exception_data = 0x0, declsec_flags = 0, parent = 0x8217d14,
nested_in = 0x0, nested_classes = 0x0, type_token = 33555017,
  name = 0xb734b8ac "EmptyTypeOps`1", name_space = 0xb7349322
"IronPython.Runtime.Types", supertypes = 0x835a6ec, idepth = 2,
  interface_count = 0, interface_id = 0, max_interface_id = 0,
interface_offsets = 0x0, interfaces = 0x0, instance_size = 0,
  vtable_size = 0, sizes = {class_size = 0, element_size = 0}, flags =
1048704, field = {first = 2364, count = 4}, method = {
    first = 7599, count = 14}, property = {first = 0, count = 0},
event = {first = 0, count = 0}, marshal_info = 0x0, fields = 0x0,
  properties = 0x0, events = 0x0, methods = 0x8333940, this_arg =
{data = {klass = 0x83336c8, type = 0x83336c8, array = 0x83336c8,
      method = 0x83336c8, generic_param = 0x83336c8, generic_class =
0x83336c8}, attrs = 0, type = 21, num_mods = 0, byref = 1,
    pinned = 0, modifiers = 0x83338e8}, byval_arg = {data = {klass =
0x83336c8, type = 0x83336c8, array = 0x83336c8,
      method = 0x83336c8, generic_param = 0x83336c8, generic_class =
0x83336c8}, attrs = 0, type = 21, num_mods = 0, byref = 0,
    pinned = 0, modifiers = 0x83338f0}, generic_class = 0x83336c8,
generic_container = 0x0, reflection_info = 0x0, gc_descr = 0x0,
  runtime_info = 0x0, vtable = 0x0}

It seems like an area that Hari has been recently looking at.




---- Additional Comments From marek.safar@seznam.cz 2007-01-10 06:27:06 MST ----

Yes, none of the test cases are the right one. That's why Paulo
recommended to download full IP and try to compile it to find what is
the real problem.



---- Additional Comments From rharinath@novell.com 2007-01-11 08:20:16 MST ----

Should be fixed in SVN r70850.


Unknown operating system unknown. Setting to default OS "Other".