let dst_src = dst.join("rust");
t!(fs::create_dir_all(&dst_src));
+ let src_files = [
+ "src/Cargo.lock",
+ ];
// This is the reduced set of paths which will become the rust-src component
// (essentially libstd and all of its path dependencies)
let std_src_dirs = [
];
copy_src_dirs(build, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
+ for file in src_files.iter() {
+ copy(&build.src.join(file), &dst_src.join(file));
+ }
// Create source tarball in rust-installer format
let mut cmd = rust_installer(builder);
let build = builder.build;
let target = self.target;
- builder.ensure(compile::Rustc {
- compiler: builder.compiler(0, build.build),
- target,
- });
-
println!("Documenting error index ({})", target);
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
None => {
// No subcommand -- show the general usage and subcommand help
println!("{}\n", subcommand_help);
- process::exit(0);
+ process::exit(1);
}
};
extern crate serde_derive;
#[macro_use]
extern crate lazy_static;
-extern crate serde;
extern crate serde_json;
extern crate cmake;
extern crate filetime;
fn force_use_stage1(&self, compiler: Compiler, target: Interned<String>) -> bool {
!self.config.full_bootstrap &&
compiler.stage >= 2 &&
- self.hosts.iter().any(|h| *h == target)
+ (self.hosts.iter().any(|h| *h == target) || target == self.build)
}
/// Returns the directory that OpenSSL artifacts are compiled into if
Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd;
CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd;
Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
- BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Librustc;
+ BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Libstd;
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
);
// decode last 1 or 2 chars
if n < 10 {
curr -= 1;
- *buf_ptr.offset(curr) = (n as u8) + 48;
+ *buf_ptr.offset(curr) = (n as u8) + b'0';
} else {
let d1 = n << 1;
curr -= 2;
/// on MSVC it's `*mut [usize; 2]`. For more information see the compiler's
/// source as well as std's catch implementation.
pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32;
+
+ /// Computes the byte offset that needs to be applied to `ptr` in order to
+ /// make it aligned to `align`.
+ /// If it is not possible to align `ptr`, the implementation returns
+ /// `usize::max_value()`.
+ ///
+ /// There are no guarantees whatsover that offsetting the pointer will not
+ /// overflow or go beyond the allocation that `ptr` points into.
+ /// It is up to the caller to ensure that the returned offset is correct
+ /// in all terms other than alignment.
+ ///
+ /// # Examples
+ ///
+ /// Accessing adjacent `u8` as `u16`
+ ///
+ /// ```
+ /// # #![feature(core_intrinsics)]
+ /// # fn foo(n: usize) {
+ /// # use std::intrinsics::align_offset;
+ /// # use std::mem::align_of;
+ /// # unsafe {
+ /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
+ /// let ptr = &x[n] as *const u8;
+ /// let offset = align_offset(ptr as *const (), align_of::<u16>());
+ /// if offset < x.len() - n - 1 {
+ /// let u16_ptr = ptr.offset(offset as isize) as *const u16;
+ /// assert_ne!(*u16_ptr, 500);
+ /// } else {
+ /// // while the pointer can be aligned via `offset`, it would point
+ /// // outside the allocation
+ /// }
+ /// # } }
+ /// ```
+ #[cfg(not(stage0))]
+ pub fn align_offset(ptr: *const (), align: usize) -> usize;
+}
+
+#[cfg(stage0)]
+/// Computes the byte offset that needs to be applied to `ptr` in order to
+/// make it aligned to `align`.
+/// If it is not possible to align `ptr`, the implementation returns
+/// `usize::max_value()`.
+///
+/// There are no guarantees whatsover that offsetting the pointer will not
+/// overflow or go beyond the allocation that `ptr` points into.
+/// It is up to the caller to ensure that the returned offset is correct
+/// in all terms other than alignment.
+///
+/// # Examples
+///
+/// Accessing adjacent `u8` as `u16`
+///
+/// ```
+/// # #![feature(core_intrinsics)]
+/// # fn foo(n: usize) {
+/// # use std::intrinsics::align_offset;
+/// # use std::mem::align_of;
+/// # unsafe {
+/// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
+/// let ptr = &x[n] as *const u8;
+/// let offset = align_offset(ptr as *const (), align_of::<u16>());
+/// if offset < x.len() - n - 1 {
+/// let u16_ptr = ptr.offset(offset as isize) as *const u16;
+/// assert_ne!(*u16_ptr, 500);
+/// } else {
+/// // while the pointer can be aligned via `offset`, it would point
+/// // outside the allocation
+/// }
+/// # } }
+/// ```
+pub unsafe fn align_offset(ptr: *const (), align: usize) -> usize {
+ let offset = ptr as usize % align;
+ if offset == 0 {
+ 0
+ } else {
+ align - offset
+ }
}
}
}
+impl<'a, T: Clone> Option<&'a mut T> {
+ /// Maps an `Option<&mut T>` to an `Option<T>` by cloning the contents of the
+ /// option.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(option_ref_mut_cloned)]
+ /// let mut x = 12;
+ /// let opt_x = Some(&mut x);
+ /// assert_eq!(opt_x, Some(&mut 12));
+ /// let cloned = opt_x.cloned();
+ /// assert_eq!(cloned, Some(12));
+ /// ```
+ #[unstable(feature = "option_ref_mut_cloned", issue = "43738")]
+ pub fn cloned(self) -> Option<T> {
+ self.map(|t| t.clone())
+ }
+}
+
impl<T: Default> Option<T> {
/// Returns the contained value or a default
///
use iter::{Map, Cloned, FusedIterator};
use slice::{self, SliceIndex};
use mem;
+use intrinsics::align_offset;
pub mod pattern;
// When the pointer is aligned, read 2 words of data per iteration
// until we find a word containing a non-ascii byte.
let ptr = v.as_ptr();
- let align = (ptr as usize + index) & (usize_bytes - 1);
+ let align = unsafe {
+ // the offset is safe, because `index` is guaranteed inbounds
+ align_offset(ptr.offset(index as isize) as *const (), usize_bytes)
+ };
if align == 0 {
while index < blocks_end {
unsafe {
//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
//! on what type that type variable is ultimately assigned, the match may or may not succeed.
//!
+//! To handle closures, freshened types also have to contain the signature and kind of any
+//! closure in the local inference context, as otherwise the cache key might be invalidated.
+//! The way this is done is somewhat hacky - the closure signature is appended to the substs,
+//! as well as the closure kind "encoded" as a type. Also, special handling is needed when
+//! the closure signature contains a reference to the original closure.
+//!
//! Note that you should be careful not to allow the output of freshening to leak to the user in
//! error messages or in any other form. Freshening is only really useful as an internal detail.
//!
-//! __An important detail concerning regions.__ The freshener also replaces *all* regions with
+//! Because of the manipulation required to handle closures, doing arbitrary operations on
+//! freshened types is not recommended. However, in addition to doing equality/hash
+//! comparisons (for caching), it is possible to do a `ty::_match` operation between
+//! 2 freshened types - this works even with the closure encoding.
+//!
+//! __An important detail concerning regions.__ The freshener also replaces *all* free regions with
//! 'erased. The reason behind this is that, in general, we do not take region relationships into
//! account when making type-overloaded decisions. This is important because of the design of the
//! region inferencer, which is not based on unification but rather on accumulating and then
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeFolder;
+use ty::subst::Substs;
use util::nodemap::FxHashMap;
+use hir::def_id::DefId;
+
use std::collections::hash_map::Entry;
use super::InferCtxt;
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
freshen_count: u32,
freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
+ closure_set: Vec<DefId>,
}
impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
infcx,
freshen_count: 0,
freshen_map: FxHashMap(),
+ closure_set: vec![],
}
}
}
}
}
+
+ fn next_fresh<F>(&mut self,
+ freshener: F)
+ -> Ty<'tcx>
+ where F: FnOnce(u32) -> ty::InferTy,
+ {
+ let index = self.freshen_count;
+ self.freshen_count += 1;
+ self.infcx.tcx.mk_infer(freshener(index))
+ }
+
+ fn freshen_closure_like<M, C>(&mut self,
+ def_id: DefId,
+ substs: ty::ClosureSubsts<'tcx>,
+ t: Ty<'tcx>,
+ markers: M,
+ combine: C)
+ -> Ty<'tcx>
+ where M: FnOnce(&mut Self) -> (Ty<'tcx>, Ty<'tcx>),
+ C: FnOnce(&'tcx Substs<'tcx>) -> Ty<'tcx>
+ {
+ let tcx = self.infcx.tcx;
+
+ let closure_in_progress = self.infcx.in_progress_tables.map_or(false, |tables| {
+ tcx.hir.as_local_node_id(def_id).map_or(false, |closure_id| {
+ tables.borrow().local_id_root ==
+ Some(DefId::local(tcx.hir.node_to_hir_id(closure_id).owner))
+ })
+ });
+
+ if !closure_in_progress {
+ // If this closure belongs to another infcx, its kind etc. were
+ // fully inferred and its signature/kind are exactly what's listed
+ // in its infcx. So we don't need to add the markers for them.
+ return t.super_fold_with(self);
+ }
+
+ // We are encoding a closure in progress. Because we want our freshening
+ // key to contain all inference information needed to make sense of our
+ // value, we need to encode the closure signature and kind. The way
+ // we do that is to add them as 2 variables to the closure substs,
+ // basically because it's there (and nobody cares about adding extra stuff
+ // to substs).
+ //
+ // This means the "freshened" closure substs ends up looking like
+ // fresh_substs = [PARENT_SUBSTS* ; UPVARS* ; SIG_MARKER ; KIND_MARKER]
+ let (marker_1, marker_2) = if self.closure_set.contains(&def_id) {
+ // We found the closure def-id within its own signature. Just
+ // leave a new freshened type - any matching operations would
+ // have found and compared the exterior closure already to
+ // get here.
+ //
+ // In that case, we already know what the signature would
+ // be - the parent closure on the stack already contains a
+ // "copy" of the signature, so there is no reason to encode
+ // it again for injectivity. Just use a fresh type variable
+ // to make everything comparable.
+ //
+ // For example (closure kinds omitted for clarity)
+ // t=[closure FOO sig=[closure BAR sig=[closure FOO ..]]]
+ // Would get encoded to
+ // t=[closure FOO sig=[closure BAR sig=[closure FOO sig=$0]]]
+ //
+ // and we can decode by having
+ // $0=[closure BAR {sig doesn't exist in decode}]
+ // and get
+ // t=[closure FOO]
+ // sig[FOO] = [closure BAR]
+ // sig[BAR] = [closure FOO]
+ (self.next_fresh(ty::FreshTy), self.next_fresh(ty::FreshTy))
+ } else {
+ self.closure_set.push(def_id);
+ let markers = markers(self);
+ self.closure_set.pop();
+ markers
+ };
+
+ combine(tcx.mk_substs(
+ substs.substs.iter().map(|k| k.fold_with(self)).chain(
+ [marker_1, marker_2].iter().cloned().map(From::from)
+ )))
+ }
}
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.needs_infer() && !t.has_erasable_regions() {
+ if !t.needs_infer() && !t.has_erasable_regions() &&
+ !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) {
return t;
}
t
}
+ ty::TyClosure(def_id, substs) => {
+ self.freshen_closure_like(
+ def_id, substs, t,
+ |this| {
+ // HACK: use a "random" integer type to mark the kind. Because
+ // different closure kinds shouldn't get unified during
+ // selection, the "subtyping" relationship (where any kind is
+ // better than no kind) shouldn't matter here, just that the
+ // types are different.
+ let closure_kind = this.infcx.closure_kind(def_id);
+ let closure_kind_marker = match closure_kind {
+ None => tcx.types.i8,
+ Some(ty::ClosureKind::Fn) => tcx.types.i16,
+ Some(ty::ClosureKind::FnMut) => tcx.types.i32,
+ Some(ty::ClosureKind::FnOnce) => tcx.types.i64,
+ };
+
+ let closure_sig = this.infcx.fn_sig(def_id);
+ (tcx.mk_fn_ptr(closure_sig.fold_with(this)),
+ closure_kind_marker)
+ },
+ |substs| tcx.mk_closure(def_id, substs)
+ )
+ }
+
+ ty::TyGenerator(def_id, substs, interior) => {
+ self.freshen_closure_like(
+ def_id, substs, t,
+ |this| {
+ let gen_sig = this.infcx.generator_sig(def_id).unwrap();
+ // FIXME: want to revise this strategy when generator
+ // signatures can actually contain LBRs.
+ let sig = this.tcx().no_late_bound_regions(&gen_sig)
+ .unwrap_or_else(|| {
+ bug!("late-bound regions in signature of {:?}",
+ def_id)
+ });
+ (sig.yield_ty, sig.return_ty).fold_with(this)
+ },
+ |substs| {
+ tcx.mk_generator(def_id, ty::ClosureSubsts { substs }, interior)
+ }
+ )
+ }
+
ty::TyBool |
ty::TyChar |
ty::TyInt(..) |
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyDynamic(..) |
- ty::TyClosure(..) |
- ty::TyGenerator(..) |
ty::TyNever |
ty::TyTuple(..) |
ty::TyProjection(..) |
ProjectionCandidate,
/// Implementation of a `Fn`-family trait by one of the anonymous types
- /// generated for a `||` expression. The ty::ClosureKind informs the
- /// confirmation step what ClosureKind obligation to emit.
- ClosureCandidate(/* closure */ DefId, ty::ClosureSubsts<'tcx>, ty::ClosureKind),
+ /// generated for a `||` expression.
+ ClosureCandidate,
/// Implementation of a `Generator` trait by one of the anonymous types
/// generated for a generator.
- GeneratorCandidate(/* function / closure */ DefId, ty::ClosureSubsts<'tcx>),
+ GeneratorCandidate,
/// Implementation of a `Fn`-family trait by one of the anonymous
/// types generated for a fn pointer type (e.g., `fn(int)->int`)
ObjectCandidate => ObjectCandidate,
BuiltinObjectCandidate => BuiltinObjectCandidate,
BuiltinUnsizeCandidate => BuiltinUnsizeCandidate,
+ ClosureCandidate => ClosureCandidate,
+ GeneratorCandidate => GeneratorCandidate,
ParamCandidate(ref trait_ref) => {
return tcx.lift(trait_ref).map(ParamCandidate);
}
- GeneratorCandidate(def_id, ref substs) => {
- return tcx.lift(substs).map(|substs| {
- GeneratorCandidate(def_id, substs)
- });
- }
- ClosureCandidate(def_id, ref substs, kind) => {
- return tcx.lift(substs).map(|substs| {
- ClosureCandidate(def_id, substs, kind)
- });
- }
})
}
}
dep_node: DepNodeIndex,
result: EvaluationResult)
{
- // Avoid caching results that depend on more than just the trait-ref:
- // The stack can create recursion, and closure signatures
- // being yet uninferred can create "spurious" EvaluatedToAmbig
- // and EvaluatedToOk.
- if result.is_stack_dependent() ||
- ((result == EvaluatedToAmbig || result == EvaluatedToOk)
- && trait_ref.has_closure_types())
- {
+ // Avoid caching results that depend on more than just the trait-ref
+ // - the stack can create recursion.
+ if result.is_stack_dependent() {
return;
}
this.candidate_from_obligation_no_cache(stack)
});
- if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) {
- debug!("CACHE MISS: SELECT({:?})={:?}",
- cache_fresh_trait_pred, candidate);
- self.insert_candidate_cache(stack.obligation.param_env,
- cache_fresh_trait_pred,
- dep_node,
- candidate.clone());
- }
-
+ debug!("CACHE MISS: SELECT({:?})={:?}",
+ cache_fresh_trait_pred, candidate);
+ self.insert_candidate_cache(stack.obligation.param_env,
+ cache_fresh_trait_pred,
+ dep_node,
+ candidate.clone());
candidate
}
.insert(trait_ref, WithDepNode::new(dep_node, candidate));
}
- fn should_update_candidate_cache(&mut self,
- cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>,
- candidate: &SelectionResult<'tcx, SelectionCandidate<'tcx>>)
- -> bool
- {
- // In general, it's a good idea to cache results, even
- // ambiguous ones, to save us some trouble later. But we have
- // to be careful not to cache results that could be
- // invalidated later by advances in inference. Normally, this
- // is not an issue, because any inference variables whose
- // types are not yet bound are "freshened" in the cache key,
- // which means that if we later get the same request once that
- // type variable IS bound, we'll have a different cache key.
- // For example, if we have `Vec<_#0t> : Foo`, and `_#0t` is
- // not yet known, we may cache the result as `None`. But if
- // later `_#0t` is bound to `Bar`, then when we freshen we'll
- // have `Vec<Bar> : Foo` as the cache key.
- //
- // HOWEVER, it CAN happen that we get an ambiguity result in
- // one particular case around closures where the cache key
- // would not change. That is when the precise types of the
- // upvars that a closure references have not yet been figured
- // out (i.e., because it is not yet known if they are captured
- // by ref, and if by ref, what kind of ref). In these cases,
- // when matching a builtin bound, we will yield back an
- // ambiguous result. But the *cache key* is just the closure type,
- // it doesn't capture the state of the upvar computation.
- //
- // To avoid this trap, just don't cache ambiguous results if
- // the self-type contains no inference byproducts (that really
- // shouldn't happen in other circumstances anyway, given
- // coherence).
-
- match *candidate {
- Ok(Some(_)) | Err(_) => true,
- Ok(None) => cache_fresh_trait_pred.has_infer_types()
- }
- }
-
fn assemble_candidates<'o>(&mut self,
stack: &TraitObligationStack<'o, 'tcx>)
-> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>>
// touch bound regions, they just capture the in-scope
// type/region parameters
let self_ty = *obligation.self_ty().skip_binder();
- let (closure_def_id, substs) = match self_ty.sty {
- ty::TyGenerator(id, substs, _) => (id, substs),
+ match self_ty.sty {
+ ty::TyGenerator(..) => {
+ debug!("assemble_generator_candidates: self_ty={:?} obligation={:?}",
+ self_ty,
+ obligation);
+
+ candidates.vec.push(GeneratorCandidate);
+ Ok(())
+ }
ty::TyInfer(ty::TyVar(_)) => {
debug!("assemble_generator_candidates: ambiguous self-type");
candidates.ambiguous = true;
return Ok(());
}
_ => { return Ok(()); }
- };
-
- debug!("assemble_generator_candidates: self_ty={:?} obligation={:?}",
- self_ty,
- obligation);
-
- candidates.vec.push(GeneratorCandidate(closure_def_id, substs));
-
- Ok(())
+ }
}
/// Check for the artificial impl that the compiler will create for an obligation like `X :
// ok to skip binder because the substs on closure types never
// touch bound regions, they just capture the in-scope
// type/region parameters
- let self_ty = *obligation.self_ty().skip_binder();
- let (closure_def_id, substs) = match self_ty.sty {
- ty::TyClosure(id, substs) => (id, substs),
+ match obligation.self_ty().skip_binder().sty {
+ ty::TyClosure(closure_def_id, _) => {
+ debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}",
+ kind, obligation);
+ match self.infcx.closure_kind(closure_def_id) {
+ Some(closure_kind) => {
+ debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
+ if closure_kind.extends(kind) {
+ candidates.vec.push(ClosureCandidate);
+ }
+ }
+ None => {
+ debug!("assemble_unboxed_candidates: closure_kind not yet known");
+ candidates.vec.push(ClosureCandidate);
+ }
+ };
+ Ok(())
+ }
ty::TyInfer(ty::TyVar(_)) => {
debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
candidates.ambiguous = true;
return Ok(());
}
_ => { return Ok(()); }
- };
-
- debug!("assemble_unboxed_candidates: self_ty={:?} kind={:?} obligation={:?}",
- self_ty,
- kind,
- obligation);
-
- match self.infcx.closure_kind(closure_def_id) {
- Some(closure_kind) => {
- debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
- if closure_kind.extends(kind) {
- candidates.vec.push(ClosureCandidate(closure_def_id, substs, kind));
- }
- }
- None => {
- debug!("assemble_unboxed_candidates: closure_kind not yet known");
- candidates.vec.push(ClosureCandidate(closure_def_id, substs, kind));
- }
}
-
- Ok(())
}
/// Implement one of the `Fn()` family for a fn pointer.
when there are other valid candidates");
}
ImplCandidate(..) |
- ClosureCandidate(..) |
- GeneratorCandidate(..) |
+ ClosureCandidate |
+ GeneratorCandidate |
FnPointerCandidate |
BuiltinObjectCandidate |
BuiltinUnsizeCandidate |
Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id)))
}
- ClosureCandidate(closure_def_id, substs, kind) => {
- let vtable_closure =
- self.confirm_closure_candidate(obligation, closure_def_id, substs, kind)?;
+ ClosureCandidate => {
+ let vtable_closure = self.confirm_closure_candidate(obligation)?;
Ok(VtableClosure(vtable_closure))
}
- GeneratorCandidate(closure_def_id, substs) => {
- let vtable_generator =
- self.confirm_generator_candidate(obligation, closure_def_id, substs)?;
+ GeneratorCandidate => {
+ let vtable_generator = self.confirm_generator_candidate(obligation)?;
Ok(VtableGenerator(vtable_generator))
}
}
fn confirm_generator_candidate(&mut self,
- obligation: &TraitObligation<'tcx>,
- closure_def_id: DefId,
- substs: ty::ClosureSubsts<'tcx>)
- -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>,
+ obligation: &TraitObligation<'tcx>)
+ -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>,
SelectionError<'tcx>>
{
+ // ok to skip binder because the substs on generator types never
+ // touch bound regions, they just capture the in-scope
+ // type/region parameters
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+ let (closure_def_id, substs) = match self_ty.sty {
+ ty::TyGenerator(id, substs, _) => (id, substs),
+ _ => bug!("closure candidate for non-closure {:?}", obligation)
+ };
+
debug!("confirm_generator_candidate({:?},{:?},{:?})",
obligation,
closure_def_id,
substs);
+ let trait_ref =
+ self.generator_trait_ref_unnormalized(obligation, closure_def_id, substs);
let Normalized {
value: trait_ref,
obligations
- } = self.generator_trait_ref(obligation, closure_def_id, substs);
+ } = normalize_with_depth(self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth+1,
+ &trait_ref);
debug!("confirm_generator_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
closure_def_id,
}
fn confirm_closure_candidate(&mut self,
- obligation: &TraitObligation<'tcx>,
- closure_def_id: DefId,
- substs: ty::ClosureSubsts<'tcx>,
- kind: ty::ClosureKind)
+ obligation: &TraitObligation<'tcx>)
-> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
SelectionError<'tcx>>
{
- debug!("confirm_closure_candidate({:?},{:?},{:?})",
- obligation,
- closure_def_id,
- substs);
+ debug!("confirm_closure_candidate({:?})", obligation);
+ let kind = match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
+ Some(k) => k,
+ None => bug!("closure candidate for non-fn trait {:?}", obligation)
+ };
+
+ // ok to skip binder because the substs on closure types never
+ // touch bound regions, they just capture the in-scope
+ // type/region parameters
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+ let (closure_def_id, substs) = match self_ty.sty {
+ ty::TyClosure(id, substs) => (id, substs),
+ _ => bug!("closure candidate for non-closure {:?}", obligation)
+ };
+
+ let trait_ref =
+ self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs);
let Normalized {
value: trait_ref,
mut obligations
- } = self.closure_trait_ref(obligation, closure_def_id, substs);
+ } = normalize_with_depth(self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth+1,
+ &trait_ref);
debug!("confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
closure_def_id,
ty::Binder(trait_ref)
}
- fn closure_trait_ref(&mut self,
- obligation: &TraitObligation<'tcx>,
- closure_def_id: DefId,
- substs: ty::ClosureSubsts<'tcx>)
- -> Normalized<'tcx, ty::PolyTraitRef<'tcx>>
- {
- let trait_ref = self.closure_trait_ref_unnormalized(
- obligation, closure_def_id, substs);
-
- // A closure signature can contain associated types which
- // must be normalized.
- normalize_with_depth(self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth+1,
- &trait_ref)
- }
-
fn generator_trait_ref_unnormalized(&mut self,
obligation: &TraitObligation<'tcx>,
closure_def_id: DefId,
ty::Binder(trait_ref)
}
- fn generator_trait_ref(&mut self,
- obligation: &TraitObligation<'tcx>,
- closure_def_id: DefId,
- substs: ty::ClosureSubsts<'tcx>)
- -> Normalized<'tcx, ty::PolyTraitRef<'tcx>>
- {
- let trait_ref = self.generator_trait_ref_unnormalized(
- obligation, closure_def_id, substs);
-
- // A generator signature can contain associated types which
- // must be normalized.
- normalize_with_depth(self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth+1,
- &trait_ref)
- }
-
/// Returns the obligations that are implied by instantiating an
/// impl or trait. The obligations are substituted and fully
/// normalized. This is used when confirming an impl or default
self.continue_after_error.set(continue_after_error);
}
+ // NOTE: DO NOT call this function from rustc, as it relies on `err_count` being non-zero
+ // if an error happened to avoid ICEs. This function should only be called from tools.
+ pub fn reset_err_count(&self) {
+ self.err_count.set(0);
+ }
+
pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
DiagnosticBuilder::new(self, Level::Cancelled, "")
}
_ => C_null(llret_ty)
}
}
+
+ "align_offset" => {
+ // `ptr as usize`
+ let ptr_val = bcx.ptrtoint(llargs[0], bcx.ccx.int_type());
+ // `ptr_val % align`
+ let offset = bcx.urem(ptr_val, llargs[1]);
+ let zero = C_null(bcx.ccx.int_type());
+ // `offset == 0`
+ let is_zero = bcx.icmp(llvm::IntPredicate::IntEQ, offset, zero);
+ // `if offset == 0 { 0 } else { offset - align }`
+ bcx.select(is_zero, zero, bcx.sub(offset, llargs[1]))
+ }
name if name.starts_with("simd_") => {
generic_simd_intrinsic(bcx, name,
callee_ty,
(0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
}
+ "align_offset" => {
+ let ptr_ty = tcx.mk_imm_ptr(tcx.mk_nil());
+ (0, vec![ptr_ty, tcx.types.usize], tcx.types.usize)
+ },
+
ref other => {
struct_span_err!(tcx.sess, it.span, E0093,
"unrecognized intrinsic function: `{}`",
})
}
- probe::ExtensionImplPick(impl_def_id) => {
- // The method being invoked is the method as defined on the trait,
- // so return the substitutions from the trait. Consider:
- //
- // impl<A,B,C> Trait<A,B> for Foo<C> { ... }
- //
- // If we instantiate A, B, and C with $A, $B, and $C
- // respectively, then we want to return the type
- // parameters from the trait ([$A,$B]), not those from
- // the impl ([$A,$B,$C]) not the receiver type ([$C]).
- let impl_polytype = self.impl_self_ty(self.span, impl_def_id);
- let impl_trait_ref =
- self.instantiate_type_scheme(self.span,
- impl_polytype.substs,
- &self.tcx.impl_trait_ref(impl_def_id).unwrap());
- impl_trait_ref.substs
- }
-
probe::TraitPick => {
let trait_def_id = pick.item.container.id();
// Multiple methods might apply.
Ambiguity(Vec<CandidateSource>),
- // Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind.
- ClosureAmbiguity(// DefId of fn trait
- DefId),
-
// Found an applicable method, but it is not visible. The second argument contains a list of
// not-in-scope traits which may work.
PrivateMatch(Def, Vec<DefId>),
// Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
// forgotten to import a trait.
IllegalSizedBound(Vec<DefId>),
+
+ // Found a match, but the return type is wrong
+ BadReturnType,
}
// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
Ok(..) => true,
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
- Err(ClosureAmbiguity(..)) => true,
Err(PrivateMatch(..)) => allow_private,
Err(IllegalSizedBound(..)) => true,
+ Err(BadReturnType) => {
+ bug!("no return type expectations but got BadReturnType")
+ }
+
}
}
use hir::def::Def;
use rustc::ty::subst::{Subst, Substs};
use rustc::traits::{self, ObligationCause};
-use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
+use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::util::nodemap::FxHashSet;
use rustc::infer::{self, InferOk};
use self::CandidateKind::*;
pub use self::PickKind::*;
-pub enum LookingFor<'tcx> {
- /// looking for methods with the given name; this is the normal case
- MethodName(ast::Name),
-
- /// looking for methods that return a given type; this is used to
- /// assemble suggestions
- ReturnType(Ty<'tcx>),
-}
-
/// Boolean flag used to indicate if this search is for a suggestion
/// or not. If true, we can allow ambiguity and so forth.
pub struct IsSuggestion(pub bool);
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
span: Span,
mode: Mode,
- looking_for: LookingFor<'tcx>,
+ method_name: Option<ast::Name>,
+ return_type: Option<Ty<'tcx>>,
steps: Rc<Vec<CandidateStep<'tcx>>>,
- opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>,
inherent_candidates: Vec<Candidate<'tcx>>,
extension_candidates: Vec<Candidate<'tcx>>,
impl_dups: FxHashSet<DefId>,
#[derive(Debug)]
struct Candidate<'tcx> {
xform_self_ty: Ty<'tcx>,
+ xform_ret_ty: Option<Ty<'tcx>>,
item: ty::AssociatedItem,
kind: CandidateKind<'tcx>,
import_id: Option<ast::NodeId>,
InherentImplCandidate(&'tcx Substs<'tcx>,
// Normalize obligations
Vec<traits::PredicateObligation<'tcx>>),
- ExtensionImplCandidate(// Impl
- DefId,
- &'tcx Substs<'tcx>,
- // Normalize obligations
- Vec<traits::PredicateObligation<'tcx>>),
ObjectCandidate,
- TraitCandidate,
+ TraitCandidate(ty::TraitRef<'tcx>),
WhereClauseCandidate(// Trait
ty::PolyTraitRef<'tcx>),
}
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+enum ProbeResult {
+ NoMatch,
+ BadReturnType,
+ Match,
+}
+
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Pick<'tcx> {
pub item: ty::AssociatedItem,
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PickKind<'tcx> {
InherentImplPick,
- ExtensionImplPick(// Impl
- DefId),
ObjectPick,
TraitPick,
WhereClausePick(// Trait
return_type,
scope_expr_id);
let method_names =
- self.probe_op(span, mode, LookingFor::ReturnType(return_type), IsSuggestion(true),
+ self.probe_op(span, mode, None, Some(return_type), IsSuggestion(true),
self_ty, scope_expr_id, ProbeScope::TraitsInScope,
|probe_cx| Ok(probe_cx.candidate_method_names()))
.unwrap_or(vec![]);
- method_names
- .iter()
- .flat_map(|&method_name| {
- match self.probe_for_name(span, mode, method_name, IsSuggestion(true), self_ty,
- scope_expr_id, ProbeScope::TraitsInScope) {
- Ok(pick) => Some(pick.item),
- Err(_) => None,
- }
- })
+ method_names
+ .iter()
+ .flat_map(|&method_name| {
+ self.probe_op(
+ span, mode, Some(method_name), Some(return_type),
+ IsSuggestion(true), self_ty, scope_expr_id,
+ ProbeScope::TraitsInScope, |probe_cx| probe_cx.pick()
+ ).ok().map(|pick| pick.item)
+ })
.collect()
}
scope_expr_id);
self.probe_op(span,
mode,
- LookingFor::MethodName(item_name),
+ Some(item_name),
+ None,
is_suggestion,
self_ty,
scope_expr_id,
fn probe_op<OP,R>(&'a self,
span: Span,
mode: Mode,
- looking_for: LookingFor<'tcx>,
+ method_name: Option<ast::Name>,
+ return_type: Option<Ty<'tcx>>,
is_suggestion: IsSuggestion,
self_ty: Ty<'tcx>,
scope_expr_id: ast::NodeId,
}]
};
- // Create a list of simplified self types, if we can.
- let mut simplified_steps = Vec::new();
- for step in &steps {
- match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) {
- None => {
- break;
- }
- Some(simplified_type) => {
- simplified_steps.push(simplified_type);
- }
- }
- }
- let opt_simplified_steps = if simplified_steps.len() < steps.len() {
- None // failed to convert at least one of the steps
- } else {
- Some(simplified_steps)
- };
-
debug!("ProbeContext: steps for self_ty={:?} are {:?}",
self_ty,
steps);
// that we create during the probe process are removed later
self.probe(|_| {
let mut probe_cx =
- ProbeContext::new(self, span, mode, looking_for,
- steps, opt_simplified_steps);
+ ProbeContext::new(self, span, mode, method_name, return_type, steps);
probe_cx.assemble_inherent_candidates();
match scope {
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
span: Span,
mode: Mode,
- looking_for: LookingFor<'tcx>,
- steps: Vec<CandidateStep<'tcx>>,
- opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>)
+ method_name: Option<ast::Name>,
+ return_type: Option<Ty<'tcx>>,
+ steps: Vec<CandidateStep<'tcx>>)
-> ProbeContext<'a, 'gcx, 'tcx> {
ProbeContext {
fcx,
span,
mode,
- looking_for,
+ method_name,
+ return_type,
inherent_candidates: Vec::new(),
extension_candidates: Vec::new(),
impl_dups: FxHashSet(),
steps: Rc::new(steps),
- opt_simplified_steps,
static_candidates: Vec::new(),
private_candidate: None,
unsatisfied_predicates: Vec::new(),
///////////////////////////////////////////////////////////////////////////
// CANDIDATE ASSEMBLY
- fn push_inherent_candidate(&mut self, xform_self_ty: Ty<'tcx>, item: ty::AssociatedItem,
- kind: CandidateKind<'tcx>, import_id: Option<ast::NodeId>) {
- let is_accessible = if let LookingFor::MethodName(name) = self.looking_for {
- let def_scope = self.tcx.adjust(name, item.container.id(), self.body_id).1;
- item.vis.is_accessible_from(def_scope, self.tcx)
- } else {
- true
- };
- if is_accessible {
- self.inherent_candidates.push(Candidate { xform_self_ty, item, kind, import_id });
- } else if self.private_candidate.is_none() {
- self.private_candidate = Some(item.def());
- }
- }
-
- fn push_extension_candidate(&mut self, xform_self_ty: Ty<'tcx>, item: ty::AssociatedItem,
- kind: CandidateKind<'tcx>, import_id: Option<ast::NodeId>) {
- let is_accessible = if let LookingFor::MethodName(name) = self.looking_for {
+ fn push_candidate(&mut self,
+ candidate: Candidate<'tcx>,
+ is_inherent: bool)
+ {
+ let is_accessible = if let Some(name) = self.method_name {
+ let item = candidate.item;
let def_scope = self.tcx.adjust(name, item.container.id(), self.body_id).1;
item.vis.is_accessible_from(def_scope, self.tcx)
} else {
true
};
if is_accessible {
- self.extension_candidates.push(Candidate { xform_self_ty, item, kind, import_id });
+ if is_inherent {
+ self.inherent_candidates.push(candidate);
+ } else {
+ self.extension_candidates.push(candidate);
+ }
} else if self.private_candidate.is_none() {
- self.private_candidate = Some(item.def());
+ self.private_candidate = Some(candidate.item.def());
}
}
let impl_ty = impl_ty.subst(self.tcx, impl_substs);
// Determine the receiver type that the method itself expects.
- let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs);
+ let xform_tys = self.xform_self_ty(&item, impl_ty, impl_substs);
// We can't use normalize_associated_types_in as it will pollute the
// fcx's fulfillment context after this probe is over.
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let selcx = &mut traits::SelectionContext::new(self.fcx);
- let traits::Normalized { value: xform_self_ty, obligations } =
- traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
- debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
- xform_self_ty);
-
- self.push_inherent_candidate(xform_self_ty, item,
- InherentImplCandidate(impl_substs, obligations), None);
+ let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } =
+ traits::normalize(selcx, self.param_env, cause, &xform_tys);
+ debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}",
+ xform_self_ty, xform_ret_ty);
+
+ self.push_candidate(Candidate {
+ xform_self_ty, xform_ret_ty, item,
+ kind: InherentImplCandidate(impl_substs, obligations),
+ import_id: None
+ }, true);
}
}
self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| {
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
- let xform_self_ty =
+ let (xform_self_ty, xform_ret_ty) =
this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
-
- this.push_inherent_candidate(xform_self_ty, item, ObjectCandidate, None);
+ this.push_candidate(Candidate {
+ xform_self_ty, xform_ret_ty, item,
+ kind: ObjectCandidate,
+ import_id: None
+ }, true);
});
}
self.elaborate_bounds(&bounds, |this, poly_trait_ref, item| {
let trait_ref = this.erase_late_bound_regions(&poly_trait_ref);
- let xform_self_ty = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs);
+ let (xform_self_ty, xform_ret_ty) =
+ this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs);
// Because this trait derives from a where-clause, it
// should not contain any inference variables or other
// `WhereClausePick`.
assert!(!trait_ref.substs.needs_infer());
- this.push_inherent_candidate(xform_self_ty, item,
- WhereClauseCandidate(poly_trait_ref), None);
+ this.push_candidate(Candidate {
+ xform_self_ty, xform_ret_ty, item,
+ kind: WhereClauseCandidate(poly_trait_ref),
+ import_id: None
+ }, true);
});
}
Ok(())
}
- pub fn matches_return_type(&self, method: &ty::AssociatedItem,
- expected: ty::Ty<'tcx>) -> bool {
+ pub fn matches_return_type(&self,
+ method: &ty::AssociatedItem,
+ self_ty: Option<Ty<'tcx>>,
+ expected: Ty<'tcx>) -> bool {
match method.def() {
Def::Method(def_id) => {
let fty = self.tcx.fn_sig(def_id);
self.probe(|_| {
let substs = self.fresh_substs_for_item(self.span, method.def_id);
- let output = fty.output().subst(self.tcx, substs);
- let (output, _) = self.replace_late_bound_regions_with_fresh_var(
- self.span, infer::FnCall, &output);
- self.can_sub(self.param_env, output, expected).is_ok()
+ let fty = fty.subst(self.tcx, substs);
+ let (fty, _) = self.replace_late_bound_regions_with_fresh_var(
+ self.span, infer::FnCall, &fty);
+
+ if let Some(self_ty) = self_ty {
+ if let Err(_) = self.at(&ObligationCause::dummy(), self.param_env)
+ .sup(fty.inputs()[0], self_ty)
+ {
+ return false
+ }
+ }
+ self.can_sub(self.param_env, fty.output(), expected).is_ok()
})
}
_ => false,
-> Result<(), MethodError<'tcx>> {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
trait_def_id);
+ let trait_substs = self.fresh_item_substs(trait_def_id);
+ let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
for item in self.impl_or_trait_item(trait_def_id) {
// Check whether `trait_def_id` defines a method with suitable name:
continue;
}
- self.assemble_builtin_candidates(import_id, trait_def_id, item.clone());
-
- self.assemble_extension_candidates_for_trait_impls(import_id, trait_def_id,
- item.clone());
-
- self.assemble_closure_candidates(import_id, trait_def_id, item.clone())?;
-
- self.assemble_generator_candidates(import_id, trait_def_id, item.clone())?;
-
- self.assemble_projection_candidates(import_id, trait_def_id, item.clone());
-
- self.assemble_where_clause_candidates(import_id, trait_def_id, item.clone());
- }
-
- Ok(())
- }
-
- fn assemble_builtin_candidates(&mut self,
- import_id: Option<ast::NodeId>,
- trait_def_id: DefId,
- item: ty::AssociatedItem) {
- if Some(trait_def_id) == self.tcx.lang_items.clone_trait() {
- self.assemble_builtin_clone_candidates(import_id, trait_def_id, item);
- }
- }
-
- fn assemble_builtin_clone_candidates(&mut self,
- import_id: Option<ast::NodeId>,
- trait_def_id: DefId,
- item: ty::AssociatedItem) {
- for step in Rc::clone(&self.steps).iter() {
- match step.self_ty.sty {
- ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
- ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
- ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
- ty::TyRawPtr(..) | ty::TyError | ty::TyNever |
- ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) |
- ty::TyArray(..) | ty::TyTuple(..) => {
- ()
- }
-
- _ => continue,
- };
-
- let substs = Substs::for_item(self.tcx,
- trait_def_id,
- |def, _| self.region_var_for_def(self.span, def),
- |def, substs| {
- if def.index == 0 {
- step.self_ty
- } else {
- self.type_var_for_def(self.span, def, substs)
- }
- });
-
- let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs);
- self.push_inherent_candidate(xform_self_ty, item, TraitCandidate, import_id);
- }
- }
-
- fn assemble_extension_candidates_for_trait_impls(&mut self,
- import_id: Option<ast::NodeId>,
- trait_def_id: DefId,
- item: ty::AssociatedItem) {
- // FIXME(arielb1): can we use for_each_relevant_impl here?
- self.tcx.for_each_impl(trait_def_id, |impl_def_id| {
- debug!("assemble_extension_candidates_for_trait_impl: trait_def_id={:?} \
- impl_def_id={:?}",
- trait_def_id,
- impl_def_id);
-
- if !self.impl_can_possibly_match(impl_def_id) {
- return;
- }
-
- let (_, impl_substs) = self.impl_ty_and_substs(impl_def_id);
-
- debug!("impl_substs={:?}", impl_substs);
-
- let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id)
- .unwrap() // we know this is a trait impl
- .subst(self.tcx, impl_substs);
-
- debug!("impl_trait_ref={:?}", impl_trait_ref);
-
- // Determine the receiver type that the method itself expects.
- let xform_self_ty =
- self.xform_self_ty(&item, impl_trait_ref.self_ty(), impl_trait_ref.substs);
-
- // Normalize the receiver. We can't use normalize_associated_types_in
- // as it will pollute the fcx's fulfillment context after this probe
- // is over.
- let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let selcx = &mut traits::SelectionContext::new(self.fcx);
- let traits::Normalized { value: xform_self_ty, obligations } =
- traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
-
- debug!("xform_self_ty={:?}", xform_self_ty);
-
- self.push_extension_candidate(xform_self_ty, item,
- ExtensionImplCandidate(impl_def_id, impl_substs, obligations), import_id);
- });
- }
-
- fn impl_can_possibly_match(&self, impl_def_id: DefId) -> bool {
- let simplified_steps = match self.opt_simplified_steps {
- Some(ref simplified_steps) => simplified_steps,
- None => {
- return true;
- }
- };
-
- let impl_type = self.tcx.type_of(impl_def_id);
- let impl_simplified_type =
- match ty::fast_reject::simplify_type(self.tcx, impl_type, false) {
- Some(simplified_type) => simplified_type,
- None => {
- return true;
- }
- };
-
- simplified_steps.contains(&impl_simplified_type)
- }
-
- fn assemble_closure_candidates(&mut self,
- import_id: Option<ast::NodeId>,
- trait_def_id: DefId,
- item: ty::AssociatedItem)
- -> Result<(), MethodError<'tcx>> {
- // Check if this is one of the Fn,FnMut,FnOnce traits.
- let tcx = self.tcx;
- let kind = if Some(trait_def_id) == tcx.lang_items.fn_trait() {
- ty::ClosureKind::Fn
- } else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
- ty::ClosureKind::FnMut
- } else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
- ty::ClosureKind::FnOnce
- } else {
- return Ok(());
- };
-
- // Check if there is an unboxed-closure self-type in the list of receivers.
- // If so, add "synthetic impls".
- let steps = self.steps.clone();
- for step in steps.iter() {
- let closure_id = match step.self_ty.sty {
- ty::TyClosure(def_id, _) => {
- if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
- self.tcx.hir.node_to_hir_id(id)
- } else {
- continue;
- }
- }
- _ => continue,
- };
-
- let closure_kind = {
- match self.tables.borrow().closure_kinds().get(closure_id) {
- Some(&(k, _)) => k,
- None => {
- return Err(MethodError::ClosureAmbiguity(trait_def_id));
- }
- }
- };
-
- // this closure doesn't implement the right kind of `Fn` trait
- if !closure_kind.extends(kind) {
- continue;
- }
-
- // create some substitutions for the argument/return type;
- // for the purposes of our method lookup, we only take
- // receiver type into account, so we can just substitute
- // fresh types here to use during substitution and subtyping.
- let substs = Substs::for_item(self.tcx,
- trait_def_id,
- |def, _| self.region_var_for_def(self.span, def),
- |def, substs| {
- if def.index == 0 {
- step.self_ty
- } else {
- self.type_var_for_def(self.span, def, substs)
- }
- });
-
- let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs);
- self.push_inherent_candidate(xform_self_ty, item, TraitCandidate, import_id);
- }
-
- Ok(())
- }
-
- fn assemble_generator_candidates(&mut self,
- import_id: Option<ast::NodeId>,
- trait_def_id: DefId,
- item: ty::AssociatedItem)
- -> Result<(), MethodError<'tcx>> {
- // Check if this is the Generator trait.
- let tcx = self.tcx;
- if Some(trait_def_id) != tcx.lang_items.gen_trait() {
- return Ok(());
- }
-
- // Check if there is an generator self-type in the list of receivers.
- // If so, add "synthetic impls".
- let steps = self.steps.clone();
- for step in steps.iter() {
- match step.self_ty.sty {
- ty::TyGenerator(..) => (),
- _ => continue,
- };
-
- // create some substitutions for the argument/return type;
- // for the purposes of our method lookup, we only take
- // receiver type into account, so we can just substitute
- // fresh types here to use during substitution and subtyping.
- let substs = Substs::for_item(self.tcx,
- trait_def_id,
- |def, _| self.region_var_for_def(self.span, def),
- |def, substs| {
- if def.index == 0 {
- step.self_ty
- } else {
- self.type_var_for_def(self.span, def, substs)
- }
- });
-
- let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs);
- self.push_inherent_candidate(xform_self_ty, item, TraitCandidate, import_id);
+ let (xform_self_ty, xform_ret_ty) =
+ self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
+ self.push_candidate(Candidate {
+ xform_self_ty, xform_ret_ty, item, import_id,
+ kind: TraitCandidate(trait_ref),
+ }, false);
}
-
Ok(())
}
- fn assemble_projection_candidates(&mut self,
- import_id: Option<ast::NodeId>,
- trait_def_id: DefId,
- item: ty::AssociatedItem) {
- debug!("assemble_projection_candidates(\
- trait_def_id={:?}, \
- item={:?})",
- trait_def_id,
- item);
-
- for step in Rc::clone(&self.steps).iter() {
- debug!("assemble_projection_candidates: step={:?}", step);
-
- let (def_id, substs) = match step.self_ty.sty {
- ty::TyProjection(ref data) => {
- let trait_ref = data.trait_ref(self.tcx);
- (trait_ref.def_id, trait_ref.substs)
- },
- ty::TyAnon(def_id, substs) => (def_id, substs),
- _ => continue,
- };
-
- debug!("assemble_projection_candidates: def_id={:?} substs={:?}",
- def_id,
- substs);
-
- let trait_predicates = self.tcx.predicates_of(def_id);
- let bounds = trait_predicates.instantiate(self.tcx, substs);
- let predicates = bounds.predicates;
- debug!("assemble_projection_candidates: predicates={:?}",
- predicates);
- for poly_bound in traits::elaborate_predicates(self.tcx, predicates)
- .filter_map(|p| p.to_opt_poly_trait_ref())
- .filter(|b| b.def_id() == trait_def_id) {
- let bound = self.erase_late_bound_regions(&poly_bound);
-
- debug!("assemble_projection_candidates: def_id={:?} substs={:?} bound={:?}",
- def_id,
- substs,
- bound);
-
- if self.can_eq(self.param_env, step.self_ty, bound.self_ty()).is_ok() {
- let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
-
- debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}",
- bound,
- xform_self_ty);
-
- self.push_extension_candidate(xform_self_ty, item, TraitCandidate, import_id);
- }
- }
- }
- }
-
- fn assemble_where_clause_candidates(&mut self,
- import_id: Option<ast::NodeId>,
- trait_def_id: DefId,
- item: ty::AssociatedItem) {
- debug!("assemble_where_clause_candidates(trait_def_id={:?})",
- trait_def_id);
-
- let caller_predicates = self.param_env.caller_bounds.to_vec();
- for poly_bound in traits::elaborate_predicates(self.tcx, caller_predicates)
- .filter_map(|p| p.to_opt_poly_trait_ref())
- .filter(|b| b.def_id() == trait_def_id) {
- let bound = self.erase_late_bound_regions(&poly_bound);
- let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
-
- debug!("assemble_where_clause_candidates: bound={:?} xform_self_ty={:?}",
- bound,
- xform_self_ty);
-
- self.push_extension_candidate(xform_self_ty, item,
- WhereClauseCandidate(poly_bound), import_id);
- }
- }
-
fn candidate_method_names(&self) -> Vec<ast::Name> {
let mut set = FxHashSet();
- let mut names: Vec<_> =
- self.inherent_candidates
- .iter()
- .chain(&self.extension_candidates)
- .map(|candidate| candidate.item.name)
- .filter(|&name| set.insert(name))
- .collect();
+ let mut names: Vec<_> = self.inherent_candidates
+ .iter()
+ .chain(&self.extension_candidates)
+ .filter(|candidate| {
+ if let Some(return_ty) = self.return_type {
+ self.matches_return_type(&candidate.item, None, return_ty)
+ } else {
+ true
+ }
+ })
+ .map(|candidate| candidate.item.name)
+ .filter(|&name| set.insert(name))
+ .collect();
// sort them by the name so we have a stable result
names.sort_by_key(|n| n.as_str());
// THE ACTUAL SEARCH
fn pick(mut self) -> PickResult<'tcx> {
- assert!(match self.looking_for {
- LookingFor::MethodName(_) => true,
- LookingFor::ReturnType(_) => false,
- });
+ assert!(self.method_name.is_some());
if let Some(r) = self.pick_core() {
return r;
assert!(others.is_empty());
vec![]
}
- Some(Err(MethodError::ClosureAmbiguity(..))) => {
- // this error only occurs when assembling candidates
- span_bug!(span, "encountered ClosureAmbiguity from pick_core");
- }
_ => vec![],
};
let steps = self.steps.clone();
// find the first step that works
- steps.iter().filter_map(|step| self.pick_step(step)).next()
- }
-
- fn pick_step(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
- debug!("pick_step: step={:?}", step);
-
- if step.self_ty.references_error() {
- return None;
- }
-
- if let Some(result) = self.pick_by_value_method(step) {
- return Some(result);
- }
-
- self.pick_autorefd_method(step)
+ steps
+ .iter()
+ .filter(|step| {
+ debug!("pick_core: step={:?}", step);
+ !step.self_ty.references_error()
+ }).flat_map(|step| {
+ self.pick_by_value_method(step).or_else(|| {
+ self.pick_autorefd_method(step, hir::MutImmutable).or_else(|| {
+ self.pick_autorefd_method(step, hir::MutMutable)
+ })})})
+ .next()
}
fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
})
}
- fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
+ fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>, mutbl: hir::Mutability)
+ -> Option<PickResult<'tcx>> {
let tcx = self.tcx;
// In general, during probing we erase regions. See
// `impl_self_ty()` for an explanation.
let region = tcx.types.re_erased;
- // Search through mutabilities in order to find one where pick works:
- [hir::MutImmutable, hir::MutMutable]
- .iter()
- .filter_map(|&m| {
- let autoref_ty = tcx.mk_ref(region,
- ty::TypeAndMut {
- ty: step.self_ty,
- mutbl: m,
- });
- self.pick_method(autoref_ty).map(|r| {
- r.map(|mut pick| {
- pick.autoderefs = step.autoderefs;
- pick.autoref = Some(m);
- pick.unsize = if step.unsize {
- Some(step.self_ty)
- } else {
- None
- };
- pick
- })
- })
+ let autoref_ty = tcx.mk_ref(region,
+ ty::TypeAndMut {
+ ty: step.self_ty, mutbl
+ });
+ self.pick_method(autoref_ty).map(|r| {
+ r.map(|mut pick| {
+ pick.autoderefs = step.autoderefs;
+ pick.autoref = Some(mutbl);
+ pick.unsize = if step.unsize {
+ Some(step.self_ty)
+ } else {
+ None
+ };
+ pick
})
- .nth(0)
+ })
}
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
-> Option<PickResult<'tcx>> {
let mut applicable_candidates: Vec<_> = probes.iter()
- .filter(|&probe| self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
+ .map(|probe| {
+ (probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
+ })
+ .filter(|&(_, status)| status != ProbeResult::NoMatch)
.collect();
debug!("applicable_candidates: {:?}", applicable_candidates);
}
if applicable_candidates.len() > 1 {
- let sources = probes.iter().map(|p| p.to_source()).collect();
+ let sources = probes.iter()
+ .map(|p| self.candidate_source(p, self_ty))
+ .collect();
return Some(Err(MethodError::Ambiguity(sources)));
}
- applicable_candidates.pop().map(|probe| Ok(probe.to_unadjusted_pick()))
+ applicable_candidates.pop().map(|(probe, status)| {
+ if status == ProbeResult::Match {
+ Ok(probe.to_unadjusted_pick())
+ } else {
+ Err(MethodError::BadReturnType)
+ }
+ })
+ }
+
+ fn select_trait_candidate(&self, trait_ref: ty::TraitRef<'tcx>)
+ -> traits::SelectionResult<'tcx, traits::Selection<'tcx>>
+ {
+ let cause = traits::ObligationCause::misc(self.span, self.body_id);
+ let predicate =
+ trait_ref.to_poly_trait_ref().to_poly_trait_predicate();
+ let obligation = traits::Obligation::new(cause, self.param_env, predicate);
+ traits::SelectionContext::new(self).select(&obligation)
+ }
+
+ fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>)
+ -> CandidateSource
+ {
+ match candidate.kind {
+ InherentImplCandidate(..) => ImplSource(candidate.item.container.id()),
+ ObjectCandidate |
+ WhereClauseCandidate(_) => TraitSource(candidate.item.container.id()),
+ TraitCandidate(trait_ref) => self.probe(|_| {
+ let _ = self.at(&ObligationCause::dummy(), self.param_env)
+ .sup(candidate.xform_self_ty, self_ty);
+ match self.select_trait_candidate(trait_ref) {
+ Ok(Some(traits::Vtable::VtableImpl(ref impl_data))) => {
+ // If only a single impl matches, make the error message point
+ // to that impl.
+ ImplSource(impl_data.impl_def_id)
+ }
+ _ => {
+ TraitSource(candidate.item.container.id())
+ }
+ }
+ })
+ }
}
fn consider_probe(&self,
self_ty: Ty<'tcx>,
probe: &Candidate<'tcx>,
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
- -> bool {
+ -> ProbeResult {
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
self.probe(|_| {
Ok(InferOk { obligations, value: () }) => obligations,
Err(_) => {
debug!("--> cannot relate self-types");
- return false;
+ return ProbeResult::NoMatch;
}
};
+ let mut result = ProbeResult::Match;
+ let selcx = &mut traits::SelectionContext::new(self);
+ let cause = traits::ObligationCause::misc(self.span, self.body_id);
+
// If so, impls may carry other conditions (e.g., where
// clauses) that must be considered. Make sure that those
// match as well (or at least may match, sometimes we
// don't have enough information to fully evaluate).
- let (impl_def_id, substs, ref_obligations) = match probe.kind {
+ let candidate_obligations : Vec<_> = match probe.kind {
InherentImplCandidate(ref substs, ref ref_obligations) => {
- (probe.item.container.id(), substs, ref_obligations)
- }
-
- ExtensionImplCandidate(impl_def_id, ref substs, ref ref_obligations) => {
- (impl_def_id, substs, ref_obligations)
+ // Check whether the impl imposes obligations we have to worry about.
+ let impl_def_id = probe.item.container.id();
+ let impl_bounds = self.tcx.predicates_of(impl_def_id);
+ let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
+ let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
+ traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds);
+
+ // Convert the bounds into obligations.
+ let impl_obligations = traits::predicates_for_generics(
+ cause.clone(), self.param_env, &impl_bounds);
+
+ debug!("impl_obligations={:?}", impl_obligations);
+ impl_obligations.into_iter()
+ .chain(norm_obligations.into_iter())
+ .chain(ref_obligations.iter().cloned())
+ .collect()
}
ObjectCandidate |
- TraitCandidate |
WhereClauseCandidate(..) => {
// These have no additional conditions to check.
- return true;
+ vec![]
}
- };
- let selcx = &mut traits::SelectionContext::new(self);
- let cause = traits::ObligationCause::misc(self.span, self.body_id);
-
- // Check whether the impl imposes obligations we have to worry about.
- let impl_bounds = self.tcx.predicates_of(impl_def_id);
- let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
- let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
- traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds);
+ TraitCandidate(trait_ref) => {
+ let predicate = trait_ref.to_predicate();
+ let obligation =
+ traits::Obligation::new(cause.clone(), self.param_env, predicate);
+ if !selcx.evaluate_obligation(&obligation) {
+ if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) {
+ // This candidate's primary obligation doesn't even
+ // select - don't bother registering anything in
+ // `potentially_unsatisfied_predicates`.
+ return ProbeResult::NoMatch;
+ } else {
+ // Some nested subobligation of this predicate
+ // failed.
+ //
+ // FIXME: try to find the exact nested subobligation
+ // and point at it rather than reporting the entire
+ // trait-ref?
+ result = ProbeResult::NoMatch;
+ let trait_ref = self.resolve_type_vars_if_possible(&trait_ref);
+ possibly_unsatisfied_predicates.push(trait_ref);
+ }
+ }
+ vec![]
+ }
+ };
- // Convert the bounds into obligations.
- let obligations = traits::predicates_for_generics(cause.clone(),
- self.param_env,
- &impl_bounds);
- debug!("impl_obligations={:?}", obligations);
+ debug!("consider_probe - candidate_obligations={:?} sub_obligations={:?}",
+ candidate_obligations, sub_obligations);
// Evaluate those obligations to see if they might possibly hold.
- let mut all_true = true;
- for o in obligations.iter()
- .chain(sub_obligations.iter())
- .chain(norm_obligations.iter())
- .chain(ref_obligations.iter()) {
- if !selcx.evaluate_obligation(o) {
- all_true = false;
+ for o in candidate_obligations.into_iter().chain(sub_obligations) {
+ let o = self.resolve_type_vars_if_possible(&o);
+ if !selcx.evaluate_obligation(&o) {
+ result = ProbeResult::NoMatch;
if let &ty::Predicate::Trait(ref pred) = &o.predicate {
possibly_unsatisfied_predicates.push(pred.0.trait_ref);
}
}
}
- all_true
+
+ if let ProbeResult::Match = result {
+ if let (Some(return_ty), Some(xform_ret_ty)) =
+ (self.return_type, probe.xform_ret_ty)
+ {
+ let xform_ret_ty = self.resolve_type_vars_if_possible(&xform_ret_ty);
+ debug!("comparing return_ty {:?} with xform ret ty {:?}",
+ return_ty,
+ probe.xform_ret_ty);
+ if self.at(&ObligationCause::dummy(), self.param_env)
+ .sup(return_ty, xform_ret_ty)
+ .is_err()
+ {
+ return ProbeResult::BadReturnType;
+ }
+ }
+ }
+
+ result
})
}
///
/// Now imagine the receiver is `Vec<_>`. It doesn't really matter at this time which impl we
/// use, so it's ok to just commit to "using the method from the trait Foo".
- fn collapse_candidates_to_trait_pick(&self, probes: &[&Candidate<'tcx>]) -> Option<Pick<'tcx>> {
+ fn collapse_candidates_to_trait_pick(&self, probes: &[(&Candidate<'tcx>, ProbeResult)])
+ -> Option<Pick<'tcx>>
+ {
// Do all probes correspond to the same trait?
- let container = probes[0].item.container;
+ let container = probes[0].0.item.container;
match container {
ty::TraitContainer(_) => {}
ty::ImplContainer(_) => return None,
}
- if probes[1..].iter().any(|p| p.item.container != container) {
+ if probes[1..].iter().any(|&(p, _)| p.item.container != container) {
return None;
}
+ // FIXME: check the return type here somehow.
// If so, just use this trait and call it a day.
Some(Pick {
- item: probes[0].item.clone(),
+ item: probes[0].0.item.clone(),
kind: TraitPick,
- import_id: probes[0].import_id,
+ import_id: probes[0].0.import_id,
autoderefs: 0,
autoref: None,
unsize: None,
item: &ty::AssociatedItem,
impl_ty: Ty<'tcx>,
substs: &Substs<'tcx>)
- -> Ty<'tcx> {
+ -> (Ty<'tcx>, Option<Ty<'tcx>>) {
if item.kind == ty::AssociatedKind::Method && self.mode == Mode::MethodCall {
- self.xform_method_self_ty(item.def_id, impl_ty, substs)
+ let sig = self.xform_method_sig(item.def_id, substs);
+ (sig.inputs()[0], Some(sig.output()))
} else {
- impl_ty
+ (impl_ty, None)
}
}
- fn xform_method_self_ty(&self,
- method: DefId,
- impl_ty: Ty<'tcx>,
- substs: &Substs<'tcx>)
- -> Ty<'tcx> {
- let self_ty = self.tcx.fn_sig(method).input(0);
- debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})",
- impl_ty,
- self_ty,
+ fn xform_method_sig(&self,
+ method: DefId,
+ substs: &Substs<'tcx>)
+ -> ty::FnSig<'tcx>
+ {
+ let fn_sig = self.tcx.fn_sig(method);
+ debug!("xform_self_ty(fn_sig={:?}, substs={:?})",
+ fn_sig,
substs);
assert!(!substs.has_escaping_regions());
// Erase any late-bound regions from the method and substitute
// in the values from the substitution.
- let xform_self_ty = self.erase_late_bound_regions(&self_ty);
+ let xform_fn_sig = self.erase_late_bound_regions(&fn_sig);
if generics.types.is_empty() && generics.regions.is_empty() {
- xform_self_ty.subst(self.tcx, substs)
+ xform_fn_sig.subst(self.tcx, substs)
} else {
let substs = Substs::for_item(self.tcx, method, |def, _| {
let i = def.index as usize;
self.type_var_for_def(self.span, def, cur_substs)
}
});
- xform_self_ty.subst(self.tcx, substs)
+ xform_fn_sig.subst(self.tcx, substs)
}
}
/// Get the type of an impl and generate substitutions with placeholders.
fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) {
- let impl_ty = self.tcx.type_of(impl_def_id);
-
- let substs = Substs::for_item(self.tcx,
- impl_def_id,
- |_, _| self.tcx.types.re_erased,
- |_, _| self.next_ty_var(
- TypeVariableOrigin::SubstitutionPlaceholder(
- self.tcx.def_span(impl_def_id))));
+ (self.tcx.type_of(impl_def_id), self.fresh_item_substs(impl_def_id))
+ }
- (impl_ty, substs)
+ fn fresh_item_substs(&self, def_id: DefId) -> &'tcx Substs<'tcx> {
+ Substs::for_item(self.tcx,
+ def_id,
+ |_, _| self.tcx.types.re_erased,
+ |_, _| self.next_ty_var(
+ TypeVariableOrigin::SubstitutionPlaceholder(
+ self.tcx.def_span(def_id))))
}
/// Replace late-bound-regions bound by `value` with `'static` using
/// Find the method with the appropriate name (or return type, as the case may be).
fn impl_or_trait_item(&self, def_id: DefId) -> Vec<ty::AssociatedItem> {
- match self.looking_for {
- LookingFor::MethodName(name) => {
- self.fcx.associated_item(def_id, name).map_or(Vec::new(), |x| vec![x])
- }
- LookingFor::ReturnType(return_ty) => {
- self.tcx
- .associated_items(def_id)
- .map(|did| self.tcx.associated_item(did.def_id))
- .filter(|m| self.matches_return_type(m, return_ty))
- .collect()
- }
+ if let Some(name) = self.method_name {
+ self.fcx.associated_item(def_id, name).map_or(Vec::new(), |x| vec![x])
+ } else {
+ self.tcx.associated_items(def_id).collect()
}
}
}
item: self.item.clone(),
kind: match self.kind {
InherentImplCandidate(..) => InherentImplPick,
- ExtensionImplCandidate(def_id, ..) => ExtensionImplPick(def_id),
ObjectCandidate => ObjectPick,
- TraitCandidate => TraitPick,
+ TraitCandidate(_) => TraitPick,
WhereClauseCandidate(ref trait_ref) => {
// Only trait derived from where-clauses should
// appear here, so they should not contain any
unsize: None,
}
}
-
- fn to_source(&self) -> CandidateSource {
- match self.kind {
- InherentImplCandidate(..) => ImplSource(self.item.container.id()),
- ExtensionImplCandidate(def_id, ..) => ImplSource(def_id),
- ObjectCandidate |
- TraitCandidate |
- WhereClauseCandidate(_) => TraitSource(self.item.container.id()),
- }
- }
}
err.emit();
}
- MethodError::ClosureAmbiguity(trait_def_id) => {
- let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
- invoked on this closure as we have not yet inferred what \
- kind of closure it is",
- item_name,
- self.tcx.item_path_str(trait_def_id));
- let msg = if let Some(callee) = rcvr_expr {
- format!("{}; use overloaded call notation instead (e.g., `{}()`)",
- msg,
- self.tcx.hir.node_to_pretty_string(callee.id))
- } else {
- msg
- };
- self.sess().span_err(span, &msg);
- }
-
MethodError::PrivateMatch(def, out_of_scope_traits) => {
let mut err = struct_span_err!(self.tcx.sess, span, E0624,
"{} `{}` is private", def.kind_name(), item_name);
}
err.emit();
}
+
+ MethodError::BadReturnType => {
+ bug!("no return type expectations but got BadReturnType")
+ }
}
}
formal_ret: Ty<'tcx>,
formal_args: &[Ty<'tcx>])
-> Vec<Ty<'tcx>> {
+ let formal_ret = self.resolve_type_vars_with_obligations(formal_ret);
let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| {
self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || {
// Attempt to apply a subtyping relationship between the formal
}
hir::ExprTup(ref elts) => {
let flds = expected.only_has_type(self).and_then(|ty| {
+ let ty = self.resolve_type_vars_with_obligations(ty);
match ty.sty {
ty::TyTuple(ref flds, _) => Some(&flds[..]),
_ => None
}
if end_newline {
- //add a space so stripping <br> tags and breaking spaces still renders properly
+ // add a space so stripping <br> tags and breaking spaces still renders properly
if f.alternate() {
clause.push(' ');
} else {
}
}
+ /// Gets the next token out of the lexer, emitting fatal errors if lexing fails.
+ fn try_next_token(&mut self) -> io::Result<TokenAndSpan> {
+ match self.lexer.try_next_token() {
+ Ok(tas) => Ok(tas),
+ Err(_) => {
+ self.lexer.emit_fatal_errors();
+ self.lexer.sess.span_diagnostic
+ .struct_warn("Backing out of syntax highlighting")
+ .note("You probably did not intend to render this as a rust code-block")
+ .emit();
+ Err(io::Error::new(io::ErrorKind::Other, ""))
+ }
+ }
+ }
+
/// Exhausts the `lexer` writing the output into `out`.
///
/// The general structure for this method is to iterate over each token,
out: &mut W)
-> io::Result<()> {
loop {
- let next = match self.lexer.try_next_token() {
- Ok(tas) => tas,
- Err(_) => {
- self.lexer.emit_fatal_errors();
- self.lexer.sess.span_diagnostic
- .struct_warn("Backing out of syntax highlighting")
- .note("You probably did not intend to render this as a rust code-block")
- .emit();
- return Err(io::Error::new(io::ErrorKind::Other, ""));
- }
- };
-
+ let next = self.try_next_token()?;
if next.tok == token::Eof {
break;
}
}
}
- // This is the start of an attribute. We're going to want to
+ // This might be the start of an attribute. We're going to want to
// continue highlighting it as an attribute until the ending ']' is
// seen, so skip out early. Down below we terminate the attribute
// span when we see the ']'.
token::Pound => {
- self.in_attribute = true;
- out.enter_span(Class::Attribute)?;
+ // We can't be sure that our # begins an attribute (it could
+ // just be appearing in a macro) until we read either `#![` or
+ // `#[` from the input stream.
+ //
+ // We don't want to start highlighting as an attribute until
+ // we're confident there is going to be a ] coming up, as
+ // otherwise # tokens in macros highlight the rest of the input
+ // as an attribute.
+
+ // Case 1: #![inner_attribute]
+ if self.lexer.peek().tok == token::Not {
+ self.try_next_token()?; // NOTE: consumes `!` token!
+ if self.lexer.peek().tok == token::OpenDelim(token::Bracket) {
+ self.in_attribute = true;
+ out.enter_span(Class::Attribute)?;
+ }
+ out.string("#", Class::None, None)?;
+ out.string("!", Class::None, None)?;
+ return Ok(());
+ }
+
+ // Case 2: #[outer_attribute]
+ if self.lexer.peek().tok == token::OpenDelim(token::Bracket) {
+ self.in_attribute = true;
+ out.enter_span(Class::Attribute)?;
+ }
out.string("#", Class::None, None)?;
return Ok(());
}
} else {
write!(fmt, "Module ")?;
},
- clean::FunctionItem(..) | clean::ForeignFunctionItem(..) =>
- write!(fmt, "Function ")?,
+ clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => write!(fmt, "Function ")?,
clean::TraitItem(..) => write!(fmt, "Trait ")?,
clean::StructItem(..) => write!(fmt, "Struct ")?,
clean::UnionItem(..) => write!(fmt, "Union ")?,
clean::TypedefItem(..) => write!(fmt, "Type Definition ")?,
clean::MacroItem(..) => write!(fmt, "Macro ")?,
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
- clean::StaticItem(..) | clean::ForeignStaticItem(..) =>
- write!(fmt, "Static ")?,
+ clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?,
clean::ConstantItem(..) => write!(fmt, "Constant ")?,
_ => {
// We don't generate pages for any other type.
display: inline-block;
}
+.in-band > code {
+ display: inline-block;
+}
+
#main { position: relative; }
#main > .since {
top: inherit;
}
.in-band:hover > .anchor {
- display: initial;
+ display: inline-block;
+ position: absolute;
}
.anchor {
display: none;
///
/// # Examples
///
+/// Creating a [`SocketAddr`] iterator that yields one item:
+///
+/// ```
+/// use std::net::{ToSocketAddrs, SocketAddr};
+///
+/// let addr = SocketAddr::from(([127, 0, 0, 1], 443));
+/// let mut addrs_iter = addr.to_socket_addrs().unwrap();
+///
+/// assert_eq!(Some(addr), addrs_iter.next());
+/// assert!(addrs_iter.next().is_none());
+/// ```
+///
+/// Creating a [`SocketAddr`] iterator from a hostname:
+///
/// ```no_run
-/// use std::net::{SocketAddrV4, TcpStream, UdpSocket, TcpListener, Ipv4Addr};
-///
-/// fn main() {
-/// let ip = Ipv4Addr::new(127, 0, 0, 1);
-/// let port = 12345;
-///
-/// // The following lines are equivalent modulo possible "localhost" name
-/// // resolution differences
-/// let tcp_s = TcpStream::connect(SocketAddrV4::new(ip, port));
-/// let tcp_s = TcpStream::connect((ip, port));
-/// let tcp_s = TcpStream::connect(("127.0.0.1", port));
-/// let tcp_s = TcpStream::connect(("localhost", port));
-/// let tcp_s = TcpStream::connect("127.0.0.1:12345");
-/// let tcp_s = TcpStream::connect("localhost:12345");
-///
-/// // TcpListener::bind(), UdpSocket::bind() and UdpSocket::send_to()
-/// // behave similarly
-/// let tcp_l = TcpListener::bind("localhost:12345");
-///
-/// let mut udp_s = UdpSocket::bind(("127.0.0.1", port)).unwrap();
-/// udp_s.send_to(&[7], (ip, 23451)).unwrap();
-/// }
+/// use std::net::{SocketAddr, ToSocketAddrs};
+///
+/// // assuming 'localhost' resolves to 127.0.0.1
+/// let mut addrs_iter = "localhost:443".to_socket_addrs().unwrap();
+/// assert_eq!(addrs_iter.next(), Some(SocketAddr::from(([127, 0, 0, 1], 443))));
+/// assert!(addrs_iter.next().is_none());
+///
+/// // assuming 'foo' does not resolve
+/// assert!("foo:443".to_socket_addrs().is_err());
/// ```
+///
+/// Creating a [`SocketAddr`] iterator that yields multiple items:
+///
+/// ```
+/// use std::net::{SocketAddr, ToSocketAddrs};
+///
+/// let addr1 = SocketAddr::from(([0, 0, 0, 0], 80));
+/// let addr2 = SocketAddr::from(([127, 0, 0, 1], 443));
+/// let addrs = vec![addr1, addr2];
+///
+/// let mut addrs_iter = (&addrs[..]).to_socket_addrs().unwrap();
+///
+/// assert_eq!(Some(addr1), addrs_iter.next());
+/// assert_eq!(Some(addr2), addrs_iter.next());
+/// assert!(addrs_iter.next().is_none());
+/// ```
+///
+/// Attempting to create a [`SocketAddr`] iterator from an improperly formatted
+/// socket address `&str` (missing the port):
+///
+/// ```
+/// use std::io;
+/// use std::net::ToSocketAddrs;
+///
+/// let err = "127.0.0.1".to_socket_addrs().unwrap_err();
+/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+/// ```
+///
+/// [`TcpStream::connect`] is an example of an function that utilizes
+/// `ToSocketsAddr` as a trait bound on its parameter in order to accept
+/// different types:
+///
+/// ```no_run
+/// use std::net::{TcpStream, Ipv4Addr};
+///
+/// let stream = TcpStream::connect(("127.0.0.1", 443));
+/// // or
+/// let stream = TcpStream::connect("127.0.0.1.443");
+/// // or
+/// let stream = TcpStream::connect((Ipv4Addr::new(127, 0, 0, 1), 443));
+/// ```
+///
+/// [`TcpStream::connect`]: ../../std/net/struct.TcpStream.html#method.connect
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ToSocketAddrs {
/// Returned iterator over socket addresses which this type may correspond
+++ /dev/null
-// Copyright 2014 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.
-
-fn main() {
- let mut zero = || {};
- let () = zero.call_mut(());
- //~^ ERROR we have not yet inferred what kind of closure it is
-}
--- /dev/null
+// 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.
+
+pub struct ClientMap;
+pub struct ClientMap2;
+
+pub trait Service {
+ type Request;
+ fn call(&self, _req: Self::Request);
+}
+
+pub struct S<T>(T);
+
+impl Service for ClientMap {
+ type Request = S<Box<Fn(i32)>>;
+ fn call(&self, _req: Self::Request) {}
+}
+
+
+impl Service for ClientMap2 {
+ type Request = (Box<Fn(i32)>,);
+ fn call(&self, _req: Self::Request) {}
+}
+
+
+fn main() {
+ ClientMap.call(S { 0: Box::new(|_msgid| ()) });
+ ClientMap.call(S(Box::new(|_msgid| ())));
+ ClientMap2.call((Box::new(|_msgid| ()),));
+}
--- /dev/null
+// Copyright 2014 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.
+
+#![feature(fn_traits)]
+
+fn main() {
+ let mut zero = || 0;
+ let x = zero.call_mut(());
+ assert_eq!(x, 0);
+}
// @!has - 'space'
// @!has - 'comment'
// @has - '# <span class="ident">single'
-// @has - '#<span class="attribute"># <span class="ident">double</span>'
-// @has - '#<span class="attribute">#<span class="attribute"># <span class="ident">triple</span>'
+// @has - '## <span class="ident">double</span>'
+// @has - '### <span class="ident">triple</span>'
+// @has - '<span class="attribute">#[<span class="ident">outer</span>]</span>'
+// @has - '<span class="attribute">#![<span class="ident">inner</span>]</span>'
/// ```no_run
/// # # space
/// ## single
/// ### double
/// #### triple
+/// ##[outer]
+/// ##![inner]
/// ```
pub struct Foo;
= note: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
candidate #1: `use foo::Bar;`
candidate #2: `use no_method_suggested_traits::foo::PubPub;`
+ candidate #3: `use no_method_suggested_traits::qux::PrivPub;`
+ candidate #4: `use no_method_suggested_traits::Reexported;`
error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&u32>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:38:44
= note: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
candidate #1: `use foo::Bar;`
candidate #2: `use no_method_suggested_traits::foo::PubPub;`
+ candidate #3: `use no_method_suggested_traits::qux::PrivPub;`
+ candidate #4: `use no_method_suggested_traits::Reexported;`
error[E0599]: no method named `method` found for type `char` in the current scope
--> $DIR/no-method-suggested-traits.rs:44:9
| ^^^^^
|
= note: the method `count` exists but the following trait bounds were not satisfied:
- `[closure@$DIR/issue-36053-2.rs:17:39: 17:53] : std::ops::FnMut<(&_,)>`
`std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator`
+ `&mut std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator`
error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` implements the trait `for<'r> std::ops::FnMut<(&'r str,)>`, but the trait `for<'r> std::ops::FnMut<(&'r &str,)>` is required
--> $DIR/issue-36053-2.rs:17:32
--- /dev/null
+// 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.
+
+// check that we substitute type parameters before we suggest anything - otherwise
+// we would suggest function such as `as_slice` for the `&[u16]`.
+
+fn foo(b: &[u16]) {}
+
+fn main() {
+ let a: Vec<u8> = Vec::new();
+ foo(&a);
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-43420-no-over-suggest.rs:18:9
+ |
+18 | foo(&a);
+ | ^^ expected slice, found struct `std::vec::Vec`
+ |
+ = note: expected type `&[u16]`
+ found type `&std::vec::Vec<u8>`
+
+error: aborting due to previous error
+
self.package("rust-std", &mut manifest.pkg, TARGETS);
self.package("rust-docs", &mut manifest.pkg, TARGETS);
self.package("rust-src", &mut manifest.pkg, &["*"]);
- self.package("rls", &mut manifest.pkg, HOSTS);
+ let rls_package_name = if self.rust_release == "nightly" {
+ "rls"
+ } else {
+ "rls-preview"
+ };
+ self.package(rls_package_name, &mut manifest.pkg, HOSTS);
self.package("rust-analysis", &mut manifest.pkg, TARGETS);
let mut pkg = Package {
}
extensions.push(Component {
- pkg: "rls".to_string(),
+ pkg: rls_package_name.to_string(),
target: host.to_string(),
});
extensions.push(Component {
format!("rust-src-{}.tar.gz", self.rust_release)
} else if component == "cargo" {
format!("cargo-{}-{}.tar.gz", self.cargo_release, target)
- } else if component == "rls" {
+ } else if component == "rls" || component == "rls-preview" {
format!("rls-{}-{}.tar.gz", self.rls_release, target)
} else {
format!("{}-{}-{}.tar.gz", component, self.rust_release, target)
fn cached_version(&self, component: &str) -> &str {
if component == "cargo" {
&self.cargo_version
- } else if component == "rls" {
+ } else if component == "rls" || component == "rls-preview" {
&self.rls_version
} else {
&self.rust_version
#[derive(Clone)]
pub struct Config {
- // The library paths required for running the compiler
+ /// The library paths required for running the compiler
pub compile_lib_path: PathBuf,
- // The library paths required for running compiled programs
+ /// The library paths required for running compiled programs
pub run_lib_path: PathBuf,
- // The rustc executable
+ /// The rustc executable
pub rustc_path: PathBuf,
- // The rustdoc executable
+ /// The rustdoc executable
pub rustdoc_path: Option<PathBuf>,
- // The python executable to use for LLDB
+ /// The python executable to use for LLDB
pub lldb_python: String,
- // The python executable to use for htmldocck
+ /// The python executable to use for htmldocck
pub docck_python: String,
- // The llvm FileCheck binary path
+ /// The llvm FileCheck binary path
pub llvm_filecheck: Option<PathBuf>,
- // The valgrind path
+ /// The valgrind path
pub valgrind_path: Option<String>,
- // Whether to fail if we can't run run-pass-valgrind tests under valgrind
- // (or, alternatively, to silently run them like regular run-pass tests).
+ /// Whether to fail if we can't run run-pass-valgrind tests under valgrind
+ /// (or, alternatively, to silently run them like regular run-pass tests).
pub force_valgrind: bool,
- // The directory containing the tests to run
+ /// The directory containing the tests to run
pub src_base: PathBuf,
- // The directory where programs should be built
+ /// The directory where programs should be built
pub build_base: PathBuf,
- // The name of the stage being built (stage1, etc)
+ /// The name of the stage being built (stage1, etc)
pub stage_id: String,
- // The test mode, compile-fail, run-fail, run-pass
+ /// The test mode, compile-fail, run-fail, run-pass
pub mode: Mode,
- // Run ignored tests
+ /// Run ignored tests
pub run_ignored: bool,
- // Only run tests that match this filter
+ /// Only run tests that match this filter
pub filter: Option<String>,
- // Exactly match the filter, rather than a substring
+ /// Exactly match the filter, rather than a substring
pub filter_exact: bool,
- // Write out a parseable log of tests that were run
+ /// Write out a parseable log of tests that were run
pub logfile: Option<PathBuf>,
- // A command line to prefix program execution with,
- // for running under valgrind
+ /// A command line to prefix program execution with,
+ /// for running under valgrind
pub runtool: Option<String>,
- // Flags to pass to the compiler when building for the host
+ /// Flags to pass to the compiler when building for the host
pub host_rustcflags: Option<String>,
- // Flags to pass to the compiler when building for the target
+ /// Flags to pass to the compiler when building for the target
pub target_rustcflags: Option<String>,
- // Target system to be tested
+ /// Target system to be tested
pub target: String,
- // Host triple for the compiler being invoked
+ /// Host triple for the compiler being invoked
pub host: String,
- // Path to / name of the GDB executable
+ /// Path to / name of the GDB executable
pub gdb: Option<String>,
- // Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch
+ /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch
pub gdb_version: Option<u32>,
- // Whether GDB has native rust support
+ /// Whether GDB has native rust support
pub gdb_native_rust: bool,
- // Version of LLDB
+ /// Version of LLDB
pub lldb_version: Option<String>,
- // Version of LLVM
+ /// Version of LLVM
pub llvm_version: Option<String>,
- // Is LLVM a system LLVM
+ /// Is LLVM a system LLVM
pub system_llvm: bool,
- // Path to the android tools
+ /// Path to the android tools
pub android_cross_path: PathBuf,
- // Extra parameter to run adb on arm-linux-androideabi
+ /// Extra parameter to run adb on arm-linux-androideabi
pub adb_path: String,
- // Extra parameter to run test suite on arm-linux-androideabi
+ /// Extra parameter to run test suite on arm-linux-androideabi
pub adb_test_dir: String,
- // status whether android device available or not
+ /// status whether android device available or not
pub adb_device_status: bool,
- // the path containing LLDB's Python module
+ /// the path containing LLDB's Python module
pub lldb_python_dir: Option<String>,
- // Explain what's going on
+ /// Explain what's going on
pub verbose: bool,
- // Print one character per test instead of one line
+ /// Print one character per test instead of one line
pub quiet: bool,
- // Whether to use colors in test.
+ /// Whether to use colors in test.
pub color: ColorConfig,
- // where to find the remote test client process, if we're using it
+ /// where to find the remote test client process, if we're using it
pub remote_test_client: Option<PathBuf>,
// Configuration for various run-make tests frobbing things like C compilers