From 99210b0e0c6bb05ed87dc5f76fff5260ca8e40da Mon Sep 17 00:00:00 2001 From: adamperlin Date: Thu, 4 Aug 2022 15:53:27 -0700 Subject: [PATCH 01/23] WIP add default parameter information to synthesized delegate types --- .../CSharp/Portable/Binder/Binder_Expressions.cs | 8 ++++++-- .../CSharp/Portable/BoundTree/UnboundLambda.cs | 3 ++- .../Lowering/SynthesizedMethodBaseSymbol.cs | 1 + .../AnonymousTypes/AnonymousTypeDescriptor.cs | 2 +- .../Symbols/AnonymousTypes/AnonymousTypeField.cs | 5 ++++- .../AnonymousType.DelegatePublicSymbol.cs | 4 ++-- .../AnonymousType.DelegateTemplateSymbol.cs | 8 ++++---- .../Synthesized/SynthesizedDelegateSymbol.cs | 4 ++-- .../SynthesizedIntrinsicOperatorSymbol.cs | 2 +- .../Synthesized/SynthesizedParameterSymbol.cs | 16 ++++++++++++---- 10 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 096834571c6e..0361b2db3a7a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8935,7 +8935,8 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) TypeWithAnnotations returnType, ImmutableArray parameterRefKinds, ImmutableArray parameterScopes, - ImmutableArray parameterTypes) + ImmutableArray parameterTypes, + ImmutableArray parameterDefaultValues = default) { Debug.Assert(ContainingMemberOrLambda is { }); Debug.Assert(parameterRefKinds.IsDefault || parameterRefKinds.Length == parameterTypes.Length); @@ -8958,6 +8959,7 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) // Use System.Action<...> or System.Func<...> if possible. if (returnRefKind == RefKind.None && + parameterDefaultValues.IsDefault && (parameterRefKinds.IsDefault || parameterRefKinds.All(refKind => refKind == RefKind.None)) && (parameterScopes.IsDefault || parameterScopes.All(scope => scope == DeclarationScope.Unscoped))) { @@ -8992,7 +8994,9 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) location, parameterTypes[i], parameterRefKinds.IsDefault ? RefKind.None : parameterRefKinds[i], - parameterScopes.IsDefault ? DeclarationScope.Unscoped : parameterScopes[i])); + parameterScopes.IsDefault ? DeclarationScope.Unscoped : parameterScopes[i], + parameterDefaultValues.IsDefault ? null : parameterDefaultValues[i]) + ); } fieldsBuilder.Add(new AnonymousTypeField(name: "", location, returnType, returnRefKind, DeclarationScope.Unscoped)); diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 134452ca97a8..d83e63dea316 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -702,7 +702,8 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo returnType, parameterRefKinds, parameterScopes, - parameterTypes); + parameterTypes, + parameterDefaultValues); } private BoundLambda ReallyBind(NamedTypeSymbol delegateType, bool inExpressionTree) diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs index d7d406f635e2..1a91531c1b7d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs @@ -137,6 +137,7 @@ private ImmutableArray MakeParameters() p.RefKind, p.Name, p.Scope, + p.ExplicitDefaultConstantValue, // the synthesized parameter doesn't need to have the same ref custom modifiers as the base refCustomModifiers: default, inheritAttributes ? p as SourceComplexParameterSymbolBase : null)); diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs index 024358de355c..90399e415bfe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs @@ -78,7 +78,7 @@ internal bool Equals(AnonymousTypeDescriptor other, TypeCompareKind comparison) return Fields.SequenceEqual( other.Fields, comparison, - static (x, y, comparison) => x.TypeWithAnnotations.Equals(y.TypeWithAnnotations, comparison) && x.RefKind == y.RefKind && x.Scope == y.Scope); + static (x, y, comparison) => x.TypeWithAnnotations.Equals(y.TypeWithAnnotations, comparison) && x.RefKind == y.RefKind && x.Scope == y.Scope && x.DefaultValue == y.DefaultValue); } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs index 65f769a5cd8f..4a74f066c6e1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs @@ -24,16 +24,19 @@ internal readonly struct AnonymousTypeField public readonly DeclarationScope Scope; + public readonly ConstantValue? DefaultValue; + /// Anonymous type field type public TypeSymbol Type => TypeWithAnnotations.Type; - public AnonymousTypeField(string name, Location location, TypeWithAnnotations typeWithAnnotations, RefKind refKind, DeclarationScope scope) + public AnonymousTypeField(string name, Location location, TypeWithAnnotations typeWithAnnotations, RefKind refKind, DeclarationScope scope, ConstantValue? defaultValue = null) { this.Name = name; this.Location = location; this.TypeWithAnnotations = typeWithAnnotations; this.RefKind = refKind; this.Scope = scope; + this.DefaultValue = defaultValue; } [Conditional("DEBUG")] diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.DelegatePublicSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.DelegatePublicSymbol.cs index aa0e5a55b450..a173588ef7aa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.DelegatePublicSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.DelegatePublicSymbol.cs @@ -54,11 +54,11 @@ private ImmutableArray CreateMembers() var constructor = new SynthesizedDelegateConstructor(this, Manager.System_Object, Manager.System_IntPtr); var fields = TypeDescriptor.Fields; int parameterCount = fields.Length - 1; - var parameters = ArrayBuilder<(TypeWithAnnotations, RefKind, DeclarationScope)>.GetInstance(parameterCount); + var parameters = ArrayBuilder<(TypeWithAnnotations, RefKind, DeclarationScope, ConstantValue?)>.GetInstance(parameterCount); for (int i = 0; i < parameterCount; i++) { var field = fields[i]; - parameters.Add((field.TypeWithAnnotations, field.RefKind, field.Scope)); + parameters.Add((field.TypeWithAnnotations, field.RefKind, field.Scope, field.DefaultValue)); } var returnField = fields.Last(); var invokeMethod = new SynthesizedDelegateInvokeMethod(this, parameters, returnField.TypeWithAnnotations, returnField.RefKind); diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs index f2d34959dbac..70804693dedd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs @@ -53,10 +53,10 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod(AnonymousDelegateTempl var typeParams = containingType.TypeParameters; int parameterCount = typeParams.Length - (voidReturnTypeOpt is null ? 1 : 0); - var parameters = ArrayBuilder<(TypeWithAnnotations, RefKind, DeclarationScope)>.GetInstance(parameterCount); + var parameters = ArrayBuilder<(TypeWithAnnotations, RefKind, DeclarationScope, ConstantValue?)>.GetInstance(parameterCount); for (int i = 0; i < parameterCount; i++) { - parameters.Add((TypeWithAnnotations.Create(typeParams[i]), refKinds.IsNull ? RefKind.None : refKinds[i], DeclarationScope.Unscoped)); + parameters.Add((TypeWithAnnotations.Create(typeParams[i]), refKinds.IsNull ? RefKind.None : refKinds[i], DeclarationScope.Unscoped, null)); } // if we are given Void type the method returns Void, otherwise its return type is the last type parameter of the delegate: @@ -127,11 +127,11 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod( TypeMap typeMap) { var parameterCount = fields.Length - 1; - var parameters = ArrayBuilder<(TypeWithAnnotations, RefKind, DeclarationScope)>.GetInstance(parameterCount); + var parameters = ArrayBuilder<(TypeWithAnnotations, RefKind, DeclarationScope, ConstantValue?)>.GetInstance(parameterCount); for (int i = 0; i < parameterCount; i++) { var field = fields[i]; - parameters.Add((typeMap.SubstituteType(field.Type), field.RefKind, field.Scope)); + parameters.Add((typeMap.SubstituteType(field.Type), field.RefKind, field.Scope, field.DefaultValue)); } var returnParameter = fields[^1]; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs index de22eb3fadbd..d93069435e7e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs @@ -32,11 +32,11 @@ internal sealed class SynthesizedDelegateInvokeMethod : SynthesizedInstanceMetho { private readonly NamedTypeSymbol _containingType; - internal SynthesizedDelegateInvokeMethod(NamedTypeSymbol containingType, ArrayBuilder<(TypeWithAnnotations Type, RefKind RefKind, DeclarationScope Scope)> parameterDescriptions, TypeWithAnnotations returnType, RefKind refKind) + internal SynthesizedDelegateInvokeMethod(NamedTypeSymbol containingType, ArrayBuilder<(TypeWithAnnotations Type, RefKind RefKind, DeclarationScope Scope, ConstantValue? DefaultValue)> parameterDescriptions, TypeWithAnnotations returnType, RefKind refKind) { _containingType = containingType; - Parameters = parameterDescriptions.SelectAsArrayWithIndex((p, i, m) => SynthesizedParameterSymbol.Create(m, p.Type, i, p.RefKind, scope: p.Scope), this); + Parameters = parameterDescriptions.SelectAsArrayWithIndex((p, i, m) => SynthesizedParameterSymbol.Create(m, p.Type, i, p.RefKind, scope: p.Scope, defaultValue: p.DefaultValue), this); ReturnTypeWithAnnotations = returnType; RefKind = refKind; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index 6777f7dcc2a9..fae824cfb659 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -471,7 +471,7 @@ public SynthesizedOperatorParameterSymbol( TypeSymbol type, int ordinal, string name - ) : base(container, TypeWithAnnotations.Create(type), ordinal, RefKind.None, DeclarationScope.Unscoped, name) + ) : base(container, TypeWithAnnotations.Create(type), ordinal, RefKind.None, DeclarationScope.Unscoped, null, name) { } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index cbd679652473..0b8e4d00d3a7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -21,6 +21,7 @@ internal abstract class SynthesizedParameterSymbolBase : ParameterSymbol private readonly string _name; private readonly RefKind _refKind; private readonly DeclarationScope _scope; + private readonly ConstantValue? _defaultValue; public SynthesizedParameterSymbolBase( MethodSymbol? container, @@ -28,6 +29,7 @@ public SynthesizedParameterSymbolBase( int ordinal, RefKind refKind, DeclarationScope scope, + ConstantValue? defaultValue, string name) { Debug.Assert(type.HasType); @@ -39,6 +41,7 @@ public SynthesizedParameterSymbolBase( _ordinal = ordinal; _refKind = refKind; _scope = scope; + _defaultValue = defaultValue; _name = name; } @@ -81,7 +84,7 @@ public override bool IsImplicitlyDeclared internal override ConstantValue? ExplicitDefaultConstantValue { - get { return null; } + get { return _defaultValue; } } internal override bool IsIDispatchConstant @@ -199,8 +202,9 @@ private SynthesizedParameterSymbol( int ordinal, RefKind refKind, DeclarationScope scope, + ConstantValue? defaultValue, string name) - : base(container, type, ordinal, refKind, scope, name) + : base(container, type, ordinal, refKind, scope, defaultValue, name) { } @@ -211,12 +215,13 @@ public static ParameterSymbol Create( RefKind refKind, string name = "", DeclarationScope scope = DeclarationScope.Unscoped, + ConstantValue? defaultValue = null, ImmutableArray refCustomModifiers = default, SourceComplexParameterSymbolBase? baseParameterForAttributes = null) { if (refCustomModifiers.IsDefaultOrEmpty && baseParameterForAttributes is null) { - return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, name); + return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, defaultValue, name); } return new SynthesizedComplexParameterSymbol( @@ -225,6 +230,7 @@ public static ParameterSymbol Create( ordinal, refKind, scope, + defaultValue, name, refCustomModifiers.NullToEmpty(), baseParameterForAttributes); @@ -252,6 +258,7 @@ internal static ImmutableArray DeriveParameters(MethodSymbol so oldParam.RefKind, oldParam.Name, oldParam.Scope, + oldParam.ExplicitDefaultConstantValue, oldParam.RefCustomModifiers, baseParameterForAttributes: null)); } @@ -283,10 +290,11 @@ public SynthesizedComplexParameterSymbol( int ordinal, RefKind refKind, DeclarationScope scope, + ConstantValue? defaultValue, string name, ImmutableArray refCustomModifiers, SourceComplexParameterSymbolBase? baseParameterForAttributes) - : base(container, type, ordinal, refKind, scope, name) + : base(container, type, ordinal, refKind, scope, defaultValue, name) { Debug.Assert(!refCustomModifiers.IsDefault); Debug.Assert(!refCustomModifiers.IsEmpty || baseParameterForAttributes is object); From f846cf5ea68f5e5dc5e3b6a110c69c801bf6c7f0 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 5 Aug 2022 08:47:04 -0700 Subject: [PATCH 02/23] Update closure codegen tests file to see codegen in current state --- .../Emit/CodeGen/CodeGenClosureLambdaTests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenClosureLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenClosureLambdaTests.cs index 42bbf668e19a..803dc24e2d38 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenClosureLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenClosureLambdaTests.cs @@ -5809,5 +5809,24 @@ .locals init (Program.<>c__DisplayClass1_0 V_0, //CS$<>8__locals0 IL_004f: ret }"); } + + [Fact] + public void LambdaWithDefaultParameter() + { + string source = """ +using System; +class C +{ + public static void Main() + { + var lam = (int x = 3) => x + x + x; + Console.WriteLine(lam(10)); + } +} +"""; + var comp = CompileAndVerify(source, expectedOutput: "30"); + //comp.VerifyIL("C.Main", expectedIL: ""); + comp.VerifyTypeIL("C", ""); + } } } From 4e8dddc3b3615b8688b681d250e310c4c5450745 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 8 Aug 2022 17:11:04 -0700 Subject: [PATCH 03/23] Finish adding default parameters to synthesized delegate types and update closure conversion pass + add tests --- .../Portable/BoundTree/UnboundLambda.cs | 8 + .../AnonymousTypes/AnonymousTypeDescriptor.cs | 2 +- .../AnonymousTypeManager.Templates.cs | 1 + .../Symbols/Source/LambdaParameterSymbol.cs | 5 - .../Synthesized/SynthesizedParameterSymbol.cs | 10 +- .../Emit/CodeGen/CodeGenClosureLambdaTests.cs | 19 - .../Semantic/Semantics/DelegateTypeTests.cs | 352 ++++++++++++++++++ 7 files changed, 367 insertions(+), 30 deletions(-) diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index d83e63dea316..63fcdc2b1418 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -665,6 +665,14 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo } } + // Account for the situation where we have trailing required parameters AFTER an optional one, i.e., (int opt1 = 3, T1 req1, ..., TN reqN) => {...} + // so we will be missing null default values for req1, ..., reqN when exiting the previous loop and the length of the default value builder will + // be too short. + if (parameterDefaultValueBuilder is { }) + { + parameterDefaultValueBuilder.AddMany(null, lambdaSymbol.Parameters.Length - parameterDefaultValueBuilder.Count); + } + var parameterDefaultValues = parameterDefaultValueBuilder?.ToImmutableAndFree() ?? default; if (!HasExplicitReturnType(out var returnRefKind, out var returnType)) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs index 90399e415bfe..aa16ebed1872 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs @@ -103,7 +103,7 @@ internal AnonymousTypeDescriptor WithNewFieldsTypes(ImmutableArray new AnonymousTypeField(field.Name, field.Location, type, field.RefKind, field.Scope)); + var newFields = Fields.ZipAsArray(newFieldTypes, static (field, type) => new AnonymousTypeField(field.Name, field.Location, type, field.RefKind, field.Scope, field.DefaultValue)); return new AnonymousTypeDescriptor(newFields, this.Location); } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs index 686635a73031..9e07d49c2976 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs @@ -264,6 +264,7 @@ static bool hasDefaultScope(AnonymousTypeField field) => static bool isValidTypeArgument(AnonymousTypeField field) { return hasDefaultScope(field) && + field.DefaultValue is null && field.Type is { } type && !type.IsPointerOrFunctionPointer() && !type.IsRestrictedType(); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaParameterSymbol.cs index c4072c2879cf..0a68041a7f5b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaParameterSymbol.cs @@ -31,11 +31,6 @@ public LambdaParameterSymbol( public override bool IsDiscard { get; } - internal override bool IsMetadataOptional - { - get { return false; } - } - public override bool IsParams { get { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 0b8e4d00d3a7..d4392681e9cb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -74,7 +74,7 @@ public override bool IsParams internal override bool IsMetadataOptional { - get { return false; } + get { return ExplicitDefaultConstantValue != null; } } public override bool IsImplicitlyDeclared @@ -99,17 +99,17 @@ internal override bool IsIUnknownConstant internal override bool IsCallerLineNumber { - get { throw ExceptionUtilities.Unreachable; } + get { return false; } } internal override bool IsCallerFilePath { - get { throw ExceptionUtilities.Unreachable; } + get { return false; } } internal override bool IsCallerMemberName { - get { throw ExceptionUtilities.Unreachable; } + get { return false; } } internal override int CallerArgumentExpressionParameterIndex @@ -202,7 +202,7 @@ private SynthesizedParameterSymbol( int ordinal, RefKind refKind, DeclarationScope scope, - ConstantValue? defaultValue, + ConstantValue? defaultValue, string name) : base(container, type, ordinal, refKind, scope, defaultValue, name) { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenClosureLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenClosureLambdaTests.cs index 803dc24e2d38..42bbf668e19a 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenClosureLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenClosureLambdaTests.cs @@ -5809,24 +5809,5 @@ .locals init (Program.<>c__DisplayClass1_0 V_0, //CS$<>8__locals0 IL_004f: ret }"); } - - [Fact] - public void LambdaWithDefaultParameter() - { - string source = """ -using System; -class C -{ - public static void Main() - { - var lam = (int x = 3) => x + x + x; - Console.WriteLine(lam(10)); - } -} -"""; - var comp = CompileAndVerify(source, expectedOutput: "30"); - //comp.VerifyIL("C.Main", expectedIL: ""); - comp.VerifyTypeIL("C", ""); - } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 616b917091ce..1f4091ef19ab 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Reflection.Metadata; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -11494,5 +11495,356 @@ .maxstack 0 IL_0000: ret }"); } + + internal static void CheckNames(IEnumerable readers, IEnumerable handles, params string[] expectedNames) + { + var actualNames = readers.GetStrings(handles); + AssertEx.Equal(expectedNames, actualNames); + } + + [Fact] + public void LambdaWithDefaultParameter() + { + var source = """ +using System; + +class Program +{ + // static void Report(object d) => Console.WriteLine(d.GetType()); + public static void Main() + { + var lam = (int x = 30) => x; + Console.WriteLine(lam() + " " + lam(10)); + // Report(lam); + } +} +"""; + + var expectAnonymousDelegateIL = """ +.class private auto ansi sealed '<>f__AnonymousDelegate0' + extends [netstandard]System.MulticastDelegate +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method '<>f__AnonymousDelegate0'::.ctor + .method public hidebysig newslot virtual + instance int32 Invoke ( + [opt] int32 '' + ) runtime managed + { + .param [1] = int32(30) + } // end of method '<>f__AnonymousDelegate0'::Invoke +} // end of class <>f__AnonymousDelegate0 +"""; + + + var loweredLambdaContainerClassIL = """ +.class nested private auto ansi sealed serializable beforefieldinit '<>c' + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static initonly class Program/'<>c' '<>9' + .field public static class '<>f__AnonymousDelegate0' '<>9__0_0' + // Methods + .method private hidebysig specialname rtspecialname static + void .cctor () cil managed + { + // Method begins at RVA 0x20b4 + // Code size 11 (0xb) + .maxstack 8 + IL_0000: newobj instance void Program/'<>c'::.ctor() + IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_000a: ret + } // end of method '<>c'::.cctor + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20ac + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [netstandard]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c'::.ctor + .method assembly hidebysig + instance int32 '
b__0_0' ( + [opt] int32 x + ) cil managed + { + .param [1] = int32(30) + // Method begins at RVA 0x20c0 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ret + } // end of method '<>c'::'
b__0_0' +} // end of class <>c +"""; + + var verifier = CompileAndVerify(source, expectedOutput: "30 10"); + var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); + var reader = m.MetadataReader; + CheckNames(new[] { reader }, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "Program", "<>c"); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0", expectAnonymousDelegateIL); + verifier.VerifyTypeIL("<>c", loweredLambdaContainerClassIL); + } + + [Fact] + public void LambdaWithMultipleDefaultParameters() + { + var source = """ +using System; + +class Program +{ + public static string Report(object obj) => obj.GetType().ToString(); + public static void Main() + { + var lam = (int a = 1, int b = 2, int c = 3) => a + b + c; + Console.WriteLine(lam(2) + " " + Report(lam)); + } +} +"""; + var verifier = CompileAndVerify(source, expectedOutput: "7 <>f__AnonymousDelegate0"); + } + + [Fact] + public void LambdaWithOptionalAndDefaultParameters() + { + var source = """ +using System; + +class Program +{ + public static string Report(object obj) => obj.GetType().ToString(); + public static void Main() + { + var lam = (string s1, string s2 = "b", string s3 = "c") => s1 + s2 + s3; + Console.WriteLine(lam("a") + " " + Report(lam)); + } +} +"""; + var verifier = CompileAndVerify(source, expectedOutput: "abc <>f__AnonymousDelegate0"); + } + + [Fact] + public void LambdaWithIdenticalSignatureDifferentDefaultValue() + { + var source = """ +using System; + +class Program +{ + public static void Report(object obj) => Console.WriteLine(obj.GetType()); + public static void Main() + { + var lam1 = (int x = 10) => x + x; + var lam2 = (int x = 20) => x + x; + Report(lam1); + Report(lam2); + } +} +"""; + CompileAndVerify(source, expectedOutput: +@"<>f__AnonymousDelegate0 +<>f__AnonymousDelegate1 +"); + } + + [Fact] + public void LambdaWithIdenticalSignatureIdenticalDefaultValue() + { + var source = """ +using System; + +class Program +{ + public static void Report(object obj) => Console.WriteLine(obj.GetType()); + public static void Main() + { + var lam1 = (int x = 10) => x + x; + var lam2 = (int x = 10) => x + 1; + Report(lam1); + Report(lam2); + } +} +"""; + CompileAndVerify(source, expectedOutput: + @"<>f__AnonymousDelegate0 +<>f__AnonymousDelegate0"); + + } + + [Fact] + public void LambdaWithIdenticalSignatureOptionalMismatch() + { + var source = """ +using System; + +class Program +{ + public static void Report(object obj) => Console.WriteLine(obj.GetType()); + public static void Main() + { + var lam1 = (int x = 10) => x + x; + var lam2 = (int x) => x + 1; + Report(lam1); + Report(lam2); + } +} +"""; + CompileAndVerify(source, expectedOutput: +@"<>f__AnonymousDelegate0 +System.Func`2[System.Int32,System.Int32] +"); + } + + [Fact] + public void LambdaConversionDefaultParameterValueMismatch() + { + var source = """ +using System; + +class Program +{ + public static void Report(object obj) => Console.WriteLine(obj.GetType()); + public static void Main() + { + var lam1 = (int x = 10) => x + x; + var lam2 = (int x = 20) => x + 1; + lam1 = lam2; + lam1(); + } +} +"""; + CreateCompilation(source).VerifyDiagnostics( + // (10,16): error CS0029: Cannot implicitly convert type '' to '' + // lam1 = lam2; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "lam2").WithArguments("", "").WithLocation(10, 16)); + } + + [Fact] + public void LambdaNoConversionDefaultParameterValueMatch() + { + + var source = """ +using System; + +class Program +{ + public static void Report(object obj) => Console.WriteLine(obj.GetType()); + public static void Main() + { + var lam1 = (int x = 10) => x + x; + var lam2 = (int x = 10) => x + 1; + lam1 = lam2; + Console.WriteLine(lam1()); + } +} +"""; + CompileAndVerify(source, expectedOutput: "11"); + } + + [Fact] + public void LambdaWithDefaultNamedDelegateConversion_DefaultValueMatch() + { + // TODO: This code should compile with no diagnostics. We want to do a target-type conversion here to the named delegate type + var source = """ +using System; + +class Program +{ + delegate int D(int x = 1); + public static void Main() + { + D d = (int x = 1) => x + x; + Console.WriteLine(d()); + } +} +"""; + CompileAndVerify(source, expectedOutput: "2"); + } + + [Fact] + public void LambdaWithDefaultNamedDelegateConversion_DefaultValueMismatch() + { + + var source = """ +using System; + +class Program +{ + delegate int D(int x = 1); + public static void Main() + { + D d = (int x = 1000) => x + x; + Console.WriteLine(d()); + } +} +"""; + CompileAndVerify(source, expectedOutput: "2"); + } + + [Fact] + public void LambdaWithDefaultNamedDelegateConversion_RequiredOptionalMismatch() + { + + // TODO: we want to add a warning here, since we have an implicit target-type conversion from a lambda WITH an optional parameter + // to a named delegate WITHOUT one, so the default value was useless to specify in code. + var source = """ +class Program +{ + // Named delegate has required parameter x + delegate int D(int x); + public static void Main() + { + // lambda has optional parameter x + D d = (int x = 1000) => x + x; + d(); + } +} +"""; + CreateCompilation(source).VerifyDiagnostics( + // (9,9): error CS7036: There is no argument given that corresponds to the required formal parameter 'x' of 'Program.D' + // d(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "d").WithArguments("x", "Program.D").WithLocation(9, 9)); + } + + [Fact] + public void LambdaOptionalBeforeRequiredBadConversion() + { + + var source = """ +class Program +{ + public static void Main() + { + // lambda has optional parameter x + var lam1 = (int x, int y = 10, int z) => x * x + y * y + z * z; + var lam2 = (int x, int y, int z) => x * x + y * y + z * z; + + lam2 = lam1; + } +} +"""; + CreateCompilation(source).VerifyDiagnostics( + // (6,45): error CS1737: Optional parameters must appear after all required parameters + // var lam1 = (int x, int y = 10, int z) => x * x + y * y + z * z; + Diagnostic(ErrorCode.ERR_DefaultValueBeforeRequiredValue, ")").WithLocation(6, 45), + // (9,16): error CS0029: Cannot implicitly convert type '' to 'System.Func' + // lam2 = lam1; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "lam1").WithArguments("", "System.Func").WithLocation(9, 16)); + } } } From 020b563c87329f96435b1aa70ec52b303db1e5a2 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 9 Aug 2022 14:43:37 -0700 Subject: [PATCH 04/23] Add additional unit tests --- .../Semantic/Semantics/DelegateTypeTests.cs | 228 +++++++++++++++++- 1 file changed, 215 insertions(+), 13 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 1f4091ef19ab..6462de1648cb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -11502,6 +11502,12 @@ internal static void CheckNames(IEnumerable readers, IEnumerable AssertEx.Equal(expectedNames, actualNames); } + internal static void CheckNames(MetadataReader reader, IEnumerable handles, params string[] expectedNames) + { + CheckNames(new[] { reader }, handles, expectedNames); + } + + [Fact] public void LambdaWithDefaultParameter() { @@ -11546,7 +11552,7 @@ [opt] int32 '' """; - var loweredLambdaContainerClassIL = """ + var expectLoweredClosureContainerIL = """ .class nested private auto ansi sealed serializable beforefieldinit '<>c' extends [netstandard]System.Object { @@ -11595,9 +11601,9 @@ .maxstack 8 var verifier = CompileAndVerify(source, expectedOutput: "30 10"); var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); var reader = m.MetadataReader; - CheckNames(new[] { reader }, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "Program", "<>c"); + CheckNames(reader, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "Program", "<>c"); verifier.VerifyTypeIL("<>f__AnonymousDelegate0", expectAnonymousDelegateIL); - verifier.VerifyTypeIL("<>c", loweredLambdaContainerClassIL); + verifier.VerifyTypeIL("<>c", expectLoweredClosureContainerIL); } [Fact] @@ -11635,7 +11641,91 @@ public static void Main() } } """; + var expectAnonymousDelegateIL = +@" +.class private auto ansi sealed '<>f__AnonymousDelegate0' + extends [netstandard]System.MulticastDelegate +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method '<>f__AnonymousDelegate0'::.ctor + .method public hidebysig newslot virtual + instance string Invoke ( + string '', + [opt] string '', + [opt] string '' + ) runtime managed + { + .param [2] = ""b"" + .param [3] = ""c"" + } // end of method '<>f__AnonymousDelegate0'::Invoke +} // end of class <>f__AnonymousDelegate0 +"; + + var expectLoweredClosureContainerIL = +@" + .class nested private auto ansi sealed serializable beforefieldinit '<>c' + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static initonly class Program/'<>c' '<>9' + .field public static class '<>f__AnonymousDelegate0' '<>9__1_0' + // Methods + .method private hidebysig specialname rtspecialname static + void .cctor () cil managed + { + // Method begins at RVA 0x20bf + // Code size 11 (0xb) + .maxstack 8 + IL_0000: newobj instance void Program/'<>c'::.ctor() + IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_000a: ret + } // end of method '<>c'::.cctor + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20b7 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [netstandard]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c'::.ctor + .method assembly hidebysig + instance string '
b__1_0' ( + string s1, + [opt] string s2, + [opt] string s3 + ) cil managed + { + .param [2] = ""b"" + .param [3] = ""c"" + // Method begins at RVA 0x20cb + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ldarg.2 + IL_0002: ldarg.3 + IL_0003: call string [netstandard]System.String::Concat(string, string, string) + IL_0008: ret + } // end of method '<>c'::'
b__1_0' +} // end of class <>c +"; + var verifier = CompileAndVerify(source, expectedOutput: "abc <>f__AnonymousDelegate0"); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0", expectAnonymousDelegateIL); + verifier.VerifyTypeIL("<>c", expectLoweredClosureContainerIL); } [Fact] @@ -11656,10 +11746,14 @@ public static void Main() } } """; - CompileAndVerify(source, expectedOutput: + var verifier = CompileAndVerify(source, expectedOutput: @"<>f__AnonymousDelegate0 <>f__AnonymousDelegate1 "); + + var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); + var reader = m.MetadataReader; + CheckNames(reader, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "<>f__AnonymousDelegate1", "Program", "<>c"); } [Fact] @@ -11680,10 +11774,13 @@ public static void Main() } } """; - CompileAndVerify(source, expectedOutput: + var verifier = CompileAndVerify(source, expectedOutput: @"<>f__AnonymousDelegate0 <>f__AnonymousDelegate0"); + var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); + var reader = m.MetadataReader; + CheckNames(reader, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "Program", "<>c"); } [Fact] @@ -11704,10 +11801,41 @@ public static void Main() } } """; - CompileAndVerify(source, expectedOutput: + var verifier = CompileAndVerify(source, expectedOutput: @"<>f__AnonymousDelegate0 System.Func`2[System.Int32,System.Int32] "); + + var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); + var reader = m.MetadataReader; + CheckNames(reader, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "Program", "<>c"); + } + + [Fact] + public void LambdaIdenticalArityIdenticalDefaultParamDifferentRequiredParams() + { + var source = """ +using System; + +class Program +{ + public static void Report(object obj) => Console.WriteLine(obj.GetType()); + public static void Main() + { + var lam1 = (double d, int x = 10) => { }; + var lam2 = (string s, int x = 10) => { }; + Report(lam1); + Report(lam2); + } +} +"""; + + // PROTOTYPE: these two delegate types could be unified into a single anonymous delegate class that has a type parameter + // for the first argument, so the invoke would look like `<>f__AnonymousDelegate0::Invoke(T arg1, int arg2 = 10)`. + // Do we want to change the behavior here to avoid generating too many anonymous delegates? + CompileAndVerify(source, expectedOutput: +@"<>f__AnonymousDelegate0 +<>f__AnonymousDelegate1"); } [Fact] @@ -11737,7 +11865,6 @@ public static void Main() [Fact] public void LambdaNoConversionDefaultParameterValueMatch() { - var source = """ using System; @@ -11747,19 +11874,18 @@ class Program public static void Main() { var lam1 = (int x = 10) => x + x; - var lam2 = (int x = 10) => x + 1; + var lam2 = (int a = 10) => a + a; lam1 = lam2; Console.WriteLine(lam1()); } } """; - CompileAndVerify(source, expectedOutput: "11"); + CompileAndVerify(source, expectedOutput: "20"); } [Fact] public void LambdaWithDefaultNamedDelegateConversion_DefaultValueMatch() { - // TODO: This code should compile with no diagnostics. We want to do a target-type conversion here to the named delegate type var source = """ using System; @@ -11793,15 +11919,15 @@ public static void Main() } } """; + + // TODO: we want to have a warning here, because the default value when calling the named delegate will come from the delegate + // itself and not the underlying lambda which could be confusing. CompileAndVerify(source, expectedOutput: "2"); } [Fact] public void LambdaWithDefaultNamedDelegateConversion_RequiredOptionalMismatch() { - - // TODO: we want to add a warning here, since we have an implicit target-type conversion from a lambda WITH an optional parameter - // to a named delegate WITHOUT one, so the default value was useless to specify in code. var source = """ class Program { @@ -11815,6 +11941,8 @@ public static void Main() } } """; + // TODO: we want to add a warning here, since we have an implicit target-type conversion from a lambda WITH an optional parameter + // to a named delegate WITHOUT one, so the default value was useless to specify in code. CreateCompilation(source).VerifyDiagnostics( // (9,9): error CS7036: There is no argument given that corresponds to the required formal parameter 'x' of 'Program.D' // d(); @@ -11846,5 +11974,79 @@ public static void Main() // lam2 = lam1; Diagnostic(ErrorCode.ERR_NoImplicitConv, "lam1").WithArguments("", "System.Func").WithLocation(9, 16)); } + + [Fact] + public void LambdaRequiredBetweenOptionalsParameters() + { + var source = """ + class Program + { + public static void Main() + { + var lam = (string s1 = null, string s2, string s3, string s4, string s5 = "") => s5; + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (5,47): error CS1737: Optional parameters must appear after all required parameters + // var lam = (string s1 = null, string s2, string s3, string s4, string s5 = "") => s5; + Diagnostic(ErrorCode.ERR_DefaultValueBeforeRequiredValue, ",").WithLocation(5, 47), + // (5,58): error CS1737: Optional parameters must appear after all required parameters + // var lam = (string s1 = null, string s2, string s3, string s4, string s5 = "") => s5; + Diagnostic(ErrorCode.ERR_DefaultValueBeforeRequiredValue, ",").WithLocation(5, 58), + // (5,69): error CS1737: Optional parameters must appear after all required parameters + // var lam = (string s1 = null, string s2, string s3, string s4, string s5 = "") => s5; + Diagnostic(ErrorCode.ERR_DefaultValueBeforeRequiredValue, ",").WithLocation(5, 69)); + } + + [Fact] + public void LambdaWithDefaultInvalidTargetTypeConversion_01() + { + var source = """ + class Program + { + delegate double D(int x, int d = 3); + public static void Main() + { + D d = (int x, double d = 3.0) => x + d; + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (6,15): error CS1661: Cannot convert lambda expression to type 'Program.D' because the parameter types do not match the delegate parameter types + // D d = (int x, double d = 3.0) => x + d; + Diagnostic(ErrorCode.ERR_CantConvAnonMethParams, "(int x, double d = 3.0) => x + d").WithArguments("lambda expression", "Program.D").WithLocation(6, 15), + // (6,30): error CS1678: Parameter 2 is declared as type 'double' but should be 'int' + // D d = (int x, double d = 3.0) => x + d; + Diagnostic(ErrorCode.ERR_BadParamType, "d").WithArguments("2", "", "double", "", "int").WithLocation(6, 30)); + } + + [Fact] + public void LambdaWithInvalidDefaultValidTargetTypeConversion_02() + { + var source = """ + class A + { } + + class B : A + { } + + class Program + { + delegate double D(int x, B b = null); + public static void Main() + { + D d = (int x, A a = null) => { }; + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (12,15): error CS1661: Cannot convert lambda expression to type 'Program.D' because the parameter types do not match the delegate parameter types + // D d = (int x, A a = null) => { }; + Diagnostic(ErrorCode.ERR_CantConvAnonMethParams, "(int x, A a = null) => { }").WithArguments("lambda expression", "Program.D").WithLocation(12, 15), + // (12,25): error CS1678: Parameter 2 is declared as type 'A' but should be 'B' + // D d = (int x, A a = null) => { }; + Diagnostic(ErrorCode.ERR_BadParamType, "a").WithArguments("2", "", "A", "", "B").WithLocation(12, 25)); + } } } From ef79ab7818c818bb0a454a5e705d41fc67dbd86a Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 9 Aug 2022 15:42:47 -0700 Subject: [PATCH 05/23] Add additional test case --- .../Semantic/Semantics/DelegateTypeTests.cs | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 6462de1648cb..cd523449bb22 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -12048,5 +12048,118 @@ public static void Main() // D d = (int x, A a = null) => { }; Diagnostic(ErrorCode.ERR_BadParamType, "a").WithArguments("2", "", "A", "", "B").WithLocation(12, 25)); } + + [Fact] + public void LambdaWithDefaultsAndRefParameters() + { + + var source = """ + using System; + + class Program + { + static void Report(object d) => Console.WriteLine(d.GetType()); + public static void Main() + { + int x = 9; + var lam = (ref int x, out int y, int z = 3) => { y = x + z; }; + lam(ref x, out var y); + lam(ref x, out var w, 20); + + Console.WriteLine(y); + Console.WriteLine(w); + Report(lam); + } + } + """; + var expectAnonymousDelegateIL = +@" + .class private auto ansi sealed '<>f__AnonymousDelegate0' + extends [netstandard]System.MulticastDelegate +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method '<>f__AnonymousDelegate0'::.ctor + .method public hidebysig newslot virtual + instance void Invoke ( + int32& '', + [out] int32& '', + [opt] int32 '' + ) runtime managed + { + .param [3] = int32(3) + } // end of method '<>f__AnonymousDelegate0'::Invoke +} // end of class <>f__AnonymousDelegate0 +"; + + var expectLoweredClosureContainerIL = +@" +.class nested private auto ansi sealed serializable beforefieldinit '<>c' + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static initonly class Program/'<>c' '<>9' + .field public static class '<>f__AnonymousDelegate0' '<>9__1_0' + // Methods + .method private hidebysig specialname rtspecialname static + void .cctor () cil managed + { + // Method begins at RVA 0x20bf + // Code size 11 (0xb) + .maxstack 8 + IL_0000: newobj instance void Program/'<>c'::.ctor() + IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_000a: ret + } // end of method '<>c'::.cctor + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20b7 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [netstandard]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c'::.ctor + .method assembly hidebysig + instance void '
b__1_0' ( + int32& x, + [out] int32& y, + [opt] int32 z + ) cil managed + { + .param [3] = int32(3) + // Method begins at RVA 0x20cb + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.2 + IL_0001: ldarg.1 + IL_0002: ldind.i4 + IL_0003: ldarg.3 + IL_0004: add + IL_0005: stind.i4 + IL_0006: ret + } // end of method '<>c'::'
b__1_0' +} // end of class <>c +"; + + var verifier = CompileAndVerify(source, expectedOutput: + @"12 +29 +<>f__AnonymousDelegate0"); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0", expectAnonymousDelegateIL); + verifier.VerifyTypeIL("<>c", expectLoweredClosureContainerIL); + } } } From 0f757da6204418a21dbf129b90831f5200a2e388 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 9 Aug 2022 17:42:12 -0700 Subject: [PATCH 06/23] Fix Roslyn build --- .../CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs | 2 +- .../Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index 6fb4e0fbc25e..d633e6944626 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -188,7 +188,7 @@ internal EEMethodSymbol( private ParameterSymbol MakeParameterSymbol(int ordinal, string name, ParameterSymbol sourceParameter) { - return SynthesizedParameterSymbol.Create(this, sourceParameter.TypeWithAnnotations, ordinal, sourceParameter.RefKind, name, DeclarationScope.Unscoped, sourceParameter.RefCustomModifiers); + return SynthesizedParameterSymbol.Create(this, sourceParameter.TypeWithAnnotations, ordinal, sourceParameter.RefKind, name, DeclarationScope.Unscoped, refCustomModifiers: sourceParameter.RefCustomModifiers); } internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs index a9a75c0c859a..116f69a1a133 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs @@ -77,7 +77,7 @@ internal override BoundExpression GetAddress(BoundPseudoVariable variable) method.Name, m => method.TypeParameters.SelectAsArray(t => (TypeParameterSymbol)new SimpleTypeParameterSymbol(m, t.Ordinal, t.Name)), m => m.TypeParameters[0], // return type is <>T& - m => method.Parameters.SelectAsArray(p => SynthesizedParameterSymbol.Create(m, p.TypeWithAnnotations, p.Ordinal, p.RefKind, p.Name, p.DeclaredScope, p.RefCustomModifiers))); + m => method.Parameters.SelectAsArray(p => SynthesizedParameterSymbol.Create(m, p.TypeWithAnnotations, p.Ordinal, p.RefKind, p.Name, p.DeclaredScope, refCustomModifiers: p.RefCustomModifiers))); var local = variable.LocalSymbol; return InvokeGetMethod(method.Construct(local.Type), variable.Syntax, local.Name); } From c1d4482b7364c068dfa68498189de9823e71c50e Mon Sep 17 00:00:00 2001 From: adamperlin Date: Thu, 11 Aug 2022 11:00:50 -0700 Subject: [PATCH 07/23] Address review feedback and fix unit tests --- .../Portable/Binder/Binder_Expressions.cs | 1 + .../Portable/BoundTree/UnboundLambda.cs | 2 +- .../SynthesizedIntrinsicOperatorSymbol.cs | 2 +- .../Emit/CodeGen/CodeGenAsyncIteratorTests.cs | 3 +- .../Semantic/Semantics/DelegateTypeTests.cs | 211 +++++++++++------- .../Test/Semantic/Semantics/LambdaTests.cs | 12 +- 6 files changed, 141 insertions(+), 90 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 7cc665c607e3..a64841d7aca1 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8944,6 +8944,7 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) { Debug.Assert(ContainingMemberOrLambda is { }); Debug.Assert(parameterRefKinds.IsDefault || parameterRefKinds.Length == parameterTypes.Length); + Debug.Assert(parameterDefaultValues.IsDefault || parameterDefaultValues.Length == parameterTypes.Length); Debug.Assert(returnType.Type is { }); // Expecting System.Void rather than null return type. bool returnsVoid = returnType.Type.IsVoidType(); diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 63fcdc2b1418..813fe18a183d 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -668,7 +668,7 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo // Account for the situation where we have trailing required parameters AFTER an optional one, i.e., (int opt1 = 3, T1 req1, ..., TN reqN) => {...} // so we will be missing null default values for req1, ..., reqN when exiting the previous loop and the length of the default value builder will // be too short. - if (parameterDefaultValueBuilder is { }) + if (parameterDefaultValueBuilder is not null) { parameterDefaultValueBuilder.AddMany(null, lambdaSymbol.Parameters.Length - parameterDefaultValueBuilder.Count); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index 43d5d7818e32..fb4e2bcbf34b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -473,7 +473,7 @@ public SynthesizedOperatorParameterSymbol( TypeSymbol type, int ordinal, string name - ) : base(container, TypeWithAnnotations.Create(type), ordinal, RefKind.None, DeclarationScope.Unscoped, null, name) + ) : base(container, TypeWithAnnotations.Create(type), ordinal, RefKind.None, DeclarationScope.Unscoped, defaultValue: null, name) { } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 44950a696d36..e5d091242be8 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; +using Newtonsoft.Json.Linq; using Roslyn.Test.Utilities; using Xunit; using static Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen.Instruction; @@ -2116,7 +2117,7 @@ void verifyMembersAndInterfaces(ModuleSymbol module) "C.d__0..ctor(System.Int32 <>1__state)", "void C.d__0.MoveNext()", "void C.d__0.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine)", - "System.Collections.Generic.IAsyncEnumerator C.d__0.System.Collections.Generic.IAsyncEnumerable.GetAsyncEnumerator(System.Threading.CancellationToken token)", + "System.Collections.Generic.IAsyncEnumerator C.d__0.System.Collections.Generic.IAsyncEnumerable.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])", "System.Threading.Tasks.ValueTask C.d__0.System.Collections.Generic.IAsyncEnumerator.MoveNextAsync()", "System.Int32 C.d__0.System.Collections.Generic.IAsyncEnumerator.Current.get", "System.Boolean C.d__0.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(System.Int16 token)", diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index cd523449bb22..497a2a6f7f9c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -64,6 +64,7 @@ private static string Concat(string container, string name) private static readonly string s_expressionOfTDelegate1ArgTypeName = ExecutionConditionUtil.IsDesktop ? "System.Linq.Expressions.Expression`1" : "System.Linq.Expressions.Expression1`1"; + private static readonly string s_libPrefix = ExecutionConditionUtil.IsDesktop ? "mscorlib" : "netstandard"; [Fact] public void LanguageVersion() @@ -11516,21 +11517,22 @@ public void LambdaWithDefaultParameter() class Program { - // static void Report(object d) => Console.WriteLine(d.GetType()); + static void Report(object d) => Console.WriteLine(d.GetType()); public static void Main() { var lam = (int x = 30) => x; Console.WriteLine(lam() + " " + lam(10)); - // Report(lam); + Report(lam); } } """; - var expectAnonymousDelegateIL = """ + var expectAnonymousDelegateIL = +@" .class private auto ansi sealed '<>f__AnonymousDelegate0' - extends [netstandard]System.MulticastDelegate + extends [" + s_libPrefix + @"]System.MulticastDelegate { - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Methods @@ -11549,59 +11551,58 @@ [opt] int32 '' .param [1] = int32(30) } // end of method '<>f__AnonymousDelegate0'::Invoke } // end of class <>f__AnonymousDelegate0 -"""; - +"; - var expectLoweredClosureContainerIL = """ -.class nested private auto ansi sealed serializable beforefieldinit '<>c' - extends [netstandard]System.Object -{ - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Fields - .field public static initonly class Program/'<>c' '<>9' - .field public static class '<>f__AnonymousDelegate0' '<>9__0_0' - // Methods - .method private hidebysig specialname rtspecialname static - void .cctor () cil managed - { - // Method begins at RVA 0x20b4 - // Code size 11 (0xb) - .maxstack 8 - IL_0000: newobj instance void Program/'<>c'::.ctor() - IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_000a: ret - } // end of method '<>c'::.cctor - .method public hidebysig specialname rtspecialname - instance void .ctor () cil managed - { - // Method begins at RVA 0x20ac - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [netstandard]System.Object::.ctor() - IL_0006: ret - } // end of method '<>c'::.ctor - .method assembly hidebysig - instance int32 '
b__0_0' ( - [opt] int32 x - ) cil managed - { - .param [1] = int32(30) - // Method begins at RVA 0x20c0 - // Code size 2 (0x2) - .maxstack 8 - IL_0000: ldarg.1 - IL_0001: ret - } // end of method '<>c'::'
b__0_0' + var expectLoweredClosureContainerIL = +@" + .class nested private auto ansi sealed serializable beforefieldinit '<>c' + extends [" + s_libPrefix + @"]System.Object +{ + .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static initonly class Program/'<>c' '<>9' + .field public static class '<>f__AnonymousDelegate0' '<>9__1_0' + // Methods + .method private hidebysig specialname rtspecialname static + void .cctor () cil managed + { + // Method begins at RVA 0x20ca + // Code size 11 (0xb) + .maxstack 8 + IL_0000: newobj instance void Program/'<>c'::.ctor() + IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_000a: ret + } // end of method '<>c'::.cctor + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20c2 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [" + s_libPrefix + @"]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c'::.ctor + .method assembly hidebysig + instance int32 '
b__1_0' ( + [opt] int32 x + ) cil managed + { + .param [1] = int32(30) + // Method begins at RVA 0x20d6 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ret + } // end of method '<>c'::'
b__1_0' } // end of class <>c -"""; +"; - var verifier = CompileAndVerify(source, expectedOutput: "30 10"); - var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); - var reader = m.MetadataReader; - CheckNames(reader, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "Program", "<>c"); + var verifier = CompileAndVerify(source, expectedOutput: +@"30 10 +<>f__AnonymousDelegate0"); verifier.VerifyTypeIL("<>f__AnonymousDelegate0", expectAnonymousDelegateIL); verifier.VerifyTypeIL("<>c", expectLoweredClosureContainerIL); } @@ -11644,9 +11645,9 @@ public static void Main() var expectAnonymousDelegateIL = @" .class private auto ansi sealed '<>f__AnonymousDelegate0' - extends [netstandard]System.MulticastDelegate + extends [" + s_libPrefix + @"]System.MulticastDelegate { - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Methods @@ -11673,9 +11674,9 @@ [opt] string '' var expectLoweredClosureContainerIL = @" .class nested private auto ansi sealed serializable beforefieldinit '<>c' - extends [netstandard]System.Object + extends [" + s_libPrefix + @"]System.Object { - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields @@ -11699,7 +11700,7 @@ instance void .ctor () cil managed // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void [netstandard]System.Object::.ctor() + IL_0001: call instance void [" + s_libPrefix + @"]System.Object::.ctor() IL_0006: ret } // end of method '<>c'::.ctor .method assembly hidebysig @@ -11717,7 +11718,7 @@ .maxstack 8 IL_0000: ldarg.1 IL_0001: ldarg.2 IL_0002: ldarg.3 - IL_0003: call string [netstandard]System.String::Concat(string, string, string) + IL_0003: call string [" + s_libPrefix + @"]System.String::Concat(string, string, string) IL_0008: ret } // end of method '<>c'::'
b__1_0' } // end of class <>c @@ -11746,14 +11747,10 @@ public static void Main() } } """; - var verifier = CompileAndVerify(source, expectedOutput: + CompileAndVerify(source, expectedOutput: @"<>f__AnonymousDelegate0 <>f__AnonymousDelegate1 "); - - var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); - var reader = m.MetadataReader; - CheckNames(reader, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "<>f__AnonymousDelegate1", "Program", "<>c"); } [Fact] @@ -11801,14 +11798,11 @@ public static void Main() } } """; - var verifier = CompileAndVerify(source, expectedOutput: + CompileAndVerify(source, expectedOutput: @"<>f__AnonymousDelegate0 System.Func`2[System.Int32,System.Int32] "); - var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); - var reader = m.MetadataReader; - CheckNames(reader, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "Program", "<>c"); } [Fact] @@ -11863,7 +11857,7 @@ public static void Main() } [Fact] - public void LambdaNoConversionDefaultParameterValueMatch() + public void LambdaDefaultParameterNameMismatch() { var source = """ using System; @@ -11920,7 +11914,7 @@ public static void Main() } """; - // TODO: we want to have a warning here, because the default value when calling the named delegate will come from the delegate + // PROTOTYPE: we want to have a warning here, because the default value when calling the named delegate will come from the delegate // itself and not the underlying lambda which could be confusing. CompileAndVerify(source, expectedOutput: "2"); } @@ -11941,7 +11935,7 @@ public static void Main() } } """; - // TODO: we want to add a warning here, since we have an implicit target-type conversion from a lambda WITH an optional parameter + // PROTOTYPE: we want to add a warning here, since we have an implicit target-type conversion from a lambda WITH an optional parameter // to a named delegate WITHOUT one, so the default value was useless to specify in code. CreateCompilation(source).VerifyDiagnostics( // (9,9): error CS7036: There is no argument given that corresponds to the required formal parameter 'x' of 'Program.D' @@ -12075,9 +12069,9 @@ public static void Main() var expectAnonymousDelegateIL = @" .class private auto ansi sealed '<>f__AnonymousDelegate0' - extends [netstandard]System.MulticastDelegate + extends [" + s_libPrefix + @"]System.MulticastDelegate { - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Methods @@ -12103,9 +12097,9 @@ [opt] int32 '' var expectLoweredClosureContainerIL = @" .class nested private auto ansi sealed serializable beforefieldinit '<>c' - extends [netstandard]System.Object + extends [" + s_libPrefix + @"]System.Object { - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields @@ -12129,7 +12123,7 @@ instance void .ctor () cil managed // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void [netstandard]System.Object::.ctor() + IL_0001: call instance void [" + s_libPrefix + @"]System.Object::.ctor() IL_0006: ret } // end of method '<>c'::.ctor .method assembly hidebysig @@ -12161,5 +12155,66 @@ .maxstack 8 verifier.VerifyTypeIL("<>f__AnonymousDelegate0", expectAnonymousDelegateIL); verifier.VerifyTypeIL("<>c", expectLoweredClosureContainerIL); } + + [Fact] + public void LambdaOutOfOrderParameterInvocation_AllParametersSpecified() + { + var source = """ +using System; + +class Program +{ + public static void Main() + { + var lam = (string a, string b, string c = "c") => $"{a}{b}{c}"; + Console.WriteLine(lam(b: "b", c: "a", a: "c")); + } + } +"""; + CreateCompilation(source).VerifyDiagnostics( + // (8,31): error CS1746: The delegate '' does not have a parameter named 'b' + // Console.WriteLine(lam(b: "b", c: "a", a: "c")); + Diagnostic(ErrorCode.ERR_BadNamedArgumentForDelegateInvoke, "b").WithArguments("", "b").WithLocation(8, 31)); + } + + [Fact] + public void LambdaOutOfOrderParameterInvocation_MissingOptionalParameter() + { + var source = """ +using System; + +class Program +{ + public static void Main() + { + var lam = (string a, string b, string c = "c") => $"{a}{b}{c}"; + Console.WriteLine(lam(b: "a", a: "b")); + } +} +"""; + CreateCompilation(source).VerifyDiagnostics( + // (8,31): error CS1746: The delegate '' does not have a parameter named 'b' + // Console.WriteLine(lam(b: "a", a: "b")); + Diagnostic(ErrorCode.ERR_BadNamedArgumentForDelegateInvoke, "b").WithArguments("", "b").WithLocation(8, 31)); + } + + [Fact] + public void LambdaOptionalParameterDecimalExpression() + { + var source = """ +using System; + +class Program +{ + public static void Main() + { + var lam = (decimal dec = Decimal.One / (decimal) 3) => dec; + Console.WriteLine(lam()); + } + +} +"""; + CompileAndVerify(source, expectedOutput: "0.3333333333333333333333333333"); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index ed41552bf898..706d43588fdb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -4858,7 +4858,7 @@ static void Main() var lambda = exprs.SelectAsArray(e => GetLambdaSymbol(model, e)).Single(); var parameter = (SourceParameterSymbol)lambda.Parameters[0]; Assert.True(parameter.HasOptionalAttribute); - Assert.False(parameter.HasExplicitDefaultValue); + Assert.True(parameter.HasExplicitDefaultValue); Assert.Equal(2, parameter.DefaultValueFromAttributes.Value); } @@ -6972,10 +6972,7 @@ public static void Main(string[] args) "; var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (6,9): error CS7036: There is no argument given that corresponds to the required formal parameter 'arg' of 'Func' - // lam1(); - Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "lam1").WithArguments("arg", "System.Func").WithLocation(6, 9)); + comp.VerifyDiagnostics(); } [Fact] @@ -6993,10 +6990,7 @@ public void M() """; var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (6,9): error CS7036: There is no argument given that corresponds to the required formal parameter 'arg' of 'Func' - // lam(); - Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "lam").WithArguments("arg", "System.Func").WithLocation(6, 9)); + comp.VerifyDiagnostics(); } [Fact] From 26375e1e38435fbad6bbbbe2e868f7ba4dc7f620 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Thu, 11 Aug 2022 13:14:47 -0700 Subject: [PATCH 08/23] Remove default value from SynthesizedParameterSymbol constructor to follow convention from source parameter symbols --- .../Symbols/Synthesized/SynthesizedParameterSymbol.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 7feee49db865..c399f1b5bae5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -204,9 +204,8 @@ private SynthesizedParameterSymbol( int ordinal, RefKind refKind, DeclarationScope scope, - ConstantValue? defaultValue, string name) - : base(container, type, ordinal, refKind, scope, defaultValue, name) + : base(container, type, ordinal, refKind, scope, defaultValue: null, name) { } @@ -221,9 +220,9 @@ public static ParameterSymbol Create( ImmutableArray refCustomModifiers = default, SourceComplexParameterSymbolBase? baseParameterForAttributes = null) { - if (refCustomModifiers.IsDefaultOrEmpty && baseParameterForAttributes is null) + if (refCustomModifiers.IsDefaultOrEmpty && baseParameterForAttributes is null && defaultValue is null) { - return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, defaultValue, name); + return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, name); } return new SynthesizedComplexParameterSymbol( From 13d4974ec0d54d183619f4d99c54547800d32301 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Thu, 11 Aug 2022 13:22:58 -0700 Subject: [PATCH 09/23] Revert "Remove default value from SynthesizedParameterSymbol constructor to follow convention from source parameter symbols" This reverts commit 26375e1e38435fbad6bbbbe2e868f7ba4dc7f620. --- .../Symbols/Synthesized/SynthesizedParameterSymbol.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index c399f1b5bae5..7feee49db865 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -204,8 +204,9 @@ private SynthesizedParameterSymbol( int ordinal, RefKind refKind, DeclarationScope scope, + ConstantValue? defaultValue, string name) - : base(container, type, ordinal, refKind, scope, defaultValue: null, name) + : base(container, type, ordinal, refKind, scope, defaultValue, name) { } @@ -220,9 +221,9 @@ public static ParameterSymbol Create( ImmutableArray refCustomModifiers = default, SourceComplexParameterSymbolBase? baseParameterForAttributes = null) { - if (refCustomModifiers.IsDefaultOrEmpty && baseParameterForAttributes is null && defaultValue is null) + if (refCustomModifiers.IsDefaultOrEmpty && baseParameterForAttributes is null) { - return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, name); + return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, defaultValue, name); } return new SynthesizedComplexParameterSymbol( From 8ba94ee961d6f4c1c33b973c9776efa3601dfc83 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Thu, 11 Aug 2022 14:19:44 -0700 Subject: [PATCH 10/23] Use SynthesizedComplexParameterSymbol instead of SynthesizedParameterSymbol in all cases for default values --- .../Synthesized/SynthesizedParameterSymbol.cs | 14 +- .../Semantic/Semantics/DelegateTypeTests.cs | 128 +++++++++--------- 2 files changed, 70 insertions(+), 72 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 7feee49db865..f07eab8d2b6a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -204,9 +204,8 @@ private SynthesizedParameterSymbol( int ordinal, RefKind refKind, DeclarationScope scope, - ConstantValue? defaultValue, string name) - : base(container, type, ordinal, refKind, scope, defaultValue, name) + : base(container, type, ordinal, refKind, scope, defaultValue: null, name) { } @@ -221,9 +220,9 @@ public static ParameterSymbol Create( ImmutableArray refCustomModifiers = default, SourceComplexParameterSymbolBase? baseParameterForAttributes = null) { - if (refCustomModifiers.IsDefaultOrEmpty && baseParameterForAttributes is null) + if (refCustomModifiers.IsDefaultOrEmpty && baseParameterForAttributes is null && defaultValue is null) { - return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, defaultValue, name); + return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, name); } return new SynthesizedComplexParameterSymbol( @@ -251,7 +250,6 @@ internal static ImmutableArray DeriveParameters(MethodSymbol so foreach (var oldParam in sourceMethod.Parameters) { - Debug.Assert(!(oldParam is SynthesizedComplexParameterSymbol)); //same properties as the old one, just change the owner builder.Add(Create( destinationMethod, @@ -299,7 +297,7 @@ public SynthesizedComplexParameterSymbol( : base(container, type, ordinal, refKind, scope, defaultValue, name) { Debug.Assert(!refCustomModifiers.IsDefault); - Debug.Assert(!refCustomModifiers.IsEmpty || baseParameterForAttributes is object); + Debug.Assert(!refCustomModifiers.IsEmpty || baseParameterForAttributes is object || defaultValue is not null); _refCustomModifiers = refCustomModifiers; _baseParameterForAttributes = baseParameterForAttributes; @@ -319,9 +317,9 @@ public override ImmutableArray GetAttributes() internal override MarshalPseudoCustomAttributeData? MarshallingInformation => _baseParameterForAttributes?.MarshallingInformation; - internal override bool IsMetadataOptional => _baseParameterForAttributes?.IsMetadataOptional == true; + internal override bool IsMetadataOptional => _baseParameterForAttributes is not null ? _baseParameterForAttributes.IsMetadataOptional == true : base.IsMetadataOptional; - internal override ConstantValue? ExplicitDefaultConstantValue => _baseParameterForAttributes?.ExplicitDefaultConstantValue; + internal override ConstantValue? ExplicitDefaultConstantValue => _baseParameterForAttributes?.ExplicitDefaultConstantValue ?? base.ExplicitDefaultConstantValue; internal override FlowAnalysisAnnotations FlowAnalysisAnnotations { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 497a2a6f7f9c..9ac5f242008d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -11528,11 +11528,11 @@ public static void Main() """; var expectAnonymousDelegateIL = -@" +$@" .class private auto ansi sealed '<>f__AnonymousDelegate0' - extends [" + s_libPrefix + @"]System.MulticastDelegate -{ - .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + extends [{s_libPrefix}]System.MulticastDelegate +{{ + .custom instance void [{s_libPrefix}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Methods @@ -11541,24 +11541,24 @@ instance void .ctor ( object 'object', native int 'method' ) runtime managed - { - } // end of method '<>f__AnonymousDelegate0'::.ctor + {{ + }} // end of method '<>f__AnonymousDelegate0'::.ctor .method public hidebysig newslot virtual instance int32 Invoke ( [opt] int32 '' ) runtime managed - { + {{ .param [1] = int32(30) - } // end of method '<>f__AnonymousDelegate0'::Invoke -} // end of class <>f__AnonymousDelegate0 + }} // end of method '<>f__AnonymousDelegate0'::Invoke +}} // end of class <>f__AnonymousDelegate0 "; var expectLoweredClosureContainerIL = -@" +$@" .class nested private auto ansi sealed serializable beforefieldinit '<>c' - extends [" + s_libPrefix + @"]System.Object -{ - .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + extends [{s_libPrefix}]System.Object +{{ + .custom instance void [{s_libPrefix}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields @@ -11567,37 +11567,37 @@ .field public static class '<>f__AnonymousDelegate0' '<>9__1_0' // Methods .method private hidebysig specialname rtspecialname static void .cctor () cil managed - { + {{ // Method begins at RVA 0x20ca // Code size 11 (0xb) .maxstack 8 IL_0000: newobj instance void Program/'<>c'::.ctor() IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' IL_000a: ret - } // end of method '<>c'::.cctor + }} // end of method '<>c'::.cctor .method public hidebysig specialname rtspecialname instance void .ctor () cil managed - { + {{ // Method begins at RVA 0x20c2 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void [" + s_libPrefix + @"]System.Object::.ctor() + IL_0001: call instance void [{s_libPrefix}]System.Object::.ctor() IL_0006: ret - } // end of method '<>c'::.ctor + }} // end of method '<>c'::.ctor .method assembly hidebysig instance int32 '
b__1_0' ( [opt] int32 x ) cil managed - { + {{ .param [1] = int32(30) // Method begins at RVA 0x20d6 // Code size 2 (0x2) .maxstack 8 IL_0000: ldarg.1 IL_0001: ret - } // end of method '<>c'::'
b__1_0' -} // end of class <>c + }} // end of method '<>c'::'
b__1_0' +}} // end of class <>c "; var verifier = CompileAndVerify(source, expectedOutput: @@ -11643,11 +11643,11 @@ public static void Main() } """; var expectAnonymousDelegateIL = -@" +$@" .class private auto ansi sealed '<>f__AnonymousDelegate0' - extends [" + s_libPrefix + @"]System.MulticastDelegate -{ - .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + extends [{s_libPrefix}]System.MulticastDelegate +{{ + .custom instance void [{s_libPrefix}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Methods @@ -11656,27 +11656,27 @@ instance void .ctor ( object 'object', native int 'method' ) runtime managed - { - } // end of method '<>f__AnonymousDelegate0'::.ctor + {{ + }} // end of method '<>f__AnonymousDelegate0'::.ctor .method public hidebysig newslot virtual instance string Invoke ( string '', [opt] string '', [opt] string '' ) runtime managed - { + {{ .param [2] = ""b"" .param [3] = ""c"" - } // end of method '<>f__AnonymousDelegate0'::Invoke -} // end of class <>f__AnonymousDelegate0 + }} // end of method '<>f__AnonymousDelegate0'::Invoke +}} // end of class <>f__AnonymousDelegate0 "; var expectLoweredClosureContainerIL = -@" +$@" .class nested private auto ansi sealed serializable beforefieldinit '<>c' - extends [" + s_libPrefix + @"]System.Object -{ - .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + extends [{s_libPrefix}]System.Object +{{ + .custom instance void [{s_libPrefix}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields @@ -11685,31 +11685,31 @@ .field public static class '<>f__AnonymousDelegate0' '<>9__1_0' // Methods .method private hidebysig specialname rtspecialname static void .cctor () cil managed - { + {{ // Method begins at RVA 0x20bf // Code size 11 (0xb) .maxstack 8 IL_0000: newobj instance void Program/'<>c'::.ctor() IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' IL_000a: ret - } // end of method '<>c'::.cctor + }} // end of method '<>c'::.cctor .method public hidebysig specialname rtspecialname instance void .ctor () cil managed - { + {{ // Method begins at RVA 0x20b7 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void [" + s_libPrefix + @"]System.Object::.ctor() + IL_0001: call instance void [{s_libPrefix}]System.Object::.ctor() IL_0006: ret - } // end of method '<>c'::.ctor + }} // end of method '<>c'::.ctor .method assembly hidebysig instance string '
b__1_0' ( string s1, [opt] string s2, [opt] string s3 ) cil managed - { + {{ .param [2] = ""b"" .param [3] = ""c"" // Method begins at RVA 0x20cb @@ -11718,10 +11718,10 @@ .maxstack 8 IL_0000: ldarg.1 IL_0001: ldarg.2 IL_0002: ldarg.3 - IL_0003: call string [" + s_libPrefix + @"]System.String::Concat(string, string, string) + IL_0003: call string [{s_libPrefix}]System.String::Concat(string, string, string) IL_0008: ret - } // end of method '<>c'::'
b__1_0' -} // end of class <>c + }} // end of method '<>c'::'
b__1_0' +}} // end of class <>c "; var verifier = CompileAndVerify(source, expectedOutput: "abc <>f__AnonymousDelegate0"); @@ -12067,11 +12067,11 @@ public static void Main() } """; var expectAnonymousDelegateIL = -@" +$@" .class private auto ansi sealed '<>f__AnonymousDelegate0' - extends [" + s_libPrefix + @"]System.MulticastDelegate -{ - .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + extends [{s_libPrefix}]System.MulticastDelegate +{{ + .custom instance void [{s_libPrefix}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Methods @@ -12080,26 +12080,26 @@ instance void .ctor ( object 'object', native int 'method' ) runtime managed - { - } // end of method '<>f__AnonymousDelegate0'::.ctor + {{ + }} // end of method '<>f__AnonymousDelegate0'::.ctor .method public hidebysig newslot virtual instance void Invoke ( int32& '', [out] int32& '', [opt] int32 '' ) runtime managed - { + {{ .param [3] = int32(3) - } // end of method '<>f__AnonymousDelegate0'::Invoke -} // end of class <>f__AnonymousDelegate0 + }} // end of method '<>f__AnonymousDelegate0'::Invoke +}} // end of class <>f__AnonymousDelegate0 "; var expectLoweredClosureContainerIL = -@" +$@" .class nested private auto ansi sealed serializable beforefieldinit '<>c' - extends [" + s_libPrefix + @"]System.Object -{ - .custom instance void [" + s_libPrefix + @"]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + extends [{s_libPrefix}]System.Object +{{ + .custom instance void [{s_libPrefix}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields @@ -12108,31 +12108,31 @@ .field public static class '<>f__AnonymousDelegate0' '<>9__1_0' // Methods .method private hidebysig specialname rtspecialname static void .cctor () cil managed - { + {{ // Method begins at RVA 0x20bf // Code size 11 (0xb) .maxstack 8 IL_0000: newobj instance void Program/'<>c'::.ctor() IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' IL_000a: ret - } // end of method '<>c'::.cctor + }} // end of method '<>c'::.cctor .method public hidebysig specialname rtspecialname instance void .ctor () cil managed - { + {{ // Method begins at RVA 0x20b7 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void [" + s_libPrefix + @"]System.Object::.ctor() + IL_0001: call instance void [{s_libPrefix}]System.Object::.ctor() IL_0006: ret - } // end of method '<>c'::.ctor + }} // end of method '<>c'::.ctor .method assembly hidebysig instance void '
b__1_0' ( int32& x, [out] int32& y, [opt] int32 z ) cil managed - { + {{ .param [3] = int32(3) // Method begins at RVA 0x20cb // Code size 7 (0x7) @@ -12144,8 +12144,8 @@ .maxstack 8 IL_0004: add IL_0005: stind.i4 IL_0006: ret - } // end of method '<>c'::'
b__1_0' -} // end of class <>c + }} // end of method '<>c'::'
b__1_0' +}} // end of class <>c "; var verifier = CompileAndVerify(source, expectedOutput: From ccaddb8cc0841363b3b4648e224391c32d6a4a39 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Thu, 11 Aug 2022 14:34:43 -0700 Subject: [PATCH 11/23] Remove unused imports --- .../CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs | 1 - .../CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index e5d091242be8..39fb9889a334 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; -using Newtonsoft.Json.Linq; using Roslyn.Test.Utilities; using Xunit; using static Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen.Instruction; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 9ac5f242008d..ad81e2e14777 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Reflection.Metadata; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; From 0b88e79db27e8cacc31c343444279315de646863 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 12 Aug 2022 11:55:10 -0700 Subject: [PATCH 12/23] Remove all uses of CheckNames --- .../Semantic/Semantics/DelegateTypeTests.cs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index ad81e2e14777..b60135b65447 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -11496,18 +11496,6 @@ .maxstack 0 }"); } - internal static void CheckNames(IEnumerable readers, IEnumerable handles, params string[] expectedNames) - { - var actualNames = readers.GetStrings(handles); - AssertEx.Equal(expectedNames, actualNames); - } - - internal static void CheckNames(MetadataReader reader, IEnumerable handles, params string[] expectedNames) - { - CheckNames(new[] { reader }, handles, expectedNames); - } - - [Fact] public void LambdaWithDefaultParameter() { @@ -11770,13 +11758,9 @@ public static void Main() } } """; - var verifier = CompileAndVerify(source, expectedOutput: + CompileAndVerify(source, expectedOutput: @"<>f__AnonymousDelegate0 <>f__AnonymousDelegate0"); - - var m = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); - var reader = m.MetadataReader; - CheckNames(reader, reader.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "Program", "<>c"); } [Fact] From d484d30fc1416844a74acb62d5e71f9a221fab35 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 12 Aug 2022 14:14:02 -0700 Subject: [PATCH 13/23] Move default value from base into SourceComplexParameterSymbol and add test coverage for Caller{LineNumber, MemberName, FilePath} on lambda parameters with default values --- .../SynthesizedIntrinsicOperatorSymbol.cs | 2 +- .../Synthesized/SynthesizedParameterSymbol.cs | 40 ++++++++++++------- .../Semantic/Semantics/DelegateTypeTests.cs | 20 ++++++++++ 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index fb4e2bcbf34b..46466ac5fed9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -473,7 +473,7 @@ public SynthesizedOperatorParameterSymbol( TypeSymbol type, int ordinal, string name - ) : base(container, TypeWithAnnotations.Create(type), ordinal, RefKind.None, DeclarationScope.Unscoped, defaultValue: null, name) + ) : base(container, TypeWithAnnotations.Create(type), ordinal, RefKind.None, DeclarationScope.Unscoped, name) { } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index f07eab8d2b6a..17b38e3a0278 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -21,7 +21,6 @@ internal abstract class SynthesizedParameterSymbolBase : ParameterSymbol private readonly string _name; private readonly RefKind _refKind; private readonly DeclarationScope _scope; - private readonly ConstantValue? _defaultValue; public SynthesizedParameterSymbolBase( MethodSymbol? container, @@ -29,7 +28,6 @@ public SynthesizedParameterSymbolBase( int ordinal, RefKind refKind, DeclarationScope scope, - ConstantValue? defaultValue, string name) { Debug.Assert(type.HasType); @@ -41,7 +39,6 @@ public SynthesizedParameterSymbolBase( _ordinal = ordinal; _refKind = refKind; _scope = scope; - _defaultValue = defaultValue; _name = name; } @@ -77,16 +74,13 @@ internal override bool IsMetadataOptional get { return ExplicitDefaultConstantValue != null; } } + internal override ConstantValue? ExplicitDefaultConstantValue => null; + public override bool IsImplicitlyDeclared { get { return true; } } - internal override ConstantValue? ExplicitDefaultConstantValue - { - get { return _defaultValue; } - } - internal override bool IsIDispatchConstant { get { throw ExceptionUtilities.Unreachable; } @@ -99,17 +93,17 @@ internal override bool IsIUnknownConstant internal override bool IsCallerLineNumber { - get { return false; } + get { throw ExceptionUtilities.Unreachable; } } internal override bool IsCallerFilePath { - get { return false; } + get { throw ExceptionUtilities.Unreachable; } } internal override bool IsCallerMemberName { - get { return false; } + get { throw ExceptionUtilities.Unreachable; } } internal override int CallerArgumentExpressionParameterIndex @@ -205,7 +199,7 @@ private SynthesizedParameterSymbol( RefKind refKind, DeclarationScope scope, string name) - : base(container, type, ordinal, refKind, scope, defaultValue: null, name) + : base(container, type, ordinal, refKind, scope, name) { } @@ -283,6 +277,7 @@ internal sealed class SynthesizedComplexParameterSymbol : SynthesizedParameterSy // The parameter containing attributes to inherit into this synthesized parameter, if any. private readonly SourceComplexParameterSymbolBase? _baseParameterForAttributes; + private readonly ConstantValue? _defaultValue; public SynthesizedComplexParameterSymbol( MethodSymbol? container, @@ -294,13 +289,14 @@ public SynthesizedComplexParameterSymbol( string name, ImmutableArray refCustomModifiers, SourceComplexParameterSymbolBase? baseParameterForAttributes) - : base(container, type, ordinal, refKind, scope, defaultValue, name) + : base(container, type, ordinal, refKind, scope, name) { Debug.Assert(!refCustomModifiers.IsDefault); Debug.Assert(!refCustomModifiers.IsEmpty || baseParameterForAttributes is object || defaultValue is not null); _refCustomModifiers = refCustomModifiers; _baseParameterForAttributes = baseParameterForAttributes; + _defaultValue = defaultValue; } public override ImmutableArray RefCustomModifiers @@ -319,7 +315,22 @@ public override ImmutableArray GetAttributes() internal override bool IsMetadataOptional => _baseParameterForAttributes is not null ? _baseParameterForAttributes.IsMetadataOptional == true : base.IsMetadataOptional; - internal override ConstantValue? ExplicitDefaultConstantValue => _baseParameterForAttributes?.ExplicitDefaultConstantValue ?? base.ExplicitDefaultConstantValue; + internal override bool IsCallerLineNumber + { + get => _baseParameterForAttributes?.IsCallerLineNumber ?? false; + } + + internal override bool IsCallerFilePath + { + get => _baseParameterForAttributes?.IsCallerFilePath ?? false; + } + + internal override bool IsCallerMemberName + { + get => _baseParameterForAttributes?.IsCallerMemberName ?? false; + } + + internal override ConstantValue? ExplicitDefaultConstantValue => _baseParameterForAttributes?.ExplicitDefaultConstantValue ?? _defaultValue; internal override FlowAnalysisAnnotations FlowAnalysisAnnotations { @@ -338,5 +349,6 @@ internal override ImmutableHashSet NotNullIfParameterNotNull return base.NotNullIfParameterNotNull; } } + } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index b60135b65447..d90e8e768bf3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -12199,5 +12199,25 @@ public static void Main() """; CompileAndVerify(source, expectedOutput: "0.3333333333333333333333333333"); } + + [Fact] + public void CallerAttributesOnLambdaWithDefaultParam() + { + var source = """ +using System; +using System.Runtime.CompilerServices; + +class Program +{ + public static void Main() + { + var lam = ([CallerMemberName] string member = "member", [CallerFilePath] string filePath = "file", + [CallerLineNumber] int lineNumber = 0) => Console.WriteLine($"{filePath}::{member}:{lineNumber}"); + lam(); + } +} +"""; + CompileAndVerify(source, expectedOutput: "file::member:0"); + } } } From 8254fcad38c78e9ccb63c99ea20cc47cdaceeb89 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 12 Aug 2022 14:22:15 -0700 Subject: [PATCH 14/23] Add PROTOTYPE comment about Caller... attributes --- .../CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index d90e8e768bf3..0c76a13085e0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -12217,6 +12217,9 @@ public static void Main() } } """; + // PROTOTYPE: Do we want to allow [Caller{MemberName, LineNumber, FilePath}] attributes for lambdas since + // we now have default parameters? The current behavior is to ignore these attributes so that the provided + // default would always be used in these cases. CompileAndVerify(source, expectedOutput: "file::member:0"); } } From 9d113cf53613cee4b296e6d56a0672fecd0cdcbb Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 15 Aug 2022 13:15:46 -0700 Subject: [PATCH 15/23] Address review feedback --- .../Portable/Binder/Binder_Expressions.cs | 6 +++-- .../Portable/BoundTree/UnboundLambda.cs | 22 +++++-------------- .../Lowering/SynthesizedMethodBaseSymbol.cs | 1 + .../Synthesized/SynthesizedParameterSymbol.cs | 10 +++++---- .../Semantic/Semantics/DelegateTypeTests.cs | 11 +++++----- 5 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index a64841d7aca1..1793ef4ae952 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8853,7 +8853,9 @@ private MethodGroupResolution ResolveDefaultMethodGroup( var parameterScopes = parameters.Any(p => p.EffectiveScope != DeclarationScope.Unscoped) ? parameters.SelectAsArray(p => p.EffectiveScope) : default; - return GetMethodGroupOrLambdaDelegateType(node.Syntax, method.RefKind, method.ReturnTypeWithAnnotations, method.ParameterRefKinds, parameterScopes, method.ParameterTypesWithAnnotations); + + // PROTOTYPE: bind default values and pass them through here to allow support for default parameters in method groups + return GetMethodGroupOrLambdaDelegateType(node.Syntax, method.RefKind, method.ReturnTypeWithAnnotations, method.ParameterRefKinds, parameterScopes, method.ParameterTypesWithAnnotations, parameterDefaultValues: default); } /// @@ -8940,7 +8942,7 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) ImmutableArray parameterRefKinds, ImmutableArray parameterScopes, ImmutableArray parameterTypes, - ImmutableArray parameterDefaultValues = default) + ImmutableArray parameterDefaultValues) { Debug.Assert(ContainingMemberOrLambda is { }); Debug.Assert(parameterRefKinds.IsDefault || parameterRefKinds.Length == parameterTypes.Length); diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 813fe18a183d..c20b64a9f0e8 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -651,28 +651,18 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo { var param = lambdaSymbol.Parameters[i]; var constVal = param.ExplicitDefaultConstantValue; - if (constVal != null) + if (constVal != null && parameterDefaultValueBuilder == null) { - if (parameterDefaultValueBuilder == null) - { - parameterDefaultValueBuilder = ArrayBuilder.GetInstance(ParameterCount); - - // front fill the array with nulls because all the parameters before this one must have been non-default. - parameterDefaultValueBuilder.AddMany(null, i); - } + parameterDefaultValueBuilder = ArrayBuilder.GetInstance(ParameterCount); + parameterDefaultValueBuilder.AddMany(null, i); + } + if (parameterDefaultValueBuilder != null) + { parameterDefaultValueBuilder.Add(constVal); } } - // Account for the situation where we have trailing required parameters AFTER an optional one, i.e., (int opt1 = 3, T1 req1, ..., TN reqN) => {...} - // so we will be missing null default values for req1, ..., reqN when exiting the previous loop and the length of the default value builder will - // be too short. - if (parameterDefaultValueBuilder is not null) - { - parameterDefaultValueBuilder.AddMany(null, lambdaSymbol.Parameters.Length - parameterDefaultValueBuilder.Count); - } - var parameterDefaultValues = parameterDefaultValueBuilder?.ToImmutableAndFree() ?? default; if (!HasExplicitReturnType(out var returnRefKind, out var returnType)) diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs index 6886b9de0afd..39bdaf389ba6 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs @@ -54,6 +54,7 @@ protected SynthesizedMethodBaseSymbol(NamedTypeSymbol containingType, } protected void AssignTypeMapAndTypeParameters(TypeMap typeMap, ImmutableArray typeParameters) + { Debug.Assert(typeMap != null); Debug.Assert(this.TypeMap == null); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 17b38e3a0278..0a270fd2a59c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -74,13 +74,16 @@ internal override bool IsMetadataOptional get { return ExplicitDefaultConstantValue != null; } } - internal override ConstantValue? ExplicitDefaultConstantValue => null; - public override bool IsImplicitlyDeclared { get { return true; } } + internal override ConstantValue? ExplicitDefaultConstantValue + { + get { return null; } + } + internal override bool IsIDispatchConstant { get { throw ExceptionUtilities.Unreachable; } @@ -313,7 +316,7 @@ public override ImmutableArray GetAttributes() internal override MarshalPseudoCustomAttributeData? MarshallingInformation => _baseParameterForAttributes?.MarshallingInformation; - internal override bool IsMetadataOptional => _baseParameterForAttributes is not null ? _baseParameterForAttributes.IsMetadataOptional == true : base.IsMetadataOptional; + internal override bool IsMetadataOptional => _baseParameterForAttributes?.IsMetadataOptional ?? base.IsMetadataOptional; internal override bool IsCallerLineNumber { @@ -349,6 +352,5 @@ internal override ImmutableHashSet NotNullIfParameterNotNull return base.NotNullIfParameterNotNull; } } - } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 0c76a13085e0..fec2ce250b2e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -12211,16 +12211,17 @@ class Program { public static void Main() { - var lam = ([CallerMemberName] string member = "member", [CallerFilePath] string filePath = "file", - [CallerLineNumber] int lineNumber = 0) => Console.WriteLine($"{filePath}::{member}:{lineNumber}"); - lam(); + var lam = (int arg, [CallerMemberName] string member = "member", [CallerFilePath] string filePath = "file", + [CallerLineNumber] int lineNumber = 0, + [CallerArgumentExpression("arg")] string argExpression = "callerArgExpression") => Console.WriteLine($"{filePath}::{member}({argExpression}):{lineNumber}"); + lam(3); } } """; - // PROTOTYPE: Do we want to allow [Caller{MemberName, LineNumber, FilePath}] attributes for lambdas since + // PROTOTYPE: Do we want to allow [Caller{MemberName, LineNumber, FilePath, ArgumentExpression}] attributes for lambdas since // we now have default parameters? The current behavior is to ignore these attributes so that the provided // default would always be used in these cases. - CompileAndVerify(source, expectedOutput: "file::member:0"); + CompileAndVerify(source, targetFramework: TargetFramework.Net60, expectedOutput: "file::member(callerArgExpression):0"); } } } From 91f93b497da14d8f7002d4548e481f8cf97ba8b4 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 15 Aug 2022 13:44:10 -0700 Subject: [PATCH 16/23] Add assert in constructor to clarify dependence between default value for synthesized parameter and default value for _baseParameterForAttributes --- .../Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 0a270fd2a59c..9b1c7e2d1a3a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -296,6 +296,7 @@ public SynthesizedComplexParameterSymbol( { Debug.Assert(!refCustomModifiers.IsDefault); Debug.Assert(!refCustomModifiers.IsEmpty || baseParameterForAttributes is object || defaultValue is not null); + Debug.Assert(baseParameterForAttributes is null || baseParameterForAttributes.ExplicitDefaultConstantValue == defaultValue); _refCustomModifiers = refCustomModifiers; _baseParameterForAttributes = baseParameterForAttributes; From 7632698b312eb5490bf3684c84b593dd9b0b3032 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Mon, 15 Aug 2022 13:45:15 -0700 Subject: [PATCH 17/23] Remove line in src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs Co-authored-by: Youssef Victor --- .../CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs index 39bdaf389ba6..6886b9de0afd 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs @@ -54,7 +54,6 @@ protected SynthesizedMethodBaseSymbol(NamedTypeSymbol containingType, } protected void AssignTypeMapAndTypeParameters(TypeMap typeMap, ImmutableArray typeParameters) - { Debug.Assert(typeMap != null); Debug.Assert(this.TypeMap == null); From ab22426306747fa43e3279b43286aa669af48c91 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 15 Aug 2022 16:16:28 -0700 Subject: [PATCH 18/23] Put CallerArgumentExpression attribute test under CoreClrOnly to fix CI failures --- .../Semantic/Semantics/DelegateTypeTests.cs | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index fec2ce250b2e..63e47a2a0d64 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -12200,6 +12200,11 @@ public static void Main() CompileAndVerify(source, expectedOutput: "0.3333333333333333333333333333"); } + + // PROTOTYPE: Do we want to allow [Caller{MemberName, LineNumber, FilePath, ArgumentExpression}] attributes for lambdas since + // we now have default parameters? The current behavior is to ignore these attributes so that the provided + // default would always be used in these cases. + [Fact] public void CallerAttributesOnLambdaWithDefaultParam() { @@ -12211,17 +12216,32 @@ class Program { public static void Main() { - var lam = (int arg, [CallerMemberName] string member = "member", [CallerFilePath] string filePath = "file", - [CallerLineNumber] int lineNumber = 0, - [CallerArgumentExpression("arg")] string argExpression = "callerArgExpression") => Console.WriteLine($"{filePath}::{member}({argExpression}):{lineNumber}"); + var lam = ([CallerMemberName] string member = "member", [CallerFilePath] string filePath = "file", [CallerLineNumber] int lineNumber = 0) => Console.WriteLine($"{filePath}::{member}:{lineNumber}"); + lam(); + } +} +"""; + CompileAndVerify(source, expectedOutput: "file::member:0"); + } + + + [ConditionalFact(typeof(CoreClrOnly))] + public void CallerArgumentExpressionAttributeOnLambdaWithDefaultParam() + { + var source = """ +using System; +using System.Runtime.CompilerServices; + +class Program +{ + public static void Main() + { + var lam = (int arg, [CallerArgumentExpression("arg")] string argExpression = "callerArgExpression") => Console.WriteLine($"{argExpression}"); lam(3); } } """; - // PROTOTYPE: Do we want to allow [Caller{MemberName, LineNumber, FilePath, ArgumentExpression}] attributes for lambdas since - // we now have default parameters? The current behavior is to ignore these attributes so that the provided - // default would always be used in these cases. - CompileAndVerify(source, targetFramework: TargetFramework.Net60, expectedOutput: "file::member(callerArgExpression):0"); + CompileAndVerify(source, targetFramework: TargetFramework.Net60, expectedOutput: "callerArgExpression"); } } } From 97fbff95a0325c3540830601f9bbefbbce24db52 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 15 Aug 2022 16:29:56 -0700 Subject: [PATCH 19/23] Switch from ConditionalFact to condition in test body --- .../CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 63e47a2a0d64..e82633ece8ce 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -12225,7 +12225,7 @@ public static void Main() } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CallerArgumentExpressionAttributeOnLambdaWithDefaultParam() { var source = """ @@ -12241,7 +12241,7 @@ public static void Main() } } """; - CompileAndVerify(source, targetFramework: TargetFramework.Net60, expectedOutput: "callerArgExpression"); + CompileAndVerify(source, targetFramework: TargetFramework.Net60, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Skipped); } } } From c45d77c43ea63d89e2f9ef55d91163a2545c3324 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 16 Aug 2022 09:37:21 -0700 Subject: [PATCH 20/23] Add expected output to [CallerArgumentExpression] attribute test --- .../CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index e82633ece8ce..123999196be9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -12241,7 +12241,9 @@ public static void Main() } } """; - CompileAndVerify(source, targetFramework: TargetFramework.Net60, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Skipped); + CompileAndVerify(source, targetFramework: TargetFramework.Net60, + verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Skipped, + expectedOutput: ExecutionConditionUtil.IsCoreClr ? "callerArgExpression" : null); } } } From 2247ab47ef519d7e10a8bfcefef1ca184d652c65 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 16 Aug 2022 11:28:17 -0700 Subject: [PATCH 21/23] Add prototype comment --- .../CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs index 4a74f066c6e1..edd4f5f3fe09 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs @@ -29,6 +29,7 @@ internal readonly struct AnonymousTypeField /// Anonymous type field type public TypeSymbol Type => TypeWithAnnotations.Type; + // PROTOTYPE: Sync with IDE about the addition of DefaultValue to AnonymousTypeField to see how it will affect their usage of anonymous type symbols public AnonymousTypeField(string name, Location location, TypeWithAnnotations typeWithAnnotations, RefKind refKind, DeclarationScope scope, ConstantValue? defaultValue = null) { this.Name = name; From fff9e9af55bf00f3259c1d5f2bbec95ca6d07594 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 16 Aug 2022 12:59:22 -0700 Subject: [PATCH 22/23] Add prototype comment to add different language version tests --- src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 706d43588fdb..237eafa8988f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -6957,6 +6957,7 @@ void Choice(Action a) AssertEx.Equal("System.Action", model.GetTypeInfo(action).Type.ToTestDisplayString()); } + // PROTOTYPE: Add separate test cases for lang version 11 vs. lang version 11 preview [Fact] public void LambdaWithExplicitDefaultParam() { From b0b2d65103fcab699e5ee54cd40ff579ed5b7c69 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 16 Aug 2022 13:01:34 -0700 Subject: [PATCH 23/23] Add additional prototype comment --- src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 237eafa8988f..d44b2d2718df 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -6976,6 +6976,8 @@ public static void Main(string[] args) comp.VerifyDiagnostics(); } + + // PROTOTYPE: Add separate test cases for lang version 11 vs. lang version 11 preview [Fact] public void AnonymousMethodWithExplicitDefaultParam() {