dotnet/roslyn

Clarify errors around void expressions in switch expressions / Disallow them in switch exp. instead of propagating void

Open

#67,889 opened on Apr 20, 2023

View on GitHub
 (0 comments) (0 reactions) (0 assignees)C# (4,257 forks)batch import
Area-CompilersBugInteractive-ScriptingLogichelp wanted

Repository metrics

Stars
 (20,414 stars)
PR merge metrics
 (Avg merge 6d 17h) (256 merged PRs in 30d)

Description

Void expressions make no sense and do not seem to be usable at all - at least until dotnet/csharplang#2632 gets accepted and implemented. It looks like void expression type is propagated until it can't be anymore.

This propagation is probably why 1 switch { int => Console.WriteLine() } evaluated in any REPL that uses MS.CA.Scripting causes:

System.InvalidProgramException: Common Language Runtime detected an invalid program.
  at void Submission#1.<<Initialize>>d__0.MoveNext()
  at void System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<TStateMachine>(ref TStateMachine stateMachine)
  at Task<object> Submission#1.<Initialize>()
  at Task<object> Submission#1.<Factory>(object[] submissionArray)
  at async Task<TResult> Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync<TResult>(ImmutableArray<Func<object[], Task>> precedingExecutors, Func<object[], Task> currentExecutor, StrongBox<Exception> exceptionHolderOpt, Func<Exception, bool> catchExceptionOpt, CancellationToken cancellationToken)

Versions Used

  • Compiler version: '4.5.0-1.22524.5 (03cf426e)'. Language version: preview.
  • Sharplab main (25 Jan 2023): Compiler version: '4.6.0-ci (<developer build>)'. Language version: preview.
  • Compiler version: '4.5.0-6.23127.3 (e2bc27d2)'. Language version: 11.0.

Steps to Reproduce

Try to compile:

void AsStatement() => 1 switch { int => Console.WriteLine() };
void Discard() => _ = 1 switch { int => Console.WriteLine() };
void Var() { var v = 1 switch { int => Console.WriteLine() }; }
void Argument() => Console.WriteLine(1 switch { int => Console.WriteLine() });
void Assignment() { int i = 1 switch { int => Console.WriteLine() }; }
int Return() => 1 switch { int => Console.WriteLine() };

(sharplab)

Expected Behavior

  • AsStatement: you can't use a switch expression as a statement - this should have higher priority than anything that happens in the expression.
  • Discard, Var: Console.WriteLine() produces an error clearly indicating that this expression is the root cause of the problem, like "Expected an non-void expression".
  • Argument: Console.WriteLine() produces "CS0029: Cannot implicitly convert type 'void' to 'bool'", since the required target type(s) is known and it was decided to use bool in this instance of the error.
  • Assignment and Return: Console.WriteLine() produces "CS0029: Cannot implicitly convert type 'void' to 'int'", since it's known that the switch must have expression type int.

Implicit conversion of void (which means "no type") to a non-void type (CS0029) sounds as if it couldn't materialize a type - kind of nonsense, so maybe this should be replaced with a clearer error? However, int i = Console.WriteLine(); results in the same error.

Actual Behavior

  • :heavy_check_mark: AsStatement: CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement on the switch,
  • :x: Discard: CS8209: A value of type 'void' may not be assigned on _,
  • :x: Var: CS0815: Cannot assign void to an implicitly-typed variable on ident = expr,
  • :x: Argument: CS1503: Argument 1: cannot convert from 'void' to 'bool' on the switch,
  • :grey_question: Assignment and Return: CS0029: Cannot implicitly convert type 'void' to 'int'
    • :heavy_check_mark: on Console.WriteLine()

Contributor guide