diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f51a3e71d0741..dd2c41dda6403 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1297,7 +1297,7 @@ impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind { }); impl_stable_hash_for!( - impl<'tcx, R> for struct infer::canonical::QueryResult<'tcx, R> { + impl<'tcx, R> for struct infer::canonical::QueryResponse<'tcx, R> { var_values, region_constraints, certainty, value } ); diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 1119c928a89ae..8c87c2a01c04f 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -17,7 +17,7 @@ use infer::canonical::{ Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized, - SmallCanonicalVarValues, + OriginalQueryValues, }; use infer::InferCtxt; use std::sync::atomic::Ordering; @@ -48,7 +48,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { pub fn canonicalize_query( &self, value: &V, - var_values: &mut SmallCanonicalVarValues<'tcx> + query_state: &mut OriginalQueryValues<'tcx>, ) -> Canonicalized<'gcx, V> where V: TypeFoldable<'tcx> + Lift<'gcx>, @@ -63,11 +63,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { value, Some(self), self.tcx, - CanonicalizeRegionMode { - static_region: true, - other_free_regions: true, - }, - var_values, + &CanonicalizeAllFreeRegions, + query_state, ) } @@ -96,23 +93,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// out the [chapter in the rustc guide][c]. /// /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query-result - pub fn canonicalize_response( - &self, - value: &V, - ) -> Canonicalized<'gcx, V> + pub fn canonicalize_response(&self, value: &V) -> Canonicalized<'gcx, V> where V: TypeFoldable<'tcx> + Lift<'gcx>, { - let mut var_values = SmallVec::new(); + let mut query_state = OriginalQueryValues::default(); Canonicalizer::canonicalize( value, Some(self), self.tcx, - CanonicalizeRegionMode { - static_region: false, - other_free_regions: false, - }, - &mut var_values + &CanonicalizeQueryResponse, + &mut query_state, ) } @@ -128,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { pub fn canonicalize_hr_query_hack( &self, value: &V, - var_values: &mut SmallCanonicalVarValues<'tcx> + query_state: &mut OriginalQueryValues<'tcx>, ) -> Canonicalized<'gcx, V> where V: TypeFoldable<'tcx> + Lift<'gcx>, @@ -143,27 +134,87 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { value, Some(self), self.tcx, - CanonicalizeRegionMode { - static_region: false, - other_free_regions: true, - }, - var_values + &CanonicalizeFreeRegionsOtherThanStatic, + query_state, ) } } -/// If this flag is true, then all free regions will be replaced with -/// a canonical var. This is used to make queries as generic as -/// possible. For example, the query `F: Foo<'static>` would be -/// canonicalized to `F: Foo<'0>`. -struct CanonicalizeRegionMode { - static_region: bool, - other_free_regions: bool, +/// Controls how we canonicalize "free regions" that are not inference +/// variables. This depends on what we are canonicalizing *for* -- +/// e.g., if we are canonicalizing to create a query, we want to +/// replace those with inference variables, since we want to make a +/// maximally general query. But if we are canonicalizing a *query +/// response*, then we don't typically replace free regions, as they +/// must have been introduced from other parts of the system. +trait CanonicalizeRegionMode { + fn canonicalize_free_region( + &self, + canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>, + r: ty::Region<'tcx>, + ) -> ty::Region<'tcx>; + + fn any(&self) -> bool; +} + +struct CanonicalizeQueryResponse; + +impl CanonicalizeRegionMode for CanonicalizeQueryResponse { + fn canonicalize_free_region( + &self, + _canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>, + r: ty::Region<'tcx>, + ) -> ty::Region<'tcx> { + match r { + ty::ReFree(_) | ty::ReEmpty | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r, + _ => { + // Other than `'static` or `'empty`, the query + // response should be executing in a fully + // canonicalized environment, so there shouldn't be + // any other region names it can come up. + bug!("unexpected region in query response: `{:?}`", r) + } + } + } + + fn any(&self) -> bool { + false + } } -impl CanonicalizeRegionMode { +struct CanonicalizeAllFreeRegions; + +impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions { + fn canonicalize_free_region( + &self, + canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>, + r: ty::Region<'tcx>, + ) -> ty::Region<'tcx> { + canonicalizer.canonical_var_for_region(r) + } + fn any(&self) -> bool { - self.static_region || self.other_free_regions + true + } +} + +struct CanonicalizeFreeRegionsOtherThanStatic; + +impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic { + fn canonicalize_free_region( + &self, + canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>, + r: ty::Region<'tcx>, + ) -> ty::Region<'tcx> { + if let ty::ReStatic = r { + r + } else { + canonicalizer.canonical_var_for_region(r) + } + } + + fn any(&self) -> bool { + true } } @@ -171,11 +222,11 @@ struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, tcx: TyCtxt<'cx, 'gcx, 'tcx>, variables: SmallVec<[CanonicalVarInfo; 8]>, - var_values: &'cx mut SmallCanonicalVarValues<'tcx>, + query_state: &'cx mut OriginalQueryValues<'tcx>, // Note that indices is only used once `var_values` is big enough to be // heap-allocated. indices: FxHashMap, CanonicalVar>, - canonicalize_region_mode: CanonicalizeRegionMode, + canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode, needs_canonical_flags: TypeFlags, } @@ -192,51 +243,25 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> } ty::ReVar(vid) => { - let r = self - .infcx + let r = self.infcx .unwrap() .borrow_region_constraints() .opportunistic_resolve_var(self.tcx, vid); - let info = CanonicalVarInfo { - kind: CanonicalVarKind::Region, - }; debug!( "canonical: region var found with vid {:?}, \ opportunistically resolved to {:?}", vid, r ); - let cvar = self.canonical_var(info, r.into()); - self.tcx().mk_region(ty::ReCanonical(cvar)) - } - - ty::ReStatic => { - if self.canonicalize_region_mode.static_region { - let info = CanonicalVarInfo { - kind: CanonicalVarKind::Region, - }; - let cvar = self.canonical_var(info, r.into()); - self.tcx().mk_region(ty::ReCanonical(cvar)) - } else { - r - } + self.canonical_var_for_region(r) } - ty::ReEarlyBound(..) + ty::ReStatic + | ty::ReEarlyBound(..) | ty::ReFree(_) | ty::ReScope(_) | ty::RePlaceholder(..) | ty::ReEmpty - | ty::ReErased => { - if self.canonicalize_region_mode.other_free_regions { - let info = CanonicalVarInfo { - kind: CanonicalVarKind::Region, - }; - let cvar = self.canonical_var(info, r.into()); - self.tcx().mk_region(ty::ReCanonical(cvar)) - } else { - r - } - } + | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r), ty::ReClosureBound(..) | ty::ReCanonical(_) => { bug!("canonical region encountered during canonicalization") @@ -302,10 +327,10 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { /// `canonicalize_query` and `canonicalize_response`. fn canonicalize( value: &V, - infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - canonicalize_region_mode: CanonicalizeRegionMode, - var_values: &'cx mut SmallCanonicalVarValues<'tcx> + infcx: Option<&InferCtxt<'_, 'gcx, 'tcx>>, + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalize_region_mode: &dyn CanonicalizeRegionMode, + query_state: &mut OriginalQueryValues<'tcx>, ) -> Canonicalized<'gcx, V> where V: TypeFoldable<'tcx> + Lift<'gcx>, @@ -340,7 +365,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { canonicalize_region_mode, needs_canonical_flags, variables: SmallVec::new(), - var_values, + query_state, indices: FxHashMap::default(), }; let out_value = value.fold_with(&mut canonicalizer); @@ -371,11 +396,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> CanonicalVar { let Canonicalizer { variables, - var_values, + query_state, indices, .. } = self; + let var_values = &mut query_state.var_values; + // This code is hot. `variables` and `var_values` are usually small // (fewer than 8 elements ~95% of the time). They are SmallVec's to // avoid allocations in those cases. We also don't use `indices` to @@ -398,28 +425,34 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { // fill up `indices` to facilitate subsequent lookups. if var_values.spilled() { assert!(indices.is_empty()); - *indices = - var_values.iter() - .enumerate() - .map(|(i, &kind)| (kind, CanonicalVar::new(i))) - .collect(); + *indices = var_values + .iter() + .enumerate() + .map(|(i, &kind)| (kind, CanonicalVar::new(i))) + .collect(); } // The cv is the index of the appended element. CanonicalVar::new(var_values.len() - 1) } } else { // `var_values` is large. Do a hashmap search via `indices`. - *indices - .entry(kind) - .or_insert_with(|| { - variables.push(info); - var_values.push(kind); - assert_eq!(variables.len(), var_values.len()); - CanonicalVar::new(variables.len() - 1) - }) + *indices.entry(kind).or_insert_with(|| { + variables.push(info); + var_values.push(kind); + assert_eq!(variables.len(), var_values.len()); + CanonicalVar::new(variables.len() - 1) + }) } } + fn canonical_var_for_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + }; + let cvar = self.canonical_var(info, r.into()); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } + /// Given a type variable `ty_var` of the given kind, first check /// if `ty_var` is bound to anything; if so, canonicalize /// *that*. Otherwise, create a new canonical variable for diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 85aa4f62f214c..a78b5b7d07264 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -44,7 +44,7 @@ use ty::{self, CanonicalVar, Lift, Region, List, TyCtxt}; mod canonicalizer; -pub mod query_result; +pub mod query_response; mod substitute; @@ -75,9 +75,16 @@ pub struct CanonicalVarValues<'tcx> { pub var_values: IndexVec>, } -/// Like CanonicalVarValues, but for use in places where a SmallVec is -/// appropriate. -pub type SmallCanonicalVarValues<'tcx> = SmallVec<[Kind<'tcx>; 8]>; +/// When we canonicalize a value to form a query, we wind up replacing +/// various parts of it with canonical variables. This struct stores +/// those replaced bits to remember for when we process the query +/// result. +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +pub struct OriginalQueryValues<'tcx> { + /// This is equivalent to `CanonicalVarValues`, but using a + /// `SmallVec` yields a significant performance win. + pub var_values: SmallVec<[Kind<'tcx>; 8]>, +} /// Information about a canonical variable that is included with the /// canonical value. This is sufficient information for code to create @@ -118,10 +125,10 @@ pub enum CanonicalTyVarKind { } /// After we execute a query with a canonicalized key, we get back a -/// `Canonical>`. You can use +/// `Canonical>`. You can use /// `instantiate_query_result` to access the data in this result. #[derive(Clone, Debug)] -pub struct QueryResult<'tcx, R> { +pub struct QueryResponse<'tcx, R> { pub var_values: CanonicalVarValues<'tcx>, pub region_constraints: Vec>, pub certainty: Certainty, @@ -130,8 +137,8 @@ pub struct QueryResult<'tcx, R> { pub type Canonicalized<'gcx, V> = Canonical<'gcx, >::Lifted>; -pub type CanonicalizedQueryResult<'gcx, T> = - Lrc>::Lifted>>>; +pub type CanonicalizedQueryResponse<'gcx, T> = + Lrc>::Lifted>>>; /// Indicates whether or not we were able to prove the query to be /// true. @@ -168,7 +175,7 @@ impl Certainty { } } -impl<'tcx, R> QueryResult<'tcx, R> { +impl<'tcx, R> QueryResponse<'tcx, R> { pub fn is_proven(&self) -> bool { self.certainty.is_proven() } @@ -178,7 +185,7 @@ impl<'tcx, R> QueryResult<'tcx, R> { } } -impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> { +impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { pub fn is_proven(&self) -> bool { self.value.is_proven() } @@ -225,12 +232,16 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// inference variables and applies it to the canonical value. /// Returns both the instantiated result *and* the substitution S. /// - /// This is useful at the start of a query: it basically brings - /// the canonical value "into scope" within your new infcx. At the - /// end of processing, the substitution S (once canonicalized) - /// then represents the values that you computed for each of the - /// canonical inputs to your query. - pub fn instantiate_canonical_with_fresh_inference_vars( + /// This is only meant to be invoked as part of constructing an + /// inference context at the start of a query (see + /// `InferCtxtBuilder::enter_with_canonical`). It basically + /// brings the canonical value "into scope" within your new infcx. + /// + /// At the end of processing, the substitution S (once + /// canonicalized) then represents the values that you computed + /// for each of the canonical inputs to your query. + + pub(in infer) fn instantiate_canonical_with_fresh_inference_vars( &self, span: Span, canonical: &Canonical<'tcx, T>, @@ -238,6 +249,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { where T: TypeFoldable<'tcx>, { + assert_eq!(self.universe(), ty::UniverseIndex::ROOT, "infcx not newly created"); + assert_eq!(self.type_variables.borrow().num_vars(), 0, "infcx not newly created"); + let canonical_inference_vars = self.fresh_inference_vars_for_canonical_vars(span, canonical.variables); let result = canonical.substitute(self.tcx, &canonical_inference_vars); @@ -344,14 +358,14 @@ BraceStructTypeFoldableImpl! { } BraceStructTypeFoldableImpl! { - impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> { + impl<'tcx, R> TypeFoldable<'tcx> for QueryResponse<'tcx, R> { var_values, region_constraints, certainty, value } where R: TypeFoldable<'tcx>, } BraceStructLiftImpl! { - impl<'a, 'tcx, R> Lift<'tcx> for QueryResult<'a, R> { - type Lifted = QueryResult<'tcx, R::Lifted>; + impl<'a, 'tcx, R> Lift<'tcx> for QueryResponse<'a, R> { + type Lifted = QueryResponse<'tcx, R::Lifted>; var_values, region_constraints, certainty, value } where R: Lift<'tcx> } diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_response.rs similarity index 82% rename from src/librustc/infer/canonical/query_result.rs rename to src/librustc/infer/canonical/query_response.rs index a327f1f5c9d50..c29a75c34cf9d 100644 --- a/src/librustc/infer/canonical/query_result.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -19,8 +19,8 @@ use infer::canonical::substitute::substitute_value; use infer::canonical::{ - Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, Certainty, - QueryRegionConstraint, QueryResult, SmallCanonicalVarValues, + Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, + OriginalQueryValues, QueryRegionConstraint, QueryResponse, }; use infer::region_constraints::{Constraint, RegionConstraintData}; use infer::InferCtxtBuilder; @@ -59,18 +59,20 @@ impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> { canonical_key: &Canonical<'tcx, K>, operation: impl FnOnce(&InferCtxt<'_, 'gcx, 'tcx>, &mut FulfillmentContext<'tcx>, K) -> Fallible, - ) -> Fallible> + ) -> Fallible> where K: TypeFoldable<'tcx>, R: Debug + Lift<'gcx> + TypeFoldable<'tcx>, { - self.enter(|ref infcx| { - let (key, canonical_inference_vars) = - infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_key); - let fulfill_cx = &mut FulfillmentContext::new(); - let value = operation(infcx, fulfill_cx, key)?; - infcx.make_canonicalized_query_result(canonical_inference_vars, value, fulfill_cx) - }) + self.enter_with_canonical( + DUMMY_SP, + canonical_key, + |ref infcx, key, canonical_inference_vars| { + let fulfill_cx = &mut FulfillmentContext::new(); + let value = operation(infcx, fulfill_cx, key)?; + infcx.make_canonicalized_query_response(canonical_inference_vars, value, fulfill_cx) + }, + ) } } @@ -94,41 +96,41 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// the same thing happens, but the resulting query is marked as ambiguous. /// - Finally, if any of the obligations result in a hard error, /// then `Err(NoSolution)` is returned. - pub fn make_canonicalized_query_result( + pub fn make_canonicalized_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, fulfill_cx: &mut FulfillmentContext<'tcx>, - ) -> Fallible> + ) -> Fallible> where T: Debug + Lift<'gcx> + TypeFoldable<'tcx>, { - let query_result = self.make_query_result(inference_vars, answer, fulfill_cx)?; - let canonical_result = self.canonicalize_response(&query_result); + let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; + let canonical_result = self.canonicalize_response(&query_response); debug!( - "make_canonicalized_query_result: canonical_result = {:#?}", + "make_canonicalized_query_response: canonical_result = {:#?}", canonical_result ); Ok(Lrc::new(canonical_result)) } - /// Helper for `make_canonicalized_query_result` that does + /// Helper for `make_canonicalized_query_response` that does /// everything up until the final canonicalization. - fn make_query_result( + fn make_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, fulfill_cx: &mut FulfillmentContext<'tcx>, - ) -> Result, NoSolution> + ) -> Result, NoSolution> where T: Debug + TypeFoldable<'tcx> + Lift<'gcx>, { let tcx = self.tcx; debug!( - "make_query_result(\ + "make_query_response(\ inference_vars={:?}, \ answer={:?})", inference_vars, answer, @@ -140,7 +142,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { if !true_errors.is_empty() { // FIXME -- we don't indicate *why* we failed to solve - debug!("make_query_result: true_errors={:#?}", true_errors); + debug!("make_query_response: true_errors={:#?}", true_errors); return Err(NoSolution); } @@ -155,7 +157,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { region_obligations .iter() .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)), - region_constraints) + region_constraints, + ) }); let certainty = if ambig_errors.is_empty() { @@ -164,7 +167,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { Certainty::Ambiguous }; - Ok(QueryResult { + Ok(QueryResponse { var_values: inference_vars, region_constraints, certainty, @@ -182,12 +185,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// out the [chapter in the rustc guide][c]. /// /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result - pub fn instantiate_query_result_and_region_obligations( + pub fn instantiate_query_response_and_region_obligations( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - original_values: &SmallCanonicalVarValues<'tcx>, - query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + original_values: &OriginalQueryValues<'tcx>, + query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, ) -> InferResult<'tcx, R> where R: Debug + TypeFoldable<'tcx>, @@ -195,17 +198,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { let InferOk { value: result_subst, mut obligations, - } = self.query_result_substitution(cause, param_env, original_values, query_result)?; + } = self.query_response_substitution(cause, param_env, original_values, query_response)?; obligations.extend(self.query_region_constraints_into_obligations( cause, param_env, - &query_result.value.region_constraints, + &query_response.value.region_constraints, &result_subst, )); let user_result: R = - query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); Ok(InferOk { value: user_result, @@ -214,7 +217,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { } /// An alternative to - /// `instantiate_query_result_and_region_obligations` that is more + /// `instantiate_query_response_and_region_obligations` that is more /// efficient for NLL. NLL is a bit more advanced in the /// "transition to chalk" than the rest of the compiler. During /// the NLL type check, all of the "processing" of types and @@ -229,8 +232,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// into the older infcx-style constraints (e.g., calls to /// `sub_regions` or `register_region_obligation`). /// - /// Therefore, `instantiate_nll_query_result_and_region_obligations` performs the same - /// basic operations as `instantiate_query_result_and_region_obligations` but + /// Therefore, `instantiate_nll_query_response_and_region_obligations` performs the same + /// basic operations as `instantiate_query_response_and_region_obligations` but /// it returns its result differently: /// /// - It creates a substitution `S` that maps from the original @@ -248,12 +251,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// are propagated back in the return value. /// - Finally, the query result (of type `R`) is propagated back, /// after applying the substitution `S`. - pub fn instantiate_nll_query_result_and_region_obligations( + pub fn instantiate_nll_query_response_and_region_obligations( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - original_values: &SmallCanonicalVarValues<'tcx>, - query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + original_values: &OriginalQueryValues<'tcx>, + query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, output_query_region_constraints: &mut Vec>, ) -> InferResult<'tcx, R> where @@ -261,22 +264,22 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { { // In an NLL query, there should be no type variables in the // query, only region variables. - debug_assert!(query_result.variables.iter().all(|v| match v.kind { + debug_assert!(query_response.variables.iter().all(|v| match v.kind { CanonicalVarKind::Ty(_) => false, CanonicalVarKind::Region => true, })); let result_subst = - self.query_result_substitution_guess(cause, original_values, query_result); + self.query_response_substitution_guess(cause, original_values, query_response); // Compute `QueryRegionConstraint` values that unify each of // the original values `v_o` that was canonicalized into a // variable... let mut obligations = vec![]; - for (index, original_value) in original_values.iter().enumerate() { + for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. - let result_value = query_result.substitute_projected(self.tcx, &result_subst, |v| { + let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { &v.var_values[CanonicalVar::new(index)] }); match (original_value.unpack(), result_value.unpack()) { @@ -311,7 +314,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // ...also include the other query region constraints from the query. output_query_region_constraints.extend( - query_result.value.region_constraints.iter().filter_map(|r_c| { + query_response.value.region_constraints.iter().filter_map(|r_c| { let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below let k1 = substitute_value(self.tcx, &result_subst, &k1); let r2 = substitute_value(self.tcx, &result_subst, &r2); @@ -324,7 +327,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ); let user_result: R = - query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); Ok(InferOk { value: user_result, @@ -342,30 +345,30 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// example) we are doing lazy normalization and the value /// assigned to a type variable is unified with an unnormalized /// projection. - fn query_result_substitution( + fn query_response_substitution( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - original_values: &SmallCanonicalVarValues<'tcx>, - query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + original_values: &OriginalQueryValues<'tcx>, + query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, ) -> InferResult<'tcx, CanonicalVarValues<'tcx>> where R: Debug + TypeFoldable<'tcx>, { debug!( - "query_result_substitution(original_values={:#?}, query_result={:#?})", - original_values, query_result, + "query_response_substitution(original_values={:#?}, query_response={:#?})", + original_values, query_response, ); let result_subst = - self.query_result_substitution_guess(cause, original_values, query_result); + self.query_response_substitution_guess(cause, original_values, query_response); - let obligations = self.unify_query_result_substitution_guess( + let obligations = self.unify_query_response_substitution_guess( cause, param_env, original_values, &result_subst, - query_result, + query_response, )? .into_obligations(); @@ -384,26 +387,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// will instantiate fresh inference variables for each canonical /// variable instead. Therefore, the result of this method must be /// properly unified - fn query_result_substitution_guess( + fn query_response_substitution_guess( &self, cause: &ObligationCause<'tcx>, - original_values: &SmallCanonicalVarValues<'tcx>, - query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + original_values: &OriginalQueryValues<'tcx>, + query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, ) -> CanonicalVarValues<'tcx> where R: Debug + TypeFoldable<'tcx>, { debug!( - "query_result_substitution_guess(original_values={:#?}, query_result={:#?})", - original_values, query_result, + "query_response_substitution_guess(original_values={:#?}, query_response={:#?})", + original_values, query_response, ); // Every canonical query result includes values for each of // the inputs to the query. Therefore, we begin by unifying // these values with the original inputs that were // canonicalized. - let result_values = &query_result.value.var_values; - assert_eq!(original_values.len(), result_values.len()); + let result_values = &query_response.value.var_values; + assert_eq!(original_values.var_values.len(), result_values.len()); // Quickly try to find initial values for the canonical // variables in the result in terms of the query. We do this @@ -413,11 +416,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // result, then we can type the corresponding value from the // input. See the example above. let mut opt_values: IndexVec>> = - IndexVec::from_elem_n(None, query_result.variables.len()); + IndexVec::from_elem_n(None, query_response.variables.len()); // In terms of our example above, we are iterating over pairs like: // [(?A, Vec), ('static, '?1), (?B, ?0)] - for (original_value, result_value) in original_values.iter().zip(result_values) { + for (original_value, result_value) in original_values.var_values.iter().zip(result_values) { match result_value.unpack() { UnpackedKind::Type(result_value) => { // e.g., here `result_value` might be `?0` in the example above... @@ -440,7 +443,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. let result_subst = CanonicalVarValues { - var_values: query_result + var_values: query_response .variables .iter() .enumerate() @@ -458,29 +461,34 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// query result. Often, but not always, this is a no-op, because /// we already found the mapping in the "guessing" step. /// - /// See also: `query_result_substitution_guess` - fn unify_query_result_substitution_guess( + /// See also: `query_response_substitution_guess` + fn unify_query_response_substitution_guess( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - original_values: &SmallCanonicalVarValues<'tcx>, + original_values: &OriginalQueryValues<'tcx>, result_subst: &CanonicalVarValues<'tcx>, - query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, ) -> InferResult<'tcx, ()> where R: Debug + TypeFoldable<'tcx>, { // A closure that yields the result value for the given // canonical variable; this is taken from - // `query_result.var_values` after applying the substitution + // `query_response.var_values` after applying the substitution // `result_subst`. - let substituted_query_result = |index: CanonicalVar| -> Kind<'tcx> { - query_result.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) + let substituted_query_response = |index: CanonicalVar| -> Kind<'tcx> { + query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) }; // Unify the original value for each variable with the value - // taken from `query_result` (after applying `result_subst`). - Ok(self.unify_canonical_vars(cause, param_env, original_values, substituted_query_result)?) + // taken from `query_response` (after applying `result_subst`). + Ok(self.unify_canonical_vars( + cause, + param_env, + original_values, + substituted_query_response, + )?) } /// Converts the region constraints resulting from a query into an @@ -524,12 +532,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - variables1: &SmallCanonicalVarValues<'tcx>, + variables1: &OriginalQueryValues<'tcx>, variables2: impl Fn(CanonicalVar) -> Kind<'tcx>, ) -> InferResult<'tcx, ()> { self.commit_if_ok(|_| { let mut obligations = vec![]; - for (index, value1) in variables1.iter().enumerate() { + for (index, value1) in variables1.var_values.iter().enumerate() { let value2 = variables2(CanonicalVar::new(index)); match (value1.unpack(), value2.unpack()) { diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index e77d20665bf3b..ae1892caa744e 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -593,11 +593,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { where T : TypeFoldable<'tcx>, { - let new_universe = self.create_subuniverse(); + let next_universe = self.create_next_universe(); let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { self.tcx.mk_region(ty::RePlaceholder(ty::Placeholder { - universe: new_universe, + universe: next_universe, name: br, })) }); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 291b46edccfb2..ef9886e06d4be 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -20,6 +20,7 @@ pub use ty::IntVarValue; use arena::SyncDroplessArena; use errors::DiagnosticBuilder; use hir::def_id::DefId; +use infer::canonical::{Canonical, CanonicalVarValues}; use middle::free_region::RegionRelations; use middle::lang_items; use middle::region; @@ -49,7 +50,6 @@ use self::region_constraints::{RegionConstraintCollector, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; -pub mod opaque_types; pub mod at; pub mod canonical; mod combine; @@ -62,6 +62,7 @@ mod higher_ranked; pub mod lattice; mod lexical_region_resolve; mod lub; +pub mod opaque_types; pub mod outlives; pub mod region_constraints; pub mod resolve; @@ -86,7 +87,7 @@ pub type FixupResult = Result; // "fixup result" /// NLL borrow checker will also do -- it might be set to true. #[derive(Copy, Clone, Default, Debug)] pub struct SuppressRegionErrors { - suppressed: bool + suppressed: bool, } impl SuppressRegionErrors { @@ -100,15 +101,11 @@ impl SuppressRegionErrors { pub fn when_nll_is_enabled(tcx: TyCtxt<'_, '_, '_>) -> Self { match tcx.borrowck_mode() { // If we're on AST or Migrate mode, report AST region errors - BorrowckMode::Ast | BorrowckMode::Migrate => SuppressRegionErrors { - suppressed: false - }, + BorrowckMode::Ast | BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false }, // If we're on MIR or Compare mode, don't report AST region errors as they should // be reported by NLL - BorrowckMode::Compare | BorrowckMode::Mir => SuppressRegionErrors { - suppressed: true - }, + BorrowckMode::Compare | BorrowckMode::Mir => SuppressRegionErrors { suppressed: true }, } } } @@ -494,10 +491,30 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { self } - pub fn enter(&'tcx mut self, f: F) -> R + /// Given a canonical value `C` as a starting point, create an + /// inference context that contains each of the bound values + /// within instantiated as a fresh variable. The `f` closure is + /// invoked with the new infcx, along with the instantiated value + /// `V` and a substitution `S`. This substitution `S` maps from + /// the bound values in `C` to their instantiated values in `V` + /// (in other words, `S(C) = V`). + pub fn enter_with_canonical( + &'tcx mut self, + span: Span, + canonical: &Canonical<'tcx, T>, + f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>, T, CanonicalVarValues<'tcx>) -> R, + ) -> R where - F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R, + T: TypeFoldable<'tcx>, { + self.enter(|infcx| { + let (value, subst) = + infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); + f(infcx, value, subst) + }) + } + + pub fn enter(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R) -> R { let InferCtxtBuilder { global_tcx, ref arena, @@ -1472,13 +1489,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.universe.get() } - /// Create and return a new subunivese of the current universe; - /// update `self.universe` to that new subuniverse. At present, - /// used only in the NLL subtyping code, which uses the new - /// universe-based scheme instead of the more limited leak-check - /// scheme. - pub fn create_subuniverse(&self) -> ty::UniverseIndex { - let u = self.universe.get().subuniverse(); + /// Create and return a fresh universe that extends all previous + /// universes. Updates `self.universe` to that new universe. + pub fn create_next_universe(&self) -> ty::UniverseIndex { + let u = self.universe.get().next_universe(); self.universe.set(u); u } diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index aaf03f8e7fb55..8f7b0df8b95aa 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -10,7 +10,7 @@ use infer::at::At; use infer::InferOk; -use smallvec::SmallVec; +use infer::canonical::OriginalQueryValues; use std::iter::FromIterator; use syntax::source_map::Span; use ty::subst::Kind; @@ -51,14 +51,14 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { } let gcx = tcx.global_tcx(); - let mut orig_values = SmallVec::new(); + let mut orig_values = OriginalQueryValues::default(); let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); let span = self.cause.span; debug!("c_ty = {:?}", c_ty); match &gcx.dropck_outlives(c_ty) { Ok(result) if result.is_proven() => { if let Ok(InferOk { value, obligations }) = - self.infcx.instantiate_query_result_and_region_obligations( + self.infcx.instantiate_query_response_and_region_obligations( self.cause, self.param_env, &orig_values, diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs index f573b1ef45e9c..ca11c5f5a0874 100644 --- a/src/librustc/traits/query/evaluate_obligation.rs +++ b/src/librustc/traits/query/evaluate_obligation.rs @@ -9,7 +9,7 @@ // except according to those terms. use infer::InferCtxt; -use smallvec::SmallVec; +use infer::canonical::OriginalQueryValues; use traits::{EvaluationResult, PredicateObligation, SelectionContext, TraitQueryMode, OverflowError}; @@ -38,7 +38,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, ) -> Result { - let mut _orig_values = SmallVec::new(); + let mut _orig_values = OriginalQueryValues::default(); let c_pred = self.canonicalize_query(&obligation.param_env.and(obligation.predicate), &mut _orig_values); // Run canonical query. If overflow occurs, rerun from scratch but this time diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 9b9643aab97d5..4adb65dc58d91 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -13,9 +13,9 @@ //! `normalize_projection_ty` query when it encounters projections. use infer::at::At; +use infer::canonical::OriginalQueryValues; use infer::{InferCtxt, InferOk}; use mir::interpret::{ConstValue, GlobalId}; -use smallvec::SmallVec; use traits::project::Normalized; use traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use ty::fold::{TypeFoldable, TypeFolder}; @@ -154,7 +154,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx let gcx = self.infcx.tcx.global_tcx(); - let mut orig_values = SmallVec::new(); + let mut orig_values = OriginalQueryValues::default(); let c_data = self.infcx.canonicalize_query( &self.param_env.and(*data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); @@ -167,7 +167,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx return ty; } - match self.infcx.instantiate_query_result_and_region_obligations( + match self.infcx.instantiate_query_response_and_region_obligations( self.cause, self.param_env, &orig_values, diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs index 47c8ee357fbe8..99f557d44d9aa 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -9,9 +9,9 @@ // except according to those terms. use infer::InferCtxt; +use infer::canonical::OriginalQueryValues; use syntax::ast; use syntax::source_map::Span; -use smallvec::SmallVec; use traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt}; use traits::query::NoSolution; use ty::{self, Ty, TyCtxt}; @@ -105,7 +105,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ) -> Vec> { debug!("implied_outlives_bounds(ty = {:?})", ty); - let mut orig_values = SmallVec::new(); + let mut orig_values = OriginalQueryValues::default(); let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); let result = match self.tcx.global_tcx().implied_outlives_bounds(key) { Ok(r) => r, @@ -119,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { }; assert!(result.value.is_proven()); - let result = self.instantiate_query_result_and_region_obligations( + let result = self.instantiate_query_response_and_region_obligations( &ObligationCause::misc(span, body_id), param_env, &orig_values, &result); debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); let result = match result { diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc/traits/query/type_op/custom.rs index 6708112697bb5..54860dd0434a0 100644 --- a/src/librustc/traits/query/type_op/custom.rs +++ b/src/librustc/traits/query/type_op/custom.rs @@ -12,7 +12,7 @@ use infer::{InferCtxt, InferOk}; use std::fmt; use traits::query::Fallible; -use infer::canonical::query_result; +use infer::canonical::query_response; use infer::canonical::QueryRegionConstraint; use std::rc::Rc; use syntax::source_map::DUMMY_SP; @@ -102,7 +102,7 @@ fn scrape_region_constraints<'gcx, 'tcx, R>( let region_constraint_data = infcx.take_and_reset_region_constraints(); - let outlives = query_result::make_query_outlives( + let outlives = query_response::make_query_outlives( infcx.tcx, region_obligations .iter() diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs index 52a087cbc8069..43dea442df65a 100644 --- a/src/librustc/traits/query/type_op/eq.rs +++ b/src/librustc/traits/query/type_op/eq.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; use traits::query::Fallible; use ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -25,12 +25,12 @@ impl<'tcx> Eq<'tcx> { } impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Eq<'tcx> { - type QueryResult = (); + type QueryResponse = (); fn try_fast_path( _tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Eq<'tcx>>, - ) -> Option { + ) -> Option { if key.value.a == key.value.b { Some(()) } else { @@ -41,13 +41,13 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Eq<'tcx> { fn perform_query( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible> { + ) -> Fallible> { tcx.type_op_eq(canonicalized) } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, ()>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v: &'a CanonicalizedQueryResponse<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { v } } diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs index 27534bc8c3cf7..b113a322d370a 100644 --- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs +++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; use traits::query::outlives_bounds::OutlivesBound; use traits::query::Fallible; use ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -25,19 +25,19 @@ impl<'tcx> ImpliedOutlivesBounds<'tcx> { } impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ImpliedOutlivesBounds<'tcx> { - type QueryResult = Vec>; + type QueryResponse = Vec>; fn try_fast_path( _tcx: TyCtxt<'_, 'gcx, 'tcx>, _key: &ParamEnvAnd<'tcx, Self>, - ) -> Option { + ) -> Option { None } fn perform_query( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible> { + ) -> Fallible> { // FIXME the query should take a `ImpliedOutlivesBounds` let Canonical { variables, @@ -56,8 +56,8 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ImpliedOutlivesBounds< } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>> { + v: &'a CanonicalizedQueryResponse<'gcx, Self::QueryResponse>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>> { v } } diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs index 8e4236d1754c2..b292df758eeb5 100644 --- a/src/librustc/traits/query/type_op/mod.rs +++ b/src/librustc/traits/query/type_op/mod.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint, - QueryResult}; +use infer::canonical::{ + Canonical, Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, + QueryRegionConstraint, QueryResponse, +}; use infer::{InferCtxt, InferOk}; -use smallvec::SmallVec; use std::fmt; use std::rc::Rc; use traits::query::Fallible; @@ -55,7 +56,7 @@ pub trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug { pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + Lift<'gcx> { - type QueryResult: TypeFoldable<'tcx> + Lift<'gcx>; + type QueryResponse: TypeFoldable<'tcx> + Lift<'gcx>; /// Give query the option for a simple fast path that never /// actually hits the tcx cache lookup etc. Return `Some(r)` with @@ -63,7 +64,7 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: fn try_fast_path( tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>, - ) -> Option; + ) -> Option; /// Performs the actual query with the canonicalized key -- the /// real work happens here. This method is not given an `infcx` @@ -74,29 +75,29 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: fn perform_query( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible>; + ) -> Fallible>; /// Casts a lifted query result (which is in the gcx lifetime) /// into the tcx lifetime. This is always just an identity cast, /// but the generic code doesn't realize it -- put another way, in - /// the generic code, we have a `Lifted<'gcx, Self::QueryResult>` - /// and we want to convert that to a `Self::QueryResult`. This is + /// the generic code, we have a `Lifted<'gcx, Self::QueryResponse>` + /// and we want to convert that to a `Self::QueryResponse`. This is /// not a priori valid, so we can't do it -- but in practice, it /// is always a no-op (e.g., the lifted form of a type, /// `Ty<'gcx>`, is a subtype of `Ty<'tcx>`). So we have to push /// the operation into the impls that know more specifically what - /// `QueryResult` is. This operation would (maybe) be nicer with + /// `QueryResponse` is. This operation would (maybe) be nicer with /// something like HKTs or GATs, since then we could make - /// `QueryResult` parametric and `'gcx` and `'tcx` etc. + /// `QueryResponse` parametric and `'gcx` and `'tcx` etc. fn shrink_to_tcx_lifetime( - lifted_query_result: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>>; + lifted_query_result: &'a CanonicalizedQueryResponse<'gcx, Self::QueryResponse>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>>; fn fully_perform_into( query_key: ParamEnvAnd<'tcx, Self>, infcx: &InferCtxt<'_, 'gcx, 'tcx>, output_query_region_constraints: &mut Vec>, - ) -> Fallible { + ) -> Fallible { if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { return Ok(result); } @@ -105,7 +106,7 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: // `canonicalize_hr_query_hack` here because of things // like the subtype query, which go awry around // `'static` otherwise. - let mut canonical_var_values = SmallVec::new(); + let mut canonical_var_values = OriginalQueryValues::default(); let canonical_self = infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; @@ -114,7 +115,7 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: let param_env = query_key.param_env; let InferOk { value, obligations } = infcx - .instantiate_nll_query_result_and_region_obligations( + .instantiate_nll_query_response_and_region_obligations( &ObligationCause::dummy(), param_env, &canonical_var_values, @@ -145,7 +146,7 @@ impl<'gcx: 'tcx, 'tcx, Q> TypeOp<'gcx, 'tcx> for ParamEnvAnd<'tcx, Q> where Q: QueryTypeOp<'gcx, 'tcx>, { - type Output = Q::QueryResult; + type Output = Q::QueryResponse; fn fully_perform( self, diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs index 0c393fa4ca80f..c45e8b2554b0f 100644 --- a/src/librustc/traits/query/type_op/normalize.rs +++ b/src/librustc/traits/query/type_op/normalize.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; use std::fmt; use traits::query::Fallible; use ty::fold::TypeFoldable; @@ -32,7 +32,7 @@ impl<'gcx: 'tcx, 'tcx, T> super::QueryTypeOp<'gcx, 'tcx> for Normalize where T: Normalizable<'gcx, 'tcx>, { - type QueryResult = T; + type QueryResponse = T; fn try_fast_path(_tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option { if !key.value.value.has_projections() { @@ -45,13 +45,13 @@ where fn perform_query( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible> { + ) -> Fallible> { T::type_op_method(tcx, canonicalized) } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, T>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, T>> { + v: &'a CanonicalizedQueryResponse<'gcx, T>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, T>> { T::shrink_to_tcx_lifetime(v) } } @@ -60,13 +60,13 @@ pub trait Normalizable<'gcx, 'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'gcx> fn type_op_method( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, - ) -> Fallible>; + ) -> Fallible>; /// Convert from the `'gcx` (lifted) form of `Self` into the `tcx` /// form of `Self`. fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, Self>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>>; + v: &'a CanonicalizedQueryResponse<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>>; } impl Normalizable<'gcx, 'tcx> for Ty<'tcx> @@ -76,13 +76,13 @@ where fn type_op_method( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, - ) -> Fallible> { + ) -> Fallible> { tcx.type_op_normalize_ty(canonicalized) } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, Self>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v: &'a CanonicalizedQueryResponse<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> { v } } @@ -94,13 +94,13 @@ where fn type_op_method( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, - ) -> Fallible> { + ) -> Fallible> { tcx.type_op_normalize_predicate(canonicalized) } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, Self>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v: &'a CanonicalizedQueryResponse<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> { v } } @@ -112,13 +112,13 @@ where fn type_op_method( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, - ) -> Fallible> { + ) -> Fallible> { tcx.type_op_normalize_poly_fn_sig(canonicalized) } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, Self>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v: &'a CanonicalizedQueryResponse<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> { v } } @@ -130,13 +130,13 @@ where fn type_op_method( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, - ) -> Fallible> { + ) -> Fallible> { tcx.type_op_normalize_fn_sig(canonicalized) } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, Self>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v: &'a CanonicalizedQueryResponse<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> { v } } diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs index e41ae7a72f9c2..a36c5accd2a68 100644 --- a/src/librustc/traits/query/type_op/outlives.rs +++ b/src/librustc/traits/query/type_op/outlives.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; use traits::query::dropck_outlives::trivial_dropck_outlives; use traits::query::dropck_outlives::DropckOutlivesResult; use traits::query::Fallible; @@ -29,12 +29,12 @@ impl super::QueryTypeOp<'gcx, 'tcx> for DropckOutlives<'tcx> where 'gcx: 'tcx, { - type QueryResult = DropckOutlivesResult<'tcx>; + type QueryResponse = DropckOutlivesResult<'tcx>; fn try_fast_path( tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>, - ) -> Option { + ) -> Option { if trivial_dropck_outlives(tcx, key.value.dropped_ty) { Some(DropckOutlivesResult::default()) } else { @@ -45,7 +45,7 @@ where fn perform_query( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible> { + ) -> Fallible> { // Subtle: note that we are not invoking // `infcx.at(...).dropck_outlives(...)` here, but rather the // underlying `dropck_outlives` query. This same underlying @@ -76,8 +76,8 @@ where } fn shrink_to_tcx_lifetime( - lifted_query_result: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>> { + lifted_query_result: &'a CanonicalizedQueryResponse<'gcx, Self::QueryResponse>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>> { lifted_query_result } } diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs index e1b3b3c436dab..460ddb2a138b5 100644 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ b/src/librustc/traits/query/type_op/prove_predicate.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; use traits::query::Fallible; use ty::{ParamEnvAnd, Predicate, TyCtxt}; @@ -24,12 +24,12 @@ impl<'tcx> ProvePredicate<'tcx> { } impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ProvePredicate<'tcx> { - type QueryResult = (); + type QueryResponse = (); fn try_fast_path( tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>, - ) -> Option { + ) -> Option { // Proving Sized, very often on "obviously sized" types like // `&T`, accounts for about 60% percentage of the predicates // we have to prove. No need to canonicalize and all that for @@ -50,13 +50,13 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ProvePredicate<'tcx> { fn perform_query( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible> { + ) -> Fallible> { tcx.type_op_prove_predicate(canonicalized) } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, ()>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v: &'a CanonicalizedQueryResponse<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { v } } diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs index dc41bb1d6ab69..2b2939c644aa3 100644 --- a/src/librustc/traits/query/type_op/subtype.rs +++ b/src/librustc/traits/query/type_op/subtype.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; use traits::query::Fallible; use ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -28,7 +28,7 @@ impl<'tcx> Subtype<'tcx> { } impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Subtype<'tcx> { - type QueryResult = (); + type QueryResponse = (); fn try_fast_path(_tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> { if key.value.sub == key.value.sup { @@ -41,13 +41,13 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Subtype<'tcx> { fn perform_query( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible> { + ) -> Fallible> { tcx.type_op_subtype(canonicalized) } fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResult<'gcx, ()>, - ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v: &'a CanonicalizedQueryResponse<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { v } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2e8734a6aa8eb..4135d499c5853 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -57,6 +57,7 @@ use syntax::symbol::{keywords, Symbol, LocalInternedString, InternedString}; use syntax_pos::{DUMMY_SP, Span}; use smallvec; +use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; @@ -1456,10 +1457,10 @@ impl<'tcx> InstantiatedPredicates<'tcx> { /// "Universes" are used during type- and trait-checking in the /// presence of `for<..>` binders to control what sets of names are /// visible. Universes are arranged into a tree: the root universe -/// contains names that are always visible. But when you enter into -/// some subuniverse, then it may add names that are only visible -/// within that subtree (but it can still name the names of its -/// ancestor universes). +/// contains names that are always visible. Each child then adds a new +/// set of names that are visible, in addition to those of its parent. +/// We say that the child universe "extends" the parent universe with +/// new names. /// /// To make this more concrete, consider this program: /// @@ -1471,11 +1472,11 @@ impl<'tcx> InstantiatedPredicates<'tcx> { /// ``` /// /// The struct name `Foo` is in the root universe U0. But the type -/// parameter `T`, introduced on `bar`, is in a subuniverse U1 -- -/// i.e., within `bar`, we can name both `T` and `Foo`, but outside of -/// `bar`, we cannot name `T`. Then, within the type of `y`, the -/// region `'a` is in a subuniverse U2 of U1, because we can name it -/// inside the fn type but not outside. +/// parameter `T`, introduced on `bar`, is in an extended universe U1 +/// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside +/// of `bar`, we cannot name `T`. Then, within the type of `y`, the +/// region `'a` is in a universe U2 that extends U1, because we can +/// name it inside the fn type but not outside. /// /// Universes are used to do type- and trait-checking around these /// "forall" binders (also called **universal quantification**). The @@ -1488,65 +1489,39 @@ impl<'tcx> InstantiatedPredicates<'tcx> { /// declared, but a type name in a non-zero universe is a placeholder /// type -- an idealized representative of "types in general" that we /// use for checking generic functions. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub struct UniverseIndex(u32); - -impl UniverseIndex { - /// The root universe, where things that the user defined are - /// visible. - pub const ROOT: Self = UniverseIndex(0); +newtype_index! { + pub struct UniverseIndex { + DEBUG_FORMAT = "U{}", + } +} - /// The "max universe" -- this isn't really a valid universe, but - /// it's useful sometimes as a "starting value" when you are - /// taking the minimum of a (non-empty!) set of universes. - pub const MAX: Self = UniverseIndex(::std::u32::MAX); +impl_stable_hash_for!(struct UniverseIndex { private }); - /// Creates a universe index from the given integer. Not to be - /// used lightly lest you pick a bad value. But sometimes we - /// convert universe indices into integers and back for various - /// reasons. - pub fn from_u32(index: u32) -> Self { - UniverseIndex(index) - } +impl UniverseIndex { + pub const ROOT: UniverseIndex = UniverseIndex::from_u32_const(0); - /// A "subuniverse" corresponds to being inside a `forall` quantifier. - /// So, for example, suppose we have this type in universe `U`: + /// Returns the "next" universe index in order -- this new index + /// is considered to extend all previous universes. This + /// corresponds to entering a `forall` quantifier. So, for + /// example, suppose we have this type in universe `U`: /// /// ``` /// for<'a> fn(&'a u32) /// ``` /// /// Once we "enter" into this `for<'a>` quantifier, we are in a - /// subuniverse of `U` -- in this new universe, we can name the - /// region `'a`, but that region was not nameable from `U` because - /// it was not in scope there. - pub fn subuniverse(self) -> UniverseIndex { - UniverseIndex(self.0.checked_add(1).unwrap()) - } - - /// True if the names in this universe are a subset of the names in `other`. - pub fn is_subset_of(self, other: UniverseIndex) -> bool { - self.0 <= other.0 - } - - pub fn as_u32(&self) -> u32 { - self.0 - } - - pub fn as_usize(&self) -> usize { - self.0 as usize - } -} - -impl fmt::Debug for UniverseIndex { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "U{}", self.as_u32()) - } -} - -impl From for UniverseIndex { - fn from(index: u32) -> Self { - UniverseIndex(index) + /// new universe that extends `U` -- in this new universe, we can + /// name the region `'a`, but that region was not nameable from + /// `U` because it was not in scope there. + pub fn next_universe(self) -> UniverseIndex { + UniverseIndex::from_u32(self.private.checked_add(1).unwrap()) + } + + /// True if `self` can name a name from `other` -- in other words, + /// if the set of names in `self` is a superset of those in + /// `other`. + pub fn can_name(self, other: UniverseIndex) -> bool { + self.private >= other.private } } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 7f5bc35f91f9b..c4f39ffcd2067 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -559,7 +559,7 @@ define_queries! { <'tcx> [] fn normalize_projection_ty: NormalizeProjectionTy( CanonicalProjectionGoal<'tcx> ) -> Result< - Lrc>>>, + Lrc>>>, NoSolution, >, @@ -571,7 +571,7 @@ define_queries! { <'tcx> [] fn implied_outlives_bounds: ImpliedOutlivesBounds( CanonicalTyGoal<'tcx> ) -> Result< - Lrc>>>>, + Lrc>>>>, NoSolution, >, @@ -579,7 +579,7 @@ define_queries! { <'tcx> [] fn dropck_outlives: DropckOutlives( CanonicalTyGoal<'tcx> ) -> Result< - Lrc>>>, + Lrc>>>, NoSolution, >, @@ -593,7 +593,7 @@ define_queries! { <'tcx> [] fn type_op_eq: TypeOpEq( CanonicalTypeOpEqGoal<'tcx> ) -> Result< - Lrc>>, + Lrc>>, NoSolution, >, @@ -601,7 +601,7 @@ define_queries! { <'tcx> [] fn type_op_subtype: TypeOpSubtype( CanonicalTypeOpSubtypeGoal<'tcx> ) -> Result< - Lrc>>, + Lrc>>, NoSolution, >, @@ -609,7 +609,7 @@ define_queries! { <'tcx> [] fn type_op_prove_predicate: TypeOpProvePredicate( CanonicalTypeOpProvePredicateGoal<'tcx> ) -> Result< - Lrc>>, + Lrc>>, NoSolution, >, @@ -617,7 +617,7 @@ define_queries! { <'tcx> [] fn type_op_normalize_ty: TypeOpNormalizeTy( CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>> ) -> Result< - Lrc>>>, + Lrc>>>, NoSolution, >, @@ -625,7 +625,7 @@ define_queries! { <'tcx> [] fn type_op_normalize_predicate: TypeOpNormalizePredicate( CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> ) -> Result< - Lrc>>>, + Lrc>>>, NoSolution, >, @@ -633,7 +633,7 @@ define_queries! { <'tcx> [] fn type_op_normalize_poly_fn_sig: TypeOpNormalizePolyFnSig( CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>> ) -> Result< - Lrc>>>, + Lrc>>>, NoSolution, >, @@ -641,7 +641,7 @@ define_queries! { <'tcx> [] fn type_op_normalize_fn_sig: TypeOpNormalizeFnSig( CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>> ) -> Result< - Lrc>>>, + Lrc>>>, NoSolution, >, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 3f62883c6a57b..273799bd4bd34 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! { ::ty::ClosureKind, ::ty::IntVarValue, ::ty::ParamTy, + ::ty::UniverseIndex, ::ty::Variance, ::syntax_pos::Span, } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 56bb6a87d44fa..dd8a7f19a63bd 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -112,7 +112,7 @@ struct RegionDefinition<'tcx> { /// Which universe is this region variable defined in? This is /// most often `ty::UniverseIndex::ROOT`, but when we encounter /// forall-quantifiers like `for<'a> { 'a = 'b }`, we would create - /// the variable for `'a` in a subuniverse. + /// the variable for `'a` in a fresh universe that extends ROOT. universe: ty::UniverseIndex, /// If this is 'static or an early-bound region, then this is @@ -339,11 +339,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { NLLRegionVariableOrigin::Placeholder(placeholder) => { // Each placeholder region is only visible from - // its universe `ui` and its superuniverses. So we + // its universe `ui` and its extensions. So we // can't just add it into `scc` unless the // universe of the scc can name this region. let scc_universe = self.scc_universes[scc]; - if placeholder.universe.is_subset_of(scc_universe) { + if scc_universe.can_name(placeholder.universe) { self.scc_values.add_element(scc, placeholder); } else { self.add_incompatible_universe(scc); @@ -541,7 +541,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Quick check: if scc_b's declared universe is a subset of // scc_a's declared univese (typically, both are ROOT), then // it cannot contain any problematic universe elements. - if self.scc_universes[scc_b].is_subset_of(universe_a) { + if universe_a.can_name(self.scc_universes[scc_b]) { return true; } @@ -550,7 +550,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // from universe_a self.scc_values .placeholders_contained_in(scc_b) - .all(|p| p.universe.is_subset_of(universe_a)) + .all(|p| universe_a.can_name(p.universe)) } /// Extend `scc` so that it can outlive some placeholder region diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 07372c19c46c9..3607ae4f5088d 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -148,8 +148,8 @@ crate enum RegionElement { /// a lifetime parameter). RootUniversalRegion(RegionVid), - /// A subuniverse from a subuniverse (e.g., instantiated from a - /// `for<'a> fn(&'a u32)` type). + /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)` + /// type). PlaceholderRegion(ty::Placeholder), } @@ -252,19 +252,6 @@ impl PlaceholderIndices { } } -impl ::std::iter::FromIterator for PlaceholderIndices { - fn from_iter(iter: I) -> Self - where - I: IntoIterator, - { - let mut result = Self::default(); - iter.into_iter().for_each(|p| { - result.insert(p); - }); - result - } -} - /// Stores the full values for a set of regions (in contrast to /// `LivenessValues`, which only stores those points in the where a /// region is live). The full value for a region may contain points in diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 1e279aef07981..96cc1c0afecb4 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -159,7 +159,7 @@ trait TypeRelatingDelegate<'tcx> { fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>); /// Creates a new universe index. Used when instantiating placeholders. - fn next_subuniverse(&mut self) -> ty::UniverseIndex; + fn create_next_universe(&mut self) -> ty::UniverseIndex; /// Creates a new region variable representing a higher-ranked /// region that is instantiated existentially. This creates an @@ -218,8 +218,8 @@ impl NllTypeRelatingDelegate<'me, 'bccx, 'gcx, 'tcx> { } impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { - fn next_subuniverse(&mut self) -> ty::UniverseIndex { - self.infcx.create_subuniverse() + fn create_next_universe(&mut self) -> ty::UniverseIndex { + self.infcx.create_next_universe() } fn next_existential_region_var(&mut self) -> ty::Region<'tcx> { @@ -324,7 +324,7 @@ where // new universe for the placeholders we will make // from here out. let universe = lazy_universe.unwrap_or_else(|| { - let universe = delegate.next_subuniverse(); + let universe = delegate.create_next_universe(); lazy_universe = Some(universe); universe }); diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs index dea3aa4372a33..536c15234064f 100644 --- a/src/librustc_traits/chalk_context.rs +++ b/src/librustc_traits/chalk_context.rs @@ -10,7 +10,9 @@ use chalk_engine::fallible::Fallible as ChalkEngineFallible; use chalk_engine::{context, hh::HhGoal, DelayedLiteral, ExClause}; -use rustc::infer::canonical::{Canonical, CanonicalVarValues, QueryRegionConstraint, QueryResult}; +use rustc::infer::canonical::{ + Canonical, CanonicalVarValues, OriginalQueryValues, QueryRegionConstraint, QueryResponse, +}; use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc::traits::{ WellFormed, @@ -26,7 +28,6 @@ use rustc::traits::{ use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc::ty::subst::Kind; use rustc::ty::{self, TyCtxt}; -use smallvec::SmallVec; use std::fmt::{self, Debug}; use std::marker::PhantomData; @@ -77,7 +78,7 @@ impl context::Context for ChalkArenas<'tcx> { // u-canonicalization not yet implemented type UniverseMap = UniverseMap; - type Solution = Canonical<'tcx, QueryResult<'tcx, ()>>; + type Solution = Canonical<'tcx, QueryResponse<'tcx, ()>>; type InferenceNormalizedSubst = CanonicalVarValues<'tcx>; @@ -116,7 +117,7 @@ impl context::AggregateOps> for ChalkContext<'cx, 'gcx> { &self, _root_goal: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>, _simplified_answers: impl context::AnswerStream>, - ) -> Option>> { + ) -> Option>> { unimplemented!() } } @@ -390,7 +391,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> &mut self, value: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>, ) -> Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> { - let mut _orig_values = SmallVec::new(); + let mut _orig_values = OriginalQueryValues::default(); self.infcx.canonicalize_query(value, &mut _orig_values) } diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 2996fe0320042..ed61f07c4d83d 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::hir::def_id::DefId; -use rustc::infer::canonical::{Canonical, QueryResult}; +use rustc::infer::canonical::{Canonical, QueryResponse}; use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint}; use rustc::traits::query::{CanonicalTyGoal, NoSolution}; use rustc::traits::{FulfillmentContext, Normalized, ObligationCause, TraitEngineExt}; @@ -30,124 +30,125 @@ crate fn provide(p: &mut Providers) { fn dropck_outlives<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, - goal: CanonicalTyGoal<'tcx>, -) -> Result>>>, NoSolution> { - debug!("dropck_outlives(goal={:#?})", goal); - - tcx.infer_ctxt().enter(|ref infcx| { - let tcx = infcx.tcx; - let ( - ParamEnvAnd { + canonical_goal: CanonicalTyGoal<'tcx>, +) -> Result>>>, NoSolution> { + debug!("dropck_outlives(goal={:#?})", canonical_goal); + + tcx.infer_ctxt().enter_with_canonical( + DUMMY_SP, + &canonical_goal, + |ref infcx, goal, canonical_inference_vars| { + let tcx = infcx.tcx; + let ParamEnvAnd { param_env, value: for_ty, - }, - canonical_inference_vars, - ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal); + } = goal; - let mut result = DropckOutlivesResult { - kinds: vec![], - overflows: vec![], - }; + let mut result = DropckOutlivesResult { + kinds: vec![], + overflows: vec![], + }; - // A stack of types left to process. Each round, we pop - // something from the stack and invoke - // `dtorck_constraint_for_ty`. This may produce new types that - // have to be pushed on the stack. This continues until we have explored - // all the reachable types from the type `for_ty`. - // - // Example: Imagine that we have the following code: - // - // ```rust - // struct A { - // value: B, - // children: Vec, - // } - // - // struct B { - // value: u32 - // } - // - // fn f() { - // let a: A = ...; - // .. - // } // here, `a` is dropped - // ``` - // - // at the point where `a` is dropped, we need to figure out - // which types inside of `a` contain region data that may be - // accessed by any destructors in `a`. We begin by pushing `A` - // onto the stack, as that is the type of `a`. We will then - // invoke `dtorck_constraint_for_ty` which will expand `A` - // into the types of its fields `(B, Vec)`. These will get - // pushed onto the stack. Eventually, expanding `Vec` will - // lead to us trying to push `A` a second time -- to prevent - // infinite recursion, we notice that `A` was already pushed - // once and stop. - let mut ty_stack = vec![(for_ty, 0)]; - - // Set used to detect infinite recursion. - let mut ty_set = FxHashSet(); - - let fulfill_cx = &mut FulfillmentContext::new(); - - let cause = ObligationCause::dummy(); - while let Some((ty, depth)) = ty_stack.pop() { - let DtorckConstraint { - dtorck_types, - outlives, - overflows, - } = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?; - - // "outlives" represent types/regions that may be touched - // by a destructor. - result.kinds.extend(outlives); - result.overflows.extend(overflows); - - // dtorck types are "types that will get dropped but which - // do not themselves define a destructor", more or less. We have - // to push them onto the stack to be expanded. - for ty in dtorck_types { - match infcx.at(&cause, param_env).normalize(&ty) { - Ok(Normalized { - value: ty, - obligations, - }) => { - fulfill_cx.register_predicate_obligations(infcx, obligations); - - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - - match ty.sty { - // All parameters live for the duration of the - // function. - ty::Param(..) => {} - - // A projection that we couldn't resolve - it - // might have a destructor. - ty::Projection(..) | ty::Opaque(..) => { - result.kinds.push(ty.into()); - } + // A stack of types left to process. Each round, we pop + // something from the stack and invoke + // `dtorck_constraint_for_ty`. This may produce new types that + // have to be pushed on the stack. This continues until we have explored + // all the reachable types from the type `for_ty`. + // + // Example: Imagine that we have the following code: + // + // ```rust + // struct A { + // value: B, + // children: Vec, + // } + // + // struct B { + // value: u32 + // } + // + // fn f() { + // let a: A = ...; + // .. + // } // here, `a` is dropped + // ``` + // + // at the point where `a` is dropped, we need to figure out + // which types inside of `a` contain region data that may be + // accessed by any destructors in `a`. We begin by pushing `A` + // onto the stack, as that is the type of `a`. We will then + // invoke `dtorck_constraint_for_ty` which will expand `A` + // into the types of its fields `(B, Vec)`. These will get + // pushed onto the stack. Eventually, expanding `Vec` will + // lead to us trying to push `A` a second time -- to prevent + // infinite recursion, we notice that `A` was already pushed + // once and stop. + let mut ty_stack = vec![(for_ty, 0)]; + + // Set used to detect infinite recursion. + let mut ty_set = FxHashSet(); + + let fulfill_cx = &mut FulfillmentContext::new(); + + let cause = ObligationCause::dummy(); + while let Some((ty, depth)) = ty_stack.pop() { + let DtorckConstraint { + dtorck_types, + outlives, + overflows, + } = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?; + + // "outlives" represent types/regions that may be touched + // by a destructor. + result.kinds.extend(outlives); + result.overflows.extend(overflows); + + // dtorck types are "types that will get dropped but which + // do not themselves define a destructor", more or less. We have + // to push them onto the stack to be expanded. + for ty in dtorck_types { + match infcx.at(&cause, param_env).normalize(&ty) { + Ok(Normalized { + value: ty, + obligations, + }) => { + fulfill_cx.register_predicate_obligations(infcx, obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + + match ty.sty { + // All parameters live for the duration of the + // function. + ty::Param(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::Projection(..) | ty::Opaque(..) => { + result.kinds.push(ty.into()); + } - _ => { - if ty_set.insert(ty) { - ty_stack.push((ty, depth + 1)); + _ => { + if ty_set.insert(ty) { + ty_stack.push((ty, depth + 1)); + } } } } - } - // We don't actually expect to fail to normalize. - // That implies a WF error somewhere else. - Err(NoSolution) => { - return Err(NoSolution); + // We don't actually expect to fail to normalize. + // That implies a WF error somewhere else. + Err(NoSolution) => { + return Err(NoSolution); + } } } } - } - debug!("dropck_outlives: result = {:#?}", result); + debug!("dropck_outlives: result = {:#?}", result); - infcx.make_canonicalized_query_result(canonical_inference_vars, result, fulfill_cx) - }) + infcx.make_canonicalized_query_response(canonical_inference_vars, result, fulfill_cx) + }, + ) } /// Return a set of constraints that needs to be satisfied in @@ -195,8 +196,7 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety) } - ty::Tuple(tys) => tys - .iter() + ty::Tuple(tys) => tys.iter() .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) .collect(), @@ -308,8 +308,7 @@ crate fn adt_dtorck_constraint<'a, 'tcx>( return Ok(result); } - let mut result = def - .all_fields() + let mut result = def.all_fields() .map(|field| tcx.type_of(field.did)) .map(|fty| dtorck_constraint_for_ty(tcx, span, fty, 0, fty)) .collect::>()?; diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs index b5ee346569a69..15ef1106311b3 100644 --- a/src/librustc_traits/evaluate_obligation.rs +++ b/src/librustc_traits/evaluate_obligation.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::traits::{EvaluationResult, Obligation, ObligationCause, - OverflowError, SelectionContext, TraitQueryMode}; use rustc::traits::query::CanonicalPredicateGoal; +use rustc::traits::{ + EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, +}; use rustc::ty::query::Providers; use rustc::ty::{ParamEnvAnd, TyCtxt}; use syntax::source_map::DUMMY_SP; @@ -24,20 +25,21 @@ crate fn provide(p: &mut Providers) { fn evaluate_obligation<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, - goal: CanonicalPredicateGoal<'tcx>, + canonical_goal: CanonicalPredicateGoal<'tcx>, ) -> Result { - tcx.infer_ctxt().enter(|ref infcx| { - let ( - ParamEnvAnd { + tcx.infer_ctxt().enter_with_canonical( + DUMMY_SP, + &canonical_goal, + |ref infcx, goal, _canonical_inference_vars| { + let ParamEnvAnd { param_env, value: predicate, - }, - _canonical_inference_vars, - ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal); + } = goal; - let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); - let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); + let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); + let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); - selcx.evaluate_obligation_recursively(&obligation) - }) + selcx.evaluate_obligation_recursively(&obligation) + }, + ) } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 7b31518c07b18..ad0a54e392f58 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -37,7 +37,7 @@ fn implied_outlives_bounds<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, goal: CanonicalTyGoal<'tcx>, ) -> Result< - Lrc>>>>, + Lrc>>>>, NoSolution, > { tcx.infer_ctxt() diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index 1c0f677fbf3cb..637a50728f39c 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::infer::canonical::{Canonical, QueryResult}; +use rustc::infer::canonical::{Canonical, QueryResponse}; use rustc::traits::query::{normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution}; use rustc::traits::{self, ObligationCause, SelectionContext, TraitEngineExt}; use rustc::ty::query::Providers; @@ -28,7 +28,7 @@ crate fn provide(p: &mut Providers) { fn normalize_projection_ty<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, goal: CanonicalProjectionGoal<'tcx>, -) -> Result>>>, NoSolution> { +) -> Result>>>, NoSolution> { debug!("normalize_provider(goal={:#?})", goal); tcx.sess diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 8fe4290528e74..a857cdbda45ae 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::infer::canonical::{Canonical, QueryResult}; +use rustc::infer::canonical::{Canonical, QueryResponse}; use rustc::infer::InferCtxt; use rustc::traits::query::type_op::eq::Eq; use rustc::traits::query::type_op::normalize::Normalize; @@ -38,7 +38,7 @@ crate fn provide(p: &mut Providers) { fn type_op_eq<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, -) -> Result>>, NoSolution> { +) -> Result>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { let (param_env, Eq { a, b }) = key.into_parts(); @@ -68,7 +68,7 @@ where fn type_op_normalize_ty( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>>, -) -> Result>>>, NoSolution> { +) -> Result>>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, type_op_normalize) } @@ -76,7 +76,7 @@ fn type_op_normalize_ty( fn type_op_normalize_predicate( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>>, -) -> Result>>>, NoSolution> { +) -> Result>>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, type_op_normalize) } @@ -84,7 +84,7 @@ fn type_op_normalize_predicate( fn type_op_normalize_fn_sig( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>>, -) -> Result>>>, NoSolution> { +) -> Result>>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, type_op_normalize) } @@ -92,7 +92,7 @@ fn type_op_normalize_fn_sig( fn type_op_normalize_poly_fn_sig( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>>, -) -> Result>>>, NoSolution> { +) -> Result>>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, type_op_normalize) } @@ -100,7 +100,7 @@ fn type_op_normalize_poly_fn_sig( fn type_op_subtype<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>, -) -> Result>>, NoSolution> { +) -> Result>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { let (param_env, Subtype { sub, sup }) = key.into_parts(); @@ -114,7 +114,7 @@ fn type_op_subtype<'tcx>( fn type_op_prove_predicate<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, -) -> Result>>, NoSolution> { +) -> Result>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { let (param_env, ProvePredicate { predicate }) = key.into_parts();