diff --git a/src/expressions/closure-expr.md b/src/expressions/closure-expr.md
index 217a6a19c..6fbbd4c4c 100644
--- a/src/expressions/closure-expr.md
+++ b/src/expressions/closure-expr.md
@@ -10,7 +10,7 @@
> _ClosureParam_ (`,` _ClosureParam_)\* `,`?
>
> _ClosureParam_ :\
-> [_OuterAttribute_]\* [_Pattern_] ( `:` [_Type_] )?
+> [_OuterAttribute_]\* [_PatternNoTopAlt_] ( `:` [_Type_] )?
A _closure expression_, also know as a lambda expression or a lambda, defines a
closure and denotes it as a value, in a single expression. A closure expression
@@ -80,7 +80,7 @@ Attributes on closure parameters follow the same rules and restrictions as
[_Expression_]: ../expressions.md
[_BlockExpression_]: block-expr.md
[_TypeNoBounds_]: ../types.md#type-expressions
-[_Pattern_]: ../patterns.md
+[_PatternNoTopAlt_]: ../patterns.md
[_Type_]: ../types.md#type-expressions
[`let` binding]: ../statements.md#let-statements
[_OuterAttribute_]: ../attributes.md
diff --git a/src/expressions/if-expr.md b/src/expressions/if-expr.md
index 5d04bb5c7..a00c823a8 100644
--- a/src/expressions/if-expr.md
+++ b/src/expressions/if-expr.md
@@ -44,7 +44,7 @@ assert_eq!(y, "Bigger");
> **Syntax**\
> _IfLetExpression_ :\
-> `if` `let` [_MatchArmPatterns_] `=` [_Expression_]_except struct or lazy boolean operator expression_
+> `if` `let` [_Pattern_] `=` [_Expression_]_except struct or lazy boolean operator expression_
> [_BlockExpression_]\
> (`else` (
> [_BlockExpression_]
@@ -155,7 +155,7 @@ if let PAT = ( EXPR || EXPR ) { .. }
[_BlockExpression_]: block-expr.md
[_Expression_]: ../expressions.md
[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
-[_MatchArmPatterns_]: match-expr.md
+[_Pattern_]: ../patterns.md
[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
[`match` expression]: match-expr.md
[scrutinee]: ../glossary.md#scrutinee
diff --git a/src/expressions/loop-expr.md b/src/expressions/loop-expr.md
index 9ddefa12f..40cb90a9d 100644
--- a/src/expressions/loop-expr.md
+++ b/src/expressions/loop-expr.md
@@ -67,7 +67,7 @@ while i < 10 {
> **Syntax**\
> [_PredicatePatternLoopExpression_] :\
-> `while` `let` [_MatchArmPatterns_] `=` [_Expression_]_except struct or lazy boolean operator expression_
+> `while` `let` [_Pattern_] `=` [_Expression_]_except struct or lazy boolean operator expression_
> [_BlockExpression_]
A `while let` loop is semantically similar to a `while` loop but in place of a
@@ -291,7 +291,6 @@ expression `()`.
[LIFETIME_OR_LABEL]: ../tokens.md#lifetimes-and-loop-labels
[_BlockExpression_]: block-expr.md
[_Expression_]: ../expressions.md
-[_MatchArmPatterns_]: match-expr.md
[_Pattern_]: ../patterns.md
[`match` expression]: match-expr.md
[scrutinee]: ../glossary.md#scrutinee
diff --git a/src/expressions/match-expr.md b/src/expressions/match-expr.md
index 6d9f3f2af..9716d8bda 100644
--- a/src/expressions/match-expr.md
+++ b/src/expressions/match-expr.md
@@ -15,10 +15,7 @@
> _MatchArm_ `=>` [_Expression_] `,`?
>
> _MatchArm_ :\
-> [_OuterAttribute_]\* _MatchArmPatterns_ _MatchArmGuard_?
->
-> _MatchArmPatterns_ :\
-> `|`? [_Pattern_] ( `|` [_Pattern_] )\*
+> [_OuterAttribute_]\* [_Pattern_] _MatchArmGuard_?
>
> _MatchArmGuard_ :\
> `if` [_Expression_]
diff --git a/src/items/functions.md b/src/items/functions.md
index b6bd15904..9d6ebcde3 100644
--- a/src/items/functions.md
+++ b/src/items/functions.md
@@ -32,7 +32,7 @@
> )
>
> _FunctionParamPattern_ :\
-> [_Pattern_] `:` ( [_Type_] | `...` )
+> [_PatternNoTopAlt_] `:` ( [_Type_] | `...` )
>
> _FunctionReturnType_ :\
> `->` [_Type_]
@@ -378,7 +378,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) {
[_BlockExpression_]: ../expressions/block-expr.md
[_GenericParams_]: generics.md
[_Lifetime_]: ../trait-bounds.md
-[_Pattern_]: ../patterns.md
+[_PatternNoTopAlt_]: ../patterns.md
[_Type_]: ../types.md#type-expressions
[_WhereClause_]: generics.md#where-clauses
[_OuterAttribute_]: ../attributes.md
diff --git a/src/macros-by-example.md b/src/macros-by-example.md
index e97455d0b..172b9863e 100644
--- a/src/macros-by-example.md
+++ b/src/macros-by-example.md
@@ -122,7 +122,7 @@ fragment specifiers are:
* `block`: a [_BlockExpression_]
* `stmt`: a [_Statement_] without the trailing semicolon (except for item
statements that require semicolons)
- * `pat`: a [_Pattern_]
+ * `pat`: a [_PatternNoTopAlt_]
* `expr`: an [_Expression_]
* `ty`: a [_Type_]
* `ident`: an [IDENTIFIER_OR_KEYWORD]
@@ -488,7 +488,7 @@ For more detail, see the [formal specification].
[_Item_]: items.md
[_LiteralExpression_]: expressions/literal-expr.md
[_MetaListIdents_]: attributes.md#meta-item-attribute-syntax
-[_Pattern_]: patterns.md
+[_PatternNoTopAlt_]: patterns.md
[_Statement_]: statements.md
[_TokenTree_]: macros.md#macro-invocation
[_Token_]: tokens.md
diff --git a/src/patterns.md b/src/patterns.md
index 121b825d1..7676d5255 100644
--- a/src/patterns.md
+++ b/src/patterns.md
@@ -2,6 +2,9 @@
> **Syntax**\
> _Pattern_ :\
+> `|`? _PatternNoTopAlt_ ( `|` _PatternNoTopAlt_ )\*
+>
+> _PatternNoTopAlt_ :\
> _PatternWithoutRange_\
> | [_RangePattern_]
>
@@ -756,6 +759,63 @@ Path patterns are irrefutable when they refer to structs or an enum variant when
has only one variant or a constant whose type is irrefutable. They are refutable when they
refer to refutable constants or enum variants for enums with multiple variants.
+## Or-patterns
+
+_Or-patterns_ are patterns that match on one of two or more sub-patterns (e.g.
+`A | B | C`). They can nest arbitrarily. Syntactically, or-patterns are allowed
+in any of the places where other patterns are allowed (represented by the
+_Pattern_ production), with the exceptions of `let`-bindings and function and
+closure arguments (represented by the _PatternNoTopAlt_ production).
+
+### Static semantics
+
+1. Given a pattern `p | q` at some depth for some arbitrary patterns `p` and `q`,
+ the pattern is considered ill-formed if:
+
+ + the type inferred for `p` does not unify with the type inferred for `q`, or
+ + the same set of bindings are not introduced in `p` and `q`, or
+ + the type of any two bindings with the same name in `p` and `q` do not unify
+ with respect to types or binding modes.
+
+ Unification of types is in all instances aforementioned exact and
+ implicit [type coercions] do not apply.
+
+2. When type checking an expression `match e_s { a_1 => e_1, ... a_n => e_n }`,
+ for each match arm `a_i` which contains a pattern of form `p_i | q_i`,
+ the pattern `p_i | q_i` is considered ill formed if,
+ at the depth `d` where it exists the fragment of `e_s` at depth `d`,
+ the type of the expression fragment does not unify with `p_i | q_i`.
+
+3. With respect to exhaustiveness checking, a pattern `p | q` is
+ considered to cover `p` as well as `q`. For some constructor `c(x, ..)`
+ the distributive law applies such that `c(p | q, ..rest)` covers the same
+ set of value as `c(p, ..rest) | c(q, ..rest)` does. This can be applied
+ recursively until there are no more nested patterns of form `p | q` other
+ than those that exist at the top level.
+
+ Note that by *"constructor"* we do not refer to tuple struct patterns,
+ but rather we refer to a pattern for any product type.
+ This includes enum variants, tuple structs, structs with named fields,
+ arrays, tuples, and slices.
+
+### Dynamic semantics
+
+1. The dynamic semantics of pattern matching a scrutinee expression `e_s`
+ against a pattern `c(p | q, ..rest)` at depth `d` where `c` is some constructor,
+ `p` and `q` are arbitrary patterns, and `rest` is optionally any remaining
+ potential factors in `c`, is defined as being the same as that of
+ `c(p, ..rest) | c(q, ..rest)`.
+
+### Precedence with other undelimited patterns
+
+As shown elsewhere in this chapter, there are several types of patterns that
+are syntactically undelimited, including identifier patterns, reference
+patterns, and or-patterns. Or-patterns always have the lowest-precedence. This
+allows us to reserve syntactic space for a possible future type ascription
+feature and also to reduce ambiguity. For example, `x @ A(..) | B(..)` will
+result in an error that `x` is not bound in all patterns, `&A(x) | B(x)` will
+result in a type mismatch between `x` in the different subpatterns.
+
[_GroupedPattern_]: #grouped-patterns
[_IdentifierPattern_]: #identifier-patterns
[_LiteralPattern_]: #literal-patterns
@@ -782,3 +842,4 @@ refer to refutable constants or enum variants for enums with multiple variants.
[structs]: items/structs.md
[tuples]: types/tuple.md
[scrutinee]: glossary.md#scrutinee
+[type coercions]: type-coercions.md
diff --git a/src/statements.md b/src/statements.md
index 5d8e0e95d..06cd9513e 100644
--- a/src/statements.md
+++ b/src/statements.md
@@ -53,7 +53,7 @@ fn outer() {
> **Syntax**\
> _LetStatement_ :\
-> [_OuterAttribute_]\* `let` [_Pattern_]
+> [_OuterAttribute_]\* `let` [_PatternNoTopAlt_]
> ( `:` [_Type_] )? (`=` [_Expression_] )? `;`
A *`let` statement* introduces a new set of [variables], given by an
@@ -133,5 +133,5 @@ statement are [`cfg`], and [the lint check attributes].
[_LetStatement_]: #let-statements
[_MacroInvocationSemi_]: macros.md#macro-invocation
[_OuterAttribute_]: attributes.md
-[_Pattern_]: patterns.md
+[_PatternNoTopAlt_]: patterns.md
[_Type_]: types.md