From f310d0e5003cde10959eba46dd969f37b8089382 Mon Sep 17 00:00:00 2001
From: ltdk <usr@ltdk.xyz>
Date: Tue, 1 Jun 2021 22:50:42 -0400
Subject: [PATCH 01/10] Add lerp method

---
 library/std/src/f32.rs | 28 ++++++++++++++++++++++++++++
 library/std/src/f64.rs | 28 ++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index c16d27fa1f58c..32a4d415362a6 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -876,4 +876,32 @@ impl f32 {
     pub fn atanh(self) -> f32 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
+
+    /// Linear interpolation between `start` and `end`.
+    ///
+    /// This enables the calculation of a "smooth" transition between `start` and `end`,
+    /// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`.
+    ///
+    /// Values below 0.0 or above 1.0 are allowed, and in general this function closely
+    /// resembles the value of `start + self * (end - start)`, plus additional guarantees.
+    ///
+    /// Those guarantees are, assuming that all values are [`finite`]:
+    ///
+    /// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness)
+    /// * If `start == end`, the value at any point will always be `start == end` (consistency)
+    /// * The values will always move in the direction from `start` to `end` (monotonicity)
+    ///
+    /// [`finite`]: #method.is_finite
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "float_interpolation", issue = "71015")]
+    pub fn lerp(self, start: f32, end: f32) -> f32 {
+        // consistent
+        if start == end {
+            start
+
+        // exact/monotonic
+        } else {
+            self.mul_add(end, (-self).mul_add(start, start))
+        }
+    }
 }
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 4c95df5ffe04a..39c3e587e1f6f 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -879,6 +879,34 @@ impl f64 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
 
+    /// Linear interpolation between `start` and `end`.
+    ///
+    /// This enables the calculation of a "smooth" transition between `start` and `end`,
+    /// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`.
+    ///
+    /// Values below 0.0 or above 1.0 are allowed, and in general this function closely
+    /// resembles the value of `start + self * (end - start)`, plus additional guarantees.
+    ///
+    /// Those guarantees are, assuming that all values are [`finite`]:
+    ///
+    /// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness)
+    /// * If `start == end`, the value at any point will always be `start == end` (consistency)
+    /// * The values will always move in the direction from `start` to `end` (monotonicity)
+    ///
+    /// [`finite`]: #method.is_finite
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "float_interpolation", issue = "71015")]
+    pub fn lerp(self, start: f64, end: f64) -> f64 {
+        // consistent
+        if start == end {
+            start
+
+        // exact/monotonic
+        } else {
+            self.mul_add(end, (-self).mul_add(start, start))
+        }
+    }
+
     // Solaris/Illumos requires a wrapper around log, log2, and log10 functions
     // because of their non-standard behavior (e.g., log(-n) returns -Inf instead
     // of expected NaN).

From 0865acd22b9f0fa2d2ac0bcec61b479e4b3613d9 Mon Sep 17 00:00:00 2001
From: ltdk <usr@ltdk.xyz>
Date: Sun, 6 Jun 2021 22:42:53 -0400
Subject: [PATCH 02/10] A few lerp tests

---
 library/std/src/f32/tests.rs | 21 +++++++++++++++++++++
 library/std/src/f64/tests.rs | 21 +++++++++++++++++++++
 library/std/src/lib.rs       |  1 +
 3 files changed, 43 insertions(+)

diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs
index 0d4b865f3392a..7b54bc2335450 100644
--- a/library/std/src/f32/tests.rs
+++ b/library/std/src/f32/tests.rs
@@ -757,3 +757,24 @@ fn test_total_cmp() {
     assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
     assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
 }
+
+#[test]
+fn test_lerp_exact() {
+    assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0);
+    assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0);
+    assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN);
+    assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX);
+}
+
+#[test]
+fn test_lerp_consistent() {
+    assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN);
+    assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX);
+}
+
+#[test]
+fn test_lerp_values() {
+    assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25);
+    assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50);
+    assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75);
+}
diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs
index 5c163cfe90e0b..3efb2e9d3236c 100644
--- a/library/std/src/f64/tests.rs
+++ b/library/std/src/f64/tests.rs
@@ -753,3 +753,24 @@ fn test_total_cmp() {
     assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
     assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
 }
