Skip to content

Commit a2cec1a

Browse files
Create check_ref method to allow to check coercion with & types
1 parent 19bb4ed commit a2cec1a

File tree

7 files changed

+114
-69
lines changed

7 files changed

+114
-69
lines changed

src/libcollections/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
#![cfg_attr(test, allow(deprecated))] // rand
3030
#![cfg_attr(not(stage0), deny(warnings))]
31-
#![cfg_attr(not(stage0), feature(safe_suggestion))]
3231

3332
#![feature(alloc)]
3433
#![feature(allow_internal_unstable)]

src/libcollections/string.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,6 @@ impl String {
12341234
/// assert_eq!(a.len(), 3);
12351235
/// ```
12361236
#[inline]
1237-
#[cfg_attr(not(stage0), safe_suggestion)]
12381237
#[stable(feature = "rust1", since = "1.0.0")]
12391238
pub fn len(&self) -> usize {
12401239
self.vec.len()

src/librustc/infer/error_reporting.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
548548
{
549549
let expected_found = match values {
550550
None => None,
551-
Some(ref values) => match self.values_str(&values) {
551+
Some(values) => match self.values_str(&values) {
552552
Some((expected, found)) => Some((expected, found)),
553553
None => {
554554
// Derived error. Cancel the emitter.

src/librustc_typeck/check/demand.rs

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,10 @@ use syntax_pos::{self, Span};
1818
use rustc::hir;
1919
use rustc::ty::{self, ImplOrTraitItem};
2020

21-
use hir::def_id::DefId;
22-
2321
use std::rc::Rc;
2422

2523
use super::method::probe;
2624

27-
struct MethodInfo<'tcx> {
28-
ast: Option<ast::Attribute>,
29-
id: DefId,
30-
item: Rc<ImplOrTraitItem<'tcx>>,
31-
}
32-
33-
impl<'tcx> MethodInfo<'tcx> {
34-
fn new(ast: Option<ast::Attribute>, id: DefId, item: Rc<ImplOrTraitItem<'tcx>>) -> MethodInfo {
35-
MethodInfo {
36-
ast: ast,
37-
id: id,
38-
item: item,
39-
}
40-
}
41-
}
42-
4325
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4426
// Requires that the two types unify, and prints an error message if
4527
// they don't.
@@ -76,41 +58,70 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
7658
}
7759
}
7860

61+
fn check_ref(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>,
62+
expected: Ty<'tcx>) -> Option<String> {
63+
match (&checked_ty.sty, &expected.sty) {
64+
(&ty::TyRef(_, x_mutability), &ty::TyRef(_, y_mutability)) => {
65+
// check if there is a mutability difference
66+
if x_mutability.mutbl == hir::Mutability::MutImmutable &&
67+
x_mutability.mutbl != y_mutability.mutbl &&
68+
self.can_sub_types(&x_mutability.ty, y_mutability.ty).is_ok() {
69+
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
70+
return Some(format!("try with `&mut {}`", &src.replace("&", "")));
71+
}
72+
}
73+
None
74+
}
75+
(_, &ty::TyRef(_, mutability)) => {
76+
// check if it can work when put into a ref
77+
let ref_ty = match mutability.mutbl {
78+
hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
79+
self.tcx.mk_region(ty::ReStatic),
80+
checked_ty),
81+
hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
82+
self.tcx.mk_region(ty::ReStatic),
83+
checked_ty),
84+
};
85+
if self.try_coerce(expr, ref_ty, expected).is_ok() {
86+
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
87+
return Some(format!("try with `{}{}`",
88+
match mutability.mutbl {
89+
hir::Mutability::MutMutable => "&mut ",
90+
hir::Mutability::MutImmutable => "&",
91+
},
92+
&src));
93+
}
94+
}
95+
None
96+
}
97+
_ => None,
98+
}
99+
}
100+
79101
// Checks that the type of `expr` can be coerced to `expected`.
80102
pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
81103
let expected = self.resolve_type_vars_with_obligations(expected);
82104
if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
83105
let origin = TypeOrigin::Misc(expr.span);
84106
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
85107
let mode = probe::Mode::MethodCall;
86-
let suggestions =
87-
if let Ok(methods) = self.probe_return(syntax_pos::DUMMY_SP, mode, expected,
88-
checked_ty, ast::DUMMY_NODE_ID) {
108+
let suggestions = if let Some(s) = self.check_ref(expr, checked_ty, expected) {
109+
Some(s)
110+
} else if let Ok(methods) = self.probe_return(syntax_pos::DUMMY_SP,
111+
mode,
112+
expected,
113+
checked_ty,
114+
ast::DUMMY_NODE_ID) {
89115
let suggestions: Vec<_> =
90116
methods.iter()
91-
.filter_map(|ref x| {
92-
if let Some(id) = self.get_impl_id(&x.item) {
93-
Some(MethodInfo::new(None, id, Rc::new(x.item.clone())))
94-
} else {
95-
None
96-
}})
117+
.map(|ref x| {
118+
Rc::new(x.item.clone())
119+
})
97120
.collect();
98121
if suggestions.len() > 0 {
99-
let safe_suggestions: Vec<_> =
100-
suggestions.iter()
101-
.map(|ref x| MethodInfo::new(
102-
self.find_attr(x.id, "safe_suggestion"),
103-
x.id,
104-
x.item.clone()))
105-
.filter(|ref x| x.ast.is_some())
106-
.collect();
107-
Some(if safe_suggestions.len() > 0 {
108-
self.get_best_match(&safe_suggestions)
109-
} else {
110-
format!("no safe suggestion found, here are functions which match your \
111-
needs but be careful:\n - {}",
112-
self.get_best_match(&suggestions))
113-
})
122+
Some(format!("here are some functions which \
123+
might fulfill your needs:\n - {}",
124+
self.get_best_match(&suggestions)))
114125
} else {
115126
None
116127
}
@@ -125,34 +136,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
125136
}
126137
}
127138

