diff --git a/query-languages/m/m-spec-consolidated-grammar.md b/query-languages/m/m-spec-consolidated-grammar.md
index d8237bea..6ce7eb19 100644
--- a/query-languages/m/m-spec-consolidated-grammar.md
+++ b/query-languages/m/m-spec-consolidated-grammar.md
@@ -260,15 +260,13 @@ logical-and-expression:
_is-expression:
as-expression
- is-expression_ `is` _nullable-primitive-type
-nullable-primitive-type:_
- `nullable`_opt primitive-type_
+ is-expression_ `is` _primitive-or-nullable-primitive-type_
#### As expression
_as-expression:
equality-expression
- as-expression_ `as` _nullable-primitive-type_
+ as-expression_ `as` _primitive-or-nullable-primitive-type_
#### Equality expression
@@ -448,15 +446,15 @@ fixed-parameter-list:
parameter
parameter_ `,` _fixed-parameter-list
parameter:
- parameter-name primitive-parameter-typeopt
+ parameter-name parameter-typeopt
parameter-name:
identifier
-primitive-parameter-type:
- primitive-assertion
+parameter-type:
+ primitive-or-nullable-primitive-type-assertion
return-type:
- primitive-assertion
-primitive-assertion:_
- `as` _nullable-primitive-type
+ primitive-or-nullable-primitive-type-assertion
+primitive-or-nullable-primitive-type-assertion:_
+ `as` _primitive-or-nullable-primitive-type
optional-parameter-list:
optional-parameter
optional-parameter_ `,` _optional-parameter-list
@@ -510,7 +508,9 @@ primary-type:
nullable-type
primitive-type:_ one of
`any anynonnull binary date datetime datetimezone duration function`
- `list logical none null number record table text time type`
+ `list logical none null number record table text time type`
+_primitive-or-nullable-primitive-type:_
+ `nullable`_opt primitive-type_
_record-type:_
`[` _open-record-marker_ `]`
`[` _field-specification-listopt_ `]`
@@ -548,7 +548,7 @@ optional-parameter-specification-list:
optional-parameter-specification:_
`optional` _parameter-specification
parameter-specification:
- parameter-name parameter-type
+ parameter-name parameter-type
parameter-type:
assertion
assertion:_
diff --git a/query-languages/m/m-spec-functions.md b/query-languages/m/m-spec-functions.md
index 6fe331ff..e368b12a 100644
--- a/query-languages/m/m-spec-functions.md
+++ b/query-languages/m/m-spec-functions.md
@@ -17,7 +17,7 @@ A _function_ is a value that represents a mapping from a set of argument values
Functions are written using a _function-expression_:
_function-expression:_
- `(` _parameter-listopt_ `)` _function-return-typeopt_ `=>` _function-body
+ `(` _parameter-listopt_ `)` _return-typeopt_ `=>` _function-body
function-body:
expression
parameter-list:
@@ -26,24 +26,24 @@ parameter-list:
optional-parameter-list
fixed-parameter-list:
parameter
- parameter_ `,` _fixed-parameter-list
+ parameter_ `,` _fixed-parameter-list
parameter:
parameter-name parameter-typeopt
parameter-name:
identifier
parameter-type:
- assertion
-function-return-type:
- assertion
-assertion:_
- `as` _nullable-primiitve-type
+ primitive-or-nullable-primitive-type-assertion
+return-type:
+ primitive-or-nullable-primitive-type-assertion
+primitive-or-nullable-primitive-type-assertion:_
+ `as` _primitive-or-nullable-primitive-type
optional-parameter-list:
optional-parameter
optional-parameter_ `,` _optional-parameter-list
optional-parameter:_
- `optional` _parameter
-nullable-primitve-type
- `nullable`_opt _primitive-type_
+ `optional` _parameter_
+_primitive-or-nullable-primitive-type:_
+ `nullable`_opt primitive-type_
The following is an example of a function that requires exactly two values `x` and `y`, and produces the result of applying the `+` operator to those values. The `x` and `y` are _parameters_ that are part of the _parameter-list_ of the function, and the `x + y` is the _function-body_:
diff --git a/query-languages/m/m-spec-operators.md b/query-languages/m/m-spec-operators.md
index 520c42b8..402a2ae2 100644
--- a/query-languages/m/m-spec-operators.md
+++ b/query-languages/m/m-spec-operators.md
@@ -2,7 +2,7 @@
title: M Language Operators
description: Describes using operators in the Power Query M formula language
ms.topic: conceptual
-ms.date: 12/12/2024
+ms.date: 1/7/2025
ms.custom: "nonautomated-date"
ms.subservice: m-specification
---
@@ -133,12 +133,12 @@ The following table summarizes the M operators, listing the operator categories
Type assertion |
x as y |
- Is compatible nullable-primitive type or error |
+ Is compatible with primitive or nullable primitive type or error |
Type conformance |
x is y |
- Test if compatible nullable-primitive type |
+ Test if compatible with primitive or nullable primitive type |
Logical AND |
@@ -1253,21 +1253,21 @@ The type compatibility operator `x is y` is defined for the following types of
| X | Y | Result |
| --- | --- | --- |
-| `type any` | _nullable-primitive-type_ | `type logical` |
+| `type any` | _primitive-or-nullable-primitive-type_ | `type logical` |
-The expression `x is y` returns `true` if the ascribed type of `x` is compatible with `y`, and returns `false` if the ascribed type of `x` is incompatible with `y`. `y` must be a _nullable-primitivetype_.
+The expression `x is y` returns `true` if the ascribed type of `x` is compatible with `y`, and returns `false` if it is not compatible. `y` must be a _primitive-or-nullable-primitive-type_.
_is-expression:
as-expression
- is-expression_ `is` _nullable-primitive-type
-nullable-primitive-type:_
- `nullable`_opt primitive-type_
+ is-expression_ `is` _primitive-or-nullable-primitive-type
+primitive-or-nullable-primitive-type:_
+ `nullable`_opt primitive-type_
Type compatibility, as supported by the `is` operator, is a subset of [general type compatibility](m-spec-types.md) and is defined using the following rules:
* If `x` is null then it is compatible if `y` is the type `any`, the type `null`, or a nullable type.
-* If `x` is non-null then if it is a compatible if the the primitive type of `x` is the same as `y`.
+* If `x` is non-null then it is a compatible if the primitive type of `x` is the same as `y`.
The following holds when evaluating the expression `x is y`:
@@ -1279,13 +1279,15 @@ The type assertion operator `x as y` is defined for the following types of value
| X | Y | Result |
| --- | --- | --- |
-| `type any` | _nullable-primitive-type_ | `type any` |
+| `type any` | _primitive-or-nullable-primitive-type_ | `type any` |
-The expression `x as y` asserts that the value `x` is compatible with `y` as per the `is` operator. If it is not compatible, an error is raised. `y` must be a _nullable-primitive-type_.
+The expression `x as y` asserts that the value `x` is compatible with `y` as per the `is` operator. If it is not compatible, an error is raised. `y` must be a primitive type or a nullable primitive type.
_as-expression:
equality-expression
- as-expression_ `as` _nullable-primitive-type_
+ as-expression_ `as` _primitive-or-nullable-primitive-type
+primitive-or-nullable-primitive-type:_
+ `nullable`_opt primitive-type_
The expression `x as y` is evaluated as follows:
diff --git a/query-languages/m/m-spec-types.md b/query-languages/m/m-spec-types.md
index e44eea8a..97ada8aa 100644
--- a/query-languages/m/m-spec-types.md
+++ b/query-languages/m/m-spec-types.md
@@ -2,7 +2,7 @@
title: M Language types
description: Describes using types in the Power Query M formula language
ms.topic: conceptual
-ms.date: 1/31/2024
+ms.date: 1/3/2025
ms.custom: "nonautomated-date"
ms.subservice: m-specification
---
@@ -29,22 +29,24 @@ The set of _primitive types_ includes the types of primitive values, and a numbe
All types that are not members of the closed set of primitive types plus their nullable counterparts are collectively referred to as _custom types_. Custom types can be written using a `type-expression`:
+_primitive-type:_ one of
+ `any anynonnull binary date datetime datetimezone duration function list logical`
+ `none null number record table text time type`
+_primitive-or-nullable-primitive-type:_
+ `nullable`_opt primitive-type_
+
+All other types are collectively referred to as _custom types_. Custom types can be written using a `type-expression`:
+
_type-expression:
primary-expression_
`type` _primary-type
-type:
- primary-expression
- primary-type
primary-type:
primitive-type
record-type
list-type
function-type
table-type
- nullable-type
-primitive-type:_ one of
- `any anynonnull binary date datetime datetimezone duration function list logical`
- `none null number record table text time type`
+ nullable-type_
The _primitive-type_ names are _contextual keywords_ recognized only in a _type_ context. The use of parentheses in a _type_ context moves the grammar back to a regular expression context, requiring the use of the type keyword to move back into a type context. For example, to invoke a function in a _type_ context, parentheses can be used:
@@ -95,7 +97,7 @@ Value.Type( 1 as number ) // type number
{2} as text // error, type mismatch
```
-Note that the `is` and `as` operators only accept nullable primitive types as their right operand. M does not provide means to check values for conformance to custom types.
+Note that the `is` and `as` operators only accept a _primitive or nullable primitive type_ (i.e. a _non-custom type_) as their right operand. M does not provide means to check values for conformance to custom types.
A type `X` is _compatible_ with a type `Y` if and only if all values that conform to `X` also conform to `Y`. All types are compatible with type `any` and no types (but `none` itself) are compatible with type `none`. The following graph shows the compatibility relation. (Type compatibility is reflexive and transitive. It forms a lattice with type `any` as the top and type `none` as the bottom value.) The names of abstract types are set in _italics_.
@@ -210,28 +212,28 @@ A conforming value may contain field names not listed in the field specification
Any function value conforms to the primitive type `function`, which does not place any restrictions on the types of the function's formal parameters or the function's return value. A custom _function-type value_ is used to place type restrictions on the signatures of conformant function values.
-_function-type:_
- `function (` _parameter-specification-listopt_ `)` _function-return-type
+function-type:_
+ `function (` _parameter-specification-listopt_ `)` _return-type
parameter-specification-list:
required-parameter-specification-list
required-parameter-specification-list_ `,` _optional-parameter-specification-list
optional-parameter-specification-list
required-parameter-specification-list:
required-parameter-specification
- required-parameter-specification_ `,` _required-parameter-specification-list
+ required-parameter-specification_ `,` _required-parameter-specification-list
required-parameter-specification:
parameter-specification
optional-parameter-specification-list:
optional-parameter-specification
- optional-parameter-specification_ `,` _optional-parameter-specification-list
+ optional-parameter-specification_ `,` _optional-parameter-specification-list
optional-parameter-specification:_
- `optional` _parameter-specification
+ `optional` _parameter-specification
parameter-specification:
- parameter-name parameter-type
-function-return-type:
+ parameter-name parameter-type
+parameter-type:
assertion
assertion:_
- `as` _nullable-primitive-type_
+ `as` _type_
The result of evaluating a _function-type_ is a type value whose base type is `function`.
@@ -364,7 +366,7 @@ Value.Type( Value.ReplaceType( {1}, type {number} )
Type equivalence is not defined in M. An M implementation may optionally choose to use its own rules to perform equality comparisons between type values. Comparing two type values for equality should evaluate to `true` if they are considered identical by the implementation, and `false` otherwise. In either case, the response returned must be consistent if the same two values are repeatedly compared. Note that within a given implementation, comparing some identical type values (such as `(type text) = (type text)`) may return `true`, while comparing others (such as `(type [a = text]) = (type [a = text])`) may not.
-Compatibility between a given type and a nullable primitive type can be determined using the library function `Type.Is`, which accepts an arbitrary type value as its first and a nullable primitive type value as its second argument:
+Compatibility between a given type and either a primitive type or a nullable primitive type can be determined using the library function `Type.Is`, which accepts an arbitrary type value as its first argument and a primitive or nullable primitive type value as its second argument:
```powerquery-m
Type.Is(type text, type nullable text) // true