Skip to content

Commit 75d5e2f

Browse files
committed
Move the TypeContents-based "Sized" queries into trans, where the full
types are always known and hence the ParameterEnvironment is not necessary. For other `Sized` queries, use the trait infrastructure just like `Copy`.
1 parent 82c9966 commit 75d5e2f

File tree

13 files changed

+207
-119
lines changed

13 files changed

+207
-119
lines changed

src/librustc/middle/check_rvalues.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub fn check_crate(tcx: &ty::ctxt,
2828
}
2929

3030
struct RvalueContext<'a, 'tcx: 'a> {
31-
tcx: &'a ty::ctxt<'tcx>
31+
tcx: &'a ty::ctxt<'tcx>,
3232
}
3333

3434
impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
@@ -40,21 +40,27 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
4040
fn_id: ast::NodeId) {
4141
{
4242
let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
43-
let mut euv = euv::ExprUseVisitor::new(self, self.tcx, &param_env);
43+
let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: &param_env };
44+
let mut euv = euv::ExprUseVisitor::new(&mut delegate, self.tcx, &param_env);
4445
euv.walk_fn(fd, b);
4546
}
4647
visit::walk_fn(self, fk, fd, b, s)
4748
}
4849
}
4950

50-
impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContext<'a, 'tcx> {
51+
struct RvalueContextDelegate<'a, 'tcx: 'a> {
52+
tcx: &'a ty::ctxt<'tcx>,
53+
param_env: &'a ty::ParameterEnvironment<'tcx>,
54+
}
55+
56+
impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
5157
fn consume(&mut self,
5258
_: ast::NodeId,
5359
span: Span,
5460
cmt: mc::cmt<'tcx>,
5561
_: euv::ConsumeMode) {
5662
debug!("consume; cmt: {}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
57-
if !ty::type_is_sized(self.tcx, cmt.ty) {
63+
if !ty::type_is_sized(self.tcx, cmt.ty, self.param_env) {
5864
span_err!(self.tcx.sess, span, E0161,
5965
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
6066
ty_to_string(self.tcx, cmt.ty));

src/librustc/middle/traits/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::rc::Rc;
2222
use std::slice::Iter;
2323
use syntax::ast;
2424
use syntax::codemap::{Span, DUMMY_SP};
25+
use util::ppaux::Repr;
2526

2627
pub use self::fulfill::{FulfillmentContext, RegionObligation};
2728
pub use self::select::SelectionContext;
@@ -259,6 +260,43 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
259260
util::predicates_for_generics(tcx, cause, 0, generic_bounds)
260261
}
261262

263+
/// Determines whether the type `ty` is known to meet `bound` and
264+
/// returns true if so. Returns false if `ty` either does not meet
265+
/// `bound` or is not known to meet bound (note that this is
266+
/// conservative towards *no impl*, which is the opposite of the
267+
/// `evaluate` methods).
268+
pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
269+
param_env: &ty::ParameterEnvironment<'tcx>,
270+
ty: Ty<'tcx>,
271+
bound: ty::BuiltinBound)
272+
-> bool
273+
{
274+
debug!("type_known_to_meet_builtin_bound(ty={}, bound={})",
275+
ty.repr(infcx.tcx),
276+
bound);
277+
278+
let mut fulfill_cx = FulfillmentContext::new();
279+
280+
// We can use dummy values here because we won't report any errors
281+
// that result nor will we pay any mind to region obligations that arise
282+
// (there shouldn't really be any anyhow).
283+
let cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
284+
285+
fulfill_cx.register_builtin_bound(infcx.tcx, ty, bound, cause);
286+
287+
// Note: we only assume something is `Copy` if we can
288+
// *definitively* show that it implements `Copy`. Otherwise,
289+
// assume it is move; linear is always ok.
290+
let result = fulfill_cx.select_all_or_error(infcx, param_env, infcx.tcx).is_ok();
291+
292+
debug!("type_known_to_meet_builtin_bound: ty={} bound={} result={}",
293+
ty.repr(infcx.tcx),
294+
bound,
295+
result);
296+
297+
result
298+
}
299+
262300
impl<'tcx,O> Obligation<'tcx,O> {
263301
pub fn new(cause: ObligationCause<'tcx>,
264302
trait_ref: O)

src/librustc/middle/ty.rs

Lines changed: 49 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ use middle::resolve_lifetime;
5656
use middle::infer;
5757
use middle::stability;
5858
use middle::subst::{mod, Subst, Substs, VecPerParamSpace};
59-
use middle::traits::ObligationCause;
6059
use middle::traits;
6160
use middle::ty;
6261
use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
@@ -65,7 +64,7 @@ use util::ppaux::{trait_store_to_string, ty_to_string};
6564
use util::ppaux::{Repr, UserString};
6665
use util::common::{indenter, memoized, ErrorReported};
6766
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
68-
use util::nodemap::{FnvHashMap, FnvHashSet};
67+
use util::nodemap::{FnvHashMap};
6968

7069
use arena::TypedArena;
7170
use std::borrow::BorrowFrom;
@@ -80,13 +79,13 @@ use collections::enum_set::{EnumSet, CLike};
8079
use std::collections::{HashMap, HashSet};
8180
use std::collections::hash_map::Entry::{Occupied, Vacant};
8281
use syntax::abi;
83-
use syntax::ast::{CrateNum, DefId, DUMMY_NODE_ID, Ident, ItemTrait, LOCAL_CRATE};
82+
use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE};
8483
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
8584
use syntax::ast::{Onceness, StmtExpr, StmtSemi, StructField, UnnamedField};
8685
use syntax::ast::{Visibility};
8786
use syntax::ast_util::{mod, is_local, lit_is_str, local_def, PostExpansionMethod};
8887
use syntax::attr::{mod, AttrMetaMethods};
89-
use syntax::codemap::{DUMMY_SP, Span};
88+
use syntax::codemap::Span;
9089
use syntax::parse::token::{mod, InternedString};
9190
use syntax::{ast, ast_map};
9291

@@ -756,8 +755,15 @@ pub struct ctxt<'tcx> {
756755
/// Caches the representation hints for struct definitions.
757756
pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
758757

759-
/// Caches whether types move by default.
760-
pub type_moves_by_default_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
758+
/// Caches whether types are known to impl Copy. Note that type
759+
/// parameters are never placed into this cache, because their
760+
/// results are dependent on the parameter environment.
761+
pub type_impls_copy_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
762+
763+
/// Caches whether types are known to impl Sized. Note that type
764+
/// parameters are never placed into this cache, because their
765+
/// results are dependent on the parameter environment.
766+
pub type_impls_sized_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
761767
}
762768

763769
// Flags that we track on types. These flags are propagated upwards
@@ -2040,7 +2046,8 @@ pub fn mk_ctxt<'tcx>(s: Session,
20402046
associated_types: RefCell::new(DefIdMap::new()),
20412047
selection_cache: traits::SelectionCache::new(),
20422048
repr_hint_cache: RefCell::new(DefIdMap::new()),
2043-
type_moves_by_default_cache: RefCell::new(HashMap::new()),
2049+
type_impls_copy_cache: RefCell::new(HashMap::new()),
2050+
type_impls_sized_cache: RefCell::new(HashMap::new()),
20442051
}
20452052
}
20462053

