eddyb's changes for DST coercions

+ lots of rebasing
This commit is contained in:
Nick Cameron 2015-04-15 11:57:29 +12:00
parent c2b30b86df
commit 843db01bd9
40 changed files with 1019 additions and 514 deletions

View file

@ -807,6 +807,9 @@ register_diagnostics! {
E0017,
E0019,
E0022,
E0038,
E0079, // enum variant: expected signed integer constant
E0080, // enum variant: constant evaluation error
E0109,
E0110,
E0134,

View file

@ -259,3 +259,5 @@ pub const tag_codemap_filemap: usize = 0xa2;
pub const tag_item_super_predicates: usize = 0xa3;
pub const tag_defaulted_trait: usize = 0xa4;
pub const tag_impl_coerce_unsized_kind: usize = 0xa5;

View file

@ -279,6 +279,14 @@ pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>,
decoder::get_impl_polarity(&*cdata, def.node)
}
pub fn get_custom_coerce_unsized_kind<'tcx>(tcx: &ty::ctxt<'tcx>,
def: ast::DefId)
-> Option<ty::CustomCoerceUnsized> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
decoder::get_custom_coerce_unsized_kind(&*cdata, def.node)
}
// Given a def_id for an impl, return the trait it implements,
// if there is one.
pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>,

View file

@ -489,6 +489,16 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd,
}
}
pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd,
id: ast::NodeId)
-> Option<ty::CustomCoerceUnsized> {
let item_doc = lookup_item(id, cdata.data());
reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| {
let mut decoder = reader::Decoder::new(kind_doc);
Decodable::decode(&mut decoder).unwrap()
})
}
pub fn get_impl_trait<'tcx>(cdata: Cmd,
id: ast::NodeId,
tcx: &ty::ctxt<'tcx>)

View file

