Do not report MA0148/MA0149 when the constant does not convert to the operand type - #1470
Merged
Merged
Conversation
… operand type The equality operator may implicitly convert the operand (numeric promotion, nullable lifting, user-defined conversions), while the pattern is matched against the type of the operand itself. For instance, 'intValue == 1L' is valid but 'intValue is 1L' fails with CS0266. The analyzer and the code fixer (single and merged comparisons) now only rewrite the comparison when the constant is implicitly convertible to the type of the operand, without user-defined conversion. This replaces the previous check that only excluded implicit user-defined conversions.
meziantou
commented
Sep 12, 2026
… model
The type of the operand can be read from the operation tree. The semantic
model is still needed to classify the conversion of the constant, as it
depends on its value ('byteValue == 1' is valid, 'byteValue == 300' is not).
meziantou
deleted the
feature/ma0148-numeric-promotion-pattern-209ec7
branch
September 12, 2026 03:35
This was referenced Sep 12, 2026
This was referenced Sep 17, 2026
Merged
Open
Open
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
MA0148/MA0149 rewrite
value == 1L(withint value) intovalue is 1L, which fails with CS0266. The binary equality operator promotes theintoperand tolong, but the fixer copies the operand syntax into anisexpression, dropping the implicit conversion. Constant patterns are matched against the operand's own type, so thelongconstant is not valid there.The existing guard only excluded implicit user-defined conversions, not built-in numeric promotion.
Fix
When the comparison implicitly converts the operand, the analyzer and the fixer now check that the constant is implicitly convertible (without user-defined conversion) to the type of the operand as written in source (or its underlying type when nullable). If not, the comparison is not reported nor rewritten. This check replaces
HasImplicitUserDefinedConversion, which it covers.byteValue == 1→byteValue is 1(same forshort,ushort,byte?)intvs1L/1.0/1m,int?vs1L,floatvs0.1,bytevs300,charvs65value == 1 || value == 2L→value is 1 || value == 2LThe fixer shares the check for both single comparisons and merged
||/&&candidates, so a fix triggered on a valid term can no longer merge an invalid one.Note for reviewers
The operand type is taken from
SemanticModel.GetTypeInfo(operandSyntax).Typerather than by unwrapping the conversion operations: Roslyn 4.8 represents(DayOfWeek?)1as a chain of implicit conversions down to theintliteral, so unwrapping overshoots and broke the existingEqualityComparison_NullableEnumtest on that version.Tests
UsePatternMatchingForEqualityComparisonsAnalyzerTestsfor non-convertible constants, convertible promoted operands, and mixed/merged comparisons (verified that 9 of the new cases fail without the fix).docs/Rules/MA0148.mdanddocs/Rules/MA0149.mddocument the new exclusion;DocumentationGeneratorreports no further changes.