@@ -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 knowning 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`.
23712381 *
2372- * 1. assign `x` the pseudo type `T_x`,
2382+ * ### Case B
2383+ *
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.
@@ -3131,47 +3148,51 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31313148 pragma [ nomagic]
31323149 private Type inferClosureParameterTypeCand ( AstNode n , TypePath path ) {
31333150 result = inferType ( n , path ) and
3134- hasClosureParameterPseudoType ( n ) and
3135- not result instanceof UnknownType
3151+ hasClosureParameterPseudoType ( n )
31363152 }
31373153
31383154 private Type inferClosureParameterPseudoType ( AstNode n , TypePath path ) {
3139- // The `case X` comments below refer to the cases in the QL doc for
3140- // `ClosureParameterPseudoType`.
3155+ // The `step X` comments below refer to the steps for 'Case B' in the
3156+ // QL doc for `ClosureParameterPseudoType`.
31413157 exists ( Closure c , Parameter p | p = c .getParameter ( _) |
3142- // case 1
3158+ // step 1
31433159 n = p .getPattern ( ) and
31443160 path .isEmpty ( ) and
31453161 not exists ( p .getType ( ) ) and
31463162 result .( ClosureParameterPseudoType ) .getParameter ( ) = p
31473163 or
3148- // case 3
3164+ // step 3
31493165 hasClosureParameterPseudoType ( c , p , path ) and
31503166 n = c and
31513167 result instanceof UnknownType
31523168 )
31533169 or
3154- // case 6
3170+ // step 6
31553171 exists ( AstNode n0 , TypePath path0 |
31563172 hasClosureParameterPseudoType ( n0 , path0 , n , path ) and
3157- result = inferClosureParameterTypeCand ( n0 , path0 )
3173+ result = inferClosureParameterTypeCand ( n0 , path0 ) and
3174+ not ( path .isEmpty ( ) and result instanceof UnknownType )
31583175 )
31593176 }
31603177
31613178 Type inferClosureType ( AstNode n , TypePath path ) {
31623179 result = inferClosureParameterPseudoType ( n , path )
31633180 or
3181+ // The `step X` comments below refer to the steps for 'Case A' in the
3182+ // QL doc for `ClosureParameterPseudoType`.
31643183 exists ( Closure c , Parameter p |
31653184 p = c .getParameter ( _) and
31663185 not exists ( p .getType ( ) )
31673186 |
3187+ // step 1
31683188 n = c and
31693189 path = getClosureParameterTypePath ( p ) and
31703190 result instanceof UnknownType
31713191 or
3192+ // step 3
31723193 n = p .getPattern ( ) and
31733194 result = inferType ( c , getClosureParameterTypePath ( p ) .appendInverse ( path ) ) and
3174- not result instanceof UnknownType
3195+ not ( path . isEmpty ( ) and result instanceof UnknownType )
31753196 )
31763197 }
31773198 }
@@ -3194,7 +3215,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31943215 n = decl .getPattern ( ) and
31953216 not exists ( decl .getInitializer ( ) ) and
31963217 not exists ( decl .getType ( ) ) and
3197- not n = any ( Parameter p ) .getPattern ( ) and
3218+ not n = any ( Parameter p ) .getPattern ( ) and // closure parameters are handled in `ClosureTyping`
31983219 path .isEmpty ( )
31993220 )
32003221 ) and
0 commit comments