Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for target typed new expressions #990

Draft
wants to merge 5 commits into
base: draft-v9
Choose a base branch
from
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
6 changes: 6 additions & 0 deletions standard/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,12 @@ An implicit conversion exists from a *default_literal* ([§12.8.20](expressions.

While throw expressions do not have a type, they may be implicitly converted to any type.

### §imp-obj-creation-conv Implicit object-creation conversions

There is an implicit ***object-creation conversion*** from a *target_typed_new* expression ([§12.8.16.2](expressions.md#128162-object-creation-expressions)) to every type.

Given a target type `T`, if `T` is an instance of `System.Nullable`, the type `T0` is `T`'s underlying type. Otherwise `T0` is `T`. The meaning of a *target_typed_new* expression that is converted to the type `T` is the same as the meaning of a corresponding *object_creation_expression* that specifies `T0` as the type.
Copy link
Contributor

Choose a reason for hiding this comment

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

System.Nullable is a type but not a generic type. How is this worded elsewhere — System.Nullable<> or System.Nullable<T>?


## 10.3 Explicit conversions

### 10.3.1 General
Expand Down
13 changes: 11 additions & 2 deletions standard/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2286,6 +2286,11 @@ An *object_creation_expression* is used to create a new instance of a *class_typ
object_creation_expression
: 'new' type '(' argument_list? ')' object_or_collection_initializer?
| 'new' type object_or_collection_initializer
| target_typed_new
;

target_typed_new
: 'new' '(' argument_list? ')' object_or_collection_initializer?
;

object_or_collection_initializer
Expand All @@ -2296,6 +2301,10 @@ object_or_collection_initializer

The *type* of an *object_creation_expression* shall be a *class_type*, a *value_type*, or a *type_parameter*. The *type* cannot be a *tuple_type* or an abstract or static *class_type*.
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok I suppose this disallows dynamic and pointer types as type even in target-typed new.


If `type` can be inferred from usage, it can be omitted, as allowed by *target_typed_new*. It is a compile-time error to omit `type` if the type cannot be inferred. A *target_typed_new* expression has no type. However, there is an implicit object-creation conversion (§imp-obj-creation-conv) from a *target_typed_new* expression to every type. It is a compile-time error if a *target_typed_new* is used as an operand of a unary or binary operator, or if it is used where it is not subject to an object-creation conversion.
Copy link
Contributor

Choose a reason for hiding this comment

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

Together with C# 9 target-typed conditional expressions, this will then allow

class C {
    char M() {
        return new() ? new() : new();
    }
}

in which the target types will be inferred as

class C {
    char M() {
        return new bool() ? new char() : new char();
    }
}

It might be clearest to merge that feature before this one, so that there is no doubt about why target-typed new is allowed in operands of the ternary operator.


If `type` is present, let `T` be that type; otherwise, let `T` be the implied type.

The optional *argument_list* ([§12.6.2](expressions.md#1262-argument-lists)) is permitted only if the *type* is a *class_type* or a *struct_type*.

An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.
Expand All @@ -2304,7 +2313,7 @@ Processing of an object creation expression that includes an object initializer

If any of the arguments in the optional *argument_list* has the compile-time type `dynamic` then the *object_creation_expression* is dynamically bound ([§12.3.3](expressions.md#1233-dynamic-binding)) and the following rules are applied at run-time using the run-time type of those arguments of the *argument_list* that have the compile-time type `dynamic`. However, the object creation undergoes a limited compile-time check as described in [§12.6.5](expressions.md#1265-compile-time-checking-of-dynamic-member-invocation).

The binding-time processing of an *object_creation_expression* of the form new `T(A)`, where `T` is a *class_type*, or a *value_type*, and `A` is an optional *argument_list*, consists of the following steps:
The binding-time processing of an *object_creation_expression* of the form `new T(A)`, where the specified or implied type `T` is a *class_type*, or a *value_type*, and `A` is an optional *argument_list*, consists of the following steps:

- If `T` is a *value_type* and `A` is not present:
- The *object_creation_expression* is a default constructor invocation. The result of the *object_creation_expression* is a value of type `T`, namely the default value for `T` as defined in [§8.3.3](types.md#833-default-constructors).
Expand All @@ -2319,7 +2328,7 @@ The binding-time processing of an *object_creation_expression* of the form new `

Even if the *object_creation_expression* is dynamically bound, the compile-time type is still `T`.

The run-time processing of an *object_creation_expression* of the form new `T(A)`, where `T` is *class_type* or a *struct_type* and `A` is an optional *argument_list*, consists of the following steps:
The run-time processing of an *object_creation_expression* of the form `new T(A)`, where the specified or implied type `T` is *class_type* or a *struct_type* and `A` is an optional *argument_list*, consists of the following steps:

- If `T` is a *class_type*:
- A new instance of class `T` is allocated. If there is not enough memory available to allocate the new instance, a `System.OutOfMemoryException` is thrown and no further steps are executed.
Expand Down
2 changes: 1 addition & 1 deletion standard/statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ throw_statement
;
```

A `throw` statement with an expression throws an exception produced by evaluating the expression. The expression shall be implicitly convertible to `System.Exception`, and the result of evaluating the expression is converted to `System.Exception` before being thrown. If the result of the conversion is `null`, a `System.NullReferenceException` is thrown instead.
A `throw` statement with an expression throws an exception produced by evaluating the expression. The expression shall be implicitly convertible to `System.Exception`, and the result of evaluating the expression is converted to `System.Exception` before being thrown. If *expression* is a *target_typed_new* expression ([§12.8.16.2](expressions.md#128162-object-creation-expressions)), the target type is `System.Exception`. If the result of the conversion is `null`, a `System.NullReferenceException` is thrown instead.

A `throw` statement with no expression can be used only in a `catch` block, in which case, that statement re-throws the exception that is currently being handled by that `catch` block.

Expand Down
Loading