Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove dedicated tuple type symbol #39370

Merged
merged 22 commits into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,8 @@ could be different than the one that compiler used to find.
- `e is T t + c`

These all have in common that the left operand is of looser precedence than the `+` operator, but the left operand does not end in an expression so it cannot "consume" the addition. Such expressions will no longer be permitted in Visual Studio 2019 version 16.5 and later.

14. In Visual Studio version 15.0 and onwards, the compiler would allow compiling some malformed definitions of the `System.ValueTuple` types. For instance, one with a private `Item1` field. In *Visual Studio 2019 version 16.5* such definitions produce warnings.

15. In Visual Studio version 15.0 and onwards, the compiler APIs would produce non-generic tuple symbols (`Arity` would be 0, would have no type arguments, would be original definitions). In *Visual Studio 2019 version 16.5* a 2-tuple symbol has `Arity` 2, and a 9-tuple symbol has `Arity` 8 (since it is a `ValueTuple'8`).

2 changes: 1 addition & 1 deletion docs/contributing/Compiler Test Plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ This document provides guidance for thinking about language interactions and tes
- events (including add/remove accessors)
- Parameter modifiers (ref, out, in, params)
- Attributes (including security attribute)
- Generics (type arguments, variance, constraints including `class`, `struct`, `new()`, `unmanaged`)
- Generics (type arguments, variance, constraints including `class`, `struct`, `new()`, `unmanaged`, `notnull`, types and interfaces with nullability)
- Default and constant values
- Partial classes
- Literals
Expand Down
20 changes: 9 additions & 11 deletions src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ protected BoundExpression CreateConversion(
{
if (source is BoundTupleLiteral sourceTuple)
{
TupleTypeSymbol.ReportNamesMismatchesIfAny(destination, sourceTuple, diagnostics);
NamedTypeSymbol.ReportTupleNamesMismatchesIfAny(destination, sourceTuple, diagnostics);
}

// identity tuple and switch conversions result in a converted expression
Expand Down Expand Up @@ -435,20 +435,17 @@ private BoundExpression CreateTupleLiteralConversion(SyntaxNode syntax, BoundTup
NamedTypeSymbol targetType = (NamedTypeSymbol)destinationWithoutNullable;
if (targetType.IsTupleType)
{
var destTupleType = (TupleTypeSymbol)targetType;

TupleTypeSymbol.ReportNamesMismatchesIfAny(targetType, sourceTuple, diagnostics);
NamedTypeSymbol.ReportTupleNamesMismatchesIfAny(targetType, sourceTuple, diagnostics);

// do not lose the original element names and locations in the literal if different from names in the target
//
// the tuple has changed the type of elements due to target-typing,
// but element names has not changed and locations of their declarations
// should not be confused with element locations on the target type.
var sourceType = sourceTuple.Type as TupleTypeSymbol;

if ((object)sourceType != null)
if (sourceTuple.Type is NamedTypeSymbol { IsTupleType: true } sourceType)
{
targetType = sourceType.WithUnderlyingType(destTupleType.UnderlyingNamedType);
targetType = targetType.WithTupleDataFrom(sourceType);
}
else
{
Expand All @@ -460,16 +457,17 @@ private BoundExpression CreateTupleLiteralConversion(SyntaxNode syntax, BoundTup
locationBuilder.Add(argument.NameColon?.Name.Location);
}

targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt,
tupleSyntax.Location,
locationBuilder.ToImmutableAndFree());
targetType = targetType.WithElementNames(sourceTuple.ArgumentNamesOpt,
locationBuilder.ToImmutableAndFree(),
errorPositions: default,
ImmutableArray.Create(tupleSyntax.Location));
}
}

var arguments = sourceTuple.Arguments;
var convertedArguments = ArrayBuilder<BoundExpression>.GetInstance(arguments.Length);

var targetElementTypes = targetType.GetElementTypesOfTupleOrCompatible();
var targetElementTypes = targetType.TupleElementTypesWithAnnotations;
Debug.Assert(targetElementTypes.Length == arguments.Length, "converting a tuple literal to incompatible type?");
var underlyingConversions = conversionWithoutNullable.UnderlyingConversions;

Expand Down
6 changes: 0 additions & 6 deletions src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,6 @@ private NamespaceOrTypeSymbol BindNamespaceOrTypeSymbolInCref(TypeSyntax syntax)
NamespaceOrTypeSymbol namespaceOrTypeSymbol = BindNamespaceOrTypeSymbol(syntax, unusedDiagnostics).NamespaceOrTypeSymbol;
unusedDiagnostics.Free();

// BindNamespaceOrTypeSymbol will wrap any tuple types in a TupleTypeSymbol. We unwrap it here, as doc comments don't consider the (T,T) form of tuples
if (namespaceOrTypeSymbol is TupleTypeSymbol t)
{
namespaceOrTypeSymbol = t.UnderlyingNamedType;
}

Debug.Assert((object)namespaceOrTypeSymbol != null);
return namespaceOrTypeSymbol;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ private static TypeSymbol MakeMergedTupleType(ArrayBuilder<DeconstructionVariabl
// The tuple created here is not identical to the one created by
// DeconstructionVariablesAsTuple. It represents a smaller
// tree of types used for figuring out natural types in tuple literal.
return TupleTypeSymbol.Create(
return NamedTypeSymbol.CreateTuple(
locationOpt: null,
elementTypesWithAnnotations: typesWithAnnotationsBuilder.ToImmutableAndFree(),
elementLocations: locationsBuilder.ToImmutableAndFree(),
Expand Down Expand Up @@ -566,7 +566,7 @@ private BoundTupleExpression DeconstructionVariablesAsTuple(CSharpSyntaxNode syn
ImmutableArray<bool> inferredPositions = tupleNames.IsDefault ? default : tupleNames.SelectAsArray(n => n != null);
bool disallowInferredNames = this.Compilation.LanguageVersion.DisallowInferredTupleElementNames();

var type = TupleTypeSymbol.Create(
var type = NamedTypeSymbol.CreateTuple(
syntax.Location,
typesWithAnnotationsBuilder.ToImmutableAndFree(), locationsBuilder.ToImmutableAndFree(),
tupleNames, this.Compilation,
Expand Down
12 changes: 6 additions & 6 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ internal BoundExpression BindToTypeForErrorRecovery(BoundExpression expression,
return null;
var discardedDiagnostics = DiagnosticBag.GetInstance();
var result =
(!expression.NeedsToBeConverted() || expression.WasConverted) ? expression :
!expression.NeedsToBeConverted() ? expression :
type is null ? BindToNaturalType(expression, discardedDiagnostics, reportDefaultMissingType: false) :
GenerateConversionForAssignment(type, expression, discardedDiagnostics);
discardedDiagnostics.Free();
Expand Down Expand Up @@ -804,7 +804,7 @@ private BoundExpression BindDeclarationVariablesForErrorRecovery(TypeWithAnnotat

// We will not check constraints at this point as this code path
// is failure-only and the caller is expected to produce a diagnostic.
var tupleType = TupleTypeSymbol.Create(
var tupleType = NamedTypeSymbol.CreateTuple(
locationOpt: null,
subExpressions.SelectAsArray(e => TypeWithAnnotations.Create(e.Type)),
elementLocations: default,
Expand Down Expand Up @@ -888,13 +888,13 @@ private BoundExpression BindTupleExpression(TupleExpressionSyntax node, Diagnost
{
bool disallowInferredNames = this.Compilation.LanguageVersion.DisallowInferredTupleElementNames();

tupleTypeOpt = TupleTypeSymbol.Create(node.Location, elements, locations, elementNames,
tupleTypeOpt = NamedTypeSymbol.CreateTuple(node.Location, elements, locations, elementNames,
this.Compilation, syntax: node, diagnostics: diagnostics, shouldCheckConstraints: true,
includeNullability: false, errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray<bool>));
}
else
{
TupleTypeSymbol.VerifyTupleTypePresent(elements.Length, node, this.Compilation, diagnostics);
NamedTypeSymbol.VerifyTupleTypePresent(elements.Length, node, this.Compilation, diagnostics);
}

// Always track the inferred positions in the bound node, so that conversions don't produce a warning
Expand Down Expand Up @@ -1028,7 +1028,7 @@ private static string InferTupleElementName(SyntaxNode syntax)
string name = syntax.TryGetInferredMemberName();

// Reserved names are never candidates to be inferred names, at any position
if (name == null || TupleTypeSymbol.IsElementNameReserved(name) != -1)
if (name == null || NamedTypeSymbol.IsTupleElementNameReserved(name) != -1)
{
return null;
}
Expand Down Expand Up @@ -2269,7 +2269,7 @@ private void GenerateExplicitConversionErrors(

// If target is a tuple or compatible type with the same number of elements,
// report errors for tuple arguments that failed to convert, which would be more useful.
if (targetType.TryGetElementTypesWithAnnotationsIfTupleOrCompatible(out targetElementTypesWithAnnotations) &&
if (targetType.TryGetElementTypesWithAnnotationsIfTupleType(out targetElementTypesWithAnnotations) &&
targetElementTypesWithAnnotations.Length == tuple.Arguments.Length)
{
GenerateExplicitConversionErrorsForTupleLiteralArguments(diagnostics, tuple.Arguments, targetElementTypesWithAnnotations);
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2087,7 +2087,7 @@ protected void GenerateImplicitConversionError(

// If target is a tuple or compatible type with the same number of elements,
// report errors for tuple arguments that failed to convert, which would be more useful.
if (targetType.TryGetElementTypesWithAnnotationsIfTupleOrCompatible(out targetElementTypes) &&
if (targetType.TryGetElementTypesWithAnnotationsIfTupleType(out targetElementTypes) &&
targetElementTypes.Length == tuple.Arguments.Length)
{
GenerateImplicitConversionErrorsForTupleLiteralArguments(diagnostics, tuple.Arguments, targetElementTypes);
Expand Down
8 changes: 3 additions & 5 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ private TypeSymbol BindTupleType(TupleTypeSyntax syntax, DiagnosticBag diagnosti
}

bool includeNullability = Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
return TupleTypeSymbol.Create(syntax.Location,
return NamedTypeSymbol.CreateTuple(syntax.Location,
typesArray,
locationsArray,
elementNames == null ?
Expand Down Expand Up @@ -694,7 +694,7 @@ private static void CollectTupleFieldMemberName(string name, int elementIndex, i

private static bool CheckTupleMemberName(string name, int index, SyntaxNodeOrToken syntax, DiagnosticBag diagnostics, PooledHashSet<string> uniqueFieldNames)
{
int reserved = TupleTypeSymbol.IsElementNameReserved(name);
int reserved = NamedTypeSymbol.IsTupleElementNameReserved(name);
if (reserved == 0)
{
Error(diagnostics, ErrorCode.ERR_TupleReservedElementNameAnyPosition, syntax, name);
Expand Down Expand Up @@ -1263,11 +1263,9 @@ private NamedTypeSymbol ConstructNamedType(
if (ShouldCheckConstraints && ConstraintsHelper.RequiresChecking(type))
{
bool includeNullability = Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
type.CheckConstraintsForNonTuple(this.Conversions, includeNullability, typeSyntax, typeArgumentsSyntax, this.Compilation, basesBeingResolved, diagnostics);
type.CheckConstraintsForNamedType(this.Conversions, includeNullability, typeSyntax, typeArgumentsSyntax, this.Compilation, basesBeingResolved, diagnostics);
}

type = (NamedTypeSymbol)TupleTypeSymbol.TransformToTupleIfCompatible(type);

return type;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ private TypeSymbol MakeConvertedType(ImmutableArray<TypeSymbol> convertedTypes,

ImmutableArray<Location> elementLocations = elements.SelectAsArray(e => e.Syntax.Location);

var tuple = TupleTypeSymbol.Create(locationOpt: null,
var tuple = NamedTypeSymbol.CreateTuple(locationOpt: null,
elementTypesWithAnnotations: convertedTypes.SelectAsArray(t => TypeWithAnnotations.Create(t)),
elementLocations, elementNames: names, compilation,
shouldCheckConstraints: true, includeNullability: false, errorPositions: default, syntax, diagnostics);
Expand Down
5 changes: 0 additions & 5 deletions src/Compilers/CSharp/Portable/Binder/Semantics/AccessCheck.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,6 @@ private static bool IsMemberAccessible(

failedThroughTypeCheck = false;

if (containingType.IsTupleType)
{
containingType = containingType.TupleUnderlyingType;
}

// easy case - members of containing type are accessible.
if ((object)containingType == (object)within)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2011,12 +2011,12 @@ private Conversion GetTupleLiteralConversion(
var arguments = source.Arguments;

// check if the type is actually compatible type for a tuple of given cardinality
if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(arguments.Length))
if (!destination.IsTupleTypeOfCardinality(arguments.Length))
{
return Conversion.NoConversion;
}

var targetElementTypes = destination.GetElementTypesOfTupleOrCompatible();
var targetElementTypes = destination.TupleElementTypesWithAnnotations;
Debug.Assert(arguments.Length == targetElementTypes.Length);

// check arguments against flattened list of target element types
Expand Down Expand Up @@ -2084,8 +2084,8 @@ private Conversion ClassifyTupleConversion(
ImmutableArray<TypeWithAnnotations> sourceTypes;
ImmutableArray<TypeWithAnnotations> destTypes;

if (!source.TryGetElementTypesWithAnnotationsIfTupleOrCompatible(out sourceTypes) ||
!destination.TryGetElementTypesWithAnnotationsIfTupleOrCompatible(out destTypes) ||
if (!source.TryGetElementTypesWithAnnotationsIfTupleType(out sourceTypes) ||
!destination.TryGetElementTypesWithAnnotationsIfTupleType(out destTypes) ||
sourceTypes.Length != destTypes.Length)
{
return Conversion.NoConversion;
Expand Down Expand Up @@ -2790,7 +2790,6 @@ static bool isTypeIEquatable(NamedTypeSymbol type)
TypeParameters: { Length: 1 }
};
}

}

// Spec 6.1.10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,13 +605,13 @@ private bool MakeExplicitParameterTypeInferences(Binder binder, BoundTupleLitera
var sourceArguments = argument.Arguments;

// check if the type is actually compatible type for a tuple of given cardinality
if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(sourceArguments.Length))
if (!destination.IsTupleTypeOfCardinality(sourceArguments.Length))
{
// target is not a tuple of appropriate shape
return false;
}

var destTypes = destination.GetElementTypesOfTupleOrCompatible();
var destTypes = destination.TupleElementTypesWithAnnotations;
Debug.Assert(sourceArguments.Length == destTypes.Length);

// NOTE: we are losing tuple element names when recursing into argument expressions.
Expand Down Expand Up @@ -778,12 +778,12 @@ private void MakeOutputTypeInferences(Binder binder, BoundTupleLiteral argument,
var sourceArguments = argument.Arguments;

// check if the type is actually compatible type for a tuple of given cardinality
if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(sourceArguments.Length))
if (!destination.IsTupleTypeOfCardinality(sourceArguments.Length))
{
return;
}

var destTypes = destination.GetElementTypesOfTupleOrCompatible();
var destTypes = destination.TupleElementTypesWithAnnotations;
Debug.Assert(sourceArguments.Length == destTypes.Length);

for (int i = 0; i < sourceArguments.Length; i++)
Expand Down Expand Up @@ -1561,8 +1561,8 @@ private bool LowerBoundTupleInference(TypeWithAnnotations source, TypeWithAnnota
ImmutableArray<TypeWithAnnotations> sourceTypes;
ImmutableArray<TypeWithAnnotations> targetTypes;

if (!source.Type.TryGetElementTypesWithAnnotationsIfTupleOrCompatible(out sourceTypes) ||
!target.Type.TryGetElementTypesWithAnnotationsIfTupleOrCompatible(out targetTypes) ||
if (!source.Type.TryGetElementTypesWithAnnotationsIfTupleType(out sourceTypes) ||
!target.Type.TryGetElementTypesWithAnnotationsIfTupleType(out targetTypes) ||
sourceTypes.Length != targetTypes.Length)
{
return false;
Expand All @@ -1585,13 +1585,13 @@ private bool ExactConstructedInference(TypeWithAnnotations source, TypeWithAnnot
// SPEC: type C<U1...Uk> then an exact inference
// SPEC: is made from each Ui to the corresponding Vi.

var namedSource = source.Type.TupleUnderlyingTypeOrSelf() as NamedTypeSymbol;
var namedSource = source.Type as NamedTypeSymbol;
if ((object)namedSource == null)
{
return false;
}

var namedTarget = target.Type.TupleUnderlyingTypeOrSelf() as NamedTypeSymbol;
var namedTarget = target.Type as NamedTypeSymbol;
if ((object)namedTarget == null)
{
return false;
Expand Down Expand Up @@ -1824,9 +1824,6 @@ private bool LowerBoundConstructedInference(TypeSymbol source, TypeSymbol target
Debug.Assert((object)source != null);
Debug.Assert((object)target != null);

source = source.TupleUnderlyingTypeOrSelf();
target = target.TupleUnderlyingTypeOrSelf();

var constructedTarget = target as NamedTypeSymbol;
if ((object)constructedTarget == null)
{
Expand Down Expand Up @@ -2174,8 +2171,8 @@ private bool UpperBoundConstructedInference(TypeWithAnnotations sourceWithAnnota
{
Debug.Assert(sourceWithAnnotations.HasType);
Debug.Assert(targetWithAnnotations.HasType);
var source = sourceWithAnnotations.Type.TupleUnderlyingTypeOrSelf();
var target = targetWithAnnotations.Type.TupleUnderlyingTypeOrSelf();
var source = sourceWithAnnotations.Type;
var target = targetWithAnnotations.Type;

var constructedSource = source as NamedTypeSymbol;
if ((object)constructedSource == null)
Expand Down
Loading