Skip to content

Commit

Permalink
Auto merge of #57792 - Centril:rollup, r=Centril
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #56796 (Change bounds on `TryFrom` blanket impl to use `Into` instead of `From`)
 - #57768 (Continue parsing after parent type args and suggest using angle brackets)
 - #57769 (Suggest correct cast for struct fields with shorthand syntax)
 - #57783 (Add "dereference boxed value" suggestion.)
 - #57784 (Add span for bad doc comment)

Failed merges:

r? @ghost
  • Loading branch information
bors committed Jan 21, 2019
2 parents b5f5a27 + 00c60d1 commit 33b0b71
Show file tree
Hide file tree
Showing 36 changed files with 484 additions and 88 deletions.
4 changes: 2 additions & 2 deletions src/libcore/convert.rs
Expand Up @@ -463,11 +463,11 @@ impl<T, U> TryInto<U> for T where U: TryFrom<T>
// Infallible conversions are semantically equivalent to fallible conversions
// with an uninhabited error type.
#[unstable(feature = "try_from", issue = "33417")]
impl<T, U> TryFrom<U> for T where T: From<U> {
impl<T, U> TryFrom<U> for T where U: Into<T> {
type Error = !;

fn try_from(value: U) -> Result<Self, Self::Error> {
Ok(T::from(value))
Ok(U::into(value))
}
}

Expand Down
26 changes: 21 additions & 5 deletions src/librustc/hir/lowering.rs
Expand Up @@ -31,6 +31,7 @@
//! in the HIR, especially for multiple identifiers.

use dep_graph::DepGraph;
use errors::Applicability;
use hir::{self, ParamName};
use hir::HirVec;
use hir::map::{DefKey, DefPathData, Definitions};
Expand Down Expand Up @@ -1806,7 +1807,7 @@ impl<'a> LoweringContext<'a> {
explicit_owner: Option<NodeId>,
) -> hir::PathSegment {
let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
let msg = "parenthesized parameters may only be used with a trait";
let msg = "parenthesized type parameters may only be used with a `Fn` trait";
match **generic_args {
GenericArgs::AngleBracketed(ref data) => {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
Expand All @@ -1823,10 +1824,25 @@ impl<'a> LoweringContext<'a> {
(hir::GenericArgs::none(), true)
}
ParenthesizedGenericArgs::Err => {
struct_span_err!(self.sess, data.span, E0214, "{}", msg)
.span_label(data.span, "only traits may use parentheses")
.emit();
(hir::GenericArgs::none(), true)
let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
err.span_label(data.span, "only `Fn` traits may use parentheses");
if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
// Do not suggest going from `Trait()` to `Trait<>`
if data.inputs.len() > 0 {
err.span_suggestion_with_applicability(
data.span,
"use angle brackets instead",
format!("<{}>", &snippet[1..snippet.len() - 1]),
Applicability::MaybeIncorrect,
);
}
};
err.emit();
(self.lower_angle_bracketed_parameter_data(
&data.as_angle_bracketed_args(),
param_mode,
itctx).0,
false)
}
},
}
Expand Down
21 changes: 19 additions & 2 deletions src/librustc/infer/error_reporting/mod.rs
Expand Up @@ -485,12 +485,29 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}

fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) {
fn note_error_origin(
&self,
err: &mut DiagnosticBuilder<'tcx>,
cause: &ObligationCause<'tcx>,
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
) {
match cause.code {
ObligationCauseCode::MatchExpressionArmPattern { span, ty } => {
if ty.is_suggestable() { // don't show type `_`
err.span_label(span, format!("this match expression has type `{}`", ty));
}
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found {
if ty.is_box() && ty.boxed_ty() == found {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
err.span_suggestion_with_applicability(
span,
"consider dereferencing the boxed value",
format!("*{}", snippet),
Applicability::MachineApplicable,
);
}
}
}
}
ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
hir::MatchSource::IfLetDesugar { .. } => {
Expand Down Expand Up @@ -1013,7 +1030,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {

// It reads better to have the error origin as the final
// thing.
self.note_error_origin(diag, &cause);
self.note_error_origin(diag, &cause, exp_found);
}

/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
Expand Down
48 changes: 36 additions & 12 deletions src/librustc_typeck/check/demand.rs
Expand Up @@ -454,12 +454,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
false
}

pub fn check_for_cast(&self,
err: &mut DiagnosticBuilder<'tcx>,
expr: &hir::Expr,
checked_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>)
-> bool {
pub fn check_for_cast(
&self,
err: &mut DiagnosticBuilder<'tcx>,
expr: &hir::Expr,
checked_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) -> bool {
let parent_id = self.tcx.hir().get_parent_node(expr.id);
if let Some(parent) = self.tcx.hir().find(parent_id) {
// Shouldn't suggest `.into()` on `const`s.
Expand Down Expand Up @@ -487,17 +488,40 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// For now, don't suggest casting with `as`.
let can_cast = false;

let mut prefix = String::new();
if let Some(hir::Node::Expr(hir::Expr {
node: hir::ExprKind::Struct(_, fields, _),
..
})) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.id)) {
// `expr` is a literal field for a struct, only suggest if appropriate
for field in fields {
if field.expr.id == expr.id && field.is_shorthand {
// This is a field literal
prefix = format!("{}: ", field.ident);
break;
}
}
if &prefix == "" {
// Likely a field was meant, but this field wasn't found. Do not suggest anything.
return false;
}
}

let needs_paren = expr.precedence().order() < (PREC_POSTFIX as i8);

if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
let msg = format!("you can cast an `{}` to `{}`", checked_ty, expected_ty);
let cast_suggestion = format!("{}{}{} as {}",
if needs_paren { "(" } else { "" },
src,
if needs_paren { ")" } else { "" },
expected_ty);
let cast_suggestion = format!(
"{}{}{}{} as {}",
prefix,
if needs_paren { "(" } else { "" },
src,
if needs_paren { ")" } else { "" },
expected_ty,
);
let into_suggestion = format!(
"{}{}{}.into()",
"{}{}{}{}.into()",
prefix,
if needs_paren { "(" } else { "" },
src,
if needs_paren { ")" } else { "" },
Expand Down
10 changes: 10 additions & 0 deletions src/libsyntax/ast.rs
Expand Up @@ -192,6 +192,16 @@ pub struct ParenthesisedArgs {
pub output: Option<P<Ty>>,
}

impl ParenthesisedArgs {
pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
AngleBracketedArgs {
span: self.span,
args: self.inputs.iter().cloned().map(|input| GenericArg::Type(input)).collect(),
bindings: vec![],
}
}
}

// hack to ensure that we don't try to access the private parts of `NodeId` in this module
mod node_id_inner {
use rustc_data_structures::indexed_vec::Idx;
Expand Down
14 changes: 9 additions & 5 deletions src/libsyntax/parse/parser.rs
Expand Up @@ -2176,11 +2176,11 @@ impl<'a> Parser<'a> {
style != PathStyle::Mod && self.check(&token::ModSep)
&& self.look_ahead(1, |t| is_args_start(t)) {
// Generic arguments are found - `<`, `(`, `::<` or `::(`.
let lo = self.span;
if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning {
self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator")
.span_label(self.prev_span, "try removing `::`").emit();
}
let lo = self.span;

let args = if self.eat_lt() {
// `<'a, T, A = U>`
Expand Down Expand Up @@ -4483,13 +4483,17 @@ impl<'a> Parser<'a> {
}

/// Emit an expected item after attributes error.
fn expected_item_err(&self, attrs: &[Attribute]) {
fn expected_item_err(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
let message = match attrs.last() {
Some(&Attribute { is_sugared_doc: true, .. }) => "expected item after doc comment",
_ => "expected item after attributes",
};

self.span_err(self.prev_span, message);
let mut err = self.diagnostic().struct_span_err(self.prev_span, message);
if attrs.last().unwrap().is_sugared_doc {
err.span_label(self.prev_span, "this doc comment doesn't document anything");
}
Err(err)
}

/// Parse a statement. This stops just before trailing semicolons on everything but items.
Expand Down Expand Up @@ -7636,7 +7640,7 @@ impl<'a> Parser<'a> {
}
None => {
if !attrs.is_empty() {
self.expected_item_err(&attrs);
self.expected_item_err(&attrs)?;
}

self.unexpected()
Expand Down Expand Up @@ -7699,7 +7703,7 @@ impl<'a> Parser<'a> {
}

if !attributes_allowed && !attrs.is_empty() {
self.expected_item_err(&attrs);
self.expected_item_err(&attrs)?;
}
Ok(None)
}
Expand Down
37 changes: 37 additions & 0 deletions src/test/run-pass/try_from.rs
@@ -0,0 +1,37 @@
// This test relies on `TryFrom` being blanket impl for all `T: Into`
// and `TryInto` being blanket impl for all `U: TryFrom`

// This test was added to show the motivation for doing this
// over `TryFrom` being blanket impl for all `T: From`

#![feature(try_from, never_type)]

use std::convert::TryInto;

struct Foo<T> {
t: T,
}

// This fails to compile due to coherence restrictions
// as of Rust version 1.32.x, therefore it could not be used
// instead of the `Into` version of the impl, and serves as
// motivation for a blanket impl for all `T: Into`, instead
// of a blanket impl for all `T: From`
/*
impl<T> From<Foo<T>> for Box<T> {
fn from(foo: Foo<T>) -> Box<T> {
Box::new(foo.t)
}
}
*/

impl<T> Into<Vec<T>> for Foo<T> {
fn into(self) -> Vec<T> {
vec![self.t]
}
}

pub fn main() {
let _: Result<Vec<i32>, !> = Foo { t: 10 }.try_into();
}

2 changes: 1 addition & 1 deletion src/test/ui/e0119/conflict-with-std.stderr
Expand Up @@ -25,7 +25,7 @@ LL | impl TryFrom<X> for X { //~ ERROR conflicting implementations
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
where T: std::convert::From<U>;
where U: std::convert::Into<T>;

error: aborting due to 3 previous errors

Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/error-codes/E0214.stderr
@@ -1,8 +1,11 @@
error[E0214]: parenthesized parameters may only be used with a trait
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/E0214.rs:2:15
|
LL | let v: Vec(&str) = vec!["foo"];
| ^^^^^^ only traits may use parentheses
| ^^^^^^
| |
| only `Fn` traits may use parentheses
| help: use angle brackets instead: `<&str>`

error: aborting due to previous error

Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/issues/issue-23589.rs
@@ -1,4 +1,5 @@
fn main() {
let v: Vec(&str) = vec!['1', '2'];
//~^ ERROR parenthesized parameters may only be used with a trait
//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| ERROR mismatched types
}
21 changes: 17 additions & 4 deletions src/test/ui/issues/issue-23589.stderr
@@ -1,9 +1,22 @@
error[E0214]: parenthesized parameters may only be used with a trait
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-23589.rs:2:15
|
LL | let v: Vec(&str) = vec!['1', '2'];
| ^^^^^^ only traits may use parentheses
| ^^^^^^
| |
| only `Fn` traits may use parentheses
| help: use angle brackets instead: `<&str>`

error: aborting due to previous error
error[E0308]: mismatched types
--> $DIR/issue-23589.rs:2:29
|
LL | let v: Vec(&str) = vec!['1', '2'];
| ^^^ expected &str, found char
|
= note: expected type `&str`
found type `char`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0214`.
Some errors occurred: E0214, E0308.
For more information about an error, try `rustc --explain E0214`.
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-32995-2.rs
Expand Up @@ -2,17 +2,17 @@

fn main() {
{ fn f<X: ::std::marker()::Send>() {} }
//~^ ERROR parenthesized parameters may only be used with a trait
//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted

{ fn f() -> impl ::std::marker()::Send { } }
//~^ ERROR parenthesized parameters may only be used with a trait
//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
}

#[derive(Clone)]
struct X;

impl ::std::marker()::Copy for X {}
//~^ ERROR parenthesized parameters may only be used with a trait
//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-32995-2.stderr
@@ -1,4 +1,4 @@
error: parenthesized parameters may only be used with a trait
error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995-2.rs:4:28
|
LL | { fn f<X: ::std::marker()::Send>() {} }
Expand All @@ -8,7 +8,7 @@ LL | { fn f<X: ::std::marker()::Send>() {} }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>

error: parenthesized parameters may only be used with a trait
error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995-2.rs:8:35
|
LL | { fn f() -> impl ::std::marker()::Send { } }
Expand All @@ -17,7 +17,7 @@ LL | { fn f() -> impl ::std::marker()::Send { } }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>

error: parenthesized parameters may only be used with a trait
error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995-2.rs:16:19
|
LL | impl ::std::marker()::Copy for X {}
Expand Down

0 comments on commit 33b0b71

Please sign in to comment.