@@ -10,7 +10,7 @@ use hir_def::{expr::ExprId, lang_item::LangItemTarget};
10
10
11
11
use crate :: {
12
12
autoderef,
13
- infer:: { Adjust , Adjustment , AutoBorrow , PointerCast , TypeMismatch } ,
13
+ infer:: { Adjust , Adjustment , AutoBorrow , InferResult , PointerCast , TypeMismatch } ,
14
14
static_lifetime, Canonical , DomainGoal , FnPointer , FnSig , Interner , Solution , Substitution , Ty ,
15
15
TyBuilder , TyExt , TyKind ,
16
16
} ;
@@ -36,23 +36,25 @@ fn success(
36
36
) -> CoerceResult {
37
37
Ok ( InferOk { goals, value : ( adj, target) } )
38
38
}
39
+ #[ derive( Clone , Debug ) ]
40
+ pub ( super ) struct CoerceMany {
41
+ expected_ty : Ty ,
42
+ }
39
43
40
- impl < ' a > InferenceContext < ' a > {
41
- /// Unify two types, but may coerce the first one to the second one
42
- /// using "implicit coercion rules" if needed.
43
- pub ( super ) fn coerce ( & mut self , from_ty : & Ty , to_ty : & Ty ) -> CoerceResult {
44
- let from_ty = self . resolve_ty_shallow ( from_ty) ;
45
- let to_ty = self . resolve_ty_shallow ( to_ty) ;
46
- match self . coerce_inner ( from_ty, & to_ty) {
47
- Ok ( InferOk { value, goals } ) => {
48
- self . table . register_infer_ok ( InferOk { value : ( ) , goals } ) ;
49
- Ok ( InferOk { value, goals : Vec :: new ( ) } )
50
- }
51
- Err ( e) => {
52
- // FIXME deal with error
53
- Err ( e)
54
- }
55
- }
44
+ impl CoerceMany {
45
+ pub ( super ) fn new ( expected : Ty ) -> Self {
46
+ CoerceMany { expected_ty : expected }
47
+ }
48
+
49
+ pub ( super ) fn once (
50
+ ctx : & mut InferenceContext < ' _ > ,
51
+ expected : Ty ,
52
+ expr : Option < ExprId > ,
53
+ expr_ty : & Ty ,
54
+ ) -> Ty {
55
+ let mut this = CoerceMany :: new ( expected) ;
56
+ this. coerce ( ctx, expr, expr_ty) ;
57
+ this. complete ( )
56
58
}
57
59
58
60
/// Merge two types from different branches, with possible coercion.
@@ -62,51 +64,88 @@ impl<'a> InferenceContext<'a> {
62
64
/// coerce both to function pointers;
63
65
/// - if we were concerned with lifetime subtyping, we'd need to look for a
64
66
/// least upper bound.
65
- pub ( super ) fn coerce_merge_branch ( & mut self , id : Option < ExprId > , ty1 : & Ty , ty2 : & Ty ) -> Ty {
66
- // TODO
67
- let ty1 = self . resolve_ty_shallow ( ty1) ;
68
- let ty2 = self . resolve_ty_shallow ( ty2) ;
67
+ pub ( super ) fn coerce (
68
+ & mut self ,
69
+ ctx : & mut InferenceContext < ' _ > ,
70
+ expr : Option < ExprId > ,
71
+ expr_ty : & Ty ,
72
+ ) {
73
+ let expr_ty = ctx. resolve_ty_shallow ( expr_ty) ;
74
+ self . expected_ty = ctx. resolve_ty_shallow ( & self . expected_ty ) ;
75
+
69
76
// Special case: two function types. Try to coerce both to
70
77
// pointers to have a chance at getting a match. See
71
78
// https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
72
- let sig = match ( ty1 . kind ( & Interner ) , ty2 . kind ( & Interner ) ) {
79
+ let sig = match ( self . expected_ty . kind ( & Interner ) , expr_ty . kind ( & Interner ) ) {
73
80
( TyKind :: FnDef ( ..) | TyKind :: Closure ( ..) , TyKind :: FnDef ( ..) | TyKind :: Closure ( ..) ) => {
74
81
// FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
75
82
// we should be coercing the closure to a fn pointer of the safety of the FnDef
76
83
cov_mark:: hit!( coerce_fn_reification) ;
77
- let sig = ty1. callable_sig ( self . db ) . expect ( "FnDef without callable sig" ) ;
84
+ let sig =
85
+ self . expected_ty . callable_sig ( ctx. db ) . expect ( "FnDef without callable sig" ) ;
78
86
Some ( sig)
79
87
}
80
88
_ => None ,
81
89
} ;
82
90
if let Some ( sig) = sig {
83
91
let target_ty = TyKind :: Function ( sig. to_fn_ptr ( ) ) . intern ( & Interner ) ;
84
- let result1 = self . coerce_inner ( ty1 . clone ( ) , & target_ty) ;
85
- let result2 = self . coerce_inner ( ty2 . clone ( ) , & target_ty) ;
92
+ let result1 = ctx . coerce_inner ( self . expected_ty . clone ( ) , & target_ty) ;
93
+ let result2 = ctx . coerce_inner ( expr_ty . clone ( ) , & target_ty) ;
86
94
if let ( Ok ( result1) , Ok ( result2) ) = ( result1, result2) {
87
- self . table . register_infer_ok ( result1) ;
88
- self . table . register_infer_ok ( result2) ;
89
- return target_ty;
95
+ ctx . table . register_infer_ok ( result1) ;
96
+ ctx . table . register_infer_ok ( result2) ;
97
+ return self . expected_ty = target_ty;
90
98
}
91
99
}
92
100
93
- // It might not seem like it, but order is important here: ty1 is our
94
- // "previous" type, ty2 is the "new" one being added. If the previous
101
+ // It might not seem like it, but order is important here: If the expected
95
102
// type is a type variable and the new one is `!`, trying it the other
96
103
// way around first would mean we make the type variable `!`, instead of
97
104
// just marking it as possibly diverging.
98
- if self . coerce ( & ty2 , & ty1 ) . is_ok ( ) {
99
- ty1
100
- } else if self . coerce ( & ty1 , & ty2 ) . is_ok ( ) {
101
- ty2
105
+ if ctx . coerce ( expr , & expr_ty , & self . expected_ty ) . is_ok ( ) {
106
+ /* self.expected_ty is already correct */
107
+ } else if ctx . coerce ( expr , & self . expected_ty , & expr_ty ) . is_ok ( ) {
108
+ self . expected_ty = expr_ty ;
102
109
} else {
103
- if let Some ( id) = id {
104
- self . result
105
- . type_mismatches
106
- . insert ( id. into ( ) , TypeMismatch { expected : ty1. clone ( ) , actual : ty2 } ) ;
110
+ if let Some ( id) = expr {
111
+ ctx. result . type_mismatches . insert (
112
+ id. into ( ) ,
113
+ TypeMismatch { expected : self . expected_ty . clone ( ) , actual : expr_ty } ,
114
+ ) ;
107
115
}
108
116
cov_mark:: hit!( coerce_merge_fail_fallback) ;
109
- ty1
117
+ /* self.expected_ty is already correct */
118
+ }
119
+ }
120
+
121
+ pub ( super ) fn complete ( self ) -> Ty {
122
+ self . expected_ty
123
+ }
124
+ }
125
+
126
+ impl < ' a > InferenceContext < ' a > {
127
+ /// Unify two types, but may coerce the first one to the second one
128
+ /// using "implicit coercion rules" if needed.
129
+ pub ( super ) fn coerce (
130
+ & mut self ,
131
+ expr : Option < ExprId > ,
132
+ from_ty : & Ty ,
133
+ to_ty : & Ty ,
134
+ ) -> InferResult < Ty > {
135
+ let from_ty = self . resolve_ty_shallow ( from_ty) ;
136
+ let to_ty = self . resolve_ty_shallow ( to_ty) ;
137
+ match self . coerce_inner ( from_ty, & to_ty) {
138
+ Ok ( InferOk { value : ( adjustments, ty) , goals } ) => {
139
+ if let Some ( expr) = expr {
140
+ self . write_expr_adj ( expr, adjustments) ;
141
+ }
142
+ self . table . register_infer_ok ( InferOk { value : ( ) , goals } ) ;
143
+ Ok ( InferOk { value : ty, goals : Vec :: new ( ) } )
144
+ }
145
+ Err ( e) => {
146
+ // FIXME deal with error
147
+ Err ( e)
148
+ }
110
149
}
111
150
}
112
151
@@ -189,7 +228,6 @@ impl<'a> InferenceContext<'a> {
189
228
190
229
// Check that the types which they point at are compatible.
191
230
let from_raw = TyKind :: Raw ( to_mt, from_inner. clone ( ) ) . intern ( & Interner ) ;
192
- // self.table.try_unify(&from_raw, to_ty);
193
231
194
232
// Although references and unsafe ptrs have the same
195
233
// representation, we still register an Adjust::DerefRef so that
@@ -518,15 +556,13 @@ impl<'a> InferenceContext<'a> {
518
556
// FIXME: should we accept ambiguous results here?
519
557
_ => return Err ( TypeError ) ,
520
558
} ;
521
- // TODO: this is probably wrong?
522
- let coerce_target = self . table . new_type_var ( ) ;
523
- self . unify_and ( & coerce_target, to_ty, |target| {
524
- let unsize = Adjustment { kind : Adjust :: Pointer ( PointerCast :: Unsize ) , target } ;
525
- match reborrow {
526
- None => vec ! [ unsize] ,
527
- Some ( ( ref deref, ref autoref) ) => vec ! [ deref. clone( ) , autoref. clone( ) , unsize] ,
528
- }
529
- } )
559
+ let unsize =
560
+ Adjustment { kind : Adjust :: Pointer ( PointerCast :: Unsize ) , target : to_ty. clone ( ) } ;
561
+ let adjustments = match reborrow {
562
+ None => vec ! [ unsize] ,
563
+ Some ( ( deref, autoref) ) => vec ! [ deref, autoref, unsize] ,
564
+ } ;
565
+ success ( adjustments, to_ty. clone ( ) , vec ! [ ] )
530
566
}
531
567
}
532
568
0 commit comments