+
+#[test]
+fn test_lerp_exact() {
+    assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0);
+    assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0);
+    assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN);
+    assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX);
+}
+
+#[test]
+fn test_lerp_consistent() {
+    assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN);
+    assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX);
+}
+
+#[test]
+fn test_lerp_values() {
+    assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25);
+    assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50);
+    assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75);
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 8e4c63762fd38..a0f7b41b8a0f5 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -268,6 +268,7 @@
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
 #![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
+#![feature(float_interpolation)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]

From 2cbd5d1df54400b8bd718b7e0dadc4c38c6f9932 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= <bdgdlm@outlook.com>
Date: Thu, 10 Jun 2021 19:09:04 +0200
Subject: [PATCH 03/10] Specialize `io::Bytes::size_hint` for more types

---
 library/std/src/io/buffered/bufreader.rs |  8 +++-
 library/std/src/io/mod.rs                | 58 +++++++++++++++++++++++-
 library/std/src/io/tests.rs              | 20 +++++++-
 library/std/src/io/util.rs               | 13 ++++++
 4 files changed, 96 insertions(+), 3 deletions(-)

diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index d8021d3e99a70..32d194d961652 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -438,7 +438,13 @@ impl<R: Seek> Seek for BufReader<R> {
 }
 
 impl<T> SizeHint for BufReader<T> {
+    #[inline]
     fn lower_bound(&self) -> usize {
-        self.buffer().len()
+        SizeHint::lower_bound(self.get_ref()) + self.buffer().len()
+    }
+
+    #[inline]
+    fn upper_bound(&self) -> Option<usize> {
+        SizeHint::upper_bound(self.get_ref()).and_then(|up| self.buffer().len().checked_add(up))
     }
 }
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 4c154dbe01a5a..95aef0bd0fc42 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -252,6 +252,7 @@
 mod tests;
 
 use crate::cmp;
+use crate::convert::TryInto;
 use crate::fmt;
 use crate::ops::{Deref, DerefMut};
 use crate::ptr;
@@ -2291,13 +2292,15 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
 }
 
 impl<T, U> SizeHint for Chain<T, U> {
+    #[inline]
     fn lower_bound(&self) -> usize {
         SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second)
     }
 
+    #[inline]
     fn upper_bound(&self) -> Option<usize> {
         match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) {
-            (Some(first), Some(second)) => Some(first + second),
+            (Some(first), Some(second)) => first.checked_add(second),
             _ => None,
         }
     }
@@ -2502,6 +2505,21 @@ impl<T: BufRead> BufRead for Take<T> {
     }
 }
 
+impl<T> SizeHint for Take<T> {
+    #[inline]
+    fn lower_bound(&self) -> usize {
+        cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize
+    }
+
+    #[inline]
+    fn upper_bound(&self) -> Option<usize> {
+        match SizeHint::upper_bound(&self.inner) {
+            Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize),
+            None => self.limit.try_into().ok(),
+        }
+    }
+}
+
 /// An iterator over `u8` values of a reader.
 ///
 /// This struct is generally created by calling [`bytes`] on a reader.
@@ -2546,15 +2564,53 @@ trait SizeHint {
 }
 
 impl<T> SizeHint for T {
+    #[inline]
     default fn lower_bound(&self) -> usize {
         0
     }
 
+    #[inline]
     default fn upper_bound(&self) -> Option<usize> {
         None
     }
 }
 
+impl<T> SizeHint for &mut T {
+    #[inline]
+    fn lower_bound(&self) -> usize {
+        SizeHint::lower_bound(*self)
+    }
+
+    #[inline]
+    fn upper_bound(&self) -> Option<usize> {
+        SizeHint::upper_bound(*self)
+    }
+}
+
+impl<T> SizeHint for Box<T> {
+    #[inline]
+    fn lower_bound(&self) -> usize {
+        SizeHint::lower_bound(&**self)
+    }
+
+    #[inline]
+    fn upper_bound(&self) -> Option<usize> {
+        SizeHint::upper_bound(&**self)
+    }
+}
+
+impl SizeHint for &[u8] {
+    #[inline]
+    fn lower_bound(&self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn upper_bound(&self) -> Option<usize> {
+        Some(self.len())
+    }
+}
+
 /// An iterator over the contents of an instance of `BufRead` split on a
 /// particular byte.
 ///
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 2b14e16150317..a483847fb26c8 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -224,6 +224,24 @@ fn empty_size_hint() {
     assert_eq!(size_hint, (0, Some(0)));
 }
 
+#[test]
+fn slice_size_hint() {
+    let size_hint = (&[1, 2, 3]).bytes().size_hint();
+    assert_eq!(size_hint, (3, Some(3)));
+}
+
+#[test]
+fn take_size_hint() {
+    let size_hint = (&[1, 2, 3]).take(2).bytes().size_hint();
+    assert_eq!(size_hint, (2, Some(2)));
+
+    let size_hint = (&[1, 2, 3]).take(4).bytes().size_hint();
+    assert_eq!(size_hint, (3, Some(3)));
+
+    let size_hint = io::repeat(0).take(3).bytes().size_hint();
+    assert_eq!(size_hint, (3, Some(3)));
+}
+
 #[test]
 fn chain_empty_size_hint() {
     let chain = io::empty().chain(io::empty());
@@ -242,7 +260,7 @@ fn chain_size_hint() {
 
     let chain = buf_reader_1.chain(buf_reader_2);
     let size_hint = chain.bytes().size_hint();
-    assert_eq!(size_hint, (testdata.len(), None));
+    assert_eq!(size_hint, (testdata.len(), Some(testdata.len())));
 }
 
 #[test]
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index 73f2f3eb3f5dc..f3bff391fb3ea 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -83,6 +83,7 @@ impl fmt::Debug for Empty {
 }
 
 impl SizeHint for Empty {
+    #[inline]
     fn upper_bound(&self) -> Option<usize> {
         Some(0)
     }
@@ -147,6 +148,18 @@ impl Read for Repeat {
     }
 }
 
+impl SizeHint for Repeat {
+    #[inline]
+    fn lower_bound(&self) -> usize {
+        usize::MAX
+    }
+
+    #[inline]
+    fn upper_bound(&self) -> Option<usize> {
+        None
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl fmt::Debug for Repeat {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

From d8e247e38c9ce6746a595d374cf260b46ac54f27 Mon Sep 17 00:00:00 2001
From: ltdk <usr@ltdk.xyz>
Date: Sun, 13 Jun 2021 14:00:15 -0400
Subject: [PATCH 04/10] More lerp tests, altering lerp docs

---
 library/std/src/f32.rs       | 34 ++++++++++++++++++-----------
 library/std/src/f32/tests.rs | 42 ++++++++++++++++++++++++++++++++++++
 library/std/src/f64.rs       | 34 ++++++++++++++++++-----------
 library/std/src/f64/tests.rs | 34 +++++++++++++++++++++++++++++
 4 files changed, 118 insertions(+), 26 deletions(-)

diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 32a4d415362a6..00cab72564f94 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -879,19 +879,27 @@ impl f32 {
 
     /// Linear interpolation between `start` and `end`.
     ///
-    /// This enables the calculation of a "smooth" transition between `start` and `end`,
-    /// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`.
-    ///
-    /// Values below 0.0 or above 1.0 are allowed, and in general this function closely
-    /// resembles the value of `start + self * (end - start)`, plus additional guarantees.
-    ///
-    /// Those guarantees are, assuming that all values are [`finite`]:
-    ///
-    /// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness)
-    /// * If `start == end`, the value at any point will always be `start == end` (consistency)
-    /// * The values will always move in the direction from `start` to `end` (monotonicity)
-    ///
-    /// [`finite`]: #method.is_finite
+    /// This enables linear interpolation between `start` and `end`, where start is represented by
+    /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
+    /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
+    /// at a given rate, the result will change from `start` to `end` at a similar rate.
+    ///
+    /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
+    /// range from `start` to `end`. This also is useful for transition functions which might
+    /// move slightly past the end or start for a desired effect. Mathematically, the values
+    /// returned are equivalent to `start + self * (end - start)`, although we make a few specific
+    /// guarantees that are useful specifically to linear interpolation.
+    ///
+    /// These guarantees are:
+    ///
+    /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
+    ///   value at 1.0 is always `end`. (exactness)
+    /// * If `start` and `end` are [finite], the values will always move in the direction from
+    ///   `start` to `end` (monotonicity)
+    /// * If `self` is [finite] and `start == end`, the value at any point will always be
+    ///   `start == end`. (consistency)
+    ///
+    /// [finite]: #method.is_finite
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[unstable(feature = "float_interpolation", issue = "71015")]
     pub fn lerp(self, start: f32, end: f32) -> f32 {
diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs
index 7b54bc2335450..fe66a73afd63a 100644
--- a/library/std/src/f32/tests.rs
+++ b/library/std/src/f32/tests.rs
@@ -760,8 +760,11 @@ fn test_total_cmp() {
 
 #[test]
 fn test_lerp_exact() {
+    // simple values
     assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0);
     assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0);
+
+    // boundary values
     assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN);
     assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX);
 }
@@ -770,11 +773,50 @@ fn test_lerp_exact() {
 fn test_lerp_consistent() {
     assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN);
     assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX);
+
+    // as long as t is finite, a/b can be infinite
+    assert_eq!(f32::lerp(f32::MAX, f32::NEG_INFINITY, f32::NEG_INFINITY), f32::NEG_INFINITY);
+    assert_eq!(f32::lerp(f32::MIN, f32::INFINITY, f32::INFINITY), f32::INFINITY);
+}
+
+#[test]
+fn test_lerp_nan_infinite() {
+    // non-finite t is not NaN if a/b different
+    assert!(!f32::lerp(f32::INFINITY, f32::MIN, f32::MAX).is_nan());
+    assert!(!f32::lerp(f32::NEG_INFINITY, f32::MIN, f32::MAX).is_nan());
 }
 
 #[test]
 fn test_lerp_values() {
+    // just a few basic values
     assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25);
     assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50);
     assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75);
 }
+
+#[test]
+fn test_lerp_monotonic() {
+    // near 0
+    let below_zero = f32::lerp(-f32::EPSILON, f32::MIN, f32::MAX);
+    let zero = f32::lerp(0.0, f32::MIN, f32::MAX);
+    let above_zero = f32::lerp(f32::EPSILON, f32::MIN, f32::MAX);
+    assert!(below_zero <= zero);
+    assert!(zero <= above_zero);
+    assert!(below_zero <= above_zero);
+
+    // near 0.5
+    let below_half = f32::lerp(0.5 - f32::EPSILON, f32::MIN, f32::MAX);
+    let half = f32::lerp(0.5, f32::MIN, f32::MAX);
+    let above_half = f32::lerp(0.5 + f32::EPSILON, f32::MIN, f32::MAX);
+    assert!(below_half <= half);
+    assert!(half <= above_half);
+    assert!(below_half <= above_half);
+
+    // near 1
+    let below_one = f32::lerp(1.0 - f32::EPSILON, f32::MIN, f32::MAX);
+    let one = f32::lerp(1.0, f32::MIN, f32::MAX);
+    let above_one = f32::lerp(1.0 + f32::EPSILON, f32::MIN, f32::MAX);
+    assert!(below_one <= one);
+    assert!(one <= above_one);
+    assert!(below_one <= above_one);
+}
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 39c3e587e1f6f..ff41f999dd565 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -881,19 +881,27 @@ impl f64 {
 
     /// Linear interpolation between `start` and `end`.
     ///
-    /// This enables the calculation of a "smooth" transition between `start` and `end`,
-    /// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`.
-    ///
-    /// Values below 0.0 or above 1.0 are allowed, and in general this function closely
-    /// resembles the value of `start + self * (end - start)`, plus additional guarantees.
-    ///
-    /// Those guarantees are, assuming that all values are [`finite`]:
-    ///
-    /// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness)
-    /// * If `start == end`, the value at any point will always be `start == end` (consistency)
-    /// * The values will always move in the direction from `start` to `end` (monotonicity)
-    ///
-    /// [`finite`]: #method.is_finite
+    /// This enables linear interpolation between `start` and `end`, where start is represented by
+    /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
+    /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
+    /// at a given rate, the result will change from `start` to `end` at a similar rate.
+    ///
+    /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
+    /// range from `start` to `end`. This also is useful for transition functions which might
+    /// move slightly past the end or start for a desired effect. Mathematically, the values
+    /// returned are equivalent to `start + self * (end - start)`, although we make a few specific
+    /// guarantees that are useful specifically to linear interpolation.
+    ///
+    /// These guarantees are:
+    ///
+    /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
+    ///   value at 1.0 is always `end`. (exactness)
+    /// * If `start` and `end` are [finite], the values will always move in the direction from
+    ///   `start` to `end` (monotonicity)
+    /// * If `self` is [finite] and `start == end`, the value at any point will always be
+    ///   `start == end`. (consistency)
+    ///
+    /// [finite]: #method.is_finite
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[unstable(feature = "float_interpolation", issue = "71015")]
     pub fn lerp(self, start: f64, end: f64) -> f64 {
diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs
index 3efb2e9d3236c..04cb0109261a4 100644
--- a/library/std/src/f64/tests.rs
+++ b/library/std/src/f64/tests.rs
@@ -756,8 +756,11 @@ fn test_total_cmp() {
 
 #[test]
 fn test_lerp_exact() {
+    // simple values
     assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0);
     assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0);
+
+    // boundary values
     assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN);
     assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX);
 }
@@ -766,11 +769,42 @@ fn test_lerp_exact() {
 fn test_lerp_consistent() {
     assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN);
     assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX);
+
+    // as long as t is finite, a/b can be infinite
+    assert_eq!(f64::lerp(f64::MAX, f64::NEG_INFINITY, f64::NEG_INFINITY), f64::NEG_INFINITY);
+    assert_eq!(f64::lerp(f64::MIN, f64::INFINITY, f64::INFINITY), f64::INFINITY);
+}
+
+#[test]
+fn test_lerp_nan_infinite() {
+    // non-finite t is not NaN if a/b different
+    assert!(!f64::lerp(f64::INFINITY, f64::MIN, f64::MAX).is_nan());
+    assert!(!f64::lerp(f64::NEG_INFINITY, f64::MIN, f64::MAX).is_nan());
 }
 
 #[test]
 fn test_lerp_values() {
+    // just a few basic values
     assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25);
     assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50);
     assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75);
 }
+
+#[test]
+fn test_lerp_monotonic() {
+    // near 0
+    let below_zero = f64::lerp(-f64::EPSILON, f64::MIN, f64::MAX);
+    let zero = f64::lerp(0.0, f64::MIN, f64::MAX);
+    let above_zero = f64::lerp(f64::EPSILON, f64::MIN, f64::MAX);
+    assert!(below_zero <= zero);
+    assert!(zero <= above_zero);
+    assert!(below_zero <= above_zero);
+
+    // near 1
+    let below_one = f64::lerp(1.0 - f64::EPSILON, f64::MIN, f64::MAX);
+    let one = f64::lerp(1.0, f64::MIN, f64::MAX);
+    let above_one = f64::lerp(1.0 + f64::EPSILON, f64::MIN, f64::MAX);
+    assert!(below_one <= one);
+    assert!(one <= above_one);
+    assert!(below_one <= above_one);
+}

From 525d76026fe855f6a9de4604d9fee50d974994a3 Mon Sep 17 00:00:00 2001
From: ltdk <usr@ltdk.xyz>
Date: Sun, 13 Jun 2021 14:04:43 -0400
Subject: [PATCH 05/10] Change tracking issue

---
 library/std/src/f32.rs | 2 +-
 library/std/src/f64.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 00cab72564f94..21bd79611a5e5 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -901,7 +901,7 @@ impl f32 {
     ///
     /// [finite]: #method.is_finite
     #[must_use = "method returns a new number and does not mutate the original value"]
-    #[unstable(feature = "float_interpolation", issue = "71015")]
+    #[unstable(feature = "float_interpolation", issue = "86269")]
     pub fn lerp(self, start: f32, end: f32) -> f32 {
         // consistent
         if start == end {
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index ff41f999dd565..8c8cf73741b51 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -903,7 +903,7 @@ impl f64 {
     ///
     /// [finite]: #method.is_finite
     #[must_use = "method returns a new number and does not mutate the original value"]
-    #[unstable(feature = "float_interpolation", issue = "71015")]
+    #[unstable(feature = "float_interpolation", issue = "86269")]
     pub fn lerp(self, start: f64, end: f64) -> f64 {
         // consistent
         if start == end {

From 34f38bf76006b0dfdc2784d76e3e1775cee024a4 Mon Sep 17 00:00:00 2001
From: Yuki Okushi <yuki.okushi@huawei.com>
Date: Thu, 17 Jun 2021 09:45:19 +0900
Subject: [PATCH 06/10] Make `s` pre-interned

---
 compiler/rustc_builtin_macros/src/deriving/encodable.rs | 7 +------
 compiler/rustc_span/src/symbol.rs                       | 1 +
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 01a57bea14e3b..c5f3a9d3379a7 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -124,12 +124,7 @@ pub fn expand_deriving_rustc_encodable(
             explicit_self: borrowed_explicit_self(),
             args: vec![(
                 Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
-                // FIXME: we could use `sym::s` here, but making `s` a static
-                // symbol changes the symbol index ordering in a way that makes
-                // ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
-                // fail. The linting code should be fixed so that its output
-                // does not depend on the symbol index ordering.
-                Symbol::intern("s"),
+                sym::s,
             )],
             ret_ty: Literal(Path::new_(
                 pathvec_std!(result::Result),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index a96d37c652d12..862bde3f6a3e8 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1062,6 +1062,7 @@ symbols! {
         rustdoc,
         rustfmt,
         rvalue_static_promotion,
+        s,
         sanitize,
         sanitizer_runtime,
         saturating_add,

From 259bf5f47a7247c3ecf7100845953859d02562b4 Mon Sep 17 00:00:00 2001
From: Maarten de Vries <maarten@de-vri.es>
Date: Wed, 16 Jun 2021 12:37:00 +0200
Subject: [PATCH 07/10] Rely on libc for correct integer types in
 os/unix/net/ancillary.rs.

---
 library/std/src/os/unix/net/ancillary.rs | 110 +++--------------------
 1 file changed, 10 insertions(+), 100 deletions(-)

diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 15ce7056fea34..cd429d1426937 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -32,23 +32,8 @@ pub(super) fn recv_vectored_with_ancillary_from(
         msg.msg_name = &mut msg_name as *mut _ as *mut _;
         msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
         msg.msg_iov = bufs.as_mut_ptr().cast();
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                msg.msg_iovlen = bufs.len() as libc::size_t;
-                msg.msg_controllen = ancillary.buffer.len() as libc::size_t;
-            } else if #[cfg(any(
-                          target_os = "dragonfly",
-                          target_os = "emscripten",
-                          target_os = "freebsd",
-                          all(target_os = "linux", target_env = "musl",),
-                          target_os = "macos",
-                          target_os = "netbsd",
-                          target_os = "openbsd",
-                      ))] {
-                msg.msg_iovlen = bufs.len() as libc::c_int;
-                msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
-            }
-        }
+        msg.msg_iovlen = bufs.len() as _;
+        msg.msg_controllen = ancillary.buffer.len() as _;
         // macos requires that the control pointer is null when the len is 0.
         if msg.msg_controllen > 0 {
             msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
@@ -80,23 +65,8 @@ pub(super) fn send_vectored_with_ancillary_to(
         msg.msg_name = &mut msg_name as *mut _ as *mut _;
         msg.msg_namelen = msg_namelen;
         msg.msg_iov = bufs.as_ptr() as *mut _;
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                msg.msg_iovlen = bufs.len() as libc::size_t;
-                msg.msg_controllen = ancillary.length as libc::size_t;
-            } else if #[cfg(any(
-                          target_os = "dragonfly",
-                          target_os = "emscripten",
-                          target_os = "freebsd",
-                          all(target_os = "linux", target_env = "musl",),
-                          target_os = "macos",
-                          target_os = "netbsd",
-                          target_os = "openbsd",
-                      ))] {
-                msg.msg_iovlen = bufs.len() as libc::c_int;
-                msg.msg_controllen = ancillary.length as libc::socklen_t;
-            }
-        }
+        msg.msg_iovlen = bufs.len() as _;
+        msg.msg_controllen = ancillary.length as _;
         // macos requires that the control pointer is null when the len is 0.
         if msg.msg_controllen > 0 {
             msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
@@ -144,21 +114,7 @@ fn add_to_ancillary_data<T>(
 
         let mut msg: libc::msghdr = zeroed();
         msg.msg_control = buffer.as_mut_ptr().cast();
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                msg.msg_controllen = *length as libc::size_t;
-            } else if #[cfg(any(
-                          target_os = "dragonfly",
-                          target_os = "emscripten",
-                          target_os = "freebsd",
-                          all(target_os = "linux", target_env = "musl",),
-                          target_os = "macos",
-                          target_os = "netbsd",
-                          target_os = "openbsd",
-                      ))] {
-                msg.msg_controllen = *length as libc::socklen_t;
-            }
-        }
+        msg.msg_controllen = *length as _;
 
         let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
         let mut previous_cmsg = cmsg;
@@ -180,21 +136,7 @@ fn add_to_ancillary_data<T>(
 
         (*previous_cmsg).cmsg_level = cmsg_level;
         (*previous_cmsg).cmsg_type = cmsg_type;
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t;
-            } else if #[cfg(any(
-                          target_os = "dragonfly",
-                          target_os = "emscripten",
-                          target_os = "freebsd",
-                          all(target_os = "linux", target_env = "musl",),
-                          target_os = "macos",
-                          target_os = "netbsd",
-                          target_os = "openbsd",
-                      ))] {
-                (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t;
-            }
-        }
+        (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
 
         let data = libc::CMSG_DATA(previous_cmsg).cast();
 
@@ -364,28 +306,10 @@ impl<'a> AncillaryData<'a> {
 
     fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
         unsafe {
-            cfg_if::cfg_if! {
-                if #[cfg(any(
-                        target_os = "android",
-                        all(target_os = "linux", target_env = "gnu"),
-                        all(target_os = "linux", target_env = "uclibc"),
-                   ))] {
-                    let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t;
-                } else if #[cfg(any(
-                              target_os = "dragonfly",
-                              target_os = "emscripten",
-                              target_os = "freebsd",
-                              all(target_os = "linux", target_env = "musl",),
-                              target_os = "macos",
-                              target_os = "netbsd",
-                              target_os = "openbsd",
-                          ))] {
-                    let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t;
-                }
-            }
-            let data_len = (*cmsg).cmsg_len - cmsg_len_zero;
+            let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
+            let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
             let data = libc::CMSG_DATA(cmsg).cast();
-            let data = from_raw_parts(data, data_len as usize);
+            let data = from_raw_parts(data, data_len);
 
             match (*cmsg).cmsg_level {
                 libc::SOL_SOCKET => match (*cmsg).cmsg_type {
@@ -419,21 +343,7 @@ impl<'a> Iterator for Messages<'a> {
         unsafe {
             let mut msg: libc::msghdr = zeroed();
             msg.msg_control = self.buffer.as_ptr() as *mut _;
-            cfg_if::cfg_if! {
-                if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                    msg.msg_controllen = self.buffer.len() as libc::size_t;
-                } else if #[cfg(any(
-                              target_os = "dragonfly",
-                              target_os = "emscripten",
-                              target_os = "freebsd",
-                              all(target_os = "linux", target_env = "musl",),
-                              target_os = "macos",
-                              target_os = "netbsd",
-                              target_os = "openbsd",
-                          ))] {
-                    msg.msg_controllen = self.buffer.len() as libc::socklen_t;
-                }
-            }
+            msg.msg_controllen = self.buffer.len() as _;
 
             let cmsg = if let Some(current) = self.current {
                 libc::CMSG_NXTHDR(&msg, current)

From 2cedd86b1c25db321e7e023f6a429e23425a7e00 Mon Sep 17 00:00:00 2001
From: Fabian Wolff <fabian.wolff@alumni.ethz.ch>
Date: Thu, 17 Jun 2021 16:45:26 +0200
Subject: [PATCH 08/10] Fix ICE when using `#[doc(keyword = "...")]` on
 non-items

---
 compiler/rustc_passes/src/check_attr.rs |  7 +++++--
 src/test/ui/rustdoc/issue-83512.rs      | 10 ++++++++++
 src/test/ui/rustdoc/issue-83512.stderr  |  8 ++++++++
 3 files changed, 23 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ui/rustdoc/issue-83512.rs
 create mode 100644 src/test/ui/rustdoc/issue-83512.stderr

diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index eca84c791fb3f..e85392cf0bda5 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -525,8 +525,11 @@ impl CheckAttrVisitor<'tcx> {
             self.doc_attr_str_error(meta, "keyword");
             return false;
         }
-        match self.tcx.hir().expect_item(hir_id).kind {
-            ItemKind::Mod(ref module) => {
+        match self.tcx.hir().find(hir_id).and_then(|node| match node {
+            hir::Node::Item(item) => Some(&item.kind),
+            _ => None,
+        }) {
+            Some(ItemKind::Mod(ref module)) => {
                 if !module.item_ids.is_empty() {
                     self.tcx
                         .sess
diff --git a/src/test/ui/rustdoc/issue-83512.rs b/src/test/ui/rustdoc/issue-83512.rs
new file mode 100644
index 0000000000000..378f685ed30aa
--- /dev/null
+++ b/src/test/ui/rustdoc/issue-83512.rs
@@ -0,0 +1,10 @@
+// Regression test for the ICE described in #83512.
+
+#![feature(doc_keyword)]
+#![crate_type="lib"]
+
+trait Foo {
+    #[doc(keyword = "match")]
+    //~^ ERROR: `#[doc(keyword = "...")]` can only be used on modules
+    fn quux() {}
+}
diff --git a/src/test/ui/rustdoc/issue-83512.stderr b/src/test/ui/rustdoc/issue-83512.stderr
new file mode 100644
index 0000000000000..da7e480c63e37
--- /dev/null
+++ b/src/test/ui/rustdoc/issue-83512.stderr
@@ -0,0 +1,8 @@
+error: `#[doc(keyword = "...")]` can only be used on modules
+  --> $DIR/issue-83512.rs:7:11
+   |
+LL |     #[doc(keyword = "match")]
+   |           ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+

From e9e844f44cf21bfa9ff8931b9256da57a2dec79f Mon Sep 17 00:00:00 2001
From: Fabian Wolff <fabian.wolff@alumni.ethz.ch>
Date: Thu, 17 Jun 2021 17:28:55 +0200
Subject: [PATCH 09/10] Move regression test for #83512 into doc_keyword.rs

---
 src/test/ui/rustdoc/doc_keyword.rs     |  8 ++++++++
 src/test/ui/rustdoc/doc_keyword.stderr |  8 +++++++-
 src/test/ui/rustdoc/issue-83512.rs     | 10 ----------
 src/test/ui/rustdoc/issue-83512.stderr |  8 --------
 4 files changed, 15 insertions(+), 19 deletions(-)
 delete mode 100644 src/test/ui/rustdoc/issue-83512.rs
 delete mode 100644 src/test/ui/rustdoc/issue-83512.stderr

diff --git a/src/test/ui/rustdoc/doc_keyword.rs b/src/test/ui/rustdoc/doc_keyword.rs
index 4c72e7e96842c..4518f77ef933d 100644
--- a/src/test/ui/rustdoc/doc_keyword.rs
+++ b/src/test/ui/rustdoc/doc_keyword.rs
@@ -10,3 +10,11 @@ mod foo {
 
 #[doc(keyword = "hall")] //~ ERROR
 fn foo() {}
+
+
+// Regression test for the ICE described in #83512.
+trait Foo {
+    #[doc(keyword = "match")]
+    //~^ ERROR: `#[doc(keyword = "...")]` can only be used on modules
+    fn quux() {}
+}
diff --git a/src/test/ui/rustdoc/doc_keyword.stderr b/src/test/ui/rustdoc/doc_keyword.stderr
index 0679bb8c5a7a6..6ba7034d54122 100644
--- a/src/test/ui/rustdoc/doc_keyword.stderr
+++ b/src/test/ui/rustdoc/doc_keyword.stderr
@@ -10,11 +10,17 @@ error: `#[doc(keyword = "...")]` can only be used on modules
 LL | #[doc(keyword = "hall")]
    |       ^^^^^^^^^^^^^^^^
 
+error: `#[doc(keyword = "...")]` can only be used on modules
+  --> $DIR/doc_keyword.rs:17:11
+   |
+LL |     #[doc(keyword = "match")]
+   |           ^^^^^^^^^^^^^^^^^
+
 error: `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute
   --> $DIR/doc_keyword.rs:4:8
    |
 LL | #![doc(keyword = "hello")]
    |        ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/rustdoc/issue-83512.rs b/src/test/ui/rustdoc/issue-83512.rs
deleted file mode 100644
index 378f685ed30aa..0000000000000
--- a/src/test/ui/rustdoc/issue-83512.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Regression test for the ICE described in #83512.
-
-#![feature(doc_keyword)]
-#![crate_type="lib"]
-
-trait Foo {
-    #[doc(keyword = "match")]
-    //~^ ERROR: `#[doc(keyword = "...")]` can only be used on modules
-    fn quux() {}
-}
diff --git a/src/test/ui/rustdoc/issue-83512.stderr b/src/test/ui/rustdoc/issue-83512.stderr
deleted file mode 100644
index da7e480c63e37..0000000000000
--- a/src/test/ui/rustdoc/issue-83512.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `#[doc(keyword = "...")]` can only be used on modules
-  --> $DIR/issue-83512.rs:7:11
-   |
-LL |     #[doc(keyword = "match")]
-   |           ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-

From 3fbac90c4d3b8db48d1f4e5634135b0d22723f16 Mon Sep 17 00:00:00 2001
From: Felix S Klock II <pnkfelix@pnkfx.org>
Date: Thu, 17 Jun 2021 12:45:50 -0400
Subject: [PATCH 10/10] Update RELEASES.md

---
 RELEASES.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/RELEASES.md b/RELEASES.md
index 9001f9c4b00f0..4b753a2b32fff 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -113,6 +113,7 @@ Compatibility Notes
   In particular, this was known to be a problem in the `lexical-core` crate,
   but they have published fixes for semantic versions 0.4 through 0.7. To
   update this dependency alone, use `cargo update -p lexical-core`.
+- Incremental compilation remains off by default, unless one uses the `RUSTC_FORCE_INCREMENTAL=1` environment variable added in 1.52.1.
 
 Internal Only
 -------------