diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 29cd23bdbb197..7836ad214edc4 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 index ec5660820dea9..98921e9de849a 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ec5660820dea91df470dab0b9eb26ef798f20889 +Subproject commit 98921e9de849acdaeaed08cfad6758bb89769b7d diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index cdaad973a7123..75a59de337cef 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -359,8 +359,6 @@ impl Box { /// 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 Box { /// 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 Box { /// 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) -> &'a mut T where diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e3af285053805..89ed47ea194fb 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 = []` - 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 { @@ -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)); } // _ => [|()] @@ -3000,7 +3000,7 @@ impl<'a> LoweringContext<'a> { // Desugar ExprWhileLet // From: `[opt_ident]: while let = ` - 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> { // ` => ` 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 d1e431597e745..71a57dbf32fb1 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(&self, hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher) { - self.as_type().hash_stable(hcx, hasher); - self.as_region().hash_stable(hcx, hasher); + self.unpack().hash_stable(hcx, hasher); + } +} + +impl<'gcx> HashStable> +for ty::subst::UnpackedKind<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + 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 f5b88dbc2a9c7..a749d0dddd7ee 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>; @@ -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 520b997882e07..49f43b18e6198 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, 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 } -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableAutoImplData { pub trait_def_id: DefId, pub nested: Vec } -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableBuiltinData { pub nested: Vec } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 0d0476e7c21dd..1778a8d693a83 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>, - 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 `>::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 cfeb456acefe6..9a3738c163d38 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 63bf52a9bdf78..f4b5ffbb7dc40 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 f52f2ea0f9fc8..3ab2cd274b90e 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 { - Some(self.cmp(other)) - } -} - impl<'tcx> TyS<'tcx> { pub fn is_primitive_ty(&self) -> bool { match self.sty { @@ -581,19 +566,6 @@ impl PartialEq for Slice { } impl Eq for Slice {} -impl Ord for Slice { - #[inline] - fn cmp(&self, other: &Slice) -> Ordering { - (&self.0 as *const [T]).cmp(&(&other.0 as *const [T])) - } -} -impl PartialOrd for Slice { - #[inline] - fn partial_cmp(&self, other: &Slice) -> Option { - Some(self.cmp(other)) - } -} - impl Hash for Slice { fn hash(&self, s: &mut H) { (self.as_ptr(), self.len()).hash(s) @@ -1128,7 +1100,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder>; /// 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> 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 a6c72728a5125..b9927c7eeb2fa 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 961c2650afdef..a18e8f578364d 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> + '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` 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(pub T); impl Binder { @@ -745,7 +750,7 @@ impl Binder { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `>::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 7c167f69ebd8c..5e3417e98c2e9 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, 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> 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> for Kind<'tcx> { impl<'tcx> From> 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> for Kind<'tcx> { + fn from(ty: Ty<'tcx>) -> Kind<'tcx> { + UnpackedKind::Type(ty).pack() } } impl<'tcx> Kind<'tcx> { #[inline] - unsafe fn downcast(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> { - unsafe { - self.downcast(TYPE_TAG) - } - } - - #[inline] - pub fn as_region(self) -> Option> { 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, "", 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>(&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(&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> + '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> + '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 34f05232adcab..110808919e905 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 e30f5cb4f1293..54e3418d4f017 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. - 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 306e7e9c16dce..35d2205cf33f3 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 699765dde03ff..f3c6ff2f2b3a1 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -152,6 +152,12 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { NON_SNAKE_CASE, 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, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3578164feb7c5..08c16fed5dd3f 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 95ebb6c970a58..2ca6c76a8009a 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 812665f5fa498..04ebaa031fe5a 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 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 e6b9150fa3aec..e4e9ee58330cc 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]) { + 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 bf82b0774238b..6e98604101345 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]) { + 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 { + "".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 { - "".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 9e745c3a1f5dd..37bd225a7d9cb 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 1139ea5fbd364..650e530519887 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 bf253a88d27c2..427641aaf0951 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 4aed688027f76..039669a62e104 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 a6776a0fe8612..a28625be2c739 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!("") - }; - 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 f7e10a4a47d37..44ac7a10e8287 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 d4233309627f5..b382ba7f22da7 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 df7371cdf817b..9ee0937f425c9 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, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` pub external_traits: RefCell>, + /// Used while populating `external_traits` to ensure we don't process the same trait twice at + /// the same time. + pub active_extern_traits: RefCell>, // 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 e03a182653e5a..4bbad30a5a315 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 c7ce7fffaa21b..6609b77b132c6 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, P, P, Option>), + IfLet(Vec>, P, P, Option>), /// 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, P, P, Option