Auto merge of #47574 - zilbuz:issue-14844, r=nikomatsakis
Show the used type variable when issuing a "can't use type parameters from outer function" error message Fix #14844 r? @estebank
This commit is contained in:
commit
87344aa59a
13 changed files with 309 additions and 43 deletions
|
|
@ -571,7 +571,8 @@ impl<'a> LoweringContext<'a> {
|
|||
def_node_id,
|
||||
DefPathData::LifetimeDef(name.as_str()),
|
||||
DefIndexAddressSpace::High,
|
||||
Mark::root()
|
||||
Mark::root(),
|
||||
span
|
||||
);
|
||||
|
||||
hir::GenericParam::Lifetime(hir::LifetimeDef {
|
||||
|
|
@ -1003,7 +1004,8 @@ impl<'a> LoweringContext<'a> {
|
|||
def_node_id,
|
||||
DefPathData::ImplTrait,
|
||||
DefIndexAddressSpace::High,
|
||||
Mark::root()
|
||||
Mark::root(),
|
||||
span
|
||||
);
|
||||
|
||||
let hir_bounds = self.lower_bounds(bounds, itctx);
|
||||
|
|
@ -1150,7 +1152,8 @@ impl<'a> LoweringContext<'a> {
|
|||
def_node_id,
|
||||
DefPathData::LifetimeDef(name.name().as_str()),
|
||||
DefIndexAddressSpace::High,
|
||||
Mark::root()
|
||||
Mark::root(),
|
||||
lifetime.span
|
||||
);
|
||||
let def_lifetime = hir::Lifetime {
|
||||
id: def_node_id,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use syntax::visit;
|
|||
use syntax::symbol::keywords;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::parse::token::{self, Token};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use hir::map::{ITEM_LIKE_SPACE, REGULAR_SPACE};
|
||||
|
||||
|
|
@ -57,12 +58,13 @@ impl<'a> DefCollector<'a> {
|
|||
fn create_def(&mut self,
|
||||
node_id: NodeId,
|
||||
data: DefPathData,
|
||||
address_space: DefIndexAddressSpace)
|
||||
address_space: DefIndexAddressSpace,
|
||||
span: Span)
|
||||
-> DefIndex {
|
||||
let parent_def = self.parent_def.unwrap();
|
||||
debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
|
||||
self.definitions
|
||||
.create_def_with_parent(parent_def, node_id, data, address_space, self.expansion)
|
||||
.create_def_with_parent(parent_def, node_id, data, address_space, self.expansion, span)
|
||||
}
|
||||
|
||||
pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
|
||||
|
|
@ -83,7 +85,7 @@ impl<'a> DefCollector<'a> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
self.create_def(expr.id, DefPathData::Initializer, REGULAR_SPACE);
|
||||
self.create_def(expr.id, DefPathData::Initializer, REGULAR_SPACE, expr.span);
|
||||
}
|
||||
|
||||
fn visit_macro_invoc(&mut self, id: NodeId, const_expr: bool) {
|
||||
|
|
@ -122,7 +124,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
return visit::walk_item(self, i);
|
||||
}
|
||||
};
|
||||
let def = self.create_def(i.id, def_data, ITEM_LIKE_SPACE);
|
||||
let def = self.create_def(i.id, def_data, ITEM_LIKE_SPACE, i.span);
|
||||
|
||||
self.with_parent(def, |this| {
|
||||
match i.node {
|
||||
|
|
@ -131,14 +133,16 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
let variant_def_index =
|
||||
this.create_def(v.node.data.id(),
|
||||
DefPathData::EnumVariant(v.node.name.name.as_str()),
|
||||
REGULAR_SPACE);
|
||||
REGULAR_SPACE,
|
||||
v.span);
|
||||
this.with_parent(variant_def_index, |this| {
|
||||
for (index, field) in v.node.data.fields().iter().enumerate() {
|
||||
let name = field.ident.map(|ident| ident.name)
|
||||
.unwrap_or_else(|| Symbol::intern(&index.to_string()));
|
||||
this.create_def(field.id,
|
||||
DefPathData::Field(name.as_str()),
|
||||
REGULAR_SPACE);
|
||||
REGULAR_SPACE,
|
||||
field.span);
|
||||
}
|
||||
|
||||
if let Some(ref expr) = v.node.disr_expr {
|
||||
|
|
@ -152,13 +156,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
if !struct_def.is_struct() {
|
||||
this.create_def(struct_def.id(),
|
||||
DefPathData::StructCtor,
|
||||
REGULAR_SPACE);
|
||||
REGULAR_SPACE,
|
||||
i.span);
|
||||
}
|
||||
|
||||
for (index, field) in struct_def.fields().iter().enumerate() {
|
||||
let name = field.ident.map(|ident| ident.name)
|
||||
.unwrap_or_else(|| Symbol::intern(&index.to_string()));
|
||||
this.create_def(field.id, DefPathData::Field(name.as_str()), REGULAR_SPACE);
|
||||
this.create_def(field.id,
|
||||
DefPathData::Field(name.as_str()),
|
||||
REGULAR_SPACE,
|
||||
field.span);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -168,14 +176,15 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
}
|
||||
|
||||
fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
|
||||
self.create_def(id, DefPathData::Misc, ITEM_LIKE_SPACE);
|
||||
self.create_def(id, DefPathData::Misc, ITEM_LIKE_SPACE, use_tree.span);
|
||||
visit::walk_use_tree(self, use_tree, id);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
|
||||
let def = self.create_def(foreign_item.id,
|
||||
DefPathData::ValueNs(foreign_item.ident.name.as_str()),
|
||||
REGULAR_SPACE);
|
||||
REGULAR_SPACE,
|
||||
foreign_item.span);
|
||||
|
||||
self.with_parent(def, |this| {
|
||||
visit::walk_foreign_item(this, foreign_item);
|
||||
|
|
@ -188,14 +197,16 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
self.create_def(
|
||||
lifetime_def.lifetime.id,
|
||||
DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_str()),
|
||||
REGULAR_SPACE
|
||||
REGULAR_SPACE,
|
||||
lifetime_def.lifetime.span
|
||||
);
|
||||
}
|
||||
GenericParam::Type(ref ty_param) => {
|
||||
self.create_def(
|
||||
ty_param.id,
|
||||
DefPathData::TypeParam(ty_param.ident.name.as_str()),
|
||||
REGULAR_SPACE
|
||||
REGULAR_SPACE,
|
||||
ty_param.span
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -211,7 +222,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
|
||||
};
|
||||
|
||||
let def = self.create_def(ti.id, def_data, ITEM_LIKE_SPACE);
|
||||
let def = self.create_def(ti.id, def_data, ITEM_LIKE_SPACE, ti.span);
|
||||
self.with_parent(def, |this| {
|
||||
if let TraitItemKind::Const(_, Some(ref expr)) = ti.node {
|
||||
this.visit_const_expr(expr);
|
||||
|
|
@ -229,7 +240,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
|
||||
};
|
||||
|
||||
let def = self.create_def(ii.id, def_data, ITEM_LIKE_SPACE);
|
||||
let def = self.create_def(ii.id, def_data, ITEM_LIKE_SPACE, ii.span);
|
||||
self.with_parent(def, |this| {
|
||||
if let ImplItemKind::Const(_, ref expr) = ii.node {
|
||||
this.visit_const_expr(expr);
|
||||
|
|
@ -255,7 +266,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
ExprKind::Closure(..) => {
|
||||
let def = self.create_def(expr.id,
|
||||
DefPathData::ClosureExpr,
|
||||
REGULAR_SPACE);
|
||||
REGULAR_SPACE,
|
||||
expr.span);
|
||||
self.parent_def = Some(def);
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -270,7 +282,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
|
||||
TyKind::Array(_, ref length) => self.visit_const_expr(length),
|
||||
TyKind::ImplTrait(..) => {
|
||||
self.create_def(ty.id, DefPathData::ImplTrait, REGULAR_SPACE);
|
||||
self.create_def(ty.id, DefPathData::ImplTrait, REGULAR_SPACE, ty.span);
|
||||
}
|
||||
TyKind::Typeof(ref expr) => self.visit_const_expr(expr),
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ use std::hash::Hash;
|
|||
use syntax::ast;
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::symbol::{Symbol, InternedString};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
/// The DefPathTable maps DefIndexes to DefKeys and vice versa.
|
||||
|
|
@ -159,6 +160,7 @@ pub struct Definitions {
|
|||
macro_def_scopes: FxHashMap<Mark, DefId>,
|
||||
expansions: FxHashMap<DefIndex, Mark>,
|
||||
next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>,
|
||||
def_index_to_span: FxHashMap<DefIndex, Span>,
|
||||
}
|
||||
|
||||
// Unfortunately we have to provide a manual impl of Clone because of the
|
||||
|
|
@ -176,6 +178,7 @@ impl Clone for Definitions {
|
|||
macro_def_scopes: self.macro_def_scopes.clone(),
|
||||
expansions: self.expansions.clone(),
|
||||
next_disambiguator: self.next_disambiguator.clone(),
|
||||
def_index_to_span: self.def_index_to_span.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -410,6 +413,7 @@ impl Definitions {
|
|||
macro_def_scopes: FxHashMap(),
|
||||
expansions: FxHashMap(),
|
||||
next_disambiguator: FxHashMap(),
|
||||
def_index_to_span: FxHashMap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -493,6 +497,22 @@ impl Definitions {
|
|||
self.node_to_hir_id[node_id]
|
||||
}
|
||||
|
||||
/// Retrieve the span of the given `DefId` if `DefId` is in the local crate, the span exists and
|
||||
/// it's not DUMMY_SP
|
||||
#[inline]
|
||||
pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
|
||||
if def_id.krate == LOCAL_CRATE {
|
||||
let span = self.def_index_to_span.get(&def_id.index).cloned().unwrap_or(DUMMY_SP);
|
||||
if span != DUMMY_SP {
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a definition with a parent definition.
|
||||
pub fn create_root_def(&mut self,
|
||||
crate_name: &str,
|
||||
|
|
@ -530,7 +550,8 @@ impl Definitions {
|
|||
node_id: ast::NodeId,
|
||||
data: DefPathData,
|
||||
address_space: DefIndexAddressSpace,
|
||||
expansion: Mark)
|
||||
expansion: Mark,
|
||||
span: Span)
|
||||
-> DefIndex {
|
||||
debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
|
||||
parent, node_id, data);
|
||||
|
|
@ -583,6 +604,11 @@ impl Definitions {
|
|||
self.expansions.insert(index, expansion);
|
||||
}
|
||||
|
||||
// The span is added if it isn't DUMMY_SP
|
||||
if span != DUMMY_SP {
|
||||
self.def_index_to_span.insert(index, span);
|
||||
}
|
||||
|
||||
index
|
||||
}
|
||||
|
||||
|
|
@ -692,7 +718,8 @@ macro_rules! define_global_metadata_kind {
|
|||
ast::DUMMY_NODE_ID,
|
||||
DefPathData::GlobalMetaData(instance.name().as_str()),
|
||||
GLOBAL_MD_ADDRESS_SPACE,
|
||||
Mark::root()
|
||||
Mark::root(),
|
||||
DUMMY_SP
|
||||
);
|
||||
|
||||
// Make sure calling def_index does not crash.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ use rustc::ty;
|
|||
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
|
||||
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
|
||||
|
||||
use syntax::codemap::{dummy_spanned, respan};
|
||||
use syntax::codemap::{dummy_spanned, respan, CodeMap};
|
||||
use syntax::ext::hygiene::{Mark, MarkKind, SyntaxContext};
|
||||
use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
|
|
@ -123,7 +123,7 @@ impl Ord for BindingError {
|
|||
|
||||
enum ResolutionError<'a> {
|
||||
/// error E0401: can't use type parameters from outer function
|
||||
TypeParametersFromOuterFunction,
|
||||
TypeParametersFromOuterFunction(Def),
|
||||
/// error E0403: the name is already used for a type parameter in this type parameter list
|
||||
NameAlreadyUsedInTypeParameterList(Name, &'a Span),
|
||||
/// error E0407: method is not a member of trait
|
||||
|
|
@ -173,13 +173,49 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
|
|||
resolution_error: ResolutionError<'a>)
|
||||
-> DiagnosticBuilder<'sess> {
|
||||
match resolution_error {
|
||||
ResolutionError::TypeParametersFromOuterFunction => {
|
||||
ResolutionError::TypeParametersFromOuterFunction(outer_def) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0401,
|
||||
"can't use type parameters from outer function; \
|
||||
try using a local type parameter instead");
|
||||
"can't use type parameters from outer function");
|
||||
err.span_label(span, "use of type variable from outer function");
|
||||
match outer_def {
|
||||
Def::SelfTy(_, maybe_impl_defid) => {
|
||||
if let Some(impl_span) = maybe_impl_defid.map_or(None,
|
||||
|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),
|
||||
"`Self` type implicitely declared here, on the `impl`");
|
||||
}
|
||||
},
|
||||
Def::TyParam(typaram_defid) => {
|
||||
if let Some(typaram_span) = resolver.definitions.opt_span(typaram_defid) {
|
||||
err.span_label(typaram_span, "type variable from outer function");
|
||||
}
|
||||
},
|
||||
Def::Mod(..) | Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Variant(..) |
|
||||
Def::Trait(..) | Def::TyAlias(..) | Def::TyForeign(..) | Def::TraitAlias(..) |
|
||||
Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) |
|
||||
Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) |
|
||||
Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) |
|
||||
Def::Macro(..) | Def::GlobalAsm(..) | Def::Err =>
|
||||
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
|
||||
Def::TyParam")
|
||||
}
|
||||
|
||||
// Try to retrieve the span of the function signature and generate a new message with
|
||||
// a local type parameter
|
||||
let sugg_msg = "try using a local type parameter instead";
|
||||
if let Some((sugg_span, new_snippet)) = generate_local_type_param_snippet(
|
||||
resolver.session.codemap(), span) {
|
||||
// Suggest the modification to the user
|
||||
err.span_suggestion(sugg_span,
|
||||
sugg_msg,
|
||||
new_snippet);
|
||||
} else {
|
||||
err.help("try using a local type parameter instead");
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
ResolutionError::NameAlreadyUsedInTypeParameterList(name, first_use_span) => {
|
||||
|
|
@ -358,6 +394,86 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
|
|||
}
|
||||
}
|
||||
|
||||
/// Adjust the impl span so that just the `impl` keyword is taken by removing
|
||||
/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
|
||||
/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`)
|
||||
///
|
||||
/// Attention: The method used is very fragile since it essentially duplicates the work of the
|
||||
/// parser. If you need to use this function or something similar, please consider updating the
|
||||
/// codemap functions and this function to something more robust.
|
||||
fn reduce_impl_span_to_impl_keyword(cm: &CodeMap, impl_span: Span) -> Span {
|
||||
let impl_span = cm.span_until_char(impl_span, '<');
|
||||
let impl_span = cm.span_until_whitespace(impl_span);
|
||||
impl_span
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// a new local type parameter.
|
||||
///
|
||||
/// For instance:
|
||||
/// ```
|
||||
/// // Given span
|
||||
/// fn my_function(param: T)
|
||||
/// ^ Original span
|
||||
///
|
||||
/// // Result
|
||||
/// fn my_function(param: T)
|
||||
/// ^^^^^^^^^^^ Generated span with snippet `my_function<T>`
|
||||
/// ```
|
||||
///
|
||||
/// Attention: The method used is very fragile since it essentially duplicates the work of the
|
||||
/// parser. If you need to use this function or something similar, please consider updating the
|
||||
/// codemap functions and this function to something more robust.
|
||||
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
|
||||
// signature
|
||||
let sugg_span = cm.span_extend_to_prev_str(span, "fn");
|
||||
if sugg_span != span {
|
||||
if let Ok(snippet) = cm.span_to_snippet(sugg_span) {
|
||||
use syntax::codemap::BytePos;
|
||||
|
||||
// Consume the function name
|
||||
let mut offset = 0;
|
||||
for c in snippet.chars().take_while(|c| c.is_ascii_alphanumeric() ||
|
||||
*c == '_') {
|
||||
offset += c.len_utf8();
|
||||
}
|
||||
|
||||
// Consume the generics part of the function signature
|
||||
let mut bracket_counter = 0;
|
||||
let mut last_char = None;
|
||||
for c in snippet[offset..].chars() {
|
||||
match c {
|
||||
'<' => bracket_counter += 1,
|
||||
'>' => bracket_counter -= 1,
|
||||
'(' => if bracket_counter == 0 { break; }
|
||||
_ => {}
|
||||
}
|
||||
offset += c.len_utf8();
|
||||
last_char = Some(c);
|
||||
}
|
||||
|
||||
// Adjust the suggestion span to encompass the function name with its generics
|
||||
let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32));
|
||||
|
||||
// Prepare the new suggested snippet to append the type parameter that triggered
|
||||
// the error in the generics of the function signature
|
||||
let mut new_snippet = if last_char == Some('>') {
|
||||
format!("{}, ", &snippet[..(offset - '>'.len_utf8())])
|
||||
} else {
|
||||
format!("{}<", &snippet[..offset])
|
||||
};
|
||||
new_snippet.push_str(&cm.span_to_snippet(span).unwrap_or("T".to_string()));
|
||||
new_snippet.push('>');
|
||||
|
||||
return Some((sugg_span, new_snippet));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct BindingInfo {
|
||||
span: Span,
|
||||
|
|
@ -3280,7 +3396,7 @@ impl<'a> Resolver<'a> {
|
|||
// its scope.
|
||||
if record_used {
|
||||
resolve_error(self, span,
|
||||
ResolutionError::TypeParametersFromOuterFunction);
|
||||
ResolutionError::TypeParametersFromOuterFunction(def));
|
||||
}
|
||||
return Def::Err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -533,7 +533,12 @@ impl CodeMap {
|
|||
Ok(FileLines {file: lo.file, lines: lines})
|
||||
}
|
||||
|
||||
pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
|
||||
/// Extract the source surrounding the given `Span` using the `extract_source` function. The
|
||||
/// extract function takes three arguments: a string slice containing the source, an index in
|
||||
/// the slice for the beginning of the span and an index in the slice for the end of the span.
|
||||
fn span_to_source<F>(&self, sp: Span, extract_source: F) -> Result<String, SpanSnippetError>
|
||||
where F: Fn(&str, usize, usize) -> String
|
||||
{
|
||||
if sp.lo() > sp.hi() {
|
||||
return Err(SpanSnippetError::IllFormedSpan(sp));
|
||||
}
|
||||
|
|
@ -567,9 +572,9 @@ impl CodeMap {
|
|||
}
|
||||
|
||||
if let Some(ref src) = local_begin.fm.src {
|
||||
return Ok((&src[start_index..end_index]).to_string());
|
||||
return Ok(extract_source(src, start_index, end_index));
|
||||
} else if let Some(src) = local_begin.fm.external_src.borrow().get_source() {
|
||||
return Ok((&src[start_index..end_index]).to_string());
|
||||
return Ok(extract_source(src, start_index, end_index));
|
||||
} else {
|
||||
return Err(SpanSnippetError::SourceNotAvailable {
|
||||
filename: local_begin.fm.name.clone()
|
||||
|
|
@ -578,6 +583,17 @@ impl CodeMap {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return the source snippet as `String` corresponding to the given `Span`
|
||||
pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
|
||||
self.span_to_source(sp, |src, start_index, end_index| src[start_index..end_index]
|
||||
.to_string())
|
||||
}
|
||||
|
||||
/// Return the source snippet as `String` before the given `Span`
|
||||
pub fn span_to_prev_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
|
||||
self.span_to_source(sp, |src, start_index, _| src[..start_index].to_string())
|
||||
}
|
||||
|
||||
/// Given a `Span`, try to get a shorter span ending before the first occurrence of `c` `char`
|
||||
pub fn span_until_char(&self, sp: Span, c: char) -> Span {
|
||||
match self.span_to_snippet(sp) {
|
||||
|
|
@ -593,6 +609,32 @@ impl CodeMap {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extend the given `Span` to just after the previous occurrence of `c`. Return the same span
|
||||
/// if no character could be found or if an error occurred while retrieving the code snippet.
|
||||
pub fn span_extend_to_prev_char(&self, sp: Span, c: char) -> Span {
|
||||
if let Ok(prev_source) = self.span_to_prev_source(sp) {
|
||||
let prev_source = prev_source.rsplit(c).nth(0).unwrap_or("").trim_left();
|
||||
if !prev_source.is_empty() && !prev_source.contains('\n') {
|
||||
return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
|
||||
}
|
||||
}
|
||||
|
||||
sp
|
||||
}
|
||||
|
||||
/// Extend the given `Span` to just after the previous occurrence of `pat`. Return the same span
|
||||
/// if no character could be found or if an error occurred while retrieving the code snippet.
|
||||
pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str) -> Span {
|
||||
if let Ok(prev_source) = self.span_to_prev_source(sp) {
|
||||
let prev_source = prev_source.rsplit(pat).nth(0).unwrap_or("").trim_left();
|
||||
if !prev_source.is_empty() && !prev_source.contains('\n') {
|
||||
return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
|
||||
}
|
||||
}
|
||||
|
||||
sp
|
||||
}
|
||||
|
||||
/// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or
|
||||
/// the original `Span`.
|
||||
///
|
||||
|
|
@ -615,6 +657,24 @@ impl CodeMap {
|
|||
sp
|
||||
}
|
||||
|
||||
/// Given a `Span`, get a new `Span` covering the first token without its trailing whitespace or
|
||||
/// the original `Span` in case of error.
|
||||
///
|
||||
/// If `sp` points to `"let mut x"`, then a span pointing at `"let"` will be returned.
|
||||
pub fn span_until_whitespace(&self, sp: Span) -> Span {
|
||||
if let Ok(snippet) = self.span_to_snippet(sp) {
|
||||
let mut offset = 0;
|
||||
// Get the bytes width of all the non-whitespace characters
|
||||
for c in snippet.chars().take_while(|c| !c.is_whitespace()) {
|
||||
offset += c.len_utf8();
|
||||
}
|
||||
if offset > 1 {
|
||||
return sp.with_hi(BytePos(sp.lo().0 + offset as u32));
|
||||
}
|
||||
}
|
||||
sp
|
||||
}
|
||||
|
||||
/// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char`
|
||||
/// `c`.
|
||||
pub fn span_through_char(&self, sp: Span, c: char) -> Span {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ enum Bar<T> { What } //~ ERROR parameter `T` is never used
|
|||
|
||||
fn foo<T>() {
|
||||
static a: Bar<T> = Bar::What;
|
||||
//~^ ERROR can't use type parameters from outer function; try using a local type parameter instead
|
||||
//~^ ERROR can't use type parameters from outer function
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
fn siphash<T>() {
|
||||
|
||||
trait t {
|
||||
fn g(&self, x: T) -> T; //~ ERROR can't use type parameters from outer function; try using
|
||||
//~^ ERROR can't use type parameters from outer function; try using
|
||||
fn g(&self, x: T) -> T; //~ ERROR can't use type parameters from outer function
|
||||
//~^ ERROR can't use type parameters from outer function
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
fn foo<T>() {
|
||||
struct foo {
|
||||
x: T, //~ ERROR can't use type parameters from outer function;
|
||||
x: T, //~ ERROR can't use type parameters from outer function
|
||||
}
|
||||
|
||||
impl<T> Drop for foo<T> {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
fn f<T>() -> bool {
|
||||
struct S(T); //~ ERROR can't use type parameters from outer function; try using
|
||||
struct S(T); //~ ERROR can't use type parameters from outer function
|
||||
|
||||
true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern:can't use type parameters from outer function; try using
|
||||
// error-pattern:can't use type parameters from outer function
|
||||
fn hd<U>(v: Vec<U> ) -> U {
|
||||
fn hd1(w: [U]) -> U { return w[0]; }
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern:can't use type parameters from outer function; try using
|
||||
// error-pattern:can't use type parameters from outer function
|
||||
fn foo<T>(x: T) {
|
||||
fn bar(f: Box<FnMut(T) -> T>) { }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,33 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
trait Baz<T> {}
|
||||
|
||||
fn foo<T>(x: T) {
|
||||
fn bar(y: T) { //~ ERROR E0401
|
||||
fn bar<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
|
||||
}
|
||||
fn baz<U,
|
||||
V: Baz<U>,
|
||||
W: Fn()>
|
||||
(y: T) { //~ ERROR E0401
|
||||
}
|
||||
bar(x);
|
||||
}
|
||||
|
||||
|
||||
struct A<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T> Iterator for A<T> {
|
||||
type Item = u8;
|
||||
fn next(&mut self) -> Option<u8> {
|
||||
fn helper(sel: &Self) -> u8 { //~ ERROR E0401
|
||||
unimplemented!();
|
||||
}
|
||||
Some(helper(self))
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,35 @@
|
|||
error[E0401]: can't use type parameters from outer function; try using a local type parameter instead
|
||||
--> $DIR/E0401.rs:12:15
|
||||
error[E0401]: can't use type parameters from outer function
|
||||
--> $DIR/E0401.rs:14:38
|
||||
|
|
||||
LL | fn bar(y: T) { //~ ERROR E0401
|
||||
| ^ use of type variable from outer function
|
||||
LL | fn foo<T>(x: T) {
|
||||
| - type variable from outer function
|
||||
LL | fn bar<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
|
||||
| -------------------------- ^ use of type variable from outer function
|
||||
| |
|
||||
| help: try using a local type parameter instead: `bar<U, V: Baz<U>, W: Fn(), T>`
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0401]: can't use type parameters from outer function
|
||||
--> $DIR/E0401.rs:19:16
|
||||
|
|
||||
LL | fn foo<T>(x: T) {
|
||||
| - type variable from outer function
|
||||
...
|
||||
LL | (y: T) { //~ ERROR E0401
|
||||
| ^ 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
|
||||
--> $DIR/E0401.rs:32:25
|
||||
|
|
||||
LL | impl<T> Iterator for A<T> {
|
||||
| ---- `Self` type implicitely declared here, on the `impl`
|
||||
...
|
||||
LL | fn helper(sel: &Self) -> u8 { //~ ERROR E0401
|
||||
| ------ ^^^^ use of type variable from outer function
|
||||
| |
|
||||
| help: try using a local type parameter instead: `helper<Self>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
If you want more information on this error, try using "rustc --explain E0401"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue