Merge pull request #20830 from hvitved/rust/path-resolution-slice-array-builtin

Rust: Model builtin types in path resolution
This commit is contained in:
Tom Hvitved
2025-11-18 14:42:59 +01:00
committed by GitHub
18 changed files with 5614 additions and 5304 deletions

View File

@@ -4,6 +4,7 @@
private import rust private import rust
private import codeql.rust.controlflow.CfgNodes private import codeql.rust.controlflow.CfgNodes
private import codeql.rust.frameworks.stdlib.Builtins
private import DataFlowImpl private import DataFlowImpl
/** /**
@@ -28,7 +29,11 @@ abstract class FieldContent extends Content {
class TupleFieldContent extends FieldContent, TTupleFieldContent { class TupleFieldContent extends FieldContent, TTupleFieldContent {
private TupleField field; private TupleField field;
TupleFieldContent() { this = TTupleFieldContent(field) } TupleFieldContent() {
this = TTupleFieldContent(field) and
// tuples are handled using the special `TupleContent` type
not field = any(TupleType tt).getATupleField()
}
/** Holds if this field belongs to an enum variant. */ /** Holds if this field belongs to an enum variant. */
predicate isVariantField(Variant v, int pos) { field.isVariantField(v, pos) } predicate isVariantField(Variant v, int pos) { field.isVariantField(v, pos) }

View File

@@ -32,10 +32,16 @@ module Impl {
result.getName().getText() = name result.getName().getText() = name
} }
/** Gets a record field, if any. */
StructField getAStructField() { result = this.getStructField(_) }
/** Gets the `i`th tuple field, if any. */ /** Gets the `i`th tuple field, if any. */
pragma[nomagic] pragma[nomagic]
TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) } TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) }
/** Gets a tuple field, if any. */
TupleField getATupleField() { result = this.getTupleField(_) }
/** Holds if this struct uses tuple fields. */ /** Holds if this struct uses tuple fields. */
pragma[nomagic] pragma[nomagic]
predicate isTuple() { this.getFieldList() instanceof TupleFieldList } predicate isTuple() { this.getFieldList() instanceof TupleFieldList }

View File

@@ -136,3 +136,36 @@ class F32 extends FloatingPointTypeImpl {
class F64 extends FloatingPointTypeImpl { class F64 extends FloatingPointTypeImpl {
F64() { this.getName() = "f64" } F64() { this.getName() = "f64" }
} }
/** The builtin slice type `[T]`. */
class SliceType extends BuiltinType {
SliceType() { this.getName() = "Slice" }
}
/** The builtin array type `[T; N]`. */
class ArrayType extends BuiltinType {
ArrayType() { this.getName() = "Array" }
}
/** The builtin reference type `&T` or `&mut T`. */
class RefType extends BuiltinType {
RefType() { this.getName() = "Ref" }
}
/** The builtin pointer type `*const T` or `*mut T`. */
class PtrType extends BuiltinType {
PtrType() { this.getName() = "Ptr" }
}
/** A builtin tuple type `(T1, T2, ...)`. */
class TupleType extends BuiltinType {
TupleType() { this.getName().matches("Tuple%") }
/** Gets the arity of this tuple type. */
int getArity() {
not this.hasGenericParamList() and
result = 0
or
result = this.getGenericParamList().getNumberOfGenericParams()
}
}

View File

@@ -713,12 +713,34 @@ abstract class ImplOrTraitItemNode extends ItemNode {
predicate hasAssocItem(string name) { name = this.getAnAssocItem().getName() } predicate hasAssocItem(string name) { name = this.getAnAssocItem().getName() }
} }
private TypeItemNode resolveBuiltin(TypeRepr tr) {
tr instanceof SliceTypeRepr and
result instanceof Builtins::SliceType
or
tr instanceof ArrayTypeRepr and
result instanceof Builtins::ArrayType
or
tr instanceof RefTypeRepr and
result instanceof Builtins::RefType
or
tr instanceof PtrTypeRepr and
result instanceof Builtins::PtrType
or
result.(Builtins::TupleType).getArity() = tr.(TupleTypeRepr).getNumberOfFields()
}
final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl { final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
Path getSelfPath() { result = super.getSelfTy().(PathTypeRepr).getPath() } Path getSelfPath() { result = super.getSelfTy().(PathTypeRepr).getPath() }
Path getTraitPath() { result = super.getTrait().(PathTypeRepr).getPath() } Path getTraitPath() { result = super.getTrait().(PathTypeRepr).getPath() }
TypeItemNode resolveSelfTy() { result = resolvePath(this.getSelfPath()) } TypeItemNode resolveSelfTyBuiltin() { result = resolveBuiltin(this.(Impl).getSelfTy()) }
TypeItemNode resolveSelfTy() {
result = resolvePath(this.getSelfPath())
or
result = this.resolveSelfTyBuiltin()
}
TraitItemNode resolveTraitTy() { result = resolvePath(this.getTraitPath()) } TraitItemNode resolveTraitTy() { result = resolvePath(this.getTraitPath()) }
@@ -893,7 +915,11 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
} }
private class ImplItemNodeImpl extends ImplItemNode { private class ImplItemNodeImpl extends ImplItemNode {
TypeItemNode resolveSelfTyCand() { result = resolvePathCand(this.getSelfPath()) } TypeItemNode resolveSelfTyCand() {
result = resolvePathCand(this.getSelfPath())
or
result = this.resolveSelfTyBuiltin()
}
TraitItemNode resolveTraitTyCand() { result = resolvePathCand(this.getTraitPath()) } TraitItemNode resolveTraitTyCand() { result = resolvePathCand(this.getTraitPath()) }
} }
@@ -1764,6 +1790,10 @@ private ItemNode resolvePathCand0(RelevantPath path, Namespace ns) {
or or
result = resolveUseTreeListItem(_, _, path, _) and result = resolveUseTreeListItem(_, _, path, _) and
ns = result.getNamespace() ns = result.getNamespace()
or
result = resolveBuiltin(path.getSegment().getTypeRepr()) and
not path.getSegment().hasTraitTypeRepr() and
ns.isType()
} }
pragma[nomagic] pragma[nomagic]
@@ -2141,7 +2171,8 @@ pragma[nomagic]
private predicate builtin(string name, ItemNode i) { private predicate builtin(string name, ItemNode i) {
exists(BuiltinSourceFile builtins | exists(BuiltinSourceFile builtins |
builtins.getFile().getBaseName() = "types.rs" and builtins.getFile().getBaseName() = "types.rs" and
i = builtins.getASuccessor(name) i = builtins.getASuccessor(name) and
i.isPublic()
) )
} }

View File

@@ -7,6 +7,7 @@ private import codeql.rust.internal.CachedStages
private import codeql.rust.elements.internal.generated.Raw private import codeql.rust.elements.internal.generated.Raw
private import codeql.rust.elements.internal.generated.Synth private import codeql.rust.elements.internal.generated.Synth
private import codeql.rust.frameworks.stdlib.Stdlib private import codeql.rust.frameworks.stdlib.Stdlib
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
/** /**
* Holds if a dyn trait type should have a type parameter associated with `n`. A * Holds if a dyn trait type should have a type parameter associated with `n`. A
@@ -31,39 +32,21 @@ private predicate dynTraitTypeParameter(Trait trait, AstNode n) {
cached cached
newtype TType = newtype TType =
TTuple(int arity) { TStruct(Struct s) { Stages::TypeInferenceStage::ref() } or
arity =
[
any(TupleTypeRepr t).getNumberOfFields(),
any(TupleExpr e).getNumberOfFields(),
any(TuplePat p).getNumberOfFields()
] and
Stages::TypeInferenceStage::ref()
} or
TStruct(Struct s) or
TEnum(Enum e) or TEnum(Enum e) or
TTrait(Trait t) or TTrait(Trait t) or
TUnion(Union u) or TUnion(Union u) or
TArrayType() or // todo: add size?
TRefType() or // todo: add mut?
TImplTraitType(ImplTraitTypeRepr impl) or TImplTraitType(ImplTraitTypeRepr impl) or
TDynTraitType(Trait t) { t = any(DynTraitTypeRepr dt).getTrait() } or TDynTraitType(Trait t) { t = any(DynTraitTypeRepr dt).getTrait() } or
TSliceType() or
TNeverType() or TNeverType() or
TPtrType() or
TUnknownType() or TUnknownType() or
TTupleTypeParameter(int arity, int i) { exists(TTuple(arity)) and i in [0 .. arity - 1] } or
TTypeParamTypeParameter(TypeParam t) or TTypeParamTypeParameter(TypeParam t) or
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
TArrayTypeParameter() or
TDynTraitTypeParameter(AstNode n) { dynTraitTypeParameter(_, n) } or TDynTraitTypeParameter(AstNode n) { dynTraitTypeParameter(_, n) } or
TImplTraitTypeParameter(ImplTraitTypeRepr implTrait, TypeParam tp) { TImplTraitTypeParameter(ImplTraitTypeRepr implTrait, TypeParam tp) {
implTraitTypeParam(implTrait, _, tp) implTraitTypeParam(implTrait, _, tp)
} or } or
TRefTypeParameter() or TSelfTypeParameter(Trait t)
TSelfTypeParameter(Trait t) or
TSliceTypeParameter() or
TPtrTypeParameter()
private predicate implTraitTypeParam(ImplTraitTypeRepr implTrait, int i, TypeParam tp) { private predicate implTraitTypeParam(ImplTraitTypeRepr implTrait, int i, TypeParam tp) {
implTrait.isInReturnPos() and implTrait.isInReturnPos() and
@@ -106,26 +89,25 @@ abstract class Type extends TType {
} }
/** A tuple type `(T, ...)`. */ /** A tuple type `(T, ...)`. */
class TupleType extends Type, TTuple { class TupleType extends StructType {
private int arity; private int arity;
TupleType() { this = TTuple(arity) } TupleType() { arity = this.getStruct().(Builtins::TupleType).getArity() }
override TypeParameter getPositionalTypeParameter(int i) {
result = TTupleTypeParameter(arity, i)
}
/** Gets the arity of this tuple type. */ /** Gets the arity of this tuple type. */
int getArity() { result = arity } int getArity() { result = arity }
override string toString() { result = "(T_" + arity + ")" } override string toString() { result = "(T_" + arity + ")" }
}
override Location getLocation() { result instanceof EmptyLocation } pragma[nomagic]
TypeParamTypeParameter getTupleTypeParameter(int arity, int i) {
result = any(TupleType t | t.getArity() = arity).getPositionalTypeParameter(i)
} }
/** The unit type `()`. */ /** The unit type `()`. */
class UnitType extends TupleType { class UnitType extends TupleType {
UnitType() { this = TTuple(0) } UnitType() { this.getArity() = 0 }
override string toString() { result = "()" } override string toString() { result = "()" }
} }
@@ -226,20 +208,17 @@ class UnionType extends Type, TUnion {
/** /**
* An array type. * An array type.
* *
* Array types like `[i64; 5]` are modeled as normal generic types * Array types like `[i64; 5]` are modeled as normal generic types.
* with a single type argument.
*/ */
class ArrayType extends Type, TArrayType { class ArrayType extends StructType {
ArrayType() { this = TArrayType() } ArrayType() { this.getStruct() instanceof Builtins::ArrayType }
override TypeParameter getPositionalTypeParameter(int i) { override string toString() { result = "[;]" }
result = TArrayTypeParameter() and }
i = 0
}
override string toString() { result = "[]" } pragma[nomagic]
TypeParamTypeParameter getArrayTypeParameter() {
override Location getLocation() { result instanceof EmptyLocation } result = any(ArrayType t).getPositionalTypeParameter(0)
} }
/** /**
@@ -248,17 +227,15 @@ class ArrayType extends Type, TArrayType {
* Reference types like `& i64` are modeled as normal generic types * Reference types like `& i64` are modeled as normal generic types
* with a single type argument. * with a single type argument.
*/ */
class RefType extends Type, TRefType { class RefType extends StructType {
RefType() { this = TRefType() } RefType() { this.getStruct() instanceof Builtins::RefType }
override TypeParameter getPositionalTypeParameter(int i) {
result = TRefTypeParameter() and
i = 0
}
override string toString() { result = "&" } override string toString() { result = "&" }
}
override Location getLocation() { result instanceof EmptyLocation } pragma[nomagic]
TypeParamTypeParameter getRefTypeParameter() {
result = any(RefType t).getPositionalTypeParameter(0)
} }
/** /**
@@ -340,17 +317,15 @@ class ImplTraitReturnType extends ImplTraitType {
* Slice types like `[i64]` are modeled as normal generic types * Slice types like `[i64]` are modeled as normal generic types
* with a single type argument. * with a single type argument.
*/ */
class SliceType extends Type, TSliceType { class SliceType extends StructType {
SliceType() { this = TSliceType() } SliceType() { this.getStruct() instanceof Builtins::SliceType }
override TypeParameter getPositionalTypeParameter(int i) {
result = TSliceTypeParameter() and
i = 0
}
override string toString() { result = "[]" } override string toString() { result = "[]" }
}
override Location getLocation() { result instanceof EmptyLocation } pragma[nomagic]
TypeParamTypeParameter getSliceTypeParameter() {
result = any(SliceType t).getPositionalTypeParameter(0)
} }
class NeverType extends Type, TNeverType { class NeverType extends Type, TNeverType {
@@ -361,11 +336,8 @@ class NeverType extends Type, TNeverType {
override Location getLocation() { result instanceof EmptyLocation } override Location getLocation() { result instanceof EmptyLocation }
} }
class PtrType extends Type, TPtrType { class PtrType extends StructType {
override TypeParameter getPositionalTypeParameter(int i) { PtrType() { this.getStruct() instanceof Builtins::PtrType }
i = 0 and
result = TPtrTypeParameter()
}
override string toString() { result = "*" } override string toString() { result = "*" }
@@ -402,6 +374,11 @@ class UnknownType extends Type, TUnknownType {
override Location getLocation() { result instanceof EmptyLocation } override Location getLocation() { result instanceof EmptyLocation }
} }
pragma[nomagic]
TypeParamTypeParameter getPtrTypeParameter() {
result = any(PtrType t).getPositionalTypeParameter(0)
}
/** A type parameter. */ /** A type parameter. */
abstract class TypeParameter extends Type { abstract class TypeParameter extends Type {
override TypeParameter getPositionalTypeParameter(int i) { none() } override TypeParameter getPositionalTypeParameter(int i) { none() }
@@ -461,37 +438,6 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara
override Location getLocation() { result = typeAlias.getLocation() } override Location getLocation() { result = typeAlias.getLocation() }
} }
/**
* A tuple type parameter. For instance the `T` in `(T, U)`.
*
* Since tuples are structural their type parameters can be represented as their
* positional index. The type inference library requires that type parameters
* belong to a single type, so we also include the arity of the tuple type.
*/
class TupleTypeParameter extends TypeParameter, TTupleTypeParameter {
private int arity;
private int index;
TupleTypeParameter() { this = TTupleTypeParameter(arity, index) }
override string toString() { result = index.toString() + "(" + arity + ")" }
override Location getLocation() { result instanceof EmptyLocation }
/** Gets the index of this tuple type parameter. */
int getIndex() { result = index }
/** Gets the tuple type that corresponds to this tuple type parameter. */
TupleType getTupleType() { result = TTuple(arity) }
}
/** An implicit array type parameter. */
class ArrayTypeParameter extends TypeParameter, TArrayTypeParameter {
override string toString() { result = "[T;...]" }
override Location getLocation() { result instanceof EmptyLocation }
}
class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter { class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter {
private AstNode n; private AstNode n;
@@ -539,26 +485,6 @@ class ImplTraitTypeParameter extends TypeParameter, TImplTraitTypeParameter {
override Location getLocation() { result = typeParam.getLocation() } override Location getLocation() { result = typeParam.getLocation() }
} }
/** An implicit reference type parameter. */
class RefTypeParameter extends TypeParameter, TRefTypeParameter {
override string toString() { result = "&T" }
override Location getLocation() { result instanceof EmptyLocation }
}
/** An implicit slice type parameter. */
class SliceTypeParameter extends TypeParameter, TSliceTypeParameter {
override string toString() { result = "[T]" }
override Location getLocation() { result instanceof EmptyLocation }
}
class PtrTypeParameter extends TypeParameter, TPtrTypeParameter {
override string toString() { result = "*T" }
override Location getLocation() { result instanceof EmptyLocation }
}
/** /**
* The implicit `Self` type parameter of a trait, that refers to the * The implicit `Self` type parameter of a trait, that refers to the
* implementing type of the trait. * implementing type of the trait.

View File

@@ -87,26 +87,6 @@ private module Input1 implements InputSig1<Location> {
int getTypeParameterId(TypeParameter tp) { int getTypeParameterId(TypeParameter tp) {
tp = tp =
rank[result](TypeParameter tp0, int kind, int id1, int id2 | rank[result](TypeParameter tp0, int kind, int id1, int id2 |
tp0 instanceof ArrayTypeParameter and
kind = 0 and
id1 = 0 and
id2 = 0
or
tp0 instanceof RefTypeParameter and
kind = 0 and
id1 = 0 and
id2 = 1
or
tp0 instanceof SliceTypeParameter and
kind = 0 and
id1 = 0 and
id2 = 2
or
tp0 instanceof PtrTypeParameter and
kind = 0 and
id1 = 0 and
id2 = 3
or
kind = 1 and kind = 1 and
id1 = 0 and id1 = 0 and
id2 = id2 =
@@ -127,10 +107,6 @@ private module Input1 implements InputSig1<Location> {
node = tp0.(SelfTypeParameter).getTrait() or node = tp0.(SelfTypeParameter).getTrait() or
node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr() node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr()
) )
or
kind = 4 and
id1 = tp0.(TupleTypeParameter).getTupleType().getArity() and
id2 = tp0.(TupleTypeParameter).getIndex()
| |
tp0 order by kind, id1, id2 tp0 order by kind, id1, id2
) )
@@ -421,7 +397,9 @@ module CertainTypeInference {
any(IdentPat ip | any(IdentPat ip |
n2 = ip.getName() and n2 = ip.getName() and
prefix1.isEmpty() and prefix1.isEmpty() and
if ip.isRef() then prefix2 = TypePath::singleton(TRefTypeParameter()) else prefix2.isEmpty() if ip.isRef()
then prefix2 = TypePath::singleton(getRefTypeParameter())
else prefix2.isEmpty()
) )
} }
@@ -631,11 +609,11 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
n1 = n2.(RefPat).getPat() n1 = n2.(RefPat).getPat()
) and ) and
prefix1.isEmpty() and prefix1.isEmpty() and
prefix2 = TypePath::singleton(TRefTypeParameter()) prefix2 = TypePath::singleton(getRefTypeParameter())
or or
exists(int i, int arity | exists(int i, int arity |
prefix1.isEmpty() and prefix1.isEmpty() and
prefix2 = TypePath::singleton(TTupleTypeParameter(arity, i)) prefix2 = TypePath::singleton(getTupleTypeParameter(arity, i))
| |
arity = n2.(TupleExpr).getNumberOfFields() and arity = n2.(TupleExpr).getNumberOfFields() and
n1 = n2.(TupleExpr).getField(i) n1 = n2.(TupleExpr).getField(i)
@@ -663,12 +641,12 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
ale.getAnExpr() = n2 and ale.getAnExpr() = n2 and
ale.getNumberOfExprs() = 1 ale.getNumberOfExprs() = 1
) and ) and
prefix1 = TypePath::singleton(TArrayTypeParameter()) and prefix1 = TypePath::singleton(getArrayTypeParameter()) and
prefix2.isEmpty() prefix2.isEmpty()
or or
// an array repeat expression (`[1; 3]`) has the type of the repeat operand // an array repeat expression (`[1; 3]`) has the type of the repeat operand
n1.(ArrayRepeatExpr).getRepeatOperand() = n2 and n1.(ArrayRepeatExpr).getRepeatOperand() = n2 and
prefix1 = TypePath::singleton(TArrayTypeParameter()) and prefix1 = TypePath::singleton(getArrayTypeParameter()) and
prefix2.isEmpty() prefix2.isEmpty()
or or
exists(Struct s | exists(Struct s |
@@ -717,7 +695,7 @@ private predicate lubCoercion(AstNode parent, AstNode child, TypePath prefix) {
child = ale.getAnExpr() and child = ale.getAnExpr() and
ale.getNumberOfExprs() > 1 ale.getNumberOfExprs() > 1
) and ) and
prefix = TypePath::singleton(TArrayTypeParameter()) prefix = TypePath::singleton(getArrayTypeParameter())
or or
bodyReturns(parent, child) and bodyReturns(parent, child) and
strictcount(Expr e | bodyReturns(parent, e)) > 1 and strictcount(Expr e | bodyReturns(parent, e)) > 1 and
@@ -956,9 +934,9 @@ private predicate inferStructExprType =
ContextTyping::CheckContextTyping<inferStructExprType0/3>::check/2; ContextTyping::CheckContextTyping<inferStructExprType0/3>::check/2;
pragma[nomagic] pragma[nomagic]
private Type inferTupleRootType(AstNode n) { private TupleType inferTupleRootType(AstNode n) {
// `typeEquality` handles the non-root cases // `typeEquality` handles the non-root cases
result = TTuple([n.(TupleExpr).getNumberOfFields(), n.(TuplePat).getTupleArity()]) result.getArity() = [n.(TupleExpr).getNumberOfFields(), n.(TuplePat).getTupleArity()]
} }
pragma[nomagic] pragma[nomagic]
@@ -1191,7 +1169,7 @@ private module MethodResolution {
* *
* `strippedTypePath` points to the type `strippedType` inside `selfType`, * `strippedTypePath` points to the type `strippedType` inside `selfType`,
* which is the (possibly complex-stripped) root type of `selfType`. For example, * which is the (possibly complex-stripped) root type of `selfType`. For example,
* if `m` has a `&self` parameter, then `strippedTypePath` is `TRefTypeParameter()` * if `m` has a `&self` parameter, then `strippedTypePath` is `getRefTypeParameter()`
* and `strippedType` is the type inside the reference. * and `strippedType` is the type inside the reference.
*/ */
pragma[nomagic] pragma[nomagic]
@@ -1401,7 +1379,7 @@ private module MethodResolution {
this.hasNoCompatibleTargetBorrow(derefChain0) and this.hasNoCompatibleTargetBorrow(derefChain0) and
t0 = this.getACandidateReceiverTypeAtNoBorrow(derefChain0, path0) t0 = this.getACandidateReceiverTypeAtNoBorrow(derefChain0, path0)
| |
path0.isCons(TRefTypeParameter(), path) and path0.isCons(getRefTypeParameter(), path) and
result = t0 and result = t0 and
derefChain = derefChain0 + ".ref" derefChain = derefChain0 + ".ref"
or or
@@ -1583,11 +1561,11 @@ private module MethodResolution {
borrow = true and borrow = true and
( (
path.isEmpty() and path.isEmpty() and
result = TRefType() result instanceof RefType
or or
exists(TypePath suffix | exists(TypePath suffix |
result = this.getACandidateReceiverTypeAtNoBorrow(derefChain, suffix) and result = this.getACandidateReceiverTypeAtNoBorrow(derefChain, suffix) and
path = TypePath::cons(TRefTypeParameter(), suffix) path = TypePath::cons(getRefTypeParameter(), suffix)
) )
) )
} }
@@ -1706,12 +1684,12 @@ private module MethodResolution {
override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) {
if this.(Call).implicitBorrowAt(pos, true) if this.(Call).implicitBorrowAt(pos, true)
then then
result = TRefType() and result instanceof RefType and
path.isEmpty() path.isEmpty()
or or
exists(TypePath path0 | exists(TypePath path0 |
result = inferType(this.getArgument(pos), path0) and result = inferType(this.getArgument(pos), path0) and
path = TypePath::cons(TRefTypeParameter(), path0) path = TypePath::cons(getRefTypeParameter(), path0)
) )
else result = inferType(this.getArgument(pos), path) else result = inferType(this.getArgument(pos), path)
} }
@@ -1854,7 +1832,7 @@ private module MethodResolution {
| |
mcc.hasNoBorrow() mcc.hasNoBorrow()
or or
blanketPath.getHead() = TRefTypeParameter() blanketPath.getHead() = getRefTypeParameter()
) )
} }
} }
@@ -2133,11 +2111,11 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
this instanceof IndexExpr this instanceof IndexExpr
then then
path.isEmpty() and path.isEmpty() and
result = TRefType() result instanceof RefType
or or
exists(TypePath suffix | exists(TypePath suffix |
result = inferType(this.getNodeAt(apos), suffix) and result = inferType(this.getNodeAt(apos), suffix) and
path = TypePath::cons(TRefTypeParameter(), suffix) path = TypePath::cons(getRefTypeParameter(), suffix)
) )
else ( else (
not apos.isSelf() and not apos.isSelf() and
@@ -2195,7 +2173,7 @@ private Type inferMethodCallType0(
// the implicit deref // the implicit deref
apos.isReturn() and apos.isReturn() and
a instanceof IndexExpr a instanceof IndexExpr
then path0.isCons(TRefTypeParameter(), path) then path0.isCons(getRefTypeParameter(), path)
else path = path0 else path = path0
) )
} }
@@ -2219,12 +2197,12 @@ private Type inferMethodCallType1(AstNode n, boolean isReturn, TypePath path) {
// adjust for implicit deref // adjust for implicit deref
apos.isSelf() and apos.isSelf() and
derefChainBorrow = ".ref;" and derefChainBorrow = ".ref;" and
path = TypePath::cons(TRefTypeParameter(), path0) path = TypePath::cons(getRefTypeParameter(), path0)
or or
// adjust for implicit borrow // adjust for implicit borrow
apos.isSelf() and apos.isSelf() and
derefChainBorrow = ";borrow" and derefChainBorrow = ";borrow" and
path0.isCons(TRefTypeParameter(), path) path0.isCons(getRefTypeParameter(), path)
) )
} }
@@ -2751,7 +2729,7 @@ private module OperationMatchingInput implements MatchingInputSig {
private Type getParameterType(DeclarationPosition dpos, TypePath path) { private Type getParameterType(DeclarationPosition dpos, TypePath path) {
exists(TypePath path0 | exists(TypePath path0 |
result = super.getParameterType(dpos, path0) and result = super.getParameterType(dpos, path0) and
if this.borrowsAt(dpos) then path0.isCons(TRefTypeParameter(), path) else path0 = path if this.borrowsAt(dpos) then path0.isCons(getRefTypeParameter(), path) else path0 = path
) )
} }
@@ -2762,7 +2740,7 @@ private module OperationMatchingInput implements MatchingInputSig {
private Type getReturnType(TypePath path) { private Type getReturnType(TypePath path) {
exists(TypePath path0 | exists(TypePath path0 |
result = super.getReturnType(path0) and result = super.getReturnType(path0) and
if this.derefsReturn() then path0.isCons(TRefTypeParameter(), path) else path0 = path if this.derefsReturn() then path0.isCons(getRefTypeParameter(), path) else path0 = path
) )
} }
@@ -2819,14 +2797,6 @@ private Type getTupleFieldExprLookupType(FieldExpr fe, int pos) {
) )
} }
pragma[nomagic]
private TupleTypeParameter resolveTupleTypeFieldExpr(FieldExpr fe) {
exists(int arity, int i |
TTuple(arity) = getTupleFieldExprLookupType(fe, i) and
result = TTupleTypeParameter(arity, i)
)
}
/** /**
* A matching configuration for resolving types of field expressions like `x.field`. * A matching configuration for resolving types of field expressions like `x.field`.
*/ */
@@ -2851,8 +2821,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
private newtype TDeclaration = private newtype TDeclaration =
TStructFieldDecl(StructField sf) or TStructFieldDecl(StructField sf) or
TTupleFieldDecl(TupleField tf) or TTupleFieldDecl(TupleField tf)
TTupleTypeParameterDecl(TupleTypeParameter ttp)
abstract class Declaration extends TDeclaration { abstract class Declaration extends TDeclaration {
TypeParameter getTypeParameter(TypeParameterPosition ppos) { none() } TypeParameter getTypeParameter(TypeParameterPosition ppos) { none() }
@@ -2909,31 +2878,6 @@ private module FieldExprMatchingInput implements MatchingInputSig {
override TypeRepr getTypeRepr() { result = tf.getTypeRepr() } override TypeRepr getTypeRepr() { result = tf.getTypeRepr() }
} }
private class TupleTypeParameterDecl extends Declaration, TTupleTypeParameterDecl {
private TupleTypeParameter ttp;
TupleTypeParameterDecl() { this = TTupleTypeParameterDecl(ttp) }
override Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
dpos.isSelf() and
(
result = ttp.getTupleType() and
path.isEmpty()
or
result = ttp and
path = TypePath::singleton(ttp)
)
or
dpos.isField() and
result = ttp and
path.isEmpty()
}
override string toString() { result = ttp.toString() }
override Location getLocation() { result = ttp.getLocation() }
}
class AccessPosition = DeclarationPosition; class AccessPosition = DeclarationPosition;
class Access extends FieldExpr { class Access extends FieldExpr {
@@ -2952,10 +2896,10 @@ private module FieldExprMatchingInput implements MatchingInputSig {
if apos.isSelf() if apos.isSelf()
then then
// adjust for implicit deref // adjust for implicit deref
path0.isCons(TRefTypeParameter(), path) path0.isCons(getRefTypeParameter(), path)
or or
not path0.isCons(TRefTypeParameter(), _) and not path0.isCons(getRefTypeParameter(), _) and
not (result = TRefType() and path0.isEmpty()) and not (result instanceof RefType and path0.isEmpty()) and
path = path0 path = path0
else path = path0 else path = path0
) )
@@ -2966,8 +2910,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
result = result =
[ [
TStructFieldDecl(resolveStructFieldExpr(this)).(TDeclaration), TStructFieldDecl(resolveStructFieldExpr(this)).(TDeclaration),
TTupleFieldDecl(resolveTupleFieldExpr(this)), TTupleFieldDecl(resolveTupleFieldExpr(this))
TTupleTypeParameterDecl(resolveTupleTypeFieldExpr(this))
] ]
} }
} }
@@ -2994,12 +2937,12 @@ private Type inferFieldExprType(AstNode n, TypePath path) {
if apos.isSelf() if apos.isSelf()
then then
exists(Type receiverType | receiverType = inferType(n) | exists(Type receiverType | receiverType = inferType(n) |
if receiverType = TRefType() if receiverType instanceof RefType
then then
// adjust for implicit deref // adjust for implicit deref
not path0.isCons(TRefTypeParameter(), _) and not path0.isCons(getRefTypeParameter(), _) and
not (path0.isEmpty() and result = TRefType()) and not (path0.isEmpty() and result instanceof RefType) and
path = TypePath::cons(TRefTypeParameter(), path0) path = TypePath::cons(getRefTypeParameter(), path0)
else path = path0 else path = path0
) )
else path = path0 else path = path0
@@ -3016,7 +2959,7 @@ private Type inferRefNodeType(AstNode ref) {
or or
ref instanceof RefPat ref instanceof RefPat
) and ) and
result = TRefType() result instanceof RefType
} }
pragma[nomagic] pragma[nomagic]
@@ -3070,9 +3013,9 @@ private Type inferLiteralType(LiteralExpr le, TypePath path, boolean certain) {
or or
le instanceof StringLiteralExpr and le instanceof StringLiteralExpr and
( (
path.isEmpty() and result = TRefType() path.isEmpty() and result instanceof RefType
or or
path = TypePath::singleton(TRefTypeParameter()) and path = TypePath::singleton(getRefTypeParameter()) and
result = getStrStruct() result = getStrStruct()
) and ) and
certain = true certain = true
@@ -3131,6 +3074,8 @@ private module AwaitSatisfiesConstraintInput implements SatisfiesConstraintInput
exists(term) and exists(term) and
constraint.(TraitType).getTrait() instanceof FutureTrait constraint.(TraitType).getTrait() instanceof FutureTrait
} }
predicate useUniversalConditions() { none() }
} }
pragma[nomagic] pragma[nomagic]
@@ -3146,7 +3091,7 @@ private Type inferAwaitExprType(AstNode n, TypePath path) {
* Gets the root type of the array expression `ae`. * Gets the root type of the array expression `ae`.
*/ */
pragma[nomagic] pragma[nomagic]
private Type inferArrayExprType(ArrayExpr ae) { exists(ae) and result = TArrayType() } private Type inferArrayExprType(ArrayExpr ae) { exists(ae) and result instanceof ArrayType }
/** /**
* Gets the root type of the range expression `re`. * Gets the root type of the range expression `re`.
@@ -3182,11 +3127,11 @@ private Type inferIndexExprType(IndexExpr ie, TypePath path) {
// todo: remove? // todo: remove?
exprPath.isCons(TTypeParamTypeParameter(any(Vec v).getElementTypeParam()), path) exprPath.isCons(TTypeParamTypeParameter(any(Vec v).getElementTypeParam()), path)
or or
exprPath.isCons(any(ArrayTypeParameter tp), path) exprPath.isCons(getArrayTypeParameter(), path)
or or
exists(TypePath path0 | exists(TypePath path0 |
exprPath.isCons(any(RefTypeParameter tp), path0) and exprPath.isCons(getRefTypeParameter(), path0) and
path0.isCons(any(SliceTypeParameter tp), path) path0.isCons(getSliceTypeParameter(), path)
) )
) )
} }
@@ -3306,6 +3251,8 @@ private module ForIterableSatisfiesConstraintInput implements
t instanceof IntoIteratorTrait t instanceof IntoIteratorTrait
) )
} }
predicate useUniversalConditions() { none() }
} }
pragma[nomagic] pragma[nomagic]
@@ -3331,7 +3278,7 @@ private Type inferForLoopExprType(AstNode n, TypePath path) {
or or
// TODO: Remove once we can handle the `impl<I: Iterator> IntoIterator for I` implementation // TODO: Remove once we can handle the `impl<I: Iterator> IntoIterator for I` implementation
tp = getIteratorItemTypeParameter() and tp = getIteratorItemTypeParameter() and
inferType(fe.getIterable()) != TArrayType() inferType(fe.getIterable()) != getArrayTypeParameter()
) )
} }
@@ -3360,6 +3307,8 @@ private module InvokedClosureSatisfiesConstraintInput implements
exists(term) and exists(term) and
constraint.(TraitType).getTrait() instanceof FnOnceTrait constraint.(TraitType).getTrait() instanceof FnOnceTrait
} }
predicate useUniversalConditions() { none() }
} }
/** Gets the type of `ce` when viewed as an implementation of `FnOnce`. */ /** Gets the type of `ce` when viewed as an implementation of `FnOnce`. */
@@ -3378,7 +3327,7 @@ pragma[nomagic]
private TypePath closureParameterPath(int arity, int index) { private TypePath closureParameterPath(int arity, int index) {
result = result =
TypePath::cons(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam()), TypePath::cons(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam()),
TypePath::singleton(TTupleTypeParameter(arity, index))) TypePath::singleton(getTupleTypeParameter(arity, index)))
} }
/** Gets the path to the return type of the `FnOnce` trait. */ /** Gets the path to the return type of the `FnOnce` trait. */
@@ -3394,7 +3343,7 @@ pragma[nomagic]
private TypePath fnParameterPath(int arity, int index) { private TypePath fnParameterPath(int arity, int index) {
result = result =
TypePath::cons(TTypeParamTypeParameter(any(FnOnceTrait t).getTypeParam()), TypePath::cons(TTypeParamTypeParameter(any(FnOnceTrait t).getTypeParam()),
TypePath::singleton(TTupleTypeParameter(arity, index))) TypePath::singleton(getTupleTypeParameter(arity, index)))
} }
pragma[nomagic] pragma[nomagic]
@@ -3443,7 +3392,7 @@ private Type inferClosureExprType(AstNode n, TypePath path) {
or or
n = ce and n = ce and
path = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam())) and path = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam())) and
result = TTuple(ce.getNumberOfParams()) result.(TupleType).getArity() = ce.getNumberOfParams()
or or
// Propagate return type annotation to body // Propagate return type annotation to body
n = ce.getClosureBody() and n = ce.getClosureBody() and

View File

@@ -20,11 +20,11 @@ abstract class TypeMention extends AstNode {
class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr { class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr {
override Type resolveTypeAt(TypePath path) { override Type resolveTypeAt(TypePath path) {
path.isEmpty() and path.isEmpty() and
result = TTuple(super.getNumberOfFields()) result.(TupleType).getArity() = super.getNumberOfFields()
or or
exists(TypePath suffix, int i | exists(TypePath suffix, int i |
result = super.getField(i).(TypeMention).resolveTypeAt(suffix) and result = super.getField(i).(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TTupleTypeParameter(super.getNumberOfFields(), i), suffix) path = TypePath::cons(getTupleTypeParameter(super.getNumberOfFields(), i), suffix)
) )
} }
} }
@@ -32,11 +32,11 @@ class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr {
class ParenthesizedArgListMention extends TypeMention instanceof ParenthesizedArgList { class ParenthesizedArgListMention extends TypeMention instanceof ParenthesizedArgList {
override Type resolveTypeAt(TypePath path) { override Type resolveTypeAt(TypePath path) {
path.isEmpty() and path.isEmpty() and
result = TTuple(super.getNumberOfTypeArgs()) result.(TupleType).getArity() = super.getNumberOfTypeArgs()
or or
exists(TypePath suffix, int index | exists(TypePath suffix, int index |
result = super.getTypeArg(index).getTypeRepr().(TypeMention).resolveTypeAt(suffix) and result = super.getTypeArg(index).getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TTupleTypeParameter(super.getNumberOfTypeArgs(), index), suffix) path = TypePath::cons(getTupleTypeParameter(super.getNumberOfTypeArgs(), index), suffix)
) )
} }
} }
@@ -44,11 +44,11 @@ class ParenthesizedArgListMention extends TypeMention instanceof ParenthesizedAr
class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr { class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr {
override Type resolveTypeAt(TypePath path) { override Type resolveTypeAt(TypePath path) {
path.isEmpty() and path.isEmpty() and
result = TArrayType() result instanceof ArrayType
or or
exists(TypePath suffix | exists(TypePath suffix |
result = super.getElementTypeRepr().(TypeMention).resolveTypeAt(suffix) and result = super.getElementTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TArrayTypeParameter(), suffix) path = TypePath::cons(getArrayTypeParameter(), suffix)
) )
} }
} }
@@ -56,11 +56,11 @@ class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr {
class RefTypeReprMention extends TypeMention instanceof RefTypeRepr { class RefTypeReprMention extends TypeMention instanceof RefTypeRepr {
override Type resolveTypeAt(TypePath path) { override Type resolveTypeAt(TypePath path) {
path.isEmpty() and path.isEmpty() and
result = TRefType() result instanceof RefType
or or
exists(TypePath suffix | exists(TypePath suffix |
result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TRefTypeParameter(), suffix) path = TypePath::cons(getRefTypeParameter(), suffix)
) )
} }
} }
@@ -68,11 +68,11 @@ class RefTypeReprMention extends TypeMention instanceof RefTypeRepr {
class SliceTypeReprMention extends TypeMention instanceof SliceTypeRepr { class SliceTypeReprMention extends TypeMention instanceof SliceTypeRepr {
override Type resolveTypeAt(TypePath path) { override Type resolveTypeAt(TypePath path) {
path.isEmpty() and path.isEmpty() and
result = TSliceType() result instanceof SliceType
or or
exists(TypePath suffix | exists(TypePath suffix |
result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TSliceTypeParameter(), suffix) path = TypePath::cons(getSliceTypeParameter(), suffix)
) )
} }
} }
@@ -291,6 +291,9 @@ class NonAliasPathTypeMention extends PathTypeMention {
result = this.getSelfTraitBoundArg().resolveTypeAt(suffix) and result = this.getSelfTraitBoundArg().resolveTypeAt(suffix) and
typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix) typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix)
) )
or
not this.getSegment().hasTraitTypeRepr() and
result = this.getSegment().getTypeRepr().(TypeMention).resolveTypeAt(typePath)
} }
} }
@@ -426,11 +429,11 @@ class ShorthandSelfParameterMention extends TypeMention instanceof SelfParam {
then then
// `fn f(&self, ...)` // `fn f(&self, ...)`
typePath.isEmpty() and typePath.isEmpty() and
result = TRefType() result instanceof RefType
or or
exists(TypePath suffix | exists(TypePath suffix |
result = this.resolveSelfType(suffix) and result = this.resolveSelfType(suffix) and
typePath = TypePath::cons(TRefTypeParameter(), suffix) typePath = TypePath::cons(getRefTypeParameter(), suffix)
) )
else else
// `fn f(self, ...)` // `fn f(self, ...)`
@@ -541,11 +544,11 @@ class NeverTypeReprMention extends TypeMention, NeverTypeRepr {
class PtrTypeReprMention extends TypeMention instanceof PtrTypeRepr { class PtrTypeReprMention extends TypeMention instanceof PtrTypeRepr {
override Type resolveTypeAt(TypePath path) { override Type resolveTypeAt(TypePath path) {
path.isEmpty() and path.isEmpty() and
result = TPtrType() result instanceof PtrType
or or
exists(TypePath suffix | exists(TypePath suffix |
result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TPtrTypeParameter(), suffix) path = TypePath::cons(getPtrTypeParameter(), suffix)
) )
} }
} }

View File

@@ -7,7 +7,7 @@ import rust
private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.DataFlow
private import codeql.rust.internal.TypeInference as TypeInference private import codeql.rust.internal.TypeInference as TypeInference
private import codeql.rust.internal.Type private import codeql.rust.internal.Type
private import codeql.rust.frameworks.stdlib.Builtins private import codeql.rust.frameworks.stdlib.Builtins as Builtins
/** /**
* A node whose type is a numeric or boolean type, which may be an appropriate * A node whose type is a numeric or boolean type, which may be an appropriate
@@ -19,8 +19,8 @@ class NumericTypeBarrier extends DataFlow::Node {
t = TypeInference::inferType(this.asExpr().getExpr()) and t = TypeInference::inferType(this.asExpr().getExpr()) and
s = t.getStruct() s = t.getStruct()
| |
s instanceof NumericType or s instanceof Builtins::NumericType or
s instanceof Bool s instanceof Builtins::Bool
) )
} }
} }
@@ -35,8 +35,8 @@ class IntegralOrBooleanTypeBarrier extends DataFlow::Node {
t = TypeInference::inferType(this.asExpr().getExpr()) and t = TypeInference::inferType(this.asExpr().getExpr()) and
s = t.getStruct() s = t.getStruct()
| |
s instanceof IntegralType or s instanceof Builtins::IntegralType or
s instanceof Bool s instanceof Builtins::Bool
) )
} }
} }

View File

@@ -1,3 +1,20 @@
| struct Array | |
| struct Ptr | |
| struct Ref | |
| struct Slice | |
| struct Tuple0 | |
| struct Tuple1 | |
| struct Tuple2 | |
| struct Tuple3 | |
| struct Tuple4 | |
| struct Tuple5 | |
| struct Tuple6 | |
| struct Tuple7 | |
| struct Tuple8 | |
| struct Tuple9 | |
| struct Tuple10 | |
| struct Tuple11 | |
| struct Tuple12 | |
| struct bool | | | struct bool | |
| struct char | | | struct char | |
| struct f32 | FloatingPointType, NumericType | | struct f32 | FloatingPointType, NumericType |

View File

@@ -1,6 +1,5 @@
import rust import rust
import codeql.rust.frameworks.stdlib.Builtins import codeql.rust.frameworks.stdlib.Builtins
import codeql.rust.internal.Type
string describe(BuiltinType t) { string describe(BuiltinType t) {
t instanceof NumericType and result = "NumericType" t instanceof NumericType and result = "NumericType"

View File

@@ -6,9 +6,9 @@ multipleCallTargets
| dereference.rs:186:17:186:25 | S.bar(...) | | dereference.rs:186:17:186:25 | S.bar(...) |
| dereference.rs:187:17:187:29 | S.bar(...) | | dereference.rs:187:17:187:29 | S.bar(...) |
| main.rs:590:9:590:18 | ...::m(...) | | main.rs:590:9:590:18 | ...::m(...) |
| main.rs:2553:13:2553:31 | ...::from(...) | | main.rs:2634:13:2634:31 | ...::from(...) |
| main.rs:2554:13:2554:31 | ...::from(...) | | main.rs:2635:13:2635:31 | ...::from(...) |
| main.rs:2555:13:2555:31 | ...::from(...) | | main.rs:2636:13:2636:31 | ...::from(...) |
| main.rs:2561:13:2561:31 | ...::from(...) | | main.rs:2642:13:2642:31 | ...::from(...) |
| main.rs:2562:13:2562:31 | ...::from(...) | | main.rs:2643:13:2643:31 | ...::from(...) |
| main.rs:2563:13:2563:31 | ...::from(...) | | main.rs:2644:13:2644:31 | ...::from(...) |

View File

@@ -38,7 +38,7 @@ impl<T> S<T> {
fn explicit_monomorphic_dereference() { fn explicit_monomorphic_dereference() {
// Dereference with method call // Dereference with method call
let a1 = MyIntPointer { value: 34i64 }; let a1 = MyIntPointer { value: 34i64 };
let _b1 = a1.deref(); // $ target=MyIntPointer::deref type=_b1:&T.i64 let _b1 = a1.deref(); // $ target=MyIntPointer::deref type=_b1:TRef.i64
// Dereference with overloaded dereference operator // Dereference with overloaded dereference operator
let a2 = MyIntPointer { value: 34i64 }; let a2 = MyIntPointer { value: 34i64 };
@@ -52,7 +52,7 @@ fn explicit_monomorphic_dereference() {
fn explicit_polymorphic_dereference() { fn explicit_polymorphic_dereference() {
// Explicit dereference with type parameter // Explicit dereference with type parameter
let c1 = MySmartPointer { value: 'a' }; let c1 = MySmartPointer { value: 'a' };
let _d1 = c1.deref(); // $ target=MySmartPointer::deref type=_d1:&T.char let _d1 = c1.deref(); // $ target=MySmartPointer::deref type=_d1:TRef.char
// Explicit dereference with type parameter // Explicit dereference with type parameter
let c2 = MySmartPointer { value: 'a' }; let c2 = MySmartPointer { value: 'a' };
@@ -66,7 +66,7 @@ fn explicit_polymorphic_dereference() {
fn explicit_ref_dereference() { fn explicit_ref_dereference() {
// Explicit dereference with type parameter // Explicit dereference with type parameter
let e1 = &'a'; let e1 = &'a';
let _f1 = e1.deref(); // $ target=deref type=_f1:&T.char let _f1 = e1.deref(); // $ target=deref type=_f1:TRef.char
// Explicit dereference with type parameter // Explicit dereference with type parameter
let e2 = &'a'; let e2 = &'a';
@@ -80,7 +80,7 @@ fn explicit_ref_dereference() {
fn explicit_box_dereference() { fn explicit_box_dereference() {
// Explicit dereference with type parameter // Explicit dereference with type parameter
let g1: Box<char> = Box::new('a'); // $ target=new let g1: Box<char> = Box::new('a'); // $ target=new
let _h1 = g1.deref(); // $ target=deref type=_h1:&T.char let _h1 = g1.deref(); // $ target=deref type=_h1:TRef.char
// Explicit dereference with type parameter // Explicit dereference with type parameter
let g2: Box<char> = Box::new('a'); // $ target=new let g2: Box<char> = Box::new('a'); // $ target=new
@@ -101,7 +101,7 @@ fn implicit_dereference() {
let _y = x.is_positive(); // $ MISSING: target=is_positive type=_y:bool let _y = x.is_positive(); // $ MISSING: target=is_positive type=_y:bool
let z = MySmartPointer { value: S(0i64) }; let z = MySmartPointer { value: S(0i64) };
let z_ = z.foo(); // $ MISSING: target=foo type=z_:&T.i64 let z_ = z.foo(); // $ MISSING: target=foo type=z_:TRef.i64
} }
mod implicit_deref_coercion_cycle { mod implicit_deref_coercion_cycle {

View File

@@ -1542,7 +1542,7 @@ mod method_call_type_conversion {
let x7 = S(&S2); let x7 = S(&S2);
// Non-implicit dereference with nested borrow in order to test that the // Non-implicit dereference with nested borrow in order to test that the
// implicit dereference handling doesn't affect nested borrows. // implicit dereference handling doesn't affect nested borrows.
let t = x7.m1(); // $ target=m1 type=t:& type=t:&T.S2 let t = x7.m1(); // $ target=m1 type=t:& type=t:TRef.S2
println!("{:?}", x7); println!("{:?}", x7);
let x9: String = "Hello".to_string(); // $ certainType=x9:String target=to_string let x9: String = "Hello".to_string(); // $ certainType=x9:String target=to_string
@@ -1732,10 +1732,91 @@ mod builtins {
let z = x + y; // $ type=z:i32 target=add let z = x + y; // $ type=z:i32 target=add
let z = x.abs(); // $ target=abs $ type=z:i32 let z = x.abs(); // $ target=abs $ type=z:i32
let c = 'c'; // $ certainType=c:char let c = 'c'; // $ certainType=c:char
let hello = "Hello"; // $ certainType=hello:&T.str let hello = "Hello"; // $ certainType=hello:TRef.str
let f = 123.0f64; // $ certainType=f:f64 let f = 123.0f64; // $ certainType=f:f64
let t = true; // $ certainType=t:bool let t = true; // $ certainType=t:bool
let f = false; // $ certainType=f:bool let f = false; // $ certainType=f:bool
trait MyTrait<T> {
fn my_method(&self) -> &T;
fn my_func() -> T;
}
impl<T: Default, const N: usize> MyTrait<T> for [T; N] {
fn my_method(&self) -> &T {
self.get(0).unwrap() // $ MISSING: target=get target=unwrap
}
fn my_func() -> T {
T::default() // $ target=default
}
}
let x = [1, 2, 3].my_method(); // $ target=my_method type=x:TRef.i32
let x = <[_; 3]>::my_method(&[1, 2, 3]); // $ target=my_method type=x:TRef.i32
let x = <[i32; 3]>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for [T] {
fn my_method(&self) -> &T {
self.get(0).unwrap() // $ target=get target=unwrap
}
fn my_func() -> T {
T::default() // $ target=default
}
}
let s: &[i32] = &[1, 2, 3];
let x = s.my_method(); // $ target=my_method type=x:TRef.i32
let x = <[_]>::my_method(s); // $ target=my_method type=x:TRef.i32
let x = <[i32]>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for (T, i32) {
fn my_method(&self) -> &T {
&self.0 // $ fieldof=Tuple2
}
fn my_func() -> T {
T::default() // $ target=default
}
}
let p = (42, 7);
let x = p.my_method(); // $ target=my_method type=x:TRef.i32
let x = <(_, _)>::my_method(&p); // $ target=my_method type=x:TRef.i32
let x = <(i32, i32)>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for &T {
fn my_method(&self) -> &T {
*self // $ target=deref
}
fn my_func() -> T {
T::default() // $ target=default
}
}
let r = &42;
let x = r.my_method(); // $ target=my_method type=x:TRef.i32
let x = <&_>::my_method(&r); // $ target=my_method type=x:TRef.i32
let x = <&i32>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for *mut T {
fn my_method(&self) -> &T {
unsafe { &**self } // $ target=deref target=deref
}
fn my_func() -> T {
T::default() // $ target=default
}
}
let mut v = 42;
let p: *mut i32 = &mut v;
let x = unsafe { p.my_method() }; // $ target=my_method type=x:TRef.i32
let x = unsafe { <*mut _>::my_method(&p) }; // $ target=my_method type=x:TRef.i32
let x = <*mut i32>::my_func(); // $ target=my_func type=x:i32
} }
} }
@@ -2263,7 +2344,7 @@ mod impl_trait {
// For this function the `impl` type does not appear in the root of the return type // For this function the `impl` type does not appear in the root of the return type
let f = get_a_my_trait3(S1).unwrap().get_a(); // $ target=get_a_my_trait3 target=unwrap target=MyTrait::get_a type=f:S1 let f = get_a_my_trait3(S1).unwrap().get_a(); // $ target=get_a_my_trait3 target=unwrap target=MyTrait::get_a type=f:S1
let g = get_a_my_trait4(S1).0.get_a(); // $ target=get_a_my_trait4 target=MyTrait::get_a type=g:S1 let g = get_a_my_trait4(S1).0.get_a(); // $ target=get_a_my_trait4 target=MyTrait::get_a type=g:S1 fieldof=Tuple2
} }
} }
@@ -2531,24 +2612,24 @@ mod loops {
for i in [1, 2, 3].map(|x| x + 1) {} // $ target=map MISSING: type=i:i32 for i in [1, 2, 3].map(|x| x + 1) {} // $ target=map MISSING: type=i:i32
for i in [1, 2, 3].into_iter() {} // $ target=into_iter type=i:i32 for i in [1, 2, 3].into_iter() {} // $ target=into_iter type=i:i32
let vals1 = [1u8, 2, 3]; // $ type=vals1:[T;...].u8 let vals1 = [1u8, 2, 3]; // $ type=vals1:TArray.u8
for u in vals1 {} // $ type=u:u8 for u in vals1 {} // $ type=u:u8
let vals2 = [1u16; 3]; // $ type=vals2:[T;...].u16 let vals2 = [1u16; 3]; // $ type=vals2:TArray.u16
for u in vals2 {} // $ type=u:u16 for u in vals2 {} // $ type=u:u16
let vals3: [u32; 3] = [1, 2, 3]; // $ certainType=vals3:[T;...].u32 let vals3: [u32; 3] = [1, 2, 3]; // $ certainType=vals3:TArray.u32
for u in vals3 {} // $ type=u:u32 for u in vals3 {} // $ type=u:u32
let vals4: [u64; 3] = [1; 3]; // $ certainType=vals4:[T;...].u64 let vals4: [u64; 3] = [1; 3]; // $ certainType=vals4:TArray.u64
for u in vals4 {} // $ type=u:u64 for u in vals4 {} // $ type=u:u64
let mut strings1 = ["foo", "bar", "baz"]; // $ type=strings1:[T;...].&T.str let mut strings1 = ["foo", "bar", "baz"]; // $ type=strings1:TArray.TRef.str
for s in &strings1 {} // $ type=s:&T.&T.str for s in &strings1 {} // $ type=s:TRef.TRef.str
for s in &mut strings1 {} // $ type=s:&T.&T.str for s in &mut strings1 {} // $ type=s:TRef.TRef.str
for s in strings1 {} // $ type=s:&T.str for s in strings1 {} // $ type=s:TRef.str
let strings2 = // $ type=strings2:[T;...].String let strings2 = // $ type=strings2:TArray.String
[ [
String::from("foo"), // $ target=from String::from("foo"), // $ target=from
String::from("bar"), // $ target=from String::from("bar"), // $ target=from
@@ -2556,15 +2637,15 @@ mod loops {
]; ];
for s in strings2 {} // $ type=s:String for s in strings2 {} // $ type=s:String
let strings3 = // $ type=strings3:&T.[T;...].String let strings3 = // $ type=strings3:TRef.TArray.String
&[ &[
String::from("foo"), // $ target=from String::from("foo"), // $ target=from
String::from("bar"), // $ target=from String::from("bar"), // $ target=from
String::from("baz"), // $ target=from String::from("baz"), // $ target=from
]; ];
for s in strings3 {} // $ type=s:&T.String for s in strings3 {} // $ type=s:TRef.String
let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ target=new $ type=callables:[T;...].MyCallable let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ target=new $ type=callables:TArray.MyCallable
for c // $ type=c:MyCallable for c // $ type=c:MyCallable
in callables in callables
{ {
@@ -2578,7 +2659,7 @@ mod loops {
let range = 0..10; // $ certainType=range:Range type=range:Idx.i32 let range = 0..10; // $ certainType=range:Range type=range:Idx.i32
for i in range {} // $ type=i:i32 for i in range {} // $ type=i:i32
let range_full = ..; // $ certainType=range_full:RangeFull let range_full = ..; // $ certainType=range_full:RangeFull
for i in &[1i64, 2i64, 3i64][range_full] {} // $ target=index MISSING: type=i:&T.i64 for i in &[1i64, 2i64, 3i64][range_full] {} // $ target=index MISSING: type=i:TRef.i64
let range1 = // $ certainType=range1:Range type=range1:Idx.u16 let range1 = // $ certainType=range1:Range type=range1:Idx.u16
std::ops::Range { std::ops::Range {
@@ -2589,7 +2670,7 @@ mod loops {
// for loops with containers // for loops with containers
let vals3 = vec![1, 2, 3]; // $ MISSING: type=vals3:Vec type=vals3:T.i32 let vals3 = vec![1, 2, 3]; // $ type=vals3:Vec $ MISSING: type=vals3:T.i32
for i in vals3 {} // $ MISSING: type=i:i32 for i in vals3 {} // $ MISSING: type=i:i32
let vals4a: Vec<u16> = [1u16, 2, 3].to_vec(); // $ certainType=vals4a:Vec certainType=vals4a:T.u16 let vals4a: Vec<u16> = [1u16, 2, 3].to_vec(); // $ certainType=vals4a:Vec certainType=vals4a:T.u16
@@ -2601,27 +2682,27 @@ mod loops {
let vals5 = Vec::from([1u32, 2, 3]); // $ certainType=vals5:Vec target=from type=vals5:T.u32 let vals5 = Vec::from([1u32, 2, 3]); // $ certainType=vals5:Vec target=from type=vals5:T.u32
for u in vals5 {} // $ type=u:u32 for u in vals5 {} // $ type=u:u32
let vals6: Vec<&u64> = [1u64, 2, 3].iter().collect(); // $ certainType=vals6:Vec certainType=vals6:T.&T.u64 let vals6: Vec<&u64> = [1u64, 2, 3].iter().collect(); // $ certainType=vals6:Vec certainType=vals6:T.TRef.u64
for u in vals6 {} // $ type=u:&T.u64 for u in vals6 {} // $ type=u:TRef.u64
let mut vals7 = Vec::new(); // $ target=new certainType=vals7:Vec type=vals7:T.u8 let mut vals7 = Vec::new(); // $ target=new certainType=vals7:Vec type=vals7:T.u8
vals7.push(1u8); // $ target=push vals7.push(1u8); // $ target=push
for u in vals7 {} // $ type=u:u8 for u in vals7 {} // $ type=u:u8
let matrix1 = vec![vec![1, 2], vec![3, 4]]; // $ MISSING: type=matrix1:Vec type=matrix1:T.Vec type=matrix1:T.T.i32 let matrix1 = vec![vec![1, 2], vec![3, 4]]; // $ type=matrix1:Vec $ MISSING: type=matrix1:T.Vec type=matrix1:T.T.i32
#[rustfmt::skip] #[rustfmt::skip]
let _ = for row in matrix1 { // $ MISSING: type=row:Vec type=row:T.i32 let _ = for row in matrix1 { // $ MISSING: type=row:Vec type=row:T.i32
for cell in row { // $ MISSING: type=cell:i32 for cell in row { // $ MISSING: type=cell:i32
} }
}; };
let mut map1 = std::collections::HashMap::new(); // $ target=new type=map1:K.i32 type=map1:V.Box $ MISSING: type=map1:Hashmap type1=map1:V.T.&T.str let mut map1 = std::collections::HashMap::new(); // $ target=new type=map1:K.i32 type=map1:V.Box $ MISSING: type=map1:Hashmap type1=map1:V.T.TRef.str
map1.insert(1, Box::new("one")); // $ target=insert target=new map1.insert(1, Box::new("one")); // $ target=insert target=new
map1.insert(2, Box::new("two")); // $ target=insert target=new map1.insert(2, Box::new("two")); // $ target=insert target=new
for key in map1.keys() {} // $ target=keys type=key:&T.i32 for key in map1.keys() {} // $ target=keys type=key:TRef.i32
for value in map1.values() {} // $ target=values type=value:&T.Box type=value:&T.T.&T.str for value in map1.values() {} // $ target=values type=value:TRef.Box type=value:TRef.T.TRef.str
for (key, value) in map1.iter() {} // $ target=iter type=key:&T.i32 type=value:&T.Box type=value:&T.T.&T.str for (key, value) in map1.iter() {} // $ target=iter type=key:TRef.i32 type=value:TRef.Box type=value:TRef.T.TRef.str
for (key, value) in &map1 {} // $ type=key:&T.i32 type=value:&T.Box type=value:&T.T.&T.str for (key, value) in &map1 {} // $ type=key:TRef.i32 type=value:TRef.Box type=value:TRef.T.TRef.str
// while loops // while loops
@@ -2709,8 +2790,8 @@ mod tuples {
let (mut e, f) = S1::get_pair(); // $ target=get_pair type=e:S1 type=f:S1 let (mut e, f) = S1::get_pair(); // $ target=get_pair type=e:S1 type=f:S1
let (mut g, mut h) = S1::get_pair(); // $ target=get_pair type=g:S1 type=h:S1 let (mut g, mut h) = S1::get_pair(); // $ target=get_pair type=g:S1 type=h:S1
a.0.foo(); // $ target=foo a.0.foo(); // $ target=foo fieldof=Tuple2
b.1.foo(); // $ target=foo b.1.foo(); // $ target=foo fieldof=Tuple2
c.foo(); // $ target=foo c.foo(); // $ target=foo
d.foo(); // $ target=foo d.foo(); // $ target=foo
e.foo(); // $ target=foo e.foo(); // $ target=foo
@@ -2723,19 +2804,19 @@ mod tuples {
// `a` and `b` to be inferred. // `a` and `b` to be inferred.
let a = Default::default(); // $ target=default type=a:i64 let a = Default::default(); // $ target=default type=a:i64
let b = Default::default(); // $ target=default type=b:bool let b = Default::default(); // $ target=default type=b:bool
let pair = (a, b); // $ type=pair:0(2).i64 type=pair:1(2).bool let pair = (a, b); // $ type=pair:T0.i64 type=pair:T1.bool
let i: i64 = pair.0; let i: i64 = pair.0; // $ fieldof=Tuple2
let j: bool = pair.1; let j: bool = pair.1; // $ fieldof=Tuple2
let pair = [1, 1].into(); // $ type=pair:(T_2) type=pair:0(2).i32 type=pair:1(2).i32 MISSING: target=into let pair = [1, 1].into(); // $ type=pair:(T_2) type=pair:T0.i32 type=pair:T1.i32 MISSING: target=into
match pair { match pair {
(0, 0) => print!("unexpected"), (0, 0) => print!("unexpected"),
_ => print!("expected"), _ => print!("expected"),
} }
let x = pair.0; // $ type=x:i32 let x = pair.0; // $ type=x:i32 fieldof=Tuple2
let y = &S1::get_pair(); // $ target=get_pair let y = &S1::get_pair(); // $ target=get_pair
y.0.foo(); // $ target=foo y.0.foo(); // $ target=foo fieldof=Tuple2
} }
} }

View File

@@ -37,18 +37,18 @@ pub fn f() -> Option<()> {
let value3 = 42; let value3 = 42;
if let ref mesg = value3 { if let ref mesg = value3 {
let mesg = mesg; // $ type=mesg:&T.i32 let mesg = mesg; // $ type=mesg:TRef.i32
println!("{mesg}"); println!("{mesg}");
} }
let value4 = Some(42); let value4 = Some(42);
if let Some(ref mesg) = value4 { if let Some(ref mesg) = value4 {
let mesg = mesg; // $ type=mesg:&T.i32 let mesg = mesg; // $ type=mesg:TRef.i32
println!("{mesg}"); println!("{mesg}");
} }
let ref value5 = 42; let ref value5 = 42;
let x = value5; // $ type=x:&T.i32 let x = value5; // $ type=x:TRef.i32
let my_record_struct = MyRecordStruct { let my_record_struct = MyRecordStruct {
value1: 42, value1: 42,
@@ -102,7 +102,7 @@ pub fn f() -> Option<()> {
) => { ) => {
let a = value1; // $ type=a:bool let a = value1; // $ type=a:bool
let b = x; // $ type=b:i32 let b = x; // $ type=b:i32
let c = y; // $ type=c:&T.str let c = y; // $ type=c:TRef.str
(); ();
} }
_ => (), _ => (),
@@ -197,7 +197,7 @@ pub fn literal_patterns() {
let string_val = "hello"; let string_val = "hello";
match string_val { match string_val {
"hello" => { "hello" => {
let hello_match = string_val; // $ certainType=hello_match:&T.str let hello_match = string_val; // $ certainType=hello_match:TRef.str
println!("String literal: {}", hello_match); println!("String literal: {}", hello_match);
} }
_ => {} _ => {}
@@ -230,7 +230,7 @@ pub fn identifier_patterns() {
// IdentPat with ref // IdentPat with ref
match &value { match &value {
ref x => { ref x => {
let ref_bound = x; // $ type=ref_bound:&T.&T.i32 let ref_bound = x; // $ type=ref_bound:TRef.TRef.i32
println!("Reference identifier: {:?}", ref_bound); println!("Reference identifier: {:?}", ref_bound);
} }
} }
@@ -269,7 +269,7 @@ pub fn identifier_patterns() {
let mut ref_mut_val = 5i32; let mut ref_mut_val = 5i32;
match &mut ref_mut_val { match &mut ref_mut_val {
ref mut x => { ref mut x => {
let ref_mut_bound = x; // $ type=ref_mut_bound:&T.&T.i32 let ref_mut_bound = x; // $ type=ref_mut_bound:TRef.TRef.i32
**ref_mut_bound += 1; // $ target=deref target=add_assign **ref_mut_bound += 1; // $ target=deref target=add_assign
println!("Ref mut pattern"); println!("Ref mut pattern");
} }
@@ -341,14 +341,14 @@ pub fn reference_patterns() {
match &mut mutable_value { match &mut mutable_value {
&mut ref x => { &mut ref x => {
let mut_ref_bound = x; // $ type=mut_ref_bound:&T.i32 let mut_ref_bound = x; // $ type=mut_ref_bound:TRef.i32
println!("Mutable ref pattern: {}", mut_ref_bound); println!("Mutable ref pattern: {}", mut_ref_bound);
} }
} }
match &value { match &value {
ref x => { ref x => {
let ref_pattern = x; // $ type=ref_pattern:&T.&T.i32 let ref_pattern = x; // $ type=ref_pattern:TRef.TRef.i32
println!("Reference pattern: {}", ref_pattern); println!("Reference pattern: {}", ref_pattern);
} }
} }
@@ -525,7 +525,7 @@ pub fn slice_patterns() {
// SlicePat - Slice patterns // SlicePat - Slice patterns
match slice { match slice {
[] => { [] => {
let empty_slice = slice; // $ certainType=empty_slice:&T.[T].i32 let empty_slice = slice; // $ certainType=empty_slice:TRef.TSlice.i32
println!("Empty slice: {:?}", empty_slice); println!("Empty slice: {:?}", empty_slice);
} }
[x] => { [x] => {
@@ -540,7 +540,7 @@ pub fn slice_patterns() {
[first, middle @ .., last] => { [first, middle @ .., last] => {
let slice_start = *first; // $ MISSING: type=slice_start:i32 let slice_start = *first; // $ MISSING: type=slice_start:i32
let slice_end = *last; // $ MISSING: type=slice_end:i32 let slice_end = *last; // $ MISSING: type=slice_end:i32
let slice_middle = middle; // $ MISSING: type=slice_middle:&T.[T].i32 let slice_middle = middle; // $ MISSING: type=slice_middle:TRef.TSlice.i32
println!( println!(
"First: {}, last: {}, middle len: {}", "First: {}, last: {}, middle len: {}",
slice_start, slice_start,
@@ -717,7 +717,7 @@ pub fn complex_nested_patterns() {
} }
// Catch-all with identifier pattern // Catch-all with identifier pattern
other => { other => {
let other_complex = other; // $ type=other_complex:0(2).Point type=other_complex:1(2).MyOption let other_complex = other; // $ type=other_complex:T0.Point type=other_complex:T1.MyOption
println!("Other complex data: {:?}", other_complex); println!("Other complex data: {:?}", other_complex);
} }
} }
@@ -750,7 +750,7 @@ pub fn patterns_in_let_statements() {
// Let with reference pattern // Let with reference pattern
let value = 42i32; let value = 42i32;
let ref ref_val = value; let ref ref_val = value;
let let_ref = ref_val; // $ certainType=let_ref:&T.i32 let let_ref = ref_val; // $ certainType=let_ref:TRef.i32
// Let with mutable pattern // Let with mutable pattern
let mut mut_val = 10i32; let mut mut_val = 10i32;
@@ -779,13 +779,13 @@ pub fn patterns_in_function_parameters() {
// Call the functions to use them // Call the functions to use them
let point = Point { x: 5, y: 10 }; let point = Point { x: 5, y: 10 };
let extracted = extract_point(point); // $ target=extract_point certainType=extracted:0(2).i32 certainType=extracted:1(2).i32 let extracted = extract_point(point); // $ target=extract_point certainType=extracted:T0.i32 certainType=extracted:T1.i32
let color = Color(200, 100, 50); let color = Color(200, 100, 50);
let red = extract_color(color); // $ target=extract_color certainType=red:u8 let red = extract_color(color); // $ target=extract_color certainType=red:u8
let tuple = (42i32, 3.14f64, true); let tuple = (42i32, 3.14f64, true);
let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple certainType=tuple_extracted:0(2).i32 certainType=tuple_extracted:1(2).bool let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple certainType=tuple_extracted:T0.i32 certainType=tuple_extracted:T1.bool
} }
#[rustfmt::skip] #[rustfmt::skip]

View File

@@ -60,9 +60,10 @@ module TypeTest implements TestSig {
exists(AstNode n, TypePath path, Type t | exists(AstNode n, TypePath path, Type t |
t = TypeInference::inferType(n, path) and t = TypeInference::inferType(n, path) and
( (
if t = TypeInference::CertainTypeInference::inferCertainType(n, path) tag = "type"
then tag = "certainType" or
else tag = "type" t = TypeInference::CertainTypeInference::inferCertainType(n, path) and
tag = "certainType"
) and ) and
location = n.getLocation() and location = n.getLocation() and
( (

View File

@@ -23,3 +23,48 @@ pub struct isize;
// floating-point types // floating-point types
pub struct f32; pub struct f32;
pub struct f64; pub struct f64;
struct Slice<TSlice>;
struct Array<TArray, const N: usize>;
struct Ref<TRef>; // todo: add mut variant
struct Ptr<TPtr>; // todo: add mut variant
// tuples
struct Tuple0;
struct Tuple1<T0>(T0);
struct Tuple2<T0, T1>(T0, T1);
struct Tuple3<T0, T1, T2>(T0, T1, T2);
struct Tuple4<T0, T1, T2, T3>(T0, T1, T2, T3);
struct Tuple5<T0, T1, T2, T3, T4>(T0, T1, T2, T3, T4);
struct Tuple6<T0, T1, T2, T3, T4, T5>(T0, T1, T2, T3, T4, T5);
struct Tuple7<T0, T1, T2, T3, T4, T5, T6>(T0, T1, T2, T3, T4, T5, T6);
struct Tuple8<T0, T1, T2, T3, T4, T5, T6, T7>(T0, T1, T2, T3, T4, T5, T6, T7);
struct Tuple9<T0, T1, T2, T3, T4, T5, T6, T7, T8>(T0, T1, T2, T3, T4, T5, T6, T7, T8);
struct Tuple10<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
struct Tuple11<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
T0,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
);
struct Tuple12<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
T0,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
T11,
);

View File

@@ -992,7 +992,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
TypeMention constraintMention TypeMention constraintMention
) { ) {
exists(Type type | hasTypeConstraint(tt, type, constraint) | exists(Type type | hasTypeConstraint(tt, type, constraint) |
useUniversalConditions() and useUniversalConditions() and // todo: remove, and instead check constraints
not exists(countConstraintImplementations(type, constraint)) and not exists(countConstraintImplementations(type, constraint)) and
conditionSatisfiesConstraintTypeAt(abs, condition, constraintMention, _, _) and conditionSatisfiesConstraintTypeAt(abs, condition, constraintMention, _, _) and
resolveTypeMentionRoot(condition) = abs.getATypeParameter() and resolveTypeMentionRoot(condition) = abs.getATypeParameter() and