Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Point at : when using it instead of ; #43096

Merged
merged 3 commits into from
Jul 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,22 @@ impl Diagnostic {
self
}

/// Prints out a message with a suggested edit of the code. If the suggestion is presented
/// inline it will only show the text message and not the text.
///
/// See `diagnostic::CodeSuggestion` for more information.
pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitution_parts: vec![Substitution {
span: sp,
substitutions: vec![suggestion],
}],
msg: msg.to_owned(),
show_code_when_inline: false,
});
self
}

/// Prints out a message with a suggested edit of the code.
///
/// See `diagnostic::CodeSuggestion` for more information.
Expand All @@ -219,6 +235,7 @@ impl Diagnostic {
substitutions: vec![suggestion],
}],
msg: msg.to_owned(),
show_code_when_inline: true,
});
self
}
Expand All @@ -230,6 +247,7 @@ impl Diagnostic {
substitutions: suggestions,
}],
msg: msg.to_owned(),
show_code_when_inline: true,
});
self
}
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_errors/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ impl<'a> DiagnosticBuilder<'a> {
sp: S,
msg: &str)
-> &mut Self);
forward!(pub fn span_suggestion_short(&mut self,
sp: Span,
msg: &str,
suggestion: String)
-> &mut Self);
forward!(pub fn span_suggestion(&mut self,
sp: Span,
msg: &str,
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_errors/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ impl Emitter for EmitterWriter {
// don't display multiline suggestions as labels
sugg.substitution_parts[0].substitutions[0].find('\n').is_none() {
let substitution = &sugg.substitution_parts[0].substitutions[0];
let msg = if substitution.len() == 0 {
// This substitution is only removal, don't show it
let msg = if substitution.len() == 0 || !sugg.show_code_when_inline {
// This substitution is only removal or we explicitely don't want to show the
// code inline, don't show it
format!("help: {}", sugg.msg)
} else {
format!("help: {} `{}`", sugg.msg, substitution)
Expand Down
1 change: 1 addition & 0 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ pub struct CodeSuggestion {
/// ```
pub substitution_parts: Vec<Substitution>,
pub msg: String,
pub show_code_when_inline: bool,
}

#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
Expand Down
77 changes: 63 additions & 14 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,19 +599,24 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
self.resolve_local(local);
}
fn visit_ty(&mut self, ty: &'tcx Ty) {
if let TyKind::Path(ref qself, ref path) = ty.node {
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
} else if let TyKind::ImplicitSelf = ty.node {
let self_ty = keywords::SelfType.ident();
let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, true, ty.span)
.map_or(Def::Err, |d| d.def());
self.record_def(ty.id, PathResolution::new(def));
} else if let TyKind::Array(ref element, ref length) = ty.node {
self.visit_ty(element);
self.with_constant_rib(|this| {
this.visit_expr(length);
});
return;
match ty.node {
TyKind::Path(ref qself, ref path) => {
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
}
TyKind::ImplicitSelf => {
let self_ty = keywords::SelfType.ident();
let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, true, ty.span)
.map_or(Def::Err, |d| d.def());
self.record_def(ty.id, PathResolution::new(def));
}
TyKind::Array(ref element, ref length) => {
self.visit_ty(element);
self.with_constant_rib(|this| {
this.visit_expr(length);
});
return;
}
_ => (),
}
visit::walk_ty(self, ty);
}
Expand Down Expand Up @@ -1221,6 +1226,9 @@ pub struct Resolver<'a> {
// This table maps struct IDs into struct constructor IDs,
// it's not used during normal resolution, only for better error reporting.
struct_constructors: DefIdMap<(Def, ty::Visibility)>,

// Only used for better errors on `fn(): fn()`
current_type_ascription: Vec<Span>,
}

pub struct ResolverArenas<'a> {
Expand Down Expand Up @@ -1411,6 +1419,7 @@ impl<'a> Resolver<'a> {
struct_constructors: DefIdMap(),
found_unresolved_macro: false,
unused_macros: FxHashSet(),
current_type_ascription: Vec::new(),
}
}

Expand Down Expand Up @@ -2495,6 +2504,7 @@ impl<'a> Resolver<'a> {
// Fallback label.
if !levenshtein_worked {
err.span_label(base_span, fallback_label);
this.type_ascription_suggestion(&mut err, base_span);
}
err
};
Expand Down Expand Up @@ -2550,6 +2560,41 @@ impl<'a> Resolver<'a> {
resolution
}

fn type_ascription_suggestion(&self,
err: &mut DiagnosticBuilder,
base_span: Span) {
debug!("type_ascription_suggetion {:?}", base_span);
let cm = self.session.codemap();
debug!("self.current_type_ascription {:?}", self.current_type_ascription);
if let Some(sp) = self.current_type_ascription.last() {
let mut sp = *sp;
loop { // try to find the `:`, bail on first non-':'/non-whitespace
sp = sp.next_point();
if let Ok(snippet) = cm.span_to_snippet(sp.to(sp.next_point())) {
debug!("snippet {:?}", snippet);
let line_sp = cm.lookup_char_pos(sp.hi).line;
let line_base_sp = cm.lookup_char_pos(base_span.lo).line;
debug!("{:?} {:?}", line_sp, line_base_sp);
if snippet == ":" {
err.span_label(base_span,
"expecting a type here because of type ascription");
if line_sp != line_base_sp {
err.span_suggestion_short(sp,
"did you mean to use `;` here instead?",
";".to_string());
}
break;
} else if snippet.trim().len() != 0 {
debug!("tried to find type ascription `:` token, couldn't find it");
break;
}
} else {
break;
}
}
}
}

fn self_type_is_available(&mut self, span: Span) -> bool {
let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(),
TypeNS, false, span);
Expand Down Expand Up @@ -3166,7 +3211,11 @@ impl<'a> Resolver<'a> {
self.resolve_expr(argument, None);
}
}

ExprKind::Type(ref type_expr, _) => {
self.current_type_ascription.push(type_expr.span);
visit::walk_expr(self, expr);
self.current_type_ascription.pop();
}
_ => {
visit::walk_expr(self, expr);
}
Expand Down
17 changes: 16 additions & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2798,7 +2798,22 @@ impl<'a> Parser<'a> {
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
continue
} else if op == AssocOp::Colon {
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?;
lhs = match self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type) {
Ok(lhs) => lhs,
Err(mut err) => {
err.span_label(self.span,
"expecting a type here because of type ascription");
let cm = self.sess.codemap();
let cur_pos = cm.lookup_char_pos(self.span.lo);
let op_pos = cm.lookup_char_pos(cur_op_span.hi);
if cur_pos.line != op_pos.line {
err.span_suggestion_short(cur_op_span,
"did you mean to use `;` here?",
";".to_string());
}
return Err(err);
}
};
continue
} else if op == AssocOp::DotDot || op == AssocOp::DotDotDot {
// If we didn’t have to handle `x..`/`x...`, it would be pretty easy to
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issue-22644.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,5 @@ error: expected type, found `4`
--> $DIR/issue-22644.rs:38:28
|
38 | println!("{}", a: &mut 4);
| ^
| ^ expecting a type here because of type ascription

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2017 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.

#![feature(type_ascription)]

fn main() {
println!("test"):
0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it work if a colon was here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output in that case is

error: expected type, found `0`
  --> ../../src/test/ui/suggestions/type-ascription-instead-of-statement-end.rs:15:5
   |
14 |     println!("test"):
   |                     - help: did you mean to use `;` here instead?
15 |     0:
   |     ^ expecting a type here because of type ascription

}

fn foo() {
println!("test"): 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: expected type, found `0`
--> $DIR/type-ascription-instead-of-statement-end.rs:15:5
|
14 | println!("test"):
| - help: did you mean to use `;` here?
15 | 0;
| ^ expecting a type here because of type ascription

error: expected type, found `0`
--> $DIR/type-ascription-instead-of-statement-end.rs:19:23
|
19 | println!("test"): 0;
| ^ expecting a type here because of type ascription

error: aborting due to 2 previous errors

18 changes: 18 additions & 0 deletions src/test/ui/suggestions/type-ascription-with-fn-call.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2017 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.

#![feature(type_ascription)]

fn main() {
f() :
f();
}

fn f() {}
13 changes: 13 additions & 0 deletions src/test/ui/suggestions/type-ascription-with-fn-call.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error[E0573]: expected type, found function `f`
--> $DIR/type-ascription-with-fn-call.rs:15:5
|
14 | f() :
| - help: did you mean to use `;` here instead?
15 | f();
| ^^^
| |
| not a type
| expecting a type here because of type ascription

error: aborting due to previous error