@@ -2657,14 +2664,6 @@ pub fn type_is_unique(ty: Ty) -> bool {
26572664
}
26582665
}
26592666

2660-
pub fn type_is_fat_ptr<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
2661-
match ty.sty {
2662-
ty_ptr(mt{ty, ..}) | ty_rptr(_, mt{ty, ..})
2663-
| ty_uniq(ty) if !type_is_sized(cx, ty) => true,
2664-
_ => false,
2665-
}
2666-
}
2667-
26682667
/*
26692668
A scalar type is one that denotes an atomic datum, with no sub-components.
26702669
(A ty_ptr is scalar because it represents a non-managed pointer, so its
@@ -3154,45 +3153,58 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
31543153
}
31553154
}
31563155

3157-
pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
3158-
ty: Ty<'tcx>,
3159-
param_env: &ParameterEnvironment<'tcx>)
3160-
-> bool
3156+
fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
3157+
cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
3158+
param_env: &ParameterEnvironment<'tcx>,
3159+
ty: Ty<'tcx>,
3160+
bound: ty::BuiltinBound)
3161+
-> bool
31613162
{
3163+
assert!(!ty::type_needs_infer(ty));
3164+
31623165
if !type_has_params(ty) && !type_has_self(ty) {
3163-
match cx.type_moves_by_default_cache.borrow().get(&ty) {
3166+
match cache.borrow().get(&ty) {
31643167
None => {}
31653168
Some(&result) => {
3166-
debug!("determined whether {} moves by default (cached): {}",
3169+
debug!("type_impls_bound({}, {}) = {} (cached)",
31673170
ty_to_string(cx, ty),
3171+
bound,
31683172
result);
31693173
return result
31703174
}
31713175
}
31723176
}
31733177

31743178
let infcx = infer::new_infer_ctxt(cx);
3175-
let mut fulfill_cx = traits::FulfillmentContext::new();
3179+
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound);
31763180

3177-
// we can use dummy values here because we won't report any errors
3178-
// that result nor will we pay any mind to region obligations that arise
3179-
// (there shouldn't really be any anyhow)
3180-
let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID);
3181+
debug!("type_impls_bound({}, {}) = {}",
3182+
ty_to_string(cx, ty),
3183+
bound,
3184+
is_impld);
31813185

3182-
fulfill_cx.register_builtin_bound(cx, ty, ty::BoundCopy, cause);
3186+
if !type_has_params(ty) && !type_has_self(ty) {
3187+
let old_value = cache.borrow_mut().insert(ty, is_impld);
3188+
assert!(old_value.is_none());
3189+
}
31833190

3184-
// Note: we only assuming something is `Copy` if we can
3185-
// *definitively* show that it implements `Copy`. Otherwise,
3186-
// assume it is move; linear is always ok.
3187-
let is_copy = fulfill_cx.select_all_or_error(&infcx, param_env, cx).is_ok();
3188-
let is_move = !is_copy;
3191+
is_impld
3192+
}
31893193

3190-
debug!("determined whether {} moves by default: {}",
3191-
ty_to_string(cx, ty),
3192-
is_move);
3194+
pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
3195+
ty: Ty<'tcx>,
3196+
param_env: &ParameterEnvironment<'tcx>)
3197+
-> bool
3198+
{
3199+
!type_impls_bound(cx, &cx.type_impls_copy_cache, param_env, ty, ty::BoundCopy)
3200+
}
31933201

3194-
cx.type_moves_by_default_cache.borrow_mut().insert(ty, is_move);
3195-
is_move
3202+
pub fn type_is_sized<'tcx>(cx: &ctxt<'tcx>,
3203+
ty: Ty<'tcx>,
3204+
param_env: &ParameterEnvironment<'tcx>)
3205+
-> bool
3206+
{
3207+
type_impls_bound(cx, &cx.type_impls_sized_cache, param_env, ty, ty::BoundSized)
31963208
}
31973209

31983210
pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -3564,40 +3576,6 @@ pub fn type_is_machine(ty: Ty) -> bool {
35643576
}
35653577
}
35663578

3567-
// Is the type's representation size known at compile time?
3568-
pub fn type_is_sized<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
3569-
type_contents(cx, ty).is_sized(cx)
3570-
}
3571-
3572-
pub fn lltype_is_sized<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
3573-
match ty.sty {
3574-
ty_open(_) => true,
3575-
_ => type_contents(cx, ty).is_sized(cx)
3576-
}
3577-
}
3578-
3579-
// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized.
3580-
// 'Smallest' here means component of the static representation of the type; not
3581-
// the size of an object at runtime.
3582-
pub fn unsized_part_of_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
3583-
match ty.sty {
3584-
ty_str | ty_trait(..) | ty_vec(..) => ty,
3585-
ty_struct(def_id, ref substs) => {
3586-
let unsized_fields: Vec<_> = struct_fields(cx, def_id, substs).iter()
3587-
.map(|f| f.mt.ty).filter(|ty| !type_is_sized(cx, *ty)).collect();
3588-
// Exactly one of the fields must be unsized.
3589-
assert!(unsized_fields.len() == 1);
3590-
3591-
unsized_part_of_type(cx, unsized_fields[0])
3592-
}
3593-
_ => {
3594-
assert!(type_is_sized(cx, ty),
3595-
"unsized_part_of_type failed even though ty is unsized");
3596-
panic!("called unsized_part_of_type with sized ty");
3597-
}
3598-
}
3599-
}
3600-
36013579
// Whether a type is enum like, that is an enum type with only nullary
36023580
// constructors
36033581
pub fn type_is_c_like_enum(cx: &ctxt, ty: Ty) -> bool {

src/librustc_trans/trans/adt.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ impl<'tcx> Case<'tcx> {
359359
// &Trait is a pair of pointers: the actual object and a vtable
360360
ty::ty_trait(..) => return Some(FatPointer(i)),
361361

362-
ty::ty_struct(..) if !ty::type_is_sized(cx.tcx(), ty) => {
362+
ty::ty_struct(..) if !type_is_sized(cx.tcx(), ty) => {
363363
return Some(FatPointer(i))
364364
}
365365

@@ -398,12 +398,12 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
398398
tys: &[Ty<'tcx>], packed: bool,
399399
scapegoat: Ty<'tcx>)
400400
-> Struct<'tcx> {
401-
let sized = tys.iter().all(|&ty| ty::type_is_sized(cx.tcx(), ty));
401+
let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty));
402402
let lltys : Vec<Type> = if sized {
403403
tys.iter()
404404
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
405405
} else {
406-
tys.iter().filter(|&ty| ty::type_is_sized(cx.tcx(), *ty))
406+
tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty))
407407
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
408408
};
409409

@@ -655,7 +655,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
655655
fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>,
656656
sizing: bool, dst: bool) -> Vec<Type> {
657657
if sizing {
658-
st.fields.iter().filter(|&ty| !dst || ty::type_is_sized(cx.tcx(), *ty))
658+
st.fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
659659
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
660660
} else {
661661
st.fields.iter().map(|&ty| type_of::type_of(cx, ty)).collect()

src/librustc_trans/trans/base.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ pub fn compare_scalar_types<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
581581
match t.sty {
582582
ty::ty_tup(ref tys) if tys.is_empty() => f(nil_type),
583583
ty::ty_bool | ty::ty_uint(_) | ty::ty_char => f(unsigned_int),
584-
ty::ty_ptr(mt) if ty::type_is_sized(cx.tcx(), mt.ty) => f(unsigned_int),
584+
ty::ty_ptr(mt) if common::type_is_sized(cx.tcx(), mt.ty) => f(unsigned_int),
585585
ty::ty_int(_) => f(signed_int),
586586
ty::ty_float(_) => f(floating_point),
587587
// Should never get here, because t is scalar.
@@ -719,7 +719,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
719719
return cx;
720720
}
721721

722-
let (data_ptr, info) = if ty::type_is_sized(cx.tcx(), t) {
722+
let (data_ptr, info) = if common::type_is_sized(cx.tcx(), t) {
723723
(av, None)
724724
} else {
725725
let data = GEPi(cx, av, &[0, abi::FAT_PTR_ADDR]);
@@ -736,7 +736,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
736736
let field_ty = field_ty.mt.ty;
737737
let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, discr, i);
738738

739-
let val = if ty::type_is_sized(cx.tcx(), field_ty) {
739+
let val = if common::type_is_sized(cx.tcx(), field_ty) {
740740
llfld_a
741741
} else {
742742
let boxed_ty = ty::mk_open(cx.tcx(), field_ty);
@@ -2506,7 +2506,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
25062506
match ret_ty.sty {
25072507
// `~` pointer return values never alias because ownership
25082508
// is transferred
2509-
ty::ty_uniq(it) if !ty::type_is_sized(ccx.tcx(), it) => {}
2509+
ty::ty_uniq(it) if !common::type_is_sized(ccx.tcx(), it) => {}
25102510
ty::ty_uniq(_) => {
25112511
attrs.ret(llvm::NoAliasAttribute);
25122512
}
@@ -2517,7 +2517,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
25172517
match ret_ty.sty {
25182518
// These are not really pointers but pairs, (pointer, len)
25192519
ty::ty_uniq(it) |
2520-
ty::ty_rptr(_, ty::mt { ty: it, .. }) if !ty::type_is_sized(ccx.tcx(), it) => {}
2520+
ty::ty_rptr(_, ty::mt { ty: it, .. }) if !common::type_is_sized(ccx.tcx(), it) => {}
25212521
ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => {
25222522
let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner));
25232523
attrs.ret(llvm::DereferenceableAttribute(llret_sz));

0 commit comments

Comments
 (0)