dotnet / dotnet/csharpstandard

Incorrect definite assignment rules for binary expressions

Open
#1,227 3 comments 1 reaction 0 assignees View on GitHub
Dominant language
C#
Stars
815
Forks
99
Avg merge
1d 14h
Merged PRs (30d)
16

Description

In trying to explain the compiler behavior for https://github.com/dotnet/roslyn/issues/17828 I found that the specification is not correct in specifying the definite assignment rules for binary expressions.

The [spec](hthttps://github.com/dotnet/csharplang/blob/master/spec/variables.md#general-rules-for-expressions-with-embedded-expressions) says

> #### General rules for expressions with embedded expressions
>
> The following rules apply to these kinds of expressions: parenthesized expressions ([Parenthesized expressions](expressions.md#parenthesized-expressions)), element access expressions ([Element access](expressions.md#element-access)), base access expressions with indexing ([Base access](expressions.md#base-access)), increment and decrement expressions ([Postfix increment and decrement operators](expressions.md#postfix-increment-and-decrement-operators), [Prefix increment and decrement operators](expressions.md#prefix-increment-and-decrement-operators)), cast expressions ([Cast expressions](expressions.md#cast-expressions)), unary `+`, `-`, `~`, `*` expressions, binary `+`, `-`, `*`, `/`, `%`, `<<`, `>
> >`, `<`, `<=`, `>`, `>=`, `==`, `!=`, `is`, `as`, `&`, `|`, `^` expressions ([Arithmetic operators](expressions.md#arithmetic-operators), [Shift operators](expressions.md#shift-operators), [Relational and type-testing operators](expressions.md#relational-and-type-testing-operators), [Logical operators](expressions.md#logical-operators)), compound assignment expressions ([Compound assignment](expressions.md#compound-assignment)), `checked` and `unchecked` expressions ([The checked and unchecked operators](expressions.md#the-checked-and-unchecked-operators)), plus array and delegate creation expressions ([The new operator](expressions.md#the-new-operator)).
>
> Each of these expressions has one or more sub-expressions that are unconditionally evaluated in a fixed order. For example, the binary `%` operator evaluates the left hand side of the operator, then the right hand side. An indexing operation evaluates the indexed expression, and then evaluates each of the index expressions, in order from left to right. For an expression *expr*, which has sub-expressions *e1, e2, ..., eN*, evaluated in that order:
>
> * The definite assignment state of *v* at the beginning of *e1* is the same as the definite assignment state at the beginning of *expr*.
> * The definite assignment state of *v* at the beginning of *ei* (*i* greater than one) is the same as the definite assignment state at the end of the previous sub-expression.
> * The definite assignment state of *v* at the end of *expr* is the same as the definite assignment state at the end of *eN*

This obviously isn't correct for an expression of the form `(false == e)` because the definite assignment state after this expression isn't the same as the definite assignment state after `e`. At best definitely assigned when `true` and definitely assigned when `false` would be inverted. However, I don't believe the binary relational operators ever produce results in these substates of "not definitely assigned".

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.