diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 21820ca071921..ced78a5784182 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1493,7 +1493,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { origin: TypeOrigin, expected: Ty<'tcx>, actual: Ty<'tcx>, - err: TypeError<'tcx>) { + err: TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { let trace = TypeTrace { origin: origin, values: Types(ExpectedFound { @@ -1501,7 +1501,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { found: actual }) }; - self.report_and_explain_type_error(trace, &err).emit(); + self.report_and_explain_type_error(trace, &err) } pub fn report_conflicting_default_types(&self, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 92dfb883ef301..29262b283cdb2 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -425,6 +425,7 @@ pub struct ProjectionTy<'tcx> { pub struct BareFnTy<'tcx> { pub unsafety: hir::Unsafety, pub abi: abi::Abi, + /// Signature (inputs and output) of this function type. pub sig: PolyFnSig<'tcx>, } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index c842514227ca0..357c41f86c4a5 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -470,7 +470,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { (result_ty, arm_ty) }; - self.report_mismatched_types(origin, expected, found, e); + self.report_mismatched_types(origin, expected, found, e).emit(); self.tcx.types.err } }; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index d622bc7f751d7..56fc970dc3cfb 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -13,8 +13,12 @@ use check::FnCtxt; use rustc::ty::Ty; use rustc::infer::{InferOk, TypeOrigin}; -use syntax_pos::Span; +use syntax::ast; +use syntax_pos::{self, Span}; use rustc::hir; +use rustc::ty::{self, ImplOrTraitItem}; + +use super::method::probe; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Requires that the two types unify, and prints an error message if @@ -27,7 +31,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(obligations.is_empty()); }, Err(e) => { - self.report_mismatched_types(origin, expected, actual, e); + self.report_mismatched_types(origin, expected, actual, e).emit(); } } } @@ -47,18 +51,148 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(obligations.is_empty()); }, Err(e) => { - self.report_mismatched_types(origin, expected, actual, e); + self.report_mismatched_types(origin, expected, actual, e).emit(); } } } + /// This function is used to determine potential "simple" improvements or users' errors and + /// provide them useful help. For example: + /// + /// ``` + /// fn some_fn(s: &str) {} + /// + /// let x = "hey!".to_owned(); + /// some_fn(x); // error + /// ``` + /// + /// No need to find every potential function which could make a coercion to transform a + /// `String` into a `&str` since a `&` would do the trick! + /// + /// In addition of this check, it also checks between references mutability state. If the + /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with + /// `&mut`!". + fn check_ref(&self, + expr: &hir::Expr, + checked_ty: Ty<'tcx>, + expected: Ty<'tcx>) + -> Option { + match (&expected.sty, &checked_ty.sty) { + (&ty::TyRef(_, expected_mutability), + &ty::TyRef(_, checked_mutability)) => { + // check if there is a mutability difference + if checked_mutability.mutbl == hir::Mutability::MutImmutable && + checked_mutability.mutbl != expected_mutability.mutbl && + self.can_sub_types(&checked_mutability.ty, + expected_mutability.ty).is_ok() { + if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { + return Some(format!("try with `&mut {}`", &src.replace("&", ""))); + } + } + None + } + (&ty::TyRef(_, mutability), _) => { + // Check if it can work when put into a ref. For example: + // + // ``` + // fn bar(x: &mut i32) {} + // + // let x = 0u32; + // bar(&x); // error, expected &mut + // ``` + let ref_ty = match mutability.mutbl { + hir::Mutability::MutMutable => self.tcx.mk_mut_ref( + self.tcx.mk_region(ty::ReStatic), + checked_ty), + hir::Mutability::MutImmutable => self.tcx.mk_imm_ref( + self.tcx.mk_region(ty::ReStatic), + checked_ty), + }; + if self.try_coerce(expr, ref_ty, expected).is_ok() { + if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { + return Some(format!("try with `{}{}`", + match mutability.mutbl { + hir::Mutability::MutMutable => "&mut ", + hir::Mutability::MutImmutable => "&", + }, + &src)); + } + } + None + } + _ => None, + } + } + // Checks that the type of `expr` can be coerced to `expected`. pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); if let Err(e) = self.try_coerce(expr, checked_ty, expected) { let origin = TypeOrigin::Misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); - self.report_mismatched_types(origin, expected, expr_ty, e); + let mode = probe::Mode::MethodCall; + let suggestions = if let Some(s) = self.check_ref(expr, checked_ty, expected) { + Some(s) + } else { + let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, + mode, + expected, + checked_ty, + ast::DUMMY_NODE_ID); + if suggestions.len() > 0 { + Some(format!("here are some functions which \ + might fulfill your needs:\n - {}", + self.get_best_match(&suggestions))) + } else { + None + } + }; + let mut err = self.report_mismatched_types(origin, expected, expr_ty, e); + if let Some(suggestions) = suggestions { + err.help(&suggestions); + } + err.emit(); + } + } + + fn format_method_suggestion(&self, method: &ImplOrTraitItem<'tcx>) -> String { + format!(".{}({})", + method.name(), + if self.has_not_input_arg(method) { + "" + } else { + "..." + }) + } + + fn display_suggested_methods(&self, methods: &[ImplOrTraitItem<'tcx>]) -> String { + methods.iter() + .take(5) + .map(|method| self.format_method_suggestion(&*method)) + .collect::>() + .join("\n - ") + } + + fn get_best_match(&self, methods: &[ImplOrTraitItem<'tcx>]) -> String { + let no_argument_methods: Vec<_> = + methods.iter() + .filter(|ref x| self.has_not_input_arg(&*x)) + .map(|x| x.clone()) + .collect(); + if no_argument_methods.len() > 0 { + self.display_suggested_methods(&no_argument_methods) + } else { + self.display_suggested_methods(&methods) + } + } + + // This function checks if the method isn't static and takes other arguments than `self`. + fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool { + match *method { + ImplOrTraitItem::MethodTraitItem(ref x) => { + x.fty.sig.skip_binder().inputs.len() == 1 + } + _ => false, } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 2df562f9ade46..d204b835d4f71 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -30,7 +30,7 @@ pub use self::CandidateSource::*; pub use self::suggest::AllTraitsVec; mod confirm; -mod probe; +pub mod probe; mod suggest; pub enum MethodError<'tcx> { @@ -91,7 +91,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { allow_private: bool) -> bool { let mode = probe::Mode::MethodCall; - match self.probe_method(span, mode, method_name, self_ty, call_expr_id) { + match self.probe_for_name(span, mode, method_name, self_ty, call_expr_id) { Ok(..) => true, Err(NoMatch(..)) => false, Err(Ambiguity(..)) => true, @@ -130,7 +130,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mode = probe::Mode::MethodCall; let self_ty = self.resolve_type_vars_if_possible(&self_ty); - let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?; + let pick = self.probe_for_name(span, mode, method_name, self_ty, call_expr.id)?; if let Some(import_id) = pick.import_id { self.tcx.used_trait_imports.borrow_mut().insert(import_id); @@ -353,7 +353,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr_id: ast::NodeId) -> Result> { let mode = probe::Mode::Path; - let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?; + let pick = self.probe_for_name(span, mode, method_name, self_ty, expr_id)?; if let Some(import_id) = pick.import_id { self.tcx.used_trait_imports.borrow_mut().insert(import_id); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 43837de2f345d..de6f66ef7dd5c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -19,7 +19,7 @@ use hir::def::Def; use rustc::ty::subst::{Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::infer::{InferOk, TypeOrigin}; +use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::util::nodemap::FnvHashSet; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; @@ -31,11 +31,16 @@ use std::rc::Rc; use self::CandidateKind::*; pub use self::PickKind::*; +pub enum LookingFor<'tcx> { + MethodName(ast::Name), + ReturnType(Ty<'tcx>), +} + struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, span: Span, mode: Mode, - item_name: ast::Name, + looking_for: LookingFor<'tcx>, steps: Rc>>, opt_simplified_steps: Option>, inherent_candidates: Vec>, @@ -143,18 +148,67 @@ pub enum Mode { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn probe_method(&self, - span: Span, - mode: Mode, - item_name: ast::Name, - self_ty: Ty<'tcx>, - scope_expr_id: ast::NodeId) - -> PickResult<'tcx> { + /// This is used to offer suggestions to users. It returns methods + /// that could have been called which have the desired return + /// type. Some effort is made to rule out methods that, if called, + /// would result in an error (basically, the same criteria we + /// would use to decide if a method is a plausible fit for + /// ambiguity purposes). + pub fn probe_for_return_type(&self, + span: Span, + mode: Mode, + return_type: Ty<'tcx>, + self_ty: Ty<'tcx>, + scope_expr_id: ast::NodeId) + -> Vec> { + debug!("probe(self_ty={:?}, return_type={}, scope_expr_id={})", + self_ty, + return_type, + scope_expr_id); + let method_names = + self.probe_op(span, mode, LookingFor::ReturnType(return_type), self_ty, scope_expr_id, + |probe_cx| Ok(probe_cx.candidate_method_names())) + .unwrap_or(vec![]); + method_names + .iter() + .flat_map(|&method_name| { + match self.probe_for_name(span, mode, method_name, self_ty, scope_expr_id) { + Ok(pick) => Some(pick.item), + Err(_) => None, + } + }) + .collect() + } + + pub fn probe_for_name(&self, + span: Span, + mode: Mode, + item_name: ast::Name, + self_ty: Ty<'tcx>, + scope_expr_id: ast::NodeId) + -> PickResult<'tcx> { debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})", self_ty, item_name, scope_expr_id); + self.probe_op(span, + mode, + LookingFor::MethodName(item_name), + self_ty, + scope_expr_id, + |probe_cx| probe_cx.pick()) + } + fn probe_op(&'a self, + span: Span, + mode: Mode, + looking_for: LookingFor<'tcx>, + self_ty: Ty<'tcx>, + scope_expr_id: ast::NodeId, + op: OP) + -> Result> + where OP: FnOnce(ProbeContext<'a, 'gcx, 'tcx>) -> Result> + { // FIXME(#18741) -- right now, creating the steps involves evaluating the // `*` operator, which registers obligations that then escape into // the global fulfillment context and thus has global @@ -206,14 +260,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // that we create during the probe process are removed later self.probe(|_| { let mut probe_cx = - ProbeContext::new(self, span, mode, item_name, steps, opt_simplified_steps); + ProbeContext::new(self, span, mode, looking_for, + steps, opt_simplified_steps); probe_cx.assemble_inherent_candidates(); probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?; - probe_cx.pick() + op(probe_cx) }) } - fn create_steps(&self, span: Span, self_ty: Ty<'tcx>) -> Option>> { + fn create_steps(&self, + span: Span, + self_ty: Ty<'tcx>) + -> Option>> { // FIXME: we don't need to create the entire steps in one pass let mut autoderef = self.autoderef(span, self_ty); @@ -252,7 +310,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, span: Span, mode: Mode, - item_name: ast::Name, + looking_for: LookingFor<'tcx>, steps: Vec>, opt_simplified_steps: Option>) -> ProbeContext<'a, 'gcx, 'tcx> { @@ -260,7 +318,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fcx: fcx, span: span, mode: mode, - item_name: item_name, + looking_for: looking_for, inherent_candidates: Vec::new(), extension_candidates: Vec::new(), impl_dups: FnvHashSet(), @@ -594,17 +652,29 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { Ok(()) } + pub fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>, + expected: ty::Ty<'tcx>) -> bool { + match *method { + ty::ImplOrTraitItem::MethodTraitItem(ref x) => { + self.probe(|_| { + let substs = self.fresh_substs_for_item(self.span, method.def_id()); + let output = x.fty.sig.output().subst(self.tcx, substs); + let (output, _) = self.replace_late_bound_regions_with_fresh_var( + self.span, infer::FnCall, &output); + self.can_sub_types(output, expected).is_ok() + }) + } + _ => false, + } + } + fn assemble_extension_candidates_for_trait(&mut self, trait_def_id: DefId) -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); - // Check whether `trait_def_id` defines a method with suitable name: - let trait_items = self.tcx.trait_items(trait_def_id); - let maybe_item = trait_items.iter() - .find(|item| item.name() == self.item_name); - let item = match maybe_item { + let item = match self.impl_or_trait_item(trait_def_id) { Some(i) => i, None => { return Ok(()); @@ -612,7 +682,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { }; // Check whether `trait_def_id` defines a method with suitable name: - if !self.has_applicable_self(item) { + if !self.has_applicable_self(&item) { debug!("method has inapplicable self"); self.record_static_candidate(TraitSource(trait_def_id)); return Ok(()); @@ -844,10 +914,30 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } } + fn candidate_method_names(&self) -> Vec { + let mut set = FnvHashSet(); + let mut names: Vec<_> = + self.inherent_candidates + .iter() + .chain(&self.extension_candidates) + .map(|candidate| candidate.item.name()) + .filter(|&name| set.insert(name)) + .collect(); + + // sort them by the name so we have a stable result + names.sort_by_key(|n| n.as_str()); + names + } + /////////////////////////////////////////////////////////////////////////// // THE ACTUAL SEARCH fn pick(mut self) -> PickResult<'tcx> { + assert!(match self.looking_for { + LookingFor::MethodName(_) => true, + LookingFor::ReturnType(_) => false, + }); + if let Some(r) = self.pick_core() { return r; } @@ -1284,7 +1374,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. fn impl_or_trait_item(&self, def_id: DefId) -> Option> { - self.fcx.impl_or_trait_item(def_id, self.item_name) + match self.looking_for { + LookingFor::MethodName(name) => { + self.fcx.impl_or_trait_item(def_id, name) + } + LookingFor::ReturnType(return_ty) => { + self.tcx + .impl_or_trait_items(def_id) + .iter() + .map(|&did| self.tcx.impl_or_trait_item(did)) + .find(|m| self.matches_return_type(m, return_ty)) + } + } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d8314bd6c2aed..077967e6095dd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2893,7 +2893,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } Err(e) => { - self.report_mismatched_types(origin, expected, found, e); + self.report_mismatched_types(origin, expected, found, e).emit(); self.tcx.types.err } } @@ -3663,7 +3663,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match result { Ok(ty) => unified = ty, Err(e) => { - self.report_mismatched_types(origin, unified, e_ty, e); + self.report_mismatched_types(origin, unified, e_ty, e).emit(); } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 4a4dea5b514e5..294bdfc759619 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -374,7 +374,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty), target, - ty::error::TypeError::Mutability); + ty::error::TypeError::Mutability).emit(); } (mt_a.ty, mt_b.ty, unsize_trait, None) }; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 75f0dac59501d..d950ef9d3b988 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -205,7 +205,7 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, true } Err(err) => { - infcx.report_mismatched_types(origin, expected, actual, err); + infcx.report_mismatched_types(origin, expected, actual, err).emit(); false } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ba16208715109..db238353f6b88 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -315,6 +315,9 @@ declare_features! ( // Allows using `Self` and associated types in struct expressions and patterns. (active, more_struct_aliases, "1.14.0", Some(37544)), + + // Allow safe suggestions for potential type conversions. + (active, safe_suggestion, "1.0.0", Some(37384)), ); declare_features! ( diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index 6b468ff96620d..f50900883999c 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -14,6 +14,6 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types //~| expected type `&[i32]` - //~| found type `[{integer}; 1]` + //~| found type `[i32; 1]` //~| expected &[i32], found array of 1 elements } diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index 672ff464718f8..975bc1300aae7 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -22,4 +22,5 @@ pub fn main() { //~| expected type `&Trait` //~| found type `Box` //~| expected &Trait, found box + //~^^^^ ERROR E0277 } diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index 883c16b089581..728b016b30fa5 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -23,11 +23,13 @@ pub fn main() { let x: *const S = &S; let y: &S = x; //~ ERROR mismatched types let y: &T = x; //~ ERROR mismatched types + //~^ ERROR E0277 // Test that we cannot convert from *-ptr to &S and &T (mut version) let x: *mut S = &mut S; let y: &S = x; //~ ERROR mismatched types let y: &T = x; //~ ERROR mismatched types + //~^ ERROR E0277 // Test that we cannot convert an immutable ptr to a mutable one using *-ptrs let x: &mut T = &S; //~ ERROR mismatched types diff --git a/src/test/compile-fail/issue-13058.rs b/src/test/compile-fail/issue-13058.rs index de578257e4684..df6675510ff2b 100644 --- a/src/test/compile-fail/issue-13058.rs +++ b/src/test/compile-fail/issue-13058.rs @@ -36,4 +36,5 @@ fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool fn main() { check((3, 5)); //~^ ERROR mismatched types +//~| HELP try with `&(3, 5)` } diff --git a/src/test/ui/span/coerce-suggestions.rs b/src/test/ui/span/coerce-suggestions.rs new file mode 100644 index 0000000000000..3177e858ff4fd --- /dev/null +++ b/src/test/ui/span/coerce-suggestions.rs @@ -0,0 +1,47 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(box_syntax)] + +fn test(_x: &mut String) {} +fn test2(_x: &mut i32) {} + +fn main() { + let x: usize = String::new(); + //~^ ERROR E0308 + //~| NOTE expected usize, found struct `std::string::String` + //~| NOTE expected type `usize` + //~| NOTE found type `std::string::String` + //~| HELP here are some functions which might fulfill your needs: + let x: &str = String::new(); + //~^ ERROR E0308 + //~| NOTE expected &str, found struct `std::string::String` + //~| NOTE expected type `&str` + //~| NOTE found type `std::string::String` + //~| HELP try with `&String::new()` + let y = String::new(); + test(&y); + //~^ ERROR E0308 + //~| NOTE types differ in mutability + //~| NOTE expected type `&mut std::string::String` + //~| NOTE found type `&std::string::String` + //~| HELP try with `&mut y` + test2(&y); + //~^ ERROR E0308 + //~| NOTE types differ in mutability + //~| NOTE expected type `&mut i32` + //~| NOTE found type `&std::string::String` + let f; + f = box f; + //~^ ERROR E0308 + //~| NOTE cyclic type of infinite size + //~| NOTE expected type `_` + //~| NOTE found type `Box<_>` +} diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr new file mode 100644 index 0000000000000..3673228301403 --- /dev/null +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -0,0 +1,52 @@ +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:17:20 + | +17 | let x: usize = String::new(); + | ^^^^^^^^^^^^^ expected usize, found struct `std::string::String` + | + = note: expected type `usize` + = note: found type `std::string::String` + = help: here are some functions which might fulfill your needs: + - .capacity() + - .len() + +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:23:19 + | +23 | let x: &str = String::new(); + | ^^^^^^^^^^^^^ expected &str, found struct `std::string::String` + | + = note: expected type `&str` + = note: found type `std::string::String` + = help: try with `&String::new()` + +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:30:10 + | +30 | test(&y); + | ^^ types differ in mutability + | + = note: expected type `&mut std::string::String` + = note: found type `&std::string::String` + = help: try with `&mut y` + +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:36:11 + | +36 | test2(&y); + | ^^ types differ in mutability + | + = note: expected type `&mut i32` + = note: found type `&std::string::String` + +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:42:9 + | +42 | f = box f; + | ^^^^^ cyclic type of infinite size + | + = note: expected type `_` + = note: found type `Box<_>` + +error: aborting due to 5 previous errors +