Address review comments

This commit is contained in:
Tom Hvitved
2025-10-20 21:42:18 +02:00
parent c2ba4ba3fc
commit 41602d3efa
6 changed files with 199 additions and 205 deletions

View File

@@ -626,6 +626,23 @@ final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeR
} }
} }
/**
* Holds if `t` is a valid complex [`self` root type][1].
*
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-items.associated.fn.method.self-ty
*/
pragma[nomagic]
predicate validSelfType(Type t) {
t instanceof RefType
or
exists(Struct s | t = TStruct(s) |
s instanceof BoxStruct or
s instanceof RcStruct or
s instanceof ArcStruct or
s instanceof PinStruct
)
}
/** /**
* Holds if `root` is a valid complex [`self` root type][1], with type * Holds if `root` is a valid complex [`self` root type][1], with type
* parameter `tp`. * parameter `tp`.
@@ -634,18 +651,6 @@ final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeR
*/ */
pragma[nomagic] pragma[nomagic]
predicate complexSelfRoot(Type root, TypeParameter tp) { predicate complexSelfRoot(Type root, TypeParameter tp) {
tp = root.(RefType).getPositionalTypeParameter(_) validSelfType(root) and
or tp = root.getPositionalTypeParameter(0)
exists(Struct s |
root = TStruct(s) and
tp = root.getPositionalTypeParameter(0)
|
s instanceof BoxStruct
or
s instanceof RcStruct
or
s instanceof ArcStruct
or
s instanceof PinStruct
)
} }

View File

