@@ -2684,6 +2684,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
26842684 * in `inferTypeLanguageSpecific`; if in doubt, use `inferTypeLanguageSpecific` instead.
26852685 */
26862686 default Type inferTypeCertainLanguageSpecific ( AstNode n , TypePath path ) { none ( ) }
2687+
2688+ default predicate allowContextualInference ( AstNode n , TypePath path ) { none ( ) }
26872689 }
26882690
26892691 module Make3< InputSig3 Input3> {
@@ -3034,7 +3036,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
30343036 // `inferTypeContextualCand2` performs the proper check for contextual
30353037 // typing, but we can already rule out cases where receivers don't have
30363038 // an unknown type anywhere
3037- ContextualTyping:: hasUnknownType ( receiver )
3039+ ContextualTyping:: hasUnknownType ( receiver , _ )
30383040 )
30393041 }
30403042
@@ -3223,7 +3225,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
32233225 // `inferTypeContextualCand2` performs the proper check for contextual
32243226 // typing, but we can already rule out cases where arguments don't have
32253227 // an unknown type anywhere
3226- ContextualTyping:: hasUnknownType ( arg )
3228+ ContextualTyping:: hasUnknownType ( arg , _ )
32273229 }
32283230
32293231 /**
@@ -3234,74 +3236,101 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
32343236 * This module identifies calls where the return type may need to be inferred from the
32353237 * context, and also implements logic for performing contextual inference.
32363238 */
3237- private module ContextualTyping {
3238- pragma [ nomagic]
3239- private TypeParameter getAConstrained ( TypeParameter tp ) {
3240- result = getATypeParameterConstraint ( tp ) .getTypeAt ( _)
3241- }
3242-
3239+ module ContextualTyping {
32433240 /**
3244- * Holds if callable `c` mentions type parameter `tp` at some parameter,
3245- * possibly via a constraint on another mentioned type parameter.
3241+ * Provides the input to `ContextualReturnType`.
32463242 */
3247- pragma [ nomagic]
3248- private predicate mentionsTypeParameterAtParameter ( Callable c , TypeParameter tp ) {
3249- tp = getAConstrained * ( c .getParameter ( _) .getType ( ) .getTypeAt ( _) )
3243+ signature module ContextualReturnTypeInputSig {
3244+ /** Holds if `c` has the type parameter `tp` at its return type at `path`. */
3245+ default predicate callableHasTypeParameterAtReturnType (
3246+ Callable c , TypePath path , TypeParameter tp
3247+ ) {
3248+ tp = getCallableReturnType ( c , path )
3249+ }
3250+
3251+ /** Gets a parameter of `c`. */
3252+ default Parameter getACallableParameter ( Callable c ) { result = c .getParameter ( _) }
32503253 }
32513254
32523255 /**
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.
3256+ * Provide logic for identifying calls where the return type may need to be inferred from the context.
32603257 */
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- }
3258+ module ContextualReturnType < ContextualReturnTypeInputSig Input > {
3259+ pragma [ nomagic ]
3260+ private TypeParameter getAConstrained ( TypeParameter tp ) {
3261+ result = getATypeParameterConstraint ( tp ) . getTypeAt ( _ )
3262+ }
32663263
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- }
3264+ /**
3265+ * Holds if callable `c` mentions type parameter `tp` at some parameter,
3266+ * possibly via a constraint on another mentioned type parameter.
3267+ */
3268+ pragma [ nomagic]
3269+ private predicate mentionsTypeParameterAtParameter ( Callable c , TypeParameter tp ) {
3270+ tp = getAConstrained * ( Input:: getACallableParameter ( c ) .getType ( ) .getTypeAt ( _) )
3271+ }
32773272
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 ( )
3273+ /**
3274+ * Holds if the return type of the callable `c` at `path` is type parameter
3275+ * `tp`, and `tp` does not appear in the type of any parameter of `c`.
3276+ *
3277+ * In this case, the context in which `p` is called may be needed to infer
3278+ * the instantiation of `tp`.
3279+ *
3280+ * This covers functions like `Default::default` and `Vec::new` in Rust.
3281+ */
3282+ pragma [ nomagic]
3283+ private predicate callableReturnContextTypedAt ( Callable c , TypePath path , TypeParameter tp ) {
3284+ Input:: callableHasTypeParameterAtReturnType ( c , path , tp ) and
3285+ not mentionsTypeParameterAtParameter ( c , tp )
3286+ }
3287+
3288+ bindingset [ invocation, target]
3289+ pragma [ inline_late]
3290+ private predicate hasTypeArgument ( Invocation invocation , Callable target , TypeParameter tp ) {
3291+ exists ( Type t |
3292+ InvocationTypeQualifierMatching:: typeMatch ( invocation , _, _, _, t , tp ) and
3293+ not t instanceof PseudoType
3294+ )
32863295 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 )
3296+ exists ( InvocationMatching:: getTypeArgument ( invocation , target , tp , _) )
3297+ }
3298+
3299+ /**
3300+ * Holds if `invocation` resolves to some target where the return type at `path`
3301+ * may have to be inferred from the context.
3302+ */
3303+ pragma [ nomagic]
3304+ predicate needsContextualTyping ( Invocation invocation , TypePath path ) {
3305+ exists ( Callable target , TypeParameter tp |
3306+ target = invocation .getATargetForTypeQualifierMatching ( )
3307+ or
3308+ target = invocation .getTarget ( _)
3309+ |
3310+ callableReturnContextTypedAt ( target , path , tp ) and
3311+ // check that no explicit type arguments have been supplied that bind `tp`
3312+ not exists ( TypeParameter supplied |
3313+ tp = getAConstrained * ( supplied ) and
3314+ hasTypeArgument ( invocation , target , supplied )
3315+ )
32943316 )
3295- )
3317+ }
32963318 }
32973319
3320+ private module DefaultContextualReturnTypeInput implements ContextualReturnTypeInputSig { }
3321+
3322+ predicate needsContextualTyping =
3323+ ContextualReturnType< DefaultContextualReturnTypeInput > :: needsContextualTyping / 2 ;
3324+
32983325 pragma [ nomagic]
3299- predicate hasUnknownTypeAt ( AstNode n , TypePath path ) {
3300- inferType ( n , path ) instanceof UnknownType
3326+ predicate hasUnknownTypeAt ( AstNode n , TypePath path , boolean actual ) {
3327+ inferType ( n , path ) instanceof UnknownType and actual = true
3328+ or
3329+ allowContextualInference ( n , path ) and actual = false
33013330 }
33023331
33033332 pragma [ nomagic]
3304- predicate hasUnknownType ( AstNode n ) { hasUnknownTypeAt ( n , _) }
3333+ predicate hasUnknownType ( AstNode n , boolean actual ) { hasUnknownTypeAt ( n , _, actual ) }
33053334
33063335 pragma [ nomagic]
33073336 private Type inferTypeContextualCand0 ( AstNode n , TypePath path ) {
@@ -3325,18 +3354,20 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
33253354 pragma [ nomagic]
33263355 private Type inferTypeContextualCand1 ( AstNode n , TypePath prefix , TypePath path ) {
33273356 result = inferTypeContextualCand0 ( n , path ) and
3328- hasUnknownType ( n ) and
33293357 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
3358+ exists ( boolean actual |
3359+ hasUnknownType ( n , actual ) and
3360+ // no need to propagate `UnknownType`s contextually; `n` must already have an
3361+ // `UnknownType` at some prefix of `path`
3362+ if result instanceof UnknownType then actual = false else any ( )
3363+ )
33333364 }
33343365
33353366 pragma [ nomagic]
33363367 private Type inferTypeContextualCand2 ( AstNode n , TypePath path ) {
33373368 exists ( TypePath prefix |
33383369 result = inferTypeContextualCand1 ( n , prefix , path ) and
3339- hasUnknownTypeAt ( n , prefix )
3370+ hasUnknownTypeAt ( n , prefix , _ )
33403371 )
33413372 }
33423373
@@ -3347,7 +3378,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
33473378 */
33483379 pragma [ nomagic]
33493380 private predicate isValidContextualNonEmptyPath ( AstNode n , TypePath path ) {
3350- hasUnknownType ( n ) and
3381+ hasUnknownType ( n , _ ) and
33513382 exists ( TypePath prefix , TypeParameter tp |
33523383 tp = inferType ( n , prefix ) .getATypeParameter ( ) and
33533384 path = TypePath:: snoc ( prefix , tp )
@@ -3367,6 +3398,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
33673398 path .isEmpty ( )
33683399 or
33693400 isValidContextualNonEmptyPath ( n , path )
3401+ or
3402+ allowContextualInference ( n , path .getAPrefix ( ) )
33703403 )
33713404 }
33723405 }
@@ -3487,7 +3520,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
34873520 AstNode n , TypePath prefix , int i , TypePath suffix , Type t
34883521 ) {
34893522 exists ( TypeParameter tp , TypePath suffix0 |
3490- ContextualTyping:: hasUnknownTypeAt ( n , prefix ) and
3523+ ContextualTyping:: hasUnknownTypeAt ( n , prefix , _ ) and
34913524 suffix0 .isCons ( tp , suffix ) and
34923525 tp = any ( UnknownType ut ) .getPositionalTypeParameter ( i ) and
34933526 t = inferType ( n , prefix .appendInverse ( suffix0 ) ) and
@@ -3497,7 +3530,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
34973530
34983531 pragma [ nomagic]
34993532 private predicate infersKnownAndUnknownType ( AstNode n , TypePath path , int i , TypeParameter tp ) {
3500- ContextualTyping:: hasUnknownTypeAt ( n , path ) and
3533+ ContextualTyping:: hasUnknownTypeAt ( n , path , _ ) and
35013534 exists ( Type t |
35023535 t = inferType ( n , path ) and
35033536 not t instanceof UnknownType and
0 commit comments