diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 71c78e7f87c0..f53a8168548e 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 000000000000..57d1938aca87 --- /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 000000000000..8e8793c1736b --- /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 000000000000..ef8ded0f7a34 --- /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 000000000000..b81c879a37ea --- /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 000000000000..5a59594ff500 --- /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`.