1 // This module contains some shared code for encoding and decoding various
2 // things from the `ty` module, and in particular implements support for
3 // "shorthands" which allow to have pointers back into the already encoded
4 // stream instead of re-encoding the same thing twice.
6 // The functionality in here is shared between persisting to crate metadata and
7 // persisting to incr. comp. caches.
9 use crate::arena
::ArenaAllocatable
;
10 use crate::infer
::canonical
::{CanonicalVarInfo, CanonicalVarInfos}
;
11 use crate::mir
::{self, interpret::Allocation}
;
12 use crate::ty
::subst
::SubstsRef
;
13 use crate::ty
::{self, List, Ty, TyCtxt}
;
14 use rustc_data_structures
::fx
::FxHashMap
;
15 use rustc_hir
::def_id
::{CrateNum, DefId}
;
16 use rustc_serialize
::{opaque, Decodable, Decoder, Encodable, Encoder}
;
21 /// The shorthand encoding uses an enum's variant index `usize`
22 /// and is offset by this value so it never matches a real variant.
23 /// This offset is also chosen so that the first byte is never < 0x80.
24 pub const SHORTHAND_OFFSET
: usize = 0x80;
26 pub trait EncodableWithShorthand
: Clone
+ Eq
+ Hash
{
27 type Variant
: Encodable
;
28 fn variant(&self) -> &Self::Variant
;
31 #[allow(rustc::usage_of_ty_tykind)]
32 impl<'tcx
> EncodableWithShorthand
for Ty
<'tcx
> {
33 type Variant
= ty
::TyKind
<'tcx
>;
34 fn variant(&self) -> &Self::Variant
{
39 impl<'tcx
> EncodableWithShorthand
for ty
::Predicate
<'tcx
> {
40 type Variant
= ty
::Predicate
<'tcx
>;
41 fn variant(&self) -> &Self::Variant
{
46 pub trait TyEncoder
: Encoder
{
47 fn position(&self) -> usize;
50 impl TyEncoder
for opaque
::Encoder
{
52 fn position(&self) -> usize {
57 /// Encode the given value or a previously cached shorthand.
58 pub fn encode_with_shorthand
<E
, T
, M
>(encoder
: &mut E
, value
: &T
, cache
: M
) -> Result
<(), E
::Error
>
61 M
: for<'b
> Fn(&'b
mut E
) -> &'b
mut FxHashMap
<T
, usize>,
62 T
: EncodableWithShorthand
,
64 let existing_shorthand
= cache(encoder
).get(value
).cloned();
65 if let Some(shorthand
) = existing_shorthand
{
66 return encoder
.emit_usize(shorthand
);
69 let variant
= value
.variant();
71 let start
= encoder
.position();
72 variant
.encode(encoder
)?
;
73 let len
= encoder
.position() - start
;
75 // The shorthand encoding uses the same usize as the
76 // discriminant, with an offset so they can't conflict.
77 let discriminant
= intrinsics
::discriminant_value(variant
);
78 assert
!(discriminant
< SHORTHAND_OFFSET
as u64);
79 let shorthand
= start
+ SHORTHAND_OFFSET
;
81 // Get the number of bits that leb128 could fit
82 // in the same space as the fully encoded type.
83 let leb128_bits
= len
* 7;
85 // Check that the shorthand is a not longer than the
86 // full encoding itself, i.e., it's an obvious win.
87 if leb128_bits
>= 64 || (shorthand
as u64) < (1 << leb128_bits
) {
88 cache(encoder
).insert(value
.clone(), shorthand
);
94 pub fn encode_spanned_predicates
<'tcx
, E
, C
>(
96 predicates
: &'tcx
[(ty
::Predicate
<'tcx
>, Span
)],
98 ) -> Result
<(), E
::Error
>
101 C
: for<'b
> Fn(&'b
mut E
) -> &'b
mut FxHashMap
<ty
::Predicate
<'tcx
>, usize>,
103 predicates
.len().encode(encoder
)?
;
104 for (predicate
, span
) in predicates
{
105 encode_with_shorthand(encoder
, predicate
, &cache
)?
;
106 span
.encode(encoder
)?
;
111 pub trait TyDecoder
<'tcx
>: Decoder
{
112 fn tcx(&self) -> TyCtxt
<'tcx
>;
114 fn peek_byte(&self) -> u8;
116 fn position(&self) -> usize;
118 fn cached_ty_for_shorthand
<F
>(
122 ) -> Result
<Ty
<'tcx
>, Self::Error
>
124 F
: FnOnce(&mut Self) -> Result
<Ty
<'tcx
>, Self::Error
>;
126 fn with_position
<F
, R
>(&mut self, pos
: usize, f
: F
) -> R
128 F
: FnOnce(&mut Self) -> R
;
130 fn map_encoded_cnum_to_current(&self, cnum
: CrateNum
) -> CrateNum
;
132 fn positioned_at_shorthand(&self) -> bool
{
133 (self.peek_byte() & (SHORTHAND_OFFSET
as u8)) != 0
138 pub fn decode_arena_allocable
<D
, T
: ArenaAllocatable
+ Decodable
>(
140 ) -> Result
<&'tcx T
, D
::Error
>
144 Ok(decoder
.tcx().arena
.alloc(Decodable
::decode(decoder
)?
))
148 pub fn decode_arena_allocable_slice
<D
, T
: ArenaAllocatable
+ Decodable
>(
150 ) -> Result
<&'tcx
[T
], D
::Error
>
154 Ok(decoder
.tcx().arena
.alloc_from_iter(<Vec
<T
> as Decodable
>::decode(decoder
)?
))
158 pub fn decode_cnum
<D
>(decoder
: &mut D
) -> Result
<CrateNum
, D
::Error
>
162 let cnum
= CrateNum
::from_u32(u32::decode(decoder
)?
);
163 Ok(decoder
.map_encoded_cnum_to_current(cnum
))
166 #[allow(rustc::usage_of_ty_tykind)]
168 pub fn decode_ty
<D
>(decoder
: &mut D
) -> Result
<Ty
<'tcx
>, D
::Error
>
172 // Handle shorthands first, if we have an usize > 0x80.
173 if decoder
.positioned_at_shorthand() {
174 let pos
= decoder
.read_usize()?
;
175 assert
!(pos
>= SHORTHAND_OFFSET
);
176 let shorthand
= pos
- SHORTHAND_OFFSET
;
178 decoder
.cached_ty_for_shorthand(shorthand
, |decoder
| {
179 decoder
.with_position(shorthand
, Ty
::decode
)
182 let tcx
= decoder
.tcx();
183 Ok(tcx
.mk_ty(ty
::TyKind
::decode(decoder
)?
))
188 pub fn decode_spanned_predicates
<D
>(
190 ) -> Result
<&'tcx
[(ty
::Predicate
<'tcx
>, Span
)], D
::Error
>
194 let tcx
= decoder
.tcx();
195 Ok(tcx
.arena
.alloc_from_iter(
196 (0..decoder
.read_usize()?
)
198 // Handle shorthands first, if we have an usize > 0x80.
199 let predicate
= if decoder
.positioned_at_shorthand() {
200 let pos
= decoder
.read_usize()?
;
201 assert
!(pos
>= SHORTHAND_OFFSET
);
202 let shorthand
= pos
- SHORTHAND_OFFSET
;
204 decoder
.with_position(shorthand
, ty
::Predicate
::decode
)
206 ty
::Predicate
::decode(decoder
)
208 Ok((predicate
, Decodable
::decode(decoder
)?
))
210 .collect
::<Result
<Vec
<_
>, _
>>()?
,
215 pub fn decode_substs
<D
>(decoder
: &mut D
) -> Result
<SubstsRef
<'tcx
>, D
::Error
>
219 let len
= decoder
.read_usize()?
;
220 let tcx
= decoder
.tcx();
221 Ok(tcx
.mk_substs((0..len
).map(|_
| Decodable
::decode(decoder
)))?
)
225 pub fn decode_place
<D
>(decoder
: &mut D
) -> Result
<mir
::Place
<'tcx
>, D
::Error
>
229 let local
: mir
::Local
= Decodable
::decode(decoder
)?
;
230 let len
= decoder
.read_usize()?
;
231 let projection
: &'tcx List
<mir
::PlaceElem
<'tcx
>> =
232 decoder
.tcx().mk_place_elems((0..len
).map(|_
| Decodable
::decode(decoder
)))?
;
233 Ok(mir
::Place { local, projection }
)
237 pub fn decode_region
<D
>(decoder
: &mut D
) -> Result
<ty
::Region
<'tcx
>, D
::Error
>
241 Ok(decoder
.tcx().mk_region(Decodable
::decode(decoder
)?
))
245 pub fn decode_ty_slice
<D
>(decoder
: &mut D
) -> Result
<&'tcx ty
::List
<Ty
<'tcx
>>, D
::Error
>
249 let len
= decoder
.read_usize()?
;
250 Ok(decoder
.tcx().mk_type_list((0..len
).map(|_
| Decodable
::decode(decoder
)))?
)
254 pub fn decode_adt_def
<D
>(decoder
: &mut D
) -> Result
<&'tcx ty
::AdtDef
, D
::Error
>
258 let def_id
= DefId
::decode(decoder
)?
;
259 Ok(decoder
.tcx().adt_def(def_id
))
263 pub fn decode_existential_predicate_slice
<D
>(
265 ) -> Result
<&'tcx ty
::List
<ty
::ExistentialPredicate
<'tcx
>>, D
::Error
>
269 let len
= decoder
.read_usize()?
;
270 Ok(decoder
.tcx().mk_existential_predicates((0..len
).map(|_
| Decodable
::decode(decoder
)))?
)
274 pub fn decode_canonical_var_infos
<D
>(decoder
: &mut D
) -> Result
<CanonicalVarInfos
<'tcx
>, D
::Error
>
278 let len
= decoder
.read_usize()?
;
279 let interned
: Result
<Vec
<CanonicalVarInfo
>, _
> =
280 (0..len
).map(|_
| Decodable
::decode(decoder
)).collect();
281 Ok(decoder
.tcx().intern_canonical_var_infos(interned?
.as_slice()))
285 pub fn decode_const
<D
>(decoder
: &mut D
) -> Result
<&'tcx ty
::Const
<'tcx
>, D
::Error
>
289 Ok(decoder
.tcx().mk_const(Decodable
::decode(decoder
)?
))
293 pub fn decode_allocation
<D
>(decoder
: &mut D
) -> Result
<&'tcx Allocation
, D
::Error
>
297 Ok(decoder
.tcx().intern_const_alloc(Decodable
::decode(decoder
)?
))
301 macro_rules
! __impl_decoder_methods
{
302 ($
($name
:ident
-> $ty
:ty
;)*) => {
305 fn $
name(&mut self) -> Result
<$ty
, Self::Error
> {
313 macro_rules
! impl_arena_allocatable_decoder
{
315 ([decode $
(, $attrs
:ident
)*]
316 [[$DecoderName
:ident
[$
($typaram
:tt
),*]], [$name
:ident
: $ty
:ty
], $tcx
:lifetime
]) => {
317 impl<$
($typaram
),*> SpecializedDecoder
<&$tcx $ty
> for $DecoderName
<$
($typaram
),*> {
319 fn specialized_decode(&mut self) -> Result
<&$tcx $ty
, Self::Error
> {
320 decode_arena_allocable(self)
324 impl<$
($typaram
),*> SpecializedDecoder
<&$tcx
[$ty
]> for $DecoderName
<$
($typaram
),*> {
326 fn specialized_decode(&mut self) -> Result
<&$tcx
[$ty
], Self::Error
> {
327 decode_arena_allocable_slice(self)
331 ([$ignore
:ident $
(, $attrs
:ident
)*]$args
:tt
) => {
332 impl_arena_allocatable_decoder
!([$
($attrs
),*]$args
);
337 macro_rules
! impl_arena_allocatable_decoders
{
338 ($args
:tt
, [$
($a
:tt $name
:ident
: $ty
:ty
,)*], $tcx
:lifetime
) => {
340 impl_arena_allocatable_decoder
!($a
[$args
, [$name
: $ty
], $tcx
]);
346 macro_rules
! implement_ty_decoder
{
347 ($DecoderName
:ident
<$
($typaram
:tt
),*>) => {
348 mod __ty_decoder_impl
{
349 use std
::borrow
::Cow
;
351 use rustc_serialize
::{Decoder, SpecializedDecoder}
;
353 use $
crate::infer
::canonical
::CanonicalVarInfos
;
355 use $
crate::ty
::codec
::*;
356 use $
crate::ty
::subst
::SubstsRef
;
357 use rustc_hir
::def_id
::{CrateNum}
;
359 use rustc_span
::Span
;
361 use super::$DecoderName
;
363 impl<$
($typaram
),*> Decoder
for $DecoderName
<$
($typaram
),*> {
366 __impl_decoder_methods
! {
387 read_str
-> Cow
<'_
, str>;
390 fn error(&mut self, err
: &str) -> Self::Error
{
391 self.opaque
.error(err
)
395 // FIXME(#36588): These impls are horribly unsound as they allow
396 // the caller to pick any lifetime for `'tcx`, including `'static`,
397 // by using the unspecialized proxies to them.
399 rustc_hir
::arena_types
!(impl_arena_allocatable_decoders
, [$DecoderName
[$
($typaram
),*]], 'tcx
);
400 arena_types
!(impl_arena_allocatable_decoders
, [$DecoderName
[$
($typaram
),*]], 'tcx
);
402 impl<$
($typaram
),*> SpecializedDecoder
<CrateNum
>
403 for $DecoderName
<$
($typaram
),*> {
404 fn specialized_decode(&mut self) -> Result
<CrateNum
, Self::Error
> {
409 impl<$
($typaram
),*> SpecializedDecoder
<ty
::Ty
<'tcx
>>
410 for $DecoderName
<$
($typaram
),*> {
411 fn specialized_decode(&mut self) -> Result
<ty
::Ty
<'tcx
>, Self::Error
> {
416 impl<$
($typaram
),*> SpecializedDecoder
<&'tcx
[(ty
::Predicate
<'tcx
>, Span
)]>
417 for $DecoderName
<$
($typaram
),*> {
418 fn specialized_decode(&mut self)
419 -> Result
<&'tcx
[(ty
::Predicate
<'tcx
>, Span
)], Self::Error
> {
420 decode_spanned_predicates(self)
424 impl<$
($typaram
),*> SpecializedDecoder
<SubstsRef
<'tcx
>>
425 for $DecoderName
<$
($typaram
),*> {
426 fn specialized_decode(&mut self) -> Result
<SubstsRef
<'tcx
>, Self::Error
> {
431 impl<$
($typaram
),*> SpecializedDecoder
<$
crate::mir
::Place
<'tcx
>>
432 for $DecoderName
<$
($typaram
),*> {
433 fn specialized_decode(
435 ) -> Result
<$
crate::mir
::Place
<'tcx
>, Self::Error
> {
440 impl<$
($typaram
),*> SpecializedDecoder
<ty
::Region
<'tcx
>>
441 for $DecoderName
<$
($typaram
),*> {
442 fn specialized_decode(&mut self) -> Result
<ty
::Region
<'tcx
>, Self::Error
> {
447 impl<$
($typaram
),*> SpecializedDecoder
<&'tcx ty
::List
<ty
::Ty
<'tcx
>>>
448 for $DecoderName
<$
($typaram
),*> {
449 fn specialized_decode(&mut self)
450 -> Result
<&'tcx ty
::List
<ty
::Ty
<'tcx
>>, Self::Error
> {
451 decode_ty_slice(self)
455 impl<$
($typaram
),*> SpecializedDecoder
<&'tcx ty
::AdtDef
>
456 for $DecoderName
<$
($typaram
),*> {
457 fn specialized_decode(&mut self) -> Result
<&'tcx ty
::AdtDef
, Self::Error
> {
462 impl<$
($typaram
),*> SpecializedDecoder
<&'tcx ty
::List
<ty
::ExistentialPredicate
<'tcx
>>>
463 for $DecoderName
<$
($typaram
),*> {
464 fn specialized_decode(&mut self)
465 -> Result
<&'tcx ty
::List
<ty
::ExistentialPredicate
<'tcx
>>, Self::Error
> {
466 decode_existential_predicate_slice(self)
470 impl<$
($typaram
),*> SpecializedDecoder
<CanonicalVarInfos
<'tcx
>>
471 for $DecoderName
<$
($typaram
),*> {
472 fn specialized_decode(&mut self)
473 -> Result
<CanonicalVarInfos
<'tcx
>, Self::Error
> {
474 decode_canonical_var_infos(self)
478 impl<$
($typaram
),*> SpecializedDecoder
<&'tcx $
crate::ty
::Const
<'tcx
>>
479 for $DecoderName
<$
($typaram
),*> {
480 fn specialized_decode(&mut self) -> Result
<&'tcx ty
::Const
<'tcx
>, Self::Error
> {
485 impl<$
($typaram
),*> SpecializedDecoder
<&'tcx $
crate::mir
::interpret
::Allocation
>
486 for $DecoderName
<$
($typaram
),*> {
487 fn specialized_decode(
489 ) -> Result
<&'tcx $
crate::mir
::interpret
::Allocation
, Self::Error
> {
490 decode_allocation(self)