Repository: dotnet/roslyn
File: src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs (C#)

Code before:

            return Binder.GetMethodGroupOrLambdaDelegateType(
                _unboundLambda.Syntax,
                lambdaSymbol,
                hasParams: OverloadResolution.IsValidParams(Binder, lambdaSymbol, disallowExpandedNonArrayParams: false, out _),
                parameterScopesBuilder.ToImmutableAndFree(),
                lambdaSymbol.Parameters.SelectAsArray(p => p.HasUnscopedRefAttribute && p.UseUpdatedEscapeRules),
                returnRefKind,
                returnType);
        }

        private BoundLambda ReallyBind(NamedTypeSymbol delegateType, bool inExpressionTree)
        {
            Debug.Assert(Binder.ContainingMemberOrLambda is { });

            var invokeMethod = DelegateInvokeMethod(delegateType);
            var returnType = DelegateReturnTypeWithAnnotations(invokeMethod, out RefKind refKind, out ImmutableArray<CustomModifier> refCustomModifiers);

            LambdaSymbol lambdaSymbol;
            Binder lambdaBodyBinder;
            BoundBlock block;

            var diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, _unboundLambda.WithDependencies);
            var compilation = Binder.Compilation;
            var containingMemberOrLambda = Binder.ContainingMemberOrLambda;
            var isInRuntimeAsyncContext = compilation.IsRuntimeAsyncEnabledIn(containingMemberOrLambda);
            var cacheKey = ReturnInferenceCacheKey.Create(delegateType, IsAsync, isInRuntimeAsyncContext);

            // When binding for real (not for return inference), there is still a good chance
            // we could reuse a body of a lambda previous bound for return type inference.
            // For simplicity, reuse is limited to expression-bodied lambdas. In those cases,
            // we reuse the bound expression and apply any conversion to the return value
            // since the inferred return type was not used when binding for return inference.
            // We don't reuse the body if we're binding in an expression tree, because we didn't
            // know that we were binding for an expression tree when originally binding the lambda
            // for return inference.
            if (!inExpressionTree &&
                refKind == CodeAnalysis.RefKind.None &&
                _returnInferenceCache!.TryGetValue(cacheKey, out BoundLambda? returnInferenceLambda) &&
                GetLambdaExpressionBody(returnInferenceLambda.Body) is BoundExpression expression &&
                (lambdaSymbol = (LambdaSymbol)returnInferenceLambda.Symbol).RefKind == refKind &&
                (object)LambdaSymbol.InferenceFailureReturnType != lambdaSymbol.ReturnType &&
                lambdaSymbol.ReturnTypeWithAnnotations.Equals(returnType, TypeCompareKind.ConsiderEverything) &&
                lambdaSymbol.RefCustomModifiers.SequenceEqual(refCustomModifiers))
            {
                lambdaBodyBinder = returnInferenceLambda.Binder;
                block = CreateBlockFromLambdaExpressionBody(lambdaBodyBinder, expression, diagnostics);
                diagnostics.AddRange(returnInferenceLambda.Diagnostics);
            }
            else
            {

Review comment (suggestion):
>containingMemberOrLambda [](http://example.com/codeflow?start=78&length=24)

This looks suspicious. It looks like the lambda body binding will be calling ```IsRuntimeAsyncEnabledIn``` for the enclosing lambda symbol, but here we are calling ```IsRuntimeAsyncEnabledIn``` for a method one level higher. It feels like the two values could be different.  #Closed

Code after:

            return Binder.GetMethodGroupOrLambdaDelegateType(
                _unboundLambda.Syntax,
                lambdaSymbol,
                hasParams: OverloadResolution.IsValidParams(Binder, lambdaSymbol, disallowExpandedNonArrayParams: false, out _),
                parameterScopesBuilder.ToImmutableAndFree(),
                lambdaSymbol.Parameters.SelectAsArray(p => p.HasUnscopedRefAttribute && p.UseUpdatedEscapeRules),
                returnRefKind,
                returnType);
        }

        private BoundLambda ReallyBind(NamedTypeSymbol delegateType, bool inExpressionTree)
        {
            Debug.Assert(Binder.ContainingMemberOrLambda is { });

            var invokeMethod = DelegateInvokeMethod(delegateType);
            var returnType = DelegateReturnTypeWithAnnotations(invokeMethod, out RefKind refKind, out ImmutableArray<CustomModifier> refCustomModifiers);

            LambdaSymbol lambdaSymbol;
            Binder lambdaBodyBinder;
            BoundBlock block;

            var diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, _unboundLambda.WithDependencies);
            var compilation = Binder.Compilation;
            var cacheKey = ReturnInferenceCacheKey.Create(delegateType, IsAsync);

            // When binding for real (not for return inference), there is still a good chance
            // we could reuse a body of a lambda previous bound for return type inference.
            // For simplicity, reuse is limited to expression-bodied lambdas. In those cases,
            // we reuse the bound expression and apply any conversion to the return value
            // since the inferred return type was not used when binding for return inference.
            // We don't reuse the body if we're binding in an expression tree, because we didn't
            // know that we were binding for an expression tree when originally binding the lambda
            // for return inference.
            // We also don't reuse the body if the value of CSharpCompilation.IsRuntimeAsyncEnabledInMethod
            // changed after inference with the final return type, as that will change the binding of await
            // calls within the lambda. For optimization purposes, we assume that if the lambda is async, it will
            // end up resolving to Task/ValueTask types, as that's the 95% case for C# code. If that ends up not being
            // true, then we need to bust the cache and rebind.
            if (!inExpressionTree &&
                refKind == CodeAnalysis.RefKind.None &&
                _returnInferenceCache!.TryGetValue(cacheKey, out BoundLambda? returnInferenceLambda) &&
                GetLambdaExpressionBody(returnInferenceLambda.Body) is BoundExpression expression &&
                (lambdaSymbol = (LambdaSymbol)returnInferenceLambda.Symbol).RefKind == refKind &&
                !lambdaSymbol.RuntimeAsyncEnabledChangedDuringInference &&
                (object)LambdaSymbol.InferenceFailureReturnType != lambdaSymbol.ReturnType &&
                lambdaSymbol.ReturnTypeWithAnnotations.Equals(returnType, TypeCompareKind.ConsiderEverything) &&
                lambdaSymbol.RefCustomModifiers.SequenceEqual(refCustomModifiers))
            {
                lambdaBodyBinder = returnInferenceLambda.Binder;
                block = CreateBlockFromLambdaExpressionBody(lambdaBodyBinder, expression, diagnostics);