Merge pull request #11825 from michaelnebel/csharp/genericmathsupport

C# 11: Support for static virtual and static abstract interface members.
This commit is contained in:
Michael Nebel
2023-01-17 14:14:02 +01:00
committed by GitHub
13 changed files with 8389 additions and 15 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Remove operators from the virtualizable type.
compatibility: full

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Support for `static virtual` and `static abstract` interface members.
* Support for *operators* in interface definitions.

View File

@@ -129,7 +129,7 @@ pragma[nomagic]
private Virtualizable getACompatibleInterfaceMemberAux(Virtualizable m) {
result = getACompatibleInterfaceAccessor(m) or
result = getACompatibleInterfaceIndexer(m) or
result = getACompatibleInterfaceMethod(m)
result = getACompatibleRelevantInterfaceMember(m)
}
/**
@@ -210,11 +210,13 @@ private predicate getACompatibleInterfaceIndexerAux(Indexer i, ValueOrRefType t)
t = getAPossibleImplementor(i.getDeclaringType())
}
private Method getACompatibleInterfaceMethod0(Method m, int i) {
result = getAnInterfaceMethodCandidate(m) and
private RelevantInterfaceMember getACompatibleRelevantInterfaceMember0(
RelevantInterfaceMember m, int i
) {
result = getARelevantInterfaceMemberCandidate(m) and
i = -1
or
result = getACompatibleInterfaceMethod0(m, i - 1) and
result = getACompatibleRelevantInterfaceMember0(m, i - 1) and
exists(Type t1, Type t2 |
t1 = getArgumentOrReturnType(m, i) and
t2 = getArgumentOrReturnType(result, i)
@@ -223,32 +225,47 @@ private Method getACompatibleInterfaceMethod0(Method m, int i) {
)
}
private Method getACompatibleInterfaceMethod(Method m) {
result = getACompatibleInterfaceMethod0(m, m.getNumberOfParameters())
/**
* A class of callables relevant for interface member compatibility.
*/
private class RelevantInterfaceMember extends Callable {
RelevantInterfaceMember() {
this instanceof Method or
this instanceof Operator
}
predicate isPublic() {
this.(Method).isPublic() or
this.(Operator).isPublic()
}
}
private RelevantInterfaceMember getACompatibleRelevantInterfaceMember(RelevantInterfaceMember m) {
result = getACompatibleRelevantInterfaceMember0(m, m.getNumberOfParameters())
}
/**
* Gets an interface method that may potentially be implemented by `m`.
* Gets an interface method or operator that may potentially be implemented by `m`.
*
* That is, a method with the same name, same number of parameters, and declared
* in a type that is a possible implementor type for the interface type.
*/
private Method getAnInterfaceMethodCandidate(Method m) {
getAPotentialInterfaceMethodAux(result, m.getDeclaringType(), m.getUndecoratedName(),
private RelevantInterfaceMember getARelevantInterfaceMemberCandidate(RelevantInterfaceMember m) {
getAPotentialRelevantInterfaceMemberAux(result, m.getDeclaringType(), m.getUndecoratedName(),
m.getNumberOfParameters()) and
m.isPublic()
}
pragma[nomagic]
private predicate getAPotentialInterfaceMethodAux(
Method m, ValueOrRefType t, string name, int params
private predicate getAPotentialRelevantInterfaceMemberAux(
RelevantInterfaceMember m, ValueOrRefType t, string name, int params
) {
t = getAPossibleImplementor(m.getDeclaringType()) and
name = m.getUndecoratedName() and
params = m.getNumberOfParameters()
}
private Type getArgumentOrReturnType(Method m, int i) {
private Type getArgumentOrReturnType(RelevantInterfaceMember m, int i) {
i = 0 and result = m.getReturnType()
or
result = m.getParameter(i - 1).getType()

View File

@@ -184,7 +184,7 @@ private class TOverridable = @virtualizable or @callable_accessor;
/**
* A declaration that can be overridden or implemented. That is, a method,
* a property, an indexer, an event, or an accessor.
* a property, an indexer, an event, an accessor, or an operator.
*
* Unlike `Virtualizable`, this class includes accessors.
*/
@@ -360,7 +360,7 @@ class Overridable extends Declaration, TOverridable {
/**
* A member where the `virtual` modifier is valid. That is, a method,
* a property, an indexer, or an event.
* a property, an indexer, an event, or an operator.
*
* Equivalently, these are the members that can be defined in an interface.
*

View File

@@ -670,7 +670,7 @@ compiler_generated(unique int id: @modifiable ref);
@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
@virtualizable = @method | @property | @indexer | @event;
@virtualizable = @method | @property | @indexer | @event | @operator;
exprorstmt_name(
unique int parent_id: @named_exprorstmt ref,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add operators to the virtualizable type.
compatibility: full

View File

@@ -0,0 +1,34 @@
public interface INumber<T> where T : INumber<T>
{
static abstract T operator ++(T other);
static virtual T operator --(T other) => other;
static abstract T Add(T left, T right);
static virtual T Subtract(T left, T right) => left;
static T Zero() => default(T);
}
public class Complex : INumber<Complex>
{
public double Real { get; private set; } = 0.0;
public double Imaginary { get; private set; } = 0.0;
public Complex() { }
public static Complex Zero() => new Complex();
public static Complex operator ++(Complex other) =>
new Complex { Real = other.Real + 1.0, Imaginary = other.Imaginary };
public static Complex operator --(Complex other) =>
new Complex { Real = other.Real - 1.0, Imaginary = other.Imaginary };
public static Complex Add(Complex left, Complex right) =>
new Complex { Real = left.Real + right.Real, Imaginary = left.Imaginary + right.Imaginary };
public static Complex Subtract(Complex left, Complex right) =>
new Complex { Real = left.Real - right.Real, Imaginary = left.Imaginary - right.Imaginary };
}

View File

@@ -0,0 +1,20 @@
interfacemembers
| INumber<> | StaticInterfaceMembers.cs:3:32:3:33 | ++ | abstract |
| INumber<> | StaticInterfaceMembers.cs:3:32:3:33 | ++ | public |
| INumber<> | StaticInterfaceMembers.cs:3:32:3:33 | ++ | static |
| INumber<> | StaticInterfaceMembers.cs:5:31:5:32 | -- | public |
| INumber<> | StaticInterfaceMembers.cs:5:31:5:32 | -- | static |
| INumber<> | StaticInterfaceMembers.cs:5:31:5:32 | -- | virtual |
| INumber<> | StaticInterfaceMembers.cs:7:23:7:25 | Add | abstract |
| INumber<> | StaticInterfaceMembers.cs:7:23:7:25 | Add | public |
| INumber<> | StaticInterfaceMembers.cs:7:23:7:25 | Add | static |
| INumber<> | StaticInterfaceMembers.cs:9:22:9:29 | Subtract | public |
| INumber<> | StaticInterfaceMembers.cs:9:22:9:29 | Subtract | static |
| INumber<> | StaticInterfaceMembers.cs:9:22:9:29 | Subtract | virtual |
| INumber<> | StaticInterfaceMembers.cs:11:14:11:17 | Zero | public |
| INumber<> | StaticInterfaceMembers.cs:11:14:11:17 | Zero | static |
implements
| StaticInterfaceMembers.cs:23:36:23:37 | ++ | StaticInterfaceMembers.cs:3:32:3:33 | ++ |
| StaticInterfaceMembers.cs:26:36:26:37 | -- | StaticInterfaceMembers.cs:5:31:5:32 | -- |
| StaticInterfaceMembers.cs:29:27:29:29 | Add | StaticInterfaceMembers.cs:7:23:7:25 | Add |
| StaticInterfaceMembers.cs:32:27:32:34 | Subtract | StaticInterfaceMembers.cs:9:22:9:29 | Subtract |

View File

@@ -0,0 +1,18 @@
import csharp
query predicate interfacemembers(string interface, Member m, string modifier) {
exists(Interface i |
i.isUnboundDeclaration() and
i.getFile().getStem() = "StaticInterfaceMembers" and
i.getName() = interface and
m = i.getAMember() and
modifier = m.getAModifier().getName()
)
}
query predicate implements(Overridable o, Virtualizable v) {
v.getFile().getStem() = "StaticInterfaceMembers" and
(v.isVirtual() or v.isAbstract()) and
v.isStatic() and
v.getAnImplementor() = o
}