run rustfmt on typecheck/coherence folder
This commit is contained in:
parent
95abee1a68
commit
a33b921c0d
4 changed files with 248 additions and 198 deletions
|
@ -20,7 +20,7 @@ use middle::lang_items::UnsizeTraitLangItem;
|
||||||
use rustc::ty::subst::Subst;
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::ty::{self, TyCtxt, TypeFoldable};
|
use rustc::ty::{self, TyCtxt, TypeFoldable};
|
||||||
use rustc::traits::{self, Reveal};
|
use rustc::traits::{self, Reveal};
|
||||||
use rustc::ty::{ParameterEnvironment};
|
use rustc::ty::ParameterEnvironment;
|
||||||
use rustc::ty::{Ty, TyBool, TyChar, TyError};
|
use rustc::ty::{Ty, TyBool, TyChar, TyError};
|
||||||
use rustc::ty::{TyParam, TyRawPtr};
|
use rustc::ty::{TyParam, TyRawPtr};
|
||||||
use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple};
|
use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple};
|
||||||
|
@ -44,13 +44,13 @@ mod orphan;
|
||||||
mod overlap;
|
mod overlap;
|
||||||
mod unsafety;
|
mod unsafety;
|
||||||
|
|
||||||
struct CoherenceChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
struct CoherenceChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||||
crate_context: &'a CrateCtxt<'a, 'gcx>,
|
crate_context: &'a CrateCtxt<'a, 'gcx>,
|
||||||
inference_context: InferCtxt<'a, 'gcx, 'tcx>,
|
inference_context: InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CoherenceCheckVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||||
cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>
|
cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
|
||||||
|
@ -62,36 +62,25 @@ impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, '
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Returns the def ID of the base type, if there is one.
|
// Returns the def ID of the base type, if there is one.
|
||||||
fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
|
fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
TyAdt(def, _) => {
|
TyAdt(def, _) => Some(def.did),
|
||||||
Some(def.did)
|
|
||||||
}
|
|
||||||
|
|
||||||
TyTrait(ref t) => {
|
TyTrait(ref t) => Some(t.principal.def_id()),
|
||||||
Some(t.principal.def_id())
|
|
||||||
}
|
|
||||||
|
|
||||||
TyBox(_) => {
|
TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),
|
||||||
self.inference_context.tcx.lang_items.owned_box()
|
|
||||||
}
|
|
||||||
|
|
||||||
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
|
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
|
||||||
TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
|
TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
|
||||||
TyTuple(..) | TyParam(..) | TyError | TyNever |
|
TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None,
|
||||||
TyRawPtr(_) | TyRef(..) | TyProjection(..) => {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
TyInfer(..) | TyClosure(..) | TyAnon(..) => {
|
TyInfer(..) | TyClosure(..) | TyAnon(..) => {
|
||||||
// `ty` comes from a user declaration so we should only expect types
|
// `ty` comes from a user declaration so we should only expect types
|
||||||
// that the user can type
|
// that the user can type
|
||||||
span_bug!(
|
span_bug!(span,
|
||||||
span,
|
"coherence encountered unexpected type searching for base type: {}",
|
||||||
"coherence encountered unexpected type searching for base type: {}",
|
ty);
|
||||||
ty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,9 +89,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
// Check implementations and traits. This populates the tables
|
// Check implementations and traits. This populates the tables
|
||||||
// containing the inherent methods and extension methods. It also
|
// containing the inherent methods and extension methods. It also
|
||||||
// builds up the trait inheritance table.
|
// builds up the trait inheritance table.
|
||||||
self.crate_context.tcx.visit_all_items_in_krate(
|
self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl,
|
||||||
DepNode::CoherenceCheckImpl,
|
&mut CoherenceCheckVisitor { cc: self });
|
||||||
&mut CoherenceCheckVisitor { cc: self });
|
|
||||||
|
|
||||||
// Populate the table of destructors. It might seem a bit strange to
|
// Populate the table of destructors. It might seem a bit strange to
|
||||||
// do this here, but it's actually the most convenient place, since
|
// do this here, but it's actually the most convenient place, since
|
||||||
|
@ -167,7 +155,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) {
|
fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) {
|
||||||
debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
|
debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
|
||||||
impl_trait_ref, impl_def_id);
|
impl_trait_ref,
|
||||||
|
impl_def_id);
|
||||||
let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
|
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);
|
trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
|
||||||
}
|
}
|
||||||
|
@ -176,9 +165,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
fn create_impl_from_item(&self, item: &Item) -> Vec<DefId> {
|
fn create_impl_from_item(&self, item: &Item) -> Vec<DefId> {
|
||||||
match item.node {
|
match item.node {
|
||||||
ItemImpl(.., ref impl_items) => {
|
ItemImpl(.., ref impl_items) => {
|
||||||
impl_items.iter().map(|impl_item| {
|
impl_items.iter()
|
||||||
self.crate_context.tcx.map.local_def_id(impl_item.id)
|
.map(|impl_item| self.crate_context.tcx.map.local_def_id(impl_item.id))
|
||||||
}).collect()
|
.collect()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
span_bug!(item.span, "can't convert a non-impl to an impl");
|
span_bug!(item.span, "can't convert a non-impl to an impl");
|
||||||
|
@ -186,14 +175,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Destructors
|
// Destructors
|
||||||
//
|
//
|
||||||
|
|
||||||
fn populate_destructors(&self) {
|
fn populate_destructors(&self) {
|
||||||
let tcx = self.crate_context.tcx;
|
let tcx = self.crate_context.tcx;
|
||||||
let drop_trait = match tcx.lang_items.drop_trait() {
|
let drop_trait = match tcx.lang_items.drop_trait() {
|
||||||
Some(id) => id, None => { return }
|
Some(id) => id,
|
||||||
|
None => return,
|
||||||
};
|
};
|
||||||
tcx.populate_implementations_for_trait_if_necessary(drop_trait);
|
tcx.populate_implementations_for_trait_if_necessary(drop_trait);
|
||||||
let drop_trait = tcx.lookup_trait_def(drop_trait);
|
let drop_trait = tcx.lookup_trait_def(drop_trait);
|
||||||
|
@ -219,13 +208,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
match tcx.map.find(impl_node_id) {
|
match tcx.map.find(impl_node_id) {
|
||||||
Some(hir_map::NodeItem(item)) => {
|
Some(hir_map::NodeItem(item)) => {
|
||||||
let span = match item.node {
|
let span = match item.node {
|
||||||
ItemImpl(.., ref ty, _) => {
|
ItemImpl(.., ref ty, _) => ty.span,
|
||||||
ty.span
|
_ => item.span,
|
||||||
},
|
|
||||||
_ => item.span
|
|
||||||
};
|
};
|
||||||
struct_span_err!(tcx.sess, span, E0120,
|
struct_span_err!(tcx.sess,
|
||||||
"the Drop trait may only be implemented on structures")
|
span,
|
||||||
|
E0120,
|
||||||
|
"the Drop trait may only be implemented on \
|
||||||
|
structures")
|
||||||
.span_label(span,
|
.span_label(span,
|
||||||
&format!("implementing Drop requires a struct"))
|
&format!("implementing Drop requires a struct"))
|
||||||
.emit();
|
.emit();
|
||||||
|
@ -254,15 +244,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
let copy_trait = tcx.lookup_trait_def(copy_trait);
|
let copy_trait = tcx.lookup_trait_def(copy_trait);
|
||||||
|
|
||||||
copy_trait.for_each_impl(tcx, |impl_did| {
|
copy_trait.for_each_impl(tcx, |impl_did| {
|
||||||
debug!("check_implementations_of_copy: impl_did={:?}",
|
debug!("check_implementations_of_copy: impl_did={:?}", impl_did);
|
||||||
impl_did);
|
|
||||||
|
|
||||||
let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
|
let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
|
||||||
n
|
n
|
||||||
} else {
|
} else {
|
||||||
debug!("check_implementations_of_copy(): impl not in this \
|
debug!("check_implementations_of_copy(): impl not in this \
|
||||||
crate");
|
crate");
|
||||||
return
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let self_type = tcx.lookup_item_type(impl_did);
|
let self_type = tcx.lookup_item_type(impl_did);
|
||||||
|
@ -280,14 +269,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
match param_env.can_type_implement_copy(tcx, self_type, span) {
|
match param_env.can_type_implement_copy(tcx, self_type, span) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(CopyImplementationError::InfrigingField(name)) => {
|
Err(CopyImplementationError::InfrigingField(name)) => {
|
||||||
struct_span_err!(tcx.sess, span, E0204,
|
struct_span_err!(tcx.sess,
|
||||||
"the trait `Copy` may not be implemented for \
|
span,
|
||||||
this type")
|
E0204,
|
||||||
.span_label(span, &format!(
|
"the trait `Copy` may not be implemented for this type")
|
||||||
"field `{}` does not implement `Copy`", name)
|
.span_label(span, &format!("field `{}` does not implement `Copy`", name))
|
||||||
)
|
.emit()
|
||||||
.emit()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Err(CopyImplementationError::InfrigingVariant(name)) => {
|
Err(CopyImplementationError::InfrigingVariant(name)) => {
|
||||||
let item = tcx.map.expect_item(impl_node_id);
|
let item = tcx.map.expect_item(impl_node_id);
|
||||||
|
@ -297,10 +284,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
span
|
span
|
||||||
};
|
};
|
||||||
|
|
||||||
struct_span_err!(tcx.sess, span, E0205,
|
struct_span_err!(tcx.sess,
|
||||||
|
span,
|
||||||
|
E0205,
|
||||||
"the trait `Copy` may not be implemented for this type")
|
"the trait `Copy` may not be implemented for this type")
|
||||||
.span_label(span, &format!("variant `{}` does not implement `Copy`",
|
.span_label(span,
|
||||||
name))
|
&format!("variant `{}` does not implement `Copy`", name))
|
||||||
.emit()
|
.emit()
|
||||||
}
|
}
|
||||||
Err(CopyImplementationError::NotAnAdt) => {
|
Err(CopyImplementationError::NotAnAdt) => {
|
||||||
|
@ -311,15 +300,19 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
span
|
span
|
||||||
};
|
};
|
||||||
|
|
||||||
struct_span_err!(tcx.sess, span, E0206,
|
struct_span_err!(tcx.sess,
|
||||||
|
span,
|
||||||
|
E0206,
|
||||||
"the trait `Copy` may not be implemented for this type")
|
"the trait `Copy` may not be implemented for this type")
|
||||||
.span_label(span, &format!("type is not a structure or enumeration"))
|
.span_label(span, &format!("type is not a structure or enumeration"))
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
Err(CopyImplementationError::HasDestructor) => {
|
Err(CopyImplementationError::HasDestructor) => {
|
||||||
struct_span_err!(tcx.sess, span, E0184,
|
struct_span_err!(tcx.sess,
|
||||||
"the trait `Copy` may not be implemented for this type; \
|
span,
|
||||||
the type has a destructor")
|
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"))
|
.span_label(span, &format!("Copy not allowed on types with destructors"))
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
@ -359,7 +352,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
|
let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
|
||||||
let target = trait_ref.substs.type_at(1);
|
let target = trait_ref.substs.type_at(1);
|
||||||
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
|
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
|
||||||
source, target);
|
source,
|
||||||
|
target);
|
||||||
|
|
||||||
let span = tcx.map.span(impl_node_id);
|
let span = tcx.map.span(impl_node_id);
|
||||||
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
|
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
|
||||||
|
@ -368,15 +362,19 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
assert!(!source.has_escaping_regions());
|
assert!(!source.has_escaping_regions());
|
||||||
|
|
||||||
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
|
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
|
||||||
source, target);
|
source,
|
||||||
|
target);
|
||||||
|
|
||||||
tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
|
tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
|
||||||
let origin = TypeOrigin::Misc(span);
|
let origin = TypeOrigin::Misc(span);
|
||||||
let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, mt_b: ty::TypeAndMut<'gcx>,
|
let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
|
||||||
|
mt_b: ty::TypeAndMut<'gcx>,
|
||||||
mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
|
mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
|
||||||
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
|
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
|
||||||
infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty),
|
infcx.report_mismatched_types(origin,
|
||||||
target, ty::error::TypeError::Mutability);
|
mk_ptr(mt_b.ty),
|
||||||
|
target,
|
||||||
|
ty::error::TypeError::Mutability);
|
||||||
}
|
}
|
||||||
(mt_a.ty, mt_b.ty, unsize_trait, None)
|
(mt_a.ty, mt_b.ty, unsize_trait, None)
|
||||||
};
|
};
|
||||||
|
@ -394,37 +392,45 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
|
(&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
|
||||||
if def_a.is_struct() && def_b.is_struct() => {
|
if def_a.is_struct() && def_b.is_struct() => {
|
||||||
if def_a != def_b {
|
if def_a != def_b {
|
||||||
let source_path = tcx.item_path_str(def_a.did);
|
let source_path = tcx.item_path_str(def_a.did);
|
||||||
let target_path = tcx.item_path_str(def_b.did);
|
let target_path = tcx.item_path_str(def_b.did);
|
||||||
span_err!(tcx.sess, span, E0377,
|
span_err!(tcx.sess,
|
||||||
|
span,
|
||||||
|
E0377,
|
||||||
"the trait `CoerceUnsized` may only be implemented \
|
"the trait `CoerceUnsized` may only be implemented \
|
||||||
for a coercion between structures with the same \
|
for a coercion between structures with the same \
|
||||||
definition; expected {}, found {}",
|
definition; expected {}, found {}",
|
||||||
source_path, target_path);
|
source_path,
|
||||||
|
target_path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = &def_a.struct_variant().fields;
|
let fields = &def_a.struct_variant().fields;
|
||||||
let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
|
let diff_fields = fields.iter()
|
||||||
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
|
.enumerate()
|
||||||
|
.filter_map(|(i, f)| {
|
||||||
|
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
|
||||||
|
|
||||||
if f.unsubst_ty().is_phantom_data() {
|
if f.unsubst_ty().is_phantom_data() {
|
||||||
// Ignore PhantomData fields
|
// Ignore PhantomData fields
|
||||||
None
|
None
|
||||||
} else if infcx.sub_types(false, origin, b, a).is_ok() {
|
} else if infcx.sub_types(false, origin, b, a).is_ok() {
|
||||||
// Ignore fields that aren't significantly changed
|
// Ignore fields that aren't significantly changed
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// Collect up all fields that were significantly changed
|
// Collect up all fields that were significantly changed
|
||||||
// i.e. those that contain T in coerce_unsized T -> U
|
// i.e. those that contain T in coerce_unsized T -> U
|
||||||
Some((i, a, b))
|
Some((i, a, b))
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if diff_fields.is_empty() {
|
if diff_fields.is_empty() {
|
||||||
span_err!(tcx.sess, span, E0374,
|
span_err!(tcx.sess,
|
||||||
|
span,
|
||||||
|
E0374,
|
||||||
"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");
|
||||||
|
@ -437,16 +443,22 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
tcx.map.span(impl_node_id)
|
tcx.map.span(impl_node_id)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut err = struct_span_err!(tcx.sess, span, E0375,
|
let mut err = struct_span_err!(tcx.sess,
|
||||||
"implementing the trait `CoerceUnsized` \
|
span,
|
||||||
requires multiple coercions");
|
E0375,
|
||||||
|
"implementing the trait \
|
||||||
|
`CoerceUnsized` requires multiple \
|
||||||
|
coercions");
|
||||||
err.note("`CoerceUnsized` may only be implemented for \
|
err.note("`CoerceUnsized` may only be implemented for \
|
||||||
a coercion between structures with one field being coerced");
|
a coercion between structures with one field being coerced");
|
||||||
err.note(&format!("currently, {} fields need coercions: {}",
|
err.note(&format!("currently, {} fields need coercions: {}",
|
||||||
diff_fields.len(),
|
diff_fields.len(),
|
||||||
diff_fields.iter().map(|&(i, a, b)| {
|
diff_fields.iter()
|
||||||
format!("{} ({} to {})", fields[i].name, a, b)
|
.map(|&(i, a, b)| {
|
||||||
}).collect::<Vec<_>>().join(", ") ));
|
format!("{} ({} to {})", fields[i].name, a, b)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")));
|
||||||
err.span_label(span, &format!("requires multiple coercions"));
|
err.span_label(span, &format!("requires multiple coercions"));
|
||||||
err.emit();
|
err.emit();
|
||||||
return;
|
return;
|
||||||
|
@ -458,7 +470,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
span_err!(tcx.sess, span, E0376,
|
span_err!(tcx.sess,
|
||||||
|
span,
|
||||||
|
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;
|
||||||
|
@ -469,8 +483,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Register an obligation for `A: Trait<B>`.
|
// Register an obligation for `A: Trait<B>`.
|
||||||
let cause = traits::ObligationCause::misc(span, impl_node_id);
|
let cause = traits::ObligationCause::misc(span, impl_node_id);
|
||||||
let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0,
|
let predicate =
|
||||||
source, &[target]);
|
tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
|
||||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||||
|
|
||||||
// Check that all transitive obligations are satisfied.
|
// Check that all transitive obligations are satisfied.
|
||||||
|
@ -480,8 +494,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Finally, resolve all regions.
|
// Finally, resolve all regions.
|
||||||
let mut free_regions = FreeRegionMap::new();
|
let mut free_regions = FreeRegionMap::new();
|
||||||
free_regions.relate_free_regions_from_predicates(
|
free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
|
||||||
&infcx.parameter_environment.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 {
|
if let Some(kind) = kind {
|
||||||
|
@ -495,7 +509,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||||
fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
|
fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
|
||||||
if tcx.sess.features.borrow().unboxed_closures {
|
if tcx.sess.features.borrow().unboxed_closures {
|
||||||
// the feature gate allows all of them
|
// the feature gate allows all of them
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
let did = Some(trait_def_id);
|
let did = Some(trait_def_id);
|
||||||
let li = &tcx.lang_items;
|
let li = &tcx.lang_items;
|
||||||
|
@ -507,14 +521,15 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
|
||||||
} else if did == li.fn_once_trait() {
|
} else if did == li.fn_once_trait() {
|
||||||
"FnOnce"
|
"FnOnce"
|
||||||
} else {
|
} else {
|
||||||
return // everything OK
|
return; // everything OK
|
||||||
};
|
};
|
||||||
let mut err = struct_span_err!(tcx.sess,
|
let mut err = struct_span_err!(tcx.sess,
|
||||||
sp,
|
sp,
|
||||||
E0183,
|
E0183,
|
||||||
"manual implementations of `{}` are experimental",
|
"manual implementations of `{}` are experimental",
|
||||||
trait_name);
|
trait_name);
|
||||||
help!(&mut err, "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
help!(&mut err,
|
||||||
|
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,9 +537,10 @@ pub fn check_coherence(ccx: &CrateCtxt) {
|
||||||
let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
|
let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
|
||||||
ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
|
ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
|
||||||
CoherenceChecker {
|
CoherenceChecker {
|
||||||
crate_context: ccx,
|
crate_context: ccx,
|
||||||
inference_context: infcx,
|
inference_context: infcx,
|
||||||
}.check();
|
}
|
||||||
|
.check();
|
||||||
});
|
});
|
||||||
unsafety::check(ccx.tcx);
|
unsafety::check(ccx.tcx);
|
||||||
orphan::check(ccx.tcx);
|
orphan::check(ccx.tcx);
|
||||||
|
|
|
@ -25,17 +25,20 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||||
tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
|
tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OrphanChecker<'cx, 'tcx:'cx> {
|
struct OrphanChecker<'cx, 'tcx: 'cx> {
|
||||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>
|
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
|
fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
|
||||||
if def_id.krate != LOCAL_CRATE {
|
if def_id.krate != LOCAL_CRATE {
|
||||||
struct_span_err!(self.tcx.sess, item.span, E0116,
|
struct_span_err!(self.tcx.sess,
|
||||||
"cannot define inherent `impl` for a type outside of the \
|
item.span,
|
||||||
crate where the type is defined")
|
E0116,
|
||||||
.span_label(item.span, &format!("impl for type defined outside of crate."))
|
"cannot define inherent `impl` for a type outside of the crate \
|
||||||
|
where the type is defined")
|
||||||
|
.span_label(item.span,
|
||||||
|
&format!("impl for type defined outside of crate."))
|
||||||
.note("define and implement a trait or new type instead")
|
.note("define and implement a trait or new type instead")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
@ -48,11 +51,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
ty: &str,
|
ty: &str,
|
||||||
span: Span) {
|
span: Span) {
|
||||||
match lang_def_id {
|
match lang_def_id {
|
||||||
Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ },
|
Some(lang_def_id) if lang_def_id == impl_def_id => {
|
||||||
|
// OK
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(self.tcx.sess, span, E0390,
|
struct_span_err!(self.tcx.sess,
|
||||||
"only a single inherent implementation marked with `#[lang = \"{}\"]` \
|
span,
|
||||||
is allowed for the `{}` primitive", lang, ty)
|
E0390,
|
||||||
|
"only a single inherent implementation marked with `#[lang = \
|
||||||
|
\"{}\"]` is allowed for the `{}` primitive",
|
||||||
|
lang,
|
||||||
|
ty)
|
||||||
.span_help(span, "consider using a trait to implement these methods")
|
.span_help(span, "consider using a trait to implement these methods")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
@ -209,12 +218,14 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(self.tcx.sess, ty.span, E0118,
|
struct_span_err!(self.tcx.sess,
|
||||||
|
ty.span,
|
||||||
|
E0118,
|
||||||
"no base type found for inherent implementation")
|
"no base type found for inherent implementation")
|
||||||
.span_label(ty.span, &format!("impl requires a base type"))
|
.span_label(ty.span, &format!("impl requires a base type"))
|
||||||
.note(&format!("either implement a trait on it or create a newtype \
|
.note(&format!("either implement a trait on it or create a newtype \
|
||||||
to wrap it instead"))
|
to wrap it instead"))
|
||||||
.emit();
|
.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,20 +237,23 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
|
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
|
||||||
let trait_def_id = trait_ref.def_id;
|
let trait_def_id = trait_ref.def_id;
|
||||||
match traits::orphan_check(self.tcx, def_id) {
|
match traits::orphan_check(self.tcx, def_id) {
|
||||||
Ok(()) => { }
|
Ok(()) => {}
|
||||||
Err(traits::OrphanCheckErr::NoLocalInputType) => {
|
Err(traits::OrphanCheckErr::NoLocalInputType) => {
|
||||||
struct_span_err!(
|
struct_span_err!(self.tcx.sess,
|
||||||
self.tcx.sess, item.span, E0117,
|
item.span,
|
||||||
"only traits defined in the current crate can be \
|
E0117,
|
||||||
implemented for arbitrary types")
|
"only traits defined in the current crate can be \
|
||||||
.span_label(item.span, &format!("impl doesn't use types inside crate"))
|
implemented for arbitrary types")
|
||||||
.note(&format!("the impl does not reference any \
|
.span_label(item.span, &format!("impl doesn't use types inside crate"))
|
||||||
types defined in this crate"))
|
.note(&format!("the impl does not reference any types defined in \
|
||||||
.emit();
|
this crate"))
|
||||||
|
.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
|
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
|
||||||
span_err!(self.tcx.sess, item.span, E0210,
|
span_err!(self.tcx.sess,
|
||||||
|
item.span,
|
||||||
|
E0210,
|
||||||
"type parameter `{}` must be used as the type parameter for \
|
"type parameter `{}` must be used as the type parameter for \
|
||||||
some local type (e.g. `MyStruct<T>`); only traits defined in \
|
some local type (e.g. `MyStruct<T>`); only traits defined in \
|
||||||
the current crate can be implemented for a type parameter",
|
the current crate can be implemented for a type parameter",
|
||||||
|
@ -285,10 +299,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
self.tcx.trait_has_default_impl(trait_def_id));
|
self.tcx.trait_has_default_impl(trait_def_id));
|
||||||
if
|
if self.tcx.trait_has_default_impl(trait_def_id) &&
|
||||||
self.tcx.trait_has_default_impl(trait_def_id) &&
|
trait_def_id.krate != LOCAL_CRATE {
|
||||||
trait_def_id.krate != LOCAL_CRATE
|
|
||||||
{
|
|
||||||
let self_ty = trait_ref.self_ty();
|
let self_ty = trait_ref.self_ty();
|
||||||
let opt_self_def_id = match self_ty.sty {
|
let opt_self_def_id = match self_ty.sty {
|
||||||
ty::TyAdt(self_def, _) => Some(self_def.did),
|
ty::TyAdt(self_def, _) => Some(self_def.did),
|
||||||
|
@ -305,20 +317,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
if self_def_id.is_local() {
|
if self_def_id.is_local() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(format!(
|
Some(format!("cross-crate traits with a default impl, like `{}`, \
|
||||||
"cross-crate traits with a default impl, like `{}`, \
|
can only be implemented for a struct/enum type \
|
||||||
can only be implemented for a struct/enum type \
|
defined in the current crate",
|
||||||
defined in the current crate",
|
self.tcx.item_path_str(trait_def_id)))
|
||||||
self.tcx.item_path_str(trait_def_id)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
Some(format!(
|
Some(format!("cross-crate traits with a default impl, like `{}`, can \
|
||||||
"cross-crate traits with a default impl, like `{}`, \
|
only be implemented for a struct/enum type, not `{}`",
|
||||||
can only be implemented for a struct/enum type, \
|
self.tcx.item_path_str(trait_def_id),
|
||||||
not `{}`",
|
self_ty))
|
||||||
self.tcx.item_path_str(trait_def_id),
|
|
||||||
self_ty))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -330,14 +339,18 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
|
|
||||||
// Disallow *all* explicit impls of `Sized` and `Unsize` for now.
|
// Disallow *all* explicit impls of `Sized` and `Unsize` for now.
|
||||||
if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
|
if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
|
||||||
struct_span_err!(self.tcx.sess, item.span, E0322,
|
struct_span_err!(self.tcx.sess,
|
||||||
"explicit impls for the `Sized` trait are not permitted")
|
item.span,
|
||||||
|
E0322,
|
||||||
|
"explicit impls for the `Sized` trait are not permitted")
|
||||||
.span_label(item.span, &format!("impl of 'Sized' not allowed"))
|
.span_label(item.span, &format!("impl of 'Sized' not allowed"))
|
||||||
.emit();
|
.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
|
if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
|
||||||
span_err!(self.tcx.sess, item.span, E0328,
|
span_err!(self.tcx.sess,
|
||||||
|
item.span,
|
||||||
|
E0328,
|
||||||
"explicit impls for the `Unsize` trait are not permitted");
|
"explicit impls for the `Unsize` trait are not permitted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -348,9 +361,11 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
self.tcx.map.node_to_string(item.id));
|
self.tcx.map.node_to_string(item.id));
|
||||||
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
|
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
|
||||||
if trait_ref.def_id.krate != LOCAL_CRATE {
|
if trait_ref.def_id.krate != LOCAL_CRATE {
|
||||||
struct_span_err!(self.tcx.sess, item_trait_ref.path.span, E0318,
|
struct_span_err!(self.tcx.sess,
|
||||||
"cannot create default implementations for traits outside the \
|
item_trait_ref.path.span,
|
||||||
crate they're defined in; define a new trait instead")
|
E0318,
|
||||||
|
"cannot create default implementations for traits outside \
|
||||||
|
the crate they're defined in; define a new trait instead")
|
||||||
.span_label(item_trait_ref.path.span,
|
.span_label(item_trait_ref.path.span,
|
||||||
&format!("`{}` trait not defined in this crate",
|
&format!("`{}` trait not defined in this crate",
|
||||||
item_trait_ref.path))
|
item_trait_ref.path))
|
||||||
|
@ -365,7 +380,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
|
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &hir::Item) {
|
fn visit_item(&mut self, item: &hir::Item) {
|
||||||
self.check_item(item);
|
self.check_item(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,15 +23,17 @@ use util::nodemap::DefIdMap;
|
||||||
use lint;
|
use lint;
|
||||||
|
|
||||||
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||||
let mut overlap = OverlapChecker { tcx: tcx,
|
let mut overlap = OverlapChecker {
|
||||||
default_impls: DefIdMap() };
|
tcx: tcx,
|
||||||
|
default_impls: DefIdMap(),
|
||||||
|
};
|
||||||
|
|
||||||
// this secondary walk specifically checks for some other cases,
|
// this secondary walk specifically checks for some other cases,
|
||||||
// like defaulted traits, for which additional overlap rules exist
|
// like defaulted traits, for which additional overlap rules exist
|
||||||
tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
|
tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OverlapChecker<'cx, 'tcx:'cx> {
|
struct OverlapChecker<'cx, 'tcx: 'cx> {
|
||||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||||
|
|
||||||
// maps from a trait def-id to an impl id
|
// maps from a trait def-id to an impl id
|
||||||
|
@ -41,18 +43,21 @@ struct OverlapChecker<'cx, 'tcx:'cx> {
|
||||||
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||||
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
|
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
enum Namespace { Type, Value }
|
enum Namespace {
|
||||||
|
Type,
|
||||||
|
Value,
|
||||||
|
}
|
||||||
|
|
||||||
fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
def_id: DefId)
|
def_id: DefId)
|
||||||
-> (ast::Name, Namespace)
|
-> (ast::Name, Namespace) {
|
||||||
{
|
|
||||||
let item = tcx.impl_or_trait_item(def_id);
|
let item = tcx.impl_or_trait_item(def_id);
|
||||||
(item.name(), match item {
|
(item.name(),
|
||||||
ty::TypeTraitItem(..) => Namespace::Type,
|
match item {
|
||||||
ty::ConstTraitItem(..) => Namespace::Value,
|
ty::TypeTraitItem(..) => Namespace::Type,
|
||||||
ty::MethodTraitItem(..) => Namespace::Value,
|
ty::ConstTraitItem(..) => Namespace::Value,
|
||||||
})
|
ty::MethodTraitItem(..) => Namespace::Value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow();
|
let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow();
|
||||||
|
@ -79,11 +84,11 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||||
let inherent_impls = self.tcx.inherent_impls.borrow();
|
let inherent_impls = self.tcx.inherent_impls.borrow();
|
||||||
let impls = match inherent_impls.get(&ty_def_id) {
|
let impls = match inherent_impls.get(&ty_def_id) {
|
||||||
Some(impls) => impls,
|
Some(impls) => impls,
|
||||||
None => return
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, &impl1_def_id) in impls.iter().enumerate() {
|
for (i, &impl1_def_id) in impls.iter().enumerate() {
|
||||||
for &impl2_def_id in &impls[(i+1)..] {
|
for &impl2_def_id in &impls[(i + 1)..] {
|
||||||
self.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
|
self.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
|
||||||
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
|
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
|
||||||
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
|
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
|
||||||
|
@ -94,10 +99,12 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &'v hir::Item) {
|
fn visit_item(&mut self, item: &'v hir::Item) {
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
|
hir::ItemEnum(..) |
|
||||||
|
hir::ItemStruct(..) |
|
||||||
|
hir::ItemUnion(..) => {
|
||||||
let type_def_id = self.tcx.map.local_def_id(item.id);
|
let type_def_id = self.tcx.map.local_def_id(item.id);
|
||||||
self.check_for_overlapping_inherent_impls(type_def_id);
|
self.check_for_overlapping_inherent_impls(type_def_id);
|
||||||
}
|
}
|
||||||
|
@ -111,12 +118,14 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
|
|
||||||
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
|
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
|
||||||
if let Some(prev_id) = prev_default_impl {
|
if let Some(prev_id) = prev_default_impl {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(self.tcx.sess,
|
||||||
self.tcx.sess,
|
self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||||
self.tcx.span_of_impl(impl_def_id).unwrap(), E0521,
|
E0521,
|
||||||
"redundant default implementations of trait `{}`:",
|
"redundant default implementations of trait \
|
||||||
trait_ref);
|
`{}`:",
|
||||||
err.span_note(self.tcx.span_of_impl(self.tcx.map.local_def_id(prev_id))
|
trait_ref);
|
||||||
|
err.span_note(self.tcx
|
||||||
|
.span_of_impl(self.tcx.map.local_def_id(prev_id))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"redundant implementation is here:");
|
"redundant implementation is here:");
|
||||||
err.emit();
|
err.emit();
|
||||||
|
@ -127,8 +136,8 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
|
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||||
let trait_def_id = trait_ref.def_id;
|
let trait_def_id = trait_ref.def_id;
|
||||||
|
|
||||||
let _task = self.tcx.dep_graph.in_task(
|
let _task =
|
||||||
DepNode::CoherenceOverlapCheck(trait_def_id));
|
self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
|
||||||
|
|
||||||
let def = self.tcx.lookup_trait_def(trait_def_id);
|
let def = self.tcx.lookup_trait_def(trait_def_id);
|
||||||
|
|
||||||
|
@ -137,17 +146,19 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
|
|
||||||
// insertion failed due to overlap
|
// insertion failed due to overlap
|
||||||
if let Err(overlap) = insert_result {
|
if let Err(overlap) = insert_result {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(self.tcx.sess,
|
||||||
self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119,
|
self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||||
"conflicting implementations of trait `{}`{}:",
|
E0119,
|
||||||
overlap.trait_desc,
|
"conflicting implementations of trait `{}`{}:",
|
||||||
overlap.self_desc.clone().map_or(String::new(),
|
overlap.trait_desc,
|
||||||
|ty| format!(" for type `{}`", ty)));
|
overlap.self_desc.clone().map_or(String::new(),
|
||||||
|
|ty| {
|
||||||
|
format!(" for type `{}`", ty)
|
||||||
|
}));
|
||||||
|
|
||||||
match self.tcx.span_of_impl(overlap.with_impl) {
|
match self.tcx.span_of_impl(overlap.with_impl) {
|
||||||
Ok(span) => {
|
Ok(span) => {
|
||||||
err.span_label(span,
|
err.span_label(span, &format!("first implementation here"));
|
||||||
&format!("first implementation here"));
|
|
||||||
err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
|
err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||||
&format!("conflicting implementation{}",
|
&format!("conflicting implementation{}",
|
||||||
overlap.self_desc
|
overlap.self_desc
|
||||||
|
@ -155,8 +166,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
|ty| format!(" for `{}`", ty))));
|
|ty| format!(" for `{}`", ty))));
|
||||||
}
|
}
|
||||||
Err(cname) => {
|
Err(cname) => {
|
||||||
err.note(&format!("conflicting implementation in crate `{}`",
|
err.note(&format!("conflicting implementation in crate `{}`", cname));
|
||||||
cname));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +187,9 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
let mut supertrait_def_ids =
|
let mut supertrait_def_ids =
|
||||||
traits::supertrait_def_ids(self.tcx, data.principal.def_id());
|
traits::supertrait_def_ids(self.tcx, data.principal.def_id());
|
||||||
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
||||||
span_err!(self.tcx.sess, item.span, E0371,
|
span_err!(self.tcx.sess,
|
||||||
|
item.span,
|
||||||
|
E0371,
|
||||||
"the object type `{}` automatically \
|
"the object type `{}` automatically \
|
||||||
implements the trait `{}`",
|
implements the trait `{}`",
|
||||||
trait_ref.self_ty(),
|
trait_ref.self_ty(),
|
||||||
|
|
|
@ -20,21 +20,26 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||||
tcx.map.krate().visit_all_items(&mut orphan);
|
tcx.map.krate().visit_all_items(&mut orphan);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UnsafetyChecker<'cx, 'tcx:'cx> {
|
struct UnsafetyChecker<'cx, 'tcx: 'cx> {
|
||||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>
|
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
|
impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
|
||||||
fn check_unsafety_coherence(&mut self, item: &'v hir::Item,
|
fn check_unsafety_coherence(&mut self,
|
||||||
|
item: &'v hir::Item,
|
||||||
unsafety: hir::Unsafety,
|
unsafety: hir::Unsafety,
|
||||||
polarity: hir::ImplPolarity) {
|
polarity: hir::ImplPolarity) {
|
||||||
match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) {
|
match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) {
|
||||||
None => {
|
None => {
|
||||||
// Inherent impl.
|
// Inherent impl.
|
||||||
match unsafety {
|
match unsafety {
|
||||||
hir::Unsafety::Normal => { /* OK */ }
|
hir::Unsafety::Normal => {
|
||||||
|
// OK
|
||||||
|
}
|
||||||
hir::Unsafety::Unsafe => {
|
hir::Unsafety::Unsafe => {
|
||||||
span_err!(self.tcx.sess, item.span, E0197,
|
span_err!(self.tcx.sess,
|
||||||
|
item.span,
|
||||||
|
E0197,
|
||||||
"inherent impls cannot be declared as unsafe");
|
"inherent impls cannot be declared as unsafe");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,31 +48,33 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
|
||||||
Some(trait_ref) => {
|
Some(trait_ref) => {
|
||||||
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
|
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
|
||||||
match (trait_def.unsafety, unsafety, polarity) {
|
match (trait_def.unsafety, unsafety, polarity) {
|
||||||
(hir::Unsafety::Unsafe,
|
(hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
|
||||||
hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
|
span_err!(self.tcx.sess,
|
||||||
span_err!(self.tcx.sess, item.span, E0198,
|
item.span,
|
||||||
|
E0198,
|
||||||
"negative implementations are not unsafe");
|
"negative implementations are not unsafe");
|
||||||
}
|
}
|
||||||
|
|
||||||
(hir::Unsafety::Normal, hir::Unsafety::Unsafe, _) => {
|
(hir::Unsafety::Normal, hir::Unsafety::Unsafe, _) => {
|
||||||
span_err!(self.tcx.sess, item.span, E0199,
|
span_err!(self.tcx.sess,
|
||||||
|
item.span,
|
||||||
|
E0199,
|
||||||
"implementing the trait `{}` is not unsafe",
|
"implementing the trait `{}` is not unsafe",
|
||||||
trait_ref);
|
trait_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
(hir::Unsafety::Unsafe,
|
(hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
||||||
hir::Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
span_err!(self.tcx.sess,
|
||||||
span_err!(self.tcx.sess, item.span, E0200,
|
item.span,
|
||||||
|
E0200,
|
||||||
"the trait `{}` requires an `unsafe impl` declaration",
|
"the trait `{}` requires an `unsafe impl` declaration",
|
||||||
trait_ref);
|
trait_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
(hir::Unsafety::Unsafe,
|
(hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Negative) |
|
||||||
hir::Unsafety::Normal, hir::ImplPolarity::Negative) |
|
(hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) |
|
||||||
(hir::Unsafety::Unsafe,
|
|
||||||
hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) |
|
|
||||||
(hir::Unsafety::Normal, hir::Unsafety::Normal, _) => {
|
(hir::Unsafety::Normal, hir::Unsafety::Normal, _) => {
|
||||||
/* OK */
|
// OK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +82,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &'v hir::Item) {
|
fn visit_item(&mut self, item: &'v hir::Item) {
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ItemDefaultImpl(unsafety, _) => {
|
hir::ItemDefaultImpl(unsafety, _) => {
|
||||||
|
@ -84,7 +91,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
||||||
hir::ItemImpl(unsafety, polarity, ..) => {
|
hir::ItemImpl(unsafety, polarity, ..) => {
|
||||||
self.check_unsafety_coherence(item, unsafety, polarity);
|
self.check_unsafety_coherence(item, unsafety, polarity);
|
||||||
}
|
}
|
||||||
_ => { }
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue