@@ -74,6 +74,12 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
7474 }
7575}
7676
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`.
7783pub fn could_unify (
7884 db : & dyn HirDatabase ,
7985 env : Arc < TraitEnvironment > ,
@@ -82,30 +88,25 @@ pub fn could_unify(
8288 unify ( db, env, tys) . is_some ( )
8389}
8490
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`
8595pub fn could_unify_deeply (
8696 db : & dyn HirDatabase ,
8797 env : Arc < TraitEnvironment > ,
8898 tys : & Canonical < ( Ty , Ty ) > ,
8999) -> bool {
90100 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) ;
105102 let ty1_with_vars = vars. apply ( tys. value . 0 . clone ( ) , Interner ) ;
106103 let ty2_with_vars = vars. apply ( tys. value . 1 . clone ( ) , Interner ) ;
107104 let ty1_with_vars = table. normalize_associated_types_in ( ty1_with_vars) ;
108105 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) ;
109110 table. unify_deeply ( & ty1_with_vars, & ty2_with_vars)
110111}
111112
@@ -115,15 +116,7 @@ pub(crate) fn unify(
115116 tys : & Canonical < ( Ty , Ty ) > ,
116117) -> Option < Substitution > {
117118 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) ;
127120 let ty1_with_vars = vars. apply ( tys. value . 0 . clone ( ) , Interner ) ;
128121 let ty2_with_vars = vars. apply ( tys. value . 1 . clone ( ) , Interner ) ;
129122 if !table. unify ( & ty1_with_vars, & ty2_with_vars) {
@@ -152,6 +145,21 @@ pub(crate) fn unify(
152145 ) )
153146}
154147
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+
155163bitflags:: bitflags! {
156164 #[ derive( Default , Clone , Copy ) ]
157165 pub ( crate ) struct TypeVariableFlags : u8 {
@@ -458,15 +466,15 @@ impl<'a> InferenceTable<'a> {
458466 true
459467 }
460468
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
462470 pub ( crate ) fn unify_deeply < T : ?Sized + Zip < Interner > > ( & mut self , ty1 : & T , ty2 : & T ) -> bool {
463471 let result = match self . try_unify ( ty1, ty2) {
464472 Ok ( r) => r,
465473 Err ( _) => return false ,
466474 } ;
467475 result. goals . iter ( ) . all ( |goal| {
468476 let canonicalized = self . canonicalize ( goal. clone ( ) ) ;
469- self . try_fulfill_obligation ( & canonicalized)
477+ self . try_resolve_obligation ( & canonicalized) . is_some ( )
470478 } )
471479 }
472480
@@ -540,7 +548,8 @@ impl<'a> InferenceTable<'a> {
540548
541549 fn register_obligation_in_env ( & mut self , goal : InEnvironment < Goal > ) {
542550 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 ( _) ) ) {
544553 self . pending_obligations . push ( canonicalized) ;
545554 }
546555 }
@@ -666,70 +675,35 @@ impl<'a> InferenceTable<'a> {
666675 fn try_resolve_obligation (
667676 & mut self ,
668677 canonicalized : & Canonicalized < InEnvironment < Goal > > ,
669- ) -> bool {
678+ ) -> Option < chalk_solve :: Solution < Interner > > {
670679 let solution = self . db . trait_solve (
671680 self . trait_env . krate ,
672681 self . trait_env . block ,
673682 canonicalized. value . clone ( ) ,
674683 ) ;
675684
676- match solution {
685+ match & solution {
677686 Some ( Solution :: Unique ( canonical_subst) ) => {
678687 canonicalized. apply_solution (
679688 self ,
680689 Canonical {
681- binders : canonical_subst. binders ,
690+ binders : canonical_subst. binders . clone ( ) ,
682691 // FIXME: handle constraints
683- value : canonical_subst. value . subst ,
692+ value : canonical_subst. value . subst . clone ( ) ,
684693 } ,
685694 ) ;
686- true
687695 }
688696 Some ( Solution :: Ambig ( Guidance :: Definite ( substs) ) ) => {
689- canonicalized. apply_solution ( self , substs) ;
690- false
697+ canonicalized. apply_solution ( self , substs. clone ( ) ) ;
691698 }
692699 Some ( _) => {
693700 // FIXME use this when trying to resolve everything at the end
694- false
695701 }
696702 None => {
697703 // 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
729704 }
730- Some ( _) => true ,
731- None => false ,
732705 }
706+ solution
733707 }
734708
735709 pub ( crate ) fn callable_sig (
0 commit comments