Open dpoeschl opened 9 years ago
FYI @amcasey
Reduced repro:
Run to the breakpoint and then evaluate t.x
class Program
{
int x;
static void Main(string[] args)
{
M(new Program());
}
static void M<T>(T t)
{
System.Diagnostics.Debugger.Break();
}
}
The same thing happens for type-level type parameters.
class Program
{
int x;
static void Main(string[] args)
{
C<Program>.M(new Program(), new Program());
}
}
class C<T>
{
public static void M<U>(T t, U u)
{
System.Diagnostics.Debugger.Break();
}
}
This looks like a simple fullname bug. We just have to catch to the runtime type because the un-cast expression is typed as a type parameter.
There's a mismatch between the EC and the RP. In the EC the declared type is the type parameter. In the RP, the declared type is the type argument. Since the RP doesn't know about the type parameter, it doesn't insert the cast that the EC requires.
If you manually add the a watch to the full name without the cast, the legacy EE also rejects it. Curiously though, it requires only a single cast, whereas Roslyn requires an intermediate cast to object (per the regular C# rules). Maybe the legacy EE binder is more generous than the regular legacy binder.
My feeling is that the EC behavior is by design and the problem lies with the RP - specifically the full name. However, as things stand, I'm not sure the RP has enough information to insert the required casts.
Consider the following method:
void M<U>(U u)
{
}
In the body of M, we’ll display a row in the Locals window for u
. As far as I can tell, none of the values passed to IDkmClrResultProvider.GetResult
indicate that the declared type of u
was U
. As a result, the full names of u
's children (i.e. the members of the runtime type of u
, Bag
in the bug) generate C# expressions as though the declared type matched the runtime type (i.e. no cast is inserted). The expression compiler, however, has no knowledge of runtime types and considers u
to be of type U
. Obviously, U
has no members, so dotting into u
fails. The upshot is that you can see the children of u
if you expand it, but you can’t add watches to them.
Dev12:
u
– works
u.x
– “x is not a member of U”
((Bag)u).x
– works (generated full name)
((Bag)(object)u).x
– works
Roslyn:
u
– works
u.x
– “x is not a member of U” (generated full name)
((Bag)u).x
– “U cannot be converted to Bag” (i.e. same as during regular compilation)
((Bag)(object)u).x
– works
This is unfortunate, but I don’t think the work of designing and implementing a new information channel between Concord and the ResultProvider is justified at this point in the cycle, especially since the row is visible as a child of its parent (or directly if you manually insert the casts).
registries.array[0].handler
to the watch window. It should evaluate correctly.Method
(or any other child) and Add WatchExpected: Watch evaluates correctly. Actual: error CS1061: 'TEventHandler' does not contain a definition for 'Method' and no extension method 'Method' accepting a first argument of type 'TEventHandler' could be found (are you missing a using directive or an assembly reference?)