Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 4 pull requests #41459

Merged
merged 11 commits into from
Apr 22, 2017
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