@@ -97,6 +97,11 @@ protected BoundExpression CreateConversion(
9797 return CreateAnonymousFunctionConversion ( syntax , source , conversion , isCast : isCast , conversionGroupOpt , destination , diagnostics ) ;
9898 }
9999
100+ if ( conversion . Kind == ConversionKind . FunctionType )
101+ {
102+ return CreateFunctionTypeConversion ( syntax , source , conversion , isCast : isCast , conversionGroupOpt , destination , diagnostics ) ;
103+ }
104+
100105 if ( conversion . IsStackAlloc )
101106 {
102107 return CreateStackAllocConversion ( syntax , source , conversion , isCast , conversionGroupOpt , destination , diagnostics ) ;
@@ -546,69 +551,68 @@ private BoundExpression CreateUserDefinedConversion(
546551 return finalConversion ;
547552 }
548553
549- private BoundExpression CreateAnonymousFunctionConversion ( SyntaxNode syntax , BoundExpression source , Conversion conversion , bool isCast , ConversionGroup ? conversionGroup , TypeSymbol destination , BindingDiagnosticBag diagnostics )
554+ private BoundExpression CreateFunctionTypeConversion ( SyntaxNode syntax , BoundExpression source , Conversion conversion , bool isCast , ConversionGroup ? conversionGroup , TypeSymbol destination , BindingDiagnosticBag diagnostics )
550555 {
551- // We have a successful anonymous function conversion; rather than producing a node
552- // which is a conversion on top of an unbound lambda, replace it with the bound
553- // lambda.
556+ Debug . Assert ( conversion . Kind == ConversionKind . FunctionType ) ;
557+ Debug . Assert ( source . Kind is BoundKind . MethodGroup or BoundKind . UnboundLambda ) ;
558+ Debug . Assert ( syntax . IsFeatureEnabled ( MessageID . IDS_FeatureInferredDelegateType ) ) ;
554559
555- // UNDONE: Figure out what to do about the error case, where a lambda
556- // UNDONE: is converted to a delegate that does not match. What to surface then?
560+ CompoundUseSiteInfo < AssemblySymbol > useSiteInfo = GetNewCompoundUseSiteInfo ( diagnostics ) ;
561+ var delegateType = source . GetInferredDelegateType ( ref useSiteInfo ) ;
562+ Debug . Assert ( delegateType is { } ) ;
557563
558- var unboundLambda = ( UnboundLambda ) source ;
559- if ( ( destination . SpecialType == SpecialType . System_Delegate || destination . IsNonGenericExpressionType ( ) ) &&
560- syntax . IsFeatureEnabled ( MessageID . IDS_FeatureInferredDelegateType ) )
564+ if ( source . Kind == BoundKind . UnboundLambda &&
565+ destination . IsNonGenericExpressionType ( ) )
561566 {
562- CompoundUseSiteInfo < AssemblySymbol > useSiteInfo = GetNewCompoundUseSiteInfo ( diagnostics ) ;
563- var delegateType = unboundLambda . InferDelegateType ( ref useSiteInfo ) ;
564- BoundLambda boundLambda ;
565- if ( delegateType is { } )
566- {
567- bool isExpressionTree = destination . IsNonGenericExpressionType ( ) ;
568- if ( isExpressionTree )
569- {
570- delegateType = Compilation . GetWellKnownType ( WellKnownType . System_Linq_Expressions_Expression_T ) . Construct ( delegateType ) ;
571- delegateType . AddUseSiteInfo ( ref useSiteInfo ) ;
572- }
573- boundLambda = unboundLambda . Bind ( delegateType , isExpressionTree ) ;
574- }
575- else
576- {
577- diagnostics . Add ( ErrorCode . ERR_CannotInferDelegateType , syntax . GetLocation ( ) ) ;
578- delegateType = CreateErrorType ( ) ;
579- boundLambda = unboundLambda . BindForErrorRecovery ( ) ;
580- }
581- diagnostics . AddRange ( boundLambda . Diagnostics ) ;
582- var expr = createAnonymousFunctionConversion ( syntax , source , boundLambda , conversion , isCast , conversionGroup , delegateType ) ;
583- conversion = Conversions . ClassifyConversionFromExpression ( expr , destination , ref useSiteInfo ) ;
584- diagnostics . Add ( syntax , useSiteInfo ) ;
585- return CreateConversion ( syntax , expr , conversion , isCast , conversionGroup , destination , diagnostics ) ;
567+ delegateType = Compilation . GetWellKnownType ( WellKnownType . System_Linq_Expressions_Expression_T ) . Construct ( delegateType ) ;
568+ delegateType . AddUseSiteInfo ( ref useSiteInfo ) ;
569+ }
570+
571+ conversion = Conversions . ClassifyConversionFromExpression ( source , delegateType , ref useSiteInfo ) ;
572+ BoundExpression expr ;
573+ if ( ! conversion . Exists )
574+ {
575+ GenerateImplicitConversionError ( diagnostics , syntax , conversion , source , delegateType ) ;
576+ expr = new BoundConversion ( syntax , source , conversion , @checked : false , explicitCastInCode : isCast , conversionGroup , constantValueOpt : ConstantValue . NotAvailable , type : delegateType , hasErrors : true ) { WasCompilerGenerated = source . WasCompilerGenerated } ;
586577 }
587578 else
588579 {
589- #if DEBUG
590- // Test inferring a delegate type for all callers.
591- var discardedUseSiteInfo = CompoundUseSiteInfo < AssemblySymbol > . Discarded ;
592- _ = unboundLambda . InferDelegateType ( ref discardedUseSiteInfo ) ;
593- #endif
594- var boundLambda = unboundLambda . Bind ( ( NamedTypeSymbol ) destination , isExpressionTree : destination . IsGenericOrNonGenericExpressionType ( out _ ) ) ;
595- diagnostics . AddRange ( boundLambda . Diagnostics ) ;
596- return createAnonymousFunctionConversion ( syntax , source , boundLambda , conversion , isCast , conversionGroup , destination ) ;
580+ expr = CreateConversion ( syntax , source , conversion , isCast , conversionGroup , delegateType , diagnostics ) ;
597581 }
598582
599- static BoundConversion createAnonymousFunctionConversion ( SyntaxNode syntax , BoundExpression source , BoundLambda boundLambda , Conversion conversion , bool isCast , ConversionGroup ? conversionGroup , TypeSymbol destination )
583+ conversion = Conversions . ClassifyConversionFromExpression ( expr , destination , ref useSiteInfo ) ;
584+ if ( ! conversion . Exists )
600585 {
601- return new BoundConversion (
602- syntax ,
603- boundLambda ,
604- conversion ,
605- @checked : false ,
606- explicitCastInCode : isCast ,
607- conversionGroup ,
608- constantValueOpt : ConstantValue . NotAvailable ,
609- type : destination )
610- { WasCompilerGenerated = source . WasCompilerGenerated } ;
586+ GenerateImplicitConversionError ( diagnostics , syntax , conversion , source , destination ) ;
611587 }
588+
589+ diagnostics . Add ( syntax , useSiteInfo ) ;
590+ return CreateConversion ( syntax , expr , conversion , isCast , conversionGroup , destination , diagnostics ) ;
591+ }
592+
593+ private BoundExpression CreateAnonymousFunctionConversion ( SyntaxNode syntax , BoundExpression source , Conversion conversion , bool isCast , ConversionGroup ? conversionGroup , TypeSymbol destination , BindingDiagnosticBag diagnostics )
594+ {
595+ // We have a successful anonymous function conversion; rather than producing a node
596+ // which is a conversion on top of an unbound lambda, replace it with the bound
597+ // lambda.
598+
599+ // UNDONE: Figure out what to do about the error case, where a lambda
600+ // UNDONE: is converted to a delegate that does not match. What to surface then?
601+
602+ var unboundLambda = ( UnboundLambda ) source ;
603+
604+ var boundLambda = unboundLambda . Bind ( ( NamedTypeSymbol ) destination , isExpressionTree : destination . IsGenericOrNonGenericExpressionType ( out _ ) ) ;
605+ diagnostics . AddRange ( boundLambda . Diagnostics ) ;
606+ return new BoundConversion (
607+ syntax ,
608+ boundLambda ,
609+ conversion ,
610+ @checked : false ,
611+ explicitCastInCode : isCast ,
612+ conversionGroup ,
613+ constantValueOpt : ConstantValue . NotAvailable ,
614+ type : destination )
615+ { WasCompilerGenerated = source . WasCompilerGenerated } ;
612616 }
613617
614618 private BoundExpression CreateMethodGroupConversion ( SyntaxNode syntax , BoundExpression source , Conversion conversion , bool isCast , ConversionGroup ? conversionGroup , TypeSymbol destination , BindingDiagnosticBag diagnostics )
@@ -627,29 +631,7 @@ private BoundExpression CreateMethodGroupConversion(SyntaxNode syntax, BoundExpr
627631 hasErrors = true ;
628632 }
629633
630- if ( destination . SpecialType == SpecialType . System_Delegate &&
631- syntax . IsFeatureEnabled ( MessageID . IDS_FeatureInferredDelegateType ) )
632- {
633- // https://github.com/dotnet/roslyn/issues/52869: Avoid calculating the delegate type multiple times during conversion.
634- CompoundUseSiteInfo < AssemblySymbol > useSiteInfo = GetNewCompoundUseSiteInfo ( diagnostics ) ;
635- var delegateType = GetMethodGroupDelegateType ( group , ref useSiteInfo ) ;
636- var expr = createMethodGroupConversion ( syntax , group , conversion , isCast , conversionGroup , delegateType ! , hasErrors ) ;
637- conversion = Conversions . ClassifyConversionFromExpression ( expr , destination , ref useSiteInfo ) ;
638- diagnostics . Add ( syntax , useSiteInfo ) ;
639- return CreateConversion ( syntax , expr , conversion , isCast , conversionGroup , destination , diagnostics ) ;
640- }
641-
642- #if DEBUG
643- // Test inferring a delegate type for all callers.
644- var discardedUseSiteInfo = CompoundUseSiteInfo < AssemblySymbol > . Discarded ;
645- _ = GetMethodGroupDelegateType ( group , ref discardedUseSiteInfo ) ;
646- #endif
647- return createMethodGroupConversion ( syntax , group , conversion , isCast , conversionGroup , destination , hasErrors ) ;
648-
649- static BoundConversion createMethodGroupConversion ( SyntaxNode syntax , BoundMethodGroup group , Conversion conversion , bool isCast , ConversionGroup ? conversionGroup , TypeSymbol destination , bool hasErrors )
650- {
651- return new BoundConversion ( syntax , group , conversion , @checked : false , explicitCastInCode : isCast , conversionGroup , constantValueOpt : ConstantValue . NotAvailable , type : destination , hasErrors : hasErrors ) { WasCompilerGenerated = group . WasCompilerGenerated } ;
652- }
634+ return new BoundConversion ( syntax , group , conversion , @checked : false , explicitCastInCode : isCast , conversionGroup , constantValueOpt : ConstantValue . NotAvailable , type : destination , hasErrors : hasErrors ) { WasCompilerGenerated = group . WasCompilerGenerated } ;
653635 }
654636
655637 private BoundExpression CreateStackAllocConversion ( SyntaxNode syntax , BoundExpression source , Conversion conversion , bool isCast , ConversionGroup ? conversionGroup , TypeSymbol destination , BindingDiagnosticBag diagnostics )
@@ -814,6 +796,7 @@ private BoundMethodGroup FixMethodGroupWithTypeOrValue(BoundMethodGroup group, C
814796 group . LookupSymbolOpt ,
815797 group . LookupError ,
816798 group . Flags ,
799+ group . FunctionType ,
817800 receiverOpt , //only change
818801 group . ResultKind ) ;
819802 }
@@ -1226,13 +1209,13 @@ private bool MethodGroupConversionHasErrors(
12261209 TypeSymbol delegateOrFuncPtrType ,
12271210 BindingDiagnosticBag diagnostics )
12281211 {
1229- Debug . Assert ( delegateOrFuncPtrType . SpecialType == SpecialType . System_Delegate || delegateOrFuncPtrType . TypeKind == TypeKind . Delegate || delegateOrFuncPtrType . TypeKind == TypeKind . FunctionPointer ) ;
1230-
1212+ var discardedUseSiteInfo = CompoundUseSiteInfo < AssemblySymbol > . Discarded ;
1213+ Debug . Assert ( Conversions . IsAssignableFromMulticastDelegate ( delegateOrFuncPtrType , ref discardedUseSiteInfo ) || delegateOrFuncPtrType . TypeKind == TypeKind . Delegate || delegateOrFuncPtrType . TypeKind == TypeKind . FunctionPointer ) ;
12311214 Debug . Assert ( conversion . Method is object ) ;
12321215 MethodSymbol selectedMethod = conversion . Method ;
12331216
12341217 var location = syntax . Location ;
1235- if ( delegateOrFuncPtrType . SpecialType != SpecialType . System_Delegate )
1218+ if ( ! Conversions . IsAssignableFromMulticastDelegate ( delegateOrFuncPtrType , ref discardedUseSiteInfo ) )
12361219 {
12371220 if ( ! MethodIsCompatibleWithDelegateOrFunctionPointer ( receiverOpt , isExtensionMethod , selectedMethod , delegateOrFuncPtrType , location , diagnostics ) ||
12381221 MemberGroupFinalValidation ( receiverOpt , selectedMethod , syntax , diagnostics , isExtensionMethod ) )
0 commit comments