Skip to content

Commit e41690c

Browse files
RexJaeschkeBillWagnerNigel-Ecmajskeet
authored
C# 7.x: enhanced generic constraints (#244)
* Update classes.md * Tweak the recently added description of unmanaged constraint Describe what happens when a type called `unmanaged` exists in the scope of an unmanaged constraint. * Update standard/classes.md * Update standard/classes.md * Update standard/classes.md * Apply suggestions from code review Co-authored-by: Nigel-Ecma <[email protected]> Co-authored-by: Jon Skeet <[email protected]> * Apply suggestions from code review * Update foreword.md Remove V6-specific entries, and add first new V7 items. * add unmanaged to list of contextual keywords --------- Co-authored-by: Bill Wagner <[email protected]> Co-authored-by: Nigel-Ecma <[email protected]> Co-authored-by: Jon Skeet <[email protected]>
1 parent 8226273 commit e41690c

File tree

3 files changed

+20
-26
lines changed

3 files changed

+20
-26
lines changed

standard/classes.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ primary_constraint
415415
: class_type
416416
| 'class'
417417
| 'struct'
418+
| 'unmanaged'
418419
;
419420
420421
secondary_constraints
@@ -433,21 +434,29 @@ Each *type_parameter_constraints_clause* consists of the token `where`, followed
433434

434435
The list of constraints given in a `where` clause can include any of the following components, in this order: a single primary constraint, one or more secondary constraints, and the constructor constraint, `new()`.
435436

436-
A primary constraint can be a class type or the ***reference type constraint*** `class` or the ***value type constraint*** `struct`. A secondary constraint can be a *type_parameter* or *interface_type*.
437+
A primary constraint can be a class type, the ***reference type constraint*** `class`, the ***value type constraint*** `struct`, or the ***unmanaged type constraint*** `unmanaged`.
438+
439+
A secondary constraint can be a *type_parameter* or *interface_type*.
437440

438441
The reference type constraint specifies that a type argument used for the type parameter shall be a reference type. All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint.
439442

440443
The value type constraint specifies that a type argument used for the type parameter shall be a non-nullable value type. All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Note that although classified as a value type, a nullable value type ([§8.3.11](types.md#8311-nullable-value-types)) does not satisfy the value type constraint. A type parameter having the value type constraint shall not also have the *constructor_constraint*, although it may be used as a type argument for another type parameter with a *constructor_constraint*.
441444

442445
> *Note*: The `System.Nullable<T>` type specifies the non-nullable value type constraint for `T`. Thus, recursively constructed types of the forms `T??` and `Nullable<Nullable<T>>` are prohibited. *end note*
443446
447+
Because `unmanaged` is not a keyword, in *primary_constraint* the unmanaged constraint is always syntactically ambiguous with *class_type*. For compatibility reasons, if a name lookup (§11.7.4) of the name `unmanaged` succeeds it is treated as a `class_type`. Otherwise it is treated as the unmanaged constraint.
448+
449+
The unmanaged type constraint specifies that a type argument used for the type parameter shall be a non-nullable unmanaged type ([§8.8](types.md#88-unmanaged-types)).
450+
451+
Pointer types are never allowed to be type arguments, and don't satisfy any type constraints, even unmanaged, despite being unmanaged types.
452+
444453
If a constraint is a class type, an interface type, or a type parameter, that type specifies a minimal “base type” that every type argument used for that type parameter shall support. Whenever a constructed type or generic method is used, the type argument is checked against the constraints on the type parameter at compile-time. The type argument supplied shall satisfy the conditions described in [§8.4.5](types.md#845-satisfying-constraints).
445454

446455
A *class_type* constraint shall satisfy the following rules:
447456

448457
- The type shall be a class type.
449458
- The type shall not be `sealed`.
450-
- The type shall not be one of the following types: `System.Array`, `System.Delegate`, `System.Enum`, or `System.ValueType`.
459+
- The type shall not be one of the following types: `System.Array` or `System.ValueType`.
451460
- The type shall not be `object`.
452461
- At most one constraint for a given type parameter may be a class type.
453462

@@ -483,7 +492,7 @@ It is valid for `S` to have the value type constraint and `T` to have the refer
483492

484493
If the `where` clause for a type parameter includes a constructor constraint (which has the form `new()`), it is possible to use the `new` operator to create instances of the type ([§11.7.15.2](expressions.md#117152-object-creation-expressions)). Any type argument used for a type parameter with a constructor constraint shall be a value type, a non-abstract class having a public parameterless constructor, or a type parameter having the value type constraint or constructor constraint.
485494

486-
It is a compile-time error for *type_parameter_constraints* having a *primary_constraint* of `struct` to also have a *constructor_constraint*.
495+
It is a compile-time error for *type_parameter_constraints* having a *primary_constraint* of `struct` or `unmanaged` to also have a *constructor_constraint*.
487496

488497
> *Example*: The following are examples of constraints:
489498
>

standard/foreword.md

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,5 @@
11
# Foreword
22

3-
This specification replaces ECMA-334:2017. Changes from the previous edition include the addition of the following:
3+
This specification replaces ECMA-334:2022. Changes from the previous edition include the addition of the following:
44

5-
- Automatically implemented property initializers
6-
- `await` in catch and finally blocks
7-
- Exception filters
8-
- Expression-bodied function members
9-
- Extension Add methods in collection initializers
10-
- Improved overload resolution
11-
- Initialization of an accessible indexer
12-
- Initialization of associative collections using indexers
13-
- Interpolated strings
14-
- `nameof` operator
15-
- Null-conditional access operators `?.` and `?[]`
16-
- Read-only auto-properties
17-
- Relaxed rules for auto-properties
18-
- `using static`
19-
20-
All grammar is now expressed using ANTLR notation.
5+
- `System.Delegate` and `System.Enum` may now be used as *class_type* constraints.

standard/lexical-structure.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -569,12 +569,12 @@ A ***contextual keyword*** is an identifier-like sequence of characters that has
569569

570570
```ANTLR
571571
contextual_keyword
572-
: 'add' | 'alias' | 'ascending' | 'async' | 'await'
573-
| 'by' | 'descending' | 'dynamic' | 'equals' | 'from'
574-
| 'get' | 'global' | 'group' | 'into' | 'join'
575-
| 'let' | 'nameof' | 'on' | 'orderby' | 'partial'
576-
| 'remove' | 'select' | 'set' | 'value' | 'var'
577-
| 'when' | 'where' | 'yield'
572+
: 'add' | 'alias' | 'ascending' | 'async' | 'await'
573+
| 'by' | 'descending' | 'dynamic' | 'equals' | 'from'
574+
| 'get' | 'global' | 'group' | 'into' | 'join'
575+
| 'let' | 'nameof' | 'on' | 'orderby' | 'partial'
576+
| 'remove' | 'select' | 'set' | 'unmanaged' | 'value'
577+
| 'var' | 'when' | 'where' | 'yield'
578578
;
579579
```
580580

0 commit comments

Comments
 (0)