dotnet/roslyn

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

Open

#67,889 opened on 2023年4月20日

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
 (平均マージ 6d 17h) (30d で 256 merged PRs)

説明

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()

コントリビューターガイド