Fix up .NET method invocation with Optional argument (#21387)

This commit is contained in:
Jordan Borean
2024-07-01 15:46:39 -07:00
committed by GitHub
parent 720f145e28
commit ecdf7805ca
2 changed files with 158 additions and 0 deletions
@@ -7175,6 +7175,13 @@ namespace System.Management.Automation.Language
{
argExprs[i] = Expression.Default(parameterType);
}
else if (!parameters[i].HasDefaultValue && parameterType != typeof(object) && argValue == Type.Missing)
{
// If the method contains just [Optional] without a default value set then we cannot use
// Type.Missing as a placeholder. Instead we use the default value for that type. Only
// exception to this rule is when the parameter type is object.
argExprs[i] = Expression.Default(parameterType);
}
else
{
// We don't specify the parameter type in the constant expression. Normally the default
@@ -0,0 +1,151 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
Describe ".NET Method Binding Tests" -tags CI {
BeforeAll {
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
namespace CLRBindingTests;
public class TestClass
{
public int Prop { get; }
public TestClass(int value = 1)
{
Prop = value;
}
public static string StaticWithDefaultExpected() => StaticWithDefault();
public static string StaticWithDefault(string value = "foo") => value;
public static string StaticWithOptionalAndValueExpected() => StaticWithOptionalAndValue();
public static string StaticWithOptionalAndValue([Optional, DefaultParameterValue("bar")] string value) => value;
public static string StaticWithOptionalExpected() => StaticWithOptional();
public static string StaticWithOptional([Optional] string value) => value;
public object InstanceWithDefaultExpected() => InstanceWithDefault();
public object InstanceWithDefault(object value = null) => value;
public object InstanceWithOptionalAndValueExpected() => InstanceWithOptionalAndValue();
public object InstanceWithOptionalAndValue([Optional, DefaultParameterValue("foo")] object value) => value;
public object InstanceWithOptionalExpected() => InstanceWithOptional();
public object InstanceWithOptional([Optional] object value) => value;
public string MultipleArgsWithDefaultExpected(string prefix) => MultipleArgsWithDefault(prefix);
public string MultipleArgsWithDefault(string prefix, string extra = "abc") => $"{prefix}{extra}";
public string MultipleArgsWithOptionalAndValueExpected(string prefix) => MultipleArgsWithOptionalAndValue(prefix);
public string MultipleArgsWithOptionalAndValue(string prefix, [Optional, DefaultParameterValue("def")] string extra) => $"{prefix}{extra}";
public string MultipleArgsWithOptionalExpected(string prefix) => MultipleArgsWithOptional(prefix);
public string MultipleArgsWithOptional(string prefix, [Optional] string extra) => $"{prefix}{extra}";
}
public class TestClassCstorWithOptionalAndValue
{
public int Prop { get; }
public TestClassCstorWithOptionalAndValue([Optional, DefaultParameterValue(2)] int value)
{
Prop = value;
}
}
public class TestClassCstorWithOptional
{
public int Prop { get; }
public TestClassCstorWithOptional([Optional] int value)
{
Prop = value;
}
}
'@
}
It "Binds to constructor with default argument" {
$c = [CLRBindingTests.TestClass]::new()
$c.Prop | Should -Be 1
}
It "Binds to constructor with Optional with DefaultValue argument" {
$c = [CLRBindingTests.TestClassCstorWithOptionalAndValue]::new()
$c.Prop | Should -Be 2
}
It "Binds to constructor with Optional argument" {
$c = [CLRBindingTests.TestClassCstorWithOptional]::new()
$c.Prop | Should -Be 0
}
It "Binds to static method with default argument" {
$expected = [CLRBindingTests.TestClass]::StaticWithDefaultExpected()
$actual = [CLRBindingTests.TestClass]::StaticWithDefault()
$actual | Should -Be $expected
}
It "Binds to static method with Optional with DefaultValue argument" {
$expected = [CLRBindingTests.TestClass]::StaticWithOptionalAndValueExpected()
$actual = [CLRBindingTests.TestClass]::StaticWithOptionalAndValue()
$actual | Should -Be $expected
}
It "Binds to static method with Optional argument" {
$expected = [CLRBindingTests.TestClass]::StaticWithOptionalExpected()
$actual = [CLRBindingTests.TestClass]::StaticWithOptional()
$actual | Should -Be $expected
}
It "Binds to instance method with default argument" {
$c = [CLRBindingTests.TestClass]::new()
$expected = $c.InstanceWithDefaultExpected()
$actual = $c.InstanceWithDefault()
$actual | Should -Be $expected
}
It "Binds to instance method with Optional with DefaultValue argument" {
$c = [CLRBindingTests.TestClass]::new()
$expected = $c.InstanceWithOptionalAndValueExpected()
$actual = $c.InstanceWithOptionalAndValue()
$actual | Should -Be $expected
}
It "Binds to instance method with Optional argument" {
$c = [CLRBindingTests.TestClass]::new()
$expected = $c.InstanceWithOptionalExpected()
$actual = $c.InstanceWithOptional()
$actual | Should -Be $expected
}
It "Binds to instance method with normal arg and default argument" {
$c = [CLRBindingTests.TestClass]::new()
$expected = $c.MultipleArgsWithDefaultExpected("prefix")
$actual = $c.MultipleArgsWithDefault("prefix")
$actual | Should -Be $expected
}
It "Binds to instance method with Optional with normal arg and DefaultValue argument" {
$c = [CLRBindingTests.TestClass]::new()
$expected = $c.MultipleArgsWithOptionalAndValueExpected("prefix")
$actual = $c.MultipleArgsWithOptionalAndValue("prefix")
$actual | Should -Be $expected
}
It "Binds to instance method with normal arg and Optional argument" {
$c = [CLRBindingTests.TestClass]::new()
$expected = $c.MultipleArgsWithOptionalExpected("prefix")
$actual = $c.MultipleArgsWithOptional("prefix")
$actual | Should -Be $expected
}
}