From fcda7b2871703f704f95ea4d83552827e69938bd Mon Sep 17 00:00:00 2001 From: Son Date: Wed, 5 Sep 2018 00:03:00 -0700 Subject: [PATCH 01/18] Add doc for impl From for Std Error --- src/libstd/error.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 29534696abc5b..6ca8e28c11659 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -152,6 +152,7 @@ pub trait Error: Debug + Display { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { + /// Converts a type of [`Error`] into a box of dyn [`Error`]. fn from(err: E) -> Box { Box::new(err) } @@ -159,6 +160,8 @@ impl<'a, E: Error + 'a> From for Box { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + Send + Sync + 'a> From for Box { + /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of dyn [`Error`] + + /// [`Send`] + [`Sync`]. fn from(err: E) -> Box { Box::new(err) } @@ -166,6 +169,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { + /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. fn from(err: String) -> Box { #[derive(Debug)] struct StringError(String); @@ -186,6 +190,7 @@ impl From for Box { #[stable(feature = "string_box_error", since = "1.6.0")] impl From for Box { + /// Converts a [`String`] into a box of dyn [`Error`]. fn from(str_err: String) -> Box { let err1: Box = From::from(str_err); let err2: Box = err1; @@ -195,6 +200,7 @@ impl From for Box { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b> From<&'b str> for Box { + /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. fn from(err: &'b str) -> Box { From::from(String::from(err)) } @@ -202,6 +208,7 @@ impl<'a, 'b> From<&'b str> for Box { #[stable(feature = "string_box_error", since = "1.6.0")] impl<'a> From<&'a str> for Box { + /// Converts a [`str`] into a box of dyn [`Error`]. fn from(err: &'a str) -> Box { From::from(String::from(err)) } @@ -209,6 +216,7 @@ impl<'a> From<&'a str> for Box { #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a, 'b> From> for Box { + /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) } @@ -216,6 +224,7 @@ impl<'a, 'b> From> for Box { #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a> From> for Box { + /// Converts a [`Cow`] into a box of dyn [`Error`]. fn from(err: Cow<'a, str>) -> Box { From::from(String::from(err)) } From a7cc1fccbd49a45a4d99a4c4ccdad16972b235bf Mon Sep 17 00:00:00 2001 From: Son Date: Wed, 26 Sep 2018 04:45:41 +1000 Subject: [PATCH 02/18] Examples for docs --- src/libstd/error.rs | 148 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 6ca8e28c11659..cfc256f3644d7 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -153,6 +153,36 @@ pub trait Error: Debug + Display { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f , "An error") + /// } + /// } + /// + /// impl Error for AnError { + /// fn description(&self) -> &str { + /// "Description of an error" + /// } + /// } + /// + /// fn main() { + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// } + /// ``` fn from(err: E) -> Box { Box::new(err) } @@ -162,6 +192,41 @@ impl<'a, E: Error + 'a> From for Box { impl<'a, E: Error + Send + Sync + 'a> From for Box { /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of dyn [`Error`] + /// [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f , "An error") + /// } + /// } + /// + /// impl Error for AnError { + /// fn description(&self) -> &str { + /// "Description of an error" + /// } + /// } + /// + /// unsafe impl Send for AnError {} + /// + /// unsafe impl Sync for AnError {} + /// + /// fn main() { + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// } + /// ``` fn from(err: E) -> Box { Box::new(err) } @@ -170,6 +235,20 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// fn main() { + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// } + /// ``` fn from(err: String) -> Box { #[derive(Debug)] struct StringError(String); @@ -191,6 +270,19 @@ impl From for Box { #[stable(feature = "string_box_error", since = "1.6.0")] impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// fn main() { + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// } + /// ``` fn from(str_err: String) -> Box { let err1: Box = From::from(str_err); let err2: Box = err1; @@ -201,6 +293,20 @@ impl From for Box { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b> From<&'b str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// fn main() { + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// } + /// ``` fn from(err: &'b str) -> Box { From::from(String::from(err)) } @@ -209,6 +315,19 @@ impl<'a, 'b> From<&'b str> for Box { #[stable(feature = "string_box_error", since = "1.6.0")] impl<'a> From<&'a str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// fn main() { + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// } + /// ``` fn from(err: &'a str) -> Box { From::from(String::from(err)) } @@ -217,6 +336,21 @@ impl<'a> From<&'a str> for Box { #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// fn main() { + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// } + /// ``` fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) } @@ -225,6 +359,20 @@ impl<'a, 'b> From> for Box { #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// fn main() { + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// } + /// ``` fn from(err: Cow<'a, str>) -> Box { From::from(String::from(err)) } From 0626afbcd23d9ef2e14617c609dc47765af117e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Romanowski?= Date: Sat, 29 Sep 2018 15:13:08 +0100 Subject: [PATCH 03/18] First stab at fixing #54505 --- src/librustc_typeck/check/demand.rs | 54 ++++++++++++- src/test/ui/range/issue-54505-no-literals.rs | 85 ++++++++++++++++++++ src/test/ui/range/issue-54505-no-std.rs | 61 ++++++++++++++ src/test/ui/range/issue-54505.fixed | 53 ++++++++++++ src/test/ui/range/issue-54505.rs | 53 ++++++++++++ src/test/ui/range/issue-54505.stderr | 75 +++++++++++++++++ 6 files changed, 378 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/range/issue-54505-no-literals.rs create mode 100644 src/test/ui/range/issue-54505-no-std.rs create mode 100644 src/test/ui/range/issue-54505.fixed create mode 100644 src/test/ui/range/issue-54505.rs create mode 100644 src/test/ui/range/issue-54505.stderr diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 71c78e7f87c07..f53a8168548e5 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -310,9 +310,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if self.can_coerce(ref_ty, expected) { if let Ok(src) = cm.span_to_snippet(sp) { let sugg_expr = match expr.node { // parenthesize if needed (Issue #46756) - hir::ExprKind::Cast(_, _) | - hir::ExprKind::Binary(_, _, _) => format!("({})", src), - _ => src, + hir::ExprKind::Cast(_, _) | + hir::ExprKind::Binary(_, _, _) | + _ if self.is_range_literal(expr) => format!("({})", src), + _ => src, }; if let Some(sugg) = self.can_use_as_ref(expr) { return Some(sugg); @@ -374,6 +375,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } + // This function checks if the specified expression is a built-in range literal + // (See: librustc/hir/lowering.rs::LoweringContext::lower_expr() ) + fn is_range_literal(&self, expr: &hir::Expr) -> bool { + use hir::{Path, QPath, ExprKind, TyKind}; + + // TODO how to work out std vs core here? + let ops_path = ["{{root}}", "std", "ops"]; + + let is_range_path = |path: &Path| { + let ident_names: Vec<_> = path.segments + .iter() + .map(|seg| seg.ident.as_str()) + .collect(); + + if let Some((last, preceding)) = ident_names.split_last() { + last.starts_with("Range") && + preceding.len() == 3 && + preceding.iter() + .zip(ops_path.iter()) + .all(|(a, b)| a == b) + } else { + false + } + }; + + match expr.node { + ExprKind::Struct(QPath::Resolved(None, ref path), _, _) | + ExprKind::Path(QPath::Resolved(None, ref path)) => { + return is_range_path(&path); + } + + ExprKind::Call(ref func, _) => { + if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node { + if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node { + let calls_new = segment.ident.as_str() == "new"; + + return is_range_path(&path) && calls_new; + } + } + } + + _ => {} + } + + false + } + pub fn check_for_cast(&self, err: &mut DiagnosticBuilder<'tcx>, expr: &hir::Expr, diff --git a/src/test/ui/range/issue-54505-no-literals.rs b/src/test/ui/range/issue-54505-no-literals.rs new file mode 100644 index 0000000000000..57d1938aca87a --- /dev/null +++ b/src/test/ui/range/issue-54505-no-literals.rs @@ -0,0 +1,85 @@ +// Copyright 2018 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-rustfix + +// Regression test for changes introduced while fixing #54505 + +// This test uses non-literals for Ranges +// (expecting no parens with borrow suggestion) + +use std::ops::RangeBounds; + + +// take a reference to any built-in range +fn take_range(_r: &impl RangeBounds) {} + + +fn main() { + take_range(std::ops::Range { start: 0, end: 1 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::Range { start: 0, end: 1 } + + take_range(::std::ops::Range { start: 0, end: 1 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 } + + take_range(std::ops::RangeFrom { start: 1 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeFrom { start: 1 } + + take_range(::std::ops::RangeFrom { start: 1 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeFrom { start: 1 } + + take_range(std::ops::RangeFull {}); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeFull {} + + take_range(::std::ops::RangeFull {}); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeFull {} + + take_range(std::ops::RangeInclusive::new(0, 1)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1) + + take_range(::std::ops::RangeInclusive::new(0, 1)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1) + + take_range(std::ops::RangeTo { end: 5 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeTo { end: 5 } + + take_range(::std::ops::RangeTo { end: 5 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeTo { end: 5 } + + take_range(std::ops::RangeToInclusive { end: 5 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 } + + take_range(::std::ops::RangeToInclusive { end: 5 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 } +} diff --git a/src/test/ui/range/issue-54505-no-std.rs b/src/test/ui/range/issue-54505-no-std.rs new file mode 100644 index 0000000000000..8e8793c1736ba --- /dev/null +++ b/src/test/ui/range/issue-54505-no-std.rs @@ -0,0 +1,61 @@ +// Copyright 2018 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-rustfix +// error-pattern: error: `#[panic_handler]` function required, but not found +// error-pattern: language item required, but not found: `panic_info` + + +// Regression test for #54505 - range borrowing suggestion had +// incorrect syntax (missing parentheses). + +// This test doesn't use std +// (so all Ranges resolve to core::ops::Range...) + +#![no_std] + +use core::ops::RangeBounds; + + +// take a reference to any built-in range +fn take_range(_r: &impl RangeBounds) {} + + +fn main() { + take_range(0..1); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(0..1) + + take_range(1..); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(1..) + + take_range(..); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..) + + take_range(0..=1); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(0..=1) + + take_range(..5); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..5) + + take_range(..=42); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..=42) +} diff --git a/src/test/ui/range/issue-54505.fixed b/src/test/ui/range/issue-54505.fixed new file mode 100644 index 0000000000000..ef8ded0f7a340 --- /dev/null +++ b/src/test/ui/range/issue-54505.fixed @@ -0,0 +1,53 @@ +// Copyright 2018 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-rustfix + +// Regression test for #54505 - range borrowing suggestion had +// incorrect syntax (missing parentheses). + +use std::ops::RangeBounds; + + +// take a reference to any built-in range +fn take_range(_r: &impl RangeBounds) {} + + +fn main() { + take_range(&(0..1)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(0..1) + + take_range(&(1..)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(1..) + + take_range(&(..)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..) + + take_range(&(0..=1)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(0..=1) + + take_range(&(..5)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..5) + + take_range(&(..=42)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..=42) +} diff --git a/src/test/ui/range/issue-54505.rs b/src/test/ui/range/issue-54505.rs new file mode 100644 index 0000000000000..b81c879a37ea4 --- /dev/null +++ b/src/test/ui/range/issue-54505.rs @@ -0,0 +1,53 @@ +// Copyright 2018 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-rustfix + +// Regression test for #54505 - range borrowing suggestion had +// incorrect syntax (missing parentheses). + +use std::ops::RangeBounds; + + +// take a reference to any built-in range +fn take_range(_r: &impl RangeBounds) {} + + +fn main() { + take_range(0..1); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(0..1) + + take_range(1..); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(1..) + + take_range(..); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..) + + take_range(0..=1); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(0..=1) + + take_range(..5); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..5) + + take_range(..=42); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &(..=42) +} diff --git a/src/test/ui/range/issue-54505.stderr b/src/test/ui/range/issue-54505.stderr new file mode 100644 index 0000000000000..5a59594ff5008 --- /dev/null +++ b/src/test/ui/range/issue-54505.stderr @@ -0,0 +1,75 @@ +error[E0308]: mismatched types + --> $DIR/issue-54505.rs:24:16 + | +LL | take_range(0..1); + | ^^^^ + | | + | expected reference, found struct `std::ops::Range` + | help: consider borrowing here: `&(0..1)` + | + = note: expected type `&_` + found type `std::ops::Range<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505.rs:29:16 + | +LL | take_range(1..); + | ^^^ + | | + | expected reference, found struct `std::ops::RangeFrom` + | help: consider borrowing here: `&(1..)` + | + = note: expected type `&_` + found type `std::ops::RangeFrom<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505.rs:34:16 + | +LL | take_range(..); + | ^^ + | | + | expected reference, found struct `std::ops::RangeFull` + | help: consider borrowing here: `&(..)` + | + = note: expected type `&_` + found type `std::ops::RangeFull` + +error[E0308]: mismatched types + --> $DIR/issue-54505.rs:39:16 + | +LL | take_range(0..=1); + | ^^^^^ + | | + | expected reference, found struct `std::ops::RangeInclusive` + | help: consider borrowing here: `&(0..=1)` + | + = note: expected type `&_` + found type `std::ops::RangeInclusive<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505.rs:44:16 + | +LL | take_range(..5); + | ^^^ + | | + | expected reference, found struct `std::ops::RangeTo` + | help: consider borrowing here: `&(..5)` + | + = note: expected type `&_` + found type `std::ops::RangeTo<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505.rs:49:16 + | +LL | take_range(..=42); + | ^^^^^ + | | + | expected reference, found struct `std::ops::RangeToInclusive` + | help: consider borrowing here: `&(..=42)` + | + = note: expected type `&_` + found type `std::ops::RangeToInclusive<{integer}>` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. From 53a4b3990974ddad56fd37e6b164e57a3993694c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 28 Sep 2018 00:42:19 +0300 Subject: [PATCH 04/18] handle outlives predicates in trait evaluation Fixes #54302. --- src/librustc/traits/fulfill.rs | 1 + src/librustc/traits/select.rs | 75 ++++++++++++++++++++-- src/test/ui/issue-54302-cases.rs | 95 ++++++++++++++++++++++++++++ src/test/ui/issue-54302-cases.stderr | 65 +++++++++++++++++++ src/test/ui/issue-54302.rs | 29 +++++++++ src/test/ui/issue-54302.stderr | 17 +++++ 6 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/issue-54302-cases.rs create mode 100644 src/test/ui/issue-54302-cases.stderr create mode 100644 src/test/ui/issue-54302.rs create mode 100644 src/test/ui/issue-54302.stderr diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 0f330504334a6..8258b54104d97 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -362,6 +362,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, match binder.no_late_bound_regions() { // If so, this obligation is an error (for now). Eventually we should be // able to support additional cases here, like `for<'a> &'a str: 'a`. + // NOTE: this is duplicate-implemented between here and fulfillment. None => { ProcessResult::Error(CodeSelectionError(Unimplemented)) } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 268b8e0161b6d..0e087153673e7 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -690,10 +690,76 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { - // we do not consider region relationships when - // evaluating trait matches - Ok(EvaluatedToOk) + ty::Predicate::TypeOutlives(ref binder) => { + assert!(!binder.has_escaping_regions()); + // Check if the type has higher-ranked regions. + if binder.skip_binder().0.has_escaping_regions() { + // If so, this obligation is an error (for now). Eventually we should be + // able to support additional cases here, like `for<'a> &'a str: 'a`. + + // NOTE: this hack is implemented in both trait fulfillment and + // evaluation. If you fix it in one place, make sure you fix it + // in the other. + + // We don't want to allow this sort of reasoning in intercrate + // mode, for backwards-compatibility reasons. + if self.intercrate.is_some() { + Ok(EvaluatedToAmbig) + } else { + Ok(EvaluatedToErr) + } + } else { + // If the type has no late bound regions, then if we assign all + // the inference variables in it to be 'static, then the type + // will be 'static itself. + // + // Therefore, `staticize(T): 'a` holds for any `'a`, so this + // obligation is fulfilled. Because evaluation works with + // staticized types (yes I know this is involved with #21974), + // we are 100% OK here. + Ok(EvaluatedToOk) + } + } + + ty::Predicate::RegionOutlives(ref binder) => { + let ty::OutlivesPredicate(r_a, r_b) = binder.skip_binder(); + + if r_a == r_b { + // for<'a> 'a: 'a. OK + Ok(EvaluatedToOk) + } else if r_a.is_late_bound() || r_b.is_late_bound() { + // There is no current way to prove `for<'a> 'a: 'x` + // unless `'a = 'x`, because there are no bounds involving + // lifetimes. + + // It is possible to solve `for<'a> 'x: 'a` where `'x` + // is a free region by forcing `'x = 'static`. However, + // fulfillment does not *quite* do this ATM (it calls + // `region_outlives_predicate`, which is OK if `'x` is + // literally ReStatic, but is *not* OK if `'x` is any + // sort of inference variable, even if it *is* equal + // to `'static`). + + // If we ever want to handle that sort of obligations, + // we need to make sure we are not confused by + // technically-allowed-by-RFC-447-but-probably-should-not-be + // impls such as + // ```Rust + // impl<'a, 's, T> X<'s> for T where T: Debug + 's, 'a: 's + // ``` + + // We don't want to allow this sort of reasoning in intercrate + // mode, for backwards-compatibility reasons. + if self.intercrate.is_some() { + Ok(EvaluatedToAmbig) + } else { + Ok(EvaluatedToErr) + } + } else { + // Relating 2 inference variable regions. These will + // always hold if our query is "staticized". + Ok(EvaluatedToOk) + } } ty::Predicate::ObjectSafe(trait_def_id) => { @@ -900,6 +966,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref); + 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) { diff --git a/src/test/ui/issue-54302-cases.rs b/src/test/ui/issue-54302-cases.rs new file mode 100644 index 0000000000000..6d1c61c80f06e --- /dev/null +++ b/src/test/ui/issue-54302-cases.rs @@ -0,0 +1,95 @@ +// Copyright 2018 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. + +trait Mirror { + type Image; + fn coerce(self) -> Self::Image; +} + +impl Mirror for T { + type Image = T; + fn coerce(self) -> Self { self } +} + +trait Foo<'x, T> { + fn foo(self) -> &'x T; +} + +impl<'s, 'x, T: 'x> Foo<'x, T> for &'s T where &'s T: Foo2<'x, T> { + fn foo(self) -> &'x T { self.foo2() } +} + +trait Foo2<'x, T> { + fn foo2(self) -> &'x T; +} + +// example 1 - fails leak check +impl<'x> Foo2<'x, u32> for &'x u32 +{ + fn foo2(self) -> &'x u32 { self } +} + +// example 2 - OK with this issue +impl<'x, 'a: 'x> Foo2<'x, i32> for &'a i32 +{ + fn foo2(self) -> &'x i32 { self } +} + +// example 3 - fails due to issue #XYZ + Leak-check +impl<'x, T> Foo2<'x, u64> for T + where T: Mirror +{ + fn foo2(self) -> &'x u64 { self.coerce() } +} + +// example 4 - fails due to issue #XYZ +impl<'x, 'a: 'x, T> Foo2<'x, i64> for T + where T: Mirror +{ + fn foo2(self) -> &'x i64 { self.coerce() } +} + + +trait RefFoo { + fn ref_foo(&self) -> &'static T; +} + +impl RefFoo for T where for<'a> &'a T: Foo<'static, T> { + fn ref_foo(&self) -> &'static T { + self.foo() + } +} + + +fn coerce_lifetime1(a: &u32) -> &'static u32 +{ + >::ref_foo(a) + //~^ ERROR the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied +} + +fn coerce_lifetime2(a: &i32) -> &'static i32 +{ + >::ref_foo(a) + //~^ ERROR the requirement `for<'a> 'a : ` is not satisfied +} + +fn coerce_lifetime3(a: &u64) -> &'static u64 +{ + >::ref_foo(a) + //~^ ERROR type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64` +} + +fn coerce_lifetime4(a: &i64) -> &'static i64 +{ + >::ref_foo(a) + //~^ ERROR type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64` +} + +fn main() {} diff --git a/src/test/ui/issue-54302-cases.stderr b/src/test/ui/issue-54302-cases.stderr new file mode 100644 index 0000000000000..9603f7a973c13 --- /dev/null +++ b/src/test/ui/issue-54302-cases.stderr @@ -0,0 +1,65 @@ +error[E0277]: the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied + --> $DIR/issue-54302-cases.rs:73:5 + | +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo2<'_, u32>` is not implemented for `&'a u32` + | + = help: the following implementations were found: + <&'x u32 as Foo2<'x, u32>> + = note: required because of the requirements on the impl of `for<'a> Foo<'static, u32>` for `&'a u32` + = note: required because of the requirements on the impl of `RefFoo` for `u32` +note: required by `RefFoo::ref_foo` + --> $DIR/issue-54302-cases.rs:61:5 + | +LL | fn ref_foo(&self) -> &'static T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0279]: the requirement `for<'a> 'a : ` is not satisfied (`expected bound lifetime parameter 'a, found concrete lifetime`) + --> $DIR/issue-54302-cases.rs:79:5 + | +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `for<'a> Foo2<'_, i32>` for `&'a i32` + = note: required because of the requirements on the impl of `for<'a> Foo<'static, i32>` for `&'a i32` + = note: required because of the requirements on the impl of `RefFoo` for `i32` +note: required by `RefFoo::ref_foo` + --> $DIR/issue-54302-cases.rs:61:5 + | +LL | fn ref_foo(&self) -> &'static T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64` + --> $DIR/issue-54302-cases.rs:85:5 + | +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime + | + = note: required because of the requirements on the impl of `for<'a> Foo2<'_, u64>` for `&'a u64` + = note: required because of the requirements on the impl of `for<'a> Foo<'static, u64>` for `&'a u64` + = note: required because of the requirements on the impl of `RefFoo` for `u64` +note: required by `RefFoo::ref_foo` + --> $DIR/issue-54302-cases.rs:61:5 + | +LL | fn ref_foo(&self) -> &'static T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64` + --> $DIR/issue-54302-cases.rs:91:5 + | +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime + | + = note: required because of the requirements on the impl of `for<'a> Foo2<'_, i64>` for `&'a i64` + = note: required because of the requirements on the impl of `for<'a> Foo<'static, i64>` for `&'a i64` + = note: required because of the requirements on the impl of `RefFoo` for `i64` +note: required by `RefFoo::ref_foo` + --> $DIR/issue-54302-cases.rs:61:5 + | +LL | fn ref_foo(&self) -> &'static T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors occurred: E0271, E0277, E0279. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/issue-54302.rs b/src/test/ui/issue-54302.rs new file mode 100644 index 0000000000000..969d19cac2d76 --- /dev/null +++ b/src/test/ui/issue-54302.rs @@ -0,0 +1,29 @@ +// Copyright 2018 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. + +trait Deserialize<'de> {} + +trait DeserializeOwned: for<'de> Deserialize<'de> {} +impl DeserializeOwned for T where T: for<'de> Deserialize<'de> {} + +// Based on this impl, `&'static str` only implements Deserialize<'static>. +// It does not implement for<'de> Deserialize<'de>. +impl<'de: 'a, 'a> Deserialize<'de> for &'a str {} + +fn main() { + // Then why does it implement DeserializeOwned? This compiles. + fn assert_deserialize_owned() {} + assert_deserialize_owned::<&'static str>(); + //~^ ERROR the requirement `for<'de> 'de : ` is not satisfied + + // It correctly does not implement for<'de> Deserialize<'de>. + //fn assert_hrtb Deserialize<'de>>() {} + //assert_hrtb::<&'static str>(); +} diff --git a/src/test/ui/issue-54302.stderr b/src/test/ui/issue-54302.stderr new file mode 100644 index 0000000000000..f122daeecf63a --- /dev/null +++ b/src/test/ui/issue-54302.stderr @@ -0,0 +1,17 @@ +error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`) + --> $DIR/issue-54302.rs:23:5 + | +LL | assert_deserialize_owned::<&'static str>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `for<'de> Deserialize<'de>` for `&'static str` + = note: required because of the requirements on the impl of `DeserializeOwned` for `&'static str` +note: required by `main::assert_deserialize_owned` + --> $DIR/issue-54302.rs:22:5 + | +LL | fn assert_deserialize_owned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0279`. From 9d44e9eb7ce65d1ae13db56c56713de4f4ef95bd Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 28 Sep 2018 23:20:16 +0300 Subject: [PATCH 05/18] enable using the evaluation cache on predicates with LBRs There is no reason not to do it. --- src/librustc/traits/fulfill.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 8258b54104d97..e6bf02cd73e0d 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -292,7 +292,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, ty::Predicate::Trait(ref data) => { let trait_obligation = obligation.with(data.clone()); - if data.is_global() && !data.has_late_bound_regions() { + if data.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if self.selcx.infcx().predicate_must_hold(&obligation) { From 1069c0e38f28539ab29c32921435b3f28eb63808 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 29 Sep 2018 00:22:35 +0300 Subject: [PATCH 06/18] add a special case for literal `'static: 'a` where-clauses This makes evaluation more consistent with fulfillment. --- src/librustc/traits/select.rs | 46 +++++++++++++------ .../traits-static-outlives-a-where-clause.rs | 33 +++++++++++++ 2 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 0e087153673e7..860914d1984ec 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -727,26 +727,42 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if r_a == r_b { // for<'a> 'a: 'a. OK Ok(EvaluatedToOk) + } else if **r_a == ty::ReStatic { + // 'static: 'x always holds. + // + // This special case is handled somewhat inconsistently - if we + // have an inference variable that is supposed to be equal to + // `'static`, then we don't allow it to be equated to an LBR, + // but if we have a literal `'static`, then we *do*. + // + // This is actually consistent with how our region inference works. + // + // It would appear that this sort of inconsistency would + // cause "instability" problems with evaluation caching. However, + // evaluation caching is only for trait predicates, and when + // trait predicates create nested obligations, they contain + // inference variables for all the regions in the trait - the + // only way this codepath can be reached from trait predicate + // evaluation is when the user typed an explicit `where 'static: 'a` + // lifetime bound (in which case we want to return EvaluatedToOk). + // + // If we ever want to handle inference variables that might be + // equatable with ReStatic, we need to make sure we are not confused by + // technically-allowed-by-RFC-447-but-probably-should-not-be + // impls such as + // ```Rust + // impl<'a, 's, T> X<'s> for T where T: Debug + 'a, 'a: 's + // ``` + Ok(EvaluatedToOk) } else if r_a.is_late_bound() || r_b.is_late_bound() { // There is no current way to prove `for<'a> 'a: 'x` // unless `'a = 'x`, because there are no bounds involving // lifetimes. - // It is possible to solve `for<'a> 'x: 'a` where `'x` - // is a free region by forcing `'x = 'static`. However, - // fulfillment does not *quite* do this ATM (it calls - // `region_outlives_predicate`, which is OK if `'x` is - // literally ReStatic, but is *not* OK if `'x` is any - // sort of inference variable, even if it *is* equal - // to `'static`). - - // If we ever want to handle that sort of obligations, - // we need to make sure we are not confused by - // technically-allowed-by-RFC-447-but-probably-should-not-be - // impls such as - // ```Rust - // impl<'a, 's, T> X<'s> for T where T: Debug + 's, 'a: 's - // ``` + // It might be possible to prove `for<'a> 'x: 'a` by forcing `'x` + // to be `'static`. However, this is not currently done by type + // inference unless `'x` is literally ReStatic. See the comment + // above. // We don't want to allow this sort of reasoning in intercrate // mode, for backwards-compatibility reasons. diff --git a/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs b/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs new file mode 100644 index 0000000000000..1051bec63079e --- /dev/null +++ b/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs @@ -0,0 +1,33 @@ +// Copyright 2018 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 + +trait Foo<'a> { + fn xyz(self); +} +impl<'a, T> Foo<'a> for T where 'static: 'a { + fn xyz(self) {} +} + +trait Bar { + fn uvw(self); +} +impl Bar for T where for<'a> T: Foo<'a> { + fn uvw(self) { self.xyz(); } +} + +fn foo(t: T) where T: Bar { + t.uvw(); +} + +fn main() { + foo(0); +} From f7d35cc5a8ffcf74937e8c00586d97609b1095ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Romanowski?= Date: Mon, 1 Oct 2018 23:23:57 +0100 Subject: [PATCH 07/18] Fix range borrowing suggestions logic --- src/librustc_typeck/check/demand.rs | 48 ++++-- .../ui/range/issue-54505-no-literals.fixed | 85 ++++++++++ .../ui/range/issue-54505-no-literals.stderr | 147 ++++++++++++++++++ src/test/ui/range/issue-54505-no-std.rs | 5 +- src/test/ui/range/issue-54505-no-std.stderr | 79 ++++++++++ 5 files changed, 351 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/range/issue-54505-no-literals.fixed create mode 100644 src/test/ui/range/issue-54505-no-literals.stderr create mode 100644 src/test/ui/range/issue-54505-no-std.stderr diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index f53a8168548e5..e0577add61c21 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -309,12 +309,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if self.can_coerce(ref_ty, expected) { if let Ok(src) = cm.span_to_snippet(sp) { - let sugg_expr = match expr.node { // parenthesize if needed (Issue #46756) - hir::ExprKind::Cast(_, _) | - hir::ExprKind::Binary(_, _, _) | - _ if self.is_range_literal(expr) => format!("({})", src), - _ => src, + let needs_parens = match expr.node { + // parenthesize if needed (Issue #46756) + hir::ExprKind::Cast(_, _) | + hir::ExprKind::Binary(_, _, _) => true, + // parenthesize borrows of range literals (Issue #54505) + _ if self.is_range_literal(expr) => true, + _ => false, }; + let sugg_expr = if needs_parens { format!("({})", src) } else { src }; + if let Some(sugg) = self.can_use_as_ref(expr) { return Some(sugg); } @@ -380,8 +384,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn is_range_literal(&self, expr: &hir::Expr) -> bool { use hir::{Path, QPath, ExprKind, TyKind}; - // TODO how to work out std vs core here? - let ops_path = ["{{root}}", "std", "ops"]; + // we support `::std::ops::Range` and `::std::core::Range` prefixes + // (via split on "|") + let ops_path = ["{{root}}", "std|core", "ops"]; let is_range_path = |path: &Path| { let ident_names: Vec<_> = path.segments @@ -394,24 +399,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { preceding.len() == 3 && preceding.iter() .zip(ops_path.iter()) - .all(|(a, b)| a == b) + .all(|(seg, match_seg)| { + match_seg.split("|") + .into_iter() + .any(|ref spl_seg| seg == spl_seg) + }) + } else { + false + } + }; + + let is_range_struct_snippet = |span: &Span| { + // Tell if expression span snippet looks like an explicit + // Range struct or new() call. This is to allow rejecting + // Ranges constructed with non-literals. + let source_map = self.tcx.sess.source_map(); + let end_point = source_map.end_point(*span); + + if let Ok(end_string) = source_map.span_to_snippet(end_point) { + end_string.ends_with("}") || end_string.ends_with(")") } else { false } + }; match expr.node { + // all built-in range literals but `..=` and `..` + // desugar to Structs, `..` desugars to its struct path ExprKind::Struct(QPath::Resolved(None, ref path), _, _) | ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path); + return is_range_path(&path) && !is_range_struct_snippet(&expr.span); } + // `..=` desugars into RangeInclusive::new(...) ExprKind::Call(ref func, _) => { if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node { if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node { let calls_new = segment.ident.as_str() == "new"; - return is_range_path(&path) && calls_new; + return is_range_path(&path) && calls_new && + !is_range_struct_snippet(&expr.span); } } } diff --git a/src/test/ui/range/issue-54505-no-literals.fixed b/src/test/ui/range/issue-54505-no-literals.fixed new file mode 100644 index 0000000000000..5be024dff5309 --- /dev/null +++ b/src/test/ui/range/issue-54505-no-literals.fixed @@ -0,0 +1,85 @@ +// Copyright 2018 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-rustfix + +// Regression test for changes introduced while fixing #54505 + +// This test uses non-literals for Ranges +// (expecting no parens with borrow suggestion) + +use std::ops::RangeBounds; + + +// take a reference to any built-in range +fn take_range(_r: &impl RangeBounds) {} + + +fn main() { + take_range(&std::ops::Range { start: 0, end: 1 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::Range { start: 0, end: 1 } + + take_range(&::std::ops::Range { start: 0, end: 1 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 } + + take_range(&std::ops::RangeFrom { start: 1 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeFrom { start: 1 } + + take_range(&::std::ops::RangeFrom { start: 1 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeFrom { start: 1 } + + take_range(&std::ops::RangeFull {}); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeFull {} + + take_range(&::std::ops::RangeFull {}); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeFull {} + + take_range(&std::ops::RangeInclusive::new(0, 1)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1) + + take_range(&::std::ops::RangeInclusive::new(0, 1)); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1) + + take_range(&std::ops::RangeTo { end: 5 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeTo { end: 5 } + + take_range(&::std::ops::RangeTo { end: 5 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeTo { end: 5 } + + take_range(&std::ops::RangeToInclusive { end: 5 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 } + + take_range(&::std::ops::RangeToInclusive { end: 5 }); + //~^ ERROR mismatched types [E0308] + //~| HELP consider borrowing here + //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 } +} diff --git a/src/test/ui/range/issue-54505-no-literals.stderr b/src/test/ui/range/issue-54505-no-literals.stderr new file mode 100644 index 0000000000000..a8be4de5f0e78 --- /dev/null +++ b/src/test/ui/range/issue-54505-no-literals.stderr @@ -0,0 +1,147 @@ +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:26:16 + | +LL | take_range(std::ops::Range { start: 0, end: 1 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::Range` + | help: consider borrowing here: `&std::ops::Range { start: 0, end: 1 }` + | + = note: expected type `&_` + found type `std::ops::Range<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:31:16 + | +LL | take_range(::std::ops::Range { start: 0, end: 1 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::Range` + | help: consider borrowing here: `&::std::ops::Range { start: 0, end: 1 }` + | + = note: expected type `&_` + found type `std::ops::Range<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:36:16 + | +LL | take_range(std::ops::RangeFrom { start: 1 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeFrom` + | help: consider borrowing here: `&std::ops::RangeFrom { start: 1 }` + | + = note: expected type `&_` + found type `std::ops::RangeFrom<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:41:16 + | +LL | take_range(::std::ops::RangeFrom { start: 1 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeFrom` + | help: consider borrowing here: `&::std::ops::RangeFrom { start: 1 }` + | + = note: expected type `&_` + found type `std::ops::RangeFrom<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:46:16 + | +LL | take_range(std::ops::RangeFull {}); + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeFull` + | help: consider borrowing here: `&std::ops::RangeFull {}` + | + = note: expected type `&_` + found type `std::ops::RangeFull` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:51:16 + | +LL | take_range(::std::ops::RangeFull {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeFull` + | help: consider borrowing here: `&::std::ops::RangeFull {}` + | + = note: expected type `&_` + found type `std::ops::RangeFull` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:56:16 + | +LL | take_range(std::ops::RangeInclusive::new(0, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeInclusive` + | help: consider borrowing here: `&std::ops::RangeInclusive::new(0, 1)` + | + = note: expected type `&_` + found type `std::ops::RangeInclusive<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:61:16 + | +LL | take_range(::std::ops::RangeInclusive::new(0, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeInclusive` + | help: consider borrowing here: `&::std::ops::RangeInclusive::new(0, 1)` + | + = note: expected type `&_` + found type `std::ops::RangeInclusive<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:66:16 + | +LL | take_range(std::ops::RangeTo { end: 5 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeTo` + | help: consider borrowing here: `&std::ops::RangeTo { end: 5 }` + | + = note: expected type `&_` + found type `std::ops::RangeTo<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:71:16 + | +LL | take_range(::std::ops::RangeTo { end: 5 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeTo` + | help: consider borrowing here: `&::std::ops::RangeTo { end: 5 }` + | + = note: expected type `&_` + found type `std::ops::RangeTo<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:76:16 + | +LL | take_range(std::ops::RangeToInclusive { end: 5 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeToInclusive` + | help: consider borrowing here: `&std::ops::RangeToInclusive { end: 5 }` + | + = note: expected type `&_` + found type `std::ops::RangeToInclusive<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-literals.rs:81:16 + | +LL | take_range(::std::ops::RangeToInclusive { end: 5 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected reference, found struct `std::ops::RangeToInclusive` + | help: consider borrowing here: `&::std::ops::RangeToInclusive { end: 5 }` + | + = note: expected type `&_` + found type `std::ops::RangeToInclusive<{integer}>` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/range/issue-54505-no-std.rs b/src/test/ui/range/issue-54505-no-std.rs index 8e8793c1736ba..0dadaecd7d8a3 100644 --- a/src/test/ui/range/issue-54505-no-std.rs +++ b/src/test/ui/range/issue-54505-no-std.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// run-rustfix -// error-pattern: error: `#[panic_handler]` function required, but not found -// error-pattern: language item required, but not found: `panic_info` +// error-pattern: `#[panic_handler]` function required, but not found +// error-pattern: language item required, but not found: `eh_personality` // Regression test for #54505 - range borrowing suggestion had diff --git a/src/test/ui/range/issue-54505-no-std.stderr b/src/test/ui/range/issue-54505-no-std.stderr new file mode 100644 index 0000000000000..035bc6406586c --- /dev/null +++ b/src/test/ui/range/issue-54505-no-std.stderr @@ -0,0 +1,79 @@ +error: `#[panic_handler]` function required, but not found + +error: language item required, but not found: `eh_personality` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-std.rs:31:16 + | +LL | take_range(0..1); + | ^^^^ + | | + | expected reference, found struct `core::ops::Range` + | help: consider borrowing here: `&(0..1)` + | + = note: expected type `&_` + found type `core::ops::Range<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-std.rs:36:16 + | +LL | take_range(1..); + | ^^^ + | | + | expected reference, found struct `core::ops::RangeFrom` + | help: consider borrowing here: `&(1..)` + | + = note: expected type `&_` + found type `core::ops::RangeFrom<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-std.rs:41:16 + | +LL | take_range(..); + | ^^ + | | + | expected reference, found struct `core::ops::RangeFull` + | help: consider borrowing here: `&(..)` + | + = note: expected type `&_` + found type `core::ops::RangeFull` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-std.rs:46:16 + | +LL | take_range(0..=1); + | ^^^^^ + | | + | expected reference, found struct `core::ops::RangeInclusive` + | help: consider borrowing here: `&(0..=1)` + | + = note: expected type `&_` + found type `core::ops::RangeInclusive<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-std.rs:51:16 + | +LL | take_range(..5); + | ^^^ + | | + | expected reference, found struct `core::ops::RangeTo` + | help: consider borrowing here: `&(..5)` + | + = note: expected type `&_` + found type `core::ops::RangeTo<{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-54505-no-std.rs:56:16 + | +LL | take_range(..=42); + | ^^^^^ + | | + | expected reference, found struct `core::ops::RangeToInclusive` + | help: consider borrowing here: `&(..=42)` + | + = note: expected type `&_` + found type `core::ops::RangeToInclusive<{integer}>` + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0308`. From ec59188025582fd91ab868206cfb3f3f05e27ade Mon Sep 17 00:00:00 2001 From: Nathan West Date: Tue, 2 Oct 2018 12:35:25 -0700 Subject: [PATCH 08/18] Make spec_extend use for_each() --- src/liballoc/vec.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index e845438c0a836..2bc037e3fee12 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1822,12 +1822,12 @@ impl SpecExtend for Vec unsafe { let mut ptr = self.as_mut_ptr().add(self.len()); let mut local_len = SetLenOnDrop::new(&mut self.len); - for element in iterator { + iterator.for_each(move |element| { ptr::write(ptr, element); ptr = ptr.offset(1); // NB can't overflow since we would have had to alloc the address space local_len.increment_len(1); - } + }); } } else { self.extend_desugared(iterator) From 87bf9e2056f8ee71c71e5f9c91afbc1fd965def8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Romanowski?= Date: Tue, 2 Oct 2018 22:10:04 +0100 Subject: [PATCH 09/18] Address review comments --- src/librustc_typeck/check/demand.rs | 63 +++++++++---------- .../ui/range/issue-54505-no-literals.fixed | 10 --- src/test/ui/range/issue-54505-no-literals.rs | 10 --- .../ui/range/issue-54505-no-literals.stderr | 24 +++---- src/test/ui/range/issue-54505-no-std.rs | 10 --- src/test/ui/range/issue-54505-no-std.stderr | 12 ++-- src/test/ui/range/issue-54505.fixed | 10 --- src/test/ui/range/issue-54505.rs | 10 --- src/test/ui/range/issue-54505.stderr | 12 ++-- 9 files changed, 52 insertions(+), 109 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index e0577add61c21..6eaeee5c0e28b 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -317,7 +317,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_range_literal(expr) => true, _ => false, }; - let sugg_expr = if needs_parens { format!("({})", src) } else { src }; + let sugg_expr = if needs_parens { + format!("({})", src) + } else { + src + }; if let Some(sugg) = self.can_use_as_ref(expr) { return Some(sugg); @@ -379,67 +383,56 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } - // This function checks if the specified expression is a built-in range literal - // (See: librustc/hir/lowering.rs::LoweringContext::lower_expr() ) + /// This function checks if the specified expression is a built-in range literal. + /// (See: ``librustc::hir::lowering::LoweringContext::lower_expr()``). fn is_range_literal(&self, expr: &hir::Expr) -> bool { use hir::{Path, QPath, ExprKind, TyKind}; - // we support `::std::ops::Range` and `::std::core::Range` prefixes - // (via split on "|") - let ops_path = ["{{root}}", "std|core", "ops"]; - + // We support `::std::ops::Range` and `::core::ops::Range` prefixes let is_range_path = |path: &Path| { - let ident_names: Vec<_> = path.segments - .iter() - .map(|seg| seg.ident.as_str()) - .collect(); - - if let Some((last, preceding)) = ident_names.split_last() { - last.starts_with("Range") && - preceding.len() == 3 && - preceding.iter() - .zip(ops_path.iter()) - .all(|(seg, match_seg)| { - match_seg.split("|") - .into_iter() - .any(|ref spl_seg| seg == spl_seg) - }) + let mut segs = path.segments.iter() + .map(|seg| seg.ident.as_str()); + + if let (Some(root), Some(std_core), Some(ops), Some(range), None) = + (segs.next(), segs.next(), segs.next(), segs.next(), segs.next()) + { + // "{{root}}" is the equivalent of `::` prefix in Path + root == "{{root}}" && (std_core == "std" || std_core == "core") + && ops == "ops" && range.starts_with("Range") } else { false } }; - let is_range_struct_snippet = |span: &Span| { - // Tell if expression span snippet looks like an explicit - // Range struct or new() call. This is to allow rejecting - // Ranges constructed with non-literals. + let is_range_literal = |span: &Span| { + // Tell if expression span snippet doesn't look like an explicit + // Range struct or `new()` call. This is to allow inferring + // that this is a range literal. let source_map = self.tcx.sess.source_map(); let end_point = source_map.end_point(*span); if let Ok(end_string) = source_map.span_to_snippet(end_point) { - end_string.ends_with("}") || end_string.ends_with(")") + !(end_string.ends_with("}") || end_string.ends_with(")")) } else { false } - }; match expr.node { - // all built-in range literals but `..=` and `..` - // desugar to Structs, `..` desugars to its struct path + // All built-in range literals but `..=` and `..` desugar to Structs ExprKind::Struct(QPath::Resolved(None, ref path), _, _) | + // `..` desugars to its struct path ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && !is_range_struct_snippet(&expr.span); + return is_range_path(&path) && is_range_literal(&expr.span); } - // `..=` desugars into RangeInclusive::new(...) + // `..=` desugars into `::std::ops::RangeInclusive::new(...)` ExprKind::Call(ref func, _) => { if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node { if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node { - let calls_new = segment.ident.as_str() == "new"; + let call_to_new = segment.ident.as_str() == "new"; - return is_range_path(&path) && calls_new && - !is_range_struct_snippet(&expr.span); + return is_range_path(&path) && is_range_literal(&expr.span) && call_to_new; } } } diff --git a/src/test/ui/range/issue-54505-no-literals.fixed b/src/test/ui/range/issue-54505-no-literals.fixed index 5be024dff5309..4d8f67182b9ac 100644 --- a/src/test/ui/range/issue-54505-no-literals.fixed +++ b/src/test/ui/range/issue-54505-no-literals.fixed @@ -1,13 +1,3 @@ -// Copyright 2018 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-rustfix // Regression test for changes introduced while fixing #54505 diff --git a/src/test/ui/range/issue-54505-no-literals.rs b/src/test/ui/range/issue-54505-no-literals.rs index 57d1938aca87a..dc21dcbc2db41 100644 --- a/src/test/ui/range/issue-54505-no-literals.rs +++ b/src/test/ui/range/issue-54505-no-literals.rs @@ -1,13 +1,3 @@ -// Copyright 2018 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-rustfix // Regression test for changes introduced while fixing #54505 diff --git a/src/test/ui/range/issue-54505-no-literals.stderr b/src/test/ui/range/issue-54505-no-literals.stderr index a8be4de5f0e78..b8811c98d21bd 100644 --- a/src/test/ui/range/issue-54505-no-literals.stderr +++ b/src/test/ui/range/issue-54505-no-literals.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:26:16 + --> $DIR/issue-54505-no-literals.rs:16:16 | LL | take_range(std::ops::Range { start: 0, end: 1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | take_range(std::ops::Range { start: 0, end: 1 }); found type `std::ops::Range<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:31:16 + --> $DIR/issue-54505-no-literals.rs:21:16 | LL | take_range(::std::ops::Range { start: 0, end: 1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | take_range(::std::ops::Range { start: 0, end: 1 }); found type `std::ops::Range<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:36:16 + --> $DIR/issue-54505-no-literals.rs:26:16 | LL | take_range(std::ops::RangeFrom { start: 1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | take_range(std::ops::RangeFrom { start: 1 }); found type `std::ops::RangeFrom<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:41:16 + --> $DIR/issue-54505-no-literals.rs:31:16 | LL | take_range(::std::ops::RangeFrom { start: 1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | take_range(::std::ops::RangeFrom { start: 1 }); found type `std::ops::RangeFrom<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:46:16 + --> $DIR/issue-54505-no-literals.rs:36:16 | LL | take_range(std::ops::RangeFull {}); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | take_range(std::ops::RangeFull {}); found type `std::ops::RangeFull` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:51:16 + --> $DIR/issue-54505-no-literals.rs:41:16 | LL | take_range(::std::ops::RangeFull {}); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | take_range(::std::ops::RangeFull {}); found type `std::ops::RangeFull` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:56:16 + --> $DIR/issue-54505-no-literals.rs:46:16 | LL | take_range(std::ops::RangeInclusive::new(0, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +83,7 @@ LL | take_range(std::ops::RangeInclusive::new(0, 1)); found type `std::ops::RangeInclusive<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:61:16 + --> $DIR/issue-54505-no-literals.rs:51:16 | LL | take_range(::std::ops::RangeInclusive::new(0, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | take_range(::std::ops::RangeInclusive::new(0, 1)); found type `std::ops::RangeInclusive<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:66:16 + --> $DIR/issue-54505-no-literals.rs:56:16 | LL | take_range(std::ops::RangeTo { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | take_range(std::ops::RangeTo { end: 5 }); found type `std::ops::RangeTo<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:71:16 + --> $DIR/issue-54505-no-literals.rs:61:16 | LL | take_range(::std::ops::RangeTo { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | take_range(::std::ops::RangeTo { end: 5 }); found type `std::ops::RangeTo<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:76:16 + --> $DIR/issue-54505-no-literals.rs:66:16 | LL | take_range(std::ops::RangeToInclusive { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | take_range(std::ops::RangeToInclusive { end: 5 }); found type `std::ops::RangeToInclusive<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-literals.rs:81:16 + --> $DIR/issue-54505-no-literals.rs:71:16 | LL | take_range(::std::ops::RangeToInclusive { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/range/issue-54505-no-std.rs b/src/test/ui/range/issue-54505-no-std.rs index 0dadaecd7d8a3..c2b17b53ba16b 100644 --- a/src/test/ui/range/issue-54505-no-std.rs +++ b/src/test/ui/range/issue-54505-no-std.rs @@ -1,13 +1,3 @@ -// Copyright 2018 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. - // error-pattern: `#[panic_handler]` function required, but not found // error-pattern: language item required, but not found: `eh_personality` diff --git a/src/test/ui/range/issue-54505-no-std.stderr b/src/test/ui/range/issue-54505-no-std.stderr index 035bc6406586c..2810a3f076d4b 100644 --- a/src/test/ui/range/issue-54505-no-std.stderr +++ b/src/test/ui/range/issue-54505-no-std.stderr @@ -3,7 +3,7 @@ error: `#[panic_handler]` function required, but not found error: language item required, but not found: `eh_personality` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:31:16 + --> $DIR/issue-54505-no-std.rs:21:16 | LL | take_range(0..1); | ^^^^ @@ -15,7 +15,7 @@ LL | take_range(0..1); found type `core::ops::Range<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:36:16 + --> $DIR/issue-54505-no-std.rs:26:16 | LL | take_range(1..); | ^^^ @@ -27,7 +27,7 @@ LL | take_range(1..); found type `core::ops::RangeFrom<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:41:16 + --> $DIR/issue-54505-no-std.rs:31:16 | LL | take_range(..); | ^^ @@ -39,7 +39,7 @@ LL | take_range(..); found type `core::ops::RangeFull` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:46:16 + --> $DIR/issue-54505-no-std.rs:36:16 | LL | take_range(0..=1); | ^^^^^ @@ -51,7 +51,7 @@ LL | take_range(0..=1); found type `core::ops::RangeInclusive<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:51:16 + --> $DIR/issue-54505-no-std.rs:41:16 | LL | take_range(..5); | ^^^ @@ -63,7 +63,7 @@ LL | take_range(..5); found type `core::ops::RangeTo<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:56:16 + --> $DIR/issue-54505-no-std.rs:46:16 | LL | take_range(..=42); | ^^^^^ diff --git a/src/test/ui/range/issue-54505.fixed b/src/test/ui/range/issue-54505.fixed index ef8ded0f7a340..f8298c0b5ceff 100644 --- a/src/test/ui/range/issue-54505.fixed +++ b/src/test/ui/range/issue-54505.fixed @@ -1,13 +1,3 @@ -// Copyright 2018 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-rustfix // Regression test for #54505 - range borrowing suggestion had diff --git a/src/test/ui/range/issue-54505.rs b/src/test/ui/range/issue-54505.rs index b81c879a37ea4..03673252dd3ba 100644 --- a/src/test/ui/range/issue-54505.rs +++ b/src/test/ui/range/issue-54505.rs @@ -1,13 +1,3 @@ -// Copyright 2018 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-rustfix // Regression test for #54505 - range borrowing suggestion had diff --git a/src/test/ui/range/issue-54505.stderr b/src/test/ui/range/issue-54505.stderr index 5a59594ff5008..d6e1fb0cef238 100644 --- a/src/test/ui/range/issue-54505.stderr +++ b/src/test/ui/range/issue-54505.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-54505.rs:24:16 + --> $DIR/issue-54505.rs:14:16 | LL | take_range(0..1); | ^^^^ @@ -11,7 +11,7 @@ LL | take_range(0..1); found type `std::ops::Range<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505.rs:29:16 + --> $DIR/issue-54505.rs:19:16 | LL | take_range(1..); | ^^^ @@ -23,7 +23,7 @@ LL | take_range(1..); found type `std::ops::RangeFrom<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505.rs:34:16 + --> $DIR/issue-54505.rs:24:16 | LL | take_range(..); | ^^ @@ -35,7 +35,7 @@ LL | take_range(..); found type `std::ops::RangeFull` error[E0308]: mismatched types - --> $DIR/issue-54505.rs:39:16 + --> $DIR/issue-54505.rs:29:16 | LL | take_range(0..=1); | ^^^^^ @@ -47,7 +47,7 @@ LL | take_range(0..=1); found type `std::ops::RangeInclusive<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505.rs:44:16 + --> $DIR/issue-54505.rs:34:16 | LL | take_range(..5); | ^^^ @@ -59,7 +59,7 @@ LL | take_range(..5); found type `std::ops::RangeTo<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505.rs:49:16 + --> $DIR/issue-54505.rs:39:16 | LL | take_range(..=42); | ^^^^^ From 84f75f0dbb2459d2c73ef8736d835aa651c3686a Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 2 Oct 2018 16:59:48 -0500 Subject: [PATCH 10/18] Fix typo in CONTRIBUTING.md I noticed a small typo while reading over this document. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2e51a786f4682..49961d02ddab7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -566,7 +566,7 @@ labels to triage issues: to fix the issue. * The dark blue **final-comment-period** label marks bugs that are using the - RFC signoff functionality of [rfcbot][rfcbot] and are currenty in the final + RFC signoff functionality of [rfcbot][rfcbot] and are currently in the final comment period. * Red, **I**-prefixed labels indicate the **importance** of the issue. The From 30f2e96ab1d3f36d115249d932f7e5291e18b911 Mon Sep 17 00:00:00 2001 From: Son Date: Wed, 3 Oct 2018 08:21:51 +1000 Subject: [PATCH 11/18] Remove main() in examples --- src/libstd/error.rs | 76 ++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index cfc256f3644d7..1b872664e8d13 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -176,12 +176,10 @@ impl<'a, E: Error + 'a> From for Box { /// } /// } /// - /// fn main() { - /// let an_error = AnError; - /// assert!(0 == mem::size_of_val(&an_error)); - /// let a_boxed_error = Box::::from(an_error); - /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) - /// } + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: E) -> Box { Box::new(err) @@ -219,13 +217,11 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box::from(an_error); - /// assert!( - /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) - /// } + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: E) -> Box { Box::new(err) @@ -242,12 +238,10 @@ impl From for Box { /// use std::error::Error; /// use std::mem; /// - /// fn main() { - /// let a_string_error = "a string error".to_string(); - /// let a_boxed_error = Box::::from(a_string_error); - /// assert!( - /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) - /// } + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: String) -> Box { #[derive(Debug)] @@ -277,11 +271,9 @@ impl From for Box { /// use std::error::Error; /// use std::mem; /// - /// fn main() { - /// let a_string_error = "a string error".to_string(); - /// let a_boxed_error = Box::::from(a_string_error); - /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) - /// } + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(str_err: String) -> Box { let err1: Box = From::from(str_err); @@ -300,12 +292,10 @@ impl<'a, 'b> From<&'b str> for Box { /// use std::error::Error; /// use std::mem; /// - /// fn main() { - /// let a_str_error = "a str error"; - /// let a_boxed_error = Box::::from(a_str_error); - /// assert!( - /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) - /// } + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: &'b str) -> Box { From::from(String::from(err)) @@ -322,11 +312,9 @@ impl<'a> From<&'a str> for Box { /// use std::error::Error; /// use std::mem; /// - /// fn main() { - /// let a_str_error = "a str error"; - /// let a_boxed_error = Box::::from(a_str_error); - /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) - /// } + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: &'a str) -> Box { From::from(String::from(err)) @@ -344,12 +332,10 @@ impl<'a, 'b> From> for Box { /// use std::mem; /// use std::borrow::Cow; /// - /// fn main() { - /// let a_cow_str_error = Cow::from("a str error"); - /// let a_boxed_error = Box::::from(a_cow_str_error); - /// assert!( - /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) - /// } + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) @@ -367,11 +353,9 @@ impl<'a> From> for Box { /// use std::mem; /// use std::borrow::Cow; /// - /// fn main() { - /// let a_cow_str_error = Cow::from("a str error"); - /// let a_boxed_error = Box::::from(a_cow_str_error); - /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) - /// } + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: Cow<'a, str>) -> Box { From::from(String::from(err)) From d686896f907c75083c61783fe17b3f90e8985428 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 2 Oct 2018 22:11:38 -0400 Subject: [PATCH 12/18] Update a FIXME in memory.rs In #51833, I improved the performance of `copy_undef_mask()`. As such, the old FIXME wasn't appropriate anymore. The main remaining thing left to do is to implement a fast path for non-overlapping copies (per @oli-obk). --- src/librustc_mir/interpret/memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 11e27a597fbca..222d1164667d3 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -971,7 +971,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// Undefined bytes impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { - // FIXME(solson): This is a very naive, slow version. + // FIXME: Add a fast version for the common, nonoverlapping case fn copy_undef_mask( &mut self, src: Pointer, From 1081bbbfc5d170f22b5810b40c456a17da59cf7f Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Tue, 2 Oct 2018 21:43:05 -0700 Subject: [PATCH 13/18] abolish ICE when pretty-printing async block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Joshua Netterfield reported an ICE when the unused-parentheses lint triggered around an async block (#54752). In order to compose an autofixable suggestion, the lint invokes the pretty-printer on the unnecessarily-parenthesized expression. (One wonders why the lint doesn't just use `SourceMap::span_to_snippet` instead, to preserve the formatting of the original source?—but for that, you'd have to ask the author of 5c9f806d.) But then the pretty-printer panics when trying to call `::end` when `State.boxes` is empty. Empirically, the problem would seem to be solved if we start some "boxes" beforehand in the `ast::ExprKind::Async` arm of the big match in `print_expr_outer_attr_style`, exactly like we do in the immediately-preceding match arm for `ast::ExprKind::Block`—it would seem pretty ("pretty") reasonable for the pretty-printing of async blocks to work a lot like the pretty-printing of ordinary non-async blocks, right?? Of course, it would be shamefully cargo-culty to commit code on the basis of this kind of mere reasoning-by-analogy (in contrast to understanding the design of the pretty-printer in such detail that the correctness of the patch is comprehended with all the lucid certainty of mathematical proof, rather than being merely surmised by intuition). But maybe we care more about fixing the bug with high probability today, than with certainty in some indefinite hypothetical future? Maybe the effort is worth a fifth of a shirt?? Humbly resolves #54752. --- src/libsyntax/print/pprust.rs | 3 +++ src/test/pretty/issue-54752-async-block.rs | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 src/test/pretty/issue-54752-async-block.rs diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f2acdb3f469d1..83a05921510b4 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2228,6 +2228,9 @@ impl<'a> State<'a> { self.word_nbsp("async")?; self.print_capture_clause(capture_clause)?; self.s.space()?; + // cbox/ibox in analogy to the `ExprKind::Block` arm above + self.cbox(INDENT_UNIT)?; + self.ibox(0)?; self.print_block_with_attrs(blk, attrs)?; } ast::ExprKind::Assign(ref lhs, ref rhs) => { diff --git a/src/test/pretty/issue-54752-async-block.rs b/src/test/pretty/issue-54752-async-block.rs new file mode 100644 index 0000000000000..6930ee1a386fe --- /dev/null +++ b/src/test/pretty/issue-54752-async-block.rs @@ -0,0 +1,7 @@ +#![feature(async_await)] +#![allow(unused_parens)] + +// edition:2018 +// pp-exact + +fn main() { let _a = (async { }); } From 611e5c475106d41ee20847f8291594a708f0cbc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Romanowski?= Date: Wed, 3 Oct 2018 08:08:14 +0100 Subject: [PATCH 14/18] Address review comments --- src/librustc_typeck/check/demand.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 6eaeee5c0e28b..85b6bcbd144fc 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -384,7 +384,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// This function checks if the specified expression is a built-in range literal. - /// (See: ``librustc::hir::lowering::LoweringContext::lower_expr()``). + /// (See: `LoweringContext::lower_expr()` in `src/librustc/hir/lowering.rs`). fn is_range_literal(&self, expr: &hir::Expr) -> bool { use hir::{Path, QPath, ExprKind, TyKind}; @@ -404,10 +404,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - let is_range_literal = |span: &Span| { - // Tell if expression span snippet doesn't look like an explicit - // Range struct or `new()` call. This is to allow inferring - // that this is a range literal. + let span_is_range_literal = |span: &Span| { + // Check whether a span corresponding to a range expression + // is a range literal, rather than an explicit struct or `new()` call. let source_map = self.tcx.sess.source_map(); let end_point = source_map.end_point(*span); @@ -423,7 +422,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ExprKind::Struct(QPath::Resolved(None, ref path), _, _) | // `..` desugars to its struct path ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && is_range_literal(&expr.span); + return is_range_path(&path) && span_is_range_literal(&expr.span); } // `..=` desugars into `::std::ops::RangeInclusive::new(...)` @@ -432,7 +431,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node { let call_to_new = segment.ident.as_str() == "new"; - return is_range_path(&path) && is_range_literal(&expr.span) && call_to_new; + return is_range_path(&path) && span_is_range_literal(&expr.span) + && call_to_new; } } } From 832797689012ca63a7c9a7acdc7a4f34322d4faf Mon Sep 17 00:00:00 2001 From: scalexm Date: Wed, 3 Oct 2018 11:47:09 +0200 Subject: [PATCH 15/18] Remove duplicate predicates in `explicit_predicates_of` Fixes #52187. --- src/librustc_typeck/collect.rs | 36 ++++++++++++++++++++++++-- src/test/ui/chalkify/lower_env1.stderr | 6 ++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 17e0b0431da6e..f96c85ae7ae3f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1637,9 +1637,39 @@ fn explicit_predicates_of<'a, 'tcx>( def_id: DefId, ) -> ty::GenericPredicates<'tcx> { use rustc::hir::*; + use rustc_data_structures::fx::FxHashSet; debug!("explicit_predicates_of(def_id={:?})", def_id); + /// A data structure with unique elements, which preserves order of insertion. + /// Preserving the order of insertion is important here so as not to break + /// compile-fail UI tests. + struct UniquePredicates<'tcx> { + predicates: Vec<(ty::Predicate<'tcx>, Span)>, + uniques: FxHashSet<(ty::Predicate<'tcx>, Span)>, + } + + impl<'tcx> UniquePredicates<'tcx> { + fn new() -> Self { + UniquePredicates { + predicates: vec![], + uniques: FxHashSet::default(), + } + } + + fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) { + if self.uniques.insert(value) { + self.predicates.push(value); + } + } + + fn extend, Span)>>(&mut self, iter: I) { + for value in iter { + self.push(value); + } + } + } + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let node = tcx.hir.get(node_id); @@ -1649,7 +1679,7 @@ fn explicit_predicates_of<'a, 'tcx>( let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); - let mut predicates = vec![]; + let mut predicates = UniquePredicates::new(); let ast_generics = match node { Node::TraitItem(item) => &item.generics, @@ -1744,7 +1774,7 @@ fn explicit_predicates_of<'a, 'tcx>( // on a trait we need to add in the supertrait bounds and bounds found on // associated types. if let Some((_trait_ref, _)) = is_trait { - predicates = tcx.super_predicates_of(def_id).predicates; + predicates.extend(tcx.super_predicates_of(def_id).predicates); } // In default impls, we can assume that the self type implements @@ -1895,6 +1925,8 @@ fn explicit_predicates_of<'a, 'tcx>( })) } + let mut predicates = predicates.predicates; + // Subtle: before we store the predicates into the tcx, we // sort them so that predicates like `T: Foo` come // before uses of `U`. This avoids false ambiguity errors diff --git a/src/test/ui/chalkify/lower_env1.stderr b/src/test/ui/chalkify/lower_env1.stderr index d6673f6a8a6fb..4a3e14ac03472 100644 --- a/src/test/ui/chalkify/lower_env1.stderr +++ b/src/test/ui/chalkify/lower_env1.stderr @@ -5,9 +5,8 @@ LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar). - = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar). = note: Implemented(Self: Bar) :- FromEnv(Self: Bar). - = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo), WellFormed(Self: Foo). + = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo). error: program clause dump --> $DIR/lower_env1.rs:19:1 @@ -16,11 +15,10 @@ LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar). - = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar). = note: Implemented(Self: Bar) :- FromEnv(Self: Bar). = note: Implemented(Self: Foo) :- FromEnv(Self: Foo). = note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). - = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo), WellFormed(Self: Foo). + = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo). = note: WellFormed(Self: Foo) :- Implemented(Self: Foo). = note: WellFormed(Self: std::marker::Sized) :- Implemented(Self: std::marker::Sized). From f0de294a9b6d09b9933c1a22419831ac4bc49ca9 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 3 Oct 2018 15:07:18 +0200 Subject: [PATCH 16/18] A handful of cleanups for rustc/mir --- src/librustc/mir/interpret/value.rs | 4 ++-- src/librustc/mir/mod.rs | 31 ++++++++++++----------------- src/librustc/mir/mono.rs | 2 +- src/librustc/mir/tcx.rs | 12 +++++------ 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index d695ad88e47aa..c81d55e69b61a 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -171,7 +171,7 @@ impl<'tcx> Scalar { pub fn from_uint(i: impl Into, size: Size) -> Self { let i = i.into(); debug_assert_eq!(truncate(i, size), i, - "Unsigned value {} does not fit in {} bits", i, size.bits()); + "Unsigned value {} does not fit in {} bits", i, size.bits()); Scalar::Bits { bits: i, size: size.bytes() as u8 } } @@ -181,7 +181,7 @@ impl<'tcx> Scalar { // `into` performed sign extension, we have to truncate let truncated = truncate(i as u128, size); debug_assert_eq!(sign_extend(truncated, size) as i128, i, - "Signed value {} does not fit in {} bits", i, size.bits()); + "Signed value {} does not fit in {} bits", i, size.bits()); Scalar::Bits { bits: truncated, size: size.bytes() as u8 } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f36d9553d31c9..fe88897a82ccc 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -12,7 +12,6 @@ //! //! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir/index.html -use graphviz::IntoCow; use hir::def::CtorKind; use hir::def_id::DefId; use hir::{self, HirId, InlineAsm}; @@ -327,22 +326,20 @@ impl<'tcx> Mir<'tcx> { if idx < stmts.len() { &stmts[idx].source_info } else { - assert!(idx == stmts.len()); + assert_eq!(idx, stmts.len()); &block.terminator().source_info } } /// Check if `sub` is a sub scope of `sup` pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool { - loop { - if sub == sup { - return true; - } + while sub != sup { match self.source_scopes[sub].parent_scope { None => return false, Some(p) => sub = p, } } + true } /// Return the return type, it always return first element from `local_decls` array @@ -526,9 +523,7 @@ impl BorrowKind { pub fn allows_two_phase_borrow(&self) -> bool { match *self { BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, - BorrowKind::Mut { - allow_two_phase_borrow, - } => allow_two_phase_borrow, + BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, } } } @@ -1551,42 +1546,42 @@ impl<'tcx> TerminatorKind<'tcx> { }; fmt_const_val(&mut s, &c).unwrap(); s.into() - }).chain(iter::once(String::from("otherwise").into())) + }).chain(iter::once("otherwise".into())) .collect() } Call { destination: Some(_), cleanup: Some(_), .. - } => vec!["return".into_cow(), "unwind".into_cow()], + } => vec!["return".into(), "unwind".into()], Call { destination: Some(_), cleanup: None, .. - } => vec!["return".into_cow()], + } => vec!["return".into()], Call { destination: None, cleanup: Some(_), .. - } => vec!["unwind".into_cow()], + } => vec!["unwind".into()], Call { destination: None, cleanup: None, .. } => vec![], - Yield { drop: Some(_), .. } => vec!["resume".into_cow(), "drop".into_cow()], - Yield { drop: None, .. } => vec!["resume".into_cow()], + Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], + Yield { drop: None, .. } => vec!["resume".into()], DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { - vec!["return".into_cow()] + vec!["return".into()] } DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. - } => vec!["return".into_cow(), "unwind".into_cow()], + } => vec!["return".into(), "unwind".into()], Assert { cleanup: None, .. } => vec!["".into()], - Assert { .. } => vec!["success".into_cow(), "unwind".into_cow()], + Assert { .. } => vec!["success".into(), "unwind".into()], FalseEdges { ref imaginary_targets, .. diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 4d353a36db02a..7520695a7cd90 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -325,7 +325,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> { String::new() }; - let crate_disambiguator = format!("{}", tcx.crate_disambiguator(cnum)); + let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string(); // Using a shortened disambiguator of about 40 bits format!("{}.{}{}", tcx.crate_name(cnum), diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 2a25e057a7149..fc7b4862b0ae5 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -87,8 +87,8 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { assert!(index < adt_def.variants.len()); assert_eq!(adt_def, adt_def1); PlaceTy::Downcast { adt_def, - substs, - variant_index: index } + substs, + variant_index: index } } _ => { bug!("cannot downcast non-ADT type: `{:?}`", self) @@ -151,7 +151,7 @@ impl<'tcx> Place<'tcx> { } }, _ => None, - } + } _ => None, } } @@ -255,9 +255,9 @@ impl<'tcx> Operand<'tcx> { impl<'tcx> BinOp { pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - lhs_ty: Ty<'tcx>, - rhs_ty: Ty<'tcx>) - -> Ty<'tcx> { + lhs_ty: Ty<'tcx>, + rhs_ty: Ty<'tcx>) + -> Ty<'tcx> { // FIXME: handle SIMD correctly match self { &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem | From 608adfc3f01c425d2ede9263e6fafaaf7f38b377 Mon Sep 17 00:00:00 2001 From: scalexm Date: Wed, 3 Oct 2018 17:06:28 +0200 Subject: [PATCH 17/18] Introduce `TyKind::UnnormalizedProjection` --- src/librustc/ich/impls_ty.rs | 4 ++-- src/librustc/infer/canonical/canonicalizer.rs | 1 + src/librustc/infer/freshen.rs | 1 + src/librustc/traits/coherence.rs | 1 + src/librustc/traits/error_reporting.rs | 3 ++- src/librustc/traits/query/dropck_outlives.rs | 2 ++ src/librustc/traits/select.rs | 3 +++ src/librustc/ty/context.rs | 2 +- src/librustc/ty/error.rs | 1 + src/librustc/ty/fast_reject.rs | 1 + src/librustc/ty/flags.rs | 2 ++ src/librustc/ty/item_path.rs | 1 + src/librustc/ty/layout.rs | 6 +++--- src/librustc/ty/mod.rs | 2 ++ src/librustc/ty/outlives.rs | 2 ++ src/librustc/ty/structural_impls.rs | 7 ++++++- src/librustc/ty/sty.rs | 9 ++++++++- src/librustc/ty/util.rs | 2 ++ src/librustc/ty/walk.rs | 2 +- src/librustc/ty/wf.rs | 2 ++ src/librustc/util/ppaux.rs | 7 ++++++- src/librustc_codegen_llvm/debuginfo/type_names.rs | 1 + src/librustc_lint/types.rs | 1 + src/librustc_mir/monomorphize/item.rs | 1 + src/librustc_traits/dropck_outlives.rs | 2 ++ src/librustc_typeck/check/cast.rs | 1 + src/librustc_typeck/variance/constraints.rs | 1 + 27 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 9c4e995e24d01..388abc88cfd71 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -873,8 +873,8 @@ for ty::TyKind<'gcx> Tuple(inner_tys) => { inner_tys.hash_stable(hcx, hasher); } - Projection(ref projection_ty) => { - projection_ty.hash_stable(hcx, hasher); + Projection(ref data) | UnnormalizedProjection(ref data) => { + data.hash_stable(hcx, hasher); } Opaque(def_id, substs) => { def_id.hash_stable(hcx, hasher); diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index b30ccb5976c98..6449227af4ab8 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -283,6 +283,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> | ty::Never | ty::Tuple(..) | ty::Projection(..) + | ty::UnnormalizedProjection(..) | ty::Foreign(..) | ty::Param(..) | ty::Opaque(..) => { diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 1cb813c39e68c..e17e777332ec6 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -193,6 +193,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::Never | ty::Tuple(..) | ty::Projection(..) | + ty::UnnormalizedProjection(..) | ty::Foreign(..) | ty::Param(..) | ty::Closure(..) | diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 7401d4099ff6d..caf549e37a907 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -475,6 +475,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { ty::Error => true, + ty::UnnormalizedProjection(..) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7695f26d70115..3b3e38a8bb7ca 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -269,7 +269,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Generator(..) => Some(18), ty::Foreign(..) => Some(19), ty::GeneratorWitness(..) => Some(20), - ty::Infer(..) | ty::Error => None + ty::Infer(..) | ty::Error => None, + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), } } diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index f5fb183ec1a5d..aaf03f8e7fb55 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -253,5 +253,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> | ty::Opaque(..) | ty::Infer(_) | ty::Generator(..) => false, + + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 268b8e0161b6d..0ea9098378be5 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2200,6 +2200,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, ty::Infer(ty::TyVar(_)) => Ambiguous, + ty::UnnormalizedProjection(..) | ty::Infer(ty::CanonicalTy(_)) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | @@ -2272,6 +2273,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ambiguous } + ty::UnnormalizedProjection(..) | ty::Infer(ty::CanonicalTy(_)) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | @@ -2310,6 +2312,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Vec::new() } + ty::UnnormalizedProjection(..) | ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) | diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 64e9d15092eb8..29b3db400b116 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2266,7 +2266,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { self, Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr, Generator, GeneratorWitness, Dynamic, Closure, Tuple, - Param, Infer, Projection, Opaque, Foreign); + Param, Infer, UnnormalizedProjection, Projection, Opaque, Foreign); println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("Region interner: #{}", self.interners.region.borrow().len()); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 9f9d918415e7e..b3a1b312ca1d3 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -222,6 +222,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::Infer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(), ty::Infer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(), ty::Projection(_) => "associated type".to_string(), + ty::UnnormalizedProjection(_) => "non-normalized associated type".to_string(), ty::Param(ref p) => { if p.is_self() { "Self".to_string() diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 2d055fd307dc4..0f68e7aba4def 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -103,6 +103,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::FnPtr(ref f) => { Some(FunctionSimplifiedType(f.skip_binder().inputs().len())) } + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), ty::Projection(_) | ty::Param(_) => { if can_simplify_params { // In normalized types, projections don't unify with diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 08d1057823873..3ccc24e73a5c9 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -150,6 +150,8 @@ impl FlagComputation { self.add_projection_ty(data); } + &ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + &ty::Opaque(_, substs) => { self.add_flags(TypeFlags::HAS_PROJECTION); self.add_substs(substs); diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index c8d104e6c321f..46d133224f819 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -463,6 +463,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { ty::Str | ty::FnPtr(_) | ty::Projection(_) | + ty::UnnormalizedProjection(..) | ty::Param(_) | ty::Opaque(..) | ty::Infer(_) | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 8bfe46568eb19..7df8af5fa2e7d 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1123,7 +1123,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } tcx.layout_raw(param_env.and(normalized))? } - ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { bug!("LayoutDetails::compute: unexpected type `{}`", ty) } ty::Param(_) | ty::Error => { @@ -1702,8 +1702,8 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } } - ty::Projection(_) | ty::Opaque(..) | ty::Param(_) | - ty::Infer(_) | ty::Error => { + ty::Projection(_) | ty::UnnormalizedProjection(..) | + ty::Opaque(..) | ty::Param(_) | ty::Infer(_) | ty::Error => { bug!("TyLayout::field_type: unexpected type `{}`", this.ty) } }) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b2281691bd660..77e0b9e91bce6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2339,6 +2339,8 @@ impl<'a, 'gcx, 'tcx> AdtDef { vec![ty] } + UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + Param(..) => { // perf hack: if there is a `T: Sized` bound, then // we know that `T` is Sized and do not need to check diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 68f6707087687..91eda66e08c6e 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -124,6 +124,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + // We assume that inference variables are fully resolved. // So, if we encounter an inference variable, just record // the unresolved variable as a component. diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index aab268c07c4fb..c3c4cbed89d88 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -876,6 +876,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)), ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)), ty::Projection(ref data) => ty::Projection(data.fold_with(folder)), + ty::UnnormalizedProjection(ref data) => { + ty::UnnormalizedProjection(data.fold_with(folder)) + } ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)), ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) | @@ -910,7 +913,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } ty::GeneratorWitness(ref types) => types.visit_with(visitor), ty::Closure(_did, ref substs) => substs.visit_with(visitor), - ty::Projection(ref data) => data.visit_with(visitor), + ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => { + data.visit_with(visitor) + } ty::Opaque(_, ref substs) => substs.visit_with(visitor), ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) | diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 6c40dd8923916..06d559fd9dbea 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -157,6 +157,11 @@ pub enum TyKind<'tcx> { /// `>::N`. Projection(ProjectionTy<'tcx>), + /// A placeholder type used when we do not have enough information + /// to normalize the projection of an associated type to an + /// existing concrete type. Currently only used with chalk-engine. + UnnormalizedProjection(ProjectionTy<'tcx>), + /// Opaque (`impl Trait`) type found in a return type. /// The `DefId` comes either from /// * the `impl Trait` ast::Ty node, @@ -1806,7 +1811,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { Generator(_, GeneratorSubsts { ref substs }, _) => { substs.regions().collect() } - Projection(ref data) => { + Projection(ref data) | UnnormalizedProjection(ref data) => { data.substs.regions().collect() } FnDef(..) | @@ -1886,6 +1891,8 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false, + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + ty::Infer(ty::TyVar(_)) => false, ty::Infer(ty::CanonicalTy(_)) | diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 93fc77359e43a..4d7bab3cf433b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -958,6 +958,8 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) | ty::Opaque(..) | ty::Infer(_) | ty::Error => true, + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + // Structural recursion. ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty), diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index cf87c2d457471..d20c4f716429b 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -97,7 +97,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::Ref(_, ty, _) => { stack.push(ty); } - ty::Projection(ref data) => { + ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => { stack.extend(data.substs.types().rev()); } ty::Dynamic(ref obj, ..) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 63206a660df41..397c63a149a4c 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -289,6 +289,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.compute_projection(data); } + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + ty::Adt(def, substs) => { // WfNominalType let obligations = self.nominal_obligations(def.did, substs); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 10382008e0d43..814f8880bbf2f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -18,7 +18,7 @@ use ty::{Bool, Char, Adt}; use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; use ty::{Param, RawPtr, Ref, Never, Tuple}; use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque}; -use ty::{Dynamic, Int, Uint, Infer}; +use ty::{UnnormalizedProjection, Dynamic, Int, Uint, Infer}; use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; use util::nodemap::FxHashSet; @@ -1143,6 +1143,11 @@ define_print! { } Foreign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]), Projection(ref data) => data.print(f, cx), + UnnormalizedProjection(ref data) => { + write!(f, "Unnormalized(")?; + data.print(f, cx)?; + write!(f, ")") + } Opaque(def_id, substs) => { if cx.is_verbose { return write!(f, "Opaque({:?}, {:?})", def_id, substs); diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs index f9eb80a1988af..2f110fd552a8d 100644 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -173,6 +173,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } ty::Error | ty::Infer(_) | + ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Opaque(..) | ty::GeneratorWitness(..) | diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 01d4d0f8cdb67..a441f7a87f763 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -722,6 +722,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) | + ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Opaque(..) | ty::FnDef(..) => bug!("Unexpected type in foreign function"), diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 3f5a05f9d0ed8..f0ea93bfffd3e 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -382,6 +382,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { } ty::Error | ty::Infer(_) | + ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Param(_) | ty::GeneratorWitness(_) | diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index e3ec2e6b9ce02..2996fe0320042 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -272,6 +272,8 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( overflows: vec![], }), + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + ty::Infer(..) | ty::Error => { // By the time this code runs, all type variables ought to // be fully resolved. diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 564ecae15dc35..285fed9544ddb 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -124,6 +124,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Foreign(..) => Some(PointerKind::Thin), // We should really try to normalize here. ty::Projection(ref pi) => Some(PointerKind::OfProjection(pi)), + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)), ty::Param(ref p) => Some(PointerKind::OfParam(p)), // Insufficient type information. diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 95544da0b8e0d..1125de55a0668 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -336,6 +336,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } + ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Infer(..) => { bug!("unexpected type encountered in \ From edb3f9777b179c3da4519ec39ffd50f96e8f664c Mon Sep 17 00:00:00 2001 From: scalexm Date: Wed, 3 Oct 2018 18:49:27 +0200 Subject: [PATCH 18/18] Fix `ty::UnnormalizedProjection` in rustdoc --- src/librustdoc/clean/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 371b631723a39..9b305ad03b056 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2737,6 +2737,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton) + ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"), ty::Infer(..) => panic!("Infer"), ty::Error => panic!("Error"),