@@ -371,16 +371,20 @@ trait LowerWhereClause<T> {
371
371
fn lower ( & self , env : & Env ) -> Result < T > ;
372
372
}
373
373
374
- /// Lowers a where-clause in the context of a clause; this is limited
375
- /// to the kinds of where-clauses users can actually type in Rust.
374
+ /// Lowers a where-clause in the context of a clause (i.e. in "negative"
375
+ /// position); this is limited to the kinds of where-clauses users can actually
376
+ /// type in Rust.
376
377
impl LowerWhereClause < ir:: DomainGoal > for WhereClause {
377
378
fn lower ( & self , env : & Env ) -> Result < ir:: DomainGoal > {
378
379
Ok ( match * self {
379
380
WhereClause :: Implemented { ref trait_ref } => {
380
381
ir:: DomainGoal :: Implemented ( trait_ref. lower ( env) ?)
381
382
}
382
383
WhereClause :: ProjectionEq { ref projection, ref ty } => {
383
- ir:: DomainGoal :: Normalize ( ir:: Normalize {
384
+ // NB: here we generate a RawNormalize, because we want to make
385
+ // make a maximally-strong assumption (and not allow fallback to
386
+ // trigger).
387
+ ir:: DomainGoal :: RawNormalize ( ir:: Normalize {
384
388
projection : projection. lower ( env) ?,
385
389
ty : ty. lower ( env) ?,
386
390
} )
@@ -395,16 +399,24 @@ impl LowerWhereClause<ir::DomainGoal> for WhereClause {
395
399
}
396
400
}
397
401
398
- /// Lowers a where-clause in the context of a goal; this is richer in
399
- /// terms of the legal sorts of where-clauses that can appear, because
400
- /// it includes all the sorts of things that the compiler must verify.
402
+ /// Lowers a where-clause in the context of a goal (i.e. in "positive"
403
+ /// position); this is richer in terms of the legal sorts of where-clauses that
404
+ /// can appear, because it includes all the sorts of things that the compiler
405
+ /// must verify.
401
406
impl LowerWhereClause < ir:: LeafGoal > for WhereClause {
402
407
fn lower ( & self , env : & Env ) -> Result < ir:: LeafGoal > {
403
408
Ok ( match * self {
404
- WhereClause :: Implemented { .. } |
405
- WhereClause :: ProjectionEq { .. } => {
406
- let wc: ir:: DomainGoal = self . lower ( env) ?;
407
- wc. cast ( )
409
+ WhereClause :: Implemented { .. } => {
410
+ let g: ir:: DomainGoal = self . lower ( env) ?;
411
+ g. cast ( )
412
+ }
413
+ WhereClause :: ProjectionEq { ref projection, ref ty } => {
414
+ // NB: here we generate a full Normalize clause, allowing for
415
+ // fallback to trigger when we're trying to *prove* a goal
416
+ ir:: DomainGoal :: Normalize ( ir:: Normalize {
417
+ projection : projection. lower ( env) ?,
418
+ ty : ty. lower ( env) ?,
419
+ } ) . cast ( )
408
420
}
409
421
WhereClause :: TyWellFormed { ref ty } => {
410
422
ir:: WellFormed :: Ty ( ty. lower ( env) ?) . cast ( )
@@ -812,11 +824,7 @@ impl ir::AssociatedTyValue {
812
824
///
813
825
/// ```notrust
814
826
/// forall<'a, T> {
815
- /// (Vec<T>: Iterable<IntoIter<'a> = Iter<'a, T>>) :-
816
- /// (Vec<T>: Iterable), // (1)
817
- /// (T: 'a) // (2)
818
- ///
819
- /// known(Iterable::IntoIter<Vec<T>, 'a>) :-
827
+ /// (Vec<T>: Iterable<IntoIter<'a> =raw Iter<'a, T>>) :-
820
828
/// (Vec<T>: Iterable), // (1)
821
829
/// (T: 'a) // (2)
822
830
/// }
@@ -856,11 +864,11 @@ impl ir::AssociatedTyValue {
856
864
} ;
857
865
858
866
// Determine the normalization
859
- let norm_clause = ir:: ProgramClause {
867
+ let normalization = ir:: ProgramClause {
860
868
implication : ir:: Binders {
861
869
binders : all_binders. clone ( ) ,
862
870
value : ir:: ProgramClauseImplication {
863
- consequence : ir:: DomainGoal :: Normalize ( ir:: Normalize {
871
+ consequence : ir:: DomainGoal :: RawNormalize ( ir:: Normalize {
864
872
projection : projection. clone ( ) ,
865
873
ty : self . value . value . ty . clone ( )
866
874
} ) ,
@@ -869,18 +877,7 @@ impl ir::AssociatedTyValue {
869
877
}
870
878
} ;
871
879
872
- // Record that the projection is known
873
- let known_clause = ir:: ProgramClause {
874
- implication : ir:: Binders {
875
- binders : all_binders. clone ( ) ,
876
- value : ir:: ProgramClauseImplication {
877
- consequence : ir:: DomainGoal :: KnownProjection ( projection) ,
878
- conditions : conditions. clone ( ) ,
879
- }
880
- }
881
- } ;
882
-
883
- vec ! [ norm_clause, known_clause]
880
+ vec ! [ normalization]
884
881
}
885
882
}
886
883
@@ -984,46 +981,73 @@ impl ir::TraitDatum {
984
981
985
982
impl ir:: AssociatedTyDatum {
986
983
fn to_program_clauses ( & self ) -> Vec < ir:: ProgramClause > {
987
- // For each associated type, we have a "normalization fallback" clause.
984
+ // For each associated type, we define normalization including a
985
+ // "fallback" if we can't resolve a projection using an impl/where clauses.
988
986
//
989
987
// Given:
990
988
//
991
- // trait SomeTrait {
989
+ // trait Foo {
992
990
// type Assoc;
993
991
// }
994
992
//
995
993
// we generate:
996
994
//
997
- // ?T: SomeTrait<Assoc = (SomeTrait::Assoc)<?T>> :-
998
- // // we can't resolve the normalization through an impl clause
999
- // not { known { <?T as SomeTrait>::Assoc } }.
995
+ // ?T: Foo<Assoc = ?U> :- ?T: Foo<Assoc =raw ?U>.
996
+ // ?T: Foo<Assoc = (Foo::Assoc)<?T>> :- not { exists<U> { ?T: Foo<Assoc =raw U> } }.
1000
997
1001
998
let binders: Vec < _ > = self . parameter_kinds . iter ( ) . map ( |pk| pk. map ( |_| ( ) ) ) . collect ( ) ;
1002
999
let parameters: Vec < _ > = binders. iter ( ) . zip ( 0 ..) . map ( |p| p. to_parameter ( ) ) . collect ( ) ;
1003
-
1004
1000
let projection = ir:: ProjectionTy {
1005
1001
associated_ty_id : self . id ,
1006
1002
parameters : parameters. clone ( ) ,
1007
1003
} ;
1008
1004
1009
- // Construct an application from the projection. So if we have `<T as
1010
- // Iterator>::Item`, we would produce `(Iterator::Item)<T>`.
1011
- let app = ir:: ApplicationTy { name : ir:: TypeName :: AssociatedType ( self . id ) , parameters } ;
1012
- let fallback_ty = ir:: Ty :: Apply ( app) ;
1013
- let norm_fallback = ir:: Normalize { projection : projection. clone ( ) , ty : fallback_ty } ;
1005
+ let raw = {
1006
+ let binders: Vec < _ > = binders. iter ( )
1007
+ . cloned ( )
1008
+ . chain ( Some ( ir:: ParameterKind :: Ty ( ( ) ) ) )
1009
+ . collect ( ) ;
1010
+ let ty = ir:: Ty :: Var ( binders. len ( ) - 1 ) ;
1011
+ let normalize = ir:: Normalize { projection : projection. clone ( ) , ty } ;
1012
+
1013
+ ir:: ProgramClause {
1014
+ implication : ir:: Binders {
1015
+ binders,
1016
+ value : ir:: ProgramClauseImplication {
1017
+ consequence : normalize. clone ( ) . cast ( ) ,
1018
+ conditions : vec ! [ ir:: DomainGoal :: RawNormalize ( normalize) . cast( ) ] ,
1019
+ }
1020
+ }
1021
+ }
1022
+ } ;
1014
1023
1015
- let fallback = ir:: ProgramClause {
1016
- implication : ir:: Binders {
1017
- binders,
1018
- value : ir:: ProgramClauseImplication {
1019
- consequence : ir:: DomainGoal :: Normalize ( norm_fallback) ,
1020
- conditions : vec ! [
1021
- ir:: Goal :: Not ( Box :: new( ir:: DomainGoal :: KnownProjection ( projection) . cast( ) ) )
1022
- ]
1024
+ let fallback = {
1025
+ // Construct an application from the projection. So if we have `<T as Iterator>::Item`,
1026
+ // we would produce `(Iterator::Item)<T>`.
1027
+ let app = ir:: ApplicationTy { name : ir:: TypeName :: AssociatedType ( self . id ) , parameters } ;
1028
+ let ty = ir:: Ty :: Apply ( app) ;
1029
+
1030
+ let raw = ir:: DomainGoal :: RawNormalize ( ir:: Normalize {
1031
+ projection : projection. clone ( ) . up_shift ( 1 ) ,
1032
+ ty : ir:: Ty :: Var ( 0 ) ,
1033
+ } ) ;
1034
+ let exists_binders = ir:: Binders {
1035
+ binders : vec ! [ ir:: ParameterKind :: Ty ( ( ) ) ] ,
1036
+ value : Box :: new ( raw. cast ( ) ) ,
1037
+ } ;
1038
+ let exists = ir:: Goal :: Quantified ( ir:: QuantifierKind :: Exists , exists_binders) ;
1039
+
1040
+ ir:: ProgramClause {
1041
+ implication : ir:: Binders {
1042
+ binders,
1043
+ value : ir:: ProgramClauseImplication {
1044
+ consequence : ir:: Normalize { projection : projection. clone ( ) , ty } . cast ( ) ,
1045
+ conditions : vec ! [ ir:: Goal :: Not ( Box :: new( exists) ) ]
1046
+ }
1023
1047
}
1024
1048
}
1025
1049
} ;
1026
1050
1027
- vec ! [ fallback]
1051
+ vec ! [ raw , fallback]
1028
1052
}
1029
1053
}
0 commit comments