Skip to content

Commit ff13b7c

Browse files
committed
Auto merge of #41459 - frewsxcv:rollup, r=frewsxcv
Rollup of 4 pull requests - Successful merges: #37658, #41405, #41432, #41435 - Failed merges:
2 parents 1785bca + df72158 commit ff13b7c

File tree

16 files changed

+227
-38
lines changed

16 files changed

+227
-38
lines changed

src/librustc_typeck/check/coercion.rs

+11
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ use errors::DiagnosticBuilder;
7878
use syntax::abi;
7979
use syntax::feature_gate;
8080
use syntax::ptr::P;
81+
use syntax_pos;
8182

8283
use std::collections::VecDeque;
8384
use std::ops::Deref;
@@ -722,6 +723,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
722723
Ok(target)
723724
}
724725

726+
/// Same as `try_coerce()`, but without side-effects.
727+
pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
728+
let source = self.resolve_type_vars_with_obligations(expr_ty);
729+
debug!("coercion::can({:?} -> {:?})", source, target);
730+
731+
let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
732+
let coerce = Coerce::new(self, cause);
733+
self.probe(|_| coerce.coerce::<hir::Expr>(&[], source, target)).is_ok()
734+
}
735+
725736
/// Given some expressions, their known unified type and another expression,
726737
/// tries to unify the types, potentially inserting coercions on any of the
727738
/// provided expressions and returns their LUB (aka "common supertype").

src/librustc_typeck/check/demand.rs

+75-14
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@
1010

1111

1212
use check::FnCtxt;
13-
use rustc::ty::Ty;
14-
use rustc::infer::{InferOk};
13+
use rustc::infer::InferOk;
1514
use rustc::traits::ObligationCause;
1615

1716
use syntax::ast;
1817
use syntax_pos::{self, Span};
1918
use rustc::hir;
2019
use rustc::hir::def::Def;
21-
use rustc::ty::{self, AssociatedItem};
20+
use rustc::ty::{self, Ty, AssociatedItem};
2221
use errors::DiagnosticBuilder;
2322

2423
use super::method::probe;
@@ -80,18 +79,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
8079
if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
8180
let cause = self.misc(expr.span);
8281
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
83-
let mode = probe::Mode::MethodCall;
84-
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
85-
mode,
86-
expected,
87-
checked_ty,
88-
ast::DUMMY_NODE_ID);
8982
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
90-
if suggestions.len() > 0 {
91-
err.help(&format!("here are some functions which \
92-
might fulfill your needs:\n{}",
93-
self.get_best_match(&suggestions).join("\n")));
94-
};
83+
if let Some(suggestion) = self.check_ref(expr,
84+
checked_ty,
85+
expected) {
86+
err.help(&suggestion);
87+
} else {
88+
let mode = probe::Mode::MethodCall;
89+
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
90+
mode,
91+
expected,
92+
checked_ty,
93+
ast::DUMMY_NODE_ID);
94+
if suggestions.len() > 0 {
95+
err.help(&format!("here are some functions which \
96+
might fulfill your needs:\n{}",
97+
self.get_best_match(&suggestions).join("\n")));
98+
}
99+
}
95100
err.emit();
96101
}
97102
}
@@ -140,4 +145,60 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
140145
_ => false,
141146
}
142147
}
148+
149+
/// This function is used to determine potential "simple" improvements or users' errors and
150+
/// provide them useful help. For example:
151+
///
152+
/// ```
153+
/// fn some_fn(s: &str) {}
154+
///
155+
/// let x = "hey!".to_owned();
156+
/// some_fn(x); // error
157+
/// ```
158+
///
159+
/// No need to find every potential function which could make a coercion to transform a
160+
/// `String` into a `&str` since a `&` would do the trick!
161+
///
162+
/// In addition of this check, it also checks between references mutability state. If the
163+
/// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
164+
/// `&mut`!".
165+
fn check_ref(&self,
166+
expr: &hir::Expr,
167+
checked_ty: Ty<'tcx>,
168+
expected: Ty<'tcx>)
169+
-> Option<String> {
170+
match (&expected.sty, &checked_ty.sty) {
171+
(&ty::TyRef(_, _), &ty::TyRef(_, _)) => None,
172+
(&ty::TyRef(_, mutability), _) => {
173+
// Check if it can work when put into a ref. For example:
174+
//
175+
// ```
176+
// fn bar(x: &mut i32) {}
177+
//
178+
// let x = 0u32;
179+
// bar(&x); // error, expected &mut
180+
// ```
181+
let ref_ty = match mutability.mutbl {
182+
hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
183+
self.tcx.mk_region(ty::ReStatic),
184+
checked_ty),
185+
hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
186+
self.tcx.mk_region(ty::ReStatic),
187+
checked_ty),
188+
};
189+
if self.can_coerce(ref_ty, expected) {
190+
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
191+
return Some(format!("try with `{}{}`",
192+
match mutability.mutbl {
193+
hir::Mutability::MutMutable => "&mut ",
194+
hir::Mutability::MutImmutable => "&",
195+
},
196+
&src));
197+
}
198+
}
199+
None
200+
}
201+
_ => None,
202+
}
203+
}
143204
}

