dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.11k stars 4.04k forks source link

[VB] Type inference fails on inner type of jagged array literals #36504

Open bandleader opened 5 years ago

bandleader commented 5 years ago

Version Used: VS2015

Code to Reproduce: (also available in fiddle)

'This works, and prints: 'System.String[]'
Dim array1 As String() = {}
Console.WriteLine(array1.GetType()) 

'The following line fails at runtime with the error: 
'"System.InvalidCastException: Unable to cast object of type 
'System.Object[]' to type 'System.String[]'."
Dim array2 As String()() = {({})}
Console.WriteLine(array2(0).GetType()) 'Never executes, but would say 'System.Object[]'.

Expected Behavior: Type inference should type the RHS of the expression {({})} as declared on the left side: String()() i.e. an array of an array of String.

Actual Behavior: The outer array { ... } on the RHS is correctly typed as String() like on the LHS, but the inner array ({}) is incorrectly typed as Object(), which results in the error message above.

(Also, this is not caught at compile-time, only at runtime, which just crashed our production app.)

Further reference: https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/arrays/how-to-initialize-an-array-variable#to-initialize-a-jagged-array-variable-by-using-array-literals

wqnvlz commented 5 years ago

This not being caught at compile-time seems to be an Option-Strict-Off gotcha.

With Option Strict off, the inner literal, lacking a target type, is typed as Object() without complaint; with Option Strict on, the code does not compile because assuming Object for element type is disallowed.

This appears to be a more general problem of array literals failing to find a target type in many situations, such as when parenthesized or when used as an operand in an infix operator expression (method-style operator invocations behave like regular method calls).

Current behavior of similar constructs: