This project is read-only.
1
Vote

GetQueryClauseInfo has incorrect CastInfo for simple select-many query using IQueryable

description

An explicit type in any "from" clause should induce a Cast call on the collection expression in the clause. The symbol associated with this call should be returned by a call to GetQueryClauseInfo. Oddly enough, this is done correctly if the collection expression is IEnumerable<object> but NOT if it is IQueryable<object>, and it fails on the second from clause but not the first.

A program will make it more clear.
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace EricLippertScratch
{
    class Program
    {
        static void Main(string[] args)
        {
            const string sourceText = @"
using System.Linq;
using System.Collections.Generic;
class C
{
    static IEnumerable<object> M(int q) { return null; }
    void M(IEnumerable<object> seq)
    {
        var r = from int x in seq
                from int y in M(x)
                select x + y;
    }

    static IQueryable<object> N(int q) { return null; }
    void M(IQueryable<object> seq)
    {
        var r = from int x in seq
                from int y in N(x)
                select x + y;
    }

}
";
            var references =
                ImmutableArray.Create(
                    typeof(object),
                    typeof(System.Linq.Enumerable))
                .Select(type => new MetadataFileReference(
                    fullPath: type.Assembly.Location,
                    kind: MetadataImageKind.Assembly,
                    alias: null,
                    embedInteropTypes: false))
                .ToImmutableArray();

            var tree = SyntaxFactory.ParseSyntaxTree(sourceText, "fileName", CSharpParseOptions.Default);

            var compilation = CSharpCompilation.Create(
                assemblyName: "outputFile",
                options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
                syntaxTrees: new[] { tree },
                references: references);

            var model = compilation.GetSemanticModel(tree);

            var diagnostics = compilation.GetDiagnostics();

            var clauses = tree
                .GetRoot()
                .DescendantNodes()
                .OfType<FromClauseSyntax>()
                .ToImmutableArray();

            var casts = clauses
                .Select(clause => model.GetQueryClauseInfo(clause).CastInfo.Symbol)
                .ToImmutableArray();

            foreach(var cast in casts)
                Console.WriteLine(cast != null);
        }
    } 
}
Expected output: true true true true
Observed output: true true true false

I have not yet debugged into the analyzer to figure out what is going wrong here.

comments