@@ -817,7 +817,7 @@ private Type getCallExprTypeQualifier(CallExpr ce, TypePath path) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate assocFunctionInfo( private predicate assocFunctionInfo(
Function f, string name, int arity, ImplOrTraitItemNode i, FunctionTypePosition pos, Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPosition pos,
AssocFunctionType t AssocFunctionType t
) { ) {
f = i.getASuccessor(name) and f = i.getASuccessor(name) and
@@ -835,7 +835,7 @@ private predicate assocFunctionInfo(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate functionInfoBlanket( private predicate functionInfoBlanket(
Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionTypePosition pos, Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionPosition pos,
AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam
) { ) {
exists(TypePath blanketSelfPath | exists(TypePath blanketSelfPath |
@@ -859,7 +859,7 @@ private predicate functionInfoBlanket(
bindingset[path, type] bindingset[path, type]
private predicate isComplexRootStripped(TypePath path, Type type) { private predicate isComplexRootStripped(TypePath path, Type type) {
path.isEmpty() and path.isEmpty() and
not complexSelfRoot(type, _) not validSelfType(type)
or or
exists(TypeParameter tp | exists(TypeParameter tp |
complexSelfRoot(_, tp) and complexSelfRoot(_, tp) and
@@ -918,7 +918,7 @@ private module MethodResolution {
Method m, string name, int arity, ImplOrTraitItemNode i, AssocFunctionType selfType, Method m, string name, int arity, ImplOrTraitItemNode i, AssocFunctionType selfType,
TypePath strippedTypePath, Type strippedType TypePath strippedTypePath, Type strippedType
) { ) {
exists(FunctionTypePosition pos | exists(FunctionPosition pos |
assocFunctionInfo(m, name, arity, i, pos, selfType) and assocFunctionInfo(m, name, arity, i, pos, selfType) and
strippedType = selfType.getTypeAt(strippedTypePath) and strippedType = selfType.getTypeAt(strippedTypePath) and
isComplexRootStripped(strippedTypePath, strippedType) and isComplexRootStripped(strippedTypePath, strippedType) and
@@ -964,7 +964,7 @@ private module MethodResolution {
Method m, string name, int arity, ImplItemNode impl, Trait trait, AssocFunctionType selfType, Method m, string name, int arity, ImplItemNode impl, Trait trait, AssocFunctionType selfType,
TypePath blanketPath, TypeParam blanketTypeParam TypePath blanketPath, TypeParam blanketTypeParam
) { ) {
exists(FunctionTypePosition pos | exists(FunctionPosition pos |
functionInfoBlanket(m, name, arity, impl, trait, pos, selfType, blanketPath, blanketTypeParam) and functionInfoBlanket(m, name, arity, impl, trait, pos, selfType, blanketPath, blanketTypeParam) and
pos.isSelf() pos.isSelf()
) )
@@ -1089,7 +1089,7 @@ private module MethodResolution {
abstract predicate supportsAutoDerefAndBorrow(); abstract predicate supportsAutoDerefAndBorrow();
AstNode getNodeAt(FunctionTypePosition apos) { AstNode getNodeAt(FunctionPosition apos) {
result = this.getArgument(apos.asArgumentPosition()) result = this.getArgument(apos.asArgumentPosition())
or or
result = this and apos.isReturn() result = this and apos.isReturn()
@@ -1113,7 +1113,7 @@ private module MethodResolution {
or or
this.supportsAutoDerefAndBorrow() and this.supportsAutoDerefAndBorrow() and
exists(TypePath path0, Type t0, string derefChain0 | exists(TypePath path0, Type t0, string derefChain0 |
this.hasNoCompatibleTarget(derefChain0, _) and this.hasNoCompatibleTargetBorrow(derefChain0) and
t0 = this.getACandidateReceiverTypeAtNoBorrow(path0, derefChain0) t0 = this.getACandidateReceiverTypeAtNoBorrow(path0, derefChain0)
| |
path0.isCons(TRefTypeParameter(), path) and path0.isCons(TRefTypeParameter(), path) and
@@ -1131,15 +1131,16 @@ private module MethodResolution {
/** /**
* Holds if the method inside `i` with matching name and arity can be ruled * Holds if the method inside `i` with matching name and arity can be ruled
* out as a target of this call, because the candidate receiver type represented * out as a target of this call, because the candidate receiver type represented
* by `derefChainBorrow` is incompatible with the `self` parameter type. * by `derefChain` and `borrow` is incompatible with the `self` parameter type.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate hasIncompatibleTarget(ImplOrTraitItemNode i, string derefChainBorrow) { private predicate hasIncompatibleTarget(ImplOrTraitItemNode i, string derefChain, boolean borrow) {
ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, derefChain,
derefChainBorrow), i, _) borrow), i, _)
or or
TypeQualifierIsInstantiationOfImplSelf::isNotInstantiationOf(this, i, _) and TypeQualifierIsInstantiationOfImplSelf::isNotInstantiationOf(this, i, _) and
derefChainBorrow = ";" derefChain = "" and
borrow = false
} }
/** /**
@@ -1147,20 +1148,22 @@ private module MethodResolution {
* with trait bounds. * with trait bounds.
*/ */
pragma[nomagic] pragma[nomagic]
Type getACandidateReceiverTypeAtSubstituteLookupTraits(TypePath path, string derefChainBorrow) { Type getACandidateReceiverTypeAtSubstituteLookupTraits(
result = substituteLookupTraits(this.getACandidateReceiverTypeAt(path, derefChainBorrow)) TypePath path, string derefChain, boolean borrow
) {
result = substituteLookupTraits(this.getACandidateReceiverTypeAt(path, derefChain, borrow))
} }
pragma[nomagic] pragma[nomagic]
private Type getComplexStrippedType(TypePath strippedTypePath, string derefChainBorrow) { private Type getComplexStrippedType(TypePath strippedTypePath, string derefChain, boolean borrow) {
result = result =
this.getACandidateReceiverTypeAtSubstituteLookupTraits(strippedTypePath, derefChainBorrow) and this.getACandidateReceiverTypeAtSubstituteLookupTraits(strippedTypePath, derefChain, borrow) and
isComplexRootStripped(strippedTypePath, result) isComplexRootStripped(strippedTypePath, result)
} }
bindingset[strippedTypePath, strippedType, derefChainBorrow] bindingset[strippedTypePath, strippedType, derefChain, borrow]
private predicate hasNoCompatibleTargetCheck( private predicate hasNoCompatibleTargetCheck(
TypePath strippedTypePath, Type strippedType, string derefChainBorrow TypePath strippedTypePath, Type strippedType, string derefChain, boolean borrow
) { ) {
// todo: also check that all blanket implementation candidates are incompatible // todo: also check that all blanket implementation candidates are incompatible
forall(ImplOrTraitItemNode i | forall(ImplOrTraitItemNode i |
@@ -1168,16 +1171,16 @@ private module MethodResolution {
or or
this.(MethodCallCallExpr).hasTypeQualifiedCandidate(i) this.(MethodCallCallExpr).hasTypeQualifiedCandidate(i)
| |
this.hasIncompatibleTarget(i, derefChainBorrow) this.hasIncompatibleTarget(i, derefChain, borrow)
) )
} }
/** /**
* Holds if the candidate receiver type represented by * Holds if the candidate receiver type represented by `derefChain` does not
* `derefChainBorrow = derefChain;` does not have a matching method target. * have a matching method target.
*/ */
pragma[nomagic] pragma[nomagic]
predicate hasNoCompatibleTargetNoBorrow(string derefChain, string derefChainBorrow) { predicate hasNoCompatibleTargetNoBorrow(string derefChain) {
( (
this.supportsAutoDerefAndBorrow() this.supportsAutoDerefAndBorrow()
or or
@@ -1186,25 +1189,22 @@ private module MethodResolution {
derefChain = "" derefChain = ""
) and ) and
exists(TypePath strippedTypePath, Type strippedType | exists(TypePath strippedTypePath, Type strippedType |
derefChainBorrow = derefChain + ";" and
not derefChain.matches("%.ref") and // no need to try a borrow if the last thing we did was a deref not derefChain.matches("%.ref") and // no need to try a borrow if the last thing we did was a deref
strippedType = this.getComplexStrippedType(strippedTypePath, derefChainBorrow) and strippedType = this.getComplexStrippedType(strippedTypePath, derefChain, false) and
this.hasNoCompatibleTargetCheck(strippedTypePath, strippedType, derefChainBorrow) this.hasNoCompatibleTargetCheck(strippedTypePath, strippedType, derefChain, false)
) )
} }
/** /**
* Holds if the candidate receiver type represented by * Holds if the candidate receiver type represented by `derefChain`, followed
* `derefChainBorrow = derefChain;borrow` does not have a matching method * by a borrow, does not have a matching method target.
* target.
*/ */
pragma[nomagic] pragma[nomagic]
predicate hasNoCompatibleTarget(string derefChain, string derefChainBorrow) { predicate hasNoCompatibleTargetBorrow(string derefChain) {
exists(TypePath strippedTypePath, Type strippedType | exists(TypePath strippedTypePath, Type strippedType |
derefChainBorrow = derefChain + ";borrow" and this.hasNoCompatibleTargetNoBorrow(derefChain) and
this.hasNoCompatibleTargetNoBorrow(derefChain, _) and strippedType = this.getComplexStrippedType(strippedTypePath, derefChain, true) and
strippedType = this.getComplexStrippedType(strippedTypePath, derefChainBorrow) and this.hasNoCompatibleTargetCheck(strippedTypePath, strippedType, derefChain, true)
this.hasNoCompatibleTargetCheck(strippedTypePath, strippedType, derefChainBorrow)
) )
} }
@@ -1215,28 +1215,26 @@ private module MethodResolution {
* as long as the method cannot be resolved in an earlier candidate type, and possibly * as long as the method cannot be resolved in an earlier candidate type, and possibly
* applying a borrow at the end. * applying a borrow at the end.
* *
* The string `derefChainBorrow` encodes the sequence of dereferences and whether a * The string `derefChain` encodes the sequence of dereferences, and `borrows` indicates
* borrow has been applied. * whether a borrow has been applied.
* *
* [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers
*/ */
pragma[nomagic] pragma[nomagic]
Type getACandidateReceiverTypeAt(TypePath path, string derefChainBorrow) { Type getACandidateReceiverTypeAt(TypePath path, string derefChain, boolean borrow) {
exists(string derefChain | result = this.getACandidateReceiverTypeAtNoBorrow(path, derefChain) and
result = this.getACandidateReceiverTypeAtNoBorrow(path, derefChain) and borrow = false
derefChainBorrow = derefChain + ";" or
this.supportsAutoDerefAndBorrow() and
this.hasNoCompatibleTargetNoBorrow(derefChain) and
borrow = true and
(
path.isEmpty() and
result = TRefType()
or or
this.supportsAutoDerefAndBorrow() and exists(TypePath suffix |
this.hasNoCompatibleTargetNoBorrow(derefChain, _) and result = this.getACandidateReceiverTypeAtNoBorrow(suffix, derefChain) and
derefChainBorrow = derefChain + ";borrow" and path = TypePath::cons(TRefTypeParameter(), suffix)
(
path.isEmpty() and
result = TRefType()
or
exists(TypePath suffix |
result = this.getACandidateReceiverTypeAtNoBorrow(suffix, derefChain) and
path = TypePath::cons(TRefTypeParameter(), suffix)
)
) )
) )
} }
@@ -1244,23 +1242,23 @@ private module MethodResolution {
/** /**
* Gets a method that this call resolves to after having applied a sequence of * Gets a method that this call resolves to after having applied a sequence of
* dereferences and possibly a borrow on the receiver type, encoded in the string * dereferences and possibly a borrow on the receiver type, encoded in the string
* `derefChainBorrow`. * `derefChain` and the Boolean `borrow`.
*/ */
pragma[nomagic] pragma[nomagic]
Method resolveCallTarget(string derefChainBorrow) { Method resolveCallTarget(string derefChain, boolean borrow) {
exists(MethodCallCand mcc | exists(MethodCallCand mcc |
mcc = MkMethodCallCand(this, derefChainBorrow) and mcc = MkMethodCallCand(this, derefChain, borrow) and
result = mcc.resolveCallTarget() result = mcc.resolveCallTarget()
) )
} }
predicate receiverHasImplicitDeref(AstNode receiver) { predicate receiverHasImplicitDeref(AstNode receiver) {
exists(this.resolveCallTarget(".ref;")) and exists(this.resolveCallTarget(".ref", false)) and
receiver = this.getArgument(CallImpl::TSelfArgumentPosition()) receiver = this.getArgument(CallImpl::TSelfArgumentPosition())
} }
predicate receiverHasImplicitBorrow(AstNode receiver) { predicate receiverHasImplicitBorrow(AstNode receiver) {
exists(this.resolveCallTarget(";borrow")) and exists(this.resolveCallTarget("", true)) and
receiver = this.getArgument(CallImpl::TSelfArgumentPosition()) receiver = this.getArgument(CallImpl::TSelfArgumentPosition())
} }
} }
@@ -1382,28 +1380,31 @@ private module MethodResolution {
} }
private newtype TMethodCallCand = private newtype TMethodCallCand =
MkMethodCallCand(MethodCall mc, string derefChainBorrow) { MkMethodCallCand(MethodCall mc, string derefChain, boolean borrow) {
exists(mc.getACandidateReceiverTypeAt(_, derefChainBorrow)) exists(mc.getACandidateReceiverTypeAt(_, derefChain, borrow))
} }
/** A method call tagged with a candidate receiver type. */ /** A method call tagged with a candidate receiver type. */
private class MethodCallCand extends MkMethodCallCand { private class MethodCallCand extends MkMethodCallCand {
MethodCall mc_; MethodCall mc_;
string derefChainBorrow; string derefChain;
boolean borrow;
MethodCallCand() { this = MkMethodCallCand(mc_, derefChainBorrow) } MethodCallCand() { this = MkMethodCallCand(mc_, derefChain, borrow) }
MethodCall getMethodCall() { result = mc_ } MethodCall getMethodCall() { result = mc_ }
Type getTypeAt(TypePath path) { Type getTypeAt(TypePath path) {
result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(path, derefChainBorrow) result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(path, derefChain, borrow)
} }
pragma[nomagic] pragma[nomagic]
predicate hasNoCompatibleTarget() { predicate hasNoCompatibleTarget() {
mc_.hasNoCompatibleTarget(_, derefChainBorrow) mc_.hasNoCompatibleTargetBorrow(derefChain) and
borrow = true
or or
mc_.hasNoCompatibleTargetNoBorrow(_, derefChainBorrow) mc_.hasNoCompatibleTargetNoBorrow(derefChain) and
borrow = false
} }
pragma[nomagic] pragma[nomagic]
@@ -1470,18 +1471,18 @@ private module MethodResolution {
Method resolveCallTarget() { Method resolveCallTarget() {
exists(ImplOrTraitItemNode i | exists(ImplOrTraitItemNode i |
result = this.resolveCallTargetCand(i) and result = this.resolveCallTargetCand(i) and
not exists(FunctionTypePosition pos | not exists(FunctionPosition pos |
FunctionOverloading::functionResolutionDependsOnArgument(i, _, pos, _, _) and FunctionOverloading::functionResolutionDependsOnArgument(i, _, pos, _, _) and
pos.isPositional() pos.isPosition()
) )
) )
or or
MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, _, result) MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, _, result)
} }
predicate hasNoBorrow() { not derefChainBorrow = any(string s) + ";borrow" } predicate hasNoBorrow() { borrow = false }
string toString() { result = mc_.toString() + " [" + derefChainBorrow + "]" } string toString() { result = mc_.toString() + " [" + derefChain + "; " + borrow + "]" }
Location getLocation() { result = mc_.getLocation() } Location getLocation() { result = mc_.getLocation() }
} }
@@ -1583,7 +1584,7 @@ private module MethodResolution {
then then
// inherent methods take precedence over trait methods, so only allow // inherent methods take precedence over trait methods, so only allow
// trait methods when there are no matching inherent methods // trait methods when there are no matching inherent methods
MkMethodCallCand(ce, _).(MethodCallCand).hasNoInherentTarget() MkMethodCallCand(ce, _, _).(MethodCallCand).hasNoInherentTarget()
else any() else any()
} }
@@ -1624,11 +1625,9 @@ private module MethodResolution {
* types of parameters, when needed to disambiguate the call. * types of parameters, when needed to disambiguate the call.
*/ */
private module MethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { private module MethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig {
predicate toCheck( predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
ImplOrTraitItemNode i, Function f, FunctionTypePosition pos, AssocFunctionType t
) {
exists(TypePath path, Type t0 | exists(TypePath path, Type t0 |
pos.isPositional() and pos.isPosition() and
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, path, t0) and FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, path, t0) and
t.appliesTo(f, pos, i) and t.appliesTo(f, pos, i) and
// for now, we do not handle ambiguous targets when one of the types it iself // for now, we do not handle ambiguous targets when one of the types it iself
@@ -1639,7 +1638,7 @@ private module MethodResolution {
} }
class Call extends MethodCallCand { class Call extends MethodCallCand {
Type getArgType(FunctionTypePosition pos, TypePath path) { Type getArgType(FunctionPosition pos, TypePath path) {
result = inferType(mc_.getNodeAt(pos), path) result = inferType(mc_.getNodeAt(pos), path)
} }
@@ -1658,7 +1657,7 @@ private module MethodResolution {
* like `foo.bar(baz)`. * like `foo.bar(baz)`.
*/ */
private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSig { private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSig {
import FunctionTypePositionMatchingInput import FunctionPositionMatchingInput
final class Declaration extends Function { final class Declaration extends Function {
TypeParameter getTypeParameter(TypeParameterPosition ppos) { TypeParameter getTypeParameter(TypeParameterPosition ppos) {
@@ -1681,7 +1680,7 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
Type getParameterType(DeclarationPosition dpos, TypePath path) { Type getParameterType(DeclarationPosition dpos, TypePath path) {
exists(Param p, int i | exists(Param p, int i |
p = this.getParam(i) and p = this.getParam(i) and
i = dpos.asPositional() and i = dpos.asPosition() and
result = p.getTypeRepr().(TypeMention).resolveTypeAt(path) result = p.getTypeRepr().(TypeMention).resolveTypeAt(path)
) )
or or
@@ -1720,6 +1719,13 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
class AccessEnvironment = string; class AccessEnvironment = string;
bindingset[derefChain, borrow]
private AccessEnvironment encodeDerefChainBorrow(string derefChain, boolean borrow) {
exists(string suffix | if borrow = true then suffix = "borrow" else suffix = "" |
result = derefChain + ";" + suffix
)
}
final private class MethodCallFinal = MethodResolution::MethodCall; final private class MethodCallFinal = MethodResolution::MethodCall;
class Access extends MethodCallFinal { class Access extends MethodCallFinal {
@@ -1739,8 +1745,8 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
} }
pragma[nomagic] pragma[nomagic]
private Type getInferredSelfType(string derefChainBorrow, TypePath path) { private Type getInferredSelfType(string derefChain, boolean borrow, TypePath path) {
result = this.getACandidateReceiverTypeAt(path, derefChainBorrow) result = this.getACandidateReceiverTypeAt(path, derefChain, borrow)
} }
pragma[nomagic] pragma[nomagic]
@@ -1764,17 +1770,22 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
) )
} }
pragma[nomagic] bindingset[derefChainBorrow]
Type getInferredType(string derefChainBorrow, AccessPosition apos, TypePath path) { Type getInferredType(string derefChainBorrow, AccessPosition apos, TypePath path) {
apos.isSelf() and exists(string derefChain, boolean borrow |
result = this.getInferredSelfType(derefChainBorrow, path) derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and
apos.isSelf() and
result = this.getInferredSelfType(derefChain, borrow, path)
)
or or
result = this.getInferredNonSelfType(apos, path) and result = this.getInferredNonSelfType(apos, path)
exists(this.getTarget(derefChainBorrow))
} }
Declaration getTarget(string derefChainBorrow) { Declaration getTarget(string derefChainBorrow) {
result = this.resolveCallTarget(derefChainBorrow) // mutual recursion; resolving method calls requires resolving types and vice versa exists(string derefChain, boolean borrow |
derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and
result = this.resolveCallTarget(derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa
)
} }
} }
} }
@@ -1847,11 +1858,11 @@ private module NonMethodResolution {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate traitFunctionDependsOnArgument( private predicate traitFunctionDependsOnArgument(
TraitItemNode trait, NonMethodFunction traitFunction, FunctionTypePosition pos, Type type, TraitItemNode trait, NonMethodFunction traitFunction, FunctionPosition pos, Type type,
ImplItemNode impl, NonMethodFunction implFunction ImplItemNode impl, NonMethodFunction implFunction
) { ) {
exists(TypePath path | exists(TypePath path |
assocFunctionTypeAtPath(implFunction, impl, pos, path, type) and assocFunctionTypeAt(implFunction, impl, pos, path, type) and
implFunction.implements(traitFunction) and implFunction.implements(traitFunction) and
FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos, path, _) FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos, path, _)
| |
@@ -1859,7 +1870,7 @@ private module NonMethodResolution {
or or
// We only check that the context of the call provides relevant type information // We only check that the context of the call provides relevant type information
// when no argument can // when no argument can
not exists(FunctionTypePosition pos0 | not exists(FunctionPosition pos0 |
FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos0, _, _) or FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos0, _, _) or
FunctionOverloading::functionResolutionDependsOnArgument(impl, implFunction, pos0, _, _) FunctionOverloading::functionResolutionDependsOnArgument(impl, implFunction, pos0, _, _)
| |
@@ -1871,7 +1882,7 @@ private module NonMethodResolution {
pragma[nomagic] pragma[nomagic]
private predicate functionInfoBlanketRelevantPos( private predicate functionInfoBlanketRelevantPos(
NonMethodFunction f, string name, int arity, ImplItemNode impl, Trait trait, NonMethodFunction f, string name, int arity, ImplItemNode impl, Trait trait,
FunctionTypePosition pos, AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam FunctionPosition pos, AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam
) { ) {
functionInfoBlanket(f, name, arity, impl, trait, pos, t, blanketPath, blanketTypeParam) and functionInfoBlanket(f, name, arity, impl, trait, pos, t, blanketPath, blanketTypeParam) and
( (
@@ -1879,7 +1890,7 @@ private module NonMethodResolution {
or or
// We only check that the context of the call provides relevant type information // We only check that the context of the call provides relevant type information
// when no argument can // when no argument can
not exists(FunctionTypePosition pos0 | not exists(FunctionPosition pos0 |
functionInfoBlanket(f, name, arity, impl, trait, pos0, _, _, _) and functionInfoBlanket(f, name, arity, impl, trait, pos0, _, _, _) and
not pos0.isReturn() not pos0.isReturn()
) )
@@ -1946,19 +1957,19 @@ private module NonMethodResolution {
result = this.resolveCallTargetBlanketCand(i) result = this.resolveCallTargetBlanketCand(i)
} }
AstNode getNodeAt(FunctionTypePosition pos) { AstNode getNodeAt(FunctionPosition pos) {
result = this.getArg(pos.asPositional()) result = this.getArg(pos.asPosition())
or or
result = this and pos.isReturn() result = this and pos.isReturn()
} }
Type getTypeAt(FunctionTypePosition pos, TypePath path) { Type getTypeAt(FunctionPosition pos, TypePath path) {
result = inferType(this.getNodeAt(pos), path) result = inferType(this.getNodeAt(pos), path)
} }
pragma[nomagic] pragma[nomagic]
predicate resolveCallTargetBlanketCandidate( predicate resolveCallTargetBlanketCandidate(
ImplItemNode impl, FunctionTypePosition pos, TypePath blanketPath, TypeParam blanketTypeParam ImplItemNode impl, FunctionPosition pos, TypePath blanketPath, TypeParam blanketTypeParam
) { ) {
exists(string name, int arity, Trait trait, AssocFunctionType t | exists(string name, int arity, Trait trait, AssocFunctionType t |
this.hasNameAndArity(name, arity) and this.hasNameAndArity(name, arity) and
@@ -1999,14 +2010,14 @@ private module NonMethodResolution {
} }
private newtype TCallAndBlanketPos = private newtype TCallAndBlanketPos =
MkCallAndBlanketPos(NonMethodCall fc, FunctionTypePosition pos) { MkCallAndBlanketPos(NonMethodCall fc, FunctionPosition pos) {
fc.resolveCallTargetBlanketCandidate(_, pos, _, _) fc.resolveCallTargetBlanketCandidate(_, pos, _, _)
} }
/** A call tagged with a position. */ /** A call tagged with a position. */
private class CallAndBlanketPos extends MkCallAndBlanketPos { private class CallAndBlanketPos extends MkCallAndBlanketPos {
NonMethodCall fc; NonMethodCall fc;
FunctionTypePosition pos; FunctionPosition pos;
CallAndBlanketPos() { this = MkCallAndBlanketPos(fc, pos) } CallAndBlanketPos() { this = MkCallAndBlanketPos(fc, pos) }
@@ -2024,7 +2035,7 @@ private module NonMethodResolution {
predicate hasBlanketCandidate( predicate hasBlanketCandidate(
CallAndBlanketPos fcp, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam CallAndBlanketPos fcp, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam
) { ) {
exists(NonMethodCall fc, FunctionTypePosition pos | exists(NonMethodCall fc, FunctionPosition pos |
fcp = MkCallAndBlanketPos(fc, pos) and fcp = MkCallAndBlanketPos(fc, pos) and
fc.resolveCallTargetBlanketCandidate(impl, pos, blanketPath, blanketTypeParam) fc.resolveCallTargetBlanketCandidate(impl, pos, blanketPath, blanketTypeParam)
) )
@@ -2046,7 +2057,7 @@ private module NonMethodResolution {
predicate potentialInstantiationOf( predicate potentialInstantiationOf(
CallAndBlanketPos fcp, TypeAbstraction abs, AssocFunctionType constraint CallAndBlanketPos fcp, TypeAbstraction abs, AssocFunctionType constraint
) { ) {
exists(FunctionTypePosition pos | exists(FunctionPosition pos |
ArgSatisfiesBlanketConstraint::satisfiesBlanketConstraint(fcp, abs) and ArgSatisfiesBlanketConstraint::satisfiesBlanketConstraint(fcp, abs) and
fcp = MkCallAndBlanketPos(_, pos) and fcp = MkCallAndBlanketPos(_, pos) and
functionInfoBlanketRelevantPos(_, _, _, abs, _, pos, constraint, _, _) functionInfoBlanketRelevantPos(_, _, _, abs, _, pos, constraint, _, _)
@@ -2062,9 +2073,7 @@ private module NonMethodResolution {
ArgIsInstantiationOf<CallAndBlanketPos, ArgIsInstantiationOfBlanketParamInput>; ArgIsInstantiationOf<CallAndBlanketPos, ArgIsInstantiationOfBlanketParamInput>;
private module NonMethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { private module NonMethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig {
predicate toCheck( predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
ImplOrTraitItemNode i, Function f, FunctionTypePosition pos, AssocFunctionType t
) {
t.appliesTo(f, pos, i) and t.appliesTo(f, pos, i) and
( (
exists(Type t0 | exists(Type t0 |
@@ -2087,7 +2096,7 @@ private module NonMethodResolution {
} }
class Call extends NonMethodCall { class Call extends NonMethodCall {
Type getArgType(FunctionTypePosition pos, TypePath path) { Type getArgType(FunctionPosition pos, TypePath path) {
result = inferType(this.getNodeAt(pos), path) result = inferType(this.getNodeAt(pos), path)
} }
@@ -2117,7 +2126,7 @@ private module NonMethodResolution {
* `foo::bar(baz)` where the target is not a method. * `foo::bar(baz)` where the target is not a method.
*/ */
private module NonMethodCallMatchingInput implements MatchingInputSig { private module NonMethodCallMatchingInput implements MatchingInputSig {
import FunctionTypePositionMatchingInput import FunctionPositionMatchingInput
abstract class Declaration extends AstNode { abstract class Declaration extends AstNode {
abstract TypeParameter getTypeParameter(TypeParameterPosition ppos); abstract TypeParameter getTypeParameter(TypeParameterPosition ppos);
@@ -2154,7 +2163,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig {
override Type getParameterType(DeclarationPosition dpos, TypePath path) { override Type getParameterType(DeclarationPosition dpos, TypePath path) {
exists(int pos | exists(int pos |
result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and
pos = dpos.asPositional() pos = dpos.asPosition()
) )
} }
@@ -2177,7 +2186,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig {
override Type getParameterType(DeclarationPosition dpos, TypePath path) { override Type getParameterType(DeclarationPosition dpos, TypePath path) {
exists(int pos | exists(int pos |
result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and
pos = dpos.asPositional() pos = dpos.asPosition()
) )
} }
@@ -2221,7 +2230,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig {
result = resolveImplOrTraitType(i, path) result = resolveImplOrTraitType(i, path)
) )
or or
exists(FunctionTypePosition fpos | exists(FunctionPosition fpos |
result = MethodCallMatchingInput::Declaration.super.getParameterType(fpos, path) and result = MethodCallMatchingInput::Declaration.super.getParameterType(fpos, path) and
dpos = fpos.getFunctionCallAdjusted(this) dpos = fpos.getFunctionCallAdjusted(this)
) )
@@ -2267,7 +2276,7 @@ private Type inferNonMethodCallType(AstNode n, TypePath path) {
*/ */
private module OperationMatchingInput implements MatchingInputSig { private module OperationMatchingInput implements MatchingInputSig {
private import codeql.rust.elements.internal.OperationImpl as OperationImpl private import codeql.rust.elements.internal.OperationImpl as OperationImpl
import FunctionTypePositionMatchingInput import FunctionPositionMatchingInput
class Declaration extends MethodCallMatchingInput::Declaration { class Declaration extends MethodCallMatchingInput::Declaration {
private Method getSelfOrImpl() { private Method getSelfOrImpl() {
@@ -2284,7 +2293,7 @@ private module OperationMatchingInput implements MatchingInputSig {
exists(int borrows | OperationImpl::isOverloaded(_, _, path, method, borrows) | exists(int borrows | OperationImpl::isOverloaded(_, _, path, method, borrows) |
pos.isSelf() and borrows >= 1 pos.isSelf() and borrows >= 1
or or
pos.asPositional() = 0 and pos.asPosition() = 0 and
borrows >= 2 borrows >= 2
) )
) )
@@ -2326,7 +2335,7 @@ private module OperationMatchingInput implements MatchingInputSig {
} }
Declaration getTarget() { Declaration getTarget() {
result = this.resolveCallTarget(_) // mutual recursion result = this.resolveCallTarget(_, _) // mutual recursion
} }
} }
} }
@@ -2760,7 +2769,7 @@ private Type inferStructPatType(AstNode n, TypePath path) {
* like `let Some(x) = ...`. * like `let Some(x) = ...`.
*/ */
private module TupleStructPatMatchingInput implements MatchingInputSig { private module TupleStructPatMatchingInput implements MatchingInputSig {
import FunctionTypePositionMatchingInput import FunctionPositionMatchingInput
class Declaration = NonMethodCallMatchingInput::TupleDeclaration; class Declaration = NonMethodCallMatchingInput::TupleDeclaration;
@@ -2768,7 +2777,7 @@ private module TupleStructPatMatchingInput implements MatchingInputSig {
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() }
AstNode getNodeAt(AccessPosition apos) { AstNode getNodeAt(AccessPosition apos) {
result = this.getField(apos.asPositional()) result = this.getField(apos.asPosition())
or or
result = this and result = this and
apos.isSelf() apos.isSelf()
@@ -2987,7 +2996,7 @@ private module Cached {
/** Gets an item (function or tuple struct/variant) that `call` resolves to, if any. */ /** Gets an item (function or tuple struct/variant) that `call` resolves to, if any. */
cached cached
Addressable resolveCallTarget(Call call) { Addressable resolveCallTarget(Call call) {
result = call.(MethodResolution::MethodCall).resolveCallTarget(_) result = call.(MethodResolution::MethodCall).resolveCallTarget(_, _)
or or
result = call.(NonMethodResolution::NonMethodCall).resolveCallTarget() result = call.(NonMethodResolution::NonMethodCall).resolveCallTarget()
} }

View File

@@ -9,6 +9,7 @@ private import TypeInference
/** An AST node that may mention a type. */ /** An AST node that may mention a type. */
abstract class TypeMention extends AstNode { abstract class TypeMention extends AstNode {
/** Gets the type at `path` that this mention resolves to, if any. */ /** Gets the type at `path` that this mention resolves to, if any. */
pragma[nomagic]
abstract Type resolveTypeAt(TypePath path); abstract Type resolveTypeAt(TypePath path);
/** Gets the type that this node resolves to, if any. */ /** Gets the type that this node resolves to, if any. */
@@ -93,7 +94,6 @@ class AliasPathTypeMention extends PathTypeMention {
* Holds if this path resolved to a type alias with a rhs. that has the * Holds if this path resolved to a type alias with a rhs. that has the
* resulting type at `typePath`. * resulting type at `typePath`.
*/ */
pragma[nomagic]
override Type resolveTypeAt(TypePath typePath) { override Type resolveTypeAt(TypePath typePath) {
result = rhs.resolveTypeAt(typePath) and result = rhs.resolveTypeAt(typePath) and
not result = pathGetTypeParameter(resolved, _) not result = pathGetTypeParameter(resolved, _)
@@ -245,7 +245,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
} }
pragma[nomagic] pragma[nomagic]
private Type resolveImplSelfType(Impl i, TypePath path) { private Type resolveImplSelfTypeAt(Impl i, TypePath path) {
result = i.getSelfTy().(TypeMention).resolveTypeAt(path) result = i.getSelfTy().(TypeMention).resolveTypeAt(path)
} }
@@ -254,7 +254,7 @@ class ImplSelfMention extends PathTypeMention {
ImplSelfMention() { this = impl.getASelfPath() } ImplSelfMention() { this = impl.getASelfPath() }
override Type resolveTypeAt(TypePath typePath) { result = resolveImplSelfType(impl, typePath) } override Type resolveTypeAt(TypePath typePath) { result = resolveImplSelfTypeAt(impl, typePath) }
} }
class PathTypeReprMention extends TypeMention, PathTypeRepr { class PathTypeReprMention extends TypeMention, PathTypeRepr {
@@ -334,17 +334,14 @@ class SelfTypeParameterMention extends TypeMention instanceof Name {
*/ */
pragma[nomagic] pragma[nomagic]
Type resolveImplOrTraitType(ImplOrTraitItemNode i, TypePath path) { Type resolveImplOrTraitType(ImplOrTraitItemNode i, TypePath path) {
result = resolveImplSelfType(i, path) result = resolveImplSelfTypeAt(i, path)
or or
result = TSelfTypeParameter(i) and path.isEmpty() result = TSelfTypeParameter(i) and path.isEmpty()
} }
pragma[nomagic] pragma[nomagic]
private ImplOrTraitItemNode getSelfParamEnclosingImplOrTrait(SelfParam self) { private ImplOrTraitItemNode getSelfParamEnclosingImplOrTrait(SelfParam self) {
exists(Function f | self = result.getAnAssocItem().(Function).getSelfParam()
f = result.getAnAssocItem() and
self = f.getSelfParam()
)
} }
/** /**
@@ -360,34 +357,30 @@ class ShorthandSelfParameterMention extends TypeMention instanceof SelfParam {
not super.hasTypeRepr() and not super.hasTypeRepr() and
encl = getSelfParamEnclosingImplOrTrait(this) and encl = getSelfParamEnclosingImplOrTrait(this) and
( (
encl instanceof Trait not encl instanceof Impl
or or
// avoid generating a type mention if the type being implemented cannot be resolved // avoid generating a type mention if the type being implemented does not have a type mention
encl.(Impl).getSelfTy() instanceof TypeMention encl.(Impl).getSelfTy() instanceof TypeMention
) )
} }
pragma[nomagic]
private Type resolveSelfType(TypePath path) { result = resolveImplOrTraitType(encl, path) } private Type resolveSelfType(TypePath path) { result = resolveImplOrTraitType(encl, path) }
pragma[nomagic] override Type resolveTypeAt(TypePath typePath) {
private Type inferImplicitSelfType(TypePath path) {
if super.isRef() if super.isRef()
then then
// `fn f(&self, ...)` // `fn f(&self, ...)`
path.isEmpty() and typePath.isEmpty() and
result = TRefType() result = TRefType()
or or
exists(TypePath suffix | exists(TypePath suffix |
result = this.resolveSelfType(suffix) and result = this.resolveSelfType(suffix) and
path = TypePath::cons(TRefTypeParameter(), suffix) typePath = TypePath::cons(TRefTypeParameter(), suffix)
) )
else else
// `fn f(self, ...)` // `fn f(self, ...)`
result = this.resolveSelfType(path) result = this.resolveSelfType(typePath)
} }
override Type resolveTypeAt(TypePath typePath) { result = this.inferImplicitSelfType(typePath) }
} }
pragma[nomagic] pragma[nomagic]

View File

@@ -1,8 +1,8 @@
/** /**
* Provides logic for identifying functions that are overloaded based on their * Provides logic for identifying functions that are overloaded based on their
* argument types. While Rust does not allow for overloading inside a single * non-`self` parameter types. While Rust does not allow for overloading inside a single
* `impl` block, it is still possible for a trait to have multiple implementations * `impl` block, it is still possible for a trait to have multiple implementations
* that differ only in the types of non-`self` arguments. * that differ only in the types of non-`self` parameters.
*/ */
private import rust private import rust
@@ -75,11 +75,11 @@ private predicate implHasSibling(Impl impl, Trait trait) { implSiblings(trait, i
bindingset[trait] bindingset[trait]
pragma[inline_late] pragma[inline_late]
predicate traitTypeParameterOccurrence( predicate traitTypeParameterOccurrence(
TraitItemNode trait, Function f, string functionName, FunctionTypePosition pos, TypePath path, TraitItemNode trait, Function f, string functionName, FunctionPosition pos, TypePath path,
TypeParameter tp TypeParameter tp
) { ) {
f = trait.getASuccessor(functionName) and f = trait.getASuccessor(functionName) and
assocFunctionTypeAtPath(f, trait, pos, path, tp) and assocFunctionTypeAt(f, trait, pos, path, tp) and
tp = trait.(TraitTypeAbstraction).getATypeParameter() tp = trait.(TraitTypeAbstraction).getATypeParameter()
} }
@@ -90,7 +90,7 @@ predicate traitTypeParameterOccurrence(
*/ */
pragma[nomagic] pragma[nomagic]
predicate functionResolutionDependsOnArgument( predicate functionResolutionDependsOnArgument(
ImplItemNode impl, Function f, FunctionTypePosition pos, TypePath path, Type type ImplItemNode impl, Function f, FunctionPosition pos, TypePath path, Type type
) { ) {
/* /*
* As seen in the example below, when an implementation has a sibling for a * As seen in the example below, when an implementation has a sibling for a
@@ -120,7 +120,7 @@ predicate functionResolutionDependsOnArgument(
exists(TraitItemNode trait, string functionName | exists(TraitItemNode trait, string functionName |
implHasSibling(impl, trait) and implHasSibling(impl, trait) and
traitTypeParameterOccurrence(trait, _, functionName, pos, path, _) and traitTypeParameterOccurrence(trait, _, functionName, pos, path, _) and
assocFunctionTypeAtPath(f, impl, pos, path, type) and assocFunctionTypeAt(f, impl, pos, path, type) and
f = impl.getASuccessor(functionName) and f = impl.getASuccessor(functionName) and
not pos.isReturn() not pos.isReturn()
) )

View File

@@ -5,37 +5,37 @@ private import codeql.rust.internal.Type
private import codeql.rust.internal.TypeMention private import codeql.rust.internal.TypeMention
private import codeql.rust.elements.Call private import codeql.rust.elements.Call
private newtype TFunctionTypePosition = private newtype TFunctionPosition =
TArgumentFunctionTypePosition(ArgumentPosition pos) or TArgumentFunctionPosition(ArgumentPosition pos) or
TReturnFunctionTypePosition() TReturnFunctionPosition()
/** /**
* A position of a type related to a function. * A position of a type related to a function.
* *
* Either `self`, `return`, or a positional parameter index. * Either `self`, `return`, or a positional parameter index.
*/ */
class FunctionTypePosition extends TFunctionTypePosition { class FunctionPosition extends TFunctionPosition {
predicate isSelf() { this.asArgumentPosition().isSelf() } predicate isSelf() { this.asArgumentPosition().isSelf() }
int asPositional() { result = this.asArgumentPosition().asPosition() } int asPosition() { result = this.asArgumentPosition().asPosition() }
predicate isPositional() { exists(this.asPositional()) } predicate isPosition() { exists(this.asPosition()) }
ArgumentPosition asArgumentPosition() { this = TArgumentFunctionTypePosition(result) } ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) }
predicate isReturn() { this = TReturnFunctionTypePosition() } predicate isReturn() { this = TReturnFunctionPosition() }
/** Gets the corresponding position when `f` is invoked via a function call. */ /** Gets the corresponding position when `f` is invoked via a function call. */
bindingset[f] bindingset[f]
FunctionTypePosition getFunctionCallAdjusted(Function f) { FunctionPosition getFunctionCallAdjusted(Function f) {
this.isReturn() and this.isReturn() and
result = this result = this
or or
if f.hasSelfParam() if f.hasSelfParam()
then then
this.isSelf() and result.asPositional() = 0 this.isSelf() and result.asPosition() = 0
or or
result.asPositional() = this.asPositional() + 1 result.asPosition() = this.asPosition() + 1
else result = this else result = this
} }
@@ -43,7 +43,7 @@ class FunctionTypePosition extends TFunctionTypePosition {
this.isSelf() and this.isSelf() and
result = getSelfParamTypeMention(f.getSelfParam()) result = getSelfParamTypeMention(f.getSelfParam())
or or
result = f.getParam(this.asPositional()).getTypeRepr() result = f.getParam(this.asPosition()).getTypeRepr()
or or
this.isReturn() and this.isReturn() and
result = f.getRetType().getTypeRepr() result = f.getRetType().getTypeRepr()
@@ -59,10 +59,10 @@ class FunctionTypePosition extends TFunctionTypePosition {
/** /**
* A helper module for implementing `Matching(WithEnvironment)InputSig` with * A helper module for implementing `Matching(WithEnvironment)InputSig` with
* `DeclarationPosition = AccessPosition = FunctionTypePosition`. * `DeclarationPosition = AccessPosition = FunctionPosition`.
*/ */
module FunctionTypePositionMatchingInput { module FunctionPositionMatchingInput {
class DeclarationPosition = FunctionTypePosition; class DeclarationPosition = FunctionPosition;
class AccessPosition = DeclarationPosition; class AccessPosition = DeclarationPosition;
@@ -72,12 +72,12 @@ module FunctionTypePositionMatchingInput {
} }
private newtype TAssocFunctionType = private newtype TAssocFunctionType =
MkAssocFunctionType(Function f, FunctionTypePosition pos, ImplOrTraitItemNode i) { MkAssocFunctionType(Function f, FunctionPosition pos, ImplOrTraitItemNode i) {
f = i.getAnAssocItem() and f = i.getAnAssocItem() and
exists(pos.getTypeMention(f)) exists(pos.getTypeMention(f))
} or } or
MkInheritedAssocFunctionType( MkInheritedAssocFunctionType(
Function f, FunctionTypePosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, Function f, FunctionPosition pos, TypeMention parentMention, ImplOrTraitItemNode parent,
ImplOrTraitItemNode i ImplOrTraitItemNode i
) { ) {
exists(AssocFunctionType inherited | exists(AssocFunctionType inherited |
@@ -127,12 +127,12 @@ private newtype TAssocFunctionType =
* `self5` | `impl T2 for X` | `X` * `self5` | `impl T2 for X` | `X`
*/ */
class AssocFunctionType extends TAssocFunctionType { class AssocFunctionType extends TAssocFunctionType {
private predicate isFunctionType(Function f, FunctionTypePosition pos, ImplOrTraitItemNode i) { private predicate isFunctionType(Function f, FunctionPosition pos, ImplOrTraitItemNode i) {
this = MkAssocFunctionType(f, pos, i) this = MkAssocFunctionType(f, pos, i)
} }
private predicate isInheritedFunctionType( private predicate isInheritedFunctionType(
Function f, FunctionTypePosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, Function f, FunctionPosition pos, TypeMention parentMention, ImplOrTraitItemNode parent,
ImplOrTraitItemNode i ImplOrTraitItemNode i
) { ) {
this = MkInheritedAssocFunctionType(f, pos, parentMention, parent, i) this = MkInheritedAssocFunctionType(f, pos, parentMention, parent, i)
@@ -142,7 +142,7 @@ class AssocFunctionType extends TAssocFunctionType {
* Holds if this function type applies to the function `f` at position `pos`, * Holds if this function type applies to the function `f` at position `pos`,
* when viewed as a member of the `impl` or trait item `i`. * when viewed as a member of the `impl` or trait item `i`.
*/ */
predicate appliesTo(Function f, FunctionTypePosition pos, ImplOrTraitItemNode i) { predicate appliesTo(Function f, FunctionPosition pos, ImplOrTraitItemNode i) {
this.isFunctionType(f, pos, i) this.isFunctionType(f, pos, i)
or or
this.isInheritedFunctionType(f, pos, _, _, i) this.isInheritedFunctionType(f, pos, _, _, i)
@@ -151,13 +151,13 @@ class AssocFunctionType extends TAssocFunctionType {
/** Gets the type at the given path. */ /** Gets the type at the given path. */
pragma[nomagic] pragma[nomagic]
Type getDeclaredTypeAt(TypePath path) { Type getDeclaredTypeAt(TypePath path) {
exists(Function f, FunctionTypePosition pos | exists(Function f, FunctionPosition pos |
this.isFunctionType(f, pos, _) and this.isFunctionType(f, pos, _) and
result = pos.getTypeMention(f).resolveTypeAt(path) result = pos.getTypeMention(f).resolveTypeAt(path)
) )
or or
exists( exists(
Function f, FunctionTypePosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, Function f, FunctionPosition pos, TypeMention parentMention, ImplOrTraitItemNode parent,
AssocFunctionType parentType, ImplOrTraitItemNode i AssocFunctionType parentType, ImplOrTraitItemNode i
| |
this.isInheritedFunctionType(f, pos, parentMention, parent, i) and this.isInheritedFunctionType(f, pos, parentMention, parent, i) and
@@ -171,7 +171,7 @@ class AssocFunctionType extends TAssocFunctionType {
result = resolveImplOrTraitType(i, suffix) result = resolveImplOrTraitType(i, suffix)
or or
exists(TypeParameter tp | exists(TypeParameter tp |
parentType.hasTypeParameterAt(prefix, tp) and tp = parentType.getTypeParameterAt(prefix) and
result = parentMention.resolveTypeAt(TypePath::singleton(tp).appendInverse(suffix)) result = parentMention.resolveTypeAt(TypePath::singleton(tp).appendInverse(suffix))
) )
) )
@@ -179,19 +179,17 @@ class AssocFunctionType extends TAssocFunctionType {
} }
pragma[nomagic] pragma[nomagic]
private predicate hasTypeParameterAt(TypePath path, TypeParameter tp) { private TypeParameter getTypeParameterAt(TypePath path) { result = this.getDeclaredTypeAt(path) }
this.getDeclaredTypeAt(path) = tp
}
pragma[nomagic] pragma[nomagic]
private predicate hasSelfTypeParameterAt(TypePath path) { private predicate hasSelfTypeParameterAt(TypePath path) {
this.hasTypeParameterAt(path, TSelfTypeParameter(_)) this.getTypeParameterAt(path) = TSelfTypeParameter(_)
} }
/** /**
* Gets the type at the given path. * Gets the type at the given path.
* *
* For functions belonging to a `trait`, we use the type of the trait itself instead * For functions belonging to a trait, we use the type of the trait itself instead
* of the implicit `Self` type parameter, as otherwise any type will match. * of the implicit `Self` type parameter, as otherwise any type will match.
* *
* Calls should use `substituteLookupTraits` to map receiver types to the relevant * Calls should use `substituteLookupTraits` to map receiver types to the relevant
@@ -206,26 +204,16 @@ class AssocFunctionType extends TAssocFunctionType {
) )
} }
private AstNode getReportingNode() { private TypeMention getTypeMention() {
exists(Function f, FunctionTypePosition pos | this.appliesTo(f, pos, _) | exists(Function f, FunctionPosition pos |
pos.isSelf() and this.appliesTo(f, pos, _) and
exists(SelfParam self | self = f.getSelfParam() | result = pos.getTypeMention(f)
result = self.getTypeRepr()
or
not self.hasTypeRepr() and
result = self
)
or
result = f.getParam(pos.asPositional()).getTypeRepr()
or
pos.isReturn() and
result = f.getRetType().getTypeRepr()
) )
} }
string toString() { result = this.getReportingNode().toString() } string toString() { result = this.getTypeMention().toString() }
Location getLocation() { result = this.getReportingNode().getLocation() } Location getLocation() { result = this.getTypeMention().getLocation() }
} }
/** /**
@@ -233,8 +221,8 @@ class AssocFunctionType extends TAssocFunctionType {
* `i` is `type`. * `i` is `type`.
*/ */
pragma[nomagic] pragma[nomagic]
predicate assocFunctionTypeAtPath( predicate assocFunctionTypeAt(
Function f, ImplOrTraitItemNode i, FunctionTypePosition pos, TypePath path, Type type Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path, Type type
) { ) {
exists(AssocFunctionType aft | exists(AssocFunctionType aft |
aft.appliesTo(f, pos, i) and aft.appliesTo(f, pos, i) and
@@ -313,7 +301,7 @@ signature module ArgsAreInstantiationsOfInputSig {
* Holds if types need to be matched against the type `t` at position `pos` of * Holds if types need to be matched against the type `t` at position `pos` of
* `f` inside `i`. * `f` inside `i`.
*/ */
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionTypePosition pos, AssocFunctionType t); predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t);
/** A call whose argument types are to be checked. */ /** A call whose argument types are to be checked. */
class Call { class Call {
@@ -321,7 +309,7 @@ signature module ArgsAreInstantiationsOfInputSig {
Location getLocation(); Location getLocation();
Type getArgType(FunctionTypePosition pos, TypePath path); Type getArgType(FunctionPosition pos, TypePath path);
predicate hasTargetCand(ImplOrTraitItemNode i, Function f); predicate hasTargetCand(ImplOrTraitItemNode i, Function f);
} }
@@ -334,15 +322,13 @@ signature module ArgsAreInstantiationsOfInputSig {
*/ */
module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> { module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
pragma[nomagic] pragma[nomagic]
private predicate toCheckRanked( private predicate toCheckRanked(ImplOrTraitItemNode i, Function f, FunctionPosition pos, int rnk) {
ImplOrTraitItemNode i, Function f, FunctionTypePosition pos, int rnk
) {
Input::toCheck(i, f, pos, _) and Input::toCheck(i, f, pos, _) and
pos = pos =
rank[rnk + 1](FunctionTypePosition pos0, int j | rank[rnk + 1](FunctionPosition pos0, int j |
Input::toCheck(i, f, pos0, _) and Input::toCheck(i, f, pos0, _) and
( (
j = pos0.asPositional() j = pos0.asPosition()
or or
pos0.isSelf() and j = -1 pos0.isSelf() and j = -1
or or
@@ -354,18 +340,18 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
} }
private newtype TCallAndPos = private newtype TCallAndPos =
MkCallAndPos(Input::Call call, FunctionTypePosition pos) { exists(call.getArgType(pos, _)) } MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) }
/** A call tagged with a position. */ /** A call tagged with a position. */
private class CallAndPos extends MkCallAndPos { private class CallAndPos extends MkCallAndPos {
Input::Call call; Input::Call call;
FunctionTypePosition pos; FunctionPosition pos;
CallAndPos() { this = MkCallAndPos(call, pos) } CallAndPos() { this = MkCallAndPos(call, pos) }
Input::Call getCall() { result = call } Input::Call getCall() { result = call }
FunctionTypePosition getPos() { result = pos } FunctionPosition getPos() { result = pos }
Location getLocation() { result = call.getLocation() } Location getLocation() { result = call.getLocation() }
@@ -379,7 +365,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
{ {
pragma[nomagic] pragma[nomagic]
private predicate potentialInstantiationOf0( private predicate potentialInstantiationOf0(
CallAndPos cp, Input::Call call, FunctionTypePosition pos, int rnk, Function f, CallAndPos cp, Input::Call call, FunctionPosition pos, int rnk, Function f,
TypeAbstraction abs, AssocFunctionType constraint TypeAbstraction abs, AssocFunctionType constraint
) { ) {
cp = MkCallAndPos(call, pos) and cp = MkCallAndPos(call, pos) and
@@ -413,7 +399,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
private predicate argsAreInstantiationsOfFromIndex( private predicate argsAreInstantiationsOfFromIndex(
Input::Call call, ImplOrTraitItemNode i, Function f, int rnk Input::Call call, ImplOrTraitItemNode i, Function f, int rnk
) { ) {
exists(FunctionTypePosition pos | exists(FunctionPosition pos |
ArgIsInstantiationOfFromIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and ArgIsInstantiationOfFromIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
call.hasTargetCand(i, f) and call.hasTargetCand(i, f) and
toCheckRanked(i, f, pos, rnk) toCheckRanked(i, f, pos, rnk)

View File

@@ -1118,6 +1118,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
* For example, if this access is the method call `M(42)`, then the inferred * For example, if this access is the method call `M(42)`, then the inferred
* type at argument position `0` is `int`. * type at argument position `0` is `int`.
*/ */
bindingset[e]
Type getInferredType(AccessEnvironment e, AccessPosition apos, TypePath path); Type getInferredType(AccessEnvironment e, AccessPosition apos, TypePath path);
/** Gets the declaration that this access targets in environment `e`. */ /** Gets the declaration that this access targets in environment `e`. */