Skip to content

Commit 462e91a

Browse files
committed
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.
1 parent 7c3d2f7 commit 462e91a

File tree

10 files changed

+78
-34
lines changed

10 files changed

+78
-34
lines changed

Diff for: src/librustc/ty/adjustment.rs

+15
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,21 @@ pub enum AutoBorrow<'tcx> {
139139
RawPtr(hir::Mutability),
140140
}
141141

142+
/// Information for `CoerceUnsized` impls, storing information we
143+
/// have computed about the coercion.
144+
///
145+
/// This struct can be obtained via the `coerce_impl_info` query.
146+
/// Demanding this struct also has the side-effect of reporting errors
147+
/// for inappropriate impls.
148+
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
149+
pub struct CoerceUnsizedInfo {
150+
/// If this is a "custom coerce" impl, then what kind of custom
151+
/// coercion is it? This applies to impls of `CoerceUnsized` for
152+
/// structs, primarily, where we store a bit of info about which
153+
/// fields need to be coerced.
154+
pub custom_kind: Option<CustomCoerceUnsized>
155+
}
156+
142157
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
143158
pub enum CustomCoerceUnsized {
144159
/// Records the index of the field being coerced.

Diff for: src/librustc/ty/maps.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ macro_rules! define_maps {
252252
provider(tcx.global_tcx(), key)
253253
})?;
254254

255-
Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result)))
255+
Ok(f(&tcx.maps.$name.borrow_mut().__entry__(key).or_insert(result)))
256256
}
257257

258258
pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K)
@@ -376,8 +376,8 @@ define_maps! { <'tcx>
376376
pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
377377

378378
/// Caches CoerceUnsized kinds for impls on custom types.
379-
pub custom_coerce_unsized_kind: ItemSignature(DefId)
380-
-> ty::adjustment::CustomCoerceUnsized,
379+
pub coerce_unsized_info: ItemSignature(DefId)
380+
-> ty::adjustment::CoerceUnsizedInfo,
381381

382382
pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
383383

Diff for: src/librustc/ty/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2030,8 +2030,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
20302030
})
20312031
}
20322032

2033-
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
2034-
queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did)
2033+
pub fn coerce_unsized_info(self, did: DefId) -> adjustment::CoerceUnsizedInfo {
2034+
queries::coerce_unsized_info::get(self, DUMMY_SP, did)
20352035
}
20362036

20372037
pub fn associated_item(self, def_id: DefId) -> AssociatedItem {

Diff for: src/librustc_metadata/cstore_impl.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ provide! { <'tcx> tcx, def_id, cdata
8888
}
8989
associated_item => { cdata.get_associated_item(def_id.index) }
9090
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
91-
custom_coerce_unsized_kind => {
92-
cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| {
93-
bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id);
91+
coerce_unsized_info => {
92+
cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
93+
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
9494
})
9595
}
9696
mir => {

Diff for: src/librustc_metadata/decoder.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -651,10 +651,10 @@ impl<'a, 'tcx> CrateMetadata {
651651
self.get_impl_data(id).polarity
652652
}
653653

654-
pub fn get_custom_coerce_unsized_kind(&self,
655-
id: DefIndex)
656-
-> Option<ty::adjustment::CustomCoerceUnsized> {
657-
self.get_impl_data(id).coerce_unsized_kind
654+
pub fn get_coerce_unsized_info(&self,
655+
id: DefIndex)
656+
-> Option<ty::adjustment::CoerceUnsizedInfo> {
657+
self.get_impl_data(id).coerce_unsized_info
658658
}
659659

660660
pub fn get_impl_trait(&self,

Diff for: src/librustc_metadata/encoder.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
695695
let data = ImplData {
696696
polarity: hir::ImplPolarity::Positive,
697697
parent_impl: None,
698-
coerce_unsized_kind: None,
698+
coerce_unsized_info: None,
699699
trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)),
700700
};
701701

@@ -715,13 +715,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
715715
None
716716
};
717717

718+
// if this is an impl of `CoerceUnsized`, create its
719+
// "unsized info", else just store None
720+
let coerce_unsized_info =
721+
trait_ref.and_then(|t| {
722+
if Some(t.def_id) == tcx.lang_items.coerce_unsized_trait() {
723+
Some(ty::queries::coerce_unsized_info::get(tcx, item.span, def_id))
724+
} else {
725+
None
726+
}
727+
});
728+
718729
let data = ImplData {
719730
polarity: polarity,
720731
parent_impl: parent,
721-
coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind
722-
.borrow()
723-
.get(&def_id)
724-
.cloned(),
732+
coerce_unsized_info: coerce_unsized_info,
725733
trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)),
726734
};
727735

