Some tweaks to "type parameters from outer function" diagnostic
Follow up to #47574.
This commit is contained in:
parent
883e74645d
commit
16d424f147
4 changed files with 42 additions and 27 deletions
|
@ -41,7 +41,7 @@ use rustc::ty;
|
||||||
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
|
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
|
||||||
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
|
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
|
||||||
|
|
||||||
use syntax::codemap::{dummy_spanned, respan, CodeMap};
|
use syntax::codemap::{dummy_spanned, respan, BytePos, CodeMap};
|
||||||
use syntax::ext::hygiene::{Mark, MarkKind, SyntaxContext};
|
use syntax::ext::hygiene::{Mark, MarkKind, SyntaxContext};
|
||||||
use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
|
use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
|
||||||
use syntax::ext::base::SyntaxExtension;
|
use syntax::ext::base::SyntaxExtension;
|
||||||
|
@ -179,11 +179,12 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
|
||||||
E0401,
|
E0401,
|
||||||
"can't use type parameters from outer function");
|
"can't use type parameters from outer function");
|
||||||
err.span_label(span, "use of type variable from outer function");
|
err.span_label(span, "use of type variable from outer function");
|
||||||
|
|
||||||
|
let cm = resolver.session.codemap();
|
||||||
match outer_def {
|
match outer_def {
|
||||||
Def::SelfTy(_, maybe_impl_defid) => {
|
Def::SelfTy(_, maybe_impl_defid) => {
|
||||||
if let Some(impl_span) = maybe_impl_defid.map_or(None,
|
if let Some(impl_span) = maybe_impl_defid.map_or(None,
|
||||||
|def_id| resolver.definitions.opt_span(def_id)) {
|
|def_id| resolver.definitions.opt_span(def_id)) {
|
||||||
let cm = resolver.session.codemap();
|
|
||||||
err.span_label(reduce_impl_span_to_impl_keyword(cm, impl_span),
|
err.span_label(reduce_impl_span_to_impl_keyword(cm, impl_span),
|
||||||
"`Self` type implicitely declared here, on the `impl`");
|
"`Self` type implicitely declared here, on the `impl`");
|
||||||
}
|
}
|
||||||
|
@ -206,12 +207,13 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
|
||||||
// Try to retrieve the span of the function signature and generate a new message with
|
// Try to retrieve the span of the function signature and generate a new message with
|
||||||
// a local type parameter
|
// a local type parameter
|
||||||
let sugg_msg = "try using a local type parameter instead";
|
let sugg_msg = "try using a local type parameter instead";
|
||||||
if let Some((sugg_span, new_snippet)) = generate_local_type_param_snippet(
|
if let Some((sugg_span, new_snippet)) = generate_local_type_param_snippet(cm, span) {
|
||||||
resolver.session.codemap(), span) {
|
|
||||||
// Suggest the modification to the user
|
// Suggest the modification to the user
|
||||||
err.span_suggestion(sugg_span,
|
err.span_suggestion(sugg_span,
|
||||||
sugg_msg,
|
sugg_msg,
|
||||||
new_snippet);
|
new_snippet);
|
||||||
|
} else if let Some(sp) = generate_fn_name_span(cm, span) {
|
||||||
|
err.span_label(sp, "try adding a local type parameter in this method instead");
|
||||||
} else {
|
} else {
|
||||||
err.help("try using a local type parameter instead");
|
err.help("try using a local type parameter instead");
|
||||||
}
|
}
|
||||||
|
@ -407,6 +409,15 @@ fn reduce_impl_span_to_impl_keyword(cm: &CodeMap, impl_span: Span) -> Span {
|
||||||
impl_span
|
impl_span
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_fn_name_span(cm: &CodeMap, span: Span) -> Option<Span> {
|
||||||
|
let prev_span = cm.span_extend_to_prev_str(span, "fn", true);
|
||||||
|
cm.span_to_snippet(prev_span).map(|snippet| {
|
||||||
|
let len = snippet.find(|c: char| !c.is_alphanumeric() && c != '_')
|
||||||
|
.expect("no label after fn");
|
||||||
|
prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))
|
||||||
|
}).ok()
|
||||||
|
}
|
||||||
|
|
||||||
/// Take the span of a type parameter in a function signature and try to generate a span for the
|
/// Take the span of a type parameter in a function signature and try to generate a span for the
|
||||||
/// function name (with generics) and a new snippet for this span with the pointed type parameter as
|
/// function name (with generics) and a new snippet for this span with the pointed type parameter as
|
||||||
/// a new local type parameter.
|
/// a new local type parameter.
|
||||||
|
@ -428,17 +439,12 @@ fn reduce_impl_span_to_impl_keyword(cm: &CodeMap, impl_span: Span) -> Span {
|
||||||
fn generate_local_type_param_snippet(cm: &CodeMap, span: Span) -> Option<(Span, String)> {
|
fn generate_local_type_param_snippet(cm: &CodeMap, span: Span) -> Option<(Span, String)> {
|
||||||
// Try to extend the span to the previous "fn" keyword to retrieve the function
|
// Try to extend the span to the previous "fn" keyword to retrieve the function
|
||||||
// signature
|
// signature
|
||||||
let sugg_span = cm.span_extend_to_prev_str(span, "fn");
|
let sugg_span = cm.span_extend_to_prev_str(span, "fn", false);
|
||||||
if sugg_span != span {
|
if sugg_span != span {
|
||||||
if let Ok(snippet) = cm.span_to_snippet(sugg_span) {
|
if let Ok(snippet) = cm.span_to_snippet(sugg_span) {
|
||||||
use syntax::codemap::BytePos;
|
|
||||||
|
|
||||||
// Consume the function name
|
// Consume the function name
|
||||||
let mut offset = 0;
|
let mut offset = snippet.find(|c: char| !c.is_alphanumeric() && c != '_')
|
||||||
for c in snippet.chars().take_while(|c| c.is_ascii_alphanumeric() ||
|
.expect("no label after fn");
|
||||||
*c == '_') {
|
|
||||||
offset += c.len_utf8();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume the generics part of the function signature
|
// Consume the generics part of the function signature
|
||||||
let mut bracket_counter = 0;
|
let mut bracket_counter = 0;
|
||||||
|
|
|
@ -622,15 +622,23 @@ impl CodeMap {
|
||||||
sp
|
sp
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extend the given `Span` to just after the previous occurrence of `pat`. Return the same span
|
/// Extend the given `Span` to just after the previous occurrence of `pat` when surrounded by
|
||||||
/// if no character could be found or if an error occurred while retrieving the code snippet.
|
/// whitespace. Return the same span if no character could be found or if an error occurred
|
||||||
pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str) -> Span {
|
/// while retrieving the code snippet.
|
||||||
|
pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str, accept_newlines: bool) -> Span {
|
||||||
|
// assure that the pattern is delimited, to avoid the following
|
||||||
|
// fn my_fn()
|
||||||
|
// ^^^^ returned span without the check
|
||||||
|
// ---------- correct span
|
||||||
|
for ws in &[" ", "\t", "\n"] {
|
||||||
|
let pat = pat.to_owned() + ws;
|
||||||
if let Ok(prev_source) = self.span_to_prev_source(sp) {
|
if let Ok(prev_source) = self.span_to_prev_source(sp) {
|
||||||
let prev_source = prev_source.rsplit(pat).nth(0).unwrap_or("").trim_left();
|
let prev_source = prev_source.rsplit(&pat).nth(0).unwrap_or("").trim_left();
|
||||||
if !prev_source.is_empty() && !prev_source.contains('\n') {
|
if !prev_source.is_empty() && (!prev_source.contains('\n') || accept_newlines) {
|
||||||
return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
|
return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sp
|
sp
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
trait Baz<T> {}
|
trait Baz<T> {}
|
||||||
|
|
||||||
fn foo<T>(x: T) {
|
fn foo<T>(x: T) {
|
||||||
fn bar<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
|
fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
|
||||||
}
|
}
|
||||||
fn baz<U,
|
fn baz<U,
|
||||||
V: Baz<U>,
|
V: Baz<U>,
|
||||||
W: Fn()>
|
W: Fn()>
|
||||||
(y: T) { //~ ERROR E0401
|
(y: T) { //~ ERROR E0401
|
||||||
}
|
}
|
||||||
bar(x);
|
bfnr(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
error[E0401]: can't use type parameters from outer function
|
error[E0401]: can't use type parameters from outer function
|
||||||
--> $DIR/E0401.rs:14:38
|
--> $DIR/E0401.rs:14:39
|
||||||
|
|
|
|
||||||
LL | fn foo<T>(x: T) {
|
LL | fn foo<T>(x: T) {
|
||||||
| - type variable from outer function
|
| - type variable from outer function
|
||||||
LL | fn bar<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
|
LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
|
||||||
| -------------------------- ^ use of type variable from outer function
|
| --------------------------- ^ use of type variable from outer function
|
||||||
| |
|
| |
|
||||||
| help: try using a local type parameter instead: `bar<U, V: Baz<U>, W: Fn(), T>`
|
| help: try using a local type parameter instead: `bfnr<U, V: Baz<U>, W: Fn(), T>`
|
||||||
|
|
||||||
error[E0401]: can't use type parameters from outer function
|
error[E0401]: can't use type parameters from outer function
|
||||||
--> $DIR/E0401.rs:19:16
|
--> $DIR/E0401.rs:19:16
|
||||||
|
@ -14,10 +14,11 @@ error[E0401]: can't use type parameters from outer function
|
||||||
LL | fn foo<T>(x: T) {
|
LL | fn foo<T>(x: T) {
|
||||||
| - type variable from outer function
|
| - type variable from outer function
|
||||||
...
|
...
|
||||||
|
LL | fn baz<U,
|
||||||
|
| --- try adding a local type parameter in this method instead
|
||||||
|
...
|
||||||
LL | (y: T) { //~ ERROR E0401
|
LL | (y: T) { //~ ERROR E0401
|
||||||
| ^ use of type variable from outer function
|
| ^ use of type variable from outer function
|
||||||
|
|
|
||||||
= help: try using a local type parameter instead
|
|
||||||
|
|
||||||
error[E0401]: can't use type parameters from outer function
|
error[E0401]: can't use type parameters from outer function
|
||||||
--> $DIR/E0401.rs:32:25
|
--> $DIR/E0401.rs:32:25
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue