diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 006835b89188..b67cdd9a60b3 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2835,6 +2835,24 @@ mod contextual_bound { } } +mod multi_bound { + trait MyTrait {} + + struct S; + + impl MyTrait for S {} + + impl MyTrait for S {} + + fn f + MyTrait>(x: X, t: T) -> X { + x + } + + fn call_f() { + let res = f(true, S); // $ target=f type=res:bool + } +} + fn main() { field_access::f(); // $ target=f method_impl::f(); // $ target=f diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 6321f11c3b85..2f4e4106f088 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -3781,10 +3781,16 @@ inferCertainType | main.rs:2825:55:2825:56 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2827:19:2835:5 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2834:13:2834:15 | [...] | | {EXTERNAL LOCATION} | [;] | -| main.rs:2838:11:2874:1 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2841:20:2841:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2841:41:2841:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2871:16:2871:19 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2847:43:2847:43 | x | | main.rs:2847:10:2847:10 | X | +| main.rs:2847:49:2847:49 | t | | main.rs:2847:13:2847:40 | T | +| main.rs:2847:60:2849:5 | { ... } | | main.rs:2847:10:2847:10 | X | +| main.rs:2848:9:2848:9 | x | | main.rs:2847:10:2847:10 | X | +| main.rs:2851:17:2853:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2852:21:2852:24 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2856:11:2892:1 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2859:20:2859:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2859:41:2859:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2889:16:2889:19 | true | | {EXTERNAL LOCATION} | bool | | overloading.rs:4:19:4:23 | SelfParam | | {EXTERNAL LOCATION} | & | | overloading.rs:4:19:4:23 | SelfParam | TRef | overloading.rs:2:5:11:5 | Self [trait FirstTrait] | | overloading.rs:4:34:6:9 | { ... } | | {EXTERNAL LOCATION} | bool | @@ -12806,49 +12812,58 @@ inferType | main.rs:2834:23:2834:23 | z | | main.rs:2817:5:2817:26 | MyThingB | | main.rs:2834:23:2834:23 | z | B | main.rs:2814:5:2815:19 | S | | main.rs:2834:23:2834:23 | z | B.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2838:11:2874:1 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2839:5:2839:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2840:5:2840:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2841:5:2841:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2841:20:2841:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2841:41:2841:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2842:5:2842:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2843:5:2843:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2844:5:2844:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2845:5:2845:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2846:5:2846:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2847:5:2847:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2848:5:2848:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2849:5:2849:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2850:5:2850:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2851:5:2851:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2852:5:2852:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2853:5:2853:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2854:5:2854:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2855:5:2855:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2856:5:2856:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2857:5:2857:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | -| main.rs:2857:5:2857:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | -| main.rs:2858:5:2858:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2859:5:2859:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2860:5:2860:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2861:5:2861:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2862:5:2862:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2863:5:2863:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2864:5:2864:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2865:5:2865:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2866:5:2866:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2867:5:2867:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2868:5:2868:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2869:5:2869:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2870:5:2870:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2871:5:2871:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2871:5:2871:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2871:5:2871:20 | ...::f(...) | T | main.rs:2564:5:2566:5 | dyn MyTrait | -| main.rs:2871:5:2871:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | -| main.rs:2871:16:2871:19 | true | | {EXTERNAL LOCATION} | bool | -| main.rs:2872:5:2872:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2873:5:2873:17 | empty_array(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2847:43:2847:43 | x | | main.rs:2847:10:2847:10 | X | +| main.rs:2847:49:2847:49 | t | | main.rs:2847:13:2847:40 | T | +| main.rs:2847:60:2849:5 | { ... } | | main.rs:2847:10:2847:10 | X | +| main.rs:2848:9:2848:9 | x | | main.rs:2847:10:2847:10 | X | +| main.rs:2851:17:2853:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2852:13:2852:15 | res | | {EXTERNAL LOCATION} | bool | +| main.rs:2852:19:2852:28 | f(...) | | {EXTERNAL LOCATION} | bool | +| main.rs:2852:21:2852:24 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2852:27:2852:27 | S | | main.rs:2841:5:2841:13 | S | +| main.rs:2856:11:2892:1 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2857:5:2857:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2858:5:2858:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2859:5:2859:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2859:20:2859:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2859:41:2859:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2860:5:2860:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2861:5:2861:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2862:5:2862:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2863:5:2863:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2864:5:2864:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2865:5:2865:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2866:5:2866:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2867:5:2867:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2868:5:2868:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2869:5:2869:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2870:5:2870:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2871:5:2871:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2872:5:2872:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2873:5:2873:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2874:5:2874:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2875:5:2875:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | +| main.rs:2875:5:2875:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | +| main.rs:2876:5:2876:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2877:5:2877:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2878:5:2878:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2879:5:2879:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2880:5:2880:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2881:5:2881:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2882:5:2882:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2883:5:2883:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2884:5:2884:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2885:5:2885:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2886:5:2886:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2887:5:2887:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2888:5:2888:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2889:5:2889:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2889:5:2889:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2889:5:2889:20 | ...::f(...) | T | main.rs:2564:5:2566:5 | dyn MyTrait | +| main.rs:2889:5:2889:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | +| main.rs:2889:16:2889:19 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2890:5:2890:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2891:5:2891:17 | empty_array(...) | | {EXTERNAL LOCATION} | () | | overloading.rs:4:19:4:23 | SelfParam | | {EXTERNAL LOCATION} | & | | overloading.rs:4:19:4:23 | SelfParam | TRef | overloading.rs:2:5:11:5 | Self [trait FirstTrait] | | overloading.rs:4:34:6:9 | { ... } | | {EXTERNAL LOCATION} | bool | diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index 0e259e7b0e02..de115227a07f 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -962,6 +962,31 @@ module Make1 Input1> { ) } + pragma[nomagic] + private predicate conditionSatisfiesAmbigousConstraintTypeAt0( + Term term, Constraint constraint, TypeAbstraction abs, TypeMention sub, TypePath path, + Type t + ) { + exists(TypeMention constraintMention | + satisfiesConstraintTypeMention0(term, constraint, constraintMention, abs, sub, _, _, true) and + conditionSatisfiesConstraintTypeAtForDisambiguation(abs, sub, constraintMention, path, t) + ) + } + + pragma[nomagic] + private predicate conditionSatisfiesAmbigousConstraintTypeAt( + Term term, Constraint constraint, TypeAbstraction abs, TypeMention sub, TypePath path, + Type t + ) { + conditionSatisfiesAmbigousConstraintTypeAt0(term, constraint, abs, sub, path, t) and + ( + t = constraint.getTypeAt(path) + or + // The constraint may contain a type parameter, which we can match to the right type + constraintTypeMatchForDisambiguation(term, constraint, path, t) + ) + } + pragma[nomagic] private predicate satisfiesConstraint0( Term term, Constraint constraint, TypeAbstraction abs, TypeMention sub, TypePath path, @@ -981,10 +1006,7 @@ module Make1 Input1> { conditionSatisfiesConstraintTypeAtForDisambiguation(abs, sub, constraintMention, path1, t1) | - t1 = constraint.getTypeAt(path1) - or - // The constraint may contain a type parameter, which we can match to the right type - constraintTypeMatchForDisambiguation(term, constraint, path1, t1) + conditionSatisfiesAmbigousConstraintTypeAt(term, constraint, abs, sub, path1, t1) ) else any() ) @@ -1357,112 +1379,241 @@ module Make1 Input1> { ) } - private module AccessBaseType { + private module ConstraintMatching { /** - * Holds if the type of `target` at `apos` and `pathToTp` is type parameter `tp`, - * and an argument with root type `argRootType` may be able to be matched against - * `tp` via the `conditionSatisfiesConstraint` hierarchy. + * Holds if the type of `target` at `dpos` contains a type parameter, and an + * access with a corresponding root type `argRootType` may be able to match + * against it. */ pragma[nomagic] private predicate argRootTypeSatisfiesTargetTypeCand( - Type argRootType, Declaration target, AccessPosition apos, TypeParameter tp, - TypePath pathToTp + Type argRootType, Declaration target, DeclarationPosition dpos ) { exists( - DeclarationPosition dpos, TypeMention condition, TypeMention constraint, - Type constraintRootType + TypeParameter tp, TypePath pathToTp, TypeMention condition, Type constraintRootType | - accessDeclarationPositionMatch(apos, dpos) and tp = target.getDeclaredType(dpos, pathToTp) and - conditionSatisfiesConstraintTypeAt(_, condition, constraint, TypePath::nil(), - constraintRootType) and constraintRootType.getATypeParameter() = pathToTp.getHead() and + conditionSatisfiesConstraintTypeAt(_, condition, _, TypePath::nil(), constraintRootType) and argRootType = condition.getTypeAt(TypePath::nil()) ) } - private newtype TRelevantTarget = - MkRelevantTarget(Declaration target, AccessPosition apos) { - argRootTypeSatisfiesTargetTypeCand(_, target, apos, _, _) + private newtype TConstraintPosition = + TDeclarationConstraintPosition(DeclarationPosition dpos) { + argRootTypeSatisfiesTargetTypeCand(_, _, dpos) + } or + TConstrainedTypeParameterConstraintPosition( + TypeParameter constrainedTp, TypeMention constraint + ) { + typeParameterHasConstraint(_, constrainedTp, constraint) } - private class RelevantTarget extends MkRelevantTarget { - Declaration target; - AccessPosition apos; + /** + * A position of a constraint inside a declaration. + * + * This is either a direct `DeclarationPosition` (for example the position of + * a parameter, in which case the constraint is the type of that parameter) or + * a constrained type parameter. + */ + abstract class ConstraintPosition extends TConstraintPosition { + abstract predicate relevantFor(Access a, AccessEnvironment e, Declaration target); - RelevantTarget() { this = MkRelevantTarget(target, apos) } + bindingset[target] + abstract Type getConstraintTypeAt(Declaration target, TypePath path); - Type getTypeAt(TypePath path) { - exists(DeclarationPosition dpos | + bindingset[a, e] + abstract Type getInferredType(Access a, AccessEnvironment e, TypePath path); + + /** Gets the path that leads from `pos` in `target` to the type being constrained at this position. */ + bindingset[target] + abstract TypePath getPathToConstrained(Declaration target, DeclarationPosition pos); + + abstract string toString(); + } + + private class DeclarationConstraintPosition extends ConstraintPosition, + TDeclarationConstraintPosition + { + DeclarationPosition dpos; + + DeclarationConstraintPosition() { this = TDeclarationConstraintPosition(dpos) } + + pragma[nomagic] + private predicate accessTargetsWithArgRootType( + Access a, AccessEnvironment e, Declaration target, Type t + ) { + exists(AccessPosition apos | accessDeclarationPositionMatch(apos, dpos) and - result = target.getDeclaredType(dpos, path) + target = a.getTarget(e) and + t = a.getInferredType(e, apos, TypePath::nil()) + ) + } + + override predicate relevantFor(Access a, AccessEnvironment e, Declaration target) { + exists(Type t | + this.accessTargetsWithArgRootType(a, e, target, t) and + argRootTypeSatisfiesTargetTypeCand(t, target, dpos) ) } - string toString() { result = target.toString() + ", " + apos.toString() } + bindingset[target] + override Type getConstraintTypeAt(Declaration target, TypePath path) { + result = target.getDeclaredType(dpos, path) + } - Location getLocation() { result = target.getLocation() } + bindingset[a, e] + override Type getInferredType(Access a, AccessEnvironment e, TypePath path) { + exists(AccessPosition apos | + accessDeclarationPositionMatch(apos, dpos) and + result = a.getInferredType(e, apos, path) + ) + } + + bindingset[target] + override TypePath getPathToConstrained(Declaration target, DeclarationPosition pos) { + exists(target) and + pos = dpos and + result = TypePath::nil() + } + + override string toString() { result = dpos.toString() } } - pragma[nomagic] - private predicate accessTargetsWithArgRootType( - Access a, AccessEnvironment e, Declaration target, AccessPosition apos, Type t - ) { - target = a.getTarget(e) and - t = a.getInferredType(e, apos, TypePath::nil()) + private class ConstrainedTypeParameterConstraintPosition extends ConstraintPosition, + TConstrainedTypeParameterConstraintPosition + { + TypeParameter constrainedTp; + TypeMention constraint; + + ConstrainedTypeParameterConstraintPosition() { + this = TConstrainedTypeParameterConstraintPosition(constrainedTp, constraint) + } + + override predicate relevantFor(Access a, AccessEnvironment e, Declaration target) { + typeParameterHasConstraint(target, constrainedTp, _) and + target = a.getTarget(e) + } + + bindingset[target] + override Type getConstraintTypeAt(Declaration target, TypePath path) { + typeParameterHasConstraint(target, constrainedTp, constraint) and + result = constraint.getTypeAt(path) + } + + bindingset[a, e] + override Type getInferredType(Access a, AccessEnvironment e, TypePath path) { + typeMatch(a, e, _, path, result, constrainedTp) + } + + bindingset[target] + override TypePath getPathToConstrained(Declaration target, DeclarationPosition pos) { + constrainedTp = target.getDeclaredType(pos, result) + } + + override string toString() { result = constrainedTp.toString() } } - private predicate relevantAccessTarget( - Access a, AccessPosition apos, AccessEnvironment e, Declaration target - ) { - exists(Type t | - accessTargetsWithArgRootType(a, e, target, apos, t) and - argRootTypeSatisfiesTargetTypeCand(t, target, apos, _, _) - ) + private newtype TRelevantConstraint = + MkRelevantConstraint(Declaration target, ConstraintPosition pos) { + pos.relevantFor(_, _, target) + } + + class RelevantConstraint extends MkRelevantConstraint { + Declaration target; + ConstraintPosition pos; + + RelevantConstraint() { this = MkRelevantConstraint(target, pos) } + + pragma[nomagic] + predicate isRelevantFor(Access a, ConstraintPosition pos_, AccessEnvironment e) { + pos.relevantFor(a, e, target) and + pos = pos_ + } + + Type getTypeAt(TypePath path) { result = pos.getConstraintTypeAt(target, path) } + + pragma[nomagic] + TypePath getPathToConstrained(ConstraintPosition pos_, AccessPosition apos) { + exists(DeclarationPosition dpos | + accessDeclarationPositionMatch(apos, dpos) and + result = pos.getPathToConstrained(target, dpos) and + pos = pos_ + ) + } + + pragma[nomagic] + predicate hasTypeParameterAt( + Declaration target_, ConstraintPosition pos_, TypePath path, TypeParameter tp + ) { + tp = pos.getConstraintTypeAt(target, path) and + not pos = TConstrainedTypeParameterConstraintPosition(tp, _) and + pos = pos_ and + target = target_ + } + + pragma[nomagic] + Type typeParameterMatch(Access a, AccessEnvironment e, TypePath pathToTp, TypePath suffix) { + exists(TypeParameter tp | + this.hasTypeParameterAt(target, pos, pathToTp, tp) and + typeMatch(a, e, target, suffix, result, tp) + ) + } + + string toString() { result = target + ", " + pos } + + Location getLocation() { result = target.getLocation() } } private newtype TRelevantAccess = - MkRelevantAccess(Access a, AccessPosition apos, AccessEnvironment e) { - relevantAccessTarget(a, apos, e, _) + MkRelevantAccess(Access a, ConstraintPosition pos, AccessEnvironment e) { + pos.relevantFor(a, e, _) } private class RelevantAccess extends MkRelevantAccess { Access a; - AccessPosition apos; + ConstraintPosition pos; AccessEnvironment e; - RelevantAccess() { this = MkRelevantAccess(a, apos, e) } + RelevantAccess() { this = MkRelevantAccess(a, pos, e) } - RelevantTarget getTarget() { - exists(Declaration target | - relevantAccessTarget(a, apos, e, target) and - result = MkRelevantTarget(target, apos) - ) - } + RelevantConstraint getConstraint() { result.isRelevantFor(a, pos, e) } pragma[nomagic] - Type getTypeAt(TypePath path) { result = a.getInferredType(e, apos, path) } + Type getTypeAt(TypePath path) { result = pos.getInferredType(a, e, path) } - string toString() { result = a.toString() + ", " + apos.toString() } + string toString() { result = a + ", " + pos } Location getLocation() { result = a.getLocation() } } - private module SatisfiesParameterConstraintInput implements - SatisfiesConstraintInputSig + private module SatisfiesRelevantConstraintInput implements + SatisfiesConstraintWithTypeMatchingInputSig { - predicate relevantConstraint(RelevantAccess at, RelevantTarget constraint) { - constraint = at.getTarget() + predicate relevantConstraint(RelevantAccess at, RelevantConstraint constraint) { + constraint = at.getConstraint() + } + + class TypeMatchingContext = Access; + + TypeMatchingContext getTypeMatchingContext(RelevantAccess at) { + at = MkRelevantAccess(result, _, _) + } + + pragma[nomagic] + predicate typeMatch(TypeMatchingContext ctx, TypeParameter tp, TypePath path, Type t) { + typeMatch(ctx, _, _, path, t, tp) } } - private module SatisfiesParameterConstraint = - SatisfiesConstraint; + private module SatisfiesRelevantConstraint = + SatisfiesConstraintWithTypeMatching; /** * Holds if the (transitive) base type `t` at `path` of `a` in environment `e` - * for some `AccessPosition` matches the type parameter `tp`, which is used in - * the declared types of `target`. + * for some argument or type argument position matches the type parameter + * `tp` in a declared type or type parameter constraint of `target`. * * For example, in * @@ -1495,177 +1646,25 @@ module Make1 Input1> { predicate baseTypeMatch( Access a, AccessEnvironment e, Declaration target, TypePath path, Type t, TypeParameter tp ) { - exists(AccessPosition apos, TypePath pathToTp | - argRootTypeSatisfiesTargetTypeCand(_, target, pragma[only_bind_into](apos), tp, pathToTp) and - SatisfiesParameterConstraint::satisfiesConstraint(MkRelevantAccess(a, - pragma[only_bind_into](apos), e), - MkRelevantTarget(target, pragma[only_bind_into](apos)), pathToTp.appendInverse(path), - t) and + exists(RelevantConstraint constraint, ConstraintPosition pos, TypePath pathToTp | + constraint.hasTypeParameterAt(target, pragma[only_bind_into](pos), pathToTp, tp) and + SatisfiesRelevantConstraint::satisfiesConstraint(MkRelevantAccess(a, + pragma[only_bind_into](pos), e), constraint, pathToTp.appendInverse(path), t) and hasNotTypeArgument(a, target, tp) ) } - predicate baseTypeMatchAtTypeParameter( - Access a, AccessEnvironment e, AccessPosition apos, Declaration target, TypeParameter tp, - TypePath prefix, TypePath requiredPrefix - ) { - exists( - TypePath pathToTypeParamInConstraint, TypePath pathToTp, TypePath pathToTypeParamInSub - | - argRootTypeSatisfiesTargetTypeCand(_, target, pragma[only_bind_into](apos), tp, pathToTp) and - SatisfiesParameterConstraint::satisfiesConstraintAtTypeParameter(MkRelevantAccess(a, - pragma[only_bind_into](apos), e), - MkRelevantTarget(target, pragma[only_bind_into](apos)), pathToTypeParamInConstraint, - pathToTypeParamInSub) and - hasNotTypeArgument(a, target, tp) - | - /* - * Example: - * - * ```swift - * class Base { - * init(_ value: B) {} - * } - * - * class Derived: Base<[D]> { - * init(_ value: D) { super.init([value]) } - * } - * - * func foo(_ value: T, _ base: Base) { } - * - * foo([2], Derived()) - * ``` - * - * - tp = T (bound by `foo`) - * - prefix = pathToTypeParamInSub = "D" - * - requiredPrefix = "Element" - * - pathToTypeParamInConstraint = "B.Element" - * - pathToTp = "B" - */ - - pathToTypeParamInConstraint = pathToTp.appendInverse(requiredPrefix) and - prefix = pathToTypeParamInSub - or - /* - * Example: - * - * ```swift - * class Base { - * init(_ value: B) {} - * } - * - * class Derived: Base { - * override init(_ value: D) { super.init(value) } - * } - * - * func foo(_ value: T, _ base: Base) {} - * - * foo(2, Derived(Optional.none)) - * ``` - * - * - tp = T (bound by `foo`) - * - prefix = "D.Wrapped" - * - pathToTypeParamInSub = "D" - * - requiredPrefix = "" - * - pathToTypeParamInConstraint = "B" - * - pathToTp = "B.Wrapped" - */ - - exists(TypePath path0 | - pathToTp = pathToTypeParamInConstraint.appendInverse(path0) and - prefix = pathToTypeParamInSub.append(path0) and - requiredPrefix = TypePath::nil() - ) - ) - } - } - - private module AccessConstraint { - private predicate relevantAccessConstraint( - Access a, AccessEnvironment e, Declaration target, TypeParameter constrainedTp, - TypeMention constraint - ) { - target = a.getTarget(e) and - typeParameterHasConstraint(target, constrainedTp, constraint) - } - - private newtype TRelevantAccess = - MkRelevantAccess(Access a, AccessEnvironment e, TypeParameter constrainedTp) { - relevantAccessConstraint(a, e, _, constrainedTp, _) - } - - private class RelevantAccess extends MkRelevantAccess { - Access a; - AccessEnvironment e; - TypeParameter constrainedTp; - - RelevantAccess() { this = MkRelevantAccess(a, e, constrainedTp) } - - pragma[nomagic] - Type getTypeAt(TypePath path) { typeMatch(a, e, _, path, result, constrainedTp) } - - /** Gets the constraint that this relevant access should satisfy. */ - TypeMention getConstraint(Declaration target) { - relevantAccessConstraint(a, e, target, constrainedTp, result) - } - - string toString() { - result = a.toString() + ", " + e.toString() + ", " + constrainedTp.toString() - } - - Location getLocation() { result = a.getLocation() } - } - - private module SatisfiesTypeParameterConstraintInput implements - SatisfiesConstraintWithTypeMatchingInputSig - { - predicate relevantConstraint(RelevantAccess at, TypeMention constraint) { - constraint = at.getConstraint(_) - } - - class TypeMatchingContext = Access; - - TypeMatchingContext getTypeMatchingContext(RelevantAccess at) { - at = MkRelevantAccess(result, _, _) - } - - pragma[nomagic] - predicate typeMatch(TypeMatchingContext ctx, TypeParameter tp, TypePath path, Type t) { - typeMatch(ctx, _, _, path, t, tp) - } - } - - private module SatisfiesTypeParameterConstraint = - SatisfiesConstraintWithTypeMatching; - pragma[nomagic] predicate argSatisfiesConstraintAtTypeParameter( - Access a, AccessEnvironment e, Declaration target, AccessPosition apos, TypePath prefix, - TypeMention constraint, TypePath pathToTypeParamInConstraint, + Access a, AccessEnvironment e, AccessPosition apos, TypePath prefix, + RelevantConstraint constraint, TypePath pathToTypeParamInConstraint, TypePath pathToTypeParamInSub ) { - exists(RelevantAccess ra, TypeParameter constrainedTp | - ra = MkRelevantAccess(a, e, constrainedTp) and - relevantAccessConstraint(a, e, target, constrainedTp, constraint) and - SatisfiesTypeParameterConstraint::satisfiesConstraintAtTypeParameter(ra, constraint, - pathToTypeParamInConstraint, pathToTypeParamInSub) and - exists(DeclarationPosition dpos | - accessDeclarationPositionMatch(apos, dpos) and - constrainedTp = target.getDeclaredType(dpos, prefix) - ) - ) - } - - pragma[nomagic] - predicate satisfiesConstraint( - Access a, AccessEnvironment e, Declaration target, TypeParameter constrainedTp, - TypeMention constraint, TypePath path, Type t - ) { - exists(RelevantAccess ra | - ra = MkRelevantAccess(a, e, constrainedTp) and - relevantAccessConstraint(a, e, target, constrainedTp, constraint) and - SatisfiesTypeParameterConstraint::satisfiesConstraint(ra, constraint, path, t) + exists(ConstraintPosition pos | + prefix = constraint.getPathToConstrained(pragma[only_bind_into](pos), apos) and + SatisfiesRelevantConstraint::satisfiesConstraintAtTypeParameter(MkRelevantAccess(a, + pragma[only_bind_into](pos), e), constraint, pathToTypeParamInConstraint, + pathToTypeParamInSub) ) } } @@ -1686,25 +1685,6 @@ module Make1 Input1> { /** * Holds if the type parameter `constrainedTp` applies to `target` and the * constraint `constraint` applies to `constrainedTp`. - */ - pragma[nomagic] - private predicate typeParameterHasConstraint( - Declaration target, TypeParameter constrainedTp, TypeMention constraint - ) { - constraint = getATypeParameterConstraint(constrainedTp, target) and - ( - constrainedTp = target.getTypeParameter(_) - or - // a declaration may reference type parameters that are not declared on it, - // for example type parameters from the enclosing type - constrainedTp = target.getDeclaredType(_, _) - ) - } - - /** - * Holds if the type parameter `constrainedTp` applies to `target`, the - * constraint `constraint` applies to `constrainedTp`, and type parameter - * `tp` occurs at `pathToTp` in `constraint`. * * For example, in * @@ -1715,29 +1695,19 @@ module Make1 Input1> { * * with the method declaration being the target, we have the following * - `constrainedTp = T2`, - * - `constraint = IFoo`, - * - `tp = T1`, and - * - `pathToTp = "A"`. + * - `constraint = IFoo`. */ pragma[nomagic] - private predicate typeParameterConstraintHasTypeParameter( - Declaration target, TypeParameter constrainedTp, TypeMention constraint, TypePath pathToTp, - TypeParameter tp - ) { - typeParameterHasConstraint(target, constrainedTp, constraint) and - tp = constraint.getTypeAt(pathToTp) and - constrainedTp != tp - } - - pragma[nomagic] - private predicate typeConstraintBaseTypeMatch( - Access a, AccessEnvironment e, Declaration target, TypePath path, Type t, TypeParameter tp + private predicate typeParameterHasConstraint( + Declaration target, TypeParameter constrainedTp, TypeMention constraint ) { - hasNotTypeArgument(a, target, tp) and - exists(TypeMention constraint, TypeParameter constrainedTp, TypePath pathToTp | - typeParameterConstraintHasTypeParameter(target, constrainedTp, constraint, pathToTp, tp) and - AccessConstraint::satisfiesConstraint(a, e, target, constrainedTp, constraint, - pathToTp.appendInverse(path), t) + constraint = getATypeParameterConstraint(constrainedTp, target) and + ( + constrainedTp = target.getTypeParameter(_) + or + // a declaration may reference type parameters that are not declared on it, + // for example type parameters from the enclosing type + constrainedTp = target.getDeclaredType(_, _) ) } @@ -1756,11 +1726,8 @@ module Make1 Input1> { // We can infer the type of `tp` from one of the access positions directTypeMatch(a, e, target, path, t, tp) or - // We can infer the type of `tp` by going up the type hierarchy - AccessBaseType::baseTypeMatch(a, e, target, path, t, tp) - or - // We can infer the type of `tp` by a type constraint - typeConstraintBaseTypeMatch(a, e, target, path, t, tp) + // We can infer the type of `tp` via the type hierarchy or a type constraint + ConstraintMatching::baseTypeMatch(a, e, target, path, t, tp) } /** @@ -1820,61 +1787,44 @@ module Make1 Input1> { ) or exists( - Declaration target, TypePath prefix, TypePath requiredPrefix, TypePath suffix, - TypeParameter tp - | - AccessBaseType::baseTypeMatchAtTypeParameter(a, e, apos, target, tp, prefix, - requiredPrefix) and - typeMatch(a, e, target, requiredPrefix.appendInverse(suffix), result, tp) and - path = prefix.append(suffix) - ) - or - exists( - Declaration target, TypePath prefix, TypeMention constraint, + TypePath prefix, TypePath suffix, ConstraintMatching::RelevantConstraint constraint, TypePath pathToTypeParamInConstraint, TypePath pathToTypeParamInSub | - AccessConstraint::argSatisfiesConstraintAtTypeParameter(a, e, target, apos, prefix, - constraint, pathToTypeParamInConstraint, pathToTypeParamInSub) + ConstraintMatching::argSatisfiesConstraintAtTypeParameter(a, e, apos, prefix, constraint, + pathToTypeParamInConstraint, pathToTypeParamInSub) | - exists(TypePath suffix | - /* - * Example: - * - * ```rust - * struct MyThing { ... } - * - * trait MyTrait { ... } - * - * impl MyTrait for MyThing { ... } - * - * fn foo>(x: T) { ... } - * - * let x = MyThing(Default::default()); - * foo(x); - * ``` - * - * At `term` = `foo(x)`, we have - * - `constraint = MyTrait`, - * - `pathToTypeParamInConstraint` = `"B"`, - * - `pathToTypeParamInSub` = `"A"`, - * - `prefix` = `suffix` = `""`, and - * - `result` = `i32`. - * - * That is, it allows us to infer that the type of `x` is `MyThing`. - */ + /* + * Example: + * + * ```rust + * struct MyThing { ... } + * + * trait MyTrait { ... } + * + * impl MyTrait for MyThing { ... } + * + * fn foo>(x: T) { ... } + * + * let x = MyThing(Default::default()); + * foo(x); + * ``` + * + * At `term` = `foo(x)`, we have + * - `constraint = MyTrait`, + * - `pathToTypeParamInConstraint` = `"B"`, + * - `pathToTypeParamInSub` = `"A"`, + * - `prefix` = `suffix` = `""`, and + * - `result` = `i32`. + * + * That is, it allows us to infer that the type of `x` is `MyThing`. + */ - result = constraint.getTypeAt(pathToTypeParamInConstraint.appendInverse(suffix)) and - not result instanceof TypeParameter and - path = prefix.append(pathToTypeParamInSub.append(suffix)) - ) + result = constraint.getTypeAt(pathToTypeParamInConstraint.appendInverse(suffix)) and + not result instanceof TypeParameter and + path = prefix.append(pathToTypeParamInSub.append(suffix)) or - exists(TypeParameter tp, TypePath suffix, TypePath mid, TypePath pathToTp | - exists(TypeParameter constrainedTp, DeclarationPosition dpos | - typeParameterConstraintHasTypeParameter(target, constrainedTp, constraint, pathToTp, - tp) and - accessDeclarationPositionMatch(apos, dpos) and - constrainedTp = target.getDeclaredType(dpos, _) - ) + exists(TypePath mid, TypePath pathToTp | + result = constraint.typeParameterMatch(a, e, pathToTp, suffix) | /* * Example: @@ -1909,7 +1859,6 @@ module Make1 Input1> { * That is, it allows us to infer that the type of `y` is `MyThing>`. */ - typeMatch(a, e, target, suffix, result, tp) and pathToTp = pathToTypeParamInConstraint.appendInverse(mid) and path = prefix.append(pathToTypeParamInSub.append(mid).append(suffix)) or @@ -1946,9 +1895,11 @@ module Make1 Input1> { * That is, it allows us to infer that the type of `y` is `MyThing>`. */ - pathToTypeParamInConstraint = pathToTp.appendInverse(mid) and - typeMatch(a, e, target, mid.appendInverse(suffix), result, tp) and - path = prefix.append(pathToTypeParamInSub.append(suffix)) + exists(TypePath midSuffix | + suffix = mid.appendInverse(midSuffix) and + pathToTypeParamInConstraint = pathToTp.appendInverse(mid) and + path = prefix.append(pathToTypeParamInSub.append(midSuffix)) + ) ) ) }