Skip to content

Check that switch expressions with a natural type do not cause additional conversions #1739

Closed

Description

@jskeet

See #1651 (comment) for an example

Activity

  1. self-assigned this
    on Jul 22, 2026
  2. added this to the C# 8.0 milestone on Jul 22, 2026
  3. jskeet commented on Jul 22, 2026

    @jskeet
    ContributorAuthor

    (Shouldn't be too hard to check and/or fix, so marked as C# 8 - but if it becomes more fiddly, we may make it "pre-C# 9")

  4. added
    meeting: discussThis issue should be discussed at the next TC49-TG2 meeting
    meeting: proposalThere is an informal proposal in the issue, worth discussing in a meeting
    on Aug 26, 2026
  5. jskeet commented on Aug 26, 2026

    @jskeet
    ContributorAuthor

    Okay, moving the first of Kalle's examples here, and adding a Main method:

    class B { }
    class C1 : B { }
    class C2 : B { }
    
    struct S
    {
        public static implicit operator S(B _) { Console.WriteLine("S(B)"); return default; }
        public static implicit operator S(C1 _) { Console.WriteLine("S(C1)"); return default; }
        public static implicit operator S(C2 _) { Console.WriteLine("S(C2)"); return default; }
    }
    
    class P
    {
        public static S M1(int i)
        {
            // First converts from C1, C2, or B to the switch common type B, then from B to S.
            return i switch { 1 => new C1(), 2 => new C2(), _ => new B() };
        }
    
        public static S M2(int i)
        {
            // Converts C1 or C2 directly to S.
            return i switch { 1 => new C1(), 2 => new C2(), _ => throw new System.ArgumentException() };
        }
    }
    
    class Program
    {
        static void Main()
        {
            P.M1(1);
            P.M1(2);
            P.M1(3);
            P.M2(1);
            P.M2(2);
        }
    }

    Observed behavior (admittedly with .NET 10) is:

    S(B)
    S(B)
    S(B)
    S(C1)
    S(C2)

    In other words, the "natural type" of the switch expression is used in the case of M1 before switch expression conversions.

    I don't think this is currently covered in the spec.

    We may be able to fix it by adding "which does not have a type " to 10.2.18:

    Before:

    There is an implicit conversion from a switch_expression (§12.11) to every type T for which there exists an implicit conversion from each switch_expression_arm’s switch_expression_arm_expression’s to T.

    After:

    There is an implicit conversion from a switch_expression (§12.11) which does not have a type to every type T for which there exists an implicit conversion from each switch_expression_arm’s switch_expression_arm_expression’s to T.

    Added "meeting: discuss" so we can check if that makes sense; it'll be easy to whip up a PR if so.

  6. KalleOlaviNiemitalo commented on Aug 26, 2026

    @KalleOlaviNiemitalo
    Contributor

    Perhaps clearer with a comma in "does not have a type, to every type".

  7. jskeet commented on Sep 9, 2026

    @jskeet
    ContributorAuthor

    Meeting resolution: proposal is fine. @jskeet to create a PR.

  8. removed
    meeting: discussThis issue should be discussed at the next TC49-TG2 meeting
    meeting: proposalThere is an informal proposal in the issue, worth discussing in a meeting
    on Sep 9, 2026
  9. added a commit that references this issue on Sep 13, 2026
    891944a
  10. added a commit that references this issue on Sep 15, 2026
    df649b5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions