dotnet / csharplang

The official repo for the design of the C# programming language
11.49k stars 1.02k forks source link

Compiler can't determine best common type for `switch` expression #8025

Open gurustron opened 9 months ago

gurustron commented 9 months ago

Probably my understanding of the spec in this part is incorrect, but according to switch expression feature spec:

The type of the switch_expression is the best common type (§11.6.3.15) of the expressions appearing to the right of the => tokens of the switch_expression_arms if such a type exists and the expression in every arm of the switch expression can be implicitly converted to that type.

And the natural function type has the following:

Function_types are used in a few specific contexts only:

  • implicit and explicit conversions
  • method type inference (§11.6.3) and best common type (§11.6.3.15)
  • var initializers

And:

Best common type (§11.6.3.15) is defined in terms of type inference so the type inference changes above apply to best common type as well.

With following sample which compiles:

var fs = new[] { (string s) => s.Length, (string s) => int.Parse(s) };

So for array construction compiler is able to determine the best common type.

Version Used: .NET 8.0.101, C# 12

Steps to Reproduce:

Create a swtich expression with anonymous lambdas:

var func = (args.Length == 1) switch
{
    false => () => "Hello World",
    true => () => "Foo Bar"
};

A minimal repro, with source-code provided, is ideal. Repro @sharplab

Expected Behavior:

Compiles

Actual Behavior:

error CS8506: No best type was found for the switch expression.

PoseidonEnergy commented 9 months ago

I would also like to highlight another discrepancy related to functions.

This does not compile:

var str = (() => "Hello World")(); // does not compile

However, this compiles:

var str = ((Func<string>)(() => "Hello World"))(); // compiles
RikkiGibson commented 9 months ago

@cston for visibility. I think this is a subtle issue relating to lambda natural type.

jaredpar commented 7 months ago

@cston ping for comment on whether or not this is about lambda natural type

cston commented 7 months ago

It looks like the best common type calculation for switch expressions currently ignores function types.

There is a similar issue with conditional expressions:

// error CS0173: Type of conditional expression cannot be determined
var func = (args.Length == 1) ? () => "Hello" : () => "World";

For switch expressions and conditional expressions, we could potentially use function types in the best common type calculation of the overall expression type.

jaredpar commented 6 months ago

Moving to csharplang as this is a design question vs. compiler impl.

CyrusNajmabadi commented 6 months ago

Definitely seems odd. I can't come up with a rational as to why array BCT works differently than switch or conditional BCT vis-a-vis function-types.

HaloFour commented 6 months ago

I would also like to highlight another discrepancy related to functions.

IIRC, the team decided against supporting IIFE in those scenarios: https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-07-26.md#direct-invocation-of-lambdas

PrinceSatish commented 5 months ago

By explicitly casting the lambdas to Func, you provide the necessary type information for the compiler to determine the return type of the switch expression, and it will compile without errors.