Skip to content

Commit ea39c09

Browse files
committed
wip
1 parent d9f3769 commit ea39c09

1 file changed

Lines changed: 269 additions & 0 deletions

File tree

rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,275 @@ private module AssocFunctionResolution {
18581858
}
18591859
}
18601860

1861+
/**
1862+
* A matching configuration for resolving types of function call expressions
1863+
* like `foo.bar(baz)` and `Foo::bar(baz)`.
1864+
*/
1865+
private module FunctionCallMatchingInput implements MatchingWithEnvironmentInputSig {
1866+
import FunctionPositionMatchingInput
1867+
1868+
private newtype TDeclaration =
1869+
TFunctionDeclaration(ImplOrTraitItemNodeOption i, FunctionDeclaration f) { f.isFor(i) }
1870+
1871+
final class Declaration extends TFunctionDeclaration {
1872+
ImplOrTraitItemNodeOption i;
1873+
FunctionDeclaration f;
1874+
1875+
Declaration() { this = TFunctionDeclaration(i, f) }
1876+
1877+
FunctionDeclaration getFunction() { result = f }
1878+
1879+
predicate isAssocFunction(ImplOrTraitItemNode i_, Function f_) {
1880+
i_ = i.asSome() and
1881+
f_ = f
1882+
}
1883+
1884+
TypeParameter getTypeParameter(TypeParameterPosition ppos) {
1885+
result = f.getTypeParameter(i, ppos)
1886+
}
1887+
1888+
Type getDeclaredType(FunctionPosition pos, TypePath path) {
1889+
result = f.getParameterType(i, pos, path)
1890+
or
1891+
pos.isReturn() and
1892+
result = f.getReturnType(i, path)
1893+
}
1894+
1895+
string toString() {
1896+
i.isNone() and result = f.toString()
1897+
or
1898+
result = f.toStringExt(i.asSome())
1899+
}
1900+
1901+
Location getLocation() { result = f.getLocation() }
1902+
}
1903+
1904+
pragma[nomagic]
1905+
private TypeMention getAdditionalTypeParameterConstraint(TypeParameter tp, Declaration decl) {
1906+
result =
1907+
tp.(TypeParamTypeParameter)
1908+
.getTypeParam()
1909+
.getAdditionalTypeBound(decl.getFunction(), _)
1910+
.getTypeRepr()
1911+
}
1912+
1913+
bindingset[decl]
1914+
TypeMention getATypeParameterConstraint(TypeParameter tp, Declaration decl) {
1915+
result = Input2::getATypeParameterConstraint(tp) and
1916+
exists(decl)
1917+
or
1918+
result = getAdditionalTypeParameterConstraint(tp, decl)
1919+
}
1920+
1921+
class AccessEnvironment = string;
1922+
1923+
bindingset[derefChain, borrow]
1924+
private AccessEnvironment encodeDerefChainBorrow(DerefChain derefChain, BorrowKind borrow) {
1925+
result = derefChain + ";" + borrow
1926+
}
1927+
1928+
bindingset[derefChainBorrow]
1929+
additional predicate decodeDerefChainBorrow(
1930+
string derefChainBorrow, DerefChain derefChain, BorrowKind borrow
1931+
) {
1932+
exists(int i |
1933+
i = derefChainBorrow.indexOf(";") and
1934+
derefChain = derefChainBorrow.prefix(i) and
1935+
borrow.toString() = derefChainBorrow.suffix(i + 1)
1936+
)
1937+
}
1938+
1939+
private string noDerefChainBorrow() {
1940+
exists(DerefChain derefChain, BorrowKind borrow |
1941+
derefChain.isEmpty() and
1942+
borrow.isNoBorrow() and
1943+
result = encodeDerefChainBorrow(derefChain, borrow)
1944+
)
1945+
}
1946+
1947+
abstract class Access extends ContextTyping::ContextTypedCallCand {
1948+
abstract AstNode getNodeAt(FunctionPosition pos);
1949+
1950+
bindingset[derefChainBorrow]
1951+
abstract Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path);
1952+
1953+
abstract Declaration getTarget(string derefChainBorrow);
1954+
1955+
/**
1956+
* Holds if the return type of this call at `path` may have to be inferred
1957+
* from the context.
1958+
*/
1959+
abstract predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path);
1960+
}
1961+
1962+
private class AssocFunctionCallAccess extends Access instanceof AssocFunctionResolution::AssocFunctionCall
1963+
{
1964+
AssocFunctionCallAccess() {
1965+
// handled in the `OperationMatchingInput` module
1966+
not this instanceof Operation
1967+
}
1968+
1969+
pragma[nomagic]
1970+
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
1971+
result =
1972+
this.(MethodCallExpr)
1973+
.getGenericArgList()
1974+
.getTypeArg(apos.asMethodTypeArgumentPosition())
1975+
.(TypeMention)
1976+
.getTypeAt(path)
1977+
or
1978+
result = getCallExprTypeArgument(this, apos, path)
1979+
}
1980+
1981+
override AstNode getNodeAt(FunctionPosition pos) {
1982+
result = AssocFunctionResolution::AssocFunctionCall.super.getNodeAt(pos)
1983+
}
1984+
1985+
pragma[nomagic]
1986+
private Type getInferredSelfType(FunctionPosition pos, string derefChainBorrow, TypePath path) {
1987+
exists(DerefChain derefChain, BorrowKind borrow |
1988+
result = super.getSelfTypeAt(pos, derefChain, borrow, path) and
1989+
derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and
1990+
super.hasReceiverAtPos(pos)
1991+
)
1992+
}
1993+
1994+
pragma[nomagic]
1995+
private Type getInferredNonSelfType(FunctionPosition pos, TypePath path) {
1996+
if
1997+
// index expression `x[i]` desugars to `*x.index(i)`, so we must account for
1998+
// the implicit deref
1999+
pos.isReturn() and
2000+
this instanceof IndexExpr
2001+
then
2002+
path.isEmpty() and
2003+
result instanceof RefType
2004+
or
2005+
exists(TypePath suffix |
2006+
result = super.getTypeAt(pos, suffix) and
2007+
path = TypePath::cons(getRefTypeParameter(_), suffix)
2008+
)
2009+
else (
2010+
not super.hasReceiverAtPos(pos) and
2011+
result = super.getTypeAt(pos, path)
2012+
)
2013+
}
2014+
2015+
bindingset[derefChainBorrow]
2016+
override Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path) {
2017+
result = this.getInferredSelfType(pos, derefChainBorrow, path)
2018+
or
2019+
result = this.getInferredNonSelfType(pos, path)
2020+
}
2021+
2022+
private AssocFunctionDeclaration getTarget(ImplOrTraitItemNode i, string derefChainBorrow) {
2023+
exists(DerefChain derefChain, BorrowKind borrow |
2024+
derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and
2025+
result = super.resolveCallTarget(i, _, derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa
2026+
)
2027+
}
2028+
2029+
override Declaration getTarget(string derefChainBorrow) {
2030+
exists(ImplOrTraitItemNode i | result.isAssocFunction(i, this.getTarget(i, derefChainBorrow)))
2031+
}
2032+
2033+
pragma[nomagic]
2034+
override predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) {
2035+
exists(ImplOrTraitItemNode i |
2036+
this.hasUnknownTypeAt(i, this.getTarget(i, derefChainBorrow), pos, path)
2037+
)
2038+
or
2039+
derefChainBorrow = noDerefChainBorrow() and
2040+
forex(ImplOrTraitItemNode i, Function f |
2041+
f = CallExprImpl::getResolvedFunction(this) and
2042+
f = i.getAnAssocItem()
2043+
|
2044+
this.hasUnknownTypeAt(i, f, pos, path)
2045+
)
2046+
}
2047+
}
2048+
2049+
private class NonAssocFunctionCallAccess extends Access instanceof NonAssocCallExpr,
2050+
CallExprImpl::CallExprCall
2051+
{
2052+
pragma[nomagic]
2053+
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
2054+
result = NonAssocCallExpr.super.getTypeArgument(apos, path)
2055+
}
2056+
2057+
override AstNode getNodeAt(FunctionPosition pos) {
2058+
result = NonAssocCallExpr.super.getNodeAt(pos)
2059+
}
2060+
2061+
pragma[nomagic]
2062+
private Type getInferredType(FunctionPosition pos, TypePath path) {
2063+
result = super.getInferredType(pos, path)
2064+
}
2065+
2066+
bindingset[derefChainBorrow]
2067+
override Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path) {
2068+
exists(derefChainBorrow) and
2069+
result = this.getInferredType(pos, path)
2070+
}
2071+
2072+
pragma[nomagic]
2073+
private Declaration getTarget() {
2074+
result =
2075+
TFunctionDeclaration(ImplOrTraitItemNodeOption::none_(),
2076+
super.resolveCallTargetViaPathResolution())
2077+
}
2078+
2079+
override Declaration getTarget(string derefChainBorrow) {
2080+
result = this.getTarget() and
2081+
derefChainBorrow = noDerefChainBorrow()
2082+
}
2083+
2084+
pragma[nomagic]
2085+
override predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) {
2086+
derefChainBorrow = noDerefChainBorrow() and
2087+
exists(FunctionDeclaration f, TypeParameter tp |
2088+
f = super.resolveCallTargetViaPathResolution() and
2089+
pos.isReturn() and
2090+
tp = f.getReturnType(_, path) and
2091+
not tp = f.getParameterType(_, _, _) and
2092+
// check that no explicit type arguments have been supplied for `tp`
2093+
not exists(TypeArgumentPosition tapos |
2094+
this.hasTypeArgument(tapos) and
2095+
TTypeParamTypeParameter(tapos.asTypeParam()) = tp
2096+
)
2097+
)
2098+
}
2099+
}
2100+
}
2101+
2102+
private module FunctionCallMatching = MatchingWithEnvironment<FunctionCallMatchingInput>;
2103+
2104+
pragma[nomagic]
2105+
private Type inferFunctionCallType0(
2106+
FunctionCallMatchingInput::Access call, FunctionPosition pos, AstNode n, DerefChain derefChain,
2107+
BorrowKind borrow, TypePath path
2108+
) {
2109+
exists(TypePath path0 |
2110+
n = call.getNodeAt(pos) and
2111+
exists(string derefChainBorrow |
2112+
FunctionCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow)
2113+
|
2114+
result = FunctionCallMatching::inferAccessType(call, derefChainBorrow, pos, path0)
2115+
or
2116+
call.hasUnknownTypeAt(derefChainBorrow, pos, path0) and
2117+
result = TUnknownType()
2118+
)
2119+
|
2120+
if
2121+
// index expression `x[i]` desugars to `*x.index(i)`, so we must account for
2122+
// the implicit deref
2123+
pos.isReturn() and
2124+
call instanceof IndexExpr
2125+
then path0.isCons(getRefTypeParameter(_), path)
2126+
else path = path0
2127+
)
2128+
}
2129+
18612130
pragma[nomagic]
18622131
private Type getFieldExprLookupType(FieldExpr fe, string name, DerefChain derefChain) {
18632132
exists(TypePath path |

0 commit comments

Comments
 (0)