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:
parent
d5580374d7
commit
1a87fc2635
10 changed files with 77 additions and 33 deletions
|
@ -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.
|
||||
|
|
|
@ -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>,
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)),
|
||||
};
|
||||
|
||||
|
|
|
@ -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>>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ¶m_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
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue