From 6b5f63c3fc4cc5bcaaf5cad60e2cc7e56df3487f Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Wed, 15 Dec 2021 01:58:01 +0800
Subject: [PATCH 1/4] Constify (most) `Option` methods

---
 library/core/src/lib.rs      |   1 +
 library/core/src/option.rs   | 242 +++++++++++++++++++++++++++--------
 library/core/tests/lib.rs    |   2 +
 library/core/tests/option.rs |  98 ++++++++++++--
 4 files changed, 282 insertions(+), 61 deletions(-)

diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index da1baa36d6eae..67f77f14a6e6b 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -123,6 +123,7 @@
 #![feature(const_num_from_num)]
 #![feature(const_ops)]
 #![feature(const_option)]
+#![feature(const_option_ext)]
 #![feature(const_pin)]
 #![feature(const_replace)]
 #![feature(const_ptr_is_null)]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 015366ed490c7..5e375d27bddb7 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -589,12 +589,13 @@ impl<T> Option<T> {
     #[must_use]
     #[inline]
     #[unstable(feature = "option_result_contains", issue = "62358")]
-    pub fn contains<U>(&self, x: &U) -> bool
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn contains<U>(&self, x: &U) -> bool
     where
-        U: PartialEq<T>,
+        U: ~const PartialEq<T>,
     {
         match self {
-            Some(y) => x == y,
+            Some(y) => x.eq(y),
             None => false,
         }
     }
@@ -660,10 +661,14 @@ impl<T> Option<T> {
     #[inline]
     #[must_use]
     #[stable(feature = "pin", since = "1.33.0")]
-    pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
-        // SAFETY: `x` is guaranteed to be pinned because it comes from `self`
-        // which is pinned.
-        unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) }
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
+        match Pin::get_ref(self).as_ref() {
+            // SAFETY: `x` is guaranteed to be pinned because it comes from `self`
+            // which is pinned.
+            Some(x) => unsafe { Some(Pin::new_unchecked(x)) },
+            None => None,
+        }
     }
 
     /// Converts from <code>[Pin]<[&mut] Option\<T>></code> to <code>Option<[Pin]<[&mut] T>></code>.
@@ -672,10 +677,16 @@ impl<T> Option<T> {
     #[inline]
     #[must_use]
     #[stable(feature = "pin", since = "1.33.0")]
-    pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
         // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`.
         // `x` is guaranteed to be pinned because it comes from `self` which is pinned.
-        unsafe { Pin::get_unchecked_mut(self).as_mut().map(|x| Pin::new_unchecked(x)) }
+        unsafe {
+            match Pin::get_unchecked_mut(self).as_mut() {
+                Some(x) => Some(Pin::new_unchecked(x)),
+                None => None,
+            }
+        }
     }
 
     /////////////////////////////////////////////////////////////////////////
