@@ -178,7 +178,7 @@ public TypeConversionKind AnalyzeConversion(VBSyntax.ExpressionSyntax vbNode, bo
178178 var csConvertedType = GetCSType ( vbConvertedType ) ;
179179
180180 if ( csType != null && csConvertedType != null &&
181- TryAnalyzeCsConversion ( vbNode , csType , csConvertedType , vbConversion , vbConvertedType , vbType , isConst , forceSourceType != null , out TypeConversionKind analyzeConversion ) ) {
181+ TryAnalyzeCsConversion ( vbCompilation , vbNode , csType , csConvertedType , vbConversion , vbConvertedType , vbType , isConst , forceSourceType != null , out TypeConversionKind analyzeConversion ) ) {
182182 return analyzeConversion ;
183183 }
184184
@@ -273,20 +273,28 @@ private ITypeSymbol GetCSType(ITypeSymbol vbType, VBSyntax.ExpressionSyntax vbNo
273273 return csType ;
274274 }
275275
276- private bool TryAnalyzeCsConversion ( VBSyntax . ExpressionSyntax vbNode , ITypeSymbol csType ,
276+ private bool TryAnalyzeCsConversion ( VBasic . VisualBasicCompilation vbCompilation , VBSyntax . ExpressionSyntax vbNode , ITypeSymbol csType ,
277277 ITypeSymbol csConvertedType , Conversion vbConversion , ITypeSymbol vbConvertedType , ITypeSymbol vbType , bool isConst , bool sourceForced ,
278278 out TypeConversionKind typeConversionKind )
279279 {
280280 var csConversion = _csCompilation . ClassifyConversion ( csType , csConvertedType ) ;
281- vbType . IsNullable ( out var underlyingType ) ;
282- vbConvertedType . IsNullable ( out var underlyingConvertedType ) ;
283- var nullableVbType = underlyingType ?? vbType ;
284- var nullableVbConvertedType = underlyingConvertedType ?? vbConvertedType ;
281+
282+ vbType . IsNullable ( out var underlyingVbType ) ;
283+ vbConvertedType . IsNullable ( out var underlyingVbConvertedType ) ;
284+ underlyingVbType ??= vbType ;
285+ underlyingVbConvertedType ??= vbConvertedType ;
286+ var vbUnderlyingConversion = vbCompilation . ClassifyConversion ( underlyingVbType , underlyingVbConvertedType ) ;
287+
288+ csType . IsNullable ( out var underlyingCsType ) ;
289+ csConvertedType . IsNullable ( out var underlyingCsConvertedType ) ;
290+ underlyingCsType ??= csType ;
291+ underlyingCsConvertedType ??= csConvertedType ;
292+ var csUnderlyingConversion = _csCompilation . ClassifyConversion ( underlyingCsType , underlyingCsConvertedType ) ;
285293
286294 bool isConvertToString =
287295 ( vbConversion . IsString || vbConversion . IsReference && vbConversion . IsNarrowing ) && vbConvertedType . SpecialType == SpecialType . System_String ;
288296 bool isConvertFractionalToInt =
289- ! csConversion . IsImplicit && nullableVbType . IsFractionalNumericType ( ) && nullableVbConvertedType . IsIntegralOrEnumType ( ) ;
297+ ! csConversion . IsImplicit && underlyingVbType . IsFractionalNumericType ( ) && underlyingVbConvertedType . IsIntegralOrEnumType ( ) ;
290298
291299 if ( ! csConversion . Exists || csConversion . IsUnboxing ) {
292300 if ( ConvertStringToCharLiteral ( vbNode , vbConvertedType , out _ ) ) {
@@ -300,21 +308,21 @@ private bool TryAnalyzeCsConversion(VBSyntax.ExpressionSyntax vbNode, ITypeSymbo
300308 return true ;
301309 }
302310 if ( isConvertToString || vbConversion . IsNarrowing ) {
303- typeConversionKind = nullableVbConvertedType . IsEnumType ( ) && ! csConversion . Exists
311+ typeConversionKind = underlyingVbConvertedType . IsEnumType ( ) && ! csConversion . Exists
304312 ? TypeConversionKind . EnumConversionThenCast
305313 : TypeConversionKind . Conversion ;
306314 return true ;
307315 }
308316 } else if ( vbConversion . IsNarrowing && vbConversion . IsNullableValueType && isConvertFractionalToInt ) {
309317 typeConversionKind = TypeConversionKind . FractionalNumberRoundThenCast ;
310318 return true ;
311- } else if ( vbConversion . IsNumeric && ( csConversion . IsNumeric || nullableVbConvertedType . IsEnumType ( ) ) && isConvertFractionalToInt ) {
319+ } else if ( vbConversion . IsNumeric && ( csConversion . IsNumeric || underlyingVbConvertedType . IsEnumType ( ) ) && isConvertFractionalToInt ) {
312320 typeConversionKind = TypeConversionKind . FractionalNumberRoundThenCast ;
313321 return true ;
314322 } else if ( csConversion is { IsExplicit : true , IsEnumeration : true } or { IsBoxing : true , IsImplicit : false } ) {
315323 typeConversionKind = TypeConversionKind . NonDestructiveCast ;
316324 return true ;
317- } else if ( vbConversion . IsNumeric && csConversion . IsNumeric ) {
325+ } else if ( vbUnderlyingConversion . IsNumeric && csUnderlyingConversion . IsNumeric ) {
318326 // For widening, implicit, a cast is really only needed to help resolve the overload for the operator/method used.
319327 // e.g. When VB "&" changes to C# "+", there are lots more overloads available that implicit casts could match.
320328 // e.g. sbyte * ulong uses the decimal * operator in VB. In C# it's ambiguous - see ExpressionTests.vb "TestMul".
0 commit comments