Skip to content

Commit 8c7d323

Browse files
author
msftbot[bot]
authored
Merge pull request #44755 from dotnet/merges/master-to-master-vs-deps
Merge master to master-vs-deps
2 parents 8449260 + b08173b commit 8c7d323

File tree

292 files changed

+24576
-773
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

292 files changed

+24576
-773
lines changed

eng/build.sh

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ usage()
2626
echo "Test actions:"
2727
echo " --testCoreClr Run unit tests on .NET Core (short: --test, -t)"
2828
echo " --testMono Run unit tests on Mono"
29+
echo " --testIOperation Run unit tests with the IOperation test hook"
2930
echo ""
3031
echo "Advanced settings:"
3132
echo " --ci Building in CI"
@@ -58,6 +59,7 @@ pack=false
5859
publish=false
5960
test_core_clr=false
6061
test_mono=false
62+
test_ioperation=false
6163

6264
configuration="Debug"
6365
verbosity='minimal'
@@ -121,6 +123,9 @@ while [[ $# > 0 ]]; do
121123
--testmono)
122124
test_mono=true
123125
;;
126+
--testioperation)
127+
test_ioperation=true
128+
;;
124129
--ci)
125130
ci=true
126131
;;
@@ -129,7 +134,7 @@ while [[ $# > 0 ]]; do
129134
# Bootstrap requires restore
130135
restore=true
131136
;;
132-
--runAnalyzers)
137+
--runanalyzers)
133138
run_analyzers=true
134139
;;
135140
--preparemachine)
@@ -235,6 +240,14 @@ function BuildSolution {
235240
disable_parallel_restore=true
236241
fi
237242

243+
if [[ "$test_ioperation" == true ]]; then
244+
export ROSLYN_TEST_IOPERATION="true"
245+
246+
if [[ "$test_mono" != true && "$test_core_clr" != true ]]; then
247+
test_core_clr=true
248+
fi
249+
fi
250+
238251
local test=false
239252
local test_runtime=""
240253
local mono_tool=""

src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -370,10 +370,20 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin
370370
Error(diagnostics, GetStandardLvalueError(valueKind), node);
371371
return false;
372372

373+
case BoundKind.UnconvertedAddressOfOperator:
374+
var unconvertedAddressOf = (BoundUnconvertedAddressOfOperator)expr;
375+
Error(diagnostics, GetMethodGroupOrFunctionPointerLvalueError(valueKind), node, unconvertedAddressOf.Operand.Name, MessageID.IDS_AddressOfMethodGroup.Localize());
376+
return false;
377+
378+
case BoundKind.MethodGroup when valueKind == BindValueKind.AddressOf:
379+
// If the addressof operator is used not as an rvalue, that will get flagged when CheckValue
380+
// is called on the parent BoundUnconvertedAddressOf node.
381+
return true;
382+
373383
case BoundKind.MethodGroup:
374-
// method groups can only be used as RValues
384+
// method groups can only be used as RValues except when taking the address of one
375385
var methodGroup = (BoundMethodGroup)expr;
376-
Error(diagnostics, GetMethodGroupLvalueError(valueKind), node, methodGroup.Name, MessageID.IDS_MethodGroup.Localize());
386+
Error(diagnostics, GetMethodGroupOrFunctionPointerLvalueError(valueKind), node, methodGroup.Name, MessageID.IDS_MethodGroup.Localize());
377387
return false;
378388

379389
case BoundKind.RangeVariable:
@@ -495,6 +505,14 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin
495505
var call = (BoundCall)expr;
496506
return CheckCallValueKind(call, node, valueKind, checkingReceiver, diagnostics);
497507

508+
case BoundKind.FunctionPointerInvocation:
509+
return CheckMethodReturnValueKind(((BoundFunctionPointerInvocation)expr).FunctionPointer.Signature,
510+
expr.Syntax,
511+
node,
512+
valueKind,
513+
checkingReceiver,
514+
diagnostics);
515+
498516
case BoundKind.IndexOrRangePatternIndexerAccess:
499517
var patternIndexer = (BoundIndexOrRangePatternIndexerAccess)expr;
500518
// If we got here this should be a pttern indexer taking a Range,
@@ -1634,13 +1652,8 @@ private static ErrorCode GetRangeLvalueError(BindValueKind kind)
16341652
throw ExceptionUtilities.UnexpectedValue(kind);
16351653
}
16361654