@ -1219,6 +1219,16 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_attributes(rbml_w, &item.attrs);
encode_unsafety(rbml_w, unsafety);
encode_polarity(rbml_w, polarity);
match tcx.custom_coerce_unsized_kinds.borrow().get(&local_def(item.id)) {
Some(&kind) => {
rbml_w.start_tag(tag_impl_coerce_unsized_kind);
kind.encode(rbml_w);
rbml_w.end_tag();
}
None => {}
}
match ty.node {
ast::TyPath(None, ref path) if path.segments.len() == 1 => {
let name = path.segments.last().unwrap().identifier.name;

View file

@ -890,10 +890,6 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
}
};
debug!("walk_autoref: expr.id={} cmt_base={}",
expr.id,
cmt_base.repr(self.tcx()));
match *autoref {
ty::AutoPtr(r, m) => {
self.delegate.borrow(expr.id,

View file

@ -261,11 +261,14 @@ lets_do_this! {
SendTraitLangItem, "send", send_trait;
SizedTraitLangItem, "sized", sized_trait;
UnsizeTraitLangItem, "unsize", unsize_trait;
CopyTraitLangItem, "copy", copy_trait;
SyncTraitLangItem, "sync", sync_trait;
DropTraitLangItem, "drop", drop_trait;
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait;
AddTraitLangItem, "add", add_trait;
SubTraitLangItem, "sub", sub_trait;
MulTraitLangItem, "mul", mul_trait;

View file

@ -15,8 +15,12 @@ use super::{
Obligation,
ObligationCauseCode,
OutputTypeParameterMismatch,
TraitNotObjectSafe,
PredicateObligation,
SelectionError,
ObjectSafetyViolation,
MethodViolationCode,
object_safety_violations,
};
use fmt_macros::{Parser, Piece, Position};
@ -252,6 +256,54 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
note_obligation_cause(infcx, obligation);
}
}
TraitNotObjectSafe(did) => {
span_err!(infcx.tcx.sess, obligation.cause.span, E0038,
"cannot convert to a trait object because trait `{}` is not object-safe",
ty::item_path_str(infcx.tcx, did));
for violation in object_safety_violations(infcx.tcx, did) {
match violation {
ObjectSafetyViolation::SizedSelf => {
infcx.tcx.sess.span_note(
obligation.cause.span,
"the trait cannot require that `Self : Sized`");
}
ObjectSafetyViolation::SupertraitSelf => {
infcx.tcx.sess.span_note(
obligation.cause.span,
"the trait cannot use `Self` as a type parameter \
in the supertrait listing");
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::StaticMethod) => {
infcx.tcx.sess.span_note(
obligation.cause.span,
&format!("method `{}` has no receiver",
method.name.user_string(infcx.tcx)));
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::ReferencesSelf) => {
infcx.tcx.sess.span_note(
obligation.cause.span,
&format!("method `{}` references the `Self` type \
in its arguments or return type",
method.name.user_string(infcx.tcx)));
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::Generic) => {
infcx.tcx.sess.span_note(
obligation.cause.span,
&format!("method `{}` has generic type parameters",
method.name.user_string(infcx.tcx)));
}
}
}
}
}
}
@ -403,10 +455,6 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
"only the last field of a struct or enum variant \
may have a dynamically sized type")
}
ObligationCauseCode::ObjectSized => {
span_note!(tcx.sess, cause_span,
"only sized types can be made into objects");
}
ObligationCauseCode::SharedStatic => {
span_note!(tcx.sess, cause_span,
"shared static variables must have a type that implements `Sync`");

View file

@ -28,6 +28,7 @@ use util::ppaux::Repr;
pub use self::error_reporting::report_fulfillment_errors;
pub use self::error_reporting::report_overflow_error;
pub use self::error_reporting::report_selection_error;
pub use self::error_reporting::suggest_new_overflow_limit;
pub use self::coherence::orphan_check;
pub use self::coherence::overlapping_impls;
@ -48,6 +49,7 @@ pub use self::select::{MethodMatchedData}; // intentionally don't export variant
pub use self::util::elaborate_predicates;
pub use self::util::get_vtable_index_of_object_method;
pub use self::util::trait_ref_for_builtin_bound;
pub use self::util::predicate_for_trait_def;
pub use self::util::supertraits;
pub use self::util::Supertraits;
pub use self::util::supertrait_def_ids;
@ -121,9 +123,6 @@ pub enum ObligationCauseCode<'tcx> {
// Types of fields (other than the last) in a struct must be sized.
FieldSized,
// Only Sized types can be made into objects
ObjectSized,
// static items must have `Sync` type
SharedStatic,
@ -159,6 +158,7 @@ pub enum SelectionError<'tcx> {
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
ty::type_err<'tcx>),
TraitNotObjectSafe(ast::DefId),
}
pub struct FulfillmentError<'tcx> {
@ -536,7 +536,9 @@ impl<'tcx, N> Vtable<'tcx, N> {
}
}
pub fn map_nested<M, F>(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M {
pub fn map_nested<M, F>(&self, op: F) -> Vtable<'tcx, M> where
F: FnMut(&N) -> M,
{
match *self {
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
VtableDefaultImpl(ref t) => VtableDefaultImpl(t.map_nested(op)),

View file

@ -25,6 +25,8 @@ use super::{PredicateObligation, TraitObligation, ObligationCause};
use super::report_overflow_error;
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
use super::{ObjectCastObligation, Obligation};
use super::TraitNotObjectSafe;
use super::Selection;
use super::SelectionResult;
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
@ -35,7 +37,7 @@ use super::util;
use middle::fast_reject;
use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::{self, AsPredicate, RegionEscape, ToPolyTraitRef, Ty};
use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener};
use middle::ty_fold::TypeFoldable;
@ -207,6 +209,8 @@ enum SelectionCandidate<'tcx> {
BuiltinObjectCandidate,
BuiltinUnsizeCandidate,
ErrorCandidate,
}
@ -904,6 +908,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
}
None if self.tcx().lang_items.unsize_trait() ==
Some(obligation.predicate.def_id()) => {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
}
Some(ty::BoundSend) |
Some(ty::BoundSync) |
None => {
@ -1356,6 +1365,64 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}).unwrap();
}
/// Search for unsizing that might apply to `obligation`.
fn assemble_candidates_for_unsizing(&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>) {
// TODO is it Ok to skip the binder here?
let source = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]);
debug!("assemble_candidates_for_unsizing(source={}, target={})",
source.repr(self.tcx()), target.repr(self.tcx()));
let may_apply = match (&source.sty, &target.sty) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
// Upcasts permit two things:
//
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
//
// Note that neither of these changes requires any
// change at runtime. Eventually this will be
// generalized.
//
// We always upcast when we can because of reason
// #2 (region bounds).
data_a.principal.def_id() == data_a.principal.def_id() &&
data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds)
}
// T -> Trait.
(_, &ty::ty_trait(_)) => true,
// Ambiguous handling is below T -> Trait, because inference
// variables can still implement Unsize<Trait> and nested
// obligations will have the final say (likely deferred).
(&ty::ty_infer(ty::TyVar(_)), _) |
(_, &ty::ty_infer(ty::TyVar(_))) => {
debug!("assemble_candidates_for_unsizing: ambiguous");
candidates.ambiguous = true;
false
}
// [T; n] -> [T].
(&ty::ty_vec(_, Some(_)), &ty::ty_vec(_, None)) => true,
// Struct<T> -> Struct<U>.
(&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => {
def_id_a == def_id_b
}
_ => false
};
if may_apply {
candidates.vec.push(BuiltinUnsizeCandidate);
}
}
///////////////////////////////////////////////////////////////////////////
// WINNOW
//
@ -1427,6 +1494,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&ClosureCandidate(..) |
&FnPointerCandidate(..) |
&BuiltinObjectCandidate(..) |
&&BuiltinUnsizeCandidate(..) |
&DefaultImplObjectCandidate(..) |
&BuiltinCandidate(..) => {
// We have a where-clause so don't go around looking
@ -1855,11 +1923,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.recursion_depth + 1,
&skol_ty);
let skol_obligation =
try!(util::predicate_for_trait_def(self.tcx(),
derived_cause.clone(),
trait_def_id,
obligation.recursion_depth + 1,
normalized_ty));
util::predicate_for_trait_def(self.tcx(),
derived_cause.clone(),
trait_def_id,
obligation.recursion_depth + 1,
normalized_ty,
vec![]);
obligations.push(skol_obligation);
Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations))
})
@ -1949,6 +2018,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.confirm_projection_candidate(obligation);
Ok(VtableParam(Vec::new()))
}
BuiltinUnsizeCandidate => {
let data = try!(self.confirm_builtin_unsize_candidate(obligation));
Ok(VtableBuiltin(data))
}
}
}
@ -2322,6 +2396,159 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
fn confirm_builtin_unsize_candidate(&mut self,
obligation: &TraitObligation<'tcx>,)
-> Result<VtableBuiltinData<PredicateObligation<'tcx>>,
SelectionError<'tcx>> {
let tcx = self.tcx();
// TODO is this skip_binder Ok?
let source = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]);
debug!("confirm_builtin_unsize_candidate(source={}, target={})",
source.repr(tcx), target.repr(tcx));
let mut nested = vec![];
match (&source.sty, &target.sty) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
// See assemble_candidates_for_unsizing for more info.
let bounds = ty::ExistentialBounds {
region_bound: data_b.bounds.region_bound,
builtin_bounds: data_b.bounds.builtin_bounds,
projection_bounds: data_a.bounds.projection_bounds.clone(),
};
let new_trait = ty::mk_trait(tcx, data_a.principal.clone(), bounds);
let origin = infer::Misc(obligation.cause.span);
if self.infcx.sub_types(false, origin, new_trait, target).is_err() {
return Err(Unimplemented);
}
// Register one obligation for 'a: 'b.
let cause = ObligationCause::new(obligation.cause.span,
obligation.cause.body_id,
ObjectCastObligation(target));
let outlives = ty::OutlivesPredicate(data_a.bounds.region_bound,
data_b.bounds.region_bound);
nested.push(Obligation::with_depth(cause,
obligation.recursion_depth + 1,
ty::Binder(outlives).as_predicate()));
}
// T -> Trait.
(_, &ty::ty_trait(ref data)) => {
let object_did = data.principal_def_id();
if !object_safety::is_object_safe(tcx, object_did) {
return Err(TraitNotObjectSafe(object_did));
}
let cause = ObligationCause::new(obligation.cause.span,
obligation.cause.body_id,
ObjectCastObligation(target));
let mut push = |predicate| {
nested.push(Obligation::with_depth(cause.clone(),
obligation.recursion_depth + 1,
predicate));
};
// Create the obligation for casting from T to Trait.
push(data.principal_trait_ref_with_self_ty(tcx, source).as_predicate());
// We can only make objects from sized types.
let mut builtin_bounds = data.bounds.builtin_bounds;
builtin_bounds.insert(ty::BoundSized);
// Create additional obligations for all the various builtin
// bounds attached to the object cast. (In other words, if the
// object type is Foo+Send, this would create an obligation
// for the Send check.)
for bound in &builtin_bounds {
if let Ok(tr) = util::trait_ref_for_builtin_bound(tcx, bound, source) {
push(tr.as_predicate());
} else {
return Err(Unimplemented);
}
}
// Create obligations for the projection predicates.
for bound in data.projection_bounds_with_self_ty(tcx, source) {
push(bound.as_predicate());
}
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` outlives `'a`:
let outlives = ty::OutlivesPredicate(source,
data.bounds.region_bound);
push(ty::Binder(outlives).as_predicate());
}
// [T; n] -> [T].
(&ty::ty_vec(a, Some(_)), &ty::ty_vec(b, None)) => {
let origin = infer::Misc(obligation.cause.span);
if self.infcx.sub_types(false, origin, a, b).is_err() {
return Err(Unimplemented);
}
}
// Struct<T> -> Struct<U>.
(&ty::ty_struct(def_id, substs_a), &ty::ty_struct(_, substs_b)) => {
let fields = ty::lookup_struct_fields(tcx, def_id).iter().map(|f| {
ty::lookup_field_type_unsubstituted(tcx, def_id, f.id)
}).collect::<Vec<_>>();
// The last field of the structure has to exist and be a
// type parameter (for now, to avoid tracking edge cases).
let i = if let Some(&ty::ty_param(p)) = fields.last().map(|ty| &ty.sty) {
assert!(p.space == TypeSpace);
p.idx as usize
} else {
return Err(Unimplemented);
};
// Replace the type parameter chosen for unsizing with
// ty_err and ensure it does not affect any other fields.
// This could be checked after type collection for any struct
// with a potentially unsized trailing field.
let mut new_substs = substs_a.clone();
new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err;
for &ty in fields.init() {
if ty::type_is_error(ty.subst(tcx, &new_substs)) {
return Err(Unimplemented);
}
}
// Extract T and U from Struct<T> and Struct<U>.
let inner_source = *substs_a.types.get(TypeSpace, i);
let inner_target = *substs_b.types.get(TypeSpace, i);
// Check that all the source structure with the unsized
// type parameter is a subtype of the target.
new_substs.types.get_mut_slice(TypeSpace)[i] = inner_target;
let new_struct = ty::mk_struct(tcx, def_id, tcx.mk_substs(new_substs));
let origin = infer::Misc(obligation.cause.span);
if self.infcx.sub_types(false, origin, new_struct, target).is_err() {
return Err(Unimplemented);
}
// Construct the nested T: Unsize<U> predicate.
nested.push(util::predicate_for_trait_def(tcx,
obligation.cause.clone(),
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
inner_source,
vec![inner_target]));
}
_ => unreachable!()
};
Ok(VtableBuiltinData {
nested: VecPerParamSpace::new(nested, vec![], vec![])
})
}
///////////////////////////////////////////////////////////////////////////
// Matching
//
@ -2683,6 +2910,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
ErrorCandidate => format!("ErrorCandidate"),
BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b),
BuiltinObjectCandidate => format!("BuiltinObjectCandidate"),
BuiltinUnsizeCandidate => format!("BuiltinUnsizeCandidate"),
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
@ -2756,7 +2984,8 @@ impl<'tcx> EvaluationResult<'tcx> {
match *self {
EvaluatedToOk |
EvaluatedToAmbig |
EvaluatedToErr(OutputTypeParameterMismatch(..)) =>
EvaluatedToErr(OutputTypeParameterMismatch(..)) |
EvaluatedToErr(TraitNotObjectSafe(_)) =>
true,
EvaluatedToErr(Unimplemented) =>

View file

@ -356,13 +356,13 @@ pub fn predicate_for_trait_ref<'tcx>(
cause: ObligationCause<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
recursion_depth: usize)
-> Result<PredicateObligation<'tcx>, ErrorReported>
-> PredicateObligation<'tcx>
{
Ok(Obligation {
Obligation {
cause: cause,
recursion_depth: recursion_depth,
predicate: trait_ref.as_predicate(),
})
}
}
pub fn predicate_for_trait_def<'tcx>(
@ -370,13 +370,14 @@ pub fn predicate_for_trait_def<'tcx>(
cause: ObligationCause<'tcx>,
trait_def_id: ast::DefId,
recursion_depth: usize,
param_ty: Ty<'tcx>)
-> Result<PredicateObligation<'tcx>, ErrorReported>
param_ty: Ty<'tcx>,
ty_params: Vec<Ty<'tcx>>)
-> PredicateObligation<'tcx>
{
let trait_ref = ty::TraitRef {
def_id: trait_def_id,
substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty))
};
substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty))
});
predicate_for_trait_ref(cause, trait_ref, recursion_depth)
}
@ -389,7 +390,7 @@ pub fn predicate_for_builtin_bound<'tcx>(
-> Result<PredicateObligation<'tcx>, ErrorReported>
{
let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty));
predicate_for_trait_ref(cause, trait_ref, recursion_depth)
Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth))
}
/// Cast a trait reference into a reference to one of its super
@ -561,6 +562,10 @@ impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
a.repr(tcx),
b.repr(tcx),
c.repr(tcx)),
super::TraitNotObjectSafe(ref tr) =>
format!("TraitNotObjectSafe({})",
tr.repr(tcx))
}
}
}

View file

@ -404,6 +404,12 @@ pub enum AutoRef<'tcx> {
AutoUnsafe(ast::Mutability),
}
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
pub enum CustomCoerceUnsized {
/// Records the index of the field being coerced.
Struct(usize)
}
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)]
pub struct param_index {
pub space: subst::ParamSpace,
@ -818,6 +824,9 @@ pub struct ctxt<'tcx> {
/// Maps Expr NodeId's to their constant qualification.
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
/// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<CustomCoerceUnsized>>,
}
impl<'tcx> ctxt<'tcx> {
@ -2809,6 +2818,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
type_impls_copy_cache: RefCell::new(HashMap::new()),
type_impls_sized_cache: RefCell::new(HashMap::new()),
const_qualif_map: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
}
}
@ -5351,6 +5361,26 @@ pub fn trait_impl_polarity<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
}
}
pub fn custom_coerce_unsized_kind<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
-> CustomCoerceUnsized {
memoized(&cx.custom_coerce_unsized_kinds, did, |did: DefId| {
let (kind, src) = if did.krate != ast::LOCAL_CRATE {
(csearch::get_custom_coerce_unsized_kind(cx, did), "external")
} else {
(None, "local")
};
match kind {
Some(kind) => kind,
None => {
cx.sess.bug(&format!("custom_coerce_unsized_kind: \
{} impl `{}` is missing its kind",
src, item_path_str(cx, did)));
}
}
})
}
pub fn impl_or_trait_item<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
-> ImplOrTraitItem<'tcx> {
lookup_locally_or_in_crate_store("impl_or_trait_items",
@ -6012,6 +6042,20 @@ pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
})
}
// Look up a field ID, whether or not it's local
pub fn lookup_field_type_unsubstituted<'tcx>(tcx: &ctxt<'tcx>,
struct_id: DefId,
id: DefId)
-> Ty<'tcx> {
if id.krate == ast::LOCAL_CRATE {
node_id_to_type(tcx, id.node)
} else {
let mut tcache = tcx.tcache.borrow_mut();
tcache.entry(id).or_insert_with(|| csearch::get_field_type(tcx, struct_id, id)).ty
}
}
// Look up a field ID, whether or not it's local
// Takes a list of type substs in case the struct is generic
pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>,
@ -6019,13 +6063,7 @@ pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>,
id: DefId,
substs: &Substs<'tcx>)
-> Ty<'tcx> {
let ty = if id.krate == ast::LOCAL_CRATE {
node_id_to_type(tcx, id.node)
} else {
let mut tcache = tcx.tcache.borrow_mut();
tcache.entry(id).or_insert_with(|| csearch::get_field_type(tcx, struct_id, id)).ty
};
ty.subst(tcx, substs)
lookup_field_type_unsubstituted(tcx, struct_id, id).subst(tcx, substs)
}
// Look up the list of field names and IDs for a given struct.