Diff for: src/librustc_metadata/schema.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,9 @@ pub struct TraitData<'tcx> {
285285
pub struct ImplData<'tcx> {
286286
pub polarity: hir::ImplPolarity,
287287
pub parent_impl: Option<DefId>,
288-
pub coerce_unsized_kind: Option<ty::adjustment::CustomCoerceUnsized>,
288+
289+
/// This is `Some` only for impls of `CoerceUnsized`.
290+
pub coerce_unsized_info: Option<ty::adjustment::CoerceUnsizedInfo>,
289291
pub trait_ref: Option<Lazy<ty::TraitRef<'tcx>>>,
290292
}
291293

Diff for: src/librustc_trans/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
328328

329329
match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
330330
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
331-
scx.tcx().custom_coerce_unsized_kind(impl_def_id)
331+
scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap()
332332
}
333333
vtable => {
334334
bug!("invalid CoerceUnsized vtable: {:?}", vtable);

Diff for: src/librustc_typeck/coherence/builtin.rs

+31-15
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc::traits::{self, ObligationCause, Reveal};
1818
use rustc::ty::{self, Ty, TyCtxt};
1919
use rustc::ty::ParameterEnvironment;
2020
use rustc::ty::TypeFoldable;
21+
use rustc::ty::adjustment::CoerceUnsizedInfo;
2122
use rustc::ty::subst::Subst;
2223
use rustc::ty::util::CopyImplementationError;
2324
use rustc::infer;
@@ -159,28 +160,41 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
159160
}
160161

161162
fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
162-
coerce_unsized_trait: DefId,
163+
_: DefId,
163164
impl_did: DefId) {
164165
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
165166
impl_did);
166167

168+
// Just compute this for the side-effects, in particular reporting
169+
// errors; other parts of the code may demand it for the info of
170+
// course.
171+
if impl_did.is_local() {
172+
let span = tcx.def_span(impl_did);
173+
ty::queries::coerce_unsized_info::get(tcx, span, impl_did);
174+
}
175+
}
176+
177+
pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
178+
impl_did: DefId)
179+
-> CoerceUnsizedInfo {
180+
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
181+
let coerce_unsized_trait = tcx.lang_items.coerce_unsized_trait().unwrap();
182+
167183
let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
168184
Ok(id) => id,
169185
Err(err) => {
170186
tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
171187
}
172188
};
173189

174-
let impl_node_id = if let Some(n) = tcx.hir.as_local_node_id(impl_did) {
175-
n
176-
} else {
177-
debug!("visit_implementation_of_coerce_unsized(): impl not \
178-
in this crate");
179-
return;
180-
};
190+
// this provider should only get invoked for local def-ids
191+
let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| {
192+
bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did)
193+
});
181194

182195
let source = tcx.item_type(impl_did);
183196
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
197+
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
184198
let target = trait_ref.substs.type_at(1);
185199
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
186200
source,
@@ -192,6 +206,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
192206
let target = target.subst(tcx, &param_env.free_substs);
193207
assert!(!source.has_escaping_regions());
194208

209+
let err_info = CoerceUnsizedInfo { custom_kind: None };
210+
195211
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
196212
source,
197213
target);
@@ -234,7 +250,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
234250
definition; expected {}, found {}",
235251
source_path,
236252
target_path);
237-
return;
253+
return err_info;
238254
}
239255

240256
let fields = &def_a.struct_variant().fields;
@@ -268,7 +284,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
268284
"the trait `CoerceUnsized` may only be implemented \
269285
for a coercion between structures with one field \
270286
being coerced, none found");
271-
return;
287+
return err_info;
272288
} else if diff_fields.len() > 1 {
273289
let item = tcx.hir.expect_item(impl_node_id);
274290
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>,
295311
.join(", ")));
296312
err.span_label(span, &format!("requires multiple coercions"));
297313
err.emit();
298-
return;
314+
return err_info;
299315
}
300316

301317
let (i, a, b) = diff_fields[0];
@@ -309,7 +325,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
309325
E0376,
310326
"the trait `CoerceUnsized` may only be implemented \
311327
for a coercion between structures");
312-
return;
328+
return err_info;
313329
}
314330
};
315331

@@ -331,8 +347,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
331347
.caller_bounds);
332348
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
333349

334-
if let Some(kind) = kind {
335-
tcx.maps.custom_coerce_unsized_kind.borrow_mut().__insert__(impl_did, kind);
350+
CoerceUnsizedInfo {
351+
custom_kind: kind
336352
}
337-
});
353+
})
338354
}

Diff for: src/librustc_typeck/coherence/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,12 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d
102102
}
103103

104104
pub fn provide(providers: &mut Providers) {
105+
use self::builtin::coerce_unsized_info;
106+
105107
*providers = Providers {
106108
coherent_trait,
107109
coherent_inherent_impls,
110+
coerce_unsized_info,
108111
..*providers
109112
};
110113
}

0 commit comments

Comments
 (0)