Skip to content

Commit

Permalink
Auto merge of #41459 - frewsxcv:rollup, r=frewsxcv
Browse files Browse the repository at this point in the history
Rollup of 4 pull requests

- Successful merges: #37658, #41405, #41432, #41435
- Failed merges:
  • Loading branch information
bors committed Apr 22, 2017
2 parents 1785bca + df72158 commit ff13b7c
Show file tree
Hide file tree
Showing 16 changed files with 227 additions and 38 deletions.
11 changes: 11 additions & 0 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ use errors::DiagnosticBuilder;
use syntax::abi;
use syntax::feature_gate;
use syntax::ptr::P;
use syntax_pos;

use std::collections::VecDeque;
use std::ops::Deref;
Expand Down Expand Up @@ -722,6 +723,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Ok(target)
}

/// Same as `try_coerce()`, but without side-effects.
pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
let source = self.resolve_type_vars_with_obligations(expr_ty);
debug!("coercion::can({:?} -> {:?})", source, target);

let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
let coerce = Coerce::new(self, cause);
self.probe(|_| coerce.coerce::<hir::Expr>(&[], source, target)).is_ok()
}

/// Given some expressions, their known unified type and another expression,
/// tries to unify the types, potentially inserting coercions on any of the
/// provided expressions and returns their LUB (aka "common supertype").
Expand Down
89 changes: 75 additions & 14 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@


use check::FnCtxt;
use rustc::ty::Ty;
use rustc::infer::{InferOk};
use rustc::infer::InferOk;
use rustc::traits::ObligationCause;

use syntax::ast;
use syntax_pos::{self, Span};
use rustc::hir;
use rustc::hir::def::Def;
use rustc::ty::{self, AssociatedItem};
use rustc::ty::{self, Ty, AssociatedItem};
use errors::DiagnosticBuilder;

use super::method::probe;
Expand Down Expand Up @@ -80,18 +79,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
let cause = self.misc(expr.span);
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
let mode = probe::Mode::MethodCall;
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
mode,
expected,
checked_ty,
ast::DUMMY_NODE_ID);
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
if suggestions.len() > 0 {
err.help(&format!("here are some functions which \
might fulfill your needs:\n{}",
self.get_best_match(&suggestions).join("\n")));
};
if let Some(suggestion) = self.check_ref(expr,
checked_ty,
expected) {
err.help(&suggestion);
} else {
let mode = probe::Mode::MethodCall;
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
mode,
expected,
checked_ty,
ast::DUMMY_NODE_ID);
if suggestions.len() > 0 {
err.help(&format!("here are some functions which \
might fulfill your needs:\n{}",
self.get_best_match(&suggestions).join("\n")));
}
}
err.emit();
}
}
Expand Down Expand Up @@ -140,4 +145,60 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => false,
}
}

