mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Merge pull request #19847 from hvitved/rust/type-inference-explicit-args
Rust: Handle more explicit type arguments in type inference
This commit is contained in:
@@ -78,7 +78,7 @@ module Impl {
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if the call expression dispatches to a trait method. */
|
||||
/** Holds if the call expression dispatches to a method. */
|
||||
private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName) {
|
||||
exists(Path path, Function f |
|
||||
path = call.getFunction().(PathExpr).getPath() and
|
||||
|
||||
@@ -165,7 +165,8 @@ abstract class ItemNode extends Locatable {
|
||||
exists(ItemNode node |
|
||||
this = node.(ImplItemNode).resolveSelfTy() and
|
||||
result = node.getASuccessorRec(name) and
|
||||
result instanceof AssocItemNode
|
||||
result instanceof AssocItemNode and
|
||||
not result instanceof TypeAlias
|
||||
)
|
||||
or
|
||||
// trait items with default implementations made available in an implementation
|
||||
@@ -181,6 +182,10 @@ abstract class ItemNode extends Locatable {
|
||||
result = this.(TypeParamItemNode).resolveABound().getASuccessorRec(name).(AssocItemNode)
|
||||
or
|
||||
result = this.(ImplTraitTypeReprItemNode).resolveABound().getASuccessorRec(name).(AssocItemNode)
|
||||
or
|
||||
result = this.(TypeAliasItemNode).resolveAlias().getASuccessorRec(name) and
|
||||
// type parameters defined in the RHS are not available in the LHS
|
||||
not result instanceof TypeParam
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,6 +294,8 @@ abstract class ItemNode extends Locatable {
|
||||
Location getLocation() { result = super.getLocation() }
|
||||
}
|
||||
|
||||
abstract class TypeItemNode extends ItemNode { }
|
||||
|
||||
/** A module or a source file. */
|
||||
abstract private class ModuleLikeNode extends ItemNode {
|
||||
/** Gets an item that may refer directly to items defined in this module. */
|
||||
@@ -438,7 +445,7 @@ private class ConstItemNode extends AssocItemNode instanceof Const {
|
||||
override TypeParam getTypeParam(int i) { none() }
|
||||
}
|
||||
|
||||
private class EnumItemNode extends ItemNode instanceof Enum {
|
||||
private class EnumItemNode extends TypeItemNode instanceof Enum {
|
||||
override string getName() { result = Enum.super.getName().getText() }
|
||||
|
||||
override Namespace getNamespace() { result.isType() }
|
||||
@@ -746,7 +753,7 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
|
||||
}
|
||||
}
|
||||
|
||||
private class StructItemNode extends ItemNode instanceof Struct {
|
||||
private class StructItemNode extends TypeItemNode instanceof Struct {
|
||||
override string getName() { result = Struct.super.getName().getText() }
|
||||
|
||||
override Namespace getNamespace() {
|
||||
@@ -781,7 +788,7 @@ private class StructItemNode extends ItemNode instanceof Struct {
|
||||
}
|
||||
}
|
||||
|
||||
class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
|
||||
class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof Trait {
|
||||
pragma[nomagic]
|
||||
Path getABoundPath() {
|
||||
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
|
||||
@@ -838,7 +845,10 @@ class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
|
||||
}
|
||||
}
|
||||
|
||||
class TypeAliasItemNode extends AssocItemNode instanceof TypeAlias {
|
||||
class TypeAliasItemNode extends TypeItemNode, AssocItemNode instanceof TypeAlias {
|
||||
pragma[nomagic]
|
||||
ItemNode resolveAlias() { result = resolvePathFull(super.getTypeRepr().(PathTypeRepr).getPath()) }
|
||||
|
||||
override string getName() { result = TypeAlias.super.getName().getText() }
|
||||
|
||||
override predicate hasImplementation() { super.hasTypeRepr() }
|
||||
@@ -854,7 +864,7 @@ class TypeAliasItemNode extends AssocItemNode instanceof TypeAlias {
|
||||
override string getCanonicalPath(Crate c) { none() }
|
||||
}
|
||||
|
||||
private class UnionItemNode extends ItemNode instanceof Union {
|
||||
private class UnionItemNode extends TypeItemNode instanceof Union {
|
||||
override string getName() { result = Union.super.getName().getText() }
|
||||
|
||||
override Namespace getNamespace() { result.isType() }
|
||||
@@ -912,7 +922,7 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
|
||||
override string getCanonicalPath(Crate c) { none() }
|
||||
}
|
||||
|
||||
class TypeParamItemNode extends ItemNode instanceof TypeParam {
|
||||
class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
|
||||
private WherePred getAWherePred() {
|
||||
exists(ItemNode declaringItem |
|
||||
this = resolveTypeParamPathTypeRepr(result.getTypeRepr()) and
|
||||
|
||||
@@ -139,9 +139,6 @@ class TraitType extends Type, TTrait {
|
||||
|
||||
override TypeParameter getTypeParameter(int i) {
|
||||
result = TTypeParamTypeParameter(trait.getGenericParamList().getTypeParam(i))
|
||||
or
|
||||
result =
|
||||
any(AssociatedTypeTypeParameter param | param.getTrait() = trait and param.getIndex() = i)
|
||||
}
|
||||
|
||||
override TypeMention getTypeParameterDefault(int i) {
|
||||
@@ -299,20 +296,6 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
|
||||
override Location getLocation() { result = typeParam.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type alias that is the `i`th type parameter of `trait`. Type aliases
|
||||
* are numbered consecutively but in arbitrary order, starting from the index
|
||||
* following the last ordinary type parameter.
|
||||
*/
|
||||
predicate traitAliasIndex(Trait trait, int i, TypeAlias typeAlias) {
|
||||
typeAlias =
|
||||
rank[i + 1 - trait.getNumberOfGenericParams()](TypeAlias alias |
|
||||
trait.(TraitItemNode).getADescendant() = alias
|
||||
|
|
||||
alias order by idOfTypeParameterAstNode(alias)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A type parameter corresponding to an associated type in a trait.
|
||||
*
|
||||
@@ -341,8 +324,6 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara
|
||||
/** Gets the trait that contains this associated type declaration. */
|
||||
TraitItemNode getTrait() { result.getAnAssocItem() = typeAlias }
|
||||
|
||||
int getIndex() { traitAliasIndex(_, result, typeAlias) }
|
||||
|
||||
override string toString() { result = typeAlias.getName().getText() }
|
||||
|
||||
override Location getLocation() { result = typeAlias.getLocation() }
|
||||
|
||||
@@ -10,6 +10,7 @@ private import codeql.typeinference.internal.TypeInference
|
||||
private import codeql.rust.frameworks.stdlib.Stdlib
|
||||
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
|
||||
private import codeql.rust.elements.Call
|
||||
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
|
||||
|
||||
class Type = T::Type;
|
||||
|
||||
@@ -353,19 +354,6 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any of the types mentioned in `path` that corresponds to the type
|
||||
* parameter `tp`.
|
||||
*/
|
||||
private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) {
|
||||
exists(int i |
|
||||
result = path.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
|
||||
tp = resolvePath(path).getTypeParam(pragma[only_bind_into](i))
|
||||
)
|
||||
or
|
||||
result = getExplicitTypeArgMention(path.getQualifier(), tp)
|
||||
}
|
||||
|
||||
/**
|
||||
* A matching configuration for resolving types of struct expressions
|
||||
* like `Foo { bar = baz }`.
|
||||
@@ -452,9 +440,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
|
||||
class AccessPosition = DeclarationPosition;
|
||||
|
||||
class Access extends StructExpr {
|
||||
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
result = getExplicitTypeArgMention(this.getPath(), apos.asTypeParam()).resolveTypeAt(path)
|
||||
}
|
||||
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() }
|
||||
|
||||
AstNode getNodeAt(AccessPosition apos) {
|
||||
result = this.getFieldExpr(apos.asFieldPos()).getExpr()
|
||||
@@ -465,6 +451,16 @@ private module StructExprMatchingInput implements MatchingInputSig {
|
||||
|
||||
Type getInferredType(AccessPosition apos, TypePath path) {
|
||||
result = inferType(this.getNodeAt(apos), path)
|
||||
or
|
||||
// The struct type is supplied explicitly as a type qualifier, e.g.
|
||||
// `Foo<Bar>::Variant { ... }`.
|
||||
apos.isStructPos() and
|
||||
exists(Path p, TypeMention tm |
|
||||
p = this.getPath() and
|
||||
if resolvePath(p) instanceof Variant then tm = p.getQualifier() else tm = p
|
||||
|
|
||||
result = tm.resolveTypeAt(path)
|
||||
)
|
||||
}
|
||||
|
||||
Declaration getTarget() { result = resolvePath(this.getPath()) }
|
||||
@@ -537,7 +533,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
|
||||
abstract Type getReturnType(TypePath path);
|
||||
|
||||
final Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
|
||||
Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
|
||||
result = this.getParameterType(dpos, path)
|
||||
or
|
||||
dpos.isReturn() and
|
||||
@@ -545,7 +541,16 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
}
|
||||
}
|
||||
|
||||
private class TupleStructDecl extends Declaration, Struct {
|
||||
abstract private class TupleDeclaration extends Declaration {
|
||||
override Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
|
||||
result = super.getDeclaredType(dpos, path)
|
||||
or
|
||||
dpos.isSelf() and
|
||||
result = this.getReturnType(path)
|
||||
}
|
||||
}
|
||||
|
||||
private class TupleStructDecl extends TupleDeclaration, Struct {
|
||||
TupleStructDecl() { this.isTuple() }
|
||||
|
||||
override TypeParameter getTypeParameter(TypeParameterPosition ppos) {
|
||||
@@ -568,7 +573,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
}
|
||||
}
|
||||
|
||||
private class TupleVariantDecl extends Declaration, Variant {
|
||||
private class TupleVariantDecl extends TupleDeclaration, Variant {
|
||||
TupleVariantDecl() { this.isTuple() }
|
||||
|
||||
override TypeParameter getTypeParameter(TypeParameterPosition ppos) {
|
||||
@@ -597,13 +602,13 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
override TypeParameter getTypeParameter(TypeParameterPosition ppos) {
|
||||
typeParamMatchPosition(this.getGenericParamList().getATypeParam(), result, ppos)
|
||||
or
|
||||
exists(TraitItemNode trait | this = trait.getAnAssocItem() |
|
||||
typeParamMatchPosition(trait.getTypeParam(_), result, ppos)
|
||||
exists(ImplOrTraitItemNode i | this = i.getAnAssocItem() |
|
||||
typeParamMatchPosition(i.getTypeParam(_), result, ppos)
|
||||
or
|
||||
ppos.isImplicit() and result = TSelfTypeParameter(trait)
|
||||
ppos.isImplicit() and result = TSelfTypeParameter(i)
|
||||
or
|
||||
ppos.isImplicit() and
|
||||
result.(AssociatedTypeTypeParameter).getTrait() = trait
|
||||
result.(AssociatedTypeTypeParameter).getTrait() = i
|
||||
)
|
||||
or
|
||||
ppos.isImplicit() and
|
||||
@@ -625,6 +630,33 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
or
|
||||
result = inferImplicitSelfType(self, path) // `self` parameter without type annotation
|
||||
)
|
||||
or
|
||||
// For associated functions, we may also need to match type arguments against
|
||||
// the `Self` type. For example, in
|
||||
//
|
||||
// ```rust
|
||||
// struct Foo<T>(T);
|
||||
//
|
||||
// impl<T : Default> Foo<T> {
|
||||
// fn default() -> Self {
|
||||
// Foo(Default::default())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Foo::<i32>::default();
|
||||
// ```
|
||||
//
|
||||
// we need to match `i32` against the type parameter `T` of the `impl` block.
|
||||
exists(ImplOrTraitItemNode i |
|
||||
this = i.getAnAssocItem() and
|
||||
dpos.isSelf() and
|
||||
not this.getParamList().hasSelfParam()
|
||||
|
|
||||
result = TSelfTypeParameter(i) and
|
||||
path.isEmpty()
|
||||
or
|
||||
result = resolveImplSelfType(i, path)
|
||||
)
|
||||
}
|
||||
|
||||
private Type resolveRetType(TypePath path) {
|
||||
@@ -670,9 +702,14 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl
|
||||
|
||||
final class Access extends Call {
|
||||
pragma[nomagic]
|
||||
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
exists(TypeMention arg | result = arg.resolveTypeAt(path) |
|
||||
arg = getExplicitTypeArgMention(CallExprImpl::getFunctionPath(this), apos.asTypeParam())
|
||||
exists(Path p, int i |
|
||||
p = CallExprImpl::getFunctionPath(this) and
|
||||
arg = p.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
|
||||
apos.asTypeParam() = resolvePath(p).getTypeParam(pragma[only_bind_into](i))
|
||||
)
|
||||
or
|
||||
arg =
|
||||
this.(MethodCallExpr).getGenericArgList().getTypeArg(apos.asMethodTypeArgumentPosition())
|
||||
@@ -696,6 +733,14 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
|
||||
Type getInferredType(AccessPosition apos, TypePath path) {
|
||||
result = inferType(this.getNodeAt(apos), path)
|
||||
or
|
||||
// The `Self` type is supplied explicitly as a type qualifier, e.g. `Foo::<Bar>::baz()`
|
||||
apos = TArgumentAccessPosition(CallImpl::TSelfArgumentPosition(), false, false) and
|
||||
exists(PathExpr pe, TypeMention tm |
|
||||
pe = this.(CallExpr).getFunction() and
|
||||
tm = pe.getPath().getQualifier() and
|
||||
result = tm.resolveTypeAt(path)
|
||||
)
|
||||
}
|
||||
|
||||
Declaration getTarget() {
|
||||
@@ -1110,12 +1155,7 @@ private Type inferForLoopExprType(AstNode n, TypePath path) {
|
||||
}
|
||||
|
||||
final class MethodCall extends Call {
|
||||
MethodCall() {
|
||||
exists(this.getReceiver()) and
|
||||
// We want the method calls that don't have a path to a concrete method in
|
||||
// an impl block. We need to exclude calls like `MyType::my_method(..)`.
|
||||
(this instanceof CallExpr implies exists(this.getTrait()))
|
||||
}
|
||||
MethodCall() { exists(this.getReceiver()) }
|
||||
|
||||
/** Gets the type of the receiver of the method call at `path`. */
|
||||
Type getTypeAt(TypePath path) {
|
||||
@@ -1582,19 +1622,51 @@ private module Debug {
|
||||
result = resolveMethodCallTarget(mce)
|
||||
}
|
||||
|
||||
predicate debugInferImplicitSelfType(SelfParam self, TypePath path, Type t) {
|
||||
self = getRelevantLocatable() and
|
||||
t = inferImplicitSelfType(self, path)
|
||||
}
|
||||
|
||||
predicate debugInferCallExprBaseType(AstNode n, TypePath path, Type t) {
|
||||
n = getRelevantLocatable() and
|
||||
t = inferCallExprBaseType(n, path)
|
||||
}
|
||||
|
||||
predicate debugTypeMention(TypeMention tm, TypePath path, Type type) {
|
||||
tm = getRelevantLocatable() and
|
||||
tm.resolveTypeAt(path) = type
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private int countTypes(AstNode n, TypePath path, Type t) {
|
||||
private int countTypesAtPath(AstNode n, TypePath path, Type t) {
|
||||
t = inferType(n, path) and
|
||||
result = strictcount(Type t0 | t0 = inferType(n, path))
|
||||
}
|
||||
|
||||
predicate maxTypes(AstNode n, TypePath path, Type t, int c) {
|
||||
c = countTypes(n, path, t) and
|
||||
c = max(countTypes(_, _, _))
|
||||
c = countTypesAtPath(n, path, t) and
|
||||
c = max(countTypesAtPath(_, _, _))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typePathLength(AstNode n, TypePath path, Type t, int len) {
|
||||
t = inferType(n, path) and
|
||||
len = path.length()
|
||||
}
|
||||
|
||||
predicate maxTypePath(AstNode n, TypePath path, Type t, int len) {
|
||||
typePathLength(n, path, t, len) and
|
||||
len = max(int i | typePathLength(_, _, _, i))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private int countTypePaths(AstNode n, TypePath path, Type t) {
|
||||
t = inferType(n, path) and
|
||||
result = strictcount(TypePath path0, Type t0 | t0 = inferType(n, path0))
|
||||
}
|
||||
|
||||
predicate maxTypePaths(AstNode n, TypePath path, Type t, int c) {
|
||||
c = countTypePaths(n, path, t) and
|
||||
c = max(countTypePaths(_, _, _))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import TypeInference::Consistency
|
||||
|
||||
query predicate illFormedTypeMention(TypeMention tm) {
|
||||
Consistency::illFormedTypeMention(tm) and
|
||||
not tm instanceof PathTypeReprMention and // avoid overlap with `PathTypeMention`
|
||||
// Only include inconsistencies in the source, as we otherwise get
|
||||
// inconsistencies from library code in every project.
|
||||
tm.fromSource()
|
||||
|
||||
@@ -7,65 +7,60 @@ private import TypeInference
|
||||
|
||||
/** An AST node that may mention a type. */
|
||||
abstract class TypeMention extends AstNode {
|
||||
/** Gets the `i`th type argument mention, if any. */
|
||||
abstract TypeMention getTypeArgument(int i);
|
||||
/** Gets the type at `path` that this mention resolves to, if any. */
|
||||
abstract Type resolveTypeAt(TypePath path);
|
||||
|
||||
/** Gets the type that this node resolves to, if any. */
|
||||
abstract Type resolveType();
|
||||
|
||||
/** Gets the sub mention at `path`. */
|
||||
pragma[nomagic]
|
||||
TypeMention getMentionAt(TypePath path) {
|
||||
path.isEmpty() and
|
||||
result = this
|
||||
or
|
||||
exists(int i, TypeParameter tp, TypeMention arg, TypePath suffix |
|
||||
arg = this.getTypeArgument(pragma[only_bind_into](i)) and
|
||||
result = arg.getMentionAt(suffix) and
|
||||
path = TypePath::cons(tp, suffix) and
|
||||
tp = this.resolveType().getTypeParameter(pragma[only_bind_into](i))
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the type that the sub mention at `path` resolves to, if any. */
|
||||
Type resolveTypeAt(TypePath path) { result = this.getMentionAt(path).resolveType() }
|
||||
final Type resolveType() { result = this.resolveTypeAt(TypePath::nil()) }
|
||||
}
|
||||
|
||||
class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr {
|
||||
override TypeMention getTypeArgument(int i) { result = super.getElementTypeRepr() and i = 0 }
|
||||
|
||||
override Type resolveType() { result = TArrayType() }
|
||||
override Type resolveTypeAt(TypePath path) {
|
||||
path.isEmpty() and
|
||||
result = TArrayType()
|
||||
or
|
||||
exists(TypePath suffix |
|
||||
result = super.getElementTypeRepr().(TypeMention).resolveTypeAt(suffix) and
|
||||
path = TypePath::cons(TArrayTypeParameter(), suffix)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class RefTypeReprMention extends TypeMention instanceof RefTypeRepr {
|
||||
override TypeMention getTypeArgument(int i) { result = super.getTypeRepr() and i = 0 }
|
||||
|
||||
override Type resolveType() { result = TRefType() }
|
||||
override Type resolveTypeAt(TypePath path) {
|
||||
path.isEmpty() and
|
||||
result = TRefType()
|
||||
or
|
||||
exists(TypePath suffix |
|
||||
result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
|
||||
path = TypePath::cons(TRefTypeParameter(), suffix)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class SliceTypeReprMention extends TypeMention instanceof SliceTypeRepr {
|
||||
override TypeMention getTypeArgument(int i) { result = super.getTypeRepr() and i = 0 }
|
||||
|
||||
override Type resolveType() { result = TSliceType() }
|
||||
override Type resolveTypeAt(TypePath path) {
|
||||
path.isEmpty() and
|
||||
result = TSliceType()
|
||||
or
|
||||
exists(TypePath suffix |
|
||||
result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
|
||||
path = TypePath::cons(TSliceTypeParameter(), suffix)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
|
||||
Path path;
|
||||
ItemNode resolved;
|
||||
class PathTypeMention extends TypeMention, Path {
|
||||
TypeItemNode resolved;
|
||||
|
||||
PathTypeReprMention() {
|
||||
path = super.getPath() and
|
||||
// NOTE: This excludes unresolvable paths which is intentional as these
|
||||
// don't add value to the type inference anyway.
|
||||
resolved = resolvePath(path)
|
||||
}
|
||||
PathTypeMention() { resolved = resolvePath(this) }
|
||||
|
||||
ItemNode getResolved() { result = resolved }
|
||||
|
||||
pragma[nomagic]
|
||||
private TypeAlias getResolvedTraitAlias(string name) {
|
||||
exists(TraitItemNode trait |
|
||||
trait = resolvePath(path) and
|
||||
trait = resolved and
|
||||
result = trait.getAnAssocItem() and
|
||||
name = result.getName().getText()
|
||||
)
|
||||
@@ -73,7 +68,7 @@ class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
|
||||
|
||||
pragma[nomagic]
|
||||
private TypeRepr getAssocTypeArg(string name) {
|
||||
result = path.getSegment().getGenericArgList().getAssocTypeArg(name)
|
||||
result = this.getSegment().getGenericArgList().getAssocTypeArg(name)
|
||||
}
|
||||
|
||||
/** Gets the type argument for the associated type `alias`, if any. */
|
||||
@@ -85,13 +80,8 @@ class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
|
||||
)
|
||||
}
|
||||
|
||||
override TypeMention getTypeArgument(int i) {
|
||||
result = path.getSegment().getGenericArgList().getTypeArg(i)
|
||||
or
|
||||
// If a type argument is not given in the path, then we use the default for
|
||||
// the type parameter if one exists for the type.
|
||||
not exists(path.getSegment().getGenericArgList().getTypeArg(i)) and
|
||||
result = this.resolveType().getTypeParameterDefault(i)
|
||||
private TypeMention getPositionalTypeArgument0(int i) {
|
||||
result = this.getSegment().getGenericArgList().getTypeArg(i)
|
||||
or
|
||||
// `Self` paths inside `impl` blocks have implicit type arguments that are
|
||||
// the type parameters of the `impl` block. For example, in
|
||||
@@ -106,35 +96,20 @@ class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
|
||||
//
|
||||
// the `Self` return type is shorthand for `Foo<T>`.
|
||||
exists(ImplItemNode node |
|
||||
path = node.getASelfPath() and
|
||||
this = node.getASelfPath() and
|
||||
result = node.(ImplItemNode).getSelfPath().getSegment().getGenericArgList().getTypeArg(i)
|
||||
)
|
||||
}
|
||||
|
||||
private TypeMention getPositionalTypeArgument(int i) {
|
||||
result = this.getPositionalTypeArgument0(i)
|
||||
or
|
||||
// If `path` is the trait of an `impl` block then any associated types
|
||||
// defined in the `impl` block are type arguments to the trait.
|
||||
//
|
||||
// For instance, for a trait implementation like this
|
||||
// ```rust
|
||||
// impl MyTrait for MyType {
|
||||
// ^^^^^^^ path
|
||||
// type AssociatedType = i64
|
||||
// ^^^ result
|
||||
// // ...
|
||||
// }
|
||||
// ```
|
||||
// the rhs. of the type alias is a type argument to the trait.
|
||||
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias |
|
||||
path = impl.getTraitPath() and
|
||||
param.getTrait() = resolved and
|
||||
alias = impl.getASuccessor(param.getTypeAlias().getName().getText()) and
|
||||
result = alias.getTypeRepr() and
|
||||
param.getIndex() = i
|
||||
)
|
||||
or
|
||||
exists(TypeAlias alias |
|
||||
result = this.getAnAssocTypeArgument(alias) and
|
||||
traitAliasIndex(_, i, alias)
|
||||
)
|
||||
// If a type argument is not given in the path, then we use the default for
|
||||
// the type parameter if one exists for the type.
|
||||
not exists(this.getPositionalTypeArgument0(i)) and
|
||||
result = this.resolveType().getTypeParameterDefault(i) and
|
||||
// Defaults only apply to type mentions in type annotations
|
||||
this = any(PathTypeRepr ptp).getPath().getQualifier*()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,25 +117,25 @@ class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
|
||||
* resulting type at `typePath`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Type aliasResolveTypeAt(TypePath typePath) {
|
||||
private Type aliasResolveTypeAt(TypePath typePath) {
|
||||
exists(TypeAlias alias, TypeMention rhs | alias = resolved and rhs = alias.getTypeRepr() |
|
||||
result = rhs.resolveTypeAt(typePath) and
|
||||
not result = pathGetTypeParameter(alias, _)
|
||||
or
|
||||
exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i |
|
||||
tp = rhs.resolveTypeAt(prefix) and
|
||||
tp = pathGetTypeParameter(alias, i) and
|
||||
arg = path.getSegment().getGenericArgList().getTypeArg(i) and
|
||||
tp = pathGetTypeParameter(alias, pragma[only_bind_into](i)) and
|
||||
arg = this.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
|
||||
result = arg.resolveTypeAt(suffix) and
|
||||
typePath = prefix.append(suffix)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override Type resolveType() {
|
||||
result = this.aliasResolveTypeAt(TypePath::nil())
|
||||
override Type resolveTypeAt(TypePath typePath) {
|
||||
result = this.aliasResolveTypeAt(typePath)
|
||||
or
|
||||
not exists(resolved.(TypeAlias).getTypeRepr()) and
|
||||
typePath.isEmpty() and
|
||||
(
|
||||
result = TStruct(resolved)
|
||||
or
|
||||
@@ -169,33 +144,72 @@ class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
|
||||
exists(TraitItemNode trait | trait = resolved |
|
||||
// If this is a `Self` path, then it resolves to the implicit `Self`
|
||||
// type parameter, otherwise it is a trait bound.
|
||||
if super.getPath() = trait.getASelfPath()
|
||||
if this = trait.getASelfPath()
|
||||
then result = TSelfTypeParameter(trait)
|
||||
else result = TTrait(trait)
|
||||
)
|
||||
or
|
||||
result = TTypeParamTypeParameter(resolved)
|
||||
or
|
||||
exists(TypeAlias alias | alias = resolved |
|
||||
result.(AssociatedTypeTypeParameter).getTypeAlias() = alias
|
||||
or
|
||||
result = alias.getTypeRepr().(TypeMention).resolveType()
|
||||
result = TAssociatedTypeTypeParameter(resolved)
|
||||
)
|
||||
or
|
||||
not exists(resolved.(TypeAlias).getTypeRepr()) and
|
||||
exists(TypeParameter tp, TypeMention arg, TypePath suffix |
|
||||
result = arg.resolveTypeAt(suffix) and
|
||||
typePath = TypePath::cons(tp, suffix)
|
||||
|
|
||||
exists(int i |
|
||||
arg = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and
|
||||
tp = this.resolveType().getTypeParameter(pragma[only_bind_into](i))
|
||||
)
|
||||
or
|
||||
exists(TypeAlias alias |
|
||||
arg = this.getAnAssocTypeArgument(alias) and
|
||||
tp = TAssociatedTypeTypeParameter(alias)
|
||||
)
|
||||
or
|
||||
// If `path` is the trait of an `impl` block then any associated types
|
||||
// defined in the `impl` block are type arguments to the trait.
|
||||
//
|
||||
// For instance, for a trait implementation like this
|
||||
// ```rust
|
||||
// impl MyTrait for MyType {
|
||||
// ^^^^^^^ path
|
||||
// type AssociatedType = i64
|
||||
// ^^^ result
|
||||
// // ...
|
||||
// }
|
||||
// ```
|
||||
// the rhs. of the type alias is a type argument to the trait.
|
||||
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias, string name |
|
||||
this = impl.getTraitPath() and
|
||||
param.getTrait() = resolved and
|
||||
name = param.getTypeAlias().getName().getText() and
|
||||
alias = impl.getASuccessor(pragma[only_bind_into](name)) and
|
||||
arg = alias.getTypeRepr() and
|
||||
tp =
|
||||
TAssociatedTypeTypeParameter(resolved
|
||||
.(TraitItemNode)
|
||||
.getAssocItem(pragma[only_bind_into](name)))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override Type resolveTypeAt(TypePath typePath) {
|
||||
result = this.aliasResolveTypeAt(typePath)
|
||||
or
|
||||
not exists(resolved.(TypeAlias).getTypeRepr()) and
|
||||
result = super.resolveTypeAt(typePath)
|
||||
}
|
||||
class PathTypeReprMention extends TypeMention, PathTypeRepr {
|
||||
private PathTypeMention path;
|
||||
|
||||
PathTypeReprMention() { path = this.getPath() }
|
||||
|
||||
override Type resolveTypeAt(TypePath typePath) { result = path.resolveTypeAt(typePath) }
|
||||
}
|
||||
|
||||
class ImplTraitTypeReprMention extends TypeMention instanceof ImplTraitTypeRepr {
|
||||
override TypeMention getTypeArgument(int i) { none() }
|
||||
|
||||
override ImplTraitType resolveType() { result.getImplTraitTypeRepr() = this }
|
||||
override Type resolveTypeAt(TypePath typePath) {
|
||||
typePath.isEmpty() and
|
||||
result.(ImplTraitType).getImplTraitTypeRepr() = this
|
||||
}
|
||||
}
|
||||
|
||||
private TypeParameter pathGetTypeParameter(TypeAlias alias, int i) {
|
||||
@@ -205,30 +219,29 @@ private TypeParameter pathGetTypeParameter(TypeAlias alias, int i) {
|
||||
// Used to represent implicit `Self` type arguments in traits and `impl` blocks,
|
||||
// see `PathMention` for details.
|
||||
class TypeParamMention extends TypeMention instanceof TypeParam {
|
||||
override TypeMention getTypeArgument(int i) { none() }
|
||||
|
||||
override Type resolveType() { result = TTypeParamTypeParameter(this) }
|
||||
}
|
||||
|
||||
// Used to represent implicit type arguments for associated types in traits.
|
||||
class TypeAliasMention extends TypeMention instanceof TypeAlias {
|
||||
private Type t;
|
||||
|
||||
TypeAliasMention() { t = TAssociatedTypeTypeParameter(this) }
|
||||
|
||||
override TypeMention getTypeArgument(int i) { none() }
|
||||
|
||||
override Type resolveType() { result = t }
|
||||
override Type resolveTypeAt(TypePath typePath) {
|
||||
typePath.isEmpty() and
|
||||
result = TTypeParamTypeParameter(this)
|
||||
}
|
||||
}
|
||||
|
||||
class TraitMention extends TypeMention instanceof TraitItemNode {
|
||||
override TypeMention getTypeArgument(int i) {
|
||||
result = super.getTypeParam(i)
|
||||
override Type resolveTypeAt(TypePath typePath) {
|
||||
typePath.isEmpty() and
|
||||
result = TTrait(this)
|
||||
or
|
||||
traitAliasIndex(this, i, result)
|
||||
exists(TypeAlias alias |
|
||||
alias = super.getAnAssocItem() and
|
||||
typePath = TypePath::singleton(result) and
|
||||
result = TAssociatedTypeTypeParameter(alias)
|
||||
)
|
||||
or
|
||||
exists(TypeParam tp |
|
||||
tp = super.getTypeParam(_) and
|
||||
typePath = TypePath::singleton(result) and
|
||||
result = TTypeParamTypeParameter(tp)
|
||||
)
|
||||
}
|
||||
|
||||
override Type resolveType() { result = TTrait(this) }
|
||||
}
|
||||
|
||||
// NOTE: Since the implicit type parameter for the self type parameter never
|
||||
@@ -242,7 +255,8 @@ class SelfTypeParameterMention extends TypeMention instanceof Name {
|
||||
|
||||
Trait getTrait() { result = trait }
|
||||
|
||||
override Type resolveType() { result = TSelfTypeParameter(trait) }
|
||||
|
||||
override TypeMention getTypeArgument(int i) { none() }
|
||||
override Type resolveTypeAt(TypePath typePath) {
|
||||
typePath.isEmpty() and
|
||||
result = TSelfTypeParameter(trait)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
multipleCallTargets
|
||||
| proc_macro.rs:6:18:6:61 | ...::from(...) |
|
||||
| proc_macro.rs:7:15:7:58 | ...::from(...) |
|
||||
| proc_macro.rs:15:5:17:5 | ...::new(...) |
|
||||
| proc_macro.rs:16:12:16:16 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:22:15:22:58 | ...::from(...) |
|
||||
| proc_macro.rs:25:5:28:5 | ...::new(...) |
|
||||
| proc_macro.rs:26:10:26:12 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:27:10:27:16 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:38:15:38:64 | ...::from(...) |
|
||||
| proc_macro.rs:41:5:49:5 | ...::new(...) |
|
||||
| proc_macro.rs:41:5:49:5 | ...::new(...) |
|
||||
| proc_macro.rs:41:5:49:5 | ...::new(...) |
|
||||
| proc_macro.rs:41:5:49:5 | ...::new(...) |
|
||||
| proc_macro.rs:42:16:42:26 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:44:27:44:30 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:46:18:46:28 | ...::to_tokens(...) |
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
multipleCallTargets
|
||||
| main.rs:118:9:118:11 | f(...) |
|
||||
| proc_macro.rs:6:16:6:59 | ...::from(...) |
|
||||
| proc_macro.rs:7:19:7:62 | ...::from(...) |
|
||||
| proc_macro.rs:9:5:11:5 | ...::new(...) |
|
||||
| proc_macro.rs:10:10:10:12 | ...::to_tokens(...) |
|
||||
multiplePathResolutions
|
||||
| main.rs:626:3:626:12 | proc_macro |
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
multipleCallTargets
|
||||
| dereference.rs:61:15:61:24 | e1.deref() |
|
||||
| main.rs:2076:13:2076:31 | ...::from(...) |
|
||||
| main.rs:2077:13:2077:31 | ...::from(...) |
|
||||
| main.rs:2078:13:2078:31 | ...::from(...) |
|
||||
| main.rs:2084:13:2084:31 | ...::from(...) |
|
||||
| main.rs:2085:13:2085:31 | ...::from(...) |
|
||||
| main.rs:2086:13:2086:31 | ...::from(...) |
|
||||
| main.rs:2122:21:2122:43 | ...::from(...) |
|
||||
| main.rs:2087:13:2087:31 | ...::from(...) |
|
||||
| main.rs:2088:13:2088:31 | ...::from(...) |
|
||||
| main.rs:2094:13:2094:31 | ...::from(...) |
|
||||
| main.rs:2095:13:2095:31 | ...::from(...) |
|
||||
| main.rs:2096:13:2096:31 | ...::from(...) |
|
||||
| main.rs:2132:21:2132:43 | ...::from(...) |
|
||||
|
||||
@@ -860,7 +860,7 @@ mod method_supertraits {
|
||||
if 3 > 2 { // $ method=gt
|
||||
self.m1() // $ method=MyTrait1::m1
|
||||
} else {
|
||||
Self::m1(self)
|
||||
Self::m1(self) // $ method=MyTrait1::m1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -874,7 +874,7 @@ mod method_supertraits {
|
||||
if 3 > 2 { // $ method=gt
|
||||
self.m2().a // $ method=m2 $ fieldof=MyThing
|
||||
} else {
|
||||
Self::m2(self).a // $ fieldof=MyThing
|
||||
Self::m2(self).a // $ method=m2 fieldof=MyThing
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1030,6 +1030,14 @@ mod type_aliases {
|
||||
println!("{:?}", x);
|
||||
}
|
||||
|
||||
struct S4<T41, T42>(T41, T42);
|
||||
|
||||
struct S5<T5>(T5);
|
||||
|
||||
type S6<T6> = S4<T6, S5<T6>>;
|
||||
|
||||
type S7<T7> = Result<S6<T7>, S1>;
|
||||
|
||||
pub fn f() {
|
||||
// Type can be inferred from the constructor
|
||||
let p1: MyPair = PairOption::PairBoth(S1, S2);
|
||||
@@ -1048,6 +1056,8 @@ mod type_aliases {
|
||||
println!("{:?}", p3);
|
||||
|
||||
g(PairOption::PairSnd(PairOption::PairSnd(S3)));
|
||||
|
||||
let x: S7<S2>; // $ type=x:Result $ type=x:E.S1 $ type=x:T.S4 $ type=x:T.T41.S2 $ type=x:T.T42.S5 $ type=x:T.T42.T5.S2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1091,7 +1101,7 @@ mod option_methods {
|
||||
struct S;
|
||||
|
||||
pub fn f() {
|
||||
let x1 = MyOption::<S>::new(); // $ MISSING: type=x1:T.S
|
||||
let x1 = MyOption::<S>::new(); // $ type=x1:T.S
|
||||
println!("{:?}", x1);
|
||||
|
||||
let mut x2 = MyOption::new();
|
||||
@@ -1110,7 +1120,7 @@ mod option_methods {
|
||||
println!("{:?}", x5.flatten()); // $ method=flatten
|
||||
|
||||
let x6 = MyOption::MySome(MyOption::<S>::MyNone());
|
||||
println!("{:?}", MyOption::<MyOption<S>>::flatten(x6));
|
||||
println!("{:?}", MyOption::<MyOption<S>>::flatten(x6)); // $ method=flatten
|
||||
|
||||
#[rustfmt::skip]
|
||||
let from_if = if 3 > 2 { // $ method=gt
|
||||
@@ -2157,6 +2167,57 @@ mod loops {
|
||||
|
||||
mod dereference;
|
||||
|
||||
mod explicit_type_args {
|
||||
struct S1<T>(T);
|
||||
|
||||
#[derive(Default)]
|
||||
struct S2;
|
||||
|
||||
impl<T: Default> S1<T> {
|
||||
fn assoc_fun() -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
fn default() -> Self {
|
||||
S1(T::default())
|
||||
}
|
||||
|
||||
fn method(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
type S3 = S1<S2>;
|
||||
|
||||
struct S4<T4 = S2>(T4);
|
||||
|
||||
struct S5<T5 = S2> {
|
||||
field: T5,
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
let x1: Option<S1<S2>> = S1::assoc_fun(); // $ type=x1:T.T.S2
|
||||
let x2 = S1::<S2>::assoc_fun(); // $ type=x2:T.T.S2
|
||||
let x3 = S3::assoc_fun(); // $ type=x3:T.T.S2
|
||||
let x4 = S1::<S2>::method(S1::default()); // $ method=method type=x4:T.S2
|
||||
let x5 = S3::method(S1::default()); // $ method=method type=x5:T.S2
|
||||
let x6 = S4::<S2>(Default::default()); // $ type=x6:T4.S2
|
||||
let x7 = S4(S2); // $ type=x7:T4.S2
|
||||
let x8 = S4(0); // $ type=x8:T4.i32
|
||||
let x9 = S4(S2::default()); // $ type=x9:T4.S2
|
||||
let x10 = S5::<S2> // $ type=x10:T5.S2
|
||||
{
|
||||
field: Default::default(),
|
||||
};
|
||||
let x11 = S5 { field: S2 }; // $ type=x11:T5.S2
|
||||
let x12 = S5 { field: 0 }; // $ type=x12:T5.i32
|
||||
let x13 = S5 // $ type=x13:T5.S2
|
||||
{
|
||||
field: S2::default(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
field_access::f();
|
||||
method_impl::f();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
multipleCallTargets
|
||||
| test_cipher.rs:20:27:20:48 | ...::new(...) |
|
||||
| test_cipher.rs:26:27:26:48 | ...::new(...) |
|
||||
| test_cipher.rs:29:27:29:48 | ...::new(...) |
|
||||
| test_cipher.rs:36:30:36:59 | ...::new(...) |
|
||||
| test_cipher.rs:39:30:39:63 | ...::new(...) |
|
||||
| test_cipher.rs:110:23:110:50 | ...::new(...) |
|
||||
Reference in New Issue
Block a user