diff --git a/cargo b/cargo index c416fb60b11ec..770512b08fb29 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 770512b08fb2985aed6f06311f1c58ed587fa259 diff --git a/src/Cargo.lock b/src/Cargo.lock index 62b853480394f..80a8596a499c7 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -269,7 +269,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.0.18" +version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -425,7 +425,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1004,7 +1004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" -"checksum mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "06a68e8738e42b38a02755d3ce5fa12d559e17acb238e4326cbc3cc056e65280" +"checksum mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "2598843aeda0c5bb2e8e4d714564f1c3fc40f7844157e34563bf96ae3866b56e" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f8f641060c442..a439e79fce538 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -78,14 +78,6 @@ pub fn linkcheck(build: &Build, host: &str) { pub fn cargotest(build: &Build, stage: u32, host: &str) { let ref compiler = Compiler::new(stage, host); - // Configure PATH to find the right rustc. NB. we have to use PATH - // and not RUSTC because the Cargo test suite has tests that will - // fail if rustc is not spelled `rustc`. - let path = build.sysroot(compiler).join("bin"); - let old_path = ::std::env::var("PATH").expect(""); - let sep = if cfg!(windows) { ";" } else {":" }; - let ref newpath = format!("{}{}{}", path.display(), sep, old_path); - // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise // quickly run into path name limit constraints. @@ -95,11 +87,49 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) { let _time = util::timeit(); let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest")); build.prepare_tool_cmd(compiler, &mut cmd); - build.run(cmd.env("PATH", newpath) - .arg(&build.cargo) + build.run(cmd.arg(&build.cargo) .arg(&out_dir)); } +/// Runs `cargo test` for `cargo` packaged with Rust. +pub fn cargo(build: &Build, stage: u32, host: &str) { + let ref compiler = Compiler::new(stage, host); + + // Configure PATH to find the right rustc. NB. we have to use PATH + // and not RUSTC because the Cargo test suite has tests that will + // fail if rustc is not spelled `rustc`. + let path = build.sysroot(compiler).join("bin"); + let old_path = ::std::env::var("PATH").expect(""); + let sep = if cfg!(windows) { ";" } else {":" }; + let ref newpath = format!("{}{}{}", path.display(), sep, old_path); + + let mut cargo = build.cargo(compiler, Mode::Tool, host, "test"); + cargo.arg("--manifest-path").arg(build.src.join("cargo/Cargo.toml")); + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + // Don't run cross-compile tests, we may not have cross-compiled libstd libs + // available. + cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); + + // When being tested Cargo will at some point call `nmake.exe` on Windows + // MSVC. Unfortunately `nmake` will read these two environment variables + // below and try to intepret them. We're likely being run, however, from + // MSYS `make` which uses the same variables. + // + // As a result, to prevent confusion and errors, we remove these variables + // from our environment to prevent passing MSYS make flags to nmake, causing + // it to blow up. + if cfg!(target_env = "msvc") { + cargo.env_remove("MAKE"); + cargo.env_remove("MAKEFLAGS"); + } + + + build.run(cargo.env("PATH", newpath)); +} + /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler. /// /// This tool in `src/tools` checks up on various bits and pieces of style and diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 457ac825832ce..a5df741e2bfc8 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -55,6 +55,7 @@ check: check-aux: $(Q)$(BOOTSTRAP) test \ src/tools/cargotest \ + cargo \ src/test/pretty \ src/test/run-pass/pretty \ src/test/run-fail/pretty \ diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 34705040e8a5e..4e3166acbd67e 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -468,6 +468,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("librustc")) .host(true) .run(move |s| check::cargotest(build, s.stage, s.target)); + rules.test("check-cargo", "cargo") + .dep(|s| s.name("tool-cargo")) + .host(true) + .run(move |s| check::cargo(build, s.stage, s.target)); rules.test("check-tidy", "src/tools/tidy") .dep(|s| s.name("tool-tidy").stage(0)) .default(true) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 8a391f9cde3a3..618561f3b0257 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1812,6 +1812,8 @@ makes a difference in practice.) register_diagnostics! { // E0006 // merged with E0005 +// E0101, // replaced with E0282 +// E0102, // replaced with E0282 // E0134, // E0135, E0278, // requirement is not satisfied diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e98792b120de2..a1bafe113e415 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -199,10 +199,8 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // `tained_by_errors`) to avoid reporting certain kinds of errors. err_count_on_creation: usize, - // This flag is used for debugging, and is set to true if there are - // any obligations set during the current snapshot. In that case, the - // snapshot can't be rolled back. - pub obligations_in_snapshot: Cell, + // This flag is true while there is an active snapshot. + in_snapshot: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -507,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { projection_mode: Reveal::UserFacing, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), - obligations_in_snapshot: Cell::new(false), + in_snapshot: Cell::new(false), } } } @@ -545,7 +543,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), - obligations_in_snapshot: Cell::new(false), + in_snapshot: Cell::new(false), })) } } @@ -573,7 +571,7 @@ pub struct CombinedSnapshot { int_snapshot: unify::Snapshot, float_snapshot: unify::Snapshot, region_vars_snapshot: RegionSnapshot, - obligations_in_snapshot: bool, + was_in_snapshot: bool, } /// Helper trait for shortening the lifetimes inside a @@ -734,6 +732,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.projection_mode } + pub fn is_in_snapshot(&self) -> bool { + self.in_snapshot.get() + } + pub fn freshen>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } @@ -861,38 +863,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } - // Clear the "obligations in snapshot" flag, invoke the closure, + // Clear the "currently in a snapshot" flag, invoke the closure, // then restore the flag to its original value. This flag is a // debugging measure designed to detect cases where we start a - // snapshot, create type variables, register obligations involving - // those type variables in the fulfillment cx, and then have to - // unroll the snapshot, leaving "dangling type variables" behind. - // In such cases, the flag will be set by the fulfillment cx, and - // an assertion will fail when rolling the snapshot back. Very - // useful, much better than grovelling through megabytes of - // RUST_LOG output. + // snapshot, create type variables, and register obligations + // which may involve those type variables in the fulfillment cx, + // potentially leaving "dangling type variables" behind. + // In such cases, an assertion will fail when attempting to + // register obligations, within a snapshot. Very useful, much + // better than grovelling through megabytes of RUST_LOG output. // - // HOWEVER, in some cases the flag is wrong. In particular, we + // HOWEVER, in some cases the flag is unhelpful. In particular, we // sometimes create a "mini-fulfilment-cx" in which we enroll // obligations. As long as this fulfillment cx is fully drained // before we return, this is not a problem, as there won't be any // escaping obligations in the main cx. In those cases, you can // use this function. - pub fn save_and_restore_obligations_in_snapshot_flag(&self, func: F) -> R + pub fn save_and_restore_in_snapshot_flag(&self, func: F) -> R where F: FnOnce(&Self) -> R { - let flag = self.obligations_in_snapshot.get(); - self.obligations_in_snapshot.set(false); + let flag = self.in_snapshot.get(); + self.in_snapshot.set(false); let result = func(self); - self.obligations_in_snapshot.set(flag); + self.in_snapshot.set(flag); result } fn start_snapshot(&self) -> CombinedSnapshot { debug!("start_snapshot()"); - let obligations_in_snapshot = self.obligations_in_snapshot.get(); - self.obligations_in_snapshot.set(false); + let in_snapshot = self.in_snapshot.get(); + self.in_snapshot.set(true); CombinedSnapshot { projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(), @@ -900,7 +901,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot: self.int_unification_table.borrow_mut().snapshot(), float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_vars_snapshot: self.region_vars.start_snapshot(), - obligations_in_snapshot: obligations_in_snapshot, + was_in_snapshot: in_snapshot, } } @@ -911,10 +912,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - obligations_in_snapshot } = snapshot; + was_in_snapshot } = snapshot; - assert!(!self.obligations_in_snapshot.get()); - self.obligations_in_snapshot.set(obligations_in_snapshot); + self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() @@ -939,9 +939,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - obligations_in_snapshot } = snapshot; + was_in_snapshot } = snapshot; - self.obligations_in_snapshot.set(obligations_in_snapshot); + self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f7a7d0e2071f2..71dff3b2bb94d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -25,7 +25,7 @@ use super::{ use errors::DiagnosticBuilder; use fmt_macros::{Parser, Piece, Position}; -use hir::{intravisit, Local, Pat}; +use hir::{self, intravisit, Local, Pat, Body}; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::map::NodeExpr; use hir::def_id::DefId; @@ -33,8 +33,8 @@ use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; -use syntax::ast; -use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use syntax::ast::{self, NodeId}; +use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; @@ -66,37 +66,52 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, target_ty: &'a Ty<'tcx>, - found_pattern: Option<&'a Pat>, + hir_map: &'a hir::map::Map<'gcx>, + found_local_pattern: Option<&'gcx Pat>, + found_arg_pattern: Option<&'gcx Pat>, } impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn is_match(&self, ty: Ty<'tcx>) -> bool { - ty == *self.target_ty || match (&ty.sty, &self.target_ty.sty) { - (&ty::TyInfer(ty::TyVar(a_vid)), &ty::TyInfer(ty::TyVar(b_vid))) => - self.infcx.type_variables - .borrow_mut() - .sub_unified(a_vid, b_vid), - + fn node_matches_type(&mut self, node_id: &'gcx NodeId) -> bool { + match self.infcx.tables.borrow().node_types.get(node_id) { + Some(&ty) => { + let ty = self.infcx.resolve_type_vars_if_possible(&ty); + ty.walk().any(|inner_ty| { + inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) { + (&TyInfer(TyVar(a_vid)), &TyInfer(TyVar(b_vid))) => { + self.infcx + .type_variables + .borrow_mut() + .sub_unified(a_vid, b_vid) + } + _ => false, + } + }) + } _ => false, } } } -impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> { - NestedVisitorMap::None +impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { + NestedVisitorMap::OnlyBodies(&self.hir_map) } - fn visit_local(&mut self, local: &'a Local) { - if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) { - let ty = self.infcx.resolve_type_vars_if_possible(&ty); - let is_match = ty.walk().any(|t| self.is_match(t)); + fn visit_local(&mut self, local: &'gcx Local) { + if self.found_local_pattern.is_none() && self.node_matches_type(&local.id) { + self.found_local_pattern = Some(&*local.pat); + } + intravisit::walk_local(self, local); + } - if is_match && self.found_pattern.is_none() { - self.found_pattern = Some(&*local.pat); + fn visit_body(&mut self, body: &'gcx Body) { + for argument in &body.arguments { + if self.found_arg_pattern.is_none() && self.node_matches_type(&argument.id) { + self.found_arg_pattern = Some(&*argument.pat); } } - intravisit::walk_local(self, local); + intravisit::walk_body(self, body); } } @@ -721,6 +736,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // coherence violation, so we don't report it here. let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); + let body_id = hir::BodyId { node_id: obligation.cause.body_id }; + let span = obligation.cause.span; debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", predicate, @@ -768,10 +785,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.lang_items.sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - self.need_type_info(obligation, self_ty); + self.need_type_info(body_id, span, self_ty); } else { let mut err = struct_span_err!(self.tcx.sess, - obligation.cause.span, E0283, + span, E0283, "type annotations required: \ cannot resolve `{}`", predicate); @@ -785,7 +802,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Same hacky approach as above to avoid deluging user // with error messages. if !ty.references_error() && !self.tcx.sess.has_errors() { - self.need_type_info(obligation, ty); + self.need_type_info(body_id, span, ty); } } @@ -796,7 +813,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info(obligation, a); + self.need_type_info(hir::BodyId { node_id: obligation.cause.body_id }, + obligation.cause.span, + a); } } @@ -874,42 +893,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn need_type_info(&self, obligation: &PredicateObligation<'tcx>, ty: Ty<'tcx>) { + pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) { let ty = self.resolve_type_vars_if_possible(&ty); let name = self.extract_type_name(&ty); - let ref cause = obligation.cause; - let mut err = struct_span_err!(self.tcx.sess, - cause.span, - E0282, - "type annotations needed"); - - err.span_label(cause.span, &format!("cannot infer type for `{}`", name)); + let mut err_span = span; + let mut labels = vec![(span, format!("cannot infer type for `{}`", name))]; let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, target_ty: &ty, - found_pattern: None, + hir_map: &self.tcx.hir, + found_local_pattern: None, + found_arg_pattern: None, }; // #40294: cause.body_id can also be a fn declaration. // Currently, if it's anything other than NodeExpr, we just ignore it - match self.tcx.hir.find(cause.body_id) { + match self.tcx.hir.find(body_id.node_id) { Some(NodeExpr(expr)) => local_visitor.visit_expr(expr), _ => () } - if let Some(pattern) = local_visitor.found_pattern { - let pattern_span = pattern.span; + if let Some(pattern) = local_visitor.found_arg_pattern { + err_span = pattern.span; + // We don't want to show the default label for closures. + // + // So, before clearing, the output would look something like this: + // ``` + // let x = |_| { }; + // - ^^^^ cannot infer type for `[_; 0]` + // | + // consider giving this closure parameter a type + // ``` + // + // After clearing, it looks something like this: + // ``` + // let x = |_| { }; + // ^ consider giving this closure parameter a type + // ``` + labels.clear(); + labels.push((pattern.span, format!("consider giving this closure parameter a type"))); + } + + if let Some(pattern) = local_visitor.found_local_pattern { if let Some(simple_name) = pattern.simple_name() { - err.span_label(pattern_span, - &format!("consider giving `{}` a type", - simple_name)); + labels.push((pattern.span, format!("consider giving `{}` a type", simple_name))); } else { - err.span_label(pattern_span, &format!("consider giving a type to pattern")); + labels.push((pattern.span, format!("consider giving the pattern a type"))); } } + let mut err = struct_span_err!(self.tcx.sess, + err_span, + E0282, + "type annotations needed"); + + for (target_span, label_message) in labels { + err.span_label(target_span, &label_message); + } + err.emit(); } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 64453f2983b92..d771be077ae3a 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -171,7 +171,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { debug!("register_predicate_obligation(obligation={:?})", obligation); - infcx.obligations_in_snapshot.set(true); + assert!(!infcx.is_in_snapshot()); if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { debug!("register_predicate_obligation: duplicate"); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 50a4d982832ac..92b7c736d42fd 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -242,7 +242,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) - infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| { + infcx.save_and_restore_in_snapshot_flag(|infcx| { let mut fulfill_cx = FulfillmentContext::new(); for oblig in obligations.into_iter() { fulfill_cx.register_predicate_obligation(&infcx, oblig); diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 2daebf5cf3d6b..2cfab7df8b30b 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -229,12 +229,12 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType }; if in_mem { - // `sret` / `byval` parameter thus one less integer register available - int_regs -= 1; - arg.make_indirect(ccx); if is_arg { arg.attrs.set(ArgAttribute::ByVal); + } else { + // `sret` parameter thus one less integer register available + int_regs -= 1; } } else { // split into sized chunks passed individually diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs deleted file mode 100644 index 9610477d8fd91..0000000000000 --- a/src/librustc_typeck/check/assoc.rs +++ /dev/null @@ -1,39 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::infer::InferCtxt; -use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext, - ObligationCause}; -use rustc::ty::fold::TypeFoldable; -use syntax::ast; -use syntax_pos::Span; - -// FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument. -pub fn normalize_associated_types_in<'a, 'gcx, 'tcx, T>( - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - fulfillment_cx: &mut FulfillmentContext<'tcx>, - span: Span, - body_id: ast::NodeId, - value: &T) -> T - - where T : TypeFoldable<'tcx> -{ - debug!("normalize_associated_types_in(value={:?})", value); - let mut selcx = SelectionContext::new(infcx); - let cause = ObligationCause::new(span, body_id, MiscObligation); - let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value); - debug!("normalize_associated_types_in: result={:?} predicates={:?}", - result, - obligations); - for obligation in obligations { - fulfillment_cx.register_predicate_obligation(infcx, obligation); - } - result -} diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 647adbbb82f2d..92fb02c6379dc 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -149,22 +149,25 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.fcx.resolve_type_vars_if_possible(&self.cur_ty) } - pub fn finalize(self, pref: LvaluePreference, exprs: &[E]) - where E: AsCoercionSite - { + pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) { let fcx = self.fcx; - fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); + fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr])); } pub fn finalize_as_infer_ok(self, pref: LvaluePreference, exprs: &[E]) -> InferOk<'tcx, ()> where E: AsCoercionSite { - let methods: Vec<_> = self.steps + let Autoderef { fcx, span, mut obligations, steps, .. } = self; + let methods: Vec<_> = steps .iter() .map(|&(ty, kind)| { if let AutoderefKind::Overloaded = kind { - self.fcx.try_overloaded_deref(self.span, None, ty, pref) + fcx.try_overloaded_deref(span, None, ty, pref) + .map(|InferOk { value, obligations: o }| { + obligations.extend(o); + value + }) } else { None } @@ -174,7 +177,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { debug!("finalize({:?}) - {:?},{:?}", pref, methods, - self.obligations); + obligations); for expr in exprs { let expr = expr.as_coercion_site(); @@ -182,14 +185,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { for (n, method) in methods.iter().enumerate() { if let &Some(method) = method { let method_call = MethodCall::autoderef(expr.id, n as u32); - self.fcx.tables.borrow_mut().method_map.insert(method_call, method); + fcx.tables.borrow_mut().method_map.insert(method_call, method); } } } InferOk { value: (), - obligations: self.obligations + obligations } } } @@ -211,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base_expr: Option<&hir::Expr>, base_ty: Ty<'tcx>, lvalue_pref: LvaluePreference) - -> Option> { + -> Option>> { debug!("try_overloaded_deref({:?},{:?},{:?},{:?})", span, base_expr, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 9c5870c12aad4..32f130aca1cb9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) .next(); let callee_ty = autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, &[callee_expr]); + autoderef.finalize(LvaluePreference::NoPreference, callee_expr); let output = match result { None => { @@ -173,7 +173,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { adjusted_ty, None) { None => continue, - Some(method_callee) => { + Some(ok) => { + let method_callee = self.register_infer_ok_obligations(ok); return Some(method_callee); } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 2e9057800a54a..c6a1f6cfc0d7f 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -711,16 +711,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); - self.commit_if_ok(|_| { - let ok = coerce.coerce(&[expr], source, target)?; - let adjustment = self.register_infer_ok_obligations(ok); - self.apply_adjustment(expr.id, adjustment); - - // We should now have added sufficient adjustments etc to - // ensure that the type of expression, post-adjustment, is - // a subtype of target. - Ok(target) - }) + let ok = self.commit_if_ok(|_| coerce.coerce(&[expr], source, target))?; + + let adjustment = self.register_infer_ok_obligations(ok); + self.apply_adjustment(expr.id, adjustment); + + // We should now have added sufficient adjustments etc to + // ensure that the type of expression, post-adjustment, is + // a subtype of target. + Ok(target) } /// Given some expressions, their known unified type and another expression, diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 905d8688ea194..8a6853461a5e8 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -20,7 +20,6 @@ use rustc::util::common::ErrorReported; use syntax::ast; use syntax_pos::Span; -use super::assoc; use super::{Inherited, FnCtxt}; use astconv::ExplicitSelf; @@ -227,7 +226,6 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| { let inh = Inherited::new(infcx); let infcx = &inh.infcx; - let fulfillment_cx = &inh.fulfillment_cx; debug!("compare_impl_method: caller_bounds={:?}", infcx.parameter_environment.caller_bounds); @@ -239,12 +237,11 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, infer::HigherRankedType, &ty::Binder(impl_m_own_bounds.predicates)); for predicate in impl_m_own_bounds { - let traits::Normalized { value: predicate, .. } = + let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); - fulfillment_cx.borrow_mut().register_predicate_obligation( - &infcx, - traits::Obligation::new(cause.clone(), predicate)); + inh.register_predicates(obligations); + inh.register_predicate(traits::Obligation::new(cause.clone(), predicate)); } // We now need to check that the signature of the impl method is @@ -277,11 +274,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs); let impl_sig = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx.borrow_mut(), - impl_m_span, - impl_m_body_id, - &impl_sig); + inh.normalize_associated_types_in(impl_m_span, + impl_m_body_id, + &impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -291,11 +286,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx.borrow_mut(), - impl_m_span, - impl_m_body_id, - &trait_sig); + inh.normalize_associated_types_in(impl_m_span, + impl_m_body_id, + &trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -344,7 +337,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { + if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { infcx.report_fulfillment_errors(errors); return Err(ErrorReported); } @@ -731,7 +724,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { - let mut fulfillment_cx = traits::FulfillmentContext::new(); + let inh = Inherited::new(infcx); + let infcx = &inh.infcx; // The below is for the most part highly similar to the procedure // for methods above. It is simpler in many respects, especially @@ -761,31 +755,21 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs); let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id); - let err = infcx.commit_if_ok(|_| { - // There is no "body" here, so just pass dummy id. - let impl_ty = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_c_span, - ast::CRATE_NODE_ID, - &impl_ty); + // There is no "body" here, so just pass dummy id. + let impl_ty = inh.normalize_associated_types_in(impl_c_span, + impl_c_node_id, + &impl_ty); - debug!("compare_const_impl: impl_ty={:?}", impl_ty); + debug!("compare_const_impl: impl_ty={:?}", impl_ty); - let trait_ty = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_c_span, - ast::CRATE_NODE_ID, - &trait_ty); + let trait_ty = inh.normalize_associated_types_in(impl_c_span, + impl_c_node_id, + &trait_ty); - debug!("compare_const_impl: trait_ty={:?}", trait_ty); + debug!("compare_const_impl: trait_ty={:?}", trait_ty); - infcx.sub_types(false, &cause, impl_ty, trait_ty) - .map(|InferOk { obligations, value: () }| { - for obligation in obligations { - fulfillment_cx.register_predicate_obligation(&infcx, obligation); - } - }) - }); + let err = infcx.sub_types(false, &cause, impl_ty, trait_ty) + .map(|ok| inh.register_infer_ok_obligations(ok)); if let Err(terr) = err { debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", @@ -822,5 +806,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &terr); diag.emit(); } + + // FIXME(#41323) Check the obligations in the fulfillment context. }); } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 28ac335cf195a..26ba965fe5cc6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { assert_eq!(n, pick.autoderefs); autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, &[self.self_expr]); + autoderef.finalize(LvaluePreference::NoPreference, self.self_expr); let target = pick.unsize.unwrap_or(autoderefd_ty); let target = target.adjust_for_autoref(self.tcx, autoref); @@ -445,7 +445,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { "expr was deref-able {} times but now isn't?", autoderefs); }); - autoderef.finalize(PreferMutLvalue, &[expr]); + autoderef.finalize(PreferMutLvalue, expr); } } Some(_) | None => {} @@ -543,7 +543,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { Some(&base_expr), self.node_ty(base_expr.id), PreferMutLvalue); - let method = method.expect("re-trying deref failed"); + let ok = method.expect("re-trying deref failed"); + let method = self.register_infer_ok_obligations(ok); self.tables.borrow_mut().method_map.insert(method_call, method); } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 9ecf0ffa71ebd..7dd2699a6eaf0 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -17,7 +17,8 @@ use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; -use rustc::infer; +use rustc::ty::subst::Subst; +use rustc::infer::{self, InferOk}; use syntax::ast; use syntax_pos::Span; @@ -159,7 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, self_ty: ty::Ty<'tcx>, opt_input_types: Option>>) - -> Option> { + -> Option>> { self.lookup_method_in_trait_adjusted(span, self_expr, m_name, @@ -190,7 +191,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { unsize: bool, self_ty: ty::Ty<'tcx>, opt_input_types: Option>>) - -> Option> { + -> Option>> { debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \ m_name={}, trait_def_id={:?})", self_ty, @@ -236,6 +237,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert_eq!(generics.regions.len(), 0); debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); + let mut obligations = vec![]; // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -248,10 +250,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &fn_sig).0; - let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); + let fn_sig = fn_sig.subst(self.tcx, substs); + let fn_sig = match self.normalize_associated_types_in_as_infer_ok(span, &fn_sig) { + InferOk { value, obligations: o } => { + obligations.extend(o); + value + } + }; let transformed_self_ty = fn_sig.inputs()[0]; - let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs, - ty::Binder(fn_sig)); + let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig)); debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", method_ty, @@ -265,18 +272,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = self.instantiate_bounds(span, def_id, trait_ref.substs); - assert!(!method_bounds.has_escaping_regions()); - self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id), - &method_bounds); + let bounds = self.tcx.item_predicates(def_id).instantiate(self.tcx, substs); + let bounds = match self.normalize_associated_types_in_as_infer_ok(span, &bounds) { + InferOk { value, obligations: o } => { + obligations.extend(o); + value + } + }; + assert!(!bounds.has_escaping_regions()); - // Also register an obligation for the method type being well-formed. - self.register_wf_obligation(method_ty, span, traits::MiscObligation); + let cause = traits::ObligationCause::misc(span, self.body_id); + obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds)); - // FIXME(#18653) -- Try to resolve obligations, giving us more - // typing information, which can sometimes be needed to avoid - // pathological region inference failures. - self.select_obligations_where_possible(); + // Also add an obligation for the method type being well-formed. + obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty))); // Insert any adjustments needed (always an autoref of some mutability). if let Some(self_expr) = self_expr { @@ -317,7 +326,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("callee = {:?}", callee); - Some(callee) + Some(InferOk { + obligations, + value: callee + }) } pub fn resolve_ufcs(&self, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 32aeeeb110556..902cfb889f8c2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -128,7 +128,6 @@ use rustc_back::slice; use rustc::middle::const_val::eval_length; use rustc_const_math::ConstInt; -mod assoc; mod autoderef; pub mod dropck; pub mod _match; @@ -536,7 +535,7 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { - pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { + fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { Inherited { infcx: infcx, fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), @@ -547,20 +546,55 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { } } + fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { + debug!("register_predicate({:?})", obligation); + if obligation.has_escaping_regions() { + span_bug!(obligation.cause.span, "escaping regions in predicate {:?}", + obligation); + } + self.fulfillment_cx + .borrow_mut() + .register_predicate_obligation(self, obligation); + } + + fn register_predicates(&self, obligations: Vec>) { + for obligation in obligations { + self.register_predicate(obligation); + } + } + + fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + self.register_predicates(infer_ok.obligations); + infer_ok.value + } + fn normalize_associated_types_in(&self, span: Span, body_id: ast::NodeId, - value: &T) - -> T + value: &T) -> T where T : TypeFoldable<'tcx> { - assoc::normalize_associated_types_in(self, - &mut self.fulfillment_cx.borrow_mut(), - span, - body_id, - value) + let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, value); + self.register_infer_ok_obligations(ok) } + fn normalize_associated_types_in_as_infer_ok(&self, + span: Span, + body_id: ast::NodeId, + value: &T) + -> InferOk<'tcx, T> + where T : TypeFoldable<'tcx> + { + debug!("normalize_associated_types_in(value={:?})", value); + let mut selcx = traits::SelectionContext::new(self); + let cause = ObligationCause::misc(span, body_id); + let traits::Normalized { value, obligations } = + traits::normalize(&mut selcx, cause, value); + debug!("normalize_associated_types_in: result={:?} predicates={:?}", + value, + obligations); + InferOk { value, obligations } + } } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } @@ -1713,14 +1747,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> ty::InstantiatedPredicates<'tcx> { let bounds = self.tcx.item_predicates(def_id); let result = bounds.instantiate(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &result.predicates); + let result = self.normalize_associated_types_in(span, &result); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result); - ty::InstantiatedPredicates { - predicates: result - } + result } /// Replace all anonymized types with fresh inference variables @@ -1763,7 +1795,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn normalize_associated_types_in(&self, span: Span, value: &T) -> T where T : TypeFoldable<'tcx> { - self.inh.normalize_associated_types_in(span, self.body_id, value) + let ok = self.normalize_associated_types_in_as_infer_ok(span, value); + self.register_infer_ok_obligations(ok) + } + + fn normalize_associated_types_in_as_infer_ok(&self, span: Span, value: &T) + -> InferOk<'tcx, T> + where T : TypeFoldable<'tcx> + { + self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, value) } pub fn write_nil(&self, node_id: ast::NodeId) { @@ -1804,32 +1844,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .register_bound(self, ty, def_id, cause); } - pub fn register_predicate(&self, - obligation: traits::PredicateObligation<'tcx>) - { - debug!("register_predicate({:?})", obligation); - if obligation.has_escaping_regions() { - span_bug!(obligation.cause.span, "escaping regions in predicate {:?}", - obligation); - } - self.fulfillment_cx - .borrow_mut() - .register_predicate_obligation(self, obligation); - } - - pub fn register_predicates(&self, - obligations: Vec>) - { - for obligation in obligations { - self.register_predicate(obligation); - } - } - - pub fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { - self.register_predicates(infer_ok.obligations); - infer_ok.value - } - pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { let t = AstConv::ast_ty_to_ty(self, ast_t); self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); @@ -2072,12 +2086,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, base_expr, adj_ty, autoderefs, false, lvalue_pref, idx_ty) { - autoderef.finalize(lvalue_pref, &[base_expr]); + autoderef.finalize(lvalue_pref, base_expr); return Some(final_mt); } if let ty::TyArray(element_ty, _) = adj_ty.sty { - autoderef.finalize(lvalue_pref, &[base_expr]); + autoderef.finalize(lvalue_pref, base_expr); let adjusted_ty = self.tcx.mk_slice(element_ty); return self.try_index_step( MethodCall::expr(expr.id), expr, base_expr, @@ -2161,8 +2175,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - method.map(|method| { + method.map(|ok| { debug!("try_index_step: success, using overloaded indexing"); + let method = self.register_infer_ok_obligations(ok); self.tables.borrow_mut().method_map.insert(method_call, method); (input_ty, self.make_overloaded_lvalue_return_type(method).ty) }) @@ -2586,7 +2601,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // we can. We don't care if some things turn // out unconstrained or ambiguous, as we're // just trying to get hints here. - let result = self.save_and_restore_obligations_in_snapshot_flag(|_| { + let result = self.save_and_restore_in_snapshot_flag(|_| { let mut fulfill = FulfillmentContext::new(); let ok = ok; // FIXME(#30046) for obligation in ok.obligations { @@ -2755,7 +2770,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field) = base_def.struct_variant().find_field_named(field.node) { let field_ty = self.field_ty(expr.span, field, substs); if self.tcx.vis_is_accessible_from(field.vis, self.body_id) { - autoderef.finalize(lvalue_pref, &[base]); + autoderef.finalize(lvalue_pref, base); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -2879,7 +2894,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - autoderef.finalize(lvalue_pref, &[base]); + autoderef.finalize(lvalue_pref, base); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } @@ -3292,8 +3307,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { oprnd_t = mt.ty; - } else if let Some(method) = self.try_overloaded_deref( + } else if let Some(ok) = self.try_overloaded_deref( expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { + let method = self.register_infer_ok_obligations(ok); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), method); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index cc33bd8754d9e..42296006b79d1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -398,20 +398,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match trait_did { Some(trait_did) => { - self.lookup_method_in_trait_adjusted(expr.span, - Some(lhs_expr), - opname, - trait_did, - 0, - false, - lhs_ty, - Some(other_tys)) + self.lookup_method_in_trait(expr.span, + Some(lhs_expr), + opname, + trait_did, + lhs_ty, + Some(other_tys)) } None => None }; match method { - Some(method) => { + Some(ok) => { + let method = self.register_infer_ok_obligations(ok); + self.select_obligations_where_possible(); + let method_ty = method.ty; // HACK(eddyb) Fully qualified path to work around a resolve bug. diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 7fffbd14e2160..f196aa82b1ef3 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -11,22 +11,18 @@ // Type resolution: the phase that finds all the types in the AST with // unresolved type variables and replaces "ty_var" types with their // substitutions. -use self::ResolveReason::*; use check::FnCtxt; +use rustc::hir; +use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::infer::{InferCtxt}; use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::fold::{TypeFolder,TypeFoldable}; -use rustc::infer::{InferCtxt, FixupError}; use rustc::util::nodemap::{DefIdMap, DefIdSet}; - -use std::mem; - use syntax::ast; use syntax_pos::Span; - -use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::hir; +use std::mem; /////////////////////////////////////////////////////////////////////////// // Entry point @@ -37,9 +33,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let item_id = self.tcx.hir.body_owner(body.id()); let item_def_id = self.tcx.hir.local_def_id(item_id); - let mut wbcx = WritebackCx::new(self); + let mut wbcx = WritebackCx::new(self, body); for arg in &body.arguments { - wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); + wbcx.visit_node_id(arg.pat.span, arg.id); } wbcx.visit_body(body); wbcx.visit_upvar_borrow_map(); @@ -80,15 +76,19 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { // early-bound versions of them, visible from the // outside of the function. This is needed by, and // only populated if there are any `impl Trait`. - free_to_bound_regions: DefIdMap<&'gcx ty::Region> + free_to_bound_regions: DefIdMap<&'gcx ty::Region>, + + body: &'gcx hir::Body, } impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { - fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> { + fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body) + -> WritebackCx<'cx, 'gcx, 'tcx> { let mut wbcx = WritebackCx { fcx: fcx, tables: ty::TypeckTables::empty(), - free_to_bound_regions: DefIdMap() + free_to_bound_regions: DefIdMap(), + body: body }; // Only build the reverse mapping if `impl Trait` is used. @@ -195,21 +195,20 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_stmt(&mut self, s: &'gcx hir::Stmt) { - self.visit_node_id(ResolvingExpr(s.span), s.node.id()); + self.visit_node_id(s.span, s.node.id()); intravisit::walk_stmt(self, s); } fn visit_expr(&mut self, e: &'gcx hir::Expr) { self.fix_scalar_builtin_expr(e); - self.visit_node_id(ResolvingExpr(e.span), e.id); - self.visit_method_map_entry(ResolvingExpr(e.span), - MethodCall::expr(e.id)); + self.visit_node_id(e.span, e.id); + self.visit_method_map_entry(e.span, MethodCall::expr(e.id)); if let hir::ExprClosure(_, _, body, _) = e.node { let body = self.fcx.tcx.hir.body(body); for arg in &body.arguments { - self.visit_node_id(ResolvingExpr(e.span), arg.id); + self.visit_node_id(e.span, arg.id); } self.visit_body(body); @@ -219,20 +218,20 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_block(&mut self, b: &'gcx hir::Block) { - self.visit_node_id(ResolvingExpr(b.span), b.id); + self.visit_node_id(b.span, b.id); intravisit::walk_block(self, b); } fn visit_pat(&mut self, p: &'gcx hir::Pat) { - self.visit_node_id(ResolvingPattern(p.span), p.id); + self.visit_node_id(p.span, p.id); intravisit::walk_pat(self, p); } fn visit_local(&mut self, l: &'gcx hir::Local) { + intravisit::walk_local(self, l); let var_ty = self.fcx.local_ty(l.span, l.id); - let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span)); + let var_ty = self.resolve(&var_ty, &l.span); self.write_ty_to_tables(l.id, var_ty); - intravisit::walk_local(self, l); } } @@ -243,7 +242,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, ty::UpvarCapture::ByRef(ref upvar_borrow) => { let r = upvar_borrow.region; - let r = self.resolve(&r, ResolvingUpvar(*upvar_id)); + let r = self.resolve(&r, &upvar_id.var_id); ty::UpvarCapture::ByRef( ty::UpvarBorrow { kind: upvar_borrow.kind, region: r }) } @@ -257,7 +256,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_closures(&mut self) { for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() { - let closure_ty = self.resolve(closure_ty, ResolvingClosure(id)); + let closure_ty = self.resolve(closure_ty, &id); self.tables.closure_tys.insert(id, closure_ty); } @@ -282,8 +281,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_anon_types(&mut self) { let gcx = self.tcx().global_tcx(); for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { - let reason = ResolvingAnonTy(node_id); - let inside_ty = self.resolve(&concrete_ty, reason); + let inside_ty = self.resolve(&concrete_ty, &node_id); // Convert the type from the function into a type valid outside // the function, by replacing free regions with early-bound ones. @@ -305,7 +303,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ty::ReLateBound(..) | ty::ReScope(_) | ty::ReSkolemized(..) => { - let span = reason.span(self.tcx()); + let span = node_id.to_span(&self.fcx.tcx); span_err!(self.tcx().sess, span, E0564, "only named lifetimes are allowed in `impl Trait`, \ but `{}` was found in the type `{}`", r, inside_ty); @@ -314,7 +312,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ty::ReVar(_) | ty::ReErased => { - let span = reason.span(self.tcx()); + let span = node_id.to_span(&self.fcx.tcx); span_bug!(span, "invalid region in impl Trait: {:?}", r); } } @@ -324,37 +322,37 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn visit_node_id(&mut self, reason: ResolveReason, id: ast::NodeId) { + fn visit_node_id(&mut self, span: Span, node_id: ast::NodeId) { // Export associated path extensions. - if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&id) { - self.tables.type_relative_path_defs.insert(id, def); + if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&node_id) { + self.tables.type_relative_path_defs.insert(node_id, def); } - // Resolve any borrowings for the node with id `id` - self.visit_adjustments(reason, id); + // Resolve any borrowings for the node with id `node_id` + self.visit_adjustments(span, node_id); - // Resolve the type of the node with id `id` - let n_ty = self.fcx.node_ty(id); - let n_ty = self.resolve(&n_ty, reason); - self.write_ty_to_tables(id, n_ty); - debug!("Node {} has type {:?}", id, n_ty); + // Resolve the type of the node with id `node_id` + let n_ty = self.fcx.node_ty(node_id); + let n_ty = self.resolve(&n_ty, &span); + self.write_ty_to_tables(node_id, n_ty); + debug!("Node {} has type {:?}", node_id, n_ty); // Resolve any substitutions - self.fcx.opt_node_ty_substs(id, |item_substs| { - let item_substs = self.resolve(item_substs, reason); + self.fcx.opt_node_ty_substs(node_id, |item_substs| { + let item_substs = self.resolve(item_substs, &span); if !item_substs.is_noop() { - debug!("write_substs_to_tcx({}, {:?})", id, item_substs); + debug!("write_substs_to_tcx({}, {:?})", node_id, item_substs); assert!(!item_substs.substs.needs_infer()); - self.tables.item_substs.insert(id, item_substs); + self.tables.item_substs.insert(node_id, item_substs); } }); } - fn visit_adjustments(&mut self, reason: ResolveReason, id: ast::NodeId) { - let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&id); + fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) { + let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&node_id); match adjustments { None => { - debug!("No adjustments for node {}", id); + debug!("No adjustments for node {}", node_id); } Some(adjustment) => { @@ -381,29 +379,29 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { for autoderef in 0..autoderefs { - let method_call = MethodCall::autoderef(id, autoderef as u32); - self.visit_method_map_entry(reason, method_call); + let method_call = MethodCall::autoderef(node_id, autoderef as u32); + self.visit_method_map_entry(span, method_call); } adjustment::Adjust::DerefRef { autoderefs: autoderefs, - autoref: self.resolve(&autoref, reason), + autoref: self.resolve(&autoref, &span), unsize: unsize, } } }; let resolved_adjustment = adjustment::Adjustment { kind: resolved_adjustment, - target: self.resolve(&adjustment.target, reason) + target: self.resolve(&adjustment.target, &span) }; - debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); - self.tables.adjustments.insert(id, resolved_adjustment); + debug!("Adjustments for node {}: {:?}", node_id, resolved_adjustment); + self.tables.adjustments.insert(node_id, resolved_adjustment); } } } fn visit_method_map_entry(&mut self, - reason: ResolveReason, + method_span: Span, method_call: MethodCall) { // Resolve any method map entry let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) { @@ -413,8 +411,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { method); let new_method = MethodCallee { def_id: method.def_id, - ty: self.resolve(&method.ty, reason), - substs: self.resolve(&method.substs, reason), + ty: self.resolve(&method.ty, &method_span), + substs: self.resolve(&method.substs, &method_span), }; Some(new_method) @@ -430,72 +428,49 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_liberated_fn_sigs(&mut self) { for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() { - let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id)); + let fn_sig = self.resolve(fn_sig, &node_id); self.tables.liberated_fn_sigs.insert(node_id, fn_sig.clone()); } } fn visit_fru_field_types(&mut self) { for (&node_id, ftys) in self.fcx.tables.borrow().fru_field_types.iter() { - let ftys = self.resolve(ftys, ResolvingFieldTypes(node_id)); + let ftys = self.resolve(ftys, &node_id); self.tables.fru_field_types.insert(node_id, ftys); } } fn visit_type_nodes(&self) { for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() { - let ty = self.resolve(ty, ResolvingTyNode(id)); + let ty = self.resolve(ty, &id); self.fcx.tcx.ast_ty_to_ty_cache.borrow_mut().insert(id, ty); } } - fn resolve(&self, x: &T, reason: ResolveReason) -> T::Lifted + fn resolve(&self, x: &T, span: &Locatable) -> T::Lifted where T: TypeFoldable<'tcx> + ty::Lift<'gcx> { - let x = x.fold_with(&mut Resolver::new(self.fcx, reason)); + let x = x.fold_with(&mut Resolver::new(self.fcx, span, self.body)); if let Some(lifted) = self.tcx().lift_to_global(&x) { lifted } else { - span_bug!(reason.span(self.tcx()), - "writeback: `{:?}` missing from the global type context", x); + span_bug!(span.to_span(&self.fcx.tcx), + "writeback: `{:?}` missing from the global type context", + x); } } } -/////////////////////////////////////////////////////////////////////////// -// Resolution reason. - -#[derive(Copy, Clone, Debug)] -enum ResolveReason { - ResolvingExpr(Span), - ResolvingLocal(Span), - ResolvingPattern(Span), - ResolvingUpvar(ty::UpvarId), - ResolvingClosure(ast::NodeId), - ResolvingFnSig(ast::NodeId), - ResolvingFieldTypes(ast::NodeId), - ResolvingAnonTy(ast::NodeId), - ResolvingTyNode(ast::NodeId), +trait Locatable { + fn to_span(&self, tcx: &TyCtxt) -> Span; } -impl<'a, 'gcx, 'tcx> ResolveReason { - fn span(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Span { - match *self { - ResolvingExpr(s) => s, - ResolvingLocal(s) => s, - ResolvingPattern(s) => s, - ResolvingUpvar(upvar_id) => { - tcx.expr_span(upvar_id.closure_expr_id) - } - ResolvingClosure(id) | - ResolvingFnSig(id) | - ResolvingFieldTypes(id) | - ResolvingTyNode(id) | - ResolvingAnonTy(id) => { - tcx.hir.span(id) - } - } - } +impl Locatable for Span { + fn to_span(&self, _: &TyCtxt) -> Span { *self } +} + +impl Locatable for ast::NodeId { + fn to_span(&self, tcx: &TyCtxt) -> Span { tcx.hir.span(*self) } } /////////////////////////////////////////////////////////////////////////// @@ -505,82 +480,25 @@ impl<'a, 'gcx, 'tcx> ResolveReason { struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'gcx, 'tcx>, infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, - reason: ResolveReason, + span: &'cx Locatable, + body: &'gcx hir::Body, } impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> { - fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, - reason: ResolveReason) - -> Resolver<'cx, 'gcx, 'tcx> + fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, span: &'cx Locatable, body: &'gcx hir::Body) + -> Resolver<'cx, 'gcx, 'tcx> { - Resolver::from_infcx(fcx, reason) - } - - fn from_infcx(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, - reason: ResolveReason) - -> Resolver<'cx, 'gcx, 'tcx> - { - Resolver { infcx: infcx, - tcx: infcx.tcx, - reason: reason } + Resolver { + tcx: fcx.tcx, + infcx: fcx, + span: span, + body: body, + } } - fn report_error(&self, e: FixupError) { + fn report_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { - match self.reason { - ResolvingExpr(span) => { - struct_span_err!( - self.tcx.sess, span, E0101, - "cannot determine a type for this expression: {}", e) - .span_label(span, &format!("cannot resolve type of expression")) - .emit(); - } - - ResolvingLocal(span) => { - struct_span_err!( - self.tcx.sess, span, E0102, - "cannot determine a type for this local variable: {}", e) - .span_label(span, &format!("cannot resolve type of variable")) - .emit(); - } - - ResolvingPattern(span) => { - span_err!(self.tcx.sess, span, E0103, - "cannot determine a type for this pattern binding: {}", e); - } - - ResolvingUpvar(upvar_id) => { - let span = self.reason.span(self.tcx); - span_err!(self.tcx.sess, span, E0104, - "cannot resolve lifetime for captured variable `{}`: {}", - self.tcx.local_var_name_str(upvar_id.var_id), e); - } - - ResolvingClosure(_) => { - let span = self.reason.span(self.tcx); - span_err!(self.tcx.sess, span, E0196, - "cannot determine a type for this closure") - } - - ResolvingFnSig(_) | - ResolvingFieldTypes(_) | - ResolvingTyNode(_) => { - // any failures here should also fail when - // resolving the patterns, closure types, or - // something else. - let span = self.reason.span(self.tcx); - self.tcx.sess.delay_span_bug( - span, - &format!("cannot resolve some aspect of data for {:?}: {}", - self.reason, e)); - } - - ResolvingAnonTy(_) => { - let span = self.reason.span(self.tcx); - span_err!(self.tcx.sess, span, E0563, - "cannot determine a type for this `impl Trait`: {}", e) - } - } + self.infcx.need_type_info(self.body.id(), self.span.to_span(&self.tcx), t); } } } @@ -593,20 +511,21 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match self.infcx.fully_resolve(&t) { Ok(t) => t, - Err(e) => { + Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); - self.report_error(e); + self.report_error(t); self.tcx().types.err } } } + // FIXME This should be carefully checked + // We could use `self.report_error` but it doesn't accept a ty::Region, right now. fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { match self.infcx.fully_resolve(&r) { Ok(r) => r, - Err(e) => { - self.report_error(e); + Err(_) => { self.tcx.mk_region(ty::ReStatic) } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 2d72052f1e5ad..68afcae2b6746 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1351,50 +1351,6 @@ extern "rust-intrinsic" { ``` "##, -E0101: r##" -You hit this error because the compiler lacks the information to -determine a type for this expression. Erroneous code example: - -```compile_fail,E0101 -let x = |_| {}; // error: cannot determine a type for this expression -``` - -You have two possibilities to solve this situation: - -* Give an explicit definition of the expression -* Infer the expression - -Examples: - -``` -let x = |_ : u32| {}; // ok! -// or: -let x = |_| {}; -x(0u32); -``` -"##, - -E0102: r##" -You hit this error because the compiler lacks the information to -determine the type of this variable. Erroneous code example: - -```compile_fail,E0282 -// could be an array of anything -let x = []; // error: cannot determine a type for this local variable -``` - -To solve this situation, constrain the type of the variable. -Examples: - -``` -#![allow(unused_variables)] - -fn main() { - let x: [u8; 0] = []; -} -``` -"##, - E0107: r##" This error means that an incorrect number of lifetime parameters were provided for a type (like a struct or enum) or trait: @@ -4146,8 +4102,8 @@ register_diagnostics! { // E0068, // E0085, // E0086, - E0103, // @GuillaumeGomez: I was unable to get this error, try your best! - E0104, +// E0103, +// E0104, // E0123, // E0127, // E0129, @@ -4164,7 +4120,7 @@ register_diagnostics! { // E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object // E0190, // deprecated: can only cast a &-pointer to an &-object - E0196, // cannot determine a type for this closure +// E0196, // cannot determine a type for this closure E0203, // type parameter has more than one relaxed default bound, // and only one is supported E0208, diff --git a/src/libstd/path.rs b/src/libstd/path.rs index db446d88900c1..22889b5de4c2a 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -10,11 +10,18 @@ //! Cross-platform path manipulation. //! -//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] +//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] //! and [`str`]), for working with paths abstractly. These types are thin wrappers //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. //! +//! Paths can be parsed into [`Component`]s by iterating over the structure +//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly +//! correspond to the substrings between path separators (`/` or `\`). You can +//! reconstruct an equivalent path from components with the [`push`] method on +//! [`PathBuf`]; note that the paths may differ syntactically by the +//! normalization described in the documentation for the [`components`] method. +//! //! ## Simple usage //! //! Path manipulation includes both parsing components from slices and building @@ -50,62 +57,11 @@ //! path.set_extension("dll"); //! ``` //! -//! ## Path components and normalization -//! -//! The path APIs are built around the notion of "components", which roughly -//! correspond to the substrings between path separators (`/` and, on Windows, -//! `\`). The APIs for path parsing are largely specified in terms of the path's -//! components, so it's important to clearly understand how those are -//! determined. -//! -//! A path can always be reconstructed into an *equivalent* path by -//! putting together its components via `push`. Syntactically, the -//! paths may differ by the normalization described below. -//! -//! ### Component types -//! -//! Components come in several types: -//! -//! * Normal components are the default: standard references to files or -//! directories. The path `a/b` has two normal components, `a` and `b`. -//! -//! * Current directory components represent the `.` character. For example, -//! `./a` has a current directory component and a normal component `a`. -//! -//! * The root directory component represents a separator that designates -//! starting from root. For example, `/a/b` has a root directory component -//! followed by normal components `a` and `b`. -//! -//! On Windows, an additional component type comes into play: -//! -//! * Prefix components, of which there is a large variety. For example, `C:` -//! and `\\server\share` are prefixes. The path `C:windows` has a prefix -//! component `C:` and a normal component `windows`; the path `C:\windows` has a -//! prefix component `C:`, a root directory component, and a normal component -//! `windows`. -//! -//! ### Normalization -//! -//! Aside from splitting on the separator(s), there is a small amount of -//! "normalization": -//! -//! * Repeated separators are ignored: `a/b` and `a//b` both have components `a` -//! and `b`. -//! -//! * Occurrences of `.` are normalized away, *except* if they are at -//! the beginning of the path (in which case they are often meaningful -//! in terms of path searching). So, for example, `a/./b`, `a/b/`, -//! `/a/b/.` and `a/b` all have components `a` and `b`, but `./a/b` -//! has a leading current directory component. -//! -//! No other normalization takes place by default. In particular, -//! `a/c` and `a/b/../c` are distinct, to account for the possibility -//! that `b` is a symbolic link (so its parent isn't `a`). Further -//! normalization is possible to build on top of the components APIs, -//! and will be included in this library in the near future. -//! +//! [`Component`]: ../../std/path/enum.Component.html +//! [`components`]: ../../std/path/struct.Path.html#method.components //! [`PathBuf`]: ../../std/path/struct.PathBuf.html //! [`Path`]: ../../std/path/struct.Path.html +//! [`push`]: ../../std/path/struct.PathBuf.html#method.push //! [`String`]: ../../std/string/struct.String.html //! [`str`]: ../../std/primitive.str.html //! [`OsString`]: ../../std/ffi/struct.OsString.html @@ -143,36 +99,81 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// -/// Path prefixes (Windows only). +/// Windows path prefixes, e.g. `C:` or `\\server\share`. /// -/// Windows uses a variety of path styles, including references to drive -/// volumes (like `C:`), network shared folders (like `\\server\share`) and -/// others. In addition, some path prefixes are "verbatim", in which case -/// `/` is *not* treated as a separator and essentially no normalization is -/// performed. +/// Windows uses a variety of path prefix styles, including references to drive +/// volumes (like `C:`), network shared folders (like `\\server\share`), and +/// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with +/// `\\?\`), in which case `/` is *not* treated as a separator and essentially +/// no normalization is performed. +/// +/// # Examples +/// +/// ``` +/// use std::path::{Component, Path, Prefix}; +/// use std::path::Prefix::*; +/// use std::ffi::OsStr; +/// +/// fn get_path_prefix(s: &str) -> Prefix { +/// let path = Path::new(s); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => prefix_component.kind(), +/// _ => panic!(), +/// } +/// } +/// +/// # if cfg!(windows) { +/// assert_eq!(Verbatim(OsStr::new("pictures")), +/// get_path_prefix(r"\\?\pictures\kittens")); +/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\?\UNC\server\share")); +/// assert_eq!(VerbatimDisk('C' as u8), get_path_prefix(r"\\?\c:\")); +/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")), +/// get_path_prefix(r"\\.\BrainInterface")); +/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\server\share")); +/// assert_eq!(Disk('C' as u8), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris")); +/// # } +/// ``` #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Prefix<'a> { - /// Prefix `\\?\`, together with the given component immediately following it. + /// Verbatim prefix, e.g. `\\?\cat_pics`. + /// + /// Verbatim prefixes consist of `\\?\` immediately followed by the given + /// component. #[stable(feature = "rust1", since = "1.0.0")] Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\?\UNC\`, with the "server" and "share" components following it. + /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_, + /// e.g. `\\?\UNC\server\share`. + /// + /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the + /// server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] VerbatimUNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, ), - /// Prefix like `\\?\C:\`, for the given drive letter + /// Verbatim disk prefix, e.g. `\\?\C:\`. + /// + /// Verbatim disk prefixes consist of `\\?\` immediately followed by the + /// drive letter and `:\`. #[stable(feature = "rust1", since = "1.0.0")] VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8), - /// Prefix `\\.\`, together with the given component immediately following it. + /// Device namespace prefix, e.g. `\\.\COM42`. + /// + /// Device namespace prefixes consist of `\\.\` immediately followed by the + /// device name. #[stable(feature = "rust1", since = "1.0.0")] DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\server\share`, with the given "server" and "share" components. + /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g. + /// `\\server\share`. + /// + /// UNC prefixes consist of the server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] UNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, @@ -217,6 +218,20 @@ impl<'a> Prefix<'a> { } /// Determines if the prefix is verbatim, i.e. begins with `\\?\`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Prefix::*; + /// use std::ffi::OsStr; + /// + /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim()); + /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(VerbatimDisk('C' as u8).is_verbatim()); + /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim()); + /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(!Disk('C' as u8).is_verbatim()); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { @@ -356,9 +371,42 @@ enum State { Done = 3, } -/// A Windows path prefix, e.g. `C:` or `\\server\share`. +/// A structure wrapping a Windows path prefix as well as its unparsed string +/// representation. +/// +/// In addition to the parsed [`Prefix`] information returned by [`kind`], +/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice, +/// returned by [`as_os_str`]. +/// +/// Instances of this `struct` can be obtained by matching against the +/// [`Prefix` variant] on [`Component`]. /// /// Does not occur on Unix. +/// +/// # Examples +/// +/// ``` +/// # if cfg!(windows) { +/// use std::path::{Component, Path, Prefix}; +/// use std::ffi::OsStr; +/// +/// let path = Path::new(r"c:\you\later\"); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => { +/// assert_eq!(Prefix::Disk('C' as u8), prefix_component.kind()); +/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str()); +/// } +/// _ => unreachable!(), +/// } +/// # } +/// ``` +/// +/// [`as_os_str`]: #method.as_os_str +/// [`Component`]: enum.Component.html +/// [`kind`]: #method.kind +/// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Prefix` variant]: enum.Component.html#variant.Prefix +/// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Eq, Debug)] pub struct PrefixComponent<'a> { @@ -370,13 +418,20 @@ pub struct PrefixComponent<'a> { } impl<'a> PrefixComponent<'a> { - /// The parsed prefix data. + /// Returns the parsed prefix data. + /// + /// See [`Prefix`]'s documentation for more information on the different + /// kinds of prefixes. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> Prefix<'a> { self.parsed } - /// The raw `OsStr` slice for this prefix. + /// Returns the raw [`OsStr`] slice for this prefix. + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &'a OsStr { self.raw @@ -413,11 +468,11 @@ impl<'a> Hash for PrefixComponent<'a> { /// A single component of a path. /// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. +/// A `Component` roughtly corresponds to a substring between path separators +/// (`/` or `\`). /// -/// This `enum` is created from iterating over the [`path::Components`] -/// `struct`. +/// This `enum` is created by iterating over [`Components`], which in turn is +/// created by the [`components`][`Path::components`] method on [`Path`]. /// /// # Examples /// @@ -434,37 +489,49 @@ impl<'a> Hash for PrefixComponent<'a> { /// ]); /// ``` /// -/// [`path::Components`]: struct.Components.html +/// [`Components`]: struct.Components.html +/// [`Path`]: struct.Path.html +/// [`Path::components`]: struct.Path.html#method.components #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Component<'a> { /// A Windows path prefix, e.g. `C:` or `\\server\share`. /// + /// There is a large variety of prefix types, see [`Prefix`]'s documentation + /// for more. + /// /// Does not occur on Unix. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] Prefix( #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a> ), - /// The root directory component, appears after any prefix and before anything else + /// The root directory component, appears after any prefix and before anything else. + /// + /// It represents a separator that designates that a path starts from root. #[stable(feature = "rust1", since = "1.0.0")] RootDir, - /// A reference to the current directory, i.e. `.` + /// A reference to the current directory, i.e. `.`. #[stable(feature = "rust1", since = "1.0.0")] CurDir, - /// A reference to the parent directory, i.e. `..` + /// A reference to the parent directory, i.e. `..`. #[stable(feature = "rust1", since = "1.0.0")] ParentDir, - /// A normal component, i.e. `a` and `b` in `a/b` + /// A normal component, e.g. `a` and `b` in `a/b`. + /// + /// This variant is the most common one, it represents references to files + /// or directories. #[stable(feature = "rust1", since = "1.0.0")] Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), } impl<'a> Component<'a> { - /// Extracts the underlying `OsStr` slice. + /// Extracts the underlying [`OsStr`] slice. /// /// # Examples /// @@ -475,6 +542,8 @@ impl<'a> Component<'a> { /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); /// ``` + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { @@ -494,12 +563,10 @@ impl<'a> AsRef for Component<'a> { } } -/// The core iterator giving the components of a path. -/// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. +/// An interator over the [`Component`]s of a [`Path`]. /// -/// This `struct` is created by the [`path::Path::components`] method. +/// This `struct` is created by the [`components`] method on [`Path`]. +/// See its documentation for more. /// /// # Examples /// @@ -513,7 +580,9 @@ impl<'a> AsRef for Component<'a> { /// } /// ``` /// -/// [`path::Path::components`]: struct.Path.html#method.components +/// [`Component`]: enum.Component.html +/// [`components`]: struct.Path.html#method.components +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { @@ -534,9 +603,15 @@ pub struct Components<'a> { back: State, } -/// An iterator over the components of a path, as [`OsStr`] slices. +/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices. /// +/// This `struct` is created by the [`iter`] method on [`Path`]. +/// See its documentation for more. +/// +/// [`Component`]: enum.Component.html +/// [`iter`]: struct.Path.html#method.iter /// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a> { @@ -762,6 +837,18 @@ impl<'a> fmt::Debug for Iter<'a> { impl<'a> Iter<'a> { /// Extracts a slice corresponding to the portion of the path remaining for iteration. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let mut iter = Path::new("/tmp/foo/bar.txt").iter(); + /// iter.next(); + /// iter.next(); + /// + /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -1067,9 +1154,10 @@ impl PathBuf { /// Truncate `self` to [`self.parent`]. /// - /// Returns false and does nothing if [`self.file_name`] is `None`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`]. /// Otherwise, returns `true`. /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`self.parent`]: struct.PathBuf.html#method.parent /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// @@ -1132,10 +1220,11 @@ impl PathBuf { /// Updates [`self.extension`] to `extension`. /// - /// If [`self.file_name`] is `None`, does nothing and returns `false`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`], + /// returns `true` and updates the extension otherwise. /// - /// Otherwise, returns `true`; if [`self.extension`] is [`None`], the - /// extension is added; otherwise it is replaced. + /// If [`self.extension`] is [`None`], the extension is added; otherwise + /// it is replaced. /// /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// [`self.extension`]: struct.PathBuf.html#method.extension @@ -1195,7 +1284,10 @@ impl PathBuf { self.inner } - /// Converts this `PathBuf` into a boxed `Path`. + /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`]. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`Path`]: struct.Path.html #[unstable(feature = "into_boxed_path", issue = "40380")] pub fn into_boxed_path(self) -> Box { unsafe { mem::transmute(self.inner.into_boxed_os_str()) } @@ -1402,10 +1494,14 @@ pub struct Path { inner: OsStr, } -/// An error returned from the [`Path::strip_prefix`] method indicating that the -/// prefix was not found in `self`. +/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix +/// was not found. +/// +/// This `struct` is created by the [`strip_prefix`] method on [`Path`]. +/// See its documentation for more. /// -/// [`Path::strip_prefix`]: struct.Path.html#method.strip_prefix +/// [`strip_prefix`]: struct.Path.html#method.strip_prefix +/// [`Path`]: struct.Path.html #[derive(Debug, Clone, PartialEq, Eq)] #[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); @@ -1421,7 +1517,7 @@ impl Path { os_str_as_u8_slice(&self.inner) } - /// Directly wrap a string slice as a `Path` slice. + /// Directly wraps a string slice as a `Path` slice. /// /// This is a cost-free conversion. /// @@ -1525,10 +1621,11 @@ impl Path { PathBuf::from(self.inner.to_os_string()) } - /// A path is *absolute* if it is independent of the current directory. + /// Returns `true` if the `Path` is absolute, i.e. if it is independent of + /// the current directory. /// /// * On Unix, a path is absolute if it starts with the root, so - /// `is_absolute` and `has_root` are equivalent. + /// `is_absolute` and [`has_root`] are equivalent. /// /// * On Windows, a path is absolute if it has a prefix and starts with the /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. @@ -1540,6 +1637,8 @@ impl Path { /// /// assert!(!Path::new("foo.txt").is_absolute()); /// ``` + /// + /// [`has_root`]: #method.has_root #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { @@ -1547,7 +1646,9 @@ impl Path { self.has_root() && (cfg!(unix) || cfg!(target_os = "redox") || self.prefix().is_some()) } - /// A path is *relative* if it is not absolute. + /// Return `false` if the `Path` is relative, i.e. not absolute. + /// + /// See [`is_absolute`]'s documentation for more details. /// /// # Examples /// @@ -1556,6 +1657,8 @@ impl Path { /// /// assert!(Path::new("foo.txt").is_relative()); /// ``` + /// + /// [`is_absolute`]: #method.is_absolute #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -1565,7 +1668,7 @@ impl Path { self.components().prefix } - /// A path has a root if the body of the path begins with the directory separator. + /// Returns `true` if the `Path` has a root. /// /// * On Unix, a path has a root if it begins with `/`. /// @@ -1586,7 +1689,7 @@ impl Path { self.components().has_root() } - /// The path without its final component, if any. + /// Returns the `Path` without its final component, if there is one. /// /// Returns [`None`] if the path terminates in a root or prefix. /// @@ -1619,9 +1722,9 @@ impl Path { }) } - /// The final component of the path, if it is a normal file. + /// Returns the final component of the `Path`, if it is a normal file. /// - /// If the path terminates in `..`, `file_name` will return [`None`]. + /// Returns [`None`] If the path terminates in `..`. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// @@ -1631,18 +1734,7 @@ impl Path { /// use std::path::Path; /// use std::ffi::OsStr; /// - /// let path = Path::new("foo.txt"); - /// let os_str = OsStr::new("foo.txt"); - /// - /// assert_eq!(Some(os_str), path.file_name()); - /// ``` - /// - /// # Other examples - /// - /// ``` - /// use std::path::Path; - /// use std::ffi::OsStr; - /// + /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); /// assert_eq!(None, Path::new("foo.txt/..").file_name()); @@ -1869,7 +1961,21 @@ impl Path { buf } - /// Produce an iterator over the components of the path. + /// Produces an iterator over the [`Component`]s of the path. + /// + /// When parsing the path, there is a small amount of normalization: + /// + /// * Repeated separators are ignored, so `a/b` and `a//b` both have + /// `a` and `b` as components. + /// + /// * Occurentces of `.` are normalized away, exept if they are at the + /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and + /// `a/b` all have `a` and `b` as components, but `./a/b` starts with + /// an additional [`CurDir`] component. + /// + /// Note that no other normalization takes place; in particular, `a/c` + /// and `a/b/../c` are distinct, to account for the possibility that `b` + /// is a symbolic link (so its parent isn't `a`). /// /// # Examples /// @@ -1884,6 +1990,9 @@ impl Path { /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt")))); /// assert_eq!(components.next(), None) /// ``` + /// + /// [`Component`]: enum.Component.html + /// [`CurDir`]: enum.Component.html#variant.CurDir #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); @@ -1896,8 +2005,13 @@ impl Path { } } - /// Produce an iterator over the path's components viewed as [`OsStr`] slices. + /// Produces an iterator over the path's components viewed as [`OsStr`] + /// slices. + /// + /// For more information about the particulars of how the path is separated + /// into components, see [`components`]. /// + /// [`components`]: #method.components /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples @@ -1936,7 +2050,7 @@ impl Path { Display { path: self } } - /// Query the file system to get information about a file, directory, etc. + /// Queries the file system to get information about a file, directory, etc. /// /// This function will traverse symbolic links to query information about the /// destination file. @@ -1959,7 +2073,7 @@ impl Path { fs::metadata(self) } - /// Query the metadata about a file without following symlinks. + /// Queries the metadata about a file without following symlinks. /// /// This is an alias to [`fs::symlink_metadata`]. /// @@ -2096,7 +2210,11 @@ impl Path { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } - /// Converts a `Box` into a `PathBuf` without copying or allocating. + /// Converts a [`Box`][`Box`] into a [`PathBuf`] without copying or + /// allocating. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`PathBuf`]: struct.PathBuf.html #[unstable(feature = "into_boxed_path", issue = "40380")] pub fn into_path_buf(self: Box) -> PathBuf { let inner: Box = unsafe { mem::transmute(self) }; @@ -2118,7 +2236,26 @@ impl fmt::Debug for Path { } } -/// Helper struct for safely printing paths with `format!()` and `{}` +/// Helper struct for safely printing paths with [`format!`] and `{}`. +/// +/// A [`Path`] might contain non-Unicode data. This `struct` implements the +/// [`Display`] trait in a way that mitigates that. It is created by the +/// [`display`][`Path::display`] method on [`Path`]. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/tmp/foo.rs"); +/// +/// println!("{}", path.display()); +/// ``` +/// +/// [`Display`]: ../../std/fmt/trait.Display.html +/// [`format!`]: ../../std/macro.format.html +/// [`Path`]: struct.Path.html +/// [`Path::display`]: struct.Path.html#method.display #[stable(feature = "rust1", since = "1.0.0")] pub struct Display<'a> { path: &'a Path, diff --git a/src/stage0.txt b/src/stage0.txt index 60fbcadf49157..dc6931c1d0bdd 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,4 +12,4 @@ # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was # released on `$date` -rustc: beta-2017-03-21 +rustc: beta-2017-04-05 diff --git a/src/test/compile-fail/issue-12187-1.rs b/src/test/compile-fail/issue-12187-1.rs index 6aeb9442c40ed..a79021d3cd5d2 100644 --- a/src/test/compile-fail/issue-12187-1.rs +++ b/src/test/compile-fail/issue-12187-1.rs @@ -16,5 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` - //~| NOTE consider giving a type to pattern + //~| NOTE consider giving the pattern a type } diff --git a/src/test/compile-fail/issue-12187-2.rs b/src/test/compile-fail/issue-12187-2.rs index d52ed06c4085d..38b3c5d4e9a64 100644 --- a/src/test/compile-fail/issue-12187-2.rs +++ b/src/test/compile-fail/issue-12187-2.rs @@ -16,5 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` - //~| NOTE consider giving a type to pattern + //~| NOTE consider giving the pattern a type } diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c index 4e09928edc6d1..44a940a17a98a 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.c +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c @@ -137,6 +137,21 @@ void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d, assert(s.d == 556); } +// System V x86_64 ABI: +// a, b, d, e, f should be byval pointer (on the stack) +// g passed via register (fixes #41375) +// +// Win64 ABI: +// a, b, d, e, f, g should be byval pointer +void byval_rect_with_many_huge(struct Huge a, struct Huge b, struct Huge c, + struct Huge d, struct Huge e, struct Huge f, + struct Rect g) { + assert(g.a == 123); + assert(g.b == 456); + assert(g.c == 789); + assert(g.d == 420); +} + // System V x86_64 & Win64 ABI: // a, b should be in registers // s should be split across 2 integer registers diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs index ff845a644b114..dcd7f43c074d2 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.rs +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs @@ -64,6 +64,8 @@ extern { fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect); + fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect); + fn split_rect(a: i32, b: i32, s: Rect); fn split_rect_floats(a: f32, b: f32, s: FloatRect); @@ -95,6 +97,12 @@ fn main() { byval_many_rect(1, 2, 3, 4, 5, 6, s); byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u); byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s); + byval_rect_with_many_huge(v, v, v, v, v v, Rect { + a: 123, + b: 456, + c: 789, + d: 420 + }); split_rect(1, 2, s); split_rect_floats(1., 2., u); split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s); diff --git a/src/test/run-pass/coerce-overloaded-autoderef.rs b/src/test/run-pass/coerce-overloaded-autoderef.rs index a053311a0403e..091e29dd18a6b 100644 --- a/src/test/run-pass/coerce-overloaded-autoderef.rs +++ b/src/test/run-pass/coerce-overloaded-autoderef.rs @@ -68,4 +68,8 @@ fn use_vec_ref(v: &Vec) { use_slice(&&&mut &&&v); } +fn use_op_rhs(s: &mut String) { + *s += {&String::from(" ")}; +} + pub fn main() {} diff --git a/src/test/ui/type-check/issue-38812-2.rs b/src/test/ui/type-check/cannot_infer_local_or_array.rs similarity index 94% rename from src/test/ui/type-check/issue-38812-2.rs rename to src/test/ui/type-check/cannot_infer_local_or_array.rs index c476657d20796..0b35a9c3dbebc 100644 --- a/src/test/ui/type-check/issue-38812-2.rs +++ b/src/test/ui/type-check/cannot_infer_local_or_array.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let (x,) = (vec![],); + let x = []; } diff --git a/src/test/ui/type-check/cannot_infer_local_or_array.stderr b/src/test/ui/type-check/cannot_infer_local_or_array.stderr new file mode 100644 index 0000000000000..8c52bb5a1d3a5 --- /dev/null +++ b/src/test/ui/type-check/cannot_infer_local_or_array.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/cannot_infer_local_or_array.rs:12:13 + | +12 | let x = []; + | - ^^ cannot infer type for `_` + | | + | consider giving `x` a type + +error: aborting due to previous error + diff --git a/src/test/ui/type-check/issue-38812.rs b/src/test/ui/type-check/cannot_infer_local_or_vec.rs similarity index 100% rename from src/test/ui/type-check/issue-38812.rs rename to src/test/ui/type-check/cannot_infer_local_or_vec.rs diff --git a/src/test/ui/type-check/issue-38812.stderr b/src/test/ui/type-check/cannot_infer_local_or_vec.stderr similarity index 86% rename from src/test/ui/type-check/issue-38812.stderr rename to src/test/ui/type-check/cannot_infer_local_or_vec.stderr index 6365e761453f9..4788fad20889e 100644 --- a/src/test/ui/type-check/issue-38812.stderr +++ b/src/test/ui/type-check/cannot_infer_local_or_vec.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-38812.rs:12:13 + --> $DIR/cannot_infer_local_or_vec.rs:12:13 | 12 | let x = vec![]; | - ^^^^^^ cannot infer type for `T` diff --git a/src/test/compile-fail/E0101.rs b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.rs similarity index 73% rename from src/test/compile-fail/E0101.rs rename to src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.rs index 0005da048e4a5..8d32c1ff683bb 100644 --- a/src/test/compile-fail/E0101.rs +++ b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -9,7 +9,5 @@ // except according to those terms. fn main() { - let x = |_| {}; - //~^ ERROR E0101 - //~| NOTE cannot resolve type of expression + let (x, ) = (vec![], ); } diff --git a/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr new file mode 100644 index 0000000000000..ccffadebe9ee2 --- /dev/null +++ b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr @@ -0,0 +1,12 @@ +error[E0282]: type annotations needed + --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:12:18 + | +12 | let (x, ) = (vec![], ); + | ----- ^^^^^^ cannot infer type for `T` + | | + | consider giving the pattern a type + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-22897.rs b/src/test/ui/type-check/issue-22897.rs similarity index 63% rename from src/test/compile-fail/issue-22897.rs rename to src/test/ui/type-check/issue-22897.rs index c6bbf2d4abcc0..296dc81a89bcf 100644 --- a/src/test/compile-fail/issue-22897.rs +++ b/src/test/ui/type-check/issue-22897.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -10,10 +10,6 @@ fn main() { } -// Before these errors would ICE as "cat_expr Errd" because the errors -// were unknown when the bug was triggered. - fn unconstrained_type() { []; - //~^ ERROR cannot determine a type for this expression: unconstrained type } diff --git a/src/test/ui/type-check/issue-22897.stderr b/src/test/ui/type-check/issue-22897.stderr new file mode 100644 index 0000000000000..9568411885192 --- /dev/null +++ b/src/test/ui/type-check/issue-22897.stderr @@ -0,0 +1,8 @@ +error[E0282]: type annotations needed + --> $DIR/issue-22897.rs:14:5 + | +14 | []; + | ^^ cannot infer type for `[_; 0]` + +error: aborting due to previous error + diff --git a/src/test/ui/type-check/issue-38812-2.stderr b/src/test/ui/type-check/issue-38812-2.stderr deleted file mode 100644 index 156a6bdee9979..0000000000000 --- a/src/test/ui/type-check/issue-38812-2.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/issue-38812-2.rs:12:17 - | -12 | let (x,) = (vec![],); - | ---- ^^^^^^ cannot infer type for `T` - | | - | consider giving a type to pattern - | - = note: this error originates in a macro outside of the current crate - -error: aborting due to previous error - diff --git a/src/test/compile-fail/E0102.rs b/src/test/ui/type-check/unknown_type_for_closure.rs similarity index 67% rename from src/test/compile-fail/E0102.rs rename to src/test/ui/type-check/unknown_type_for_closure.rs index 6a17ddebd1dc1..f1d357df12c43 100644 --- a/src/test/compile-fail/E0102.rs +++ b/src/test/ui/type-check/unknown_type_for_closure.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -9,8 +9,5 @@ // except according to those terms. fn main() { - let x = []; - //~^ ERROR type annotations needed - //~| NOTE consider giving `x` a type - //~| NOTE cannot infer type for `_` + let x = |_| { }; } diff --git a/src/test/ui/type-check/unknown_type_for_closure.stderr b/src/test/ui/type-check/unknown_type_for_closure.stderr new file mode 100644 index 0000000000000..afbd15ca486bd --- /dev/null +++ b/src/test/ui/type-check/unknown_type_for_closure.stderr @@ -0,0 +1,8 @@ +error[E0282]: type annotations needed + --> $DIR/unknown_type_for_closure.rs:12:14 + | +12 | let x = |_| { }; + | ^ consider giving this closure parameter a type + +error: aborting due to previous error + diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index c7113edbf9e68..012ee835494e8 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -22,12 +22,6 @@ struct Test { } const TEST_REPOS: &'static [Test] = &[ - Test { - name: "cargo", - repo: "https://github.com/rust-lang/cargo", - sha: "0e1e34be7540bdaed4918457654fbf028cf69e56", - lock: None, - }, Test { name: "iron", repo: "https://github.com/iron/iron", @@ -61,20 +55,6 @@ const TEST_REPOS: &'static [Test] = &[ ]; fn main() { - // One of the projects being tested here is Cargo, and when being tested - // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately - // `nmake` will read these two environment variables below and try to - // intepret them. We're likely being run, however, from MSYS `make` which - // uses the same variables. - // - // As a result, to prevent confusion and errors, we remove these variables - // from our environment to prevent passing MSYS make flags to nmake, causing - // it to blow up. - if cfg!(target_env = "msvc") { - env::remove_var("MAKE"); - env::remove_var("MAKEFLAGS"); - } - let args = env::args().collect::>(); let ref cargo = args[1]; let out_dir = Path::new(&args[2]); diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index d5b95c08306b2..e320933067226 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -8,5 +8,5 @@ license = "MIT/Apache-2.0" clap = "2.19.3" [dependencies.mdbook] -version = "0.0.18" +version = "0.0.19" default-features = false