Merge pull request #2095 from hvitved/csharp/type-unification

C#: Type unification library
This commit is contained in:
Calum Grant
2019-11-13 09:48:59 +00:00
committed by GitHub
14 changed files with 1379 additions and 370 deletions

View File

@@ -47,5 +47,6 @@ The following changes in version 1.23 affect C# analysis in all applications.
`TaintTracking::localExprTaint` predicate to make it easy to use the most
common case of local data flow and taint: from one `Expr` to another.
* Data is now tracked through null-coalescing expressions (`??`).
* A new library `semmle.code.csharp.Unification` has been added. This library exposes two predicates `unifiable` and `subsumes` for calculating type unification and type subsumption, respectively.
## Changes to autobuilder

View File

@@ -79,4 +79,21 @@ module Stages {
forceCachingInSameStageRev()
}
}
cached
module UnificationStage {
private import semmle.code.csharp.Unification
cached
predicate forceCachingInSameStage() { any() }
cached
private predicate forceCachingInSameStageRev() {
exists(CompoundTypeKind k)
or
exists(Unification::UnconstrainedTypeParameter utp)
or
forceCachingInSameStageRev()
}
}
}

View File

@@ -15,29 +15,48 @@ import Type
private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.frameworks.system.collections.Generic
/**
* INTERNAL: Do not use.
*
* Holds if there exists an implicit conversion from `fromType` to `toType`.
*
* 6.1: Implicit type conversions.
*
* The following conversions are classified as implicit conversions:
*
* - Identity conversions
* - Implicit numeric conversions
* - Implicit nullable conversions
* - Implicit reference conversions
* - Boxing conversions
* - User-defined implicit conversions
*/
cached
predicate implicitConversion(Type fromType, Type toType) {
implicitConversionNonNull(fromType, toType)
or
defaultNullConversion(fromType, toType)
private module Cached {
/**
* INTERNAL: Do not use.
*
* Holds if there exists an implicit conversion from `fromType` to `toType`.
*
* 6.1: Implicit type conversions.
*
* The following conversions are classified as implicit conversions:
*
* - Identity conversions
* - Implicit numeric conversions
* - Implicit nullable conversions
* - Implicit reference conversions
* - Boxing conversions
* - User-defined implicit conversions
*/
cached
predicate implicitConversion(Type fromType, Type toType) {
implicitConversionNonNull(fromType, toType)
or
defaultNullConversion(fromType, toType)
}
/**
* INTERNAL: Do not use.
*
* Holds if there is a constant expression conversion from `fromType` to `toType`.
*
* 6.1.9: Implicit constant expression conversions.
*/
cached
predicate convConstantExpr(SignedIntegralConstantExpr e, SimpleType toType) {
convConstantIntExpr(e, toType)
or
convConstantLongExpr(e) and toType instanceof ULongType
}
}
import Cached
private predicate implicitConversionNonNull(Type fromType, Type toType) {
convIdentity(fromType, toType)
or
@@ -477,7 +496,7 @@ predicate convNullableType(ValueOrRefType fromType, NullableType toType) {
// This is a deliberate, small Cartesian product, so we have manually lifted it to force the
// evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
pragma[noinline]
private predicate defaultNullConversion(Type fromType, Type toType) {
predicate defaultNullConversion(Type fromType, Type toType) {
fromType instanceof NullType and convNullType(toType)
}
@@ -612,19 +631,6 @@ private predicate convBoxingValueType(ValueType fromType, Type toType) {
toType = fromType.getABaseInterface+()
}
/**
* INTERNAL: Do not use.
*
* Holds if there is a constant expression conversion from `fromType` to `toType`.
*
* 6.1.9: Implicit constant expression conversions.
*/
predicate convConstantExpr(SignedIntegralConstantExpr e, SimpleType toType) {
convConstantIntExpr(e, toType)
or
convConstantLongExpr(e) and toType instanceof ULongType
}
private class SignedIntegralConstantExpr extends Expr {
SignedIntegralConstantExpr() {
this.getType() instanceof SignedIntegralType and

View File

@@ -236,63 +236,13 @@ private Type getArgumentOrReturnType(Method m, int i) {
}
/**
* INTERNAL: Do not use.
*
* Provides an implementation of Global Value Numbering for types
* (see https://en.wikipedia.org/wiki/Global_value_numbering), where
* types are considered equal modulo identity conversions and method
* type parameters (at the same index).
*/
module Gvn {
private newtype TCompoundTypeKind =
TPointerTypeKind() or
TNullableTypeKind() or
TArrayTypeKind(int dim, int rnk) {
exists(ArrayType at | dim = at.getDimension() and rnk = at.getRank())
} or
TConstructedType(UnboundGenericType ugt)
/** A type kind for a compound type. */
class CompoundTypeKind extends TCompoundTypeKind {
int getNumberOfTypeParameters() {
this = TPointerTypeKind() and result = 1
or
this = TNullableTypeKind() and result = 1
or
this = TArrayTypeKind(_, _) and result = 1
or
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
result = ugt.getNumberOfTypeParameters()
)
}
string toString() {
this = TPointerTypeKind() and result = "*"
or
this = TNullableTypeKind() and result = "?"
or
exists(int dim, int rnk | this = TArrayTypeKind(dim, rnk) |
result = "[" + dim + ", " + rnk + "]"
)
or
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
result = ugt.getNameWithoutBrackets()
)
}
Location getLocation() { result instanceof EmptyLocation }
}
/** Gets the type kind for type `t`, if any. */
CompoundTypeKind getTypeKind(Type t) {
result = TPointerTypeKind() and t instanceof PointerType
or
result = TNullableTypeKind() and t instanceof NullableType
or
t = any(ArrayType at | result = TArrayTypeKind(at.getDimension(), at.getRank()))
or
result = TConstructedType(t.(ConstructedType).getUnboundGeneric())
}
private module Gvn {
private import semmle.code.csharp.Unification
private class MethodTypeParameter extends TypeParameter {
MethodTypeParameter() { this = any(UnboundGenericMethod ugm).getATypeParameter() }
@@ -310,38 +260,47 @@ module Gvn {
private newtype TGvnType =
TLeafGvnType(int i) { id(_, i) } or
TMethodTypeParameterGvnType(int i) { i = any(MethodTypeParameter p).getIndex() } or
TConstructedGvnType(TConstructedGvnType0 t)
TConstructedGvnType(ConstructedGvnTypeList l)
private newtype TConstructedGvnType0 =
private newtype TConstructedGvnTypeList =
TConstructedGvnTypeNil(CompoundTypeKind k) or
TConstructedGvnTypeCons(TGvnType head, TConstructedGvnType0 tail) {
gvnConstructedCons(_, _, head, tail)
TConstructedGvnTypeCons(GvnType head, ConstructedGvnTypeList tail) {
gvnConstructedCons(_, _, _, head, tail)
}
private TConstructedGvnType0 gvnConstructed(Type t, int i) {
result = TConstructedGvnTypeNil(getTypeKind(t)) and i = -1
private ConstructedGvnTypeList gvnConstructed(Type t, CompoundTypeKind k, int i) {
result = TConstructedGvnTypeNil(k) and
i = -1 and
k = getTypeKind(t)
or
exists(TGvnType head, TConstructedGvnType0 tail | gvnConstructedCons(t, i, head, tail) |
exists(GvnType head, ConstructedGvnTypeList tail | gvnConstructedCons(t, k, i, head, tail) |
result = TConstructedGvnTypeCons(head, tail)
)
}
pragma[noinline]
private TGvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) }
private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) }
pragma[noinline]
private predicate gvnConstructedCons(Type t, int i, TGvnType head, TConstructedGvnType0 tail) {
tail = gvnConstructed(t, i - 1) and
private predicate gvnConstructedCons(
Type t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail
) {
tail = gvnConstructed(t, k, i - 1) and
head = gvnTypeChild(t, i)
}
/** Gets the global value number for a given type. */
pragma[nomagic]
GvnType getGlobalValueNumber(Type t) {
result = TLeafGvnType(any(int i | id(t, i)))
or
result = TMethodTypeParameterGvnType(t.(MethodTypeParameter).getIndex())
or
result = TConstructedGvnType(gvnConstructed(t, getTypeKind(t).getNumberOfTypeParameters() - 1))
exists(ConstructedGvnTypeList l, CompoundTypeKind k, int i |
l = gvnConstructed(t, k, i) and
i = k.getNumberOfTypeParameters() - 1 and
result = TConstructedGvnType(l)
)
}
/** A global value number for a type. */
@@ -351,40 +310,42 @@ module Gvn {
or
exists(int i | this = TMethodTypeParameterGvnType(i) | result = "M!" + i)
or
exists(GvnConstructedType t | this = TConstructedGvnType(t) | result = t.toString())
exists(ConstructedGvnTypeList l | this = TConstructedGvnType(l) | result = l.toString())
}
Location getLocation() { result instanceof EmptyLocation }
}
/** A global value number for a constructed type. */
class GvnConstructedType extends TConstructedGvnType0 {
private CompoundTypeKind getKind() {
this = TConstructedGvnTypeNil(result)
private class ConstructedGvnTypeList extends TConstructedGvnTypeList {
private int length() {
this = TConstructedGvnTypeNil(_) and result = -1
or
exists(GvnConstructedType tail | this = TConstructedGvnTypeCons(_, tail) |
result = tail.getKind()
exists(ConstructedGvnTypeList tail | this = TConstructedGvnTypeCons(_, tail) |
result = tail.length() + 1
)
}
private GvnType getArg(int i) {
this = TConstructedGvnTypeCons(result, TConstructedGvnTypeNil(_)) and
i = 0
or
exists(GvnConstructedType tail | this = TConstructedGvnTypeCons(result, tail) |
exists(tail.getArg(i - 1))
exists(GvnType head, ConstructedGvnTypeList tail |
this = TConstructedGvnTypeCons(head, tail)
|
result = head and
i = this.length()
or
result = tail.getArg(i)
)
}
language[monotonicAggregates]
string toString() {
exists(CompoundTypeKind k | k = this.getKind() |
result = k + "<" +
concat(int i |
i in [0 .. k.getNumberOfTypeParameters() - 1]
|
this.getArg(i).toString(), ", "
) + ">"
exists(CompoundTypeKind k, string args |
this = gvnConstructed(_, k, _) and
args = concat(int i |
i in [0 .. k.getNumberOfTypeParameters() - 1]
|
this.getArg(i).toString(), ", " order by i
) and
result = k.toString(args)
)
}

View File

@@ -941,6 +941,8 @@ class TupleType extends ValueType, @tuple_type {
}
override string getLabel() { result = getUnderlyingType().getLabel() }
override Type getChild(int i) { result = this.getUnderlyingType().getChild(i) }
}
/**

View File

@@ -0,0 +1,629 @@
import csharp
private import Conversion
private import Caching
pragma[noinline]
private Type getAProperSubType(Type t) {
not result instanceof DynamicType and
not result instanceof NullType and
result.isImplicitlyConvertibleTo(t)
}
/**
* Provides an implementation of Global Value Numbering for types (see
* https://en.wikipedia.org/wiki/Global_value_numbering), where types are considered
* equal modulo identity conversions and type parameters.
*/
private module Gvn {
private class LeafType extends Type {
LeafType() {
not exists(this.getAChild()) and
not this instanceof TypeParameter
}
}
/** A type kind for a compound type. */
class CompoundTypeKindImpl extends TCompoundTypeKind {
/** Gets the number of type parameters for this kind. */
int getNumberOfTypeParameters() {
this = TPointerTypeKind() and result = 1
or
this = TNullableTypeKind() and result = 1
or
this = TArrayTypeKind(_, _) and result = 1
or
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
result = ugt.getNumberOfTypeParameters()
)
}
/** Gets a textual representation of this kind when applied to arguments `args`. */
bindingset[args]
string toString(string args) {
this = TPointerTypeKind() and result = args + "*"
or
this = TNullableTypeKind() and result = args + "?"
or
exists(int dim, int rnk | this = TArrayTypeKind(dim, rnk) |
result = args + "[" + dim + ", " + rnk + "]"
)
or
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
result = ugt.getNameWithoutBrackets() + "<" + args + ">"
)
}
/** Gets a textual representation of this kind. */
string toString() { result = toString("") }
/** Gets the location of this kind. */
Location getLocation() { result instanceof EmptyLocation }
}
/** Gets the type kind for type `t`, if any. */
CompoundTypeKind getTypeKindImpl(Type t) {
result = TPointerTypeKind() and t instanceof PointerType
or
result = TNullableTypeKind() and t instanceof NullableType
or
t = any(ArrayType at | result = TArrayTypeKind(at.getDimension(), at.getRank()))
or
result = TConstructedType(t.(ConstructedType).getUnboundGeneric())
or
result = TConstructedType(t.(TupleType).getUnderlyingType().getUnboundGeneric())
or
result = TConstructedType(t)
}
/**
* A global value number for a type. Two types have the same GVN when they
* are structurally equal modulo type parameters and identity conversions.
* For example, `Func<T, int>` and `Func<S, int>` have the same GVN, but
* `Func<T, int>` and `Func<string, int>` do not.
*/
class GvnType extends TGvnType {
/** Gets the compound type kind of this GVN, if any. */
CompoundTypeKind getKind() { none() }
/** Gets a textual representation of this GVN. */
string toString() {
exists(int i | this = TLeafGvnType(i) | result = i.toString())
or
this instanceof TTypeParameterGvnType and
result = "<type parameter>"
or
exists(ConstructedGvnTypeList l | this = TConstructedGvnType(l) | result = l.toString())
}
/** Gets the location of this GVN. */
Location getLocation() { result instanceof EmptyLocation }
}
class ConstructedGvnType extends GvnType, TConstructedGvnType {
private ConstructedGvnTypeList l;
ConstructedGvnType() { this = TConstructedGvnType(l) }
override CompoundTypeKind getKind() { result = l.getKind() }
}
private ConstructedGvnTypeList gvnConstructed(Type t, CompoundTypeKind k, int i) {
result = TConstructedGvnTypeNil(k) and
i = -1 and
k = getTypeKind(t)
or
exists(GvnType head, ConstructedGvnTypeList tail | gvnConstructedCons(t, k, i, head, tail) |
result = TConstructedGvnTypeCons(head, tail)
)
}
pragma[noinline]
private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) }
pragma[noinline]
private predicate gvnConstructedCons(
Type t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail
) {
tail = gvnConstructed(t, k, i - 1) and
head = gvnTypeChild(t, i)
}
private class ConstructedGvnTypeList extends TConstructedGvnTypeList {
CompoundTypeKind getKind() { this = gvnConstructed(_, result, _) }
private int length() {
this = TConstructedGvnTypeNil(_) and result = -1
or
exists(ConstructedGvnTypeList tail | this = TConstructedGvnTypeCons(_, tail) |
result = tail.length() + 1
)
}
GvnType getArg(int i) {
exists(GvnType head, ConstructedGvnTypeList tail |
this = TConstructedGvnTypeCons(head, tail)
|
result = head and
i = this.length()
or
result = tail.getArg(i)
)
}
language[monotonicAggregates]
string toString() {
exists(CompoundTypeKind k, string args |
k = this.getKind() and
args = concat(int i |
i in [0 .. k.getNumberOfTypeParameters() - 1]
|
this.getArg(i).toString(), ", " order by i
) and
result = k.toString(args)
)
}
Location getLocation() { result instanceof EmptyLocation }
}
/** A GVN type that is an argument in a constructed type. */
private class GvnTypeArgument extends GvnType {
GvnTypeArgument() { this = any(ConstructedGvnTypeList l).getArg(_) }
}
/** Gets the 'i'th type argument of GVN type `t`, which is of kind `k`. */
private GvnTypeArgument getTypeArgument(CompoundTypeKind k, ConstructedGvnType t, int i) {
exists(ConstructedGvnTypeList l | t = TConstructedGvnType(l) |
result = l.getArg(i) and
k = l.getKind()
)
}
pragma[noinline]
private GvnTypeArgument getNonTypeParameterTypeArgument(
CompoundTypeKind k, ConstructedGvnType t, int i
) {
result = getTypeArgument(k, t, i) and
result != TTypeParameterGvnType()
}
pragma[noinline]
private predicate typeArgumentIsTypeParameter(CompoundTypeKind k, ConstructedGvnType t, int i) {
getTypeArgument(k, t, i) = TTypeParameterGvnType()
}
/**
* Hold if (non-type-parameters) `arg1` and `arg2` are unifiable, and both are
* the `i`th type argument of a compound type of kind `k`.
*/
pragma[nomagic]
private predicate unifiableNonTypeParameterTypeArguments(
CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2, int i
) {
exists(int j |
arg1 = getNonTypeParameterTypeArgument(k, _, i) and
arg2 = getNonTypeParameterTypeArgument(k, _, j) and
i <= j and
j <= i
|
arg1 = arg2
or
unifiable(arg1, arg2)
)
}
/**
* Hold if `arg1` and `arg2` are unifiable, and both are the `i`th type argument
* of a compound type of kind `k`.
*/
pragma[nomagic]
private predicate unifiableTypeArguments(
CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2, int i
) {
unifiableNonTypeParameterTypeArguments(k, arg1, arg2, i)
or
exists(int j |
arg1 = TTypeParameterGvnType() and
typeArgumentIsTypeParameter(k, _, i) and
arg2 = getTypeArgument(k, _, j) and
i <= j and
j <= i
)
or
exists(int j |
arg1 = getTypeArgument(k, _, i) and
typeArgumentIsTypeParameter(k, _, j) and
arg2 = TTypeParameterGvnType() and
i <= j and
j <= i
)
}
pragma[nomagic]
private predicate unifiableSingle0(
CompoundTypeKind k, ConstructedGvnType t2, GvnTypeArgument arg1, GvnTypeArgument arg2
) {
unifiableTypeArguments(k, arg1, arg2, 0) and
arg2 = getTypeArgument(k, t2, 0) and
k.getNumberOfTypeParameters() = 1
}
/**
* Holds if the type arguments of types `t1` and `t2` are unifiable, `t1`
* and `t2` are of the same kind, and the number of type arguments is 1.
*/
private predicate unifiableSingle(ConstructedGvnType t1, ConstructedGvnType t2) {
exists(CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2 |
unifiableSingle0(k, t2, arg1, arg2) and
arg1 = getTypeArgument(k, t1, 0)
)
}
pragma[nomagic]
private predicate unifiableMultiple01Aux0(
CompoundTypeKind k, ConstructedGvnType t2, GvnTypeArgument arg10, GvnTypeArgument arg21
) {
exists(GvnTypeArgument arg20 |
unifiableTypeArguments(k, arg10, arg20, 0) and
arg20 = getTypeArgument(k, t2, 0) and
arg21 = getTypeArgument(k, t2, 1)
)
}
pragma[nomagic]
private predicate unifiableMultiple01Aux1(
CompoundTypeKind k, ConstructedGvnType t1, GvnTypeArgument arg10, GvnTypeArgument arg21
) {
exists(GvnTypeArgument arg11 |
unifiableTypeArguments(k, arg11, arg21, 1) and
arg10 = getTypeArgument(k, t1, 0) and
arg11 = getTypeArgument(k, t1, 1)
)
}
/**
* Holds if the first two type arguments of types `t1` and `t2` are unifiable,
* and both `t1` and `t2` are of kind `k`.
*/
private predicate unifiableMultiple01(
CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2
) {
exists(GvnTypeArgument arg10, GvnTypeArgument arg21 |
unifiableMultiple01Aux0(k, t2, arg10, arg21) and
unifiableMultiple01Aux1(k, t1, arg10, arg21)
)
}
pragma[nomagic]
private predicate unifiableMultiple2Aux(
CompoundTypeKind k, ConstructedGvnType t2, int i, GvnTypeArgument arg1, GvnTypeArgument arg2
) {
unifiableTypeArguments(k, arg1, arg2, i) and
arg2 = getTypeArgument(k, t2, i) and
i >= 2
}
private predicate unifiableMultiple2(
CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2, int i
) {
exists(GvnTypeArgument arg1, GvnTypeArgument arg2 |
unifiableMultiple2Aux(k, t2, i, arg1, arg2) and
arg1 = getTypeArgument(k, t1, i)
)
}
/**
* Holds if the arguments 0 through `i` (with `i >= 1`) of types
* `t1` and `t2` are unifiable, and both `t1` and `t2` are of kind `k`.
*/
pragma[nomagic]
private predicate unifiableMultiple(
CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2, int i
) {
unifiableMultiple01(k, t1, t2) and i = 1
or
unifiableMultiple(k, t1, t2, i - 1) and
unifiableMultiple2(k, t1, t2, i)
}
private newtype TTypePath =
TTypePathNil() or
TTypePathCons(int head, TTypePath tail) { exists(getTypeAtCons(_, head, tail)) }
/**
* Gets the GVN inside GVN `t`, by following the path `path`, if any.
*/
private GvnType getTypeAt(GvnType t, TTypePath path) {
path = TTypePathNil() and
result = t
or
exists(ConstructedGvnTypeList l, int head, TTypePath tail |
t = TConstructedGvnType(l) and
path = TTypePathCons(head, tail) and
result = getTypeAtCons(l, head, tail)
)
}
private GvnType getTypeAtCons(ConstructedGvnTypeList l, int head, TTypePath tail) {
result = getTypeAt(l.getArg(head), tail)
}
/**
* Gets the leaf GVN inside GVN `t`, by following the path `path`, if any.
*/
private GvnType getLeafTypeAt(GvnType t, TTypePath path) {
result = getTypeAt(t, path) and
not result instanceof ConstructedGvnType
}
private predicate id(LeafType t, int i) = equivalenceRelation(convIdentity/2)(t, i)
cached
private module Cached {
cached
newtype TCompoundTypeKind =
TPointerTypeKind() { Stages::UnificationStage::forceCachingInSameStage() } or
TNullableTypeKind() or
TArrayTypeKind(int dim, int rnk) {
exists(ArrayType at | dim = at.getDimension() and rnk = at.getRank())
} or
TConstructedType(UnboundGenericType ugt)
cached
newtype TGvnType =
TLeafGvnType(int i) { id(_, i) } or
TTypeParameterGvnType() or
TConstructedGvnType(ConstructedGvnTypeList l)
cached
newtype TConstructedGvnTypeList =
TConstructedGvnTypeNil(CompoundTypeKind k) or
TConstructedGvnTypeCons(GvnType head, ConstructedGvnTypeList tail) {
gvnConstructedCons(_, _, _, head, tail)
}
/** Gets the GVN for type `t`. */
cached
GvnType getGlobalValueNumber(Type t) {
result = TLeafGvnType(any(int i | id(t, i)))
or
t instanceof TypeParameter and
result = TTypeParameterGvnType()
or
exists(ConstructedGvnTypeList l, CompoundTypeKind k, int i |
l = gvnConstructed(t, k, i) and
i = k.getNumberOfTypeParameters() - 1 and
result = TConstructedGvnType(l)
)
}
/**
* Holds if GVNs `t1` and `t2` can be unified. That is, is it possible to
* replace all type parameters in `t1` and `t2` with some GVNs (possibly
* type parameters themselves) to make the two substituted terms equal.
*/
cached
predicate unifiable(ConstructedGvnType t1, ConstructedGvnType t2) {
unifiableSingle(t1, t2)
or
exists(CompoundTypeKind k | unifiableMultiple(k, t1, t2, k.getNumberOfTypeParameters() - 1))
}
/**
* Holds if GVN `t1` subsumes GVN `t2`. That is, is it possible to replace all
* type parameters in `t1` with some GVNs (possibly type parameters themselves)
* to make the two substituted terms equal.
*/
cached
predicate subsumes(ConstructedGvnType t1, ConstructedGvnType t2) {
unifiable(t1, t2) and // subsumption implies unification
forall(TTypePath path, GvnType leaf1 | leaf1 = getLeafTypeAt(t1, path) |
exists(GvnType child2 | child2 = getTypeAt(t2, path) |
leaf1 = TTypeParameterGvnType()
or
leaf1 = child2
)
)
}
}
import Cached
}
class CompoundTypeKind = Gvn::CompoundTypeKindImpl;
predicate getTypeKind = Gvn::getTypeKindImpl/1;
/** Provides definitions related to type unification. */
module Unification {
/** A type parameter that is compatible with any type. */
class UnconstrainedTypeParameter extends TypeParameter {
UnconstrainedTypeParameter() { not exists(getATypeConstraint(this)) }
}
/** A type parameter that is constrained. */
class ConstrainedTypeParameter extends TypeParameter {
int constraintCount;
ConstrainedTypeParameter() { constraintCount = strictcount(getATypeConstraint(this)) }
/**
* Holds if this type parameter is unifiable with type `t`.
*
* Note: This predicate is inlined.
*/
bindingset[t]
predicate unifiable(Type t) { none() }
/**
* Holds if this type parameter subsumes type `t`
*
* Note: This predicate is inlined.
*/
bindingset[t]
predicate subsumes(Type t) { none() }
}
/** A type parameter that has a single constraint. */
private class SingleConstraintTypeParameter extends ConstrainedTypeParameter {
SingleConstraintTypeParameter() { constraintCount = 1 }
bindingset[t]
override predicate unifiable(Type t) {
exists(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
ttc = TRefTypeConstraint() and
t.isRefType()
or
ttc = TValueTypeConstraint() and
t.isValueType()
or
typeConstraintUnifiable(ttc, t)
)
}
bindingset[t]
override predicate subsumes(Type t) {
exists(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
ttc = TRefTypeConstraint() and
t.isRefType()
or
ttc = TValueTypeConstraint() and
t.isValueType()
or
typeConstraintSubsumes(ttc, t)
)
}
}
/** A type parameter that has multiple constraints. */
private class MultiConstraintTypeParameter extends ConstrainedTypeParameter {
MultiConstraintTypeParameter() { constraintCount > 1 }
bindingset[t]
override predicate unifiable(Type t) {
forex(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
ttc = TRefTypeConstraint() and
t.isRefType()
or
ttc = TValueTypeConstraint() and
t.isValueType()
or
typeConstraintUnifiable(ttc, t)
)
}
bindingset[t]
override predicate subsumes(Type t) {
forex(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
ttc = TRefTypeConstraint() and
t.isRefType()
or
ttc = TValueTypeConstraint() and
t.isValueType()
or
typeConstraintSubsumes(ttc, t)
)
}
}
cached
private module Cached {
cached
newtype TTypeParameterConstraint =
TRefTypeConstraint() or
TValueTypeConstraint() or
TTypeConstraint(Type t) {
t = any(TypeParameterConstraints tpc).getATypeConstraint() and
not t instanceof TypeParameter
}
cached
TTypeParameterConstraint getATypeConstraint(TypeParameter tp) {
exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
tpc.hasRefTypeConstraint() and
result = TRefTypeConstraint()
or
tpc.hasNullableRefTypeConstraint() and
result = TRefTypeConstraint()
or
tpc.hasValueTypeConstraint() and
result = TValueTypeConstraint()
or
result = TTypeConstraint(tpc.getATypeConstraint())
or
result = getATypeConstraint(tpc.getATypeConstraint())
)
}
cached
predicate typeConstraintUnifiable(TTypeConstraint ttc, Type t) {
exists(Type t0 | ttc = TTypeConstraint(t0) | t = getAProperSubType(t0))
or
exists(Type t0, Type t1 | ttc = TTypeConstraint(t0) and unifiable(t0, t1) |
t = getAProperSubType(t1)
)
}
cached
predicate typeConstraintSubsumes(TTypeConstraint ttc, Type t) {
exists(Type t0 | ttc = TTypeConstraint(t0) | t = getAProperSubType(t0))
or
exists(Type t0, Type t1 | ttc = TTypeConstraint(t0) and subsumes(t0, t1) |
t = getAProperSubType(t1)
)
}
}
private import Cached
/**
* Holds if types `t1` and `t2` are unifiable. That is, is it possible to replace
* all type parameters in `t1` and `t2` with some (other) types to make the two
* substituted terms equal.
*
* This predicate covers only the case when `t1` and `t2` are constructed types;
* the other three cases are:
*
* 1. Neither `t1` nor `t2` are type parameters; in this case `t1` and `t2` must
* be equal.
* 2. `t1` or `t2` is an unconstrained type parameter; in this case `t1` and
* `t2` are always unifiable.
* 3. `t1` or `t2` is a constrained type parameter; in this case the predicate
* `ConstrainedTypeParameter::unifiable()` can be used.
*
*
* For performance reasons, type paramater constraints inside `t1` and `t2` are
* *not* taken into account, and there is also no guarantee that the same type
* parameter can be substituted with two different terms. For example, in
*
* ```csharp
* class C<T1, T2>
* {
* void M<T3>(C<T3, T3> c) where T3 : struct { }
* }
* ```
*
* the type `C<T3, T3>` is considered unifiable with both `C<object, object>` and
* `C<int, bool>`.
*
* Note: This predicate is inlined.
*/
pragma[inline]
predicate unifiable(Type t1, Type t2) {
Gvn::unifiable(Gvn::getGlobalValueNumber(t1), Gvn::getGlobalValueNumber(t2))
}
/**
* Holds if type `t1` subsumes type `t2`. That is, is it possible to replace all
* type parameters in `t1` with some (other) types to make the two types equal.
*
* The same limitations that apply to the predicate `unifiable()` apply to this
* predicate as well.
*
* Note: This predicate is inlined.
*/
pragma[inline]
predicate subsumes(Type t1, Type t2) {
Gvn::subsumes(Gvn::getGlobalValueNumber(t1), Gvn::getGlobalValueNumber(t2))
}
}

View File

@@ -7,11 +7,6 @@
import csharp
private import RuntimeCallable
private import OverridableCallable
private import semmle.code.csharp.Conversion
private import semmle.code.csharp.dataflow.internal.Steps
private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.frameworks.system.Reflection
/** A call. */
class DispatchCall extends Internal::TDispatchCall {
@@ -39,7 +34,12 @@ class DispatchCall extends Internal::TDispatchCall {
/** Internal implementation details. */
private module Internal {
private import semmle.code.csharp.Implements
private import OverridableCallable
private import semmle.code.csharp.Conversion
private import semmle.code.csharp.Unification
private import semmle.code.csharp.dataflow.internal.Steps
private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.frameworks.system.Reflection
cached
private module Cached {
@@ -166,7 +166,10 @@ private module Internal {
/** A call. */
abstract private class DispatchCallImpl extends TDispatchCall {
/** Gets a textual representation of this call. */
string toString() { none() }
string toString() { result = this.getCall().toString() }
/** Gets the location of this call. */
Location getLocation() { result = this.getCall().getLocation() }
/** Gets the underlying expression of this call. */
abstract Expr getCall();
@@ -185,56 +188,65 @@ private module Internal {
/** Gets a dynamic (run-time) target of this call, if any. */
abstract RuntimeCallable getADynamicTarget();
}
/**
* Holds if the qualifier of this call has type `qualifierType`.
* `isExactType` indicates whether the type is exact, that is, whether
* the qualifier is guaranteed not to be a subtype of `qualifierType`.
*/
predicate hasQualifierType(Type qualifierType, boolean isExactType) {
exists(Type trackedType | trackedType = getAPossibleType(this.getQualifier(), isExactType) |
qualifierType = trackedType and
not qualifierType instanceof TypeParameter
or
qualifierType = trackedType.(TypeParameter).getAnUltimatelySuppliedType()
)
pragma[noinline]
private predicate hasCallable(OverridableCallable source, ValueOrRefType t, OverridableCallable c) {
c.getSourceDeclaration() = source and
t.hasCallable(c) and
hasQualifierTypeOverridden0(t, _) and
hasQualifierTypeOverridden1(source, _)
}
pragma[noinline]
private Unification::ConstrainedTypeParameter getAConstrainedTypeParameterQualifierType(
DispatchMethodOrAccessorCall call
) {
result = getAPossibleType(call.getQualifier(), false)
}
pragma[noinline]
private predicate constrainedTypeParameterQualifierTypeSubsumes(
ValueOrRefType t, Unification::ConstrainedTypeParameter tp
) {
tp = getAConstrainedTypeParameterQualifierType(_) and
tp.subsumes(t)
}
pragma[noinline]
private predicate hasQualifierTypeOverridden0(ValueOrRefType t, DispatchMethodOrAccessorCall call) {
exists(Type t0 | t0 = getAPossibleType(call.getQualifier(), false) |
t = t0
or
Unification::subsumes(t0, t)
or
t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()
)
or
constrainedTypeParameterQualifierTypeSubsumes(t, getAConstrainedTypeParameterQualifierType(call))
}
pragma[noinline]
private predicate hasQualifierTypeOverridden1(
OverridableCallable c, DispatchMethodOrAccessorCall call
) {
exists(OverridableCallable target | call.getAStaticTarget() = target |
c = target.getSourceDeclaration()
or
c = target.getAnUltimateImplementor().getSourceDeclaration()
)
}
abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl {
pragma[nomagic]
predicate hasQualifierTypeInherited(SourceDeclarationType t) {
t = getAPossibleType(this.getQualifier(), _).getSourceDeclaration()
}
/**
* Gets a non-exact (see `hasQualifierType()`) qualifier type of this call
* that does not contain type parameters.
*/
private TypeWithoutTypeParameters getANonExactQualifierTypeWithoutTypeParameters() {
exists(Type qualifierType | hasQualifierType(qualifierType, false) |
// Qualifier type contains no type parameters: use it
result = qualifierType
or
// Qualifier type is a constructed type where all type arguments are type
// parameters: use the unbound generic type
exists(ConstructedType ct |
ct = qualifierType and
forex(Type arg | arg = ct.getATypeArgument() | arg instanceof TypeParameter) and
result = ct.getUnboundGeneric()
)
or
// Qualifier type is a constructed type where some (but not all) type arguments
// are type parameters: consider all potential instantiations
result = qualifierType.(QualifierTypeWithTypeParameters).getAPotentialInstance()
)
}
/**
* Gets a non-exact (see `hasQualifierType()`) qualifier type of this call.
*/
ValueOrRefType getANonExactQualifierType() {
exists(TypeWithoutTypeParameters t |
t = this.getANonExactQualifierTypeWithoutTypeParameters()
|
result.(ConstructedType).getUnboundGeneric() = t
or
not t instanceof UnboundGenericType and
result = t
)
pragma[nomagic]
predicate hasQualifierTypeOverridden(ValueOrRefType t, OverridableCallable c) {
hasQualifierTypeOverridden0(t, this) and
hasCallable(any(OverridableCallable oc | hasQualifierTypeOverridden1(oc, this)), t, c)
}
}
@@ -394,7 +406,7 @@ private module Internal {
* The set of viable targets is determined by taking virtual dispatch
* into account.
*/
private class DispatchMethodCall extends DispatchCallImpl, TDispatchMethodCall {
private class DispatchMethodCall extends DispatchMethodOrAccessorCall, TDispatchMethodCall {
override MethodCall getCall() { this = TDispatchMethodCall(result) }
override Expr getArgument(int i) {
@@ -453,11 +465,14 @@ private module Internal {
* `B.M`, and `B.M`, respectively.
*/
private RuntimeInstanceMethod getViableInherited() {
exists(NonConstructedOverridableMethod m, Type qualifierType, SourceDeclarationType t |
getAStaticTarget() = m.getAConstructingMethodOrSelf() and
hasQualifierType(qualifierType, _) and
t = qualifierType.getSourceDeclaration() and
exists(NonConstructedOverridableMethod m, SourceDeclarationType t |
this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and
this.hasQualifierTypeInherited(t)
|
result = m.getInherited(t)
or
t instanceof TypeParameter and
result = m
)
}
@@ -498,8 +513,7 @@ private module Internal {
*/
private RuntimeInstanceMethod getAViableOverrider() {
exists(ValueOrRefType t, NonConstructedOverridableMethod m |
t = this.getANonExactQualifierType() and
this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and
this.hasQualifierTypeOverridden(t, m.getAConstructingMethodOrSelf()) and
result = m.getAnOverrider(t)
)
}
@@ -514,7 +528,7 @@ private module Internal {
* The set of viable targets is determined by taking virtual dispatch
* into account.
*/
private class DispatchAccessorCall extends DispatchCallImpl, TDispatchAccessorCall {
private class DispatchAccessorCall extends DispatchMethodOrAccessorCall, TDispatchAccessorCall {
override AccessorCall getCall() { this = TDispatchAccessorCall(result) }
override Expr getArgument(int i) { result = getCall().getArgument(i) }
@@ -587,19 +601,11 @@ private module Internal {
private RuntimeAccessor getViableInherited() {
exists(OverridableAccessor a, SourceDeclarationType t |
this.getAStaticTarget() = a and
this.hasQualifierTypeSourceDecl(t) and
this.hasQualifierTypeInherited(t) and
result = a.getInherited(t)
)
}
pragma[noinline]
private predicate hasQualifierTypeSourceDecl(SourceDeclarationType t) {
exists(Type qualifierType |
this.hasQualifierType(qualifierType, _) and
t = qualifierType.getSourceDeclaration()
)
}
/**
* Gets an accessor that is defined in a subtype of the qualifier type of
* this call, and which overrides the static target of this call.
@@ -637,110 +643,32 @@ private module Internal {
* respectively.
*/
private RuntimeAccessor getAViableOverrider() {
exists(ValueOrRefType t | t = this.getANonExactQualifierType() |
result = this.getAStaticTarget().(OverridableAccessor).getAnOverrider(t)
exists(ValueOrRefType t, OverridableAccessor a |
this.hasQualifierTypeOverridden(t, a) and
result = a.getAnOverrider(t)
)
}
}
/** An internal helper class for comparing two types modulo type parameters. */
abstract private class StructurallyComparedModuloTypeParameters extends Type {
/** Gets a candidate for comparison against this type. */
abstract Type getACandidate();
/**
* Holds if this type equals the type `t` modulo type parameters.
*
* Equality modulo type parameters is a weaker form of type unifiability.
* That is, if constructed types `s` and `t` are unifiable, then `s` and
* `t` are equal modulo type parameters, but the converse does not
* necessarily hold. (For example, `C<int, string, T, T[]>` and
* `C<T, T, int, string[]>` are equal modulo type parameters, but not
* unifiable.)
*/
predicate equalsModuloTypeParameters(Type t) {
t = getACandidate() and
sameModuloTypeParameters(this, t)
}
/**
* Gets a potential instantiation of this type.
*
* A potential instantiation is a type without type parameters that
* is the result of replacing all type parameters in this type with
* non-type parameters. Note: the same type parameter may be replaced
* by different types at different positions. For example,
* `C<int, string>` is considered a potential instantiation of `C<T, T>`.
*/
TypeWithoutTypeParameters getAPotentialInstance() { equalsModuloTypeParameters(result) }
}
private Type candidateInternal(Type t) {
result = t.(StructurallyComparedModuloTypeParameters).getACandidate()
or
exists(Type parent, Type uncle, int i |
uncle = candidateInternal(parent) and
t = parent.getChild(i) and
result = uncle.getChild(i)
)
}
/** Holds if types `x` and `y` are equal modulo type parameters. */
private predicate sameModuloTypeParameters(Type x, Type y) {
y = candidateInternal(x) and
(
x = y
or
x instanceof TypeParameter
or
y instanceof TypeParameter
or
// All of the children must be structurally equal
sameChildrenModuloTypeParameters(x, y, x.getNumberOfChildren() - 1)
)
}
pragma[noinline]
private Type candidateInternalKind(Type t, Gvn::CompoundTypeKind k) {
result = candidateInternal(t) and
k = Gvn::getTypeKind(t)
}
/**
* Holds if the `i+1` first children of types `x` and `y` are equal
* modulo type parameters.
*/
pragma[nomagic]
private predicate sameChildrenModuloTypeParameters(Type x, Type y, int i) {
i = -1 and
y = candidateInternalKind(x, Gvn::getTypeKind(y))
or
sameChildrenModuloTypeParameters(x, y, i - 1) and
sameModuloTypeParameters(x.getChild(i), y.getChild(i))
}
/**
* A qualifier type containing type parameters for which at
* least one of the type arguments is *not* a type parameter.
*/
private class QualifierTypeWithTypeParameters extends StructurallyComparedModuloTypeParameters {
QualifierTypeWithTypeParameters() {
containsTypeParameters() and
any(DispatchCallImpl dc).hasQualifierType(this, false) and
exists(Type arg | arg = getAChild() | not arg instanceof TypeParameter)
}
override ConstructedType getACandidate() {
not result.containsTypeParameters() and
this.(ConstructedType).getUnboundGeneric() = result.getUnboundGeneric()
}
}
/** A reflection-based call or a call using dynamic types. */
abstract private class DispatchReflectionOrDynamicCall extends DispatchCallImpl {
/** Gets the name of the callable being called in this call. */
abstract string getName();
pragma[nomagic]
private predicate hasQualifierType(Type qualifierType, boolean isExactType) {
exists(Type t | t = getAPossibleType(this.getQualifier(), isExactType) |
qualifierType = t and
not t instanceof TypeParameter
or
Unification::subsumes(t, qualifierType)
or
t.(Unification::ConstrainedTypeParameter).unifiable(qualifierType)
or
qualifierType = t.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()
)
}
/**
* Gets a potential qualifier type of this call.
*
@@ -779,21 +707,17 @@ private module Internal {
this.hasQualifierType(result, true)
or
// Non-exact qualifier type
exists(Type qualifierType | this.hasNonExactQualifierType(qualifierType) |
exists(Type qualifierType | this.hasQualifierType(qualifierType, false) |
result = getANonExactQualifierSubType(qualifierType)
)
}
private predicate hasNonExactQualifierType(Type qualifierType) {
this.hasQualifierType(qualifierType, false)
}
/**
* Holds if the qualifier type is unknown (it is either `object` or
* `dynamic`).
*/
private predicate hasUnknownQualifierType() {
exists(Type qualifierType | this.hasNonExactQualifierType(qualifierType) |
exists(Type qualifierType | this.hasQualifierType(qualifierType, false) |
isUnknownType(qualifierType)
)
}
@@ -952,10 +876,21 @@ private module Internal {
private predicate reflectionOrDynamicArgEqualsParamModuloTypeParameters(
Type argumentType, Type parameterType
) {
exists(Type t | reflectionOrDynamicArgumentTypeIsImplicitlyConvertibleTo(argumentType, t) |
t
.(ReflectionOrDynamicCallArgumentWithTypeParameters)
.equalsModuloTypeParameters(parameterType)
exists(Type t |
reflectionOrDynamicArgumentTypeIsImplicitlyConvertibleTo(argumentType, t) and
isReflectionOrDynamicCallArgumentWithTypeParameters(t, parameterType)
|
parameterType = t
or
t instanceof Unification::UnconstrainedTypeParameter
or
parameterType instanceof Unification::UnconstrainedTypeParameter
or
t.(Unification::ConstrainedTypeParameter).unifiable(parameterType)
or
parameterType.(Unification::ConstrainedTypeParameter).unifiable(t)
or
Unification::unifiable(parameterType, t)
)
}
@@ -999,21 +934,6 @@ private module Internal {
)
}
/**
* A type that is the argument type of a reflection-based call or a call using
* dynamic types, where either the type or the relevant parameter type of a
* potential run-time target contains type parameters.
*/
private class ReflectionOrDynamicCallArgumentWithTypeParameters extends StructurallyComparedModuloTypeParameters {
ReflectionOrDynamicCallArgumentWithTypeParameters() {
isReflectionOrDynamicCallArgumentWithTypeParameters(this, _)
}
override Type getACandidate() {
isReflectionOrDynamicCallArgumentWithTypeParameters(this, result)
}
}
/** A call using reflection. */
private class DispatchReflectionCall extends DispatchReflectionOrDynamicCall,
TDispatchReflectionCall {

View File

@@ -185,28 +185,16 @@ class OverridableCallable extends Callable {
pragma[noinline]
private Callable getAnOverrider0(ValueOrRefType t) {
not this.declaredInTypeWithTypeParameters() and
(
// A (transitive) overrider
result = this.getAnOverrider+() and
t = result.getDeclaringType()
or
// An interface implementation
result = this.getAnImplementorSubType(t)
or
// A (transitive) overrider of an interface implementation
result = this.getAnOverridingImplementor() and
t = result.getDeclaringType()
)
}
private Callable getAnOverrider1(ValueOrRefType t) {
result = this.getAnOverrider0(t)
// A (transitive) overrider
result = this.getAnOverrider+() and
t = result.getDeclaringType()
or
exists(ValueOrRefType mid | result = this.getAnOverrider1(mid) |
t = mid.getABaseType() and
this.isDeclaringSubType(t)
)
// An interface implementation
result = this.getAnImplementorSubType(t)
or
// A (transitive) overrider of an interface implementation
result = this.getAnOverridingImplementor() and
t = result.getDeclaringType()
}
/**
@@ -220,36 +208,12 @@ class OverridableCallable extends Callable {
* contains a callable that overrides this callable, then only if `C2<int>`
* is ever constructed will the callable in `C2` be considered valid.
*/
Callable getAnOverrider(ValueOrRefType t) { result = this.getABoundInstance().getAnOverrider1(t) }
/**
* Gets a bound instance of this callable.
*
* If this callable is defined in a type that contains type parameters,
* returns an instance defined in a constructed type, otherwise the
* callable itself.
*/
private OverridableCallable getABoundInstance() {
not declaredInTypeWithTypeParameters() and
result = this
Callable getAnOverrider(ValueOrRefType t) {
result = this.getAnOverrider0(t)
or
result.getSourceDeclaration() = getSourceDeclarationInTypeWithTypeParameters()
}
// predicate folding to get proper join order
private OverridableCallable getSourceDeclarationInTypeWithTypeParameters() {
declaredInTypeWithTypeParameters() and
result = getSourceDeclaration()
}
private predicate declaredInTypeWithTypeParameters() {
exists(ValueOrRefType t | t = getDeclaringType() |
t.containsTypeParameters()
or
// Access to a local callable, `this.M()`, in a generic class
// results in a static target where the declaring type is
// the unbound generic version
t instanceof UnboundGenericType
exists(ValueOrRefType mid | result = this.getAnOverrider(mid) |
t = mid.getABaseType() and
this.isDeclaringSubType(t)
)
}
}
@@ -328,12 +292,7 @@ private int getAccessorKind(Accessor a) {
event_accessors(a, -result, _, _, _)
}
/** A type not containing type parameters. */
class TypeWithoutTypeParameters extends Type {
TypeWithoutTypeParameters() { not containsTypeParameters() }
}
/** A source declared type. */
class SourceDeclarationType extends TypeWithoutTypeParameters {
SourceDeclarationType() { this = getSourceDeclaration() }
class SourceDeclarationType extends Type {
SourceDeclarationType() { this = this.getSourceDeclaration() }
}

View File

@@ -41,21 +41,28 @@
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:241:23:241:27 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:241:23:241:27 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:241:23:241:27 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:241:23:241:27 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:35:242:37 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:35:242:37 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:35:242:37 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:35:242:37 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:40:242:42 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:40:242:42 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:40:242:42 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:40:242:42 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:40:243:42 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:40:243:42 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:40:243:42 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:40:243:42 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:71:243:73 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:71:243:73 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:71:243:73 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:71:243:73 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:56:244:58 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:56:244:58 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:56:244:58 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:56:244:58 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:64:244:69 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:64:244:69 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:64:244:69 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:64:244:69 | remove_Event |
@@ -67,11 +74,18 @@
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:252:56:252:58 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:252:64:252:69 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:257:26:257:30 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:257:26:257:30 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:258:32:258:34 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:258:32:258:34 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:258:37:258:39 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:258:37:258:39 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:259:40:259:42 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:259:40:259:42 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:259:71:259:73 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:259:71:259:73 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:260:53:260:55 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:260:53:260:55 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:260:61:260:66 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:260:61:260:66 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:265:26:265:30 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:266:24:266:24 | M |
@@ -91,6 +105,11 @@
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
@@ -103,6 +122,12 @@
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
@@ -115,12 +140,21 @@
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
@@ -128,11 +162,18 @@
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:293:26:293:30 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:293:26:293:30 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:294:31:294:33 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:294:31:294:33 | get_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:294:36:294:38 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:294:36:294:38 | set_Prop |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:295:39:295:41 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:295:39:295:41 | get_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:295:70:295:72 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:295:70:295:72 | set_Item |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:296:52:296:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:296:52:296:54 | add_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:296:60:296:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:296:60:296:65 | remove_Event |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:313:25:313:25 | M |
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:314:24:314:28 | M2 |
@@ -152,17 +193,25 @@
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:241:23:241:27 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:241:23:241:27 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:241:23:241:27 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:241:23:241:27 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:249:29:249:33 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:257:26:257:30 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:257:26:257:30 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:265:26:265:30 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:293:26:293:30 | M |
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:293:26:293:30 | M |
| ViableCallable.cs:281:17:281:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:281:17:281:19 | Run | ViableCallable.cs:293:26:293:30 | M |
| ViableCallable.cs:281:17:281:19 | Run | ViableCallable.cs:293:26:293:30 | M |
| ViableCallable.cs:298:17:298:19 | Run | ViableCallable.cs:276:24:276:28 | M |
| ViableCallable.cs:298:17:298:19 | Run | ViableCallable.cs:293:26:293:30 | M |
| ViableCallable.cs:348:17:348:19 | Run | ViableCallable.cs:346:10:346:10 | M |
@@ -174,6 +223,16 @@
| ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:397:36:397:40 | M |
| ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:403:53:403:57 | M |
| ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:405:42:405:46 | M |
| ViableCallable.cs:431:25:431:29 | M2 | ViableCallable.cs:442:17:442:23 | (...) => ... |
| ViableCallable.cs:436:10:436:10 | M | ViableCallable.cs:430:23:430:24 | M1 |
| ViableCallable.cs:436:10:436:10 | M | ViableCallable.cs:431:25:431:29 | M2 |
| ViableCallable.cs:431:22:431:26 | M2 | ViableCallable.cs:456:14:456:29 | (...) => ... |
| ViableCallable.cs:431:22:431:26 | M2 | ViableCallable.cs:462:14:462:29 | (...) => ... |
| ViableCallable.cs:436:10:436:11 | M1 | ViableCallable.cs:430:23:430:24 | M1 |
| ViableCallable.cs:436:10:436:11 | M1 | ViableCallable.cs:445:23:445:27 | M2 |
| ViableCallable.cs:445:23:445:27 | M2 | ViableCallable.cs:442:17:442:23 | (...) => ... |
| ViableCallable.cs:445:23:445:27 | M2 | ViableCallable.cs:450:14:450:20 | (...) => ... |
| ViableCallable.cs:445:23:445:27 | M2 | ViableCallable.cs:456:14:456:29 | (...) => ... |
| ViableCallable.cs:445:23:445:27 | M2 | ViableCallable.cs:462:14:462:29 | (...) => ... |
| ViableCallable.cs:447:10:447:14 | M3 | ViableCallable.cs:445:23:445:27 | M2 |
| ViableCallable.cs:453:10:453:14 | M4 | ViableCallable.cs:431:22:431:26 | M2 |
| ViableCallable.cs:453:10:453:14 | M4 | ViableCallable.cs:445:23:445:27 | M2 |
| ViableCallable.cs:459:10:459:14 | M5 | ViableCallable.cs:431:22:431:26 | M2 |
| ViableCallable.cs:459:10:459:14 | M5 | ViableCallable.cs:445:23:445:27 | M2 |

View File

@@ -66,102 +66,151 @@
| TypeFlow.cs:33:9:33:18 | call to method Method | TypeFlow.C2.Method() |
| TypeFlow.cs:37:11:37:26 | call to method Method | TypeFlow.C2.Method() |
| TypeFlow.cs:40:9:40:18 | call to method Method | TypeFlow.C2.Method() |
| ViableCallable.cs:12:9:12:28 | call to method M | C2<>.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C2<Boolean>.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C2<Decimal>.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C2<Int32>.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C3.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C4<>.M<T3>(T[], T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C4<Int32>.M<T3>(int[], T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C5.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C6<,>.M<T3>(T1, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C6<Boolean,Byte>.M<T3>(bool, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C6<Int32[],Boolean>.M<T3>(int[], T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C6<String,Boolean>.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C6<String,Decimal>.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C6<String,Int32>.M<T3>(string, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C6<T1,Boolean>.M<T3>(T1, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C6<T1,Byte>.M<T3>(T1, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C7<>.M<T3>(T1, T3) |
| ViableCallable.cs:12:9:12:28 | call to method M | C7<Boolean>.M<T3>(bool, T3) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C2<>.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C2<Boolean>.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C2<Decimal>.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C2<Int32>.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C3.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C4<>.set_Prop(T[]) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C4<Int32>.set_Prop(int[]) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C5.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<,>.set_Prop(T1) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<Boolean,Byte>.set_Prop(bool) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<Int32[],Boolean>.set_Prop(int[]) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<String,Boolean>.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<String,Decimal>.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<String,Int32>.set_Prop(string) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<T1,Boolean>.set_Prop(T1) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<T1,Byte>.set_Prop(T1) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C7<>.set_Prop(T1) |
| ViableCallable.cs:14:9:14:15 | access to property Prop | C7<Boolean>.set_Prop(bool) |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C2<>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C2<Boolean>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C2<Decimal>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C2<Int32>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C3.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C4<>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C4<Int32>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C5.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<,>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<Boolean,Byte>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<Int32[],Boolean>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<String,Boolean>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<String,Decimal>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<String,Int32>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<T1,Boolean>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<T1,Byte>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C7<>.get_Prop() |
| ViableCallable.cs:14:19:14:25 | access to property Prop | C7<Boolean>.get_Prop() |
| ViableCallable.cs:16:9:16:23 | access to indexer | C2<>.set_Item(T, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C2<Boolean>.set_Item(bool, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C2<Decimal>.set_Item(decimal, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C2<Int32>.set_Item(int, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C3.set_Item(decimal, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C4<>.set_Item(bool, T[]) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C4<Int32>.set_Item(bool, int[]) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C5.set_Item(bool, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<,>.set_Item(T2, T1) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<Boolean,Byte>.set_Item(byte, bool) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<Int32[],Boolean>.set_Item(bool, int[]) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<String,Boolean>.set_Item(bool, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<String,Decimal>.set_Item(decimal, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<String,Int32>.set_Item(int, string) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<T1,Boolean>.set_Item(bool, T1) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<T1,Byte>.set_Item(byte, T1) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C7<>.set_Item(byte, T1) |
| ViableCallable.cs:16:9:16:23 | access to indexer | C7<Boolean>.set_Item(byte, bool) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C2<>.get_Item(T) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C2<Boolean>.get_Item(bool) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C2<Decimal>.get_Item(decimal) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C2<Int32>.get_Item(int) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C3.get_Item(decimal) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C4<>.get_Item(bool) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C4<Int32>.get_Item(bool) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C5.get_Item(bool) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<,>.get_Item(T2) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<Boolean,Byte>.get_Item(byte) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<Int32[],Boolean>.get_Item(bool) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<String,Boolean>.get_Item(bool) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<String,Decimal>.get_Item(decimal) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<String,Int32>.get_Item(int) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<T1,Boolean>.get_Item(bool) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<T1,Byte>.get_Item(byte) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C7<>.get_Item(byte) |
| ViableCallable.cs:16:27:16:41 | access to indexer | C7<Boolean>.get_Item(byte) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C2<>.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C2<Boolean>.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C2<Decimal>.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C2<Int32>.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C3.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C4<>.add_Event(EventHandler<T[]>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C4<Int32>.add_Event(EventHandler<int[]>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C5.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<,>.add_Event(EventHandler<T1>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<Boolean,Byte>.add_Event(EventHandler<bool>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<Int32[],Boolean>.add_Event(EventHandler<int[]>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<String,Boolean>.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<String,Decimal>.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<String,Int32>.add_Event(EventHandler<string>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<T1,Boolean>.add_Event(EventHandler<T1>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<T1,Byte>.add_Event(EventHandler<T1>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C7<>.add_Event(EventHandler<T1>) |
| ViableCallable.cs:18:9:18:16 | access to event Event | C7<Boolean>.add_Event(EventHandler<bool>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C2<>.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C2<Boolean>.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C2<Decimal>.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C2<Int32>.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C3.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C4<>.remove_Event(EventHandler<T[]>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C4<Int32>.remove_Event(EventHandler<int[]>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C5.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<,>.remove_Event(EventHandler<T1>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<Boolean,Byte>.remove_Event(EventHandler<bool>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<Int32[],Boolean>.remove_Event(EventHandler<int[]>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<String,Boolean>.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<String,Decimal>.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<String,Int32>.remove_Event(EventHandler<string>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<T1,Boolean>.remove_Event(EventHandler<T1>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<T1,Byte>.remove_Event(EventHandler<T1>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C7<>.remove_Event(EventHandler<T1>) |
| ViableCallable.cs:19:9:19:16 | access to event Event | C7<Boolean>.remove_Event(EventHandler<bool>) |
| ViableCallable.cs:22:9:22:30 | call to method M | C4<>.M<T3>(T[], T3) |
| ViableCallable.cs:22:9:22:30 | call to method M | C4<Int32>.M<T3>(int[], T3) |
| ViableCallable.cs:22:9:22:30 | call to method M | C6<Int32[],Boolean>.M<T3>(int[], T3) |
| ViableCallable.cs:24:9:24:15 | access to property Prop | C4<>.set_Prop(T[]) |
| ViableCallable.cs:24:9:24:15 | access to property Prop | C4<Int32>.set_Prop(int[]) |
| ViableCallable.cs:24:9:24:15 | access to property Prop | C6<Int32[],Boolean>.set_Prop(int[]) |
| ViableCallable.cs:24:19:24:25 | access to property Prop | C4<>.get_Prop() |
| ViableCallable.cs:24:19:24:25 | access to property Prop | C4<Int32>.get_Prop() |
| ViableCallable.cs:24:19:24:25 | access to property Prop | C6<Int32[],Boolean>.get_Prop() |
| ViableCallable.cs:26:9:26:23 | access to indexer | C4<>.set_Item(bool, T[]) |
| ViableCallable.cs:26:9:26:23 | access to indexer | C4<Int32>.set_Item(bool, int[]) |
| ViableCallable.cs:26:9:26:23 | access to indexer | C6<Int32[],Boolean>.set_Item(bool, int[]) |
| ViableCallable.cs:26:27:26:41 | access to indexer | C4<>.get_Item(bool) |
| ViableCallable.cs:26:27:26:41 | access to indexer | C4<Int32>.get_Item(bool) |
| ViableCallable.cs:26:27:26:41 | access to indexer | C6<Int32[],Boolean>.get_Item(bool) |
| ViableCallable.cs:28:9:28:16 | access to event Event | C4<>.add_Event(EventHandler<T[]>) |
| ViableCallable.cs:28:9:28:16 | access to event Event | C4<Int32>.add_Event(EventHandler<int[]>) |
| ViableCallable.cs:28:9:28:16 | access to event Event | C6<Int32[],Boolean>.add_Event(EventHandler<int[]>) |
| ViableCallable.cs:29:9:29:16 | access to event Event | C4<>.remove_Event(EventHandler<T[]>) |
| ViableCallable.cs:29:9:29:16 | access to event Event | C4<Int32>.remove_Event(EventHandler<int[]>) |
| ViableCallable.cs:29:9:29:16 | access to event Event | C6<Int32[],Boolean>.remove_Event(EventHandler<int[]>) |
| ViableCallable.cs:32:30:32:52 | call to method Mock | ViableCallable.Mock<C1<string, int>>() |
@@ -264,10 +313,15 @@
| ViableCallable.cs:106:9:106:17 | access to event Event2 | C5.remove_Event2(EventHandler<string>) |
| ViableCallable.cs:120:9:120:25 | dynamic call to method M2 | C8.M2<decimal>(decimal[]) |
| ViableCallable.cs:124:9:124:24 | dynamic call to method M2 | C8.M2<string>(string[]) |
| ViableCallable.cs:132:9:132:28 | dynamic call to method M | C6<Boolean,Byte>.M<T3>(bool, T3) |
| ViableCallable.cs:132:9:132:28 | dynamic call to method M | C6<T1,Byte>.M<T3>(T1, T3) |
| ViableCallable.cs:134:9:134:14 | dynamic access to member Prop | C6<Boolean,Byte>.set_Prop(bool) |
| ViableCallable.cs:134:9:134:14 | dynamic access to member Prop | C6<T1,Byte>.set_Prop(T1) |
| ViableCallable.cs:134:18:134:23 | dynamic access to member Prop | C6<Boolean,Byte>.get_Prop() |
| ViableCallable.cs:134:18:134:23 | dynamic access to member Prop | C6<T1,Byte>.get_Prop() |
| ViableCallable.cs:136:9:136:18 | dynamic access to element | C6<Boolean,Byte>.set_Item(byte, bool) |
| ViableCallable.cs:136:9:136:18 | dynamic access to element | C6<T1,Byte>.set_Item(byte, T1) |
| ViableCallable.cs:136:22:136:31 | dynamic access to element | C6<Boolean,Byte>.get_Item(byte) |
| ViableCallable.cs:136:22:136:31 | dynamic access to element | C6<T1,Byte>.get_Item(byte) |
| ViableCallable.cs:138:9:138:52 | ... += ... | C6<T1,Byte>.add_Event(EventHandler<T1>) |
| ViableCallable.cs:139:9:139:52 | ... -= ... | C6<T1,Byte>.remove_Event(EventHandler<T1>) |
@@ -368,21 +422,29 @@
| ViableCallable.cs:195:9:195:152 | call to method InvokeMember | C10.set_Item(int, bool) |
| ViableCallable.cs:199:9:199:147 | call to method InvokeMember | C10.add_Event(EventHandler<bool>) |
| ViableCallable.cs:200:9:200:150 | call to method InvokeMember | C10.remove_Event(EventHandler<bool>) |
| ViableCallable.cs:235:9:235:15 | call to method M | C2<>.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C2<Boolean>.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C2<Decimal>.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C2<Int32>.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C3.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C4<>.M<T3>(T[], T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C4<Int32>.M<T3>(int[], T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C5.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C6<,>.M<T3>(T1, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C6<Boolean,Byte>.M<T3>(bool, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C6<Int32[],Boolean>.M<T3>(int[], T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C6<String,Boolean>.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C6<String,Decimal>.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C6<String,Int32>.M<T3>(string, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C6<T1,Boolean>.M<T3>(T1, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C6<T1,Byte>.M<T3>(T1, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C7<>.M<T3>(T1, T3) |
| ViableCallable.cs:235:9:235:15 | call to method M | C7<Boolean>.M<T3>(bool, T3) |
| ViableCallable.cs:284:9:284:15 | call to method M | C6<,>.M<T3>(T1, T3) |
| ViableCallable.cs:284:9:284:15 | call to method M | C7<>.M<T3>(T1, T3) |
| ViableCallable.cs:284:9:284:15 | call to method M | C7<Boolean>.M<T3>(bool, T3) |
| ViableCallable.cs:287:9:287:20 | call to method M | C6<,>.M<T3>(T1, T3) |
| ViableCallable.cs:287:9:287:20 | call to method M | C7<>.M<T3>(T1, T3) |
| ViableCallable.cs:287:9:287:20 | call to method M | C7<Boolean>.M<T3>(bool, T3) |
| ViableCallable.cs:301:9:301:15 | call to method M | C7<>.M<T3>(T1, T3) |
| ViableCallable.cs:304:9:304:20 | call to method M | C7<>.M<T3>(T1, T3) |
@@ -401,4 +463,9 @@
| ViableCallable.cs:424:9:424:21 | call to method M | C15.A4.M<T1>() |
| ViableCallable.cs:424:9:424:21 | call to method M | C15.A5.M<T1>() |
| ViableCallable.cs:439:9:439:19 | call to method M1 | C16<String,Int32>.M1(string) |
| ViableCallable.cs:442:9:442:24 | call to method M2 | C16<String,Int32>.M2<T>(Func<T>) |
| ViableCallable.cs:442:9:442:24 | call to method M2 | C17.M2<T>(Func<T>) |
| ViableCallable.cs:450:9:450:21 | call to method M2 | C17.M2<T>(Func<T>) |
| ViableCallable.cs:456:9:456:30 | call to method M2 | C16<T,Int32>.M2<T>(Func<T>) |
| ViableCallable.cs:456:9:456:30 | call to method M2 | C17.M2<T>(Func<T>) |
| ViableCallable.cs:462:9:462:30 | call to method M2 | C16<T,Int32>.M2<T>(Func<T>) |
| ViableCallable.cs:462:9:462:30 | call to method M2 | C17.M2<T>(Func<T>) |

View File

@@ -428,12 +428,12 @@ public class C15
abstract class C16<T1, T2>
{
public virtual T2 M1(T1 x) => throw null;
protected virtual T M2<T>(Func<T> x) => x();
public virtual T M2<T>(Func<T> x) => x();
}
class C17 : C16<string, int>
{
void M(int i)
void M1(int i)
{
// Viable callables: C16<string, int>.M1()
this.M1("");
@@ -441,4 +441,24 @@ class C17 : C16<string, int>
// Viable callables: C16<string, int>.M2<int>()
this.M2(() => i);
}
public override T M2<T>(Func<T> x) => x();
void M3<T>(T t, string s) where T : C17
{
// Viable callable: C17.M2()
t.M2(() => s);
}
void M4<T>(C16<T, int> c) where T : struct
{
// Viable callable: C16.M2() [also reports C17.M2(); false positive]
c.M2(() => default(T));
}
void M5<T>(C16<T, int> c) where T : class
{
// Viable callables: {C16,C17}.M1()
c.M2(() => default(T));
}
}

View File

@@ -0,0 +1,33 @@
interface I1 { }
struct S1 { } struct S2 { }
class C0 { }
class C1<T1> { }
class C2<T2> : C1<T2>, I1 where T2 : struct { }
class C3<T3> where T3 : class { }
class C4<T4> where T4 : C1<C0> { }
class C5<T5> where T5 : C1<S1>, I1 { }
class C6<T6a, T6b, T6c, T6d> where T6a : C1<T6d> where T6b : T6a, I1 where T6c : C3<T6b> where T6d : struct { }
class ConstructSomeTypes
{
C1<S1> f1;
C2<S1> f2;
C3<C1<S1>> f3;
C3<C2<S1>> f4;
C4<C1<C0>> f5;
C5<C2<S1>> f6;
C6<C1<S1>, C2<S1>, C3<C2<S1>>, S1> f7;
void M<Tm>(C6<C2<S2>, Tm, C3<Tm>, S2> x, C6<C2<S2>, C2<S2>, C3<C2<S2>>, S2> y) where Tm : C2<S2> { }
}
class Tuples<T8, T9>
{
static (T8, int) t1;
static (string, int) t2;
static (string, T9) t3;
static (T8, T9) t4;
static (T8 a, T9 b) t5 = t4;
}

View File

@@ -0,0 +1,298 @@
constrainedTypeParameterSubsumes
| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:8:3:9 | S1 |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:22:3:23 | S2 |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:7:10:7:11 | T2 |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:11:25:11:27 | T6d |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:32:12:32:23 | (T8,T9) |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:1:11:1:12 | I1 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:5:7:5:8 | C0 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<S1> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<S2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C1<S1>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C2<S1>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C2<S2>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:10:8:11 | T3 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<C1<C0>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:10:9:11 | T4 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<C2<S1>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:10:10:11 | T5 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<,,,> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:10:11:12 | T6a |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:15:11:17 | T6b |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:20:11:22 | T6c |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:13:7:13:24 | ConstructSomeTypes |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:23:12:23:13 | Tm |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:26:7:26:20 | Tuples<,> |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:9:10:9:11 | T4 |
| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:10:10:10:11 | T5 | Unification.cs:10:10:10:11 | T5 |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<S1> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<S2> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:9:10:9:11 | T4 |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:10:10:10:11 | T5 |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:10:11:12 | T6a |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:15:11:17 | T6b |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:23:12:23:13 | Tm |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:10:10:10:11 | T5 |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:11:15:11:17 | T6b |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:23:12:23:13 | Tm |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C1<S1>> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C2<S1>> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C2<S2>> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:11:20:11:22 | T6c |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:8:3:9 | S1 |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:22:3:23 | S2 |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:7:10:7:11 | T2 |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:11:25:11:27 | T6d |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:32:12:32:23 | (T8,T9) |
| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:23:12:23:13 | Tm | Unification.cs:23:12:23:13 | Tm |
constrainedTypeParameterSubsumptionImpliesUnification
constrainedTypeParameterUnifiable
| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:8:3:9 | S1 |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:22:3:23 | S2 |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:7:10:7:11 | T2 |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:11:25:11:27 | T6d |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:7:10:7:11 | T2 | Unification.cs:32:12:32:23 | (T8,T9) |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:1:11:1:12 | I1 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:5:7:5:8 | C0 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<S1> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<S2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C1<S1>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C2<S1>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C2<S2>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:10:8:11 | T3 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<C1<C0>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:10:9:11 | T4 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<C2<S1>> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:10:10:11 | T5 |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<,,,> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:10:11:12 | T6a |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:15:11:17 | T6b |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:20:11:22 | T6c |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:13:7:13:24 | ConstructSomeTypes |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:23:12:23:13 | Tm |
| Unification.cs:8:10:8:11 | T3 | Unification.cs:26:7:26:20 | Tuples<,> |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:9:10:9:11 | T4 |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:11:10:11:12 | T6a |
| Unification.cs:9:10:9:11 | T4 | Unification.cs:11:15:11:17 | T6b |
| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:10:10:10:11 | T5 | Unification.cs:10:10:10:11 | T5 |
| Unification.cs:10:10:10:11 | T5 | Unification.cs:11:15:11:17 | T6b |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<S1> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<S2> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:9:10:9:11 | T4 |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:10:10:10:11 | T5 |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:10:11:12 | T6a |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:15:11:17 | T6b |
| Unification.cs:11:10:11:12 | T6a | Unification.cs:23:12:23:13 | Tm |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:10:10:10:11 | T5 |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:11:15:11:17 | T6b |
| Unification.cs:11:15:11:17 | T6b | Unification.cs:23:12:23:13 | Tm |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C1<S1>> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C2<S1>> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C2<S2>> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:11:20:11:22 | T6c | Unification.cs:11:20:11:22 | T6c |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:8:3:9 | S1 |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:22:3:23 | S2 |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:7:10:7:11 | T2 |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:11:25:11:27 | T6d |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:11:25:11:27 | T6d | Unification.cs:32:12:32:23 | (T8,T9) |
| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:23:12:23:13 | Tm | Unification.cs:23:12:23:13 | Tm |
subsumes
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<S1> |
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<S2> |
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:6:7:6:12 | C1<C0> | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:6:7:6:12 | C1<S1> | Unification.cs:6:7:6:12 | C1<S1> |
| Unification.cs:6:7:6:12 | C1<S2> | Unification.cs:6:7:6:12 | C1<S2> |
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<S1> |
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<S2> |
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<C0> |
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<S1> |
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<S2> |
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:7:7:7:12 | C2<S1> | Unification.cs:7:7:7:12 | C2<S1> |
| Unification.cs:7:7:7:12 | C2<S2> | Unification.cs:7:7:7:12 | C2<S2> |
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<C1<S1>> |
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<C2<S1>> |
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<C2<S2>> |
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:8:7:8:12 | C3<C1<S1>> | Unification.cs:8:7:8:12 | C3<C1<S1>> |
| Unification.cs:8:7:8:12 | C3<C2<S1>> | Unification.cs:8:7:8:12 | C3<C2<S1>> |
| Unification.cs:8:7:8:12 | C3<C2<S2>> | Unification.cs:8:7:8:12 | C3<C2<S2>> |
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<C1<S1>> |
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<C2<S1>> |
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<C2<S2>> |
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<C1<S1>> |
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<C2<S1>> |
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<C2<S2>> |
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:9:7:9:12 | C4<> | Unification.cs:9:7:9:12 | C4<> |
| Unification.cs:9:7:9:12 | C4<> | Unification.cs:9:7:9:12 | C4<C1<C0>> |
| Unification.cs:9:7:9:12 | C4<C1<C0>> | Unification.cs:9:7:9:12 | C4<C1<C0>> |
| Unification.cs:10:7:10:12 | C5<> | Unification.cs:10:7:10:12 | C5<> |
| Unification.cs:10:7:10:12 | C5<> | Unification.cs:10:7:10:12 | C5<C2<S1>> |
| Unification.cs:10:7:10:12 | C5<C2<S1>> | Unification.cs:10:7:10:12 | C5<C2<S1>> |
| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<,,,> |
| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> |
| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
| Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> | Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> |
| Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
| Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
| Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
| Unification.cs:26:7:26:20 | Tuples<,> | Unification.cs:26:7:26:20 | Tuples<,> |
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:32:12:32:23 | (T8,T9) |
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:29:12:29:24 | (String,Int32) |
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:32:12:32:23 | (T8,T9) |
subsumptionImpliesUnification
unifiable
| Unification.cs:6:7:6:12 | C1<C0> | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:6:7:6:12 | C1<C0> | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:6:7:6:12 | C1<C0> | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:6:7:6:12 | C1<S1> | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:6:7:6:12 | C1<S1> | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:6:7:6:12 | C1<S1> | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:6:7:6:12 | C1<S2> | Unification.cs:6:7:6:12 | C1<> |
| Unification.cs:6:7:6:12 | C1<S2> | Unification.cs:6:7:6:12 | C1<T2> |
| Unification.cs:6:7:6:12 | C1<S2> | Unification.cs:6:7:6:12 | C1<T6d> |
| Unification.cs:7:7:7:12 | C2<S1> | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:7:7:7:12 | C2<S2> | Unification.cs:7:7:7:12 | C2<> |
| Unification.cs:8:7:8:12 | C3<C1<S1>> | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:8:7:8:12 | C3<C1<S1>> | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:8:7:8:12 | C3<C1<S1>> | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:8:7:8:12 | C3<C2<S1>> | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:8:7:8:12 | C3<C2<S1>> | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:8:7:8:12 | C3<C2<S1>> | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:8:7:8:12 | C3<C2<S2>> | Unification.cs:8:7:8:12 | C3<> |
| Unification.cs:8:7:8:12 | C3<C2<S2>> | Unification.cs:8:7:8:12 | C3<T6b> |
| Unification.cs:8:7:8:12 | C3<C2<S2>> | Unification.cs:8:7:8:12 | C3<Tm> |
| Unification.cs:9:7:9:12 | C4<C1<C0>> | Unification.cs:9:7:9:12 | C4<> |
| Unification.cs:10:7:10:12 | C5<C2<S1>> | Unification.cs:10:7:10:12 | C5<> |
| Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> | Unification.cs:11:7:11:28 | C6<,,,> |
| Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> | Unification.cs:11:7:11:28 | C6<,,,> |
| Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
| Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> | Unification.cs:11:7:11:28 | C6<,,,> |
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:32:12:32:23 | (T8,T9) |
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:30:12:30:23 | (String,T9) |
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:32:12:32:23 | (T8,T9) |
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:28:12:28:20 | (T8,Int32) |
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:31:12:31:19 | (T8,T9) |
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:32:12:32:23 | (T8,T9) |

View File

@@ -0,0 +1,37 @@
import semmle.code.csharp.Unification
class InterestingType extends Type {
InterestingType() {
this.fromSource() or
this.(TupleType).getAChild() instanceof InterestingType
}
}
query predicate constrainedTypeParameterSubsumes(InterestingType tp, InterestingType t) {
tp.(Unification::ConstrainedTypeParameter).subsumes(t)
}
// Should be empty
query predicate constrainedTypeParameterSubsumptionImpliesUnification(
InterestingType tp, InterestingType t
) {
tp.(Unification::ConstrainedTypeParameter).subsumes(t) and
not tp.(Unification::ConstrainedTypeParameter).unifiable(t)
}
query predicate constrainedTypeParameterUnifiable(InterestingType tp, InterestingType t) {
tp.(Unification::ConstrainedTypeParameter).unifiable(t)
}
query predicate subsumes(InterestingType t1, InterestingType t2) { Unification::subsumes(t1, t2) }
// Should be empty
query predicate subsumptionImpliesUnification(Type t1, Type t2) {
Unification::subsumes(t1, t2) and
not Unification::unifiable(t1, t2)
}
query predicate unifiable(InterestingType t1, InterestingType t2) {
Unification::unifiable(t1, t2) and
not Unification::subsumes(t1, t2)
}