/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb
637 строк
32 KB
Cyrus Najmabadi
Update code to use GetFirstLocation() instead of Locations[0] or Locations.First() (#80709)
21 окт 2025, 00:00
Не верифицирован
21 окт 2025, 00:00
3a723bb
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports System.Collections.Generic Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend NotInheritable Class AsyncRewriter Inherits StateMachineRewriter(Of CapturedSymbolOrExpression) Private ReadOnly _binder As Binder Private ReadOnly _lookupOptions As LookupOptions Private ReadOnly _asyncMethodKind As AsyncMethodKind Private ReadOnly _builderType As NamedTypeSymbol Private ReadOnly _resultType As TypeSymbol Private _builderField As FieldSymbol Private _lastExpressionCaptureNumber As Integer Public Sub New(body As BoundStatement, method As MethodSymbol, stateMachineType As AsyncStateMachine, stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, asyncKind As AsyncMethodKind, compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag) MyBase.New(body, method, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics) Me._binder = CreateMethodBinder(method) Me._lookupOptions = LookupOptions.AllMethodsOfAnyArity Or LookupOptions.IgnoreExtensionMethods Or LookupOptions.NoBaseClassLookup If compilationState.ModuleBuilderOpt.IgnoreAccessibility Then Me._binder = New IgnoreAccessibilityBinder(Me._binder) Me._lookupOptions = Me._lookupOptions Or LookupOptions.IgnoreAccessibility End If Debug.Assert(asyncKind <> AsyncMethodKind.None) Debug.Assert(asyncKind = GetAsyncMethodKind(method)) Me._asyncMethodKind = asyncKind Select Case Me._asyncMethodKind Case AsyncMethodKind.Sub Me._resultType = Me.F.SpecialType(SpecialType.System_Void) Me._builderType = Me.F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncVoidMethodBuilder) Case AsyncMethodKind.TaskFunction Me._resultType = Me.F.SpecialType(SpecialType.System_Void) Me._builderType = Me.F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder) Case AsyncMethodKind.GenericTaskFunction Me._resultType = DirectCast(Me.Method.ReturnType, NamedTypeSymbol).TypeArgumentsNoUseSiteDiagnostics().Single().InternalSubstituteTypeParameters(Me.TypeMap).Type Me._builderType = Me.F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T).Construct(Me._resultType) Case Else Throw ExceptionUtilities.UnexpectedValue(Me._asyncMethodKind) End Select End Sub ''' <summary> ''' Rewrite an async method into a state machine class. ''' </summary> Friend Overloads Shared Function Rewrite(body As BoundBlock, method As MethodSymbol, methodOrdinal As Integer, stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag, <Out> ByRef stateMachineType As AsyncStateMachine) As BoundBlock If body.HasErrors Then Return body End If Dim asyncMethodKind As AsyncMethodKind = GetAsyncMethodKind(method) If asyncMethodKind = AsyncMethodKind.None Then Return body End If ' The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. Dim kind = If(compilationState.Compilation.Options.EnableEditAndContinue, TypeKind.Class, TypeKind.Struct) stateMachineType = New AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, kind) compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType) Dim rewriter As New AsyncRewriter(body, method, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, asyncMethodKind, compilationState, diagnostics) ' check if we have all the types we need If rewriter.EnsureAllSymbolsAndSignature() Then Return body End If Return rewriter.Rewrite() End Function Private Shared Function CreateMethodBinder(method As MethodSymbol) As Binder ' For source method symbol create a binder Dim sourceMethod = TryCast(method, SourceMethodSymbol) If sourceMethod IsNot Nothing Then Return BinderBuilder.CreateBinderForMethodBody(DirectCast(sourceMethod.ContainingModule, SourceModuleSymbol), sourceMethod.ContainingType.GetFirstLocation().PossiblyEmbeddedOrMySourceTree(), sourceMethod) End If ' For all other symbols we assume that it should be a synthesized method ' placed inside source named type or in one of its nested types Debug.Assert((TypeOf method Is SynthesizedLambdaMethod) OrElse (TypeOf method Is SynthesizedInteractiveInitializerMethod)) Dim containingType As NamedTypeSymbol = method.ContainingType While containingType IsNot Nothing Dim syntaxTree = containingType.Locations.FirstOrDefault()?.SourceTree If syntaxTree IsNot Nothing Then Return BinderBuilder.CreateBinderForType( DirectCast(containingType.ContainingModule, SourceModuleSymbol), syntaxTree, containingType) End If containingType = containingType.ContainingType End While Throw ExceptionUtilities.Unreachable End Function Protected Overrides Sub GenerateControlFields() ' The fields are initialized from async method, so they need to be public: Me.StateField = Me.F.StateMachineField(Me.F.SpecialType(SpecialType.System_Int32), Me.Method, GeneratedNames.MakeStateMachineStateFieldName(), Accessibility.Public) Me._builderField = Me.F.StateMachineField(Me._builderType, Me.Method, GeneratedNames.MakeStateMachineBuilderFieldName(), Accessibility.Public) End Sub Protected Overrides Sub InitializeStateMachine(bodyBuilder As ArrayBuilder(Of BoundStatement), frameType As NamedTypeSymbol, stateMachineLocal As LocalSymbol) If frameType.TypeKind = TypeKind.Class Then ' Dim stateMachineLocal = new AsyncImplementationClass() bodyBuilder.Add( Me.F.Assignment( Me.F.Local(stateMachineLocal, True), Me.F.[New](StateMachineType.Constructor.AsMember(frameType)))) Else ' STAT: localStateMachine = Nothing ' Initialization bodyBuilder.Add( Me.F.Assignment( Me.F.Local(stateMachineLocal, True), Me.F.Null(stateMachineLocal.Type))) End If End Sub Protected Overrides ReadOnly Property PreserveInitialParameterValues As Boolean Get Return False End Get End Property Friend Overrides ReadOnly Property TypeMap As TypeSubstitution Get Return Me.StateMachineType.TypeSubstitution End Get End Property Protected Overrides Sub GenerateMethodImplementations() ' Add IAsyncStateMachine.MoveNext() GenerateMoveNext( Me.OpenMoveNextMethodImplementation( WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext, Accessibility.Friend)) 'Add IAsyncStateMachine.SetStateMachine() Me.OpenMethodImplementation( WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_SetStateMachine, "System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine", Accessibility.Private, hasMethodBodyDependency:=False) ' SetStateMachine is used to initialize the underlying AsyncMethodBuilder's reference to the boxed copy of the state machine. ' If the state machine is a class there is no copy made and thus the initialization is not necessary. ' In fact it is an error to reinitialize the builder since it already is initialized. If Me.F.CurrentType.TypeKind = TypeKind.Class Then Me.F.CloseMethod(F.Return()) Else Me.CloseMethod( Me.F.Block( Me.F.ExpressionStatement( Me.GenerateMethodCall( Me.F.Field(Me.F.Me(), Me._builderField, False), Me._builderType, "SetStateMachine", {Me.F.Parameter(Me.F.CurrentMethod.Parameters(0))})), Me.F.Return())) End If ' Constructor If StateMachineType.TypeKind = TypeKind.Class Then Me.F.CurrentMethod = StateMachineType.Constructor Me.F.CloseMethod(F.Block(ImmutableArray.Create(F.BaseInitialization(), F.Return()))) End If End Sub Protected Overrides Function GenerateStateMachineCreation(stateMachineVariable As LocalSymbol, frameType As NamedTypeSymbol) As BoundStatement Dim bodyBuilder = ArrayBuilder(Of BoundStatement).GetInstance() ' STAT: localStateMachine.$stateField = NotStartedStateMachine Dim stateFieldAsLValue As BoundExpression = Me.F.Field( Me.F.Local(stateMachineVariable, True), Me.StateField.AsMember(frameType), True) bodyBuilder.Add( Me.F.Assignment( stateFieldAsLValue, Me.F.Literal(StateMachineState.NotStartedOrRunningState))) ' STAT: localStateMachine.$builder = System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of typeArgs).Create() Dim constructedBuilderField As FieldSymbol = Me._builderField.AsMember(frameType) Dim builderFieldAsLValue As BoundExpression = Me.F.Field(Me.F.Local(stateMachineVariable, True), constructedBuilderField, True) ' All properties and methods will be searched in this type Dim builderType As TypeSymbol = constructedBuilderField.Type bodyBuilder.Add( Me.F.Assignment( builderFieldAsLValue, Me.GenerateMethodCall(Nothing, builderType, "Create"))) ' STAT: localStateMachine.$builder.Start(ref localStateMachine) -- binding to the method AsyncTaskMethodBuilder<typeArgs>.Start(...) bodyBuilder.Add( Me.F.ExpressionStatement( Me.GenerateMethodCall( builderFieldAsLValue, builderType, "Start", ImmutableArray.Create(Of TypeSymbol)(frameType), Me.F.Local(stateMachineVariable, True)))) ' STAT: Return ' or ' STAT: Return localStateMachine.$builder.Task bodyBuilder.Add( If(Me._asyncMethodKind = AsyncMethodKind.[Sub], Me.F.Return(), Me.F.Return(Me.GeneratePropertyGet(builderFieldAsLValue, builderType, "Task")))) Return RewriteBodyIfNeeded(Me.F.Block(ImmutableArray(Of LocalSymbol).Empty, bodyBuilder.ToImmutableAndFree()), Me.F.TopLevelMethod, Me.Method) End Function Private Sub GenerateMoveNext(moveNextMethod As MethodSymbol) Dim rewriter = New AsyncMethodToClassRewriter( method:=Method, F:=F, state:=StateField, builder:=_builderField, hoistedVariables:=hoistedVariables, nonReusableLocalProxies:=nonReusableLocalProxies, StateDebugInfoBuilder, slotAllocatorOpt:=SlotAllocatorOpt, owner:=Me, diagnostics:=Diagnostics) rewriter.GenerateMoveNext(Body, moveNextMethod) End Sub Friend Overrides Function RewriteBodyIfNeeded(body As BoundStatement, topMethod As MethodSymbol, currentMethod As MethodSymbol) As BoundStatement If body.HasErrors Then Return body End If Dim rewrittenNodes As HashSet(Of BoundNode) = Nothing Dim hasLambdas As Boolean = False Dim symbolsCapturedWithoutCtor As ISet(Of Symbol) = Nothing If body.Kind <> BoundKind.Block Then body = Me.F.Block(body) End If Const rewritingFlags As LocalRewriter.RewritingFlags = LocalRewriter.RewritingFlags.AllowSequencePoints Or LocalRewriter.RewritingFlags.AllowEndOfMethodReturnWithExpression Or LocalRewriter.RewritingFlags.AllowCatchWithErrorLineNumberReference Return LocalRewriter.Rewrite(DirectCast(body, BoundBlock), topMethod, F.CompilationState, previousSubmissionFields:=Nothing, diagnostics:=Me.Diagnostics, rewrittenNodes:=rewrittenNodes, hasLambdas:=hasLambdas, symbolsCapturedWithoutCopyCtor:=symbolsCapturedWithoutCtor, flags:=rewritingFlags, instrumenterOpt:=Nothing, ' Do not instrument anything during this rewrite currentMethod:=currentMethod) End Function ''' <returns> ''' Returns true if any members that we need are missing or have use-site errors. ''' </returns> Friend Overrides Function EnsureAllSymbolsAndSignature() As Boolean If MyBase.EnsureAllSymbolsAndSignature Then Return True End If Dim bag = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, withDependencies:=Me.Diagnostics.AccumulatesDependencies) EnsureSpecialType(SpecialType.System_Object, bag) EnsureSpecialType(SpecialType.System_Void, bag) EnsureSpecialType(SpecialType.System_ValueType, bag) EnsureWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine, bag) EnsureWellKnownMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext, bag) EnsureWellKnownMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_SetStateMachine, bag) ' We don't ensure those types because we don't know if they will be actually used, ' use-site errors will be reported later if any of those types is actually requested ' ' EnsureSpecialType(SpecialType.System_Boolean, hasErrors) ' EnsureWellKnownType(WellKnownType.System_Runtime_CompilerServices_ICriticalNotifyCompletion, hasErrors) ' EnsureWellKnownType(WellKnownType.System_Runtime_CompilerServices_INotifyCompletion, hasErrors) ' NOTE: We don't ensure DebuggerStepThroughAttribute, it is just not emitted if not found ' EnsureWellKnownMember(Of MethodSymbol)(WellKnownMember.System_Diagnostics_DebuggerStepThroughAttribute__ctor, hasErrors) Select Case Me._asyncMethodKind Case AsyncMethodKind.GenericTaskFunction EnsureWellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T, bag) Case AsyncMethodKind.TaskFunction EnsureWellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder, bag) Case AsyncMethodKind.[Sub] EnsureWellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncVoidMethodBuilder, bag) Case Else Throw ExceptionUtilities.UnexpectedValue(Me._asyncMethodKind) End Select Dim hasErrors As Boolean = bag.HasAnyErrors If hasErrors Then Me.Diagnostics.AddRange(bag) End If bag.Free() Return hasErrors End Function ''' <summary> ''' Specifies a kind of an Async method ''' ''' None is returned for non-Async methods or methods with wrong return type ''' </summary> Friend Enum AsyncMethodKind None [Sub] TaskFunction GenericTaskFunction End Enum ''' <summary> ''' Returns method's async kind ''' </summary> Friend Shared Function GetAsyncMethodKind(method As MethodSymbol) As AsyncMethodKind Debug.Assert(Not method.IsPartial) If Not method.IsAsync Then Return AsyncMethodKind.None End If If method.IsSub Then Return AsyncMethodKind.[Sub] End If Dim compilation As VisualBasicCompilation = method.DeclaringCompilation Debug.Assert(compilation IsNot Nothing) Dim returnType As TypeSymbol = method.ReturnType If TypeSymbol.Equals(returnType, compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task), TypeCompareKind.ConsiderEverything) Then Return AsyncMethodKind.TaskFunction End If If returnType.Kind = SymbolKind.NamedType AndAlso TypeSymbol.Equals(returnType.OriginalDefinition, compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T), TypeCompareKind.ConsiderEverything) Then Return AsyncMethodKind.GenericTaskFunction End If ' Wrong return type Return AsyncMethodKind.None End Function Protected Overrides Function CreateByRefLocalCapture(typeMap As TypeSubstitution, local As LocalSymbol, initializers As Dictionary(Of LocalSymbol, BoundExpression)) As CapturedSymbolOrExpression Debug.Assert(local.IsByRef) Return CaptureExpression(typeMap, initializers(local), initializers) End Function Private Function CaptureExpression(typeMap As TypeSubstitution, expression As BoundExpression, initializers As Dictionary(Of LocalSymbol, BoundExpression)) As CapturedSymbolOrExpression If expression Is Nothing Then Return Nothing End If Select Case expression.Kind Case BoundKind.Literal Debug.Assert(Not expression.IsLValue) ' TODO: Do we want to extend support of this constant ' folding to non-literal expressions? Return New CapturedConstantExpression(expression.ConstantValueOpt, expression.Type.InternalSubstituteTypeParameters(typeMap).Type) Case BoundKind.Local Return CaptureLocalSymbol(typeMap, DirectCast(expression, BoundLocal).LocalSymbol, initializers) Case BoundKind.Parameter Return CaptureParameterSymbol(typeMap, DirectCast(expression, BoundParameter).ParameterSymbol) Case BoundKind.MeReference Return CaptureParameterSymbol(typeMap, Me.Method.MeParameter) Case BoundKind.MyClassReference Return CaptureParameterSymbol(typeMap, Me.Method.MeParameter) Case BoundKind.MyBaseReference Return CaptureParameterSymbol(typeMap, Me.Method.MeParameter) Case BoundKind.FieldAccess If Not expression.IsLValue Then GoTo lCaptureRValue End If Dim fieldAccess = DirectCast(expression, BoundFieldAccess) Return New CapturedFieldAccessExpression(CaptureExpression(typeMap, fieldAccess.ReceiverOpt, initializers), fieldAccess.FieldSymbol) Case BoundKind.ArrayAccess If Not expression.IsLValue Then GoTo lCaptureRValue End If Dim arrayAccess = DirectCast(expression, BoundArrayAccess) Dim capturedArrayPointer As CapturedSymbolOrExpression = CaptureExpression(typeMap, arrayAccess.Expression, initializers) Dim indices As ImmutableArray(Of BoundExpression) = arrayAccess.Indices Dim indicesCount As Integer = indices.Length Dim capturedIndices(indicesCount - 1) As CapturedSymbolOrExpression For i = 0 To indicesCount - 1 capturedIndices(i) = CaptureExpression(typeMap, indices(i), initializers) Next Return New CapturedArrayAccessExpression(capturedArrayPointer, capturedIndices.AsImmutableOrNull) Case Else lCaptureRValue: Debug.Assert(Not expression.IsLValue, "Need to support LValues of type " + expression.GetType.Name) Me._lastExpressionCaptureNumber += 1 Return New CapturedRValueExpression( Me.F.StateMachineField( expression.Type, Me.Method, GeneratedNameConstants.StateMachineExpressionCapturePrefix & Me._lastExpressionCaptureNumber, Accessibility.Friend), expression) End Select Throw ExceptionUtilities.UnexpectedValue(expression.Kind) End Function Protected Overrides Sub InitializeParameterWithProxy(parameter As ParameterSymbol, proxy As CapturedSymbolOrExpression, stateMachineVariable As LocalSymbol, initializers As ArrayBuilder(Of BoundExpression)) Debug.Assert(TypeOf proxy Is CapturedParameterSymbol) Dim field As FieldSymbol = DirectCast(proxy, CapturedParameterSymbol).Field Dim frameType As NamedTypeSymbol = If(Me.Method.IsGenericMethod, Me.StateMachineType.Construct(Me.Method.TypeArguments), Me.StateMachineType) Dim expression As BoundExpression = If(parameter.IsMe, DirectCast(Me.F.[Me](), BoundExpression), Me.F.Parameter(parameter).MakeRValue()) initializers.Add( Me.F.AssignmentExpression( Me.F.Field( Me.F.Local(stateMachineVariable, True), field.AsMember(frameType), True), expression)) End Sub Protected Overrides Function CreateByValLocalCapture(field As FieldSymbol, local As LocalSymbol) As CapturedSymbolOrExpression Return New CapturedLocalSymbol(field, local) End Function Protected Overrides Function CreateParameterCapture(field As FieldSymbol, parameter As ParameterSymbol) As CapturedSymbolOrExpression Return New CapturedParameterSymbol(field) End Function #Region "Method call and property access generation" Private Function GenerateMethodCall(receiver As BoundExpression, type As TypeSymbol, methodName As String, ParamArray arguments As BoundExpression()) As BoundExpression Return GenerateMethodCall(receiver, type, methodName, ImmutableArray(Of TypeSymbol).Empty, arguments) End Function Private Function GenerateMethodCall(receiver As BoundExpression, type As TypeSymbol, methodName As String, typeArgs As ImmutableArray(Of TypeSymbol), ParamArray arguments As BoundExpression()) As BoundExpression ' Get the method group Dim methodGroup = FindMethodAndReturnMethodGroup(receiver, type, methodName, typeArgs) If methodGroup Is Nothing OrElse arguments.Any(Function(a) a.HasErrors) OrElse (receiver IsNot Nothing AndAlso receiver.HasErrors) Then Return Me.F.BadExpression(arguments) End If ' Do overload resolution and bind an invocation of the method. Dim result = _binder.BindInvocationExpression(Me.F.Syntax, Me.F.Syntax, TypeCharacter.None, methodGroup, ImmutableArray.Create(Of BoundExpression)(arguments), argumentNames:=Nothing, diagnostics:=Me.Diagnostics, callerInfoOpt:=Nothing) Return result End Function Private Function FindMethodAndReturnMethodGroup(receiver As BoundExpression, type As TypeSymbol, methodName As String, typeArgs As ImmutableArray(Of TypeSymbol)) As BoundMethodGroup Dim group As BoundMethodGroup = Nothing Dim result = LookupResult.GetInstance() Dim useSiteInfo = Me._binder.GetNewCompoundUseSiteInfo(Me.Diagnostics) Me._binder.LookupMember(result, type, methodName, arity:=0, options:=_lookupOptions, useSiteInfo:=useSiteInfo) Me.Diagnostics.Add(Me.F.Syntax, useSiteInfo) If result.IsGood Then Debug.Assert(result.Symbols.Count > 0) Dim symbol0 = result.Symbols(0) If result.Symbols(0).Kind = SymbolKind.Method Then group = New BoundMethodGroup(Me.F.Syntax, Me.F.TypeArguments(typeArgs), result.Symbols.ToDowncastedImmutable(Of MethodSymbol), result.Kind, receiver, QualificationKind.QualifiedViaValue) End If End If If group Is Nothing Then Me.Diagnostics.Add(If(result.HasDiagnostic, result.Diagnostic, ErrorFactory.ErrorInfo(ERRID.ERR_NameNotMember2, methodName, type)), Me.F.Syntax.GetLocation()) End If result.Free() Return group End Function Private Function GeneratePropertyGet(receiver As BoundExpression, type As TypeSymbol, propertyName As String) As BoundExpression ' Get the property group Dim propertyGroup = FindPropertyAndReturnPropertyGroup(receiver, type, propertyName) If propertyGroup Is Nothing OrElse (receiver IsNot Nothing AndAlso receiver.HasErrors) Then Return Me.F.BadExpression() End If ' Do overload resolution and bind an invocation of the property. Dim result = _binder.BindInvocationExpression(Me.F.Syntax, Me.F.Syntax, TypeCharacter.None, propertyGroup, Nothing, argumentNames:=Nothing, diagnostics:=Me.Diagnostics, callerInfoOpt:=Nothing) ' reclassify property access as Get If result.Kind = BoundKind.PropertyAccess Then result = DirectCast(result, BoundPropertyAccess).SetAccessKind(PropertyAccessKind.Get) End If Debug.Assert(Not result.IsLValue) Return result End Function Private Function FindPropertyAndReturnPropertyGroup(receiver As BoundExpression, type As TypeSymbol, propertyName As String) As BoundPropertyGroup Dim group As BoundPropertyGroup = Nothing Dim result = LookupResult.GetInstance() Dim useSiteInfo = Me._binder.GetNewCompoundUseSiteInfo(Me.Diagnostics) Me._binder.LookupMember(result, type, propertyName, arity:=0, options:=_lookupOptions, useSiteInfo:=useSiteInfo) Me.Diagnostics.Add(Me.F.Syntax, useSiteInfo) If result.IsGood Then Debug.Assert(result.Symbols.Count > 0) Dim symbol0 = result.Symbols(0) If result.Symbols(0).Kind = SymbolKind.Property Then group = New BoundPropertyGroup(Me.F.Syntax, result.Symbols.ToDowncastedImmutable(Of PropertySymbol), result.Kind, receiver, QualificationKind.QualifiedViaValue) End If End If If group Is Nothing Then Me.Diagnostics.Add(If(result.HasDiagnostic, result.Diagnostic, ErrorFactory.ErrorInfo(ERRID.ERR_NameNotMember2, propertyName, type)), Me.F.Syntax.GetLocation()) End If result.Free() Return group End Function #End Region End Class End Namespace