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 @@
 > &nbsp;&nbsp; _ClosureParam_ (`,` _ClosureParam_)<sup>\*</sup> `,`<sup>?</sup>
 >
 > _ClosureParam_ :\
-> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> [_Pattern_]&nbsp;( `:` [_Type_] )<sup>?</sup>
+> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> [_PatternNoTopAlt_]&nbsp;( `:` [_Type_] )<sup>?</sup>
 
 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");
 
 > **<sup>Syntax</sup>**\
 > _IfLetExpression_ :\
-> &nbsp;&nbsp; `if` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
+> &nbsp;&nbsp; `if` `let` [_Pattern_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
 >              [_BlockExpression_]\
 > &nbsp;&nbsp; (`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 {
 
 > **<sup>Syntax</sup>**\
 > [_PredicatePatternLoopExpression_] :\
-> &nbsp;&nbsp; `while` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
+> &nbsp;&nbsp; `while` `let` [_Pattern_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
 >              [_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 @@
 > &nbsp;&nbsp; _MatchArm_ `=>` [_Expression_] `,`<sup>?</sup>
 >
 > _MatchArm_ :\
-> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> _MatchArmPatterns_ _MatchArmGuard_<sup>?</sup>
->
-> _MatchArmPatterns_ :\
-> &nbsp;&nbsp; `|`<sup>?</sup> [_Pattern_] ( `|` [_Pattern_] )<sup>\*</sup>
+> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> [_Pattern_] _MatchArmGuard_<sup>?</sup>
 >
 > _MatchArmGuard_ :\
 > &nbsp;&nbsp; `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_ :\
-> &nbsp;&nbsp; [_Pattern_] `:` ( [_Type_] | `...` )
+> &nbsp;&nbsp; [_PatternNoTopAlt_] `:` ( [_Type_] | `...` )
 >
 > _FunctionReturnType_ :\
 > &nbsp;&nbsp; `->` [_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 @@
 
 > **<sup>Syntax</sup>**\
 > _Pattern_ :\
+> &nbsp;&nbsp; &nbsp;&nbsp; `|`<sup>?</sup> _PatternNoTopAlt_  ( `|` _PatternNoTopAlt_ )<sup>\*</sup>
+>
+> _PatternNoTopAlt_ :\
 > &nbsp;&nbsp; &nbsp;&nbsp; _PatternWithoutRange_\
 > &nbsp;&nbsp; | [_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() {
 
 > **<sup>Syntax</sup>**\
 > _LetStatement_ :\
-> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> `let` [_Pattern_]
+> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> `let` [_PatternNoTopAlt_]
 >     ( `:` [_Type_] )<sup>?</sup> (`=` [_Expression_] )<sup>?</sup> `;`
 
 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