Skip to content

'Remove unnecessary cast' cases we could support in the future. #56938

@CyrusNajmabadi

Description

@CyrusNajmabadi

These are things we used to support, but which became unsupported in the rewrite in #56932

  1. Casting enum to int to perform bitwise negation. Added in 4828941.

  2. Unnecessary nullable cast in a constant pattern. For example: This is actually not a case to remove. These patterns are not legal.

    void Main(int? n)
    {
        var v = n is [|(int?)|]0;
    }

    This is currently broken because GetOperation on the (int?)0 currently returns null. Possibly a compiler bug.

  3. Nullable casts in constant patterns. For example: This is actually not a case to remove. These patterns are not legal.

    int? nullable;
    return nullable is (int?)1 or (int?)2
  4. Widening cast in 'is' expression. Fixed in 065873a.

  5. Comparison of an enum value against constant 0 directly. Added in 7b73cbf.

  6. Widening cast in 'is' expression. Added in 065873a.

  7. Conditional expressions where removing the cast does change the value of of the conditional. But it is not noticeable because of an outer implicit conversion. For example: Fixed in Fix cast simplification issues #57066

    long f1 = (b == 5) ? 4 : [|(long)|]5

    Here, removing the (long) cast makes the condition no return an Int32 value instead of an Int64. However, this code, the Int32 would get widened to an Int64 anyways. So the cast can be removed.

    Similarly:

    int? y = x ? [|(int?)|]1 : 0;

  8. Sign extension prior to a bitwise negation. For example: Fixed in Fix cast simplification issues #57066

    public static long P(long a, int b)
    {
        return a & ~[|(long)|]b;
    }

    Extending the signed value here doesn't need to happen prior to the bitwise negation. THe negation can happen here, and the sign extension that occurs afterwards as part of the binary operation will result in the same value.

  9. Cast to a different (but compatible) delegate type inside a delegate constructor. For example:

    delegate void D(int x);
    
    public static void M1(int i) { }
    
    static void Main(string[] args)
    {
        var cd1 = new D([|(Action<int>)|]M1);
    }

    This cast can be removed safely.

  10. Unnecessary cast in a goto case clause. For example:

    switch (5L)
    {
        case 5:
            goto case [|(long)|]5;
            break;
    }

    This is currently broken because GetOperation on the (long)5 currently returns null. Possibly a compiler bug.

  11. Cast in a foreach from a string/array to IENumerable. For example:

    foreach (var x in (IEnumerable<string>)""abc"")
        Console.WriteLine(x);

    removing this cast will change runtime behavior, but not in an observable fashion.

  12. Comparing a nullable to null, versus casting it to a reference type and comparing to null. For example:

    int? x = null;
    var y = (IComparable)x == null;
  13. Some casts in foreach-statements can be removed. For example:

    static void Main()
    {
        foreach (C x in (IEnumerable<string>) new string[] { null })
        {
            Console.WriteLine(x == null);
        }
    }
    
    public static implicit operator C(string s)
    {
        return new C();
    }

    Removing the cast causes this to have an IEnumerable conversion, not an IEnumerable conversion. But this should be allowed.

  14. Complex lambda cases where the parameter type would change, but it would have no impact on the body code. For example:

    using System;
    
    static class Program
    {
        static void Main()
        {
            new Action<string>((Action<object>)(y => Goo(1)))(null);
        }
    
        static void Goo(this object x) { Console.WriteLine(1); }
        static void Goo(this string x) { Console.WriteLine(2); }
    }

    Removing this cast is fine. While it change the type of 'y' from 'object' to 'string'. However, that has no impact on how the lambda executes (As it does not use 'y').

  15. Chained nullable casts that don't impact the final result. For example:

    Console.WriteLine((int)(float?)(int?)2147483647);

  16. Co/contravariance with delegates. For example:

    static void Main(string[] args)
    {
        static string f(object x) => """";
        M((Func<object, string>)f);
    }
    
    public static void M(Func<string, object> expected) { }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions