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:
Tom Hvitved
2025-07-04 14:46:02 +02:00
committed by GitHub
12 changed files with 2464 additions and 2191 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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() }

View File

@@ -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(_, _, _))
}
}

View File

@@ -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()

View File

@@ -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)
}
}

View File

@@ -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(...) |

View File

@@ -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 |

View File

@@ -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(...) |

View File

@@ -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();

View File

@@ -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(...) |