Skip to content

Speculative semantic model produces different behavior for local functions  #24135

@agocke

Description

@agocke

See the behavior in this test:

        [Fact]
        public void LocalFunctionAttribute()
        {
            const string text = @"
using System;
class A : Attribute {}

class C
{
    static void M()
    {
        void local<[A]T>() {}
    }
}";
            var tree = SyntaxFactory.ParseSyntaxTree(text);
            var comp = CreateStandardCompilation(tree);
            var model = comp.GetSemanticModel(tree);
            var a = tree.GetRoot().DescendantNodes()
                .OfType<IdentifierNameSyntax>().ElementAt(2);
            Assert.Equal("A", a.Identifier.Text);
            var attrInfo = model.GetSymbolInfo(a);
            var attrType = comp.GlobalNamespace.GetTypeMember("A");
            var attrCtor = attrType.GetMember(".ctor");
            Assert.Equal(attrCtor, attrInfo.Symbol);

            // Assert that this is also true for the speculative semantic model
            var newTree = SyntaxFactory.ParseSyntaxTree(text + " ");
            var m = newTree.GetRoot()
                .DescendantNodes().OfType<MethodDeclarationSyntax>().Single();

            Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(m.Body.SpanStart, m, out model));

            a = newTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().ElementAt(2);
            Assert.Equal("A", a.Identifier.Text);

            // If we aren't using the right binder here, the compiler crashes going through the binder factory
            var info = model.GetSymbolInfo(a);
            Assert.Equal(attrType, info.Symbol);
        }

When using the regular semantic model, the symbol returned by GetSymbolInfo is the attribute constructor. When using the speculative semantic model, the type is returned instead.

The root cause of this seems to be that TryGetSpeculativeSemanticModelForMethodBody directly returns a MethodBody semantic model, which bypasses the GetMemberModel call which may be needed to retrieve a more specific model (like an Attribute or InitializerSemanticModel) that may be needed to bind pieces of local functions.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions