Merge pull request #21172 from paldepind/rust/dyn-abs

Rust: Avoid unnecessary constraint satisfaction
This commit is contained in:
Simon Friis Vindum
2026-01-16 11:32:39 +01:00
committed by GitHub
6 changed files with 94 additions and 55 deletions

View File

@@ -8,6 +8,7 @@
private import rust
private import codeql.rust.internal.PathResolution
private import Type
private import TypeAbstraction
private import TypeMention
private import TypeInference
private import FunctionType

View File

@@ -1,8 +1,9 @@
private import rust
private import codeql.rust.internal.PathResolution
private import TypeInference
private import Type
private import TypeAbstraction
private import TypeMention
private import TypeInference
private newtype TFunctionPosition =
TArgumentFunctionPosition(ArgumentPosition pos) or

View File

@@ -569,58 +569,6 @@ class ImplTraitTypeTypeParameter extends ImplTraitType, TypeParameter {
override TypeParameter getPositionalTypeParameter(int i) { none() }
}
/**
* A type abstraction. I.e., a place in the program where type variables are
* introduced.
*
* Example:
* ```rust
* impl<A, B> Foo<A, B> { }
* // ^^^^^^ a type abstraction
* ```
*/
abstract class TypeAbstraction extends AstNode {
abstract TypeParameter getATypeParameter();
}
final class ImplTypeAbstraction extends TypeAbstraction, Impl {
override TypeParamTypeParameter getATypeParameter() {
result.getTypeParam() = this.getGenericParamList().getATypeParam()
}
}
final class DynTypeAbstraction extends TypeAbstraction, DynTraitTypeRepr {
override TypeParameter getATypeParameter() {
result = any(DynTraitTypeParameter tp | tp.getTrait() = this.getTrait()).getTraitTypeParameter()
}
}
final class TraitTypeAbstraction extends TypeAbstraction, Trait {
override TypeParameter getATypeParameter() {
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
or
result.(AssociatedTypeTypeParameter).getTrait() = this
or
result.(SelfTypeParameter).getTrait() = this
}
}
final class TypeBoundTypeAbstraction extends TypeAbstraction, TypeBound {
override TypeParameter getATypeParameter() { none() }
}
final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name {
SelfTypeBoundTypeAbstraction() { any(TraitTypeAbstraction trait).getName() = this }
override TypeParameter getATypeParameter() { none() }
}
final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeRepr {
override TypeParameter getATypeParameter() {
implTraitTypeParam(this, _, result.(TypeParamTypeParameter).getTypeParam())
}
}
/**
* Holds if `t` is a valid complex [`self` root type][1].
*

View File

@@ -0,0 +1,79 @@
private import rust
private import codeql.rust.elements.internal.generated.Raw
private import codeql.rust.elements.internal.generated.Synth
private import Type
/**
* A type abstraction. I.e., a place in the program where type variables are
* introduced.
*
* Example:
* ```rust
* impl<A, B> Foo<A, B> { }
* // ^^^^^^ a type abstraction
* ```
*/
abstract class TypeAbstraction extends AstNode {
abstract TypeParameter getATypeParameter();
}
final class ImplTypeAbstraction extends TypeAbstraction, Impl {
override TypeParamTypeParameter getATypeParameter() {
result.getTypeParam() = this.getGenericParamList().getATypeParam()
}
}
private predicate idDynTraitTypeRepr(Raw::DynTraitTypeRepr x, Raw::DynTraitTypeRepr y) { x = y }
private predicate idOfDynTraitTypeRepr(Raw::DynTraitTypeRepr x, int y) =
equivalenceRelation(idDynTraitTypeRepr/2)(x, y)
private int idOfDynTraitTypeRepr(DynTraitTypeRepr node) {
idOfDynTraitTypeRepr(Synth::convertAstNodeToRaw(node), result)
}
/** Holds if `dt` is the (arbitrarily chosen) canonical dyn trait type abstraction for `trait`. */
private predicate canonicalDynTraitTypeAbstraction(DynTraitTypeRepr dt) {
exists(Trait trait |
dt = min(DynTraitTypeRepr d | d.getTrait() = trait | d order by idOfDynTraitTypeRepr(d))
)
}
final class DynTypeAbstraction extends TypeAbstraction, DynTraitTypeRepr {
DynTypeAbstraction() {
// We pick a "canonical" `dyn Trait` in order to avoid including multiple
// entries in `conditionSatisfiesConstraint` with the exact same effect when
// `dyn Trait` occurs multiple times for the same trait.
canonicalDynTraitTypeAbstraction(this)
}
override TypeParameter getATypeParameter() {
result = any(DynTraitTypeParameter tp | tp.getTrait() = this.getTrait()).getTraitTypeParameter()
}
}
final class TraitTypeAbstraction extends TypeAbstraction, Trait {
override TypeParameter getATypeParameter() {
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
or
result.(AssociatedTypeTypeParameter).getTrait() = this
or
result.(SelfTypeParameter).getTrait() = this
}
}
final class TypeBoundTypeAbstraction extends TypeAbstraction, TypeBound {
override TypeParameter getATypeParameter() { none() }
}
final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name {
SelfTypeBoundTypeAbstraction() { any(TraitTypeAbstraction trait).getName() = this }
override TypeParameter getATypeParameter() { none() }
}
final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeRepr {
override TypeParamTypeParameter getATypeParameter() {
exists(TImplTraitTypeParameter(this, result.getTypeParam()))
}
}

View File

@@ -5,6 +5,8 @@ private import codeql.util.Option
private import rust
private import codeql.rust.internal.PathResolution
private import Type
private import TypeAbstraction
private import TypeAbstraction as TA
private import Type as T
private import TypeMention
private import codeql.rust.internal.typeinference.DerefChain
@@ -37,7 +39,7 @@ private module Input1 implements InputSig1<Location> {
class TypeParameter = T::TypeParameter;
class TypeAbstraction = T::TypeAbstraction;
class TypeAbstraction = TA::TypeAbstraction;
class TypeArgumentPosition extends TTypeArgumentPosition {
int asMethodTypeArgumentPosition() { this = TMethodTypeArgumentPosition(result) }

View File

@@ -4,6 +4,7 @@ private import rust
private import codeql.rust.internal.PathResolution
private import codeql.rust.frameworks.stdlib.Stdlib
private import Type
private import TypeAbstraction
private import TypeInference
/** An AST node that may mention a type. */
@@ -563,7 +564,14 @@ class DynTypeBoundListMention extends TypeMention instanceof TypeBoundList {
private Trait trait;
DynTypeBoundListMention() {
exists(DynTraitTypeRepr dyn | this = dyn.getTypeBoundList() and trait = dyn.getTrait())
exists(DynTraitTypeRepr dyn |
// We only need this type mention when the `dyn Trait` is a type
// abstraction, that is, when it's "canonical" and used in
// `conditionSatisfiesConstraint`.
dyn instanceof DynTypeAbstraction and
this = dyn.getTypeBoundList() and
trait = dyn.getTrait()
)
}
override Type resolveTypeAt(TypePath path) {