Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions standard/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@

The attribute `System.Runtime.CompilerServices.CallerFilePathAttribute` is allowed on optional parameters when there is a standard implicit conversion ([§10.4.2](conversions.md#1042-standard-implicit-conversions)) from `string` to the parameter’s type.

If a function invocation from a location in source code omits an optional parameter with the `CallerFilePathAttribute`, then a string literal representing that location’s file path is used as an argument to the invocation instead of the default parameter value.
If a function invocation from a location in source code omits an optional parameter with the `CallerFilePathAttribute`, then a UTF-16 string literal representing that location’s file path is used as an argument to the invocation instead of the default parameter value.

The format of the file path is implementation-dependent.

Expand All @@ -830,7 +830,7 @@

The attribute `System.Runtime.CompilerServices.CallerMemberNameAttribute` is allowed on optional parameters when there is a standard implicit conversion ([§10.4.2](conversions.md#1042-standard-implicit-conversions)) from `string` to the parameter’s type.

If a function invocation from a location within the body of a function member or within an attribute applied to the function member itself or its return type, parameters or type parameters in source code omits an optional parameter with the `CallerMemberNameAttribute`, then a string literal representing the name of that member is used as an argument to the invocation instead of the default parameter value. (In the case of a function invocation from a top-level statement ([§7.1.3](basic-concepts.md#713-using-top-level-statements)), the member name is that generated by the implementation.)
If a function invocation from a location within the body of a function member or within an attribute applied to the function member itself or its return type, parameters or type parameters in source code omits an optional parameter with the `CallerMemberNameAttribute`, then a UTF-16 string literal representing the name of that member is used as an argument to the invocation instead of the default parameter value. (In the case of a function invocation from a top-level statement ([§7.1.3](basic-concepts.md#713-using-top-level-statements)), the member name is that generated by the implementation.)

For invocations that occur within generic methods, only the method name itself is used, without the type parameter list.

Expand Down Expand Up @@ -860,7 +860,7 @@
using System.Runtime.CompilerServices;
#nullable enable
class Test
{

Check warning on line 863 in standard/attributes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/attributes.md#L863

MDC032::Line length 92 > maximum 81
public static void M(int val = 0, [CallerArgumentExpression("val")] string? text = null)
{
Console.WriteLine($"val = {val}, text = <{text}>");
Expand Down Expand Up @@ -1041,7 +1041,7 @@
> ```csharp
> #nullable enable
> public class X
> {

Check warning on line 1044 in standard/attributes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/attributes.md#L1044

MDC032::Line length 86 > maximum 81
> private void ThrowIfNull([DoesNotReturnIf(true)] bool isNull, string argumentName)
> {
> if (!isNull)
Expand Down Expand Up @@ -1312,7 +1312,7 @@
}
public void AppendFormatted<T>(T t, int alignment, string format)
where T : IFormattable
{

Check warning on line 1315 in standard/attributes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/attributes.md#L1315

MDC032::Line length 86 > maximum 81
builder.Append(String.Format("{0" + "," + alignment + ":" + format + "}", t));
}
public override string ToString() => builder.ToString();
Expand Down
31 changes: 26 additions & 5 deletions standard/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2292,8 +2292,8 @@
A *null_conditional_invocation_expression* is syntactically either a *null_conditional_member_access* ([§12.8.8](expressions.md#1288-null-conditional-member-access)) or *null_conditional_element_access* ([§12.8.13](expressions.md#12813-null-conditional-element-access)) where the final *dependent_access* is an invocation expression ([§12.8.10](expressions.md#12810-invocation-expressions)).

A *null_conditional_invocation_expression* occurs within the context of a *statement_expression* ([§13.7](statements.md#137-expression-statements)), *anonymous_function_body* ([§12.22.1](expressions.md#12221-general)), or *method_body* ([§15.6.1](classes.md#1561-general)).

Check warning on line 2295 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L2295

MDC032::Line length 84 > maximum 81
Unlike the syntactically equivalent *null_conditional_member_access* or *null_conditional_element_access*, a *null_conditional_invocation_expression* may be classified as nothing.

Check warning on line 2296 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L2296

MDC032::Line length 85 > maximum 81

```ANTLR
null_conditional_invocation_expression
Expand Down Expand Up @@ -2373,7 +2373,7 @@
- The *primary_expression* has compile-time type `dynamic`.
- At least one expression of the *argument_list* has compile-time type `dynamic`.

In this case the compile-time type of the *element_access* depends on the compile-time type of its *primary_expression*: if it has an array type then the compile-time type is the element type of that array type; otherwise the compile-time type is `dynamic` and the *element_access* is classified as a value of type `dynamic`. The rules below to determine the meaning of the *element_access* are then applied at run-time, using the run-time type instead of the compile-time type of those of the *primary_expression* and *argument_list* expressions which have the compile-time type `dynamic`. If the *primary_expression* does not have compile-time type `dynamic`, then the element access undergoes a limited compile-time check as described in [§12.6.5](expressions.md#1265-compile-time-checking-of-dynamic-member-invocation).

Check warning on line 2376 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L2376

MDC032::Line length 82 > maximum 81

> *Example*:
>
Expand Down Expand Up @@ -3518,7 +3518,7 @@
- one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`; or
- any enumeration type.

### 12.8.22 Stack allocation

Check warning on line 3521 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L3521

MDC032::Line length 86 > maximum 81

A stack allocation expression allocates a block of memory from the execution stack. The ***execution stack*** is an area of memory where local variables are stored. The execution stack is not part of the managed heap. The memory used for local variable storage is automatically recovered when the current function returns.

Expand Down Expand Up @@ -3986,8 +3986,8 @@
All non-positional properties being changed shall have both set and init accessors.

This expression is evaluated as follows:

Check warning on line 3989 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L3989

MDC032::Line length 84 > maximum 81
- For a record class type, the receiver's clone method ([§15.16.3](classes.md#15163-copy-and-clone-members)) is invoked, and its result is converted to the receiver’s type.

Check warning on line 3990 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L3990

MDC032::Line length 85 > maximum 81
- Each `member_initializer` is processed the same way as an assignment to
a field or property access of the result of the conversion. Assignments are processed in lexical order. If *member_initializer_list* is omitted, no members are changed.

Expand Down Expand Up @@ -4287,7 +4287,7 @@

For an operation of the form `x + y`, binary operator overload resolution ([§12.4.5](expressions.md#1245-binary-operator-overload-resolution)) is applied to select a specific operator implementation. The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

The predefined addition operators are listed below. For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. When one or both operands are of type `string`, the predefined addition operators concatenate the string representation of the operands.
The predefined addition operators are listed below. For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. When one or both operands are of type `string`, or both are of type `ReadOnlySpan<byte>`, the predefined addition operators concatenate the string representation of the operands.

- Integer addition:

Expand Down Expand Up @@ -4335,15 +4335,15 @@
```

At run-time these operators are evaluated exactly as `(E)((U)x + (U)y`).
- String concatenation:
- UTF-16 string concatenation:

```csharp
string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);
```

These overloads of the binary `+` operator perform string concatenation. If an operand of string concatenation is `null`, an empty string is substituted. Otherwise, any non-`string` operand is converted to its string representation by invoking the virtual `ToString` method inherited from type `object`. If `ToString` returns `null`, an empty string is substituted.
These overloads of the binary `+` operator perform concatenation of UTF-16 strings. If an operand is `null`, an empty UTF-16 string is substituted. Otherwise, any non-`string` operand that is not a ref struct ([§16.2.3]( structs.md#1623-ref-modifier)) is converted to its UTF-16 string representation by invoking the virtual `ToString` method inherited from type `object`. If `ToString` returns `null`, an empty UTF-16 string is substituted.

> *Example*:
>
Expand Down Expand Up @@ -4372,7 +4372,28 @@
>
> *end example*

The result of the string concatenation operator is a `string` that consists of the characters of the left operand followed by the characters of the right operand. The string concatenation operator never returns a `null` value. A `System.OutOfMemoryException` may be thrown if there is not enough memory available to allocate the resulting string.
The result of the operator is a `string` that consists of the characters of the left operand followed by the characters of the right operand. The string concatenation operator never returns a `null` value. A `System.OutOfMemoryException` may be thrown if there is not enough memory available to allocate the resulting string.
- UTF-8 string concatenation:

```csharp
ReadOnlySpan<byte> operator +(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y);
```

This overload of the binary `+` operator performs concatenation of UTF-8 string literals and the concatenated results thereof (which is much more restrictive than for UTF-16 string concatenation). The operands shall be UTF-8-encoded values.
The result of the operator is a ReadOnlySpan<byte> that consists of the bytes of the left operand followed by the bytes of the right operand. The result may be used directly as an operand to the UTF-8 string concatenation operator.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From this normative text, it is not clear whether redundant parentheses are allowed.

using System;
public class C {
    public void M() {
        ReadOnlySpan<byte> a
            = (( "A"u8 + "a"u8 ))
            + (( "B"u8 + "b"u8 ));
    }
}


> *Example*:
>
> <!-- Example: {template:"standalone-console", name:"AdditionOperator2", expectedErrors:["CS9047","CS9047"]} -->
> ```csharp
> ReadOnlySpan<byte> sp1 = "ABC"u8 + "DEF"u8; // OK
> ReadOnlySpan<byte> sp2 = sp1 + "DEF"u8; // error
> ReadOnlySpan<byte> sp3 = "ABC"u8 + "DEF"u8 + "123"u8; // OK
> ReadOnlySpan<byte> sp4 = "ABC"u8 + (ReadOnlySpan<byte>)stackalloc byte[]
> { (byte)'D', (byte)'E', (byte)'F', (byte)'\x0' }; // error
> ```
>
> In the case of `sp1`, both operands are UTF-8 string literals. However, once `sp1` is initialized, that UTF-8 pedigree is no longer tracked. That is, `sp1` itself is not seen as being UTF-8 encoded. As such, it is not permitted to be an operand in the case of the initialization of `sp2`. In the initializer for `sp3`, the left pair of operands is evaluated, and as they are both UTF-8 string literals, the result is deemed to also be UTF-8 encoded, so it can further be used as the left operand of the right operator. In the case of `sp4`, while both operands are `ReadOnlySpan<byte>`s, only the left operand is UTF-8 encoded, even though the `Span<byte>` returned by `stackalloc` has the internal form of a UTF-8 string literal (that is, an array of bytes with a null-byte terminator). See [§6.4.5.6](lexical-structure.md#6456-string-literals). *end example*
- Delegate combination. Every delegate type implicitly provides the following predefined operator, where `D` is the delegate type:

```csharp
Expand Down Expand Up @@ -5434,7 +5455,7 @@
An ***anonymous function*** is an expression that represents an “in-line” method definition. An anonymous function does not have a value or type in and of itself, but is convertible to a compatible delegate or expression-tree type. The evaluation of an anonymous-function conversion depends on the target type of the conversion: If it is a delegate type, the conversion evaluates to a delegate value referencing the method that the anonymous function defines. If it is an expression-tree type, the conversion evaluates to an expression tree that represents the structure of the method as an object structure.

> *Note*: For historical reasons, there are two syntactic flavors of anonymous functions, namely *lambda_expression* and *anonymous_method_expression*. For almost all purposes, *lambda_expression* is more concise and expressive than *anonymous_method_expression*s, which remain in the language for backwards compatibility. *end note*

Check warning on line 5458 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L5458

MDC032::Line length 90 > maximum 81
```ANTLR
lambda_expression
: attributes? anonymous_function_modifier?
Expand Down Expand Up @@ -7296,7 +7317,7 @@

Only the following constructs are permitted in constant expressions:

- Literals (including the `null` literal).
- Literals (including the `null` literal, but excluding UTF-8 string literals).
- Constant interpolated strings.
- References to `const` members of class, struct, and interface types.
- References to members of enumeration types.
Expand Down
31 changes: 28 additions & 3 deletions standard/lexical-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -920,14 +920,16 @@

In a verbatim string literal, the characters between the delimiters are interpreted verbatim, with the only exception being a *Quote_Escape_Sequence*, which represents one double-quote character. In particular, simple escape sequences, and hexadecimal and Unicode escape sequences are not processed in verbatim string literals. A verbatim string literal may span multiple lines.

All string literal forms may optionally have a trailing *Utf8_Suffix*. The representation of each form is discussed below.

```ANTLR
String_Literal
: Regular_String_Literal
| Verbatim_String_Literal
;

fragment Regular_String_Literal
: '"' Regular_String_Literal_Character* '"'
: '"' Regular_String_Literal_Character* '"' Utf8_Suffix?
;

fragment Regular_String_Literal_Character
Expand All @@ -943,7 +945,7 @@
;

fragment Verbatim_String_Literal
: '@"' Verbatim_String_Literal_Character* '"'
: '@"' Verbatim_String_Literal_Character* '"' Utf8_Suffix?
;

fragment Verbatim_String_Literal_Character
Expand All @@ -958,6 +960,10 @@
fragment Quote_Escape_Sequence
: '""'
;

fragment Utf8_Suffix
: 'u8' | 'U8'
;
```

> *Example*: The example
Expand Down Expand Up @@ -990,7 +996,26 @@
<!-- markdownlint-enable MD028 -->
> *Note*: Since a hexadecimal escape sequence can have a variable number of hex digits, the string literal `"\x123"` contains a single character with hex value `123`. To create a string containing the character with hex value `12` followed by the character `3`, one could write `"\x00123"` or `"\x12"` + `"3"` instead. *end note*

The type of a *String_Literal* is `string`.
A *String_Literal* that does not contain a *Utf8_Suffix* is a ***UTF-16 string literal***, whose type is `string`.

A *String_Literal* that contains a *Utf8_Suffix* is a ***UTF-8 string literal***, whose type is `System.ReadOnlySpan<byte>` (an indexable collection type), and whose value contains a UTF-8 byte representation of the string. A null terminator (a byte with value zero) is placed beyond the last byte in memory (and outside the length of the `ReadOnlySpan<byte>`) in order to support scenarios that expect null-terminated byte strings. A UTF-8 string literal is not a constant. A UTF-8 string literal without its *Utf8_Suffix* shall be valid UTF-16. (For example, `"\uDC00\uDD00"u8` is ill-formed as one low surrogate cannot be followed by another.)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add a new subclause within 16.5.15 Safe context constraint, saying that when a UTF-8 string literal has a ReadOnlySpan<byte> value, the safe-context of that value is caller-context. That would allow it to be returned out of the function, like so:

using System;
public class C {
    public ReadOnlySpan<byte> M() {
        return "xyz"u8;
    }
}

Concatenation of UTF-8 string literals would then follow the safe-context rule in 16.5.15.5 Operators. As the safe-context of both operands would be caller-context, the safe-context of the result would be the same, without having to be specified separately for this case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following would then likewise be valid:

public class C {
    public ref readonly byte M() {
        return ref "xyz"u8[0];
    }
}


> *Note*: While every UTF-8 string literal is a `ReadOnlySpan<byte>`, not every `ReadOnlySpan<byte>` represents a UTF-8 string literal. See the description of UTF-8 string concatenation in [§12.13.5](expressions.md#12135-addition-operator). *end note*
<!-- markdownlint-disable MD028 -->

<!-- markdownlint-enable MD028 -->
> *Note*: As `ReadOnlySpan<byte>` is a ref struct type, a UTF-8 string literal cannot be converted to `object` or used as a type parameter ([§16.2.3]( structs.md#1623-ref-modifier)). *end note*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allows ref struct is added in C# 13, and this PR is for C# 11, so that part is OK…

But the wording is imprecise. A string literal is syntax rather than a type so it couldn't be used as a type parameter (or rather a type argument) anyway.

<!-- markdownlint-disable MD028 -->

<!-- markdownlint-enable MD028 -->
> *Example*: Here are examples of each form of string literal:
>
> | **Encoding** | **Type** | **Regular String Literal** | **Verbatim String Literal** | **Raw String Literal** |
> |--------------|----------------------|---------------------|--------------------|--------------------|
> | UTF-16 | `string` | `"Hello"` | `@"Hello"` | `"""Hello"""` |
> | UTF-8 | `ReadOnlySpan<byte>` | `"Hello"u8` | `@"Hello"u8` | `"""Hello"""u8` |
>
> *end example*

Each string literal does not necessarily result in a new string instance. When two or more string literals that are equivalent according to the string equality operator ([§12.15.8](expressions.md#12158-string-equality-operators)), appear in the same assembly, these string literals refer to the same string instance.

Expand Down Expand Up @@ -1521,7 +1546,7 @@
: Decimal_Digit+ PP_Whitespace PP_Compilation_Unit_Name
| Decimal_Digit+
| DEFAULT
| 'hidden'

Check warning on line 1549 in standard/lexical-structure.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/lexical-structure.md#L1549

MDC032::Line length 85 > maximum 81
| PP_Start_Line_Character PP_Whitespace? '-' PP_Whitespace? PP_End_Line_Character
PP_Whitespace (PP_Character_Offset PP_Whitespace)? PP_Compilation_Unit_Name
;
Expand Down
Loading