@@ -764,7 +775,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or(self, default: T) -> T {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn unwrap_or(self, default: T) -> T
+    where
+        T: ~const Drop,
+    {
         match self {
             Some(x) => x,
             None => default,
@@ -782,7 +797,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn unwrap_or_else<F>(self, f: F) -> T
+    where
+        F: ~const FnOnce() -> T,
+        F: ~const Drop,
+    {
         match self {
             Some(x) => x,
             None => f(),
@@ -812,7 +832,8 @@ impl<T> Option<T> {
     #[inline]
     #[track_caller]
     #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
-    pub unsafe fn unwrap_unchecked(self) -> T {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const unsafe fn unwrap_unchecked(self) -> T {
         debug_assert!(self.is_some());
         match self {
             Some(val) => val,
@@ -842,7 +863,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn map<U, F>(self, f: F) -> Option<U>
+    where
+        F: ~const FnOnce(T) -> U,
+        F: ~const Drop,
+    {
         match self {
             Some(x) => Some(f(x)),
             None => None,
@@ -866,7 +892,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[unstable(feature = "result_option_inspect", issue = "91345")]
-    pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn inspect<F>(self, f: F) -> Self
+    where
+        F: ~const FnOnce(&T),
+        F: ~const Drop,
+    {
         if let Some(ref x) = self {
             f(x);
         }
@@ -894,7 +925,13 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn map_or<U, F>(self, default: U, f: F) -> U
+    where
+        F: ~const FnOnce(T) -> U,
+        F: ~const Drop,
+        U: ~const Drop,
+    {
         match self {
             Some(t) => f(t),
             None => default,
@@ -917,7 +954,14 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U
+    where
+        D: ~const FnOnce() -> U,
+        D: ~const Drop,
+        F: ~const FnOnce(T) -> U,
+        F: ~const Drop,
+    {
         match self {
             Some(t) => f(t),
             None => default(),
@@ -947,7 +991,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn ok_or<E>(self, err: E) -> Result<T, E>
+    where
+        E: ~const Drop,
+    {
         match self {
             Some(v) => Ok(v),
             None => Err(err),
@@ -972,7 +1020,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
+    where
+        F: ~const FnOnce() -> E,
+        F: ~const Drop,
+    {
         match self {
             Some(v) => Ok(v),
             None => Err(err()),
@@ -1049,7 +1102,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn and<U>(self, optb: Option<U>) -> Option<U> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn and<U>(self, optb: Option<U>) -> Option<U>
+    where
+        T: ~const Drop,
+        U: ~const Drop,
+    {
         match self {
             Some(_) => optb,
             None => None,
@@ -1074,7 +1132,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn and_then<U, F>(self, f: F) -> Option<U>
+    where
+        F: ~const FnOnce(T) -> Option<U>,
+        F: ~const Drop,
+    {
         match self {
             Some(x) => f(x),
             None => None,
@@ -1107,7 +1170,13 @@ impl<T> Option<T> {
     /// [`Some(t)`]: Some
     #[inline]
     #[stable(feature = "option_filter", since = "1.27.0")]
-    pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn filter<P>(self, predicate: P) -> Self
+    where
+        T: ~const Drop,
+        P: ~const FnOnce(&T) -> bool,
+        P: ~const Drop,
+    {
         if let Some(x) = self {
             if predicate(&x) {
                 return Some(x);
@@ -1145,9 +1214,13 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or(self, optb: Option<T>) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn or(self, optb: Option<T>) -> Option<T>
+    where
+        T: ~const Drop,
+    {
         match self {
-            Some(_) => self,
+            Some(x) => Some(x),
             None => optb,
         }
     }
@@ -1167,9 +1240,14 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn or_else<F>(self, f: F) -> Option<T>
+    where
+        F: ~const FnOnce() -> Option<T>,
+        F: ~const Drop,
+    {
         match self {
-            Some(_) => self,
+            Some(x) => Some(x),
             None => f(),
         }
     }
@@ -1197,7 +1275,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_xor", since = "1.37.0")]
-    pub fn xor(self, optb: Option<T>) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn xor(self, optb: Option<T>) -> Option<T>
+    where
+        T: ~const Drop,
+    {
         match (self, optb) {
             (Some(a), None) => Some(a),
             (None, Some(b)) => Some(b),
@@ -1231,7 +1313,11 @@ impl<T> Option<T> {
     #[must_use = "if you intended to set a value, consider assignment instead"]
     #[inline]
     #[stable(feature = "option_insert", since = "1.53.0")]
-    pub fn insert(&mut self, value: T) -> &mut T {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn insert(&mut self, value: T) -> &mut T
+    where
+        T: ~const Drop,
+    {
         *self = Some(value);
 
         // SAFETY: the code above just filled the option
@@ -1260,8 +1346,18 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_entry", since = "1.20.0")]
-    pub fn get_or_insert(&mut self, value: T) -> &mut T {
-        self.get_or_insert_with(|| value)
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn get_or_insert(&mut self, value: T) -> &mut T
+    where
+        T: ~const Drop,
+    {
+        if let None = *self {
+            *self = Some(value);
+        }
+
+        // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
+        // variant in the code above.
+        unsafe { self.as_mut().unwrap_unchecked() }
     }
 
     /// Inserts the default value into the option if it is [`None`], then
@@ -1285,11 +1381,17 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[unstable(feature = "option_get_or_insert_default", issue = "82901")]
-    pub fn get_or_insert_default(&mut self) -> &mut T
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn get_or_insert_default(&mut self) -> &mut T
     where
-        T: Default,
+        T: ~const Default,
     {
-        self.get_or_insert_with(Default::default)
+        #[rustc_allow_const_fn_unstable(const_fn_trait_bound)]
+        const fn default<T: ~const Default>() -> T {
+            T::default()
+        }
+
+        self.get_or_insert_with(default)
     }
 
     /// Inserts a value computed from `f` into the option if it is [`None`],
@@ -1311,17 +1413,21 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_entry", since = "1.20.0")]
-    pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
+    where
+        F: ~const FnOnce() -> T,
+        F: ~const Drop,
+    {
         if let None = *self {
-            *self = Some(f());
+            // the compiler isn't smart enough to know that we are not dropping a `T`
+            // here and wants us to ensure `T` can be dropped at compile time.
+            mem::forget(mem::replace(self, Some(f())))
         }
 
-        match self {
-            Some(v) => v,
-            // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
-            // variant in the code above.
-            None => unsafe { hint::unreachable_unchecked() },
-        }
+        // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
+        // variant in the code above.
+        unsafe { self.as_mut().unwrap_unchecked() }
     }
 
     /////////////////////////////////////////////////////////////////////////
@@ -1391,7 +1497,12 @@ impl<T> Option<T> {
     /// assert_eq!(x.zip(z), None);
     /// ```
     #[stable(feature = "option_zip_option", since = "1.46.0")]
-    pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
+    where
+        T: ~const Drop,
+        U: ~const Drop,
+    {
         match (self, other) {
             (Some(a), Some(b)) => Some((a, b)),
             _ => None,
@@ -1427,11 +1538,18 @@ impl<T> Option<T> {
     /// assert_eq!(x.zip_with(None, Point::new), None);
     /// ```
     #[unstable(feature = "option_zip", issue = "70086")]
-    pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
     where
-        F: FnOnce(T, U) -> R,
+        F: ~const FnOnce(T, U) -> R,
+        F: ~const Drop,
+        T: ~const Drop,
+        U: ~const Drop,
     {
-        Some(f(self?, other?))
+        match (self, other) {
+            (Some(a), Some(b)) => Some(f(a, b)),
+            _ => None,
+        }
     }
 }
 
@@ -1503,8 +1621,12 @@ impl<T: Copy> Option<&mut T> {
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "copied", since = "1.35.0")]
-    pub fn copied(self) -> Option<T> {
-        self.map(|&mut t| t)
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn copied(self) -> Option<T> {
+        match self {
+            Some(&mut t) => Some(t),
+            None => None,
+        }
     }
 }
 
@@ -1591,7 +1713,11 @@ impl<T: Default> Option<T> {
     /// [`FromStr`]: crate::str::FromStr
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or_default(self) -> T {
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn unwrap_or_default(self) -> T
+    where
+        T: ~const Default,
+    {
         match self {
             Some(x) => x,
             None => Default::default(),
@@ -1615,8 +1741,15 @@ impl<T: Deref> Option<T> {
     /// assert_eq!(x.as_deref(), None);
     /// ```
     #[stable(feature = "option_deref", since = "1.40.0")]
-    pub fn as_deref(&self) -> Option<&T::Target> {
-        self.as_ref().map(|t| t.deref())
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn as_deref(&self) -> Option<&T::Target>
+    where
+        T: ~const Deref,
+    {
+        match self.as_ref() {
+            Some(t) => Some(t.deref()),
+            None => None,
+        }
     }
 }
 
@@ -1636,8 +1769,15 @@ impl<T: DerefMut> Option<T> {
     /// }), Some("HEY".to_owned().as_mut_str()));
     /// ```
     #[stable(feature = "option_deref", since = "1.40.0")]
-    pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> {
-        self.as_mut().map(|t| t.deref_mut())
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target>
+    where
+        T: ~const DerefMut,
+    {
+        match self.as_mut() {
+            Some(t) => Some(t.deref_mut()),
+            None => None,
+        }
     }
 }
 
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index dacb33619f8c3..21562acf3d766 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -70,8 +70,10 @@
 #![feature(portable_simd)]
 #![feature(ptr_metadata)]
 #![feature(once_cell)]
+#![feature(option_result_contains)]
 #![feature(unsized_tuple_coercion)]
 #![feature(const_option)]
+#![feature(const_option_ext)]
 #![feature(const_result)]
 #![feature(integer_atomics)]
 #![feature(int_roundings)]
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index cd07d6c52c2ad..da692461261fc 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -86,17 +86,49 @@ fn test_and() {
     let x: Option<isize> = None;
     assert_eq!(x.and(Some(2)), None);
     assert_eq!(x.and(None::<isize>), None);
+
+    const FOO: Option<isize> = Some(1);
+    const A: Option<isize> = FOO.and(Some(2));
+    const B: Option<isize> = FOO.and(None);
+    assert_eq!(A, Some(2));
+    assert_eq!(B, None);
+
+    const BAR: Option<isize> = None;
+    const C: Option<isize> = BAR.and(Some(2));
+    const D: Option<isize> = BAR.and(None);
+    assert_eq!(C, None);
+    assert_eq!(D, None);
 }
 
 #[test]
 fn test_and_then() {
+    const fn plus_one(x: isize) -> Option<isize> {
+        Some(x + 1)
+    }
+
+    const fn none(_: isize) -> Option<isize> {
+        None
+    }
+
     let x: Option<isize> = Some(1);
-    assert_eq!(x.and_then(|x| Some(x + 1)), Some(2));
-    assert_eq!(x.and_then(|_| None::<isize>), None);
+    assert_eq!(x.and_then(plus_one), Some(2));
+    assert_eq!(x.and_then(none), None);
 
     let x: Option<isize> = None;
-    assert_eq!(x.and_then(|x| Some(x + 1)), None);
-    assert_eq!(x.and_then(|_| None::<isize>), None);
+    assert_eq!(x.and_then(plus_one), None);
+    assert_eq!(x.and_then(none), None);
+
+    const FOO: Option<isize> = Some(1);
+    const A: Option<isize> = FOO.and_then(plus_one);
+    const B: Option<isize> = FOO.and_then(none);
+    assert_eq!(A, Some(2));
+    assert_eq!(B, None);
+
+    const BAR: Option<isize> = None;
+    const C: Option<isize> = BAR.and_then(plus_one);
+    const D: Option<isize> = BAR.and_then(none);
+    assert_eq!(C, None);
+    assert_eq!(D, None);
 }
 
 #[test]
@@ -108,17 +140,49 @@ fn test_or() {
     let x: Option<isize> = None;
     assert_eq!(x.or(Some(2)), Some(2));
     assert_eq!(x.or(None), None);
+
+    const FOO: Option<isize> = Some(1);
+    const A: Option<isize> = FOO.or(Some(2));
+    const B: Option<isize> = FOO.or(None);
+    assert_eq!(A, Some(1));
+    assert_eq!(B, Some(1));
+
+    const BAR: Option<isize> = None;
+    const C: Option<isize> = BAR.or(Some(2));
+    const D: Option<isize> = BAR.or(None);
+    assert_eq!(C, Some(2));
+    assert_eq!(D, None);
 }
 
 #[test]
 fn test_or_else() {
+    const fn two() -> Option<isize> {
+        Some(2)
+    }
+
+    const fn none() -> Option<isize> {
+        None
+    }
+
     let x: Option<isize> = Some(1);
-    assert_eq!(x.or_else(|| Some(2)), Some(1));
-    assert_eq!(x.or_else(|| None), Some(1));
+    assert_eq!(x.or_else(two), Some(1));
+    assert_eq!(x.or_else(none), Some(1));
 
     let x: Option<isize> = None;
-    assert_eq!(x.or_else(|| Some(2)), Some(2));
-    assert_eq!(x.or_else(|| None), None);
+    assert_eq!(x.or_else(two), Some(2));
+    assert_eq!(x.or_else(none), None);
+
+    const FOO: Option<isize> = Some(1);
+    const A: Option<isize> = FOO.or_else(two);
+    const B: Option<isize> = FOO.or_else(none);
+    assert_eq!(A, Some(1));
+    assert_eq!(B, Some(1));
+
+    const BAR: Option<isize> = None;
+    const C: Option<isize> = BAR.or_else(two);
+    const D: Option<isize> = BAR.or_else(none);
+    assert_eq!(C, Some(2));
+    assert_eq!(D, None);
 }
 
 #[test]
@@ -149,15 +213,29 @@ fn test_unwrap_or() {
 
     let x: Option<isize> = None;
     assert_eq!(x.unwrap_or(2), 2);
+
+    const A: isize = Some(1).unwrap_or(2);
+    const B: isize = None.unwrap_or(2);
+    assert_eq!(A, 1);
+    assert_eq!(B, 2);
 }
 
 #[test]
 fn test_unwrap_or_else() {
+    const fn two() -> isize {
+        2
+    }
+
     let x: Option<isize> = Some(1);
-    assert_eq!(x.unwrap_or_else(|| 2), 1);
+    assert_eq!(x.unwrap_or_else(two), 1);
 
     let x: Option<isize> = None;
-    assert_eq!(x.unwrap_or_else(|| 2), 2);
+    assert_eq!(x.unwrap_or_else(two), 2);
+
+    const A: isize = Some(1).unwrap_or_else(two);
+    const B: isize = None.unwrap_or_else(two);
+    assert_eq!(A, 1);
+    assert_eq!(B, 2);
 }
 
 #[test]

From 2f555dec4a5e3eeaea31d991c0220c4260b794e5 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Fri, 17 Dec 2021 14:16:12 +0800
Subject: [PATCH 2/4] Add a temporary hack before env fix lands in bootstrap

---
 compiler/rustc_middle/src/query/mod.rs | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 78e33544655f0..e2de9f12aaa71 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -771,11 +771,24 @@ rustc_queries! {
         desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
         load_cached(tcx, id) {
-            let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
-                .on_disk_cache().as_ref()
-                .and_then(|c| c.try_load_query_result(*tcx, id));
+            #[cfg(bootstrap)]
+            {
+                match match tcx.on_disk_cache().as_ref() {
+                    Some(c) => c.try_load_query_result(*tcx, id),
+                    None => None,
+                } {
+                    Some(x) => Some(&*tcx.arena.alloc(x)),
+                    None => None,
+                }
+            }
+            #[cfg(not(bootstrap))]
+            {
+                let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
+                    .on_disk_cache().as_ref()
+                    .and_then(|c| c.try_load_query_result(*tcx, id));
 
-            typeck_results.map(|x| &*tcx.arena.alloc(x))
+                typeck_results.map(|x| &*tcx.arena.alloc(x))
+            }
         }
     }
 

From 493cf0c6438d1b55ae3ebf2d407fc5e5e8e5698e Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Fri, 17 Dec 2021 15:38:12 +0800
Subject: [PATCH 3/4] Bless ui tests

---
 src/test/ui/closures/closure-expected.stderr                 | 4 ++--
 src/test/ui/closures/coerce-unsafe-to-closure.stderr         | 4 ++--
 src/test/ui/expr/malformed_closure/ruby_style_closure.stderr | 4 ++--
 src/test/ui/issues/issue-47706-trait.stderr                  | 4 ++--
 src/test/ui/issues/issue-47706.stderr                        | 4 ++--
 src/test/ui/suggestions/as-ref-2.stderr                      | 4 ++--
 6 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/test/ui/closures/closure-expected.stderr b/src/test/ui/closures/closure-expected.stderr
index 8b38d5ff4592c..7ffe3c1ef954a 100644
--- a/src/test/ui/closures/closure-expected.stderr
+++ b/src/test/ui/closures/closure-expected.stderr
@@ -11,8 +11,8 @@ LL |     let y = x.or_else(4);
 note: required by a bound in `Option::<T>::or_else`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
-   |                       ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::or_else`
+LL |         F: ~const FnOnce() -> Option<T>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::or_else`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/coerce-unsafe-to-closure.stderr b/src/test/ui/closures/coerce-unsafe-to-closure.stderr
index 24db272534730..883348eb98c70 100644
--- a/src/test/ui/closures/coerce-unsafe-to-closure.stderr
+++ b/src/test/ui/closures/coerce-unsafe-to-closure.stderr
@@ -10,8 +10,8 @@ LL |     let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
 note: required by a bound in `Option::<T>::map`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
-   |                      ^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+LL |         F: ~const FnOnce(T) -> U,
+   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr b/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
index 53924e24e4638..9db9cfc7ff024 100644
--- a/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
+++ b/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
@@ -23,8 +23,8 @@ LL | |     });
 note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> {
-   |                           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::and_then`
+LL |         F: ~const FnOnce(T) -> Option<U>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::and_then`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-47706-trait.stderr b/src/test/ui/issues/issue-47706-trait.stderr
index eb0c80f8f0d1e..d596b4a69f34a 100644
--- a/src/test/ui/issues/issue-47706-trait.stderr
+++ b/src/test/ui/issues/issue-47706-trait.stderr
@@ -11,8 +11,8 @@ LL |         None::<()>.map(Self::f);
 note: required by a bound in `Option::<T>::map`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
-   |                      ^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+LL |         F: ~const FnOnce(T) -> U,
+   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-47706.stderr b/src/test/ui/issues/issue-47706.stderr
index 237b2b9e79859..0b4f84a330a54 100644
--- a/src/test/ui/issues/issue-47706.stderr
+++ b/src/test/ui/issues/issue-47706.stderr
@@ -12,8 +12,8 @@ LL |         self.foo.map(Foo::new)
 note: required by a bound in `Option::<T>::map`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
-   |                      ^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+LL |         F: ~const FnOnce(T) -> U,
+   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
 
 error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
   --> $DIR/issue-47706.rs:27:9
diff --git a/src/test/ui/suggestions/as-ref-2.stderr b/src/test/ui/suggestions/as-ref-2.stderr
index 86a175098c6be..3c9d0f72abe0c 100644
--- a/src/test/ui/suggestions/as-ref-2.stderr
+++ b/src/test/ui/suggestions/as-ref-2.stderr
@@ -11,8 +11,8 @@ LL |     let _y = foo;
 note: this function takes ownership of the receiver `self`, which moves `foo`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
-   |                                      ^^^^
+LL |     pub const fn map<U, F>(self, f: F) -> Option<U>
+   |                            ^^^^
 help: consider calling `.as_ref()` to borrow the type's contents
    |
 LL |     let _x: Option<Struct> = foo.as_ref().map(|s| bar(&s));

From f141bedd90233dad9906034562062f89158fecef Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Fri, 17 Dec 2021 20:48:04 +0800
Subject: [PATCH 4/4] Point to the tracking issue

---
 library/core/src/option.rs | 56 +++++++++++++++++++-------------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 5e375d27bddb7..8969c6f617130 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -589,7 +589,7 @@ impl<T> Option<T> {
     #[must_use]
     #[inline]
     #[unstable(feature = "option_result_contains", issue = "62358")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn contains<U>(&self, x: &U) -> bool
     where
         U: ~const PartialEq<T>,
@@ -661,7 +661,7 @@ impl<T> Option<T> {
     #[inline]
     #[must_use]
     #[stable(feature = "pin", since = "1.33.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
         match Pin::get_ref(self).as_ref() {
             // SAFETY: `x` is guaranteed to be pinned because it comes from `self`
@@ -677,7 +677,7 @@ impl<T> Option<T> {
     #[inline]
     #[must_use]
     #[stable(feature = "pin", since = "1.33.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
         // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`.
         // `x` is guaranteed to be pinned because it comes from `self` which is pinned.
@@ -775,7 +775,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn unwrap_or(self, default: T) -> T
     where
         T: ~const Drop,
@@ -797,7 +797,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn unwrap_or_else<F>(self, f: F) -> T
     where
         F: ~const FnOnce() -> T,
@@ -832,7 +832,7 @@ impl<T> Option<T> {
     #[inline]
     #[track_caller]
     #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const unsafe fn unwrap_unchecked(self) -> T {
         debug_assert!(self.is_some());
         match self {
@@ -863,7 +863,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn map<U, F>(self, f: F) -> Option<U>
     where
         F: ~const FnOnce(T) -> U,
@@ -892,7 +892,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[unstable(feature = "result_option_inspect", issue = "91345")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn inspect<F>(self, f: F) -> Self
     where
         F: ~const FnOnce(&T),
@@ -925,7 +925,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn map_or<U, F>(self, default: U, f: F) -> U
     where
         F: ~const FnOnce(T) -> U,
@@ -954,7 +954,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U
     where
         D: ~const FnOnce() -> U,
@@ -991,7 +991,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn ok_or<E>(self, err: E) -> Result<T, E>
     where
         E: ~const Drop,
@@ -1020,7 +1020,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
     where
         F: ~const FnOnce() -> E,
@@ -1102,7 +1102,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn and<U>(self, optb: Option<U>) -> Option<U>
     where
         T: ~const Drop,
@@ -1132,7 +1132,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn and_then<U, F>(self, f: F) -> Option<U>
     where
         F: ~const FnOnce(T) -> Option<U>,
@@ -1170,7 +1170,7 @@ impl<T> Option<T> {
     /// [`Some(t)`]: Some
     #[inline]
     #[stable(feature = "option_filter", since = "1.27.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn filter<P>(self, predicate: P) -> Self
     where
         T: ~const Drop,
@@ -1214,7 +1214,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn or(self, optb: Option<T>) -> Option<T>
     where
         T: ~const Drop,
@@ -1240,7 +1240,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn or_else<F>(self, f: F) -> Option<T>
     where
         F: ~const FnOnce() -> Option<T>,
@@ -1275,7 +1275,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_xor", since = "1.37.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn xor(self, optb: Option<T>) -> Option<T>
     where
         T: ~const Drop,
@@ -1313,7 +1313,7 @@ impl<T> Option<T> {
     #[must_use = "if you intended to set a value, consider assignment instead"]
     #[inline]
     #[stable(feature = "option_insert", since = "1.53.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn insert(&mut self, value: T) -> &mut T
     where
         T: ~const Drop,
@@ -1346,7 +1346,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_entry", since = "1.20.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn get_or_insert(&mut self, value: T) -> &mut T
     where
         T: ~const Drop,
@@ -1381,7 +1381,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[unstable(feature = "option_get_or_insert_default", issue = "82901")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn get_or_insert_default(&mut self) -> &mut T
     where
         T: ~const Default,
@@ -1413,7 +1413,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_entry", since = "1.20.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
     where
         F: ~const FnOnce() -> T,
@@ -1497,7 +1497,7 @@ impl<T> Option<T> {
     /// assert_eq!(x.zip(z), None);
     /// ```
     #[stable(feature = "option_zip_option", since = "1.46.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
     where
         T: ~const Drop,
@@ -1538,7 +1538,7 @@ impl<T> Option<T> {
     /// assert_eq!(x.zip_with(None, Point::new), None);
     /// ```
     #[unstable(feature = "option_zip", issue = "70086")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
     where
         F: ~const FnOnce(T, U) -> R,
@@ -1621,7 +1621,7 @@ impl<T: Copy> Option<&mut T> {
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "copied", since = "1.35.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn copied(self) -> Option<T> {
         match self {
             Some(&mut t) => Some(t),
@@ -1713,7 +1713,7 @@ impl<T: Default> Option<T> {
     /// [`FromStr`]: crate::str::FromStr
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn unwrap_or_default(self) -> T
     where
         T: ~const Default,
@@ -1741,7 +1741,7 @@ impl<T: Deref> Option<T> {
     /// assert_eq!(x.as_deref(), None);
     /// ```
     #[stable(feature = "option_deref", since = "1.40.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn as_deref(&self) -> Option<&T::Target>
     where
         T: ~const Deref,
@@ -1769,7 +1769,7 @@ impl<T: DerefMut> Option<T> {
     /// }), Some("HEY".to_owned().as_mut_str()));
     /// ```
     #[stable(feature = "option_deref", since = "1.40.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "none")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
     pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target>
     where
         T: ~const DerefMut,