diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_Exit.vb b/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_Exit.vb
index d3f2674edc21577c36c2127e52fa18da2789f891..25409ea49debdbbb82cf5df7bb5dcb90ffe4f36a 100644
--- a/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_Exit.vb
+++ b/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_Exit.vb
@@ -1,101 +1,22 @@
' 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 System.Collections.Immutable
+Imports System.Diagnostics
+Imports System.Runtime.InteropServices
+Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
+Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
+Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Friend NotInheritable Class LocalRewriter
- Public Overrides Function VisitTupleLiteral(node As BoundTupleLiteral) As BoundNode
- Return VisitTupleExpression(node)
- End Function
-
- Private Function VisitTupleExpression(node As BoundTupleExpression) As BoundNode
- Dim rewrittenArguments As ImmutableArray(Of BoundExpression) = VisitList(node.Arguments)
- Return RewriteTupleCreationExpression(node, rewrittenArguments)
- End Function
-
- '''
- ''' Converts the expression for creating a tuple instance into an expression creating a ValueTuple (if short) or nested ValueTuples (if longer).
- '''
- ''' For instance, for a long tuple we'll generate:
- ''' creationExpression(ctor=largestCtor, args=firstArgs+(nested creationExpression for remainder, with smaller ctor and next few args))
- '''
- Private Function RewriteTupleCreationExpression(node As BoundTupleExpression, rewrittenArguments As ImmutableArray(Of BoundExpression)) As BoundExpression
- Return MakeTupleCreationExpression(node.Syntax, DirectCast(node.Type, NamedTypeSymbol), rewrittenArguments)
- End Function
-
- Private Function MakeTupleCreationExpression(syntax As VisualBasicSyntaxNode, type As NamedTypeSymbol, rewrittenArguments As ImmutableArray(Of BoundExpression)) As BoundExpression
- Dim underlyingTupleType As NamedTypeSymbol = If(type.TupleUnderlyingType, type)
- Debug.Assert(underlyingTupleType.IsTupleCompatible())
-
- Dim underlyingTupleTypeChain As ArrayBuilder(Of NamedTypeSymbol) = ArrayBuilder(Of NamedTypeSymbol).GetInstance()
- TupleTypeSymbol.GetUnderlyingTypeChain(underlyingTupleType, underlyingTupleTypeChain)
-
- Try
- ' make a creation expression for the smallest type
- Dim smallestType As NamedTypeSymbol = underlyingTupleTypeChain.Pop()
- Dim smallestCtorArguments As ImmutableArray(Of BoundExpression) = ImmutableArray.Create(rewrittenArguments,
- underlyingTupleTypeChain.Count * (TupleTypeSymbol.RestPosition - 1),
- smallestType.Arity)
-
- Dim smallestCtor As MethodSymbol = DirectCast(TupleTypeSymbol.GetWellKnownMemberInType(smallestType.OriginalDefinition,
- TupleTypeSymbol.GetTupleCtor(smallestType.Arity),
- _diagnostics,
- syntax), MethodSymbol)
- If smallestCtor Is Nothing Then
- Return New BoundBadExpression(
- syntax,
- LookupResultKind.Empty,
- Nothing,
- StaticCast(Of BoundNode).From(rewrittenArguments),
- type,
- hasErrors:=True)
- End If
-
- Dim smallestConstructor As MethodSymbol = smallestCtor.AsMember(smallestType)
- Dim currentCreation As BoundObjectCreationExpression = New BoundObjectCreationExpression(syntax, smallestConstructor, smallestCtorArguments, initializerOpt:=Nothing, type:=smallestType)
-
- If underlyingTupleTypeChain.Count > 0 Then
- Dim tuple8Type As NamedTypeSymbol = underlyingTupleTypeChain.Peek()
- Dim tuple8Ctor As MethodSymbol = DirectCast(TupleTypeSymbol.GetWellKnownMemberInType(tuple8Type.OriginalDefinition,
- TupleTypeSymbol.GetTupleCtor(TupleTypeSymbol.RestPosition),
- _diagnostics,
- syntax), MethodSymbol)
- If tuple8Ctor Is Nothing Then
- Return New BoundBadExpression(
- syntax,
- LookupResultKind.Empty,
- Nothing,
- StaticCast(Of BoundNode).From(rewrittenArguments),
- type,
- hasErrors:=True)
- End If
-
- ' make successively larger creation expressions containing the previous one
- Do
- Dim ctorArguments As ImmutableArray(Of BoundExpression) = ImmutableArray.Create(rewrittenArguments,
- (underlyingTupleTypeChain.Count - 1) * (TupleTypeSymbol.RestPosition - 1),
- TupleTypeSymbol.RestPosition - 1).Add(currentCreation)
-
- Dim constructor As MethodSymbol = tuple8Ctor.AsMember(underlyingTupleTypeChain.Pop())
- currentCreation = New BoundObjectCreationExpression(syntax, constructor, ctorArguments, initializerOpt:=Nothing, type:=constructor.ContainingType)
-
- Loop While (underlyingTupleTypeChain.Count > 0)
-
- End If
-
- currentCreation = currentCreation.Update(
- currentCreation.ConstructorOpt,
- methodGroupOpt:=Nothing,
- arguments:=currentCreation.Arguments,
- initializerOpt:=currentCreation.InitializerOpt,
- type:=type)
+ Public Overrides Function VisitExitStatement(node As BoundExitStatement) As BoundNode
+ Dim boundGoto As BoundStatement = New BoundGotoStatement(node.Syntax, node.Label, Nothing)
- Return currentCreation
- Finally
- underlyingTupleTypeChain.Free()
- end try
+ If ShouldGenerateUnstructuredExceptionHandlingResumeCode(node) Then
+ boundGoto = Concat(RegisterUnstructuredExceptionHandlingNonThrowingResumeTarget(node.Syntax), boundGoto)
+ End If
+ Return MarkStatementWithSequencePoint(boundGoto)
End Function
End Class
End Namespace
diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_TupleLiteralExpression.vb b/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_TupleLiteralExpression.vb
index 25409ea49debdbbb82cf5df7bb5dcb90ffe4f36a..5afe14c54e79158a60ce718cc5f9117d5685889d 100644
--- a/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_TupleLiteralExpression.vb
+++ b/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_TupleLiteralExpression.vb
@@ -1,22 +1,101 @@
' 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 System.Diagnostics
-Imports System.Runtime.InteropServices
-Imports Microsoft.CodeAnalysis.Text
+Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
-Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
-Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Friend NotInheritable Class LocalRewriter
- Public Overrides Function VisitExitStatement(node As BoundExitStatement) As BoundNode
- Dim boundGoto As BoundStatement = New BoundGotoStatement(node.Syntax, node.Label, Nothing)
+ Public Overrides Function VisitTupleLiteral(node As BoundTupleLiteral) As BoundNode
+ Return VisitTupleExpression(node)
+ End Function
+
+ Private Function VisitTupleExpression(node As BoundTupleExpression) As BoundNode
+ Dim rewrittenArguments As ImmutableArray(Of BoundExpression) = VisitList(node.Arguments)
+ Return RewriteTupleCreationExpression(node, rewrittenArguments)
+ End Function
+
+ '''
+ ''' Converts the expression for creating a tuple instance into an expression creating a ValueTuple (if short) or nested ValueTuples (if longer).
+ '''
+ ''' For instance, for a long tuple we'll generate:
+ ''' creationExpression(ctor=largestCtor, args=firstArgs+(nested creationExpression for remainder, with smaller ctor and next few args))
+ '''
+ Private Function RewriteTupleCreationExpression(node As BoundTupleExpression, rewrittenArguments As ImmutableArray(Of BoundExpression)) As BoundExpression
+ Return MakeTupleCreationExpression(node.Syntax, DirectCast(node.Type, NamedTypeSymbol), rewrittenArguments)
+ End Function
+
+ Private Function MakeTupleCreationExpression(syntax As VisualBasicSyntaxNode, type As NamedTypeSymbol, rewrittenArguments As ImmutableArray(Of BoundExpression)) As BoundExpression
+ Dim underlyingTupleType As NamedTypeSymbol = If(type.TupleUnderlyingType, type)
+ Debug.Assert(underlyingTupleType.IsTupleCompatible())
+
+ Dim underlyingTupleTypeChain As ArrayBuilder(Of NamedTypeSymbol) = ArrayBuilder(Of NamedTypeSymbol).GetInstance()
+ TupleTypeSymbol.GetUnderlyingTypeChain(underlyingTupleType, underlyingTupleTypeChain)
+
+ Try
+ ' make a creation expression for the smallest type
+ Dim smallestType As NamedTypeSymbol = underlyingTupleTypeChain.Pop()
+ Dim smallestCtorArguments As ImmutableArray(Of BoundExpression) = ImmutableArray.Create(rewrittenArguments,
+ underlyingTupleTypeChain.Count * (TupleTypeSymbol.RestPosition - 1),
+ smallestType.Arity)
+
+ Dim smallestCtor As MethodSymbol = DirectCast(TupleTypeSymbol.GetWellKnownMemberInType(smallestType.OriginalDefinition,
+ TupleTypeSymbol.GetTupleCtor(smallestType.Arity),
+ _diagnostics,
+ syntax), MethodSymbol)
+ If smallestCtor Is Nothing Then
+ Return New BoundBadExpression(
+ syntax,
+ LookupResultKind.Empty,
+ ImmutableArray(Of Symbol).Empty,
+ StaticCast(Of BoundNode).From(rewrittenArguments),
+ type,
+ hasErrors:=True)
+ End If
+
+ Dim smallestConstructor As MethodSymbol = smallestCtor.AsMember(smallestType)
+ Dim currentCreation As BoundObjectCreationExpression = New BoundObjectCreationExpression(syntax, smallestConstructor, smallestCtorArguments, initializerOpt:=Nothing, type:=smallestType)
+
+ If underlyingTupleTypeChain.Count > 0 Then
+ Dim tuple8Type As NamedTypeSymbol = underlyingTupleTypeChain.Peek()
+ Dim tuple8Ctor As MethodSymbol = DirectCast(TupleTypeSymbol.GetWellKnownMemberInType(tuple8Type.OriginalDefinition,
+ TupleTypeSymbol.GetTupleCtor(TupleTypeSymbol.RestPosition),
+ _diagnostics,
+ syntax), MethodSymbol)
+ If tuple8Ctor Is Nothing Then
+ Return New BoundBadExpression(
+ syntax,
+ LookupResultKind.Empty,
+ ImmutableArray(Of Symbol).Empty,
+ StaticCast(Of BoundNode).From(rewrittenArguments),
+ type,
+ hasErrors:=True)
+ End If
+
+ ' make successively larger creation expressions containing the previous one
+ Do
+ Dim ctorArguments As ImmutableArray(Of BoundExpression) = ImmutableArray.Create(rewrittenArguments,
+ (underlyingTupleTypeChain.Count - 1) * (TupleTypeSymbol.RestPosition - 1),
+ TupleTypeSymbol.RestPosition - 1).Add(currentCreation)
+
+ Dim constructor As MethodSymbol = tuple8Ctor.AsMember(underlyingTupleTypeChain.Pop())
+ currentCreation = New BoundObjectCreationExpression(syntax, constructor, ctorArguments, initializerOpt:=Nothing, type:=constructor.ContainingType)
+
+ Loop While (underlyingTupleTypeChain.Count > 0)
+
+ End If
+
+ 'currentCreation = currentCreation.Update(
+ ' currentCreation.ConstructorOpt,
+ ' methodGroupOpt:=Nothing,
+ ' arguments:=currentCreation.Arguments,
+ ' initializerOpt:=currentCreation.InitializerOpt,
+ ' type:=type)
- If ShouldGenerateUnstructuredExceptionHandlingResumeCode(node) Then
- boundGoto = Concat(RegisterUnstructuredExceptionHandlingNonThrowingResumeTarget(node.Syntax), boundGoto)
- End If
+ Return currentCreation
+ Finally
+ underlyingTupleTypeChain.Free()
+ End Try
- Return MarkStatementWithSequencePoint(boundGoto)
End Function
End Class
End Namespace
diff --git a/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb b/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb
index 387a19230d91b1b7e0f866bb040c3612970145d4..32fd0ff39c0c3c0560a3ce2b1bae5b2dff7999f5 100644
--- a/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb
+++ b/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb
@@ -320,7 +320,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' Assignment expressions in lowered form should always have suppressObjectClone = True
'''
Public Function AssignmentExpression(left As BoundExpression, right As BoundExpression) As BoundAssignmentOperator
- Debug.Assert(left.Type = right.Type OrElse right.Type.IsErrorType() OrElse left.Type.IsErrorType())
+ Debug.Assert(left.Type.IsSameTypeIgnoringCustomModifiers(right.Type) OrElse right.Type.IsErrorType() OrElse left.Type.IsErrorType())
Dim boundNode = New BoundAssignmentOperator(_syntax, left, right, True)
boundNode.SetWasCompilerGenerated()
Return boundNode
diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb
index 2d4d81c0635874a2a0d01417b6a6b51e42393efc..179417b2d65f31e1b20682f2253f27ebee0b14b4 100644
--- a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb
+++ b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb
@@ -888,8 +888,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Dim myNames = Me.TupleElementNames
Dim otherNames = otherTuple.TupleElementNames
- If myNames.IsDefaultOrEmpty AndAlso otherNames.IsDefaultOrEmpty Then
- Return True
+ If myNames.IsDefaultOrEmpty Then
+ Return otherNames.IsDefaultOrEmpty
+ End If
+
+ If otherNames.IsDefaultOrEmpty Then
+ Return False
End If
Return myNames.SequenceEqual(otherNames)
@@ -954,7 +958,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Function
Friend Overrides Function InternalSubstituteTypeParameters(substitution As TypeSubstitution) As TypeWithModifiers
- Throw ExceptionUtilities.Unreachable
+ Dim substitutedUnderlying = DirectCast(Me.TupleUnderlyingType.InternalSubstituteTypeParameters(substitution).Type, NamedTypeSymbol)
+ Dim tupleType = TupleTypeSymbol.Create(Me._locations, substitutedUnderlying, Me._elementLocations, Me._elementNames)
+
+ Return New TypeWithModifiers(tupleType, Nothing)
End Function
Friend Overrides Function MakeDeclaredBase(basesBeingResolved As ConsList(Of Symbol), diagnostics As DiagnosticBag) As NamedTypeSymbol
diff --git a/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbolExtensions.vb b/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbolExtensions.vb
index 24e2de9bc0c75be810bc54e805d3e6fafde71f82..03a27b1f0733019f2c9e1eb41117202e38380096 100644
--- a/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbolExtensions.vb
+++ b/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbolExtensions.vb
@@ -176,6 +176,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Friend Function IsSameTypeIgnoringCustomModifiers(t1 As TypeSymbol, t2 As TypeSymbol) As Boolean
+ If t1.IsTupleType Then
+ t1 = t1.TupleUnderlyingType
+ End If
+
+ If t2.IsTupleType Then
+ t2 = t2.TupleUnderlyingType
+ End If
+
If t1 Is t2 Then
Return True
End If
diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb
index 88c84d61ceba4323613150756ff944a3030d871a..1bc1bb7513615abab3c278eb51edd6c447d2e38c 100644
--- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb
+++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb
@@ -205,6 +205,61 @@ End Namespace
]]>)
End Sub
+
+
+ Public Sub TupleDefaultFieldBinding()
+
+ Dim verifier = CompileAndVerify(
+
+
+Imports System
+Module Module1
+ Sub Main()
+ Dim t As (Integer, Integer) = nothing
+
+ t.Item1 = 42
+ t.Item2 = t.Item1
+
+ Console.WriteLine(t.Item2)
+
+ Dim t1 = (A:=1, B:=123)
+ Console.WriteLine(t1.B)
+ End Sub
+End Module
+
+
+, expectedOutput:=, additionalRefs:={ValueTupleRef, SystemRuntimeFacadeRef})
+
+ verifier.VerifyIL("Module1.Main", )
+ End Sub
+
Public Sub TupleNamedFieldBindingLong()
@@ -258,7 +313,6 @@ End Module
]]>)
End Sub
-
Public Sub TupleLiteralBinding()
@@ -293,7 +347,6 @@ End Module
]]>)
End Sub
-
Public Sub TupleLiteralBindingNamed()
@@ -328,6 +381,69 @@ hello
]]>)
End Sub
+
+ Public Sub TupleLiteralSample()
+
+ Dim verifier = CompileAndVerify(
+
+
+Imports System
+Imports System.Collections.Generic
+Imports System.Threading.Tasks
+
+Module Module1
+ Sub Main()
+
+ Dim t As (Integer, Integer) = Nothing
+ t.Item1 = 42
+ t.Item2 = t.Item1
+ Console.WriteLine(t.Item2)
+
+ Dim t1 = (A:=1, B:=123)
+ Console.WriteLine(t1.B)
+
+ Dim numbers = {1, 2, 3, 4}
+
+ Dim t2 = Tally(numbers).Result
+ System.Console.WriteLine($"Sum: {t2.Sum}, Count: {t2.Count}")
+
+ End Sub
+
+ Public Async Function Tally(values As IEnumerable(Of Integer)) As Task(Of (Sum As Integer, Count As Integer))
+ Dim s = 0, c = 0
+
+ For Each n In values
+ s += n
+ c += 1
+ Next
+
+ 'Await Task.Yield()
+
+ Return (Sum:=s, Count:=c)
+ End Function
+End Module
+
+
+Namespace System
+ Structure ValueTuple(Of T1, T2)
+ Public Item1 As T1
+ Public Item2 As T2
+
+ Sub New(item1 as T1, item2 as T2)
+ Me.Item1 = item1
+ Me.Item2 = item2
+ End Sub
+ End Structure
+End Namespace
+
+
+, useLatestFramework:=True, expectedOutput:="42
+123
+Sum: 10, Count: 4")
+
+ End Sub
+
+
End Class
End Namespace