Skip to content

Commit

Permalink
Merge pull request #57893 from dotnet/merges/release/dev17.1-to-main
Browse files Browse the repository at this point in the history
Merge release/dev17.1 to main
  • Loading branch information
dotnet-bot authored Nov 22, 2021
2 parents 2ad1393 + 844c30d commit 5b20a71
Show file tree
Hide file tree
Showing 8 changed files with 477 additions and 41 deletions.
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3246,7 +3246,7 @@ private BoundExpression BindImplicitArrayCreationExpression(ImplicitArrayCreatio
ImmutableArray<BoundExpression> boundInitializerExpressions = BindArrayInitializerExpressions(initializer, diagnostics, dimension: 1, rank: rank);

CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
TypeSymbol bestType = BestTypeInferrer.InferBestType(boundInitializerExpressions, this.Conversions, ref useSiteInfo);
TypeSymbol bestType = BestTypeInferrer.InferBestType(boundInitializerExpressions, this.Conversions, ref useSiteInfo, out _);
diagnostics.Add(node, useSiteInfo);

if ((object)bestType == null || bestType.IsVoidType()) // Dev10 also reports ERR_ImplicitlyTypedArrayNoBestType for void.
Expand All @@ -3273,7 +3273,7 @@ private BoundExpression BindImplicitStackAllocArrayCreationExpression(ImplicitSt
ImmutableArray<BoundExpression> boundInitializerExpressions = BindArrayInitializerExpressions(initializer, diagnostics, dimension: 1, rank: 1);

CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
TypeSymbol bestType = BestTypeInferrer.InferBestType(boundInitializerExpressions, this.Conversions, ref useSiteInfo);
TypeSymbol bestType = BestTypeInferrer.InferBestType(boundInitializerExpressions, this.Conversions, ref useSiteInfo, out _);
diagnostics.Add(node, useSiteInfo);

if ((object)bestType == null || bestType.IsVoidType())
Expand Down
13 changes: 11 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public static NullableFlowState GetNullableState(ArrayBuilder<TypeWithState> typ
public static TypeSymbol? InferBestType(
ImmutableArray<BoundExpression> exprs,
ConversionsBase conversions,
ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo,
out bool inferredFromFunctionType)
{
// SPEC: 7.5.2.14 Finding the best common type of a set of expressions
// SPEC: In some cases, a common type needs to be inferred for a set of expressions. In particular, the element types of implicitly typed arrays and
Expand All @@ -74,6 +75,7 @@ public static NullableFlowState GetNullableState(ArrayBuilder<TypeWithState> typ
{
if (type.IsErrorType())
{
inferredFromFunctionType = false;
return type;
}

Expand All @@ -87,7 +89,14 @@ public static NullableFlowState GetNullableState(ArrayBuilder<TypeWithState> typ
var result = GetBestType(builder, conversions, ref useSiteInfo);
builder.Free();

return (result as FunctionTypeSymbol)?.GetInternalDelegateType() ?? result;
if (result is FunctionTypeSymbol functionType)
{
inferredFromFunctionType = true;
return functionType.GetInternalDelegateType();
}

inferredFromFunctionType = false;
return result;
}

/// <remarks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,8 @@ private bool InferredReturnTypeInference(BoundExpression source, TypeWithAnnotat
return false;
}

Debug.Assert(inferredReturnType.Type is not FunctionTypeSymbol);

LowerBoundInference(inferredReturnType, returnType, ref useSiteInfo);
return true;
}
Expand Down Expand Up @@ -2924,7 +2926,12 @@ private TypeWithAnnotations InferReturnType(BoundExpression source, NamedTypeSym
// the anonymous function is explicitly typed. Make an inference from the
// delegate parameters to the return type.

return anonymousFunction.InferReturnType(_conversions, fixedDelegate, ref useSiteInfo);
var returnType = anonymousFunction.InferReturnType(_conversions, fixedDelegate, ref useSiteInfo, out bool inferredFromFunctionType);
if (inferredFromFunctionType)
{
return default;
}
return returnType;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2539,7 +2539,7 @@ private bool ExpressionMatchExactly(BoundExpression node, TypeSymbol t, ref Comp
BoundLambda lambda = ((UnboundLambda)node).BindForReturnTypeInference(d);

// - an inferred return type X exists for E in the context of the parameter list of D(§7.5.2.12), and an identity conversion exists from X to Y
var x = lambda.GetInferredReturnType(ref useSiteInfo);
var x = lambda.GetInferredReturnType(ref useSiteInfo, out _);
if (x.HasType && Conversions.HasIdentityConversion(x.Type, y))
{
return true;
Expand Down Expand Up @@ -2962,7 +2962,7 @@ private bool CanDowngradeConversionFromLambdaToNeither(BetterResult currentResul
return true;
}

var x = lambda.InferReturnType(Conversions, d1, ref useSiteInfo);
var x = lambda.InferReturnType(Conversions, d1, ref useSiteInfo, out _);
if (!x.HasType)
{
return true;
Expand Down
65 changes: 47 additions & 18 deletions src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ internal readonly struct InferredLambdaReturnType
internal readonly bool HadExpressionlessReturn;
internal readonly RefKind RefKind;
internal readonly TypeWithAnnotations TypeWithAnnotations;
internal readonly bool InferredFromFunctionType;
internal readonly ImmutableArray<DiagnosticInfo> UseSiteDiagnostics;
internal readonly ImmutableArray<AssemblySymbol> Dependencies;

Expand All @@ -50,6 +51,7 @@ internal InferredLambdaReturnType(
bool hadExpressionlessReturn,
RefKind refKind,
TypeWithAnnotations typeWithAnnotations,
bool inferredFromFunctionType,
ImmutableArray<DiagnosticInfo> useSiteDiagnostics,
ImmutableArray<AssemblySymbol> dependencies)
{
Expand All @@ -58,6 +60,7 @@ internal InferredLambdaReturnType(
HadExpressionlessReturn = hadExpressionlessReturn;
RefKind = refKind;
TypeWithAnnotations = typeWithAnnotations;
InferredFromFunctionType = inferredFromFunctionType;
UseSiteDiagnostics = useSiteDiagnostics;
Dependencies = dependencies;
}
Expand Down Expand Up @@ -85,18 +88,18 @@ public BoundLambda(SyntaxNode syntax, UnboundLambda unboundLambda, BoundBlock bo
);
}

public TypeWithAnnotations GetInferredReturnType(ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
public TypeWithAnnotations GetInferredReturnType(ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo, out bool inferredFromFunctionType)
{
// Nullability (and conversions) are ignored.
return GetInferredReturnType(conversions: null, nullableState: null, ref useSiteInfo);
return GetInferredReturnType(conversions: null, nullableState: null, ref useSiteInfo, out inferredFromFunctionType);
}

/// <summary>
/// Infer return type. If `nullableState` is non-null, nullability is also inferred and `NullableWalker.Analyze`
/// uses that state to set the inferred nullability of variables in the enclosing scope. `conversions` is
/// only needed when nullability is inferred.
/// </summary>
public TypeWithAnnotations GetInferredReturnType(ConversionsBase? conversions, NullableWalker.VariableState? nullableState, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
public TypeWithAnnotations GetInferredReturnType(ConversionsBase? conversions, NullableWalker.VariableState? nullableState, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo, out bool inferredFromFunctionType)
{
if (!InferredReturnType.UseSiteDiagnostics.IsEmpty)
{
Expand All @@ -108,9 +111,11 @@ public TypeWithAnnotations GetInferredReturnType(ConversionsBase? conversions, N
useSiteInfo.AddDependencies(InferredReturnType.Dependencies);
}

InferredLambdaReturnType inferredReturnType;

if (nullableState == null || InferredReturnType.IsExplicitType)
{
return InferredReturnType.TypeWithAnnotations;
inferredReturnType = InferredReturnType;
}
else
{
Expand All @@ -133,10 +138,12 @@ public TypeWithAnnotations GetInferredReturnType(ConversionsBase? conversions, N
initialState: nullableState,
returnTypes);
diagnostics.Free();
var inferredReturnType = InferReturnType(returnTypes, node: this, Binder, delegateType, Symbol.IsAsync, conversions);
inferredReturnType = InferReturnType(returnTypes, node: this, Binder, delegateType, Symbol.IsAsync, conversions);
returnTypes.Free();
return inferredReturnType.TypeWithAnnotations;
}

inferredFromFunctionType = inferredReturnType.InferredFromFunctionType;
return inferredReturnType.TypeWithAnnotations;
}

internal LambdaSymbol CreateLambdaSymbol(NamedTypeSymbol delegateType, Symbol containingSymbol) =>
Expand Down Expand Up @@ -202,13 +209,17 @@ private static InferredLambdaReturnType InferReturnTypeImpl(ArrayBuilder<(BoundR
}

var useSiteInfo = withDependencies ? new CompoundUseSiteInfo<AssemblySymbol>(binder.Compilation.Assembly) : CompoundUseSiteInfo<AssemblySymbol>.DiscardedDependencies;
var bestType = CalculateReturnType(binder, conversions, delegateType, types, isAsync, node, ref useSiteInfo);
var bestType = CalculateReturnType(binder, conversions, delegateType, types, isAsync, node, ref useSiteInfo, out bool inferredFromFunctionType);
Debug.Assert(bestType.Type is not FunctionTypeSymbol);
int numExpressions = types.Count;
types.Free();
return new InferredLambdaReturnType(
numExpressions,
isExplicitType: false,
hasReturnWithoutArgument, refKind, bestType,
hadExpressionlessReturn: hasReturnWithoutArgument,
refKind,
bestType,
inferredFromFunctionType: inferredFromFunctionType,
useSiteInfo.Diagnostics.AsImmutableOrEmpty(),
useSiteInfo.AccumulatesDependencies ? useSiteInfo.Dependencies.AsImmutableOrEmpty() : ImmutableArray<AssemblySymbol>.Empty);
}
Expand All @@ -220,38 +231,47 @@ private static TypeWithAnnotations CalculateReturnType(
ArrayBuilder<(BoundExpression expr, TypeWithAnnotations resultType)> returns,
bool isAsync,
BoundNode node,
ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo,
out bool inferredFromFunctionType)
{
TypeWithAnnotations bestResultType;
int n = returns.Count;
switch (n)
{
case 0:
inferredFromFunctionType = false;
bestResultType = default;
break;
case 1:
if (conversions.IncludeNullability)
{
inferredFromFunctionType = false;
bestResultType = returns[0].resultType;
}
else
{
var exprType = returns[0].expr.GetTypeOrFunctionType();
var bestType = exprType is FunctionTypeSymbol functionType ?
functionType.GetInternalDelegateType() :
exprType;
var bestType = returns[0].expr.GetTypeOrFunctionType();
if (bestType is FunctionTypeSymbol functionType)
{
inferredFromFunctionType = true;
bestType = functionType.GetInternalDelegateType();
}
else
{
inferredFromFunctionType = false;
}
bestResultType = TypeWithAnnotations.Create(bestType);
}
break;
default:
// Need to handle ref returns. See https://github.com/dotnet/roslyn/issues/30432
if (conversions.IncludeNullability)
{
bestResultType = NullableWalker.BestTypeForLambdaReturns(returns, binder, node, (Conversions)conversions);
bestResultType = NullableWalker.BestTypeForLambdaReturns(returns, binder, node, (Conversions)conversions, out inferredFromFunctionType);
}
else
{
var bestType = BestTypeInferrer.InferBestType(returns.SelectAsArray(pair => pair.expr), conversions, ref useSiteInfo);
var bestType = BestTypeInferrer.InferBestType(returns.SelectAsArray(pair => pair.expr), conversions, ref useSiteInfo, out inferredFromFunctionType);
bestResultType = TypeWithAnnotations.Create(bestType);
}
break;
Expand Down Expand Up @@ -424,8 +444,8 @@ public bool HasExplicitReturnType(out RefKind refKind, out TypeWithAnnotations r
=> Data.HasExplicitReturnType(out refKind, out returnType);
public bool HasExplicitlyTypedParameterList { get { return Data.HasExplicitlyTypedParameterList; } }
public int ParameterCount { get { return Data.ParameterCount; } }
public TypeWithAnnotations InferReturnType(ConversionsBase conversions, NamedTypeSymbol delegateType, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
=> BindForReturnTypeInference(delegateType).GetInferredReturnType(conversions, _nullableState, ref useSiteInfo);
public TypeWithAnnotations InferReturnType(ConversionsBase conversions, NamedTypeSymbol delegateType, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo, out bool inferredFromFunctionType)
=> BindForReturnTypeInference(delegateType).GetInferredReturnType(conversions, _nullableState, ref useSiteInfo, out inferredFromFunctionType);

public RefKind RefKind(int index) { return Data.RefKind(index); }
public void GenerateAnonymousFunctionConversionError(BindingDiagnosticBag diagnostics, TypeSymbol targetType) { Data.GenerateAnonymousFunctionConversionError(diagnostics, targetType); }
Expand Down Expand Up @@ -816,6 +836,7 @@ private BoundLambda ReallyInferReturnType(
hadExpressionlessReturn: false,
refKind,
returnType,
inferredFromFunctionType: false,
ImmutableArray<DiagnosticInfo>.Empty,
ImmutableArray<AssemblySymbol>.Empty);
}
Expand Down Expand Up @@ -1094,7 +1115,15 @@ private BoundLambda ReallyBindForErrorRecovery(
diagnostics.ToReadOnlyAndFree(),
lambdaBodyBinder,
delegateType,
new InferredLambdaReturnType(inferredReturnType.NumExpressions, isExplicitType: inferredReturnType.IsExplicitType, inferredReturnType.HadExpressionlessReturn, refKind, returnType, ImmutableArray<DiagnosticInfo>.Empty, ImmutableArray<AssemblySymbol>.Empty))
new InferredLambdaReturnType(
inferredReturnType.NumExpressions,
isExplicitType: inferredReturnType.IsExplicitType,
inferredReturnType.HadExpressionlessReturn,
refKind,
returnType,
inferredFromFunctionType: inferredReturnType.InferredFromFunctionType,
ImmutableArray<DiagnosticInfo>.Empty,
ImmutableArray<AssemblySymbol>.Empty))
{ WasCompilerGenerated = _unboundLambda.WasCompilerGenerated };
}

Expand Down
7 changes: 4 additions & 3 deletions src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3457,7 +3457,7 @@ private int GetOrCreatePlaceholderSlot(object identifier, TypeWithAnnotations ty
if (!node.HasErrors)
{
var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;
bestType = BestTypeInferrer.InferBestType(placeholders, _conversions, ref discardedUseSiteInfo);
bestType = BestTypeInferrer.InferBestType(placeholders, _conversions, ref discardedUseSiteInfo, out _);
}

TypeWithAnnotations inferredType = (bestType is null)
Expand Down Expand Up @@ -3517,7 +3517,8 @@ internal static TypeWithAnnotations BestTypeForLambdaReturns(
ArrayBuilder<(BoundExpression, TypeWithAnnotations)> returns,
Binder binder,
BoundNode node,
Conversions conversions)
Conversions conversions,
out bool inferredFromFunctionType)
{
var walker = new NullableWalker(binder.Compilation,
symbol: null,
Expand Down Expand Up @@ -3545,7 +3546,7 @@ internal static TypeWithAnnotations BestTypeForLambdaReturns(

var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;
var placeholders = placeholdersBuilder.ToImmutableAndFree();
TypeSymbol? bestType = BestTypeInferrer.InferBestType(placeholders, walker._conversions, ref discardedUseSiteInfo);
TypeSymbol? bestType = BestTypeInferrer.InferBestType(placeholders, walker._conversions, ref discardedUseSiteInfo, out inferredFromFunctionType);

TypeWithAnnotations inferredType;
if (bestType is { })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ private void VisitSwitchExpressionCore(BoundSwitchExpression node, bool inferTyp
var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;

TypeSymbol inferredType =
(inferType ? BestTypeInferrer.InferBestType(placeholders, _conversions, ref discardedUseSiteInfo) : null)
(inferType ? BestTypeInferrer.InferBestType(placeholders, _conversions, ref discardedUseSiteInfo, out _) : null)
?? node.Type?.SetUnknownNullabilityForReferenceTypes();

var inferredTypeWithAnnotations = TypeWithAnnotations.Create(inferredType);
Expand Down
Loading

0 comments on commit 5b20a71

Please sign in to comment.