src/librustdoc/html/markdown.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
492492
text: *const hoedown_buffer,
493493
lang: *const hoedown_buffer,
494494
data: *const hoedown_renderer_data,
495-
line: libc::size_t) {
495+
_line: libc::size_t) {
496496
unsafe {
497497
if text.is_null() { return }
498498
let block_info = if lang.is_null() {
@@ -503,11 +503,15 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
503503
LangString::parse(s)
504504
};
505505
if !block_info.rust { return }
506+
let text = (*text).as_bytes();
506507
let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
507508
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
508-
let line = tests.get_line() + line;
509+
let text = str::from_utf8(text).unwrap();
510+
let lines = text.lines().map(|l| {
511+
stripped_filtered_line(l).unwrap_or(l)
512+
});
509513
let filename = tests.get_filename();
510-
tests.add_old_test(line, filename);
514+
tests.add_old_test(lines.collect::<Vec<&str>>().join("\n"), filename);
511515
}
512516
}
513517

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#![feature(staged_api)]
2828
#![feature(test)]
2929
#![feature(unicode)]
30+
#![feature(vec_remove_item)]
3031

3132
extern crate arena;
3233
extern crate getopts;

src/librustdoc/test.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use std::collections::HashMap;
1112
use std::env;
1213
use std::ffi::OsString;
1314
use std::io::prelude::*;
@@ -381,7 +382,7 @@ fn partition_source(s: &str) -> (String, String) {
381382
pub struct Collector {
382383
pub tests: Vec<testing::TestDescAndFn>,
383384
// to be removed when hoedown will be definitely gone
384-
pub old_tests: Vec<String>,
385+
pub old_tests: HashMap<String, Vec<String>>,
385386
names: Vec<String>,
386387
cfgs: Vec<String>,
387388
libs: SearchPaths,
@@ -403,7 +404,7 @@ impl Collector {
403404
codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector {
404405
Collector {
405406
tests: Vec::new(),
406-
old_tests: Vec::new(),
407+
old_tests: HashMap::new(),
407408
names: Vec::new(),
408409
cfgs: cfgs,
409410
libs: libs,
@@ -432,17 +433,39 @@ impl Collector {
432433
}
433434
}
434435

435-
pub fn add_old_test(&mut self, line: usize, filename: String) {
436-
let name = self.generate_name(line, &filename);
437-
self.old_tests.push(name);
436+
// to be removed once hoedown is gone
437+
fn generate_name_beginning(&self, filename: &str) -> String {
438+
if self.use_headers {
439+
if let Some(ref header) = self.current_header {
440+
format!("{} - {} (line", filename, header)
441+
} else {
442+
format!("{} - (line", filename)
443+
}
444+
} else {
445+
format!("{} - {} (line", filename, self.names.join("::"))
446+
}
447+
}
448+
449+
pub fn add_old_test(&mut self, test: String, filename: String) {
450+
let name_beg = self.generate_name_beginning(&filename);
451+
let entry = self.old_tests.entry(name_beg)
452+
.or_insert(Vec::new());
453+
entry.push(test.trim().to_owned());
438454
}
439455

440456
pub fn add_test(&mut self, test: String,
441457
should_panic: bool, no_run: bool, should_ignore: bool,
442458
as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
443459
line: usize, filename: String) {
444460
let name = self.generate_name(line, &filename);
445-
if self.old_tests.iter().find(|&x| x == &name).is_none() {
461+
let name_beg = self.generate_name_beginning(&filename);
462+
let mut found = false;
463+
// to be removed when hoedown is removed
464+
let test = test.trim().to_owned();
465+
if let Some(entry) = self.old_tests.get_mut(&name_beg) {
466+
found = entry.remove_item(&test).is_some();
467+
}
468+
if !found {
446469
let _ = writeln!(&mut io::stderr(),
447470
"WARNING: {} Code block is not currently run as a test, but will in \
448471
future versions of rustdoc. Please ensure this code block is a \

src/libsyntax/ext/expand.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
205205
module.directory.pop();
206206
self.cx.current_expansion.module = Rc::new(module);
207207

208+
let orig_mod_span = krate.module.inner;
209+
208210
let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
209211
attrs: krate.attrs,
210212
span: krate.span,
@@ -214,11 +216,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
214216
vis: ast::Visibility::Public,
215217
})));
216218

217-
match self.expand(krate_item).make_items().pop().unwrap().unwrap() {
218-
ast::Item { attrs, node: ast::ItemKind::Mod(module), .. } => {
219+
match self.expand(krate_item).make_items().pop().map(P::unwrap) {
220+
Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => {
219221
krate.attrs = attrs;
220222
krate.module = module;
221223
},
224+
None => {
225+
// Resolution failed so we return an empty expansion
226+
krate.attrs = vec![];
227+
krate.module = ast::Mod {
228+
inner: orig_mod_span,
229+
items: vec![],
230+
};
231+
},
222232
_ => unreachable!(),
223233
};
224234

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2017 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+
// force-host
12+
// no-prefer-dynamic
13+
14+
#![crate_type = "proc-macro"]
15+
#![feature(proc_macro)]
16+
17+
extern crate proc_macro;
18+
use proc_macro::TokenStream;
19+
20+
#[proc_macro_attribute]
21+
pub fn emit_unchanged(_args: TokenStream, input: TokenStream) -> TokenStream {
22+
input
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2017 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+
// aux-build:issue-41211.rs
12+
13+
// FIXME: https://github.com/rust-lang/rust/issues/41430
14+
// This is a temporary regression test for the ICE reported in #41211
15+
16+
#![feature(proc_macro)]
17+
#![emit_unchanged]
18+
//~^ ERROR: cannot find attribute macro `emit_unchanged` in this scope
19+
extern crate issue_41211;
20+
use issue_41211::emit_unchanged;
21+
22+
fn main() {}

src/test/compile-fail/coercion-slice.rs

-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,5 @@ fn main() {
1414
let _: &[i32] = [0];
1515
//~^ ERROR mismatched types
1616
//~| expected type `&[i32]`
17-
//~| found type `[{integer}; 1]`
1817
//~| expected &[i32], found array of 1 elements
1918
}

src/test/compile-fail/cross-borrow-trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl Trait for Foo {}
1717

1818
pub fn main() {
1919
let x: Box<Trait> = Box::new(Foo);
20-
let _y: &Trait = x; //~ ERROR mismatched types
20+
let _y: &Trait = x; //~ ERROR E0308
2121
//~| expected type `&Trait`
2222
//~| found type `std::boxed::Box<Trait>`
2323
}

src/test/compile-fail/issue-11374.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
3333
fn main() {
3434
let mut c = for_stdin();
3535
let mut v = Vec::new();
36-
c.read_to(v); //~ ERROR mismatched types
36+
c.read_to(v); //~ ERROR E0308
3737
}

src/test/compile-fail/issue-13058.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
3535
fn main() {
3636
check((3, 5));
3737
//~^ ERROR mismatched types
38+
//~| HELP try with `&(3, 5)`
3839
}

src/test/ui/span/coerce-suggestions.rs

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ fn main() {
3232
//~| NOTE types differ in mutability
3333
//~| NOTE expected type `&mut std::string::String`
3434
//~| NOTE found type `&std::string::String`
35-
//~| HELP try with `&mut y`
3635
test2(&y);
3736
//~^ ERROR E0308
3837
//~| NOTE types differ in mutability

src/test/ui/span/coerce-suggestions.stderr

+5-9
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@ error[E0308]: mismatched types
1818
|
1919
= note: expected type `&str`
2020
found type `std::string::String`
21-
= help: here are some functions which might fulfill your needs:
22-
- .as_str()
23-
- .trim()
24-
- .trim_left()
25-
- .trim_right()
21+
= help: try with `&String::new()`
2622

2723
error[E0308]: mismatched types
2824
--> $DIR/coerce-suggestions.rs:30:10
@@ -34,18 +30,18 @@ error[E0308]: mismatched types
3430
found type `&std::string::String`
3531

3632
error[E0308]: mismatched types
37-
--> $DIR/coerce-suggestions.rs:36:11
33+
--> $DIR/coerce-suggestions.rs:35:11
3834
|
39-
36 | test2(&y);
35+
35 | test2(&y);
4036
| ^^ types differ in mutability
4137
|
4238
= note: expected type `&mut i32`
4339
found type `&std::string::String`
4440

4541
error[E0308]: mismatched types
46-
--> $DIR/coerce-suggestions.rs:42:9
42+
--> $DIR/coerce-suggestions.rs:41:9
4743
|
48-
42 | f = box f;
44+
41 | f = box f;
4945
| ^^^^^ cyclic type of infinite size
5046
|
5147
= note: expected type `_`

0 commit comments

Comments
 (0)