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