Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

early-prohibit objects with Self-containing supertraits #28629

Merged
merged 1 commit into from
Sep 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/librustc/middle/traits/error_reporting.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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);
}
Original file line number Diff line number Diff line change
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