710 lines
32 KiB
C#
710 lines
32 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal abstract class UnboundLambdaState
|
|
{
|
|
private sealed class ReturnInferenceCacheKey
|
|
{
|
|
public readonly ImmutableArray<TypeWithAnnotations> ParameterTypes;
|
|
|
|
public readonly ImmutableArray<RefKind> ParameterRefKinds;
|
|
|
|
public readonly NamedTypeSymbol? TaskLikeReturnTypeOpt;
|
|
|
|
public static readonly ReturnInferenceCacheKey Empty = new ReturnInferenceCacheKey(ImmutableArray<TypeWithAnnotations>.Empty, ImmutableArray<RefKind>.Empty, null);
|
|
|
|
private ReturnInferenceCacheKey(ImmutableArray<TypeWithAnnotations> parameterTypes, ImmutableArray<RefKind> parameterRefKinds, NamedTypeSymbol? taskLikeReturnTypeOpt)
|
|
{
|
|
ParameterTypes = parameterTypes;
|
|
ParameterRefKinds = parameterRefKinds;
|
|
TaskLikeReturnTypeOpt = taskLikeReturnTypeOpt;
|
|
}
|
|
|
|
public override bool Equals(object? obj)
|
|
{
|
|
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
|
|
if (this == obj)
|
|
{
|
|
return true;
|
|
}
|
|
if (!(obj is ReturnInferenceCacheKey returnInferenceCacheKey) || returnInferenceCacheKey.ParameterTypes.Length != ParameterTypes.Length || !TypeSymbol.Equals(returnInferenceCacheKey.TaskLikeReturnTypeOpt, TaskLikeReturnTypeOpt, (TypeCompareKind)0))
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < ParameterTypes.Length; i++)
|
|
{
|
|
if (!returnInferenceCacheKey.ParameterTypes[i].Equals(ParameterTypes[i], (TypeCompareKind)0) || returnInferenceCacheKey.ParameterRefKinds[i] != ParameterRefKinds[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
int num = TaskLikeReturnTypeOpt?.GetHashCode() ?? 0;
|
|
ImmutableArray<TypeWithAnnotations>.Enumerator enumerator = ParameterTypes.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
num = Hash.Combine<TypeSymbol>(enumerator.Current.Type, num);
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public static ReturnInferenceCacheKey Create(NamedTypeSymbol? delegateType, bool isAsync)
|
|
{
|
|
GetFields(delegateType, isAsync, out ImmutableArray<TypeWithAnnotations> parameterTypes, out ImmutableArray<RefKind> parameterRefKinds, out NamedTypeSymbol taskLikeReturnTypeOpt);
|
|
if (parameterTypes.IsEmpty && parameterRefKinds.IsEmpty && (object)taskLikeReturnTypeOpt == null)
|
|
{
|
|
return Empty;
|
|
}
|
|
return new ReturnInferenceCacheKey(parameterTypes, parameterRefKinds, taskLikeReturnTypeOpt);
|
|
}
|
|
|
|
public static void GetFields(NamedTypeSymbol? delegateType, bool isAsync, out ImmutableArray<TypeWithAnnotations> parameterTypes, out ImmutableArray<RefKind> parameterRefKinds, out NamedTypeSymbol? taskLikeReturnTypeOpt)
|
|
{
|
|
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
|
|
parameterTypes = ImmutableArray<TypeWithAnnotations>.Empty;
|
|
parameterRefKinds = ImmutableArray<RefKind>.Empty;
|
|
taskLikeReturnTypeOpt = null;
|
|
MethodSymbol methodSymbol = DelegateInvokeMethod(delegateType);
|
|
if ((object)methodSymbol == null)
|
|
{
|
|
return;
|
|
}
|
|
int parameterCount = methodSymbol.ParameterCount;
|
|
if (parameterCount > 0)
|
|
{
|
|
ArrayBuilder<TypeWithAnnotations> instance = ArrayBuilder<TypeWithAnnotations>.GetInstance(parameterCount);
|
|
ArrayBuilder<RefKind> instance2 = ArrayBuilder<RefKind>.GetInstance(parameterCount);
|
|
ImmutableArray<ParameterSymbol>.Enumerator enumerator = methodSymbol.Parameters.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
ParameterSymbol current = enumerator.Current;
|
|
instance2.Add(current.RefKind);
|
|
instance.Add(current.TypeWithAnnotations);
|
|
}
|
|
parameterTypes = instance.ToImmutableAndFree();
|
|
parameterRefKinds = instance2.ToImmutableAndFree();
|
|
}
|
|
if (isAsync && methodSymbol.ReturnType is NamedTypeSymbol namedTypeSymbol && !namedTypeSymbol.IsVoidType() && namedTypeSymbol.IsCustomTaskType(out object _))
|
|
{
|
|
taskLikeReturnTypeOpt = namedTypeSymbol.ConstructedFrom;
|
|
}
|
|
}
|
|
}
|
|
|
|
private sealed class BindingCacheComparer : IEqualityComparer<(NamedTypeSymbol Type, bool IsExpressionTree)>
|
|
{
|
|
public static readonly BindingCacheComparer Instance = new BindingCacheComparer();
|
|
|
|
public bool Equals([AllowNull] (NamedTypeSymbol Type, bool IsExpressionTree) x, [AllowNull] (NamedTypeSymbol Type, bool IsExpressionTree) y)
|
|
{
|
|
if (x.IsExpressionTree == y.IsExpressionTree)
|
|
{
|
|
return Symbol.Equals(x.Type, y.Type, (TypeCompareKind)0);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public int GetHashCode([DisallowNull] (NamedTypeSymbol Type, bool IsExpressionTree) obj)
|
|
{
|
|
return Hash.Combine<NamedTypeSymbol>(obj.Type, obj.IsExpressionTree.GetHashCode());
|
|
}
|
|
}
|
|
|
|
private UnboundLambda _unboundLambda;
|
|
|
|
internal readonly Binder Binder;
|
|
|
|
private ImmutableDictionary<(NamedTypeSymbol Type, bool IsExpressionLambda), BoundLambda>? _bindingCache;
|
|
|
|
private ImmutableDictionary<ReturnInferenceCacheKey, BoundLambda>? _returnInferenceCache;
|
|
|
|
private BoundLambda? _errorBinding;
|
|
|
|
public UnboundLambda UnboundLambda => _unboundLambda;
|
|
|
|
public abstract MessageID MessageID { get; }
|
|
|
|
public abstract bool HasSignature { get; }
|
|
|
|
public abstract bool HasExplicitlyTypedParameterList { get; }
|
|
|
|
public abstract int ParameterCount { get; }
|
|
|
|
public abstract bool IsAsync { get; }
|
|
|
|
public abstract bool IsStatic { get; }
|
|
|
|
public abstract bool HasParamsArray { get; }
|
|
|
|
public UnboundLambdaState(Binder binder, bool includeCache)
|
|
{
|
|
if (includeCache)
|
|
{
|
|
_bindingCache = ImmutableDictionary<(NamedTypeSymbol, bool), BoundLambda>.Empty.WithComparers(BindingCacheComparer.Instance);
|
|
_returnInferenceCache = ImmutableDictionary<ReturnInferenceCacheKey, BoundLambda>.Empty;
|
|
}
|
|
Binder = binder;
|
|
}
|
|
|
|
public void SetUnboundLambda(UnboundLambda unbound)
|
|
{
|
|
_unboundLambda = unbound;
|
|
}
|
|
|
|
protected abstract UnboundLambdaState WithCachingCore(bool includeCache);
|
|
|
|
internal UnboundLambdaState WithCaching(bool includeCache)
|
|
{
|
|
if (_bindingCache == null != includeCache)
|
|
{
|
|
return this;
|
|
}
|
|
return WithCachingCore(includeCache);
|
|
}
|
|
|
|
public abstract string ParameterName(int index);
|
|
|
|
public abstract bool ParameterIsDiscard(int index);
|
|
|
|
public abstract SyntaxList<AttributeListSyntax> ParameterAttributes(int index);
|
|
|
|
public abstract bool HasExplicitReturnType(out RefKind refKind, out TypeWithAnnotations returnType);
|
|
|
|
public abstract Location ParameterLocation(int index);
|
|
|
|
public abstract TypeWithAnnotations ParameterTypeWithAnnotations(int index);
|
|
|
|
public abstract RefKind RefKind(int index);
|
|
|
|
public abstract ScopedKind DeclaredScope(int index);
|
|
|
|
public abstract ParameterSyntax? ParameterSyntax(int i);
|
|
|
|
protected BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, Binder lambdaBodyBinder, BindingDiagnosticBag diagnostics)
|
|
{
|
|
if (lambdaSymbol.DeclaringCompilation?.TestOnlyCompilationData is LambdaBindingData lambdaBindingData)
|
|
{
|
|
Interlocked.Increment(ref lambdaBindingData.LambdaBindingCount);
|
|
}
|
|
return BindLambdaBodyCore(lambdaSymbol, lambdaBodyBinder, diagnostics);
|
|
}
|
|
|
|
protected abstract BoundBlock BindLambdaBodyCore(LambdaSymbol lambdaSymbol, Binder lambdaBodyBinder, BindingDiagnosticBag diagnostics);
|
|
|
|
protected abstract BoundExpression? GetLambdaExpressionBody(BoundBlock body);
|
|
|
|
protected abstract BoundBlock CreateBlockFromLambdaExpressionBody(Binder lambdaBodyBinder, BoundExpression expression, BindingDiagnosticBag diagnostics);
|
|
|
|
public virtual void GenerateAnonymousFunctionConversionError(BindingDiagnosticBag diagnostics, TypeSymbol targetType)
|
|
{
|
|
Binder.GenerateAnonymousFunctionConversionError(diagnostics, _unboundLambda.Syntax, _unboundLambda, targetType);
|
|
}
|
|
|
|
public BoundLambda Bind(NamedTypeSymbol delegateType, bool isTargetExpressionTree)
|
|
{
|
|
bool flag = Binder.InExpressionTree || isTargetExpressionTree;
|
|
if (!_bindingCache.TryGetValue((delegateType, flag), out BoundLambda value))
|
|
{
|
|
value = ReallyBind(delegateType, flag);
|
|
return ImmutableInterlocked.GetOrAdd(ref _bindingCache, (delegateType, flag), value);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
internal IEnumerable<TypeSymbol> InferredReturnTypes()
|
|
{
|
|
bool any = false;
|
|
foreach (BoundLambda value in _returnInferenceCache.Values)
|
|
{
|
|
TypeWithAnnotations typeWithAnnotations = value.InferredReturnType.TypeWithAnnotations;
|
|
if (typeWithAnnotations.HasType)
|
|
{
|
|
any = true;
|
|
yield return typeWithAnnotations.Type;
|
|
}
|
|
}
|
|
if (!any)
|
|
{
|
|
TypeWithAnnotations typeWithAnnotations2 = BindForErrorRecovery().InferredReturnType.TypeWithAnnotations;
|
|
if (typeWithAnnotations2.HasType)
|
|
{
|
|
yield return typeWithAnnotations2.Type;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static MethodSymbol? DelegateInvokeMethod(NamedTypeSymbol? delegateType)
|
|
{
|
|
return delegateType.GetDelegateType()?.DelegateInvokeMethod;
|
|
}
|
|
|
|
private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbol? invokeMethod, out RefKind refKind)
|
|
{
|
|
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0018: Expected I4, but got Unknown
|
|
if ((object)invokeMethod == null)
|
|
{
|
|
refKind = (RefKind)0;
|
|
return default(TypeWithAnnotations);
|
|
}
|
|
refKind = (RefKind)(int)invokeMethod.RefKind;
|
|
return invokeMethod.ReturnTypeWithAnnotations;
|
|
}
|
|
|
|
internal (ImmutableArray<RefKind>, ArrayBuilder<ScopedKind>, ImmutableArray<TypeWithAnnotations>, bool) CollectParameterProperties()
|
|
{
|
|
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
|
|
ArrayBuilder<RefKind> instance = ArrayBuilder<RefKind>.GetInstance(ParameterCount);
|
|
ArrayBuilder<ScopedKind> instance2 = ArrayBuilder<ScopedKind>.GetInstance(ParameterCount);
|
|
ArrayBuilder<TypeWithAnnotations> instance3 = ArrayBuilder<TypeWithAnnotations>.GetInstance(ParameterCount);
|
|
bool item = false;
|
|
for (int i = 0; i < ParameterCount; i++)
|
|
{
|
|
RefKind val = RefKind(i);
|
|
ScopedKind val2 = DeclaredScope(i);
|
|
TypeWithAnnotations typeWithAnnotations = ParameterTypeWithAnnotations(i);
|
|
if ((int)val2 == 0 && ParameterHelpers.IsRefScopedByDefault(Binder.UseUpdatedEscapeRules, val))
|
|
{
|
|
val2 = (ScopedKind)1;
|
|
if (_unboundLambda.ParameterAttributes(i).Any())
|
|
{
|
|
item = true;
|
|
}
|
|
}
|
|
instance.Add(val);
|
|
instance2.Add(val2);
|
|
instance3.Add(typeWithAnnotations);
|
|
}
|
|
ImmutableArray<RefKind> item2 = instance.ToImmutableAndFree();
|
|
ImmutableArray<TypeWithAnnotations> item3 = instance3.ToImmutableAndFree();
|
|
return (item2, instance2, item3, item);
|
|
}
|
|
|
|
internal NamedTypeSymbol? InferDelegateType()
|
|
{
|
|
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00fe: Invalid comparison between Unknown and I4
|
|
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
|
|
if (!HasExplicitlyTypedParameterList)
|
|
{
|
|
return null;
|
|
}
|
|
(ImmutableArray<RefKind>, ArrayBuilder<ScopedKind>, ImmutableArray<TypeWithAnnotations>, bool) tuple = CollectParameterProperties();
|
|
ImmutableArray<RefKind> item = tuple.Item1;
|
|
ArrayBuilder<ScopedKind> item2 = tuple.Item2;
|
|
ImmutableArray<TypeWithAnnotations> item3 = tuple.Item3;
|
|
bool item4 = tuple.Item4;
|
|
LambdaSymbol lambdaSymbol = CreateLambdaSymbol(Binder.ContainingMemberOrLambda, default(TypeWithAnnotations), item3, item, (RefKind)0);
|
|
if (!HasExplicitReturnType(out var refKind, out var returnType))
|
|
{
|
|
ExecutableCodeBinder executableCodeBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, GetWithParametersBinder(lambdaSymbol, Binder));
|
|
BoundBlock block = BindLambdaBody(lambdaSymbol, executableCodeBinder, BindingDiagnosticBag.Discarded);
|
|
ArrayBuilder<(BoundReturnStatement, TypeWithAnnotations)> instance = ArrayBuilder<(BoundReturnStatement, TypeWithAnnotations)>.GetInstance();
|
|
BoundLambda.BlockReturns.GetReturnTypes(instance, block);
|
|
InferredLambdaReturnType inferredLambdaReturnType = BoundLambda.InferReturnType(instance, _unboundLambda, executableCodeBinder, null, IsAsync, Binder.Conversions);
|
|
returnType = inferredLambdaReturnType.TypeWithAnnotations;
|
|
refKind = inferredLambdaReturnType.RefKind;
|
|
if (!returnType.HasType && inferredLambdaReturnType.NumExpressions > 0)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
if (item4)
|
|
{
|
|
for (int i = 0; i < ParameterCount; i++)
|
|
{
|
|
if ((int)DeclaredScope(i) == 0 && (int)item2[i] == 1 && _unboundLambda.ParameterAttributes(i).Any())
|
|
{
|
|
item2[i] = lambdaSymbol.Parameters[i].EffectiveScope;
|
|
}
|
|
}
|
|
}
|
|
if (!returnType.HasType)
|
|
{
|
|
returnType = TypeWithAnnotations.Create(Binder.Compilation.GetSpecialType((SpecialType)6));
|
|
}
|
|
return Binder.GetMethodGroupOrLambdaDelegateType(_unboundLambda.Syntax, lambdaSymbol, item2.ToImmutableAndFree(), ImmutableArrayExtensions.SelectAsArray<ParameterSymbol, bool>(lambdaSymbol.Parameters, (Func<ParameterSymbol, bool>)((ParameterSymbol p) => p.HasUnscopedRefAttribute)), refKind, returnType);
|
|
}
|
|
|
|
private BoundLambda ReallyBind(NamedTypeSymbol delegateType, bool inExpressionTree)
|
|
{
|
|
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0124: Invalid comparison between Unknown and I4
|
|
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
|
|
RefKind refKind;
|
|
TypeWithAnnotations typeWithAnnotations = DelegateReturnTypeWithAnnotations(DelegateInvokeMethod(delegateType), out refKind);
|
|
BindingDiagnosticBag instance = BindingDiagnosticBag.GetInstance(withDiagnostics: true, _unboundLambda.WithDependencies);
|
|
CSharpCompilation compilation = Binder.Compilation;
|
|
ReturnInferenceCacheKey returnInferenceCacheKey = ReturnInferenceCacheKey.Create(delegateType, IsAsync);
|
|
LambdaSymbol lambdaSymbol;
|
|
Binder binder;
|
|
BoundBlock boundBlock;
|
|
if (!inExpressionTree && (int)refKind == 0 && _returnInferenceCache.TryGetValue(returnInferenceCacheKey, out BoundLambda value))
|
|
{
|
|
BoundExpression lambdaExpressionBody = GetLambdaExpressionBody(value.Body);
|
|
if (lambdaExpressionBody != null && (lambdaSymbol = value.Symbol).RefKind == refKind && (object)LambdaSymbol.InferenceFailureReturnType != lambdaSymbol.ReturnType && lambdaSymbol.ReturnTypeWithAnnotations.Equals(typeWithAnnotations, (TypeCompareKind)0))
|
|
{
|
|
binder = value.Binder;
|
|
boundBlock = CreateBlockFromLambdaExpressionBody(binder, lambdaExpressionBody, instance);
|
|
((BindingDiagnosticBag<AssemblySymbol>)(object)instance).AddRange(value.Diagnostics, false);
|
|
goto IL_0115;
|
|
}
|
|
}
|
|
lambdaSymbol = CreateLambdaSymbol(Binder.ContainingMemberOrLambda, typeWithAnnotations, returnInferenceCacheKey.ParameterTypes, returnInferenceCacheKey.ParameterRefKinds, refKind);
|
|
binder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, GetWithParametersBinder(lambdaSymbol, Binder), inExpressionTree ? BinderFlags.InExpressionTree : BinderFlags.None);
|
|
boundBlock = BindLambdaBody(lambdaSymbol, binder, instance);
|
|
goto IL_0115;
|
|
IL_0115:
|
|
lambdaSymbol.GetDeclarationDiagnostics(instance);
|
|
if ((int)lambdaSymbol.RefKind == 3)
|
|
{
|
|
compilation.EnsureIsReadOnlyAttributeExists(instance, lambdaSymbol.DiagnosticLocation, modifyCompilation: false);
|
|
}
|
|
ImmutableArray<ParameterSymbol> parameters = lambdaSymbol.Parameters;
|
|
ParameterHelpers.EnsureRefKindAttributesExist(compilation, parameters, instance, modifyCompilation: false);
|
|
if (typeWithAnnotations.HasType)
|
|
{
|
|
if (compilation.ShouldEmitNativeIntegerAttributes(typeWithAnnotations.Type))
|
|
{
|
|
compilation.EnsureNativeIntegerAttributeExists(instance, lambdaSymbol.DiagnosticLocation, modifyCompilation: false);
|
|
}
|
|
if (compilation.ShouldEmitNullableAttributes(lambdaSymbol) && typeWithAnnotations.NeedsNullableAttribute())
|
|
{
|
|
compilation.EnsureNullableAttributeExists(instance, lambdaSymbol.DiagnosticLocation, modifyCompilation: false);
|
|
}
|
|
}
|
|
ParameterHelpers.EnsureNativeIntegerAttributeExists(compilation, parameters, instance, modifyCompilation: false);
|
|
ParameterHelpers.EnsureScopedRefAttributeExists(compilation, parameters, instance, modifyCompilation: false);
|
|
ParameterHelpers.EnsureNullableAttributeExists(compilation, lambdaSymbol, parameters, instance, modifyCompilation: false);
|
|
ValidateUnsafeParameters(instance, returnInferenceCacheKey.ParameterTypes);
|
|
if (ControlFlowPass.Analyze(compilation, lambdaSymbol, boundBlock, ((BindingDiagnosticBag)instance).DiagnosticBag))
|
|
{
|
|
if (Microsoft.CodeAnalysis.CSharp.Binder.MethodOrLambdaRequiresValue(lambdaSymbol, Binder.Compilation))
|
|
{
|
|
instance.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.DiagnosticLocation, MessageID.Localize(), delegateType);
|
|
}
|
|
else
|
|
{
|
|
boundBlock = FlowAnalysisPass.AppendImplicitReturn(boundBlock, lambdaSymbol);
|
|
}
|
|
}
|
|
if (IsAsync && !ErrorFacts.PreventsSuccessfulDelegateConversion(((BindingDiagnosticBag)instance).DiagnosticBag) && typeWithAnnotations.HasType && !typeWithAnnotations.IsVoidType() && !lambdaSymbol.IsAsyncEffectivelyReturningTask(compilation) && !lambdaSymbol.IsAsyncEffectivelyReturningGenericTask(compilation))
|
|
{
|
|
instance.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.DiagnosticLocation, lambdaSymbol.MessageID.Localize(), delegateType);
|
|
}
|
|
return new BoundLambda(_unboundLambda.Syntax, _unboundLambda, boundBlock, ((BindingDiagnosticBag<AssemblySymbol>)(object)instance).ToReadOnlyAndFree(), binder, delegateType, default(InferredLambdaReturnType))
|
|
{
|
|
WasCompilerGenerated = _unboundLambda.WasCompilerGenerated
|
|
};
|
|
}
|
|
|
|
internal LambdaSymbol CreateLambdaSymbol(Symbol containingSymbol, TypeWithAnnotations returnType, ImmutableArray<TypeWithAnnotations> parameterTypes, ImmutableArray<RefKind> parameterRefKinds, RefKind refKind)
|
|
{
|
|
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
|
|
return new LambdaSymbol(Binder, Binder.Compilation, containingSymbol, _unboundLambda, parameterTypes, parameterRefKinds, refKind, returnType);
|
|
}
|
|
|
|
internal LambdaSymbol CreateLambdaSymbol(NamedTypeSymbol delegateType, Symbol containingSymbol)
|
|
{
|
|
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
|
|
RefKind refKind;
|
|
TypeWithAnnotations returnType = DelegateReturnTypeWithAnnotations(DelegateInvokeMethod(delegateType), out refKind);
|
|
ReturnInferenceCacheKey.GetFields(delegateType, IsAsync, out ImmutableArray<TypeWithAnnotations> parameterTypes, out ImmutableArray<RefKind> parameterRefKinds, out NamedTypeSymbol _);
|
|
return CreateLambdaSymbol(containingSymbol, returnType, parameterTypes, parameterRefKinds, refKind);
|
|
}
|
|
|
|
private void ValidateUnsafeParameters(BindingDiagnosticBag diagnostics, ImmutableArray<TypeWithAnnotations> targetParameterTypes)
|
|
{
|
|
if (!HasSignature)
|
|
{
|
|
return;
|
|
}
|
|
int num = Math.Min(targetParameterTypes.Length, ParameterCount);
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
if (targetParameterTypes[i].Type.ContainsPointer())
|
|
{
|
|
Binder.ReportUnsafeIfNotAllowed(ParameterLocation(i), diagnostics);
|
|
}
|
|
}
|
|
}
|
|
|
|
private BoundLambda ReallyInferReturnType(NamedTypeSymbol? delegateType, ImmutableArray<TypeWithAnnotations> parameterTypes, ImmutableArray<RefKind> parameterRefKinds)
|
|
{
|
|
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
|
|
RefKind refKind;
|
|
TypeWithAnnotations returnType;
|
|
bool flag = HasExplicitReturnType(out refKind, out returnType);
|
|
var (lambdaSymbol, boundBlock, executableCodeBinder, bindingDiagnosticBag) = BindWithParameterAndReturnType(parameterTypes, parameterRefKinds, returnType, refKind);
|
|
InferredLambdaReturnType inferredReturnType;
|
|
if (flag)
|
|
{
|
|
inferredReturnType = new InferredLambdaReturnType(0, isExplicitType: true, hadExpressionlessReturn: false, refKind, returnType, inferredFromFunctionType: false, ImmutableArray<DiagnosticInfo>.Empty, ImmutableArray<AssemblySymbol>.Empty);
|
|
}
|
|
else
|
|
{
|
|
ArrayBuilder<(BoundReturnStatement, TypeWithAnnotations)> instance = ArrayBuilder<(BoundReturnStatement, TypeWithAnnotations)>.GetInstance();
|
|
BoundLambda.BlockReturns.GetReturnTypes(instance, boundBlock);
|
|
inferredReturnType = BoundLambda.InferReturnType(instance, _unboundLambda, executableCodeBinder, delegateType, lambdaSymbol.IsAsync, executableCodeBinder.Conversions);
|
|
refKind = inferredReturnType.RefKind;
|
|
returnType = inferredReturnType.TypeWithAnnotations;
|
|
if (!returnType.HasType)
|
|
{
|
|
returnType = (((object)delegateType == null && instance.Count == 0) ? TypeWithAnnotations.Create(Binder.Compilation.GetSpecialType((SpecialType)6)) : TypeWithAnnotations.Create(LambdaSymbol.InferenceFailureReturnType));
|
|
}
|
|
instance.Free();
|
|
}
|
|
BoundLambda result = new BoundLambda(_unboundLambda.Syntax, _unboundLambda, boundBlock, ((BindingDiagnosticBag<AssemblySymbol>)(object)bindingDiagnosticBag).ToReadOnlyAndFree(), executableCodeBinder, delegateType, inferredReturnType)
|
|
{
|
|
WasCompilerGenerated = _unboundLambda.WasCompilerGenerated
|
|
};
|
|
if (!flag)
|
|
{
|
|
lambdaSymbol.SetInferredReturnType(refKind, returnType);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private (LambdaSymbol lambdaSymbol, BoundBlock block, ExecutableCodeBinder lambdaBodyBinder, BindingDiagnosticBag diagnostics) BindWithParameterAndReturnType(ImmutableArray<TypeWithAnnotations> parameterTypes, ImmutableArray<RefKind> parameterRefKinds, TypeWithAnnotations returnType, RefKind refKind)
|
|
{
|
|
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
|
|
BindingDiagnosticBag instance = BindingDiagnosticBag.GetInstance(withDiagnostics: true, _unboundLambda.WithDependencies);
|
|
LambdaSymbol lambdaSymbol = CreateLambdaSymbol(Binder.ContainingMemberOrLambda, returnType, parameterTypes, parameterRefKinds, refKind);
|
|
ExecutableCodeBinder executableCodeBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, GetWithParametersBinder(lambdaSymbol, Binder));
|
|
BoundBlock item = BindLambdaBody(lambdaSymbol, executableCodeBinder, instance);
|
|
lambdaSymbol.GetDeclarationDiagnostics(instance);
|
|
return (lambdaSymbol: lambdaSymbol, block: item, lambdaBodyBinder: executableCodeBinder, diagnostics: instance);
|
|
}
|
|
|
|
public BoundLambda BindForReturnTypeInference(NamedTypeSymbol delegateType)
|
|
{
|
|
ReturnInferenceCacheKey returnInferenceCacheKey = ReturnInferenceCacheKey.Create(delegateType, IsAsync);
|
|
if (!_returnInferenceCache.TryGetValue(returnInferenceCacheKey, out BoundLambda value))
|
|
{
|
|
value = ReallyInferReturnType(delegateType, returnInferenceCacheKey.ParameterTypes, returnInferenceCacheKey.ParameterRefKinds);
|
|
return ImmutableInterlocked.GetOrAdd(ref _returnInferenceCache, returnInferenceCacheKey, value);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public virtual Binder GetWithParametersBinder(LambdaSymbol lambdaSymbol, Binder binder)
|
|
{
|
|
return new WithLambdaParametersBinder(lambdaSymbol, binder);
|
|
}
|
|
|
|
public BoundLambda BindForErrorRecovery()
|
|
{
|
|
if (_errorBinding == null)
|
|
{
|
|
Interlocked.CompareExchange(ref _errorBinding, ReallyBindForErrorRecovery(), null);
|
|
}
|
|
return _errorBinding;
|
|
}
|
|
|
|
private BoundLambda ReallyBindForErrorRecovery()
|
|
{
|
|
return GuessBestBoundLambda(_bindingCache) ?? rebind(GuessBestBoundLambda(_returnInferenceCache)) ?? rebind(ReallyInferReturnType(null, ImmutableArray<TypeWithAnnotations>.Empty, ImmutableArray<RefKind>.Empty));
|
|
[return: NotNullIfNotNull("lambda")]
|
|
BoundLambda? rebind(BoundLambda? lambda)
|
|
{
|
|
if (lambda == null)
|
|
{
|
|
return null;
|
|
}
|
|
NamedTypeSymbol delegateType = (NamedTypeSymbol)lambda.Type;
|
|
ReturnInferenceCacheKey.GetFields(delegateType, IsAsync, out ImmutableArray<TypeWithAnnotations> parameterTypes, out ImmutableArray<RefKind> parameterRefKinds, out NamedTypeSymbol _);
|
|
return ReallyBindForErrorRecovery(delegateType, lambda.InferredReturnType, parameterTypes, parameterRefKinds);
|
|
}
|
|
}
|
|
|
|
private BoundLambda ReallyBindForErrorRecovery(NamedTypeSymbol? delegateType, InferredLambdaReturnType inferredReturnType, ImmutableArray<TypeWithAnnotations> parameterTypes, ImmutableArray<RefKind> parameterRefKinds)
|
|
{
|
|
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
|
|
TypeWithAnnotations typeWithAnnotations = inferredReturnType.TypeWithAnnotations;
|
|
RefKind refKind = inferredReturnType.RefKind;
|
|
if (!typeWithAnnotations.HasType)
|
|
{
|
|
typeWithAnnotations = DelegateReturnTypeWithAnnotations(DelegateInvokeMethod(delegateType), out refKind);
|
|
if (!typeWithAnnotations.HasType || typeWithAnnotations.Type.ContainsTypeParameter())
|
|
{
|
|
typeWithAnnotations = TypeWithAnnotations.Create((inferredReturnType.HadExpressionlessReturn || inferredReturnType.NumExpressions == 0) ? Binder.Compilation.GetSpecialType((SpecialType)6) : Binder.CreateErrorType());
|
|
refKind = (RefKind)0;
|
|
}
|
|
}
|
|
(LambdaSymbol lambdaSymbol, BoundBlock block, ExecutableCodeBinder lambdaBodyBinder, BindingDiagnosticBag diagnostics) tuple = BindWithParameterAndReturnType(parameterTypes, parameterRefKinds, typeWithAnnotations, refKind);
|
|
BoundBlock item = tuple.block;
|
|
ExecutableCodeBinder item2 = tuple.lambdaBodyBinder;
|
|
BindingDiagnosticBag item3 = tuple.diagnostics;
|
|
return new BoundLambda(_unboundLambda.Syntax, _unboundLambda, item, ((BindingDiagnosticBag<AssemblySymbol>)(object)item3).ToReadOnlyAndFree(), item2, delegateType, new InferredLambdaReturnType(inferredReturnType.NumExpressions, inferredReturnType.IsExplicitType, inferredReturnType.HadExpressionlessReturn, refKind, typeWithAnnotations, inferredReturnType.InferredFromFunctionType, ImmutableArray<DiagnosticInfo>.Empty, ImmutableArray<AssemblySymbol>.Empty))
|
|
{
|
|
WasCompilerGenerated = _unboundLambda.WasCompilerGenerated
|
|
};
|
|
}
|
|
|
|
private static BoundLambda? GuessBestBoundLambda<T>(ImmutableDictionary<T, BoundLambda> candidates) where T : notnull
|
|
{
|
|
return candidates.Count switch
|
|
{
|
|
0 => null,
|
|
1 => candidates.First().Value,
|
|
_ => (from lambda in (from lambda in candidates
|
|
group lambda by lambda.Value.Diagnostics.Diagnostics.Length into @group
|
|
orderby @group.Key
|
|
select @group).First()
|
|
orderby GetLambdaSortString(lambda.Value.Symbol)
|
|
select lambda).FirstOrDefault().Value,
|
|
};
|
|
}
|
|
|
|
private static string GetLambdaSortString(LambdaSymbol lambda)
|
|
{
|
|
PooledStringBuilder instance = PooledStringBuilder.GetInstance();
|
|
ImmutableArray<ParameterSymbol>.Enumerator enumerator = lambda.Parameters.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
ParameterSymbol current = enumerator.Current;
|
|
instance.Builder.Append(current.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageNoParameterNamesFormat));
|
|
}
|
|
if (lambda.ReturnTypeWithAnnotations.HasType)
|
|
{
|
|
instance.Builder.Append(lambda.ReturnTypeWithAnnotations.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
|
|
}
|
|
return instance.ToStringAndFree();
|
|
}
|
|
|
|
public bool GenerateSummaryErrors(BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
|
|
IEnumerable<ImmutableBindingDiagnostic<AssemblySymbol>> first = _bindingCache.Select<KeyValuePair<(NamedTypeSymbol, bool), BoundLambda>, ImmutableBindingDiagnostic<AssemblySymbol>>(delegate(KeyValuePair<(NamedTypeSymbol Type, bool IsExpressionLambda), BoundLambda> boundLambda)
|
|
{
|
|
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
|
|
KeyValuePair<(NamedTypeSymbol, bool), BoundLambda> keyValuePair = boundLambda;
|
|
return keyValuePair.Value.Diagnostics;
|
|
});
|
|
IEnumerable<ImmutableBindingDiagnostic<AssemblySymbol>> second = _returnInferenceCache.Values.Select((BoundLambda boundLambda) => boundLambda.Diagnostics);
|
|
IEnumerable<ImmutableBindingDiagnostic<AssemblySymbol>> enumerable = first.Concat(second);
|
|
FirstAmongEqualsSet<Diagnostic> firstAmongEqualsSet = null;
|
|
foreach (ImmutableBindingDiagnostic<AssemblySymbol> item in enumerable)
|
|
{
|
|
if (firstAmongEqualsSet == null)
|
|
{
|
|
firstAmongEqualsSet = CreateFirstAmongEqualsSet(item.Diagnostics);
|
|
}
|
|
else
|
|
{
|
|
firstAmongEqualsSet.IntersectWith(item.Diagnostics);
|
|
}
|
|
}
|
|
if (firstAmongEqualsSet != null && PreventsSuccessfulDelegateConversion(firstAmongEqualsSet))
|
|
{
|
|
((BindingDiagnosticBag)diagnostics).AddRange((IEnumerable<Diagnostic>)firstAmongEqualsSet);
|
|
return true;
|
|
}
|
|
FirstAmongEqualsSet<Diagnostic> firstAmongEqualsSet2 = null;
|
|
foreach (ImmutableBindingDiagnostic<AssemblySymbol> item2 in enumerable)
|
|
{
|
|
if (firstAmongEqualsSet2 == null)
|
|
{
|
|
firstAmongEqualsSet2 = CreateFirstAmongEqualsSet(item2.Diagnostics);
|
|
}
|
|
else
|
|
{
|
|
firstAmongEqualsSet2.UnionWith(item2.Diagnostics);
|
|
}
|
|
}
|
|
if (firstAmongEqualsSet2 != null && PreventsSuccessfulDelegateConversion(firstAmongEqualsSet2))
|
|
{
|
|
((BindingDiagnosticBag)diagnostics).AddRange((IEnumerable<Diagnostic>)firstAmongEqualsSet2);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static bool PreventsSuccessfulDelegateConversion(FirstAmongEqualsSet<Diagnostic> set)
|
|
{
|
|
foreach (Diagnostic item in set)
|
|
{
|
|
if (ErrorFacts.PreventsSuccessfulDelegateConversion((ErrorCode)item.Code))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static FirstAmongEqualsSet<Diagnostic> CreateFirstAmongEqualsSet(ImmutableArray<Diagnostic> bag)
|
|
{
|
|
return new FirstAmongEqualsSet<Diagnostic>(bag, (IEqualityComparer<Diagnostic>)CommonDiagnosticComparer.Instance, CanonicallyCompareDiagnostics);
|
|
}
|
|
|
|
private static int CanonicallyCompareDiagnostics(Diagnostic x, Diagnostic y)
|
|
{
|
|
if (x.Code != y.Code)
|
|
{
|
|
return x.Code - y.Code;
|
|
}
|
|
int num = x.Arguments?.Count ?? 0;
|
|
int num2 = y.Arguments?.Count ?? 0;
|
|
int i = 0;
|
|
for (int num3 = Math.Min(num, num2); i < num3; i++)
|
|
{
|
|
object obj = x.Arguments[i];
|
|
int num4 = string.CompareOrdinal(strB: y.Arguments[i]?.ToString(), strA: obj?.ToString());
|
|
if (num4 != 0)
|
|
{
|
|
return num4;
|
|
}
|
|
}
|
|
return num - num2;
|
|
}
|
|
}
|