@@ -74,6 +74,12 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
74
74
}
75
75
}
76
76
77
+ /// Check if types unify.
78
+ ///
79
+ /// Note that we consider placeholder types to unify with everything.
80
+ /// This means that there may be some unresolved goals that actually set bounds for the placeholder
81
+ /// type for the types to unify. For example `Option<T>` and `Option<U>` unify although there is
82
+ /// unresolved goal `T = U`.
77
83
pub fn could_unify (
78
84
db : & dyn HirDatabase ,
79
85
env : Arc < TraitEnvironment > ,
@@ -82,30 +88,25 @@ pub fn could_unify(
82
88
unify ( db, env, tys) . is_some ( )
83
89
}
84
90
91
+ /// Check if types unify eagerly making sure there are no unresolved goals.
92
+ ///
93
+ /// This means that placeholder types are not considered to unify if there are any bounds set on
94
+ /// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
85
95
pub fn could_unify_deeply (
86
96
db : & dyn HirDatabase ,
87
97
env : Arc < TraitEnvironment > ,
88
98
tys : & Canonical < ( Ty , Ty ) > ,
89
99
) -> bool {
90
100
let mut table = InferenceTable :: new ( db, env) ;
91
- let vars = Substitution :: from_iter (
92
- Interner ,
93
- tys. binders . iter ( Interner ) . map ( |it| match & it. kind {
94
- chalk_ir:: VariableKind :: Ty ( _) => {
95
- GenericArgData :: Ty ( table. new_type_var ( ) ) . intern ( Interner )
96
- }
97
- chalk_ir:: VariableKind :: Lifetime => {
98
- GenericArgData :: Ty ( table. new_type_var ( ) ) . intern ( Interner )
99
- } // FIXME: maybe wrong?
100
- chalk_ir:: VariableKind :: Const ( ty) => {
101
- GenericArgData :: Const ( table. new_const_var ( ty. clone ( ) ) ) . intern ( Interner )
102
- }
103
- } ) ,
104
- ) ;
101
+ let vars = make_substitutions ( tys, & mut table) ;
105
102
let ty1_with_vars = vars. apply ( tys. value . 0 . clone ( ) , Interner ) ;
106
103
let ty2_with_vars = vars. apply ( tys. value . 1 . clone ( ) , Interner ) ;
107
104
let ty1_with_vars = table. normalize_associated_types_in ( ty1_with_vars) ;
108
105
let ty2_with_vars = table. normalize_associated_types_in ( ty2_with_vars) ;
106
+ table. resolve_obligations_as_possible ( ) ;
107
+ table. propagate_diverging_flag ( ) ;
108
+ let ty1_with_vars = table. resolve_completely ( ty1_with_vars) ;
109
+ let ty2_with_vars = table. resolve_completely ( ty2_with_vars) ;
109
110
table. unify_deeply ( & ty1_with_vars, & ty2_with_vars)
110
111
}
111
112
@@ -115,15 +116,7 @@ pub(crate) fn unify(
115
116
tys : & Canonical < ( Ty , Ty ) > ,
116
117
) -> Option < Substitution > {
117
118
let mut table = InferenceTable :: new ( db, env) ;
118
- let vars = Substitution :: from_iter (
119
- Interner ,
120
- tys. binders . iter ( Interner ) . map ( |it| match & it. kind {
121
- chalk_ir:: VariableKind :: Ty ( _) => table. new_type_var ( ) . cast ( Interner ) ,
122
- // FIXME: maybe wrong?
123
- chalk_ir:: VariableKind :: Lifetime => table. new_type_var ( ) . cast ( Interner ) ,
124
- chalk_ir:: VariableKind :: Const ( ty) => table. new_const_var ( ty. clone ( ) ) . cast ( Interner ) ,
125
- } ) ,
126
- ) ;
119
+ let vars = make_substitutions ( tys, & mut table) ;
127
120
let ty1_with_vars = vars. apply ( tys. value . 0 . clone ( ) , Interner ) ;
128
121
let ty2_with_vars = vars. apply ( tys. value . 1 . clone ( ) , Interner ) ;
129
122
if !table. unify ( & ty1_with_vars, & ty2_with_vars) {
@@ -152,6 +145,21 @@ pub(crate) fn unify(
152
145
) )
153
146
}
154
147
148
+ fn make_substitutions (
149
+ tys : & chalk_ir:: Canonical < ( chalk_ir:: Ty < Interner > , chalk_ir:: Ty < Interner > ) > ,
150
+ table : & mut InferenceTable < ' _ > ,
151
+ ) -> chalk_ir:: Substitution < Interner > {
152
+ Substitution :: from_iter (
153
+ Interner ,
154
+ tys. binders . iter ( Interner ) . map ( |it| match & it. kind {
155
+ chalk_ir:: VariableKind :: Ty ( _) => table. new_type_var ( ) . cast ( Interner ) ,
156
+ // FIXME: maybe wrong?
157
+ chalk_ir:: VariableKind :: Lifetime => table. new_type_var ( ) . cast ( Interner ) ,
158
+ chalk_ir:: VariableKind :: Const ( ty) => table. new_const_var ( ty. clone ( ) ) . cast ( Interner ) ,
159
+ } ) ,
160
+ )
161
+ }
162
+
155
163
bitflags:: bitflags! {
156
164
#[ derive( Default , Clone , Copy ) ]
157
165
pub ( crate ) struct TypeVariableFlags : u8 {
@@ -458,15 +466,15 @@ impl<'a> InferenceTable<'a> {
458
466
true
459
467
}
460
468
461
- /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
469
+ /// Unify two relatable values (e.g. `Ty`) and check whether trait goals which arise from that could be fulfilled
462
470
pub ( crate ) fn unify_deeply < T : ?Sized + Zip < Interner > > ( & mut self , ty1 : & T , ty2 : & T ) -> bool {
463
471
let result = match self . try_unify ( ty1, ty2) {
464
472
Ok ( r) => r,
465
473
Err ( _) => return false ,
466
474
} ;
467
475
result. goals . iter ( ) . all ( |goal| {
468
476
let canonicalized = self . canonicalize ( goal. clone ( ) ) ;
469
- self . try_fulfill_obligation ( & canonicalized)
477
+ self . try_resolve_obligation ( & canonicalized) . is_some ( )
470
478
} )
471
479
}
472
480
@@ -540,7 +548,8 @@ impl<'a> InferenceTable<'a> {
540
548
541
549
fn register_obligation_in_env ( & mut self , goal : InEnvironment < Goal > ) {
542
550
let canonicalized = self . canonicalize ( goal) ;
543
- if !self . try_resolve_obligation ( & canonicalized) {
551
+ let solution = self . try_resolve_obligation ( & canonicalized) ;
552
+ if matches ! ( solution, Some ( Solution :: Ambig ( _) ) ) {
544
553
self . pending_obligations . push ( canonicalized) ;
545
554
}
546
555
}
@@ -666,70 +675,35 @@ impl<'a> InferenceTable<'a> {
666
675
fn try_resolve_obligation (
667
676
& mut self ,
668
677
canonicalized : & Canonicalized < InEnvironment < Goal > > ,
669
- ) -> bool {
678
+ ) -> Option < chalk_solve :: Solution < Interner > > {
670
679
let solution = self . db . trait_solve (
671
680
self . trait_env . krate ,
672
681
self . trait_env . block ,
673
682
canonicalized. value . clone ( ) ,
674
683
) ;
675
684
676
- match solution {
685
+ match & solution {
677
686
Some ( Solution :: Unique ( canonical_subst) ) => {
678
687
canonicalized. apply_solution (
679
688
self ,
680
689
Canonical {
681
- binders : canonical_subst. binders ,
690
+ binders : canonical_subst. binders . clone ( ) ,
682
691
// FIXME: handle constraints
683
- value : canonical_subst. value . subst ,
692
+ value : canonical_subst. value . subst . clone ( ) ,
684
693
} ,
685
694
) ;
686
- true
687
695
}
688
696
Some ( Solution :: Ambig ( Guidance :: Definite ( substs) ) ) => {
689
- canonicalized. apply_solution ( self , substs) ;
690
- false
697
+ canonicalized. apply_solution ( self , substs. clone ( ) ) ;
691
698
}
692
699
Some ( _) => {
693
700
// FIXME use this when trying to resolve everything at the end
694
- false
695
701
}
696
702
None => {
697
703
// FIXME obligation cannot be fulfilled => diagnostic
698
- true
699
- }
700
- }
701
- }
702
-
703
- fn try_fulfill_obligation (
704
- & mut self ,
705
- canonicalized : & Canonicalized < InEnvironment < Goal > > ,
706
- ) -> bool {
707
- let solution = self . db . trait_solve (
708
- self . trait_env . krate ,
709
- self . trait_env . block ,
710
- canonicalized. value . clone ( ) ,
711
- ) ;
712
-
713
- // FIXME: Does just returning `solution.is_some()` work?
714
- match solution {
715
- Some ( Solution :: Unique ( canonical_subst) ) => {
716
- canonicalized. apply_solution (
717
- self ,
718
- Canonical {
719
- binders : canonical_subst. binders ,
720
- // FIXME: handle constraints
721
- value : canonical_subst. value . subst ,
722
- } ,
723
- ) ;
724
- true
725
- }
726
- Some ( Solution :: Ambig ( Guidance :: Definite ( substs) ) ) => {
727
- canonicalized. apply_solution ( self , substs) ;
728
- true
729
704
}
730
- Some ( _) => true ,
731
- None => false ,
732
705
}
706
+ solution
733
707
}
734
708
735
709
pub ( crate ) fn callable_sig (
0 commit comments