diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index c6a268be126f..4b038f58d31f 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -1718,7 +1718,7 @@ private module AssocFunctionResolution { * inside `root`. */ pragma[nomagic] - private predicate hasIncompatibleTarget( + predicate hasIncompatibleTarget( ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, Type root ) { @@ -1743,7 +1743,7 @@ private module AssocFunctionResolution { * is not satisfied. */ pragma[nomagic] - private predicate hasIncompatibleBlanketLikeTarget( + predicate hasIncompatibleBlanketLikeTarget( ImplItemNode impl, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { SelfArgIsNotInstantiationOfBlanketLike::argIsNotInstantiationOf(MkAssocFunctionCallCand(this, @@ -1795,7 +1795,7 @@ private module AssocFunctionResolution { } pragma[nomagic] - private Type getComplexStrippedSelfType( + Type getComplexStrippedSelfType( FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath ) { result = this.getANonPseudoSelfTypeAt(selfPos, derefChain, borrow, strippedTypePath) and @@ -1806,258 +1806,25 @@ private module AssocFunctionResolution { ) } - bindingset[derefChain, borrow, strippedTypePath, strippedType] - private predicate hasNoCompatibleNonBlanketLikeTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType - ) { - forall(ImplOrTraitItemNode i | - nonBlanketLikeCandidate(this, _, selfPos, i, _, strippedTypePath, strippedType) - | - this.hasIncompatibleTarget(i, selfPos, derefChain, borrow, strippedType) - ) - } - - bindingset[derefChain, borrow, strippedTypePath, strippedType] - private predicate hasNoCompatibleTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType - ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, - strippedType) and - forall(ImplItemNode i | blanketLikeCandidate(this, _, selfPos, i, _, _, _) | - this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) - ) - } - - bindingset[derefChain, borrow, strippedTypePath, strippedType] - private predicate hasNoCompatibleNonBlanketTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType - ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, - strippedType) and - forall(ImplItemNode i | - blanketLikeCandidate(this, _, selfPos, i, _, _, _) and - not i.isBlanketImplementation() - | - this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) - ) - } - - // forex using recursion - pragma[nomagic] - private predicate hasNoCompatibleTargetNoBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n - ) { - this.supportsAutoDerefAndBorrow() and - this.hasReceiverAtPos(selfPos) and - strippedType = - this.getComplexStrippedSelfType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and - n = -1 - or - this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, - n - 1) and - exists(Type t | - t = getNthLookupType(this, strippedType, n) and - this.hasNoCompatibleTargetCheck(selfPos, derefChain, TNoBorrowKind(), strippedTypePath, t) - ) - } - - /** - * Holds if the candidate receiver type represented by `derefChain` does not - * have a matching call target at function-call adjusted position `selfPos`. - */ - pragma[nomagic] - predicate hasNoCompatibleTargetNoBorrow(FunctionPosition selfPos, DerefChain derefChain) { - exists(Type strippedType | - this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, - getLastLookupTypeIndex(this, strippedType)) - ) - } - - // forex using recursion - pragma[nomagic] - private predicate hasNoCompatibleNonBlanketTargetNoBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n - ) { - ( - this.supportsAutoDerefAndBorrow() and - this.hasReceiverAtPos(selfPos) - or - // needed for the `hasNoCompatibleNonBlanketTarget` check in - // `ArgSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` - exists(ImplItemNode i | - derefChain.isEmpty() and - blanketLikeCandidate(this, _, selfPos, i, _, _, _) and - i.isBlanketImplementation() - ) - ) and - strippedType = - this.getComplexStrippedSelfType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and - n = -1 - or - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | - t = getNthLookupType(this, strippedType, n) and - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TNoBorrowKind(), - strippedTypePath, t) - ) - } - - /** - * Holds if the candidate receiver type represented by `derefChain` does not have - * a matching non-blanket call target at function-call adjusted position `selfPos`. - */ - pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetNoBorrow( - FunctionPosition selfPos, DerefChain derefChain - ) { - exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, - getLastLookupTypeIndex(this, strippedType)) - ) - } - - // forex using recursion - pragma[nomagic] - private predicate hasNoCompatibleTargetSharedBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n - ) { - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and - strippedType = - this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(false), - strippedTypePath) and - n = -1 - or - this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | - t = getNthLookupType(this, strippedType, n) and - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), - strippedTypePath, t) - ) - } - - /** - * Holds if the candidate receiver type represented by `derefChain`, followed - * by a shared borrow, does not have a matching call target at function-call - * adjusted position `selfPos`. - */ - pragma[nomagic] - predicate hasNoCompatibleTargetSharedBorrow(FunctionPosition selfPos, DerefChain derefChain) { - exists(Type strippedType | - this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, _, strippedType, - getLastLookupTypeIndex(this, strippedType)) - ) - } - - // forex using recursion - pragma[nomagic] - private predicate hasNoCompatibleTargetMutBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n - ) { - this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and - strippedType = - this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and - n = -1 - or - this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | - t = getNthLookupType(this, strippedType, n) and - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), - strippedTypePath, t) - ) - } - - /** - * Holds if the candidate receiver type represented by `derefChain`, followed - * by a `mut` borrow, does not have a matching call target at function-call - * adjusted position `selfPos`. - */ - pragma[nomagic] - predicate hasNoCompatibleTargetMutBorrow(FunctionPosition selfPos, DerefChain derefChain) { - exists(Type strippedType | - this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, - getLastLookupTypeIndex(this, strippedType)) - ) - } - - // forex using recursion - pragma[nomagic] - private predicate hasNoCompatibleNonBlanketTargetSharedBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n - ) { - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and - strippedType = - this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(false), - strippedTypePath) and - n = -1 - or - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | - t = getNthLookupType(this, strippedType, n) and - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), - strippedTypePath, t) - ) - } - /** - * Holds if the candidate receiver type represented by `derefChain`, followed - * by a shared borrow, does not have a matching non-blanket call target at - * function-call adjusted position `selfPos`. + * Holds if the candidate receiver type represented by `derefChain` and `borrow` + * does not have a matching call target at function-call adjusted position `selfPos`. */ - pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetSharedBorrow( - FunctionPosition selfPos, DerefChain derefChain - ) { - exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, _, - strippedType, getLastLookupTypeIndex(this, strippedType)) - ) - } - - // forex using recursion - pragma[nomagic] - private predicate hasNoCompatibleNonBlanketTargetMutBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + predicate hasNoCompatibleTarget( + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { - this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and - strippedType = - this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and - n = -1 - or - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | - t = getNthLookupType(this, strippedType, n) and - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), - strippedTypePath, t) - ) + NoCompatibleTarget::hasNoCompatibleTarget(this, selfPos, derefChain, borrow) } /** - * Holds if the candidate receiver type represented by `derefChain`, followed - * by a `mut` borrow, does not have a matching non-blanket call target at - * function-call adjusted position `selfPos`. + * Holds if the candidate receiver type represented by `derefChain` and `borrow` + * does not have a matching non-blanket call target at function-call adjusted + * position `selfPos`. */ - pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetMutBorrow( - FunctionPosition selfPos, DerefChain derefChain + predicate hasNoCompatibleNonBlanketTarget( + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { - exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, - getLastLookupTypeIndex(this, strippedType)) - ) + NoCompatibleTarget::hasNoCompatibleNonBlanketTarget(this, selfPos, derefChain, borrow) } /** @@ -2082,6 +1849,25 @@ private module AssocFunctionResolution { ) } + /** + * Holds if this call may have an implicit borrow of kind `borrow` at + * function-call adjusted position `selfPos` with the given `derefChain`. + */ + pragma[nomagic] + predicate hasImplicitBorrowCand( + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + ) { + exists(BorrowKind prev | this.hasNoCompatibleTarget(selfPos, derefChain, prev) | + // first try shared borrow + prev.isNoBorrow() and + borrow.isSharedBorrow() + or + // then try mutable borrow + prev.isSharedBorrow() and + borrow.isMutableBorrow() + ) + } + /** * Gets the type of this call at function-call adjusted position `selfPos` and * type path `path`. @@ -2107,23 +1893,15 @@ private module AssocFunctionResolution { borrow.isNoBorrow() or exists(RefType rt | - // first try shared borrow - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and - borrow.isSharedBorrow() - or - // then try mutable borrow - this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and - borrow.isMutableBorrow() + this.hasImplicitBorrowCand(selfPos, derefChain, borrow) and + rt = borrow.getRefType() | - rt = borrow.getRefType() and - ( - path.isEmpty() and - result = rt - or - exists(TypePath suffix | - result = this.getSelfTypeAtNoBorrow(selfPos, derefChain, suffix) and - path = TypePath::cons(rt.getPositionalTypeParameter(0), suffix) - ) + path.isEmpty() and + result = rt + or + exists(TypePath suffix | + result = this.getSelfTypeAtNoBorrow(selfPos, derefChain, suffix) and + path = TypePath::cons(rt.getPositionalTypeParameter(0), suffix) ) ) } @@ -2322,6 +2100,177 @@ private module AssocFunctionResolution { override Trait getTrait() { result instanceof AnyFnTrait } } + /** + * Provides logic for efficiently checking that there are no compatible call + * targets for a given candidate receiver type. + * + * For calls with non-blanket target candidates, we need to check: + * + * ```text + * forall types `t` where `t` is a lookup type for the given candidate receiver type: + * forall non-blanket candidates `c` matching `t`: + * check that `c` is not a compatible target + * ``` + * + * Instead of implementing the above using `forall`, we apply the standard trick + * of using ranked recursion. + */ + private module NoCompatibleTarget { + private import codeql.rust.elements.internal.generated.Raw + private import codeql.rust.elements.internal.generated.Synth + + private class RawImplOrTrait = @impl or @trait; + + private predicate id(RawImplOrTrait x, RawImplOrTrait y) { x = y } + + private predicate idOfRaw(RawImplOrTrait x, int y) = equivalenceRelation(id/2)(x, y) + + private int idOfImplOrTraitItemNode(ImplOrTraitItemNode i) { + idOfRaw(Synth::convertAstNodeToRaw(i), result) + } + + /** + * Holds if `t` is the `n`th lookup type for the candidate receiver type + * represented by `derefChain` and `borrow` at function-call adjusted position + * `selfPos` of `afc`. + * + * There are no compatible non-blanket-like candidates for lookup types `0` to `n - 1`. + */ + pragma[nomagic] + private predicate noCompatibleNonBlanketLikeTargetCandNthLookupType( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType, int n, Type t + ) { + ( + ( + ( + afc.supportsAutoDerefAndBorrow() and + afc.hasReceiverAtPos(selfPos) + or + // needed for the `hasNoCompatibleNonBlanketTarget` check in + // `ArgSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` + exists(ImplItemNode i | + derefChain.isEmpty() and + blanketLikeCandidate(afc, _, selfPos, i, _, _, _) and + i.isBlanketImplementation() + ) + ) and + borrow.isNoBorrow() + or + afc.hasImplicitBorrowCand(selfPos, derefChain, borrow) + ) and + strippedType = afc.getComplexStrippedSelfType(selfPos, derefChain, borrow, strippedTypePath) and + n = 0 + or + hasNoCompatibleNonBlanketLikeTargetForNthLookupType(afc, selfPos, derefChain, borrow, + strippedTypePath, strippedType, n - 1) + ) and + t = getNthLookupType(afc, strippedType, n) + } + + pragma[nomagic] + private ImplOrTraitItemNode getKthNonBlanketLikeCandidateForNthLookupType( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType, int n, Type t, int k + ) { + noCompatibleNonBlanketLikeTargetCandNthLookupType(afc, selfPos, derefChain, borrow, + strippedTypePath, strippedType, n, t) and + result = + rank[k + 1](ImplOrTraitItemNode i, int id | + nonBlanketLikeCandidate(afc, _, selfPos, i, _, strippedTypePath, t) and + id = idOfImplOrTraitItemNode(i) + | + i order by id + ) + } + + pragma[nomagic] + private int getLastNonBlanketLikeCandidateForNthLookupType( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType, int n + ) { + exists(Type t | + noCompatibleNonBlanketLikeTargetCandNthLookupType(afc, selfPos, derefChain, borrow, + strippedTypePath, strippedType, n, t) and + result = + count(ImplOrTraitItemNode i | + nonBlanketLikeCandidate(afc, _, selfPos, i, _, strippedTypePath, t) + ) - 1 + ) + } + + pragma[nomagic] + private predicate hasNoCompatibleNonBlanketLikeTargetForNthLookupTypeToIndex( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType, int n, int k + ) { + exists(Type t | + noCompatibleNonBlanketLikeTargetCandNthLookupType(afc, selfPos, derefChain, borrow, + strippedTypePath, strippedType, n, t) + | + k = -1 + or + hasNoCompatibleNonBlanketLikeTargetForNthLookupTypeToIndex(afc, selfPos, derefChain, borrow, + strippedTypePath, strippedType, n, k - 1) and + exists(ImplOrTraitItemNode i | + i = + getKthNonBlanketLikeCandidateForNthLookupType(afc, selfPos, derefChain, borrow, + strippedTypePath, strippedType, n, t, k) and + afc.hasIncompatibleTarget(i, selfPos, derefChain, borrow, t) + ) + ) + } + + pragma[nomagic] + private predicate hasNoCompatibleNonBlanketLikeTargetForNthLookupType( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType, int n + ) { + exists(int last | + last = + getLastNonBlanketLikeCandidateForNthLookupType(afc, selfPos, derefChain, borrow, + strippedTypePath, strippedType, n) and + hasNoCompatibleNonBlanketLikeTargetForNthLookupTypeToIndex(afc, selfPos, derefChain, borrow, + strippedTypePath, strippedType, n, last) + ) + } + + pragma[nomagic] + private predicate hasNoCompatibleNonBlanketLikeTarget( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + ) { + exists(Type strippedType | + hasNoCompatibleNonBlanketLikeTargetForNthLookupType(afc, selfPos, derefChain, borrow, _, + strippedType, getLastLookupTypeIndex(afc, strippedType)) + ) + } + + pragma[nomagic] + predicate hasNoCompatibleTarget( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + ) { + hasNoCompatibleNonBlanketLikeTarget(afc, selfPos, derefChain, borrow) and + // todo: replace with ranked recursion if needed + forall(ImplItemNode i | blanketLikeCandidate(afc, _, selfPos, i, _, _, _) | + afc.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) + ) + } + + pragma[nomagic] + predicate hasNoCompatibleNonBlanketTarget( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + ) { + hasNoCompatibleNonBlanketLikeTarget(afc, selfPos, derefChain, borrow) and + // todo: replace with ranked recursion if needed + forall(ImplItemNode i | + blanketLikeCandidate(afc, _, selfPos, i, _, _, _) and + not i.isBlanketImplementation() + | + afc.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) + ) + } + } + pragma[nomagic] private AssocFunctionDeclaration getAssocFunctionSuccessor( ImplOrTraitItemNode i, string name, int arity @@ -2358,14 +2307,7 @@ private module AssocFunctionResolution { pragma[nomagic] predicate hasNoCompatibleNonBlanketTarget() { - afc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos_, derefChain) and - borrow.isSharedBorrow() - or - afc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPos_, derefChain) and - borrow.isMutableBorrow() - or - afc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPos_, derefChain) and - borrow.isNoBorrow() + afc_.hasNoCompatibleNonBlanketTarget(selfPos_, derefChain, borrow) } pragma[nomagic] @@ -2474,7 +2416,7 @@ private module AssocFunctionResolution { MkCallDerefCand(AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain) { afc.supportsAutoDerefAndBorrow() and afc.hasReceiverAtPos(selfPos) and - afc.hasNoCompatibleTargetMutBorrow(selfPos, derefChain) and + afc.hasNoCompatibleTarget(selfPos, derefChain, TSomeBorrowKind(true)) and exists(afc.getSelfTypeAtNoBorrow(selfPos, derefChain, TypePath::nil())) } diff --git a/rust/ql/test/library-tests/type-inference/closure.rs b/rust/ql/test/library-tests/type-inference/closure.rs index fbef401bb083..635b169bf96b 100644 --- a/rust/ql/test/library-tests/type-inference/closure.rs +++ b/rust/ql/test/library-tests/type-inference/closure.rs @@ -228,8 +228,16 @@ mod implicit_deref { let x = 0i32; let v = Default::default(); // $ type=v:i32 target=default let s = S(v); + let _ret = s(x); // $ type=_ret:bool let s_ref = &s; - let _ret = s_ref(x); // $ type=_ret:bool + // The call below incorrectly resolves to + // `impl FnOnce for &F` from + // https://doc.rust-lang.org/std/ops/trait.FnOnce.html#impl-FnOnce%3CA%3E-for-%26F + // because `s_ref` gets an implicit borrow `&&S`, and then we incorrectly + // conclude that `&S` satisfies the blanket constraint `Fn` because of the + // `impl FnOnce for &F` implementation (we do not currently identify that + // `&S` does not satisfy `Fn`) + let _ret = s_ref(x); // $ MISSING: type=_ret:bool // The call below is not an implicit deref, instead it will target // `impl FnOnce for &F` from 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 4be703598427..5e870ae6ca5d 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -873,7 +873,7 @@ inferCertainType | closure.rs:218:13:218:22 | &... | | {EXTERNAL LOCATION} | & | | closure.rs:218:14:218:22 | \|...\| false | | {EXTERNAL LOCATION} | dyn Fn | | closure.rs:218:18:218:22 | false | | {EXTERNAL LOCATION} | bool | -| closure.rs:222:19:240:5 | { ... } | | {EXTERNAL LOCATION} | () | +| closure.rs:222:19:248:5 | { ... } | | {EXTERNAL LOCATION} | () | | closure.rs:223:13:223:13 | x | | {EXTERNAL LOCATION} | i64 | | closure.rs:223:17:223:20 | 0i64 | | {EXTERNAL LOCATION} | i64 | | closure.rs:226:21:226:23 | ArgList | | {EXTERNAL LOCATION} | (T_1) | @@ -881,20 +881,23 @@ inferCertainType | closure.rs:226:22:226:22 | x | | {EXTERNAL LOCATION} | i64 | | closure.rs:228:13:228:13 | x | | {EXTERNAL LOCATION} | i32 | | closure.rs:228:17:228:20 | 0i32 | | {EXTERNAL LOCATION} | i32 | -| closure.rs:231:13:231:17 | s_ref | | {EXTERNAL LOCATION} | & | -| closure.rs:231:21:231:22 | &s | | {EXTERNAL LOCATION} | & | -| closure.rs:232:20:232:24 | s_ref | | {EXTERNAL LOCATION} | & | -| closure.rs:232:25:232:27 | ArgList | | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:232:25:232:27 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:232:26:232:26 | x | | {EXTERNAL LOCATION} | i32 | -| closure.rs:238:13:238:13 | c | | {EXTERNAL LOCATION} | dyn Fn | -| closure.rs:238:17:238:21 | \|...\| x | | {EXTERNAL LOCATION} | dyn Fn | -| closure.rs:239:9:239:12 | (...) | | {EXTERNAL LOCATION} | & | -| closure.rs:239:10:239:11 | &c | | {EXTERNAL LOCATION} | & | -| closure.rs:239:11:239:11 | c | | {EXTERNAL LOCATION} | dyn Fn | -| closure.rs:239:13:239:15 | ArgList | | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:239:13:239:15 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:14:239:14 | x | | {EXTERNAL LOCATION} | i32 | +| closure.rs:231:21:231:23 | ArgList | | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:231:21:231:23 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:231:22:231:22 | x | | {EXTERNAL LOCATION} | i32 | +| closure.rs:232:13:232:17 | s_ref | | {EXTERNAL LOCATION} | & | +| closure.rs:232:21:232:22 | &s | | {EXTERNAL LOCATION} | & | +| closure.rs:240:20:240:24 | s_ref | | {EXTERNAL LOCATION} | & | +| closure.rs:240:25:240:27 | ArgList | | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:240:25:240:27 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:240:26:240:26 | x | | {EXTERNAL LOCATION} | i32 | +| closure.rs:246:13:246:13 | c | | {EXTERNAL LOCATION} | dyn Fn | +| closure.rs:246:17:246:21 | \|...\| x | | {EXTERNAL LOCATION} | dyn Fn | +| closure.rs:247:9:247:12 | (...) | | {EXTERNAL LOCATION} | & | +| closure.rs:247:10:247:11 | &c | | {EXTERNAL LOCATION} | & | +| closure.rs:247:11:247:11 | c | | {EXTERNAL LOCATION} | dyn Fn | +| closure.rs:247:13:247:15 | ArgList | | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:247:13:247:15 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:14:247:14 | x | | {EXTERNAL LOCATION} | i32 | | dereference.rs:13:14:13:18 | SelfParam | | {EXTERNAL LOCATION} | & | | dereference.rs:13:14:13:18 | SelfParam | TRef | dereference.rs:5:1:7:1 | MyIntPointer | | dereference.rs:13:29:15:5 | { ... } | | {EXTERNAL LOCATION} | & | @@ -6894,7 +6897,7 @@ inferType | closure.rs:218:14:218:22 | \|...\| false | dyn(Output) | {EXTERNAL LOCATION} | bool | | closure.rs:218:15:218:15 | _ | | closure.rs:214:10:214:10 | T | | closure.rs:218:18:218:22 | false | | {EXTERNAL LOCATION} | bool | -| closure.rs:222:19:240:5 | { ... } | | {EXTERNAL LOCATION} | () | +| closure.rs:222:19:248:5 | { ... } | | {EXTERNAL LOCATION} | () | | closure.rs:223:13:223:13 | x | | {EXTERNAL LOCATION} | i64 | | closure.rs:223:17:223:20 | 0i64 | | {EXTERNAL LOCATION} | i64 | | closure.rs:224:13:224:13 | v | | {EXTERNAL LOCATION} | i64 | @@ -6920,50 +6923,55 @@ inferType | closure.rs:230:17:230:20 | S(...) | | closure.rs:212:5:212:19 | S | | closure.rs:230:17:230:20 | S(...) | T | {EXTERNAL LOCATION} | i32 | | closure.rs:230:19:230:19 | v | | {EXTERNAL LOCATION} | i32 | -| closure.rs:231:13:231:17 | s_ref | | {EXTERNAL LOCATION} | & | -| closure.rs:231:13:231:17 | s_ref | TRef | closure.rs:212:5:212:19 | S | -| closure.rs:231:13:231:17 | s_ref | TRef.T | {EXTERNAL LOCATION} | i32 | -| closure.rs:231:21:231:22 | &s | | {EXTERNAL LOCATION} | & | -| closure.rs:231:21:231:22 | &s | TRef | closure.rs:212:5:212:19 | S | -| closure.rs:231:21:231:22 | &s | TRef.T | {EXTERNAL LOCATION} | i32 | -| closure.rs:231:22:231:22 | s | | closure.rs:212:5:212:19 | S | -| closure.rs:231:22:231:22 | s | T | {EXTERNAL LOCATION} | i32 | -| closure.rs:232:13:232:16 | _ret | | {EXTERNAL LOCATION} | bool | -| closure.rs:232:20:232:24 | s_ref | | {EXTERNAL LOCATION} | & | -| closure.rs:232:20:232:24 | s_ref | TRef | closure.rs:212:5:212:19 | S | -| closure.rs:232:20:232:24 | s_ref | TRef.T | {EXTERNAL LOCATION} | i32 | -| closure.rs:232:20:232:27 | s_ref(...) | | {EXTERNAL LOCATION} | bool | -| closure.rs:232:25:232:27 | ArgList | | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:232:25:232:27 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:232:26:232:26 | x | | {EXTERNAL LOCATION} | i32 | -| closure.rs:238:13:238:13 | c | | {EXTERNAL LOCATION} | dyn Fn | -| closure.rs:238:13:238:13 | c | dyn(Args) | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:238:13:238:13 | c | dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:238:13:238:13 | c | dyn(Output) | {EXTERNAL LOCATION} | i32 | -| closure.rs:238:17:238:21 | \|...\| x | | {EXTERNAL LOCATION} | dyn Fn | -| closure.rs:238:17:238:21 | \|...\| x | dyn(Args) | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:238:17:238:21 | \|...\| x | dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:238:17:238:21 | \|...\| x | dyn(Output) | {EXTERNAL LOCATION} | i32 | -| closure.rs:238:18:238:18 | x | | {EXTERNAL LOCATION} | i32 | -| closure.rs:238:21:238:21 | x | | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:9:239:12 | (...) | | {EXTERNAL LOCATION} | & | -| closure.rs:239:9:239:12 | (...) | TRef | {EXTERNAL LOCATION} | dyn Fn | -| closure.rs:239:9:239:12 | (...) | TRef.dyn(Args) | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:239:9:239:12 | (...) | TRef.dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:9:239:12 | (...) | TRef.dyn(Output) | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:9:239:15 | ...(...) | | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:10:239:11 | &c | | {EXTERNAL LOCATION} | & | -| closure.rs:239:10:239:11 | &c | TRef | {EXTERNAL LOCATION} | dyn Fn | -| closure.rs:239:10:239:11 | &c | TRef.dyn(Args) | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:239:10:239:11 | &c | TRef.dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:10:239:11 | &c | TRef.dyn(Output) | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:11:239:11 | c | | {EXTERNAL LOCATION} | dyn Fn | -| closure.rs:239:11:239:11 | c | dyn(Args) | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:239:11:239:11 | c | dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:11:239:11 | c | dyn(Output) | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:13:239:15 | ArgList | | {EXTERNAL LOCATION} | (T_1) | -| closure.rs:239:13:239:15 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | -| closure.rs:239:14:239:14 | x | | {EXTERNAL LOCATION} | i32 | +| closure.rs:231:13:231:16 | _ret | | {EXTERNAL LOCATION} | bool | +| closure.rs:231:20:231:20 | s | | closure.rs:212:5:212:19 | S | +| closure.rs:231:20:231:20 | s | T | {EXTERNAL LOCATION} | i32 | +| closure.rs:231:20:231:23 | s(...) | | {EXTERNAL LOCATION} | bool | +| closure.rs:231:21:231:23 | ArgList | | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:231:21:231:23 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:231:22:231:22 | x | | {EXTERNAL LOCATION} | i32 | +| closure.rs:232:13:232:17 | s_ref | | {EXTERNAL LOCATION} | & | +| closure.rs:232:13:232:17 | s_ref | TRef | closure.rs:212:5:212:19 | S | +| closure.rs:232:13:232:17 | s_ref | TRef.T | {EXTERNAL LOCATION} | i32 | +| closure.rs:232:21:232:22 | &s | | {EXTERNAL LOCATION} | & | +| closure.rs:232:21:232:22 | &s | TRef | closure.rs:212:5:212:19 | S | +| closure.rs:232:21:232:22 | &s | TRef.T | {EXTERNAL LOCATION} | i32 | +| closure.rs:232:22:232:22 | s | | closure.rs:212:5:212:19 | S | +| closure.rs:232:22:232:22 | s | T | {EXTERNAL LOCATION} | i32 | +| closure.rs:240:20:240:24 | s_ref | | {EXTERNAL LOCATION} | & | +| closure.rs:240:20:240:24 | s_ref | TRef | closure.rs:212:5:212:19 | S | +| closure.rs:240:20:240:24 | s_ref | TRef.T | {EXTERNAL LOCATION} | i32 | +| closure.rs:240:25:240:27 | ArgList | | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:240:25:240:27 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:240:26:240:26 | x | | {EXTERNAL LOCATION} | i32 | +| closure.rs:246:13:246:13 | c | | {EXTERNAL LOCATION} | dyn Fn | +| closure.rs:246:13:246:13 | c | dyn(Args) | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:246:13:246:13 | c | dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:246:13:246:13 | c | dyn(Output) | {EXTERNAL LOCATION} | i32 | +| closure.rs:246:17:246:21 | \|...\| x | | {EXTERNAL LOCATION} | dyn Fn | +| closure.rs:246:17:246:21 | \|...\| x | dyn(Args) | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:246:17:246:21 | \|...\| x | dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:246:17:246:21 | \|...\| x | dyn(Output) | {EXTERNAL LOCATION} | i32 | +| closure.rs:246:18:246:18 | x | | {EXTERNAL LOCATION} | i32 | +| closure.rs:246:21:246:21 | x | | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:9:247:12 | (...) | | {EXTERNAL LOCATION} | & | +| closure.rs:247:9:247:12 | (...) | TRef | {EXTERNAL LOCATION} | dyn Fn | +| closure.rs:247:9:247:12 | (...) | TRef.dyn(Args) | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:247:9:247:12 | (...) | TRef.dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:9:247:12 | (...) | TRef.dyn(Output) | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:9:247:15 | ...(...) | | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:10:247:11 | &c | | {EXTERNAL LOCATION} | & | +| closure.rs:247:10:247:11 | &c | TRef | {EXTERNAL LOCATION} | dyn Fn | +| closure.rs:247:10:247:11 | &c | TRef.dyn(Args) | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:247:10:247:11 | &c | TRef.dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:10:247:11 | &c | TRef.dyn(Output) | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:11:247:11 | c | | {EXTERNAL LOCATION} | dyn Fn | +| closure.rs:247:11:247:11 | c | dyn(Args) | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:247:11:247:11 | c | dyn(Args).T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:11:247:11 | c | dyn(Output) | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:13:247:15 | ArgList | | {EXTERNAL LOCATION} | (T_1) | +| closure.rs:247:13:247:15 | ArgList | T0 | {EXTERNAL LOCATION} | i32 | +| closure.rs:247:14:247:14 | x | | {EXTERNAL LOCATION} | i32 | | dereference.rs:13:14:13:18 | SelfParam | | {EXTERNAL LOCATION} | & | | dereference.rs:13:14:13:18 | SelfParam | TRef | dereference.rs:5:1:7:1 | MyIntPointer | | dereference.rs:13:29:15:5 | { ... } | | {EXTERNAL LOCATION} | & |