From 1ebc7eff46fb01c625ecce55a0537dcc78e58756 Mon Sep 17 00:00:00 2001 From: scalexm Date: Thu, 10 Aug 2017 14:41:24 +0200 Subject: [PATCH 1/6] Fix for the supertrait example in #43784 --- src/librustc/ty/wf.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c24c583ad1e19..580a3aec3e870 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -141,6 +141,17 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); let param_env = self.param_env; + + let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, vec![ + ty::Predicate::Trait(ty::Binder( + ty::TraitPredicate { trait_ref: *trait_ref } + )) + ]); + let implied_obligations = implied_obligations.map(|pred| { + traits::Obligation::new(cause.clone(), param_env, pred) + }); + self.out.extend(implied_obligations); + self.out.extend( trait_ref.substs.types() .filter(|ty| !ty.has_escaping_regions()) From 488dccbe877f82e9a665aa39aa521e142fcf6efb Mon Sep 17 00:00:00 2001 From: scalexm Date: Thu, 10 Aug 2017 15:02:41 +0200 Subject: [PATCH 2/6] Elaborate trait obligations when typechecking impls Fixes #43784. --- src/librustc/ty/wf.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 580a3aec3e870..0ff94097c8ede 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -137,20 +137,19 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// `self.out`. fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); - self.out.extend(obligations); let cause = self.cause(traits::MiscObligation); let param_env = self.param_env; - let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, vec![ - ty::Predicate::Trait(ty::Binder( - ty::TraitPredicate { trait_ref: *trait_ref } - )) - ]); + let predicates = obligations.iter() + .map(|obligation| obligation.predicate.clone()) + .collect(); + let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, predicates); let implied_obligations = implied_obligations.map(|pred| { traits::Obligation::new(cause.clone(), param_env, pred) }); - self.out.extend(implied_obligations); + + self.out.extend(implied_obligations.chain(obligations)); self.out.extend( trait_ref.substs.types() From e3b28b4ae8092ca58f45053fc8f6be4f9b82c2e8 Mon Sep 17 00:00:00 2001 From: scalexm Date: Thu, 10 Aug 2017 15:13:34 +0200 Subject: [PATCH 3/6] Add tests --- .../issue-43784-associated-type.rs | 25 +++++++++++++++++++ .../compile-fail/issue-43784-supertrait.rs | 18 +++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/test/compile-fail/issue-43784-associated-type.rs create mode 100644 src/test/compile-fail/issue-43784-supertrait.rs diff --git a/src/test/compile-fail/issue-43784-associated-type.rs b/src/test/compile-fail/issue-43784-associated-type.rs new file mode 100644 index 0000000000000..94b5c0034a76d --- /dev/null +++ b/src/test/compile-fail/issue-43784-associated-type.rs @@ -0,0 +1,25 @@ +// Copyright 2017 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. + +pub trait Partial: Copy { +} + +pub trait Complete { + type Assoc: Partial; +} + +impl Partial for T::Assoc where + T: Complete +{ +} + +impl Complete for T { //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied + type Assoc = T; +} diff --git a/src/test/compile-fail/issue-43784-supertrait.rs b/src/test/compile-fail/issue-43784-supertrait.rs new file mode 100644 index 0000000000000..e70df113da33c --- /dev/null +++ b/src/test/compile-fail/issue-43784-supertrait.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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. + +pub trait Partial: Copy { +} + +pub trait Complete: Partial { +} + +impl Partial for T where T: Complete {} +impl Complete for T {} //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied From 94703ce3f7de97c8e8aa1fdda92724bea38dce28 Mon Sep 17 00:00:00 2001 From: scalexm Date: Thu, 10 Aug 2017 15:52:08 +0200 Subject: [PATCH 4/6] Do not elaborate trait obligations in where clauses --- src/librustc/ty/wf.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 0ff94097c8ede..bd9eb12ee03a2 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -58,7 +58,7 @@ pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, -> Vec> { let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] }; - wf.compute_trait_ref(trait_ref); + wf.compute_trait_ref(trait_ref, Elaborate::All); wf.normalize() } @@ -74,7 +74,7 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // (*) ok to skip binders, because wf code is prepared for it match *predicate { ty::Predicate::Trait(ref t) => { - wf.compute_trait_ref(&t.skip_binder().trait_ref); // (*) + wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) } ty::Predicate::Equate(ref t) => { wf.compute(t.skip_binder().0); @@ -114,6 +114,12 @@ struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { out: Vec>, } +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +enum Elaborate { + All, + None, +} + impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { traits::ObligationCause::new(self.span, self.body_id, code) @@ -135,21 +141,24 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// Pushes the obligations required for `trait_ref` to be WF into /// `self.out`. - fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { + fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); let cause = self.cause(traits::MiscObligation); let param_env = self.param_env; - let predicates = obligations.iter() - .map(|obligation| obligation.predicate.clone()) - .collect(); - let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, predicates); - let implied_obligations = implied_obligations.map(|pred| { - traits::Obligation::new(cause.clone(), param_env, pred) - }); + if let Elaborate::All = elaborate { + let predicates = obligations.iter() + .map(|obligation| obligation.predicate.clone()) + .collect(); + let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, predicates); + let implied_obligations = implied_obligations.map(|pred| { + traits::Obligation::new(cause.clone(), param_env, pred) + }); + self.out.extend(implied_obligations); + } - self.out.extend(implied_obligations.chain(obligations)); + self.out.extend(obligations); self.out.extend( trait_ref.substs.types() @@ -166,7 +175,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // WF and (b) the trait-ref holds. (It may also be // normalizable and be WF that way.) let trait_ref = data.trait_ref(self.infcx.tcx); - self.compute_trait_ref(&trait_ref); + self.compute_trait_ref(&trait_ref, Elaborate::All); if !data.has_escaping_regions() { let predicate = trait_ref.to_predicate(); From 373e909d07344f18b6e8ce443d4a4c484afc5c92 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 23 Aug 2017 18:56:19 -0400 Subject: [PATCH 5/6] add a comment --- src/librustc/ty/wf.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index bd9eb12ee03a2..4d5f9e8f51c78 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -114,6 +114,29 @@ struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { out: Vec>, } +/// Controls whether we "elaborate" supertraits and so forth on the WF +/// predicates. This is a kind of hack to address #43784. The +/// underlying problem in that issue was a trait structure like: +/// +/// ``` +/// trait Foo: Copy { } +/// trait Bar: Foo { } +/// impl Foo for T { } +/// impl Bar for T { } +/// ``` +/// +/// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but +/// we decide that this is true because `T: Bar` is in the +/// where-clauses (and we can elaborate that to include `T: +/// Copy`). This wouldn't be a problem, except that when we check the +/// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo` +/// impl. And so nowhere did we check that `T: Copy` holds! +/// +/// To resolve this, we elaborate the WF requirements that must be +/// proven when checking impls. This means that (e.g.) the `impl Bar +/// for T` will be forced to prove not only that `T: Foo` but also `T: +/// Copy` (which it won't be able to do, because there is no `Copy` +/// impl for `T`). #[derive(Debug, PartialEq, Eq, Copy, Clone)] enum Elaborate { All, From 68fd322a957480db16f1ab0af9915056adbe07b1 Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 25 Aug 2017 03:57:44 +0200 Subject: [PATCH 6/6] Change to `Elaborate::None` inside `compute_projection` --- src/librustc/ty/wf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 4d5f9e8f51c78..6d9e648452fd3 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -198,7 +198,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // WF and (b) the trait-ref holds. (It may also be // normalizable and be WF that way.) let trait_ref = data.trait_ref(self.infcx.tcx); - self.compute_trait_ref(&trait_ref, Elaborate::All); + self.compute_trait_ref(&trait_ref, Elaborate::None); if !data.has_escaping_regions() { let predicate = trait_ref.to_predicate();