Skip to content

Commit 00e62a1

Browse files
committed
C#: Improve unification logic to handle ref structs.
1 parent a358617 commit 00e62a1

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

csharp/ql/lib/semmle/code/csharp/Unification.qll

+29-9
Original file line numberDiff line numberDiff line change
@@ -522,16 +522,21 @@ module Gvn {
522522

523523
/** Provides definitions related to type unification. */
524524
module Unification {
525-
/** A type parameter that is compatible with any type. */
525+
/** A type parameter that is compatible with any type except `ref struct`. */
526526
class UnconstrainedTypeParameter extends TypeParameter {
527-
UnconstrainedTypeParameter() { not exists(getATypeConstraint(this)) }
527+
UnconstrainedTypeParameter() {
528+
not exists(getATypeConstraint(this)) and not exists(getANegativeTypeConstraint(this))
529+
}
528530
}
529531

530532
/** A type parameter that is constrained. */
531533
class ConstrainedTypeParameter extends TypeParameter {
532534
int constraintCount;
533535

534-
ConstrainedTypeParameter() { constraintCount = strictcount(getATypeConstraint(this)) }
536+
ConstrainedTypeParameter() {
537+
constraintCount = count(getATypeConstraint(this)) + count(getANegativeTypeConstraint(this)) and
538+
constraintCount > 0
539+
}
535540

536541
/**
537542
* Holds if this type parameter is unifiable with type `t`.
@@ -559,29 +564,31 @@ module Unification {
559564
bindingset[this]
560565
pragma[inline_late]
561566
override predicate unifiable(Type t) {
562-
exists(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
567+
forall(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
563568
ttc = TRefTypeConstraint() and
564569
t.isRefType()
565570
or
566571
ttc = TValueTypeConstraint() and
567572
t.isValueType()
568573
or
569574
typeConstraintUnifiable(ttc, t)
570-
)
575+
) and
576+
(t.isRefLikeType() implies getANegativeTypeConstraint(this) = TAllowRefTypeConstraint())
571577
}
572578

573579
bindingset[this]
574580
pragma[inline_late]
575581
override predicate subsumes(Type t) {
576-
exists(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
582+
forall(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
577583
ttc = TRefTypeConstraint() and
578584
t.isRefType()
579585
or
580586
ttc = TValueTypeConstraint() and
581587
t.isValueType()
582588
or
583589
typeConstraintSubsumes(ttc, t)
584-
)
590+
) and
591+
(t.isRefLikeType() implies getANegativeTypeConstraint(this) = TAllowRefTypeConstraint())
585592
}
586593
}
587594

@@ -603,7 +610,8 @@ module Unification {
603610
t.isValueType()
604611
or
605612
typeConstraintUnifiable(ttc, t)
606-
)
613+
) and
614+
(t.isRefLikeType() implies getANegativeTypeConstraint(this) = TAllowRefTypeConstraint())
607615
}
608616

609617
bindingset[this]
@@ -617,7 +625,8 @@ module Unification {
617625
t.isValueType()
618626
or
619627
typeConstraintSubsumes(ttc, t)
620-
)
628+
) and
629+
(t.isRefLikeType() implies getANegativeTypeConstraint(this) = TAllowRefTypeConstraint())
621630
}
622631
}
623632

@@ -632,6 +641,9 @@ module Unification {
632641
not t instanceof TypeParameter
633642
}
634643

644+
cached
645+
newtype TTypeParameterNegativeConstraint = TAllowRefTypeConstraint()
646+
635647
cached
636648
TTypeParameterConstraint getATypeConstraint(TypeParameter tp) {
637649
exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
@@ -650,6 +662,14 @@ module Unification {
650662
)
651663
}
652664

665+
cached
666+
TTypeParameterNegativeConstraint getANegativeTypeConstraint(TypeParameter tp) {
667+
exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
668+
tpc.hasAllowRefLikeTypeConstraint() and
669+
result = TAllowRefTypeConstraint()
670+
)
671+
}
672+
653673
cached
654674
predicate typeConstraintUnifiable(TTypeConstraint ttc, Type t) {
655675
exists(Type t0 | ttc = TTypeConstraint(t0) | implicitConversionRestricted(t, t0))

0 commit comments

Comments
 (0)