@@ -512,36 +512,35 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
512
512
513
513
private module AccessBaseType {
514
514
/**
515
- * Holds if inferring types at `a` might depend on the type at `apos`
516
- * having `baseMention` as a transitive base type mention.
515
+ * Holds if inferring types at `a` might depend on the type at `path` of
516
+ * `apos` having `baseMention` as a transitive base type mention.
517
517
*/
518
- private predicate relevantAccess ( Access a , AccessPosition apos , Type base ) {
518
+ private predicate relevantAccess ( Access a , AccessPosition apos , TypePath path , Type base ) {
519
519
exists ( Declaration target , DeclarationPosition dpos |
520
520
adjustedAccessType ( a , apos , target , _, _) and
521
- accessDeclarationPositionMatch ( apos , dpos ) and
522
- declarationBaseType ( target , dpos , base , _, _)
521
+ accessDeclarationPositionMatch ( apos , dpos )
522
+ |
523
+ path .isEmpty ( ) and declarationBaseType ( target , dpos , base , _, _)
524
+ or
525
+ typeParameterConstraintHasTypeParameter ( target , dpos , path , _, base , _, _)
523
526
)
524
527
}
525
528
526
529
pragma [ nomagic]
527
- private Type inferRootType ( Access a , AccessPosition apos ) {
528
- relevantAccess ( a , apos , _) and
529
- result = a .getInferredType ( apos , TypePath:: nil ( ) )
530
- }
531
-
532
- pragma [ nomagic]
533
- private Type inferTypeAt ( Access a , AccessPosition apos , TypeParameter tp , TypePath suffix ) {
534
- relevantAccess ( a , apos , _) and
530
+ private Type inferTypeAt (
531
+ Access a , AccessPosition apos , TypePath prefix , TypeParameter tp , TypePath suffix
532
+ ) {
533
+ relevantAccess ( a , apos , prefix , _) and
535
534
exists ( TypePath path0 |
536
- result = a .getInferredType ( apos , path0 ) and
535
+ result = a .getInferredType ( apos , prefix . append ( path0 ) ) and
537
536
path0 .isCons ( tp , suffix )
538
537
)
539
538
}
540
539
541
540
/**
542
- * Holds if `baseMention` is a (transitive) base type mention of the type of
543
- * `a` at position `apos`, and `t` is mentioned (implicitly) at `path` inside
544
- * `base`. For example, in
541
+ * Holds if `baseMention` is a (transitive) base type mention of the
542
+ * type of `a` at position `apos` at path `pathToSub`, and `t` is
543
+ * mentioned (implicitly) at `path` inside `base`. For example, in
545
544
*
546
545
* ```csharp
547
546
* class C<T1> { }
@@ -570,17 +569,18 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
570
569
*/
571
570
pragma [ nomagic]
572
571
predicate hasBaseTypeMention (
573
- Access a , AccessPosition apos , TypeMention baseMention , TypePath path , Type t
572
+ Access a , AccessPosition apos , TypePath pathToSub , TypeMention baseMention , TypePath path ,
573
+ Type t
574
574
) {
575
- relevantAccess ( a , apos , resolveTypeMentionRoot ( baseMention ) ) and
576
- exists ( Type sub | sub = inferRootType ( a , apos ) |
575
+ relevantAccess ( a , apos , pathToSub , resolveTypeMentionRoot ( baseMention ) ) and
576
+ exists ( Type sub | sub = a . getInferredType ( apos , pathToSub ) |
577
577
not t = sub .getATypeParameter ( ) and
578
578
baseTypeMentionHasTypeAt ( sub , baseMention , path , t )
579
579
or
580
580
exists ( TypePath prefix , TypePath suffix , TypeParameter tp |
581
581
tp = sub .getATypeParameter ( ) and
582
582
baseTypeMentionHasTypeAt ( sub , baseMention , prefix , tp ) and
583
- t = inferTypeAt ( a , apos , tp , suffix ) and
583
+ t = inferTypeAt ( a , apos , pathToSub , tp , suffix ) and
584
584
path = prefix .append ( suffix )
585
585
)
586
586
)
@@ -596,7 +596,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
596
596
Access a , AccessPosition apos , Type base , TypePath path , Type t
597
597
) {
598
598
exists ( TypeMention tm |
599
- AccessBaseType:: hasBaseTypeMention ( a , apos , tm , path , t ) and
599
+ AccessBaseType:: hasBaseTypeMention ( a , apos , TypePath :: nil ( ) , tm , path , t ) and
600
600
base = resolveTypeMentionRoot ( tm )
601
601
)
602
602
}
@@ -671,6 +671,58 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
671
671
t = getTypeArgument ( a , target , tp , path )
672
672
}
673
673
674
+ /**
675
+ * Holds if `tp1` and `tp2` are distinct type parameters of `target`, the
676
+ * declared type at `apos` mentions `tp1` at `path1`, `tp1` has a base
677
+ * type mention of type `constrant` that mentions `tp2` at the path
678
+ * `path2`.
679
+ *
680
+ * For this example
681
+ * ```csharp
682
+ * interface IFoo<A> { }
683
+ * void M<T1, T2>(T2 item) where T2 : IFoo<T1> { }
684
+ * ```
685
+ * with the method declaration being the target and the for the first
686
+ * parameter position, we have the following
687
+ * - `path1 = ""`,
688
+ * - `tp1 = T2`,
689
+ * - `constraint = IFoo`,
690
+ * - `path2 = "A"`,
691
+ * - `tp2 = T1`
692
+ */
693
+ pragma [ nomagic]
694
+ private predicate typeParameterConstraintHasTypeParameter (
695
+ Declaration target , DeclarationPosition dpos , TypePath path1 , TypeParameter tp1 ,
696
+ Type constraint , TypePath path2 , TypeParameter tp2
697
+ ) {
698
+ tp1 = target .getTypeParameter ( _) and
699
+ tp2 = target .getTypeParameter ( _) and
700
+ tp1 != tp2 and
701
+ tp1 = target .getDeclaredType ( dpos , path1 ) and
702
+ exists ( TypeMention tm |
703
+ tm = getABaseTypeMention ( tp1 ) and
704
+ tm .resolveTypeAt ( path2 ) = tp2 and
705
+ constraint = resolveTypeMentionRoot ( tm )
706
+ )
707
+ }
708
+
709
+ pragma [ nomagic]
710
+ private predicate typeConstraintBaseTypeMatch (
711
+ Access a , Declaration target , TypePath path , Type t , TypeParameter tp
712
+ ) {
713
+ not exists ( getTypeArgument ( a , target , tp , _) ) and
714
+ target = a .getTarget ( ) and
715
+ exists (
716
+ TypeMention base , AccessPosition apos , DeclarationPosition dpos , TypePath pathToTp ,
717
+ TypePath pathToTp2
718
+ |
719
+ accessDeclarationPositionMatch ( apos , dpos ) and
720
+ typeParameterConstraintHasTypeParameter ( target , dpos , pathToTp2 , _,
721
+ resolveTypeMentionRoot ( base ) , pathToTp , tp ) and
722
+ AccessBaseType:: hasBaseTypeMention ( a , apos , pathToTp2 , base , pathToTp .append ( path ) , t )
723
+ )
724
+ }
725
+
674
726
pragma [ inline]
675
727
private predicate typeMatch (
676
728
Access a , Declaration target , TypePath path , Type t , TypeParameter tp
@@ -684,6 +736,9 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
684
736
or
685
737
// We can infer the type of `tp` by going up the type hiearchy
686
738
baseTypeMatch ( a , target , path , t , tp )
739
+ or
740
+ // We can infer the type of `tp` by a type bound
741
+ typeConstraintBaseTypeMatch ( a , target , path , t , tp )
687
742
}
688
743
689
744
/**
0 commit comments