提交 2bded28b 编写于 作者: A AlekseyTs

Ensure proper validation of operator signatures when tuple types are involved.

Fixes #11986.
Fixes #11530.
上级 d1780905
......@@ -285,10 +285,9 @@ private void CheckUserDefinedConversionSignature(DiagnosticBag diagnostics)
// SPEC: Either S0 or T0 is the class or struct type in which the operator
// SPEC: declaration takes place.
if (source0 != this.ContainingType && target0 != this.ContainingType &&
if (source0.TupleUnderlyingTypeOrSelf() != this.ContainingType && target0.TupleUnderlyingTypeOrSelf() != this.ContainingType &&
// allow conversion between T and Nullable<T> in declaration of Nullable<T>
source.TupleUnderlyingTypeOrSelf() != this.ContainingType &&
target.TupleUnderlyingTypeOrSelf() != this.ContainingType)
source != this.ContainingType && target != this.ContainingType)
{
// CS0556: User-defined conversion must convert to or from the enclosing type
diagnostics.Add(ErrorCode.ERR_ConversionNotInvolvingContainedType, this.Locations[0]);
......
......@@ -11466,8 +11466,9 @@ static void Main()
System.Console.WriteLine(x <= 1);
}
}
";
var tuple = @"
namespace System
{
// struct with two values
......@@ -11640,11 +11641,7 @@ public override int GetHashCode()
}
";
var comp = CompileAndVerify(source,
additionalRefs: s_valueTupleRefs,
parseOptions: TestOptions.Regular,
options: TestOptions.ReleaseExe.WithAllowUnsafe(true),
expectedOutput:
var expectedOutput =
@"{1, 3}
4
{2, 4}
......@@ -11673,7 +11670,15 @@ public override int GetHashCode()
False
True
False
");
";
var lib = CreateCompilationWithMscorlib(tuple, options: TestOptions.ReleaseDll);
lib.VerifyDiagnostics();
var consumer1 = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, references: new[] { lib.ToMetadataReference() });
CompileAndVerify(consumer1, expectedOutput: expectedOutput).VerifyDiagnostics();
var consumer2 = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, references: new[] { lib.EmitToImageReference() });
CompileAndVerify(consumer2, expectedOutput: expectedOutput).VerifyDiagnostics();
}
[Fact]
......@@ -11723,8 +11728,8 @@ static void Main()
System.Console.WriteLine(x <= 1);
}
}
";
var tuple = @"
namespace System
{
// struct with two values
......@@ -11897,11 +11902,7 @@ public override int GetHashCode()
}
";
var comp = CompileAndVerify(source,
additionalRefs: s_valueTupleRefs,
parseOptions: TestOptions.Regular,
options: TestOptions.ReleaseExe.WithAllowUnsafe(true),
expectedOutput:
var expectedOutput =
@"{1, 3}
4
{2, 4}
......@@ -11930,7 +11931,663 @@ public override int GetHashCode()
False
True
False
");
";
var lib = CreateCompilationWithMscorlib(tuple, options: TestOptions.ReleaseDll);
lib.VerifyDiagnostics();
var consumer1 = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, references: new[] { lib.ToMetadataReference() });
CompileAndVerify(consumer1, expectedOutput: expectedOutput).VerifyDiagnostics();
var consumer2 = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, references: new[] { lib.EmitToImageReference() });
CompileAndVerify(consumer2, expectedOutput: expectedOutput).VerifyDiagnostics();
}
[Fact]
[WorkItem(11530, "https://github.com/dotnet/roslyn/issues/11530")]
public void UnifyUnderlyingWithTuple_10()
{
var source = @"
using System.Collections.Generic;
class Test
{
static void Main()
{
var a = new KeyValuePair<int, long>(1, 2);
(int, long) b = a;
System.Console.WriteLine(b.Item1);
System.Console.WriteLine(b.Item2);
b.Item1++;
b.Item2++;
a = b;
System.Console.WriteLine(a.Key);
System.Console.WriteLine(a.Value);
}
}
namespace System
{
public struct ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;
public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
public static implicit operator KeyValuePair<T1, T2>(ValueTuple<T1, T2> tuple)
{
T1 k;
T2 v;
(k, v) = tuple;
return new KeyValuePair<T1, T2>(k, v);
}
public static implicit operator ValueTuple<T1, T2>(KeyValuePair<T1, T2> kvp)
{
return (kvp.Key, kvp.Value);
}
}
}
";
var comp = CompileAndVerify(source,
parseOptions: TestOptions.Regular,
options: TestOptions.ReleaseExe,
expectedOutput:
@"1
2
2
3");
}
[Fact]
[WorkItem(11986, "https://github.com/dotnet/roslyn/issues/11986")]
public void UnifyUnderlyingWithTuple_11()
{
var source = @"
using System.Collections.Generic;
class Test
{
static void Main()
{
var a = (1, 2);
System.Console.WriteLine((int)a);
System.Console.WriteLine((long)a);
System.Console.WriteLine((string)a);
System.Console.WriteLine((double)a);
}
}
namespace System
{
public struct ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;
public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
public static explicit operator int((T1, T2)? source)
{
return 1;
}
public static explicit operator long(Nullable<(T1, T2)> source)
{
return 2;
}
public static explicit operator string(Nullable<ValueTuple<T1, T2>> source)
{
return ""3"";
}
public static explicit operator double(ValueTuple<T1, T2>? source)
{
return 4;
}
}
}
";
var comp = CompileAndVerify(source,
parseOptions: TestOptions.Regular,
options: TestOptions.ReleaseExe,
expectedOutput:
@"1
2
3
4");
}
[Fact]
public void UnifyUnderlyingWithTuple_12()
{
var source = @"
using System;
using System.Collections.Generic;
class C
{
static void Main()
{
(int, int)? x = (1, 3);
string s = x;
System.Console.WriteLine(s);
System.Console.WriteLine((long)x);
(int, string)? y = new KeyValuePair<int, string>(2, ""4"");
System.Console.WriteLine(y);
System.Console.WriteLine((ValueTuple<string, string>)""5"");
System.Console.WriteLine(+x);
System.Console.WriteLine(-x);
System.Console.WriteLine(!x);
System.Console.WriteLine(~x);
System.Console.WriteLine(++x);
System.Console.WriteLine(--x);
System.Console.WriteLine(x ? true : false);
System.Console.WriteLine(!x ? true : false);
System.Console.WriteLine(x + 1);
System.Console.WriteLine(x - 1);
System.Console.WriteLine(x * 3);
System.Console.WriteLine(x / 2);
System.Console.WriteLine(x % 3);
System.Console.WriteLine(x & 3);
System.Console.WriteLine(x | 15);
System.Console.WriteLine(x ^ 4);
System.Console.WriteLine(x << 1);
System.Console.WriteLine(x >> 1);
System.Console.WriteLine(x == 1);
System.Console.WriteLine(x != 1);
System.Console.WriteLine(x > 1);
System.Console.WriteLine(x < 1);
System.Console.WriteLine(x >= 1);
System.Console.WriteLine(x <= 1);
}
}
";
var tuple = @"
namespace System
{
// struct with two values
public struct ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;
public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
public override string ToString()
{
return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}';
}
public static implicit operator string(ValueTuple<T1, T2>? arg)
{
return arg.ToString();
}
public static explicit operator long(ValueTuple<T1, T2>? arg)
{
return ((long)(int)(object)arg.Value.Item1 + (long)(int)(object)arg.Value.Item2);
}
public static implicit operator ValueTuple<T1, T2>?(System.Collections.Generic.KeyValuePair<T1, T2> arg)
{
return new ValueTuple<T1, T2>(arg.Key, arg.Value);
}
public static explicit operator ValueTuple<T1, T2>?(string arg)
{
return new ValueTuple<T1, T2>((T1)(object)arg, (T2)(object)arg);
}
public static ValueTuple<T1, T2>? operator +(ValueTuple<T1, T2>? arg)
{
return arg;
}
public static long operator -(ValueTuple<T1, T2>? arg)
{
return -(long)arg;
}
public static bool operator !(ValueTuple<T1, T2>? arg)
{
return (long)arg == 0;
}
public static long operator ~(ValueTuple<T1, T2>? arg)
{
return -(long)arg;
}
public static ValueTuple<T1, T2>? operator ++(ValueTuple<T1, T2>? arg)
{
return new ValueTuple<T1, T2>((T1)(object)((int)(object)arg.Value.Item1+1), (T2)(object)((int)(object)arg.Value.Item2+1));
}
public static ValueTuple<T1, T2>? operator --(ValueTuple<T1, T2>? arg)
{
return new ValueTuple<T1, T2>((T1)(object)((int)(object)arg.Value.Item1 - 1), (T2)(object)((int)(object)arg.Value.Item2 - 1));
}
public static bool operator true(ValueTuple<T1, T2>? arg)
{
return (long)arg != 0;
}
public static bool operator false(ValueTuple<T1, T2>? arg)
{
return (long)arg == 0;
}
public static long operator + (ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 + arg2;
}
public static long operator -(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 - arg2;
}
public static long operator *(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 * arg2;
}
public static long operator /(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 / arg2;
}
public static long operator %(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 % arg2;
}
public static long operator &(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 & arg2;
}
public static long operator |(ValueTuple<T1, T2>? arg1, long arg2)
{
return (long)arg1 | arg2;
}
public static long operator ^(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 ^ arg2;
}
public static long operator <<(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 << arg2;
}
public static long operator >>(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 >> arg2;
}
public static bool operator ==(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 == arg2;
}
public static bool operator !=(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 != arg2;
}
public static bool operator >(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 > arg2;
}
public static bool operator <(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 < arg2;
}
public static bool operator >=(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 >= arg2;
}
public static bool operator <=(ValueTuple<T1, T2>? arg1, int arg2)
{
return (long)arg1 <= arg2;
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}
";
var expectedOutput =
@"{1, 3}
4
{2, 4}
{5, 5}
{1, 3}
-4
False
-4
{2, 4}
{1, 3}
True
False
5
3
12
2
1
0
15
0
8
2
False
True
True
False
True
False
";
var lib = CreateCompilationWithMscorlib(tuple, options: TestOptions.ReleaseDll);
lib.VerifyDiagnostics();
var consumer1 = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, references: new[] { lib.ToMetadataReference() });
CompileAndVerify(consumer1, expectedOutput: expectedOutput).VerifyDiagnostics();
var consumer2 = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, references: new[] { lib.EmitToImageReference() });
CompileAndVerify(consumer2, expectedOutput: expectedOutput).VerifyDiagnostics();
}
[Fact]
public void UnifyUnderlyingWithTuple_13()
{
var source = @"
using System;
using System.Collections.Generic;
class C
{
static void Main()
{
(int, int)? x = (1, 3);
string s = x;
System.Console.WriteLine(s);
System.Console.WriteLine((long)x);
(int, string)? y = new KeyValuePair<int, string>(2, ""4"");
System.Console.WriteLine(y);
System.Console.WriteLine((ValueTuple<string, string>)""5"");
System.Console.WriteLine(+x);
System.Console.WriteLine(-x);
System.Console.WriteLine(!x);
System.Console.WriteLine(~x);
System.Console.WriteLine(++x);
System.Console.WriteLine(--x);
System.Console.WriteLine(x ? true : false);
System.Console.WriteLine(!x ? true : false);
System.Console.WriteLine(x + 1);
System.Console.WriteLine(x - 1);
System.Console.WriteLine(x * 3);
System.Console.WriteLine(x / 2);
System.Console.WriteLine(x % 3);
System.Console.WriteLine(x & 3);
System.Console.WriteLine(x | 15);
System.Console.WriteLine(x ^ 4);
System.Console.WriteLine(x << 1);
System.Console.WriteLine(x >> 1);
System.Console.WriteLine(x == 1);
System.Console.WriteLine(x != 1);
System.Console.WriteLine(x > 1);
System.Console.WriteLine(x < 1);
System.Console.WriteLine(x >= 1);
System.Console.WriteLine(x <= 1);
}
}
";
var tuple = @"
namespace System
{
// struct with two values
public struct ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;
public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
public override string ToString()
{
return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}';
}
public static implicit operator string((T1, T2)? arg)
{
return arg.ToString();
}
public static explicit operator long((T1, T2)? arg)
{
return ((long)(int)(object)arg.Value.Item1 + (long)(int)(object)arg.Value.Item2);
}
public static implicit operator (T1, T2)?(System.Collections.Generic.KeyValuePair<T1, T2> arg)
{
return new (T1, T2)(arg.Key, arg.Value);
}
public static explicit operator (T1, T2)?(string arg)
{
return new (T1, T2)((T1)(object)arg, (T2)(object)arg);
}
public static (T1, T2)? operator +((T1, T2)? arg)
{
return arg;
}
public static long operator -((T1, T2)? arg)
{
return -(long)arg;
}
public static bool operator !((T1, T2)? arg)
{
return (long)arg == 0;
}
public static long operator ~((T1, T2)? arg)
{
return -(long)arg;
}
public static (T1, T2)? operator ++((T1, T2)? arg)
{
return new ValueTuple<T1, T2>((T1)(object)((int)(object)arg.Value.Item1+1), (T2)(object)((int)(object)arg.Value.Item2+1));
}
public static (T1, T2)? operator --((T1, T2)? arg)
{
return new ValueTuple<T1, T2>((T1)(object)((int)(object)arg.Value.Item1 - 1), (T2)(object)((int)(object)arg.Value.Item2 - 1));
}
public static bool operator true((T1, T2)? arg)
{
return (long)arg != 0;
}
public static bool operator false((T1, T2)? arg)
{
return (long)arg == 0;
}
public static long operator + ((T1, T2)? arg1, int arg2)
{
return (long)arg1 + arg2;
}
public static long operator -((T1, T2)? arg1, int arg2)
{
return (long)arg1 - arg2;
}
public static long operator *((T1, T2)? arg1, int arg2)
{
return (long)arg1 * arg2;
}
public static long operator /((T1, T2)? arg1, int arg2)
{
return (long)arg1 / arg2;
}
public static long operator %((T1, T2)? arg1, int arg2)
{
return (long)arg1 % arg2;
}
public static long operator &((T1, T2)? arg1, int arg2)
{
return (long)arg1 & arg2;
}
public static long operator |((T1, T2)? arg1, long arg2)
{
return (long)arg1 | arg2;
}
public static long operator ^((T1, T2)? arg1, int arg2)
{
return (long)arg1 ^ arg2;
}
public static long operator <<((T1, T2)? arg1, int arg2)
{
return (long)arg1 << arg2;
}
public static long operator >>((T1, T2)? arg1, int arg2)
{
return (long)arg1 >> arg2;
}
public static bool operator ==((T1, T2)? arg1, int arg2)
{
return (long)arg1 == arg2;
}
public static bool operator !=((T1, T2)? arg1, int arg2)
{
return (long)arg1 != arg2;
}
public static bool operator >((T1, T2)? arg1, int arg2)
{
return (long)arg1 > arg2;
}
public static bool operator <((T1, T2)? arg1, int arg2)
{
return (long)arg1 < arg2;
}
public static bool operator >=((T1, T2)? arg1, int arg2)
{
return (long)arg1 >= arg2;
}
public static bool operator <=((T1, T2)? arg1, int arg2)
{
return (long)arg1 <= arg2;
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}
";
var expectedOutput =
@"{1, 3}
4
{2, 4}
{5, 5}
{1, 3}
-4
False
-4
{2, 4}
{1, 3}
True
False
5
3
12
2
1
0
15
0
8
2
False
True
True
False
True
False
";
var lib = CreateCompilationWithMscorlib(tuple, options: TestOptions.ReleaseDll);
lib.VerifyDiagnostics();
var consumer1 = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, references: new[] { lib.ToMetadataReference() });
CompileAndVerify(consumer1, expectedOutput: expectedOutput).VerifyDiagnostics();
var consumer2 = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, references: new[] { lib.EmitToImageReference() });
CompileAndVerify(consumer2, expectedOutput: expectedOutput).VerifyDiagnostics();
}
[Fact]
......
......@@ -116,7 +116,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
' Anonymous type being translated
If namedTypeSymbol.IsAnonymousType Then
namedTypeSymbol = AnonymousTypeManager.TranslateAnonymousTypeSymbol(namedTypeSymbol)
ElseIf (namedTypeSymbol.IsTupleType) Then
ElseIf namedTypeSymbol.IsTupleType Then
Debug.Assert(Not needDeclaration)
namedTypeSymbol = namedTypeSymbol.TupleUnderlyingType
End If
......@@ -232,10 +232,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Optional needDeclaration As Boolean = False
) As Microsoft.Cci.IFieldReference
Debug.Assert(fieldSymbol Is fieldSymbol.OriginalDefinition OrElse
Not fieldSymbol.Equals(fieldSymbol.OriginalDefinition))
If fieldSymbol.IsTupleField Then
fieldSymbol = fieldSymbol.TupleUnderlyingField
End If
Not fieldSymbol.Equals(fieldSymbol.OriginalDefinition))
Debug.Assert(Not fieldSymbol.IsTupleField, "tuple fields should be rewritten to underlying by now")
Me.ProcessReferencedSymbol(fieldSymbol)
......@@ -339,12 +337,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
' Method of anonymous type being translated
If container.IsAnonymousType Then
methodSymbol = AnonymousTypeManager.TranslateAnonymousTypeMethodSymbol(methodSymbol)
End If
If methodSymbol.IsTupleMethod Then
ElseIf methodSymbol.IsTupleMethod Then
Debug.Assert(Not needDeclaration)
Debug.Assert(container.IsTupleType)
container = container.TupleUnderlyingType
methodSymbol = methodSymbol.TupleUnderlyingMethod
End If
Debug.Assert(Not container.IsTupleType)
Me.ProcessReferencedSymbol(methodSymbol)
If methodSymbol.OriginalDefinition IsNot methodSymbol Then
......
......@@ -453,7 +453,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
If containingType.SpecialType = SpecialType.System_Nullable_T Then
Return typeFromSignature Is containingType
Else
Return typeFromSignature.GetNullableUnderlyingTypeOrSelf() Is containingType
Return typeFromSignature.GetNullableUnderlyingTypeOrSelf().GetTupleUnderlyingTypeOrSelf() = containingType.GetTupleUnderlyingTypeOrSelf()
End If
End Function
......
......@@ -8232,6 +8232,485 @@ End Module
End Sub
<Fact>
Public Sub UnifyUnderlyingWithTuple_08()
Dim source =
<compilation>
<file name="a.vb"><![CDATA[
Imports System
Imports System.Collections.Generic
Module Module1
Sub Main()
Dim x = (1, 3)
Dim s As String = x
System.Console.WriteLine(s)
System.Console.WriteLine(CType(x, Long))
Dim y As (Integer, String) = New KeyValuePair(Of Integer, String)(2, "4")
System.Console.WriteLine(y)
System.Console.WriteLine(CType("5", ValueTuple(Of String, String)))
System.Console.WriteLine(+x)
System.Console.WriteLine(-x)
System.Console.WriteLine(Not x)
System.Console.WriteLine(If(x, True, False))
System.Console.WriteLine(If(Not x, True, False))
System.Console.WriteLine(x + 1)
System.Console.WriteLine(x - 1)
System.Console.WriteLine(x * 3)
System.Console.WriteLine(x / 2)
System.Console.WriteLine(x \ 2)
System.Console.WriteLine(x Mod 3)
System.Console.WriteLine(x & 3)
System.Console.WriteLine(x And 3)
System.Console.WriteLine(x Or 15)
System.Console.WriteLine(x Xor 3)
System.Console.WriteLine(x Like 15)
System.Console.WriteLine(x ^ 4)
System.Console.WriteLine(x << 1)
System.Console.WriteLine(x >> 1)
System.Console.WriteLine(x = 1)
System.Console.WriteLine(x <> 1)
System.Console.WriteLine(x > 1)
System.Console.WriteLine(x < 1)
System.Console.WriteLine(x >= 1)
System.Console.WriteLine(x <= 1)
End Sub
End Module
]]></file>
</compilation>
Dim tuple =
<compilation>
<file name="a.vb"><![CDATA[
Namespace System
Public Structure ValueTuple(Of T1, T2)
Public Item1 As T1
Public Item2 As T2
Public Sub New(item1 As T1, item2 As T2)
Me.Item1 = item1
Me.Item2 = item2
End Sub
Public Overrides Function ToString() As String
Return "{" + Item1?.ToString() + ", " + Item2?.ToString() + "}"
End Function
Public Shared Widening Operator CType(arg As ValueTuple(Of T1, T2)) As String
Return arg.ToString()
End Operator
Public Shared Narrowing Operator CType(arg As ValueTuple(Of T1, T2)) As Long
Return CLng(CObj(arg.Item1) + CObj(arg.Item2))
End Operator
Public Shared Widening Operator CType(arg As System.Collections.Generic.KeyValuePair(Of T1, T2)) As ValueTuple(Of T1, T2)
Return New ValueTuple(Of T1, T2)(arg.Key, arg.Value)
End Operator
Public Shared Narrowing Operator CType(arg As String) As ValueTuple(Of T1, T2)
Return New ValueTuple(Of T1, T2)(CType(CObj(arg), T1), CType(CObj(arg), T2))
End Operator
Public Shared Operator +(arg As ValueTuple(Of T1, T2)) As ValueTuple(Of T1, T2)
Return arg
End Operator
Public Shared Operator -(arg As ValueTuple(Of T1, T2)) As Long
Return -CType(arg, Long)
End Operator
Public Shared Operator Not(arg As ValueTuple(Of T1, T2)) As Boolean
Return CType(arg, Long) = 0
End Operator
Public Shared Operator IsTrue(arg As ValueTuple(Of T1, T2)) As Boolean
Return CType(arg, Long) <> 0
End Operator
Public Shared Operator IsFalse(arg As ValueTuple(Of T1, T2)) As Boolean
Return CType(arg, Long) = 0
End Operator
Public Shared Operator +(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) + arg2
End Operator
Public Shared Operator -(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) - arg2
End Operator
Public Shared Operator *(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) * arg2
End Operator
Public Shared Operator /(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) / arg2
End Operator
Public Shared Operator \(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) \ arg2
End Operator
Public Shared Operator Mod(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) Mod arg2
End Operator
Public Shared Operator &(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) & arg2
End Operator
Public Shared Operator And(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) And arg2
End Operator
Public Shared Operator Or(arg1 As ValueTuple(Of T1, T2), arg2 As Long) As Long
Return CType(arg1, Long) Or arg2
End Operator
Public Shared Operator Xor(arg1 As ValueTuple(Of T1, T2), arg2 As Long) As Long
Return CType(arg1, Long) Xor arg2
End Operator
Public Shared Operator Like(arg1 As ValueTuple(Of T1, T2), arg2 As Long) As Long
Return CType(arg1, Long) Or arg2
End Operator
Public Shared Operator ^(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) ^ arg2
End Operator
Public Shared Operator <<(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) << arg2
End Operator
Public Shared Operator >>(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Long
Return CType(arg1, Long) >> arg2
End Operator
Public Shared Operator =(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Boolean
Return CType(arg1, Long) = arg2
End Operator
Public Shared Operator <>(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Boolean
Return CType(arg1, Long) <> arg2
End Operator
Public Shared Operator >(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Boolean
Return CType(arg1, Long) > arg2
End Operator
Public Shared Operator <(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Boolean
Return CType(arg1, Long) < arg2
End Operator
Public Shared Operator >=(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Boolean
Return CType(arg1, Long) >= arg2
End Operator
Public Shared Operator <=(arg1 As ValueTuple(Of T1, T2), arg2 As Integer) As Boolean
Return CType(arg1, Long) <= arg2
End Operator
Public Overrides Function Equals(obj As Object) As Boolean
Return False
End Function
Public Overrides Function GetHashCode() As Integer
Return 0
End Function
End Structure
End Namespace
]]></file>
</compilation>
Dim expectedOutput =
"{1, 3}
4
{2, 4}
{5, 5}
{1, 3}
-4
False
True
False
5
3
12
2
2
1
43
0
15
7
15
256
8
2
False
True
True
False
True
False
"
Dim [lib] = CreateCompilationWithMscorlibAndVBRuntime(tuple, options:=TestOptions.ReleaseDll)
[lib].VerifyEmitDiagnostics()
Dim consumer1 = CreateCompilationWithMscorlibAndVBRuntime(source, options:=TestOptions.ReleaseExe, additionalRefs:={[lib].ToMetadataReference()})
CompileAndVerify(consumer1, expectedOutput:=expectedOutput).VerifyDiagnostics()
Dim consumer2 = CreateCompilationWithMscorlibAndVBRuntime(source, options:=TestOptions.ReleaseExe, additionalRefs:={[lib].EmitToImageReference()})
CompileAndVerify(consumer2, expectedOutput:=expectedOutput).VerifyDiagnostics()
End Sub
<Fact>
Public Sub UnifyUnderlyingWithTuple_12()
Dim source =
<compilation>
<file name="a.vb"><![CDATA[
Imports System
Imports System.Collections.Generic
Module Module1
Sub Main()
Dim x? = (1, 3)
Dim s As String = x
System.Console.WriteLine(s)
System.Console.WriteLine(CType(x, Long))
Dim y As (Integer, String)? = New KeyValuePair(Of Integer, String)(2, "4")
System.Console.WriteLine(y)
System.Console.WriteLine(CType("5", ValueTuple(Of String, String)))
System.Console.WriteLine(+x)
System.Console.WriteLine(-x)
System.Console.WriteLine(Not x)
System.Console.WriteLine(If(x, True, False))
System.Console.WriteLine(If(Not x, True, False))
System.Console.WriteLine(x + 1)
System.Console.WriteLine(x - 1)
System.Console.WriteLine(x * 3)
System.Console.WriteLine(x / 2)
System.Console.WriteLine(x \ 2)
System.Console.WriteLine(x Mod 3)
System.Console.WriteLine(x & 3)
System.Console.WriteLine(x And 3)
System.Console.WriteLine(x Or 15)
System.Console.WriteLine(x Xor 3)
System.Console.WriteLine(x Like 15)
System.Console.WriteLine(x ^ 4)
System.Console.WriteLine(x << 1)
System.Console.WriteLine(x >> 1)
System.Console.WriteLine(x = 1)
System.Console.WriteLine(x <> 1)
System.Console.WriteLine(x > 1)
System.Console.WriteLine(x < 1)
System.Console.WriteLine(x >= 1)
System.Console.WriteLine(x <= 1)
End Sub
End Module
]]></file>
</compilation>
Dim tuple =
<compilation>
<file name="a.vb"><![CDATA[
Namespace System
Public Structure ValueTuple(Of T1, T2)
Public Item1 As T1
Public Item2 As T2
Public Sub New(item1 As T1, item2 As T2)
Me.Item1 = item1
Me.Item2 = item2
End Sub
Public Overrides Function ToString() As String
Return "{" + Item1?.ToString() + ", " + Item2?.ToString() + "}"
End Function
Public Shared Widening Operator CType(arg As ValueTuple(Of T1, T2)?) As String
Return arg.ToString()
End Operator
Public Shared Narrowing Operator CType(arg As ValueTuple(Of T1, T2)?) As Long
Return CLng(CObj(arg.Value.Item1) + CObj(arg.Value.Item2))
End Operator
Public Shared Widening Operator CType(arg As System.Collections.Generic.KeyValuePair(Of T1, T2)) As ValueTuple(Of T1, T2)?
Return New ValueTuple(Of T1, T2)(arg.Key, arg.Value)
End Operator
Public Shared Narrowing Operator CType(arg As String) As ValueTuple(Of T1, T2)?
Return New ValueTuple(Of T1, T2)(CType(CObj(arg), T1), CType(CObj(arg), T2))
End Operator
Public Shared Operator +(arg As ValueTuple(Of T1, T2)?) As ValueTuple(Of T1, T2)?
Return arg
End Operator
Public Shared Operator -(arg As ValueTuple(Of T1, T2)?) As Long
Return -CType(arg, Long)
End Operator
Public Shared Operator Not(arg As ValueTuple(Of T1, T2)?) As Boolean
Return CType(arg, Long) = 0
End Operator
Public Shared Operator IsTrue(arg As ValueTuple(Of T1, T2)?) As Boolean
Return CType(arg, Long) <> 0
End Operator
Public Shared Operator IsFalse(arg As ValueTuple(Of T1, T2)?) As Boolean
Return CType(arg, Long) = 0
End Operator
Public Shared Operator +(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) + arg2
End Operator
Public Shared Operator -(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) - arg2
End Operator
Public Shared Operator *(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) * arg2
End Operator
Public Shared Operator /(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) / arg2
End Operator
Public Shared Operator \(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) \ arg2
End Operator
Public Shared Operator Mod(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) Mod arg2
End Operator
Public Shared Operator &(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) & arg2
End Operator
Public Shared Operator And(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) And arg2
End Operator
Public Shared Operator Or(arg1 As ValueTuple(Of T1, T2)?, arg2 As Long) As Long
Return CType(arg1, Long) Or arg2
End Operator
Public Shared Operator Xor(arg1 As ValueTuple(Of T1, T2)?, arg2 As Long) As Long
Return CType(arg1, Long) Xor arg2
End Operator
Public Shared Operator Like(arg1 As ValueTuple(Of T1, T2)?, arg2 As Long) As Long
Return CType(arg1, Long) Or arg2
End Operator
Public Shared Operator ^(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) ^ arg2
End Operator
Public Shared Operator <<(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) << arg2
End Operator
Public Shared Operator >>(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Long
Return CType(arg1, Long) >> arg2
End Operator
Public Shared Operator =(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Boolean
Return CType(arg1, Long) = arg2
End Operator
Public Shared Operator <>(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Boolean
Return CType(arg1, Long) <> arg2
End Operator
Public Shared Operator >(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Boolean
Return CType(arg1, Long) > arg2
End Operator
Public Shared Operator <(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Boolean
Return CType(arg1, Long) < arg2
End Operator
Public Shared Operator >=(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Boolean
Return CType(arg1, Long) >= arg2
End Operator
Public Shared Operator <=(arg1 As ValueTuple(Of T1, T2)?, arg2 As Integer) As Boolean
Return CType(arg1, Long) <= arg2
End Operator
Public Overrides Function Equals(obj As Object) As Boolean
Return False
End Function
Public Overrides Function GetHashCode() As Integer
Return 0
End Function
End Structure
End Namespace
]]></file>
</compilation>
Dim expectedOutput =
"{1, 3}
4
{2, 4}
{5, 5}
{1, 3}
-4
False
True
False
5
3
12
2
2
1
43
0
15
7
15
256
8
2
False
True
True
False
True
False
"
Dim [lib] = CreateCompilationWithMscorlibAndVBRuntime(tuple, options:=TestOptions.ReleaseDll)
[lib].VerifyEmitDiagnostics()
Dim consumer1 = CreateCompilationWithMscorlibAndVBRuntime(source, options:=TestOptions.ReleaseExe, additionalRefs:={[lib].ToMetadataReference()})
CompileAndVerify(consumer1, expectedOutput:=expectedOutput).VerifyDiagnostics()
Dim consumer2 = CreateCompilationWithMscorlibAndVBRuntime(source, options:=TestOptions.ReleaseExe, additionalRefs:={[lib].EmitToImageReference()})
CompileAndVerify(consumer2, expectedOutput:=expectedOutput).VerifyDiagnostics()
End Sub
End Class
End Namespace
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册