提交 8ee822e1 编写于 作者: A AlekseyTs 提交者: GitHub

Merge pull request #16079 from AlekseyTs/Bug296550

Fix a crash caused by an improper reuse of lambdas from return inference cache.
...@@ -110,6 +110,9 @@ public TypeSymbol InferredReturnType(ref HashSet<DiagnosticInfo> useSiteDiagnost ...@@ -110,6 +110,9 @@ public TypeSymbol InferredReturnType(ref HashSet<DiagnosticInfo> useSiteDiagnost
return _inferredReturnType; return _inferredReturnType;
} }
/// <summary>
/// Behavior of this function should be kept aligned with <see cref="UnboundLambdaState.ReturnInferenceCacheKey"/>.
/// </summary>
private static TypeSymbol InferReturnType( private static TypeSymbol InferReturnType(
BoundBlock block, BoundBlock block,
Binder binder, Binder binder,
...@@ -148,12 +151,12 @@ public TypeSymbol InferredReturnType(ref HashSet<DiagnosticInfo> useSiteDiagnost ...@@ -148,12 +151,12 @@ public TypeSymbol InferredReturnType(ref HashSet<DiagnosticInfo> useSiteDiagnost
// Otherwise the return type is Task or Task<T>. // Otherwise the return type is Task or Task<T>.
NamedTypeSymbol taskType = null; NamedTypeSymbol taskType = null;
var delegateReturnType = delegateType?.GetDelegateType()?.DelegateInvokeMethod?.ReturnType as NamedTypeSymbol; var delegateReturnType = delegateType?.GetDelegateType()?.DelegateInvokeMethod?.ReturnType as NamedTypeSymbol;
if ((object)delegateReturnType != null) if ((object)delegateReturnType != null && delegateReturnType.SpecialType != SpecialType.System_Void)
{ {
object builderType; object builderType;
if (delegateReturnType.IsCustomTaskType(out builderType)) if (delegateReturnType.IsCustomTaskType(out builderType))
{ {
taskType = delegateReturnType; taskType = delegateReturnType.ConstructedFrom;
} }
} }
...@@ -176,7 +179,7 @@ public TypeSymbol InferredReturnType(ref HashSet<DiagnosticInfo> useSiteDiagnost ...@@ -176,7 +179,7 @@ public TypeSymbol InferredReturnType(ref HashSet<DiagnosticInfo> useSiteDiagnost
// Some non-void best type T was found; use delegate InvokeMethod // Some non-void best type T was found; use delegate InvokeMethod
// or infer type Task<T> if delegate type not available. // or infer type Task<T> if delegate type not available.
var taskTypeT = (object)taskType != null && taskType.Arity == 1 ? var taskTypeT = (object)taskType != null && taskType.Arity == 1 ?
delegateReturnType.ConstructedFrom : taskType :
binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T); binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T);
return taskTypeT.Construct(bestResultType); return taskTypeT.Construct(bestResultType);
} }
...@@ -294,10 +297,9 @@ internal abstract class UnboundLambdaState ...@@ -294,10 +297,9 @@ internal abstract class UnboundLambdaState
{ {
private UnboundLambda _unboundLambda; // we would prefer this readonly, but we have an initialization cycle. private UnboundLambda _unboundLambda; // we would prefer this readonly, but we have an initialization cycle.
protected readonly Binder binder; protected readonly Binder binder;
private readonly ConcurrentDictionary<object, BoundLambda> _bindingCache = new ConcurrentDictionary<object, BoundLambda>(); private readonly ConcurrentDictionary<NamedTypeSymbol, BoundLambda> _bindingCache = new ConcurrentDictionary<NamedTypeSymbol, BoundLambda>();
private readonly ConcurrentDictionary<MethodSymbol, BoundLambda> _returnInferenceCache = private readonly ConcurrentDictionary<ReturnInferenceCacheKey, BoundLambda> _returnInferenceCache = new ConcurrentDictionary<ReturnInferenceCacheKey, BoundLambda>();
new ConcurrentDictionary<MethodSymbol, BoundLambda>(MemberSignatureComparer.LambdaReturnInferenceCacheComparer);
private BoundLambda _errorBinding; private BoundLambda _errorBinding;
...@@ -424,35 +426,36 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) ...@@ -424,35 +426,36 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType)
// when binding for real (not for return inference), there is still // when binding for real (not for return inference), there is still
// a good chance that we could reuse a body of a lambda previously bound for // a good chance that we could reuse a body of a lambda previously bound for
// return type inference. // return type inference.
MethodSymbol cacheKey = GetCacheKey(delegateType); var cacheKey = ReturnInferenceCacheKey.Create(delegateType, IsAsync);
BoundLambda returnInferenceLambda; BoundLambda returnInferenceLambda;
if (_returnInferenceCache.TryGetValue(cacheKey, out returnInferenceLambda) && returnInferenceLambda.InferredFromSingleType && returnInferenceLambda.Symbol.ReturnType == returnType) if (_returnInferenceCache.TryGetValue(cacheKey, out returnInferenceLambda) && returnInferenceLambda.InferredFromSingleType)
{ {
lambdaSymbol = returnInferenceLambda.Symbol; lambdaSymbol = returnInferenceLambda.Symbol;
Debug.Assert(lambdaSymbol.RefKind == refKind); if ((object)LambdaSymbol.InferenceFailureReturnType != lambdaSymbol.ReturnType &&
lambdaSymbol.ReturnType == returnType && lambdaSymbol.RefKind == refKind)
lambdaBodyBinder = returnInferenceLambda.Binder; {
block = returnInferenceLambda.Body; lambdaBodyBinder = returnInferenceLambda.Binder;
diagnostics.AddRange(returnInferenceLambda.Diagnostics); block = returnInferenceLambda.Body;
diagnostics.AddRange(returnInferenceLambda.Diagnostics);
goto haveLambdaBodyAndBinders; goto haveLambdaBodyAndBinders;
}
} }
var parameters = DelegateParameters(invokeMethod);
lambdaSymbol = new LambdaSymbol( lambdaSymbol = new LambdaSymbol(
binder.Compilation, binder.Compilation,
binder.ContainingMemberOrLambda, binder.ContainingMemberOrLambda,
_unboundLambda, _unboundLambda,
parameters, cacheKey.ParameterTypes,
cacheKey.ParameterRefKinds,
refKind, refKind,
returnType); returnType);
lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder));
block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics); block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics);
((ExecutableCodeBinder)lambdaBodyBinder).ValidateIteratorMethods(diagnostics); ((ExecutableCodeBinder)lambdaBodyBinder).ValidateIteratorMethods(diagnostics);
ValidateUnsafeParameters(diagnostics, parameters); ValidateUnsafeParameters(diagnostics, cacheKey.ParameterTypes);
haveLambdaBodyAndBinders: haveLambdaBodyAndBinders:
...@@ -488,28 +491,13 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) ...@@ -488,28 +491,13 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType)
SourceMemberMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol.Parameters, diagnostics, lambdaSymbol.Locations[0]); SourceMemberMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol.Parameters, diagnostics, lambdaSymbol.Locations[0]);
} }
// This is an attempt to get a repro for https://devdiv.visualstudio.com/DevDiv/_workitems?id=278481
if ((object)returnType != null && returnType.SpecialType != SpecialType.System_Void &&
!block.HasErrors && !diagnostics.HasAnyResolvedErrors() && block.Statements.Length > 0)
{
BoundStatement first = block.Statements[0];
if (first.Kind == BoundKind.ReturnStatement)
{
var returnStmt = (BoundReturnStatement)first;
if (returnStmt.ExpressionOpt != null && (object)returnStmt.ExpressionOpt.Type == null)
{
throw ExceptionUtilities.Unreachable;
}
}
}
var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: false) var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: false)
{ WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated };
return result; return result;
} }
private void ValidateUnsafeParameters(DiagnosticBag diagnostics, ImmutableArray<ParameterSymbol> parameters) private void ValidateUnsafeParameters(DiagnosticBag diagnostics, ImmutableArray<TypeSymbol> targetParameterTypes)
{ {
// It is legal to use a delegate type that has unsafe parameter types inside // It is legal to use a delegate type that has unsafe parameter types inside
// a safe context if the anonymous method has no parameter list! // a safe context if the anonymous method has no parameter list!
...@@ -521,13 +509,12 @@ private void ValidateUnsafeParameters(DiagnosticBag diagnostics, ImmutableArray< ...@@ -521,13 +509,12 @@ private void ValidateUnsafeParameters(DiagnosticBag diagnostics, ImmutableArray<
if (this.HasSignature) if (this.HasSignature)
{ {
// NOTE: we can get here with parameters.Length > ParameterCount // NOTE: we can get here with targetParameterTypes.Length > ParameterCount
// in a case where we are binding for error reporting purposes // in a case where we are binding for error reporting purposes
var numParametersToCheck = Math.Min(parameters.Length, ParameterCount); var numParametersToCheck = Math.Min(targetParameterTypes.Length, ParameterCount);
for (int i = 0; i < numParametersToCheck; i++) for (int i = 0; i < numParametersToCheck; i++)
{ {
ParameterSymbol parameter = parameters[i]; if (targetParameterTypes[i].IsUnsafe())
if (parameter.Type.IsUnsafe())
{ {
this.binder.ReportUnsafeIfNotAllowed(this.ParameterLocation(i), diagnostics); this.binder.ReportUnsafeIfNotAllowed(this.ParameterLocation(i), diagnostics);
} }
...@@ -535,12 +522,10 @@ private void ValidateUnsafeParameters(DiagnosticBag diagnostics, ImmutableArray< ...@@ -535,12 +522,10 @@ private void ValidateUnsafeParameters(DiagnosticBag diagnostics, ImmutableArray<
} }
} }
private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType) private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType, ImmutableArray<TypeSymbol> parameterTypes, ImmutableArray<RefKind> parameterRefKinds)
{ {
var diagnostics = DiagnosticBag.GetInstance(); var diagnostics = DiagnosticBag.GetInstance();
var invokeMethod = DelegateInvokeMethod(delegateType); var lambdaSymbol = new LambdaSymbol(binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameterTypes, parameterRefKinds, refKind: Microsoft.CodeAnalysis.RefKind.None, returnType: null);
var parameters = DelegateParameters(invokeMethod);
var lambdaSymbol = new LambdaSymbol(binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameters, refKind: Microsoft.CodeAnalysis.RefKind.None, returnType: null);
Binder lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); Binder lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder));
var block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics); var block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics);
...@@ -548,7 +533,7 @@ private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType) ...@@ -548,7 +533,7 @@ private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType)
{ WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated };
HashSet<DiagnosticInfo> useSiteDiagnostics = null; // TODO: figure out if this should be somehow merged into BoundLambda.Diagnostics. HashSet<DiagnosticInfo> useSiteDiagnostics = null; // TODO: figure out if this should be somehow merged into BoundLambda.Diagnostics.
TypeSymbol returnType = result.InferredReturnType(ref useSiteDiagnostics) ?? new ExtendedErrorTypeSymbol(binder.Compilation, string.Empty, 0, null); TypeSymbol returnType = result.InferredReturnType(ref useSiteDiagnostics) ?? LambdaSymbol.InferenceFailureReturnType;
lambdaSymbol.SetInferredReturnType(result.RefKind, returnType); lambdaSymbol.SetInferredReturnType(result.RefKind, returnType);
return result; return result;
...@@ -556,35 +541,104 @@ private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType) ...@@ -556,35 +541,104 @@ private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType)
public BoundLambda BindForReturnTypeInference(NamedTypeSymbol delegateType) public BoundLambda BindForReturnTypeInference(NamedTypeSymbol delegateType)
{ {
MethodSymbol cacheKey = GetCacheKey(delegateType); var cacheKey = ReturnInferenceCacheKey.Create(delegateType, IsAsync);
BoundLambda result; BoundLambda result;
if (!_returnInferenceCache.TryGetValue(cacheKey, out result)) if (!_returnInferenceCache.TryGetValue(cacheKey, out result))
{ {
result = ReallyInferReturnType(delegateType); result = ReallyInferReturnType(delegateType, cacheKey.ParameterTypes, cacheKey.ParameterRefKinds);
_returnInferenceCache.TryAdd(cacheKey, result); _returnInferenceCache.TryAdd(cacheKey, result);
// In case the return value of the BoundLambda is distinct from
// delegateType, add the BoundLambda to the cache by the
// distinct signature as well.
_returnInferenceCache.TryAdd(result.Symbol, result);
} }
return result; return result;
} }
private MethodSymbol GetCacheKey(NamedTypeSymbol delegateType) /// <summary>
/// Behavior of this key should be kept aligned with <see cref="BoundLambda.InferReturnType"/>.
/// </summary>
internal class ReturnInferenceCacheKey
{ {
var invoke = DelegateInvokeMethod(delegateType); public readonly ImmutableArray<TypeSymbol> ParameterTypes;
if ((object)invoke != null) public readonly ImmutableArray<RefKind> ParameterRefKinds;
public readonly NamedTypeSymbol TaskLikeReturnTypeOpt;
public static readonly ReturnInferenceCacheKey Empty = new ReturnInferenceCacheKey(ImmutableArray<TypeSymbol>.Empty, ImmutableArray<RefKind>.Empty, null);
private ReturnInferenceCacheKey(ImmutableArray<TypeSymbol> parameterTypes, ImmutableArray<RefKind> parameterRefKinds, NamedTypeSymbol taskLikeReturnTypeOpt)
{ {
return invoke; Debug.Assert(parameterTypes.Length == parameterRefKinds.Length);
Debug.Assert((object)taskLikeReturnTypeOpt == null || ((object)taskLikeReturnTypeOpt == taskLikeReturnTypeOpt.ConstructedFrom && taskLikeReturnTypeOpt.IsCustomTaskType(out var builderArgument)));
this.ParameterTypes = parameterTypes;
this.ParameterRefKinds = parameterRefKinds;
this.TaskLikeReturnTypeOpt = taskLikeReturnTypeOpt;
} }
// delegateType or DelegateInvokeMethod can be null in cases of malformed delegates public override bool Equals(object obj)
// in such case we would want something trivial with no parameters, like a fake static ctor. {
// Since the containingType of the .cctor must be non-null, System.Object is used. if ((object)this == obj)
return new SynthesizedStaticConstructor(binder.Compilation.GetSpecialType(SpecialType.System_Object)); {
return true;
}
var other = obj as ReturnInferenceCacheKey;
return (object)other != null &&
other.ParameterTypes.SequenceEqual(this.ParameterTypes) &&
other.ParameterRefKinds.SequenceEqual(this.ParameterRefKinds) &&
other.TaskLikeReturnTypeOpt == this.TaskLikeReturnTypeOpt;
}
public override int GetHashCode()
{
return Hash.Combine(TaskLikeReturnTypeOpt?.GetHashCode() ?? 0, Hash.CombineValues(this.ParameterTypes));
}
public static ReturnInferenceCacheKey Create(NamedTypeSymbol delegateType, bool isAsync)
{
// delegateType or DelegateInvokeMethod can be null in cases of malformed delegates
// in such case we would want something trivial with no parameters
var parameterTypes = ImmutableArray<TypeSymbol>.Empty;
var parameterRefKinds = ImmutableArray<RefKind>.Empty;
NamedTypeSymbol taskLikeReturnTypeOpt = null;
MethodSymbol invoke = DelegateInvokeMethod(delegateType);
if ((object)invoke != null)
{
int parameterCount = invoke.ParameterCount;
if (parameterCount > 0)
{
var typesBuilder = ArrayBuilder<TypeSymbol>.GetInstance(parameterCount);
var refKindsBuilder = ArrayBuilder<RefKind>.GetInstance(parameterCount);
foreach (var p in invoke.Parameters)
{
refKindsBuilder.Add(p.RefKind);
typesBuilder.Add(p.Type);
}
parameterTypes = typesBuilder.ToImmutableAndFree();
parameterRefKinds = refKindsBuilder.ToImmutableAndFree();
}
if (isAsync)
{
var delegateReturnType = invoke.ReturnType as NamedTypeSymbol;
if ((object)delegateReturnType != null && delegateReturnType.SpecialType != SpecialType.System_Void)
{
if (delegateReturnType.IsCustomTaskType(out var builderType))
{
taskLikeReturnTypeOpt = delegateReturnType.ConstructedFrom;
}
}
}
}
if (parameterTypes.IsEmpty && parameterRefKinds.IsEmpty && (object)taskLikeReturnTypeOpt == null)
{
return Empty;
}
return new ReturnInferenceCacheKey(parameterTypes, parameterRefKinds, taskLikeReturnTypeOpt);
}
} }
public TypeSymbol InferReturnType(NamedTypeSymbol delegateType, ref HashSet<DiagnosticInfo> useSiteDiagnostics) public TypeSymbol InferReturnType(NamedTypeSymbol delegateType, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
...@@ -639,7 +693,7 @@ private BoundLambda ReallyBindForErrorRecovery() ...@@ -639,7 +693,7 @@ private BoundLambda ReallyBindForErrorRecovery()
return return
GuessBestBoundLambda(_bindingCache.Values) GuessBestBoundLambda(_bindingCache.Values)
?? GuessBestBoundLambda(_returnInferenceCache.Values) ?? GuessBestBoundLambda(_returnInferenceCache.Values)
?? ReallyInferReturnType(null); ?? ReallyInferReturnType(null, ImmutableArray<TypeSymbol>.Empty, ImmutableArray<RefKind>.Empty);
} }
private static BoundLambda GuessBestBoundLambda(ICollection<BoundLambda> candidates) private static BoundLambda GuessBestBoundLambda(ICollection<BoundLambda> candidates)
......
...@@ -274,9 +274,6 @@ private static Binder GetEnclosingBinder(SyntaxNode node, int position, Binder r ...@@ -274,9 +274,6 @@ private static Binder GetEnclosingBinder(SyntaxNode node, int position, Binder r
{ {
binder = new ExecutableCodeBinder(unexpectedAnonymousFunction, binder = new ExecutableCodeBinder(unexpectedAnonymousFunction,
new LambdaSymbol(binder.ContainingMemberOrLambda, new LambdaSymbol(binder.ContainingMemberOrLambda,
ImmutableArray<ParameterSymbol>.Empty,
RefKind.None,
ErrorTypeSymbol.UnknownResultType,
unexpectedAnonymousFunction.Kind() == SyntaxKind.AnonymousMethodExpression ? MessageID.IDS_AnonMethod : MessageID.IDS_Lambda, unexpectedAnonymousFunction.Kind() == SyntaxKind.AnonymousMethodExpression ? MessageID.IDS_AnonMethod : MessageID.IDS_Lambda,
unexpectedAnonymousFunction, unexpectedAnonymousFunction,
isSynthesized: false), isSynthesized: false),
......
...@@ -963,12 +963,6 @@ public BoundExpression Null(TypeSymbol type) ...@@ -963,12 +963,6 @@ public BoundExpression Null(TypeSymbol type)
public BoundTypeExpression Type(TypeSymbol type) public BoundTypeExpression Type(TypeSymbol type)
{ {
// This is an attempt to get a repro for https://devdiv.visualstudio.com/DevDiv/_workitems?id=278481
if ((object)type == null)
{
throw ExceptionUtilities.Unreachable;
}
return new BoundTypeExpression(Syntax, null, type) { WasCompilerGenerated = true }; return new BoundTypeExpression(Syntax, null, type) { WasCompilerGenerated = true };
} }
......
...@@ -262,21 +262,6 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol> ...@@ -262,21 +262,6 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
considerRefOutDifference: true, considerRefOutDifference: true,
considerCustomModifiers: false); considerCustomModifiers: false);
/// <summary>
/// This instance is used as a key in the lambda return type inference.
/// We basically only interested in parameters since inference will set the return type to null.
/// </summary>
public static readonly MemberSignatureComparer LambdaReturnInferenceCacheComparer = new MemberSignatureComparer(
considerName: false, // valid invoke is always called "Invoke"
considerExplicitlyImplementedInterfaces: false,
considerReturnType: true, // to differentiate Task types
considerTypeConstraints: false, // valid invoke is never generic
considerCallingConvention: false, // valid invoke is never static
considerRefOutDifference: true,
considerCustomModifiers: true,
ignoreDynamic: false,
ignoreTupleNames: false);
// Compare the "unqualified" part of the member name (no explicit part) // Compare the "unqualified" part of the member name (no explicit part)
private readonly bool _considerName; private readonly bool _considerName;
......
...@@ -18,11 +18,17 @@ internal sealed class LambdaSymbol : MethodSymbol ...@@ -18,11 +18,17 @@ internal sealed class LambdaSymbol : MethodSymbol
private readonly bool _isSynthesized; private readonly bool _isSynthesized;
private readonly bool _isAsync; private readonly bool _isAsync;
/// <summary>
/// This symbol is used as the return type of a LambdaSymbol when we failed to infer its return type.
/// </summary>
internal static readonly TypeSymbol InferenceFailureReturnType = new UnsupportedMetadataTypeSymbol();
public LambdaSymbol( public LambdaSymbol(
CSharpCompilation compilation, CSharpCompilation compilation,
Symbol containingSymbol, Symbol containingSymbol,
UnboundLambda unboundLambda, UnboundLambda unboundLambda,
ImmutableArray<ParameterSymbol> delegateParameters, ImmutableArray<TypeSymbol> parameterTypes,
ImmutableArray<RefKind> parameterRefKinds,
RefKind refKind, RefKind refKind,
TypeSymbol returnType) TypeSymbol returnType)
{ {
...@@ -34,14 +40,11 @@ internal sealed class LambdaSymbol : MethodSymbol ...@@ -34,14 +40,11 @@ internal sealed class LambdaSymbol : MethodSymbol
_isSynthesized = unboundLambda.WasCompilerGenerated; _isSynthesized = unboundLambda.WasCompilerGenerated;
_isAsync = unboundLambda.IsAsync; _isAsync = unboundLambda.IsAsync;
// No point in making this lazy. We are always going to need these soon after creation of the symbol. // No point in making this lazy. We are always going to need these soon after creation of the symbol.
_parameters = MakeParameters(compilation, unboundLambda, delegateParameters); _parameters = MakeParameters(compilation, unboundLambda, parameterTypes, parameterRefKinds);
} }
public LambdaSymbol( public LambdaSymbol(
Symbol containingSymbol, Symbol containingSymbol,
ImmutableArray<ParameterSymbol> parameters,
RefKind refKind,
TypeSymbol returnType,
MessageID messageID, MessageID messageID,
SyntaxNode syntax, SyntaxNode syntax,
bool isSynthesized) bool isSynthesized)
...@@ -49,10 +52,10 @@ internal sealed class LambdaSymbol : MethodSymbol ...@@ -49,10 +52,10 @@ internal sealed class LambdaSymbol : MethodSymbol
_containingSymbol = containingSymbol; _containingSymbol = containingSymbol;
_messageID = messageID; _messageID = messageID;
_syntax = syntax; _syntax = syntax;
_refKind = refKind; _refKind = RefKind.None;
_returnType = returnType; _returnType = ErrorTypeSymbol.UnknownResultType;
_isSynthesized = isSynthesized; _isSynthesized = isSynthesized;
_parameters = parameters.SelectAsArray(CopyParameter, this); _parameters = ImmutableArray<ParameterSymbol>.Empty;
} }
public MessageID MessageID { get { return _messageID; } } public MessageID MessageID { get { return _messageID; } }
...@@ -287,17 +290,27 @@ public override bool HidesBaseMethodsByName ...@@ -287,17 +290,27 @@ public override bool HidesBaseMethodsByName
private ImmutableArray<ParameterSymbol> MakeParameters( private ImmutableArray<ParameterSymbol> MakeParameters(
CSharpCompilation compilation, CSharpCompilation compilation,
UnboundLambda unboundLambda, UnboundLambda unboundLambda,
ImmutableArray<ParameterSymbol> delegateParameters) ImmutableArray<TypeSymbol> parameterTypes,
ImmutableArray<RefKind> parameterRefKinds)
{ {
Debug.Assert(parameterTypes.Length == parameterRefKinds.Length);
if (!unboundLambda.HasSignature || unboundLambda.ParameterCount == 0) if (!unboundLambda.HasSignature || unboundLambda.ParameterCount == 0)
{ {
// The parameters may be omitted in source, but they are still present on the symbol. // The parameters may be omitted in source, but they are still present on the symbol.
return delegateParameters.SelectAsArray(CopyParameter, this); return parameterTypes.SelectAsArray((type, ordinal, arg) =>
SynthesizedParameterSymbol.Create(
arg.owner,
type,
ordinal,
arg.refKinds[ordinal],
GeneratedNames.LambdaCopyParameterName(ordinal)), // Make sure nothing binds to this.
(owner: this, refKinds: parameterRefKinds));
} }
var builder = ArrayBuilder<ParameterSymbol>.GetInstance(); var builder = ArrayBuilder<ParameterSymbol>.GetInstance();
var hasExplicitlyTypedParameterList = unboundLambda.HasExplicitlyTypedParameterList; var hasExplicitlyTypedParameterList = unboundLambda.HasExplicitlyTypedParameterList;
var numDelegateParameters = delegateParameters.IsDefault ? 0 : delegateParameters.Length; var numDelegateParameters = parameterTypes.Length;
for (int p = 0; p < unboundLambda.ParameterCount; ++p) for (int p = 0; p < unboundLambda.ParameterCount; ++p)
{ {
...@@ -316,9 +329,8 @@ public override bool HidesBaseMethodsByName ...@@ -316,9 +329,8 @@ public override bool HidesBaseMethodsByName
} }
else if (p < numDelegateParameters) else if (p < numDelegateParameters)
{ {
ParameterSymbol delegateParameter = delegateParameters[p]; type = parameterTypes[p];
type = delegateParameter.Type; refKind = parameterRefKinds[p];
refKind = delegateParameter.RefKind;
} }
else else
{ {
...@@ -339,16 +351,6 @@ public override bool HidesBaseMethodsByName ...@@ -339,16 +351,6 @@ public override bool HidesBaseMethodsByName
return result; return result;
} }
private static ParameterSymbol CopyParameter(ParameterSymbol parameter, MethodSymbol owner)
{
return SynthesizedParameterSymbol.Create(
owner,
parameter.Type,
parameter.Ordinal,
parameter.RefKind,
GeneratedNames.LambdaCopyParameterName(parameter)); // Make sure nothing binds to this.
}
public sealed override bool Equals(object symbol) public sealed override bool Equals(object symbol)
{ {
if ((object)this == symbol) return true; if ((object)this == symbol) return true;
......
...@@ -510,9 +510,9 @@ internal static string ReusableHoistedLocalFieldName(int number) ...@@ -510,9 +510,9 @@ internal static string ReusableHoistedLocalFieldName(int number)
return "<>7__wrap" + StringExtensions.GetNumeral(number); return "<>7__wrap" + StringExtensions.GetNumeral(number);
} }
internal static string LambdaCopyParameterName(ParameterSymbol sourceParameter) internal static string LambdaCopyParameterName(int ordinal)
{ {
return "<" + sourceParameter.Name + ">"; return "<p" + StringExtensions.GetNumeral(ordinal) + ">";
} }
} }
} }
...@@ -1594,7 +1594,7 @@ public static void Main() ...@@ -1594,7 +1594,7 @@ public static void Main()
Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned));
Assert.Equal("p", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("p", GetSymbolNamesJoined(analysis.Captured));
Assert.Equal("i", GetSymbolNamesJoined(analysis.UnsafeAddressTaken)); Assert.Equal("i", GetSymbolNamesJoined(analysis.UnsafeAddressTaken));
Assert.Equal("<p>", GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("<p0>", GetSymbolNamesJoined(analysis.VariablesDeclared));
Assert.Equal("p", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("p", GetSymbolNamesJoined(analysis.DataFlowsIn));
Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut));
...@@ -1602,7 +1602,7 @@ public static void Main() ...@@ -1602,7 +1602,7 @@ public static void Main()
Assert.Equal("p", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("p", GetSymbolNamesJoined(analysis.ReadInside));
Assert.Equal("i", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("i", GetSymbolNamesJoined(analysis.ReadOutside));
Assert.Equal("<p>", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("<p0>", GetSymbolNamesJoined(analysis.WrittenInside));
Assert.Equal("i, p, d", GetSymbolNamesJoined(analysis.WrittenOutside)); Assert.Equal("i, p, d", GetSymbolNamesJoined(analysis.WrittenOutside));
} }
......
...@@ -1638,8 +1638,8 @@ static void Main(string[] args) ...@@ -1638,8 +1638,8 @@ static void Main(string[] args)
var lambdaParameters = ((MethodSymbol)(model.GetSymbolInfo(node1)).Symbol).Parameters; var lambdaParameters = ((MethodSymbol)(model.GetSymbolInfo(node1)).Symbol).Parameters;
Assert.Equal("System.Object <sender>", lambdaParameters[0].ToTestDisplayString()); Assert.Equal("System.Object <p0>", lambdaParameters[0].ToTestDisplayString());
Assert.Equal("System.EventArgs <e>", lambdaParameters[1].ToTestDisplayString()); Assert.Equal("System.EventArgs <p1>", lambdaParameters[1].ToTestDisplayString());
CompileAndVerify(compilation); CompileAndVerify(compilation);
} }
...@@ -2292,7 +2292,7 @@ public static class C ...@@ -2292,7 +2292,7 @@ public static class C
} }
[Fact, WorkItem(278481, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=278481")] [Fact, WorkItem(278481, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=278481")]
public void LambdaReturningNull() public void LambdaReturningNull_1()
{ {
var src = @" var src = @"
public static class ExtensionMethods public static class ExtensionMethods
...@@ -2319,6 +2319,18 @@ public static class ExtensionMethods ...@@ -2319,6 +2319,18 @@ public static class ExtensionMethods
return null; return null;
} }
public static System.Collections.Generic.IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(
this System.Collections.Generic.IEnumerable<TOuter> outerValues,
System.Linq.IQueryable<TInner> innerValues,
System.Func<TOuter, TKey> outerKeySelector,
System.Func<TInner, TKey> innerKeySelector,
System.Func<TOuter, TInner, TResult> fullResultSelector,
System.Func<TOuter, TResult> partialResultSelector)
{
System.Console.WriteLine(""2"");
return null;
}
public static System.Collections.Generic.IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>( public static System.Collections.Generic.IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(
this System.Collections.Generic.IEnumerable<TOuter> outerQueryable, this System.Collections.Generic.IEnumerable<TOuter> outerQueryable,
System.Collections.Generic.IEnumerable<TInner> innerQueryable, System.Collections.Generic.IEnumerable<TInner> innerQueryable,
...@@ -2356,6 +2368,36 @@ class B ...@@ -2356,6 +2368,36 @@ class B
CompileAndVerify(comp, expectedOutput: "1"); CompileAndVerify(comp, expectedOutput: "1");
} }
[Fact, WorkItem(296550, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=296550")]
public void LambdaReturningNull_2()
{
var src = @"
class Test1<T>
{
public void M1(System.Func<T> x) {}
public void M1<S>(System.Func<S> x) {}
public void M2<S>(System.Func<S> x) {}
public void M2(System.Func<T> x) {}
}
class Test2 : Test1<System.>
{
void Main()
{
M1(()=> null);
M2(()=> null);
}
}
";
var comp = CreateCompilationWithMscorlib(src, options: TestOptions.DebugDll);
comp.VerifyDiagnostics(
// (10,32): error CS1001: Identifier expected
// class Test2 : Test1<System.>
Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(10, 32)
);
}
[Fact] [Fact]
public void ThrowExpression_Lambda() public void ThrowExpression_Lambda()
{ {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册