Skip to content

Commit

Permalink
convert custom_coerce_unsized_kind into a coerce_unsized_info
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nikomatsakis committed Mar 17, 2017
1 parent 7c3d2f7 commit 462e91a
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 34 deletions.
15 changes: 15 additions & 0 deletions src/librustc/ty/adjustment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/ty/maps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ macro_rules! define_maps {
provider(tcx.global_tcx(), key)
})?;

Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result)))
Ok(f(&tcx.maps.$name.borrow_mut().__entry__(key).or_insert(result)))
}

pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K)
Expand Down Expand Up @@ -376,8 +376,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>,

Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2030,8 +2030,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 {
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_metadata/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,10 +651,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,
Expand Down
18 changes: 13 additions & 5 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
};

Expand All @@ -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)),
};

Expand Down
4 changes: 3 additions & 1 deletion src/librustc_metadata/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>>,
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,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);
Expand Down
46 changes: 31 additions & 15 deletions src/librustc_typeck/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -159,28 +160,41 @@ 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) => {
tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
}
};

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,
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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];
Expand All @@ -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;
}
};

Expand All @@ -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
}
});
})
}
3 changes: 3 additions & 0 deletions src/librustc_typeck/coherence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}
Expand Down

0 comments on commit 462e91a

Please sign in to comment.