diff --git a/src/rules.rs b/src/rules.rs index 92f20a53874..ff9d1963431 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -107,7 +107,7 @@ impl ImplDatum { /// Given `impl Clone for Vec`, generate: /// /// ```notrust - /// forall { (Vec: Clone) :- (T: Clone) } + /// forall { Implemented(Vec: Clone) :- Implemented(T: Clone) } /// ``` fn to_program_clause(&self) -> ProgramClause { self.binders @@ -137,9 +137,9 @@ impl DefaultImplDatum { /// /// ```notrust /// forall { - /// (MyList: Send) :- - /// (T: Send), - /// (Box>>: Send) + /// Implemented(MyList: Send) :- + /// Implemented(T: Send), + /// Implemented(Box>>: Send) /// } /// ``` fn to_program_clause(&self) -> ProgramClause { @@ -179,8 +179,8 @@ impl AssociatedTyValue { /// ```notrust /// forall<'a, T> { /// Normalize( as Iterable>::IntoIter<'a> -> Iter<'a, T>>) :- - /// (Vec: Iterable), // (1) - /// (Iter<'a, T>: 'a) // (2) + /// Implemented(Vec: Iterable), // (1) + /// Implemented(Iter<'a, T>: 'a) // (2) /// } /// ``` /// @@ -304,7 +304,7 @@ impl StructDatum { // // we generate the following clauses: // - // forall { WF(Foo) :- (T: Eq). } + // forall { WF(Foo) :- Implemented(T: Eq). } // forall { FromEnv(T: Eq) :- FromEnv(Foo). } // forall { IsFullyVisible(Foo) :- IsFullyVisible(T) } // @@ -456,7 +456,7 @@ impl TraitDatum { // we generate the following clause: // // forall { - // WF(Self: Ord) :- (Self: Ord), WF(Self: Eq) + // WF(Self: Ord) :- Implemented(Self: Ord), WF(Self: Eq) // } // // and the reverse rules: @@ -786,7 +786,7 @@ impl AssociatedTyDatum { // Well-formedness of projection type. // // forall { - // WellFormed((Foo::Assoc)) :- Self: Foo, WC. + // WellFormed((Foo::Assoc)) :- Implemented(Self: Foo), WC. // } clauses.push( Binders { @@ -837,12 +837,23 @@ impl AssociatedTyDatum { // Reverse rule for implied bounds. // - // forall { - // FromEnv(::Assoc: Bounds) :- FromEnv(Self: Foo) + // forall { + // FromEnv(::Assoc: Bounds) :- FromEnv(Self: Foo), FromEnv(WC) // } clauses.extend(self.bounds_on_self().into_iter().map(|bound| { // Same as above in case of higher-ranked inline bounds. let shift = bound.binders.len(); + let from_env_trait = iter::once( + FromEnv::Trait(trait_ref.clone()).shifted_in(shift).cast() + ); + + let where_clauses = self.where_clauses + .iter() + .cloned() + // `wc` may be a higher-ranked where clause + .map(|wc| wc.map(|value| value.into_from_env_goal())) + .casted(); + Binders { binders: bound .binders @@ -852,7 +863,7 @@ impl AssociatedTyDatum { .collect(), value: ProgramClauseImplication { consequence: bound.value.clone().into_from_env_goal(), - conditions: vec![FromEnv::Trait(trait_ref.clone()).shifted_in(shift).cast()], + conditions: from_env_trait.chain(where_clauses).collect(), }, }.cast() })); diff --git a/src/rules/wf/test.rs b/src/rules/wf/test.rs index 0a5e62fa45b..7763c69a3a9 100644 --- a/src/rules/wf/test.rs +++ b/src/rules/wf/test.rs @@ -563,3 +563,78 @@ fn higher_ranked_inline_bound_on_gat() { } } } + +#[test] +fn assoc_type_recursive_bound() { + lowering_error! { + program { + trait Sized { } + trait Print { + // fn print(); + } + + trait Foo { + type Item: Sized where ::Item: Sized; + } + + struct i32 { } + struct str { } // not sized + + impl Foo for i32 { + // Well-formedness checks require that the following + // goal is true: + // ``` + // if (str: Sized) { # if the where clauses hold + // str: Sized # then the bound on the associated type hold + // } + // ``` + // which it is :) + type Item = str; + } + + struct OnlySized where T: Sized { } + impl Print for OnlySized { + // fn print() { + // println!("{}", std::mem::size_of::()); + // } + } + + trait Bar { + type Assoc: Print; + } + + impl Bar for T where T: Foo { + type Assoc = OnlySized<::Item>; + } + + // Above, we used to incorrectly assume that `OnlySized<::Item>` + // is well-formed because of the `FromEnv(T: Foo)`, hence making the `T: Bar` + // impl pass the well-formedness check. But the following query will + // (and should) always succeed, as there is no where clauses on `Assoc`: + // ``` + // forall { if (T: Bar) { WellFormed(::Assoc) } } + // ``` + // + // This may lead to the following code to compile: + + // ``` + // fn foo() { + // T::print() // oops, in fact `T = OnlySized` which is ill-formed + // } + + // fn bar { + // // ok, we have `FromEnv(T: Bar)` hence + // // `::Assoc` is well-formed and + // // `Implemented(::Assoc: Print)` hold + // foo<::Assoc>( + // } + + // fn main() { + // bar::() // ok, `Implemented(i32: Bar)` hold + // } + // ``` + } error_msg { + "trait impl for \"Bar\" does not meet well-formedness requirements" + } + } +}