diff --git a/proposals/p2188.md b/proposals/p2188.md
new file mode 100644
index 000000000000..d286afdc9757
--- /dev/null
+++ b/proposals/p2188.md
@@ -0,0 +1,1761 @@
+# Pattern matching syntax and semantics
+
+
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/2188)
+
+
+
+## Table of contents
+
+- [Abstract](#abstract)
+- [Problem](#problem)
+- [Background](#background)
+- [Proposal](#proposal)
+- [Details](#details)
+ - [Expressions versus proper patterns](#expressions-versus-proper-patterns)
+ - [Expression patterns](#expression-patterns)
+ - [Bindings](#bindings)
+ - [Name bindings](#name-bindings)
+ - [Wildcard](#wildcard)
+ - [Generic bindings](#generic-bindings)
+ - [`auto` and type deduction](#auto-and-type-deduction)
+ - [`var`](#var)
+ - [Tuple patterns](#tuple-patterns)
+ - [Struct patterns](#struct-patterns)
+ - [Alternative patterns](#alternative-patterns)
+ - [Templates](#templates)
+ - [Guards](#guards)
+ - [Refutability, overlap, usefulness, and exhaustiveness](#refutability-overlap-usefulness-and-exhaustiveness)
+- [Rationale](#rationale)
+- [Alternatives considered](#alternatives-considered)
+ - [Shorthand for `auto`](#shorthand-for-auto)
+ - [Struct pattern syntax](#struct-pattern-syntax)
+ - [Type pattern matching](#type-pattern-matching)
+ - [Introducer syntax for expression patterns](#introducer-syntax-for-expression-patterns)
+ - [Allow guards on arbitrary patterns](#allow-guards-on-arbitrary-patterns)
+ - [Treat expression patterns as exhaustive if they cover all possible values](#treat-expression-patterns-as-exhaustive-if-they-cover-all-possible-values)
+ - [Allow non-exhaustive `match` statements](#allow-non-exhaustive-match-statements)
+- [Future work](#future-work)
+ - [Or patterns](#or-patterns)
+ - [As patterns](#as-patterns)
+ - [Matching classes by dynamic type](#matching-classes-by-dynamic-type)
+ - [User-defined pattern matching](#user-defined-pattern-matching)
+ - [Matching classes with struct patterns](#matching-classes-with-struct-patterns)
+ - [Matching by reference](#matching-by-reference)
+ - [Type deduction](#type-deduction)
+ - [Match expressions](#match-expressions)
+- [Examples](#examples)
+ - [Examples from P0095R1](#examples-from-p0095r1)
+ - [Figure 1. Declaration of a command data structure](#figure-1-declaration-of-a-command-data-structure)
+ - [Figure 2. Implementation of an output operator](#figure-2-implementation-of-an-output-operator)
+ - [Figure 3. Switching an enum](#figure-3-switching-an-enum)
+ - [Figure 4. Expression datatype](#figure-4-expression-datatype)
+ - [Figure 5. `struct` inspection](#figure-5-struct-inspection)
+ - [Example from P1371R5: Red-black tree rebalancing](#example-from-p1371r5-red-black-tree-rebalancing)
+ - [With P1371R5 pattern matching](#with-p1371r5-pattern-matching)
+ - [With this proposal](#with-this-proposal)
+ - [With this proposal plus #2187](#with-this-proposal-plus-2187)
+
+
+
+## Abstract
+
+This paper proposes concrete syntax and semantic choices for Carbon patterns.
+
+## Problem
+
+Carbon uses patterns wherever a value should be given a name, decomposed, or
+matched against: in function parameters, variable declarations, `match`
+statement `case`s, `for` statement loop variables, and so on. Simplified forms
+of patterns, required to be just a simple name binding, appear in additional
+contexts, such as fields in classes and implicit parameter lists. While we have
+syntax specified for some of these constructs, we do not have an approved
+proposal describing the syntax or semantics of patterns.
+
+## Background
+
+See [pattern matching](https://en.wikipedia.org/wiki/Pattern_matching) on
+wikipedia for a broad overview of the subject.
+
+We refer to the value being matched by a pattern as the _scrutinee_.
+
+## Proposal
+
+Patterns in Carbon are a generalization of the expression grammar. Compared to
+expressions, patterns add:
+
+- Bindings, of the form `name: type`, which give a name for the scrutinee.
+- `var` _pattern_, which creates a separate object to hold the value of the
+ scrutinee, and causes any nested bindings to be mutable lvalues instead of
+ immutable rvalues.
+- Additional syntax to make matching against structs more convenient.
+
+## Details
+
+### Expressions versus proper patterns
+
+Expressions are patterns, as described below. A pattern that is not an
+expression, because it contains pattern-specific syntax such as a binding, is a
+_proper pattern_. Many expression forms, such as arbitrary function calls, are
+not permitted as proper patterns, so cannot contain bindings.
+
+- _pattern_ ::= _proper-pattern_
+
+```
+fn F(n: i32) -> i32 { return n; }
+
+match (F(42)) {
+ // ❌ Error: binding can't appear in a function call.
+ case (F(n: i32)) => {}
+}
+```
+
+### Expression patterns
+
+An expression is a pattern.
+
+- _pattern_ ::= _expression_
+
+The pattern is compared with the expression using the `==` operator: _pattern_
+`==` _scrutinee_.
+
+```
+fn F(n: i32) {
+ match (n) {
+ // ✅ Results in an `n == 5` comparison.
+ // OK despite `n` and `5` having different types.
+ case 5 => {}
+ }
+}
+```
+
+Any `==` operations performed by a pattern match occur in lexical order, but for
+repeated matches against the same _pattern_, later comparisons may be skipped by
+reusing the result from an earlier comparison:
+
+```
+class ChattyIntMatcher {
+ external impl as EqWith(i32) {
+ fn Eq[me: ChattyIntMatcher](other: i32) {
+ Print("Matching {0}", other);
+ return other == 1;
+ }
+ }
+}
+
+fn F() {
+ // Prints `Matching 1` then `Matching 2`,
+ // may or may not then print `Matching 1` again.
+ match ((1, 2)) {
+ case ({} as ChattyIntMatcher, 0) => {}
+ case (1, {} as ChattyIntMatcher) => {}
+ case ({} as ChattyIntMatcher, 2) => {}
+ }
+}
+```
+
+### Bindings
+
+#### Name bindings
+
+A name binding is a pattern.
+
+- _binding-pattern_ ::= `unused`? _identifier_ `:` _expression_
+- _proper-pattern_ ::= _binding-pattern_
+
+The type of the _identifier_ is specified by the _expression_. The scrutinee is
+implicitly converted to that type if necessary.
+
+```
+fn F() -> i32 {
+ match (5) (
+ // ✅ `5` is implicitly converted to `i32`.
+ // Returns `5 as i32`.
+ case n: i32 => { return n; }
+ }
+}
+```
+
+When a new object needs to be created for the binding, the lifetime of the bound
+value matches the scope of the binding.
+
+```
+class NoisyDestructor {
+ fn Make() -> Self { return {}; }
+ external impl i32 as ImplicitAs(NoisyDestructor) {
+ fn Convert[me: i32]() -> Self { return Make(); }
+ }
+ destructor {
+ Print("Destroyed!");
+ }
+}
+
+fn G() {
+ // Does not print "Destroyed!".
+ let n: NoisyDestructor = NoisyDestructor.Make();
+ Print("Body of G");
+ // Prints "Destroyed!" here.
+}
+
+fn H(n: i32) {
+ // Does not print "Destroyed!".
+ let (v: NoisyDestructor, w: i32) = (n, n);
+ Print("Body of H");
+ // Prints "Destroyed!" here.
+}
+```
+
+As specified in
+[#2022](/proposals/p2022.md#the-behavior-of-unused-name-bindings), the `unused`
+keyword indicates that the binding is intended to not be used.
+
+#### Wildcard
+
+A syntax like a binding but with `_` in place of an identifier can be used to
+ignore part of a value.
+
+- _binding-pattern_ ::= `_` `:` _expression_
+
+See [#2022](/proposals/p2022.md) for details.
+
+The behavior is similar to that of an `unused` binding with a unique name.
+
+```
+fn F(n: i32) {
+ match (n) {
+ // ✅ Matches and discards the value of `n`.
+ case _: i32 => {}
+ // ❌ Error: unreachable.
+ default => {}
+ }
+}
+```
+
+As specified in [#1084](/proposals/p1084.md), function redeclarations may
+replace named bindings with wildcards but may not use different names.
+
+```
+fn G(n: i32);
+fn H(n: i32);
+fn J(n: i32);
+
+// ✅ Does not use `n`.
+fn G(_: i32) {}
+// ❌ Error: name of parameter does not match declaration.
+fn H(m: i32) {}
+// ✅ Does not use `n`.
+fn J(unused n: i32);
+```
+
+#### Generic bindings
+
+A `:!` can be used in place of `:` for a binding that is usable at compile time.
+
+- _generic-pattern_ ::= `unused`? `template`? _identifier_ `:!` _expression_
+- _generic-pattern_ ::= `template`? `_` `:!` _expression_
+- _proper-pattern_ ::= _generic-pattern_
+
+```
+// ✅ `F` takes a generic type parameter `T` and a parameter `x` of type `T`.
+fn F(T:! Type, x: T) {
+ var v: T = x;
+}
+```
+
+The `template` keyword indicates the binding is introducing a template
+parameter, so name lookups into the parameter should be deferred until its value
+is known.
+
+#### `auto` and type deduction
+
+The `auto` keyword is a placeholder for a unique deduced type.
+
+- _expression_ ::= `auto`
+
+```
+fn F(n: i32) {
+ var v: auto = SomeComplicatedExpression(n);
+ // Equivalent to:
+ var w: T = SomeComplicatedExpression(n);
+ // ... where `T` is the type of the initializer.
+}
+```
+
+The `auto` keyword is only permitted in specific contexts. Currently these are:
+
+- As the return type of a function.
+- As the type of a binding.
+
+It is anticipated that `auto` may be permitted in more contexts in the future,
+for example as a generic argument in a parameterized type that appears in a
+context where `auto` is allowed, such as `Vector(auto)` or `auto*`.
+
+When the type of a binding requires type deduction, the type is deduced against
+the type of the scrutinee and deduced values are substituted back into the type
+before pattern matching is performed.
+
+```
+fn G[T:! Type](p: T*);
+class X { external impl as ImplicitAs(i32*); }
+// ✅ Deduces `T = i32` then implicitly and
+// trivially converts `p` to `i32*`.
+fn H1(p: i32*) { G(p); }
+// ❌ Error, can't deduce `T*` from `X`.
+fn H2(p: X) { G(p); }
+```
+
+The above is only an illustration; the behavior of type deduction is not
+specified in this proposal.
+
+### `var`
+
+A `var` prefix indicates that a pattern provides mutable storage for the
+scrutinee.
+
+- _proper-pattern_ ::= `var` _proper-pattern_
+
+A `var` pattern matches when its nested pattern matches. The type of the storage
+is the resolved type of the nested _pattern_. Any bindings within the nested
+pattern refer to portions of the corresponding storage rather than to the
+scrutinee.
+
+```
+fn F(p: i32*);
+fn G() {
+ match ((1, 2)) {
+ // `n` is a mutable `i32`.
+ case (var n: i32, 1) => { F(&n); }
+ // `n` and `m` are the elements of a mutable `(i32, i32)`.
+ case var (n: i32, m: i32) => { F(if n then &n else &m); }
+ }
+}
+```
+
+Pattern matching precedes the initialization of the storage for any `var`
+patterns. An introduced variable is only initialized if the complete pattern
+matches.
+
+```
+class X {
+ destructor { Print("Destroyed!"); }
+}
+fn F(x: X) {
+ match ((x, 1 as i32)) {
+ case (var y: X, 0) => {}
+ case (var z: X, 1) => {}
+ // Prints "Destroyed!" only once, when `z` is destroyed.
+ }
+}
+```
+
+A `var` pattern cannot be nested within another `var` pattern. The declaration
+syntax `var` _pattern_ `=` _expresson_ `;` is equivalent to `let` `var`
+_pattern_ `=` _expression_ `;`.
+
+### Tuple patterns
+
+A tuple of patterns can be used as a pattern.
+
+- _tuple-pattern_ ::= `(` [_expression_ `,`]\* _proper-pattern_ [`,`
+ _pattern_]\* `,`? `)`
+- _proper-pattern_ ::= _tuple-pattern_
+
+A _tuple-pattern_ containing no commas is treated as grouping parens: the
+contained _proper-pattern_ is matched directly against the scrutinee. Otherwise,
+the behavior is as follows.
+
+A tuple pattern is matched left-to-right. The scrutinee is required to be of
+tuple type.
+
+Note that a tuple pattern must contain at least one _proper-pattern_. Otherwise,
+it is a tuple-valued expression. However, a tuple pattern and a corresponding
+tuple-valued expression are matched in the same way because `==` for a tuple
+compares fields left-to-right.
+
+### Struct patterns
+
+A struct can be matched with a struct pattern.
+
+- _proper-pattern_ ::= `{` [_field-init_ `,`]\* _proper-field-pattern_ [`,`
+ _field-pattern_]\* `}`
+- _proper-pattern_ ::= `{` [_field-pattern_ `,`]+ `_` `}`
+- _field-init_ ::= _designator_ `=` _expression_
+- _proper-field-pattern_ ::= _designator_ `=` _proper-pattern_
+- _proper-field-pattern_ ::= _binding-pattern_
+- _field-pattern_ ::= _field-init_
+- _field-pattern_ ::= _proper-field-pattern_
+
+A struct pattern resembles a struct literal, with at least one field initialized
+with a proper pattern:
+
+```
+match ({.a = 1, .b = 2}) {
+ // Struct literal as an expression pattern.
+ case {.b = 2, .a = 1} => {}
+ // Struct pattern.
+ case {.b = n: i32, .a = m: i32} => {}
+}
+```
+
+The scrutinee is required to be of struct type, and to have the same set of
+field names as the pattern. The pattern is matched left-to-right, meaning that
+matching is performed in the field order specified in the pattern, not in the
+field order of the scrutinee. This is consistent with the behavior of matching
+against a struct-valued expression, where the expression pattern becomes the
+left operand of the `==` and so determines the order in which `==` comparisons
+for fields are performed.
+
+In the case where a field will be bound to an identifier with the same name, a
+shorthand syntax is available: `a: T` is synonymous with `.a = a: T`.
+
+```
+match ({.a = 1, .b = 2}) {
+ case {a: i32, b: i32} => { return a + b; }
+}
+```
+
+If some fields should be ignored when matching, a trailing `, _` can be added to
+specify this:
+
+```
+match ({.a = 1, .b = 2}) {
+ case {.a = 1, _} => { return 1; }
+ case {b: i32, _} => { return b; }
+}
+```
+
+This is valid even if all fields are actually named in the pattern.
+
+### Alternative patterns
+
+An alternative pattern is used to match one alternative of a choice type.
+
+- _proper-pattern_ ::= _callee-expression_ _tuple-pattern_
+- _proper-pattern_ ::= _designator_ _tuple-pattern_?
+
+Here, _callee-expression_ is syntactically an expression that is valid as the
+callee in a function call expression, and an alternative pattern is
+syntactically a function call expression whose argument list contains at least
+one _proper-pattern_.
+
+If a _callee-expression_ is provided, it is required to name a choice type
+alternative that has a parameter list, and the scrutinee is implicitly converted
+to that choice type. Otherwise, the scrutinee is required to be of some choice
+type, and the designator is looked up in that type and is required to name an
+alternative with a parameter list if and only if a _tuple-pattern_ is specified.
+
+The pattern matches if the active alternative in the scrutinee is the specified
+alternative, and the arguments of the alternative match the given tuple pattern
+(if any).
+
+```
+choice Optional(T:! Type) {
+ None,
+ Some(T)
+}
+
+match (Optional(i32).None) {
+ // ✅ `.None` resolved to `Optional(i32).None`.
+ case .None => {}
+ // ✅ `.Some` resolved to `Optional(i32).Some`.
+ case .Some(n: i32) => { Print("{0}", n); }
+ // ❌ Error, no such alternative exists.
+ case .Other => {}
+}
+
+class X {
+ external impl as ImplicitAs(Optional(i32));
+}
+
+match ({} as X) {
+ // ✅ OK, but expression pattern.
+ case Optional(i32).None => {}
+ // ✅ OK, implicitly converts to `Optional(i32)`.
+ case Optional(i32).Some(n: i32) => { Print("{0}", n); }
+}
+```
+
+Note that a pattern of the form `Optional(T).None` is an expression pattern and
+is compared using `==`.
+
+### Templates
+
+Any checking of the type of the scrutinee against the type of the pattern that
+cannot be performed because the type of the scrutinee involves a template
+parameter is deferred until the template parameter's value is known. During
+instantiation, patterns that are not meaningful due to a type error are instead
+treated as not matching. This includes cases where an `==` fails because of a
+missing `EqWith` implementation.
+
+```
+fn TypeName[template T:! Type](x: T) -> String {
+ match (x) {
+ // ✅ OK, the type of `x` is a template parameter.
+ case _: i32 => { return "int"; }
+ case _: bool => { return "bool"; }
+ case _: auto* => { return "pointer"; }
+ default => { return "unknown"; }
+ }
+}
+```
+
+Cases where the match is invalid for reasons not involving the template
+parameter are rejected when type-checking the template:
+
+```
+fn MeaninglessMatch[template T:! Type](x: T*) {
+ match (*x) {
+ // ✅ OK, `T` could be a tuple.
+ case (_: auto, _: auto) => {}
+ default => {}
+ }
+ match (x->y) {
+ // ✅ OK, `T.y` could be a tuple.
+ case (_: auto, _: auto) => {}
+ default => {}
+ }
+ match (x) {
+ // ❌ Error, tuple pattern cannot match value of non-tuple type `T*`.
+ case (_: auto, _: auto) => {}
+ default => {}
+ }
+}
+```
+
+### Guards
+
+We allow `case`s within a `match` statement to have _guards_. These are not part
+of pattern syntax, but instead are specific to `case` syntax:
+
+- _case_ ::= `case` _pattern_ [`if` _expression_]? `=>` _block_
+
+A guard indicates that a `case` only matches if some predicate holds. The
+bindings in the pattern are in scope in the guard:
+
+```
+match (x) {
+ case (m: i32, n: i32) if m + n < 5 => { return m - n; }
+}
+```
+
+For consistency, this facility is also available for `default` clauses, so that
+`default` remains equivalent to `case _: auto`.
+
+### Refutability, overlap, usefulness, and exhaustiveness
+
+Some definitions:
+
+- A pattern _P_ is _useful_ in the context of a set of patterns _C_ if there
+ exists a value that _P_ can match that no pattern in _C_ matches.
+- A set of patterns _C_ is _exhaustive_ if it matches all possible values.
+ Equivalently, _C_ is exhaustive if the pattern `_: auto` is not useful in
+ the context of _C_.
+- A pattern _P_ is _refutable_ if there are values that it does not match,
+ that is, if the pattern `_: auto` is useful in the context of {_P_}.
+ Equivalently, the pattern _P_ is _refutable_ if the set of patterns {_P_} is
+ not exhaustive.
+- A set of patterns _C_ is _overlapping_ if there exists any value that is
+ matched by more than one pattern in _C_.
+
+For the purpose of these terms, expression patterns that match a constant tuple,
+struct, or choice value are treated as if they were tuple, struct, or
+alternative patterns, respectively, and `bool` is treated like a choice type.
+Any expression patterns that remain after applying this rule are considered to
+match a single value from an infinite set of values so that a set of expression
+patterns is never exhaustive:
+
+```
+fn IsEven(n: u8) -> bool {
+ // Not considered exhaustive.
+ match (n) {
+ case 0 => { return true; }
+ case 1 => { return false; }
+ ...
+ case 255 => { return false; }
+ }
+ // Code here is considered to be reachable.
+}
+```
+
+```
+fn IsTrue(b: bool) -> bool {
+ // Considered exhaustive.
+ match (b) {
+ case false => { return false; }
+ case true => { return true; }
+ }
+ // Code here is considered to be unreachable.
+}
+```
+
+When determining whether a pattern is useful, no attempt is made to determine
+the value of any guards, and instead a worst-case assumption is made: a guard on
+that pattern is assumed to evaluate to true and a guard on any pattern in the
+context set is assumed to evaluate to false.
+
+We will diagnose the following situations:
+
+- A pattern is not useful in the context of prior patterns. In a `match`
+ statement, this happens if a pattern or `default` cannot match because all
+ cases it could cover are handled by prior cases or a prior `default`. For
+ example:
+
+ ```
+ choice Optional(T:! Type) {
+ None,
+ Some(T)
+ }
+ fn F(a: Optional(i32), b: Optional(i32)) {
+ match ((a, b)) {
+ case (.Some(a: i32), _: auto) => {}
+ // ✅ OK, but only matches values of the form `(None, Some)`,
+ // because `(Some, Some)` is matched by the previous pattern.
+ case (_: auto, .Some(b: i32)) => {}
+ // ✅ OK, matches all remaining values.
+ case (.None, .None) => {}
+ // ❌ Error, this pattern never matches.
+ case (_: auto, _: auto) => {}
+ }
+ }
+ ```
+
+- A pattern match is not exhaustive and the program doesn't explicitly say
+ what to do when no pattern matches. For example:
+
+ - If the patterns in a `match` are not exhaustive and no `default` is
+ provided.
+
+ ```
+ fn F(n: i32) -> i32 {
+ // ❌ Error, this `match` is not exhaustive.
+ match (n) {
+ case 0 => { return 2; }
+ case 1 => { return 3; }
+ case 2 => { return 5; }
+ case 3 => { return 7; }
+ case 4 => { return 11; }
+ }
+ }
+ ```
+
+ - If a refutable pattern appears in a context where only one pattern can
+ be specified, such as a `let` or `var` declaration, and there is no
+ fallback behavior. This currently includes all pattern matching contexts
+ other than `match` statements, but the `var`/`let`-`else` feature in
+ [#1871](https://github.com/carbon-language/carbon-lang/pull/1871) would
+ introduce a second context permitting refutable matches, and overloaded
+ functions might introduce a third context.
+
+ ```
+ fn F(n: i32) {
+ // ❌ Error, refutable expression pattern `5` used in context
+ // requiring an irrefutable pattern.
+ var 5 = n;
+ }
+ // ❌ Error, refutable expression pattern `5` used in context
+ // requiring an irrefutable pattern.
+ fn G(n: i32, 5);
+ ```
+
+- When a set of patterns have no ordering or tie-breaker, it is an error for
+ them to overlap unless there is a unique best match for any value that
+ matches more than one pattern. However, this situation does not apply to any
+ current language rule:
+
+ - For `match` statements, patterns are matched top-down, so overlap is
+ permitted.
+ - We do not yet have an approved design for overloaded functions, but it
+ is anticipated that declaration order will be used in that case too.
+ - For a set of `impl`s that match a given `impl` lookup, argument
+ deduction is used rather than pattern matching, but `impl`s with the
+ same type structure are an error unless a `match_first` declaration is
+ used to order the `impl`s. (This is a pre-existing rule and is unchanged
+ by this proposal.)
+
+## Rationale
+
+- [Software and language evolution](/docs/project/goals.md#software-and-language-evolution)
+ - The `, _` syntax for struct patterns enables a style where adding a
+ struct member is not a breaking change.
+ - The requirement that matches be exhaustive makes it easier to add new
+ cases to a choice type, by requiring the compiler to detect places where
+ the new value is not handled.
+- [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)
+ - Pattern syntax makes it easier to match complex values.
+ - Modeling pattern syntax after expressions eases the burden of learning a
+ new sub-language for pattern-matching: patterns are an extension of
+ expressions, and expressions are a special case of patterns.
+ - Requiring exhaustiveness for matches makes control flow easier to
+ understand as there is never a value for which the `match` skips all
+ cases.
+- [Interoperability with and migration from existing C++ code](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code)
+ - The rules for matching a templated value can be used to replace
+ `if constexpr` in many cases.
+
+## Alternatives considered
+
+### Shorthand for `auto`
+
+We could provide a shorter syntax for `name: auto`.
+[Proposal #851](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p0851.md#elide-the-type-instead-of-using-auto)
+considered the following shorthands and decided against using them:
+
+```
+var n: _ = init;
+var n = init;
+```
+
+A novel suggestion that avoids some of the disadvantages of those syntaxes would
+be to use:
+
+```
+var n:= init;
+```
+
+Advantages:
+
+- Shorter syntax for variables with a deduced type.
+- Potentially allows removal of the `auto` keyword.
+
+Disadvantages:
+
+- Appears to introduce a `:=` syntax, but that only arises in cases where an
+ initializer immediately follows the name.
+ - Cases such as `var (a:, b:) = my_pair;` would either be invalid or would
+ not use the `:=` syntax.
+ - If we accept such cases, there is a risk of grammar ambiguities.
+ - If we reject such cases, we may still want to keep `auto` around for
+ them, creating inconsistency.
+- Not a complete replacement for `auto` if we want to also allow things like
+ `v: Vector(auto)`. C++ doesn't allow the equivalent syntax currently, but it
+ was part of the Concepts TS and seems likely to return at some point.
+- No syntactic difference between accidentally omitting a type entirely and
+ requesting type deduction. However, the mistake of omitting a type but
+ retaining the `:` seems unlikely, and the `:` followed by the absence of a
+ type is a signal that something is happening, so this seems to be less of a
+ concern than for the `var n = init;` syntax.
+
+See discussion topics
+[1](https://github.com/carbon-language/carbon-lang/discussions/1495) and
+[2](https://github.com/carbon-language/carbon-lang/discussions/1988).
+
+### Struct pattern syntax
+
+We could omit the `, _` syntax. This would simplify struct patterns, but at the
+cost of removing a feature that can be useful for reducing verbosity and making
+library evolution easier.
+
+We could always allow a struct pattern to match a struct with more fields,
+without requiring a `, _` suffix. This would aid evolution by reducing the cases
+where adding a field to a struct can be a breaking change, but such cases would
+still exist. Further, this would make matches against a struct-valued expression
+inconsistent with matches against a struct pattern.
+
+We could use a different syntax instead of `, _`. Other options that were
+explicitly considered:
+
+- `, ...` seems visually evocative of "and more stuff", but risks conflicting
+ with variadic syntax or at least being confusing when used in a variadic
+ context, given that variadics are expected to claim `...` for pack
+ expansion.
+- `, ._` suggests matching a field without specifying a name, but might create
+ an impression of matching just one field, and three low punctuation
+ characters in a row seems to be pushing the limits of readability.
+
+On balance, `, _` harmonizes well with the use of `_` to introduce a wildcard,
+without being too visually confusing given that the other use of `_` has a
+following `:`.
+
+We could remove the `{field: type}` shorthand and require
+`{.field = field: type}`. This may avoid encouraging reusing the field name even
+when it is not appropriate, and would remove some syntactic sugar that's not
+formally necessary. However, we expect this to be a common case whose ergonomics
+are important.
+
+We could use a different syntax for `{field: type}` that is less divergent from
+other struct syntaxes:
+
+- `{.field: type}` seems like a contender, but doesn't work because that is
+ already recognized as a struct type literal. Also, the use of normal binding
+ syntax means that every locally-introduced name is always introduced by
+ `name: type` where `name` is not preceded by `.`.
+- `{.=field: type}` might be a reasonable mnemonic shorthand for
+ `{.field = field: type}`, but looks a little surprising. This is probably
+ the best choice if concerns are found with `{field: type}` syntax.
+
+### Type pattern matching
+
+We could treat type deduction as a form of pattern matching. For example, we
+could allow
+
+```
+fn F(a: Vector(T:! Type)) -> T { return a[0]; }
+fn G() -> i32 {
+ let v: Vector(i32) = (1, 2, 3);
+ // Deduces `T = i32`.
+ return F(v);
+}
+```
+
+where the value of `T` is determined by pattern-matching `Vector(T:! Type)`
+against the supplied type `Vector(i32)` of `v`. And symmetrically:
+
+```
+fn H[m: i32, n: i32](k: i32, (m, n)) { return m + n; }
+fn I() {
+ // Deduces `m = 2`, `n = 3`.
+ H(1, (2, 3));
+}
+```
+
+This would ensure consistency between pattern matching and deduction,
+potentially reducing the number of rules that Carbon developers need to learn.
+
+We find that use of pattern-matching in type position can harm readability. For
+example, the first of these two examples may be easier to read due to having
+less nesting:
+
+```
+fn F[T:! Type](x: T);
+fn F(x: (T:! Type));
+```
+
+Having distinct syntax for type-level matching and value-level matching helps
+guide the reader to the correct interpretation, even though the underlying
+matching process is expected to be similar or identical. As a result, we keep
+type deduction syntax and pattern matching syntax separate for now:
+
+- In pattern matching, bindings and wildcards are introduced by nested `:` /
+ `:!` patterns, and the right-hand side of a binding pattern is never a
+ proper pattern.
+- In type deduction, deduced values are specified separately and an expression
+ written in terms of those bindings describes the type.
+
+There are some contexts where there is no syntactic location for introducing
+deduced values, such as in `case` labels. For syntactic consistency, such cases
+should be addressed by adding `forall` syntax, if there is motivation to support
+deduction:
+
+```
+match (templated_value) {
+ case forall [template T:! Type] (p: T*) => { heap.Delete(p); }
+}
+```
+
+### Introducer syntax for expression patterns
+
+We could have some separate introducer syntax to distinguish expression patterns
+from other kinds of patterns:
+
+```
+match ((a, b)) {
+ case is (1, 2) => {}
+ case (is 3, n: i32) => {}
+ case (m: i32, is 4) => {}
+}
+```
+
+This would reduce the chance of confusion in cases where an expression and a
+similar-looking pattern are treated differently:
+
+```
+class TupleLike {
+ external impl as (i32, i32);
+}
+fn MatchTupleLike(t: TupleLike) {
+ match (t) {
+ // ✅ OK, expression pattern;
+ // `t` implicitly converted to `(i32, i32)` by
+ // built-in `impl EqWith` for tuples.
+ case (1, 2) => {}
+ // ❌ Error, `t` is not a tuple.
+ case (n: i32, 3) => {}
+ }
+}
+```
+
+This would also permit the same, or overlapping, syntax to be used in
+expressions and patterns with different meanings, for example:
+
+```
+fn F() {
+ // Here, `[...]` is an array type.
+ var array: [i32; 5];
+ match (&array) {
+ // Here, `[...]` could introduce deduced parameters.
+ case [T:! Type] x: T* => {}
+ }
+}
+```
+
+Similarly, if we added a `&PATT` pattern to match the address of a value, a
+construct like `&n` would be ambiguous without in introducer:
+
+```
+var n: i32 = 5;
+fn MatchPointerOrPointee(p: i32*) {
+ match (p) {
+ case is &n => {
+ Print("given pointer to n");
+ }
+ // Here, the pattern `&PATT` could match the address of
+ // a value that matches `PATT`.
+ case &(is n) => {
+ Print("given pointer to i32 whose value equals the value of n");
+ }
+ case &(m: i32) => {
+ Print("given pointer to value {0}", m);
+ }
+ }
+}
+```
+
+Such an introducer would also denote the portions of a pattern that are
+evaluated at runtime rather than at compile time, benefitting Carbon's goals of
+readability and of predictable performance, and would also add syntactic
+separation between the parts of a pattern that have full exhaustiveness checking
+and the parts that do not.
+
+However, this would also introduce additional ceremony for the common case where
+part of a pattern is a specific value. This could be mitigated by permitting
+certain kinds of value as patterns without an introducer, such as numeric
+literals and `true` and `false`, at the cost of introducing more complexity and
+more confusion over which cases require `is` and which do not.
+
+We have also not identified a good choice for the introducer syntax, should we
+pursue this direction. `is` is not an ideal choice, because elsewhere in Carbon
+syntax, it is a relation between a value and its type, so `is T` may be misread
+as matching values whose type is `T`. `==` _expression_ has been suggested, but
+that would imply the opposite operand order of that in this proposal --
+_scrutinee_ `==` _expression_ rather than _expression_ `==` _scrutinee_ -- which
+would compare struct fields in a surprising order that diverges from the order
+of comparison for a struct pattern. A prefix `==` may also be visually
+surprising.
+
+For now, we do not add such an introducer, but this decision is expected to be
+revisited by a future proposal.
+
+See:
+
+- [2022-09-16 Discord discussion in #syntax](https://discord.com/channels/655572317891461132/709488742942900284/1020559500597538886)
+- [2022-12-05 open discussion](https://docs.google.com/document/d/1tEt4iM6vfcY0O0DG0uOEMIbaXcZXlNREc2ChNiEtn_w/edit#bookmark=id.utvzosvvfg80)
+
+### Allow guards on arbitrary patterns
+
+We could treat guards as part of pattern syntax instead of as part of `case`
+syntax. However, since guards make a pattern refutable, this wouldn't allow them
+anywhere other than in `case`s in the current language design. It would allow
+them to be nested within cases:
+
+```
+match (x) {
+ case (n: i32 if n > 5, "some string") => { ... }
+}
+```
+
+Such nesting might allow an expensive later check to be avoided. For example, in
+the above case we can avoid an `==` comparison on a string if a cheaper
+comparison of `n > 5` fails. However, this would introduce complexity into the
+grammar, and it's not clear that this feature would add sufficient value to
+justify that complexity.
+
+An additional concern is that if we add `let`...`else` syntax, this would
+presumably permit things like:
+
+```
+let n: i32 if n > 5 = 20 else { return 0; };
+```
+
+... where it would be easy to misparse the `if ... else` as being a single
+construct, where the intended parse would be:
+
+```
+let ((n: i32) if n > 5) = 20 else { return 0; };
+```
+
+See also a
+[related Discord discussion](https://discord.com/channels/655572317891461132/748959784815951963/981691016040030279).
+
+### Treat expression patterns as exhaustive if they cover all possible values
+
+We could do more work to treat a set of expression patterns as being exhaustive,
+if each pattern has a constant value and between those constant values, all
+possible values of the type are covered. The advantage of this would be that we
+improve the precision of our language rules.
+
+This change in rules has some disadvantages and problems:
+
+- It would add some complexity to the rules and to implementations in order to
+ track whether all possible values have been created.
+- For even the simplest types where this would apply, such as `i8`, it seems
+ unlikely that a `match` covering all possible values would be written, due
+ to the large number of patterns required.
+- In many cases, the value being matched will carry an invariant so that
+ matching a subset of the representable values would match all meaningful
+ values. We would still have imprecise rules in those cases.
+- Expression patterns are matched with `==`, and for an arbitrary `==` it is
+ not computable in general to tell whether a given set of values is
+ exhaustive, so we would only be able to apply this in some subset of cases.
+
+This restriction is straightforward to work around by adding a final unreachable
+`default`, or by replacing the final value match with a `default` or `_`.
+
+### Allow non-exhaustive `match` statements
+
+We could permit `match` statements that are not exhaustive, and execute none of
+the case blocks if none of the patterns match. This is a very common choice in
+the design of such language features. However, it is also a common source of
+errors, for example when matching a sum type and an alternative is missed. By
+making this a language rule, we ensure that developers can rely on such mistakes
+being caught.
+
+There is an easy syntactic way to disable this check, by adding an explicit
+`default => {}` case. If we made the opposite choice, we would not automatically
+have an easy way to request that the check be performed. We could add syntax to
+request it, but such syntax would likely be forgotten and the default behavior
+would be that errors are silently permitted. This seems sufficient to outweigh
+the potential ergonomic cost of requiring the `default => {}` case to be written
+explicitly.
+
+Another motivation for requiring exhaustiveness is that it simplifies other
+language rules. For example, when determining whether control flow can reach the
+end of a function with a declared return type, a separate exhaustiveness
+analysis is not necesasry.
+
+One concern with exhaustiveness checking is that it will cause the addition of
+an alternative to a choice type to be a breaking change by default. However,
+this is also one of the main advantages, and the design of choice types is
+intended to eventually provide a mechanism to specify that a choice type is
+extensible, which if used would mean that a set of patterns for that choice type
+would only be considered exhaustive if it includes a wildcard pattern.
+
+## Future work
+
+### Or patterns
+
+We could provide "or patterns", allowing matching of one pattern or another with
+the same handler:
+
+```
+match (x) {
+ case (m: i32, 0) | (0, m: i32) => { return m; }
+}
+```
+
+See the
+[red-black tree rebalancing example](#example-from-p1371r5-red-black-tree-rebalancing)
+for a real-world example where this would result in a simplification.
+
+### As patterns
+
+We could provide
+["as-patterns"](https://en.wikibooks.org/wiki/Haskell/Pattern_matching#As-patterns)
+as a convenient way to give a name to a value while still matching parts of that
+value. Following Haskell, we could use:
+
+- _pattern_ ::= _identifier_ `@` _pattern_
+
+For example:
+
+```
+match (x) {
+ // `s` names the first element of the tuple.
+ case (s@{.a = n: i32, .b = 12}, 4) if n > 1 => { return s; }
+}
+```
+
+### Matching classes by dynamic type
+
+We could provide a way to match polymorphic class objects based on their dynamic
+type. This might be the default when matching a polymorphic class, or might
+require opt-in. The behavior in this proposal is that only the static type of
+the operand is considered.
+
+For example, we could default to matching the static type, and allow a `dyn`
+_pattern_ syntax for matching a pointer to a polymorphic class type, meaning
+that we match the dynamic type rather than the static type of the pointer:
+
+```
+abstract class Base { virtual fn F[me: Self](); }
+class Derived1 extends Base {}
+class Derived2 extends Base {}
+
+fn PrintType(b: Base*) {
+ match (b) {
+ // `case d1: Derived*` would be invalid here,
+ // because it could never match.
+ case dyn d1: Derived1* => { Print("Derived1"); }
+ case dyn d2: Derived2* => { Print("Derived2"); }
+ default => { Print("Unknown derived class"); }
+ }
+}
+
+fn PrintTemplateType[template T:! Type](p: T*) {
+ match (p) {
+ // OK, dispatch is based on the static type.
+ case b: Base* => { Print("Base"); }
+ case d1: Derived1* => { Print("Derived1"); }
+ case d2: Derived2* => { Print("Derived2"); }
+ default => { Print("Unknown class"); }
+ }
+}
+```
+
+However, at this time we do not have a design for a checked down-cast, so it's
+not clear how this matching operation would fit into the design of classes,
+either syntactically or semantically.
+
+### User-defined pattern matching
+
+We plan to provide a mechanism for allowing a user-defined type to specify how
+it can be matched by patterns. See [proposal #157](/proposals/p0157.md) for
+details.
+
+### Matching classes with struct patterns
+
+We could allow a class to be matched by a struct pattern that matches its
+fields. This would make sense especially for data classes, and would be
+consistent with the behavior of `==` in the case where a struct is implicitly
+convertible to the class type. However, without a design for user-defined
+pattern matching and matching on dynamic type, there is a significant risk that
+this would conflict with the rules there, so it is deferred for now.
+
+### Matching by reference
+
+When the scrutinee is an lvalue, it is sometimes desirable to form a mutable
+binding to it. For example, see the
+[`struct` inspection example](#figure-5-struct-inspection) below. We currently
+support this only for the `me` binding in a method, using the `addr` keyword,
+but could allow this more generally.
+
+```carbon
+fn takeDamage(p: player*) {
+ match (*p) {
+ case {.hitpoints = 0, .lives = 0, _} => { gameOver(); }
+ case {.hitpoints = addr hp: i32*, .lives = addr l: i32*, _} if *hp == 0 => {
+ *hp = 10;
+ --*l;
+ }
+ case {.hitpoints = addr hp: i32*, _} if *hp <= 3 => {
+ --*hp;
+ messageAlmostDead();
+ }
+ case {.hitpoints = addr hp: i32*, _} => {
+ --*hp;
+ }
+ }
+}
+```
+
+Work in this area will need to consider whether we can provide this feature
+ergonomically without introducing reference-like behavior.
+
+### Type deduction
+
+This proposal does not cover type deduction, instead considering it to be a
+separate topic from pattern matching syntax, even though the semantic behavior
+of the two may be quite similar or identical.
+
+We will need a proposal to explore type deduction and describe its functioning.
+
+### Match expressions
+
+As demonstrated in the [switching an enum](#figure-3-switching-an-enum) example
+below, it would be valuable to have an expression `match` syntax in addition to
+the statement `match` syntax. We could follow the same approach as for `if`
+statements, and say that a `match` that appears at the start of a statement is a
+statement `match` and any other `match` is an expression `match`.
+
+As candidate syntax, braced `case` bodies could be replaced by an expression
+followed by a comma. For example:
+
+```
+let opengl_color: Vec3 = match (c) {
+ case .red => Vec3.Make(1.0, 0.0, 0.0),
+ case .yellow => Vec3.Make(1.0, 1.0, 0.0),
+ case .green => Vec3.Make(0.0, 1.0, 0.0),
+ case .blue => Vec3.Make(0.0, 0.0, 1.0)
+};
+```
+
+## Examples
+
+These examples are translations of examples in WG21 paper
+[P0095R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0095r1.html)
+and
+[P1371R3](https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2020/p1371r3.pdf),
+with permission from the author of those examples, David Sankel. Thank you,
+David!
+
+### Examples from P0095R1
+
+#### Figure 1. Declaration of a command data structure
+
+
+| C++ | P0095R1 | This proposal |
+|
+
+```c++
+struct set_score {
+ std::size_t value;
+};
+
+struct fire_missile {};
+
+struct fire_laser {
+ unsigned intensity;
+};
+
+struct rotate {
+ double amount;
+};
+
+struct command {
+ std::variant<
+ set_score,
+ fire_missile,
+ fire_laser,
+ rotate > value;
+};
+```
+
+ |
+
+```c++
+lvariant command {
+ std::size_t set_score;
+ std::monostate fire_missile;
+ unsigned fire_laser;
+ double rotate;
+};
+```
+
+ |
+
+```carbon
+choice command {
+ set_score(u64),
+ fire_missile,
+ fire_laser(u32),
+ rotate(f64)
+}
+```
+
+ |
+
+
+#### Figure 2. Implementation of an output operator
+
+
+| C++ | P0095R1 | This proposal |
+|
+
+```c++
+namespace {
+struct Output {
+ std::ostream& operator()(std::ostream& stream, const set_score& ss) const {
+ return stream << "Set the score to " << ss.value << ".\n";
+ }
+ std::ostream& operator()(std::ostream& stream, const fire_missile&) const {
+ return stream << "Fire a missile.\n";
+ }
+ std::ostream& operator()(std::ostream& stream, const fire_laser& fl) const {
+ return stream << "Fire a laser with " << fl.intensity << " intensity.\n";
+ }
+ std::ostream& operator()(std::ostream& stream, const rotate& r) const {
+ return stream << "Rotate by " << r.degrees << " degrees.\n"
+ }
+};
+}
+
+std::ostream& operator<<(std::ostream& stream, const command& cmd) {
+ return std::visit(std::bind(Output(), std::ref(stream), std::placeholders::_1),
+ cmd.value);
+}
+```
+
+ |
+
+```c++
+std::ostream& operator<<(std::ostream& stream, const command& cmd) {
+ return inspect(cmd) {
+ set_score value =>
+ stream << "Set the score to " << value << ".\n"
+ fire_missile _ =>
+ stream << "Fire a missile.\n"
+ fire_laser intensity =>
+ stream << "Fire a laser with " << intensity << " intensity.\n"
+ rotate degrees =>
+ stream << "Rotate by " << degrees << " degrees.\n"
+ }
+}
+```
+
+ |
+
+```carbon
+impl command as Printable {
+ fn Print[me: Self](stream: Cpp.std.ostream*) {
+ match (me) {
+ case .set_score(value: u64) => {
+ stream->Print("Set the score to {0}.\n", value);
+ }
+ case .fire_missile => {
+ stream->Print("Fire a missile.\n");
+ }
+ case .fire_laser(intensity: u32) => {
+ stream->Print("Fire a laser with {0} intensity.\n", intensity);
+ }
+ case .rotate(degrees: f64) => {
+ stream->Print("Rotate by {0} degrees.\n", degrees);
+ }
+ }
+ }
+}
+```
+
+ |
+
+
+#### Figure 3. Switching an enum
+
+
+| C++ | P0095R1 | This proposal |
+|
+
+```c++
+enum color { red, yellow, green, blue };
+```
+
+ |
+
+```carbon
+choice color { red, yellow, green, blue }
+```
+
+ |
+|
+
+```c++
+const Vec3 opengl_color = [&c] {
+ switch(c) {
+ case red:
+ return Vec3(1.0, 0.0, 0.0);
+ break;
+ case yellow:
+ return Vec3(1.0, 1.0, 0.0);
+ break;
+ case green:
+ return Vec3(0.0, 1.0, 0.0);
+ break;
+ case blue:
+ return Vec3(0.0, 0.0, 1.0);
+ break;
+ default:
+ std::abort();
+ }();
+```
+
+ |
+
+```c++
+const Vec3 opengl_color =
+ inspect(c) {
+ red => Vec3(1.0, 0.0, 0.0)
+ yellow => Vec3(1.0, 1.0, 0.0)
+ green => Vec3(0.0, 1.0, 0.0)
+ blue => Vec3(0.0, 0.0, 1.0)
+ };
+```
+
+ |
+
+```carbon
+// Carbon has neither expression-match nor lambdas yet,
+// so this can't easily be done in line.
+fn GetOpenGLColor(c: color) -> Vec3 {
+ match (c) {
+ case .red => { return Vec3.Make(1.0, 0.0, 0.0); }
+ case .yellow => { return Vec3.Make(1.0, 1.0, 0.0); }
+ case .green => { return Vec3.Make(0.0, 1.0, 0.0); }
+ case .blue => { return Vec3.Make(0.0, 0.0, 1.0); }
+ }
+}
+let opengl_color: Vec3 = GetOpenGLColor(c);
+```
+
+ |
+
+
+#### Figure 4. Expression datatype
+
+
+| C++ | P0095R1 | This proposal |
+|
+
+```c++
+struct expression;
+
+struct sum_expression {
+ std::unique_ptr left_hand_side;
+ std::unique_ptr right_hand_side;
+};
+
+struct expression {
+ std::variant value;
+};
+
+expression simplify(const expression & exp) {
+ if(sum_expression const * const sum = std::get_if(&exp)) {
+ if( int const * const lhsInt = std::get_if( sum->left_hand_side.get() )
+ && *lhsInt == 0 ) {
+ return simplify(*sum->right_hand_side);
+ }
+ else if( int const * const rhsInt = std::get_if( sum->right_hand_side.get() )
+ && *rhsInt == 0 ) {
+ return simplify(*sum->left_hand_side);
+ } else {
+ return {sum_expression{
+ std::make_unique(simplify(*sum->left_hand_side)),
+ std::make_unique(simplify(*sum->right_hand_side))}}
+ }
+ }
+ return exp;
+}
+
+void simplify2(expression & exp) {
+ if(sum_expression * const sum = std::get_if(&exp)) {
+ if( int * const lhsInt = std::get_if( sum->left_hand_side.get() )
+ && *lhsInt == 0 ) {
+ expression tmp(std::move(*sum->right_hand_side));
+ exp = std::move(tmp);
+ simplify(exp);
+ }
+ else if( int * const rhsInt = std::get_if( sum->right_hand_side.get() )
+ && *rhsInt == 0 ) {
+ expression tmp(std::move(*sum->left_hand_side));
+ exp = std::move(tmp);
+ simplify(exp);
+ } else {
+ simplify(*sum->left_hand_side);
+ simplify(*sum->right_hand_side);
+ }
+ }
+ return exp;
+}
+```
+
+ |
+
+```c++
+lvariant expression;
+
+struct sum_expression {
+ std::unique_ptr left_hand_side;
+ std::unique_ptr right_hand_side;
+};
+
+lvariant expression {
+ sum_expression sum;
+ int literal;
+ std::string var;
+};
+
+expression simplify(const expression & exp) {
+ return inspect(exp) {
+ sum {*(literal 0), *rhs} => simplify(rhs)
+ sum {*lhs , *(literal 0)} => simplify(lhs)
+ sum {*lhs , *rhs}
+ => expression::sum{
+ std::make_unique(simplify(lhs)),
+ std::make_unique(simplify(rhs))};
+ _ => exp
+ };
+}
+
+void simplify2(expression & exp) {
+ inspect(exp) {
+ sum {*(literal 0), *rhs} => {
+ expression tmp(std::move(rhs));
+ exp = std::move(tmp);
+ simplify2(exp);
+ }
+ sum {*lhs , *(literal 0)} => {
+ expression tmp(std::move(lhs));
+ exp = std::move(tmp);
+ simplify2(exp);
+ }
+ sum {*lhs , *rhs} => {
+ simplify2(lhs);
+ simplify2(rhs);
+ }
+ _ => ;
+ };
+}
+```
+
+ |
+
+```carbon
+choice expression {
+ sum(UniquePtr(expression), UniquePtr(expression)),
+ literal(i32),
+ var: String
+}
+
+// This assumes that UniquePtr provides the matching
+// functionality described in #2187.
+fn simplify(exp: expression) -> expression {
+ match (exp) {
+ case .sum(.PtrTo(.literal(0)), .PtrTo(rhs: expression)) => {
+ return simplify(rhs);
+ }
+ case .sum(.PtrTo(lhs: expression), .PtrTo(.literal(0))) => {
+ return simplify(lhs);
+ }
+ case .sum(.PtrTo(lhs: expression), .PtrTo(rhs: expression)) => {
+ return expression.sum(MakeUnique(simplify(lhs)),
+ MakeUnique(simplify(rhs)));
+ }
+ default => { return exp; }
+ }
+}
+```
+
+ |
+
+
+#### Figure 5. `struct` inspection
+
+
+| C++ | P0095R1 | This proposal |
+|
+
+```c++
+struct player {
+ std::string name;
+ int hitpoints;
+ int lives;
+};
+```
+
+ |
+
+```carbon
+class player {
+ var name: String;
+ var hitpoints: i32;
+ var lives: i32;
+}
+```
+
+ |
+|
+
+```c++
+void takeDamage(player &p) {
+ if(p.hitpoints == 0 && p.lives == 0)
+ gameOver();
+ else if(p.hitpoints == 0) {
+ p.hitpoints = 10;
+ p.lives--;
+ }
+ else if(p.hitpoints <= 3) {
+ p.hitpoints--;
+ messageAlmostDead();
+ }
+ else {
+ p.hitpoints--;
+ }
+}
+```
+
+ |
+
+```c++
+void takeDamage(player &p) {
+ inspect(p) {
+ {hitpoints: 0, lives:0} => gameOver();
+ {hitpoints:hp@0, lives:l} => hp=10, l--;
+ {hitpoints:hp} if (hp <= 3) => { hp--; messageAlmostDead(); }
+ {hitpoints:hp} => hp--;
+ }
+}
+```
+
+ |
+
+```carbon
+fn takeDamage(p: player*) {
+ match (*p) {
+ case {.hitpoints = 0, .lives = 0, _} => { gameOver(); }
+ case {.hitpoints = 0, _} => { p->hitpoints = 10; --p->lives; }
+ case {.hitpoints = hp: i32, _} if hp <= 3 => {
+ --p->hitpoints;
+ messageAlmostDead();
+ }
+ default => { --p->hitpoints; }
+ }
+}
+```
+
+ |
+
+
+### Example from P1371R5: Red-black tree rebalancing
+
+#### With P1371R5 pattern matching
+
+```c++
+enum Color { Red, Black };
+
+template
+struct Node {
+ void balance();
+
+ Color color;
+ std::shared_ptr lhs;
+ T value;
+ std::shared_ptr rhs;
+};
+
+template
+void Node::balance() {
+ *this = inspect (*this) {
+ [case Black, (*?) [case Red, (*?) [case Red, a, x, b], y, c], z, d]
+ => Node{Red, std::make_shared(Black, a, x, b),
+ y,
+ std::make_shared(Black, c, z, d)};
+ [case Black, (*?) [case Red, a, x, (*?) [case Red, b, y, c]], z, d] // left-right case
+ => Node{Red, std::make_shared(Black, a, x, b),
+ y,
+ std::make_shared(Black, c, z, d)};
+ [case Black, a, x, (*?) [case Red, (*?) [case Red, b, y, c], z, d]] // right-left case
+ => Node{Red, std::make_shared(Black, a, x, b),
+ y,
+ std::make_shared(Black, c, z, d)};
+ [case Black, a, x, (*?) [case Red, b, y, (*?) [case Red, c, z, d]]] // right-right case
+ => Node{Red, std::make_shared(Black, a, x, b),
+ y,
+ std::make_shared(Black, c, z, d)};
+ self => self;
+ };
+}
+```
+
+#### With this proposal
+
+```carbon
+choice Color { Red, Black }
+
+class Node(T:! Type) {
+ fn balance[addr me: Self*]();
+
+ var color: Color;
+ var lhs: SharedPtr(Node);
+ var value: T;
+ var rhs: SharedPtr(Node);
+}
+
+fn MakeBalanced[T:! Type](a: SharedPtr(Node(T)), x: T,
+ b: SharedPtr(Node(T)), y: T,
+ c: SharedPtr(Node(T)), z: T,
+ d: SharedPtr(Node(T))) -> Node(T) {
+ return {.color = Color.Red,
+ .lhs = MakeShared({.color = Color.Black, .lhs = a, .value = x, .rhs = b}),
+ .value = y,
+ .rhs = MakeShared({.color = Color.Black, .lhs = c, .value = z, .rhs = d})};
+}
+
+fn Node(T:! Type).balance[addr me: Self*]() {
+ match (*me) {
+ {.color = .Black, .lhs = .PtrTo(
+ {.color = .Red, .lhs = .PtrTo(
+ {.color = .Red, .lhs = a: auto, .value = x: T, .rhs = b: auto}),
+ .value = y: T, .rhs = c: auto}),
+ .value = z: T, .rhs = d: auto} => {
+ *me = MakeBalanced(a, x, b, y, c, z, d);
+ }
+ {.color = .Black, .lhs = .PtrTo(
+ {.color = .Red, .lhs = a: auto, .value = x: T, .rhs = .PtrTo(
+ {.color = .Red, .lhs = b: auto, .value = y: T, .rhs = c: auto})}),
+ .value = z: T, .rhs = d: auto} => {
+ *me = MakeBalanced(a, x, b, y, c, z, d);
+ }
+ {.color = .Black, .lhs = a: auto, .value = x: T, .rhs = .PtrTo(
+ {.color = .Red, .lhs = .PtrTo(
+ {.color = .Red, .lhs = b: auto, .value = y: T, .rhs = c: auto}),
+ .value = z: T, .rhs = d: auto})} => {
+ *me = MakeBalanced(a, x, b, y, c, z, d);
+ }
+ {.color = .Black, .lhs = a: auto, .value = x: T, .rhs = .PtrTo(
+ {.color = .Red, .lhs = b: auto, .value = y: T, .rhs = .PtrTo(
+ {.color = .Red, .lhs = c: auto, .value = z: T, .rhs = d: auto})})} => {
+ *me = MakeBalanced(a, x, b, y, c, z, d);
+ }
+ default => {}
+ };
+}
+```
+
+#### With this proposal plus #2187
+
+```carbon
+choice Color { Red, Black }
+
+class Node(T:! Type) {
+ fn balance[addr me: Self*]();
+
+ var color: Color;
+ var lhs: SharedPtr(Self);
+ var value: T;
+ var rhs: SharedPtr(Self);
+
+ external impl as Match {
+ interface Continuation {
+ extends Match.BaseContinuation;
+ fn Red[addr me: Self*](lhs: SharedPtr(Self), value: T, rhs: SharedPtr(Self)) -> ReturnType;
+ fn Black[addr me: Self*](lhs: SharedPtr(Self), value: T, rhs: SharedPtr(Self)) -> ReturnType;
+ }
+ fn Op[me: Self, C:! Continuation](continuation: C*) -> C.ReturnType {
+ match (me.color) {
+ case .Red => { return continuation->Red(me.lhs, me.value, me.rhs); }
+ case .Black => { return continuation->Black(me.lhs, me.value, me.rhs); }
+ }
+ }
+ }
+}
+
+fn MakeBalanced[T:! Type](a: SharedPtr(Node(T)), x: T,
+ b: SharedPtr(Node(T)), y: T,
+ c: SharedPtr(Node(T)), z: T,
+ d: SharedPtr(Node(T))) -> Node(T) {
+ return {.color = Color.Red,
+ .lhs = MakeShared({.color = Color.Black, .lhs = a, .value = x, .rhs = b}),
+ .value = y,
+ .rhs = MakeShared({.color = Color.Black, .lhs = c, .value = z, .rhs = d})};
+}
+
+fn Node(T:! Type).balance[addr me: Self*]() {
+ match (*me) {
+ .Black(.PtrTo(.Red(.PtrTo(.Red(a: auto, x: T, b: auto)), y: T, c: auto)), z: T, d: auto) => {
+ *me = MakeBalanced(a, x, b, y, c, z, d);
+ }
+ .Black(.PtrTo(.Red(a: auto, x: T, .PtrTo(.Red(b: auto, y: T, c: auto)))), z: T, d: auto) => {
+ *me = MakeBalanced(a, x, b, y, c, z, d);
+ }
+ .Black(a: auto, x: T, .PtrTo(.Red(.PtrTo(.Red(b: auto, y: T, c: auto)), z: T, d: auto))) => {
+ *me = MakeBalanced(a, x, b, y, c, z, d);
+ }
+ .Black(a: auto, x: T, .PtrTo(.Red(b: auto, y: T, .PtrTo(.Red(c: auto, z: T, d: auto))))) => {
+ *me = MakeBalanced(a, x, b, y, c, z, d);
+ }
+ default => {}
+ };
+}
+```