dotnet / dotnet/csharpstandard

12.6.6 function member invocation lacks specification of timing of reading receiver

Open
#1,584 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
815
Forks
99
Avg merge
1d 14h
Merged PRs (30d)
16

Description

**Describe the bug** In 12.6.6 function member invocation, for `E.M(args...)`, if `E` is not value type or does not implement `M`, then:

1. evaluate `E`
2. evaluate `args...`
3. if `E` is value type, box it and treat it as the boxed instance
4. invoke `M`

Suppose `E` is classified as a variable, then it's unclear when the value of `E` is read. Is it right after 1, or right before 3? The two options are not equivalent, because evaluation of `args...` could modify the value stored in that variable.

After some testing, it turns out that

- when `E` is reference type, the value (reference) is read right after 1,
- Suppose `E` is the identifier of a local variable and `args...` reassigns this variable, the receiver of `E.M(args...)` is the (old) object before reassignment.
- but, when `E` is value type, the value is read right before 3.
- Suppose `E` is the identifier of a local variable and `args...` reassigns this variable, the receiver of `E.M(args...)` is a boxed instance of the reassigned (new) value.

The timings are **different**!

**Example**

See replies to this issue.

**Expected behavior**

The standard should clearly specify the timing of reading of value from variable.

**Additional context**

Found when investigating the semantics of `constrained. callvirt.`. See dotnet/dotnet-api-docs#12359.

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.