From 4af749f074a255bf923dc871a7e24f5b2fd58176 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Sat, 17 Feb 2018 13:22:58 +0100 Subject: [PATCH 1/4] Add a map of `DefId` to `Span` in the `Definitions` struct --- src/librustc/hir/lowering.rs | 9 ++++-- src/librustc/hir/map/def_collector.rs | 44 +++++++++++++++++---------- src/librustc/hir/map/definitions.rs | 31 +++++++++++++++++-- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 877027a21a221..49611689fc4af 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -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, diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index cdd6395747865..3619a7fb0c603 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -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(&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), _ => {} diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 61a58a6030623..1a2840de447de 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -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, expansions: FxHashMap, next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>, + def_index_to_span: FxHashMap, } // 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 { + 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. From b3164f3ab4720c6596c7e789c0281489c62347e7 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Thu, 22 Feb 2018 15:27:41 +0100 Subject: [PATCH 2/4] Add codemap functions to retrieve the source before a given span --- src/libsyntax/codemap.rs | 66 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 53ddbfbfd4a2c..c340f1b8c8ab3 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -533,7 +533,12 @@ impl CodeMap { Ok(FileLines {file: lo.file, lines: lines}) } - pub fn span_to_snippet(&self, sp: Span) -> Result { + /// 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(&self, sp: Span, extract_source: F) -> Result + 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 { + 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 { + 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 { From 48ba50e10c275c55d5480a5102e53bdb5a977ad7 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Wed, 7 Feb 2018 11:50:11 +0100 Subject: [PATCH 3/4] Update "type parameters from outer function" error messages --- src/librustc_resolve/lib.rs | 128 ++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 6 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fc1ff24818403..a6b776125ae97 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 Iterator for A {}" -> "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` +/// ``` +/// +/// 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; } From 0e68bb97285a1ade22cf6e68103dc54fb75db43f Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Wed, 7 Feb 2018 16:26:35 +0100 Subject: [PATCH 4/4] Update tests --- .../inner-static-type-parameter.rs | 2 +- src/test/compile-fail/issue-3021-c.rs | 4 +-- src/test/compile-fail/issue-3214.rs | 2 +- src/test/compile-fail/issue-5997-struct.rs | 2 +- src/test/compile-fail/nested-ty-params.rs | 2 +- .../compile-fail/type-arg-out-of-scope.rs | 2 +- src/test/ui/error-codes/E0401.rs | 24 ++++++++++++- src/test/ui/error-codes/E0401.stderr | 36 ++++++++++++++++--- 8 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/test/compile-fail/inner-static-type-parameter.rs b/src/test/compile-fail/inner-static-type-parameter.rs index 6fb497092d217..4d763017c0f8b 100644 --- a/src/test/compile-fail/inner-static-type-parameter.rs +++ b/src/test/compile-fail/inner-static-type-parameter.rs @@ -14,7 +14,7 @@ enum Bar { What } //~ ERROR parameter `T` is never used fn foo() { static a: Bar = 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() { diff --git a/src/test/compile-fail/issue-3021-c.rs b/src/test/compile-fail/issue-3021-c.rs index 635006a3b4dad..55975cc8e8645 100644 --- a/src/test/compile-fail/issue-3021-c.rs +++ b/src/test/compile-fail/issue-3021-c.rs @@ -11,8 +11,8 @@ fn siphash() { 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 } } diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs index 010cfb54c1ae9..9a769c39eca12 100644 --- a/src/test/compile-fail/issue-3214.rs +++ b/src/test/compile-fail/issue-3214.rs @@ -10,7 +10,7 @@ fn foo() { 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 Drop for foo { diff --git a/src/test/compile-fail/issue-5997-struct.rs b/src/test/compile-fail/issue-5997-struct.rs index e9cfafc98df0e..af9e66b770bba 100644 --- a/src/test/compile-fail/issue-5997-struct.rs +++ b/src/test/compile-fail/issue-5997-struct.rs @@ -9,7 +9,7 @@ // except according to those terms. fn f() -> 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 } diff --git a/src/test/compile-fail/nested-ty-params.rs b/src/test/compile-fail/nested-ty-params.rs index 0ee2a3add8721..aac37289bb749 100644 --- a/src/test/compile-fail/nested-ty-params.rs +++ b/src/test/compile-fail/nested-ty-params.rs @@ -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(v: Vec ) -> U { fn hd1(w: [U]) -> U { return w[0]; } diff --git a/src/test/compile-fail/type-arg-out-of-scope.rs b/src/test/compile-fail/type-arg-out-of-scope.rs index 3249794e5c822..04cd961e97ff7 100644 --- a/src/test/compile-fail/type-arg-out-of-scope.rs +++ b/src/test/compile-fail/type-arg-out-of-scope.rs @@ -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(x: T) { fn bar(f: Box T>) { } } diff --git a/src/test/ui/error-codes/E0401.rs b/src/test/ui/error-codes/E0401.rs index 09bc950efd2d6..15b946625778c 100644 --- a/src/test/ui/error-codes/E0401.rs +++ b/src/test/ui/error-codes/E0401.rs @@ -8,11 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +trait Baz {} + fn foo(x: T) { - fn bar(y: T) { //~ ERROR E0401 + fn bar, W: Fn()>(y: T) { //~ ERROR E0401 + } + fn baz, + W: Fn()> + (y: T) { //~ ERROR E0401 } bar(x); } + +struct A { + inner: T, +} + +impl Iterator for A { + type Item = u8; + fn next(&mut self) -> Option { + fn helper(sel: &Self) -> u8 { //~ ERROR E0401 + unimplemented!(); + } + Some(helper(self)) + } +} + fn main() { } diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 15e1eda7722da..c306ff4a04f6a 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -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(x: T) { + | - type variable from outer function +LL | fn bar, W: Fn()>(y: T) { //~ ERROR E0401 + | -------------------------- ^ use of type variable from outer function + | | + | help: try using a local type parameter instead: `bar, 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(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 Iterator for A { + | ---- `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` + +error: aborting due to 3 previous errors If you want more information on this error, try using "rustc --explain E0401"