From c24fb126e7cdd73163af67c264bf626aebbeee84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 29 Jul 2018 07:00:13 +0300 Subject: [PATCH 01/34] duration div mul extras --- src/libcore/time.rs | 115 ++++++++++++++++++++++++++++++++++++++++++++ src/libstd/time.rs | 26 ++++++++++ 2 files changed, 141 insertions(+) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 54973b7b7783a..fcd2726b84dea 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -24,6 +24,7 @@ use fmt; use iter::Sum; use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; +use {u64, u128}; const NANOS_PER_SEC: u32 = 1_000_000_000; const NANOS_PER_MILLI: u32 = 1_000_000; @@ -501,6 +502,67 @@ impl Mul for Duration { } } +#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +impl Mul for u32 { + type Output = Duration; + + fn mul(self, rhs: Duration) -> Duration { + rhs.checked_mul(self).expect("overflow when multiplying scalar by duration") + } +} + +#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +impl Mul for Duration { + type Output = Duration; + + fn mul(self, rhs: f64) -> Duration { + const NPS: f64 = NANOS_PER_SEC as f64; + let nanos_f64 = rhs * (NPS * (self.secs as f64) + (self.nanos as f64)); + if !nanos_f64.is_finite() { + panic!("got non-finite value when multiplying duration by float"); + } + if nanos_f64 > (u128::MAX as f64) { + panic!("overflow when multiplying duration by float"); + }; + let nanos_u128 = nanos_f64 as u128; + let secs = nanos_u128 / (NANOS_PER_SEC as u128); + let nanos = nanos_u128 % (NANOS_PER_SEC as u128); + if secs > (u64::MAX as u128) { + panic!("overflow when multiplying duration by float"); + } + Duration { + secs: secs as u64, + nanos: nanos as u32, + } + } +} + +#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +impl Mul for f64 { + type Output = Duration; + + fn mul(self, rhs: Duration) -> Duration { + const NPS: f64 = NANOS_PER_SEC as f64; + let nanos_f64 = self * (NPS * (rhs.secs as f64) + (rhs.nanos as f64)); + if !nanos_f64.is_finite() { + panic!("got non-finite value when multiplying float by duration"); + } + if nanos_f64 > (u128::MAX as f64) { + panic!("overflow when multiplying float by duration"); + }; + let nanos_u128 = nanos_f64 as u128; + let secs = nanos_u128 / (NANOS_PER_SEC as u128); + let nanos = nanos_u128 % (NANOS_PER_SEC as u128); + if secs > (u64::MAX as u128) { + panic!("overflow when multiplying float by duration"); + } + Duration { + secs: secs as u64, + nanos: nanos as u32, + } + } +} + #[stable(feature = "time_augmented_assignment", since = "1.9.0")] impl MulAssign for Duration { fn mul_assign(&mut self, rhs: u32) { @@ -508,6 +570,13 @@ impl MulAssign for Duration { } } +#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +impl MulAssign for Duration { + fn mul_assign(&mut self, rhs: f64) { + *self = *self * rhs; + } +} + #[stable(feature = "duration", since = "1.3.0")] impl Div for Duration { type Output = Duration; @@ -517,6 +586,44 @@ impl Div for Duration { } } +#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +impl Div for Duration { + type Output = Duration; + + fn div(self, rhs: f64) -> Duration { + const NPS: f64 = NANOS_PER_SEC as f64; + let nanos_f64 = (NPS * (self.secs as f64) + (self.nanos as f64)) / rhs; + if !nanos_f64.is_finite() { + panic!("got non-finite value when dividing duration by float"); + } + if nanos_f64 > (u128::MAX as f64) { + panic!("overflow when dividing duration by float"); + }; + let nanos_u128 = nanos_f64 as u128; + let secs = nanos_u128 / (NANOS_PER_SEC as u128); + let nanos = nanos_u128 % (NANOS_PER_SEC as u128); + if secs > (u64::MAX as u128) { + panic!("overflow when dividing duration by float"); + } + Duration { + secs: secs as u64, + nanos: nanos as u32, + } + } +} + +#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +impl Div for Duration { + type Output = f64; + + fn div(self, rhs: Duration) -> f64 { + const NPS: f64 = NANOS_PER_SEC as f64; + let nanos1 = NPS * (self.secs as f64) + (self.nanos as f64); + let nanos2 = NPS * (rhs.secs as f64) + (rhs.nanos as f64); + nanos1/nanos2 + } +} + #[stable(feature = "time_augmented_assignment", since = "1.9.0")] impl DivAssign for Duration { fn div_assign(&mut self, rhs: u32) { @@ -524,6 +631,14 @@ impl DivAssign for Duration { } } +#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +impl DivAssign for Duration { + fn div_assign(&mut self, rhs: f64) { + *self = *self / rhs; + } +} + + macro_rules! sum_durations { ($iter:expr) => {{ let mut total_secs: u64 = 0; diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 90ab349159915..640902426cdd2 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -590,4 +590,30 @@ mod tests { let hundred_twenty_years = thirty_years * 4; assert!(a < hundred_twenty_years); } + + #[test] + fn duration_float_ops() { + let dur = Duration::new(2, 700_000_000); + + let dur2 = 3.14*dur; + assert_eq!(dur2, dur*3.14); + assert_eq!(dur2.as_secs(), 8); + assert_eq!(dur2.subsec_nanos(), 478_000_000); + + let dur3 = 3.14e5*dur; + assert_eq!(dur3, dur*3.14e5); + assert_eq!(dur3.as_secs(), 847_800); + assert_eq!(dur3.subsec_nanos(), 0); + + let dur4 = dur/3.14; + assert_eq!(dur4.as_secs(), 0); + assert_eq!(dur4.subsec_nanos(), 859_872_611); + + let dur5 = dur/3.14e5; + assert_eq!(dur5.as_secs(), 0); + // we are using truncation and not rounding + assert_eq!(dur5.subsec_nanos(), 8598); + + assert_eq!(dur/Duration::new(5, 400_000_000), 0.5); + } } From 12d8f2792a677e3e3beabec780cb2d93719095f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 29 Jul 2018 07:35:52 +0300 Subject: [PATCH 02/34] review update --- src/libcore/time.rs | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index fcd2726b84dea..56e45146f5911 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -21,10 +21,9 @@ //! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); //! ``` -use fmt; +use {fmt, u64}; use iter::Sum; use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; -use {u64, u128}; const NANOS_PER_SEC: u32 = 1_000_000_000; const NANOS_PER_MILLI: u32 = 1_000_000; @@ -517,22 +516,20 @@ impl Mul for Duration { fn mul(self, rhs: f64) -> Duration { const NPS: f64 = NANOS_PER_SEC as f64; + if rhs.is_sign_negative() { + panic!("duration can not be multiplied by negative float"); + } let nanos_f64 = rhs * (NPS * (self.secs as f64) + (self.nanos as f64)); if !nanos_f64.is_finite() { panic!("got non-finite value when multiplying duration by float"); } - if nanos_f64 > (u128::MAX as f64) { + if nanos_f64 > ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64 { panic!("overflow when multiplying duration by float"); }; let nanos_u128 = nanos_f64 as u128; - let secs = nanos_u128 / (NANOS_PER_SEC as u128); - let nanos = nanos_u128 % (NANOS_PER_SEC as u128); - if secs > (u64::MAX as u128) { - panic!("overflow when multiplying duration by float"); - } Duration { - secs: secs as u64, - nanos: nanos as u32, + secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, } } } @@ -543,22 +540,20 @@ impl Mul for f64 { fn mul(self, rhs: Duration) -> Duration { const NPS: f64 = NANOS_PER_SEC as f64; + if self.is_sign_negative() { + panic!("duration can not be multiplied by negative float"); + } let nanos_f64 = self * (NPS * (rhs.secs as f64) + (rhs.nanos as f64)); if !nanos_f64.is_finite() { panic!("got non-finite value when multiplying float by duration"); } - if nanos_f64 > (u128::MAX as f64) { + if nanos_f64 > ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64 { panic!("overflow when multiplying float by duration"); }; let nanos_u128 = nanos_f64 as u128; - let secs = nanos_u128 / (NANOS_PER_SEC as u128); - let nanos = nanos_u128 % (NANOS_PER_SEC as u128); - if secs > (u64::MAX as u128) { - panic!("overflow when multiplying float by duration"); - } Duration { - secs: secs as u64, - nanos: nanos as u32, + secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, } } } @@ -592,22 +587,20 @@ impl Div for Duration { fn div(self, rhs: f64) -> Duration { const NPS: f64 = NANOS_PER_SEC as f64; + if rhs.is_sign_negative() { + panic!("duration can not be divided by negative float"); + } let nanos_f64 = (NPS * (self.secs as f64) + (self.nanos as f64)) / rhs; if !nanos_f64.is_finite() { panic!("got non-finite value when dividing duration by float"); } - if nanos_f64 > (u128::MAX as f64) { + if nanos_f64 > ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64 { panic!("overflow when dividing duration by float"); }; let nanos_u128 = nanos_f64 as u128; - let secs = nanos_u128 / (NANOS_PER_SEC as u128); - let nanos = nanos_u128 % (NANOS_PER_SEC as u128); - if secs > (u64::MAX as u128) { - panic!("overflow when dividing duration by float"); - } Duration { - secs: secs as u64, - nanos: nanos as u32, + secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, } } } From 3e07236a31950aa8e6a4c66066de02d1bca68ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 29 Jul 2018 16:01:43 +0300 Subject: [PATCH 03/34] add MAX_NANOS_F64 constant --- src/libcore/time.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 56e45146f5911..4777b4356376b 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -30,6 +30,7 @@ const NANOS_PER_MILLI: u32 = 1_000_000; const NANOS_PER_MICRO: u32 = 1_000; const MILLIS_PER_SEC: u64 = 1_000; const MICROS_PER_SEC: u64 = 1_000_000; +const MAX_NANOS_F64: f64 = ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64; /// A `Duration` type to represent a span of time, typically used for system /// timeouts. @@ -523,7 +524,7 @@ impl Mul for Duration { if !nanos_f64.is_finite() { panic!("got non-finite value when multiplying duration by float"); } - if nanos_f64 > ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64 { + if nanos_f64 > MAX_NANOS_F64 { panic!("overflow when multiplying duration by float"); }; let nanos_u128 = nanos_f64 as u128; @@ -547,7 +548,7 @@ impl Mul for f64 { if !nanos_f64.is_finite() { panic!("got non-finite value when multiplying float by duration"); } - if nanos_f64 > ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64 { + if nanos_f64 > MAX_NANOS_F64 { panic!("overflow when multiplying float by duration"); }; let nanos_u128 = nanos_f64 as u128; @@ -594,7 +595,7 @@ impl Div for Duration { if !nanos_f64.is_finite() { panic!("got non-finite value when dividing duration by float"); } - if nanos_f64 > ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64 { + if nanos_f64 > MAX_NANOS_F64 { panic!("overflow when dividing duration by float"); }; let nanos_u128 = nanos_f64 as u128; From 2c300fa15b65e75ca07ada06819502ced7d80882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 30 Jul 2018 12:12:52 +0300 Subject: [PATCH 04/34] change negativity check --- src/libcore/time.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 4777b4356376b..cd98f51f5cdb7 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -517,16 +517,16 @@ impl Mul for Duration { fn mul(self, rhs: f64) -> Duration { const NPS: f64 = NANOS_PER_SEC as f64; - if rhs.is_sign_negative() { - panic!("duration can not be multiplied by negative float"); - } let nanos_f64 = rhs * (NPS * (self.secs as f64) + (self.nanos as f64)); if !nanos_f64.is_finite() { panic!("got non-finite value when multiplying duration by float"); } if nanos_f64 > MAX_NANOS_F64 { panic!("overflow when multiplying duration by float"); - }; + } + if nanos_f64 < 0.0 { + panic!("underflow when multiplying duration by float"); + } let nanos_u128 = nanos_f64 as u128; Duration { secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, @@ -541,16 +541,16 @@ impl Mul for f64 { fn mul(self, rhs: Duration) -> Duration { const NPS: f64 = NANOS_PER_SEC as f64; - if self.is_sign_negative() { - panic!("duration can not be multiplied by negative float"); - } let nanos_f64 = self * (NPS * (rhs.secs as f64) + (rhs.nanos as f64)); if !nanos_f64.is_finite() { panic!("got non-finite value when multiplying float by duration"); } if nanos_f64 > MAX_NANOS_F64 { panic!("overflow when multiplying float by duration"); - }; + } + if nanos_f64 < 0.0 { + panic!("underflow when multiplying float by duration"); + } let nanos_u128 = nanos_f64 as u128; Duration { secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, @@ -588,16 +588,16 @@ impl Div for Duration { fn div(self, rhs: f64) -> Duration { const NPS: f64 = NANOS_PER_SEC as f64; - if rhs.is_sign_negative() { - panic!("duration can not be divided by negative float"); - } let nanos_f64 = (NPS * (self.secs as f64) + (self.nanos as f64)) / rhs; if !nanos_f64.is_finite() { panic!("got non-finite value when dividing duration by float"); } if nanos_f64 > MAX_NANOS_F64 { panic!("overflow when dividing duration by float"); - }; + } + if nanos_f64 < 0.0 { + panic!("underflow when multiplying duration by float"); + } let nanos_u128 = nanos_f64 as u128; Duration { secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, From 2cab0deb97a09ace497c16303095f9905e1d6807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Tue, 31 Jul 2018 04:07:11 +0300 Subject: [PATCH 05/34] don't duplicate impls --- src/libcore/time.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index cd98f51f5cdb7..fff47ac44ef69 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -507,7 +507,7 @@ impl Mul for u32 { type Output = Duration; fn mul(self, rhs: Duration) -> Duration { - rhs.checked_mul(self).expect("overflow when multiplying scalar by duration") + rhs * self } } @@ -540,22 +540,7 @@ impl Mul for f64 { type Output = Duration; fn mul(self, rhs: Duration) -> Duration { - const NPS: f64 = NANOS_PER_SEC as f64; - let nanos_f64 = self * (NPS * (rhs.secs as f64) + (rhs.nanos as f64)); - if !nanos_f64.is_finite() { - panic!("got non-finite value when multiplying float by duration"); - } - if nanos_f64 > MAX_NANOS_F64 { - panic!("overflow when multiplying float by duration"); - } - if nanos_f64 < 0.0 { - panic!("underflow when multiplying float by duration"); - } - let nanos_u128 = nanos_f64 as u128; - Duration { - secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, - } + rhs * self } } From d48a649a17401d5c5fc25e9484b41f8b4643e6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sat, 4 Aug 2018 00:47:13 +0300 Subject: [PATCH 06/34] 1.29.0 -> 1.30.0 --- src/libcore/time.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index fff47ac44ef69..6ab8e18adc8ed 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -502,7 +502,7 @@ impl Mul for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] impl Mul for u32 { type Output = Duration; @@ -511,7 +511,7 @@ impl Mul for u32 { } } -#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] impl Mul for Duration { type Output = Duration; @@ -535,7 +535,7 @@ impl Mul for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] impl Mul for f64 { type Output = Duration; @@ -551,7 +551,7 @@ impl MulAssign for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] impl MulAssign for Duration { fn mul_assign(&mut self, rhs: f64) { *self = *self * rhs; @@ -567,7 +567,7 @@ impl Div for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] impl Div for Duration { type Output = Duration; @@ -591,7 +591,7 @@ impl Div for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] impl Div for Duration { type Output = f64; @@ -610,7 +610,7 @@ impl DivAssign for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.29.0")] +#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] impl DivAssign for Duration { fn div_assign(&mut self, rhs: f64) { *self = *self / rhs; From 0673417daa13cc926e2cf618627675e76730e3f8 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Sep 2018 11:50:46 +0300 Subject: [PATCH 07/34] Move float ops to unstable inherent methods --- src/libcore/time.rs | 167 ++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 84 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 6ab8e18adc8ed..64cb13c7eae75 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -459,6 +459,88 @@ impl Duration { None } } + + /// Multiply `Duration` by `f64`. + /// + /// # Examples + /// ``` + /// let dur = Duration::new(2, 700_000_000); + /// assert_eq!(dur.mul_f64(3.14), Duration::new(8, 478_000_000)); + /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0)); + /// ``` + #[unstable(feature = "duration_float_ops", + reason = "duration/floats operations are unstabe", + issue = "0")] + #[inline] + pub fn mul_f64(self, rhs: f64) -> Duration { + const NPS: f64 = NANOS_PER_SEC as f64; + let nanos_f64 = rhs * (NPS * (self.secs as f64) + (self.nanos as f64)); + if !nanos_f64.is_finite() { + panic!("got non-finite value when multiplying duration by float"); + } + if nanos_f64 > MAX_NANOS_F64 { + panic!("overflow when multiplying duration by float"); + } + if nanos_f64 < 0.0 { + panic!("underflow when multiplying duration by float"); + } + let nanos_u128 = nanos_f64 as u128; + Duration { + secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, + } + } + + /// Divide `Duration` by `f64`. + /// + /// # Examples + /// ``` + /// let dur = Duration::new(2, 700_000_000); + /// assert_eq!(dur.div_f64(3.14), Duration::new(0, 859_872_611)); + /// // note that truncation is used, not rounding + /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598)); + /// ``` + #[unstable(feature = "duration_float_ops", + reason = "duration/floats operations are unstabe", + issue = "0")] + #[inline] + pub fn div_f64(self, rhs: f64) -> Duration { + const NPS: f64 = NANOS_PER_SEC as f64; + let nanos_f64 = (NPS * (self.secs as f64) + (self.nanos as f64)) / rhs; + if !nanos_f64.is_finite() { + panic!("got non-finite value when dividing duration by float"); + } + if nanos_f64 > MAX_NANOS_F64 { + panic!("overflow when dividing duration by float"); + } + if nanos_f64 < 0.0 { + panic!("underflow when multiplying duration by float"); + } + let nanos_u128 = nanos_f64 as u128; + Duration { + secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, + } + } + + /// Divide `Duration` by `Duration` and return `f64`. + /// + /// # Examples + /// ``` + /// let dur1 = Duration::new(2, 700_000_000); + /// let dur2 = Duration::new(5, 400_000_000); + /// assert_eq!(dur1.div_duration(dur2), 0.5); + /// ``` + #[unstable(feature = "duration_float_ops", + reason = "duration/floats operations are unstabe", + issue = "0")] + #[inline] + pub fn div_duration(self, rhs: Duration) -> f64 { + const NPS: f64 = NANOS_PER_SEC as f64; + let nanos1 = NPS * (self.secs as f64) + (self.nanos as f64); + let nanos2 = NPS * (rhs.secs as f64) + (rhs.nanos as f64); + nanos1/nanos2 + } } #[stable(feature = "duration", since = "1.3.0")] @@ -502,7 +584,7 @@ impl Mul for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] +#[stable(feature = "symmetric_u32_duration_mul", since = "1.30.0")] impl Mul for u32 { type Output = Duration; @@ -511,39 +593,6 @@ impl Mul for u32 { } } -#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] -impl Mul for Duration { - type Output = Duration; - - fn mul(self, rhs: f64) -> Duration { - const NPS: f64 = NANOS_PER_SEC as f64; - let nanos_f64 = rhs * (NPS * (self.secs as f64) + (self.nanos as f64)); - if !nanos_f64.is_finite() { - panic!("got non-finite value when multiplying duration by float"); - } - if nanos_f64 > MAX_NANOS_F64 { - panic!("overflow when multiplying duration by float"); - } - if nanos_f64 < 0.0 { - panic!("underflow when multiplying duration by float"); - } - let nanos_u128 = nanos_f64 as u128; - Duration { - secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, - } - } -} - -#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] -impl Mul for f64 { - type Output = Duration; - - fn mul(self, rhs: Duration) -> Duration { - rhs * self - } -} - #[stable(feature = "time_augmented_assignment", since = "1.9.0")] impl MulAssign for Duration { fn mul_assign(&mut self, rhs: u32) { @@ -551,13 +600,6 @@ impl MulAssign for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] -impl MulAssign for Duration { - fn mul_assign(&mut self, rhs: f64) { - *self = *self * rhs; - } -} - #[stable(feature = "duration", since = "1.3.0")] impl Div for Duration { type Output = Duration; @@ -567,42 +609,6 @@ impl Div for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] -impl Div for Duration { - type Output = Duration; - - fn div(self, rhs: f64) -> Duration { - const NPS: f64 = NANOS_PER_SEC as f64; - let nanos_f64 = (NPS * (self.secs as f64) + (self.nanos as f64)) / rhs; - if !nanos_f64.is_finite() { - panic!("got non-finite value when dividing duration by float"); - } - if nanos_f64 > MAX_NANOS_F64 { - panic!("overflow when dividing duration by float"); - } - if nanos_f64 < 0.0 { - panic!("underflow when multiplying duration by float"); - } - let nanos_u128 = nanos_f64 as u128; - Duration { - secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, - } - } -} - -#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] -impl Div for Duration { - type Output = f64; - - fn div(self, rhs: Duration) -> f64 { - const NPS: f64 = NANOS_PER_SEC as f64; - let nanos1 = NPS * (self.secs as f64) + (self.nanos as f64); - let nanos2 = NPS * (rhs.secs as f64) + (rhs.nanos as f64); - nanos1/nanos2 - } -} - #[stable(feature = "time_augmented_assignment", since = "1.9.0")] impl DivAssign for Duration { fn div_assign(&mut self, rhs: u32) { @@ -610,13 +616,6 @@ impl DivAssign for Duration { } } -#[stable(feature = "duration_mul_div_extras", since = "1.30.0")] -impl DivAssign for Duration { - fn div_assign(&mut self, rhs: f64) { - *self = *self / rhs; - } -} - macro_rules! sum_durations { ($iter:expr) => {{ From 36dff2a5dec66d783ca575495c7af051f2d7de0c Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Sep 2018 11:51:33 +0300 Subject: [PATCH 08/34] Remove tests --- src/libstd/time.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 640902426cdd2..90ab349159915 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -590,30 +590,4 @@ mod tests { let hundred_twenty_years = thirty_years * 4; assert!(a < hundred_twenty_years); } - - #[test] - fn duration_float_ops() { - let dur = Duration::new(2, 700_000_000); - - let dur2 = 3.14*dur; - assert_eq!(dur2, dur*3.14); - assert_eq!(dur2.as_secs(), 8); - assert_eq!(dur2.subsec_nanos(), 478_000_000); - - let dur3 = 3.14e5*dur; - assert_eq!(dur3, dur*3.14e5); - assert_eq!(dur3.as_secs(), 847_800); - assert_eq!(dur3.subsec_nanos(), 0); - - let dur4 = dur/3.14; - assert_eq!(dur4.as_secs(), 0); - assert_eq!(dur4.subsec_nanos(), 859_872_611); - - let dur5 = dur/3.14e5; - assert_eq!(dur5.as_secs(), 0); - // we are using truncation and not rounding - assert_eq!(dur5.subsec_nanos(), 8598); - - assert_eq!(dur/Duration::new(5, 400_000_000), 0.5); - } } From 206ca68ff38604325b4479f8b66cbd50cf4c693b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Sep 2018 11:52:19 +0300 Subject: [PATCH 09/34] remove newline --- src/libcore/time.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 64cb13c7eae75..db5d948087814 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -616,7 +616,6 @@ impl DivAssign for Duration { } } - macro_rules! sum_durations { ($iter:expr) => {{ let mut total_secs: u64 = 0; From 07c15ea64552bdf78bcbb5224331c03cec7e37a2 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Sep 2018 11:56:39 +0300 Subject: [PATCH 10/34] more explicit impl --- src/libcore/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index db5d948087814..e85ac33a4196e 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -589,7 +589,7 @@ impl Mul for u32 { type Output = Duration; fn mul(self, rhs: Duration) -> Duration { - rhs * self + rhs.checked_mul(self).expect("overflow when multiplying scalar by duration") } } From c5cbea69aa4426f8b1929e2a907ee48c34013047 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Sep 2018 14:17:36 +0300 Subject: [PATCH 11/34] fix doctests --- src/libcore/time.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e85ac33a4196e..294c999269740 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -464,6 +464,8 @@ impl Duration { /// /// # Examples /// ``` + /// use std::time::Duration; + /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.mul_f64(3.14), Duration::new(8, 478_000_000)); /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0)); @@ -495,6 +497,8 @@ impl Duration { /// /// # Examples /// ``` + /// use std::time::Duration; + /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.div_f64(3.14), Duration::new(0, 859_872_611)); /// // note that truncation is used, not rounding @@ -527,6 +531,8 @@ impl Duration { /// /// # Examples /// ``` + /// use std::time::Duration; + /// /// let dur1 = Duration::new(2, 700_000_000); /// let dur2 = Duration::new(5, 400_000_000); /// assert_eq!(dur1.div_duration(dur2), 0.5); From de49681bffb5084fd04a401460a5c33a7ab5a555 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 18 Aug 2018 13:54:14 +0200 Subject: [PATCH 12/34] Warn about metadata loader errors --- src/librustc_metadata/locator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 9492385957eab..a16171e8455e5 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -617,7 +617,7 @@ impl<'a> Context<'a> { } } Err(err) => { - info!("no metadata found: {}", err); + warn!("no metadata found: {}", err); continue; } }; From 533c0f0d1f0501dbd0ca76fd4231660835d9e83b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Sep 2018 17:10:38 +0300 Subject: [PATCH 13/34] fix tests --- src/libcore/time.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 294c999269740..71eb00781f03b 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -464,6 +464,7 @@ impl Duration { /// /// # Examples /// ``` + /// #![feature(exact_chunks)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); @@ -497,6 +498,7 @@ impl Duration { /// /// # Examples /// ``` + /// #![feature(exact_chunks)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); @@ -531,6 +533,7 @@ impl Duration { /// /// # Examples /// ``` + /// #![feature(exact_chunks)] /// use std::time::Duration; /// /// let dur1 = Duration::new(2, 700_000_000); @@ -595,7 +598,7 @@ impl Mul for u32 { type Output = Duration; fn mul(self, rhs: Duration) -> Duration { - rhs.checked_mul(self).expect("overflow when multiplying scalar by duration") + rhs * self } } From c11281f1888428551ddf9c60d0030deb63be4b78 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Sep 2018 18:33:48 +0300 Subject: [PATCH 14/34] fix tests --- src/libcore/time.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 71eb00781f03b..cddc12ff58177 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -464,7 +464,7 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(exact_chunks)] + /// #![feature(duration_float_ops)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); @@ -498,7 +498,7 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(exact_chunks)] + /// #![feature(duration_float_ops)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); @@ -533,7 +533,7 @@ impl Duration { /// /// # Examples /// ``` - /// #![feature(exact_chunks)] + /// #![feature(duration_float_ops)] /// use std::time::Duration; /// /// let dur1 = Duration::new(2, 700_000_000); From 37972ae3006a1cb67ff94970c2d034063b3eb895 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 13 Sep 2018 00:43:53 +0000 Subject: [PATCH 15/34] add as_float_secs and from_float_secs methods, refactor float methods --- src/libcore/time.rs | 91 +++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index cddc12ff58177..94a167f08f700 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -459,46 +459,77 @@ impl Duration { None } } + + /// Returns the number of seconds contained by this `Duration` as `f64`. + /// + /// The returned value does include the fractional (nanosecond) part of the duration. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 700_000_000); + /// assert_eq!(dur.as_float_secs(), 2.7); + /// ``` + #[unstable(feature = "duration_float", issue = "0")] + #[inline] + pub fn as_float_secs(&self) -> f64 { + (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64) + } + /// Creates a new `Duration` from the specified number of seconds. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::from_float_secs(2.7); + /// assert_eq!(dur, Duration::new(2, 700_000_000)); + /// ``` + #[unstable(feature = "duration_float", issue = "0")] + #[inline] + pub fn from_float_secs(secs: f64) -> Duration { + let nanos = (secs * (NANOS_PER_SEC as f64)) as u128; + Duration { + secs: (nanos / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, + } + } + /// Multiply `Duration` by `f64`. /// /// # Examples /// ``` - /// #![feature(duration_float_ops)] + /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.mul_f64(3.14), Duration::new(8, 478_000_000)); /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0)); /// ``` - #[unstable(feature = "duration_float_ops", - reason = "duration/floats operations are unstabe", - issue = "0")] + #[unstable(feature = "duration_float", issue = "0")] #[inline] pub fn mul_f64(self, rhs: f64) -> Duration { - const NPS: f64 = NANOS_PER_SEC as f64; - let nanos_f64 = rhs * (NPS * (self.secs as f64) + (self.nanos as f64)); - if !nanos_f64.is_finite() { + let secs = rhs * self.as_float_secs(); + if !secs.is_finite() { panic!("got non-finite value when multiplying duration by float"); } - if nanos_f64 > MAX_NANOS_F64 { + if secs > MAX_NANOS_F64 { panic!("overflow when multiplying duration by float"); } - if nanos_f64 < 0.0 { + if secs < 0.0 { panic!("underflow when multiplying duration by float"); } - let nanos_u128 = nanos_f64 as u128; - Duration { - secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, - } + Duration::from_float_secs(secs) } /// Divide `Duration` by `f64`. /// /// # Examples /// ``` - /// #![feature(duration_float_ops)] + /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); @@ -506,49 +537,37 @@ impl Duration { /// // note that truncation is used, not rounding /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598)); /// ``` - #[unstable(feature = "duration_float_ops", - reason = "duration/floats operations are unstabe", - issue = "0")] + #[unstable(feature = "duration_float", issue = "0")] #[inline] pub fn div_f64(self, rhs: f64) -> Duration { - const NPS: f64 = NANOS_PER_SEC as f64; - let nanos_f64 = (NPS * (self.secs as f64) + (self.nanos as f64)) / rhs; - if !nanos_f64.is_finite() { + let secs = self.as_float_secs() / rhs; + if !secs.is_finite() { panic!("got non-finite value when dividing duration by float"); } - if nanos_f64 > MAX_NANOS_F64 { + if secs > MAX_NANOS_F64 { panic!("overflow when dividing duration by float"); } - if nanos_f64 < 0.0 { + if secs < 0.0 { panic!("underflow when multiplying duration by float"); } - let nanos_u128 = nanos_f64 as u128; - Duration { - secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32, - } + Duration::from_float_secs(secs) } /// Divide `Duration` by `Duration` and return `f64`. /// /// # Examples /// ``` - /// #![feature(duration_float_ops)] + /// #![feature(duration_float)] /// use std::time::Duration; /// /// let dur1 = Duration::new(2, 700_000_000); /// let dur2 = Duration::new(5, 400_000_000); /// assert_eq!(dur1.div_duration(dur2), 0.5); /// ``` - #[unstable(feature = "duration_float_ops", - reason = "duration/floats operations are unstabe", - issue = "0")] + #[unstable(feature = "duration_float", issue = "0")] #[inline] pub fn div_duration(self, rhs: Duration) -> f64 { - const NPS: f64 = NANOS_PER_SEC as f64; - let nanos1 = NPS * (self.secs as f64) + (self.nanos as f64); - let nanos2 = NPS * (rhs.secs as f64) + (rhs.nanos as f64); - nanos1/nanos2 + self.as_float_secs()/rhs.as_float_secs() } } From 8a0aa9f3ae2459f15270638add69bdc7619cd327 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 13 Sep 2018 00:52:59 +0000 Subject: [PATCH 16/34] remove trailing spaces --- src/libcore/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 94a167f08f700..b9b45e39e4023 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -459,7 +459,7 @@ impl Duration { None } } - + /// Returns the number of seconds contained by this `Duration` as `f64`. /// /// The returned value does include the fractional (nanosecond) part of the duration. @@ -497,7 +497,7 @@ impl Duration { nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, } } - + /// Multiply `Duration` by `f64`. /// /// # Examples From 9e78cb24461177ee1477abcbda01e3c4158722d1 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 13 Sep 2018 01:40:38 +0000 Subject: [PATCH 17/34] move checks to from_float_secs --- src/libcore/time.rs | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index b9b45e39e4023..f0e4b29700b46 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -30,7 +30,7 @@ const NANOS_PER_MILLI: u32 = 1_000_000; const NANOS_PER_MICRO: u32 = 1_000; const MILLIS_PER_SEC: u64 = 1_000; const MICROS_PER_SEC: u64 = 1_000_000; -const MAX_NANOS_F64: f64 = ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64; +const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128) - 1) as f64; /// A `Duration` type to represent a span of time, typically used for system /// timeouts. @@ -491,7 +491,17 @@ impl Duration { #[unstable(feature = "duration_float", issue = "0")] #[inline] pub fn from_float_secs(secs: f64) -> Duration { - let nanos = (secs * (NANOS_PER_SEC as f64)) as u128; + let nanos = secs * (NANOS_PER_SEC as f64); + if !nanos.is_finite() { + panic!("got non-finite value when converting float to duration"); + } + if nanos > MAX_NANOS_F64 { + panic!("overflow when converting float to duration"); + } + if nanos < 0.0 { + panic!("underflow when converting float to duration"); + } + let nanos = nanos as u128; Duration { secs: (nanos / (NANOS_PER_SEC as u128)) as u64, nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, @@ -512,17 +522,7 @@ impl Duration { #[unstable(feature = "duration_float", issue = "0")] #[inline] pub fn mul_f64(self, rhs: f64) -> Duration { - let secs = rhs * self.as_float_secs(); - if !secs.is_finite() { - panic!("got non-finite value when multiplying duration by float"); - } - if secs > MAX_NANOS_F64 { - panic!("overflow when multiplying duration by float"); - } - if secs < 0.0 { - panic!("underflow when multiplying duration by float"); - } - Duration::from_float_secs(secs) + Duration::from_float_secs(rhs * self.as_float_secs()) } /// Divide `Duration` by `f64`. @@ -540,17 +540,7 @@ impl Duration { #[unstable(feature = "duration_float", issue = "0")] #[inline] pub fn div_f64(self, rhs: f64) -> Duration { - let secs = self.as_float_secs() / rhs; - if !secs.is_finite() { - panic!("got non-finite value when dividing duration by float"); - } - if secs > MAX_NANOS_F64 { - panic!("overflow when dividing duration by float"); - } - if secs < 0.0 { - panic!("underflow when multiplying duration by float"); - } - Duration::from_float_secs(secs) + Duration::from_float_secs(self.as_float_secs() / rhs) } /// Divide `Duration` by `Duration` and return `f64`. @@ -567,7 +557,7 @@ impl Duration { #[unstable(feature = "duration_float", issue = "0")] #[inline] pub fn div_duration(self, rhs: Duration) -> f64 { - self.as_float_secs()/rhs.as_float_secs() + self.as_float_secs() / rhs.as_float_secs() } } From 2aca69757f078ac3aad9c2aff3c357ca35e5c486 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 13 Sep 2018 01:47:08 +0000 Subject: [PATCH 18/34] add panics section to method docs --- src/libcore/time.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index f0e4b29700b46..e2990c8660e75 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -480,6 +480,9 @@ impl Duration { /// Creates a new `Duration` from the specified number of seconds. /// + /// # Panics + /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`. + /// /// # Examples /// ``` /// #![feature(duration_float)] @@ -510,6 +513,9 @@ impl Duration { /// Multiply `Duration` by `f64`. /// + /// # Panics + /// This method will panic if result is not finite, negative or overflows `Duration`. + /// /// # Examples /// ``` /// #![feature(duration_float)] @@ -527,6 +533,9 @@ impl Duration { /// Divide `Duration` by `f64`. /// + /// # Panics + /// This method will panic if result is not finite, negative or overflows `Duration`. + /// /// # Examples /// ``` /// #![feature(duration_float)] From 40e76675065925661f582cd920db1d050dc7e96f Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 14 Sep 2018 19:06:45 +0300 Subject: [PATCH 19/34] Remove LLVM 3.9 workaround. --- src/librustc_codegen_llvm/debuginfo/metadata.rs | 8 +------- src/librustc_codegen_llvm/llvm/ffi.rs | 12 +++--------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 0221cfd9b2c28..706568b544661 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -1803,13 +1803,7 @@ pub fn create_vtable_metadata( llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), NO_SCOPE_METADATA, name.as_ptr(), - // LLVM 3.9 - // doesn't accept - // null here, so - // pass the name - // as the linkage - // name. - name.as_ptr(), + ptr::null(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, vtable_type, diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 6c2601bf1ef12..a5f4137c62b14 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -8,16 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: Rename 'DIGlobalVariable' to 'DIGlobalVariableExpression' -// once support for LLVM 3.9 is dropped. -// -// This method was changed in this LLVM patch: -// https://reviews.llvm.org/D26769 - use super::debuginfo::{ DIBuilder, DIDescriptor, DIFile, DILexicalBlock, DISubprogram, DIType, DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable, - DIGlobalVariable, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator, + DIGlobalVariableExpression, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator, DINameSpace, DIFlags, }; @@ -447,7 +441,7 @@ pub mod debuginfo { pub type DIDerivedType = DIType; pub type DICompositeType = DIDerivedType; pub type DIVariable = DIDescriptor; - pub type DIGlobalVariable = DIDescriptor; + pub type DIGlobalVariableExpression = DIDescriptor; pub type DIArray = DIDescriptor; pub type DISubrange = DIDescriptor; pub type DIEnumerator = DIDescriptor; @@ -1330,7 +1324,7 @@ extern "C" { Val: &'a Value, Decl: Option<&'a DIDescriptor>, AlignInBits: u32) - -> &'a DIGlobalVariable; + -> &'a DIGlobalVariableExpression; pub fn LLVMRustDIBuilderCreateVariable(Builder: &DIBuilder<'a>, Tag: c_uint, From b74215accedd26b57907d3473fa325861b8a2f92 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 15 Sep 2018 09:14:10 -0700 Subject: [PATCH 20/34] Switch wasm math symbols to their original names The names `Math_*` were given to help undefined symbol messages indicate how to implement them, but these are all implemented in compiler-rt now so there's no need to rename them! This change should make it so wasm binaries by default, no matter the math symbols used, will not have unresolved symbols. --- src/libstd/sys/wasm/cmath.rs | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/wasm/cmath.rs index 87ac2091cad41..64fc14d42d9b7 100644 --- a/src/libstd/sys/wasm/cmath.rs +++ b/src/libstd/sys/wasm/cmath.rs @@ -74,46 +74,19 @@ pub unsafe fn tanhf(n: f32) -> f32 { f64::tanh(n as f64) as f32 } -// Right now all these functions, the f64 version of the functions above, all -// shell out to random names. These names aren't actually defined anywhere, per -// se, but we need this to compile somehow. -// -// The idea with this is that when you're using wasm then, for now, we have no -// way of providing an implementation of these which delegates to a "correct" -// implementation. For example most wasm applications probably just want to -// delegate to the javascript `Math` object and its related functions, but wasm -// doesn't currently have the ability to seamlessly do that (when you -// instantiate a module you have to set that up). -// -// As a result these are just defined here with "hopefully helpful" names. The -// symbols won't ever be needed or show up unless these functions are called, -// and hopefully when they're called the errors are self-explanatory enough to -// figure out what's going on. - +// These symbols are all defined in `compiler-builtins` extern { - #[link_name = "Math_acos"] pub fn acos(n: f64) -> f64; - #[link_name = "Math_asin"] pub fn asin(n: f64) -> f64; - #[link_name = "Math_atan"] pub fn atan(n: f64) -> f64; - #[link_name = "Math_atan2"] pub fn atan2(a: f64, b: f64) -> f64; - #[link_name = "Math_cbrt"] pub fn cbrt(n: f64) -> f64; - #[link_name = "Math_cosh"] pub fn cosh(n: f64) -> f64; - #[link_name = "Math_expm1"] pub fn expm1(n: f64) -> f64; pub fn fdim(a: f64, b: f64) -> f64; - #[link_name = "Math_log1p"] pub fn log1p(n: f64) -> f64; - #[link_name = "Math_sinh"] pub fn sinh(n: f64) -> f64; - #[link_name = "Math_tan"] pub fn tan(n: f64) -> f64; - #[link_name = "Math_tanh"] pub fn tanh(n: f64) -> f64; - #[link_name = "Math_hypot"] pub fn hypot(x: f64, y: f64) -> f64; } From 42652565ee7da4053b24ec8cd1e31c0c30ac8174 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 15 Sep 2018 09:15:48 -0700 Subject: [PATCH 21/34] Enable fatal warnings for the wasm32 linker Historically LLD has emitted warnings for various reasons but all the bugs have since been fixed (yay!) and by enabling fatal warnings we should be able to head off bugs like #53390 sooner. --- src/librustc_codegen_llvm/back/linker.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 95be2d82123a7..c03180c02fe63 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -1071,6 +1071,10 @@ impl<'a> Linker for WasmLd<'a> { // Make the default table accessible self.cmd.arg("--export-table"); + // Rust code should never have warnings, and warnings are often + // indicative of bugs, let's prevent them. + self.cmd.arg("--fatal-warnings"); + let mut cmd = Command::new(""); ::std::mem::swap(&mut cmd, &mut self.cmd); cmd From ad8053fe73d39fb7fb7e6d052f0bd005dae31686 Mon Sep 17 00:00:00 2001 From: Lion Yang Date: Sun, 16 Sep 2018 04:30:50 +0800 Subject: [PATCH 22/34] Update LLVM to fix "bool" arguments on PPC32 Fixes #50960. --- src/llvm | 2 +- src/rustllvm/llvm-rebuild-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index 5a081f0363340..caddcd9b9dc94 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 5a081f0363340dd895d0958955d0c84661f60f05 +Subproject commit caddcd9b9dc9479a20908d93c3e47c49b021379e diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index 29b7d508f1c1e..f8ff3d37fd23e 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2018-09-11 +2018-09-16 From 73b3c28a164a03236d2953b2d45770cc049fa7c5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 17 Sep 2018 14:41:09 +0200 Subject: [PATCH 23/34] Switch linker for aarch64-pc-windows-msvc from LLD to MSVC, since that seems to work better. --- src/librustc_target/spec/aarch64_pc_windows_msvc.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs index 8747f239d3418..c71ad5ff21da0 100644 --- a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs +++ b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use spec::{LinkerFlavor, Target, TargetResult, PanicStrategy, LldFlavor}; +use spec::{LinkerFlavor, Target, TargetResult, PanicStrategy}; pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); @@ -17,7 +17,6 @@ pub fn target() -> TargetResult { // FIXME: this shouldn't be panic=abort, it should be panic=unwind base.panic_strategy = PanicStrategy::Abort; - base.linker = Some("rust-lld".to_owned()); Ok(Target { llvm_target: "aarch64-pc-windows-msvc".to_string(), @@ -29,7 +28,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "msvc".to_string(), target_vendor: "pc".to_string(), - linker_flavor: LinkerFlavor::Lld(LldFlavor::Link), + linker_flavor: LinkerFlavor::Msvc, options: base, }) } From 30556d592e5f2702fd578d289bed7a7a4facbf98 Mon Sep 17 00:00:00 2001 From: memoryruins Date: Mon, 17 Sep 2018 09:09:45 -0400 Subject: [PATCH 24/34] Suggest array indexing when tuple indexing on an array. --- src/librustc_typeck/check/mod.rs | 6 ++++++ src/test/ui/issues/issue-53712.rs | 9 +++++++++ src/test/ui/issues/issue-53712.stderr | 9 +++++++++ 3 files changed, 24 insertions(+) create mode 100644 src/test/ui/issues/issue-53712.rs create mode 100644 src/test/ui/issues/issue-53712.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aa27fe528e1fd..89ab085b03481 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3344,6 +3344,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; } + ty::Array(ty, _) if ty.is_numeric() => { + let base = self.tcx.hir.node_to_pretty_string(base.id); + let msg = format!("attempting to use tuple indexing on an array; try"); + let suggestion = format!("{}[{}]", base, field); + err.span_suggestion(field.span, &msg, suggestion); + }, ty::RawPtr(..) => { let base = self.tcx.hir.node_to_pretty_string(base.id); let msg = format!("`{}` is a native pointer; try dereferencing it", base); diff --git a/src/test/ui/issues/issue-53712.rs b/src/test/ui/issues/issue-53712.rs new file mode 100644 index 0000000000000..c8b54c2d4beb4 --- /dev/null +++ b/src/test/ui/issues/issue-53712.rs @@ -0,0 +1,9 @@ +// issue #53712: make the error generated by using tuple indexing on an array more specific + +fn main() { + let arr = [10, 20, 30, 40, 50]; + arr.0; + //~^ ERROR no field `0` on type `[{integer}; 5]` [E0609] + //~| HELP attempting to use tuple indexing on an array; try + //~| SUGGESTION arr[0] +} diff --git a/src/test/ui/issues/issue-53712.stderr b/src/test/ui/issues/issue-53712.stderr new file mode 100644 index 0000000000000..ef885a438c827 --- /dev/null +++ b/src/test/ui/issues/issue-53712.stderr @@ -0,0 +1,9 @@ +error[E0609]: no field `0` on type `[{integer}; 5]` + --> $DIR/issue-53712.rs:5:9 + | +LL | arr.0; + | ^ help: attempting to use tuple indexing on an array; try: `arr[0]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`. From 56c151920306fe5f401d39f8ad6a6ce8d9ca7391 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 18:05:17 +0200 Subject: [PATCH 25/34] miri: correctly compute expected alignment for field --- src/librustc_mir/interpret/place.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index e3f7f26f53efd..0f03aa097c9df 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -316,7 +316,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { }; let ptr = base.ptr.ptr_offset(offset, self)?; - let align = base.align.min(field_layout.align); // only use static information + let align = base.align + // We do not look at `base.layout.align` nor `field_layout.align`, unlike + // codegen -- mostly to see if we can get away with that + .restrict_for_offset(offset); // must be last thing that happens Ok(MPlaceTy { mplace: MemPlace { ptr, align, extra }, layout: field_layout }) } From a8ec8e5cb703a5904e8ea96dc4a7b2d96aa25f57 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 12 Sep 2018 16:57:19 +0200 Subject: [PATCH 26/34] A few cleanups and minor improvements to rustc/traits --- src/librustc/traits/auto_trait.rs | 18 +- src/librustc/traits/codegen/mod.rs | 31 +- src/librustc/traits/coherence.rs | 21 +- src/librustc/traits/error_reporting.rs | 145 ++++---- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/mod.rs | 12 +- src/librustc/traits/object_safety.rs | 44 +-- src/librustc/traits/on_unimplemented.rs | 18 +- src/librustc/traits/project.rs | 82 ++--- src/librustc/traits/query/dropck_outlives.rs | 32 +- src/librustc/traits/query/normalize.rs | 40 +- src/librustc/traits/select.rs | 341 +++++++++--------- src/librustc/traits/specialize/mod.rs | 29 +- .../traits/specialize/specialization_graph.rs | 9 +- src/librustc/traits/structural_impls.rs | 42 +-- src/librustc/traits/util.rs | 3 +- src/librustc/ty/trait_def.rs | 9 + src/librustc_typeck/check/closure.rs | 2 +- 18 files changed, 414 insertions(+), 466 deletions(-) diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index ed95aa73078a9..4bed3c5935cd7 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -112,6 +112,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { orig_params, trait_pred.to_poly_trait_predicate(), )); + match result { Ok(Some(Vtable::VtableImpl(_))) => { debug!( @@ -119,10 +120,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { manual impl found, bailing out", did, trait_did, generics ); - return true; + true } - _ => return false, - }; + _ => false + } }); // If an explicit impl exists, it always takes priority over an auto impl @@ -426,6 +427,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { if new_trait.def_id() == old_trait.def_id() { let new_substs = new_trait.skip_binder().trait_ref.substs; let old_substs = old_trait.skip_binder().trait_ref.substs; + if !new_substs.types().eq(old_substs.types()) { // We can't compare lifetimes if the types are different, // so skip checking old_pred @@ -489,12 +491,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { pub fn get_lifetime(&self, region: Region, names_map: &FxHashMap) -> String { self.region_name(region) - .map(|name| { - names_map.get(&name).unwrap_or_else(|| { + .map(|name| + names_map.get(&name).unwrap_or_else(|| panic!("Missing lifetime with name {:?} for {:?}", name, region) - }) - }) - .unwrap_or(&"'static".to_string()) + ) + ) + .unwrap_or(&"'static".to_owned()) .clone() } diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs index cf404202ac120..4e88150a18acc 100644 --- a/src/librustc/traits/codegen/mod.rs +++ b/src/librustc/traits/codegen/mod.rs @@ -39,7 +39,7 @@ pub fn codegen_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, let trait_ref = ty.erase_regions(&trait_ref); debug!("codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", - (param_env, trait_ref), trait_ref.def_id()); + (param_env, trait_ref), trait_ref.def_id()); // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. @@ -48,8 +48,8 @@ pub fn codegen_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, let obligation_cause = ObligationCause::dummy(); let obligation = Obligation::new(obligation_cause, - param_env, - trait_ref.to_poly_trait_predicate()); + param_env, + trait_ref.to_poly_trait_predicate()); let selection = match selcx.select(&obligation) { Ok(Some(selection)) => selection, @@ -61,12 +61,11 @@ pub fn codegen_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, // overflow bug, since I believe this is the only case // where ambiguity can result. bug!("Encountered ambiguity selecting `{:?}` during codegen, \ - presuming due to overflow", - trait_ref) + presuming due to overflow", + trait_ref) } Err(e) => { - bug!("Encountered error `{:?}` selecting `{:?}` during codegen", - e, trait_ref) + bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) } }; @@ -163,22 +162,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // In principle, we only need to do this so long as `result` // contains unbound type parameters. It could be a slight // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(self) { - Ok(()) => { } - Err(errors) => { - span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", - errors); - } + if let Err(errors) = fulfill_cx.select_all_or_error(self) { + span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", + errors); } let result = self.resolve_type_vars_if_possible(result); let result = self.tcx.erase_regions(&result); - match self.tcx.lift_to_global(&result) { - Some(result) => result, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}`", result); - } - } + self.tcx.lift_to_global(&result).unwrap_or_else(|| + span_bug!(span, "Uninferred types/regions in `{:?}`", result) + ) } } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index b8dd2a12fb58d..251743b0d3bb4 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -115,9 +115,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, b_def_id: DefId) -> Option> { - debug!("overlap(a_def_id={:?}, b_def_id={:?})", - a_def_id, - b_def_id); + debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id); // For the purposes of this check, we don't bring any skolemized // types into scope; instead, we replace the generic types with @@ -133,10 +131,9 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, // Do `a` and `b` unify? If not, no overlap. let obligations = match selcx.infcx().at(&ObligationCause::dummy(), param_env) - .eq_impl_headers(&a_impl_header, &b_impl_header) { - Ok(InferOk { obligations, value: () }) => { - obligations - } + .eq_impl_headers(&a_impl_header, &b_impl_header) + { + Ok(InferOk { obligations, value: () }) => obligations, Err(_) => return None }; @@ -164,7 +161,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, return None } - let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header); + let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header); let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); Some(OverlapResult { impl_header, intercrate_ambiguity_causes }) @@ -471,14 +468,12 @@ fn ty_is_local_constructor(ty: Ty, in_crate: InCrate) -> bool { ty::Foreign(did) => def_id_is_local(did, in_crate), ty::Dynamic(ref tt, ..) => { - tt.principal().map_or(false, |p| { + tt.principal().map_or(false, |p| def_id_is_local(p.def_id(), in_crate) - }) + ) } - ty::Error => { - true - } + ty::Error => true, ty::Closure(..) | ty::Generator(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 466d472cca338..82d4bfa521f4d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -34,6 +34,7 @@ use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use std::fmt; +use std::iter; use syntax::ast; use session::DiagnosticMessageId; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; @@ -58,7 +59,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { index: Option, // None if this is an old error } - let mut error_map : FxHashMap<_, Vec<_>> = + let mut error_map: FxHashMap<_, Vec<_>> = self.reported_trait_errors.borrow().iter().map(|(&span, predicates)| { (span, predicates.iter().map(|predicate| ErrorDescriptor { predicate: predicate.clone(), @@ -80,7 +81,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // We do this in 2 passes because we want to display errors in order, tho // maybe it *is* better to sort errors by span or something. - let mut is_suppressed: Vec = errors.iter().map(|_| false).collect(); + let mut is_suppressed = vec![false; errors.len()]; for (_, error_set) in error_map.iter() { // We want to suppress "duplicate" errors with the same span. for error in error_set { @@ -349,7 +350,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => { // this is a "direct", user-specified, rather than derived, // obligation. - flags.push(("direct".to_string(), None)); + flags.push(("direct".to_owned(), None)); } } @@ -361,24 +362,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Currently I'm leaving it for what I need for `try`. if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { let method = self.tcx.item_name(item); - flags.push(("from_method".to_string(), None)); - flags.push(("from_method".to_string(), Some(method.to_string()))); + flags.push(("from_method".to_owned(), None)); + flags.push(("from_method".to_owned(), Some(method.to_string()))); } } if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { - flags.push(("from_desugaring".to_string(), None)); - flags.push(("from_desugaring".to_string(), Some(k.name().to_string()))); + flags.push(("from_desugaring".to_owned(), None)); + flags.push(("from_desugaring".to_owned(), Some(k.name().to_string()))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); // This is also included through the generics list as `Self`, // but the parser won't allow you to use it - flags.push(("_Self".to_string(), Some(self_ty.to_string()))); + flags.push(("_Self".to_owned(), Some(self_ty.to_string()))); if let Some(def) = self_ty.ty_adt_def() { // We also want to be able to select self's original // signature with no type arguments resolved - flags.push(("_Self".to_string(), Some(self.tcx.type_of(def.did).to_string()))); + flags.push(("_Self".to_owned(), Some(self.tcx.type_of(def.did).to_string()))); } for param in generics.params.iter() { @@ -393,7 +394,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { - flags.push(("crate_local".to_string(), None)); + flags.push(("crate_local".to_owned(), None)); } if let Ok(Some(command)) = OnUnimplementedDirective::of_item( @@ -412,27 +413,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true); - let mut impl_candidates = Vec::new(); + let all_impls = self.tcx.all_impls(trait_ref.def_id()); match simp { - Some(simp) => self.tcx.for_each_impl(trait_ref.def_id(), |def_id| { + Some(simp) => all_impls.iter().filter_map(|&def_id| { let imp = self.tcx.impl_trait_ref(def_id).unwrap(); let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true); if let Some(imp_simp) = imp_simp { if simp != imp_simp { - return; + return None } } - impl_candidates.push(imp); - }), - None => self.tcx.for_each_impl(trait_ref.def_id(), |def_id| { - impl_candidates.push( - self.tcx.impl_trait_ref(def_id).unwrap()); - }) - }; - impl_candidates + + Some(imp) + }).collect(), + None => all_impls.iter().map(|&def_id| + self.tcx.impl_trait_ref(def_id).unwrap() + ).collect() + } } fn report_similar_impl_candidates(&self, @@ -603,10 +603,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span, E0277, "{}", - message.unwrap_or_else(|| { + message.unwrap_or_else(|| format!("the trait bound `{}` is not satisfied{}", trait_ref.to_predicate(), post_message) - })); + )); let explanation = if obligation.cause.code == ObligationCauseCode::MainFunctionType { @@ -645,7 +645,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // "the type `T` can't be frobnicated" // which is somewhat confusing. err.help(&format!("consider adding a `where {}` bound", - trait_ref.to_predicate())); + trait_ref.to_predicate())); } else if !have_alt_message { // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_ref); @@ -693,7 +693,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::RegionOutlives(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); let err = self.region_outlives_predicate(&obligation.cause, - &predicate).err().unwrap(); + &predicate).err().unwrap(); struct_span_err!(self.tcx.sess, span, E0279, "the requirement `{}` is not satisfied (`{}`)", predicate, err) @@ -722,7 +722,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut err = struct_span_err!( self.tcx.sess, closure_span, E0525, "expected a closure that implements the `{}` trait, \ - but this closure only implements `{}`", + but this closure only implements `{}`", kind, found_kind); @@ -779,40 +779,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => { let found_trait_ref = self.resolve_type_vars_if_possible(&*found_trait_ref); let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref); + if expected_trait_ref.self_ty().references_error() { return; } + let found_trait_ty = found_trait_ref.self_ty(); let found_did = match found_trait_ty.sty { - ty::Closure(did, _) | - ty::Foreign(did) | - ty::FnDef(did, _) => Some(did), + ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), ty::Adt(def, _) => Some(def.did), _ => None, }; - let found_span = found_did.and_then(|did| { + + let found_span = found_did.and_then(|did| self.tcx.hir.span_if_local(did) - }).map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def + ).map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def let found = match found_trait_ref.skip_binder().substs.type_at(1).sty { - ty::Tuple(ref tys) => tys.iter() - .map(|_| ArgKind::empty()).collect::>(), + ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], _ => vec![ArgKind::empty()], }; + let expected = match expected_trait_ref.skip_binder().substs.type_at(1).sty { ty::Tuple(ref tys) => tys.iter() - .map(|t| match t.sty { - ty::Tuple(ref tys) => ArgKind::Tuple( - Some(span), - tys.iter() - .map(|ty| ("_".to_owned(), ty.sty.to_string())) - .collect::>() - ), - _ => ArgKind::Arg("_".to_owned(), t.sty.to_string()), - }).collect(), + .map(|t| ArgKind::from_expected_ty(t, Some(span))).collect(), ref sty => vec![ArgKind::Arg("_".to_owned(), sty.to_string())], }; + if found.len() == expected.len() { self.report_closure_arg_mismatch(span, found_span, @@ -836,8 +830,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); - self.tcx.report_object_safety_error(span, did, - violations) + self.tcx.report_object_safety_error(span, did, violations) } ConstEvalFailure(ref err) => { @@ -981,11 +974,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .map(|arg| match arg.clone().node { hir::TyKind::Tup(ref tys) => ArgKind::Tuple( Some(arg.span), - tys.iter() - .map(|_| ("_".to_owned(), "_".to_owned())) - .collect::>(), + vec![("_".to_owned(), "_".to_owned()); tys.len()] ), - _ => ArgKind::Arg("_".to_owned(), "_".to_owned()) + _ => ArgKind::empty() }).collect::>()) } Node::Variant(&hir::Variant { @@ -997,15 +988,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .. }) => { (self.tcx.sess.source_map().def_span(span), - fields.iter().map(|field| { + fields.iter().map(|field| ArgKind::Arg(field.ident.to_string(), "_".to_string()) - }).collect::>()) + ).collect::>()) } Node::StructCtor(ref variant_data) => { (self.tcx.sess.source_map().def_span(self.tcx.hir.span(variant_data.id())), - variant_data.fields() - .iter().map(|_| ArgKind::Arg("_".to_owned(), "_".to_owned())) - .collect()) + vec![ArgKind::empty(); variant_data.fields().len()]) } _ => panic!("non-FnLike node found: {:?}", node), } @@ -1054,7 +1043,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { found_str, ); - err.span_label(span, format!( "expected {} that takes {}", kind, expected_str)); + err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); if let Some(found_span) = found_span { err.span_label(found_span, format!("takes {}", found_str)); @@ -1063,9 +1052,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // found arguments is empty (assume the user just wants to ignore args in this case). // For example, if `expected_args_length` is 2, suggest `|_, _|`. if found_args.is_empty() && is_closure { - let underscores = "_".repeat(expected_args.len()) - .split("") - .filter(|s| !s.is_empty()) + let underscores = iter::repeat("_") + .take(expected_args.len()) .collect::>() .join(", "); err.span_suggestion_with_applicability( @@ -1087,7 +1075,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if fields.len() == expected_args.len() { let sugg = fields.iter() .map(|(name, _)| name.to_owned()) - .collect::>().join(", "); + .collect::>() + .join(", "); err.span_suggestion_with_applicability(found_span, "change the closure to take multiple \ arguments instead of a single tuple", @@ -1146,7 +1135,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let inputs = trait_ref.substs.type_at(1); let sig = if let ty::Tuple(inputs) = inputs.sty { tcx.mk_fn_sig( - inputs.iter().map(|&x| x), + inputs.iter().cloned(), tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, @@ -1220,10 +1209,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let mut reported_violations = FxHashSet(); for violation in violations { - if !reported_violations.insert(violation.clone()) { - continue; + if reported_violations.insert(violation.clone()) { + err.note(&violation.error_msg()); } - err.note(&violation.error_msg()); } err } @@ -1289,10 +1277,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.need_type_info_err(body_id, span, self_ty).emit(); } else { let mut err = struct_span_err!(self.tcx.sess, - span, E0283, - "type annotations required: \ + span, E0283, + "type annotations required: \ cannot resolve `{}`", - predicate); + predicate); self.note_obligation_cause(&mut err, obligation); err.emit(); } @@ -1438,6 +1426,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.item_path_str(item_def_id); let msg = format!("required by `{}`", item_name); + if let Some(sp) = tcx.hir.span_if_local(item_def_id) { let sp = tcx.sess.source_map().def_span(sp); err.span_note(sp, &msg); @@ -1529,9 +1518,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { parent_trait_ref.skip_binder().self_ty())); let parent_predicate = parent_trait_ref.to_predicate(); self.note_obligation_cause_code(err, - &parent_predicate, - &data.parent_code, - obligated_types); + &parent_predicate, + &data.parent_code, + obligated_types); } ObligationCauseCode::CompareImplMethodObligation { .. } => { err.note( @@ -1560,21 +1549,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn is_recursive_obligation(&self, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, - cause_code: &ObligationCauseCode<'tcx>) -> bool { + obligated_types: &mut Vec<&ty::TyS<'tcx>>, + cause_code: &ObligationCauseCode<'tcx>) -> bool { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); - for obligated_type in obligated_types { - if obligated_type == &parent_trait_ref.skip_binder().self_ty() { - return true; - } + + if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) { + return true; } } - return false; + false } } /// Summarizes information +#[derive(Clone)] pub enum ArgKind { /// An argument of non-tuple type. Parameters are (name, ty) Arg(String, String), @@ -1592,11 +1581,11 @@ impl ArgKind { } /// Creates an `ArgKind` from the expected type of an - /// argument. This has no name (`_`) and no source spans.. - pub fn from_expected_ty(t: Ty<'_>) -> ArgKind { + /// argument. It has no name (`_`) and an optional source span. + pub fn from_expected_ty(t: Ty<'_>, span: Option) -> ArgKind { match t.sty { ty::Tuple(ref tys) => ArgKind::Tuple( - None, + span, tys.iter() .map(|ty| ("_".to_owned(), ty.sty.to_string())) .collect::>() diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 9998db4ad1d48..707af02acbf47 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -526,7 +526,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { debug!("process_child_obligations: coinductive match"); } else { - let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); + let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); self.selcx.infcx().report_overflow_error_cycle(&cycle); } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e2dbe88354060..edf7772f2f78e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -661,7 +661,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let predicates: Vec<_> = util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()) - .collect(); + .collect(); debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); @@ -707,7 +707,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; debug!("normalize_param_env_or_error: normalized predicates={:?}", - predicates); + predicates); let region_scope_tree = region::ScopeTree::default(); @@ -851,16 +851,16 @@ fn vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those - let substs = trait_ref.map_bound(|trait_ref| { - Substs::for_item(tcx, def_id, |param, _| { + let substs = trait_ref.map_bound(|trait_ref| + Substs::for_item(tcx, def_id, |param, _| match param.kind { GenericParamDefKind::Lifetime => tcx.types.re_erased.into(), GenericParamDefKind::Type {..} => { trait_ref.substs[param.index as usize] } } - }) - }); + ) + ); // the trait type may have higher-ranked lifetimes in it; // so erase them if they appear, so that we get the type diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 17d55b77625b2..0046a23a085e7 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -124,20 +124,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Check methods for violations. let mut violations: Vec<_> = self.associated_items(trait_def_id) .filter(|item| item.kind == ty::AssociatedKind::Method) - .filter_map(|item| { + .filter_map(|item| self.object_safety_violation_for_method(trait_def_id, &item) .map(|code| ObjectSafetyViolation::Method(item.ident.name, code)) - }).filter(|violation| { + ).filter(|violation| { if let ObjectSafetyViolation::Method(_, - MethodViolationCode::WhereClauseReferencesSelf(span)) = violation { - // Using`CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. + MethodViolationCode::WhereClauseReferencesSelf(span)) = violation + { + // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. // It's also hard to get a use site span, so we use the method definition span. self.lint_node_note( lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY, ast::CRATE_NODE_ID, *span, &format!("the trait `{}` cannot be made into an object", - self.item_path_str(trait_def_id)), + self.item_path_str(trait_def_id)), &violation.error_msg()); false } else { @@ -213,24 +214,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let predicates = self.predicates_of(def_id); let predicates = predicates.instantiate_identity(self).predicates; elaborate_predicates(self, predicates) - .any(|predicate| { - match predicate { - ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { - trait_pred.skip_binder().self_ty().is_self() - } - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::ConstEvaluatable(..) => { - false - } + .any(|predicate| match predicate { + ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { + trait_pred.skip_binder().self_ty().is_self() } - }) + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Subtype(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => { + false + } + } + ) } /// Returns `Some(_)` if this method makes the containing trait not object safe. diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 280ce75720bcf..f59812c0eea98 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -74,17 +74,17 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { let condition = if is_root { None } else { - let cond = item_iter.next().ok_or_else(|| { + let cond = item_iter.next().ok_or_else(|| parse_error(tcx, span, "empty `on`-clause in `#[rustc_on_unimplemented]`", "empty on-clause here", None) - })?.meta_item().ok_or_else(|| { + )?.meta_item().ok_or_else(|| parse_error(tcx, span, "invalid `on`-clause in `#[rustc_on_unimplemented]`", "invalid on-clause here", None) - })?; + )?; attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true); Some(cond.clone()) }; @@ -259,9 +259,9 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { // `{from_desugaring}` is allowed Position::ArgumentNamed(s) if s == "from_desugaring" => (), // So is `{A}` if A is a type parameter - Position::ArgumentNamed(s) => match generics.params.iter().find(|param| { + Position::ArgumentNamed(s) => match generics.params.iter().find(|param| param.name == s - }) { + ) { Some(_) => (), None => { span_err!(tcx.sess, span, E0230, @@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { let empty_string = String::new(); let parser = Parser::new(&self.0, None); - parser.map(|p| { + parser.map(|p| match p { Piece::String(s) => s, Piece::NextArgument(a) => match a.position { @@ -326,11 +326,9 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { } } }, - _ => { - bug!("broken on_unimplemented {:?} - bad format arg", self.0) - } + _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0) } } - }).collect() + ).collect() } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index e50f59cbc82c1..5ea936f750e2e 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -171,7 +171,7 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { match (current, candidate) { (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), (ParamEnv(..), _) => return false, - (_, ParamEnv(..)) => { unreachable!(); } + (_, ParamEnv(..)) => unreachable!(), (_, _) => convert_to_ambiguous = (), } } @@ -419,9 +419,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, normalized_ty } - _ => { - ty - } + _ => ty } } @@ -437,12 +435,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, instance, promoted: None }; - match tcx.const_eval(param_env.and(cid)) { - Ok(evaluated) => { - let evaluated = evaluated.subst(self.tcx(), substs); - return self.fold_const(evaluated); - } - Err(_) => {} + if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { + let evaluated = evaluated.subst(self.tcx(), substs); + return self.fold_const(evaluated); } } } else { @@ -453,9 +448,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, instance, promoted: None }; - match tcx.const_eval(param_env.and(cid)) { - Ok(evaluated) => return self.fold_const(evaluated), - Err(_) => {} + if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { + return self.fold_const(evaluated) } } } @@ -993,7 +987,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( candidate_set.mark_ambiguous(); return; } - _ => { return; } + _ => return }; // If so, extract what we know from the trait and try to come up with a good answer. @@ -1023,33 +1017,30 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( for predicate in env_predicates { debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); - match predicate { - ty::Predicate::Projection(data) => { - let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; - - let is_match = same_def_id && infcx.probe(|_| { - let data_poly_trait_ref = - data.to_poly_trait_ref(infcx.tcx); - let obligation_poly_trait_ref = - obligation_trait_ref.to_poly_trait_ref(); - infcx.at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .map(|InferOk { obligations: _, value: () }| { - // FIXME(#32730) -- do we need to take obligations - // into account in any way? At the moment, no. - }) - .is_ok() - }); - - debug!("assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_def_id={}", - data, is_match, same_def_id); - - if is_match { - candidate_set.push_candidate(ctor(data)); - } + if let ty::Predicate::Projection(data) = predicate { + let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; + + let is_match = same_def_id && infcx.probe(|_| { + let data_poly_trait_ref = + data.to_poly_trait_ref(infcx.tcx); + let obligation_poly_trait_ref = + obligation_trait_ref.to_poly_trait_ref(); + infcx.at(&obligation.cause, obligation.param_env) + .sup(obligation_poly_trait_ref, data_poly_trait_ref) + .map(|InferOk { obligations: _, value: () }| { + // FIXME(#32730) -- do we need to take obligations + // into account in any way? At the moment, no. + }) + .is_ok() + }); + + debug!("assemble_candidates_from_predicates: candidate={:?} \ + is_match={} same_def_id={}", + data, is_match, same_def_id); + + if is_match { + candidate_set.push_candidate(ctor(data)); } - _ => {} } } } @@ -1072,8 +1063,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( return Err(()); } Err(e) => { - debug!("assemble_candidates_from_impls: selection error {:?}", - e); + debug!("assemble_candidates_from_impls: selection error {:?}", e); candidate_set.mark_error(e); return Err(()); } @@ -1295,11 +1285,11 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( let mut env_predicates = env_predicates.filter(|data| { let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx()); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - selcx.infcx().probe(|_| { + selcx.infcx().probe(|_| selcx.infcx().at(&obligation.cause, obligation.param_env) .sup(obligation_poly_trait_ref, data_poly_trait_ref) .is_ok() - }) + ) }); // select the first matching one; there really ought to be one or @@ -1447,7 +1437,7 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( obligation.predicate.self_ty(), fn_sig, flag) - .map_bound(|(trait_ref, ret_type)| { + .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { projection_ty: ty::ProjectionTy::from_ref_and_name( tcx, @@ -1456,7 +1446,7 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( ), ty: ret_type } - }); + ); confirm_param_env_candidate(selcx, obligation, predicate) } diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index fd8898dffd4f2..f5fb183ec1a5d 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -57,22 +57,19 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { debug!("c_ty = {:?}", c_ty); match &gcx.dropck_outlives(c_ty) { Ok(result) if result.is_proven() => { - match self.infcx.instantiate_query_result_and_region_obligations( + if let Ok(InferOk { value, obligations }) = + self.infcx.instantiate_query_result_and_region_obligations( self.cause, self.param_env, &orig_values, - result, - ) { - Ok(InferOk { value, obligations }) => { - let ty = self.infcx.resolve_type_vars_if_possible(&ty); - let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); - return InferOk { - value: kinds, - obligations, - }; - } - - Err(_) => { /* fallthrough to error-handling code below */ } + result) + { + let ty = self.infcx.resolve_type_vars_if_possible(&ty); + let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); + return InferOk { + value: kinds, + obligations, + }; } } @@ -161,12 +158,7 @@ impl<'tcx> FromIterator> for DtorckConstraint<'tcx> { fn from_iter>>(iter: I) -> Self { let mut result = Self::empty(); - for DtorckConstraint { - outlives, - dtorck_types, - overflows, - } in iter - { + for DtorckConstraint { outlives, dtorck_types, overflows } in iter { result.outlives.extend(outlives); result.dtorck_types.extend(dtorck_types); result.overflows.extend(overflows); @@ -254,7 +246,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> } } - // The following *might* require a destructor: it would deeper inspection to tell. + // The following *might* require a destructor: needs deeper inspection. ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index ea8bc3b20aae9..9b9643aab97d5 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -48,6 +48,13 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { value, self.param_env, ); + if !value.has_projections() { + return Ok(Normalized { + value: value.clone(), + obligations: vec![], + }); + } + let mut normalizer = QueryNormalizer { infcx: self.infcx, cause: self.cause, @@ -56,12 +63,6 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { error: false, anon_depth: 0, }; - if !value.has_projections() { - return Ok(Normalized { - value: value.clone(), - obligations: vec![], - }); - } let value1 = value.fold_with(&mut normalizer); if normalizer.error { @@ -154,8 +155,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx let gcx = self.infcx.tcx.global_tcx(); let mut orig_values = SmallVec::new(); - let c_data = self.infcx - .canonicalize_query(&self.param_env.and(*data), &mut orig_values); + let c_data = self.infcx.canonicalize_query( + &self.param_env.and(*data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); match gcx.normalize_projection_ty(c_data) { @@ -170,12 +171,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx self.cause, self.param_env, &orig_values, - &result, - ) { - Ok(InferOk { - value: result, - obligations, - }) => { + &result) + { + Ok(InferOk { value: result, obligations }) => { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); @@ -212,12 +210,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx instance, promoted: None, }; - match tcx.const_eval(param_env.and(cid)) { - Ok(evaluated) => { - let evaluated = evaluated.subst(self.tcx(), substs); - return self.fold_const(evaluated); - } - Err(_) => {} + if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { + let evaluated = evaluated.subst(self.tcx(), substs); + return self.fold_const(evaluated); } } } else { @@ -228,9 +223,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx instance, promoted: None, }; - match tcx.const_eval(param_env.and(cid)) { - Ok(evaluated) => return self.fold_const(evaluated), - Err(_) => {} + if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { + return self.fold_const(evaluated) } } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 232ef108537fe..781cfe615a9aa 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -55,7 +55,6 @@ use rustc_target::spec::abi::Abi; use hir; use util::nodemap::{FxHashMap, FxHashSet}; - pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, @@ -149,7 +148,7 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { #[derive(Clone)] pub struct SelectionCache<'tcx> { hashmap: Lock, - WithDepNode>>>>, + WithDepNode>>>>, } /// The selection process begins by considering all impls, where @@ -623,9 +622,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &PredicateObligation<'tcx>) -> Result { - self.probe(|this, _| { + self.probe(|this, _| this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) - }) + ) } /// Evaluates the predicates in `predicates` recursively. Note that @@ -717,13 +716,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.projection_cache.borrow_mut().complete(key); } result - } - Ok(None) => { - Ok(EvaluatedToAmbig) - } - Err(_) => { - Ok(EvaluatedToErr) - } + }, + Ok(None) => Ok(EvaluatedToAmbig), + Err(_) => Ok(EvaluatedToErr) } } @@ -735,10 +730,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } else { Ok(EvaluatedToErr) } - } - None => { - Ok(EvaluatedToAmbig) - } + }, + None => Ok(EvaluatedToAmbig) } } @@ -901,13 +894,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // same unbound type variable. if let Some(rec_index) = stack.iter() - .skip(1) // skip top-most frame - .position(|prev| stack.obligation.param_env == prev.obligation.param_env && - stack.fresh_trait_ref == prev.fresh_trait_ref) + .skip(1) // skip top-most frame + .position(|prev| stack.obligation.param_env == prev.obligation.param_env && + stack.fresh_trait_ref == prev.fresh_trait_ref) { debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref); - let cycle = stack.iter().skip(1).take(rec_index+1); + let cycle = stack.iter().skip(1).take(rec_index + 1); let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate)); if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", @@ -947,10 +940,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let result = match predicate { ty::Predicate::Trait(ref data) => { self.tcx().trait_is_auto(data.def_id()) - } - _ => { - false - } + }, + _ => false }; debug!("coinductive_predicate({:?}) = {:?}", predicate, result); result @@ -1088,9 +1079,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // If no match, compute result and insert into cache. - let (candidate, dep_node) = self.in_task(|this| { + let (candidate, dep_node) = self.in_task(|this| this.candidate_from_obligation_no_cache(stack) - }); + ); debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); @@ -1104,9 +1095,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn in_task(&mut self, op: OP) -> (R, DepNodeIndex) where OP: FnOnce(&mut Self) -> R { - let (result, dep_node) = self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || { + let (result, dep_node) = self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self) - }); + ); self.tcx().dep_graph.read_index(dep_node); (result, dep_node) } @@ -1138,46 +1129,53 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Ok(None); } - match self.is_knowable(stack) { - None => {} - Some(conflict) => { - debug!("coherence stage: not knowable"); - if self.intercrate_ambiguity_causes.is_some() { - debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack) { - let no_candidates_apply = - candidate_set - .vec - .iter() - .map(|c| self.evaluate_candidate(stack, &c)) - .collect::, OverflowError>>()? - .iter() - .all(|r| !r.may_apply()); - if !candidate_set.ambiguous && no_candidates_apply { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let trait_desc = trait_ref.to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }; - let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { - trait_desc, - self_desc, - } - } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + if let Some(conflict) = self.is_knowable(stack) { + debug!("coherence stage: not knowable"); + if self.intercrate_ambiguity_causes.is_some() { + debug!("evaluate_stack: intercrate_ambiguity_causes is some"); + // Heuristics: show the diagnostics when there are no candidates in crate. + if let Ok(candidate_set) = self.assemble_candidates(stack) { + let mut no_candidates_apply = true; + { + let evaluated_candidates = candidate_set.vec.iter().map(|c| + self.evaluate_candidate(stack, &c)); + + for ec in evaluated_candidates { + match ec { + Ok(c) => { + if c.may_apply() { + no_candidates_apply = false; + break + } + }, + Err(e) => return Err(e.into()) + } } } + + if !candidate_set.ambiguous && no_candidates_apply { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let trait_desc = trait_ref.to_string(); + let self_desc = if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }; + let cause = if let Conflict::Upstream = conflict { + IntercrateAmbiguityCause::UpstreamCrateUpdate { + trait_desc, + self_desc, + } + } else { + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } } - return Ok(None); } + return Ok(None); } let candidate_set = self.assemble_candidates(stack)?; @@ -1434,9 +1432,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. - let def_id = obligation.predicate.def_id(); let lang_items = self.tcx().lang_items(); + if lang_items.copy_trait() == Some(def_id) { debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty()); @@ -1495,15 +1493,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Projection(_) | ty::Opaque(..) => {} ty::Infer(ty::TyVar(_)) => { span_bug!(obligation.cause.span, - "Self=_ should have been handled by assemble_candidates"); + "Self=_ should have been handled by assemble_candidates"); } _ => return } - let result = self.probe(|this, snapshot| { + let result = self.probe(|this, snapshot| this.match_projection_obligation_against_definition_bounds(obligation, snapshot) - }); + ); if result { candidates.vec.push(ProjectionCandidate); @@ -1533,7 +1531,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { span_bug!( obligation.cause.span, "match_projection_obligation_against_definition_bounds() called \ - but self-ty not a projection: {:?}", + but self-ty is not a projection: {:?}", skol_trait_predicate.trait_ref.self_ty()); } }; @@ -1637,14 +1635,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { where_clause_trait_ref: ty::PolyTraitRef<'tcx>) -> Result { - self.probe(move |this, _| { + self.probe(move |this, _| match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { this.evaluate_predicates_recursively(stack.list(), obligations.iter()) } Err(()) => Ok(EvaluatedToErr) } - }) + ) } fn assemble_generator_candidates(&mut self, @@ -1667,15 +1665,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation); candidates.vec.push(GeneratorCandidate); - Ok(()) } ty::Infer(ty::TyVar(_)) => { debug!("assemble_generator_candidates: ambiguous self-type"); candidates.ambiguous = true; - return Ok(()); } - _ => { return Ok(()); } + _ => {} } + + Ok(()) } /// Check for the artificial impl that the compiler will create for an obligation like `X : @@ -1712,16 +1710,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("assemble_unboxed_candidates: closure_kind not yet known"); candidates.vec.push(ClosureCandidate); } - }; - Ok(()) + } } ty::Infer(ty::TyVar(_)) => { debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); candidates.ambiguous = true; - return Ok(()); } - _ => { return Ok(()); } + _ => {} } + + Ok(()) } /// Implement one of the `Fn()` family for a fn pointer. @@ -1742,7 +1740,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("assemble_fn_pointer_candidates: ambiguous self-type"); candidates.ambiguous = true; // could wind up being a fn() type } - // provide an impl, but only for suitable `fn` pointers ty::FnDef(..) | ty::FnPtr(_) => { if let ty::FnSig { @@ -1754,8 +1751,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { candidates.vec.push(FnPointerCandidate); } } - - _ => { } + _ => {} } Ok(()) @@ -1773,18 +1769,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { - candidates.vec.push(ImplCandidate(impl_def_id)); - - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); - } - Err(_) => { } + self.probe(|this, snapshot| /* [1] */ + if let Ok(skol_map) = this.match_impl(impl_def_id, obligation, snapshot) { + candidates.vec.push(ImplCandidate(impl_def_id)); + + // NB: we can safely drop the skol map + // since we are in a probe [1] + mem::drop(skol_map); } - }); + ); } ); @@ -1874,7 +1867,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Dynamic(ref data, ..) => { if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { debug!("assemble_candidates_from_object_ty: matched builtin bound, \ - pushing candidate"); + pushing candidate"); candidates.vec.push(BuiltinObjectCandidate); return; } @@ -1889,9 +1882,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { candidates.ambiguous = true; // could wind up being an object type return; } - _ => { - return; - } + _ => return }; debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", @@ -1904,12 +1895,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // but `Foo` is declared as `trait Foo : Bar`. let upcast_trait_refs = util::supertraits(this.tcx(), poly_trait_ref) - .filter(|upcast_trait_ref| { + .filter(|upcast_trait_ref| this.probe(|this, _| { let upcast_trait_ref = upcast_trait_ref.clone(); this.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok() }) - }) + ) .count(); if upcast_trait_refs > 1 { @@ -2028,6 +2019,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { other: &EvaluatedCandidate<'tcx>) -> bool { + if victim.candidate == other.candidate { + return true; + } + // Check if a bound would previously have been removed when normalizing // the param_env so that it can be given the lowest priority. See // #50825 for the motivation for this. @@ -2035,10 +2030,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { cand.is_global() && !cand.has_late_bound_regions() }; - if victim.candidate == other.candidate { - return true; - } - match other.candidate { // Prefer BuiltinCandidate { has_nested: false } to anything else. // This is a fix for #53123 and prevents winnowing from accidentally extending the @@ -2046,9 +2037,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { BuiltinCandidate { has_nested: false } => true, ParamCandidate(ref cand) => match victim.candidate { AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates"); + bug!("default implementations shouldn't be recorded \ + when there are other valid candidates"); } // Prefer BuiltinCandidate { has_nested: false } to anything else. // This is a fix for #53123 and prevents winnowing from accidentally extending the @@ -2077,9 +2067,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ObjectCandidate | ProjectionCandidate => match victim.candidate { AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates"); + bug!("default implementations shouldn't be recorded \ + when there are other valid candidates"); } // Prefer BuiltinCandidate { has_nested: false } to anything else. // This is a fix for #53123 and prevents winnowing from accidentally extending the @@ -2151,7 +2140,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn assemble_builtin_bound_candidates<'o>(&mut self, conditions: BuiltinImplConditions<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>) - -> Result<(),SelectionError<'tcx>> + -> Result<(), SelectionError<'tcx>> { match conditions { BuiltinImplConditions::Where(nested) => { @@ -2159,18 +2148,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { candidates.vec.push(BuiltinCandidate { has_nested: nested.skip_binder().len() > 0 }); - Ok(()) } - BuiltinImplConditions::None => { Ok(()) } + BuiltinImplConditions::None => {} BuiltinImplConditions::Ambiguous => { debug!("assemble_builtin_bound_candidates: ambiguous builtin"); - Ok(candidates.ambiguous = true) + candidates.ambiguous = true; } } + + Ok(()) } - fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>) - -> BuiltinImplConditions<'tcx> + fn sized_conditions(&mut self, + obligation: &TraitObligation<'tcx>) + -> BuiltinImplConditions<'tcx> { use self::BuiltinImplConditions::{Ambiguous, None, Where}; @@ -2216,8 +2207,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>) - -> BuiltinImplConditions<'tcx> + fn copy_clone_conditions(&mut self, + obligation: &TraitObligation<'tcx>) + -> BuiltinImplConditions<'tcx> { // NOTE: binder moved to (*) let self_ty = self.infcx.shallow_resolve( @@ -2551,17 +2543,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let lang_items = self.tcx().lang_items(); let obligations = if has_nested { let trait_def = obligation.predicate.def_id(); - let conditions = match trait_def { - _ if Some(trait_def) == lang_items.sized_trait() => { + let conditions = + if Some(trait_def) == lang_items.sized_trait() { self.sized_conditions(obligation) - } - _ if Some(trait_def) == lang_items.copy_trait() => { + } else if Some(trait_def) == lang_items.copy_trait() { self.copy_clone_conditions(obligation) - } - _ if Some(trait_def) == lang_items.clone_trait() => { + } else if Some(trait_def) == lang_items.clone_trait() { self.copy_clone_conditions(obligation) - } - _ => bug!("unexpected builtin trait {:?}", trait_def) + } else { + bug!("unexpected builtin trait {:?}", trait_def) }; let nested = match conditions { BuiltinImplConditions::Where(nested) => nested, @@ -2608,10 +2598,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// See `confirm_auto_impl_candidate` fn vtable_auto_impl(&mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - nested: ty::Binder>>) - -> VtableAutoImplData> + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId, + nested: ty::Binder>>) + -> VtableAutoImplData> { debug!("vtable_auto_impl: nested={:?}", nested); @@ -2731,10 +2721,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Dynamic(ref data, ..) => { data.principal().unwrap().with_self_ty(self.tcx(), self_ty) } - _ => { - span_bug!(obligation.cause.span, - "object candidate with non-object"); - } + _ => span_bug!(obligation.cause.span, + "object candidate with non-object") }; let mut upcast_trait_ref = None; @@ -2752,10 +2740,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // record it for later.) let nonmatching = util::supertraits(tcx, poly_trait_ref) - .take_while(|&t| { - match - self.commit_if_ok( - |this, _| this.match_poly_trait_ref(obligation, t)) + .take_while(|&t| + match self.commit_if_ok(|this, _| + this.match_poly_trait_ref(obligation, t)) { Ok(obligations) => { upcast_trait_ref = Some(t); @@ -2764,16 +2751,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } Err(_) => { true } } - }); + ); // Additionally, for each of the nonmatching predicates that // we pass over, we sum up the set of number of vtable // entries, so that we can compute the offset for the selected // trait. - vtable_base = - nonmatching.map(|t| tcx.count_own_vtable_entries(t)) - .sum(); - + vtable_base = nonmatching.map(|t| tcx.count_own_vtable_entries(t)).sum(); } VtableObjectData { @@ -2816,7 +2800,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn confirm_generator_candidate(&mut self, obligation: &TraitObligation<'tcx>) -> Result>, - SelectionError<'tcx>> + SelectionError<'tcx>> { // ok to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope @@ -2869,10 +2853,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("confirm_closure_candidate({:?})", obligation); - let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()) { - Some(k) => k, - None => bug!("closure candidate for non-fn trait {:?}", obligation) - }; + let kind = self.tcx() + .lang_items() + .fn_trait_kind(obligation.predicate.def_id()) + .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", + obligation)); // ok to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope @@ -2901,9 +2886,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligations.extend( self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref)?); + obligation.param_env, + obligation.predicate.to_poly_trait_ref(), + trait_ref)?); obligations.push(Obligation::new( obligation.cause.clone(), @@ -3008,20 +2993,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { (_, &ty::Dynamic(ref data, r)) => { let mut object_dids = data.auto_traits().chain(data.principal().map(|p| p.def_id())); - if let Some(did) = object_dids.find(|did| { - !tcx.is_object_safe(*did) - }) { + if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)) } let cause = ObligationCause::new(obligation.cause.span, obligation.cause.body_id, ObjectCastObligation(target)); - let mut push = |predicate| { - nested.push(Obligation::with_depth(cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - predicate)); + + let predicate_to_obligation = |predicate| { + Obligation::with_depth(cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + predicate) }; // Create obligations: @@ -3030,21 +3014,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // words, if the object type is Foo+Send, this would create an obligation for the // Send check.) // - Projection predicates - for predicate in data.iter() { - push(predicate.with_self_ty(tcx, source)); - } + nested.extend(data.iter().map(|d| + predicate_to_obligation(d.with_self_ty(tcx, source)) + )); // We can only make objects from sized types. let tr = ty::TraitRef { def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem), substs: tcx.mk_substs_trait(source, &[]), }; - push(tr.to_predicate()); + nested.push(predicate_to_obligation(tr.to_predicate())); // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` outlives `'a`: let outlives = ty::OutlivesPredicate(source, r); - push(ty::Binder::dummy(outlives).to_predicate()); + nested.push(predicate_to_obligation( + ty::Binder::dummy(outlives).to_predicate())); } // [T; n] -> [T]. @@ -3105,13 +3090,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Check that the source struct with the target's // unsized parameters is equal to the target. - let params = substs_a.iter().enumerate().map(|(i, &k)| { + let params = substs_a.iter().enumerate().map(|(i, &k)| if ty_params.contains(i) { substs_b.type_at(i).into() } else { k } - }); + ); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let InferOk { obligations, .. } = self.infcx.at(&obligation.cause, obligation.param_env) @@ -3236,10 +3221,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let InferOk { obligations, .. } = self.infcx.at(&obligation.cause, obligation.param_env) .eq(skol_obligation_trait_ref, impl_trait_ref) - .map_err(|e| { - debug!("match_impl: failed eq_trait_refs due to `{}`", e); - () - })?; + .map_err(|e| + debug!("match_impl: failed eq_trait_refs due to `{}`", e) + )?; nested_obligations.extend(obligations); if let Err(e) = self.infcx.leak_check(false, @@ -3288,7 +3272,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn match_where_clause_trait_ref(&mut self, obligation: &TraitObligation<'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>) - -> Result>,()> + -> Result>, ()> { self.match_poly_trait_ref(obligation, where_clause_trait_ref) } @@ -3298,7 +3282,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn match_poly_trait_ref(&mut self, obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) - -> Result>,()> + -> Result>, ()> { debug!("match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", obligation, @@ -3350,20 +3334,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // in fact unparameterized (or at least does not reference any // regions bound in the obligation). Still probably some // refactoring could make this nicer. - self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(), obligation.predicate - .skip_binder().self_ty(), // (1) + .skip_binder() + .self_ty(), // (1) closure_type, util::TupleArgumentsFlag::No) .map_bound(|(trait_ref, _)| trait_ref) } fn generator_trait_ref_unnormalized(&mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: ty::GeneratorSubsts<'tcx>) - -> ty::PolyTraitRef<'tcx> + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: ty::GeneratorSubsts<'tcx>) + -> ty::PolyTraitRef<'tcx> { let gen_sig = substs.poly_sig(closure_def_id, self.tcx()); @@ -3375,7 +3359,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(), obligation.predicate - .skip_binder().self_ty(), // (1) + .skip_binder() + .self_ty(), // (1) gen_sig) .map_bound(|(trait_ref, ..)| trait_ref) } @@ -3453,8 +3438,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { impl<'tcx> TraitObligation<'tcx> { #[allow(unused_comparisons)] pub fn derived_cause(&self, - variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>) - -> ObligationCause<'tcx> + variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>) + -> ObligationCause<'tcx> { /*! * Creates a cause for obligations that are derived from diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 9343eff9e79b4..dbd84397b597d 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -100,10 +100,10 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } fulfill_implication(infcx, param_env, source_trait_ref, target_impl) - .unwrap_or_else(|_| { + .unwrap_or_else(|_| bug!("When translating substitutions for specialization, the expected \ specialization failed to hold") - }) + ) } specialization_graph::Node::Trait(..) => source_trait_ref.substs, }; @@ -137,17 +137,15 @@ pub fn find_associated_item<'a, 'tcx>( let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id, substs, node_item.node); let substs = infcx.tcx.erase_regions(&substs); - tcx.lift(&substs).unwrap_or_else(|| { + tcx.lift(&substs).unwrap_or_else(|| bug!("find_method: translate_substs \ returned {:?} which contains inference types/regions", - substs); - }) + substs) + ) }); (node_item.item.def_id, substs) } - None => { - bug!("{:?} not found in {:?}", item, impl_data.impl_def_id) - } + None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id) } } @@ -312,8 +310,7 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx -> Lrc { let mut sg = specialization_graph::Graph::new(); - let mut trait_impls = Vec::new(); - tcx.for_each_impl(trait_id, |impl_did| trait_impls.push(impl_did)); + let mut trait_impls = tcx.all_impls(trait_id); // The coherence checking implementation seems to rely on impls being // iterated over (roughly) in definition order, so we are sorting by @@ -367,9 +364,9 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx "first implementation here".to_string()); err.span_label(impl_span, format!("conflicting implementation{}", - overlap.self_desc - .map_or(String::new(), - |ty| format!(" for `{}`", ty)))); + overlap.self_desc + .map_or(String::new(), + |ty| format!(" for `{}`", ty)))); } Err(cname) => { let msg = match to_pretty_impl_header(tcx, overlap.with_impl) { @@ -428,7 +425,9 @@ fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option { // The predicates will contain default bounds like `T: Sized`. We need to // remove these bounds, and add `T: ?Sized` to any untouched type parameters. let predicates = tcx.predicates_of(impl_def_id).predicates; - let mut pretty_predicates = Vec::with_capacity(predicates.len()); + let mut pretty_predicates = Vec::with_capacity( + predicates.len() + types_without_default_bounds.len()); + for p in predicates { if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() { if Some(poly_trait_ref.def_id()) == sized_trait { @@ -438,9 +437,11 @@ fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option { } pretty_predicates.push(p.to_string()); } + pretty_predicates.extend( types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty)) ); + if !pretty_predicates.is_empty() { write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap(); } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index a7652574c1a2e..756f55545bc45 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -390,11 +390,12 @@ impl Iterator for Ancestors { let cur = self.current_source.take(); if let Some(Node::Impl(cur_impl)) = cur { let parent = self.specialization_graph.parent(cur_impl); - if parent == self.trait_def_id { - self.current_source = Some(Node::Trait(parent)); + + self.current_source = if parent == self.trait_def_id { + Some(Node::Trait(parent)) } else { - self.current_source = Some(Node::Impl(parent)); - } + Some(Node::Impl(parent)) + }; } cur } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 10e930d1c92d9..a4230707b70ca 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -166,10 +166,10 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { match *self { super::Unimplemented => Some(super::Unimplemented), super::OutputTypeParameterMismatch(a, b, ref err) => { - tcx.lift(&(a, b)).and_then(|(a, b)| { + tcx.lift(&(a, b)).and_then(|(a, b)| tcx.lift(err) .map(|err| super::OutputTypeParameterMismatch(a, b, err)) - }) + ) } super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)), super::ConstEvalFailure(ref err) => tcx.lift(&**err).map(|err| super::ConstEvalFailure( @@ -193,10 +193,10 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::ReferenceOutlivesReferent(ty) => { tcx.lift(&ty).map(super::ReferenceOutlivesReferent) } - super::ObjectTypeBound(ty, r) => tcx.lift(&ty).and_then(|ty| { + super::ObjectTypeBound(ty, r) => tcx.lift(&ty).and_then(|ty| tcx.lift(&r) - .and_then(|r| Some(super::ObjectTypeBound(ty, r))) - }), + .and_then(|r| Some(super::ObjectTypeBound(ty, r))) + ), super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), super::AssignmentLhsSized => Some(super::AssignmentLhsSized), super::TupleInitializerSized => Some(super::TupleInitializerSized), @@ -245,13 +245,13 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { type Lifted = traits::DerivedObligationCause<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| { + tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| tcx.lift(&*self.parent_code) - .map(|code| traits::DerivedObligationCause { - parent_trait_ref: trait_ref, - parent_code: Rc::new(code), - }) - }) + .map(|code| traits::DerivedObligationCause { + parent_trait_ref: trait_ref, + parent_code: Rc::new(code), + }) + ) } } @@ -275,40 +275,40 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { impl_def_id, substs, nested, - }) => tcx.lift(&substs).map(|substs| { + }) => tcx.lift(&substs).map(|substs| traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested, }) - }), + ), traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), traits::VtableGenerator(traits::VtableGeneratorData { generator_def_id, substs, nested, - }) => tcx.lift(&substs).map(|substs| { + }) => tcx.lift(&substs).map(|substs| traits::VtableGenerator(traits::VtableGeneratorData { generator_def_id: generator_def_id, substs: substs, nested: nested, }) - }), + ), traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested, - }) => tcx.lift(&substs).map(|substs| { + }) => tcx.lift(&substs).map(|substs| traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested, }) - }), + ), traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { - tcx.lift(&fn_ty).map(|fn_ty| { + tcx.lift(&fn_ty).map(|fn_ty| traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) - }) + ) } traits::VtableParam(n) => Some(traits::VtableParam(n)), traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)), @@ -316,13 +316,13 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { upcast_trait_ref, vtable_base, nested, - }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| { + }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| traits::VtableObject(traits::VtableObjectData { upcast_trait_ref: trait_ref, vtable_base, nested, }) - }), + ), } } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 40f13ac06f56f..2ca8214daf768 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -346,8 +346,7 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { Some(ty::Predicate::Trait(data)) => { return Some(data.to_poly_trait_ref()); } - Some(_) => { - } + Some(_) => {} } } } diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 6332080a1836c..fd3f7a12376d8 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -138,6 +138,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } } + + /// Return a vector containing all impls + pub fn all_impls(self, def_id: DefId) -> Vec { + let impls = self.trait_impls_of(def_id); + + impls.blanket_impls.iter().chain( + impls.non_blanket_impls.values().flatten() + ).cloned().collect() + } } // Query provider for `trait_impls_of`. diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index a283e032e0e02..f2c20238734e6 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -504,7 +504,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .sig .inputs() .iter() - .map(|ty| ArgKind::from_expected_ty(ty)) + .map(|ty| ArgKind::from_expected_ty(ty, None)) .collect(); let (closure_span, found_args) = self.get_fn_like_arguments(expr_map_node); let expected_span = expected_sig.cause_span.unwrap_or(closure_span); From dff1bc1260e5c1c13be20b5402d1b4b783cc1218 Mon Sep 17 00:00:00 2001 From: memoryruins Date: Tue, 18 Sep 2018 14:41:34 -0400 Subject: [PATCH 27/34] Set diagnostic applicability based on array length --- src/librustc_typeck/check/mod.rs | 24 ++++++++++++++++++------ src/test/ui/issues/issue-53712.rs | 2 +- src/test/ui/issues/issue-53712.stderr | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 89ab085b03481..f8628801d2519 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3344,12 +3344,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; } - ty::Array(ty, _) if ty.is_numeric() => { - let base = self.tcx.hir.node_to_pretty_string(base.id); - let msg = format!("attempting to use tuple indexing on an array; try"); - let suggestion = format!("{}[{}]", base, field); - err.span_suggestion(field.span, &msg, suggestion); - }, + ty::Array(_, len) => { + if let (Some(len), Ok(user_index)) = ( + len.assert_usize(self.tcx), + field.as_str().parse::() + ) { + let base = self.tcx.hir.node_to_pretty_string(base.id); + let help = "instead of using tuple indexing, use array indexing"; + let suggestion = format!("{}[{}]", base, field); + let applicability = if len < user_index { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + err.span_suggestion_with_applicability( + field.span, help, suggestion, applicability + ); + } + } ty::RawPtr(..) => { let base = self.tcx.hir.node_to_pretty_string(base.id); let msg = format!("`{}` is a native pointer; try dereferencing it", base); diff --git a/src/test/ui/issues/issue-53712.rs b/src/test/ui/issues/issue-53712.rs index c8b54c2d4beb4..2353904d79d75 100644 --- a/src/test/ui/issues/issue-53712.rs +++ b/src/test/ui/issues/issue-53712.rs @@ -4,6 +4,6 @@ fn main() { let arr = [10, 20, 30, 40, 50]; arr.0; //~^ ERROR no field `0` on type `[{integer}; 5]` [E0609] - //~| HELP attempting to use tuple indexing on an array; try + //~| HELP instead of using tuple indexing, use array indexing //~| SUGGESTION arr[0] } diff --git a/src/test/ui/issues/issue-53712.stderr b/src/test/ui/issues/issue-53712.stderr index ef885a438c827..06c19e19d5229 100644 --- a/src/test/ui/issues/issue-53712.stderr +++ b/src/test/ui/issues/issue-53712.stderr @@ -2,7 +2,7 @@ error[E0609]: no field `0` on type `[{integer}; 5]` --> $DIR/issue-53712.rs:5:9 | LL | arr.0; - | ^ help: attempting to use tuple indexing on an array; try: `arr[0]` + | ^ help: instead of using tuple indexing, use array indexing: `arr[0]` error: aborting due to previous error From 73fdc81b39138d3526c3629e7d83f581901dce58 Mon Sep 17 00:00:00 2001 From: memoryruins Date: Tue, 18 Sep 2018 15:35:04 -0400 Subject: [PATCH 28/34] Use expr's span --- src/librustc_typeck/check/mod.rs | 2 +- src/test/ui/issues/issue-53712.stderr | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f8628801d2519..a38bd505da9e7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3358,7 +3358,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Applicability::MaybeIncorrect }; err.span_suggestion_with_applicability( - field.span, help, suggestion, applicability + expr.span, help, suggestion, applicability ); } } diff --git a/src/test/ui/issues/issue-53712.stderr b/src/test/ui/issues/issue-53712.stderr index 06c19e19d5229..db85919afcb55 100644 --- a/src/test/ui/issues/issue-53712.stderr +++ b/src/test/ui/issues/issue-53712.stderr @@ -2,7 +2,9 @@ error[E0609]: no field `0` on type `[{integer}; 5]` --> $DIR/issue-53712.rs:5:9 | LL | arr.0; - | ^ help: instead of using tuple indexing, use array indexing: `arr[0]` + | ----^ + | | + | help: instead of using tuple indexing, use array indexing: `arr[0]` error: aborting due to previous error From e3d0d0f5edfc9507c9bb08f169aabeca1cbbb3f3 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 18 Sep 2018 16:52:47 -0400 Subject: [PATCH 29/34] Update The Book to latest Let's check out https://github.com/rust-lang/book/pull/1505 on nightly --- src/doc/book | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book b/src/doc/book index cff0930664b68..fa91738b66367 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit cff0930664b688f1dd22aefb3d16944eb4cdbfd5 +Subproject commit fa91738b66367b6f70b078251868a071f1991ace From 3d662639f650f87d3ca5aa454a14b02e30ecc14e Mon Sep 17 00:00:00 2001 From: Erich Cordoba Date: Tue, 18 Sep 2018 18:32:29 -0500 Subject: [PATCH 30/34] Remove unneeded clone() from tests The expected.clone() calls were not needed for the tests. This is just to keep consistency between the test cases. --- src/librustdoc/test.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 3b07a2ccdde09..8a9ca924ee1ab 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -775,7 +775,7 @@ fn main() { assert_eq!(2+2, 4); }".to_string(); let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected.clone(), 2)); + assert_eq!(output, (expected, 2)); } #[test] @@ -973,7 +973,7 @@ fn main() { assert_eq!(2+2, 4); }".to_string(); let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected.clone(), 2)); + assert_eq!(output, (expected, 2)); } #[test] @@ -988,7 +988,7 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);".to_string(); let output = make_test(input, None, true, &opts); - assert_eq!(output, (expected.clone(), 1)); + assert_eq!(output, (expected, 1)); } #[test] @@ -1003,6 +1003,6 @@ assert_eq!(2+2, 4);".to_string(); assert_eq!(2+2, 4); }".to_string(); let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected.clone(), 1)); + assert_eq!(output, (expected, 1)); } } From 046482e95e1b01a7f2ef01ffb7592db5045ad508 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 19 Sep 2018 11:07:43 +0300 Subject: [PATCH 31/34] rustc: future-proof error reporting for polymorphic constants in types. --- src/librustc/traits/error_reporting.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 466d472cca338..44e99e182a92f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -846,7 +846,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "could not evaluate constant expression", ) { Some(err) => err, - None => return, + None => { + self.tcx.sess.delay_span_bug(span, + &format!("constant in type had an ignored error: {:?}", err)); + return; + } } } From fd7565b076440829b86cc7bc5f2457bf42d43936 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 19 Sep 2018 18:40:33 +0300 Subject: [PATCH 32/34] Added tracking issue, fixed check, 1.30 -> 1.31 --- src/libcore/time.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e2990c8660e75..12c29a324b87e 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -30,7 +30,7 @@ const NANOS_PER_MILLI: u32 = 1_000_000; const NANOS_PER_MICRO: u32 = 1_000; const MILLIS_PER_SEC: u64 = 1_000; const MICROS_PER_SEC: u64 = 1_000_000; -const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128) - 1) as f64; +const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64; /// A `Duration` type to represent a span of time, typically used for system /// timeouts. @@ -472,7 +472,7 @@ impl Duration { /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.as_float_secs(), 2.7); /// ``` - #[unstable(feature = "duration_float", issue = "0")] + #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn as_float_secs(&self) -> f64 { (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64) @@ -491,14 +491,14 @@ impl Duration { /// let dur = Duration::from_float_secs(2.7); /// assert_eq!(dur, Duration::new(2, 700_000_000)); /// ``` - #[unstable(feature = "duration_float", issue = "0")] + #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn from_float_secs(secs: f64) -> Duration { let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { panic!("got non-finite value when converting float to duration"); } - if nanos > MAX_NANOS_F64 { + if nanos >= MAX_NANOS_F64 { panic!("overflow when converting float to duration"); } if nanos < 0.0 { @@ -525,7 +525,7 @@ impl Duration { /// assert_eq!(dur.mul_f64(3.14), Duration::new(8, 478_000_000)); /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0)); /// ``` - #[unstable(feature = "duration_float", issue = "0")] + #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn mul_f64(self, rhs: f64) -> Duration { Duration::from_float_secs(rhs * self.as_float_secs()) @@ -546,7 +546,7 @@ impl Duration { /// // note that truncation is used, not rounding /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598)); /// ``` - #[unstable(feature = "duration_float", issue = "0")] + #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn div_f64(self, rhs: f64) -> Duration { Duration::from_float_secs(self.as_float_secs() / rhs) @@ -563,7 +563,7 @@ impl Duration { /// let dur2 = Duration::new(5, 400_000_000); /// assert_eq!(dur1.div_duration(dur2), 0.5); /// ``` - #[unstable(feature = "duration_float", issue = "0")] + #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn div_duration(self, rhs: Duration) -> f64 { self.as_float_secs() / rhs.as_float_secs() @@ -611,7 +611,7 @@ impl Mul for Duration { } } -#[stable(feature = "symmetric_u32_duration_mul", since = "1.30.0")] +#[stable(feature = "symmetric_u32_duration_mul", since = "1.31.0")] impl Mul for u32 { type Output = Duration; From e2ff97a14d832b6814292d54fcea155f5d1905bc Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Wed, 19 Sep 2018 09:46:22 -0600 Subject: [PATCH 33/34] Pass --batch to gdb In one of my travis builds, I was surprised to find that the gdb pager was in use and caused travis to time out. Adding `--batch` to the gdb invocation will disable the pager. Note that the `-ex q` is retained, to make sure gdb exits with status 0, just in case `set -e` is in effect somehow. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b1701e4a65451..0646f4d4687a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -301,7 +301,7 @@ after_failure: EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; - gdb -q -c "$CORE" "$EXE" + gdb --batch -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' From ae42e537dbfabafb1f1e36d975b1fed33032c6c1 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 19 Sep 2018 17:53:12 -0300 Subject: [PATCH 34/34] Add regression test for thread local static mut borrows --- ...ead-local-static-mut-borrow-outlives-fn.rs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs diff --git a/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs new file mode 100644 index 0000000000000..e35c8095fa15d --- /dev/null +++ b/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// run-pass +// +// FIXME(#54366) - We probably shouldn't allow #[thread_local] static mut to get a 'static lifetime. + +#![feature(nll)] +#![feature(thread_local)] + +#[thread_local] +static mut X1: u64 = 0; + +struct S1 { + a: &'static mut u64, +} + +impl S1 { + fn new(_x: u64) -> S1 { + S1 { + a: unsafe { &mut X1 }, + } + } +} + +fn main() { + S1::new(0).a; +}