@@ -2667,6 +2667,19 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
26672667 */
26682668 predicate stepLanguageSpecific ( AstNode n1 , TypePath prefix1 , AstNode n2 , TypePath prefix2 ) ;
26692669
2670+ /**
2671+ * Like `stepLanguageSpecific`, but allows for recursion through type inference, which
2672+ * has the consequence that it cannot be used in the logic for inferring certain type
2673+ * information.
2674+ *
2675+ * Only use this predicate when using `stepLanguageSpecific` results in non-monotonicity.
2676+ */
2677+ default predicate stepLanguageSpecificExtra (
2678+ AstNode n1 , TypePath prefix1 , AstNode n2 , TypePath prefix2
2679+ ) {
2680+ none ( )
2681+ }
2682+
26702683 /**
26712684 * Gets the inferred type of `n` at `path`.
26722685 *
@@ -2684,6 +2697,13 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
26842697 * in `inferTypeLanguageSpecific`; if in doubt, use `inferTypeLanguageSpecific` instead.
26852698 */
26862699 default Type inferTypeCertainLanguageSpecific ( AstNode n , TypePath path ) { none ( ) }
2700+
2701+ /**
2702+ * Holds if contextual inference is allowed for the node `n` at the type path
2703+ * `path`. This has the same effect as assigning `UnknownType` to `n` at `path`,
2704+ * but prevents propagation of `UnknownType` from `n` to other nodes.
2705+ */
2706+ default predicate allowContextualInference ( AstNode n , TypePath path ) { none ( ) }
26872707 }
26882708
26892709 module Make3< InputSig3 Input3> {
@@ -2893,6 +2913,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
28932913 private predicate step ( AstNode n1 , TypePath prefix1 , AstNode n2 , TypePath prefix2 ) {
28942914 stepLanguageSpecific ( n1 , prefix1 , n2 , prefix2 )
28952915 or
2916+ stepLanguageSpecificExtra ( n1 , prefix1 , n2 , prefix2 )
2917+ or
28962918 Certain:: stepCertain ( n1 , prefix1 , n2 , prefix2 )
28972919 or
28982920 prefix1 .isEmpty ( ) and
@@ -3234,70 +3256,97 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
32343256 * This module identifies calls where the return type may need to be inferred from the
32353257 * context, and also implements logic for performing contextual inference.
32363258 */
3237- private module ContextualTyping {
3238- pragma [ nomagic]
3239- private TypeParameter getAConstrained ( TypeParameter tp ) {
3240- result = getATypeParameterConstraint ( tp ) .getTypeAt ( _)
3241- }
3242-
3259+ module ContextualTyping {
32433260 /**
3244- * Holds if callable `c` mentions type parameter `tp` at some parameter,
3245- * possibly via a constraint on another mentioned type parameter.
3261+ * Provides the input to `ContextualReturnType`.
32463262 */
3247- pragma [ nomagic]
3248- private predicate mentionsTypeParameterAtParameter ( Callable c , TypeParameter tp ) {
3249- tp = getAConstrained * ( c .getParameter ( _) .getType ( ) .getTypeAt ( _) )
3263+ signature module ContextualReturnTypeInputSig {
3264+ /** Holds if `c` has the type parameter `tp` at its return type at `path`. */
3265+ default predicate callableHasTypeParameterAtReturnType (
3266+ Callable c , TypePath path , TypeParameter tp
3267+ ) {
3268+ tp = getCallableReturnType ( c , path )
3269+ }
3270+
3271+ /** Gets a parameter of `c`. */
3272+ default Parameter getACallableParameter ( Callable c ) { result = c .getParameter ( _) }
32503273 }
32513274
32523275 /**
3253- * Holds if the return type of the callable `c` at `path` is type parameter
3254- * `tp`, and `tp` does not appear in the type of any parameter of `c`.
3255- *
3256- * In this case, the context in which `p` is called may be needed to infer
3257- * the instantiation of `tp`.
3258- *
3259- * This covers functions like `Default::default` and `Vec::new` in Rust.
3276+ * Provide logic for identifying calls where the return type may need to be inferred from the context.
32603277 */
3261- pragma [ nomagic ]
3262- private predicate callableReturnContextTypedAt ( Callable c , TypePath path , TypeParameter tp ) {
3263- tp = getCallableReturnType ( c , path ) and
3264- not mentionsTypeParameterAtParameter ( c , tp )
3265- }
3278+ module ContextualReturnType < ContextualReturnTypeInputSig Input > {
3279+ pragma [ nomagic ]
3280+ private TypeParameter getAConstrained ( TypeParameter tp ) {
3281+ result = getATypeParameterConstraint ( tp ) . getTypeAt ( _ )
3282+ }
32663283
3267- bindingset [ invocation, target]
3268- pragma [ inline_late]
3269- private predicate hasTypeArgument ( Invocation invocation , Callable target , TypeParameter tp ) {
3270- exists ( Type t |
3271- InvocationTypeQualifierMatching:: typeMatch ( invocation , _, _, _, t , tp ) and
3272- not t instanceof PseudoType
3273- )
3274- or
3275- exists ( InvocationMatching:: getTypeArgument ( invocation , target , tp , _) )
3276- }
3284+ /**
3285+ * Holds if callable `c` mentions type parameter `tp` at some parameter,
3286+ * possibly via a constraint on another mentioned type parameter.
3287+ */
3288+ pragma [ nomagic]
3289+ private predicate mentionsTypeParameterAtParameter ( Callable c , TypeParameter tp ) {
3290+ tp = getAConstrained * ( Input:: getACallableParameter ( c ) .getType ( ) .getTypeAt ( _) )
3291+ }
32773292
3278- /**
3279- * Holds if `invocation` resolves to some target where the return type at `path`
3280- * may have to be inferred from the context.
3281- */
3282- pragma [ nomagic]
3283- predicate needsContextualTyping ( Invocation invocation , TypePath path ) {
3284- exists ( Callable target , TypeParameter tp |
3285- target = invocation .getATargetForTypeQualifierMatching ( )
3293+ /**
3294+ * Holds if the return type of the callable `c` at `path` is type parameter
3295+ * `tp`, and `tp` does not appear in the type of any parameter of `c`.
3296+ *
3297+ * In this case, the context in which `p` is called may be needed to infer
3298+ * the instantiation of `tp`.
3299+ *
3300+ * This covers functions like `Default::default` and `Vec::new` in Rust.
3301+ */
3302+ pragma [ nomagic]
3303+ private predicate callableReturnContextTypedAt ( Callable c , TypePath path , TypeParameter tp ) {
3304+ Input:: callableHasTypeParameterAtReturnType ( c , path , tp ) and
3305+ not mentionsTypeParameterAtParameter ( c , tp )
3306+ }
3307+
3308+ bindingset [ invocation, target]
3309+ pragma [ inline_late]
3310+ private predicate hasTypeArgument ( Invocation invocation , Callable target , TypeParameter tp ) {
3311+ exists ( Type t |
3312+ InvocationTypeQualifierMatching:: typeMatch ( invocation , _, _, _, t , tp ) and
3313+ not t instanceof PseudoType
3314+ )
32863315 or
3287- target = invocation .getTarget ( _)
3288- |
3289- callableReturnContextTypedAt ( target , path , tp ) and
3290- // check that no explicit type arguments have been supplied that bind `tp`
3291- not exists ( TypeParameter supplied |
3292- tp = getAConstrained * ( supplied ) and
3293- hasTypeArgument ( invocation , target , supplied )
3316+ exists ( InvocationMatching:: getTypeArgument ( invocation , target , tp , _) )
3317+ }
3318+
3319+ /**
3320+ * Holds if `invocation` resolves to some target where the return type at `path`
3321+ * may have to be inferred from the context.
3322+ */
3323+ pragma [ nomagic]
3324+ predicate needsContextualTyping ( Invocation invocation , TypePath path ) {
3325+ exists ( Callable target , TypeParameter tp |
3326+ target = invocation .getATargetForTypeQualifierMatching ( )
3327+ or
3328+ target = invocation .getTarget ( _)
3329+ |
3330+ callableReturnContextTypedAt ( target , path , tp ) and
3331+ // check that no explicit type arguments have been supplied that bind `tp`
3332+ not exists ( TypeParameter supplied |
3333+ tp = getAConstrained * ( supplied ) and
3334+ hasTypeArgument ( invocation , target , supplied )
3335+ )
32943336 )
3295- )
3337+ }
32963338 }
32973339
3340+ private module DefaultContextualReturnTypeInput implements ContextualReturnTypeInputSig { }
3341+
3342+ predicate needsContextualTyping =
3343+ ContextualReturnType< DefaultContextualReturnTypeInput > :: needsContextualTyping / 2 ;
3344+
32983345 pragma [ nomagic]
32993346 predicate hasUnknownTypeAt ( AstNode n , TypePath path ) {
33003347 inferType ( n , path ) instanceof UnknownType
3348+ or
3349+ allowContextualInference ( n , path )
33013350 }
33023351
33033352 pragma [ nomagic]
@@ -3326,10 +3375,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
33263375 private Type inferTypeContextualCand1 ( AstNode n , TypePath prefix , TypePath path ) {
33273376 result = inferTypeContextualCand0 ( n , path ) and
33283377 hasUnknownType ( n ) and
3329- prefix = path .getAPrefix ( ) and
3330- // no need to propagate `UnknownType`s contextually; `n` must already have an
3331- // `UnknownType` at some prefix of `path`
3332- not result instanceof UnknownType
3378+ prefix = path .getAPrefix ( )
33333379 }
33343380
33353381 pragma [ nomagic]
@@ -3465,6 +3511,38 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
34653511 }
34663512 }
34673513
3514+ /**
3515+ * Holds if the type of `n` at `path` is `t` and the `j`th element of `path`
3516+ * corresponds to the `i`th type parameter of the unknown type.
3517+ */
3518+ pragma [ nomagic]
3519+ private predicate infersUnknownTypeArg0 ( AstNode n , int i , int j , TypePath path , Type t ) {
3520+ exists ( TypeParameter tp |
3521+ ContextualTyping:: hasUnknownType ( n ) and
3522+ tp = any ( UnknownType ut ) .getPositionalTypeParameter ( i ) and
3523+ t = inferType ( n , path ) and
3524+ not t instanceof UnknownType and
3525+ tp = path .getElement ( j )
3526+ )
3527+ }
3528+
3529+ /**
3530+ * Holds if the type of `n` at `path` is `t`, where
3531+ * `path = prefix ++ tp_i ++ suffix` and `tp_i` is the `i`th type parameter
3532+ * of the unknown type.
3533+ */
3534+ pragma [ nomagic]
3535+ private predicate infersUnknownTypeArg1 (
3536+ AstNode n , TypePath prefix , int i , TypePath suffix , Type t
3537+ ) {
3538+ exists ( TypePath path , int j , TypePath suffix0 |
3539+ infersUnknownTypeArg0 ( n , i , j , path , t ) and
3540+ prefix = path .getProperPrefix ( j ) and
3541+ path = prefix .appendInverse ( suffix0 ) and
3542+ suffix0 .isCons ( _, suffix )
3543+ )
3544+ }
3545+
34683546 /**
34693547 * Holds if `n` has unknown type at `prefix`, but is still able to
34703548 * infer a known type at `suffix` for the `i`th type parameter of whatever
@@ -3486,13 +3564,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
34863564 private predicate infersUnknownTypeArg (
34873565 AstNode n , TypePath prefix , int i , TypePath suffix , Type t
34883566 ) {
3489- exists ( TypeParameter tp , TypePath suffix0 |
3490- ContextualTyping:: hasUnknownTypeAt ( n , prefix ) and
3491- suffix0 .isCons ( tp , suffix ) and
3492- tp = any ( UnknownType ut ) .getPositionalTypeParameter ( i ) and
3493- t = inferType ( n , prefix .appendInverse ( suffix0 ) ) and
3494- not t instanceof UnknownType
3495- )
3567+ ContextualTyping:: hasUnknownTypeAt ( n , prefix ) and
3568+ infersUnknownTypeArg1 ( n , prefix , i , suffix , t )
34963569 }
34973570
34983571 pragma [ nomagic]
0 commit comments