Check for proper use of default
keyword in specializing impls.
This commit is contained in:
parent
1077ff2dec
commit
5dedbdaea4
7 changed files with 138 additions and 13 deletions
|
@ -50,7 +50,8 @@ pub use self::select::SelectionContext;
|
|||
pub use self::select::SelectionCache;
|
||||
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
||||
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
|
||||
pub use self::specialize::{Overlap, SpecializationGraph, get_impl_item_or_default, ItemSource, specializes};
|
||||
pub use self::specialize::{Overlap, SpecializationGraph, specializes};
|
||||
pub use self::specialize::{ItemSource, get_impl_item_or_default, get_parent_impl_item};
|
||||
pub use self::util::elaborate_predicates;
|
||||
pub use self::util::get_vtable_index_of_object_method;
|
||||
pub use self::util::trait_ref_for_builtin_bound;
|
||||
|
|
|
@ -299,6 +299,26 @@ pub fn get_impl_item_or_default<'tcx, I, F>(tcx: &ty::ctxt<'tcx>,
|
|||
None
|
||||
}
|
||||
|
||||
/// Convenience function for locating an item defined in a specialization parent, if any.
|
||||
pub fn get_parent_impl_item<'tcx, I, F>(tcx: &ty::ctxt<'tcx>,
|
||||
child_impl: DefId,
|
||||
f: F)
|
||||
-> Option<(I, DefId)>
|
||||
where F: for<'a> FnMut(&ImplOrTraitItem<'tcx>) -> Option<I>
|
||||
{
|
||||
let trait_def_id = tcx.trait_id_of_impl(child_impl).unwrap();
|
||||
let trait_def = tcx.lookup_trait_def(trait_def_id);
|
||||
|
||||
trait_def.parent_of_impl(child_impl)
|
||||
.and_then(|parent_impl| get_impl_item_or_default(tcx, parent_impl, f))
|
||||
.and_then(|(item, source)| {
|
||||
match source {
|
||||
ItemSource::Trait { .. } => None,
|
||||
ItemSource::Impl { actual_impl, .. } => Some((item, actual_impl)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn skolemizing_subst_for_impl<'a>(tcx: &ty::ctxt<'a>, impl_def_id: DefId) -> Substs<'a> {
|
||||
let impl_generics = tcx.lookup_item_type(impl_def_id).generics;
|
||||
|
||||
|
|
|
@ -2670,7 +2670,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
|
||||
}
|
||||
|
||||
|
||||
pub fn visit_all_items_in_krate<V,F>(&self,
|
||||
dep_node_fn: F,
|
||||
visitor: &mut V)
|
||||
|
@ -2678,6 +2677,16 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
{
|
||||
dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor);
|
||||
}
|
||||
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
|
||||
/// with the name of the crate containing the impl.
|
||||
pub fn span_of_impl(&self, impl_did: DefId) -> Result<Span, String> {
|
||||
if impl_did.is_local() {
|
||||
let node_id = self.map.as_local_node_id(impl_did).unwrap();
|
||||
Ok(self.map.span(node_id))
|
||||
} else {
|
||||
Err(self.sess.cstore.crate_name(impl_did.krate))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The category of explicit self.
|
||||
|
|
|
@ -127,7 +127,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
|
|||
|
||||
use rustc_front::intravisit::{self, Visitor};
|
||||
use rustc_front::hir;
|
||||
use rustc_front::hir::{Visibility, PatKind};
|
||||
use rustc_front::hir::{Visibility, PatKind, Defaultness};
|
||||
use rustc_front::print::pprust;
|
||||
use rustc_back::slice;
|
||||
|
||||
|
@ -864,6 +864,33 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env);
|
||||
}
|
||||
|
||||
fn check_specialization_validity<'tcx, F>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_id: DefId,
|
||||
impl_item: &hir::ImplItem,
|
||||
f: F)
|
||||
where F: FnMut(&ty::ImplOrTraitItem<'tcx>) -> Option<hir::Defaultness>
|
||||
{
|
||||
let parent_item_opt = traits::get_parent_impl_item(tcx, impl_id, f);
|
||||
if let Some((Defaultness::Final, parent_impl)) = parent_item_opt {
|
||||
span_err!(tcx.sess, impl_item.span, E0520,
|
||||
"item `{}` is provided by an implementation that \
|
||||
specializes another, but the item in the parent \
|
||||
implementations is not marked `default` and so it \
|
||||
cannot be specialized.",
|
||||
impl_item.name);
|
||||
|
||||
match tcx.span_of_impl(parent_impl) {
|
||||
Ok(span) => {
|
||||
span_note!(tcx.sess, span, "parent implementation is here:");
|
||||
}
|
||||
Err(cname) => {
|
||||
tcx.sess.note(&format!("parent implementation is in crate `{}`",
|
||||
cname));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
impl_span: Span,
|
||||
impl_id: DefId,
|
||||
|
@ -903,6 +930,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
impl_const.name,
|
||||
impl_trait_ref)
|
||||
}
|
||||
|
||||
check_specialization_validity(ccx.tcx, impl_id, impl_item, |cand| {
|
||||
if let &ty::ConstTraitItem(ref trait_const) = cand {
|
||||
if trait_const.name == impl_item.name {
|
||||
return Some(trait_const.defaultness);
|
||||
}
|
||||
}
|
||||
None
|
||||
});
|
||||
}
|
||||
hir::ImplItemKind::Method(ref sig, ref body) => {
|
||||
check_trait_fn_not_const(ccx, impl_item.span, sig.constness);
|
||||
|
@ -926,6 +962,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
impl_method.name,
|
||||
impl_trait_ref)
|
||||
}
|
||||
|
||||
check_specialization_validity(ccx.tcx, impl_id, impl_item, |cand| {
|
||||
if let &ty::MethodTraitItem(ref meth) = cand {
|
||||
if meth.name == impl_method.name {
|
||||
return Some(meth.defaultness);
|
||||
}
|
||||
}
|
||||
None
|
||||
});
|
||||
}
|
||||
hir::ImplItemKind::Type(_) => {
|
||||
let impl_type = match ty_impl_item {
|
||||
|
@ -944,6 +989,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
impl_type.name,
|
||||
impl_trait_ref)
|
||||
}
|
||||
|
||||
check_specialization_validity(ccx.tcx, impl_id, impl_item, |cand| {
|
||||
if let &ty::TypeTraitItem(ref at) = cand {
|
||||
if at.name == impl_item.name {
|
||||
return Some(at.defaultness);
|
||||
}
|
||||
}
|
||||
None
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,12 +13,10 @@
|
|||
//! constructor provide a method with the same name.
|
||||
|
||||
use middle::cstore::CrateStore;
|
||||
use middle::def_id::DefId;
|
||||
use middle::traits;
|
||||
use middle::ty::{self, TyCtxt};
|
||||
use middle::infer;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc_front::hir;
|
||||
use rustc_front::intravisit;
|
||||
|
@ -169,13 +167,14 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
|||
overlap.on_trait_ref,
|
||||
self_type);
|
||||
|
||||
if overlap.with_impl.is_local() {
|
||||
span_note!(self.tcx.sess, self.span_of_def_id(overlap.with_impl),
|
||||
"conflicting implementation is here:");
|
||||
} else {
|
||||
let cname = self.tcx.sess.cstore.crate_name(overlap.with_impl.krate);
|
||||
self.tcx.sess.note(&format!("conflicting implementation in crate `{}`",
|
||||
cname));
|
||||
match self.tcx.span_of_impl(overlap.with_impl) {
|
||||
Ok(span) => {
|
||||
span_note!(self.tcx.sess, span, "conflicting implementation is here:");
|
||||
}
|
||||
Err(cname) => {
|
||||
self.tcx.sess.note(&format!("conflicting implementation in crate `{}`",
|
||||
cname));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3696,5 +3696,6 @@ register_diagnostics! {
|
|||
// type `{}` was overridden
|
||||
E0436, // functional record update requires a struct
|
||||
E0513, // no type for local variable ..
|
||||
E0519 // redundant default implementations of trait
|
||||
E0519, // redundant default implementations of trait
|
||||
E0520 // cannot specialize non-default item
|
||||
}
|
||||
|
|
41
src/test/compile-fail/specialization-no-default.rs
Normal file
41
src/test/compile-fail/specialization-no-default.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
fn bar(&self);
|
||||
}
|
||||
|
||||
impl<T> Foo for T {
|
||||
fn foo(&self) {}
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl Foo for u8 {}
|
||||
impl Foo for u16 {
|
||||
fn foo(&self) {} //~ ERROR E0520
|
||||
}
|
||||
impl Foo for u32 {
|
||||
fn bar(&self) {} //~ ERROR E0520
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
type T;
|
||||
}
|
||||
|
||||
impl<T> Bar for T {
|
||||
type T = u8;
|
||||
}
|
||||
|
||||
impl Bar for u8 {
|
||||
type T = (); //~ ERROR E0520
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue