Handle type ascription cases with a method call instead of a type
This commit is contained in:
parent
faf90351b7
commit
e39bcecf79
3 changed files with 94 additions and 14 deletions
|
@ -599,20 +599,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||||
self.resolve_local(local);
|
self.resolve_local(local);
|
||||||
}
|
}
|
||||||
fn visit_ty(&mut self, ty: &'tcx Ty) {
|
fn visit_ty(&mut self, ty: &'tcx Ty) {
|
||||||
if let TyKind::Path(ref qself, ref path) = ty.node {
|
match ty.node {
|
||||||
|
TyKind::Path(ref qself, ref path) => {
|
||||||
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
|
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
|
||||||
} else if let TyKind::ImplicitSelf = ty.node {
|
}
|
||||||
|
TyKind::ImplicitSelf => {
|
||||||
let self_ty = keywords::SelfType.ident();
|
let self_ty = keywords::SelfType.ident();
|
||||||
let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, true, ty.span)
|
let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, true, ty.span)
|
||||||
.map_or(Def::Err, |d| d.def());
|
.map_or(Def::Err, |d| d.def());
|
||||||
self.record_def(ty.id, PathResolution::new(def));
|
self.record_def(ty.id, PathResolution::new(def));
|
||||||
} else if let TyKind::Array(ref element, ref length) = ty.node {
|
}
|
||||||
|
TyKind::Array(ref element, ref length) => {
|
||||||
self.visit_ty(element);
|
self.visit_ty(element);
|
||||||
self.with_constant_rib(|this| {
|
self.with_constant_rib(|this| {
|
||||||
this.visit_expr(length);
|
this.visit_expr(length);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
visit::walk_ty(self, ty);
|
visit::walk_ty(self, ty);
|
||||||
}
|
}
|
||||||
fn visit_poly_trait_ref(&mut self,
|
fn visit_poly_trait_ref(&mut self,
|
||||||
|
@ -1221,6 +1226,9 @@ pub struct Resolver<'a> {
|
||||||
// This table maps struct IDs into struct constructor IDs,
|
// This table maps struct IDs into struct constructor IDs,
|
||||||
// it's not used during normal resolution, only for better error reporting.
|
// it's not used during normal resolution, only for better error reporting.
|
||||||
struct_constructors: DefIdMap<(Def, ty::Visibility)>,
|
struct_constructors: DefIdMap<(Def, ty::Visibility)>,
|
||||||
|
|
||||||
|
// Only used for better errors on `fn(): fn()`
|
||||||
|
current_type_ascription: Vec<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ResolverArenas<'a> {
|
pub struct ResolverArenas<'a> {
|
||||||
|
@ -1411,6 +1419,7 @@ impl<'a> Resolver<'a> {
|
||||||
struct_constructors: DefIdMap(),
|
struct_constructors: DefIdMap(),
|
||||||
found_unresolved_macro: false,
|
found_unresolved_macro: false,
|
||||||
unused_macros: FxHashSet(),
|
unused_macros: FxHashSet(),
|
||||||
|
current_type_ascription: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2495,6 +2504,7 @@ impl<'a> Resolver<'a> {
|
||||||
// Fallback label.
|
// Fallback label.
|
||||||
if !levenshtein_worked {
|
if !levenshtein_worked {
|
||||||
err.span_label(base_span, fallback_label);
|
err.span_label(base_span, fallback_label);
|
||||||
|
this.type_ascription_suggestion(&mut err, base_span);
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
};
|
};
|
||||||
|
@ -2550,6 +2560,41 @@ impl<'a> Resolver<'a> {
|
||||||
resolution
|
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 {
|
fn self_type_is_available(&mut self, span: Span) -> bool {
|
||||||
let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(),
|
let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(),
|
||||||
TypeNS, false, span);
|
TypeNS, false, span);
|
||||||
|
@ -3166,7 +3211,11 @@ impl<'a> Resolver<'a> {
|
||||||
self.resolve_expr(argument, None);
|
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);
|
visit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
18
src/test/ui/suggestions/type-ascription-with-fn-call.rs
Normal file
18
src/test/ui/suggestions/type-ascription-with-fn-call.rs
Normal file
|
@ -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
src/test/ui/suggestions/type-ascription-with-fn-call.stderr
Normal file
13
src/test/ui/suggestions/type-ascription-with-fn-call.stderr
Normal file
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue