@@ -178,7 +178,7 @@ public TypeConversionKind AnalyzeConversion(VBSyntax.ExpressionSyntax vbNode, bo
178
178
var csConvertedType = GetCSType ( vbConvertedType ) ;
179
179
180
180
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 ) ) {
182
182
return analyzeConversion ;
183
183
}
184
184
@@ -273,20 +273,28 @@ private ITypeSymbol GetCSType(ITypeSymbol vbType, VBSyntax.ExpressionSyntax vbNo
273
273
return csType ;
274
274
}
275
275
276
- private bool TryAnalyzeCsConversion ( VBSyntax . ExpressionSyntax vbNode , ITypeSymbol csType ,
276
+ private bool TryAnalyzeCsConversion ( VBasic . VisualBasicCompilation vbCompilation , VBSyntax . ExpressionSyntax vbNode , ITypeSymbol csType ,
277
277
ITypeSymbol csConvertedType , Conversion vbConversion , ITypeSymbol vbConvertedType , ITypeSymbol vbType , bool isConst , bool sourceForced ,
278
278
out TypeConversionKind typeConversionKind )
279
279
{
280
280
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 ) ;
285
293
286
294
bool isConvertToString =
287
295
( vbConversion . IsString || vbConversion . IsReference && vbConversion . IsNarrowing ) && vbConvertedType . SpecialType == SpecialType . System_String ;
288
296
bool isConvertFractionalToInt =
289
- ! csConversion . IsImplicit && nullableVbType . IsFractionalNumericType ( ) && nullableVbConvertedType . IsIntegralOrEnumType ( ) ;
297
+ ! csConversion . IsImplicit && underlyingVbType . IsFractionalNumericType ( ) && underlyingVbConvertedType . IsIntegralOrEnumType ( ) ;
290
298
291
299
if ( ! csConversion . Exists || csConversion . IsUnboxing ) {
292
300
if ( ConvertStringToCharLiteral ( vbNode , vbConvertedType , out _ ) ) {
@@ -300,27 +308,27 @@ private bool TryAnalyzeCsConversion(VBSyntax.ExpressionSyntax vbNode, ITypeSymbo
300
308
return true ;
301
309
}
302
310
if ( isConvertToString || vbConversion . IsNarrowing ) {
303
- typeConversionKind = nullableVbConvertedType . IsEnumType ( ) && ! csConversion . Exists
311
+ typeConversionKind = underlyingVbConvertedType . IsEnumType ( ) && ! csConversion . Exists
304
312
? TypeConversionKind . EnumConversionThenCast
305
313
: TypeConversionKind . Conversion ;
306
314
return true ;
307
315
}
308
316
} else if ( vbConversion . IsNarrowing && vbConversion . IsNullableValueType && isConvertFractionalToInt ) {
309
317
typeConversionKind = TypeConversionKind . FractionalNumberRoundThenCast ;
310
318
return true ;
311
- } else if ( vbConversion . IsNumeric && ( csConversion . IsNumeric || nullableVbConvertedType . IsEnumType ( ) ) && isConvertFractionalToInt ) {
319
+ } else if ( vbConversion . IsNumeric && ( csConversion . IsNumeric || underlyingVbConvertedType . IsEnumType ( ) ) && isConvertFractionalToInt ) {
312
320
typeConversionKind = TypeConversionKind . FractionalNumberRoundThenCast ;
313
321
return true ;
314
322
} else if ( csConversion is { IsExplicit : true , IsEnumeration : true } or { IsBoxing : true , IsImplicit : false } ) {
315
323
typeConversionKind = TypeConversionKind . NonDestructiveCast ;
316
324
return true ;
317
- } else if ( vbConversion . IsNumeric && csConversion . IsNumeric ) {
325
+ } else if ( vbUnderlyingConversion . IsNumeric && csUnderlyingConversion . IsNumeric ) {
318
326
// For widening, implicit, a cast is really only needed to help resolve the overload for the operator/method used.
319
327
// e.g. When VB "&" changes to C# "+", there are lots more overloads available that implicit casts could match.
320
328
// e.g. sbyte * ulong uses the decimal * operator in VB. In C# it's ambiguous - see ExpressionTests.vb "TestMul".
321
329
typeConversionKind =
322
- isConst && IsImplicitConstantConversion ( vbNode ) || csConversion . IsIdentity || ! sourceForced && IsExactTypeNumericLiteral ( vbNode , vbConvertedType ) ? TypeConversionKind . Identity :
323
- csConversion . IsImplicit || vbType . IsNumericType ( ) ? TypeConversionKind . NonDestructiveCast
330
+ isConst && IsImplicitConstantConversion ( vbNode ) || csUnderlyingConversion . IsIdentity || ! sourceForced && IsExactTypeNumericLiteral ( vbNode , underlyingVbConvertedType ) ? TypeConversionKind . Identity :
331
+ csUnderlyingConversion . IsImplicit || underlyingVbType . IsNumericType ( ) ? TypeConversionKind . NonDestructiveCast
324
332
: TypeConversionKind . Conversion ;
325
333
return true ;
326
334
} else if ( isConvertToString && vbType . SpecialType == SpecialType . System_Object ) {
0 commit comments