Skip to content

Commit

Permalink
First stab at fixing #54505
Browse files Browse the repository at this point in the history
  • Loading branch information
pawroman committed Sep 29, 2018
1 parent 7e7bc06 commit 0626afb
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 3 deletions.
54 changes: 51 additions & 3 deletions src/librustc_typeck/check/demand.rs
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
85 changes: 85 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<i8>) {}


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 }
}
61 changes: 61 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<i8>) {}


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)
}
53 changes: 53 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<i8>) {}


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)
}
53 changes: 53 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<i8>) {}


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)
}
75 changes: 75 additions & 0 deletions 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`.

0 comments on commit 0626afb

Please sign in to comment.