From fa83ec65d2087b89ed4dca003393d38f5abdb868 Mon Sep 17 00:00:00 2001 From: VSadov Date: Thu, 14 Jul 2016 10:53:16 -0700 Subject: [PATCH] Simple type/field binding works --- .../Portable/Binding/Binder_Symbols.vb | 164 ++++++++++++++---- .../Portable/Emit/SymbolTranslator.vb | 7 +- .../VisualBasic/Portable/Errors/Errors.vb | 6 + .../Portable/Symbols/NamedTypeSymbol.vb | 61 +++++++ .../Symbols/Tuples/TupleTypeSymbol.vb | 10 +- .../Portable/VBResources.Designer.vb | 45 +++++ .../VisualBasic/Portable/VBResources.resx | 15 ++ .../Test/Emit/BasicCompilerEmitTest.vbproj | 1 + .../Test/Emit/CodeGen/CodeGenTuples.vb | 161 +++++++++++++++++ 9 files changed, 428 insertions(+), 42 deletions(-) create mode 100644 src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb index 56709ec7b49..762138880a1 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb @@ -4,6 +4,7 @@ Imports System.Collections.Generic Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports System.Threading +Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -341,7 +342,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim diagName = GetBaseNamesForDiagnostic(typeSyntax) diagInfo = NotFound(typeSyntax, diagName, binder, diagBag, reportedAnError) - Return Binder.GetErrorSymbol(diagName, diagInfo) + Return binder.GetErrorSymbol(diagName, diagInfo) Else If lookupResult.HasDiagnostic Then Dim diagName = GetBaseNamesForDiagnostic(typeSyntax) @@ -371,7 +372,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Binder.ReportDiagnostic(diagBag, typeSyntax, diagInfo) End If - Return Binder.GetErrorSymbol(GetBaseNamesForDiagnostic(typeSyntax), diagInfo, ImmutableArray.Create(Of Symbol)(sym), LookupResultKind.NotATypeOrNamespace) + Return binder.GetErrorSymbol(GetBaseNamesForDiagnostic(typeSyntax), diagInfo, ImmutableArray.Create(Of Symbol)(sym), LookupResultKind.NotATypeOrNamespace) Else ' When we bind generic type reference, we pass through here with symbols for ' the generic type definition, each type argument and for the final constructed @@ -386,7 +387,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Emit.NoPia.EmbeddedTypesManager.IsValidEmbeddableType(DirectCast(typeSymbol, NamedTypeSymbol), typeSyntax, diagBag) End If - Binder.ReportDiagnosticsIfObsolete(diagBag, sym, typeSyntax) + binder.ReportDiagnosticsIfObsolete(diagBag, sym, typeSyntax) Return sym End If @@ -596,7 +597,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Binder.ReportDiagnostic(diagBag, typeSyntax, diagInfo) End If - Return Binder.GetErrorSymbol(diagName, diagInfo) + Return binder.GetErrorSymbol(diagName, diagInfo) Else If lookupResult.HasDiagnostic Then If Not reportedAnError Then @@ -608,7 +609,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' LookupTypeOrNamespaceSyntax can't return more than one symbol. Dim result = lookupResult.SingleSymbol - Binder.ReportDiagnosticsIfObsolete(diagBag, result, typeSyntax) + binder.ReportDiagnosticsIfObsolete(diagBag, result, typeSyntax) Return result End If Finally @@ -657,28 +658,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic lookupResult.SetFrom(LookupGlobalName(DirectCast(typeSyntax, GlobalNameSyntax), binder)) Case SyntaxKind.PredefinedType - LookupResult.SetFrom(LookupPredefinedTypeName(DirectCast(typeSyntax, PredefinedTypeSyntax), binder, diagBag, reportedAnError, suppressUseSiteError)) + lookupResult.SetFrom(LookupPredefinedTypeName(DirectCast(typeSyntax, PredefinedTypeSyntax), binder, diagBag, reportedAnError, suppressUseSiteError)) Case SyntaxKind.ArrayType - LookupResult.SetFrom(LookupArrayType(DirectCast(typeSyntax, ArrayTypeSyntax), binder, diagBag, suppressUseSiteError, inGetTypeContext:=inGetTypeContext)) + lookupResult.SetFrom(LookupArrayType(DirectCast(typeSyntax, ArrayTypeSyntax), binder, diagBag, suppressUseSiteError, inGetTypeContext:=inGetTypeContext)) Case SyntaxKind.NullableType - LookupResult.SetFrom(LookupNullableType(DirectCast(typeSyntax, NullableTypeSyntax), binder, diagBag, suppressUseSiteError)) + lookupResult.SetFrom(LookupNullableType(DirectCast(typeSyntax, NullableTypeSyntax), binder, diagBag, suppressUseSiteError)) Case SyntaxKind.TupleType - 'PROTOTYPE: tuple binding - ' bind the first element for now to prevent crashing - Dim tupleType = DirectCast(typeSyntax, TupleTypeSyntax) - - LookupTypeOrNamespaceSyntax(lookupResult, - tupleType.TupleElements(0).Type, - binder, - diagBag, - reportedAnError, - unwrapAliases, - suppressUseSiteError, - inGetTypeContext, - resolvingBaseType) + lookupResult.SetFrom(LookupTupleType(DirectCast(typeSyntax, TupleTypeSyntax), binder, diagBag, suppressUseSiteError, inGetTypeContext, resolvingBaseType)) Case Else Throw ExceptionUtilities.UnexpectedValue(typeSyntax.Kind) @@ -690,6 +679,109 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If End Sub + Private Shared Function LookupTupleType(syntax As TupleTypeSyntax, + binder As Binder, + diagnostics As DiagnosticBag, + suppressUseSiteError As Boolean, + inGetTypeContext As Boolean, + resolvingBaseType As Boolean) As TypeSymbol + + Dim numElements As Integer = syntax.TupleElements.Count + Dim types = ArrayBuilder(Of TypeSymbol).GetInstance(numElements) + Dim locations = ArrayBuilder(Of Location).GetInstance(numElements) + Dim elementNames As ArrayBuilder(Of String) = Nothing + + ' set of names already used + Dim uniqueFieldNames = PooledHashSet(Of String).GetInstance() + Dim countOfExplicitNames As Integer = 0 + + For i As Integer = 0 To numElements - 1 + Dim argumentSyntax = syntax.TupleElements(i) + + Dim argumentType As TypeSymbol = binder.BindTypeSyntax(argumentSyntax.Type, diagnostics, suppressUseSiteError, inGetTypeContext, resolvingBaseType) + types.Add(argumentType) + + If argumentType.IsRestrictedType() Then + Binder.ReportDiagnostic(diagnostics, argumentSyntax, ERRID.ERR_RestrictedType1, argumentType) + End If + + Dim name As String = Nothing + Dim nameSyntax As IdentifierNameSyntax = argumentSyntax.IdentifierName + + If nameSyntax IsNot Nothing Then + name = nameSyntax.Identifier.ValueText + + ' validate name if we have one + countOfExplicitNames += 1 + CheckTupleMemberName(binder, name, i, nameSyntax, diagnostics, uniqueFieldNames) + locations.Add(nameSyntax.GetLocation) + Else + locations.Add(argumentSyntax.GetLocation) + End If + + CollectTupleFieldMemberNames(name, i + 1, numElements, elementNames) + Next + + uniqueFieldNames.Free() + + If countOfExplicitNames <> 0 AndAlso countOfExplicitNames <> numElements Then + Binder.ReportDiagnostic(diagnostics, syntax, ERRID.ERR_TupleExplicitNamesOnAllMembersOrNone) + End If + + Dim typesArray As ImmutableArray(Of TypeSymbol) = types.ToImmutableAndFree() + Dim locationsArray As ImmutableArray(Of Location) = locations.ToImmutableAndFree() + + If typesArray.Length < 2 Then + 'PROTOTYPE: tuples error ID + Dim diaginfo = diagnostics.Add(ERRID.ERR_TupleTooFewElements, syntax.GetLocation) + Return ErrorTypeSymbol.UnknownResultType + End If + + Return TupleTypeSymbol.Create(syntax.GetLocation, + typesArray, + locationsArray, + If(elementNames Is Nothing, Nothing, elementNames.ToImmutableAndFree()), + binder.Compilation, + syntax, + diagnostics) + End Function + + Private Shared Sub CollectTupleFieldMemberNames(name As String, position As Integer, tupleSize As Integer, ByRef elementNames As ArrayBuilder(Of String)) + ' add the name to the list + ' names would typically all be there Or none at all + ' but in case we need to handle this in error cases + If elementNames IsNot Nothing Then + elementNames.Add(If(name, TupleTypeSymbol.TupleMemberName(position))) + Else + If name IsNot Nothing Then + elementNames = ArrayBuilder(Of String).GetInstance(tupleSize) + For j As Integer = 1 To position - 1 + elementNames.Add(TupleTypeSymbol.TupleMemberName(j)) + Next + elementNames.Add(name) + End If + End If + End Sub + + Private Shared Function CheckTupleMemberName(binder As Binder, name As String, position As Integer, syntax As VisualBasicSyntaxNode, diagnostics As DiagnosticBag, uniqueFieldNames As PooledHashSet(Of String)) As Boolean + Dim reserved As Integer = TupleTypeSymbol.IsElementNameReserved(name) + If reserved = 0 Then + Binder.ReportDiagnostic(diagnostics, syntax, ERRID.ERR_TupleReservedMemberNameAnyPosition, name) + Return False + + ElseIf reserved > 0 AndAlso reserved <> position + 1 Then + Binder.ReportDiagnostic(diagnostics, syntax, ERRID.ERR_TupleReservedMemberName, name, reserved) + Return False + + ElseIf (Not uniqueFieldNames.Add(name)) Then + Binder.ReportDiagnostic(diagnostics, syntax, ERRID.ERR_TupleDuplicateMemberName) + Return False + + End If + + Return True + End Function + Private Shared Sub AnalyzeLookupResultForIllegalBaseTypeReferences(lookupResult As LookupResult, typeSyntax As TypeSyntax, binder As Binder, @@ -748,9 +840,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Private Shared Function ErrorTypeFromLookupResult(name As String, result As LookupResult, binder As Binder) As ErrorTypeSymbol If result.Kind = LookupResultKind.Ambiguous AndAlso result.HasSingleSymbol AndAlso TypeOf result.Diagnostic Is AmbiguousSymbolDiagnostic Then ' Special case: set of ambiguous symbols is stored in the diagnostics. - Return Binder.GetErrorSymbol(name, result.Diagnostic, DirectCast(result.Diagnostic, AmbiguousSymbolDiagnostic).AmbiguousSymbols, result.Kind) + Return binder.GetErrorSymbol(name, result.Diagnostic, DirectCast(result.Diagnostic, AmbiguousSymbolDiagnostic).AmbiguousSymbols, result.Kind) End If - Return Binder.GetErrorSymbol(name, result.Diagnostic, result.Symbols.ToImmutable(), result.Kind) + Return binder.GetErrorSymbol(name, result.Diagnostic, result.Symbols.ToImmutable(), result.Kind) End Function ''' @@ -764,7 +856,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If sym.IsNamespace Then Dim diagInfo = New BadSymbolDiagnostic(sym, ERRID.ERR_UnrecognizedType) Binder.ReportDiagnostic(diagBag, syntax, diagInfo) - Return Binder.GetErrorSymbol(sym.Name, diagInfo, ImmutableArray.Create(Of Symbol)(sym), LookupResultKind.NotATypeOrNamespace) + Return binder.GetErrorSymbol(sym.Name, diagInfo, ImmutableArray.Create(Of Symbol)(sym), LookupResultKind.NotATypeOrNamespace) Else Return DirectCast(sym, TypeSymbol) End If @@ -825,7 +917,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Throw ExceptionUtilities.UnexpectedValue(predefinedType) End Select - Dim sym = Binder.GetSpecialType(type, node, diagBag, reportedAnError, suppressUseSiteError) + Dim sym = binder.GetSpecialType(type, node, diagBag, reportedAnError, suppressUseSiteError) Return SingleLookupResult.Good(sym) End Function @@ -837,7 +929,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic diagBag As DiagnosticBag, suppressUseSiteError As Boolean, inGetTypeContext As Boolean) As SingleLookupResult - Dim elementType As TypeSymbol = Binder.BindTypeSyntax(arrayTypeSyntax.ElementType, + Dim elementType As TypeSymbol = binder.BindTypeSyntax(arrayTypeSyntax.ElementType, diagBag, suppressUseSiteError:=suppressUseSiteError, inGetTypeContext:=inGetTypeContext) @@ -851,8 +943,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic binder As Binder, diagBag As DiagnosticBag, suppressUseSiteError As Boolean) As SingleLookupResult - Dim elementType As TypeSymbol = Binder.BindTypeSyntax(nullableTypeSyntax.ElementType, diagBag, suppressUseSiteError) - Return SingleLookupResult.Good(Binder.CreateNullableOf(elementType, nullableTypeSyntax, nullableTypeSyntax.ElementType, diagBag)) + Dim elementType As TypeSymbol = binder.BindTypeSyntax(nullableTypeSyntax.ElementType, diagBag, suppressUseSiteError) + Return SingleLookupResult.Good(binder.CreateNullableOf(elementType, nullableTypeSyntax, nullableTypeSyntax.ElementType, diagBag)) End Function ''' @@ -928,7 +1020,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' TODO: Dev10 squiggles type arguments for this error, but Roslyn will squiggle the whole type name. ' If we want to preserve Dev10 behavior, it should be possible to provide optional location/syntax node ' for the diagnostic attached to LookupResult. - LookupResult.SetFrom(SingleLookupResult.WrongArity(lookupResult.SingleSymbol, + lookupResult.SetFrom(SingleLookupResult.WrongArity(lookupResult.SingleSymbol, New BadSymbolDiagnostic(lookupResult.SingleSymbol, ERRID.ERR_TypeOrMemberNotGeneric1, lookupResult.SingleSymbol))) End If Else @@ -939,11 +1031,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If ' Construct the type and validate constraints. - Dim constructedType = Binder.ConstructAndValidateConstraints( + Dim constructedType = binder.ConstructAndValidateConstraints( genericType, typeArguments, genericNameSyntax, typeArgumentsSyntax.Arguments, diagBag) ' Put the constructed type in. Note that this preserves any error associated with the lookupResult. - LookupResult.ReplaceSymbol(constructedType) + lookupResult.ReplaceSymbol(constructedType) End If End Sub @@ -985,7 +1077,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim leftSymbol As NamespaceOrTypeSymbol = DirectCast(lookupResult.SingleSymbol, NamespaceOrTypeSymbol) - Binder.ReportDiagnosticsIfObsolete(diagBag, leftSymbol, leftNameSyntax) + binder.ReportDiagnosticsIfObsolete(diagBag, leftSymbol, leftNameSyntax) lookupResult.Clear() Dim useSiteDiagnostics As HashSet(Of DiagnosticInfo) = Nothing @@ -1060,7 +1152,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim leftSymbol As NamespaceOrTypeSymbol = DirectCast(lookupResult.SingleSymbol, NamespaceOrTypeSymbol) - Binder.ReportDiagnosticsIfObsolete(diagBag, leftSymbol, leftNameSyntax) + binder.ReportDiagnosticsIfObsolete(diagBag, leftSymbol, leftNameSyntax) ' Lookup the generic type. lookupResult.Clear() @@ -1087,11 +1179,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return Else ' Construct the type and validate constraints. - Dim constructedType = Binder.ConstructAndValidateConstraints( + Dim constructedType = binder.ConstructAndValidateConstraints( genericType, typeArguments, genDottedNameSyntax, typeArgumentsSyntax.Arguments, diagBag) ' Note: this preserves any error associated with the generic type, which is what we want. - LookupResult.ReplaceSymbol(constructedType) + lookupResult.ReplaceSymbol(constructedType) End If End Sub @@ -1114,7 +1206,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim types As TypeSymbol() = New TypeSymbol(0 To arity - 1) {} For i As Integer = 0 To arity - 1 - types(i) = Binder.BindTypeSyntax(typeArgumentsSyntax.Arguments(i), diagBag, suppressUseSiteError) + types(i) = binder.BindTypeSyntax(typeArgumentsSyntax.Arguments(i), diagBag, suppressUseSiteError) Next Return types.AsImmutableOrNull() diff --git a/src/Compilers/VisualBasic/Portable/Emit/SymbolTranslator.vb b/src/Compilers/VisualBasic/Portable/Emit/SymbolTranslator.vb index e16131a9cf0..3023990dd96 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/SymbolTranslator.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/SymbolTranslator.vb @@ -120,6 +120,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ' Anonymous type being translated If namedTypeSymbol.IsAnonymousType Then namedTypeSymbol = AnonymousTypeManager.TranslateAnonymousTypeSymbol(namedTypeSymbol) + ElseIf (namedTypeSymbol.IsTupleType) Then + Debug.Assert(Not needDeclaration) + namedTypeSymbol = namedTypeSymbol.TupleUnderlyingType End If ' Substitute error types with a special singleton object. @@ -234,6 +237,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ) 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 Me.ProcessReferencedSymbol(fieldSymbol) @@ -473,6 +479,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Friend Overloads Function Translate(symbol As ArrayTypeSymbol) As Microsoft.Cci.IArrayTypeReference Return symbol End Function - End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb index bda6c9ded55..b7205c35554 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb @@ -1687,6 +1687,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERR_OptionMustBeAbsolutePath = 37257 + ERR_TupleExplicitNamesOnAllMembersOrNone = 37258 + ERR_TupleTooFewElements = 37259 + ERR_TupleReservedMemberNameAnyPosition = 37260 + ERR_TupleReservedMemberName = 37261 + ERR_TupleDuplicateMemberName = 37262 + ERR_LastPlusOne diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb index 07343198103..e6211c84d61 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb @@ -1237,5 +1237,66 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols #End Region + ''' + ''' Verify if the given type can be used to back a tuple type + ''' and return cardinality of that tuple type in . + ''' + ''' If method returns true, contains cardinality of the compatible tuple type. + ''' + Public Overrides Function IsTupleCompatible( ByRef tupleCardinality As Integer) As Boolean + If IsTupleType Then + tupleCardinality = 0 + Return False + End If + + ' Should this be optimized for perf (caching for VT<0> to VT<7>, etc.)? + If (Not IsUnboundGenericType AndAlso + ContainingSymbol?.Kind = SymbolKind.Namespace AndAlso + ContainingNamespace.ContainingNamespace?.IsGlobalNamespace = True AndAlso + Name = TupleTypeSymbol.TupleTypeName AndAlso + ContainingNamespace.Name = MetadataHelpers.SystemString) Then + + Dim arity = Me.Arity + + If arity > 0 AndAlso arity < TupleTypeSymbol.RestPosition Then + tupleCardinality = arity + Return True + ElseIf arity = TupleTypeSymbol.RestPosition AndAlso Not IsDefinition Then + ' Skip through "Rest" extensions + Dim typeToCheck As TypeSymbol = Me + Dim levelsOfNesting As Integer = 0 + + Do + levelsOfNesting += 1 + typeToCheck = DirectCast(typeToCheck, NamedTypeSymbol).TypeArgumentsNoUseSiteDiagnostics(TupleTypeSymbol.RestPosition - 1) + Loop While typeToCheck.OriginalDefinition = Me.OriginalDefinition AndAlso Not typeToCheck.IsDefinition + + If typeToCheck.IsTupleType Then + Dim underlying = typeToCheck.TupleUnderlyingType + If underlying.Arity = TupleTypeSymbol.RestPosition AndAlso underlying.OriginalDefinition <> Me.OriginalDefinition Then + tupleCardinality = 0 + Return False + End If + + tupleCardinality = (TupleTypeSymbol.RestPosition - 1) * levelsOfNesting + typeToCheck.TupleElementTypes.Length + Return True + End If + + arity = If(TryCast(typeToCheck, NamedTypeSymbol)?.Arity, 0) + + If arity > 0 AndAlso + arity < TupleTypeSymbol.RestPosition AndAlso + typeToCheck.IsTupleCompatible(tupleCardinality) Then + Debug.Assert(tupleCardinality < TupleTypeSymbol.RestPosition) + tupleCardinality += (TupleTypeSymbol.RestPosition - 1) * levelsOfNesting + Return True + End If + End If + End If + + tupleCardinality = 0 + Return False + End Function + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb index c2f272f057d..cc972373130 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb @@ -478,8 +478,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Function Private Shared Function NumberOfValueTuples(numElements As Integer, ByRef remainder As Integer) As Integer - remainder = (numElements - 1) Mod TupleTypeSymbol.RestPosition - 1 + 1 - Return (numElements - 1) \ TupleTypeSymbol.RestPosition - 1 + 1 + remainder = (numElements - 1) Mod (RestPosition - 1) + 1 + Return (numElements - 1) \ (RestPosition - 1) + 1 End Function Private Shared Function GetTupleUnderlyingType(elementTypes As ImmutableArray(Of TypeSymbol), syntax As VisualBasicSyntaxNode, compilation As VisualBasicCompilation, diagnostics As DiagnosticBag) As NamedTypeSymbol @@ -493,7 +493,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Binder.ReportUseSiteError(diagnostics, syntax, wellKnownType) End If - Dim namedTypeSymbol As NamedTypeSymbol = wellKnownType.Construct(ImmutableArray.Create(Of TypeSymbol)(elementTypes, (chainLength - 1) * TupleTypeSymbol.RestPosition - 1, remainder)) + Dim namedTypeSymbol As NamedTypeSymbol = wellKnownType.Construct(ImmutableArray.Create(Of TypeSymbol)(elementTypes, (chainLength - 1) * (TupleTypeSymbol.RestPosition - 1), remainder)) Dim [loop] As Integer = chainLength - 1 If [loop] > 0 Then Dim wellKnownType2 As NamedTypeSymbol = compilation.GetWellKnownType(TupleTypeSymbol.GetTupleType(TupleTypeSymbol.RestPosition)) @@ -502,7 +502,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Binder.ReportUseSiteError(diagnostics, syntax, wellKnownType2) End If Do - Dim typeArguments As ImmutableArray(Of TypeSymbol) = ImmutableArray.Create(Of TypeSymbol)(elementTypes, ([loop] - 1) * TupleTypeSymbol.RestPosition - 1, TupleTypeSymbol.RestPosition - 1).Add(namedTypeSymbol) + Dim typeArguments As ImmutableArray(Of TypeSymbol) = ImmutableArray.Create(Of TypeSymbol)(elementTypes, ([loop] - 1) * (TupleTypeSymbol.RestPosition - 1), TupleTypeSymbol.RestPosition - 1).Add(namedTypeSymbol) namedTypeSymbol = wellKnownType2.Construct(typeArguments) [loop] -= 1 Loop While [loop] > 0 @@ -661,7 +661,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Dim field = DirectCast(member, FieldSymbol) Dim tupleFieldIndex = currentFieldsForElements.IndexOf(field, ReferenceEqualityComparer.Instance) - If tupleFieldIndex = 0 Then + If tupleFieldIndex >= 0 Then ' This Is a tuple backing field Dim FieldSymbol = field.AsMember(currentUnderlying) diff --git a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb index 8837db23785..37858260dba 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb +++ b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb @@ -10325,6 +10325,51 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + ''' + ''' Looks up a localized string similar to Tuple member names must be unique.. + ''' + Friend ReadOnly Property ERR_TupleDuplicateMemberName() As String + Get + Return ResourceManager.GetString("ERR_TupleDuplicateMemberName", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Tuple member names must all be provided, if any one is provided.. + ''' + Friend ReadOnly Property ERR_TupleExplicitNamesOnAllMembersOrNone() As String + Get + Return ResourceManager.GetString("ERR_TupleExplicitNamesOnAllMembersOrNone", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Tuple member name '{0}' is only allowed at position {1}.. + ''' + Friend ReadOnly Property ERR_TupleReservedMemberName() As String + Get + Return ResourceManager.GetString("ERR_TupleReservedMemberName", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Tuple membername '{0}' is disallowed at any position.. + ''' + Friend ReadOnly Property ERR_TupleReservedMemberNameAnyPosition() As String + Get + Return ResourceManager.GetString("ERR_TupleReservedMemberNameAnyPosition", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Tuple must contain at least two elements.. + ''' + Friend ReadOnly Property ERR_TupleTooFewElements() As String + Get + Return ResourceManager.GetString("ERR_TupleTooFewElements", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to Operator '{0}' must have two parameters.. ''' diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index 5e502dd056e..36f04d9fbaf 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -5367,4 +5367,19 @@ Option '{0}' must be an absolute path. + + Tuple member names must be unique. + + + Tuple member names must all be provided, if any one is provided. + + + Tuple member name '{0}' is only allowed at position {1}. + + + Tuple membername '{0}' is disallowed at any position. + + + Tuple must contain at least two elements. + diff --git a/src/Compilers/VisualBasic/Test/Emit/BasicCompilerEmitTest.vbproj b/src/Compilers/VisualBasic/Test/Emit/BasicCompilerEmitTest.vbproj index 1f9e9f646c9..e366429bf89 100644 --- a/src/Compilers/VisualBasic/Test/Emit/BasicCompilerEmitTest.vbproj +++ b/src/Compilers/VisualBasic/Test/Emit/BasicCompilerEmitTest.vbproj @@ -98,6 +98,7 @@ + diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb new file mode 100644 index 00000000000..a60501d692e --- /dev/null +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb @@ -0,0 +1,161 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit +Imports Roslyn.Test.Utilities + +Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests + Public Class CodeGenTuples + Inherits BasicTestBase + + + Public Sub TupleTypeBinding() + + Dim verifier = CompileAndVerify( + + +Imports System +Module C + + Sub Main() + Dim t as (Integer, Integer) + console.writeline(t) + End Sub +End Module + +Namespace System + Structure ValueTuple(Of T1, T2) + Public Overrides Function ToString() As String + Return "hello" + End Function + End Structure +End Namespace + + +, expectedOutput:=) + + verifier.VerifyIL("C.Main", ) + End Sub + + + Public Sub TupleFieldBinding() + + Dim verifier = CompileAndVerify( + + +Imports System +Module C + + Sub Main() + Dim t as (Integer, Integer) + + t.Item1 = 42 + t.Item2 = t.Item1 + console.writeline(t.Item2) + End Sub +End Module + +Namespace System + Structure ValueTuple(Of T1, T2) + Public Item1 As T1 + Public Item2 As T2 + End Structure +End Namespace + + +, expectedOutput:=) + + verifier.VerifyIL("C.Main", ) + End Sub + + + Public Sub TupleNamedFieldBinding() + + Dim verifier = CompileAndVerify( + + +Imports System +Module C + + Sub Main() + Dim t As (a As Integer, b As Integer) + + t.a = 42 + t.b = t.a + + Console.WriteLine(t.b) + End Sub +End Module + +Namespace System + Structure ValueTuple(Of T1, T2) + Public Item1 As T1 + Public Item2 As T2 + End Structure +End Namespace + + +, expectedOutput:=) + + verifier.VerifyIL("C.Main", ) + End Sub + + End Class + +End Namespace + -- GitLab