Repository: dotnet/roslyn
File: src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs (C#)

Code before:
                        arguments: arguments,
                        argumentNamesOpt: default(ImmutableArray<string>),
                        argumentRefKindsOpt: default(ImmutableArray<RefKind>),
                        isDelegateCall: false,
                        expanded: false,
                        invokedAsExtensionMethod: false,
                        argsToParamsOpt: default(ImmutableArray<int>),
                        defaultArguments: default(BitVector),
                        resultKind: LookupResultKind.Viable,
                        type: userMain.ReturnType)
                { WasCompilerGenerated = true };

                // Try to use the new HandleAsyncEntryPoint API if it exists
                var specialMember = userMain.ReturnType.IsGenericTaskType(compilation)
                    ? SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__HandleAsyncEntryPoint_Task_T
                    : SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__HandleAsyncEntryPoint_Task;

                if (Binder.TryGetSpecialTypeMember(compilation, specialMember, _userMainReturnTypeSyntax, BindingDiagnosticBag.Discarded, out MethodSymbol handleAsyncEntryPointMethod, isOptional: true))
                {
                    // Use the new HandleAsyncEntryPoint API
                    _userEntryPointCall = new BoundCall(
                            syntax: _userMainReturnTypeSyntax,
                            receiverOpt: null,
                            initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown,
                            method: handleAsyncEntryPointMethod,
                            arguments: ImmutableArray.Create<BoundExpression>(userMainInvocation),
                            argumentNamesOpt: default(ImmutableArray<string>),
                            argumentRefKindsOpt: default(ImmutableArray<RefKind>),
                            isDelegateCall: false,
                            expanded: false,
                            invokedAsExtensionMethod: false,
                            argsToParamsOpt: default(ImmutableArray<int>),
                            defaultArguments: default(BitVector),
                            resultKind: LookupResultKind.Viable,
                            type: handleAsyncEntryPointMethod.ReturnType)
                    { WasCompilerGenerated = true };
                }
                else
                {
                    // Fall back to the old GetAwaiter/GetResult pattern
                    // The diagnostics that would be produced here will already have been captured and returned.
                    var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _userEntryPointCall!, runtimeAsyncAwaitCall: out _, _userMainReturnTypeSyntax, BindingDiagnosticBag.Discarded);
                }

                Debug.Assert(
                    ReturnType.IsVoidType() ||
                    ReturnType.SpecialType == SpecialType.System_Int32);
                Debug.Assert(!compilation.IsRuntimeAsyncEnabledIn(this));
            }

            internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder<CSharpAttributeData> attributes)

Review comment (suggestion):
>userMainInvocation [](http://example.com/codeflow?start=78&length=18)

Is there a guarantee that the argument type matches? Could. for example, user's main return a user defined `Task` type distinct from one used by the API we are about to call?  #Closed

Code after:
                        receiverOpt: null,
                        initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown,
                        method: userMain,
                        arguments: arguments,
                        argumentNamesOpt: default(ImmutableArray<string>),
                        argumentRefKindsOpt: default(ImmutableArray<RefKind>),
                        isDelegateCall: false,
                        expanded: false,
                        invokedAsExtensionMethod: false,
                        argsToParamsOpt: default(ImmutableArray<int>),
                        defaultArguments: default(BitVector),
                        resultKind: LookupResultKind.Viable,
                        type: userMain.ReturnType)
                { WasCompilerGenerated = true };

                // Try to use the new HandleAsyncEntryPoint API if it exists
                var specialMember = userMain.ReturnType.IsGenericTaskType(compilation)
                    ? SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__HandleAsyncEntryPoint_Task_Int32
                    : SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__HandleAsyncEntryPoint_Task;

                if (Binder.TryGetSpecialTypeMember(compilation, specialMember, _userMainReturnTypeSyntax, BindingDiagnosticBag.Discarded, out MethodSymbol handleAsyncEntryPointMethod, isOptional: true)
                    && handleAsyncEntryPointMethod.Parameters[0].Type.Equals(userMain.ReturnType, TypeCompareKind.AllIgnoreOptions))
                {
                    // Use the new HandleAsyncEntryPoint API
                    _userEntryPointInvocation = new BoundCall(
                            syntax: _userMainReturnTypeSyntax,
                            receiverOpt: null,
                            initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown,
                            method: handleAsyncEntryPointMethod,
                            arguments: [userMainInvocation],
                            argumentNamesOpt: default(ImmutableArray<string>),
                            argumentRefKindsOpt: default(ImmutableArray<RefKind>),
                            isDelegateCall: false,
                            expanded: false,
                            invokedAsExtensionMethod: false,
                            argsToParamsOpt: default(ImmutableArray<int>),
                            defaultArguments: default(BitVector),
                            resultKind: LookupResultKind.Viable,
                            type: handleAsyncEntryPointMethod.ReturnType)
                    { WasCompilerGenerated = true };
                }
                else
                {
                    // Fall back to the old GetAwaiter().GetResult() pattern
                    // The diagnostics that would be produced here will already have been captured and returned.
                    var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _userEntryPointInvocation!, runtimeAsyncAwaitCall: out _, _userMainReturnTypeSyntax, BindingDiagnosticBag.Discarded);
                }

                Debug.Assert(
                    ReturnType.IsVoidType() ||
                    ReturnType.SpecialType == SpecialType.System_Int32);