// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. // Type decoding // tjc note: Would be great to have a `match check` macro equivalent // for some of these #![allow(non_camel_case_types)] use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use middle::region; use rustc::ty::subst; use rustc::ty::subst::VecPerParamSpace; use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rbml; use rbml::leb128; use std::str; use syntax::abi; use syntax::ast; use syntax::parse::token; // Compact string representation for Ty values. API TyStr & // parse_from_str. Extra parameters are for converting to/from def_ids in the // data buffer. Whatever format you choose should not contain pipe characters. pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId; pub struct TyDecoder<'a, 'tcx: 'a> { data: &'a [u8], krate: ast::CrateNum, pos: usize, tcx: TyCtxt<'a, 'tcx, 'tcx>, conv_def_id: DefIdConvert<'a>, } impl<'a,'tcx> TyDecoder<'a,'tcx> { pub fn with_doc(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: ast::CrateNum, doc: rbml::Doc<'a>, conv: DefIdConvert<'a>) -> TyDecoder<'a,'tcx> { TyDecoder::new(doc.data, crate_num, doc.start, tcx, conv) } pub fn new(data: &'a [u8], crate_num: ast::CrateNum, pos: usize, tcx: TyCtxt<'a, 'tcx, 'tcx>, conv: DefIdConvert<'a>) -> TyDecoder<'a, 'tcx> { TyDecoder { data: data, krate: crate_num, pos: pos, tcx: tcx, conv_def_id: conv, } } pub fn position(&self) -> usize { self.pos } fn peek(&self) -> char { self.data[self.pos] as char } fn next(&mut self) -> char { let ch = self.data[self.pos] as char; self.pos = self.pos + 1; return ch; } fn next_byte(&mut self) -> u8 { let b = self.data[self.pos]; self.pos = self.pos + 1; return b; } fn scan(&mut self, mut is_last: F) -> &'a [u8] where F: FnMut(char) -> bool, { let start_pos = self.pos; debug!("scan: '{}' (start)", self.data[self.pos] as char); while !is_last(self.data[self.pos] as char) { self.pos += 1; debug!("scan: '{}'", self.data[self.pos] as char); } let end_pos = self.pos; self.pos += 1; return &self.data[start_pos..end_pos]; } fn parse_vuint(&mut self) -> usize { let (value, bytes_read) = leb128::read_unsigned_leb128(self.data, self.pos); self.pos += bytes_read; value as usize } fn parse_name(&mut self, last: char) -> ast::Name { fn is_last(b: char, c: char) -> bool { return c == b; } let bytes = self.scan(|a| is_last(last, a)); token::intern(str::from_utf8(bytes).unwrap()) } fn parse_size(&mut self) -> Option { assert_eq!(self.next(), '/'); if self.peek() == '|' { assert_eq!(self.next(), '|'); None } else { let n = self.parse_uint(); assert_eq!(self.next(), '|'); Some(n) } } fn parse_vec_per_param_space(&mut self, mut f: F) -> VecPerParamSpace where F: FnMut(&mut TyDecoder<'a, 'tcx>) -> T, { let mut r = VecPerParamSpace::empty(); for &space in &subst::ParamSpace::all() { assert_eq!(self.next(), '['); while self.peek() != ']' { r.push(space, f(self)); } assert_eq!(self.next(), ']'); } r } pub fn parse_substs(&mut self) -> subst::Substs<'tcx> { let regions = self.parse_vec_per_param_space(|this| this.parse_region()); let types = self.parse_vec_per_param_space(|this| this.parse_ty()); subst::Substs { types: types, regions: regions } } fn parse_bound_region(&mut self) -> ty::BoundRegion { match self.next() { 'a' => { let id = self.parse_u32(); assert_eq!(self.next(), '|'); ty::BrAnon(id) } '[' => { let def = self.parse_def(); let name = token::intern(&self.parse_str(']')); ty::BrNamed(def, name) } 'f' => { let id = self.parse_u32(); assert_eq!(self.next(), '|'); ty::BrFresh(id) } 'e' => ty::BrEnv, _ => bug!("parse_bound_region: bad input") } } pub fn parse_region(&mut self) -> ty::Region { match self.next() { 'b' => { assert_eq!(self.next(), '['); let id = ty::DebruijnIndex::new(self.parse_u32()); assert_eq!(self.next(), '|'); let br = self.parse_bound_region(); assert_eq!(self.next(), ']'); ty::ReLateBound(id, br) } 'B' => { assert_eq!(self.next(), '['); let space = self.parse_param_space(); assert_eq!(self.next(), '|'); let index = self.parse_u32(); assert_eq!(self.next(), '|'); let name = token::intern(&self.parse_str(']')); ty::ReEarlyBound(ty::EarlyBoundRegion { space: space, index: index, name: name }) } 'f' => { assert_eq!(self.next(), '['); let scope = self.parse_scope(); assert_eq!(self.next(), '|'); let br = self.parse_bound_region(); assert_eq!(self.next(), ']'); ty::ReFree(ty::FreeRegion { scope: scope, bound_region: br}) } 's' => { let scope = self.parse_scope(); assert_eq!(self.next(), '|'); ty::ReScope(scope) } 't' => { ty::ReStatic } 'e' => { ty::ReStatic } _ => bug!("parse_region: bad input") } } fn parse_scope(&mut self) -> region::CodeExtent { self.tcx.region_maps.bogus_code_extent(match self.next() { // This creates scopes with the wrong NodeId. This isn't // actually a problem because scopes only exist *within* // functions, and functions aren't loaded until trans which // doesn't care about regions. // // May still be worth fixing though. 'C' => { assert_eq!(self.next(), '['); let fn_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), '|'); let body_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), ']'); region::CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id } } // This creates scopes with the wrong NodeId. (See note above.) 'P' => { assert_eq!(self.next(), '['); let fn_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), '|'); let body_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), ']'); region::CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id } } 'M' => { let node_id = self.parse_uint() as ast::NodeId; region::CodeExtentData::Misc(node_id) } 'D' => { let node_id = self.parse_uint() as ast::NodeId; region::CodeExtentData::DestructionScope(node_id) } 'B' => { assert_eq!(self.next(), '['); let node_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), '|'); let first_stmt_index = self.parse_u32(); assert_eq!(self.next(), ']'); let block_remainder = region::BlockRemainder { block: node_id, first_statement_index: first_stmt_index, }; region::CodeExtentData::Remainder(block_remainder) } _ => bug!("parse_scope: bad input") }) } fn parse_opt(&mut self, f: F) -> Option where F: FnOnce(&mut TyDecoder<'a, 'tcx>) -> T, { match self.next() { 'n' => None, 's' => Some(f(self)), _ => bug!("parse_opt: bad input") } } fn parse_str(&mut self, term: char) -> String { let mut result = String::new(); while self.peek() != term { unsafe { result.as_mut_vec().extend_from_slice(&[self.next_byte()]) } } self.next(); result } pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> { let def = self.parse_def(); let substs = self.tcx.mk_substs(self.parse_substs()); ty::TraitRef {def_id: def, substs: substs} } pub fn parse_ty(&mut self) -> Ty<'tcx> { let tcx = self.tcx; match self.next() { 'b' => return tcx.types.bool, 'i' => { /* eat the s of is */ self.next(); return tcx.types.isize }, 'u' => { /* eat the s of us */ self.next(); return tcx.types.usize }, 'M' => { match self.next() { 'b' => return tcx.types.u8, 'w' => return tcx.types.u16, 'l' => return tcx.types.u32, 'd' => return tcx.types.u64, 'B' => return tcx.types.i8, 'W' => return tcx.types.i16, 'L' => return tcx.types.i32, 'D' => return tcx.types.i64, 'f' => return tcx.types.f32, 'F' => return tcx.types.f64, _ => bug!("parse_ty: bad numeric type") } } 'c' => return tcx.types.char, 't' => { assert_eq!(self.next(), '['); let did = self.parse_def(); let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); return tcx.mk_enum(def, self.tcx.mk_substs(substs)); } 'x' => { assert_eq!(self.next(), '['); let trait_ref = ty::Binder(self.parse_trait_ref()); let bounds = self.parse_existential_bounds(); assert_eq!(self.next(), ']'); return tcx.mk_trait(trait_ref, bounds); } 'p' => { assert_eq!(self.next(), '['); let index = self.parse_u32(); assert_eq!(self.next(), '|'); let space = self.parse_param_space(); assert_eq!(self.next(), '|'); let name = token::intern(&self.parse_str(']')); return tcx.mk_param(space, index, name); } '~' => return tcx.mk_box(self.parse_ty()), '*' => return tcx.mk_ptr(self.parse_mt()), '&' => { let r = self.parse_region(); let mt = self.parse_mt(); return tcx.mk_ref(tcx.mk_region(r), mt); } 'V' => { let t = self.parse_ty(); return match self.parse_size() { Some(n) => tcx.mk_array(t, n), None => tcx.mk_slice(t) }; } 'v' => { return tcx.mk_str(); } 'T' => { assert_eq!(self.next(), '['); let mut params = Vec::new(); while self.peek() != ']' { params.push(self.parse_ty()); } self.pos = self.pos + 1; return tcx.mk_tup(params); } 'F' => { let def_id = self.parse_def(); let substs = self.tcx.mk_substs(self.parse_substs()); return tcx.mk_fn_def(def_id, substs, self.parse_bare_fn_ty()); } 'G' => { return tcx.mk_fn_ptr(self.parse_bare_fn_ty()); } '#' => { // This is a hacky little caching scheme. The idea is that if we encode // the same type twice, the second (and third, and fourth...) time we will // just write `#123`, where `123` is the offset in the metadata of the // first appearance. Now when we are *decoding*, if we see a `#123`, we // can first check a cache (`tcx.rcache`) for that offset. If we find something, // we return it (modulo closure types, see below). But if not, then we // jump to offset 123 and read the type from there. let pos = self.parse_vuint(); let key = ty::CReaderCacheKey { cnum: self.krate, pos: pos }; match tcx.rcache.borrow().get(&key).cloned() { Some(tt) => { // If there is a closure buried in the type some where, then we // need to re-convert any def ids (see case 'k', below). That means // we can't reuse the cached version. if !tt.has_closure_types() { return tt; } } None => {} } let mut substate = TyDecoder::new(self.data, self.krate, pos, self.tcx, self.conv_def_id); let tt = substate.parse_ty(); tcx.rcache.borrow_mut().insert(key, tt); return tt; } '\"' => { let _ = self.parse_def(); let inner = self.parse_ty(); inner } 'a' => { assert_eq!(self.next(), '['); let did = self.parse_def(); let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); return self.tcx.mk_struct(def, self.tcx.mk_substs(substs)); } 'k' => { assert_eq!(self.next(), '['); let did = self.parse_def(); let substs = self.parse_substs(); let mut tys = vec![]; while self.peek() != '.' { tys.push(self.parse_ty()); } assert_eq!(self.next(), '.'); assert_eq!(self.next(), ']'); return self.tcx.mk_closure(did, self.tcx.mk_substs(substs), tys); } 'P' => { assert_eq!(self.next(), '['); let trait_ref = self.parse_trait_ref(); let name = token::intern(&self.parse_str(']')); return tcx.mk_projection(trait_ref, name); } 'e' => { return tcx.types.err; } c => { bug!("unexpected char in type string: {}", c);} } } fn parse_mutability(&mut self) -> hir::Mutability { match self.peek() { 'm' => { self.next(); hir::MutMutable } _ => { hir::MutImmutable } } } fn parse_mt(&mut self) -> ty::TypeAndMut<'tcx> { let m = self.parse_mutability(); ty::TypeAndMut { ty: self.parse_ty(), mutbl: m } } fn parse_def(&mut self) -> DefId { let def_id = parse_defid(self.scan(|c| c == '|')); return (self.conv_def_id)(def_id); } fn parse_uint(&mut self) -> usize { let mut n = 0; loop { let cur = self.peek(); if cur < '0' || cur > '9' { return n; } self.pos = self.pos + 1; n *= 10; n += (cur as usize) - ('0' as usize); }; } fn parse_u32(&mut self) -> u32 { let n = self.parse_uint(); let m = n as u32; assert_eq!(m as usize, n); m } fn parse_param_space(&mut self) -> subst::ParamSpace { subst::ParamSpace::from_uint(self.parse_uint()) } fn parse_abi_set(&mut self) -> abi::Abi { assert_eq!(self.next(), '['); let bytes = self.scan(|c| c == ']'); let abi_str = str::from_utf8(bytes).unwrap(); abi::lookup(&abi_str[..]).expect(abi_str) } pub fn parse_closure_ty(&mut self) -> ty::ClosureTy<'tcx> { let unsafety = parse_unsafety(self.next()); let sig = self.parse_sig(); let abi = self.parse_abi_set(); ty::ClosureTy { unsafety: unsafety, sig: sig, abi: abi, } } pub fn parse_bare_fn_ty(&mut self) -> &'tcx ty::BareFnTy<'tcx> { let unsafety = parse_unsafety(self.next()); let abi = self.parse_abi_set(); let sig = self.parse_sig(); self.tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig }) } fn parse_sig(&mut self) -> ty::PolyFnSig<'tcx> { assert_eq!(self.next(), '['); let mut inputs = Vec::new(); while self.peek() != ']' { inputs.push(self.parse_ty()); } self.pos += 1; // eat the ']' let variadic = match self.next() { 'V' => true, 'N' => false, r => bug!("bad variadic: {}", r), }; let output = match self.peek() { 'z' => { self.pos += 1; ty::FnDiverging } _ => ty::FnConverging(self.parse_ty()) }; ty::Binder(ty::FnSig {inputs: inputs, output: output, variadic: variadic}) } pub fn parse_predicate(&mut self) -> ty::Predicate<'tcx> { match self.next() { 't' => ty::Binder(self.parse_trait_ref()).to_predicate(), 'e' => ty::Binder(ty::EquatePredicate(self.parse_ty(), self.parse_ty())).to_predicate(), 'r' => ty::Binder(ty::OutlivesPredicate(self.parse_region(), self.parse_region())).to_predicate(), 'o' => ty::Binder(ty::OutlivesPredicate(self.parse_ty(), self.parse_region())).to_predicate(), 'p' => ty::Binder(self.parse_projection_predicate()).to_predicate(), 'w' => ty::Predicate::WellFormed(self.parse_ty()), 'O' => { let def_id = self.parse_def(); assert_eq!(self.next(), '|'); ty::Predicate::ObjectSafe(def_id) } 'c' => { let def_id = self.parse_def(); assert_eq!(self.next(), '|'); let kind = match self.next() { 'f' => ty::ClosureKind::Fn, 'm' => ty::ClosureKind::FnMut, 'o' => ty::ClosureKind::FnOnce, c => bug!("Encountered invalid character in metadata: {}", c) }; assert_eq!(self.next(), '|'); ty::Predicate::ClosureKind(def_id, kind) } c => bug!("Encountered invalid character in metadata: {}", c) } } fn parse_projection_predicate(&mut self) -> ty::ProjectionPredicate<'tcx> { ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { trait_ref: self.parse_trait_ref(), item_name: token::intern(&self.parse_str('|')), }, ty: self.parse_ty(), } } pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { let name = self.parse_name(':'); let def_id = self.parse_def(); let space = self.parse_param_space(); assert_eq!(self.next(), '|'); let index = self.parse_u32(); assert_eq!(self.next(), '|'); let default_def_id = self.parse_def(); let default = self.parse_opt(|this| this.parse_ty()); let object_lifetime_default = self.parse_object_lifetime_default(); ty::TypeParameterDef { name: name, def_id: def_id, space: space, index: index, default_def_id: default_def_id, default: default, object_lifetime_default: object_lifetime_default, } } pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { let name = self.parse_name(':'); let def_id = self.parse_def(); let space = self.parse_param_space(); assert_eq!(self.next(), '|'); let index = self.parse_u32(); assert_eq!(self.next(), '|'); let mut bounds = vec![]; loop { match self.next() { 'R' => bounds.push(self.parse_region()), '.' => { break; } c => { bug!("parse_region_param_def: bad bounds ('{}')", c) } } } ty::RegionParameterDef { name: name, def_id: def_id, space: space, index: index, bounds: bounds } } fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault { match self.next() { 'a' => ty::ObjectLifetimeDefault::Ambiguous, 'b' => ty::ObjectLifetimeDefault::BaseDefault, 's' => { let region = self.parse_region(); ty::ObjectLifetimeDefault::Specific(region) } _ => bug!("parse_object_lifetime_default: bad input") } } pub fn parse_existential_bounds(&mut self) -> ty::ExistentialBounds<'tcx> { let builtin_bounds = self.parse_builtin_bounds(); let region_bound = self.parse_region(); let mut projection_bounds = Vec::new(); loop { match self.next() { 'P' => { projection_bounds.push(ty::Binder(self.parse_projection_predicate())); } '.' => { break; } c => { bug!("parse_bounds: bad bounds ('{}')", c) } } } ty::ExistentialBounds::new( region_bound, builtin_bounds, projection_bounds) } fn parse_builtin_bounds(&mut self) -> ty::BuiltinBounds { let mut builtin_bounds = ty::BuiltinBounds::empty(); loop { match self.next() { 'S' => { builtin_bounds.insert(ty::BoundSend); } 'Z' => { builtin_bounds.insert(ty::BoundSized); } 'P' => { builtin_bounds.insert(ty::BoundCopy); } 'T' => { builtin_bounds.insert(ty::BoundSync); } '.' => { return builtin_bounds; } c => { bug!("parse_bounds: bad builtin bounds ('{}')", c) } } } } } // Rust metadata parsing fn parse_defid(buf: &[u8]) -> DefId { let mut colon_idx = 0; let len = buf.len(); while colon_idx < len && buf[colon_idx] != ':' as u8 { colon_idx += 1; } if colon_idx == len { error!("didn't find ':' when parsing def id"); bug!(); } let crate_part = &buf[0..colon_idx]; let def_part = &buf[colon_idx + 1..len]; let crate_num = match str::from_utf8(crate_part).ok().and_then(|s| { s.parse::().ok() }) { Some(cn) => cn as ast::CrateNum, None => bug!("internal error: parse_defid: crate number expected, found {:?}", crate_part) }; let def_num = match str::from_utf8(def_part).ok().and_then(|s| { s.parse::().ok() }) { Some(dn) => dn, None => bug!("internal error: parse_defid: id expected, found {:?}", def_part) }; let index = DefIndex::new(def_num); DefId { krate: crate_num, index: index } } fn parse_unsafety(c: char) -> hir::Unsafety { match c { 'u' => hir::Unsafety::Unsafe, 'n' => hir::Unsafety::Normal, _ => bug!("parse_unsafety: bad unsafety {}", c) } }