/// 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<String> {
match (&expected.sty, &checked_ty.sty) {
(&ty::TyRef(_, _), &ty::TyRef(_, _)) => 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.can_coerce(ref_ty, expected) {
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,
}
}
}
10 changes: 7 additions & 3 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
text: *const hoedown_buffer,
lang: *const hoedown_buffer,
data: *const hoedown_renderer_data,
line: libc::size_t) {
_line: libc::size_t) {
unsafe {
if text.is_null() { return }
let block_info = if lang.is_null() {
Expand All @@ -503,11 +503,15 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
LangString::parse(s)
};
if !block_info.rust { return }
let text = (*text).as_bytes();
let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
let line = tests.get_line() + line;
let text = str::from_utf8(text).unwrap();
let lines = text.lines().map(|l| {
stripped_filtered_line(l).unwrap_or(l)
});
let filename = tests.get_filename();
tests.add_old_test(line, filename);
tests.add_old_test(lines.collect::<Vec<&str>>().join("\n"), filename);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#![feature(staged_api)]
#![feature(test)]
#![feature(unicode)]
#![feature(vec_remove_item)]

extern crate arena;
extern crate getopts;
Expand Down
35 changes: 29 additions & 6 deletions src/librustdoc/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashMap;
use std::env;
use std::ffi::OsString;
use std::io::prelude::*;
Expand Down Expand Up @@ -381,7 +382,7 @@ fn partition_source(s: &str) -> (String, String) {
pub struct Collector {
pub tests: Vec<testing::TestDescAndFn>,
// to be removed when hoedown will be definitely gone
pub old_tests: Vec<String>,
pub old_tests: HashMap<String, Vec<String>>,
names: Vec<String>,
cfgs: Vec<String>,
libs: SearchPaths,
Expand All @@ -403,7 +404,7 @@ impl Collector {
codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector {
Collector {
tests: Vec::new(),
old_tests: Vec::new(),
old_tests: HashMap::new(),
names: Vec::new(),
cfgs: cfgs,
libs: libs,
Expand Down Expand Up @@ -432,17 +433,39 @@ impl Collector {
}
}

pub fn add_old_test(&mut self, line: usize, filename: String) {
let name = self.generate_name(line, &filename);
self.old_tests.push(name);
// to be removed once hoedown is gone
fn generate_name_beginning(&self, filename: &str) -> String {
if self.use_headers {
if let Some(ref header) = self.current_header {
format!("{} - {} (line", filename, header)
} else {
format!("{} - (line", filename)
}
} else {
format!("{} - {} (line", filename, self.names.join("::"))
}
}

pub fn add_old_test(&mut self, test: String, filename: String) {
let name_beg = self.generate_name_beginning(&filename);
let entry = self.old_tests.entry(name_beg)
.or_insert(Vec::new());
entry.push(test.trim().to_owned());
}

pub fn add_test(&mut self, test: String,
should_panic: bool, no_run: bool, should_ignore: bool,
as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
line: usize, filename: String) {
let name = self.generate_name(line, &filename);
if self.old_tests.iter().find(|&x| x == &name).is_none() {
let name_beg = self.generate_name_beginning(&filename);
let mut found = false;
// to be removed when hoedown is removed
let test = test.trim().to_owned();
if let Some(entry) = self.old_tests.get_mut(&name_beg) {
found = entry.remove_item(&test).is_some();
}
if !found {
let _ = writeln!(&mut io::stderr(),
"WARNING: {} Code block is not currently run as a test, but will in \
future versions of rustdoc. Please ensure this code block is a \
Expand Down
14 changes: 12 additions & 2 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
module.directory.pop();
self.cx.current_expansion.module = Rc::new(module);

let orig_mod_span = krate.module.inner;

let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
attrs: krate.attrs,
span: krate.span,
Expand All @@ -214,11 +216,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
vis: ast::Visibility::Public,
})));

match self.expand(krate_item).make_items().pop().unwrap().unwrap() {
ast::Item { attrs, node: ast::ItemKind::Mod(module), .. } => {
match self.expand(krate_item).make_items().pop().map(P::unwrap) {
Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => {
krate.attrs = attrs;
krate.module = module;
},
None => {
// Resolution failed so we return an empty expansion
krate.attrs = vec![];
krate.module = ast::Mod {
inner: orig_mod_span,
items: vec![],
};
},
_ => unreachable!(),
};

Expand Down
23 changes: 23 additions & 0 deletions src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// force-host
// no-prefer-dynamic

#![crate_type = "proc-macro"]
#![feature(proc_macro)]

extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn emit_unchanged(_args: TokenStream, input: TokenStream) -> TokenStream {
input
}
22 changes: 22 additions & 0 deletions src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:issue-41211.rs

// FIXME: https://github.com/rust-lang/rust/issues/41430
// This is a temporary regression test for the ICE reported in #41211

#![feature(proc_macro)]
#![emit_unchanged]
//~^ ERROR: cannot find attribute macro `emit_unchanged` in this scope
extern crate issue_41211;
use issue_41211::emit_unchanged;

fn main() {}
1 change: 0 additions & 1 deletion src/test/compile-fail/coercion-slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@ fn main() {
let _: &[i32] = [0];
//~^ ERROR mismatched types
//~| expected type `&[i32]`
//~| found type `[{integer}; 1]`
//~| expected &[i32], found array of 1 elements
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/cross-borrow-trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl Trait for Foo {}

pub fn main() {
let x: Box<Trait> = Box::new(Foo);
let _y: &Trait = x; //~ ERROR mismatched types
let _y: &Trait = x; //~ ERROR E0308
//~| expected type `&Trait`
//~| found type `std::boxed::Box<Trait>`
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-11374.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
fn main() {
let mut c = for_stdin();
let mut v = Vec::new();
c.read_to(v); //~ ERROR mismatched types
c.read_to(v); //~ ERROR E0308
}
1 change: 1 addition & 0 deletions src/test/compile-fail/issue-13058.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
fn main() {
check((3, 5));
//~^ ERROR mismatched types
//~| HELP try with `&(3, 5)`
}
1 change: 0 additions & 1 deletion src/test/ui/span/coerce-suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ fn main() {
//~| 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
Expand Down
14 changes: 5 additions & 9 deletions src/test/ui/span/coerce-suggestions.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ error[E0308]: mismatched types
|
= note: expected type `&str`
found type `std::string::String`
= help: here are some functions which might fulfill your needs:
- .as_str()
- .trim()
- .trim_left()
- .trim_right()
= help: try with `&String::new()`

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

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:36:11
--> $DIR/coerce-suggestions.rs:35:11
|
36 | test2(&y);
35 | test2(&y);
| ^^ types differ in mutability
|
= note: expected type `&mut i32`
found type `&std::string::String`

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:42:9
--> $DIR/coerce-suggestions.rs:41:9
|
42 | f = box f;
41 | f = box f;
| ^^^^^ cyclic type of infinite size
|
= note: expected type `_`
Expand Down
Loading

0 comments on commit ff13b7c

Please sign in to comment.