Auto merge of #33562 - GuillaumeGomez:rollup, r=steveklabnik

Rollup of 3 pull requests

- Successful merges: #33401, #33489, #33558
- Failed merges: #33342, #33475, #33517
This commit is contained in:
bors 2016-05-11 16:34:54 -07:00
commit 22ac88f1a4
12 changed files with 409 additions and 25 deletions

View File

@ -107,6 +107,20 @@
# #
# run `make nitty-gritty` # run `make nitty-gritty`
# #
# # Make command examples
#
# ## Docs linked commands
#
# * make check-stage1-rustdocck: Builds rustdoc. It has the advantage to compile
# quite quickly since we're only using stage1
# executables.
# * make doc/error-index.md: Gets all doc blocks from doc comments and error
# explanations to put them in a markdown file. You
# can then test them by running
# "rustdoc --test error-index.md".
#
# And of course, the wonderfully useful 'make tidy'! Always run it before opening a pull request to rust!
#
# </tips> # </tips>
# #
# <nitty-gritty> # <nitty-gritty>
@ -256,3 +270,9 @@ ifneq ($(strip $(findstring TAGS.emacs,$(MAKECMDGOALS)) \
CFG_INFO := $(info cfg: including ctags rules) CFG_INFO := $(info cfg: including ctags rules)
include $(CFG_SRC_DIR)mk/ctags.mk include $(CFG_SRC_DIR)mk/ctags.mk
endif endif
.DEFAULT:
@echo "\n======================================================"
@echo "== If you need help, run 'make help' or 'make tips' =="
@echo "======================================================\n"
exit 1

View File

@ -115,7 +115,7 @@ $ ls target/debug
build deps examples libphrases-a7448e02a0468eaa.rlib native build deps examples libphrases-a7448e02a0468eaa.rlib native
``` ```
`libphrases-hash.rlib` is the compiled crate. Before we see how to use this `libphrases-<hash>.rlib` is the compiled crate. Before we see how to use this
crate from another crate, lets break it up into multiple files. crate from another crate, lets break it up into multiple files.
# Multiple File Crates # Multiple File Crates

View File

@ -225,7 +225,7 @@ sense to put it into a function:
```rust ```rust
# fn find(_: &str, _: char) -> Option<usize> { None } # fn find(_: &str, _: char) -> Option<usize> { None }
// Returns the extension of the given file name, where the extension is defined // Returns the extension of the given file name, where the extension is defined
// as all characters proceeding the first `.`. // as all characters following the first `.`.
// If `file_name` has no `.`, then `None` is returned. // If `file_name` has no `.`, then `None` is returned.
fn extension_explicit(file_name: &str) -> Option<&str> { fn extension_explicit(file_name: &str) -> Option<&str> {
match find(file_name, '.') { match find(file_name, '.') {
@ -274,7 +274,7 @@ to get rid of the case analysis:
```rust ```rust
# fn find(_: &str, _: char) -> Option<usize> { None } # fn find(_: &str, _: char) -> Option<usize> { None }
// Returns the extension of the given file name, where the extension is defined // Returns the extension of the given file name, where the extension is defined
// as all characters proceeding the first `.`. // as all characters following the first `.`.
// If `file_name` has no `.`, then `None` is returned. // If `file_name` has no `.`, then `None` is returned.
fn extension(file_name: &str) -> Option<&str> { fn extension(file_name: &str) -> Option<&str> {
find(file_name, '.').map(|i| &file_name[i+1..]) find(file_name, '.').map(|i| &file_name[i+1..])

View File

@ -84,8 +84,8 @@ fn it_works() {
``` ```
`assert!` is a macro provided by Rust which takes one argument: if the argument `assert!` is a macro provided by Rust which takes one argument: if the argument
is `true`, nothing happens. If the argument is `false`, it `panic!`s. Let's run is `true`, nothing happens. If the argument is `false`, it will `panic!`. Let's
our tests again: run our tests again:
```bash ```bash
$ cargo test $ cargo test

View File

@ -43,6 +43,7 @@
// Since libcore defines many fundamental lang items, all tests live in a // Since libcore defines many fundamental lang items, all tests live in a
// separate crate, libcoretest, to avoid bizarre issues. // separate crate, libcoretest, to avoid bizarre issues.
#![cfg_attr(stage0, allow(unused_attributes))]
#![crate_name = "core"] #![crate_name = "core"]
#![stable(feature = "core", since = "1.6.0")] #![stable(feature = "core", since = "1.6.0")]
#![crate_type = "rlib"] #![crate_type = "rlib"]

View File

@ -523,6 +523,8 @@ impl<T> SliceExt for [T] {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[allow(unused_attributes)]
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
impl<T> ops::Index<usize> for [T] { impl<T> ops::Index<usize> for [T] {
type Output = T; type Output = T;
@ -533,6 +535,8 @@ impl<T> ops::Index<usize> for [T] {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[allow(unused_attributes)]
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
impl<T> ops::IndexMut<usize> for [T] { impl<T> ops::IndexMut<usize> for [T] {
#[inline] #[inline]
fn index_mut(&mut self, index: usize) -> &mut T { fn index_mut(&mut self, index: usize) -> &mut T {

View File

@ -167,7 +167,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
/// region that each late-bound region was replaced with. /// region that each late-bound region was replaced with.
pub type SkolemizationMap = FnvHashMap<ty::BoundRegion,ty::Region>; pub type SkolemizationMap = FnvHashMap<ty::BoundRegion, ty::Region>;
/// Why did we require that the two types be related? /// Why did we require that the two types be related?
/// ///

View File

@ -26,16 +26,17 @@ use super::{
use fmt_macros::{Parser, Piece, Position}; use fmt_macros::{Parser, Piece, Position};
use hir::def_id::DefId; use hir::def_id::DefId;
use infer::InferCtxt; use infer::{InferCtxt, TypeOrigin};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVariants};
use ty::fast_reject; use ty::fast_reject;
use ty::fold::{TypeFoldable, TypeFolder}; use ty::fold::TypeFolder;
use ty::subst::{self, ParamSpace, Subst};
use util::nodemap::{FnvHashMap, FnvHashSet}; use util::nodemap::{FnvHashMap, FnvHashSet};
use std::cmp; use std::cmp;
use std::fmt; use std::fmt;
use syntax::attr::{AttributeMethods, AttrMetaMethods};
use syntax::ast; use syntax::ast;
use syntax::attr::{AttributeMethods, AttrMetaMethods};
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::errors::DiagnosticBuilder; use syntax::errors::DiagnosticBuilder;
@ -60,6 +61,128 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
} }
} }
// Enum used to differentiate the "big" and "little" weights.
enum Weight {
Coarse,
Precise,
}
trait AssociatedWeight {
fn get_weight(&self) -> (u32, u32);
}
impl<'a> AssociatedWeight for TypeVariants<'a> {
// Left number is for "global"/"big" weight and right number is for better precision.
fn get_weight(&self) -> (u32, u32) {
match *self {
TypeVariants::TyBool => (1, 1),
TypeVariants::TyChar => (1, 2),
TypeVariants::TyStr => (1, 3),
TypeVariants::TyInt(_) => (2, 1),
TypeVariants::TyUint(_) => (2, 2),
TypeVariants::TyFloat(_) => (2, 3),
TypeVariants::TyRawPtr(_) => (2, 4),
TypeVariants::TyEnum(_, _) => (3, 1),
TypeVariants::TyStruct(_, _) => (3, 2),
TypeVariants::TyBox(_) => (3, 3),
TypeVariants::TyTuple(_) => (3, 4),
TypeVariants::TyArray(_, _) => (4, 1),
TypeVariants::TySlice(_) => (4, 2),
TypeVariants::TyRef(_, _) => (5, 1),
TypeVariants::TyFnDef(_, _, _) => (5, 2),
TypeVariants::TyFnPtr(_) => (5, 3),
TypeVariants::TyTrait(_) => (6, 1),
TypeVariants::TyClosure(_, _) => (7, 1),
TypeVariants::TyProjection(_) => (8, 1),
TypeVariants::TyParam(_) => (8, 2),
TypeVariants::TyInfer(_) => (8, 3),
TypeVariants::TyError => (9, 1),
}
}
}
// The "closer" the types are, the lesser the weight.
fn get_weight_diff(a: &ty::TypeVariants, b: &TypeVariants, weight: Weight) -> u32 {
let (w1, w2) = match weight {
Weight::Coarse => (a.get_weight().0, b.get_weight().0),
Weight::Precise => (a.get_weight().1, b.get_weight().1),
};
if w1 < w2 {
w2 - w1
} else {
w1 - w2
}
}
// Once we have "globally matching" types, we need to run another filter on them.
//
// In the function `get_best_matching_type`, we got the types which might fit the
// most to the type we're looking for. This second filter now intends to get (if
// possible) the type which fits the most.
//
// For example, the trait expects an `usize` and here you have `u32` and `i32`.
// Obviously, the "correct" one is `u32`.
fn filter_matching_types<'tcx>(weights: &[(usize, u32)],
imps: &[(DefId, subst::Substs<'tcx>)],
trait_types: &[ty::Ty<'tcx>])
-> usize {
let matching_weight = weights[0].1;
let iter = weights.iter().filter(|&&(_, weight)| weight == matching_weight);
let mut filtered_weights = vec!();
for &(pos, _) in iter {
let mut weight = 0;
for (type_to_compare, original_type) in imps[pos].1
.types
.get_slice(ParamSpace::TypeSpace)
.iter()
.zip(trait_types.iter()) {
weight += get_weight_diff(&type_to_compare.sty, &original_type.sty, Weight::Precise);
}
filtered_weights.push((pos, weight));
}
filtered_weights.sort_by(|a, b| a.1.cmp(&b.1));
filtered_weights[0].0
}
// Here, we run the "big" filter. Little example:
//
// We receive a `String`, an `u32` and an `i32`.
// The trait expected an `usize`.
// From human point of view, it's easy to determine that `String` doesn't correspond to
// the expected type at all whereas `u32` and `i32` could.
//
// This first filter intends to only keep the types which match the most.
fn get_best_matching_type<'tcx>(imps: &[(DefId, subst::Substs<'tcx>)],
trait_types: &[ty::Ty<'tcx>]) -> usize {
let mut weights = vec!();
for (pos, imp) in imps.iter().enumerate() {
let mut weight = 0;
for (type_to_compare, original_type) in imp.1
.types
.get_slice(ParamSpace::TypeSpace)
.iter()
.zip(trait_types.iter()) {
weight += get_weight_diff(&type_to_compare.sty, &original_type.sty, Weight::Coarse);
}
weights.push((pos, weight));
}
weights.sort_by(|a, b| a.1.cmp(&b.1));
if weights[0].1 == weights[1].1 {
filter_matching_types(&weights, &imps, trait_types)
} else {
weights[0].0
}
}
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) { pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) {
for error in errors { for error in errors {
@ -126,16 +249,101 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
} }
fn impl_substs(&self,
did: DefId,
obligation: PredicateObligation<'tcx>)
-> subst::Substs<'tcx> {
let tcx = self.tcx;
let ity = tcx.lookup_item_type(did);
let (tps, rps, _) =
(ity.generics.types.get_slice(subst::TypeSpace),
ity.generics.regions.get_slice(subst::TypeSpace),
ity.ty);
let rps = self.region_vars_for_defs(obligation.cause.span, rps);
let mut substs = subst::Substs::new(
subst::VecPerParamSpace::empty(),
subst::VecPerParamSpace::new(rps, Vec::new(), Vec::new()));
self.type_vars_for_defs(obligation.cause.span,
subst::ParamSpace::TypeSpace,
&mut substs,
tps);
substs
}
fn get_current_failing_impl(&self,
trait_ref: &TraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>)
-> Option<(DefId, subst::Substs<'tcx>)> {
let simp = fast_reject::simplify_type(self.tcx,
trait_ref.self_ty(),
true);
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
match simp {
Some(_) => {
let mut matching_impls = Vec::new();
trait_def.for_each_impl(self.tcx, |def_id| {
let imp = self.tcx.impl_trait_ref(def_id).unwrap();
let substs = self.impl_substs(def_id, obligation.clone());
let imp = imp.subst(self.tcx, &substs);
if self.eq_types(true,
TypeOrigin::Misc(obligation.cause.span),
trait_ref.self_ty(),
imp.self_ty()).is_ok() {
matching_impls.push((def_id, imp.substs.clone()));
}
});
if matching_impls.len() == 0 {
None
} else if matching_impls.len() == 1 {
Some(matching_impls[0].clone())
} else {
let end = trait_ref.input_types().len() - 1;
// we need to determine which type is the good one!
Some(matching_impls[get_best_matching_type(&matching_impls,
&trait_ref.input_types()[0..end])]
.clone())
}
},
None => None,
}
}
fn find_attr(&self,
def_id: DefId,
attr_name: &str)
-> Option<ast::Attribute> {
for item in self.tcx.get_attrs(def_id).iter() {
if item.check_name(attr_name) {
return Some(item.clone());
}
}
None
}
fn on_unimplemented_note(&self, fn on_unimplemented_note(&self,
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
span: Span) -> Option<String> { obligation: &PredicateObligation<'tcx>) -> Option<String> {
let trait_ref = trait_ref.skip_binder(); let trait_ref = trait_ref.skip_binder();
let def_id = trait_ref.def_id; let def_id = match self.get_current_failing_impl(trait_ref, obligation) {
Some((def_id, _)) => {
if let Some(_) = self.find_attr(def_id, "rustc_on_unimplemented") {
def_id
} else {
trait_ref.def_id
}
},
None => trait_ref.def_id,
};
let span = obligation.cause.span;
let mut report = None; let mut report = None;
for item in self.tcx.get_attrs(def_id).iter() { for item in self.tcx.get_attrs(def_id).iter() {
if item.check_name("rustc_on_unimplemented") { if item.check_name("rustc_on_unimplemented") {
let err_sp = item.meta().span.substitute_dummy(span); let err_sp = item.meta().span.substitute_dummy(span);
let def = self.tcx.lookup_trait_def(def_id); let def = self.tcx.lookup_trait_def(trait_ref.def_id);
let trait_str = def.trait_ref.to_string(); let trait_str = def.trait_ref.to_string();
if let Some(ref istring) = item.value_str() { if let Some(ref istring) = item.value_str() {
let mut generic_map = def.generics.types.iter_enumerated() let mut generic_map = def.generics.types.iter_enumerated()
@ -195,6 +403,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
report report
} }
fn find_similar_impl_candidates(&self,
trait_ref: ty::PolyTraitRef<'tcx>)
-> Vec<ty::TraitRef<'tcx>>
{
let simp = fast_reject::simplify_type(self.tcx,
trait_ref.skip_binder().self_ty(),
true);
let mut impl_candidates = Vec::new();
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id());
match simp {
Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| {
let imp = self.tcx.impl_trait_ref(def_id).unwrap();
let imp_simp = fast_reject::simplify_type(self.tcx,
imp.self_ty(),
true);
if let Some(imp_simp) = imp_simp {
if simp != imp_simp {
return;
}
}
impl_candidates.push(imp);
}),
None => trait_def.for_each_impl(self.tcx, |def_id| {
impl_candidates.push(
self.tcx.impl_trait_ref(def_id).unwrap());
})
};
impl_candidates
}
fn report_similar_impl_candidates(&self, fn report_similar_impl_candidates(&self,
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
err: &mut DiagnosticBuilder) err: &mut DiagnosticBuilder)
@ -425,8 +664,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// Try to report a help message // Try to report a help message
if !trait_ref.has_infer_types() && if !trait_ref.has_infer_types() &&
self.predicate_can_apply(trait_ref) self.predicate_can_apply(trait_ref) {
{
// If a where-clause may be useful, remind the // If a where-clause may be useful, remind the
// user that they can add it. // user that they can add it.
// //
@ -435,22 +673,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// "the type `T` can't be frobnicated" // "the type `T` can't be frobnicated"
// which is somewhat confusing. // which is somewhat confusing.
err.help(&format!("consider adding a `where {}` bound", err.help(&format!("consider adding a `where {}` bound",
trait_ref.to_predicate() trait_ref.to_predicate()));
)); } else if let Some(s) = self.on_unimplemented_note(trait_ref,
} else if let Some(s) = obligation) {
self.on_unimplemented_note(trait_ref, span) { // If it has a custom "#[rustc_on_unimplemented]"
// Otherwise, if there is an on-unimplemented note, // error message, let's display it!
// display it.
err.note(&s); err.note(&s);
} else { } else {
// If we can't show anything useful, try to find // If we can't show anything useful, try to find
// similar impls. // similar impls.
let impl_candidates =
self.report_similar_impl_candidates(trait_ref, &mut err); self.find_similar_impl_candidates(trait_ref);
if impl_candidates.len() > 0 {
self.report_similar_impl_candidates(trait_ref, &mut err);
}
} }
err err
} }
}, }
ty::Predicate::Equate(ref predicate) => { ty::Predicate::Equate(ref predicate) => {
let predicate = self.resolve_type_vars_if_possible(predicate); let predicate = self.resolve_type_vars_if_possible(predicate);
let err = self.equality_predicate(span, let err = self.equality_predicate(span,

View File

@ -136,7 +136,6 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
} }
impl<'tcx> Encodable for Substs<'tcx> { impl<'tcx> Encodable for Substs<'tcx> {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
cstore::tls::with_encoding_context(s, |ecx, rbml_w| { cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
ecx.encode_substs(rbml_w, self); ecx.encode_substs(rbml_w, self);

View File

@ -0,0 +1,35 @@
// 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 <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.
// Test if the on_unimplemented message override works
#![feature(on_unimplemented)]
#![feature(rustc_attrs)]
#[rustc_on_unimplemented = "invalid"]
trait Index<Idx: ?Sized> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
impl Index<usize> for [i32] {
type Output = i32;
fn index(&self, index: usize) -> &i32 {
&self[index]
}
}
#[rustc_error]
fn main() {
Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); //~ ERROR E0277
//~| NOTE a usize is required
//~| NOTE required by
}

View File

@ -0,0 +1,20 @@
// 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 <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.
// Test new Index error message for slices
#![feature(rustc_attrs)]
#[rustc_error]
fn main() {
let x = &[1, 2, 3] as &[i32];
x[1i32]; //~ ERROR E0277
//~| NOTE a usize is required
}

View File

@ -0,0 +1,64 @@
// 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 <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.
// Test if the on_unimplemented message override works
#![feature(on_unimplemented)]
#![feature(rustc_attrs)]
#[rustc_on_unimplemented = "invalid"]
trait Index<Idx: ?Sized> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
#[rustc_on_unimplemented = "a isize is required to index into a slice"]
impl Index<isize> for [i32] {
type Output = i32;
fn index(&self, index: isize) -> &i32 {
&self[index as usize]
}
}
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
impl Index<usize> for [i32] {
type Output = i32;
fn index(&self, index: usize) -> &i32 {
&self[index]
}
}
trait Foo<A, B> {
fn f(&self, a: &A, b: &B);
}
#[rustc_on_unimplemented = "two i32 Foo trait takes"]
impl Foo<i32, i32> for [i32] {
fn f(&self, a: &i32, b: &i32) {}
}
#[rustc_on_unimplemented = "two u32 Foo trait takes"]
impl Foo<u32, u32> for [i32] {
fn f(&self, a: &u32, b: &u32) {}
}
#[rustc_error]
fn main() {
Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); //~ ERROR E0277
//~| NOTE a usize is required
//~| NOTE required by
Index::<i32>::index(&[1, 2, 3] as &[i32], 2i32); //~ ERROR E0277
//~| NOTE a isize is required
//~| NOTE required by
Foo::<usize, usize>::f(&[1, 2, 3] as &[i32], &2usize, &2usize); //~ ERROR E0277
//~| NOTE two u32 Foo trait
//~| NOTE required by
}