Bug 40060 - System.TypeSpec.Parse cannot parse generics + anonymous type name
Summary: System.TypeSpec.Parse cannot parse generics + anonymous type name
Alias: None
Product: Runtime
Classification: Mono
Component: Reflection ()
Version: 4.2.0 (C6)
Hardware: PC Mac OS
: --- normal
Target Milestone: ---
Assignee: Aleksey Kliger
Depends on:
Blocks: 40057
  Show dependency tree
Reported: 2016-04-01 18:24 UTC by Aaron Bockover [MSFT]
Modified: 2016-04-07 01:28 UTC (History)
3 users (show)

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

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 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.

Related Links:

Description Aaron Bockover [MSFT] 2016-04-01 18:24:10 UTC
It seems that some Type.GetType methods use Type.internal_from_name to parse a type name (e.g. Type.GetType(string)), but some use TypeNameParser.GetType (e.g. Type.GetType(string, Func<AssemblyName,Assembly>, Func<Assembly,string,bool,Type>)).

We require a Type.GetType call that ends up calling TypeSpec.Parse by way of TypeNameParser.GetType in the Inspector, which hits this limitation when given a type name that includes generics and anonymous types:

  Type.GetType (new [] { new { A = 1 } }
      .ToDictionary (x => x.A)
      .GetType ()
      .ToString (), null, null)

Will result in:

System.ArgumentException: Invalid generic arguments spec                        Parameter name: typeName
  at System.TypeSpec.Parse (System.String name, System.Int32& p, Boolean is_recurse, Boolean allow_aqn) <0x1b66c00 + 0x00ada> in <filename unknown>:0
  at System.TypeSpec.Parse (System.String typeName) <0x1b660e0 + 0x0004c> in <filename unknown>:0
  at System.TypeNameParser.GetType (System.String typeName, System.Func`2 assemblyResolver, System.Func`4 typeResolver, Boolean throwOnError, Boolean ignoreCase, System.Threading.StackCrawlMark& stackMark) <0x1a11d60 + 0x0001d> in <filename unknown>:0
  at System.Type.GetType (System.String typeName, System.Func`2 assemblyResolver, System.Func`4 typeResolver) <0x198ab10 + 0x00050> in <filename unknown>:0
  at <InteractiveExpressionClass>.Host (System.Object& $retval) <0x302a248 + 0x000e7> in <filename unknown>:0
  at Mono.CSharp.Evaluator.Evaluate (System.String input, System.Object& result, System.Boolean& result_set) <0x6bca58 + 0x000ab> in <filename unknown>:0
  at Mono.CSharpShell.Evaluate (System.String input) <0x6bc970 + 0x00043> in <filename unknown>:0

The type name it is attempting to parse is:

Comment 1 Aleksey Kliger 2016-04-04 15:57:29 UTC

I think Type.GetType(string) also can't parse anon types correctly (ie your code above without the ,null,null args).

Looks like the example parses correctly on .NET, however.

I'll work on updating both parsers.
Comment 3 Aleksey Kliger 2016-04-04 20:38:14 UTC
It's not the parsers. It's how we do name resolution.

Here's a repro where .NET resolves the type, but Mono doesn't:

using System;
using System.Collections.Generic;

sealed class Jones<T>
    public readonly T A;
    public Jones(T a)
        A = a;
namespace Bug40060
    class Program
        static Dictionary<int, T> MakeDict<T>(T[] a)
            return new Dictionary<int, T>();

        static void Main(string[] args)
        {   var a = new Jones<int>[0];
            var t = MakeDict(a).GetType();
            var s = t.ToString();
            var tout = Type.GetType(s);
            Console.WriteLine("{0} is {1}", s, tout);
Comment 4 Aaron Bockover [MSFT] 2016-04-04 21:07:00 UTC
I think there are two separate bugs though

1. Bug in the managed parser, TypeSpec.Parse, which is the reason for this bug
2. Type.GetType (string) is parsing properly (by way of native code in mono_reflection_parse_type), but not resolving (new bug)
Comment 5 Aleksey Kliger 2016-04-04 21:14:33 UTC
No, (1) is not a problem.  The following code works as expected.  Note that I'm using FullName instead of ToString() to get around the resolver issue.   (In any case this example first takes a trip through our managed parser and then down into the native code to get everything resolved.)

using System;
using System.Collections.Generic;

namespace Bug40060
    class Program
	    static Dictionary<int,T> MakeDict<T>(T[] a)
		    return new Dictionary <int, T>();
        static void Main(string[] args)
	    var a = new { A = 1 };
	    var d = new [] { a };
            var tin = MakeDict(d).GetType (); // new[] { new { A = 1 } }.ToDictionary(x => x.A).GetType();
	    var s = tin.FullName;
	    var tout = Type.GetType(s, null, (assm,w,b) => Type.GetType(w));
            Console.WriteLine("\"{0}\" is {1}", s, tout);


"System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089],[<>__AnonType0`1[[System.Int32, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089]], ReproFullNames, Version=, Culture=neutral, PublicKeyToken=null]]" is System.Collections.Generic.Dictionary`2[System.Int32,<>__AnonType0`1[System.Int32]]
Comment 7 Aleksey Kliger 2016-04-07 01:28:18 UTC
Fixed on mono master commit 895071150a68b0a1d704f3b99ac90ee288f6e792

Fixed on mono-4.4.0-branch commit b36eb0de890aceb64605734af63a370e45ba88d2