@@ -2356,28 +2356,45 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
23562356 class Closure extends Callable , Expr ;
23572357
23582358 /**
2359- * A special pseudo type representing a particular closure parameter.
2359+ * A special pseudo type representing a particular closure parameter without
2360+ * a type annotation.
23602361 *
2361- * This is needed in cases where the type of a closure parameter must be
2362- * inferred from the inferred _return type_ of the closure. For example,
2363- * in
2362+ * For such parameters, we want to infer the type based on the context in which
2363+ * the closure occurs, and while we could do this by assigning the parameter the
2364+ * pseudo type `UnknownType`, this would mean that the parameter type could also
2365+ * be inferred from _within_ the closure body, which we want to avoid.
2366+ *
2367+ * There are two ways for type information to flow contextually into a closure
2368+ * parameter: (A) either by knowing the types of arguments, or (B) by knowing the
2369+ * return type. Only case B makes use of `ClosureParameterPseudoType`s.
2370+ *
2371+ * ### Case A
23642372 *
23652373 * ```rust
23662374 * let c = |x| (x, false);
2367- * let r: i32 = c(Default::default()).0 ;
2375+ * let r = c(0) ;
23682376 * ```
23692377 *
2370- * We
2378+ * 1. `c` is assigned the type `Fn(UnknownType) -> ...`,
2379+ * 2. since `0` has type `i32`, we can infer the `c` has type `Fn(i32) -> ...`, and
2380+ * 3. using contextual inference, we conclude that `x` has type `i32`.
2381+ *
2382+ * ### Case B
23712383 *
2372- * 1. assign `x` the pseudo type `T_x`,
2384+ * ```rust
2385+ * let c = |x| (x, false);
2386+ * let r: i32 = c(Default::default()).0;
2387+ * ```
2388+ *
2389+ * 1. `x` is assigned the pseudo type `T_x`,
23732390 * 2. infer that the return type of `c` is `(T_x, bool)` and hence that `c` has type
2374- * `Fn(<missing> ) -> (T_x, bool)`,
2391+ * `Fn(... ) -> (T_x, bool)`,
23752392 * 3. this enables us to detect that contextual inference is needed, so we also
2376- * assign `c` the type `Fn(<missing> ) -> (UnknownType, bool)`,
2393+ * assign `c` the type `Fn(... ) -> (UnknownType, bool)`,
23772394 * 4. infer that `c(Default::default()).0` must have `UnknownType`,
2378- * 5. infer, using contextual inference, that `c` has type `Fn(<missing> ) -> (i32, bool)`,
2395+ * 5. infer, using contextual inference, that `c` has type `Fn(... ) -> (i32, bool)`,
23792396 * and finally
2380- * 6. since `c` also has type `Fn(<missing> ) -> (T_x, bool)`, we conclude that `x` has type
2397+ * 6. since `c` also has type `Fn(... ) -> (T_x, bool)`, we conclude that `x` has type
23812398 * `i32` and hence that `c` has type `Fn(i32) -> (i32, bool)`.
23822399 *
23832400 * Note that steps 2, 4, and 5 are standard inference steps.
@@ -3037,11 +3054,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
30373054 // steps are reversed in contextual typing
30383055 exists ( TypePath path1 , AstNode n2 , TypePath path2 , TypePath suffix |
30393056 result = inferType ( n2 , path2 .appendInverse ( suffix ) ) and
3040- path = path1 .append ( suffix )
3041- |
3057+ path = path1 .append ( suffix ) and
30423058 step ( n , path1 , n2 , path2 )
3043- or
3044- closureStep ( n , path1 , n2 , path2 )
30453059 )
30463060 }
30473061
@@ -3131,47 +3145,51 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31313145 pragma [ nomagic]
31323146 private Type inferClosureParameterTypeCand ( AstNode n , TypePath path ) {
31333147 result = inferType ( n , path ) and
3134- hasClosureParameterPseudoType ( n ) and
3135- not result instanceof UnknownType
3148+ hasClosureParameterPseudoType ( n )
31363149 }
31373150
31383151 private Type inferClosureParameterPseudoType ( AstNode n , TypePath path ) {
3139- // The `case X` comments below refer to the cases in the QL doc for
3140- // `ClosureParameterPseudoType`.
3152+ // The `step X` comments below refer to the steps for 'Case B' in the
3153+ // QL doc for `ClosureParameterPseudoType`.
31413154 exists ( Closure c , Parameter p | p = c .getParameter ( _) |
3142- // case 1
3155+ // step 1
31433156 n = p .getPattern ( ) and
31443157 path .isEmpty ( ) and
31453158 not exists ( p .getType ( ) ) and
31463159 result .( ClosureParameterPseudoType ) .getParameter ( ) = p
31473160 or
3148- // case 3
3161+ // step 3
31493162 hasClosureParameterPseudoType ( c , p , path ) and
31503163 n = c and
31513164 result instanceof UnknownType
31523165 )
31533166 or
3154- // case 6
3167+ // step 6
31553168 exists ( AstNode n0 , TypePath path0 |
31563169 hasClosureParameterPseudoType ( n0 , path0 , n , path ) and
3157- result = inferClosureParameterTypeCand ( n0 , path0 )
3170+ result = inferClosureParameterTypeCand ( n0 , path0 ) and
3171+ not ( path .isEmpty ( ) and result instanceof UnknownType )
31583172 )
31593173 }
31603174
31613175 Type inferClosureType ( AstNode n , TypePath path ) {
31623176 result = inferClosureParameterPseudoType ( n , path )
31633177 or
3178+ // The `step X` comments below refer to the steps for 'Case A' in the
3179+ // QL doc for `ClosureParameterPseudoType`.
31643180 exists ( Closure c , Parameter p |
31653181 p = c .getParameter ( _) and
31663182 not exists ( p .getType ( ) )
31673183 |
3184+ // step 1
31683185 n = c and
31693186 path = getClosureParameterTypePath ( p ) and
31703187 result instanceof UnknownType
31713188 or
3189+ // step 3
31723190 n = p .getPattern ( ) and
31733191 result = inferType ( c , getClosureParameterTypePath ( p ) .appendInverse ( path ) ) and
3174- not result instanceof UnknownType
3192+ not ( path . isEmpty ( ) and result instanceof UnknownType )
31753193 )
31763194 }
31773195 }
@@ -3194,7 +3212,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31943212 n = decl .getPattern ( ) and
31953213 not exists ( decl .getInitializer ( ) ) and
31963214 not exists ( decl .getType ( ) ) and
3197- not n = any ( Parameter p ) .getPattern ( ) and
3215+ not n = any ( Parameter p ) .getPattern ( ) and // closure parameters are handled in `ClosureTyping`
31983216 path .isEmpty ( )
31993217 )
32003218 ) and
0 commit comments