convert custom_coerce_unsized_kind into a coerce_unsized_info

This "on-demand" task both checks for errors and computes the custom
unsized kind, if any. This task is only defined on impls of
`CoerceUnsized`; invoking it on any other kind of impl results in a bug.
This is just to avoid having an `Option`, could easily be changed.
This commit is contained in:
Niko Matsakis 2017-03-17 16:17:45 -04:00
parent d5580374d7
commit 1a87fc2635
10 changed files with 77 additions and 33 deletions

View file

@ -139,6 +139,21 @@ pub enum AutoBorrow<'tcx> {
RawPtr(hir::Mutability),
}
/// Information for `CoerceUnsized` impls, storing information we
/// have computed about the coercion.
///
/// This struct can be obtained via the `coerce_impl_info` query.
/// Demanding this struct also has the side-effect of reporting errors
/// for inappropriate impls.
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
pub struct CoerceUnsizedInfo {
/// If this is a "custom coerce" impl, then what kind of custom
/// coercion is it? This applies to impls of `CoerceUnsized` for
/// structs, primarily, where we store a bit of info about which
/// fields need to be coerced.
pub custom_kind: Option<CustomCoerceUnsized>
}
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
pub enum CustomCoerceUnsized {
/// Records the index of the field being coerced.

View file

@ -393,8 +393,8 @@ define_maps! { <'tcx>
pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
/// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kind: ItemSignature(DefId)
-> ty::adjustment::CustomCoerceUnsized,
pub coerce_unsized_info: ItemSignature(DefId)
-> ty::adjustment::CoerceUnsizedInfo,
pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,

View file

@ -2054,8 +2054,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
})
}
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did)
pub fn coerce_unsized_info(self, did: DefId) -> adjustment::CoerceUnsizedInfo {
queries::coerce_unsized_info::get(self, DUMMY_SP, did)
}
pub fn associated_item(self, def_id: DefId) -> AssociatedItem {

View file

@ -88,9 +88,9 @@ provide! { <'tcx> tcx, def_id, cdata
}
associated_item => { cdata.get_associated_item(def_id.index) }
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
custom_coerce_unsized_kind => {
cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| {
bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id);
coerce_unsized_info => {
cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
})
}
mir => {

View file

@ -643,10 +643,10 @@ impl<'a, 'tcx> CrateMetadata {
self.get_impl_data(id).polarity
}
pub fn get_custom_coerce_unsized_kind(&self,
id: DefIndex)
-> Option<ty::adjustment::CustomCoerceUnsized> {
self.get_impl_data(id).coerce_unsized_kind
pub fn get_coerce_unsized_info(&self,
id: DefIndex)
-> Option<ty::adjustment::CoerceUnsizedInfo> {
self.get_impl_data(id).coerce_unsized_info
}
pub fn get_impl_trait(&self,

View file

@ -695,7 +695,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let data = ImplData {
polarity: hir::ImplPolarity::Positive,
parent_impl: None,
coerce_unsized_kind: None,
coerce_unsized_info: None,
trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)),
};
@ -715,13 +715,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
None
};
// if this is an impl of `CoerceUnsized`, create its
// "unsized info", else just store None
let coerce_unsized_info =
trait_ref.and_then(|t| {
if Some(t.def_id) == tcx.lang_items.coerce_unsized_trait() {
Some(ty::queries::coerce_unsized_info::get(tcx, item.span, def_id))
} else {
None
}
});
let data = ImplData {
polarity: polarity,
parent_impl: parent,
coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind
.borrow()
.get(&def_id)
.cloned(),
coerce_unsized_info: coerce_unsized_info,
trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)),
};

View file

@ -285,7 +285,9 @@ pub struct TraitData<'tcx> {
pub struct ImplData<'tcx> {
pub polarity: hir::ImplPolarity,
pub parent_impl: Option<DefId>,
pub coerce_unsized_kind: Option<ty::adjustment::CustomCoerceUnsized>,
/// This is `Some` only for impls of `CoerceUnsized`.
pub coerce_unsized_info: Option<ty::adjustment::CoerceUnsizedInfo>,
pub trait_ref: Option<Lazy<ty::TraitRef<'tcx>>>,
}

View file

@ -287,7 +287,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
scx.tcx().custom_coerce_unsized_kind(impl_def_id)
scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap()
}
vtable => {
bug!("invalid CoerceUnsized vtable: {:?}", vtable);

View file

@ -18,6 +18,7 @@ use rustc::traits::{self, ObligationCause, Reveal};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::ParameterEnvironment;
use rustc::ty::TypeFoldable;
use rustc::ty::adjustment::CoerceUnsizedInfo;
use rustc::ty::subst::Subst;
use rustc::ty::util::CopyImplementationError;
use rustc::infer;
@ -159,11 +160,26 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
coerce_unsized_trait: DefId,
_: DefId,
impl_did: DefId) {
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
impl_did);
// Just compute this for the side-effects, in particular reporting
// errors; other parts of the code may demand it for the info of
// course.
if impl_did.is_local() {
let span = tcx.def_span(impl_did);
ty::queries::coerce_unsized_info::get(tcx, span, impl_did);
}
}
pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_did: DefId)
-> CoerceUnsizedInfo {
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
let coerce_unsized_trait = tcx.lang_items.coerce_unsized_trait().unwrap();
let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
Ok(id) => id,
Err(err) => {
@ -171,16 +187,14 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
};
let impl_node_id = if let Some(n) = tcx.hir.as_local_node_id(impl_did) {
n
} else {
debug!("visit_implementation_of_coerce_unsized(): impl not \
in this crate");
return;
};
// this provider should only get invoked for local def-ids
let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| {
bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did)
});
let source = tcx.item_type(impl_did);
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
let target = trait_ref.substs.type_at(1);
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
source,
@ -192,6 +206,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let target = target.subst(tcx, &param_env.free_substs);
assert!(!source.has_escaping_regions());
let err_info = CoerceUnsizedInfo { custom_kind: None };
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
source,
target);
@ -234,7 +250,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
definition; expected {}, found {}",
source_path,
target_path);
return;
return err_info;
}
let fields = &def_a.struct_variant().fields;
@ -268,7 +284,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with one field \
being coerced, none found");
return;
return err_info;
} else if diff_fields.len() > 1 {
let item = tcx.hir.expect_item(impl_node_id);
let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
@ -295,7 +311,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.join(", ")));
err.span_label(span, &format!("requires multiple coercions"));
err.emit();
return;
return err_info;
}
let (i, a, b) = diff_fields[0];
@ -309,7 +325,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
E0376,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures");
return;
return err_info;
}
};
@ -331,8 +347,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.caller_bounds);
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
if let Some(kind) = kind {
tcx.maps.custom_coerce_unsized_kind.borrow_mut().insert(impl_did, kind);
CoerceUnsizedInfo {
custom_kind: kind
}
});
})
}

View file

@ -102,9 +102,12 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d
}
pub fn provide(providers: &mut Providers) {
use self::builtin::coerce_unsized_info;
*providers = Providers {
coherent_trait,
coherent_inherent_impls,
coerce_unsized_info,
..*providers
};
}