1637-
private static ErrorCode GetMethodGroupLvalueError(BindValueKind valueKind)
1655+
private static ErrorCode GetMethodGroupOrFunctionPointerLvalueError(BindValueKind valueKind)
16381656
{
1639-
if (valueKind == BindValueKind.AddressOf)
1640-
{
1641-
return ErrorCode.ERR_InvalidAddrOp;
1642-
}
1643-
16441657
if (RequiresReferenceToLocation(valueKind))
16451658
{
16461659
return ErrorCode.ERR_RefReadonlyLocalCause;

src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ static bool isValidConstraintType(TypeConstraintSyntax syntax, TypeWithAnnotatio
510510

511511
case TypeKind.Array:
512512
case TypeKind.Pointer:
513+
case TypeKind.FunctionPointer:
513514
// "Invalid constraint type. A type used as a constraint must be an interface, a non-sealed class or a type parameter."
514515
Error(diagnostics, ErrorCode.ERR_BadConstraintType, syntax.GetLocation());
515516
return false;

src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs

Lines changed: 110 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -441,13 +441,18 @@ private static BoundExpression CreateAnonymousFunctionConversion(SyntaxNode synt
441441

442442
private BoundExpression CreateMethodGroupConversion(SyntaxNode syntax, BoundExpression source, Conversion conversion, bool isCast, ConversionGroup? conversionGroup, TypeSymbol destination, DiagnosticBag diagnostics)
443443
{
444-
BoundMethodGroup group = FixMethodGroupWithTypeOrValue((BoundMethodGroup)source, conversion, diagnostics);
444+
var originalGroup = source switch
445+
{
446+
BoundMethodGroup m => m,
447+
BoundUnconvertedAddressOfOperator { Operand: { } m } => m,
448+
_ => throw ExceptionUtilities.UnexpectedValue(source),
449+
};
450+
BoundMethodGroup group = FixMethodGroupWithTypeOrValue(originalGroup, conversion, diagnostics);
445451
BoundExpression? receiverOpt = group.ReceiverOpt;
446452
MethodSymbol? method = conversion.Method;
447453
bool hasErrors = false;
448454

449-
NamedTypeSymbol delegateType = (NamedTypeSymbol)destination;
450-
if (MethodGroupConversionHasErrors(syntax, conversion, group.ReceiverOpt, conversion.IsExtensionMethod, delegateType, diagnostics))
455+
if (MethodGroupConversionHasErrors(syntax, conversion, group.ReceiverOpt, conversion.IsExtensionMethod, destination, diagnostics))
451456
{
452457
hasErrors = true;
453458
}
@@ -859,26 +864,31 @@ internal static bool WasImplicitReceiver([NotNullWhen(false)] BoundExpression? r
859864
/// <summary>
860865
/// This method implements the checks in spec section 15.2.
861866
/// </summary>
862-
internal bool MethodGroupIsCompatibleWithDelegate(BoundExpression? receiverOpt, bool isExtensionMethod, MethodSymbol method, NamedTypeSymbol delegateType, Location errorLocation, DiagnosticBag diagnostics)
867+
internal bool MethodIsCompatibleWithDelegateOrFunctionPointer(BoundExpression? receiverOpt, bool isExtensionMethod, MethodSymbol method, TypeSymbol delegateType, Location errorLocation, DiagnosticBag diagnostics)
863868
{
864-
Debug.Assert(delegateType.TypeKind == TypeKind.Delegate);
865-
RoslynDebug.Assert((object)delegateType.DelegateInvokeMethod != null && !delegateType.DelegateInvokeMethod.HasUseSiteError,
866-
"This method should only be called for valid delegate types.");
869+
Debug.Assert(delegateType is NamedTypeSymbol { TypeKind: TypeKind.Delegate, DelegateInvokeMethod: { HasUseSiteError: false } }
870+
|| delegateType.TypeKind == TypeKind.FunctionPointer,
871+
"This method should only be called for valid delegate or function pointer types.");
867872

868-
MethodSymbol delegateMethod = delegateType.DelegateInvokeMethod;
873+
MethodSymbol delegateOrFuncPtrMethod = delegateType switch
874+
{
875+
NamedTypeSymbol { DelegateInvokeMethod: { } invokeMethod } => invokeMethod,
876+
FunctionPointerTypeSymbol { Signature: { } signature } => signature,
877+
_ => throw ExceptionUtilities.UnexpectedValue(delegateType),
878+
};
869879

870880
Debug.Assert(!isExtensionMethod || (receiverOpt != null));
871881

872882
// - Argument types "match", and
873-
var delegateParameters = delegateMethod.Parameters;
883+
var delegateOrFuncPtrParameters = delegateOrFuncPtrMethod.Parameters;
874884
var methodParameters = method.Parameters;
875-
int numParams = delegateParameters.Length;
885+
int numParams = delegateOrFuncPtrParameters.Length;
876886

877887
if (methodParameters.Length != numParams + (isExtensionMethod ? 1 : 0))
878888
{
879889
// This can happen if "method" has optional parameters.
880890
Debug.Assert(methodParameters.Length > numParams + (isExtensionMethod ? 1 : 0));
881-
Error(diagnostics, ErrorCode.ERR_MethDelegateMismatch, errorLocation, method, delegateType);
891+
Error(diagnostics, getMethodMismatchErrorCode(delegateType.TypeKind), errorLocation, method, delegateType);
882892
return false;
883893
}
884894

@@ -893,34 +903,44 @@ internal bool MethodGroupIsCompatibleWithDelegate(BoundExpression? receiverOpt,
893903

894904
for (int i = 0; i < numParams; i++)
895905
{
896-
var delegateParameter = delegateParameters[i];
906+
var delegateParameter = delegateOrFuncPtrParameters[i];
897907
var methodParameter = methodParameters[isExtensionMethod ? i + 1 : i];
898908

899-
if (delegateParameter.RefKind != methodParameter.RefKind ||
900-
!Conversions.HasIdentityOrImplicitReferenceConversion(delegateParameter.Type, methodParameter.Type, ref useSiteDiagnostics))
909+
// The delegate compatibility checks are stricter than the checks on applicable functions: it's possible
910+
// to get here with a method that, while all the parameters are applicable, is not actually delegate
911+
// compatible. This is because the Applicable function member spec requires that:
912+
// * Every value parameter (non-ref or similar) from the delegate type has an implicit conversion to the corresponding
913+
// target parameter
914+
// * Every ref or similar parameter has an identity conversion to the corresponding target parameter
915+
// However, the delegate compatiblity requirements are stricter:
916+
// * Every value parameter (non-ref or similar) from the delegate type has an implicit _reference_ conversion to the
917+
// corresponding target parameter.
918+
// * Every ref or similar parameter has an identity conversion to the corresponding target parameter
919+
// Note the addition of the reference requirement: it means that for delegate type void D(int i), void M(long l) is
920+
// _applicable_, but not _compatible_.
921+
if (!hasConversion(delegateType.TypeKind, Conversions, delegateParameter.Type, methodParameter.Type, delegateParameter.RefKind, methodParameter.RefKind, ref useSiteDiagnostics))
901922
{
902923
// No overload for '{0}' matches delegate '{1}'
903-
Error(diagnostics, ErrorCode.ERR_MethDelegateMismatch, errorLocation, method, delegateType);
924+
Error(diagnostics, getMethodMismatchErrorCode(delegateType.TypeKind), errorLocation, method, delegateType);
904925
diagnostics.Add(errorLocation, useSiteDiagnostics);
905926
return false;
906927
}
907928
}
908929

909-
if (delegateMethod.RefKind != method.RefKind)
930+
if (delegateOrFuncPtrMethod.RefKind != method.RefKind)
910931
{
911-
Error(diagnostics, ErrorCode.ERR_DelegateRefMismatch, errorLocation, method, delegateType);
932+
Error(diagnostics, getRefMismatchErrorCode(delegateType.TypeKind), errorLocation, method, delegateType);
912933
diagnostics.Add(errorLocation, useSiteDiagnostics);
913934
return false;
914935
}
915936

916937
var methodReturnType = method.ReturnType;
917-
var delegateReturnType = delegateMethod.ReturnType;
918-
bool returnsMatch = delegateMethod.RefKind != RefKind.None ?
919-
// - Return types identity-convertible
920-
Conversions.HasIdentityConversion(methodReturnType, delegateReturnType) :
921-
// - Return types "match"
922-
method.ReturnsVoid && delegateMethod.ReturnsVoid ||
923-
Conversions.HasIdentityOrImplicitReferenceConversion(methodReturnType, delegateReturnType, ref useSiteDiagnostics);
938+
var delegateReturnType = delegateOrFuncPtrMethod.ReturnType;
939+
bool returnsMatch = delegateOrFuncPtrMethod switch
940+
{
941+
{ RefKind: RefKind.None, ReturnsVoid: true } => method.ReturnsVoid,
942+
{ RefKind: var destinationRefKind } => hasConversion(delegateType.TypeKind, Conversions, methodReturnType, delegateReturnType, method.RefKind, destinationRefKind, ref useSiteDiagnostics),
943+
};
924944

925945
if (!returnsMatch)
926946
{
@@ -929,8 +949,68 @@ internal bool MethodGroupIsCompatibleWithDelegate(BoundExpression? receiverOpt,
929949
return false;
930950
}
931951

952+
if (delegateType.IsFunctionPointer())
953+
{
954+
if (isExtensionMethod)
955+
{
956+
Error(diagnostics, ErrorCode.ERR_CannotUseReducedExtensionMethodInAddressOf, errorLocation);
957+
diagnostics.Add(errorLocation, useSiteDiagnostics);
958+
return false;
959+
}
960+
961+
if (!method.IsStatic)
962+
{
963+
// This check is here purely for completeness of implementing the spec. It should
964+
// never be hit, as static methods should be eliminated as candidates in overload
965+
// resolution and should never make it to this point.
966+
Debug.Fail("This method should have been eliminated in overload resolution!");
967+
Error(diagnostics, ErrorCode.ERR_FuncPtrMethMustBeStatic, errorLocation, method);
968+
diagnostics.Add(errorLocation, useSiteDiagnostics);
969+
return false;
970+
}
971+
}
972+
932973
diagnostics.Add(errorLocation, useSiteDiagnostics);
933974
return true;
975+
976+
static bool hasConversion(TypeKind targetKind, Conversions conversions, TypeSymbol source, TypeSymbol destination,
977+
RefKind sourceRefKind, RefKind destinationRefKind, ref HashSet<DiagnosticInfo>? useSiteDiagnostics)
978+
{
979+
if (sourceRefKind != destinationRefKind)
980+
{
981+
return false;
982+
}
983+
984+
if (sourceRefKind != RefKind.None)
985+
{
986+
return ConversionsBase.HasIdentityConversion(source, destination);
987+
}
988+
989+
if (conversions.HasIdentityOrImplicitReferenceConversion(source, destination, ref useSiteDiagnostics))
990+
{
991+
return true;
992+
}
993+
994+
return targetKind == TypeKind.FunctionPointer
995+
&& (ConversionsBase.HasImplicitPointerToVoidConversion(source, destination)
996+
|| conversions.HasImplicitPointerConversion(source, destination, ref useSiteDiagnostics));
997+
}
998+
999+
static ErrorCode getMethodMismatchErrorCode(TypeKind type)
1000+
=> type switch
1001+
{
1002+
TypeKind.Delegate => ErrorCode.ERR_MethDelegateMismatch,
1003+
TypeKind.FunctionPointer => ErrorCode.ERR_MethFuncPtrMismatch,
1004+
_ => throw ExceptionUtilities.UnexpectedValue(type)
1005+
};
1006+
1007+
static ErrorCode getRefMismatchErrorCode(TypeKind type)
1008+
=> type switch
1009+
{
1010+
TypeKind.Delegate => ErrorCode.ERR_DelegateRefMismatch,
1011+
TypeKind.FunctionPointer => ErrorCode.ERR_FuncPtrRefMismatch,
1012+
_ => throw ExceptionUtilities.UnexpectedValue(type)
1013+
};
9341014
}
9351015

9361016
/// <summary>
@@ -940,23 +1020,23 @@ internal bool MethodGroupIsCompatibleWithDelegate(BoundExpression? receiverOpt,
9401020
/// <param name="conversion">Conversion to be performed.</param>
9411021
/// <param name="receiverOpt">Optional receiver.</param>
9421022
/// <param name="isExtensionMethod">Method invoked as extension method.</param>
943-
/// <param name="delegateType">Target delegate type.</param>
1023+
/// <param name="delegateOrFuncPtrType">Target delegate type.</param>
9441024
/// <param name="diagnostics">Where diagnostics should be added.</param>
9451025
/// <returns>True if a diagnostic has been added.</returns>
9461026
private bool MethodGroupConversionHasErrors(
9471027
SyntaxNode syntax,
9481028
Conversion conversion,
9491029
BoundExpression? receiverOpt,
9501030
bool isExtensionMethod,
951-
NamedTypeSymbol delegateType,
1031+
TypeSymbol delegateOrFuncPtrType,
9521032
DiagnosticBag diagnostics)
9531033
{
954-
Debug.Assert(delegateType.TypeKind == TypeKind.Delegate);
1034+
Debug.Assert(delegateOrFuncPtrType.TypeKind == TypeKind.Delegate || delegateOrFuncPtrType.TypeKind == TypeKind.FunctionPointer);
9551035

9561036
Debug.Assert(conversion.Method is object);
9571037
MethodSymbol selectedMethod = conversion.Method;
9581038

959-
if (!MethodGroupIsCompatibleWithDelegate(receiverOpt, isExtensionMethod, selectedMethod, delegateType, syntax.Location, diagnostics) ||
1039+
if (!MethodIsCompatibleWithDelegateOrFunctionPointer(receiverOpt, isExtensionMethod, selectedMethod, delegateOrFuncPtrType, syntax.Location, diagnostics) ||
9601040
MemberGroupFinalValidation(receiverOpt, selectedMethod, syntax, diagnostics, isExtensionMethod))
9611041
{
9621042
return true;
@@ -1008,11 +1088,11 @@ private bool MethodGroupConversionDoesNotExistOrHasErrors(
10081088
}
10091089

10101090
HashSet<DiagnosticInfo>? useSiteDiagnostics = null;
1011-
conversion = Conversions.GetMethodGroupConversion(boundMethodGroup, delegateType, ref useSiteDiagnostics);
1091+
conversion = Conversions.GetMethodGroupDelegateConversion(boundMethodGroup, delegateType, ref useSiteDiagnostics);
10121092
diagnostics.Add(delegateMismatchLocation, useSiteDiagnostics);
10131093
if (!conversion.Exists)
10141094
{
1015-
if (!Conversions.ReportDelegateMethodGroupDiagnostics(this, boundMethodGroup, delegateType, diagnostics))
1095+
if (!Conversions.ReportDelegateOrFunctionPointerMethodGroupDiagnostics(this, boundMethodGroup, delegateType, diagnostics))
10161096
{
10171097
// No overload for '{0}' matches delegate '{1}'
10181098
diagnostics.Add(ErrorCode.ERR_MethDelegateMismatch, delegateMismatchLocation, boundMethodGroup.Name, delegateType);

src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,22 @@ private static bool ContainsNestedTypeOfUnconstructedGenericType(TypeSymbol type
524524
return ContainsNestedTypeOfUnconstructedGenericType(((ArrayTypeSymbol)type).ElementType);
525525
case TypeKind.Pointer:
526526
return ContainsNestedTypeOfUnconstructedGenericType(((PointerTypeSymbol)type).PointedAtType);
527+
case TypeKind.FunctionPointer:
528+
MethodSymbol signature = ((FunctionPointerTypeSymbol)type).Signature;
529+
if (ContainsNestedTypeOfUnconstructedGenericType(signature.ReturnType))
530+
{
531+
return true;
532+
}
533+
534+
foreach (var param in signature.Parameters)
535+
{
536+
if (ContainsNestedTypeOfUnconstructedGenericType(param.Type))
537+
{
538+
return true;
539+
}
540+
}
541+
542+
return false;
527543
case TypeKind.Delegate:
528544
case TypeKind.Class:
529545
case TypeKind.Interface:

0 commit comments

Comments
 (0)