128-
fn get_best_match(&self, methods: &[MethodInfo<'tcx>]) -> String {
139+
fn get_best_match(&self, methods: &[Rc<ImplOrTraitItem<'tcx>>]) -> String {
129140
if methods.len() == 1 {
130-
return format!(" - {}", methods[0].item.name());
141+
return format!(" - {}", methods[0].name());
131142
}
132-
let no_argument_methods: Vec<&MethodInfo> =
143+
let no_argument_methods: Vec<&Rc<ImplOrTraitItem<'tcx>>> =
133144
methods.iter()
134-
.filter(|ref x| self.has_not_input_arg(&*x.item))
145+
.filter(|ref x| self.has_not_input_arg(&*x))
135146
.collect();
136147
if no_argument_methods.len() > 0 {
137148
no_argument_methods.iter()
138-
.map(|method| format!("{}", method.item.name()))
149+
.take(5)
150+
.map(|method| format!("{}", method.name()))
139151
.collect::<Vec<String>>()
140152
.join("\n - ")
141153
} else {
142154
methods.iter()
143-
.map(|method| format!("{}", method.item.name()))
155+
.take(5)
156+
.map(|method| format!("{}", method.name()))
144157
.collect::<Vec<String>>()
145158
.join("\n - ")
146159
}
147160
}
148161

149-
fn get_impl_id(&self, impl_: &ImplOrTraitItem<'tcx>) -> Option<DefId> {
150-
match *impl_ {
151-
ty::ImplOrTraitItem::MethodTraitItem(ref m) => Some((*m).def_id),
152-
_ => None,
153-
}
154-
}
155-
156162
fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool {
157163
match *method {
158164
ImplOrTraitItem::MethodTraitItem(ref x) => {

src/librustc_typeck/check/method/probe.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
192192
// think cause spurious errors. Really though this part should
193193
// take place in the `self.probe` below.
194194
let steps = if mode == Mode::MethodCall {
195-
match self.create_steps(span, self_ty) {
195+
match self.create_steps(span, self_ty, &looking_for) {
196196
Some(steps) => steps,
197197
None => {
198198
return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
@@ -245,7 +245,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
245245

246246
fn create_steps(&self,
247247
span: Span,
248-
self_ty: Ty<'tcx>)
248+
self_ty: Ty<'tcx>,
249+
looking_for: &LookingFor<'tcx>)
249250
-> Option<Vec<CandidateStep<'tcx>>> {
250251
// FIXME: we don't need to create the entire steps in one pass
251252

@@ -260,7 +261,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
260261
})
261262
.collect();
262263

263-
let final_ty = autoderef.unambiguous_final_ty();
264+
let final_ty = match looking_for {
265+
&LookingFor::MethodName(_) => autoderef.unambiguous_final_ty(),
266+
&LookingFor::ReturnType(_) => self_ty,
267+
};
264268
match final_ty.sty {
265269
ty::TyArray(elem_ty, _) => {
266270
let dereferences = steps.len() - 1;
@@ -637,13 +641,15 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
637641
}
638642

639643
pub fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>,
640-
expected: ty::Ty<'tcx>) -> bool {
644+
expected: ty::Ty<'tcx>) -> bool {
641645
match *method {
642646
ty::ImplOrTraitItem::MethodTraitItem(ref x) => {
643647
self.probe(|_| {
644648
let output = self.replace_late_bound_regions_with_fresh_var(
645649
self.span, infer::FnCall, &x.fty.sig.output());
646-
self.can_sub_types(output.0, expected).is_ok()
650+
let substs = self.fresh_substs_for_item(self.span, method.def_id());
651+
let output = output.0.subst(self.tcx, substs);
652+
self.can_sub_types(output, expected).is_ok()
647653
})
648654
}
649655
_ => false,

src/libsyntax/feature_gate.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -652,12 +652,6 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
652652
"internal implementation detail",
653653
cfg_fn!(rustc_attrs))),
654654

655-
("safe_suggestion", Whitelisted, Gated(Stability::Unstable,
656-
"safe_suggestion",
657-
"the `#[safe_suggestion]` attribute \
658-
is an experimental feature",
659-
cfg_fn!(safe_suggestion))),
660-
661655
// FIXME: #14408 whitelist docs since rustdoc looks at them
662656
("doc", Whitelisted, Ungated),
663657

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn test(_x: &mut String) {}
12+
fn test2(_x: &mut i32) {}
13+
14+
fn main() {
15+
let x: usize = String::new();
16+
//^ ERROR E0308
17+
//| NOTE expected type `usize`
18+
//| NOTE found type `std::string::String`
19+
//| NOTE here are some functions which might fulfill your needs:
20+
let x: &str = String::new();
21+
//^ ERROR E0308
22+
//| NOTE expected type `&str`
23+
//| NOTE found type `std::string::String`
24+
//| NOTE try with `&String::new()`
25+
let y = String::new();
26+
test(&y);
27+
//^ ERROR E0308
28+
//| NOTE expected type `&mut std::string::String`
29+
//| NOTE found type `&std::string::String`
30+
//| NOTE try with `&mut y`
31+
test2(&y);
32+
//^ ERROR E0308
33+
//| NOTE expected type `&mut i32`
34+
//| NOTE found type `&std::string::String`
35+
//| NOTE try with `&mut y`
36+
let f;
37+
f = box f;
38+
//^ ERROR E0308
39+
//| NOTE expected type `_`
40+
//| NOTE found type `Box<_>`
41+
}

0 commit comments

Comments
 (0)