--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Check properties that are required by built-in traits and set
+//! up data structures required by type-checking/translation.
+
+use rustc::middle::free_region::FreeRegionMap;
+use rustc::middle::lang_items::UnsizeTraitLangItem;
+
+use rustc::traits::{self, ObligationCause, Reveal};
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::ParameterEnvironment;
+use rustc::ty::TypeFoldable;
+use rustc::ty::subst::Subst;
+use rustc::ty::util::CopyImplementationError;
+use rustc::infer;
+
+use rustc::hir::map as hir_map;
+use rustc::hir::{self, ItemImpl};
+
+pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ populate_destructors(tcx);
+ check_implementations_of_copy(tcx);
+ check_implementations_of_coerce_unsized(tcx);
+}
+
+fn populate_destructors<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ let drop_trait = match tcx.lang_items.drop_trait() {
+ Some(id) => id,
+ None => return,
+ };
+ tcx.populate_implementations_for_trait_if_necessary(drop_trait);
+ let drop_trait = tcx.lookup_trait_def(drop_trait);
+
+ drop_trait.for_each_impl(tcx, |impl_did| {
+ let items = tcx.associated_item_def_ids(impl_did);
+ if items.is_empty() {
+ // We'll error out later. For now, just don't ICE.
+ return;
+ }
+ let method_def_id = items[0];
+
+ let self_type = tcx.item_type(impl_did);
+ match self_type.sty {
+ ty::TyAdt(type_def, _) => {
+ type_def.set_destructor(method_def_id);
+ }
+ _ => {
+ // Destructors only work on nominal types.
+ if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
+ match tcx.map.find(impl_node_id) {
+ Some(hir_map::NodeItem(item)) => {
+ let span = match item.node {
+ ItemImpl(.., ref ty, _) => ty.span,
+ _ => item.span,
+ };
+ struct_span_err!(tcx.sess,
+ span,
+ E0120,
+ "the Drop trait may only be implemented on \
+ structures")
+ .span_label(span,
+ &format!("implementing Drop requires a struct"))
+ .emit();
+ }
+ _ => {
+ bug!("didn't find impl in ast map");
+ }
+ }
+ } else {
+ bug!("found external impl of Drop trait on \
+ something other than a struct");
+ }
+ }
+ }
+ });
+}
+
+fn check_implementations_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ let copy_trait = match tcx.lang_items.copy_trait() {
+ Some(id) => id,
+ None => return,
+ };
+ tcx.populate_implementations_for_trait_if_necessary(copy_trait);
+ let copy_trait = tcx.lookup_trait_def(copy_trait);
+
+ copy_trait.for_each_impl(tcx, |impl_did| {
+ debug!("check_implementations_of_copy: impl_did={:?}", impl_did);
+
+ let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+ n
+ } else {
+ debug!("check_implementations_of_copy(): impl not in this \
+ crate");
+ return;
+ };
+
+ let self_type = tcx.item_type(impl_did);
+ debug!("check_implementations_of_copy: self_type={:?} (bound)",
+ self_type);
+
+ let span = tcx.map.span(impl_node_id);
+ let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
+ let self_type = self_type.subst(tcx, ¶m_env.free_substs);
+ assert!(!self_type.has_escaping_regions());
+
+ debug!("check_implementations_of_copy: self_type={:?} (free)",
+ self_type);
+
+ match param_env.can_type_implement_copy(tcx, self_type, span) {
+ Ok(()) => {}
+ Err(CopyImplementationError::InfrigingField(name)) => {
+ struct_span_err!(tcx.sess,
+ span,
+ E0204,
+ "the trait `Copy` may not be implemented for this type")
+ .span_label(span, &format!("field `{}` does not implement `Copy`", name))
+ .emit()
+ }
+ Err(CopyImplementationError::InfrigingVariant(name)) => {
+ let item = tcx.map.expect_item(impl_node_id);
+ let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
+ tr.path.span
+ } else {
+ span
+ };
+
+ struct_span_err!(tcx.sess,
+ span,
+ E0205,
+ "the trait `Copy` may not be implemented for this type")
+ .span_label(span,
+ &format!("variant `{}` does not implement `Copy`", name))
+ .emit()
+ }
+ Err(CopyImplementationError::NotAnAdt) => {
+ let item = tcx.map.expect_item(impl_node_id);
+ let span = if let ItemImpl(.., ref ty, _) = item.node {
+ ty.span
+ } else {
+ span
+ };
+
+ struct_span_err!(tcx.sess,
+ span,
+ E0206,
+ "the trait `Copy` may not be implemented for this type")
+ .span_label(span, &format!("type is not a structure or enumeration"))
+ .emit();
+ }
+ Err(CopyImplementationError::HasDestructor) => {
+ struct_span_err!(tcx.sess,
+ span,
+ E0184,
+ "the trait `Copy` may not be implemented for this type; the \
+ type has a destructor")
+ .span_label(span, &format!("Copy not allowed on types with destructors"))
+ .emit();
+ }
+ }
+ });
+}
+
+fn check_implementations_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() {
+ Some(id) => id,
+ None => return,
+ };
+ let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
+ Ok(id) => id,
+ Err(err) => {
+ tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
+ }
+ };
+
+ let trait_def = tcx.lookup_trait_def(coerce_unsized_trait);
+
+ trait_def.for_each_impl(tcx, |impl_did| {
+ debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
+ impl_did);
+
+ let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+ n
+ } else {
+ debug!("check_implementations_of_coerce_unsized(): impl not \
+ in this crate");
+ return;
+ };
+
+ let source = tcx.item_type(impl_did);
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ let target = trait_ref.substs.type_at(1);
+ debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
+ source,
+ target);
+
+ let span = tcx.map.span(impl_node_id);
+ let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
+ let source = source.subst(tcx, ¶m_env.free_substs);
+ let target = target.subst(tcx, ¶m_env.free_substs);
+ assert!(!source.has_escaping_regions());
+
+ debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
+ source,
+ target);
+
+ tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
+ let cause = ObligationCause::misc(span, impl_node_id);
+ let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
+ mt_b: ty::TypeAndMut<'tcx>,
+ mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
+ if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
+ infcx.report_mismatched_types(&cause,
+ mk_ptr(mt_b.ty),
+ target,
+ ty::error::TypeError::Mutability)
+ .emit();
+ }
+ (mt_a.ty, mt_b.ty, unsize_trait, None)
+ };
+ let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
+ (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
+
+ (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
+ infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
+ check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
+ }
+
+ (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
+ (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
+ check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+ }
+
+ (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
+ if def_a.is_struct() && def_b.is_struct() => {
+ if def_a != def_b {
+ let source_path = tcx.item_path_str(def_a.did);
+ let target_path = tcx.item_path_str(def_b.did);
+ span_err!(tcx.sess,
+ span,
+ E0377,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures with the same \
+ definition; expected {}, found {}",
+ source_path,
+ target_path);
+ return;
+ }
+
+ let fields = &def_a.struct_variant().fields;
+ let diff_fields = fields.iter()
+ .enumerate()
+ .filter_map(|(i, f)| {
+ let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
+
+ if tcx.item_type(f.did).is_phantom_data() {
+ // Ignore PhantomData fields
+ return None;
+ }
+
+ // Ignore fields that aren't significantly changed
+ if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
+ if ok.obligations.is_empty() {
+ return None;
+ }
+ }
+
+ // Collect up all fields that were significantly changed
+ // i.e. those that contain T in coerce_unsized T -> U
+ Some((i, a, b))
+ })
+ .collect::<Vec<_>>();
+
+ if diff_fields.is_empty() {
+ span_err!(tcx.sess,
+ span,
+ E0374,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures with one field \
+ being coerced, none found");
+ return;
+ } else if diff_fields.len() > 1 {
+ let item = tcx.map.expect_item(impl_node_id);
+ let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
+ t.path.span
+ } else {
+ tcx.map.span(impl_node_id)
+ };
+
+ let mut err = struct_span_err!(tcx.sess,
+ span,
+ E0375,
+ "implementing the trait \
+ `CoerceUnsized` requires multiple \
+ coercions");
+ err.note("`CoerceUnsized` may only be implemented for \
+ a coercion between structures with one field being coerced");
+ err.note(&format!("currently, {} fields need coercions: {}",
+ diff_fields.len(),
+ diff_fields.iter()
+ .map(|&(i, a, b)| {
+ format!("{} ({} to {})", fields[i].name, a, b)
+ })
+ .collect::<Vec<_>>()
+ .join(", ")));
+ err.span_label(span, &format!("requires multiple coercions"));
+ err.emit();
+ return;
+ }
+
+ let (i, a, b) = diff_fields[0];
+ let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
+ (a, b, coerce_unsized_trait, Some(kind))
+ }
+
+ _ => {
+ span_err!(tcx.sess,
+ span,
+ E0376,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures");
+ return;
+ }
+ };
+
+ let mut fulfill_cx = traits::FulfillmentContext::new();
+
+ // Register an obligation for `A: Trait<B>`.
+ let cause = traits::ObligationCause::misc(span, impl_node_id);
+ let predicate =
+ tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
+ fulfill_cx.register_predicate_obligation(&infcx, predicate);
+
+ // Check that all transitive obligations are satisfied.
+ if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ infcx.report_fulfillment_errors(&errors);
+ }
+
+ // Finally, resolve all regions.
+ let mut free_regions = FreeRegionMap::new();
+ free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
+ .caller_bounds);
+ infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
+
+ if let Some(kind) = kind {
+ tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
+ }
+ });
+ });
+}
// mappings. That mapping code resides here.
use hir::def_id::DefId;
-use middle::lang_items::UnsizeTraitLangItem;
-use rustc::ty::subst::Subst;
+use rustc::traits::Reveal;
use rustc::ty::{self, TyCtxt, TypeFoldable};
-use rustc::traits::{self, ObligationCause, Reveal};
-use rustc::ty::ParameterEnvironment;
use rustc::ty::{Ty, TyBool, TyChar, TyError};
use rustc::ty::{TyParam, TyRawPtr};
use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
use rustc::ty::{TyProjection, TyAnon};
-use rustc::ty::util::CopyImplementationError;
-use middle::free_region::FreeRegionMap;
use CrateCtxt;
-use rustc::infer::{self, InferCtxt};
+use rustc::infer::{InferCtxt};
use syntax_pos::Span;
use rustc::dep_graph::DepNode;
-use rustc::hir::map as hir_map;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{Item, ItemImpl};
use rustc::hir;
+mod builtin;
mod orphan;
mod overlap;
mod unsafety;
self.crate_context.tcx.visit_all_item_likes_in_krate(
DepNode::CoherenceCheckImpl,
&mut CoherenceCheckVisitor { cc: self });
-
- // Populate the table of destructors. It might seem a bit strange to
- // do this here, but it's actually the most convenient place, since
- // the coherence tables contain the trait -> type mappings.
- self.populate_destructors();
-
- // Check to make sure implementations of `Copy` are legal.
- self.check_implementations_of_copy();
-
- // Check to make sure implementations of `CoerceUnsized` are legal
- // and collect the necessary information from them.
- self.check_implementations_of_coerce_unsized();
+ builtin::check(self.crate_context.tcx);
}
fn check_implementation(&self, item: &Item) {
let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
}
-
- // Destructors
- //
-
- fn populate_destructors(&self) {
- let tcx = self.crate_context.tcx;
- let drop_trait = match tcx.lang_items.drop_trait() {
- Some(id) => id,
- None => return,
- };
- tcx.populate_implementations_for_trait_if_necessary(drop_trait);
- let drop_trait = tcx.lookup_trait_def(drop_trait);
-
- drop_trait.for_each_impl(tcx, |impl_did| {
- let items = tcx.associated_item_def_ids(impl_did);
- if items.is_empty() {
- // We'll error out later. For now, just don't ICE.
- return;
- }
- let method_def_id = items[0];
-
- let self_type = tcx.item_type(impl_did);
- match self_type.sty {
- ty::TyAdt(type_def, _) => {
- type_def.set_destructor(method_def_id);
- }
- _ => {
- // Destructors only work on nominal types.
- if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
- match tcx.map.find(impl_node_id) {
- Some(hir_map::NodeItem(item)) => {
- let span = match item.node {
- ItemImpl(.., ref ty, _) => ty.span,
- _ => item.span,
- };
- struct_span_err!(tcx.sess,
- span,
- E0120,
- "the Drop trait may only be implemented on \
- structures")
- .span_label(span,
- &format!("implementing Drop requires a struct"))
- .emit();
- }
- _ => {
- bug!("didn't find impl in ast map");
- }
- }
- } else {
- bug!("found external impl of Drop trait on \
- something other than a struct");
- }
- }
- }
- });
- }
-
- /// Ensures that implementations of the built-in trait `Copy` are legal.
- fn check_implementations_of_copy(&self) {
- let tcx = self.crate_context.tcx;
- let copy_trait = match tcx.lang_items.copy_trait() {
- Some(id) => id,
- None => return,
- };
- tcx.populate_implementations_for_trait_if_necessary(copy_trait);
- let copy_trait = tcx.lookup_trait_def(copy_trait);
-
- copy_trait.for_each_impl(tcx, |impl_did| {
- debug!("check_implementations_of_copy: impl_did={:?}", impl_did);
-
- let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
- n
- } else {
- debug!("check_implementations_of_copy(): impl not in this \
- crate");
- return;
- };
-
- let self_type = tcx.item_type(impl_did);
- debug!("check_implementations_of_copy: self_type={:?} (bound)",
- self_type);
-
- let span = tcx.map.span(impl_node_id);
- let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
- let self_type = self_type.subst(tcx, ¶m_env.free_substs);
- assert!(!self_type.has_escaping_regions());
-
- debug!("check_implementations_of_copy: self_type={:?} (free)",
- self_type);
-
- match param_env.can_type_implement_copy(tcx, self_type, span) {
- Ok(()) => {}
- Err(CopyImplementationError::InfrigingField(name)) => {
- struct_span_err!(tcx.sess,
- span,
- E0204,
- "the trait `Copy` may not be implemented for this type")
- .span_label(span, &format!("field `{}` does not implement `Copy`", name))
- .emit()
- }
- Err(CopyImplementationError::InfrigingVariant(name)) => {
- let item = tcx.map.expect_item(impl_node_id);
- let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
- tr.path.span
- } else {
- span
- };
-
- struct_span_err!(tcx.sess,
- span,
- E0205,
- "the trait `Copy` may not be implemented for this type")
- .span_label(span,
- &format!("variant `{}` does not implement `Copy`", name))
- .emit()
- }
- Err(CopyImplementationError::NotAnAdt) => {
- let item = tcx.map.expect_item(impl_node_id);
- let span = if let ItemImpl(.., ref ty, _) = item.node {
- ty.span
- } else {
- span
- };
-
- struct_span_err!(tcx.sess,
- span,
- E0206,
- "the trait `Copy` may not be implemented for this type")
- .span_label(span, &format!("type is not a structure or enumeration"))
- .emit();
- }
- Err(CopyImplementationError::HasDestructor) => {
- struct_span_err!(tcx.sess,
- span,
- E0184,
- "the trait `Copy` may not be implemented for this type; the \
- type has a destructor")
- .span_label(span, &format!("Copy not allowed on types with destructors"))
- .emit();
- }
- }
- });
- }
-
- /// Process implementations of the built-in trait `CoerceUnsized`.
- fn check_implementations_of_coerce_unsized(&self) {
- let tcx = self.crate_context.tcx;
- let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() {
- Some(id) => id,
- None => return,
- };
- let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
- Ok(id) => id,
- Err(err) => {
- tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
- }
- };
-
- let trait_def = tcx.lookup_trait_def(coerce_unsized_trait);
-
- trait_def.for_each_impl(tcx, |impl_did| {
- debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
- impl_did);
-
- let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
- n
- } else {
- debug!("check_implementations_of_coerce_unsized(): impl not \
- in this crate");
- return;
- };
-
- let source = tcx.item_type(impl_did);
- let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
- let target = trait_ref.substs.type_at(1);
- debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
- source,
- target);
-
- let span = tcx.map.span(impl_node_id);
- let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
- let source = source.subst(tcx, ¶m_env.free_substs);
- let target = target.subst(tcx, ¶m_env.free_substs);
- assert!(!source.has_escaping_regions());
-
- debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
- source,
- target);
-
- tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
- let cause = ObligationCause::misc(span, impl_node_id);
- let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
- mt_b: ty::TypeAndMut<'gcx>,
- mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
- if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
- infcx.report_mismatched_types(&cause,
- mk_ptr(mt_b.ty),
- target,
- ty::error::TypeError::Mutability).emit();
- }
- (mt_a.ty, mt_b.ty, unsize_trait, None)
- };
- let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
- (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
-
- (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
- infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
- check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
- }
-
- (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
- (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
- check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
- }
-
- (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
- if def_a.is_struct() && def_b.is_struct() => {
- if def_a != def_b {
- let source_path = tcx.item_path_str(def_a.did);
- let target_path = tcx.item_path_str(def_b.did);
- span_err!(tcx.sess,
- span,
- E0377,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures with the same \
- definition; expected {}, found {}",
- source_path,
- target_path);
- return;
- }
-
- let fields = &def_a.struct_variant().fields;
- let diff_fields = fields.iter()
- .enumerate()
- .filter_map(|(i, f)| {
- let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
-
- if tcx.item_type(f.did).is_phantom_data() {
- // Ignore PhantomData fields
- return None;
- }
-
- // Ignore fields that aren't significantly changed
- if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
- if ok.obligations.is_empty() {
- return None;
- }
- }
-
- // Collect up all fields that were significantly changed
- // i.e. those that contain T in coerce_unsized T -> U
- Some((i, a, b))
- })
- .collect::<Vec<_>>();
-
- if diff_fields.is_empty() {
- span_err!(tcx.sess,
- span,
- E0374,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures with one field \
- being coerced, none found");
- return;
- } else if diff_fields.len() > 1 {
- let item = tcx.map.expect_item(impl_node_id);
- let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
- t.path.span
- } else {
- tcx.map.span(impl_node_id)
- };
-
- let mut err = struct_span_err!(tcx.sess,
- span,
- E0375,
- "implementing the trait \
- `CoerceUnsized` requires multiple \
- coercions");
- err.note("`CoerceUnsized` may only be implemented for \
- a coercion between structures with one field being coerced");
- err.note(&format!("currently, {} fields need coercions: {}",
- diff_fields.len(),
- diff_fields.iter()
- .map(|&(i, a, b)| {
- format!("{} ({} to {})", fields[i].name, a, b)
- })
- .collect::<Vec<_>>()
- .join(", ")));
- err.span_label(span, &format!("requires multiple coercions"));
- err.emit();
- return;
- }
-
- let (i, a, b) = diff_fields[0];
- let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
- (a, b, coerce_unsized_trait, Some(kind))
- }
-
- _ => {
- span_err!(tcx.sess,
- span,
- E0376,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures");
- return;
- }
- };
-
- let mut fulfill_cx = traits::FulfillmentContext::new();
-
- // Register an obligation for `A: Trait<B>`.
- let cause = traits::ObligationCause::misc(span, impl_node_id);
- let predicate =
- tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
- fulfill_cx.register_predicate_obligation(&infcx, predicate);
-
- // Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&errors);
- }
-
- // Finally, resolve all regions.
- let mut free_regions = FreeRegionMap::new();
- free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
- .caller_bounds);
- infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
-
- if let Some(kind) = kind {
- tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
- }
- });
- });
- }
}
fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {