1
Fork 0

Check for proper use of default keyword in specializing impls.

This commit is contained in:
Aaron Turon 2015-12-29 10:55:34 -08:00
parent 1077ff2dec
commit 5dedbdaea4
7 changed files with 138 additions and 13 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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.

View file

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

View file

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

View file

@ -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
}

View 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() {}