mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge pull request #21188 from paldepind/rust/self-path-assoc
Rust: Implement type inference for associated types for concrete types
This commit is contained in:
@@ -110,18 +110,15 @@ pragma[nomagic]
|
||||
private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind kind) {
|
||||
item = result.getImmediateParent() and
|
||||
name = result.getName() and
|
||||
// Associated items in `impl` and `trait` blocks are handled elsewhere
|
||||
not (item instanceof ImplOrTraitItemNode and result instanceof AssocItem) and
|
||||
// type parameters are only available inside the declaring item
|
||||
if result instanceof TypeParam
|
||||
then kind.isInternal()
|
||||
else
|
||||
// associated items must always be qualified, also within the declaring
|
||||
// item (using `Self`)
|
||||
if item instanceof ImplOrTraitItemNode and result instanceof AssocItem
|
||||
then kind.isExternal()
|
||||
else
|
||||
if result.isPublic()
|
||||
then kind.isBoth()
|
||||
else kind.isInternal()
|
||||
if result.isPublic()
|
||||
then kind.isBoth()
|
||||
else kind.isInternal()
|
||||
}
|
||||
|
||||
private module UseOption = Option<Use>;
|
||||
@@ -327,30 +324,25 @@ abstract class ItemNode extends Locatable {
|
||||
)
|
||||
)
|
||||
or
|
||||
// a trait has access to the associated items of its supertraits
|
||||
this =
|
||||
any(TraitItemNodeImpl trait |
|
||||
result = trait.resolveABoundCand().getASuccessor(name, kind, useOpt) and
|
||||
kind.isExternalOrBoth() and
|
||||
result instanceof AssocItemNode and
|
||||
not trait.hasAssocItem(name)
|
||||
)
|
||||
result = trait.getAssocItem(name)
|
||||
or
|
||||
// a trait has access to the associated items of its supertraits
|
||||
not trait.hasAssocItem(name) and
|
||||
result = trait.resolveABoundCand().getASuccessor(name).(AssocItemNode)
|
||||
) and
|
||||
kind.isExternal() and
|
||||
useOpt.isNone()
|
||||
or
|
||||
// items made available by an implementation where `this` is the implementing type
|
||||
typeImplEdge(this, _, name, kind, result, useOpt)
|
||||
typeImplEdge(this, _, name, result) and
|
||||
kind.isExternal() and
|
||||
useOpt.isNone()
|
||||
or
|
||||
// trait items with default implementations made available in an implementation
|
||||
exists(ImplItemNodeImpl impl, TraitItemNode trait |
|
||||
this = impl and
|
||||
trait = impl.resolveTraitTyCand() and
|
||||
result = trait.getASuccessor(name, kind, useOpt) and
|
||||
// do not inherit default implementations from super traits; those are inherited by
|
||||
// their `impl` blocks
|
||||
result = trait.getAssocItem(name) and
|
||||
result.(AssocItemNode).hasImplementation() and
|
||||
kind.isExternalOrBoth() and
|
||||
not impl.hasAssocItem(name)
|
||||
)
|
||||
implEdge(this, name, result) and
|
||||
kind.isExternal() and
|
||||
useOpt.isNone()
|
||||
or
|
||||
// type parameters have access to the associated items of its bounds
|
||||
result =
|
||||
@@ -413,14 +405,8 @@ abstract class ItemNode extends Locatable {
|
||||
this instanceof SourceFile and
|
||||
builtin(name, result)
|
||||
or
|
||||
exists(ImplOrTraitItemNode i |
|
||||
name = "Self" and
|
||||
this = i.getAnItemInSelfScope()
|
||||
|
|
||||
result = i.(Trait)
|
||||
or
|
||||
result = i.(ImplItemNodeImpl).resolveSelfTyCand()
|
||||
)
|
||||
name = "Self" and
|
||||
this = result.(ImplOrTraitItemNode).getAnItemInSelfScope()
|
||||
or
|
||||
name = "crate" and
|
||||
this = result.(CrateItemNode).getASourceFile()
|
||||
@@ -755,7 +741,7 @@ abstract class ImplOrTraitItemNode extends ItemNode {
|
||||
}
|
||||
|
||||
/** Gets an associated item belonging to this trait or `impl` block. */
|
||||
abstract AssocItemNode getAnAssocItem();
|
||||
AssocItemNode getAnAssocItem() { result = this.getADescendant() }
|
||||
|
||||
/** Gets the associated item named `name` belonging to this trait or `impl` block. */
|
||||
pragma[nomagic]
|
||||
@@ -807,12 +793,12 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
|
||||
|
||||
TraitItemNode resolveTraitTy() { result = resolvePath(this.getTraitPath()) }
|
||||
|
||||
override AssocItemNode getAnAssocItem() { result = this.getADescendant() }
|
||||
|
||||
override string getName() { result = "(impl)" }
|
||||
|
||||
override Namespace getNamespace() {
|
||||
result.isType() // can be referenced with `Self`
|
||||
// `impl` blocks are referred to using `Self` paths which can appear both as
|
||||
// types and as values (when the implementing type is a tuple-like struct).
|
||||
result.isType() or result.isValue()
|
||||
}
|
||||
|
||||
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
|
||||
@@ -985,6 +971,18 @@ private class ImplItemNodeImpl extends ImplItemNode {
|
||||
}
|
||||
|
||||
TraitItemNodeImpl resolveTraitTyCand() { result = resolvePathCand(this.getTraitPath()) }
|
||||
|
||||
/**
|
||||
* Gets the associated item named `name` in this impl block or the default
|
||||
* inherited from the trait being implemented.
|
||||
*/
|
||||
AssocItemNode getAssocItemOrDefault(string name) {
|
||||
result = this.getAssocItem(name)
|
||||
or
|
||||
not this.hasAssocItem(name) and
|
||||
result = this.resolveTraitTyCand().getAssocItem(name) and
|
||||
result.hasImplementation()
|
||||
}
|
||||
}
|
||||
|
||||
private class StructItemNode extends TypeItemTypeItemNode, ParameterizableItemNode instanceof Struct
|
||||
@@ -1020,8 +1018,6 @@ final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof T
|
||||
|
||||
ItemNode resolveABound() { result = this.resolveBound(_) }
|
||||
|
||||
override AssocItemNode getAnAssocItem() { result = this.getADescendant() }
|
||||
|
||||
override string getName() { result = Trait.super.getName().getText() }
|
||||
|
||||
override Namespace getNamespace() { result.isType() }
|
||||
@@ -1790,7 +1786,17 @@ private module DollarCrateResolution {
|
||||
|
||||
pragma[nomagic]
|
||||
private ItemNode resolvePathCand0(PathExt path, Namespace ns) {
|
||||
result = unqualifiedPathLookup(path, ns, _)
|
||||
exists(ItemNode res |
|
||||
res = unqualifiedPathLookup(path, ns, _) and
|
||||
if
|
||||
// `Self` paths that are not used as qualifiers (for instance `Self` in
|
||||
// `fn(..) -> Self`) should resolve to the type being implemented.
|
||||
not any(PathExt parent).getQualifier() = path and
|
||||
isUnqualifiedSelfPath(path) and
|
||||
res instanceof ImplItemNode
|
||||
then result = res.(ImplItemNodeImpl).resolveSelfTyCand()
|
||||
else result = res
|
||||
)
|
||||
or
|
||||
DollarCrateResolution::resolveDollarCrate(path, result) and
|
||||
ns = result.getNamespace()
|
||||
@@ -1852,35 +1858,12 @@ private predicate checkQualifiedVisibility(
|
||||
not i instanceof TypeParam
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isImplSelfQualifiedPath(
|
||||
ImplItemNode impl, PathExt qualifier, PathExt path, string name
|
||||
) {
|
||||
qualifier = impl.getASelfPath() and
|
||||
qualifier = path.getQualifier() and
|
||||
name = path.getText()
|
||||
}
|
||||
|
||||
private ItemNode resolveImplSelfQualified(PathExt qualifier, PathExt path, Namespace ns) {
|
||||
exists(ImplItemNode impl, string name |
|
||||
isImplSelfQualifiedPath(impl, qualifier, path, name) and
|
||||
result = impl.getAssocItem(name) and
|
||||
ns = result.getNamespace()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item that `path` resolves to in `ns` when `qualifier` is the
|
||||
* qualifier of `path` and `qualifier` resolves to `q`, if any.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private ItemNode resolvePathCandQualified(PathExt qualifier, ItemNode q, PathExt path, Namespace ns) {
|
||||
// Special case for `Self::Assoc`; this always refers to the associated
|
||||
// item in the enclosing `impl` block, if available.
|
||||
q = resolvePathCandQualifier(qualifier, path, _) and
|
||||
result = resolveImplSelfQualified(qualifier, path, ns)
|
||||
or
|
||||
not exists(resolveImplSelfQualified(qualifier, path, ns)) and
|
||||
exists(string name, SuccessorKind kind, UseOption useOpt |
|
||||
q = resolvePathCandQualifier(qualifier, path, name) and
|
||||
result = getASuccessor(q, name, ns, kind, useOpt) and
|
||||
@@ -1940,6 +1923,37 @@ private predicate macroExportEdge(CrateItemNode crate, string name, MacroItemNod
|
||||
name = macro.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Self` path inside `impl` might refer to a function named `name`
|
||||
* from another impl block.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate relevantSelfFunctionName(ImplItemNodeImpl impl, string name) {
|
||||
any(Path path | path.getQualifier() = impl.getASelfPath()).getText() = name and
|
||||
not impl.hasAssocItem(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `impl` has a `node` available externally at `name`.
|
||||
*
|
||||
* Since `Self` in an impl block resolves to the impl block, this corresponds to
|
||||
* the items that should be available on `Self` within the `impl` block.
|
||||
*/
|
||||
private predicate implEdge(ImplItemNodeImpl impl, string name, ItemNode node) {
|
||||
node = impl.getAssocItemOrDefault(name)
|
||||
or
|
||||
// Associated types from the implemented trait are available on `Self`.
|
||||
not impl.hasAssocItem(name) and
|
||||
node = impl.resolveTraitTyCand().getASuccessor(name).(TypeAliasItemNode)
|
||||
or
|
||||
// Items available on the implementing type are available on `Self`. We only
|
||||
// add these edges when they are relevant. If a type has `n` impl blocks with
|
||||
// `m` functions each, we would otherwise end up always constructing something
|
||||
// proportional to `O(n * m)`.
|
||||
relevantSelfFunctionName(impl, name) and
|
||||
node = impl.resolveSelfTyCand().getASuccessor(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if item `i` contains a `mod` or `extern crate` definition that
|
||||
* makes the macro `macro` named `name` available using a `#[macro_use]`
|
||||
@@ -2009,9 +2023,10 @@ private ItemNode resolvePathCand(PathExt path) {
|
||||
|
||||
/** Get a trait that should be visible when `path` resolves to `node`, if any. */
|
||||
private Trait getResolvePathTraitUsed(PathExt path, AssocItemNode node) {
|
||||
exists(TypeItemNode type, ImplItemNodeImpl impl |
|
||||
node = resolvePathCandQualified(_, type, path, _) and
|
||||
typeImplEdge(type, impl, _, _, node, _) and
|
||||
exists(TypeItemNode type, ItemNode qual, ImplItemNodeImpl impl |
|
||||
node = resolvePathCandQualified(_, qual, path, _) and
|
||||
type = [qual, qual.(ImplItemNodeImpl).resolveSelfTyCand()] and
|
||||
typeImplEdge(type, impl, _, node) and
|
||||
result = impl.resolveTraitTyCand()
|
||||
)
|
||||
}
|
||||
@@ -2179,15 +2194,17 @@ private predicate externCrateEdge(
|
||||
|
||||
/**
|
||||
* Holds if `typeItem` is the implementing type of `impl` and the implementation
|
||||
* makes `assoc` available as `name` at `kind`.
|
||||
* makes `assoc` available as `name`.
|
||||
*/
|
||||
private predicate typeImplEdge(
|
||||
TypeItemNode typeItem, ImplItemNodeImpl impl, string name, SuccessorKind kind,
|
||||
AssocItemNode assoc, UseOption useOpt
|
||||
TypeItemNode typeItem, ImplItemNodeImpl impl, string name, AssocItemNode assoc
|
||||
) {
|
||||
assoc = impl.getAssocItemOrDefault(name) and
|
||||
typeItem = impl.resolveSelfTyCand() and
|
||||
assoc = impl.getASuccessor(name, kind, useOpt) and
|
||||
kind.isExternalOrBoth()
|
||||
// Functions in `impl` blocks are made available on the implementing type
|
||||
// (e.g., `S::fun` is valid) but associated types are not (e.g., `S::Output`
|
||||
// is invalid).
|
||||
not assoc instanceof TypeAlias
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -75,7 +75,7 @@ abstract class Type extends TType {
|
||||
abstract TypeParameter getPositionalTypeParameter(int i);
|
||||
|
||||
/** Gets the default type for the `i`th type parameter, if any. */
|
||||
TypeMention getTypeParameterDefault(int i) { none() }
|
||||
TypeRepr getTypeParameterDefault(int i) { none() }
|
||||
|
||||
/**
|
||||
* Gets a type parameter of this type.
|
||||
@@ -129,7 +129,7 @@ class DataType extends Type, TDataType {
|
||||
result = TTypeParamTypeParameter(typeItem.getGenericParamList().getTypeParam(i))
|
||||
}
|
||||
|
||||
override TypeMention getTypeParameterDefault(int i) {
|
||||
override TypeRepr getTypeParameterDefault(int i) {
|
||||
result = typeItem.getGenericParamList().getTypeParam(i).getDefaultType()
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ class TraitType extends Type, TTrait {
|
||||
result.(SelfTypeParameter).getTrait() = trait
|
||||
}
|
||||
|
||||
override TypeMention getTypeParameterDefault(int i) {
|
||||
override TypeRepr getTypeParameterDefault(int i) {
|
||||
result = trait.getGenericParamList().getTypeParam(i).getDefaultType()
|
||||
}
|
||||
|
||||
|
||||
@@ -134,8 +134,8 @@ class TypePath = M1::TypePath;
|
||||
|
||||
module TypePath = M1::TypePath;
|
||||
|
||||
private module Input2 implements InputSig2<TypeMention> {
|
||||
TypeMention getABaseTypeMention(Type t) { none() }
|
||||
private module Input2 implements InputSig2<PreTypeMention> {
|
||||
PreTypeMention getABaseTypeMention(Type t) { none() }
|
||||
|
||||
Type getATypeParameterConstraint(TypeParameter tp, TypePath path) {
|
||||
exists(TypeMention tm | result = tm.getTypeAt(path) |
|
||||
@@ -158,7 +158,7 @@ private module Input2 implements InputSig2<TypeMention> {
|
||||
* inference module for more information.
|
||||
*/
|
||||
predicate conditionSatisfiesConstraint(
|
||||
TypeAbstraction abs, TypeMention condition, TypeMention constraint, boolean transitive
|
||||
TypeAbstraction abs, PreTypeMention condition, PreTypeMention constraint, boolean transitive
|
||||
) {
|
||||
// `impl` blocks implementing traits
|
||||
transitive = false and
|
||||
@@ -208,7 +208,7 @@ private module Input2 implements InputSig2<TypeMention> {
|
||||
}
|
||||
}
|
||||
|
||||
private module M2 = Make2<TypeMention, Input2>;
|
||||
private module M2 = Make2<PreTypeMention, Input2>;
|
||||
|
||||
import M2
|
||||
|
||||
@@ -1960,7 +1960,7 @@ private module MethodResolution {
|
||||
pragma[nomagic]
|
||||
predicate hasTypeQualifiedCandidate(ImplItemNode impl) {
|
||||
exists(getCallExprTypeQualifier(this, _)) and
|
||||
CallExprImpl::getResolvedFunction(this) = impl.getASuccessor(_)
|
||||
CallExprImpl::getResolvedFunction(this) = impl.getADescendant()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -10,7 +10,11 @@ private import TypeInference::Consistency as Consistency
|
||||
import TypeInference::Consistency
|
||||
|
||||
query predicate illFormedTypeMention(TypeMention tm) {
|
||||
Consistency::illFormedTypeMention(tm) and
|
||||
// NOTE: We do not use `illFormedTypeMention` from the shared library as it is
|
||||
// instantiated with `PreTypeMention` and we are interested in inconsistencies
|
||||
// for `TypeMention`.
|
||||
not exists(tm.getTypeAt(TypePath::nil())) and
|
||||
exists(tm.getLocation()) and
|
||||
// avoid overlap with `PathTypeMention`
|
||||
not tm instanceof PathTypeReprMention and
|
||||
// known limitation for type mentions that would mention an escaping type parameter
|
||||
@@ -27,7 +31,8 @@ query predicate illFormedTypeMention(TypeMention tm) {
|
||||
}
|
||||
|
||||
query predicate nonUniqueCertainType(AstNode n, TypePath path) {
|
||||
Consistency::nonUniqueCertainType(n, path, _)
|
||||
Consistency::nonUniqueCertainType(n, path, _) and
|
||||
n.fromSource() // Only include inconsistencies in the source.
|
||||
}
|
||||
|
||||
int getTypeInferenceInconsistencyCounts(string type) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user