dotnet / dotnet/csharpstandard
12.6.6 function member invocation lacks specification of timing of reading receiver
- 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
Assessment
This issue has not been assessed yet.