@@ -50,11 +50,44 @@ fn success(
50
50
#[ derive( Clone , Debug ) ]
51
51
pub ( super ) struct CoerceMany {
52
52
expected_ty : Ty ,
53
+ final_ty : Option < Ty > ,
53
54
}
54
55
55
56
impl CoerceMany {
56
57
pub ( super ) fn new ( expected : Ty ) -> Self {
57
- CoerceMany { expected_ty : expected }
58
+ CoerceMany { expected_ty : expected, final_ty : None }
59
+ }
60
+
61
+ /// Returns the "expected type" with which this coercion was
62
+ /// constructed. This represents the "downward propagated" type
63
+ /// that was given to us at the start of typing whatever construct
64
+ /// we are typing (e.g., the match expression).
65
+ ///
66
+ /// Typically, this is used as the expected type when
67
+ /// type-checking each of the alternative expressions whose types
68
+ /// we are trying to merge.
69
+ pub ( super ) fn expected_ty ( & self ) -> Ty {
70
+ self . expected_ty . clone ( )
71
+ }
72
+
73
+ /// Returns the current "merged type", representing our best-guess
74
+ /// at the LUB of the expressions we've seen so far (if any). This
75
+ /// isn't *final* until you call `self.complete()`, which will return
76
+ /// the merged type.
77
+ pub ( super ) fn merged_ty ( & self ) -> Ty {
78
+ self . final_ty . clone ( ) . unwrap_or_else ( || self . expected_ty . clone ( ) )
79
+ }
80
+
81
+ pub ( super ) fn complete ( self , ctx : & mut InferenceContext < ' _ > ) -> Ty {
82
+ if let Some ( final_ty) = self . final_ty {
83
+ final_ty
84
+ } else {
85
+ ctx. result . standard_types . never . clone ( )
86
+ }
87
+ }
88
+
89
+ pub ( super ) fn coerce_forced_unit ( & mut self , ctx : & mut InferenceContext < ' _ > ) {
90
+ self . coerce ( ctx, None , & ctx. result . standard_types . unit . clone ( ) )
58
91
}
59
92
60
93
/// Merge two types from different branches, with possible coercion.
@@ -76,51 +109,46 @@ impl CoerceMany {
76
109
// Special case: two function types. Try to coerce both to
77
110
// pointers to have a chance at getting a match. See
78
111
// https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
79
- let sig = match ( self . expected_ty . kind ( Interner ) , expr_ty. kind ( Interner ) ) {
112
+ let sig = match ( self . merged_ty ( ) . kind ( Interner ) , expr_ty. kind ( Interner ) ) {
80
113
( TyKind :: FnDef ( ..) | TyKind :: Closure ( ..) , TyKind :: FnDef ( ..) | TyKind :: Closure ( ..) ) => {
81
114
// FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
82
115
// we should be coercing the closure to a fn pointer of the safety of the FnDef
83
116
cov_mark:: hit!( coerce_fn_reification) ;
84
117
let sig =
85
- self . expected_ty . callable_sig ( ctx. db ) . expect ( "FnDef without callable sig" ) ;
118
+ self . merged_ty ( ) . callable_sig ( ctx. db ) . expect ( "FnDef without callable sig" ) ;
86
119
Some ( sig)
87
120
}
88
121
_ => None ,
89
122
} ;
90
123
if let Some ( sig) = sig {
91
124
let target_ty = TyKind :: Function ( sig. to_fn_ptr ( ) ) . intern ( Interner ) ;
92
- let result1 = ctx. table . coerce_inner ( self . expected_ty . clone ( ) , & target_ty) ;
125
+ let result1 = ctx. table . coerce_inner ( self . merged_ty ( ) , & target_ty) ;
93
126
let result2 = ctx. table . coerce_inner ( expr_ty. clone ( ) , & target_ty) ;
94
127
if let ( Ok ( result1) , Ok ( result2) ) = ( result1, result2) {
95
128
ctx. table . register_infer_ok ( result1) ;
96
129
ctx. table . register_infer_ok ( result2) ;
97
- return self . expected_ty = target_ty;
130
+ return self . final_ty = Some ( target_ty) ;
98
131
}
99
132
}
100
133
101
134
// It might not seem like it, but order is important here: If the expected
102
135
// type is a type variable and the new one is `!`, trying it the other
103
136
// way around first would mean we make the type variable `!`, instead of
104
137
// just marking it as possibly diverging.
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 ;
138
+ if let Ok ( res ) = ctx. coerce ( expr, & expr_ty, & self . merged_ty ( ) ) {
139
+ self . final_ty = Some ( res ) ;
140
+ } else if let Ok ( res ) = ctx. coerce ( expr, & self . merged_ty ( ) , & expr_ty) {
141
+ self . final_ty = Some ( res ) ;
109
142
} else {
110
143
if let Some ( id) = expr {
111
144
ctx. result . type_mismatches . insert (
112
145
id. into ( ) ,
113
- TypeMismatch { expected : self . expected_ty . clone ( ) , actual : expr_ty } ,
146
+ TypeMismatch { expected : self . merged_ty ( ) . clone ( ) , actual : expr_ty. clone ( ) } ,
114
147
) ;
115
148
}
116
149
cov_mark:: hit!( coerce_merge_fail_fallback) ;
117
- /* self.expected_ty is already correct */
118
150
}
119
151
}
120
-
121
- pub ( super ) fn complete ( self ) -> Ty {
122
- self . expected_ty
123
- }
124
152
}
125
153
126
154
pub fn could_coerce (
0 commit comments