diff options
| author | bors <bors@rust-lang.org> | 2019-09-06 07:37:41 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-09-06 07:37:41 +0000 |
| commit | 1fb3c4ec7ca37d33bd1e68cce669d171c2752615 (patch) | |
| tree | 48ea5150538790309c68b9f515c4e958724a82a5 | |
| parent | 6b5f9b2e973e438fc1726a2d164d046acd80b170 (diff) | |
| parent | 61fcd057d2524175a21e2eb1d49c1d4aec29a0be (diff) | |
Auto merge of #64209 - Centril:rollup-x9kvjb7, r=Centril
Rollup of 10 pull requests Successful merges: - #63676 (Use wasi crate for Core API) - #64094 (Improve searching in rustdoc and add tests) - #64111 (or-patterns: Uniformly use `PatKind::Or` in AST & Fix/Cleanup resolve) - #64156 (Assume non-git LLVM is fresh if the stamp file exists) - #64161 (Point at variant on pattern field count mismatch) - #64174 (Add missing code examples on Iterator trait) - #64175 (Fix invalid span generation when it should be div) - #64186 (std: Improve downstream codegen in `Command::env`) - #64190 (fill metadata in rustc_lexer's Cargo.toml) - #64198 (Add Fuchsia to actually_monotonic) Failed merges: r? @ghost
73 files changed, 1991 insertions, 1163 deletions
diff --git a/Cargo.lock b/Cargo.lock index 243a326646c..313fef1c086 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3870,6 +3870,7 @@ dependencies = [ "rustc_msan", "rustc_tsan", "unwind", + "wasi", ] [[package]] @@ -4687,6 +4688,17 @@ dependencies = [ ] [[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index f02def3e1b0..7bf9ea2688f 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -81,26 +81,29 @@ impl Step for Llvm { (info, "src/llvm-project/llvm", builder.llvm_out(target), dir.join("bin")) }; - if !llvm_info.is_git() { - println!( - "git could not determine the LLVM submodule commit hash. \ - Assuming that an LLVM build is necessary.", - ); - } - let build_llvm_config = llvm_config_ret_dir .join(exe("llvm-config", &*builder.config.build)); let done_stamp = out_dir.join("llvm-finished-building"); - if let Some(llvm_commit) = llvm_info.sha() { - if done_stamp.exists() { + if done_stamp.exists() { + if let Some(llvm_commit) = llvm_info.sha() { let done_contents = t!(fs::read(&done_stamp)); // If LLVM was already built previously and the submodule's commit didn't change // from the previous build, then no action is required. if done_contents == llvm_commit.as_bytes() { - return build_llvm_config + return build_llvm_config; } + } else { + builder.info( + "Could not determine the LLVM submodule commit hash. \ + Assuming that an LLVM rebuild is not necessary.", + ); + builder.info(&format!( + "To force LLVM to rebuild, remove the file `{}`", + done_stamp.display() + )); + return build_llvm_config; } } @@ -303,9 +306,7 @@ impl Step for Llvm { cfg.build(); - if let Some(llvm_commit) = llvm_info.sha() { - t!(fs::write(&done_stamp, llvm_commit)); - } + t!(fs::write(&done_stamp, llvm_info.sha().unwrap_or(""))); build_llvm_config } diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index d644787d2c4..8fd5fe0653e 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2546,6 +2546,16 @@ pub trait Iterator { /// Lexicographically compares the elements of this `Iterator` with those /// of another. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!([1].iter().cmp([1].iter()), Ordering::Equal); + /// assert_eq!([1].iter().cmp([1, 2].iter()), Ordering::Less); + /// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn cmp<I>(mut self, other: I) -> Ordering where I: IntoIterator<Item = Self::Item>, @@ -2578,6 +2588,18 @@ pub trait Iterator { /// Lexicographically compares the elements of this `Iterator` with those /// of another. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!([1.].iter().partial_cmp([1.].iter()), Some(Ordering::Equal)); + /// assert_eq!([1.].iter().partial_cmp([1., 2.].iter()), Some(Ordering::Less)); + /// assert_eq!([1., 2.].iter().partial_cmp([1.].iter()), Some(Ordering::Greater)); + /// + /// assert_eq!([std::f64::NAN].iter().partial_cmp([1.].iter()), None); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn partial_cmp<I>(mut self, other: I) -> Option<Ordering> where I: IntoIterator, @@ -2610,6 +2632,13 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are equal to those of /// another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().eq([1].iter()), true); + /// assert_eq!([1].iter().eq([1, 2].iter()), false); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn eq<I>(mut self, other: I) -> bool where I: IntoIterator, @@ -2635,6 +2664,13 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are unequal to those of /// another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().ne([1].iter()), false); + /// assert_eq!([1].iter().ne([1, 2].iter()), true); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn ne<I>(self, other: I) -> bool where I: IntoIterator, @@ -2646,6 +2682,14 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// less than those of another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().lt([1].iter()), false); + /// assert_eq!([1].iter().lt([1, 2].iter()), true); + /// assert_eq!([1, 2].iter().lt([1].iter()), false); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn lt<I>(self, other: I) -> bool where I: IntoIterator, @@ -2657,6 +2701,14 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// less or equal to those of another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().le([1].iter()), true); + /// assert_eq!([1].iter().le([1, 2].iter()), true); + /// assert_eq!([1, 2].iter().le([1].iter()), false); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn le<I>(self, other: I) -> bool where I: IntoIterator, @@ -2671,6 +2723,14 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// greater than those of another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().gt([1].iter()), false); + /// assert_eq!([1].iter().gt([1, 2].iter()), false); + /// assert_eq!([1, 2].iter().gt([1].iter()), true); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn gt<I>(self, other: I) -> bool where I: IntoIterator, @@ -2682,6 +2742,14 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// greater than or equal to those of another. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([1].iter().ge([1].iter()), true); + /// assert_eq!([1].iter().ge([1, 2].iter()), false); + /// assert_eq!([1, 2].iter().ge([1].iter()), true); + /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn ge<I>(self, other: I) -> bool where I: IntoIterator, @@ -2730,6 +2798,18 @@ pub trait Iterator { /// function to determine the ordering of two elements. Apart from that, it's equivalent to /// [`is_sorted`]; see its documentation for more information. /// + /// # Examples + /// + /// ``` + /// #![feature(is_sorted)] + /// + /// assert!([1, 2, 2, 9].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!(![1, 3, 2, 4].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!([0].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!(std::iter::empty::<i32>().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// ``` + /// /// [`is_sorted`]: trait.Iterator.html#method.is_sorted #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] fn is_sorted_by<F>(mut self, mut compare: F) -> bool diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5e2aebfd318..190b50b10b2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -425,19 +425,44 @@ impl<'a> LoweringContext<'a> { impl<'tcx, 'interner> Visitor<'tcx> for MiscCollector<'tcx, 'interner> { fn visit_pat(&mut self, p: &'tcx Pat) { - match p.node { + if let PatKind::Paren(..) | PatKind::Rest = p.node { // Doesn't generate a HIR node - PatKind::Paren(..) | PatKind::Rest => {}, - _ => { - if let Some(owner) = self.hir_id_owner { - self.lctx.lower_node_id_with_owner(p.id, owner); - } - } - }; + } else if let Some(owner) = self.hir_id_owner { + self.lctx.lower_node_id_with_owner(p.id, owner); + } visit::walk_pat(self, p) } + // HACK(or_patterns; Centril | dlrobertson): Avoid creating + // HIR nodes for `PatKind::Or` for the top level of a `ast::Arm`. + // This is a temporary hack that should go away once we push down + // `arm.pats: HirVec<P<Pat>>` -> `arm.pat: P<Pat>` to HIR. // Centril + fn visit_arm(&mut self, arm: &'tcx Arm) { + match &arm.pat.node { + PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)), + _ => self.visit_pat(&arm.pat), + } + walk_list!(self, visit_expr, &arm.guard); + self.visit_expr(&arm.body); + walk_list!(self, visit_attribute, &arm.attrs); + } + + // HACK(or_patterns; Centril | dlrobertson): Same as above. // Centril + fn visit_expr(&mut self, e: &'tcx Expr) { + if let ExprKind::Let(pat, scrutinee) = &e.node { + walk_list!(self, visit_attribute, e.attrs.iter()); + match &pat.node { + PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)), + _ => self.visit_pat(&pat), + } + self.visit_expr(scrutinee); + self.visit_expr_post(e); + return; + } + visit::walk_expr(self, e) + } + fn visit_item(&mut self, item: &'tcx Item) { let hir_id = self.lctx.allocate_hir_id_counter(item.id); diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index bd217831faa..0d8986ddec3 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -68,7 +68,7 @@ impl LoweringContext<'_> { let ohs = P(self.lower_expr(ohs)); hir::ExprKind::AddrOf(m, ohs) } - ExprKind::Let(ref pats, ref scrutinee) => self.lower_expr_let(e.span, pats, scrutinee), + ExprKind::Let(ref pat, ref scrutinee) => self.lower_expr_let(e.span, pat, scrutinee), ExprKind::If(ref cond, ref then, ref else_opt) => { self.lower_expr_if(e.span, cond, then, else_opt.as_deref()) } @@ -227,16 +227,11 @@ impl LoweringContext<'_> { } } - /// Emit an error and lower `ast::ExprKind::Let(pats, scrutinee)` into: + /// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into: /// ```rust /// match scrutinee { pats => true, _ => false } /// ``` - fn lower_expr_let( - &mut self, - span: Span, - pats: &[AstP<Pat>], - scrutinee: &Expr - ) -> hir::ExprKind { + fn lower_expr_let(&mut self, span: Span, pat: &Pat, scrutinee: &Expr) -> hir::ExprKind { // If we got here, the `let` expression is not allowed. self.sess .struct_span_err(span, "`let` expressions are not supported here") @@ -246,23 +241,23 @@ impl LoweringContext<'_> { // For better recovery, we emit: // ``` - // match scrutinee { pats => true, _ => false } + // match scrutinee { pat => true, _ => false } // ``` // While this doesn't fully match the user's intent, it has key advantages: // 1. We can avoid using `abort_if_errors`. - // 2. We can typeck both `pats` and `scrutinee`. - // 3. `pats` is allowed to be refutable. + // 2. We can typeck both `pat` and `scrutinee`. + // 3. `pat` is allowed to be refutable. // 4. The return type of the block is `bool` which seems like what the user wanted. let scrutinee = self.lower_expr(scrutinee); let then_arm = { - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); + let pat = self.lower_pat_top_hack(pat); let expr = self.expr_bool(span, true); - self.arm(pats, P(expr)) + self.arm(pat, P(expr)) }; let else_arm = { - let pats = hir_vec![self.pat_wild(span)]; + let pat = self.pat_wild(span); let expr = self.expr_bool(span, false); - self.arm(pats, P(expr)) + self.arm(hir_vec![pat], P(expr)) }; hir::ExprKind::Match( P(scrutinee), @@ -291,13 +286,12 @@ impl LoweringContext<'_> { // Handle then + scrutinee: let then_blk = self.lower_block(then, false); let then_expr = self.expr_block(then_blk, ThinVec::new()); - let (then_pats, scrutinee, desugar) = match cond.node { + let (then_pat, scrutinee, desugar) = match cond.node { // `<pat> => <then>`: - ExprKind::Let(ref pats, ref scrutinee) => { + ExprKind::Let(ref pat, ref scrutinee) => { let scrutinee = self.lower_expr(scrutinee); - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); - let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause }; - (pats, scrutinee, desugar) + let pat = self.lower_pat_top_hack(pat); + (pat, scrutinee, hir::MatchSource::IfLetDesugar { contains_else_clause }) } // `true => <then>`: _ => { @@ -312,13 +306,11 @@ impl LoweringContext<'_> { // to preserve drop semantics since `if cond { ... }` does not // let temporaries live outside of `cond`. let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); - - let desugar = hir::MatchSource::IfDesugar { contains_else_clause }; - let pats = hir_vec![self.pat_bool(span, true)]; - (pats, cond, desugar) + let pat = self.pat_bool(span, true); + (hir_vec![pat], cond, hir::MatchSource::IfDesugar { contains_else_clause }) } }; - let then_arm = self.arm(then_pats, P(then_expr)); + let then_arm = self.arm(then_pat, P(then_expr)); hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar) } @@ -345,8 +337,8 @@ impl LoweringContext<'_> { // Handle then + scrutinee: let then_blk = self.lower_block(body, false); let then_expr = self.expr_block(then_blk, ThinVec::new()); - let (then_pats, scrutinee, desugar, source) = match cond.node { - ExprKind::Let(ref pats, ref scrutinee) => { + let (then_pat, scrutinee, desugar, source) = match cond.node { + ExprKind::Let(ref pat, ref scrutinee) => { // to: // // [opt_ident]: loop { @@ -356,9 +348,8 @@ impl LoweringContext<'_> { // } // } let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee)); - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); - let desugar = hir::MatchSource::WhileLetDesugar; - (pats, scrutinee, desugar, hir::LoopSource::WhileLet) + let pat = self.lower_pat_top_hack(pat); + (pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet) } _ => { // We desugar: `'label: while $cond $body` into: @@ -383,14 +374,12 @@ impl LoweringContext<'_> { // to preserve drop semantics since `while cond { ... }` does not // let temporaries live outside of `cond`. let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); - - let desugar = hir::MatchSource::WhileDesugar; // `true => <then>`: - let pats = hir_vec![self.pat_bool(span, true)]; - (pats, cond, desugar, hir::LoopSource::While) + let pat = self.pat_bool(span, true); + (hir_vec![pat], cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While) } }; - let then_arm = self.arm(then_pats, P(then_expr)); + let then_arm = self.arm(then_pat, P(then_expr)); // `match <scrutinee> { ... }` let match_expr = self.expr_match( @@ -440,7 +429,7 @@ impl LoweringContext<'_> { hir::Arm { hir_id: self.next_id(), attrs: self.lower_attrs(&arm.attrs), - pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(), + pats: self.lower_pat_top_hack(&arm.pat), guard: match arm.guard { Some(ref x) => Some(hir::Guard::If(P(self.lower_expr(x)))), _ => None, @@ -450,6 +439,16 @@ impl LoweringContext<'_> { } } + /// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns + /// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready + /// to deal with it. This should by fixed by pushing it down to HIR and then HAIR. + fn lower_pat_top_hack(&mut self, pat: &Pat) -> HirVec<P<hir::Pat>> { + match pat.node { + PatKind::Or(ref ps) => ps.iter().map(|x| self.lower_pat(x)).collect(), + _ => hir_vec![self.lower_pat(pat)], + } + } + pub(super) fn make_async_expr( &mut self, capture_clause: CaptureBy, @@ -1255,7 +1254,6 @@ impl LoweringContext<'_> { ThinVec::from(attrs.clone()), )); let ok_pat = self.pat_ok(span, val_pat); - self.arm(hir_vec![ok_pat], val_expr) }; @@ -1486,7 +1484,10 @@ impl LoweringContext<'_> { } } - fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm { + /// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns + /// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready + /// to deal with it. This should by fixed by pushing it down to HIR and then HAIR. + fn arm(&mut self, pats: HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm { hir::Arm { hir_id: self.next_id(), attrs: hir_vec![], diff --git a/src/librustc_lexer/Cargo.toml b/src/librustc_lexer/Cargo.toml index 675d3065c5b..950771f0a69 100644 --- a/src/librustc_lexer/Cargo.toml +++ b/src/librustc_lexer/Cargo.toml @@ -2,8 +2,14 @@ authors = ["The Rust Project Developers"] name = "rustc_lexer" version = "0.1.0" +license = "MIT OR Apache-2.0" edition = "2018" +repository = "https://github.com/rust-lang/rust/" +description = """ +Rust lexer used by rustc. No stability guarantees are provided. +""" + # Note: do not remove this blank `[lib]` section. # This will be used when publishing this crate as `rustc-ap-rustc_lexer`. [lib] diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 26e7b789f8f..aecf5c5b52d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -772,7 +772,7 @@ impl EarlyLintPass for UnusedDocComment { } fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { - let arm_span = arm.pats[0].span.with_hi(arm.body.span.hi()); + let arm_span = arm.pat.span.with_hi(arm.body.span.hi()); self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs); } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 39c0698aeec..561bf202dfe 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -493,10 +493,8 @@ impl EarlyLintPass for UnusedParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { use syntax::ast::ExprKind::*; let (value, msg, followed_by_block, left_pos, right_pos) = match e.node { - Let(ref pats, ..) => { - for p in pats { - self.check_unused_parens_pat(cx, p, false, false); - } + Let(ref pat, ..) => { + self.check_unused_parens_pat(cx, pat, false, false); return; } @@ -594,9 +592,7 @@ impl EarlyLintPass for UnusedParens { } fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { - for p in &arm.pats { - self.check_unused_parens_pat(cx, p, false, false); - } + self.check_unused_parens_pat(cx, &arm.pat, false, false); } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index e15d02a9f7e..3ddaf2d94f9 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -9,7 +9,7 @@ use GenericParameters::*; use RibKind::*; use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding}; -use crate::{Module, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult}; +use crate::{Module, ModuleOrUniformRoot, NameBindingKind, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; use log::debug; @@ -18,7 +18,7 @@ use rustc::hir::def::{self, PartialRes, DefKind, CtorKind, PerNS}; use rustc::hir::def::Namespace::{self, *}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::hir::TraitCandidate; -use rustc::util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; use syntax::{unwrap_or, walk_list}; use syntax::ast::*; @@ -35,8 +35,10 @@ mod diagnostics; type Res = def::Res<NodeId>; +type IdentMap<T> = FxHashMap<Ident, T>; + /// Map from the name in a pattern to its binding mode. -type BindingMap = FxHashMap<Ident, BindingInfo>; +type BindingMap = IdentMap<BindingInfo>; #[derive(Copy, Clone, Debug)] struct BindingInfo { @@ -73,6 +75,16 @@ impl PatternSource { } } +/// Denotes whether the context for the set of already bound bindings is a `Product` +/// or `Or` context. This is used in e.g., `fresh_binding` and `resolve_pattern_inner`. +/// See those functions for more information. +enum PatBoundCtx { + /// A product pattern context, e.g., `Variant(a, b)`. + Product, + /// An or-pattern context, e.g., `p_0 | ... | p_n`. + Or, +} + /// The rib kind restricts certain accesses, /// e.g. to a `Res::Local` of an outer item. #[derive(Copy, Clone, Debug)] @@ -143,7 +155,7 @@ impl RibKind<'_> { /// resolving, the name is looked up from inside out. #[derive(Debug)] crate struct Rib<'a, R = Res> { - pub bindings: FxHashMap<Ident, R>, + pub bindings: IdentMap<R>, pub kind: RibKind<'a>, } @@ -406,50 +418,32 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> { visit::walk_foreign_item(this, foreign_item); }); } - fn visit_fn(&mut self, - function_kind: FnKind<'tcx>, - declaration: &'tcx FnDecl, - _: Span, - _: NodeId) - { + fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, _: NodeId) { debug!("(resolving function) entering function"); - let rib_kind = match function_kind { + let rib_kind = match fn_kind { FnKind::ItemFn(..) => FnItemRibKind, FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind, }; // Create a value rib for the function. - self.ribs[ValueNS].push(Rib::new(rib_kind)); - - // Create a label rib for the function. - self.label_ribs.push(Rib::new(rib_kind)); - - // Add each argument to the rib. - let mut bindings_list = FxHashMap::default(); - for argument in &declaration.inputs { - self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); - - self.visit_ty(&argument.ty); - - debug!("(resolving function) recorded argument"); - } - visit::walk_fn_ret_ty(self, &declaration.output); - - // Resolve the function body, potentially inside the body of an async closure - match function_kind { - FnKind::ItemFn(.., body) | - FnKind::Method(.., body) => { - self.visit_block(body); - } - FnKind::Closure(body) => { - self.visit_expr(body); - } - }; - - debug!("(resolving function) leaving function"); - - self.label_ribs.pop(); - self.ribs[ValueNS].pop(); + self.with_rib(ValueNS, rib_kind, |this| { + // Create a label rib for the function. + this.with_label_rib(rib_kind, |this| { + // Add each argument to the rib. + this.resolve_params(&declaration.inputs); + + visit::walk_fn_ret_ty(this, &declaration.output); + + // Resolve the function body, potentially inside the body of an async closure + match fn_kind { + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => this.visit_block(body), + FnKind::Closure(body) => this.visit_expr(body), + }; + + debug!("(resolving function) leaving function"); + }) + }); } fn visit_generics(&mut self, generics: &'tcx Generics) { @@ -528,13 +522,14 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { // although it may be useful to track other components as well for diagnostics. let graph_root = resolver.graph_root; let parent_scope = ParentScope::module(graph_root); + let start_rib_kind = ModuleRibKind(graph_root); LateResolutionVisitor { r: resolver, parent_scope, ribs: PerNS { - value_ns: vec![Rib::new(ModuleRibKind(graph_root))], - type_ns: vec![Rib::new(ModuleRibKind(graph_root))], - macro_ns: vec![Rib::new(ModuleRibKind(graph_root))], + value_ns: vec![Rib::new(start_rib_kind)], + type_ns: vec![Rib::new(start_rib_kind)], + macro_ns: vec![Rib::new(start_rib_kind)], }, label_ribs: Vec::new(), current_trait_ref: None, @@ -588,23 +583,32 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { // generate a fake "implementation scope" containing all the // implementations thus found, for compatibility with old resolve pass. - fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T - { + /// Do some `work` within a new innermost rib of the given `kind` in the given namespace (`ns`). + fn with_rib<T>( + &mut self, + ns: Namespace, + kind: RibKind<'a>, + work: impl FnOnce(&mut Self) -> T, + ) -> T { + self.ribs[ns].push(Rib::new(kind)); + let ret = work(self); + self.ribs[ns].pop(); + ret + } + + fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { let id = self.r.definitions.local_def_id(id); let module = self.r.module_map.get(&id).cloned(); // clones a reference if let Some(module) = module { // Move down in the graph. let orig_module = replace(&mut self.parent_scope.module, module); - self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); - self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); - - let ret = f(self); - - self.parent_scope.module = orig_module; - self.ribs[ValueNS].pop(); - self.ribs[TypeNS].pop(); - ret + self.with_rib(ValueNS, ModuleRibKind(module), |this| { + this.with_rib(TypeNS, ModuleRibKind(module), |this| { + let ret = f(this); + this.parent_scope.module = orig_module; + ret + }) + }) } else { f(self) } @@ -808,7 +812,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { } fn with_generic_param_rib<'c, F>(&'c mut self, generic_params: GenericParameters<'a, 'c>, f: F) - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + where F: FnOnce(&mut Self) { debug!("with_generic_param_rib"); match generic_params { @@ -894,38 +898,24 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { } } - fn with_label_rib<F>(&mut self, f: F) - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) - { - self.label_ribs.push(Rib::new(NormalRibKind)); + fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) { + self.label_ribs.push(Rib::new(kind)); f(self); self.label_ribs.pop(); } - fn with_item_rib<F>(&mut self, f: F) - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) - { - self.ribs[ValueNS].push(Rib::new(ItemRibKind)); - self.ribs[TypeNS].push(Rib::new(ItemRibKind)); - f(self); - self.ribs[TypeNS].pop(); - self.ribs[ValueNS].pop(); + fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) { + self.with_rib(ValueNS, ItemRibKind, |this| this.with_rib(TypeNS, ItemRibKind, f)) } - fn with_constant_rib<F>(&mut self, f: F) - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) - { + fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) { debug!("with_constant_rib"); - self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind)); - self.label_ribs.push(Rib::new(ConstantItemRibKind)); - f(self); - self.label_ribs.pop(); - self.ribs[ValueNS].pop(); + self.with_rib(ValueNS, ConstantItemRibKind, |this| { + this.with_label_rib(ConstantItemRibKind, f); + }); } - fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T - { + fn with_current_self_type<T>(&mut self, self_type: &Ty, f: impl FnOnce(&mut Self) -> T) -> T { // Handle nested impls (inside fn bodies) let previous_value = replace(&mut self.current_self_type, Some(self_type.clone())); let result = f(self); @@ -933,9 +923,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { result } - fn with_current_self_item<T, F>(&mut self, self_item: &Item, f: F) -> T - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T - { + fn with_current_self_item<T>(&mut self, self_item: &Item, f: impl FnOnce(&mut Self) -> T) -> T { let previous_value = replace(&mut self.current_self_item, Some(self_item.id)); let result = f(self); self.current_self_item = previous_value; @@ -943,9 +931,11 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { } /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412. - fn with_trait_items<T, F>(&mut self, trait_items: &Vec<TraitItem>, f: F) -> T - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T - { + fn with_trait_items<T>( + &mut self, + trait_items: &Vec<TraitItem>, + f: impl FnOnce(&mut Self) -> T, + ) -> T { let trait_assoc_types = replace( &mut self.current_trait_assoc_types, trait_items.iter().filter_map(|item| match &item.node { @@ -959,9 +949,11 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { } /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`). - fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>, Option<DefId>) -> T - { + fn with_optional_trait_ref<T>( + &mut self, + opt_trait_ref: Option<&TraitRef>, + f: impl FnOnce(&mut Self, Option<DefId>) -> T + ) -> T { let mut new_val = None; let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { @@ -996,27 +988,18 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { result } - fn with_self_rib<F>(&mut self, self_res: Res, f: F) - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) - { + fn with_self_rib_ns(&mut self, ns: Namespace, self_res: Res, f: impl FnOnce(&mut Self)) { let mut self_type_rib = Rib::new(NormalRibKind); // Plain insert (no renaming, since types are not currently hygienic) self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), self_res); - self.ribs[TypeNS].push(self_type_rib); + self.ribs[ns].push(self_type_rib); f(self); - self.ribs[TypeNS].pop(); + self.ribs[ns].pop(); } - fn with_self_struct_ctor_rib<F>(&mut self, impl_id: DefId, f: F) - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) - { - let self_res = Res::SelfCtor(impl_id); - let mut self_type_rib = Rib::new(NormalRibKind); - self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), self_res); - self.ribs[ValueNS].push(self_type_rib); - f(self); - self.ribs[ValueNS].pop(); + fn with_self_rib(&mut self, self_res: Res, f: impl FnOnce(&mut Self)) { + self.with_self_rib_ns(TypeNS, self_res, f) } fn resolve_implementation(&mut self, @@ -1044,8 +1027,8 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { this.visit_generics(generics); // Resolve the items within the impl. this.with_current_self_type(self_type, |this| { - this.with_self_struct_ctor_rib(item_def_id, |this| { - debug!("resolve_implementation with_self_struct_ctor_rib"); + this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { + debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); for impl_item in impl_items { // We also need a new scope for the impl item type parameters. let generic_params = HasGenericParams(&impl_item.generics, @@ -1135,6 +1118,15 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { } } + fn resolve_params(&mut self, params: &[Param]) { + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + for Param { pat, ty, .. } in params { + self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings); + self.visit_ty(ty); + debug!("(resolving function / closure) recorded parameter"); + } + } + fn resolve_local(&mut self, local: &Local) { // Resolve the type. walk_list!(self, visit_ty, &local.ty); @@ -1143,72 +1135,93 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { walk_list!(self, visit_expr, &local.init); // Resolve the pattern. - self.resolve_pattern(&local.pat, PatternSource::Let, &mut FxHashMap::default()); + self.resolve_pattern_top(&local.pat, PatternSource::Let); } - // build a map from pattern identifiers to binding-info's. - // this is done hygienically. This could arise for a macro - // that expands into an or-pattern where one 'x' was from the - // user and one 'x' came from the macro. + /// build a map from pattern identifiers to binding-info's. + /// this is done hygienically. This could arise for a macro + /// that expands into an or-pattern where one 'x' was from the + /// user and one 'x' came from the macro. fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap { let mut binding_map = FxHashMap::default(); pat.walk(&mut |pat| { - if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node { - if sub_pat.is_some() || match self.r.partial_res_map.get(&pat.id) - .map(|res| res.base_res()) { - Some(Res::Local(..)) => true, - _ => false, - } { - let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode }; - binding_map.insert(ident, binding_info); + match pat.node { + PatKind::Ident(binding_mode, ident, ref sub_pat) + if sub_pat.is_some() || self.is_base_res_local(pat.id) => + { + binding_map.insert(ident, BindingInfo { span: ident.span, binding_mode }); + } + PatKind::Or(ref ps) => { + // Check the consistency of this or-pattern and + // then add all bindings to the larger map. + for bm in self.check_consistent_bindings(ps) { + binding_map.extend(bm); + } + return false; } + _ => {} } + true }); binding_map } - // Checks that all of the arms in an or-pattern have exactly the - // same set of bindings, with the same binding modes for each. - fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) { + fn is_base_res_local(&self, nid: NodeId) -> bool { + match self.r.partial_res_map.get(&nid).map(|res| res.base_res()) { + Some(Res::Local(..)) => true, + _ => false, + } + } + + /// Checks that all of the arms in an or-pattern have exactly the + /// same set of bindings, with the same binding modes for each. + fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) -> Vec<BindingMap> { let mut missing_vars = FxHashMap::default(); let mut inconsistent_vars = FxHashMap::default(); - for pat_outer in pats.iter() { - let map_outer = self.binding_mode_map(&pat_outer); - - for pat_inner in pats.iter().filter(|pat| pat.id != pat_outer.id) { - let map_inner = self.binding_mode_map(&pat_inner); - - for (&key_inner, &binding_inner) in map_inner.iter() { - match map_outer.get(&key_inner) { - None => { // missing binding - let binding_error = missing_vars - .entry(key_inner.name) - .or_insert(BindingError { - name: key_inner.name, - origin: BTreeSet::new(), - target: BTreeSet::new(), - could_be_path: - key_inner.name.as_str().starts_with(char::is_uppercase) - }); - binding_error.origin.insert(binding_inner.span); - binding_error.target.insert(pat_outer.span); - } - Some(binding_outer) => { // check consistent binding - if binding_outer.binding_mode != binding_inner.binding_mode { - inconsistent_vars - .entry(key_inner.name) - .or_insert((binding_inner.span, binding_outer.span)); - } + // 1) Compute the binding maps of all arms. + let maps = pats.iter() + .map(|pat| self.binding_mode_map(pat)) + .collect::<Vec<_>>(); + + // 2) Record any missing bindings or binding mode inconsistencies. + for (map_outer, pat_outer) in pats.iter().enumerate().map(|(idx, pat)| (&maps[idx], pat)) { + // Check against all arms except for the same pattern which is always self-consistent. + let inners = pats.iter().enumerate() + .filter(|(_, pat)| pat.id != pat_outer.id) + .flat_map(|(idx, _)| maps[idx].iter()) + .map(|(key, binding)| (key.name, map_outer.get(&key), binding)); + + for (name, info, &binding_inner) in inners { + match info { + None => { // The inner binding is missing in the outer. + let binding_error = missing_vars + .entry(name) + .or_insert_with(|| BindingError { + name, + origin: BTreeSet::new(), + target: BTreeSet::new(), + could_be_path: name.as_str().starts_with(char::is_uppercase), + }); + binding_error.origin.insert(binding_inner.span); + binding_error.target.insert(pat_outer.span); + } + Some(binding_outer) => { + if binding_outer.binding_mode != binding_inner.binding_mode { + // The binding modes in the outer and inner bindings differ. + inconsistent_vars + .entry(name) + .or_insert((binding_inner.span, binding_outer.span)); } } } } } + // 3) Report all missing variables we found. let mut missing_vars = missing_vars.iter_mut().collect::<Vec<_>>(); missing_vars.sort(); for (name, mut v) in missing_vars { @@ -1220,212 +1233,245 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { ResolutionError::VariableNotBoundInPattern(v)); } + // 4) Report all inconsistencies in binding modes we found. let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>(); inconsistent_vars.sort(); for (name, v) in inconsistent_vars { self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1)); } - } - fn resolve_arm(&mut self, arm: &Arm) { - self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - - self.resolve_pats(&arm.pats, PatternSource::Match); - - if let Some(ref expr) = arm.guard { - self.visit_expr(expr) - } - self.visit_expr(&arm.body); - - self.ribs[ValueNS].pop(); + // 5) Finally bubble up all the binding maps. + maps } - /// Arising from `source`, resolve a sequence of patterns (top level or-patterns). - fn resolve_pats(&mut self, pats: &[P<Pat>], source: PatternSource) { - let mut bindings_list = FxHashMap::default(); - for pat in pats { - self.resolve_pattern(pat, source, &mut bindings_list); - } - // This has to happen *after* we determine which pat_idents are variants - if pats.len() > 1 { - self.check_consistent_bindings(pats); - } + /// Check the consistency of the outermost or-patterns. + fn check_consistent_bindings_top(&mut self, pat: &Pat) { + pat.walk(&mut |pat| match pat.node { + PatKind::Or(ref ps) => { + self.check_consistent_bindings(ps); + false + }, + _ => true, + }) } - fn resolve_block(&mut self, block: &Block) { - debug!("(resolving block) entering block"); - // Move down in the graph, if there's an anonymous module rooted here. - let orig_module = self.parent_scope.module; - let anonymous_module = self.r.block_map.get(&block.id).cloned(); // clones a reference - - let mut num_macro_definition_ribs = 0; - if let Some(anonymous_module) = anonymous_module { - debug!("(resolving block) found anonymous module, moving down"); - self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module))); - self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module))); - self.parent_scope.module = anonymous_module; - } else { - self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - } - - // Descend into the block. - for stmt in &block.stmts { - if let StmtKind::Item(ref item) = stmt.node { - if let ItemKind::MacroDef(..) = item.node { - num_macro_definition_ribs += 1; - let res = self.r.definitions.local_def_id(item.id); - self.ribs[ValueNS].push(Rib::new(MacroDefinition(res))); - self.label_ribs.push(Rib::new(MacroDefinition(res))); - } - } - - self.visit_stmt(stmt); - } - - // Move back up. - self.parent_scope.module = orig_module; - for _ in 0 .. num_macro_definition_ribs { - self.ribs[ValueNS].pop(); - self.label_ribs.pop(); - } - self.ribs[ValueNS].pop(); - if anonymous_module.is_some() { - self.ribs[TypeNS].pop(); - } - debug!("(resolving block) leaving block"); + fn resolve_arm(&mut self, arm: &Arm) { + self.with_rib(ValueNS, NormalRibKind, |this| { + this.resolve_pattern_top(&arm.pat, PatternSource::Match); + walk_list!(this, visit_expr, &arm.guard); + this.visit_expr(&arm.body); + }); } - fn fresh_binding(&mut self, - ident: Ident, - pat_id: NodeId, - outer_pat_id: NodeId, - pat_src: PatternSource, - bindings: &mut FxHashMap<Ident, NodeId>) - -> Res { - // Add the binding to the local ribs, if it - // doesn't already exist in the bindings map. (We - // must not add it if it's in the bindings map - // because that breaks the assumptions later - // passes make about or-patterns.) - let ident = ident.modern_and_legacy(); - let mut res = Res::Local(pat_id); - match bindings.get(&ident).cloned() { - Some(id) if id == outer_pat_id => { - // `Variant(a, a)`, error - self.r.report_error( - ident.span, - ResolutionError::IdentifierBoundMoreThanOnceInSamePattern( - &ident.as_str()) - ); - } - Some(..) if pat_src == PatternSource::FnParam => { - // `fn f(a: u8, a: u8)`, error - self.r.report_error( - ident.span, - ResolutionError::IdentifierBoundMoreThanOnceInParameterList( - &ident.as_str()) - ); - } - Some(..) if pat_src == PatternSource::Match || - pat_src == PatternSource::Let => { - // `Variant1(a) | Variant2(a)`, ok - // Reuse definition from the first `a`. - res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident]; - } - Some(..) => { - span_bug!(ident.span, "two bindings with the same name from \ - unexpected pattern source {:?}", pat_src); - } - None => { - // A completely fresh binding, add to the lists if it's valid. - if ident.name != kw::Invalid { - bindings.insert(ident, outer_pat_id); - self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, res); - } - } - } + /// Arising from `source`, resolve a top level pattern. + fn resolve_pattern_top(&mut self, pat: &Pat, pat_src: PatternSource) { + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + self.resolve_pattern(pat, pat_src, &mut bindings); + } - res + fn resolve_pattern( + &mut self, + pat: &Pat, + pat_src: PatternSource, + bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>, + ) { + self.resolve_pattern_inner(pat, pat_src, bindings); + // This has to happen *after* we determine which pat_idents are variants: + self.check_consistent_bindings_top(pat); + visit::walk_pat(self, pat); } - fn resolve_pattern(&mut self, - pat: &Pat, - pat_src: PatternSource, - // Maps idents to the node ID for the - // outermost pattern that binds them. - bindings: &mut FxHashMap<Ident, NodeId>) { + /// Resolve bindings in a pattern. This is a helper to `resolve_pattern`. + /// + /// ### `bindings` + /// + /// A stack of sets of bindings accumulated. + /// + /// In each set, `PatBoundCtx::Product` denotes that a found binding in it should + /// be interpreted as re-binding an already bound binding. This results in an error. + /// Meanwhile, `PatBound::Or` denotes that a found binding in the set should result + /// in reusing this binding rather than creating a fresh one. + /// + /// When called at the top level, the stack must have a single element + /// with `PatBound::Product`. Otherwise, pushing to the stack happens as + /// or-patterns (`p_0 | ... | p_n`) are encountered and the context needs + /// to be switched to `PatBoundCtx::Or` and then `PatBoundCtx::Product` for each `p_i`. + /// When each `p_i` has been dealt with, the top set is merged with its parent. + /// When a whole or-pattern has been dealt with, the thing happens. + /// + /// See the implementation and `fresh_binding` for more details. + fn resolve_pattern_inner( + &mut self, + pat: &Pat, + pat_src: PatternSource, + bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>, + ) { // Visit all direct subpatterns of this pattern. - let outer_pat_id = pat.id; pat.walk(&mut |pat| { debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node); match pat.node { - PatKind::Ident(bmode, ident, ref opt_pat) => { - // First try to resolve the identifier as some existing - // entity, then fall back to a fresh binding. - let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, - None, pat.span) - .and_then(LexicalScopeBinding::item); - let res = binding.map(NameBinding::res).and_then(|res| { - let is_syntactic_ambiguity = opt_pat.is_none() && - bmode == BindingMode::ByValue(Mutability::Immutable); - match res { - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | - Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => { - // Disambiguate in favor of a unit struct/variant - // or constant pattern. - self.r.record_use(ident, ValueNS, binding.unwrap(), false); - Some(res) - } - Res::Def(DefKind::Ctor(..), _) - | Res::Def(DefKind::Const, _) - | Res::Def(DefKind::Static, _) => { - // This is unambiguously a fresh binding, either syntactically - // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves - // to something unusable as a pattern (e.g., constructor function), - // but we still conservatively report an error, see - // issues/33118#issuecomment-233962221 for one reason why. - self.r.report_error( - ident.span, - ResolutionError::BindingShadowsSomethingUnacceptable( - pat_src.descr(), ident.name, binding.unwrap()) - ); - None - } - Res::Def(DefKind::Fn, _) | Res::Err => { - // These entities are explicitly allowed - // to be shadowed by fresh bindings. - None - } - res => { - span_bug!(ident.span, "unexpected resolution for an \ - identifier in pattern: {:?}", res); - } - } - }).unwrap_or_else(|| { - self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings) - }); - + PatKind::Ident(bmode, ident, ref sub) => { + // First try to resolve the identifier as some existing entity, + // then fall back to a fresh binding. + let has_sub = sub.is_some(); + let res = self.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub) + .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings)); self.r.record_partial_res(pat.id, PartialRes::new(res)); } - PatKind::TupleStruct(ref path, ..) => { self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct); } - PatKind::Path(ref qself, ref path) => { self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); } - PatKind::Struct(ref path, ..) => { self.smart_resolve_path(pat.id, None, path, PathSource::Struct); } - + PatKind::Or(ref ps) => { + // Add a new set of bindings to the stack. `Or` here records that when a + // binding already exists in this set, it should not result in an error because + // `V1(a) | V2(a)` must be allowed and are checked for consistency later. + bindings.push((PatBoundCtx::Or, Default::default())); + for p in ps { + // Now we need to switch back to a product context so that each + // part of the or-pattern internally rejects already bound names. + // For example, `V1(a) | V2(a, a)` and `V1(a, a) | V2(a)` are bad. + bindings.push((PatBoundCtx::Product, Default::default())); + self.resolve_pattern_inner(p, pat_src, bindings); + // Move up the non-overlapping bindings to the or-pattern. + // Existing bindings just get "merged". + let collected = bindings.pop().unwrap().1; + bindings.last_mut().unwrap().1.extend(collected); + } + // This or-pattern itself can itself be part of a product, + // e.g. `(V1(a) | V2(a), a)` or `(a, V1(a) | V2(a))`. + // Both cases bind `a` again in a product pattern and must be rejected. + let collected = bindings.pop().unwrap().1; + bindings.last_mut().unwrap().1.extend(collected); + + // Prevent visiting `ps` as we've already done so above. + return false; + } _ => {} } true }); + } - visit::walk_pat(self, pat); + fn fresh_binding( + &mut self, + ident: Ident, + pat_id: NodeId, + pat_src: PatternSource, + bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>, + ) -> Res { + // Add the binding to the local ribs, if it doesn't already exist in the bindings map. + // (We must not add it if it's in the bindings map because that breaks the assumptions + // later passes make about or-patterns.) + let ident = ident.modern_and_legacy(); + + // Walk outwards the stack of products / or-patterns and + // find out if the identifier has been bound in any of these. + let mut already_bound_and = false; + let mut already_bound_or = false; + for (is_sum, set) in bindings.iter_mut().rev() { + match (is_sum, set.get(&ident).cloned()) { + // Already bound in a product pattern, e.g. `(a, a)` which is not allowed. + (PatBoundCtx::Product, Some(..)) => already_bound_and = true, + // Already bound in an or-pattern, e.g. `V1(a) | V2(a)`. + // This is *required* for consistency which is checked later. + (PatBoundCtx::Or, Some(..)) => already_bound_or = true, + // Not already bound here. + _ => {} + } + } + + if already_bound_and { + // Overlap in a product pattern somewhere; report an error. + use ResolutionError::*; + let error = match pat_src { + // `fn f(a: u8, a: u8)`: + PatternSource::FnParam => IdentifierBoundMoreThanOnceInParameterList, + // `Variant(a, a)`: + _ => IdentifierBoundMoreThanOnceInSamePattern, + }; + self.r.report_error(ident.span, error(&ident.as_str())); + } + + // Record as bound if it's valid: + let ident_valid = ident.name != kw::Invalid; + if ident_valid { + bindings.last_mut().unwrap().1.insert(ident); + } + + if already_bound_or { + // `Variant1(a) | Variant2(a)`, ok + // Reuse definition from the first `a`. + self.innermost_rib_bindings(ValueNS)[&ident] + } else { + let res = Res::Local(pat_id); + if ident_valid { + // A completely fresh binding add to the set if it's valid. + self.innermost_rib_bindings(ValueNS).insert(ident, res); + } + res + } + } + + fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut IdentMap<Res> { + &mut self.ribs[ns].last_mut().unwrap().bindings + } + + fn try_resolve_as_non_binding( + &mut self, + pat_src: PatternSource, + pat: &Pat, + bm: BindingMode, + ident: Ident, + has_sub: bool, + ) -> Option<Res> { + let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?.item()?; + let res = binding.res(); + + // An immutable (no `mut`) by-value (no `ref`) binding pattern without + // a sub pattern (no `@ $pat`) is syntactically ambiguous as it could + // also be interpreted as a path to e.g. a constant, variant, etc. + let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Immutable); + + match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | + Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => { + // Disambiguate in favor of a unit struct/variant or constant pattern. + self.r.record_use(ident, ValueNS, binding, false); + Some(res) + } + Res::Def(DefKind::Ctor(..), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Static, _) => { + // This is unambiguously a fresh binding, either syntactically + // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves + // to something unusable as a pattern (e.g., constructor function), + // but we still conservatively report an error, see + // issues/33118#issuecomment-233962221 for one reason why. + self.r.report_error( + ident.span, + ResolutionError::BindingShadowsSomethingUnacceptable( + pat_src.descr(), + ident.name, + binding, + ), + ); + None + } + Res::Def(DefKind::Fn, _) | Res::Err => { + // These entities are explicitly allowed to be shadowed by fresh bindings. + None + } + res => { + span_bug!(ident.span, "unexpected resolution for an \ + identifier in pattern: {:?}", res); + } + } } // High-level and context dependent path resolution routine. @@ -1723,12 +1769,10 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { Some(result) } - fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F) - where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) - { + fn with_resolved_label(&mut self, label: Option<Label>, id: NodeId, f: impl FnOnce(&mut Self)) { if let Some(label) = label { self.unused_labels.insert(id, label.ident.span); - self.with_label_rib(|this| { + self.with_label_rib(NormalRibKind, |this| { let ident = label.ident.modern_and_legacy(); this.label_ribs.last_mut().unwrap().bindings.insert(ident, id); f(this); @@ -1742,6 +1786,49 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { self.with_resolved_label(label, id, |this| this.visit_block(block)); } + fn resolve_block(&mut self, block: &Block) { + debug!("(resolving block) entering block"); + // Move down in the graph, if there's an anonymous module rooted here. + let orig_module = self.parent_scope.module; + let anonymous_module = self.r.block_map.get(&block.id).cloned(); // clones a reference + + let mut num_macro_definition_ribs = 0; + if let Some(anonymous_module) = anonymous_module { + debug!("(resolving block) found anonymous module, moving down"); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module))); + self.parent_scope.module = anonymous_module; + } else { + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); + } + + // Descend into the block. + for stmt in &block.stmts { + if let StmtKind::Item(ref item) = stmt.node { + if let ItemKind::MacroDef(..) = item.node { + num_macro_definition_ribs += 1; + let res = self.r.definitions.local_def_id(item.id); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(res))); + self.label_ribs.push(Rib::new(MacroDefinition(res))); + } + } + + self.visit_stmt(stmt); + } + + // Move back up. + self.parent_scope.module = orig_module; + for _ in 0 .. num_macro_definition_ribs { + self.ribs[ValueNS].pop(); + self.label_ribs.pop(); + } + self.ribs[ValueNS].pop(); + if anonymous_module.is_some() { + self.ribs[TypeNS].pop(); + } + debug!("(resolving block) leaving block"); + } + fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) { // First, record candidate traits for this expression if it could // result in the invocation of a method call. @@ -1796,39 +1883,36 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { visit::walk_expr(self, expr); } - ExprKind::Let(ref pats, ref scrutinee) => { + ExprKind::Let(ref pat, ref scrutinee) => { self.visit_expr(scrutinee); - self.resolve_pats(pats, PatternSource::Let); + self.resolve_pattern_top(pat, PatternSource::Let); } ExprKind::If(ref cond, ref then, ref opt_else) => { - self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - self.visit_expr(cond); - self.visit_block(then); - self.ribs[ValueNS].pop(); - + self.with_rib(ValueNS, NormalRibKind, |this| { + this.visit_expr(cond); + this.visit_block(then); + }); opt_else.as_ref().map(|expr| self.visit_expr(expr)); } ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block), - ExprKind::While(ref subexpression, ref block, label) => { + ExprKind::While(ref cond, ref block, label) => { self.with_resolved_label(label, expr.id, |this| { - this.ribs[ValueNS].push(Rib::new(NormalRibKind)); - this.visit_expr(subexpression); - this.visit_block(block); - this.ribs[ValueNS].pop(); + this.with_rib(ValueNS, NormalRibKind, |this| { + this.visit_expr(cond); + this.visit_block(block); + }) }); } - ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => { - self.visit_expr(subexpression); - self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap::default()); - - self.resolve_labeled_block(label, expr.id, block); - - self.ribs[ValueNS].pop(); + ExprKind::ForLoop(ref pat, ref iter_expr, ref block, label) => { + self.visit_expr(iter_expr); + self.with_rib(ValueNS, NormalRibKind, |this| { + this.resolve_pattern_top(pat, PatternSource::For); + this.resolve_labeled_block(label, expr.id, block); + }); } ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block), @@ -1860,30 +1944,22 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to // resolve the arguments within the proper scopes so that usages of them inside the // closure are detected as upvars rather than normal closure arg usages. - ExprKind::Closure( - _, IsAsync::Async { .. }, _, - ref fn_decl, ref body, _span, - ) => { - let rib_kind = NormalRibKind; - self.ribs[ValueNS].push(Rib::new(rib_kind)); - // Resolve arguments: - let mut bindings_list = FxHashMap::default(); - for argument in &fn_decl.inputs { - self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); - self.visit_ty(&argument.ty); - } - // No need to resolve return type-- the outer closure return type is - // FunctionRetTy::Default - - // Now resolve the inner closure - { - // No need to resolve arguments: the inner closure has none. - // Resolve the return type: - visit::walk_fn_ret_ty(self, &fn_decl.output); - // Resolve the body - self.visit_expr(body); - } - self.ribs[ValueNS].pop(); + ExprKind::Closure(_, IsAsync::Async { .. }, _, ref fn_decl, ref body, _span) => { + self.with_rib(ValueNS, NormalRibKind, |this| { + // Resolve arguments: + this.resolve_params(&fn_decl.inputs); + // No need to resolve return type -- + // the outer closure return type is `FunctionRetTy::Default`. + + // Now resolve the inner closure + { + // No need to resolve arguments: the inner closure has none. + // Resolve the return type: + visit::walk_fn_ret_ty(this, &fn_decl.output); + // Resolve the body + this.visit_expr(body); + } + }); } _ => { visit::walk_expr(self, expr); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 875ae449d94..9b92bb7698a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -9,6 +9,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(inner_deref)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(mem_take)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index d1fd51a97f6..12c5ce12a0e 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -897,32 +897,23 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - fn process_var_decl_multi(&mut self, pats: &'l [P<ast::Pat>]) { + fn process_var_decl(&mut self, pat: &'l ast::Pat) { + // The pattern could declare multiple new vars, + // we must walk the pattern and collect them all. let mut collector = PathCollector::new(); - for pattern in pats { - // collect paths from the arm's patterns - collector.visit_pat(&pattern); - self.visit_pat(&pattern); - } + collector.visit_pat(&pat); + self.visit_pat(&pat); - // process collected paths - for (id, ident, immut) in collector.collected_idents { + // Process collected paths. + for (id, ident, _) in collector.collected_idents { match self.save_ctxt.get_path_res(id) { Res::Local(hir_id) => { - let mut value = if immut == ast::Mutability::Immutable { - self.span.snippet(ident.span) - } else { - "<mutable>".to_owned() - }; let id = self.tcx.hir().hir_to_node_id(hir_id); - let typ = self.save_ctxt - .tables - .node_type_opt(hir_id) + let typ = self.save_ctxt.tables.node_type_opt(hir_id) .map(|t| t.to_string()) .unwrap_or_default(); - value.push_str(": "); - value.push_str(&typ); + // Rust uses the id of the pattern for var lookups, so we'll use it too. if !self.span.filter_generated(ident.span) { let qualname = format!("{}${}", ident.to_string(), id); let id = id_from_node_id(id, &self.save_ctxt); @@ -972,61 +963,6 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) { - // The local could declare multiple new vars, we must walk the - // pattern and collect them all. - let mut collector = PathCollector::new(); - collector.visit_pat(&p); - self.visit_pat(&p); - - for (id, ident, immut) in collector.collected_idents { - let mut value = match immut { - ast::Mutability::Immutable => value.to_string(), - _ => String::new(), - }; - let hir_id = self.tcx.hir().node_to_hir_id(id); - let typ = match self.save_ctxt.tables.node_type_opt(hir_id) { - Some(typ) => { - let typ = typ.to_string(); - if !value.is_empty() { - value.push_str(": "); - } - value.push_str(&typ); - typ - } - None => String::new(), - }; - - // Rust uses the id of the pattern for var lookups, so we'll use it too. - if !self.span.filter_generated(ident.span) { - let qualname = format!("{}${}", ident.to_string(), id); - let id = id_from_node_id(id, &self.save_ctxt); - let span = self.span_from_span(ident.span); - - self.dumper.dump_def( - &Access { - public: false, - reachable: false, - }, - Def { - kind: DefKind::Local, - id, - span, - name: ident.to_string(), - qualname, - value: typ, - parent: None, - children: vec![], - decl_id: None, - docs: String::new(), - sig: None, - attributes: vec![], - }, - ); - } - } - } - /// Extracts macro use and definition information from the AST node defined /// by the given NodeId, using the expansion information from the node's /// span. @@ -1565,14 +1501,13 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { }); } ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => { - let value = self.span.snippet(subexpression.span); - self.process_var_decl(pattern, value); + self.process_var_decl(pattern); debug!("for loop, walk sub-expr: {:?}", subexpression.node); self.visit_expr(subexpression); visit::walk_block(self, block); } - ast::ExprKind::Let(ref pats, ref scrutinee) => { - self.process_var_decl_multi(pats); + ast::ExprKind::Let(ref pat, ref scrutinee) => { + self.process_var_decl(pat); self.visit_expr(scrutinee); } ast::ExprKind::Repeat(ref element, ref count) => { @@ -1599,7 +1534,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { } fn visit_arm(&mut self, arm: &'l ast::Arm) { - self.process_var_decl_multi(&arm.pats); + self.process_var_decl(&arm.pat); if let Some(expr) = &arm.guard { self.visit_expr(expr); } @@ -1617,11 +1552,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { fn visit_local(&mut self, l: &'l ast::Local) { self.process_macro_use(l.span); - let value = l.init - .as_ref() - .map(|i| self.span.snippet(i.span)) - .unwrap_or_default(); - self.process_var_decl(&l.pat, value); + self.process_var_decl(&l.pat); // Just walk the initialiser and type (don't want to walk the pattern again). walk_list!(self, visit_ty, &l.ty); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 92ccd4f49f6..4bc098db686 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -1,5 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(nll)] +#![feature(inner_deref)] #![recursion_limit="256"] diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 4cf0df308fb..24d0659391b 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -675,21 +675,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span); } } else { - let subpats_ending = if subpats.len() == 1 { "" } else { "s" }; - let fields_ending = if variant.fields.len() == 1 { "" } else { "s" }; - struct_span_err!(tcx.sess, pat.span, E0023, - "this pattern has {} field{}, but the corresponding {} has {} field{}", - subpats.len(), subpats_ending, res.descr(), - variant.fields.len(), fields_ending) - .span_label(pat.span, format!("expected {} field{}, found {}", - variant.fields.len(), fields_ending, subpats.len())) - .emit(); + // Pattern has wrong number of fields. + self.e0023(pat.span, res, &subpats, &variant.fields); on_error(); return tcx.types.err; } pat_ty } + fn e0023(&self, pat_span: Span, res: Res, subpats: &'tcx [P<Pat>], fields: &[ty::FieldDef]) { + let subpats_ending = if subpats.len() == 1 { "" } else { "s" }; + let fields_ending = if fields.len() == 1 { "" } else { "s" }; + let res_span = self.tcx.def_span(res.def_id()); + struct_span_err!( + self.tcx.sess, + pat_span, + E0023, + "this pattern has {} field{}, but the corresponding {} has {} field{}", + subpats.len(), + subpats_ending, + res.descr(), + fields.len(), + fields_ending, + ) + .span_label(pat_span, format!( + "expected {} field{}, found {}", + fields.len(), + fields_ending, + subpats.len(), + )) + .span_label(res_span, format!("{} defined here", res.descr())) + .emit(); + } + fn check_pat_tuple( &self, span: Span, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d5c47a15948..0e046b8cd44 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3554,7 +3554,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, let ns_id = cx.derive_id(format!("{}.{}", variant.name.as_ref().unwrap(), ItemType::Variant.name_space())); - write!(w, "<span id=\"{id}\" class=\"variant small-section-header\">\ + write!(w, "<div id=\"{id}\" class=\"variant small-section-header\">\ <a href=\"#{id}\" class=\"anchor field\"></a>\ <code id='{ns_id}'>{name}", id = id, @@ -3572,7 +3572,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, write!(w, ")")?; } } - write!(w, "</code></span>")?; + write!(w, "</code></div>")?; document(w, cx, variant)?; document_non_exhaustive(w, variant)?; @@ -3583,7 +3583,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, let variant_id = cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.as_ref().unwrap())); - write!(w, "<span class='autohide sub-variant' id='{id}'>", + write!(w, "<div class='autohide sub-variant' id='{id}'>", id = variant_id)?; write!(w, "<h3>Fields of <b>{name}</b></h3><div>", name = variant.name.as_ref().unwrap())?; @@ -3609,7 +3609,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, document(w, cx, field)?; } } - write!(w, "</div></span>")?; + write!(w, "</div></div>")?; } render_stability_since(w, variant, it)?; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 309e5575ee4..83b0b78a0ce 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -547,6 +547,11 @@ if (!DOMTokenList.prototype.remove) { results.sort(function(aaa, bbb) { var a, b; + // sort by exact match with regard to the last word (mismatch goes later) + a = (aaa.word !== val); + b = (bbb.word !== val); + if (a !== b) { return a - b; } + // Sort by non levenshtein results and then levenshtein results by the distance // (less changes required to match means higher rankings) a = (aaa.lev); @@ -558,11 +563,6 @@ if (!DOMTokenList.prototype.remove) { b = (bbb.item.crate !== window.currentCrate); if (a !== b) { return a - b; } - // sort by exact match (mismatch goes later) - a = (aaa.word !== valLower); - b = (bbb.word !== valLower); - if (a !== b) { return a - b; } - // sort by item name length (longer goes later) a = aaa.word.length; b = bbb.word.length; @@ -1028,7 +1028,7 @@ if (!DOMTokenList.prototype.remove) { if (lev > MAX_LEV_DISTANCE) { continue; } else if (lev > 0) { - lev_add = 1; + lev_add = lev / 10; } } @@ -1099,10 +1099,6 @@ if (!DOMTokenList.prototype.remove) { if (index !== -1 || lev <= MAX_LEV_DISTANCE) { if (index !== -1 && paths.length < 2) { lev = 0; - } else if (searchWords[j] === val) { - // Small trick to fix when you're looking for a one letter type - // and there are other short named types. - lev = -1; } if (results[fullId] === undefined) { results[fullId] = { diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 157faa0af9b..18a46cf0b52 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -56,6 +56,9 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } +[target.wasm32-wasi.dependencies] +wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] } + [build-dependencies] cc = "1.0" diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs index e719b362cbf..03a59d6d7c8 100644 --- a/src/libstd/sys/cloudabi/shims/process.rs +++ b/src/libstd/sys/cloudabi/shims/process.rs @@ -4,14 +4,16 @@ use crate::io; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; + +pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { - env: CommandEnv<DefaultEnvKey>, + env: CommandEnv, } // passed back to std::process with the pipes connected to the child, if any @@ -37,7 +39,7 @@ impl Command { pub fn arg(&mut self, _arg: &OsStr) {} - pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs index a02e009d953..edf933d10e0 100644 --- a/src/libstd/sys/sgx/process.rs +++ b/src/libstd/sys/sgx/process.rs @@ -4,14 +4,16 @@ use crate::io; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; + +pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { - env: CommandEnv<DefaultEnvKey> + env: CommandEnv, } // passed back to std::process with the pipes connected to the child, if any @@ -38,7 +40,7 @@ impl Command { pub fn arg(&mut self, _arg: &OsStr) { } - pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs index bba4b21c462..056a20345f4 100644 --- a/src/libstd/sys/unix/process/mod.rs +++ b/src/libstd/sys/unix/process/mod.rs @@ -1,5 +1,6 @@ pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::Process; +pub use crate::ffi::OsString as EnvKey; mod process_common; #[cfg(not(target_os = "fuchsia"))] diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 21fca23a8fe..72e66cc8e72 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -7,7 +7,7 @@ use crate::ptr; use crate::sys::fd::FileDesc; use crate::sys::fs::{File, OpenOptions}; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; use crate::collections::BTreeMap; use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE}; @@ -69,7 +69,7 @@ pub struct Command { program: CString, args: Vec<CString>, argv: Argv, - env: CommandEnv<DefaultEnvKey>, + env: CommandEnv, cwd: Option<CString>, uid: Option<uid_t>, @@ -201,7 +201,7 @@ impl Command { self.stderr = Some(stderr); } - pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } @@ -271,7 +271,7 @@ impl CStringArray { } } -fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray { +fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray { let mut result = CStringArray::with_capacity(env.len()); for (k, v) in env { let mut k: OsString = k.into(); diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 02f377d55c9..fd6796ad22c 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -311,6 +311,7 @@ mod inner { pub fn actually_monotonic() -> bool { (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) || + cfg!(target_os = "fuchsia") || false // last clause, used so `||` is always trailing above } diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs index ba797354a73..509140229fd 100644 --- a/src/libstd/sys/vxworks/process/process_common.rs +++ b/src/libstd/sys/vxworks/process/process_common.rs @@ -7,11 +7,13 @@ use crate::ptr; use crate::sys::fd::FileDesc; use crate::sys::fs::{File, OpenOptions}; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; use crate::collections::BTreeMap; use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE}; +pub use crate::ffi::OsString as EnvKey; + //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// @@ -37,7 +39,7 @@ pub struct Command { program: CString, args: Vec<CString>, argv: Argv, - env: CommandEnv<DefaultEnvKey>, + env: CommandEnv, cwd: Option<CString>, uid: Option<uid_t>, @@ -170,7 +172,7 @@ impl Command { self.stderr = Some(stderr); } - pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } @@ -240,7 +242,7 @@ impl CStringArray { } } -fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray { +fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray { let mut result = CStringArray::with_capacity(env.len()); for (k, v) in env { let mut k: OsString = k.into(); diff --git a/src/libstd/sys/wasi/args.rs b/src/libstd/sys/wasi/args.rs index 8b4b354d9fc..3280c4990dc 100644 --- a/src/libstd/sys/wasi/args.rs +++ b/src/libstd/sys/wasi/args.rs @@ -1,11 +1,10 @@ -use crate::ffi::CStr; -use crate::io; -use crate::sys::cvt_wasi; use crate::ffi::OsString; use crate::marker::PhantomData; use crate::os::wasi::ffi::OsStringExt; use crate::vec; +use ::wasi::wasi_unstable as wasi; + pub unsafe fn init(_argc: isize, _argv: *const *const u8) { } @@ -19,31 +18,17 @@ pub struct Args { /// Returns the command line arguments pub fn args() -> Args { - maybe_args().unwrap_or_else(|_| { - Args { - iter: Vec::new().into_iter(), - _dont_send_or_sync_me: PhantomData - } - }) -} - -fn maybe_args() -> io::Result<Args> { - unsafe { - let (mut argc, mut argv_buf_size) = (0, 0); - cvt_wasi(libc::__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?; - - let mut argc = vec![core::ptr::null_mut::<libc::c_char>(); argc]; - let mut argv_buf = vec![0; argv_buf_size]; - cvt_wasi(libc::__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?; - - let args = argc.into_iter() - .map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec()) - .map(|bytes| OsString::from_vec(bytes)) - .collect::<Vec<_>>(); - Ok(Args { - iter: args.into_iter(), - _dont_send_or_sync_me: PhantomData, - }) + let buf = wasi::args_sizes_get().and_then(|args_sizes| { + let mut buf = Vec::with_capacity(args_sizes.get_count()); + wasi::args_get(args_sizes, |arg| { + let arg = OsString::from_vec(arg.to_vec()); + buf.push(arg); + })?; + Ok(buf) + }).unwrap_or(vec![]); + Args { + iter: buf.into_iter(), + _dont_send_or_sync_me: PhantomData } } diff --git a/src/libstd/sys/wasi/ext/fs.rs b/src/libstd/sys/wasi/ext/fs.rs index 0ec4122f385..9fa4abfd171 100644 --- a/src/libstd/sys/wasi/ext/fs.rs +++ b/src/libstd/sys/wasi/ext/fs.rs @@ -8,6 +8,8 @@ use crate::os::wasi::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; +use ::wasi::wasi_unstable as wasi; + /// WASI-specific extensions to [`File`]. /// /// [`File`]: ../../../../std/fs/struct.File.html @@ -336,16 +338,16 @@ pub trait FileTypeExt { impl FileTypeExt for fs::FileType { fn is_block_device(&self) -> bool { - self.as_inner().bits() == libc::__WASI_FILETYPE_BLOCK_DEVICE + self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE } fn is_character_device(&self) -> bool { - self.as_inner().bits() == libc::__WASI_FILETYPE_CHARACTER_DEVICE + self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE } fn is_socket_dgram(&self) -> bool { - self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_DGRAM + self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM } fn is_socket_stream(&self) -> bool { - self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_STREAM + self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM } } diff --git a/src/libstd/sys/wasi/ext/io.rs b/src/libstd/sys/wasi/ext/io.rs index 12afd1d42dc..f1839df3801 100644 --- a/src/libstd/sys/wasi/ext/io.rs +++ b/src/libstd/sys/wasi/ext/io.rs @@ -8,6 +8,8 @@ use crate::sys; use crate::net; use crate::sys_common::{AsInner, FromInner, IntoInner}; +use ::wasi::wasi_unstable as wasi; + /// Raw file descriptors. pub type RawFd = u32; @@ -125,18 +127,18 @@ impl IntoRawFd for fs::File { impl AsRawFd for io::Stdin { fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO as u32 + wasi::STDIN_FD } } impl AsRawFd for io::Stdout { fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO as u32 + wasi::STDOUT_FD } } impl AsRawFd for io::Stderr { fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO as u32 + wasi::STDERR_FD } } diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs index 25692ec0868..5b7a8678b66 100644 --- a/src/libstd/sys/wasi/fd.rs +++ b/src/libstd/sys/wasi/fd.rs @@ -3,348 +3,248 @@ use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; -use crate::sys::cvt_wasi; -use libc::{self, c_char, c_void}; +use super::err2io; +use ::wasi::wasi_unstable as wasi; #[derive(Debug)] pub struct WasiFd { - fd: libc::__wasi_fd_t, + fd: wasi::Fd, } -// FIXME: these should probably all be fancier structs, builders, enums, etc -pub type LookupFlags = u32; -pub type FdFlags = u16; -pub type Advice = u8; -pub type Rights = u64; -pub type Oflags = u16; -pub type DirCookie = u64; -pub type Timestamp = u64; -pub type FstFlags = u16; -pub type RiFlags = u16; -pub type RoFlags = u16; -pub type SiFlags = u16; - -fn iovec(a: &mut [IoSliceMut<'_>]) -> (*const libc::__wasi_iovec_t, usize) { +fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::IoVec] { assert_eq!( mem::size_of::<IoSliceMut<'_>>(), - mem::size_of::<libc::__wasi_iovec_t>() + mem::size_of::<wasi::IoVec>() ); assert_eq!( mem::align_of::<IoSliceMut<'_>>(), - mem::align_of::<libc::__wasi_iovec_t>() + mem::align_of::<wasi::IoVec>() ); - (a.as_ptr() as *const libc::__wasi_iovec_t, a.len()) + /// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout + unsafe { mem::transmute(a) } } -fn ciovec(a: &[IoSlice<'_>]) -> (*const libc::__wasi_ciovec_t, usize) { +fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::CIoVec] { assert_eq!( mem::size_of::<IoSlice<'_>>(), - mem::size_of::<libc::__wasi_ciovec_t>() + mem::size_of::<wasi::CIoVec>() ); assert_eq!( mem::align_of::<IoSlice<'_>>(), - mem::align_of::<libc::__wasi_ciovec_t>() + mem::align_of::<wasi::CIoVec>() ); - (a.as_ptr() as *const libc::__wasi_ciovec_t, a.len()) + /// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout + unsafe { mem::transmute(a) } } impl WasiFd { - pub unsafe fn from_raw(fd: libc::__wasi_fd_t) -> WasiFd { + pub unsafe fn from_raw(fd: wasi::Fd) -> WasiFd { WasiFd { fd } } - pub fn into_raw(self) -> libc::__wasi_fd_t { + pub fn into_raw(self) -> wasi::Fd { let ret = self.fd; mem::forget(self); ret } - pub fn as_raw(&self) -> libc::__wasi_fd_t { + pub fn as_raw(&self) -> wasi::Fd { self.fd } pub fn datasync(&self) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) }) + unsafe { wasi::fd_datasync(self.fd).map_err(err2io) } } pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { - let mut read = 0; - let (ptr, len) = iovec(bufs); - cvt_wasi(unsafe { libc::__wasi_fd_pread(self.fd, ptr, len, offset, &mut read) })?; - Ok(read) + unsafe { wasi::fd_pread(self.fd, iovec(bufs), offset).map_err(err2io) } } pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { - let mut read = 0; - let (ptr, len) = ciovec(bufs); - cvt_wasi(unsafe { libc::__wasi_fd_pwrite(self.fd, ptr, len, offset, &mut read) })?; - Ok(read) + unsafe { wasi::fd_pwrite(self.fd, ciovec(bufs), offset).map_err(err2io) } } pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - let mut read = 0; - let (ptr, len) = iovec(bufs); - cvt_wasi(unsafe { libc::__wasi_fd_read(self.fd, ptr, len, &mut read) })?; - Ok(read) + unsafe { wasi::fd_read(self.fd, iovec(bufs)).map_err(err2io) } } pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let mut read = 0; - let (ptr, len) = ciovec(bufs); - cvt_wasi(unsafe { libc::__wasi_fd_write(self.fd, ptr, len, &mut read) })?; - Ok(read) + unsafe { wasi::fd_write(self.fd, ciovec(bufs)).map_err(err2io) } } pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { let (whence, offset) = match pos { - SeekFrom::Start(pos) => (libc::__WASI_WHENCE_SET, pos as i64), - SeekFrom::End(pos) => (libc::__WASI_WHENCE_END, pos), - SeekFrom::Current(pos) => (libc::__WASI_WHENCE_CUR, pos), + SeekFrom::Start(pos) => (wasi::WHENCE_SET, pos as i64), + SeekFrom::End(pos) => (wasi::WHENCE_END, pos), + SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos), }; - let mut pos = 0; - cvt_wasi(unsafe { libc::__wasi_fd_seek(self.fd, offset, whence, &mut pos) })?; - Ok(pos) + unsafe { wasi::fd_seek(self.fd, offset, whence).map_err(err2io) } } pub fn tell(&self) -> io::Result<u64> { - let mut pos = 0; - cvt_wasi(unsafe { libc::__wasi_fd_tell(self.fd, &mut pos) })?; - Ok(pos) + unsafe { wasi::fd_tell(self.fd).map_err(err2io) } } // FIXME: __wasi_fd_fdstat_get - pub fn set_flags(&self, flags: FdFlags) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_flags(self.fd, flags) }) + pub fn set_flags(&self, flags: wasi::FdFlags) -> io::Result<()> { + unsafe { wasi::fd_fdstat_set_flags(self.fd, flags).map_err(err2io) } } - pub fn set_rights(&self, base: Rights, inheriting: Rights) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_rights(self.fd, base, inheriting) }) + pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> { + unsafe { wasi::fd_fdstat_set_rights(self.fd, base, inheriting).map_err(err2io) } } pub fn sync(&self) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_sync(self.fd) }) + unsafe { wasi::fd_sync(self.fd).map_err(err2io) } } - pub fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_advise(self.fd, offset, len, advice as u8) }) + pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { + unsafe { wasi::fd_advise(self.fd, offset, len, advice).map_err(err2io) } } pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) }) + unsafe { wasi::fd_allocate(self.fd, offset, len).map_err(err2io) } } pub fn create_directory(&self, path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len()) - }) + unsafe { wasi::path_create_directory(self.fd, path).map_err(err2io) } } pub fn link( &self, - old_flags: LookupFlags, + old_flags: wasi::LookupFlags, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8], ) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_link( - self.fd, - old_flags, - old_path.as_ptr() as *const c_char, - old_path.len(), - new_fd.fd, - new_path.as_ptr() as *const c_char, - new_path.len(), - ) - }) + unsafe { + wasi::path_link(self.fd, old_flags, old_path, new_fd.fd, new_path) + .map_err(err2io) + } } pub fn open( &self, - dirflags: LookupFlags, + dirflags: wasi::LookupFlags, path: &[u8], - oflags: Oflags, - fs_rights_base: Rights, - fs_rights_inheriting: Rights, - fs_flags: FdFlags, + oflags: wasi::OFlags, + fs_rights_base: wasi::Rights, + fs_rights_inheriting: wasi::Rights, + fs_flags: wasi::FdFlags, ) -> io::Result<WasiFd> { unsafe { - let mut fd = 0; - cvt_wasi(libc::__wasi_path_open( + wasi::path_open( self.fd, dirflags, - path.as_ptr() as *const c_char, - path.len(), + path, oflags, fs_rights_base, fs_rights_inheriting, fs_flags, - &mut fd, - ))?; - Ok(WasiFd::from_raw(fd)) + ).map(|fd| WasiFd::from_raw(fd)).map_err(err2io) } } - pub fn readdir(&self, buf: &mut [u8], cookie: DirCookie) -> io::Result<usize> { - let mut used = 0; - cvt_wasi(unsafe { - libc::__wasi_fd_readdir( - self.fd, - buf.as_mut_ptr() as *mut c_void, - buf.len(), - cookie, - &mut used, - ) - })?; - Ok(used) + pub fn readdir(&self, buf: &mut [u8], cookie: wasi::DirCookie) -> io::Result<usize> { + unsafe { wasi::fd_readdir(self.fd, buf, cookie).map_err(err2io) } } pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result<usize> { - let mut used = 0; - cvt_wasi(unsafe { - libc::__wasi_path_readlink( - self.fd, - path.as_ptr() as *const c_char, - path.len(), - buf.as_mut_ptr() as *mut c_char, - buf.len(), - &mut used, - ) - })?; - Ok(used) + unsafe { wasi::path_readlink(self.fd, path, buf).map_err(err2io) } } pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_rename( - self.fd, - old_path.as_ptr() as *const c_char, - old_path.len(), - new_fd.fd, - new_path.as_ptr() as *const c_char, - new_path.len(), - ) - }) + unsafe { + wasi::path_rename(self.fd, old_path, new_fd.fd, new_path).map_err(err2io) + } } - pub fn filestat_get(&self, buf: *mut libc::__wasi_filestat_t) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_filestat_get(self.fd, buf) }) + pub fn filestat_get(&self) -> io::Result<wasi::FileStat> { + unsafe { wasi::fd_filestat_get(self.fd).map_err(err2io) } } pub fn filestat_set_times( &self, - atim: Timestamp, - mtim: Timestamp, - fstflags: FstFlags, + atim: wasi::Timestamp, + mtim: wasi::Timestamp, + fstflags: wasi::FstFlags, ) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_times(self.fd, atim, mtim, fstflags) }) + unsafe { + wasi::fd_filestat_set_times(self.fd, atim, mtim, fstflags).map_err(err2io) + } } pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { - cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) }) + unsafe { wasi::fd_filestat_set_size(self.fd, size).map_err(err2io) } } pub fn path_filestat_get( &self, - flags: LookupFlags, + flags: wasi::LookupFlags, path: &[u8], - buf: *mut libc::__wasi_filestat_t, - ) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_filestat_get( - self.fd, - flags, - path.as_ptr() as *const c_char, - path.len(), - buf, - ) - }) + ) -> io::Result<wasi::FileStat> { + unsafe { wasi::path_filestat_get(self.fd, flags, path).map_err(err2io) } } pub fn path_filestat_set_times( &self, - flags: LookupFlags, + flags: wasi::LookupFlags, path: &[u8], - atim: Timestamp, - mtim: Timestamp, - fstflags: FstFlags, + atim: wasi::Timestamp, + mtim: wasi::Timestamp, + fstflags: wasi::FstFlags, ) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_filestat_set_times( + unsafe { + wasi::path_filestat_set_times( self.fd, flags, - path.as_ptr() as *const c_char, - path.len(), + path, atim, mtim, fstflags, - ) - }) + ).map_err(err2io) + } } pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_symlink( - old_path.as_ptr() as *const c_char, - old_path.len(), - self.fd, - new_path.as_ptr() as *const c_char, - new_path.len(), - ) - }) + unsafe { wasi::path_symlink(old_path, self.fd, new_path).map_err(err2io) } } pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_unlink_file(self.fd, path.as_ptr() as *const c_char, path.len()) - }) + unsafe { wasi::path_unlink_file(self.fd, path).map_err(err2io) } } pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> { - cvt_wasi(unsafe { - libc::__wasi_path_remove_directory(self.fd, path.as_ptr() as *const c_char, path.len()) - }) + unsafe { wasi::path_remove_directory(self.fd, path).map_err(err2io) } } pub fn sock_recv( &self, ri_data: &mut [IoSliceMut<'_>], - ri_flags: RiFlags, - ) -> io::Result<(usize, RoFlags)> { - let mut ro_datalen = 0; - let mut ro_flags = 0; - let (ptr, len) = iovec(ri_data); - cvt_wasi(unsafe { - libc::__wasi_sock_recv(self.fd, ptr, len, ri_flags, &mut ro_datalen, &mut ro_flags) - })?; - Ok((ro_datalen, ro_flags)) + ri_flags: wasi::RiFlags, + ) -> io::Result<(usize, wasi::RoFlags)> { + unsafe { wasi::sock_recv(self.fd, iovec(ri_data), ri_flags).map_err(err2io) } } - pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: SiFlags) -> io::Result<usize> { - let mut so_datalen = 0; - let (ptr, len) = ciovec(si_data); - cvt_wasi(unsafe { libc::__wasi_sock_send(self.fd, ptr, len, si_flags, &mut so_datalen) })?; - Ok(so_datalen) + pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::SiFlags) -> io::Result<usize> { + unsafe { wasi::sock_send(self.fd, ciovec(si_data), si_flags).map_err(err2io) } } pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { - Shutdown::Read => libc::__WASI_SHUT_RD, - Shutdown::Write => libc::__WASI_SHUT_WR, - Shutdown::Both => libc::__WASI_SHUT_WR | libc::__WASI_SHUT_RD, + Shutdown::Read => wasi::SHUT_RD, + Shutdown::Write => wasi::SHUT_WR, + Shutdown::Both => wasi::SHUT_WR | wasi::SHUT_RD, }; - cvt_wasi(unsafe { libc::__wasi_sock_shutdown(self.fd, how) })?; - Ok(()) + unsafe { wasi::sock_shutdown(self.fd, how).map_err(err2io) } } } impl Drop for WasiFd { fn drop(&mut self) { - unsafe { - // FIXME: can we handle the return code here even though we can't on - // unix? - libc::__wasi_fd_close(self.fd); - } + // FIXME: can we handle the return code here even though we can't on + // unix? + let _ = unsafe { wasi::fd_close(self.fd) }; } } diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index 172c60385b3..4113f6a2e09 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -7,7 +7,7 @@ use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Arc; -use crate::sys::fd::{DirCookie, WasiFd}; +use crate::sys::fd::WasiFd; use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::FromInner; @@ -15,18 +15,20 @@ use crate::sys_common::FromInner; pub use crate::sys_common::fs::copy; pub use crate::sys_common::fs::remove_dir_all; +use ::wasi::wasi_unstable as wasi; + pub struct File { fd: WasiFd, } #[derive(Clone)] pub struct FileAttr { - meta: libc::__wasi_filestat_t, + meta: wasi::FileStat, } pub struct ReadDir { inner: Arc<ReadDirInner>, - cookie: Option<DirCookie>, + cookie: Option<wasi::DirCookie>, buf: Vec<u8>, offset: usize, cap: usize, @@ -38,7 +40,7 @@ struct ReadDirInner { } pub struct DirEntry { - meta: libc::__wasi_dirent_t, + meta: wasi::Dirent, name: Vec<u8>, inner: Arc<ReadDirInner>, } @@ -47,11 +49,11 @@ pub struct DirEntry { pub struct OpenOptions { read: bool, write: bool, - dirflags: libc::__wasi_lookupflags_t, - fdflags: libc::__wasi_fdflags_t, - oflags: libc::__wasi_oflags_t, - rights_base: Option<libc::__wasi_rights_t>, - rights_inheriting: Option<libc::__wasi_rights_t>, + dirflags: wasi::LookupFlags, + fdflags: wasi::FdFlags, + oflags: wasi::OFlags, + rights_base: Option<wasi::Rights>, + rights_inheriting: Option<wasi::Rights>, } #[derive(Clone, PartialEq, Eq, Debug)] @@ -61,19 +63,13 @@ pub struct FilePermissions { #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] pub struct FileType { - bits: libc::__wasi_filetype_t, + bits: wasi::FileType, } #[derive(Debug)] pub struct DirBuilder {} impl FileAttr { - fn zero() -> FileAttr { - FileAttr { - meta: unsafe { mem::zeroed() }, - } - } - pub fn size(&self) -> u64 { self.meta.st_size } @@ -101,7 +97,7 @@ impl FileAttr { Ok(SystemTime::from_wasi_timestamp(self.meta.st_ctim)) } - pub fn as_wasi(&self) -> &libc::__wasi_filestat_t { + pub fn as_wasi(&self) -> &wasi::FileStat { &self.meta } } @@ -118,18 +114,18 @@ impl FilePermissions { impl FileType { pub fn is_dir(&self) -> bool { - self.bits == libc::__WASI_FILETYPE_DIRECTORY + self.bits == wasi::FILETYPE_DIRECTORY } pub fn is_file(&self) -> bool { - self.bits == libc::__WASI_FILETYPE_REGULAR_FILE + self.bits == wasi::FILETYPE_REGULAR_FILE } pub fn is_symlink(&self) -> bool { - self.bits == libc::__WASI_FILETYPE_SYMBOLIC_LINK + self.bits == wasi::FILETYPE_SYMBOLIC_LINK } - pub fn bits(&self) -> libc::__wasi_filetype_t { + pub fn bits(&self) -> wasi::FileType { self.bits } } @@ -173,7 +169,7 @@ impl Iterator for ReadDir { // must have been truncated at the end of the buffer, so reset our // offset so we can go back and reread into the buffer, picking up // where we last left off. - let dirent_size = mem::size_of::<libc::__wasi_dirent_t>(); + let dirent_size = mem::size_of::<wasi::Dirent>(); if data.len() < dirent_size { assert!(self.cookie.is_some()); assert!(self.buf.len() >= dirent_size); @@ -182,7 +178,7 @@ impl Iterator for ReadDir { } let (dirent, data) = data.split_at(dirent_size); let dirent = - unsafe { ptr::read_unaligned(dirent.as_ptr() as *const libc::__wasi_dirent_t) }; + unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; // If the file name was truncated, then we need to reinvoke // `readdir` so we truncate our buffer to start over and reread this @@ -241,7 +237,7 @@ impl DirEntry { }) } - pub fn ino(&self) -> libc::__wasi_inode_t { + pub fn ino(&self) -> wasi::Inode { self.meta.d_ino } } @@ -249,7 +245,7 @@ impl DirEntry { impl OpenOptions { pub fn new() -> OpenOptions { let mut base = OpenOptions::default(); - base.dirflags = libc::__WASI_LOOKUP_SYMLINK_FOLLOW; + base.dirflags = wasi::LOOKUP_SYMLINK_FOLLOW; return base; } @@ -262,23 +258,23 @@ impl OpenOptions { } pub fn truncate(&mut self, truncate: bool) { - self.oflag(libc::__WASI_O_TRUNC, truncate); + self.oflag(wasi::O_TRUNC, truncate); } pub fn create(&mut self, create: bool) { - self.oflag(libc::__WASI_O_CREAT, create); + self.oflag(wasi::O_CREAT, create); } pub fn create_new(&mut self, create_new: bool) { - self.oflag(libc::__WASI_O_EXCL, create_new); - self.oflag(libc::__WASI_O_CREAT, create_new); + self.oflag(wasi::O_EXCL, create_new); + self.oflag(wasi::O_CREAT, create_new); } pub fn directory(&mut self, directory: bool) { - self.oflag(libc::__WASI_O_DIRECTORY, directory); + self.oflag(wasi::O_DIRECTORY, directory); } - fn oflag(&mut self, bit: libc::__wasi_oflags_t, set: bool) { + fn oflag(&mut self, bit: wasi::OFlags, set: bool) { if set { self.oflags |= bit; } else { @@ -287,26 +283,26 @@ impl OpenOptions { } pub fn append(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_APPEND, set); + self.fdflag(wasi::FDFLAG_APPEND, set); } pub fn dsync(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_DSYNC, set); + self.fdflag(wasi::FDFLAG_DSYNC, set); } pub fn nonblock(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_NONBLOCK, set); + self.fdflag(wasi::FDFLAG_NONBLOCK, set); } pub fn rsync(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_RSYNC, set); + self.fdflag(wasi::FDFLAG_RSYNC, set); } pub fn sync(&mut self, set: bool) { - self.fdflag(libc::__WASI_FDFLAG_SYNC, set); + self.fdflag(wasi::FDFLAG_SYNC, set); } - fn fdflag(&mut self, bit: libc::__wasi_fdflags_t, set: bool) { + fn fdflag(&mut self, bit: wasi::FdFlags, set: bool) { if set { self.fdflags |= bit; } else { @@ -314,15 +310,15 @@ impl OpenOptions { } } - pub fn fs_rights_base(&mut self, rights: libc::__wasi_rights_t) { + pub fn fs_rights_base(&mut self, rights: wasi::Rights) { self.rights_base = Some(rights); } - pub fn fs_rights_inheriting(&mut self, rights: libc::__wasi_rights_t) { + pub fn fs_rights_inheriting(&mut self, rights: wasi::Rights) { self.rights_inheriting = Some(rights); } - fn rights_base(&self) -> libc::__wasi_rights_t { + fn rights_base(&self) -> wasi::Rights { if let Some(rights) = self.rights_base { return rights; } @@ -334,52 +330,52 @@ impl OpenOptions { // based on that. let mut base = 0; if self.read { - base |= libc::__WASI_RIGHT_FD_READ; - base |= libc::__WASI_RIGHT_FD_READDIR; + base |= wasi::RIGHT_FD_READ; + base |= wasi::RIGHT_FD_READDIR; } if self.write { - base |= libc::__WASI_RIGHT_FD_WRITE; - base |= libc::__WASI_RIGHT_FD_DATASYNC; - base |= libc::__WASI_RIGHT_FD_ALLOCATE; - base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_SIZE; + base |= wasi::RIGHT_FD_WRITE; + base |= wasi::RIGHT_FD_DATASYNC; + base |= wasi::RIGHT_FD_ALLOCATE; + base |= wasi::RIGHT_FD_FILESTAT_SET_SIZE; } // FIXME: some of these should probably be read-only or write-only... - base |= libc::__WASI_RIGHT_FD_ADVISE; - base |= libc::__WASI_RIGHT_FD_FDSTAT_SET_FLAGS; - base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_TIMES; - base |= libc::__WASI_RIGHT_FD_SEEK; - base |= libc::__WASI_RIGHT_FD_SYNC; - base |= libc::__WASI_RIGHT_FD_TELL; - base |= libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY; - base |= libc::__WASI_RIGHT_PATH_CREATE_FILE; - base |= libc::__WASI_RIGHT_PATH_FILESTAT_GET; - base |= libc::__WASI_RIGHT_PATH_LINK_SOURCE; - base |= libc::__WASI_RIGHT_PATH_LINK_TARGET; - base |= libc::__WASI_RIGHT_PATH_OPEN; - base |= libc::__WASI_RIGHT_PATH_READLINK; - base |= libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY; - base |= libc::__WASI_RIGHT_PATH_RENAME_SOURCE; - base |= libc::__WASI_RIGHT_PATH_RENAME_TARGET; - base |= libc::__WASI_RIGHT_PATH_SYMLINK; - base |= libc::__WASI_RIGHT_PATH_UNLINK_FILE; - base |= libc::__WASI_RIGHT_POLL_FD_READWRITE; + base |= wasi::RIGHT_FD_ADVISE; + base |= wasi::RIGHT_FD_FDSTAT_SET_FLAGS; + base |= wasi::RIGHT_FD_FILESTAT_SET_TIMES; + base |= wasi::RIGHT_FD_SEEK; + base |= wasi::RIGHT_FD_SYNC; + base |= wasi::RIGHT_FD_TELL; + base |= wasi::RIGHT_PATH_CREATE_DIRECTORY; + base |= wasi::RIGHT_PATH_CREATE_FILE; + base |= wasi::RIGHT_PATH_FILESTAT_GET; + base |= wasi::RIGHT_PATH_LINK_SOURCE; + base |= wasi::RIGHT_PATH_LINK_TARGET; + base |= wasi::RIGHT_PATH_OPEN; + base |= wasi::RIGHT_PATH_READLINK; + base |= wasi::RIGHT_PATH_REMOVE_DIRECTORY; + base |= wasi::RIGHT_PATH_RENAME_SOURCE; + base |= wasi::RIGHT_PATH_RENAME_TARGET; + base |= wasi::RIGHT_PATH_SYMLINK; + base |= wasi::RIGHT_PATH_UNLINK_FILE; + base |= wasi::RIGHT_POLL_FD_READWRITE; return base; } - fn rights_inheriting(&self) -> libc::__wasi_rights_t { + fn rights_inheriting(&self) -> wasi::Rights { self.rights_inheriting.unwrap_or_else(|| self.rights_base()) } - pub fn lookup_flags(&mut self, flags: libc::__wasi_lookupflags_t) { + pub fn lookup_flags(&mut self, flags: wasi::LookupFlags) { self.dirflags = flags; } } impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { - let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?; + let (dir, file) = open_parent(path, wasi::RIGHT_PATH_OPEN)?; open_at(&dir, &file, opts) } @@ -388,14 +384,12 @@ impl File { } pub fn file_attr(&self) -> io::Result<FileAttr> { - let mut ret = FileAttr::zero(); - self.fd.filestat_get(&mut ret.meta)?; - Ok(ret) + self.fd.filestat_get().map(|meta| FileAttr { meta }) } pub fn metadata_at( &self, - flags: libc::__wasi_lookupflags_t, + flags: wasi::LookupFlags, path: &Path, ) -> io::Result<FileAttr> { metadata_at(&self.fd, flags, path) @@ -477,7 +471,7 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_CREATE_DIRECTORY)?; dir.create_directory(file.as_os_str().as_bytes()) } } @@ -508,13 +502,13 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> { } pub fn unlink(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_UNLINK_FILE)?; dir.unlink_file(file.as_os_str().as_bytes()) } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?; - let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?; + let (old, old_file) = open_parent(old, wasi::RIGHT_PATH_RENAME_SOURCE)?; + let (new, new_file) = open_parent(new, wasi::RIGHT_PATH_RENAME_TARGET)?; old.rename( old_file.as_os_str().as_bytes(), &new, @@ -529,12 +523,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn rmdir(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_REMOVE_DIRECTORY)?; dir.remove_directory(file.as_os_str().as_bytes()) } pub fn readlink(p: &Path) -> io::Result<PathBuf> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_READLINK)?; read_link(&dir, &file) } @@ -570,15 +564,15 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> { } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?; + let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_SYMLINK)?; dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes()) } pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?; - let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?; + let (src, src_file) = open_parent(src, wasi::RIGHT_PATH_LINK_SOURCE)?; + let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_LINK_TARGET)?; src.link( - libc::__WASI_LOOKUP_SYMLINK_FOLLOW, + wasi::LOOKUP_SYMLINK_FOLLOW, src_file.as_os_str().as_bytes(), &dst, dst_file.as_os_str().as_bytes(), @@ -586,23 +580,22 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result<FileAttr> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; - metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file) + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?; + metadata_at(&dir, wasi::LOOKUP_SYMLINK_FOLLOW, &file) } pub fn lstat(p: &Path) -> io::Result<FileAttr> { - let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; + let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?; metadata_at(&dir, 0, &file) } fn metadata_at( fd: &WasiFd, - flags: libc::__wasi_lookupflags_t, + flags: wasi::LookupFlags, path: &Path, ) -> io::Result<FileAttr> { - let mut ret = FileAttr::zero(); - fd.path_filestat_get(flags, path.as_os_str().as_bytes(), &mut ret.meta)?; - Ok(ret) + fd.path_filestat_get(flags, path.as_os_str().as_bytes()) + .map(|meta| FileAttr { meta }) } pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> { @@ -652,12 +645,12 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> { /// to any preopened file descriptor. fn open_parent( p: &Path, - rights: libc::__wasi_rights_t, + rights: wasi::Rights, ) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> { let p = CString::new(p.as_os_str().as_bytes())?; unsafe { let mut ret = ptr::null(); - let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); + let fd = libc::__wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); if fd == -1 { let msg = format!( "failed to find a preopened file descriptor \ @@ -677,15 +670,4 @@ fn open_parent( return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path)); } - - // FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API - // there is published - extern "C" { - pub fn __wasilibc_find_relpath( - path: *const libc::c_char, - rights_base: libc::__wasi_rights_t, - rights_inheriting: libc::__wasi_rights_t, - relative_path: *mut *const libc::c_char, - ) -> libc::c_int; - } } diff --git a/src/libstd/sys/wasi/io.rs b/src/libstd/sys/wasi/io.rs index ffecca5d1b6..4be92faed30 100644 --- a/src/libstd/sys/wasi/io.rs +++ b/src/libstd/sys/wasi/io.rs @@ -1,11 +1,12 @@ use crate::marker::PhantomData; use crate::slice; -use libc::{__wasi_ciovec_t, __wasi_iovec_t, c_void}; +use ::wasi::wasi_unstable as wasi; +use core::ffi::c_void; #[repr(transparent)] pub struct IoSlice<'a> { - vec: __wasi_ciovec_t, + vec: wasi::CIoVec, _p: PhantomData<&'a [u8]>, } @@ -13,7 +14,7 @@ impl<'a> IoSlice<'a> { #[inline] pub fn new(buf: &'a [u8]) -> IoSlice<'a> { IoSlice { - vec: __wasi_ciovec_t { + vec: wasi::CIoVec { buf: buf.as_ptr() as *const c_void, buf_len: buf.len(), }, @@ -43,7 +44,7 @@ impl<'a> IoSlice<'a> { #[repr(transparent)] pub struct IoSliceMut<'a> { - vec: __wasi_iovec_t, + vec: wasi::IoVec, _p: PhantomData<&'a mut [u8]>, } @@ -51,7 +52,7 @@ impl<'a> IoSliceMut<'a> { #[inline] pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { IoSliceMut { - vec: __wasi_iovec_t { + vec: wasi::IoVec { buf: buf.as_mut_ptr() as *mut c_void, buf_len: buf.len() }, diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index 57da81b41e7..517e3be9cb5 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -14,10 +14,10 @@ //! compiling for wasm. That way it's a compile time error for something that's //! guaranteed to be a runtime error! -use libc; -use crate::io::{Error, ErrorKind}; +use crate::io as std_io; use crate::mem; use crate::os::raw::c_char; +use ::wasi::wasi_unstable as wasi; pub mod alloc; pub mod args; @@ -56,31 +56,42 @@ pub mod ext; pub fn init() { } -pub fn unsupported<T>() -> crate::io::Result<T> { +pub fn unsupported<T>() -> std_io::Result<T> { Err(unsupported_err()) } -pub fn unsupported_err() -> Error { - Error::new(ErrorKind::Other, "operation not supported on wasm yet") +pub fn unsupported_err() -> std_io::Error { + std_io::Error::new( + std_io::ErrorKind::Other, + "operation not supported on wasm yet", + ) } -pub fn decode_error_kind(errno: i32) -> ErrorKind { - match errno as libc::c_int { - libc::ECONNREFUSED => ErrorKind::ConnectionRefused, - libc::ECONNRESET => ErrorKind::ConnectionReset, - libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, - libc::EPIPE => ErrorKind::BrokenPipe, - libc::ENOTCONN => ErrorKind::NotConnected, - libc::ECONNABORTED => ErrorKind::ConnectionAborted, - libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - libc::EADDRINUSE => ErrorKind::AddrInUse, - libc::ENOENT => ErrorKind::NotFound, - libc::EINTR => ErrorKind::Interrupted, - libc::EINVAL => ErrorKind::InvalidInput, - libc::ETIMEDOUT => ErrorKind::TimedOut, - libc::EEXIST => ErrorKind::AlreadyExists, - libc::EAGAIN => ErrorKind::WouldBlock, - _ => ErrorKind::Other, +pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { + use std_io::ErrorKind::*; + if errno > u16::max_value() as i32 || errno < 0 { + return Other; + } + let code = match wasi::Error::new(errno as u16) { + Some(code) => code, + None => return Other, + }; + match code { + wasi::ECONNREFUSED => ConnectionRefused, + wasi::ECONNRESET => ConnectionReset, + wasi::EPERM | wasi::EACCES => PermissionDenied, + wasi::EPIPE => BrokenPipe, + wasi::ENOTCONN => NotConnected, + wasi::ECONNABORTED => ConnectionAborted, + wasi::EADDRNOTAVAIL => AddrNotAvailable, + wasi::EADDRINUSE => AddrInUse, + wasi::ENOENT => NotFound, + wasi::EINTR => Interrupted, + wasi::EINVAL => InvalidInput, + wasi::ETIMEDOUT => TimedOut, + wasi::EEXIST => AlreadyExists, + wasi::EAGAIN => WouldBlock, + _ => Other, } } @@ -105,40 +116,16 @@ pub unsafe fn abort_internal() -> ! { pub fn hashmap_random_keys() -> (u64, u64) { let mut ret = (0u64, 0u64); unsafe { - let base = &mut ret as *mut (u64, u64) as *mut libc::c_void; + let base = &mut ret as *mut (u64, u64) as *mut core::ffi::c_void; let len = mem::size_of_val(&ret); - cvt_wasi(libc::__wasi_random_get(base, len)).unwrap(); - } - return ret -} - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 + let ret = wasi::raw::__wasi_random_get(base, len); + if ret != 0 { + panic!("__wasi_random_get failure") } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> { - if t.is_minus_one() { - Err(Error::last_os_error()) - } else { - Ok(t) } + return ret } -pub fn cvt_wasi(r: u16) -> crate::io::Result<()> { - if r != libc::__WASI_ESUCCESS { - Err(Error::from_raw_os_error(r as i32)) - } else { - Ok(()) - } +fn err2io(err: wasi::Error) -> std_io::Error { + std_io::Error::from_raw_os_error(err.get() as i32) } diff --git a/src/libstd/sys/wasi/os.rs b/src/libstd/sys/wasi/os.rs index 822ea02a11b..feee8407825 100644 --- a/src/libstd/sys/wasi/os.rs +++ b/src/libstd/sys/wasi/os.rs @@ -9,7 +9,7 @@ use crate::path::{self, PathBuf}; use crate::ptr; use crate::str; use crate::sys::memchr; -use crate::sys::{cvt, unsupported, Void}; +use crate::sys::{unsupported, Void}; use crate::vec; #[cfg(not(target_feature = "atomics"))] @@ -28,16 +28,11 @@ pub fn errno() -> i32 { } pub fn error_string(errno: i32) -> String { - extern { - fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char, - buflen: libc::size_t) -> libc::c_int; - } - let mut buf = [0 as libc::c_char; 1024]; let p = buf.as_mut_ptr(); unsafe { - if strerror_r(errno as libc::c_int, p, buf.len()) < 0 { + if libc::strerror_r(errno as libc::c_int, p, buf.len()) < 0 { panic!("strerror_r failure"); } str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() @@ -89,7 +84,6 @@ impl StdError for JoinPathsError { pub fn current_exe() -> io::Result<PathBuf> { unsupported() } - pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, _dont_send_or_sync_me: PhantomData<*mut ()>, @@ -182,3 +176,26 @@ pub fn exit(code: i32) -> ! { pub fn getpid() -> u32 { panic!("unsupported"); } + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { + if t.is_minus_one() { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} diff --git a/src/libstd/sys/wasi/process.rs b/src/libstd/sys/wasi/process.rs index 788b829f4ba..1c4d028b761 100644 --- a/src/libstd/sys/wasi/process.rs +++ b/src/libstd/sys/wasi/process.rs @@ -4,14 +4,16 @@ use crate::io; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; + +pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { - env: CommandEnv<DefaultEnvKey> + env: CommandEnv } // passed back to std::process with the pipes connected to the child, if any @@ -38,7 +40,7 @@ impl Command { pub fn arg(&mut self, _arg: &OsStr) { } - pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs index 2bf8d803c01..1d57b9922e5 100644 --- a/src/libstd/sys/wasi/stdio.rs +++ b/src/libstd/sys/wasi/stdio.rs @@ -1,8 +1,9 @@ use crate::io::{self, IoSlice, IoSliceMut}; -use crate::libc; use crate::mem::ManuallyDrop; use crate::sys::fd::WasiFd; +use ::wasi::wasi_unstable as wasi; + pub struct Stdin; pub struct Stdout; pub struct Stderr; @@ -17,7 +18,7 @@ impl Stdin { } pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) }) + ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDIN_FD) }) .read(data) } } @@ -32,7 +33,7 @@ impl Stdout { } pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> { - ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDOUT_FILENO as u32) }) + ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDOUT_FD) }) .write(data) } @@ -51,7 +52,7 @@ impl Stderr { } pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> { - ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDERR_FILENO as u32) }) + ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDERR_FD) }) .write(data) } @@ -73,7 +74,7 @@ impl io::Write for Stderr { pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::__WASI_EBADF as i32) + err.raw_os_error() == Some(wasi::EBADF.get() as i32) } pub fn panic_output() -> Option<impl io::Write> { diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs index 5e69e4d948f..28a504f1979 100644 --- a/src/libstd/sys/wasi/thread.rs +++ b/src/libstd/sys/wasi/thread.rs @@ -1,10 +1,10 @@ -use crate::cmp; use crate::ffi::CStr; use crate::io; -use crate::sys::cvt; +use crate::mem; use crate::sys::{unsupported, Void}; use crate::time::Duration; -use libc; + +use ::wasi::wasi_unstable as wasi; pub struct Thread(Void); @@ -19,8 +19,8 @@ impl Thread { } pub fn yield_now() { - let ret = unsafe { libc::__wasi_sched_yield() }; - debug_assert_eq!(ret, 0); + let ret = wasi::sched_yield(); + debug_assert_eq!(ret, Ok(())); } pub fn set_name(_name: &CStr) { @@ -28,19 +28,37 @@ impl Thread { } pub fn sleep(dur: Duration) { - let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as i32; - - unsafe { - while secs > 0 || nsecs > 0 { - let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, - tv_nsec: nsecs, - }; - secs -= ts.tv_sec as u64; - cvt(libc::nanosleep(&ts, &mut ts)).unwrap(); - nsecs = 0; - } + let nanos = dur.as_nanos(); + assert!(nanos <= u64::max_value() as u128); + + const CLOCK_ID: wasi::Userdata = 0x0123_45678; + + let clock = wasi::raw::__wasi_subscription_u_clock_t { + identifier: CLOCK_ID, + clock_id: wasi::CLOCK_MONOTONIC, + timeout: nanos as u64, + precision: 0, + flags: 0, + }; + + let in_ = [wasi::Subscription { + userdata: 0, + type_: wasi::EVENTTYPE_CLOCK, + u: wasi::raw::__wasi_subscription_u { clock: clock }, + }]; + let (res, event) = unsafe { + let mut out: [wasi::Event; 1] = mem::zeroed(); + let res = wasi::poll_oneoff(&in_, &mut out); + (res, out[0]) + }; + match (res, event) { + (Ok(1), wasi::Event { + userdata: CLOCK_ID, + error: 0, + type_: wasi::EVENTTYPE_CLOCK, + .. + }) => {} + _ => panic!("thread::sleep(): unexpected result of poll_oneoff"), } } diff --git a/src/libstd/sys/wasi/time.rs b/src/libstd/sys/wasi/time.rs index 3f14c80928c..4394a22f9c2 100644 --- a/src/libstd/sys/wasi/time.rs +++ b/src/libstd/sys/wasi/time.rs @@ -1,7 +1,5 @@ use crate::time::Duration; -use crate::mem; -use crate::sys::cvt_wasi; -use libc; +use ::wasi::wasi_unstable as wasi; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Duration); @@ -12,23 +10,19 @@ pub struct SystemTime(Duration); pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); fn current_time(clock: u32) -> Duration { - unsafe { - let mut ts = mem::zeroed(); - cvt_wasi(libc::__wasi_clock_time_get( - clock, - 1, // precision... seems ignored though? - &mut ts, - )).unwrap(); - Duration::new( - (ts / 1_000_000_000) as u64, - (ts % 1_000_000_000) as u32, - ) - } + let ts = wasi::clock_time_get( + clock, + 1, // precision... seems ignored though? + ).unwrap(); + Duration::new( + (ts / 1_000_000_000) as u64, + (ts % 1_000_000_000) as u32, + ) } impl Instant { pub fn now() -> Instant { - Instant(current_time(libc::__WASI_CLOCK_MONOTONIC)) + Instant(current_time(wasi::CLOCK_MONOTONIC)) } pub const fn zero() -> Instant { @@ -54,10 +48,10 @@ impl Instant { impl SystemTime { pub fn now() -> SystemTime { - SystemTime(current_time(libc::__WASI_CLOCK_REALTIME)) + SystemTime(current_time(wasi::CLOCK_REALTIME)) } - pub fn from_wasi_timestamp(ts: libc::__wasi_timestamp_t) -> SystemTime { + pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { SystemTime(Duration::from_nanos(ts)) } diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs index a02e009d953..edf933d10e0 100644 --- a/src/libstd/sys/wasm/process.rs +++ b/src/libstd/sys/wasm/process.rs @@ -4,14 +4,16 @@ use crate::io; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; +use crate::sys_common::process::CommandEnv; + +pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { - env: CommandEnv<DefaultEnvKey> + env: CommandEnv, } // passed back to std::process with the pipes connected to the child, if any @@ -38,7 +40,7 @@ impl Command { pub fn arg(&mut self, _arg: &OsStr) { } - pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 05e0ca67064..8658deb8546 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -19,7 +19,7 @@ use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; -use crate::sys_common::process::{CommandEnv, EnvKey}; +use crate::sys_common::process::CommandEnv; use crate::borrow::Borrow; use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE}; @@ -30,30 +30,28 @@ use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE}; #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] #[doc(hidden)] -pub struct WindowsEnvKey(OsString); +pub struct EnvKey(OsString); -impl From<OsString> for WindowsEnvKey { +impl From<OsString> for EnvKey { fn from(k: OsString) -> Self { let mut buf = k.into_inner().into_inner(); buf.make_ascii_uppercase(); - WindowsEnvKey(FromInner::from_inner(FromInner::from_inner(buf))) + EnvKey(FromInner::from_inner(FromInner::from_inner(buf))) } } -impl From<WindowsEnvKey> for OsString { - fn from(k: WindowsEnvKey) -> Self { k.0 } +impl From<EnvKey> for OsString { + fn from(k: EnvKey) -> Self { k.0 } } -impl Borrow<OsStr> for WindowsEnvKey { +impl Borrow<OsStr> for EnvKey { fn borrow(&self) -> &OsStr { &self.0 } } -impl AsRef<OsStr> for WindowsEnvKey { +impl AsRef<OsStr> for EnvKey { fn as_ref(&self) -> &OsStr { &self.0 } } -impl EnvKey for WindowsEnvKey {} - fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> { if str.as_ref().encode_wide().any(|b| b == 0) { @@ -66,7 +64,7 @@ fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> { pub struct Command { program: OsString, args: Vec<OsString>, - env: CommandEnv<WindowsEnvKey>, + env: CommandEnv, cwd: Option<OsString>, flags: u32, detach: bool, // not currently exposed in std::process @@ -110,7 +108,7 @@ impl Command { pub fn arg(&mut self, arg: &OsStr) { self.args.push(arg.to_os_string()) } - pub fn env_mut(&mut self) -> &mut CommandEnv<WindowsEnvKey> { + pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } pub fn cwd(&mut self, dir: &OsStr) { @@ -498,7 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> { } } -fn make_envp(maybe_env: Option<BTreeMap<WindowsEnvKey, OsString>>) +fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> { // On Windows we pass an "environment block" which is not a char**, but // rather a concatenation of null-terminated k=v\0 sequences, with a final diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index 4d40dec9724..bdf66fca359 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -1,47 +1,20 @@ #![allow(dead_code)] #![unstable(feature = "process_internals", issue = "0")] -use crate::ffi::{OsStr, OsString}; -use crate::env; use crate::collections::BTreeMap; -use crate::borrow::Borrow; - -pub trait EnvKey: - From<OsString> + Into<OsString> + - Borrow<OsStr> + Borrow<Self> + AsRef<OsStr> + - Ord + Clone {} - -// Implement a case-sensitive environment variable key -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct DefaultEnvKey(OsString); - -impl From<OsString> for DefaultEnvKey { - fn from(k: OsString) -> Self { DefaultEnvKey(k) } -} - -impl From<DefaultEnvKey> for OsString { - fn from(k: DefaultEnvKey) -> Self { k.0 } -} - -impl Borrow<OsStr> for DefaultEnvKey { - fn borrow(&self) -> &OsStr { &self.0 } -} - -impl AsRef<OsStr> for DefaultEnvKey { - fn as_ref(&self) -> &OsStr { &self.0 } -} - -impl EnvKey for DefaultEnvKey {} +use crate::env; +use crate::ffi::{OsStr, OsString}; +use crate::sys::process::EnvKey; // Stores a set of changes to an environment #[derive(Clone, Debug)] -pub struct CommandEnv<K> { +pub struct CommandEnv { clear: bool, saw_path: bool, - vars: BTreeMap<K, Option<OsString>> + vars: BTreeMap<EnvKey, Option<OsString>> } -impl<K: EnvKey> Default for CommandEnv<K> { +impl Default for CommandEnv { fn default() -> Self { CommandEnv { clear: false, @@ -51,10 +24,10 @@ impl<K: EnvKey> Default for CommandEnv<K> { } } -impl<K: EnvKey> CommandEnv<K> { +impl CommandEnv { // Capture the current environment with these changes applied - pub fn capture(&self) -> BTreeMap<K, OsString> { - let mut result = BTreeMap::<K, OsString>::new(); + pub fn capture(&self) -> BTreeMap<EnvKey, OsString> { + let mut result = BTreeMap::<EnvKey, OsString>::new(); if !self.clear { for (k, v) in env::vars_os() { result.insert(k.into(), v); @@ -90,7 +63,7 @@ impl<K: EnvKey> CommandEnv<K> { !self.clear && self.vars.is_empty() } - pub fn capture_if_changed(&self) -> Option<BTreeMap<K, OsString>> { + pub fn capture_if_changed(&self) -> Option<BTreeMap<EnvKey, OsString>> { if self.is_unchanged() { None } else { @@ -103,6 +76,7 @@ impl<K: EnvKey> CommandEnv<K> { self.maybe_saw_path(&key); self.vars.insert(key.to_owned().into(), Some(value.to_owned())); } + pub fn remove(&mut self, key: &OsStr) { self.maybe_saw_path(&key); if self.clear { @@ -111,13 +85,16 @@ impl<K: EnvKey> CommandEnv<K> { self.vars.insert(key.to_owned().into(), None); } } + pub fn clear(&mut self) { self.clear = true; self.vars.clear(); } + pub fn have_changed_path(&self) -> bool { self.saw_path || self.clear } + fn maybe_saw_path(&mut self, key: &OsStr) { if !self.saw_path && key == "PATH" { self.saw_path = true; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6be00bcef45..c93e6d11ce7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -561,29 +561,31 @@ impl Pat { })) } - pub fn walk<F>(&self, it: &mut F) -> bool - where - F: FnMut(&Pat) -> bool, - { + /// Walk top-down and call `it` in each place where a pattern occurs + /// starting with the root pattern `walk` is called on. If `it` returns + /// false then we will descend no further but siblings will be processed. + pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) { if !it(self) { - return false; + return; } match &self.node { PatKind::Ident(_, _, Some(p)) => p.walk(it), - PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)), + PatKind::Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)), PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) - | PatKind::Or(s) => s.iter().all(|p| p.walk(it)), - PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it), + | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)), + PatKind::Box(s) + | PatKind::Ref(s, _) + | PatKind::Paren(s) => s.walk(it), PatKind::Wild | PatKind::Rest | PatKind::Lit(_) | PatKind::Range(..) | PatKind::Ident(..) | PatKind::Path(..) - | PatKind::Mac(_) => true, + | PatKind::Mac(_) => {}, } } @@ -928,7 +930,7 @@ pub struct Local { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Arm { pub attrs: Vec<Attribute>, - pub pats: Vec<P<Pat>>, + pub pat: P<Pat>, pub guard: Option<P<Expr>>, pub body: P<Expr>, pub span: Span, @@ -1146,12 +1148,9 @@ pub enum ExprKind { Cast(P<Expr>, P<Ty>), /// A type ascription (e.g., `42: usize`). Type(P<Expr>, P<Ty>), - /// A `let pats = expr` expression that is only semantically allowed in the condition + /// A `let pat = expr` expression that is only semantically allowed in the condition /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`). - /// - /// The `Vec<P<Pat>>` is for or-patterns at the top level. - /// FIXME(54883): Change this to just `P<Pat>`. - Let(Vec<P<Pat>>, P<Expr>), + Let(P<Pat>, P<Expr>), /// An `if` block, with an optional `else` block. /// /// `if expr { block } else { expr }` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index e894fd17ff5..dc6cbfcf6ad 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -537,9 +537,9 @@ impl<'a> ExtCtxt<'a> { let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr))); // `Ok(__try_var) => __try_var` - let ok_arm = self.arm(sp, vec![ok_pat], binding_expr); + let ok_arm = self.arm(sp, ok_pat, binding_expr); // `Err(__try_var) => return Err(__try_var)` - let err_arm = self.arm(sp, vec![err_pat], err_expr); + let err_arm = self.arm(sp, err_pat, err_expr); // `match head { Ok() => ..., Err() => ... }` self.expr_match(sp, head, vec![ok_arm, err_arm]) @@ -606,10 +606,10 @@ impl<'a> ExtCtxt<'a> { self.pat_tuple_struct(span, path, vec![pat]) } - pub fn arm(&self, span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm { + pub fn arm(&self, span: Span, pat: P<ast::Pat>, expr: P<ast::Expr>) -> ast::Arm { ast::Arm { attrs: vec![], - pats, + pat, guard: None, body: expr, span, @@ -618,7 +618,7 @@ impl<'a> ExtCtxt<'a> { } pub fn arm_unreachable(&self, span: Span) -> ast::Arm { - self.arm(span, vec![self.pat_wild(span)], self.expr_unreachable(span)) + self.arm(span, self.pat_wild(span), self.expr_unreachable(span)) } pub fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: Vec<ast::Arm>) -> P<Expr> { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index e14ca4b06a0..6023c5149d0 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -402,14 +402,11 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_flat_map_arm<T: MutVisitor>( - mut arm: Arm, - vis: &mut T, -) -> SmallVec<[Arm; 1]> { - let Arm { attrs, pats, guard, body, span, id } = &mut arm; +pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> { + let Arm { attrs, pat, guard, body, span, id } = &mut arm; visit_attrs(attrs, vis); vis.visit_id(id); - visit_vec(pats, |pat| vis.visit_pat(pat)); + vis.visit_pat(pat); visit_opt(guard, |guard| vis.visit_expr(guard)); vis.visit_expr(body); vis.visit_span(span); @@ -1132,8 +1129,8 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { node, id, span, attrs }: &mut Expr, vis.visit_ty(ty); } ExprKind::AddrOf(_m, ohs) => vis.visit_expr(ohs), - ExprKind::Let(pats, scrutinee) => { - visit_vec(pats, |pat| vis.visit_pat(pat)); + ExprKind::Let(pat, scrutinee) => { + vis.visit_pat(pat); vis.visit_expr(scrutinee); } ExprKind::If(cond, tr, fl) => { diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index e502a08f4b2..3db9c899dba 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1250,8 +1250,7 @@ impl<'a> Parser<'a> { /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { let lo = self.prev_span; - // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. - let pat = self.parse_top_pat_unpack(GateOr::No)?; + let pat = self.parse_top_pat(GateOr::No)?; self.expect(&token::Eq)?; let expr = self.with_res( Restrictions::NO_STRUCT_LITERAL, @@ -1393,8 +1392,7 @@ impl<'a> Parser<'a> { crate fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. - let pat = self.parse_top_pat_unpack(GateOr::No)?; + let pat = self.parse_top_pat(GateOr::No)?; let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { @@ -1455,7 +1453,7 @@ impl<'a> Parser<'a> { Ok(ast::Arm { attrs, - pats: pat, // FIXME(or_patterns, Centril | dlrobertson): this should just be `pat,`. + pat, guard, body: expr, span: lo.to(hi), diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 823f880337d..669f657160b 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -36,16 +36,6 @@ impl<'a> Parser<'a> { self.parse_pat_with_range_pat(true, expected) } - // FIXME(or_patterns, Centril | dlrobertson): - // remove this and use `parse_top_pat` everywhere it is used instead. - pub(super) fn parse_top_pat_unpack(&mut self, gate_or: GateOr) -> PResult<'a, Vec<P<Pat>>> { - self.parse_top_pat(gate_or) - .map(|pat| pat.and_then(|pat| match pat.node { - PatKind::Or(pats) => pats, - node => vec![self.mk_pat(pat.span, node)], - })) - } - /// Entry point to the main pattern parser. /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P<Pat>> { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 37305055e62..6772bbce21b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1710,11 +1710,11 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Block(blk)) } - /// Print a `let pats = scrutinee` expression. - crate fn print_let(&mut self, pats: &[P<ast::Pat>], scrutinee: &ast::Expr) { + /// Print a `let pat = scrutinee` expression. + crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) { self.s.word("let "); - self.print_pats(pats); + self.print_pat(pat); self.s.space(); self.word_space("="); @@ -2040,8 +2040,8 @@ impl<'a> State<'a> { self.word_space(":"); self.print_type(ty); } - ast::ExprKind::Let(ref pats, ref scrutinee) => { - self.print_let(pats, scrutinee); + ast::ExprKind::Let(ref pat, ref scrutinee) => { + self.print_let(pat, scrutinee); } ast::ExprKind::If(ref test, ref blk, ref elseopt) => { self.print_if(test, blk, elseopt.as_ref().map(|e| &**e)); @@ -2451,21 +2451,16 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - fn print_pats(&mut self, pats: &[P<ast::Pat>]) { - self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p)); - } - fn print_arm(&mut self, arm: &ast::Arm) { - // I have no idea why this check is necessary, but here it - // is :( + // I have no idea why this check is necessary, but here it is :( if arm.attrs.is_empty() { self.s.space(); } self.cbox(INDENT_UNIT); self.ibox(0); - self.maybe_print_comment(arm.pats[0].span.lo()); + self.maybe_print_comment(arm.pat.span.lo()); self.print_outer_attributes(&arm.attrs); - self.print_pats(&arm.pats); + self.print_pat(&arm.pat); self.s.space(); if let Some(ref e) = arm.guard { self.word_space("if"); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ce1568316f8..421c327aa41 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -678,9 +678,8 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo } pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { - for attr in expression.attrs.iter() { - visitor.visit_attribute(attr); - } + walk_list!(visitor, visit_attribute, expression.attrs.iter()); + match expression.node { ExprKind::Box(ref subexpression) => { visitor.visit_expr(subexpression) @@ -719,8 +718,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); visitor.visit_ty(typ) } - ExprKind::Let(ref pats, ref scrutinee) => { - walk_list!(visitor, visit_pat, pats); + ExprKind::Let(ref pat, ref scrutinee) => { + visitor.visit_pat(pat); visitor.visit_expr(scrutinee); } ExprKind::If(ref head_expression, ref if_block, ref optional_else) => { @@ -831,10 +830,10 @@ pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) { } pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { - walk_list!(visitor, visit_pat, &arm.pats); - if let Some(ref e) = &arm.guard { - visitor.visit_expr(e); - } + visitor.visit_pat(&arm.pat); + // NOTE(or_patterns; Centril | dlrobertson): + // If you change this, also change the hack in `lowering.rs`. + walk_list!(visitor, visit_expr, &arm.guard); visitor.visit_expr(&arm.body); walk_list!(visitor, visit_attribute, &arm.attrs); } diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 55687c3175b..1f4f5aa3709 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -95,11 +95,9 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P< cx.expr_call_global(span, cmp_path.clone(), args) }; - let eq_arm = cx.arm(span, - vec![cx.pat_path(span, equals_path.clone())], - old); + let eq_arm = cx.arm(span, cx.pat_path(span, equals_path.clone()), old); let neq_arm = cx.arm(span, - vec![cx.pat_ident(span, test_id)], + cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); cx.expr_match(span, new, vec![eq_arm, neq_arm]) diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 740b92a9b79..debdc300e64 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -160,10 +160,10 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_ }; let eq_arm = cx.arm(span, - vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))], + cx.pat_some(span, cx.pat_path(span, ordering.clone())), old); let neq_arm = cx.arm(span, - vec![cx.pat_ident(span, test_id)], + cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); cx.expr_match(span, new, vec![eq_arm, neq_arm]) diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 9b6f8518de0..d3d604b7252 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -119,9 +119,7 @@ fn decodable_substructure(cx: &mut ExtCtxt<'_>, vec![idx, exprdecode.clone()])) }); - arms.push(cx.arm(v_span, - vec![cx.pat_lit(v_span, cx.expr_usize(v_span, i))], - decoded)); + arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded)); } arms.push(cx.arm_unreachable(trait_span)); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 6fd763f5a91..893d89f06a1 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1071,7 +1071,7 @@ impl<'a> MethodDef<'a> { for (arg_expr, pat) in self_args.iter().zip(patterns) { body = cx.expr_match(trait_.span, arg_expr.clone(), - vec![cx.arm(trait_.span, vec![pat.clone()], body)]) + vec![cx.arm(trait_.span, pat.clone(), body)]) } body @@ -1311,7 +1311,7 @@ impl<'a> MethodDef<'a> { nonself_args, &substructure); - cx.arm(sp, vec![single_pat], arm_expr) + cx.arm(sp, single_pat, arm_expr) }) .collect(); @@ -1337,7 +1337,7 @@ impl<'a> MethodDef<'a> { _ => None, }; if let Some(arm) = default { - match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], arm)); + match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm)); } // We will usually need the catch-all after matching the diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index ad275f421af..e29f12c50c5 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -716,7 +716,7 @@ impl<'a, 'b> Context<'a, 'b> { // But the nested match expression is proved to perform not as well // as series of let's; the first approach does. let pat = self.ecx.pat_tuple(self.fmtsp, pats); - let arm = self.ecx.arm(self.fmtsp, vec![pat], args_array); + let arm = self.ecx.arm(self.fmtsp, pat, args_array); let head = self.ecx.expr(self.fmtsp, ast::ExprKind::Tup(heads)); let result = self.ecx.expr_match(self.fmtsp, head, vec![arm]); diff --git a/src/test/rustdoc-js-std/vec-new.js b/src/test/rustdoc-js-std/vec-new.js index e4daa5065d2..e1a3256876b 100644 --- a/src/test/rustdoc-js-std/vec-new.js +++ b/src/test/rustdoc-js-std/vec-new.js @@ -4,5 +4,6 @@ const EXPECTED = { 'others': [ { 'path': 'std::vec::Vec', 'name': 'new' }, { 'path': 'std::vec::Vec', 'name': 'ne' }, + { 'path': 'std::rc::Rc', 'name': 'ne' }, ], }; diff --git a/src/test/rustdoc-js/exact-match.js b/src/test/rustdoc-js/exact-match.js new file mode 100644 index 00000000000..b0a411bee58 --- /dev/null +++ b/src/test/rustdoc-js/exact-match.js @@ -0,0 +1,9 @@ +const QUERY = 'si::pc'; + +const EXPECTED = { + 'others': [ + { 'path': 'exact_match::Si', 'name': 'pc' }, + { 'path': 'exact_match::Psi', 'name': 'pc' }, + { 'path': 'exact_match::Si', 'name': 'pa' }, + ], +}; diff --git a/src/test/rustdoc-js/exact-match.rs b/src/test/rustdoc-js/exact-match.rs new file mode 100644 index 00000000000..2eacc0a3582 --- /dev/null +++ b/src/test/rustdoc-js/exact-match.rs @@ -0,0 +1,68 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; diff --git a/src/test/rustdoc-js/module-substring.js b/src/test/rustdoc-js/module-substring.js new file mode 100644 index 00000000000..a446c39ebad --- /dev/null +++ b/src/test/rustdoc-js/module-substring.js @@ -0,0 +1,9 @@ +const QUERY = 'ig::pc'; + +const EXPECTED = { + 'others': [ + { 'path': 'module_substring::Sig', 'name': 'pc' }, + { 'path': 'module_substring::Si', 'name': 'pc' }, + { 'path': 'module_substring::Si', 'name': 'pa' }, + ], +}; diff --git a/src/test/rustdoc-js/module-substring.rs b/src/test/rustdoc-js/module-substring.rs new file mode 100644 index 00000000000..2eacc0a3582 --- /dev/null +++ b/src/test/rustdoc-js/module-substring.rs @@ -0,0 +1,68 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; diff --git a/src/test/rustdoc-js/search-short-types.js b/src/test/rustdoc-js/search-short-types.js index 0ebf4860cfa..d14672af71f 100644 --- a/src/test/rustdoc-js/search-short-types.js +++ b/src/test/rustdoc-js/search-short-types.js @@ -3,6 +3,8 @@ const QUERY = 'P'; const EXPECTED = { 'others': [ { 'path': 'search_short_types', 'name': 'P' }, + { 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' }, { 'path': 'search_short_types', 'name': 'Ap' }, + { 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' }, ], }; diff --git a/src/test/rustdoc-js/search-short-types.rs b/src/test/rustdoc-js/search-short-types.rs index 2eacc0a3582..a4083f9a764 100644 --- a/src/test/rustdoc-js/search-short-types.rs +++ b/src/test/rustdoc-js/search-short-types.rs @@ -66,3 +66,9 @@ imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); pub struct P; + +pub struct VeryLongTypeName; +impl VeryLongTypeName { + pub fn p() {} + pub fn ap() {} +} diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 09f58521e5d..b4c154e5d95 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -150,12 +150,12 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e))); }, 19 => { - let ps = vec![P(Pat { + let pat = P(Pat { id: DUMMY_NODE_ID, node: PatKind::Wild, span: DUMMY_SP, - })]; - iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(ps.clone(), e))) + }); + iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e))) }, _ => panic!("bad counter value in iter_exprs"), } diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index 1bc90a995fe..d04e494c258 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -1,18 +1,27 @@ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields --> $DIR/E0023.rs:10:9 | +LL | Apple(String, String), + | --------------------- tuple variant defined here +... LL | Fruit::Apple(a) => {}, | ^^^^^^^^^^^^^^^ expected 2 fields, found 1 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/E0023.rs:11:9 | +LL | Apple(String, String), + | --------------------- tuple variant defined here +... LL | Fruit::Apple(a, b, c) => {}, | ^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3 error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field --> $DIR/E0023.rs:12:9 | +LL | Pear(u32), + | --------- tuple variant defined here +... LL | Fruit::Pear(1, 2) => {}, | ^^^^^^^^^^^^^^^^^ expected 1 field, found 2 diff --git a/src/test/ui/lint/issue-54538-unused-parens-lint.rs b/src/test/ui/lint/issue-54538-unused-parens-lint.rs index c442c39fe01..1d8cce52281 100644 --- a/src/test/ui/lint/issue-54538-unused-parens-lint.rs +++ b/src/test/ui/lint/issue-54538-unused-parens-lint.rs @@ -33,10 +33,8 @@ fn or_patterns_no_lint() { if let &mut (0 | 1) = &mut 0 {} // Same. fn foo((Ok(a) | Err(a)): Result<u8, u8>) {} // Doesn't parse if we remove parens for now. - //~^ ERROR identifier `a` is bound more than once let _ = |(Ok(a) | Err(a)): Result<u8, u8>| 1; // `|Ok(a) | Err(a)| 1` parses as bit-or. - //~^ ERROR identifier `a` is bound more than once } fn or_patterns_will_lint() { diff --git a/src/test/ui/lint/issue-54538-unused-parens-lint.stderr b/src/test/ui/lint/issue-54538-unused-parens-lint.stderr index a3e0fb938b3..7d5e286416f 100644 --- a/src/test/ui/lint/issue-54538-unused-parens-lint.stderr +++ b/src/test/ui/lint/issue-54538-unused-parens-lint.stderr @@ -1,15 +1,3 @@ -error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/issue-54538-unused-parens-lint.rs:35:25 - | -LL | fn foo((Ok(a) | Err(a)): Result<u8, u8>) {} // Doesn't parse if we remove parens for now. - | ^ used in a pattern more than once - -error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/issue-54538-unused-parens-lint.rs:38:27 - | -LL | let _ = |(Ok(a) | Err(a)): Result<u8, u8>| 1; // `|Ok(a) | Err(a)| 1` parses as bit-or. - | ^ used in a pattern more than once - warning: the feature `or_patterns` is incomplete and may cause the compiler to crash --> $DIR/issue-54538-unused-parens-lint.rs:3:12 | @@ -61,113 +49,112 @@ LL | let _ = |(a): u8| 0; | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:43:12 + --> $DIR/issue-54538-unused-parens-lint.rs:41:12 | LL | if let (0 | 1) = 0 {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:44:13 + --> $DIR/issue-54538-unused-parens-lint.rs:42:13 | LL | if let ((0 | 1),) = (0,) {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:45:13 + --> $DIR/issue-54538-unused-parens-lint.rs:43:13 | LL | if let [(0 | 1)] = [0] {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:46:16 + --> $DIR/issue-54538-unused-parens-lint.rs:44:16 | LL | if let 0 | (1 | 2) = 0 {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:48:15 + --> $DIR/issue-54538-unused-parens-lint.rs:46:15 | LL | if let TS((0 | 1)) = TS(0) {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:50:20 + --> $DIR/issue-54538-unused-parens-lint.rs:48:20 | LL | if let NS { f: (0 | 1) } = (NS { f: 0 }) {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:60:9 + --> $DIR/issue-54538-unused-parens-lint.rs:58:9 | LL | (_) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:61:9 + --> $DIR/issue-54538-unused-parens-lint.rs:59:9 | LL | (y) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:62:9 + --> $DIR/issue-54538-unused-parens-lint.rs:60:9 | LL | (ref r) => {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:63:9 + --> $DIR/issue-54538-unused-parens-lint.rs:61:9 | LL | (e @ 1...2) => {} | ^^^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:69:9 + --> $DIR/issue-54538-unused-parens-lint.rs:67:9 | LL | (e @ &(1...2)) => {} | ^^^^^^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:70:10 + --> $DIR/issue-54538-unused-parens-lint.rs:68:10 | LL | &(_) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:81:9 + --> $DIR/issue-54538-unused-parens-lint.rs:79:9 | LL | (_) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:82:9 + --> $DIR/issue-54538-unused-parens-lint.rs:80:9 | LL | (y) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:83:9 + --> $DIR/issue-54538-unused-parens-lint.rs:81:9 | LL | (ref r) => {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:84:9 + --> $DIR/issue-54538-unused-parens-lint.rs:82:9 | LL | (e @ 1..=2) => {} | ^^^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:90:9 + --> $DIR/issue-54538-unused-parens-lint.rs:88:9 | LL | (e @ &(1..=2)) => {} | ^^^^^^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:91:10 + --> $DIR/issue-54538-unused-parens-lint.rs:89:10 | LL | &(_) => {} | ^^^ help: remove these parentheses -error: aborting due to 26 previous errors +error: aborting due to 24 previous errors -For more information about this error, try `rustc --explain E0416`. diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr index 663cd2cd24d..c2298d6fbbf 100644 --- a/src/test/ui/match/match-pattern-field-mismatch.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch.stderr @@ -1,6 +1,9 @@ error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields --> $DIR/match-pattern-field-mismatch.rs:10:11 | +LL | Rgb(usize, usize, usize), + | ------------------------ tuple variant defined here +... LL | Color::Rgb(_, _) => { } | ^^^^^^^^^^^^^^^^ expected 3 fields, found 2 diff --git a/src/test/ui/or-patterns/already-bound-name.rs b/src/test/ui/or-patterns/already-bound-name.rs new file mode 100644 index 00000000000..3ebf59c6437 --- /dev/null +++ b/src/test/ui/or-patterns/already-bound-name.rs @@ -0,0 +1,46 @@ +// This test ensures that the "already bound identifier in a product pattern" +// correctly accounts for or-patterns. + +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete + +enum E<T> { A(T, T), B(T) } + +use E::*; + +fn main() { + let (a, a) = (0, 1); // Standard duplication without an or-pattern. + //~^ ERROR identifier `a` is bound more than once in the same pattern + + let (a, A(a, _) | B(a)) = (0, A(1, 2)); + //~^ ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR identifier `a` is bound more than once in the same pattern + + let (A(a, _) | B(a), a) = (A(0, 1), 2); + //~^ ERROR identifier `a` is bound more than once in the same pattern + + let A(a, a) | B(a) = A(0, 1); + //~^ ERROR identifier `a` is bound more than once in the same pattern + + let B(a) | A(a, a) = A(0, 1); + //~^ ERROR identifier `a` is bound more than once in the same pattern + + match A(0, 1) { + B(a) | A(a, a) => {} // Let's ensure `match` has no funny business. + //~^ ERROR identifier `a` is bound more than once in the same pattern + } + + let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); + //~^ ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR mismatched types + + let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); + //~^ ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR variable `a` is not bound in all patterns + + let B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); + //~^ ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR identifier `a` is bound more than once in the same pattern +} diff --git a/src/test/ui/or-patterns/already-bound-name.stderr b/src/test/ui/or-patterns/already-bound-name.stderr new file mode 100644 index 00000000000..360699a8739 --- /dev/null +++ b/src/test/ui/or-patterns/already-bound-name.stderr @@ -0,0 +1,105 @@ +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:12:13 + | +LL | let (a, a) = (0, 1); // Standard duplication without an or-pattern. + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:15:15 + | +LL | let (a, A(a, _) | B(a)) = (0, A(1, 2)); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:15:25 + | +LL | let (a, A(a, _) | B(a)) = (0, A(1, 2)); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:19:26 + | +LL | let (A(a, _) | B(a), a) = (A(0, 1), 2); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:22:14 + | +LL | let A(a, a) | B(a) = A(0, 1); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:25:21 + | +LL | let B(a) | A(a, a) = A(0, 1); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:29:21 + | +LL | B(a) | A(a, a) => {} // Let's ensure `match` has no funny business. + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:33:36 + | +LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:33:46 + | +LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:38:36 + | +LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:38:46 + | +LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); + | ^ used in a pattern more than once + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/already-bound-name.rs:38:9 + | +LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); + | ^^^^ pattern doesn't bind `a` - variable not in all patterns + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:43:49 + | +LL | let B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/already-bound-name.rs:43:59 + | +LL | let B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); + | ^ used in a pattern more than once + +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/already-bound-name.rs:4:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/already-bound-name.rs:33:31 + | +LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); + | ^ expected integer, found enum `E` + | + = note: expected type `{integer}` + found type `E<{integer}>` + +error: aborting due to 15 previous errors + +Some errors have detailed explanations: E0308, E0408, E0416. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/consistent-bindings.rs b/src/test/ui/or-patterns/consistent-bindings.rs new file mode 100644 index 00000000000..0eb539dca4c --- /dev/null +++ b/src/test/ui/or-patterns/consistent-bindings.rs @@ -0,0 +1,46 @@ +// Check that or-patterns with consistent bindings across arms are allowed. + +// edition:2018 + +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete + +fn main() { + // One level: + let Ok(a) | Err(a) = Ok(0); + let Ok(ref a) | Err(ref a) = Ok(0); + let Ok(ref mut a) | Err(ref mut a) = Ok(0); + + // Two levels: + enum Tri<S, T, U> { V1(S), V2(T), V3(U) } + use Tri::*; + + let Ok((V1(a) | V2(a) | V3(a), b)) | Err(Ok((a, b)) | Err((a, b))) + : Result<_, Result<_, _>> + = Ok((V1(1), 1)); + + let Ok((V1(a) | V2(a) | V3(a), ref b)) | Err(Ok((a, ref b)) | Err((a, ref b))) + : Result<_, Result<_, _>> + = Ok((V1(1), 1)); + + // Three levels: + let ( + a, + Err((ref mut b, ref c, d)) | + Ok(( + Ok( + V1((ref c, d)) | + V2((d, ref c)) | + V3((ref c, Ok((_, d)) | Err((d, _)))) + ) | + Err((ref c, d)), + ref mut b + )) + ) = + (1, Ok((Ok(V3((1, Ok((1, 1))))), 1))); + + // FIXME(or_patterns; Centril | dlrobertson): remove this line below and + // change this test to check-pass once MIR can handle or-patterns with bindings. + let () = 0; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/or-patterns/consistent-bindings.stderr b/src/test/ui/or-patterns/consistent-bindings.stderr new file mode 100644 index 00000000000..7f5e670c257 --- /dev/null +++ b/src/test/ui/or-patterns/consistent-bindings.stderr @@ -0,0 +1,20 @@ +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/consistent-bindings.rs:5:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/consistent-bindings.rs:44:9 + | +LL | let () = 0; + | ^^ expected integer, found () + | + = note: expected type `{integer}` + found type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/inconsistent-modes.rs b/src/test/ui/or-patterns/inconsistent-modes.rs new file mode 100644 index 00000000000..44836893ea2 --- /dev/null +++ b/src/test/ui/or-patterns/inconsistent-modes.rs @@ -0,0 +1,28 @@ +// This test ensures that or patterns require binding mode consistency across arms. + +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete + +#![allow(non_camel_case_types)] +fn main() { + // One level: + let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0); + //~^ ERROR variable `a` is bound in inconsistent ways + let Ok(ref mut a) | Err(a): Result<u8, &mut u8> = Ok(0); + //~^ ERROR variable `a` is bound in inconsistent ways + let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); + //~^ ERROR variable `a` is bound in inconsistent ways + //~| ERROR mismatched types + let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); + //~^ ERROR variable `a` is bound in inconsistent ways + //~| ERROR variable `b` is bound in inconsistent ways + //~| ERROR mismatched types + + // Two levels: + let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0); + //~^ ERROR variable `a` is bound in inconsistent ways + + // Three levels: + let Ok([ Ok((Ok(ref a) | Err(a),)) | Err(a) ]) | Err(a) = Err(&1); + //~^ ERROR variable `a` is bound in inconsistent ways +} diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr new file mode 100644 index 00000000000..0a36ed5548e --- /dev/null +++ b/src/test/ui/or-patterns/inconsistent-modes.stderr @@ -0,0 +1,80 @@ +error[E0409]: variable `a` is bound in inconsistent ways within the same match arm + --> $DIR/inconsistent-modes.rs:9:25 + | +LL | let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0); + | - ^ bound in different ways + | | + | first binding + +error[E0409]: variable `a` is bound in inconsistent ways within the same match arm + --> $DIR/inconsistent-modes.rs:11:29 + | +LL | let Ok(ref mut a) | Err(a): Result<u8, &mut u8> = Ok(0); + | - ^ bound in different ways + | | + | first binding + +error[E0409]: variable `a` is bound in inconsistent ways within the same match arm + --> $DIR/inconsistent-modes.rs:13:33 + | +LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); + | - first binding ^ bound in different ways + +error[E0409]: variable `a` is bound in inconsistent ways within the same match arm + --> $DIR/inconsistent-modes.rs:16:39 + | +LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); + | - first binding ^ bound in different ways + +error[E0409]: variable `b` is bound in inconsistent ways within the same match arm + --> $DIR/inconsistent-modes.rs:16:46 + | +LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); + | - first binding ^ bound in different ways + +error[E0409]: variable `a` is bound in inconsistent ways within the same match arm + --> $DIR/inconsistent-modes.rs:22:38 + | +LL | let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0); + | - ^ bound in different ways + | | + | first binding + +error[E0409]: variable `a` is bound in inconsistent ways within the same match arm + --> $DIR/inconsistent-modes.rs:26:34 + | +LL | let Ok([ Ok((Ok(ref a) | Err(a),)) | Err(a) ]) | Err(a) = Err(&1); + | - ^ bound in different ways + | | + | first binding + +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/inconsistent-modes.rs:3:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/inconsistent-modes.rs:13:25 + | +LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); + | ^^^^^^^^^ types differ in mutability + | + = note: expected type `&&u8` + found type `&mut &mut u8` + +error[E0308]: mismatched types + --> $DIR/inconsistent-modes.rs:16:31 + | +LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); + | ^^^^^^^^^ types differ in mutability + | + = note: expected type `&{integer}` + found type `&mut _` + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0308, E0409. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/missing-bindings.rs b/src/test/ui/or-patterns/missing-bindings.rs new file mode 100644 index 00000000000..b065028e7a5 --- /dev/null +++ b/src/test/ui/or-patterns/missing-bindings.rs @@ -0,0 +1,84 @@ +// This test ensures that or patterns do not allow missing bindings in any of the arms. + +// edition:2018 + +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete + +#![allow(non_camel_case_types)] + +fn main() {} + +fn check_handling_of_paths() { + mod bar { + pub enum foo { + alpha, + beta, + charlie + } + } + + use bar::foo::{alpha, charlie}; + let alpha | beta | charlie = alpha; //~ ERROR variable `beta` is not bound in all patterns + match Some(alpha) { + Some(alpha | beta) => {} //~ ERROR variable `beta` is not bound in all patterns + } +} + +fn check_misc_nesting() { + enum E<T> { A(T, T), B(T) } + use E::*; + enum Vars3<S, T, U> { V1(S), V2(T), V3(U) } + use Vars3::*; + + // One level: + const X: E<u8> = B(0); + let A(a, _) | _ = X; //~ ERROR variable `a` is not bound in all patterns + let _ | B(a) = X; //~ ERROR variable `a` is not bound in all patterns + let A(..) | B(a) = X; //~ ERROR variable `a` is not bound in all patterns + let A(a, _) | B(_) = X; //~ ERROR variable `a` is not bound in all patterns + let A(_, a) | B(_) = X; //~ ERROR variable `a` is not bound in all patterns + let A(a, b) | B(a) = X; //~ ERROR variable `b` is not bound in all patterns + + // Two levels: + const Y: E<E<u8>> = B(B(0)); + let A(A(..) | B(_), _) | B(a) = Y; //~ ERROR variable `a` is not bound in all patterns + let A(A(..) | B(a), _) | B(A(a, _) | B(a)) = Y; + //~^ ERROR variable `a` is not bound in all patterns + let A(A(a, b) | B(c), d) | B(e) = Y; + //~^ ERROR variable `a` is not bound in all patterns + //~| ERROR variable `a` is not bound in all patterns + //~| ERROR variable `b` is not bound in all patterns + //~| ERROR variable `b` is not bound in all patterns + //~| ERROR variable `c` is not bound in all patterns + //~| ERROR variable `c` is not bound in all patterns + //~| ERROR variable `d` is not bound in all patterns + //~| ERROR variable `e` is not bound in all patterns + + // Three levels: + let ( + V1( + //~^ ERROR variable `b` is not bound in all patterns + //~| ERROR variable `c` is not bound in all patterns + A( + Ok(a) | Err(_), //~ ERROR variable `a` is not bound in all patterns + _ + ) | + B(Ok(a) | Err(a)) + ) | + V2( + A( + A(_, a) | //~ ERROR variable `b` is not bound in all patterns + B(b), //~ ERROR variable `a` is not bound in all patterns + _ + ) | + B(_) + //~^ ERROR variable `a` is not bound in all patterns + //~| ERROR variable `b` is not bound in all patterns + ) | + V3(c), + //~^ ERROR variable `a` is not bound in all patterns + ) + : (Vars3<E<Result<u8, u8>>, E<E<u8>>, u8>,) + = (V3(0),); +} diff --git a/src/test/ui/or-patterns/missing-bindings.stderr b/src/test/ui/or-patterns/missing-bindings.stderr new file mode 100644 index 00000000000..c73af7a42ee --- /dev/null +++ b/src/test/ui/or-patterns/missing-bindings.stderr @@ -0,0 +1,250 @@ +error[E0408]: variable `beta` is not bound in all patterns + --> $DIR/missing-bindings.rs:22:9 + | +LL | let alpha | beta | charlie = alpha; + | ^^^^^ ---- ^^^^^^^ pattern doesn't bind `beta` + | | | + | | variable not in all patterns + | pattern doesn't bind `beta` + +error[E0408]: variable `beta` is not bound in all patterns + --> $DIR/missing-bindings.rs:24:14 + | +LL | Some(alpha | beta) => {} + | ^^^^^ ---- variable not in all patterns + | | + | pattern doesn't bind `beta` + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:36:19 + | +LL | let A(a, _) | _ = X; + | - ^ pattern doesn't bind `a` + | | + | variable not in all patterns + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:37:9 + | +LL | let _ | B(a) = X; + | ^ - variable not in all patterns + | | + | pattern doesn't bind `a` + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:38:9 + | +LL | let A(..) | B(a) = X; + | ^^^^^ - variable not in all patterns + | | + | pattern doesn't bind `a` + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:39:19 + | +LL | let A(a, _) | B(_) = X; + | - ^^^^ pattern doesn't bind `a` + | | + | variable not in all patterns + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:40:19 + | +LL | let A(_, a) | B(_) = X; + | - ^^^^ pattern doesn't bind `a` + | | + | variable not in all patterns + +error[E0408]: variable `b` is not bound in all patterns + --> $DIR/missing-bindings.rs:41:19 + | +LL | let A(a, b) | B(a) = X; + | - ^^^^ pattern doesn't bind `b` + | | + | variable not in all patterns + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:45:9 + | +LL | let A(A(..) | B(_), _) | B(a) = Y; + | ^^^^^^^^^^^^^^^^^^ - variable not in all patterns + | | + | pattern doesn't bind `a` + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:46:11 + | +LL | let A(A(..) | B(a), _) | B(A(a, _) | B(a)) = Y; + | ^^^^^ - variable not in all patterns + | | + | pattern doesn't bind `a` + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:48:21 + | +LL | let A(A(a, b) | B(c), d) | B(e) = Y; + | - ^^^^ pattern doesn't bind `a` + | | + | variable not in all patterns + +error[E0408]: variable `b` is not bound in all patterns + --> $DIR/missing-bindings.rs:48:21 + | +LL | let A(A(a, b) | B(c), d) | B(e) = Y; + | - ^^^^ pattern doesn't bind `b` + | | + | variable not in all patterns + +error[E0408]: variable `c` is not bound in all patterns + --> $DIR/missing-bindings.rs:48:11 + | +LL | let A(A(a, b) | B(c), d) | B(e) = Y; + | ^^^^^^^ - variable not in all patterns + | | + | pattern doesn't bind `c` + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:48:32 + | +LL | let A(A(a, b) | B(c), d) | B(e) = Y; + | - ^^^^ pattern doesn't bind `a` + | | + | variable not in all patterns + +error[E0408]: variable `b` is not bound in all patterns + --> $DIR/missing-bindings.rs:48:32 + | +LL | let A(A(a, b) | B(c), d) | B(e) = Y; + | - ^^^^ pattern doesn't bind `b` + | | + | variable not in all patterns + +error[E0408]: variable `c` is not bound in all patterns + --> $DIR/missing-bindings.rs:48:32 + | +LL | let A(A(a, b) | B(c), d) | B(e) = Y; + | - ^^^^ pattern doesn't bind `c` + | | + | variable not in all patterns + +error[E0408]: variable `d` is not bound in all patterns + --> $DIR/missing-bindings.rs:48:32 + | +LL | let A(A(a, b) | B(c), d) | B(e) = Y; + | - ^^^^ pattern doesn't bind `d` + | | + | variable not in all patterns + +error[E0408]: variable `e` is not bound in all patterns + --> $DIR/missing-bindings.rs:48:9 + | +LL | let A(A(a, b) | B(c), d) | B(e) = Y; + | ^^^^^^^^^^^^^^^^^^^^ - variable not in all patterns + | | + | pattern doesn't bind `e` + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:64:29 + | +LL | Ok(a) | Err(_), + | - ^^^^^^ pattern doesn't bind `a` + | | + | variable not in all patterns + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:72:21 + | +LL | A(_, a) | + | - variable not in all patterns +LL | B(b), + | ^^^^ pattern doesn't bind `a` + +error[E0408]: variable `b` is not bound in all patterns + --> $DIR/missing-bindings.rs:71:21 + | +LL | A(_, a) | + | ^^^^^^^ pattern doesn't bind `b` +LL | B(b), + | - variable not in all patterns + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:75:17 + | +LL | A(_, a) | + | - variable not in all patterns +... +LL | B(_) + | ^^^^ pattern doesn't bind `a` + +error[E0408]: variable `b` is not bound in all patterns + --> $DIR/missing-bindings.rs:75:17 + | +LL | B(b), + | - variable not in all patterns +... +LL | B(_) + | ^^^^ pattern doesn't bind `b` + +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/missing-bindings.rs:79:13 + | +LL | B(Ok(a) | Err(a)) + | - variable not in all patterns +... +LL | A(_, a) | + | - variable not in all patterns +... +LL | V3(c), + | ^^^^^ pattern doesn't bind `a` + +error[E0408]: variable `b` is not bound in all patterns + --> $DIR/missing-bindings.rs:60:13 + | +LL | / V1( +LL | | +LL | | +LL | | A( +... | +LL | | B(Ok(a) | Err(a)) +LL | | ) | + | |_____________^ pattern doesn't bind `b` +... +LL | B(b), + | - variable not in all patterns +... +LL | V3(c), + | ^^^^^ pattern doesn't bind `b` + +error[E0408]: variable `c` is not bound in all patterns + --> $DIR/missing-bindings.rs:60:13 + | +LL | / V1( +LL | | +LL | | +LL | | A( +... | +LL | | B(Ok(a) | Err(a)) +LL | | ) | + | |_____________^ pattern doesn't bind `c` +LL | / V2( +LL | | A( +LL | | A(_, a) | +LL | | B(b), +... | +LL | | +LL | | ) | + | |_____________^ pattern doesn't bind `c` +LL | V3(c), + | - variable not in all patterns + +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/missing-bindings.rs:5:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 26 previous errors + +For more information about this error, try `rustc --explain E0408`. diff --git a/src/test/ui/pattern/pat-tuple-overfield.stderr b/src/test/ui/pattern/pat-tuple-overfield.stderr index 0430897510b..e64b6efb08d 100644 --- a/src/test/ui/pattern/pat-tuple-overfield.stderr +++ b/src/test/ui/pattern/pat-tuple-overfield.stderr @@ -19,12 +19,18 @@ LL | (1, 2, .., 3, 4) => {} error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields --> $DIR/pat-tuple-overfield.rs:10:9 | +LL | struct S(u8, u8, u8); + | --------------------- tuple struct defined here +... LL | S(1, 2, 3, 4) => {} | ^^^^^^^^^^^^^ expected 3 fields, found 4 error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields --> $DIR/pat-tuple-overfield.rs:12:9 | +LL | struct S(u8, u8, u8); + | --------------------- tuple struct defined here +... LL | S(1, 2, .., 3, 4) => {} | ^^^^^^^^^^^^^^^^^ expected 3 fields, found 4 diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index a581f07496e..4fbc630644b 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -15,6 +15,9 @@ LL | A::D(_) => (), error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/pattern-error-continue.rs:17:9 | +LL | B(isize, isize), + | --------------- tuple variant defined here +... LL | A::B(_, _, _) => (), | ^^^^^^^^^^^^^ expected 2 fields, found 3 diff --git a/src/test/ui/shadowed/shadowing-in-the-same-pattern.stderr b/src/test/ui/shadowed/shadowing-in-the-same-pattern.stderr index 71197efcaba..1c51653db6a 100644 --- a/src/test/ui/shadowed/shadowing-in-the-same-pattern.stderr +++ b/src/test/ui/shadowed/shadowing-in-the-same-pattern.stderr @@ -1,8 +1,8 @@ -error[E0416]: identifier `a` is bound more than once in the same pattern +error[E0415]: identifier `a` is bound more than once in this parameter list --> $DIR/shadowing-in-the-same-pattern.rs:3:10 | LL | fn f((a, a): (isize, isize)) {} - | ^ used in a pattern more than once + | ^ used as parameter more than once error[E0416]: identifier `a` is bound more than once in the same pattern --> $DIR/shadowing-in-the-same-pattern.rs:6:13 @@ -12,4 +12,5 @@ LL | let (a, a) = (1, 1); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0416`. +Some errors have detailed explanations: E0415, E0416. +For more information about an error, try `rustc --explain E0415`. diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index a564b991c40..1ed39f45d3e 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -15,6 +15,7 @@ const LICENSES: &[&str] = &[ "Apache-2.0 / MIT", "MIT OR Apache-2.0", "Apache-2.0 OR MIT", + "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license "MIT", "Unlicense/MIT", "Unlicense OR MIT", @@ -172,6 +173,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("vcpkg"), Crate("version_check"), Crate("void"), + Crate("wasi"), Crate("winapi"), Crate("winapi-build"), Crate("winapi-i686-pc-windows-gnu"), |
