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),
|
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)]
|
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
|
||||||
pub enum CustomCoerceUnsized {
|
pub enum CustomCoerceUnsized {
|
||||||
/// Records the index of the field being coerced.
|
/// Records the index of the field being coerced.
|
||||||
|
|
|
@ -393,8 +393,8 @@ define_maps! { <'tcx>
|
||||||
pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
|
pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
|
||||||
|
|
||||||
/// Caches CoerceUnsized kinds for impls on custom types.
|
/// Caches CoerceUnsized kinds for impls on custom types.
|
||||||
pub custom_coerce_unsized_kind: ItemSignature(DefId)
|
pub coerce_unsized_info: ItemSignature(DefId)
|
||||||
-> ty::adjustment::CustomCoerceUnsized,
|
-> ty::adjustment::CoerceUnsizedInfo,
|
||||||
|
|
||||||
pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
|
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 {
|
pub fn coerce_unsized_info(self, did: DefId) -> adjustment::CoerceUnsizedInfo {
|
||||||
queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did)
|
queries::coerce_unsized_info::get(self, DUMMY_SP, did)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
|
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) }
|
associated_item => { cdata.get_associated_item(def_id.index) }
|
||||||
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
|
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
|
||||||
custom_coerce_unsized_kind => {
|
coerce_unsized_info => {
|
||||||
cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| {
|
cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
|
||||||
bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id);
|
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mir => {
|
mir => {
|
||||||
|
|
|
@ -643,10 +643,10 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
self.get_impl_data(id).polarity
|
self.get_impl_data(id).polarity
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_custom_coerce_unsized_kind(&self,
|
pub fn get_coerce_unsized_info(&self,
|
||||||
id: DefIndex)
|
id: DefIndex)
|
||||||
-> Option<ty::adjustment::CustomCoerceUnsized> {
|
-> Option<ty::adjustment::CoerceUnsizedInfo> {
|
||||||
self.get_impl_data(id).coerce_unsized_kind
|
self.get_impl_data(id).coerce_unsized_info
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_impl_trait(&self,
|
pub fn get_impl_trait(&self,
|
||||||
|
|
|
@ -695,7 +695,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
let data = ImplData {
|
let data = ImplData {
|
||||||
polarity: hir::ImplPolarity::Positive,
|
polarity: hir::ImplPolarity::Positive,
|
||||||
parent_impl: None,
|
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)),
|
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
|
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 {
|
let data = ImplData {
|
||||||
polarity: polarity,
|
polarity: polarity,
|
||||||
parent_impl: parent,
|
parent_impl: parent,
|
||||||
coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind
|
coerce_unsized_info: coerce_unsized_info,
|
||||||
.borrow()
|
|
||||||
.get(&def_id)
|
|
||||||
.cloned(),
|
|
||||||
trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)),
|
trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,9 @@ pub struct TraitData<'tcx> {
|
||||||
pub struct ImplData<'tcx> {
|
pub struct ImplData<'tcx> {
|
||||||
pub polarity: hir::ImplPolarity,
|
pub polarity: hir::ImplPolarity,
|
||||||
pub parent_impl: Option<DefId>,
|
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>>>,
|
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) {
|
match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
|
||||||
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
|
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 => {
|
vtable => {
|
||||||
bug!("invalid CoerceUnsized vtable: {:?}", 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::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::ParameterEnvironment;
|
use rustc::ty::ParameterEnvironment;
|
||||||
use rustc::ty::TypeFoldable;
|
use rustc::ty::TypeFoldable;
|
||||||
|
use rustc::ty::adjustment::CoerceUnsizedInfo;
|
||||||
use rustc::ty::subst::Subst;
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::ty::util::CopyImplementationError;
|
use rustc::ty::util::CopyImplementationError;
|
||||||
use rustc::infer;
|
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>,
|
fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
coerce_unsized_trait: DefId,
|
_: DefId,
|
||||||
impl_did: DefId) {
|
impl_did: DefId) {
|
||||||
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
|
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
|
||||||
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) {
|
let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
Err(err) => {
|
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) {
|
// this provider should only get invoked for local def-ids
|
||||||
n
|
let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| {
|
||||||
} else {
|
bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did)
|
||||||
debug!("visit_implementation_of_coerce_unsized(): impl not \
|
});
|
||||||
in this crate");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let source = tcx.item_type(impl_did);
|
let source = tcx.item_type(impl_did);
|
||||||
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
|
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);
|
let target = trait_ref.substs.type_at(1);
|
||||||
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
|
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
|
||||||
source,
|
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);
|
let target = target.subst(tcx, ¶m_env.free_substs);
|
||||||
assert!(!source.has_escaping_regions());
|
assert!(!source.has_escaping_regions());
|
||||||
|
|
||||||
|
let err_info = CoerceUnsizedInfo { custom_kind: None };
|
||||||
|
|
||||||
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
|
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
|
||||||
source,
|
source,
|
||||||
target);
|
target);
|
||||||
|
@ -234,7 +250,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
definition; expected {}, found {}",
|
definition; expected {}, found {}",
|
||||||
source_path,
|
source_path,
|
||||||
target_path);
|
target_path);
|
||||||
return;
|
return err_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = &def_a.struct_variant().fields;
|
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 \
|
"the trait `CoerceUnsized` may only be implemented \
|
||||||
for a coercion between structures with one field \
|
for a coercion between structures with one field \
|
||||||
being coerced, none found");
|
being coerced, none found");
|
||||||
return;
|
return err_info;
|
||||||
} else if diff_fields.len() > 1 {
|
} else if diff_fields.len() > 1 {
|
||||||
let item = tcx.hir.expect_item(impl_node_id);
|
let item = tcx.hir.expect_item(impl_node_id);
|
||||||
let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
|
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(", ")));
|
.join(", ")));
|
||||||
err.span_label(span, &format!("requires multiple coercions"));
|
err.span_label(span, &format!("requires multiple coercions"));
|
||||||
err.emit();
|
err.emit();
|
||||||
return;
|
return err_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (i, a, b) = diff_fields[0];
|
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,
|
E0376,
|
||||||
"the trait `CoerceUnsized` may only be implemented \
|
"the trait `CoerceUnsized` may only be implemented \
|
||||||
for a coercion between structures");
|
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);
|
.caller_bounds);
|
||||||
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
|
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
|
||||||
|
|
||||||
if let Some(kind) = kind {
|
CoerceUnsizedInfo {
|
||||||
tcx.maps.custom_coerce_unsized_kind.borrow_mut().insert(impl_did, kind);
|
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) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
use self::builtin::coerce_unsized_info;
|
||||||
|
|
||||||
*providers = Providers {
|
*providers = Providers {
|
||||||
coherent_trait,
|
coherent_trait,
|
||||||
coherent_inherent_impls,
|
coherent_inherent_impls,
|
||||||
|
coerce_unsized_info,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue