Skip to content

Commit

Permalink
early-prohibit objects with Self-containing supertraits
Browse files Browse the repository at this point in the history
Fixes #28576
  • Loading branch information
Ariel Ben-Yehuda committed Sep 24, 2015
1 parent 8fe79bd commit 77e8f33
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 13 deletions.
10 changes: 8 additions & 2 deletions src/librustc/middle/traits/error_reporting.rs
Expand Up @@ -248,9 +248,12 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}

ty::Predicate::ObjectSafe(trait_def_id) => {
let violations = object_safety_violations(
infcx.tcx, trait_def_id);
report_object_safety_error(infcx.tcx,
obligation.cause.span,
trait_def_id,
violations,
is_warning);
note_obligation_cause(infcx, obligation);
}
Expand Down Expand Up @@ -286,7 +289,9 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}

TraitNotObjectSafe(did) => {
report_object_safety_error(infcx.tcx, obligation.cause.span, did, is_warning);
let violations = object_safety_violations(infcx.tcx, did);
report_object_safety_error(infcx.tcx, obligation.cause.span, did,
violations, is_warning);
note_obligation_cause(infcx, obligation);
}
}
Expand All @@ -295,14 +300,15 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
trait_def_id: DefId,
violations: Vec<ObjectSafetyViolation>,
is_warning: bool)
{
span_err_or_warn!(
is_warning, tcx.sess, span, E0038,
"the trait `{}` cannot be made into an object",
tcx.item_path_str(trait_def_id));

for violation in object_safety_violations(tcx, trait_def_id) {
for violation in violations {
match violation {
ObjectSafetyViolation::SizedSelf => {
tcx.sess.fileline_note(
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/traits/mod.rs
Expand Up @@ -37,6 +37,7 @@ pub use self::project::MismatchedProjectionTypes;
pub use self::project::normalize;
pub use self::project::Normalized;
pub use self::object_safety::is_object_safe;
pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::object_safety_violations;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::object_safety::MethodViolationCode;
Expand Down
27 changes: 24 additions & 3 deletions src/librustc/middle/traits/object_safety.rs
Expand Up @@ -76,6 +76,27 @@ pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>,
result
}

/// Returns the object safety violations that affect
/// astconv - currently, Self in supertraits. This is needed
/// because `object_safety_violations` can't be used during
/// type collection.
pub fn astconv_object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: DefId)
-> Vec<ObjectSafetyViolation<'tcx>>
{
let mut violations = vec![];

if supertraits_reference_self(tcx, trait_def_id) {
violations.push(ObjectSafetyViolation::SupertraitSelf);
}

debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
trait_def_id,
violations);

violations
}

pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: DefId)
-> Vec<ObjectSafetyViolation<'tcx>>
Expand Down Expand Up @@ -118,9 +139,9 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
violations
}

fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: DefId)
-> bool
pub fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: DefId)
-> bool
{
let trait_def = tcx.lookup_trait_def(trait_def_id);
let trait_ref = trait_def.trait_ref.clone();
Expand Down
21 changes: 19 additions & 2 deletions src/librustc_typeck/astconv.rs
Expand Up @@ -393,7 +393,7 @@ fn create_substs_for_ast_path<'tcx>(
let tcx = this.tcx();

debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
types_provided={:?}, region_substs={:?}",
types_provided={:?}, region_substs={:?})",
decl_generics, self_ty, types_provided,
region_substs);

Expand Down Expand Up @@ -474,6 +474,9 @@ fn create_substs_for_ast_path<'tcx>(
}
}

debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}",
decl_generics, self_ty, substs);

substs
}

Expand Down Expand Up @@ -741,6 +744,7 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>(
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment);
// The trait reference introduces a binding level here, so
// we need to shift the `rscope`. It'd be nice if we could
// do away with this rscope stuff and work this knowledge
Expand Down Expand Up @@ -774,6 +778,8 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>(
poly_projections.extend(converted_bindings);
}

debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}",
trait_segment, poly_projections, poly_trait_ref);
poly_trait_ref
}

Expand Down Expand Up @@ -1103,7 +1109,18 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>,
object.principal_trait_ref_with_self_ty(tcx, tcx.types.err);

// ensure the super predicates and stop if we encountered an error
if this.ensure_super_predicates(span, object.principal_def_id()).is_err() {
if this.ensure_super_predicates(span, principal.def_id()).is_err() {
return tcx.types.err;
}

// check that there are no gross object safety violations,
// most importantly, that the supertraits don't contain Self,
// to avoid ICE-s.
let object_safety_violations =
traits::astconv_object_safety_violations(tcx, principal.def_id());
if !object_safety_violations.is_empty() {
traits::report_object_safety_error(
tcx, span, principal.def_id(), object_safety_violations, false);
return tcx.types.err;
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/diagnostics.rs
Expand Up @@ -3355,5 +3355,5 @@ register_diagnostics! {
E0399, // trait items need to be implemented because the associated
// type `{}` was overridden
E0436, // functional record update requires a struct
E0513, // no type for local variable ..
E0513 // no type for local variable ..
}
22 changes: 22 additions & 0 deletions src/test/compile-fail/issue-28576.rs
@@ -0,0 +1,22 @@
// 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.

pub trait Foo<RHS=Self> {
type Assoc;
}

pub trait Bar: Foo<Assoc=()> {
fn new(&self, b: &
Bar //~ ERROR the trait `Bar` cannot be made into an object
<Assoc=()>
);
}

fn main() {}
6 changes: 3 additions & 3 deletions src/test/compile-fail/object-safety-issue-22040.rs
Expand Up @@ -20,12 +20,12 @@ trait Expr: Debug + PartialEq {
#[derive(Debug)]
struct SExpr<'x> {
elements: Vec<Box<Expr+ 'x>>,
//~^ ERROR E0038
}

impl<'x> PartialEq for SExpr<'x> {
fn eq(&self, other:&SExpr<'x>) -> bool {
println!("L1: {} L2: {}", self.elements.len(), other.elements.len());
//~^ ERROR E0038
let result = self.elements.len() == other.elements.len();

println!("Got compare {}", result);
Expand All @@ -44,8 +44,8 @@ impl <'x> Expr for SExpr<'x> {
}

fn main() {
let a: Box<Expr> = Box::new(SExpr::new()); //~ ERROR E0038
let b: Box<Expr> = Box::new(SExpr::new()); //~ ERROR E0038
let a: Box<Expr> = Box::new(SExpr::new());
let b: Box<Expr> = Box::new(SExpr::new());

// assert_eq!(a , b);
}
Expand Up @@ -23,9 +23,9 @@ fn make_bar<T:Bar<u32>>(t: &T) -> &Bar<u32> {
}

fn make_baz<T:Baz>(t: &T) -> &Baz {
//~^ ERROR E0038
//~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing
t
//~^ ERROR E0038
//~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing
}

fn main() {
Expand Down

0 comments on commit 77e8f33

Please sign in to comment.