diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index eed516a438175..d9da995037325 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -165,6 +165,10 @@ pub struct Session { /// `Span`s of trait methods that weren't found to avoid emitting object safety errors pub trait_methods_not_found: Lock>, + + /// Mapping from ident span to path span for paths that don't exist as written, but that + /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. + pub confused_type_with_std_module: Lock>, } pub struct PerfStats { @@ -1248,6 +1252,7 @@ fn build_session_( has_panic_handler: Once::new(), driver_lint_caps, trait_methods_not_found: Lock::new(Default::default()), + confused_type_with_std_module: Lock::new(Default::default()), }; validate_commandline_args_with_session_available(&sess); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 08b2f1a0f16fc..8df83120738c1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3273,6 +3273,25 @@ impl<'a> Resolver<'a> { let traits = self.get_traits_containing_item(item_name, ns); self.trait_map.insert(id, traits); } + + let mut std_path = vec![Segment::from_ident(Ident::from_str("std"))]; + std_path.extend(path); + if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { + let cl = CrateLint::No; + let ns = Some(ns); + if let PathResult::Module(_) | PathResult::NonModule(_) = + self.resolve_path_without_parent_scope(&std_path, ns, false, span, cl) + { + // check if we wrote `str::from_utf8` instead of `std::str::from_utf8` + let item_span = path.iter().last().map(|segment| segment.ident.span) + .unwrap_or(span); + debug!("accessed item from `std` submodule as a bare type {:?}", std_path); + let mut hm = self.session.confused_type_with_std_module.borrow_mut(); + hm.insert(item_span, span); + // In some places (E0223) we only have access to the full path + hm.insert(span, span); + } + } resolution } _ => report_errors(self, None) @@ -3387,16 +3406,17 @@ impl<'a> Resolver<'a> { } // Resolve in alternative namespaces if resolution in the primary namespace fails. - fn resolve_qpath_anywhere(&mut self, - id: NodeId, - qself: Option<&QSelf>, - path: &[Segment], - primary_ns: Namespace, - span: Span, - defer_to_typeck: bool, - global_by_default: bool, - crate_lint: CrateLint) - -> Option { + fn resolve_qpath_anywhere( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + primary_ns: Namespace, + span: Span, + defer_to_typeck: bool, + global_by_default: bool, + crate_lint: CrateLint, + ) -> Option { let mut fin_res = None; // FIXME: can't resolve paths in macro namespace yet, macros are // processed by the little special hack below. @@ -3426,15 +3446,16 @@ impl<'a> Resolver<'a> { } /// Handles paths that may refer to associated items. - fn resolve_qpath(&mut self, - id: NodeId, - qself: Option<&QSelf>, - path: &[Segment], - ns: Namespace, - span: Span, - global_by_default: bool, - crate_lint: CrateLint) - -> Option { + fn resolve_qpath( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + ns: Namespace, + span: Span, + global_by_default: bool, + crate_lint: CrateLint, + ) -> Option { debug!( "resolve_qpath(id={:?}, qself={:?}, path={:?}, \ ns={:?}, span={:?}, global_by_default={:?})", diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0c206b27f8058..be8e5dae1d9f9 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1187,18 +1187,33 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ty } - fn report_ambiguous_associated_type(&self, - span: Span, - type_str: &str, - trait_str: &str, - name: &str) { - struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type") - .span_suggestion( + fn report_ambiguous_associated_type( + &self, + span: Span, + type_str: &str, + trait_str: &str, + name: &str, + ) { + let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); + if let (Some(_), Ok(snippet)) = ( + self.tcx().sess.confused_type_with_std_module.borrow().get(&span), + self.tcx().sess.source_map().span_to_snippet(span), + ) { + err.span_suggestion( span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", type_str, trait_str, name), - Applicability::HasPlaceholders - ).emit(); + "you are looking for the module in `std`, not the primitive type", + format!("std::{}", snippet), + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", type_str, trait_str, name), + Applicability::HasPlaceholders + ); + } + err.emit(); } // Search for a bound on a type parameter which includes the associated item @@ -1391,10 +1406,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { err.emit(); } else if !qself_ty.references_error() { // Don't print `TyErr` to the user. - self.report_ambiguous_associated_type(span, - &qself_ty.to_string(), - "Trait", - &assoc_ident.as_str()); + self.report_ambiguous_associated_type( + span, + &qself_ty.to_string(), + "Trait", + &assoc_ident.as_str(), + ); } return (tcx.types.err, Def::Err); } @@ -1461,10 +1478,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ty } else { let path_str = tcx.def_path_str(trait_def_id); - self.report_ambiguous_associated_type(span, - "Type", - &path_str, - &item_segment.ident.as_str()); + self.report_ambiguous_associated_type( + span, + "Type", + &path_str, + &item_segment.ident.as_str(), + ); return tcx.types.err; }; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index ff889c89770af..7121b06e27a0f 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -292,7 +292,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return; } else { span = item_name.span; - struct_span_err!( + let mut err = struct_span_err!( tcx.sess, span, E0599, @@ -300,7 +300,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_kind, item_name, ty_str - ) + ); + if let Some(span) = tcx.sess.confused_type_with_std_module.borrow() + .get(&span) + { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) { + err.span_suggestion( + *span, + "you are looking for the module in `std`, \ + not the primitive type", + format!("std::{}", snippet), + Applicability::MachineApplicable, + ); + } + } + err } } else { tcx.sess.diagnostic().struct_dummy() diff --git a/src/test/ui/issues/issue-22933-3.stderr b/src/test/ui/issues/issue-22933-3.stderr index b1afda6d15114..e0e8b5e18a42d 100644 --- a/src/test/ui/issues/issue-22933-3.stderr +++ b/src/test/ui/issues/issue-22933-3.stderr @@ -3,6 +3,10 @@ error[E0599]: no associated item named `MIN` found for type `u8` in the current | LL | const FOO: [u32; u8::MIN as usize] = []; | ^^^ associated item not found in `u8` +help: you are looking for the module in `std`, not the primitive type + | +LL | const FOO: [u32; std::u8::MIN as usize] = []; + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-std-when-using-type.rs b/src/test/ui/suggestions/suggest-std-when-using-type.rs new file mode 100644 index 0000000000000..9ca68a635da96 --- /dev/null +++ b/src/test/ui/suggestions/suggest-std-when-using-type.rs @@ -0,0 +1,7 @@ +fn main() { + let pi = f32::consts::PI; //~ ERROR ambiguous associated type + let bytes = "hello world".as_bytes(); + let string = unsafe { + str::from_utf8(bytes) //~ ERROR no function or associated item named `from_utf8` found + }; +} diff --git a/src/test/ui/suggestions/suggest-std-when-using-type.stderr b/src/test/ui/suggestions/suggest-std-when-using-type.stderr new file mode 100644 index 0000000000000..eecb4e60f9d59 --- /dev/null +++ b/src/test/ui/suggestions/suggest-std-when-using-type.stderr @@ -0,0 +1,24 @@ +error[E0223]: ambiguous associated type + --> $DIR/suggest-std-when-using-type.rs:2:14 + | +LL | let pi = f32::consts::PI; + | ^^^^^^^^^^^^^^^ +help: you are looking for the module in `std`, not the primitive type + | +LL | let pi = std::f32::consts::PI; + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no function or associated item named `from_utf8` found for type `str` in the current scope + --> $DIR/suggest-std-when-using-type.rs:5:14 + | +LL | str::from_utf8(bytes) + | ^^^^^^^^^ function or associated item not found in `str` +help: you are looking for the module in `std`, not the primitive type + | +LL | std::str::from_utf8(bytes) + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0223, E0599. +For more information about an error, try `rustc --explain E0223`.