diff options
| author | bors <bors@rust-lang.org> | 2018-02-25 02:07:14 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-02-25 02:07:14 +0000 |
| commit | 026339e42ba11a559767029d933d1197aefb877a (patch) | |
| tree | 884a690f24c660b4ece0ea6818846920f82631f4 | |
| parent | 28a1e4ffefa2620ad9f4179ea339833448874fd3 (diff) | |
| parent | 52047f0ba0d1b1144073963b9b009399d32fb984 (diff) | |
| download | rust-026339e42ba11a559767029d933d1197aefb877a.tar.gz rust-026339e42ba11a559767029d933d1197aefb877a.zip | |
Auto merge of #48520 - Manishearth:rollup, r=Manishearth
Rollup of 15 pull requests - Successful merges: #47689, #48110, #48197, #48296, #48386, #48392, #48404, #48415, #48441, #48448, #48452, #48481, #48490, #48499, #48503 - Failed merges:
57 files changed, 940 insertions, 545 deletions
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 29cd23bdbb1..7836ad214ed 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -313,7 +313,7 @@ impl Step for TestHelpers { type Output = (); fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/rt/rust_test_helpers.c") + run.path("src/test/auxiliary/rust_test_helpers.c") } fn make_run(run: RunConfig) { @@ -326,7 +326,7 @@ impl Step for TestHelpers { let build = builder.build; let target = self.target; let dst = build.test_helpers_out(target); - let src = build.src.join("src/rt/rust_test_helpers.c"); + let src = build.src.join("src/test/auxiliary/rust_test_helpers.c"); if up_to_date(&src, &dst.join("librust_test_helpers.a")) { return } @@ -353,7 +353,7 @@ impl Step for TestHelpers { .opt_level(0) .warnings(false) .debug(false) - .file(build.src.join("src/rt/rust_test_helpers.c")) + .file(build.src.join("src/test/auxiliary/rust_test_helpers.c")) .compile("rust_test_helpers"); } } diff --git a/src/doc/book b/src/doc/book -Subproject ec5660820dea91df470dab0b9eb26ef798f2088 +Subproject 98921e9de849acdaeaed08cfad6758bb89769b7 diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index cdaad973a71..75a59de337c 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -359,8 +359,6 @@ impl<T: ?Sized> Box<T> { /// Simple usage: /// /// ``` - /// #![feature(box_leak)] - /// /// fn main() { /// let x = Box::new(41); /// let static_ref: &'static mut usize = Box::leak(x); @@ -372,8 +370,6 @@ impl<T: ?Sized> Box<T> { /// Unsized data: /// /// ``` - /// #![feature(box_leak)] - /// /// fn main() { /// let x = vec![1, 2, 3].into_boxed_slice(); /// let static_ref = Box::leak(x); @@ -381,8 +377,7 @@ impl<T: ?Sized> Box<T> { /// assert_eq!(*static_ref, [4, 2, 3]); /// } /// ``` - #[unstable(feature = "box_leak", reason = "needs an FCP to stabilize", - issue = "46179")] + #[stable(feature = "box_leak", since = "1.26.0")] #[inline] pub fn leak<'a>(b: Box<T>) -> &'a mut T where diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e3af2850538..89ed47ea194 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2956,7 +2956,7 @@ impl<'a> LoweringContext<'a> { // Desugar ExprIfLet // From: `if let <pat> = <sub_expr> <body> [<else_opt>]` - ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { + ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => { // to: // // match <sub_expr> { @@ -2970,8 +2970,8 @@ impl<'a> LoweringContext<'a> { { let body = self.lower_block(body, false); let body_expr = P(self.expr_block(body, ThinVec::new())); - let pat = self.lower_pat(pat); - arms.push(self.arm(hir_vec![pat], body_expr)); + let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); + arms.push(self.arm(pats, body_expr)); } // _ => [<else_opt>|()] @@ -3000,7 +3000,7 @@ impl<'a> LoweringContext<'a> { // Desugar ExprWhileLet // From: `[opt_ident]: while let <pat> = <sub_expr> <body>` - ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => { + ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => { // to: // // [opt_ident]: loop { @@ -3021,8 +3021,8 @@ impl<'a> LoweringContext<'a> { // `<pat> => <body>` let pat_arm = { let body_expr = P(self.expr_block(body, ThinVec::new())); - let pat = self.lower_pat(pat); - self.arm(hir_vec![pat], body_expr) + let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); + self.arm(pats, body_expr) }; // `_ => break` diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index d1e431597e7..71a57dbf32f 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -56,8 +56,19 @@ for ty::subst::Kind<'gcx> { fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher<W>) { - self.as_type().hash_stable(hcx, hasher); - self.as_region().hash_stable(hcx, hasher); + self.unpack().hash_stable(hcx, hasher); + } +} + +impl<'gcx> HashStable<StableHashingContext<'gcx>> +for ty::subst::UnpackedKind<'gcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher<W>) { + match self { + ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher), + ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher), + } } } diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index f5b88dbc2a9..a749d0dddd7 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -17,7 +17,7 @@ use traits::{self, PredicateObligation}; use ty::{self, Ty}; use ty::fold::{BottomUpFolder, TypeFoldable}; use ty::outlives::Component; -use ty::subst::{Kind, Substs}; +use ty::subst::{Kind, UnpackedKind, Substs}; use util::nodemap::DefIdMap; pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>; @@ -321,7 +321,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let index = region_def.index as usize; // Get the value supplied for this region from the substs. - let subst_arg = anon_defn.substs[index].as_region().unwrap(); + let subst_arg = anon_defn.substs.region_at(index); // Compute the least upper bound of it with the other regions. debug!("constrain_anon_types: least_region={:?}", least_region); @@ -466,7 +466,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // All other regions, we map them appropriately to their adjusted // indices, erroring if we find any lifetimes that were not mapped // into the new set. - _ => if let Some(r1) = map.get(&Kind::from(r)).and_then(|k| k.as_region()) { + _ => if let Some(UnpackedKind::Lifetime(r1)) = map.get(&r.into()) + .map(|k| k.unpack()) { r1 } else { // No mapping was found. This means that diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 520b997882e..49f43b18e61 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -73,7 +73,7 @@ pub enum IntercrateMode { /// either identifying an `impl` (e.g., `impl Eq for int`) that /// provides the required vtable, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct Obligation<'tcx, T> { pub cause: ObligationCause<'tcx>, pub param_env: ty::ParamEnv<'tcx>, @@ -85,7 +85,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; /// Why did we incur this obligation? Used for error reporting. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -113,7 +113,7 @@ impl<'tcx> ObligationCause<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, @@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> { BlockTailExpression(ast::NodeId), } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct DerivedObligationCause<'tcx> { /// The trait reference of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to @@ -304,7 +304,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>; /// ### The type parameter `N` /// /// See explanation on `VtableImplData`. -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum Vtable<'tcx, N> { /// Vtable identifying a particular impl. VtableImpl(VtableImplData<'tcx, N>), @@ -374,13 +374,13 @@ pub struct VtableClosureData<'tcx, N> { pub nested: Vec<N> } -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableAutoImplData<N> { pub trait_def_id: DefId, pub nested: Vec<N> } -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableBuiltinData<N> { pub nested: Vec<N> } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 0d0476e7c21..1778a8d693a 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -16,6 +16,7 @@ use super::translate_substs; use super::Obligation; use super::ObligationCause; use super::PredicateObligation; +use super::Selection; use super::SelectionContext; use super::SelectionError; use super::VtableClosureData; @@ -101,7 +102,7 @@ pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx> } -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(PartialEq, Eq, Debug)] enum ProjectionTyCandidate<'tcx> { // from a where-clause in the env or object type ParamEnv(ty::PolyProjectionPredicate<'tcx>), @@ -110,12 +111,59 @@ enum ProjectionTyCandidate<'tcx> { TraitDef(ty::PolyProjectionPredicate<'tcx>), // from a "impl" (or a "pseudo-impl" returned by select) - Select, + Select(Selection<'tcx>), } -struct ProjectionTyCandidateSet<'tcx> { - vec: Vec<ProjectionTyCandidate<'tcx>>, - ambiguous: bool +enum ProjectionTyCandidateSet<'tcx> { + None, + Single(ProjectionTyCandidate<'tcx>), + Ambiguous, + Error(SelectionError<'tcx>), +} + +impl<'tcx> ProjectionTyCandidateSet<'tcx> { + fn mark_ambiguous(&mut self) { + *self = ProjectionTyCandidateSet::Ambiguous; + } + + fn mark_error(&mut self, err: SelectionError<'tcx>) { + *self = ProjectionTyCandidateSet::Error(err); + } + + // Returns true if the push was successful, or false if the candidate + // was discarded -- this could be because of ambiguity, or because + // a higher-priority candidate is already there. + fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { + use self::ProjectionTyCandidateSet::*; + use self::ProjectionTyCandidate::*; + match self { + None => { + *self = Single(candidate); + true + } + Single(current) => { + // No duplicates are expected. + assert_ne!(current, &candidate); + // Prefer where-clauses. As in select, if there are multiple + // candidates, we prefer where-clause candidates over impls. This + // may seem a bit surprising, since impls are the source of + // "truth" in some sense, but in fact some of the impls that SEEM + // applicable are not, because of nested obligations. Where + // clauses are the safer choice. See the comment on + // `select::SelectionCandidate` and #21974 for more details. + match (current, candidate) { + (ParamEnv(..), ParamEnv(..)) => { *self = Ambiguous; } + (ParamEnv(..), _) => {} + (_, ParamEnv(..)) => { unreachable!(); } + (_, _) => { *self = Ambiguous; } + } + false + } + Ambiguous | Error(..) => { + false + } + } + } } /// Evaluates constraints of the form: @@ -803,11 +851,11 @@ fn project_type<'cx, 'gcx, 'tcx>( return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); } - let mut candidates = ProjectionTyCandidateSet { - vec: Vec::new(), - ambiguous: false, - }; + let mut candidates = ProjectionTyCandidateSet::None; + // Make sure that the following procedures are kept in order. ParamEnv + // needs to be first because it has highest priority, and Select checks + // the return value of push_candidate which assumes it's ran at last. assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, @@ -818,67 +866,27 @@ fn project_type<'cx, 'gcx, 'tcx>( &obligation_trait_ref, &mut candidates); - if let Err(e) = assemble_candidates_from_impls(selcx, - obligation, - &obligation_trait_ref, - &mut candidates) { - return Err(ProjectionTyError::TraitSelectionError(e)); - } - - debug!("{} candidates, ambiguous={}", - candidates.vec.len(), - candidates.ambiguous); - - // Inherent ambiguity that prevents us from even enumerating the - // candidates. - if candidates.ambiguous { - return Err(ProjectionTyError::TooManyCandidates); - } - - // Drop duplicates. - // - // Note: `candidates.vec` seems to be on the critical path of the - // compiler. Replacing it with an HashSet was also tried, which would - // render the following dedup unnecessary. The original comment indicated - // that it was 9% slower, but that data is now obsolete and a new - // benchmark should be performed. - candidates.vec.sort_unstable(); - candidates.vec.dedup(); - - // Prefer where-clauses. As in select, if there are multiple - // candidates, we prefer where-clause candidates over impls. This - // may seem a bit surprising, since impls are the source of - // "truth" in some sense, but in fact some of the impls that SEEM - // applicable are not, because of nested obligations. Where - // clauses are the safer choice. See the comment on - // `select::SelectionCandidate` and #21974 for more details. - if candidates.vec.len() > 1 { - debug!("retaining param-env candidates only from {:?}", candidates.vec); - candidates.vec.retain(|c| match *c { - ProjectionTyCandidate::ParamEnv(..) => true, - ProjectionTyCandidate::TraitDef(..) | - ProjectionTyCandidate::Select => false, - }); - debug!("resulting candidate set: {:?}", candidates.vec); - if candidates.vec.len() != 1 { - return Err(ProjectionTyError::TooManyCandidates); - } - } - - assert!(candidates.vec.len() <= 1); + assemble_candidates_from_impls(selcx, + obligation, + &obligation_trait_ref, + &mut candidates); + + match candidates { + ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress( + confirm_candidate(selcx, + obligation, + &obligation_trait_ref, + candidate))), + ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( + selcx.tcx().mk_projection( + obligation.predicate.item_def_id, + obligation.predicate.substs))), + // Error occurred while trying to processing impls. + ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)), + // Inherent ambiguity that prevents us from even enumerating the + // candidates. + ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates), - match candidates.vec.pop() { - Some(candidate) => { - Ok(ProjectedTy::Progress( - confirm_candidate(selcx, - obligation, - &obligation_trait_ref, - candidate))) - } - None => Ok(ProjectedTy::NoProgress( - selcx.tcx().mk_projection( - obligation.predicate.item_def_id, - obligation.predicate.substs))) } } @@ -928,7 +936,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( ty::TyInfer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. - candidate_set.ambiguous = true; + candidate_set.mark_ambiguous(); return; } _ => { return; } @@ -962,7 +970,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); match predicate { - ty::Predicate::Projection(ref data) => { + ty::Predicate::Projection(data) => { let same_def_id = data.0.projection_ty.item_def_id == obligation.predicate.item_def_id; @@ -985,10 +993,10 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( data, is_match, same_def_id); if is_match { - candidate_set.vec.push(ctor(data.clone())); + candidate_set.push_candidate(ctor(data)); } } - _ => { } + _ => {} } } } @@ -998,37 +1006,36 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>) - -> Result<(), SelectionError<'tcx>> { // If we are resolving `<T as TraitRef<...>>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - selcx.infcx().probe(|_| { + let _ = selcx.infcx().commit_if_ok(|_| { let vtable = match selcx.select(&trait_obligation) { Ok(Some(vtable)) => vtable, Ok(None) => { - candidate_set.ambiguous = true; - return Ok(()); + candidate_set.mark_ambiguous(); + return Err(()); } Err(e) => { debug!("assemble_candidates_from_impls: selection error {:?}", e); - return Err(e); + candidate_set.mark_error(e); + return Err(()); } }; - match vtable { + let eligible = match &vtable { super::VtableClosure(_) | super::VtableGenerator(_) | super::VtableFnPointer(_) | super::VtableObject(_) => { debug!("assemble_candidates_from_impls: vtable={:?}", vtable); - - candidate_set.vec.push(ProjectionTyCandidate::Select); + true } - super::VtableImpl(ref impl_data) => { + super::VtableImpl(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in // trans (i.e., projection mode is not "any"), and the @@ -1072,27 +1079,25 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( node_item.item.defaultness.has_value() } else { node_item.item.defaultness.is_default() || - selcx.tcx().impl_is_default(node_item.node.def_id()) + selcx.tcx().impl_is_default(node_item.node.def_id()) }; // Only reveal a specializable default if we're past type-checking // and the obligations is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - let new_candidate = if !is_default { - Some(ProjectionTyCandidate::Select) + if !is_default { + true } else if obligation.param_env.reveal == Reveal::All { assert!(!poly_trait_ref.needs_infer()); if !poly_trait_ref.needs_subst() { - Some(ProjectionTyCandidate::Select) + true } else { - None + false } } else { - None - }; - - candidate_set.vec.extend(new_candidate); + false + } } super::VtableParam(..) => { // This case tell us nothing about the value of an @@ -1120,6 +1125,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // in the compiler: a trait predicate (`T : SomeTrait`) and a // projection. And the projection where clause is handled // in `assemble_candidates_from_param_env`. + false } super::VtableAutoImpl(..) | super::VtableBuiltin(..) => { @@ -1129,10 +1135,18 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( "Cannot project an associated type from `{:?}`", vtable); } - } + }; - Ok(()) - }) + if eligible { + if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) { + Ok(()) + } else { + Err(()) + } + } else { + Err(()) + } + }); } fn confirm_candidate<'cx, 'gcx, 'tcx>( @@ -1152,8 +1166,8 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>( confirm_param_env_candidate(selcx, obligation, poly_projection) } - ProjectionTyCandidate::Select => { - confirm_select_candidate(selcx, obligation, obligation_trait_ref) + ProjectionTyCandidate::Select(vtable) => { + confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable) } } } @@ -1161,21 +1175,10 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>( fn confirm_select_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>) + obligation_trait_ref: &ty::TraitRef<'tcx>, + vtable: Selection<'tcx>) -> Progress<'tcx> { - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - let vtable = match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => vtable, - _ => { - span_bug!( - obligation.cause.span, - "Failed to select `{:?}`", - trait_obligation); - } - }; - match vtable { super::VtableImpl(data) => confirm_impl_candidate(selcx, obligation, data), diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index cfeb456acef..9a3738c163d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -53,7 +53,7 @@ use std::rc::Rc; use syntax::abi::Abi; use hir; use lint; -use util::nodemap::FxHashMap; +use util::nodemap::{FxHashMap, FxHashSet}; struct InferredObligationsSnapshotVecDelegate<'tcx> { phantom: PhantomData<&'tcx i32>, @@ -584,7 +584,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let trait_ref = &mut trait_pred.trait_ref; let unit_substs = trait_ref.substs; let mut never_substs = Vec::with_capacity(unit_substs.len()); - never_substs.push(From::from(tcx.types.never)); + never_substs.push(tcx.types.never.into()); never_substs.extend(&unit_substs[1..]); trait_ref.substs = tcx.intern_substs(&never_substs); } @@ -2997,7 +2997,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // unsized parameters is equal to the target. let params = substs_a.iter().enumerate().map(|(i, &k)| { if ty_params.contains(i) { - Kind::from(substs_b.type_at(i)) + substs_b.type_at(i).into() } else { k } @@ -3303,7 +3303,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // that order. let predicates = tcx.predicates_of(def_id); assert_eq!(predicates.parent, None); - let predicates = predicates.predicates.iter().flat_map(|predicate| { + let mut predicates: Vec<_> = predicates.predicates.iter().flat_map(|predicate| { let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth, &predicate.subst(tcx, substs)); predicate.obligations.into_iter().chain( @@ -3314,6 +3314,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { predicate: predicate.value })) }).collect(); + // We are performing deduplication here to avoid exponential blowups + // (#38528) from happening, but the real cause of the duplication is + // unknown. What we know is that the deduplication avoids exponential + // amount of predicates being propogated when processing deeply nested + // types. + let mut seen = FxHashSet(); + predicates.retain(|i| seen.insert(i.clone())); self.infcx().plug_leaks(skol_map, snapshot, predicates) } } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 63bf52a9bdf..f4b5ffbb7dc 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -355,10 +355,7 @@ fn fn_once_adapter_instance<'a, 'tcx>( let sig = substs.closure_sig(closure_did, tcx); let sig = tcx.erase_late_bound_regions_and_normalize(&sig); assert_eq!(sig.inputs().len(), 1); - let substs = tcx.mk_substs([ - Kind::from(self_ty), - Kind::from(sig.inputs()[0]), - ].iter().cloned()); + let substs = tcx.mk_substs([Kind::from(self_ty), sig.inputs()[0].into()].iter().cloned()); debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); Instance { def, substs } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9f..3ab2cd274b9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -39,7 +39,6 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use serialize::{self, Encodable, Encoder}; use std::cell::RefCell; use std::cmp; -use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; @@ -498,20 +497,6 @@ impl<'tcx> Hash for TyS<'tcx> { } } -impl<'tcx> Ord for TyS<'tcx> { - #[inline] - fn cmp(&self, other: &TyS<'tcx>) -> Ordering { - // (self as *const _).cmp(other as *const _) - (self as *const TyS<'tcx>).cmp(&(other as *const TyS<'tcx>)) - } -} -impl<'tcx> PartialOrd for TyS<'tcx> { - #[inline] - fn partial_cmp(&self, other: &TyS<'tcx>) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - impl<'tcx> TyS<'tcx> { pub fn is_primitive_ty(&self) -> bool { match self.sty { @@ -581,19 +566,6 @@ impl<T> PartialEq for Slice<T> { } impl<T> Eq for Slice<T> {} -impl<T> Ord for Slice<T> { - #[inline] - fn cmp(&self, other: &Slice<T>) -> Ordering { - (&self.0 as *const [T]).cmp(&(&other.0 as *const [T])) - } -} -impl<T> PartialOrd for Slice<T> { - #[inline] - fn partial_cmp(&self, other: &Slice<T>) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - impl<T> Hash for Slice<T> { fn hash<H: Hasher>(&self, s: &mut H) { (self.as_ptr(), self.len()).hash(s) @@ -1128,7 +1100,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<SubtypePredicate<'tcx>>; /// equality between arbitrary types. Processing an instance of /// Form #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ProjectionPredicate<'tcx> { pub projection_ty: ProjectionTy<'tcx>, pub ty: Ty<'tcx>, @@ -1532,7 +1504,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for AdtDef { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum AdtKind { Struct, Union, Enum } bitflags! { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index a6c72728a51..b9927c7eeb2 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -16,7 +16,7 @@ use hir::def_id::DefId; use middle::const_val::ConstVal; use traits::Reveal; -use ty::subst::{Kind, Substs}; +use ty::subst::{UnpackedKind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::{TypeVisitor, TypeFolder}; use ty::error::{ExpectedFound, TypeError}; @@ -142,12 +142,14 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| { let variance = variances.map_or(ty::Invariant, |v| v[i]); - if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) { - Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?)) - } else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) { - Ok(Kind::from(relation.relate_with_variance(variance, &a_r, &b_r)?)) - } else { - bug!() + match (a.unpack(), b.unpack()) { + (UnpackedKind::Lifetime(a_lt), UnpackedKind::Lifetime(b_lt)) => { + Ok(relation.relate_with_variance(variance, &a_lt, &b_lt)?.into()) + } + (UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => { + Ok(relation.relate_with_variance(variance, &a_ty, &b_ty)?.into()) + } + (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => bug!() } }); diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 961c2650afd..a18e8f57836 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -15,10 +15,9 @@ use hir::def_id::DefId; use middle::const_val::ConstVal; use middle::region; use rustc_data_structures::indexed_vec::Idx; -use ty::subst::{Substs, Subst}; +use ty::subst::{Substs, Subst, Kind, UnpackedKind}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; use ty::{Slice, TyS}; -use ty::subst::Kind; use std::iter; use std::cmp::Ordering; @@ -297,8 +296,8 @@ impl<'tcx> ClosureSubsts<'tcx> { let generics = tcx.generics_of(def_id); let parent_len = generics.parent_count(); SplitClosureSubsts { - closure_kind_ty: self.substs[parent_len].as_type().expect("CK should be a type"), - closure_sig_ty: self.substs[parent_len + 1].as_type().expect("CS should be a type"), + closure_kind_ty: self.substs.type_at(parent_len), + closure_sig_ty: self.substs.type_at(parent_len + 1), upvar_kinds: &self.substs[parent_len + 2..], } } @@ -308,7 +307,13 @@ impl<'tcx> ClosureSubsts<'tcx> { impl Iterator<Item=Ty<'tcx>> + 'tcx { let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx); - upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type")) + upvar_kinds.iter().map(|t| { + if let UnpackedKind::Type(ty) = t.unpack() { + ty + } else { + bug!("upvar should be type") + } + }) } /// Returns the closure kind for this closure; may return a type @@ -620,7 +625,7 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { ty::TraitRef { def_id: self.def_id, substs: tcx.mk_substs( - iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned())) + iter::once(self_ty.into()).chain(self.substs.iter().cloned())) } } } @@ -645,7 +650,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { /// erase, or otherwise "discharge" these bound regions, we change the /// type from `Binder<T>` to just `T` (see /// e.g. `liberate_late_bound_regions`). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Binder<T>(pub T); impl<T> Binder<T> { @@ -745,7 +750,7 @@ impl<T> Binder<T> { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `<T as Trait<..>>::N`. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ProjectionTy<'tcx> { /// The parameters of the associated item. pub substs: &'tcx Substs<'tcx>, @@ -1127,7 +1132,7 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { projection_ty: ty::ProjectionTy { item_def_id: self.item_def_id, substs: tcx.mk_substs( - iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned())), + iter::once(self_ty.into()).chain(self.substs.iter().cloned())), }, ty: self.ty, } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 7c167f69ebd..5e3417e98c2 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -18,6 +18,7 @@ use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; use rustc_data_structures::accumulate_vec::AccumulateVec; +use core::intrinsics; use core::nonzero::NonZero; use std::fmt; use std::iter; @@ -29,7 +30,7 @@ use std::mem; /// To reduce memory usage, a `Kind` is a interned pointer, /// with the lowest 2 bits being reserved for a tag to /// indicate the type (`Ty` or `Region`) it points to. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct Kind<'tcx> { ptr: NonZero<usize>, marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)> @@ -39,15 +40,29 @@ const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; -impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> { - fn from(ty: Ty<'tcx>) -> Kind<'tcx> { - // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0); +pub enum UnpackedKind<'tcx> { + Lifetime(ty::Region<'tcx>), + Type(Ty<'tcx>), +} + +impl<'tcx> UnpackedKind<'tcx> { + fn pack(self) -> Kind<'tcx> { + let (tag, ptr) = match self { + UnpackedKind::Lifetime(lt) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0); + (REGION_TAG, lt as *const _ as usize) + } + UnpackedKind::Type(ty) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0); + (TYPE_TAG, ty as *const _ as usize) + } + }; - let ptr = ty as *const _ as usize; Kind { ptr: unsafe { - NonZero::new_unchecked(ptr | TYPE_TAG) + NonZero::new_unchecked(ptr | tag) }, marker: PhantomData } @@ -56,88 +71,60 @@ impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> { impl<'tcx> From<ty::Region<'tcx>> for Kind<'tcx> { fn from(r: ty::Region<'tcx>) -> Kind<'tcx> { - // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(r) & TAG_MASK, 0); + UnpackedKind::Lifetime(r).pack() + } +} - let ptr = r as *const _ as usize; - Kind { - ptr: unsafe { - NonZero::new_unchecked(ptr | REGION_TAG) - }, - marker: PhantomData - } +impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> { + fn from(ty: Ty<'tcx>) -> Kind<'tcx> { + UnpackedKind::Type(ty).pack() } } impl<'tcx> Kind<'tcx> { #[inline] - unsafe fn downcast<T>(self, tag: usize) -> Option<&'tcx T> { + pub fn unpack(self) -> UnpackedKind<'tcx> { let ptr = self.ptr.get(); - if ptr & TAG_MASK == tag { - Some(&*((ptr & !TAG_MASK) as *const _)) - } else { - None - } - } - - #[inline] - pub fn as_type(self) -> Option<Ty<'tcx>> { - unsafe { - self.downcast(TYPE_TAG) - } - } - - #[inline] - pub fn as_region(self) -> Option<ty::Region<'tcx>> { unsafe { - self.downcast(REGION_TAG) + match ptr & TAG_MASK { + REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)), + TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)), + _ => intrinsics::unreachable() + } } } } impl<'tcx> fmt::Debug for Kind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(ty) = self.as_type() { - write!(f, "{:?}", ty) - } else if let Some(r) = self.as_region() { - write!(f, "{:?}", r) - } else { - write!(f, "<unknown @ {:p}>", self.ptr.get() as *const ()) + match self.unpack() { + UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt), + UnpackedKind::Type(ty) => write!(f, "{:?}", ty), } } } impl<'tcx> fmt::Display for Kind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(ty) = self.as_type() { - write!(f, "{}", ty) - } else if let Some(r) = self.as_region() { - write!(f, "{}", r) - } else { - // FIXME(RFC 2000): extend this if/else chain when we support const generic. - unimplemented!(); + match self.unpack() { + UnpackedKind::Lifetime(lt) => write!(f, "{}", lt), + UnpackedKind::Type(ty) => write!(f, "{}", ty), } } } impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - if let Some(ty) = self.as_type() { - Kind::from(ty.fold_with(folder)) - } else if let Some(r) = self.as_region() { - Kind::from(r.fold_with(folder)) - } else { - bug!() + match self.unpack() { + UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(), + UnpackedKind::Type(ty) => ty.fold_with(folder).into(), } } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - if let Some(ty) = self.as_type() { - ty.visit_with(visitor) - } else if let Some(r) = self.as_region() { - r.visit_with(visitor) - } else { - bug!() + match self.unpack() { + UnpackedKind::Lifetime(lt) => lt.visit_with(visitor), + UnpackedKind::Type(ty) => ty.visit_with(visitor), } } } @@ -145,16 +132,17 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { impl<'tcx> Encodable for Kind<'tcx> { fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> { e.emit_enum("Kind", |e| { - if let Some(ty) = self.as_type() { - e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| { - e.emit_enum_variant_arg(0, |e| ty.encode(e)) - }) - } else if let Some(r) = self.as_region() { - e.emit_enum_variant("Region", REGION_TAG, 1, |e| { - e.emit_enum_variant_arg(0, |e| r.encode(e)) - }) - } else { - bug!() + match self.unpack() { + UnpackedKind::Lifetime(lt) => { + e.emit_enum_variant("Region", REGION_TAG, 1, |e| { + e.emit_enum_variant_arg(0, |e| lt.encode(e)) + }) + } + UnpackedKind::Type(ty) => { + e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| { + e.emit_enum_variant_arg(0, |e| ty.encode(e)) + }) + } } }) } @@ -247,7 +235,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { let def = types.next().unwrap(); let ty = mk_type(def, substs); assert_eq!(def.index as usize, substs.len()); - substs.push(Kind::from(ty)); + substs.push(ty.into()); } for def in &defs.regions { @@ -269,26 +257,42 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { #[inline] pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a { - self.iter().filter_map(|k| k.as_type()) + self.iter().filter_map(|k| { + if let UnpackedKind::Type(ty) = k.unpack() { + Some(ty) + } else { + None + } + }) } #[inline] pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a { - self.iter().filter_map(|k| k.as_region()) + self.iter().filter_map(|k| { + if let UnpackedKind::Lifetime(lt) = k.unpack() { + Some(lt) + } else { + None + } + }) } #[inline] pub fn type_at(&self, i: usize) -> Ty<'tcx> { - self[i].as_type().unwrap_or_else(|| { + if let UnpackedKind::Type(ty) = self[i].unpack() { + ty + } else { bug!("expected type for param #{} in {:?}", i, self); - }) + } } #[inline] pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { - self[i].as_region().unwrap_or_else(|| { + if let UnpackedKind::Lifetime(lt) = self[i].unpack() { + lt + } else { bug!("expected region for param #{} in {:?}", i, self); - }) + } } #[inline] @@ -413,13 +417,12 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { // the specialized routine `ty::replace_late_regions()`. match *r { ty::ReEarlyBound(data) => { - let r = self.substs.get(data.index as usize) - .and_then(|k| k.as_region()); + let r = self.substs.get(data.index as usize).map(|k| k.unpack()); match r { - Some(r) => { - self.shift_region_through_binders(r) + Some(UnpackedKind::Lifetime(lt)) => { + self.shift_region_through_binders(lt) } - None => { + _ => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( span, @@ -470,11 +473,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { // Look up the type in the substitutions. It really should be in there. - let opt_ty = self.substs.get(p.idx as usize) - .and_then(|k| k.as_type()); + let opt_ty = self.substs.get(p.idx as usize).map(|k| k.unpack()); let ty = match opt_ty { - Some(t) => t, - None => { + Some(UnpackedKind::Type(ty)) => ty, + _ => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( span, @@ -600,7 +602,7 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> { ty::TraitRef { def_id: trait_ref.def_id, substs: tcx.mk_substs( - iter::once(Kind::from(self_ty)).chain(trait_ref.substs.iter().cloned())) + iter::once(self_ty.into()).chain(trait_ref.substs.iter().cloned())) } }) } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 34f05232adc..110808919e9 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -19,7 +19,7 @@ use middle::const_val::ConstVal; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; -use ty::subst::{Subst, Kind}; +use ty::subst::{Subst, UnpackedKind}; use ty::TypeVariants::*; use util::common::ErrorReported; use middle::lang_items; @@ -509,16 +509,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let result = item_substs.iter().zip(impl_substs.iter()) .filter(|&(_, &k)| { - if let Some(&ty::RegionKind::ReEarlyBound(ref ebr)) = k.as_region() { - !impl_generics.region_param(ebr, self).pure_wrt_drop - } else if let Some(&ty::TyS { - sty: ty::TypeVariants::TyParam(ref pt), .. - }) = k.as_type() { - !impl_generics.type_param(pt, self).pure_wrt_drop - } else { - // not a type or region param - this should be reported - // as an error. - false + match k.unpack() { + UnpackedKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => { + !impl_generics.region_param(ebr, self).pure_wrt_drop + } + UnpackedKind::Type(&ty::TyS { + sty: ty::TypeVariants::TyParam(ref pt), .. + }) => { + !impl_generics.type_param(pt, self).pure_wrt_drop + } + UnpackedKind::Lifetime(_) | UnpackedKind::Type(_) => { + // not a type or region param - this should be reported + // as an error. + false + } } }).map(|(&item_param, _)| item_param).collect(); debug!("destructor_constraint({:?}) = {:?}", def.did, result); @@ -596,7 +600,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Objects must be alive in order for their destructor // to be called. ty::TyDynamic(..) => Ok(ty::DtorckConstraint { - outlives: vec![Kind::from(ty)], + outlives: vec![ty.into()], dtorck_types: vec![], }), diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index e30f5cb4f12..54e3418d4f0 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -878,7 +878,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, ty::TyAdt(adt, substs) => { if adt.is_box() { // Use T as the sub pattern type of Box<T>. - vec![substs[0].as_type().unwrap()] + vec![substs.type_at(0)] } else { adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { let is_visible = adt.is_enum() diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 306e7e9c16d..35d2205cf33 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -17,7 +17,7 @@ use driver; use rustc_lint; use rustc_resolve::MakeGlobMap; use rustc::middle::region; -use rustc::ty::subst::{Kind, Subst}; +use rustc::ty::subst::Subst; use rustc::traits::{ObligationCause, Reveal}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::maps::OnDiskCache; @@ -468,7 +468,7 @@ fn subst_ty_renumber_bound() { env.t_fn(&[t_param], env.t_nil()) }; - let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]); + let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) @@ -503,7 +503,7 @@ fn subst_ty_renumber_some_bounds() { env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil())) }; - let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]); + let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = (&'a isize, fn(&'a isize)) @@ -565,7 +565,7 @@ fn subst_region_renumber_region() { env.t_fn(&[env.t_rptr(re_early)], env.t_nil()) }; - let substs = env.infcx.tcx.intern_substs(&[Kind::from(re_bound1)]); + let substs = env.infcx.tcx.intern_substs(&[re_bound1.into()]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 699765dde03..f3c6ff2f2b3 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -153,6 +153,12 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { NON_UPPER_CASE_GLOBALS); add_lint_group!(sess, + "nonstandard_style", + NON_CAMEL_CASE_TYPES, + NON_SNAKE_CASE, + NON_UPPER_CASE_GLOBALS); + + add_lint_group!(sess, "unused", UNUSED_IMPORTS, UNUSED_VARIABLES, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3578164feb7..08c16fed5dd 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -7,7 +7,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir; use rustc::traits::Reveal; use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; -use rustc::ty::subst::{Subst, Substs, Kind}; +use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; use syntax::codemap::{self, DUMMY_SP}; @@ -1663,6 +1663,6 @@ pub fn resolve_drop_in_place<'a, 'tcx>( ty: Ty<'tcx>, ) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem); - let substs = tcx.intern_substs(&[Kind::from(ty)]); + let substs = tcx.intern_substs(&[ty.into()]); ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap() } diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 95ebb6c970a..2ca6c76a800 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -92,7 +92,7 @@ fn fn_once_adapter_instance<'a, 'tcx>( assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs([ Kind::from(self_ty), - Kind::from(sig.inputs()[0]), + sig.inputs()[0].into(), ].iter().cloned()); debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); @@ -153,7 +153,7 @@ pub fn resolve_drop_in_place<'a, 'tcx>( -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(DropInPlaceFnLangItem); - let substs = tcx.intern_substs(&[Kind::from(ty)]); + let substs = tcx.intern_substs(&[ty.into()]); Instance::resolve(tcx, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap() } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 812665f5fa4..04ebaa031fe 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -65,7 +65,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir::*; use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior}; -use rustc::ty::subst::{Kind, Substs}; +use rustc::ty::subst::Substs; use util::dump_mir; use util::liveness::{self, LivenessMode}; use rustc_const_math::ConstInt; @@ -858,8 +858,8 @@ impl MirPass for StateTransform { // Compute GeneratorState<yield_ty, return_ty> let state_did = tcx.lang_items().gen_state().unwrap(); let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.mk_substs([Kind::from(yield_ty), - Kind::from(mir.return_ty())].iter()); + let state_substs = tcx.mk_substs([yield_ty.into(), + mir.return_ty().into()].iter()); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e6b9150fa3a..e4e9ee58330 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -59,6 +59,7 @@ use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path}; use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue}; use syntax::parse::token; +use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use errors::{DiagnosticBuilder, DiagnosticId}; @@ -2329,17 +2330,17 @@ impl<'a> Resolver<'a> { // check 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, arm: &Arm) { - if arm.pats.is_empty() { + fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) { + if pats.is_empty() { return; } let mut missing_vars = FxHashMap(); let mut inconsistent_vars = FxHashMap(); - for (i, p) in arm.pats.iter().enumerate() { + for (i, p) in pats.iter().enumerate() { let map_i = self.binding_mode_map(&p); - for (j, q) in arm.pats.iter().enumerate() { + for (j, q) in pats.iter().enumerate() { if i == j { continue; } @@ -2404,9 +2405,8 @@ impl<'a> Resolver<'a> { self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list); } - // This has to happen *after* we determine which - // pat_idents are variants - self.check_consistent_bindings(arm); + // This has to happen *after* we determine which pat_idents are variants + self.check_consistent_bindings(&arm.pats); walk_list!(self, visit_expr, &arm.guard); self.visit_expr(&arm.body); @@ -2490,7 +2490,9 @@ impl<'a> Resolver<'a> { &ident.node.name.as_str()) ); } - Some(..) if pat_src == PatternSource::Match => { + Some(..) if pat_src == PatternSource::Match || + pat_src == PatternSource::IfLet || + pat_src == PatternSource::WhileLet => { // `Variant1(a) | Variant2(a)`, ok // Reuse definition from the first `a`. def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node]; @@ -3480,11 +3482,16 @@ impl<'a> Resolver<'a> { visit::walk_expr(self, expr); } - ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => { + ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => { self.visit_expr(subexpression); self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap()); + let mut bindings_list = FxHashMap(); + for pat in pats { + self.resolve_pattern(pat, PatternSource::IfLet, &mut bindings_list); + } + // This has to happen *after* we determine which pat_idents are variants + self.check_consistent_bindings(pats); self.visit_block(if_block); self.ribs[ValueNS].pop(); @@ -3500,11 +3507,16 @@ impl<'a> Resolver<'a> { }); } - ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => { + ExprKind::WhileLet(ref pats, ref subexpression, ref block, label) => { self.with_resolved_label(label, expr.id, |this| { this.visit_expr(subexpression); this.ribs[ValueNS].push(Rib::new(NormalRibKind)); - this.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap()); + let mut bindings_list = FxHashMap(); + for pat in pats { + this.resolve_pattern(pat, PatternSource::WhileLet, &mut bindings_list); + } + // This has to happen *after* we determine which pat_idents are variants + this.check_consistent_bindings(pats); this.visit_block(block); this.ribs[ValueNS].pop(); }); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index bf82b077423..6e986041013 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1031,6 +1031,81 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } } + fn process_var_decl_multi(&mut self, pats: &'l [P<ast::Pat>]) { + let mut collector = PathCollector::new(); + for pattern in pats { + // collect paths from the arm's patterns + collector.visit_pat(&pattern); + self.visit_pat(&pattern); + } + + // process collected paths + for (id, i, sp, immut) in collector.collected_idents { + match self.save_ctxt.get_path_def(id) { + HirDef::Local(id) => { + let mut value = if immut == ast::Mutability::Immutable { + self.span.snippet(sp).to_string() + } else { + "<mutable>".to_string() + }; + let hir_id = self.tcx.hir.node_to_hir_id(id); + let typ = self.save_ctxt + .tables + .node_id_to_type_opt(hir_id) + .map(|t| t.to_string()) + .unwrap_or(String::new()); + value.push_str(": "); + value.push_str(&typ); + + if !self.span.filter_generated(Some(sp), sp) { + let qualname = format!("{}${}", i.to_string(), id); + let id = ::id_from_node_id(id, &self.save_ctxt); + let span = self.span_from_span(sp); + + self.dumper.dump_def( + &Access { + public: false, + reachable: false, + }, + Def { + kind: DefKind::Local, + id, + span, + name: i.to_string(), + qualname, + value: typ, + parent: None, + children: vec![], + decl_id: None, + docs: String::new(), + sig: None, + attributes: vec![], + }, + ); + } + } + HirDef::StructCtor(..) | + HirDef::VariantCtor(..) | + HirDef::Const(..) | + HirDef::AssociatedConst(..) | + HirDef::Struct(..) | + HirDef::Variant(..) | + HirDef::TyAlias(..) | + HirDef::AssociatedTy(..) | + HirDef::SelfTy(..) => { + self.dump_path_ref(id, &ast::Path::from_ident(sp, i)); + } + def => error!( + "unexpected definition kind when processing collected idents: {:?}", + def + ), + } + } + + for (id, ref path) in collector.collected_paths { + self.process_path(id, path); + } + } fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) { // The local could declare multiple new vars, we must walk the @@ -1622,17 +1697,21 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc v.nest_scope(ex.id, |v| v.visit_expr(body)) }); } - ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) | - ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => { + ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => { let value = self.span.snippet(subexpression.span); self.process_var_decl(pattern, value); debug!("for loop, walk sub-expr: {:?}", subexpression.node); self.visit_expr(subexpression); visit::walk_block(self, block); } - ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => { - let value = self.span.snippet(subexpression.span); - self.process_var_decl(pattern, value); + ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => { + self.process_var_decl_multi(pats); + debug!("for loop, walk sub-expr: {:?}", subexpression.node); + self.visit_expr(subexpression); + visit::walk_block(self, block); + } + ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => { + self.process_var_decl_multi(pats); self.visit_expr(subexpression); visit::walk_block(self, block); opt_else.as_ref().map(|el| self.visit_expr(el)); @@ -1661,79 +1740,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } fn visit_arm(&mut self, arm: &'l ast::Arm) { - let mut collector = PathCollector::new(); - for pattern in &arm.pats { - // collect paths from the arm's patterns - collector.visit_pat(&pattern); - self.visit_pat(&pattern); - } - - // process collected paths - for (id, i, sp, immut) in collector.collected_idents { - match self.save_ctxt.get_path_def(id) { - HirDef::Local(id) => { - let mut value = if immut == ast::Mutability::Immutable { - self.span.snippet(sp).to_string() - } else { - "<mutable>".to_string() - }; - let hir_id = self.tcx.hir.node_to_hir_id(id); - let typ = self.save_ctxt - .tables - .node_id_to_type_opt(hir_id) - .map(|t| t.to_string()) - .unwrap_or(String::new()); - value.push_str(": "); - value.push_str(&typ); - - if !self.span.filter_generated(Some(sp), sp) { - let qualname = format!("{}${}", i.to_string(), id); - let id = ::id_from_node_id(id, &self.save_ctxt); - let span = self.span_from_span(sp); - - self.dumper.dump_def( - &Access { - public: false, - reachable: false, - }, - Def { - kind: DefKind::Local, - id, - span, - name: i.to_string(), - qualname, - value: typ, - parent: None, - children: vec![], - decl_id: None, - docs: String::new(), - sig: None, - attributes: vec![], - }, - ); - } - } - HirDef::StructCtor(..) | - HirDef::VariantCtor(..) | - HirDef::Const(..) | - HirDef::AssociatedConst(..) | - HirDef::Struct(..) | - HirDef::Variant(..) | - HirDef::TyAlias(..) | - HirDef::AssociatedTy(..) | - HirDef::SelfTy(..) => { - self.dump_path_ref(id, &ast::Path::from_ident(sp, i)); - } - def => error!( - "unexpected definition kind when processing collected idents: {:?}", - def - ), - } - } - - for (id, ref path) in collector.collected_paths { - self.process_path(id, path); - } + self.process_var_decl_multi(&arm.pats); walk_list!(self, visit_expr, &arm.guard); self.visit_expr(&arm.body); } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 9e745c3a1f5..37bd225a7d9 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -28,7 +28,6 @@ use value::Value; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{HasDataLayout, LayoutOf}; -use rustc::ty::subst::Kind; use rustc::hir; use libc::{c_uint, c_char}; @@ -413,8 +412,8 @@ pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, sig.map_bound(|sig| { let state_did = tcx.lang_items().gen_state().unwrap(); let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.mk_substs([Kind::from(sig.yield_ty), - Kind::from(sig.return_ty)].iter()); + let state_substs = tcx.mk_substs([sig.yield_ty.into(), + sig.return_ty.into()].iter()); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); tcx.mk_fn_sig(iter::once(env_ty), diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1139ea5fbd3..650e5305198 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -19,7 +19,7 @@ use hir::def::Def; use hir::def_id::DefId; use middle::resolve_lifetime as rl; use namespace::Namespace; -use rustc::ty::subst::{Kind, Subst, Substs}; +use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; @@ -1136,7 +1136,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Replace all lifetimes with 'static for subst in &mut substs { - if let Some(_) = subst.as_region() { + if let UnpackedKind::Lifetime(_) = subst.unpack() { *subst = Kind::from(&RegionKind::ReStatic); } } @@ -1146,8 +1146,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Fill in our own generics with the resolved lifetimes assert_eq!(lifetimes.len(), generics.own_count()); - substs.extend(lifetimes.iter().map(|lt| - Kind::from(self.ast_region_to_region(lt, None)))); + substs.extend(lifetimes.iter().map(|lt| Kind::from(self.ast_region_to_region(lt, None)))); debug!("impl_trait_ty_to_ty: final substs = {:?}", substs); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index bf253a88d27..427641aaf09 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -151,6 +151,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.emit(); } } + } else if let PatKind::Ref(..) = pat.node { + // When you encounter a `&pat` pattern, reset to "by + // value". This is so that `x` and `y` here are by value, + // as they appear to be: + // + // ``` + // match &(&22, &44) { + // (&x, &y) => ... + // } + // ``` + // + // cc #46688 + def_bm = ty::BindByValue(hir::MutImmutable); } // Lose mutability now that we know binding mode and discriminant type. diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4aed688027f..039669a62e1 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use rustc::infer::{self, InferOk}; use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::middle::region; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Subst, Substs, UnpackedKind}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, Reveal, ObligationCause}; use util::common::ErrorReported; @@ -331,10 +331,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( } for outlive in outlives { - if let Some(r) = outlive.as_region() { - rcx.sub_regions(origin(), parent_scope, r); - } else if let Some(ty) = outlive.as_type() { - rcx.type_must_outlive(origin(), ty, parent_scope); + match outlive.unpack() { + UnpackedKind::Lifetime(lt) => rcx.sub_regions(origin(), parent_scope, lt), + UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope), } } } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a6776a0fe86..a28625be2c7 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -13,7 +13,7 @@ use super::{FnCtxt, Needs}; use super::method::MethodCallee; use rustc::ty::{self, Ty, TypeFoldable, TypeVariants}; -use rustc::ty::TypeVariants::{TyStr, TyRef}; +use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; @@ -201,10 +201,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mutbl = match mt.mutbl { hir::MutImmutable => AutoBorrowMutability::Immutable, hir::MutMutable => AutoBorrowMutability::Mutable { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded binary ops. - allow_two_phase_borrow: false, + // Allow two-phase borrows for binops in initial deployment + // since they desugar to methods + allow_two_phase_borrow: true, } }; let autoref = Adjustment { @@ -219,10 +218,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mutbl = match mt.mutbl { hir::MutImmutable => AutoBorrowMutability::Immutable, hir::MutMutable => AutoBorrowMutability::Mutable { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded binary ops. - allow_two_phase_borrow: false, + // Allow two-phase borrows for binops in initial deployment + // since they desugar to methods + allow_two_phase_borrow: true, } }; let autoref = Adjustment { @@ -301,7 +299,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(missing_trait) = missing_trait { if missing_trait == "std::ops::Add" && - self.check_str_addition(expr, lhs_expr, lhs_ty, + self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err) { // This has nothing here because it means we did string // concatenation (e.g. "Hello " + "World!"). This means @@ -330,37 +328,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_str_addition(&self, expr: &'gcx hir::Expr, lhs_expr: &'gcx hir::Expr, + rhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>, err: &mut errors::DiagnosticBuilder) -> bool { + let codemap = self.tcx.sess.codemap(); + let msg = "`to_owned()` can be used to create an owned `String` \ + from a string reference. String concatenation \ + appends the string on the right to the string \ + on the left and may require reallocation. This \ + requires ownership of the string on the left"; // If this function returns true it means a note was printed, so we don't need // to print the normal "implementation of `std::ops::Add` might be missing" note - let mut is_string_addition = false; - if let TyRef(_, l_ty) = lhs_ty.sty { - if let TyRef(_, r_ty) = rhs_ty.sty { - if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { - err.span_label(expr.span, - "`+` can't be used to concatenate two `&str` strings"); - let codemap = self.tcx.sess.codemap(); - let suggestion = - match codemap.span_to_snippet(lhs_expr.span) { - Ok(lstring) => format!("{}.to_owned()", lstring), - _ => format!("<expression>") - }; - err.span_suggestion(lhs_expr.span, - &format!("`to_owned()` can be used to create an owned `String` \ - from a string reference. String concatenation \ - appends the string on the right to the string \ - on the left and may require reallocation. This \ - requires ownership of the string on the left"), suggestion); - is_string_addition = true; - } - + match (&lhs_ty.sty, &rhs_ty.sty) { + (&TyRef(_, ref l_ty), &TyRef(_, ref r_ty)) + if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr => { + err.span_label(expr.span, + "`+` can't be used to concatenate two `&str` strings"); + match codemap.span_to_snippet(lhs_expr.span) { + Ok(lstring) => err.span_suggestion(lhs_expr.span, + msg, + format!("{}.to_owned()", lstring)), + _ => err.help(msg), + }; + true } - + (&TyRef(_, ref l_ty), &TyAdt(..)) + if l_ty.ty.sty == TyStr && &format!("{:?}", rhs_ty) == "std::string::String" => { + err.span_label(expr.span, + "`+` can't be used to concatenate a `&str` with a `String`"); + match codemap.span_to_snippet(lhs_expr.span) { + Ok(lstring) => err.span_suggestion(lhs_expr.span, + msg, + format!("{}.to_owned()", lstring)), + _ => err.help(msg), + }; + match codemap.span_to_snippet(rhs_expr.span) { + Ok(rstring) => { + err.span_suggestion(rhs_expr.span, + "you also need to borrow the `String` on the right to \ + get a `&str`", + format!("&{}", rstring)); + } + _ => {} + }; + true + } + _ => false, } - - is_string_addition } pub fn check_user_unop(&self, diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index f7e10a4a47d..44ac7a10e82 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -14,7 +14,7 @@ //! We walk the set of items and, for each member, generate new constraints. use hir::def_id::DefId; -use rustc::ty::subst::Substs; +use rustc::ty::subst::{Substs, UnpackedKind}; use rustc::ty::{self, Ty, TyCtxt}; use syntax::ast; use rustc::hir; @@ -381,12 +381,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}", variance_decl, variance_i); - if let Some(ty) = k.as_type() { - self.add_constraints_from_ty(current, ty, variance_i); - } else if let Some(r) = k.as_region() { - self.add_constraints_from_region(current, r, variance_i); - } else { - bug!(); + match k.unpack() { + UnpackedKind::Lifetime(lt) => { + self.add_constraints_from_region(current, lt, variance_i) + } + UnpackedKind::Type(ty) => { + self.add_constraints_from_ty(current, ty, variance_i) + } } } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d4233309627..b382ba7f22d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -512,7 +512,16 @@ fn separate_supertrait_bounds(mut g: clean::Generics) } pub fn record_extern_trait(cx: &DocContext, did: DefId) { - cx.external_traits.borrow_mut().entry(did).or_insert_with(|| { - build_external_trait(cx, did) - }); + if cx.external_traits.borrow().contains_key(&did) || + cx.active_extern_traits.borrow().contains(&did) + { + return; + } + + cx.active_extern_traits.borrow_mut().push(did); + + let trait_ = build_external_trait(cx, did); + + cx.external_traits.borrow_mut().insert(did, trait_); + cx.active_extern_traits.borrow_mut().remove_item(&did); } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index df7371cdf81..9ee0937f425 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -61,6 +61,9 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { pub renderinfo: RefCell<RenderInfo>, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` pub external_traits: RefCell<FxHashMap<DefId, clean::Trait>>, + /// Used while populating `external_traits` to ensure we don't process the same trait twice at + /// the same time. + pub active_extern_traits: RefCell<Vec<DefId>>, // The current set of type and lifetime substitutions, // for expanding type aliases at the HIR level: @@ -253,6 +256,7 @@ pub fn run_core(search_paths: SearchPaths, populated_all_crate_impls: Cell::new(false), access_levels: RefCell::new(access_levels), external_traits: Default::default(), + active_extern_traits: Default::default(), renderinfo: Default::default(), ty_substs: Default::default(), lt_substs: Default::default(), diff --git a/src/libstd/path.rs b/src/libstd/path.rs index e03a182653e..4bbad30a5a3 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1825,7 +1825,7 @@ impl Path { /// If the path is a normal file, this is the file name. If it's the path of a directory, this /// is the directory name. /// - /// Returns [`None`] If the path terminates in `..`. + /// Returns [`None`] if the path terminates in `..`. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c7ce7fffaa2..6609b77b132 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1085,7 +1085,7 @@ pub enum ExprKind { /// `if let pat = expr { block } else { expr }` /// /// This is desugared to a `match` expression. - IfLet(P<Pat>, P<Expr>, P<Block>, Option<P<Expr>>), + IfLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<P<Expr>>), /// A while loop, with an optional label /// /// `'label: while expr { block }` @@ -1095,7 +1095,7 @@ pub enum ExprKind { /// `'label: while let pat = expr { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - WhileLet(P<Pat>, P<Expr>, P<Block>, Option<Label>), + WhileLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<Label>), /// A for loop, with an optional label /// /// `'label: for pat in expr { block }` diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ba24d7f914b..1ebf52e9fe8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -446,6 +446,9 @@ declare_features! ( // Use `?` as the Kleene "at most one" operator (active, macro_at_most_once_rep, "1.25.0", Some(48075)), + + // Multiple patterns with `|` in `if let` and `while let` + (active, if_while_or_patterns, "1.26.0", Some(48215)), ); declare_features! ( @@ -1618,6 +1621,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ExprKind::Catch(_) => { gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); } + ast::ExprKind::IfLet(ref pats, ..) | ast::ExprKind::WhileLet(ref pats, ..) => { + if pats.len() > 1 { + gate_feature_post!(&self, if_while_or_patterns, e.span, + "multiple patterns in `if let` and `while let` are unstable"); + } + } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a2025b073b..e8eb75f5e60 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1210,8 +1210,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu folder.fold_block(tr), fl.map(|x| folder.fold_expr(x))) } - ExprKind::IfLet(pat, expr, tr, fl) => { - ExprKind::IfLet(folder.fold_pat(pat), + ExprKind::IfLet(pats, expr, tr, fl) => { + ExprKind::IfLet(pats.move_map(|pat| folder.fold_pat(pat)), folder.fold_expr(expr), folder.fold_block(tr), fl.map(|x| folder.fold_expr(x))) @@ -1221,8 +1221,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu folder.fold_block(body), opt_label.map(|label| folder.fold_label(label))) } - ExprKind::WhileLet(pat, expr, body, opt_label) => { - ExprKind::WhileLet(folder.fold_pat(pat), + ExprKind::WhileLet(pats, expr, body, opt_label) => { + ExprKind::WhileLet(pats.move_map(|pat| folder.fold_pat(pat)), folder.fold_expr(expr), folder.fold_block(body), opt_label.map(|label| folder.fold_label(label))) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index efc191f24ac..4d457f4864a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -405,11 +405,14 @@ impl TokenType { } } -// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`, -// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`. -fn can_continue_type_after_ident(t: &token::Token) -> bool { +/// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`, +/// `IDENT<<u8 as Trait>::AssocTy>`. +/// +/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes +/// that IDENT is not the ident of a fn trait +fn can_continue_type_after_non_fn_ident(t: &token::Token) -> bool { t == &token::ModSep || t == &token::Lt || - t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren) + t == &token::BinOp(token::Shl) } /// Information about the path to a module. @@ -1321,7 +1324,7 @@ impl<'a> Parser<'a> { pub fn token_is_bare_fn_keyword(&mut self) -> bool { self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) || - self.check_keyword(keywords::Extern) + self.check_keyword(keywords::Extern) && self.is_extern_non_path() } fn eat_label(&mut self) -> Option<Label> { @@ -1619,7 +1622,8 @@ impl<'a> Parser<'a> { impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; TyKind::ImplTrait(bounds) } else if self.check_keyword(keywords::Dyn) && - self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) { + self.look_ahead(1, |t| t.can_begin_bound() && + !can_continue_type_after_non_fn_ident(t)) { self.bump(); // `dyn` // Always parse bounds greedily for better error recovery. let bounds = self.parse_ty_param_bounds()?; @@ -3224,7 +3228,7 @@ impl<'a> Parser<'a> { -> PResult<'a, P<Expr>> { let lo = self.prev_span; self.expect_keyword(keywords::Let)?; - let pat = self.parse_pat()?; + let pats = self.parse_pats()?; self.expect(&token::Eq)?; let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let thn = self.parse_block()?; @@ -3234,7 +3238,7 @@ impl<'a> Parser<'a> { } else { (thn.span, None) }; - Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs)) } // `move |args| expr` @@ -3325,13 +3329,13 @@ impl<'a> Parser<'a> { span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { self.expect_keyword(keywords::Let)?; - let pat = self.parse_pat()?; + let pats = self.parse_pats()?; self.expect(&token::Eq)?; let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let span = span_lo.to(body.span); - return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_label), attrs)); + return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs)); } // parse `loop {...}`, `loop` token already eaten diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3dfe3c9e5b9..9cad9f46e98 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1767,11 +1767,11 @@ impl<'a> State<'a> { self.print_else(e.as_ref().map(|e| &**e)) } // "another else-if-let" - ast::ExprKind::IfLet(ref pat, ref expr, ref then, ref e) => { + ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => { self.cbox(INDENT_UNIT - 1)?; self.ibox(0)?; self.s.word(" else if let ")?; - self.print_pat(pat)?; + self.print_pats(pats)?; self.s.space()?; self.word_space("=")?; self.print_expr_as_cond(expr)?; @@ -1805,10 +1805,10 @@ impl<'a> State<'a> { self.print_else(elseopt) } - pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block, + pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) -> io::Result<()> { self.head("if let")?; - self.print_pat(pat)?; + self.print_pats(pats)?; self.s.space()?; self.word_space("=")?; self.print_expr_as_cond(expr)?; @@ -2109,8 +2109,8 @@ impl<'a> State<'a> { ast::ExprKind::If(ref test, ref blk, ref elseopt) => { self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?; } - ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => { - self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?; + ast::ExprKind::IfLet(ref pats, ref expr, ref blk, ref elseopt) => { + self.print_if_let(pats, expr, blk, elseopt.as_ref().map(|e| &**e))?; } ast::ExprKind::While(ref test, ref blk, opt_label) => { if let Some(label) = opt_label { @@ -2122,13 +2122,13 @@ impl<'a> State<'a> { self.s.space()?; self.print_block_with_attrs(blk, attrs)?; } - ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_label) => { + ast::ExprKind::WhileLet(ref pats, ref expr, ref blk, opt_label) => { if let Some(label) = opt_label { self.print_ident(label.ident)?; self.word_space(":")?; } self.head("while let")?; - self.print_pat(pat)?; + self.print_pats(pats)?; self.s.space()?; self.word_space("=")?; self.print_expr_as_cond(expr)?; @@ -2664,6 +2664,20 @@ impl<'a> State<'a> { self.ann.post(self, NodePat(pat)) } + fn print_pats(&mut self, pats: &[P<ast::Pat>]) -> io::Result<()> { + let mut first = true; + for p in pats { + if first { + first = false; + } else { + self.s.space()?; + self.word_space("|")?; + } + self.print_pat(p)?; + } + Ok(()) + } + fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> { // I have no idea why this check is necessary, but here it // is :( @@ -2674,16 +2688,7 @@ impl<'a> State<'a> { self.ibox(0)?; self.maybe_print_comment(arm.pats[0].span.lo())?; self.print_outer_attributes(&arm.attrs)?; - let mut first = true; - for p in &arm.pats { - if first { - first = false; - } else { - self.s.space()?; - self.word_space("|")?; - } - self.print_pat(p)?; - } + self.print_pats(&arm.pats)?; 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 4691ddafa36..640f90ecb4a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -705,15 +705,15 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); visitor.visit_block(block); } - ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => { - visitor.visit_pat(pattern); + ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => { + walk_list!(visitor, visit_pat, pats); visitor.visit_expr(subexpression); visitor.visit_block(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_label) => { + ExprKind::WhileLet(ref pats, ref subexpression, ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); - visitor.visit_pat(pattern); + walk_list!(visitor, visit_pat, pats); visitor.visit_expr(subexpression); visitor.visit_block(block); } diff --git a/src/rt/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c index 2a14b3da7b7..2a14b3da7b7 100644 --- a/src/rt/rust_test_helpers.c +++ b/src/test/auxiliary/rust_test_helpers.c diff --git a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs index c425ed554a6..f4c36157fe9 100644 --- a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs @@ -30,8 +30,6 @@ // #![feature(rustc_attrs)] use std::ops::{Index, IndexMut}; -use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; -use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; // This is case outlined by Niko that we want to ensure we reject // (at least initially). @@ -182,56 +180,6 @@ fn coerce_index_op() { //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] } -struct A(i32); - -macro_rules! trivial_binop { - ($Trait:ident, $m:ident) => { - impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } } - } -} - -trivial_binop!(AddAssign, add_assign); -trivial_binop!(SubAssign, sub_assign); -trivial_binop!(MulAssign, mul_assign); -trivial_binop!(DivAssign, div_assign); -trivial_binop!(RemAssign, rem_assign); -trivial_binop!(BitAndAssign, bitand_assign); -trivial_binop!(BitOrAssign, bitor_assign); -trivial_binop!(BitXorAssign, bitxor_assign); -trivial_binop!(ShlAssign, shl_assign); -trivial_binop!(ShrAssign, shr_assign); - -fn overloaded_binops() { - let mut a = A(10); - a += a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a -= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a *= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a /= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a &= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a |= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a ^= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a <<= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a >>= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed -} - fn main() { // As a reminder, this is the basic case we want to ensure we handle. @@ -252,5 +200,4 @@ fn main() { coerce_unsized(); coerce_index_op(); - overloaded_binops(); } diff --git a/src/test/compile-fail/dyn-trait-compatibility.rs b/src/test/compile-fail/dyn-trait-compatibility.rs index a7cfda504c7..454b6d2f566 100644 --- a/src/test/compile-fail/dyn-trait-compatibility.rs +++ b/src/test/compile-fail/dyn-trait-compatibility.rs @@ -20,10 +20,5 @@ type A3 = dyn<<dyn as dyn>::dyn>; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope //~| ERROR Use of undeclared type or module `dyn` -type A4 = dyn(dyn, dyn) -> dyn; -//~^ ERROR cannot find type `dyn` in this scope -//~| ERROR cannot find type `dyn` in this scope -//~| ERROR cannot find type `dyn` in this scope -//~| ERROR cannot find type `dyn` in this scope fn main() {} diff --git a/src/test/run-pass/borrowck/two-phase-bin-ops.rs b/src/test/run-pass/borrowck/two-phase-bin-ops.rs new file mode 100644 index 00000000000..1b2529d7875 --- /dev/null +++ b/src/test/run-pass/borrowck/two-phase-bin-ops.rs @@ -0,0 +1,48 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: lxl nll + +#![cfg_attr(nll, feature(nll))] + +use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; +use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; + +struct A(i32); + +macro_rules! trivial_binop { + ($Trait:ident, $m:ident) => { + impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } } + } +} + +trivial_binop!(AddAssign, add_assign); +trivial_binop!(SubAssign, sub_assign); +trivial_binop!(MulAssign, mul_assign); +trivial_binop!(DivAssign, div_assign); +trivial_binop!(RemAssign, rem_assign); +trivial_binop!(BitAndAssign, bitand_assign); +trivial_binop!(BitOrAssign, bitor_assign); +trivial_binop!(BitXorAssign, bitxor_assign); +trivial_binop!(ShlAssign, shl_assign); +trivial_binop!(ShrAssign, shr_assign); + +fn main() { + let mut a = A(10); + a += a.0; + a -= a.0; + a *= a.0; + a /= a.0; + a &= a.0; + a |= a.0; + a ^= a.0; + a <<= a.0; + a >>= a.0; +} diff --git a/src/test/run-pass/dyn-trait.rs b/src/test/run-pass/dyn-trait.rs index 91930852a57..fdec6a26ac9 100644 --- a/src/test/run-pass/dyn-trait.rs +++ b/src/test/run-pass/dyn-trait.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-pretty `dyn ::foo` parses differently in the current epoch + #![feature(dyn_trait)] use std::fmt::Display; @@ -17,6 +19,8 @@ static BYTE: u8 = 33; fn main() { let x: &(dyn 'static + Display) = &BYTE; let y: Box<dyn Display + 'static> = Box::new(BYTE); + let _: &dyn (Display) = &BYTE; + let _: &dyn (::std::fmt::Display) = &BYTE; let xstr = format!("{}", x); let ystr = format!("{}", y); assert_eq!(xstr, "33"); diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/reset-mode.rs b/src/test/run-pass/rfc-2005-default-binding-mode/reset-mode.rs new file mode 100644 index 00000000000..f980ef0ccdd --- /dev/null +++ b/src/test/run-pass/rfc-2005-default-binding-mode/reset-mode.rs @@ -0,0 +1,25 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(match_default_bindings)] + +// Test that we "reset" the mode as we pass through a `&` pattern. +// +// cc #46688 + +fn surprise(x: i32) { + assert_eq!(x, 2); +} + +fn main() { + let x = &(1, &2); + let (_, &b) = x; + surprise(b); +} diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs index c3da4a51872..a5214d796cd 100644 --- a/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs +++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct S; #[derive(Debug)] pub struct Z; + +pub trait Tr<'a> {} diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs index 52b52b23c87..15b754e1fe6 100644 --- a/src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs +++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs @@ -14,6 +14,9 @@ use extern::xcrate::Z; +type A = extern::xcrate::S; +type B = for<'a> extern::xcrate::Tr<'a>; + fn f() { use extern::xcrate; use extern::xcrate as ycrate; @@ -28,4 +31,5 @@ fn main() { assert_eq!(format!("{:?}", s), "S"); let z = Z; assert_eq!(format!("{:?}", z), "Z"); + assert_eq!(A {}, extern::xcrate::S {}); } diff --git a/src/test/run-pass/rfc-2175-or-if-while-let/basic.rs b/src/test/run-pass/rfc-2175-or-if-while-let/basic.rs new file mode 100644 index 00000000000..a516a3e5dcd --- /dev/null +++ b/src/test/run-pass/rfc-2175-or-if-while-let/basic.rs @@ -0,0 +1,30 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(if_while_or_patterns)] + +enum E { + V(u8), + U(u8), + W, +} +use E::*; + +fn main() { + let mut e = V(10); + + if let V(x) | U(x) = e { + assert_eq!(x, 10); + } + while let V(x) | U(x) = e { + assert_eq!(x, 10); + e = W; + } +} diff --git a/src/test/rustdoc/auxiliary/issue-48414.rs b/src/test/rustdoc/auxiliary/issue-48414.rs new file mode 100644 index 00000000000..7e0edf76f6a --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-48414.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Woah, this trait links to [OtherTrait](OtherTrait)! +pub trait SomeTrait {} + +/// Woah, this trait links to [SomeTrait](SomeTrait)! +pub trait OtherTrait {} diff --git a/src/test/rustdoc/issue-48414.rs b/src/test/rustdoc/issue-48414.rs new file mode 100644 index 00000000000..0136f9c4759 --- /dev/null +++ b/src/test/rustdoc/issue-48414.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-48414.rs + +// ICE when resolving paths for a trait that linked to another trait, when both were in an external +// crate + +#![crate_name = "base"] + +extern crate issue_48414; + +#[doc(inline)] +pub use issue_48414::{SomeTrait, OtherTrait}; diff --git a/src/test/ui/feature-gate-if_while_or_patterns.rs b/src/test/ui/feature-gate-if_while_or_patterns.rs new file mode 100644 index 00000000000..3df140c77fc --- /dev/null +++ b/src/test/ui/feature-gate-if_while_or_patterns.rs @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable + ; + } + while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable + break; + } +} diff --git a/src/test/ui/feature-gate-if_while_or_patterns.stderr b/src/test/ui/feature-gate-if_while_or_patterns.stderr new file mode 100644 index 00000000000..c906fa5a2f4 --- /dev/null +++ b/src/test/ui/feature-gate-if_while_or_patterns.stderr @@ -0,0 +1,22 @@ +error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215) + --> $DIR/feature-gate-if_while_or_patterns.rs:12:5 + | +12 | / if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable +13 | | ; +14 | | } + | |_____^ + | + = help: add #![feature(if_while_or_patterns)] to the crate attributes to enable + +error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215) + --> $DIR/feature-gate-if_while_or_patterns.rs:15:5 + | +15 | / while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable +16 | | break; +17 | | } + | |_____^ + | + = help: add #![feature(if_while_or_patterns)] to the crate attributes to enable + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issue-45157.rs b/src/test/ui/issue-45157.rs new file mode 100644 index 00000000000..cff338f76c5 --- /dev/null +++ b/src/test/ui/issue-45157.rs @@ -0,0 +1,43 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] +#![feature(nll)] + +#[derive(Clone, Copy, Default)] +struct S { + a: u8, + b: u8, +} +#[derive(Clone, Copy, Default)] +struct Z { + c: u8, + d: u8, +} + +union U { + s: S, + z: Z, +} + +fn main() { + unsafe { + let mut u = U { s: Default::default() }; + + let mref = &mut u.s.a; + *mref = 22; + + let nref = &u.z.c; + //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502] + println!("{} {}", mref, nref) + //~^ ERROR cannot borrow `u.s.a` as mutable because it is also borrowed as immutable [E0502] + } +} + diff --git a/src/test/ui/issue-45157.stderr b/src/test/ui/issue-45157.stderr new file mode 100644 index 00000000000..e133aab31bc --- /dev/null +++ b/src/test/ui/issue-45157.stderr @@ -0,0 +1,20 @@ +error[E0502]: cannot borrow `u.z.c` as immutable because it is also borrowed as mutable + --> $DIR/issue-45157.rs:37:20 + | +34 | let mref = &mut u.s.a; + | ---------- mutable borrow occurs here +... +37 | let nref = &u.z.c; + | ^^^^^^ immutable borrow occurs here + +error[E0502]: cannot borrow `u.s.a` as mutable because it is also borrowed as immutable + --> $DIR/issue-45157.rs:39:27 + | +37 | let nref = &u.z.c; + | ------ immutable borrow occurs here +38 | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502] +39 | println!("{} {}", mref, nref) + | ^^^^ mutable borrow occurs here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lint/lint-group-nonstandard-style.rs b/src/test/ui/lint/lint-group-nonstandard-style.rs new file mode 100644 index 00000000000..55d6168e6e0 --- /dev/null +++ b/src/test/ui/lint/lint-group-nonstandard-style.rs @@ -0,0 +1,36 @@ +// Copyright 2014–2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(nonstandard_style)] +#![allow(dead_code)] + +fn CamelCase() {} //~ ERROR should have a snake + +#[allow(nonstandard_style)] +mod test { + fn CamelCase() {} + + #[forbid(nonstandard_style)] + mod bad { + fn CamelCase() {} //~ ERROR should have a snake + + static bad: isize = 1; //~ ERROR should have an upper + } + + mod warn { + #![warn(nonstandard_style)] + + fn CamelCase() {} //~ WARN should have a snake + + struct snake_case; //~ WARN should have a camel + } +} + +fn main() {} diff --git a/src/test/ui/lint/lint-group-nonstandard-style.stderr b/src/test/ui/lint/lint-group-nonstandard-style.stderr new file mode 100644 index 00000000000..b0ce19e35ee --- /dev/null +++ b/src/test/ui/lint/lint-group-nonstandard-style.stderr @@ -0,0 +1,67 @@ +error: function `CamelCase` should have a snake case name such as `camel_case` + --> $DIR/lint-group-nonstandard-style.rs:14:1 + | +14 | fn CamelCase() {} //~ ERROR should have a snake + | ^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-nonstandard-style.rs:11:9 + | +11 | #![deny(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ + = note: #[deny(non_snake_case)] implied by #[deny(nonstandard_style)] + +error: function `CamelCase` should have a snake case name such as `camel_case` + --> $DIR/lint-group-nonstandard-style.rs:22:9 + | +22 | fn CamelCase() {} //~ ERROR should have a snake + | ^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-nonstandard-style.rs:20:14 + | +20 | #[forbid(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ + = note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)] + +error: static variable `bad` should have an upper case name such as `BAD` + --> $DIR/lint-group-nonstandard-style.rs:24:9 + | +24 | static bad: isize = 1; //~ ERROR should have an upper + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-nonstandard-style.rs:20:14 + | +20 | #[forbid(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ + = note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)] + +warning: function `CamelCase` should have a snake case name such as `camel_case` + --> $DIR/lint-group-nonstandard-style.rs:30:9 + | +30 | fn CamelCase() {} //~ WARN should have a snake + | ^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-nonstandard-style.rs:28:17 + | +28 | #![warn(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ + = note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)] + +warning: type `snake_case` should have a camel case name such as `SnakeCase` + --> $DIR/lint-group-nonstandard-style.rs:32:9 + | +32 | struct snake_case; //~ WARN should have a camel + | ^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-nonstandard-style.rs:28:17 + | +28 | #![warn(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ + = note: #[warn(non_camel_case_types)] implied by #[warn(nonstandard_style)] + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs index 4c9d10ba46b..7b3288fd29c 100644 --- a/src/test/ui/span/issue-39018.rs +++ b/src/test/ui/span/issue-39018.rs @@ -17,6 +17,9 @@ pub fn main() { // that won't output for the above string concatenation let y = World::Hello + World::Goodbye; //~^ ERROR cannot be applied to type + + let x = "Hello " + "World!".to_owned(); + //~^ ERROR cannot be applied to type } enum World { diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index db662a1df59..70f8ecf42cb 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -16,5 +16,19 @@ error[E0369]: binary operation `+` cannot be applied to type `World` | = note: an implementation of `std::ops::Add` might be missing for `World` -error: aborting due to 2 previous errors +error[E0369]: binary operation `+` cannot be applied to type `&str` + --> $DIR/issue-39018.rs:21:13 + | +21 | let x = "Hello " + "World!".to_owned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate a `&str` with a `String` +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +21 | let x = "Hello ".to_owned() + "World!".to_owned(); + | ^^^^^^^^^^^^^^^^^^^ +help: you also need to borrow the `String` on the right to get a `&str` + | +21 | let x = "Hello " + &"World!".to_owned(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors |
