@@ -3900,38 +3900,93 @@ protected internal override TranslatedExpression VisitIfInstruction(IfInstructio
39003900 }
39013901 }
39023902
3903- internal ( TranslatedExpression , IType , StringToInt ) TranslateSwitchValue ( SwitchInstruction inst , bool allowImplicitConversion )
3903+ internal ( TranslatedExpression , IType , StringToInt ) TranslateSwitchValue ( SwitchInstruction inst , bool isExpressionContext )
39043904 {
39053905 TranslatedExpression value ;
39063906 IType type ;
3907+ // prepare expression and expected type
39073908 if ( inst . Value is StringToInt strToInt )
39083909 {
3909- value = Translate ( strToInt . Argument )
3910- . ConvertTo (
3911- strToInt . ExpectedType ,
3912- this ,
3913- allowImplicitConversion : allowImplicitConversion
3914- ) ;
3915- type = compilation . FindType ( KnownTypeCode . String ) ;
3910+ value = Translate ( strToInt . Argument ) ;
3911+ type = strToInt . ExpectedType ?? compilation . FindType ( KnownTypeCode . String ) ;
39163912 }
39173913 else
39183914 {
39193915 strToInt = null ;
39203916 value = Translate ( inst . Value ) ;
3921- type = value . Type ;
3922- if ( inst . Type != null )
3917+ type = inst . Type ?? value . Type ;
3918+ }
3919+
3920+ // find and unwrap the input type
3921+ IType inputType = value . Type ;
3922+ if ( value . Expression is CastExpression && value . ResolveResult is ConversionResolveResult crr )
3923+ {
3924+ inputType = crr . Input . Type ;
3925+ }
3926+ inputType = NullableType . GetUnderlyingType ( inputType ) . GetEnumUnderlyingType ( ) ;
3927+
3928+ // check input/underlying type for compatibility
3929+ bool allowImplicitConversion ;
3930+ if ( IsCompatibleWithSwitch ( inputType ) || ( strToInt != null && inputType . Equals ( type ) ) )
3931+ {
3932+ allowImplicitConversion = ! isExpressionContext ;
3933+ }
3934+ else
3935+ {
3936+ var applicableImplicitConversionOperators = inputType . GetMethods ( IsCompatibleImplicitConversionOperator ) . ToArray ( ) ;
3937+ switch ( applicableImplicitConversionOperators . Length )
39233938 {
3924- value = value . ConvertTo ( inst . Type , this , allowImplicitConversion : allowImplicitConversion ) ;
3925- type = inst . Type ;
3939+ case 0 :
3940+ allowImplicitConversion = ! isExpressionContext ;
3941+ break ;
3942+ case 1 :
3943+ allowImplicitConversion = ! isExpressionContext ;
3944+ // TODO validate
3945+ break ;
3946+ default :
3947+ allowImplicitConversion = false ;
3948+ break ;
39263949 }
39273950 }
3928- return ( value , type , strToInt ) ;
3951+
3952+ value = value . ConvertTo ( type , this , allowImplicitConversion : allowImplicitConversion ) ;
3953+
3954+ var caseType = strToInt != null
3955+ ? compilation . FindType ( KnownTypeCode . String )
3956+ : type ;
3957+
3958+ return ( value , caseType , strToInt ) ;
3959+
3960+ static bool IsCompatibleWithSwitch ( IType type )
3961+ {
3962+ return type . IsKnownType ( KnownTypeCode . SByte )
3963+ || type . IsKnownType ( KnownTypeCode . Byte )
3964+ || type . IsKnownType ( KnownTypeCode . Int16 )
3965+ || type . IsKnownType ( KnownTypeCode . UInt16 )
3966+ || type . IsKnownType ( KnownTypeCode . Int32 )
3967+ || type . IsKnownType ( KnownTypeCode . UInt32 )
3968+ || type . IsKnownType ( KnownTypeCode . Int64 )
3969+ || type . IsKnownType ( KnownTypeCode . UInt64 )
3970+ || type . IsKnownType ( KnownTypeCode . Char )
3971+ || type . IsKnownType ( KnownTypeCode . String ) ;
3972+ }
3973+
3974+ bool IsCompatibleImplicitConversionOperator ( IMethod operatorMethod )
3975+ {
3976+ if ( ! operatorMethod . IsOperator )
3977+ return false ;
3978+ if ( operatorMethod . Name != "op_Implicit" )
3979+ return false ;
3980+ if ( operatorMethod . Parameters . Count != 1 )
3981+ return false ;
3982+ return IsCompatibleWithSwitch ( operatorMethod . ReturnType ) ;
3983+ }
39293984 }
39303985
39313986 protected internal override TranslatedExpression VisitSwitchInstruction ( SwitchInstruction inst , TranslationContext context )
39323987 {
39333988 // switch-expression does not support implicit conversions
3934- var ( value , type , strToInt ) = TranslateSwitchValue ( inst , allowImplicitConversion : false ) ;
3989+ var ( value , type , strToInt ) = TranslateSwitchValue ( inst , true ) ;
39353990
39363991 IL . SwitchSection defaultSection = inst . GetDefaultSection ( ) ;
39373992 SwitchExpression switchExpr = new SwitchExpression ( ) ;
0 commit comments