diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 414e7b71f7cf2..e9c01f5bad66e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -762,16 +762,6 @@ pub struct GenericPredicates<'tcx> { } impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { - pub fn empty() -> GenericPredicates<'tcx> { - GenericPredicates { - predicates: VecPerParamSpace::empty(), - } - } - - pub fn is_empty(&self) -> bool { - self.predicates.is_empty() - } - pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { let mut instantiated = InstantiatedPredicates::empty(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 0117dfa673007..4576fc9ffdc79 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -252,33 +252,71 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } fn check_auto_trait(&mut self, - trait_def_id: DefId, - span: Span) + trait_def_id: DefId, + items: &[hir::TraitItem], + span: Span) { + // We want to ensure: + // + // 1) that there are no items contained within + // the trait defintion + // + // 2) that the definition doesn't violate the no-super trait rule + // for auto traits. + // + // 3) that the trait definition does not have any type parameters + let predicates = self.tcx().lookup_predicates(trait_def_id); - // If we must exclude the Self : Trait predicate contained by all + // We must exclude the Self : Trait predicate contained by all // traits. - let no_refl_predicates : Vec<_> = - predicates.predicates.iter().filter(|predicate| { - match *predicate { - &ty::Predicate::Trait(ref poly_trait_ref) => - poly_trait_ref.def_id() != trait_def_id, + let has_predicates = + predicates.predicates.iter().any(|predicate| { + match predicate { + &ty::Predicate::Trait(ref poly_trait_ref) => { + let self_ty = poly_trait_ref.0.self_ty(); + !(self_ty.is_self() && poly_trait_ref.def_id() == trait_def_id) + }, _ => true, - } - }).collect(); + } + }); let trait_def = self.tcx().lookup_trait_def(trait_def_id); + let has_ty_params = + trait_def.generics + .types + .len() > 1; + // We use an if-else here, since the generics will also trigger // an extraneous error message when we find predicates like // `T : Sized` for a trait like: `trait Magic`. - if !trait_def.generics.types.get_slice(ParamSpace::TypeSpace).is_empty() { - error_566(self.ccx, span); - } else if !no_refl_predicates.is_empty() { - error_565(self.ccx, span); + // + // We also put the check on the number of items here, + // as it seems confusing to report an error about + // extraneous predicates created by things like + // an associated type inside the trait. + + if !items.is_empty() { + error_380(self.ccx, span); + } else if has_ty_params { + span_err!(self.tcx().sess, span, E0566, + "traits with auto impls (`e.g. unsafe impl \ + Trait for ..`) can not have type parameters") + } else if has_predicates { + span_err!(self.tcx().sess, span, E0565, + "traits with auto impls (`e.g. unsafe impl \ + Trait for ..`) can not have predicates") } + // Finally if either of the above conditions apply we should add a note + // indicating that this error is the result of a recent soundness fix. + if has_ty_params || has_predicates { + self.tcx().sess.span_note_without_error( + span, + "the new auto trait rules are the result of a \ + recent soundness fix; see #29859 for more details") + } } fn check_trait(&mut self, @@ -287,19 +325,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { { let trait_def_id = self.tcx().map.local_def_id(item.id); + // TODO: in a second pass, globally rename to auto_trait, + // from default_impl. if self.tcx().trait_has_default_impl(trait_def_id) { - // We want to both ensure: - // 1) that there are no items contained within - // the trait defintion - // - // 2) that the definition doesn't violate the no-super trait rule - // for auto traits. - - if !items.is_empty() { - error_380(self.ccx, item.span); - } - - self.check_auto_trait(trait_def_id, item.span); + self.check_auto_trait(trait_def_id, items, item.span); } self.for_item(item).with_fcx(|fcx, this| { @@ -311,8 +340,6 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { }); } - - fn check_item_fn(&mut self, item: &hir::Item, body: &hir::Block) @@ -678,18 +705,6 @@ fn error_380(ccx: &CrateCtxt, span: Span) { Trait for ..`) must have no methods or associated items") } -fn error_565(ccx: &CrateCtxt, span: Span) { - span_err!(ccx.tcx.sess, span, E0565, - "traits with default impls (`e.g. unsafe impl \ - Trait for ..`) can not have predicates") -} - -fn error_566(ccx: &CrateCtxt, span: Span) { - span_err!(ccx.tcx.sess, span, E0566, - "traits with default impls (`e.g. unsafe impl \ - Trait for ..`) can not have type parameters") -} - fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!(ccx.tcx.sess, span, E0392, diff --git a/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs b/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs deleted file mode 100644 index cdf4b405fd83e..0000000000000 --- a/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs +++ /dev/null @@ -1,32 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test for a potential corner case in current impl where you have an -// auto trait (Magic1) that depends on a normal trait (Magic2) which -// in turn depends on the auto trait (Magic1). This was incorrectly -// being considered coinductive, but because of the normal trait -// interfering, it should not be. - -#![feature(optin_builtin_traits)] - -trait Magic1: Magic2 { } -impl Magic1 for .. {} - -trait Magic2 { } -impl Magic2 for T { } - -fn is_magic1() { } - -#[derive(Debug)] -struct NoClone; - -fn main() { - is_magic1::(); //~ ERROR E0275 -} diff --git a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs index ec8db996600d1..168148b92fe44 100644 --- a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs +++ b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs @@ -14,7 +14,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} +trait Magic: Copy {} //~ ERROR E0565 impl Magic for .. {} fn copy(x: T) -> (T, T) { (x, x) } @@ -23,6 +23,6 @@ fn copy(x: T) -> (T, T) { (x, x) } struct NoClone; fn main() { - let (a, b) = copy(NoClone); //~ ERROR E0277 + let (a, b) = copy(NoClone); println!("{:?} {:?}", a, b); } diff --git a/src/test/compile-fail/issue-29859.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs similarity index 91% rename from src/test/compile-fail/issue-29859.rs rename to src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs index 3419e66af1393..60da647f68240 100644 --- a/src/test/compile-fail/issue-29859.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs @@ -10,7 +10,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} //~ ERROR E0565 +trait Magic : Sized where Option : Magic {} //~ ERROR E0565 impl Magic for .. {} impl Magic for T {} diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs new file mode 100644 index 0000000000000..177d594da18a0 --- /dev/null +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs @@ -0,0 +1,49 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test is for #29859, we need to ensure auto traits, +// (also known previously as default traits), do not have +// supertraits. Since the compiler synthesizes these +// instances on demand, we are essentially enabling +// users to write axioms if we view trait selection, +// as a proof system. +// +// For example the below test allows us to add the rule: +// forall (T : Type), T : Copy +// +// Providing a copy instance for *any* type, which +// is most definitely unsound. Imagine copying a +// type that contains a mutable reference, enabling +// mutable aliasing. +// +// You can imagine an even more dangerous test, +// which currently compiles on nightly. +// +// fn main() { +// let mut i = 10; +// let (a, b) = copy(&mut i); +// println!("{:?} {:?}", a, b); +// } + +#![feature(optin_builtin_traits)] + +trait Magic: Copy {} //~ ERROR E0565 +impl Magic for .. {} +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); + println!("{:?} {:?}", a, b); +} diff --git a/src/test/compile-fail/issue-29859-2.rs b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs similarity index 93% rename from src/test/compile-fail/issue-29859-2.rs rename to src/test/compile-fail/typeck-auto-trait-no-typeparams.rs index 258aafb15baf4..f2841a413db9e 100644 --- a/src/test/compile-fail/issue-29859-2.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs @@ -10,5 +10,5 @@ #![feature(optin_builtin_traits)] -trait Magic {} //~ E0566 +trait Magic {} //~ ERROR E0566 impl Magic for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs b/src/test/compile-fail/typeck-default-trait-impl-superregion.rs deleted file mode 100644 index aa918119fbcee..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs +++ /dev/null @@ -1,27 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait MyTrait : 'static {} - -impl MyTrait for .. {} - -fn foo() { } - -fn bar<'a>() { - foo::<&'a ()>(); //~ ERROR does not fulfill the required lifetime -} - -fn main() { -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs b/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs deleted file mode 100644 index 0b071a9acd092..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs +++ /dev/null @@ -1,29 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait : NotImplemented {} - -impl MyTrait for .. {} - -fn foo() { bar::() } - -fn bar() { } - -fn main() { - foo::(); //~ ERROR `i32: NotImplemented` is not satisfied - bar::(); //~ ERROR `i64: NotImplemented` is not satisfied -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs deleted file mode 100644 index 3085f45a83dd1..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs +++ /dev/null @@ -1,36 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-tidy-linelength - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait: Sized - where Option : NotImplemented -{} - -impl NotImplemented for i32 {} - -impl MyTrait for .. {} - -fn bar() { } - -fn test() { - bar::>(); - //~^ ERROR `std::option::Option: NotImplemented` is not satisfied -} - -fn main() { -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs deleted file mode 100644 index 47e87c09d12b1..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs +++ /dev/null @@ -1,36 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-tidy-linelength - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait: Sized - where Option : NotImplemented -{} - -impl NotImplemented for i32 {} - -impl MyTrait for .. {} - -fn foo() { - //~^ ERROR `std::option::Option: NotImplemented` is not satisfied - // This should probably typecheck. This is #20671. -} - -fn bar() { } - -fn main() { -}