提交 3eec1c45 编写于 作者: A AlekseyTs

Merge pull request #11328 from AlekseyTs/TupleTests02

Fix some issues around tuples and add unit-tests for others.
......@@ -1832,15 +1832,11 @@ private bool ExpressionMatchExactly(BoundExpression node, TypeSymbol t, ref Hash
if (node.Kind == BoundKind.TupleLiteral)
{
if ((object)node.Type != null)
{
// expression has a natural type and
// did not have identity conversion to the target (since we are here),
// no point trying element-wise match - we know that will fail.
return false;
}
// recurse into tuple constituent arguments
// Recurse into tuple constituent arguments.
// Even if the tuple literal has a natural type and conversion
// from that type is not identity, we still have to do this
// because we might be converting to a tuple type backed by
// different definition of ValueTuple type.
return ExpressionMatchExactly((BoundTupleLiteral)node, t, ref useSiteDiagnostics);
}
......@@ -1949,8 +1945,6 @@ private bool ExpressionMatchExactly(BoundTupleLiteral tupleSource, TypeSymbol ta
}
var destination = (NamedTypeSymbol)targetType;
Debug.Assert((object)tupleSource.Type == null, "should not need to dig into elements if tuple has natural type");
var sourceArguments = tupleSource.Arguments;
// check if the type is actually compatible type for a tuple of given cardinality
......
......@@ -287,7 +287,8 @@ private void CheckUserDefinedConversionSignature(DiagnosticBag diagnostics)
if (source0 != this.ContainingType && target0 != this.ContainingType &&
// allow conversion between T and Nullable<T> in declaration of Nullable<T>
source != this.ContainingType && target != this.ContainingType)
source.TupleUnderlyingTypeOrSelf() != this.ContainingType &&
target.TupleUnderlyingTypeOrSelf() != this.ContainingType)
{
// CS0556: User-defined conversion must convert to or from the enclosing type
diagnostics.Add(ErrorCode.ERR_ConversionNotInvolvingContainedType, this.Locations[0]);
......@@ -416,7 +417,7 @@ private void CheckUnarySignature(DiagnosticBag diagnostics)
// SPEC: A unary + - ! ~ operator must take a single parameter of type
// SPEC: T or T? and can return any type.
if (this.ParameterTypes[0].StrippedType() != this.ContainingType)
if (this.ParameterTypes[0].StrippedType().TupleUnderlyingTypeOrSelf() != this.ContainingType)
{
// The parameter of a unary operator must be the containing type
diagnostics.Add(ErrorCode.ERR_BadUnaryOperatorSignature, this.Locations[0]);
......@@ -441,7 +442,7 @@ private void CheckTrueFalseSignature(DiagnosticBag diagnostics)
diagnostics.Add(ErrorCode.ERR_OpTFRetType, this.Locations[0]);
}
if (this.ParameterTypes[0].StrippedType() != this.ContainingType)
if (this.ParameterTypes[0].StrippedType().TupleUnderlyingTypeOrSelf() != this.ContainingType)
{
// The parameter of a unary operator must be the containing type
diagnostics.Add(ErrorCode.ERR_BadUnaryOperatorSignature, this.Locations[0]);
......@@ -491,7 +492,7 @@ private void CheckIncrementDecrementSignature(DiagnosticBag diagnostics)
var parameterType = this.ParameterTypes[0];
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
if (parameterType.StrippedType() != this.ContainingType)
if (parameterType.StrippedType().TupleUnderlyingTypeOrSelf() != this.ContainingType)
{
// CS0559: The parameter type for ++ or -- operator must be the containing type
diagnostics.Add(ErrorCode.ERR_BadIncDecSignature, this.Locations[0]);
......@@ -512,7 +513,7 @@ private void CheckShiftSignature(DiagnosticBag diagnostics)
// SPEC: of which must have type T or T? and the second of which must
// SPEC: have type int or int?, and can return any type.
if (this.ParameterTypes[0].StrippedType() != this.ContainingType ||
if (this.ParameterTypes[0].StrippedType().TupleUnderlyingTypeOrSelf() != this.ContainingType ||
this.ParameterTypes[1].StrippedType().SpecialType != SpecialType.System_Int32)
{
// CS0546: The first operand of an overloaded shift operator must have the
......@@ -533,9 +534,8 @@ private void CheckBinarySignature(DiagnosticBag diagnostics)
{
// SPEC: A binary nonshift operator must take two parameters, at least
// SPEC: one of which must have the type T or T?, and can return any type.
if (this.ParameterTypes[0].StrippedType() != this.ContainingType &&
this.ParameterTypes[1].StrippedType() != this.ContainingType)
if (this.ParameterTypes[0].StrippedType().TupleUnderlyingTypeOrSelf() != this.ContainingType &&
this.ParameterTypes[1].StrippedType().TupleUnderlyingTypeOrSelf() != this.ContainingType)
{
// CS0563: One of the parameters of a binary operator must be the containing type
diagnostics.Add(ErrorCode.ERR_BadBinaryOperatorSignature, this.Locations[0]);
......
......@@ -352,7 +352,7 @@ private static NamedTypeSymbol GetTupleUnderlyingType(ImmutableArray<TypeSymbol>
if ((object)diagnostics != null && (object)syntax != null)
{
Binder.ReportUseSiteDiagnostics(firstTupleType, diagnostics, syntax);
Binder.ReportUseSiteDiagnostics(chainedTupleType, diagnostics, syntax);
}
do
......
......@@ -82,6 +82,11 @@ public static TypeSymbol StrippedType(this TypeSymbol type)
return type.IsNullableType() ? type.GetNullableUnderlyingType() : type;
}
public static TypeSymbol TupleUnderlyingTypeOrSelf(this TypeSymbol type)
{
return type.TupleUnderlyingType ?? type;
}
public static TypeSymbol EnumUnderlyingType(this TypeSymbol type)
{
return type.IsEnumType() ? type.GetEnumUnderlyingType() : type;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册