diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs
index a9b6280b8b..6d42a50acc 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs
@@ -947,6 +947,7 @@ namespace Microsoft.PowerShell.Commands
}
else
{
+ parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest);
compilationOptions = GetDefaultCompilationOptions();
}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/new-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/new-object.cs
index e17d2d85dd..99fc94e0dc 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/new-object.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/new-object.cs
@@ -143,27 +143,42 @@ namespace Microsoft.PowerShell.Commands
if (e.InnerException != null && e.InnerException is TypeResolver.AmbiguousTypeException)
{
ThrowTerminatingError(
- new ErrorRecord(
- e,
- "AmbiguousTypeReference",
- ErrorCategory.InvalidType, null));
+ new ErrorRecord(
+ e,
+ "AmbiguousTypeReference",
+ ErrorCategory.InvalidType,
+ targetObject: null));
}
mshArgE = PSTraceSource.NewArgumentException(
- "TypeName",
- NewObjectStrings.TypeNotFound,
- TypeName);
+ "TypeName",
+ NewObjectStrings.TypeNotFound,
+ TypeName);
+
ThrowTerminatingError(
new ErrorRecord(
mshArgE,
"TypeNotFound",
- ErrorCategory.InvalidType, null));
+ ErrorCategory.InvalidType,
+ targetObject: null));
}
throw e;
}
Diagnostics.Assert(type != null, "LanguagePrimitives.TryConvertTo failed but returned true");
+ if (type.IsByRefLike)
+ {
+ ThrowTerminatingError(
+ new ErrorRecord(
+ PSTraceSource.NewInvalidOperationException(
+ NewObjectStrings.CannotInstantiateBoxedByRefLikeType,
+ type),
+ nameof(NewObjectStrings.CannotInstantiateBoxedByRefLikeType),
+ ErrorCategory.InvalidOperation,
+ targetObject: null));
+ }
+
if (Context.LanguageMode == PSLanguageMode.ConstrainedLanguage)
{
if (!CoreTypes.Contains(type))
diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/NewObjectStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/NewObjectStrings.resx
index cce49c375f..a435ee62db 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/resources/NewObjectStrings.resx
+++ b/src/Microsoft.PowerShell.Commands.Utility/resources/NewObjectStrings.resx
@@ -138,6 +138,9 @@
Creating instances of attribute and delegated Windows RT types is not supported.
+
+ Cannot create instances of the ByRef-like type "{0}". ByRef-like types are not supported in PowerShell.
+
Cannot create type. Only core types are supported in this language mode.
diff --git a/src/System.Management.Automation/engine/CoreAdapter.cs b/src/System.Management.Automation/engine/CoreAdapter.cs
index 6904170d13..8cc4abe4ed 100644
--- a/src/System.Management.Automation/engine/CoreAdapter.cs
+++ b/src/System.Management.Automation/engine/CoreAdapter.cs
@@ -1920,6 +1920,38 @@ namespace System.Management.Automation
internal object Invoke(object target, object[] arguments)
{
+ // There may be parameters of ByRef-like types, but they will be taken care of
+ // when we resolve overloads to find the best methods -- proper exception will
+ // be thrown when converting arguments to the ByRef-like parameter types.
+ //
+ // So when reaching here, we only care about (1) if the method return type is
+ // BeRef-like; (2) if it's a constrcutor of a ByRef-like type.
+
+ if (method is ConstructorInfo ctor)
+ {
+ if (ctor.DeclaringType.IsByRefLike)
+ {
+ throw new MethodException(
+ nameof(ExtendedTypeSystem.CannotInstantiateBoxedByRefLikeType),
+ innerException: null,
+ ExtendedTypeSystem.CannotInstantiateBoxedByRefLikeType,
+ ctor.DeclaringType);
+ }
+
+ return ctor.Invoke(arguments);
+ }
+
+ var methodInfo = (MethodInfo) method;
+ if (methodInfo.ReturnType.IsByRefLike)
+ {
+ throw new MethodException(
+ nameof(ExtendedTypeSystem.CannotCallMethodWithByRefLikeReturnType),
+ innerException: null,
+ ExtendedTypeSystem.CannotCallMethodWithByRefLikeReturnType,
+ methodInfo.Name,
+ methodInfo.ReturnType);
+ }
+
if (target is PSObject)
{
if (!method.DeclaringType.IsAssignableFrom(target.GetType()))
@@ -1932,20 +1964,15 @@ namespace System.Management.Automation
{
if (_methodInvoker == null)
{
- if (!(method is MethodInfo))
- {
- _useReflection = true;
- }
- else
- {
- _methodInvoker = GetMethodInvoker((MethodInfo)method);
- }
+ _methodInvoker = GetMethodInvoker(methodInfo);
}
+
if (_methodInvoker != null)
{
return _methodInvoker(target, arguments);
}
}
+
return method.Invoke(target, arguments);
}
@@ -2455,13 +2482,12 @@ namespace System.Management.Automation
// require different delegates
// The same is true for generics, COM Types.
Type declaringType = property.DeclaringType;
- Type propertyType = property.PropertyType;
if (declaringType.IsValueType ||
propertyType.IsGenericType ||
declaringType.IsGenericType ||
- property.DeclaringType.IsCOMObject ||
- property.PropertyType.IsCOMObject)
+ declaringType.IsCOMObject ||
+ propertyType.IsCOMObject)
{
this.readOnly = property.GetSetMethod() == null;
this.writeOnly = property.GetGetMethod() == null;
@@ -2511,7 +2537,9 @@ namespace System.Management.Automation
private void InitGetter()
{
if (writeOnly || useReflection)
+ {
return;
+ }
var parameter = Expression.Parameter(typeof(object));
Expression instance = null;
@@ -2568,7 +2596,9 @@ namespace System.Management.Automation
private void InitSetter()
{
if (readOnly || useReflection)
+ {
return;
+ }
var parameter = Expression.Parameter(typeof(object));
var value = Expression.Parameter(typeof(object));
@@ -3621,16 +3651,29 @@ namespace System.Management.Automation
protected override object PropertyGet(PSProperty property)
{
PropertyCacheEntry adapterData = (PropertyCacheEntry)property.adapterData;
+
+ if (adapterData.propertyType.IsByRefLike)
+ {
+ throw new GetValueException(
+ nameof(ExtendedTypeSystem.CannotAccessByRefLikePropertyOrField),
+ innerException: null,
+ ExtendedTypeSystem.CannotAccessByRefLikePropertyOrField,
+ adapterData.member.Name,
+ adapterData.propertyType);
+ }
+
PropertyInfo propertyInfo = adapterData.member as PropertyInfo;
if (propertyInfo != null)
{
if (adapterData.writeOnly)
{
- throw new GetValueException("WriteOnlyProperty",
- null,
+ throw new GetValueException(
+ nameof(ExtendedTypeSystem.WriteOnlyProperty),
+ innerException: null,
ExtendedTypeSystem.WriteOnlyProperty,
propertyInfo.Name);
}
+
if (adapterData.useReflection)
{
return propertyInfo.GetValue(property.baseObject, null);
@@ -3664,12 +3707,23 @@ namespace System.Management.Automation
if (adapterData.readOnly)
{
- throw new SetValueException(nameof(ExtendedTypeSystem.ReadOnlyProperty),
- null,
+ throw new SetValueException(
+ nameof(ExtendedTypeSystem.ReadOnlyProperty),
+ innerException: null,
ExtendedTypeSystem.ReadOnlyProperty,
adapterData.member.Name);
}
+ if (adapterData.propertyType.IsByRefLike)
+ {
+ throw new SetValueException(
+ nameof(ExtendedTypeSystem.CannotAccessByRefLikePropertyOrField),
+ innerException: null,
+ ExtendedTypeSystem.CannotAccessByRefLikePropertyOrField,
+ adapterData.member.Name,
+ adapterData.propertyType);
+ }
+
PropertyInfo propertyInfo = adapterData.member as PropertyInfo;
if (propertyInfo != null)
{
@@ -3755,9 +3809,7 @@ namespace System.Management.Automation
#pragma warning disable 56500
try
{
- // We cannot call MethodBase's Invoke on a constructor
- // because it requires a target we don't have.
- returnValue = ((ConstructorInfo)methodInformation.method).Invoke(arguments);
+ returnValue = methodInformation.Invoke(target: null, arguments);
}
catch (TargetInvocationException ex)
{
diff --git a/src/System.Management.Automation/engine/LanguagePrimitives.cs b/src/System.Management.Automation/engine/LanguagePrimitives.cs
index 69b0a9d62b..0c954de68d 100644
--- a/src/System.Management.Automation/engine/LanguagePrimitives.cs
+++ b/src/System.Management.Automation/engine/LanguagePrimitives.cs
@@ -4243,8 +4243,7 @@ namespace System.Management.Automation
}
}
- private static Dictionary s_converterCache
- = new Dictionary(256);
+ private static Dictionary s_converterCache = new Dictionary(256);
private static ConversionData CacheConversion(Type fromType, Type toType, PSConverter converter, ConversionRank rank)
{
@@ -4687,9 +4686,13 @@ namespace System.Management.Automation
bool debase;
var conversion = FigureConversion(valueToConvert, resultType, out debase);
- return conversion.Invoke(debase ? PSObject.Base(valueToConvert) : valueToConvert,
- resultType, recursion, debase ? (PSObject)valueToConvert : null,
- formatProvider, backupTypeTable);
+ return conversion.Invoke(
+ debase ? PSObject.Base(valueToConvert) : valueToConvert,
+ resultType,
+ recursion,
+ debase ? (PSObject)valueToConvert : null,
+ formatProvider,
+ backupTypeTable);
}
}
@@ -4704,6 +4707,14 @@ namespace System.Management.Automation
internal static Tuple GetInvalidCastMessages(object valueToConvert, Type resultType)
{
string errorId, errorMsg;
+ if (resultType.IsByRefLike)
+ {
+ typeConversion.WriteLine("Cannot convert to ByRef-Like types as they should be used on stack only.");
+ errorId = nameof(ExtendedTypeSystem.InvalidCastToByRefLikeType);
+ errorMsg = StringUtil.Format(ExtendedTypeSystem.InvalidCastToByRefLikeType, resultType);
+ return Tuple.Create(errorId, errorMsg);
+ }
+
if (PSObject.Base(valueToConvert) == null)
{
if (resultType.IsEnum)
@@ -5443,6 +5454,12 @@ namespace System.Management.Automation
toType == fromType ? ConversionRank.Identity : ConversionRank.Assignable);
}
+ if (fromType.IsByRefLike || toType.IsByRefLike)
+ {
+ // ByRef-like types are not boxable and should be used on stack only.
+ return CacheConversion(fromType, toType, ConvertNoConversion, ConversionRank.None);
+ }
+
if (typeof(PSObject).IsAssignableFrom(fromType) && typeof(InternalPSObject) != fromType)
{
// We don't attempt converting PSObject (or derived) to anything else,
diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs
index 92d8548e9f..41084c4db2 100644
--- a/src/System.Management.Automation/engine/parser/Compiler.cs
+++ b/src/System.Management.Automation/engine/parser/Compiler.cs
@@ -391,6 +391,8 @@ namespace System.Management.Automation.Language
internal static readonly MethodInfo PSCreateInstanceBinder_IsTargetTypeNonPublic =
typeof(PSCreateInstanceBinder).GetMethod(nameof(PSCreateInstanceBinder.IsTargetTypeNonPublic), staticFlags);
+ internal static readonly MethodInfo PSCreateInstanceBinder_IsTargetTypeByRefLike =
+ typeof(PSCreateInstanceBinder).GetMethod(nameof(PSCreateInstanceBinder.IsTargetTypeByRefLike), staticFlags);
internal static readonly MethodInfo PSCreateInstanceBinder_GetTargetTypeName =
typeof(PSCreateInstanceBinder).GetMethod(nameof(PSCreateInstanceBinder.GetTargetTypeName), staticFlags);
@@ -596,7 +598,7 @@ namespace System.Management.Automation.Language
return Expression.Convert(expr, type);
}
- if (type.ContainsGenericParameters)
+ if (type.ContainsGenericParameters || type.IsByRefLike)
{
return Expression.Call(
CachedReflectionInfo.LanguagePrimitives_ThrowInvalidCastException,
@@ -5504,6 +5506,22 @@ namespace System.Management.Automation.Language
var propertyInfo = memberInfo[0] as PropertyInfo;
if (propertyInfo != null)
{
+ if (propertyInfo.PropertyType.IsByRefLike)
+ {
+ // ByRef-like types are not boxable and should be used only on stack.
+ return Expression.Throw(
+ Expression.New(
+ CachedReflectionInfo.GetValueException_ctor,
+ Expression.Constant(nameof(ExtendedTypeSystem.CannotAccessByRefLikePropertyOrField)),
+ Expression.Constant(null, typeof(Exception)),
+ Expression.Constant(ExtendedTypeSystem.CannotAccessByRefLikePropertyOrField),
+ Expression.NewArrayInit(
+ typeof(object),
+ Expression.Constant(propertyInfo.Name),
+ Expression.Constant(propertyInfo.PropertyType, typeof(Type)))),
+ typeof(object));
+ }
+
if (propertyInfo.CanRead)
{
return Expression.Property(null, propertyInfo);
@@ -5512,6 +5530,8 @@ namespace System.Management.Automation.Language
}
else
{
+ // Field cannot be of a ByRef-like type unless it's an instance member of a ref struct.
+ // So we don't need to check 'IsByRefLike' for static field access.
return Expression.Field(null, (FieldInfo)memberInfo[0]);
}
}
diff --git a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs
index f4ab7c73f6..ea33af9348 100644
--- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs
+++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs
@@ -4242,6 +4242,22 @@ namespace System.Management.Automation.Language
}
}
+ // Check return type after the argument conversion, so any no-conversion error can be thrown.
+ if (getter.ReturnType.IsByRefLike)
+ {
+ return errorSuggestion ?? new DynamicMetaObject(
+ Expression.Block(
+ Expression.IfThen(
+ Compiler.IsStrictMode(3),
+ Compiler.ThrowRuntimeError(
+ nameof(ParserStrings.CannotIndexWithByRefLikeReturnType),
+ ParserStrings.CannotIndexWithByRefLikeReturnType,
+ Expression.Constant(target.LimitType, typeof(Type)),
+ Expression.Constant(getter.ReturnType, typeof(Type)))),
+ GetNullResult()),
+ target.CombineRestrictions(indexes));
+ }
+
if (getterParams.Length == 1 && getterParams[0].ParameterType == typeof(int) && CanIndexFromEndWithNegativeIndex(target))
{
// PowerShell supports negative indexing for some types (specifically, types implementing IList or IList).
@@ -5090,7 +5106,13 @@ namespace System.Management.Automation.Language
var adapterData = property.adapterData as DotNetAdapter.PropertyCacheEntry;
Diagnostics.Assert(adapterData != null, "We have an unknown PSProperty that we aren't correctly optimizing.");
- if (!adapterData.member.DeclaringType.IsGenericTypeDefinition)
+ if (adapterData.member.DeclaringType.IsGenericTypeDefinition || adapterData.propertyType.IsByRefLike)
+ {
+ // This is kinda lame - we really should throw an error, but accessing property getter
+ // doesn't throw error in PowerShell since V2, even in strict mode.
+ expr = ExpressionCache.NullConstant;
+ }
+ else
{
// For static property access, the target expr must be null. For non-static, we must convert
// because target.Expression is typeof(object) because this is a dynamic site.
@@ -5113,11 +5135,6 @@ namespace System.Management.Automation.Language
expr = Expression.Field(targetExpr, (FieldInfo)adapterData.member);
}
}
- else
- {
- // This is kinda lame - we really should throw an error, but V2 did the same thing (even in strict mode).
- expr = ExpressionCache.NullConstant;
- }
}
var scriptProperty = propertyInfo as PSScriptProperty;
@@ -6032,14 +6049,37 @@ namespace System.Management.Automation.Language
if (data.member.DeclaringType.IsGenericTypeDefinition)
{
- Expression innerException = Expression.New(CachedReflectionInfo.SetValueException_ctor,
+ Expression innerException = Expression.New(
+ CachedReflectionInfo.SetValueException_ctor,
Expression.Constant("PropertyAssignmentException"),
Expression.Constant(null, typeof(Exception)),
Expression.Constant(ExtendedTypeSystem.CannotInvokeStaticMethodOnUninstantiatedGenericType),
Expression.NewArrayInit(typeof(object), Expression.Constant(data.member.DeclaringType.FullName)));
- expr = Compiler.ThrowRuntimeErrorWithInnerException("PropertyAssignmentException",
- Expression.Constant(ExtendedTypeSystem.CannotInvokeStaticMethodOnUninstantiatedGenericType), innerException,
- this.ReturnType, Expression.Constant(data.member.DeclaringType.FullName));
+
+ expr = Compiler.ThrowRuntimeErrorWithInnerException(
+ "PropertyAssignmentException",
+ Expression.Constant(ExtendedTypeSystem.CannotInvokeStaticMethodOnUninstantiatedGenericType),
+ innerException,
+ this.ReturnType,
+ Expression.Constant(data.member.DeclaringType.FullName));
+
+ return new DynamicMetaObject(expr, restrictions).WriteToDebugLog(this);
+ }
+
+ if (data.propertyType.IsByRefLike)
+ {
+ expr = Expression.Throw(
+ Expression.New(
+ CachedReflectionInfo.SetValueException_ctor,
+ Expression.Constant(nameof(ExtendedTypeSystem.CannotAccessByRefLikePropertyOrField)),
+ Expression.Constant(null, typeof(Exception)),
+ Expression.Constant(ExtendedTypeSystem.CannotAccessByRefLikePropertyOrField),
+ Expression.NewArrayInit(
+ typeof(object),
+ Expression.Constant(data.member.Name),
+ Expression.Constant(data.propertyType, typeof(Type)))),
+ this.ReturnType);
+
return new DynamicMetaObject(expr, restrictions).WriteToDebugLog(this);
}
@@ -6769,6 +6809,45 @@ namespace System.Management.Automation.Language
List initTemps = new List();
List copyOutTemps = new List();
+ ConstructorInfo constructorInfo = null;
+ MethodInfo methodInfo = mi as MethodInfo;
+ if (methodInfo != null)
+ {
+ Type returnType = methodInfo.ReturnType;
+ if (returnType.IsByRefLike)
+ {
+ return Expression.Throw(
+ Expression.New(
+ CachedReflectionInfo.MethodException_ctor,
+ Expression.Constant(nameof(ExtendedTypeSystem.CannotCallMethodWithByRefLikeReturnType)),
+ Expression.Constant(null, typeof(Exception)),
+ Expression.Constant(ExtendedTypeSystem.CannotCallMethodWithByRefLikeReturnType),
+ Expression.NewArrayInit(
+ typeof(object),
+ Expression.Constant(methodInfo.Name),
+ Expression.Constant(returnType, typeof(Type)))),
+ typeof(object));
+ }
+ }
+ else
+ {
+ constructorInfo = (ConstructorInfo)mi;
+ Type declaringType = constructorInfo.DeclaringType;
+ if (declaringType.IsByRefLike)
+ {
+ return Expression.Throw(
+ Expression.New(
+ CachedReflectionInfo.MethodException_ctor,
+ Expression.Constant(nameof(ExtendedTypeSystem.CannotInstantiateBoxedByRefLikeType)),
+ Expression.Constant(null, typeof(Exception)),
+ Expression.Constant(ExtendedTypeSystem.CannotInstantiateBoxedByRefLikeType),
+ Expression.NewArrayInit(
+ typeof(object),
+ Expression.Constant(declaringType, typeof(Type)))),
+ typeof(object));
+ }
+ }
+
var parameters = mi.GetParameters();
var argExprs = new Expression[parameters.Length];
for (int i = 0; i < parameters.Length; ++i)
@@ -6846,13 +6925,6 @@ namespace System.Management.Automation.Language
}
}
- ConstructorInfo constructorInfo = null;
- var methodInfo = mi as MethodInfo;
- if (methodInfo == null)
- {
- constructorInfo = (ConstructorInfo)mi;
- }
-
Expression call;
if (constructorInfo != null)
{
@@ -7266,16 +7338,35 @@ namespace System.Management.Automation.Language
var instanceType = targetValue as Type ?? targetValue.GetType();
BindingRestrictions restrictions;
+ if (instanceType.IsByRefLike)
+ {
+ // ByRef-like types are not boxable and should be used only on stack
+ restrictions = BindingRestrictions.GetExpressionRestriction(
+ Expression.Call(CachedReflectionInfo.PSCreateInstanceBinder_IsTargetTypeByRefLike, target.Expression));
+
+ return target.ThrowRuntimeError(
+ restrictions,
+ nameof(ExtendedTypeSystem.CannotInstantiateBoxedByRefLikeType),
+ ExtendedTypeSystem.CannotInstantiateBoxedByRefLikeType,
+ Expression.Call(
+ CachedReflectionInfo.PSCreateInstanceBinder_GetTargetTypeName,
+ target.Expression)).WriteToDebugLog(this);
+ }
+
if (_publicTypeOnly && !TypeResolver.IsPublic(instanceType))
{
// If 'publicTypeOnly' specified, we only support creating instance for public types.
restrictions = BindingRestrictions.GetExpressionRestriction(
Expression.Call(CachedReflectionInfo.PSCreateInstanceBinder_IsTargetTypeNonPublic, target.Expression));
- return target.ThrowRuntimeError(restrictions, "MethodNotFound", ParserStrings.MethodNotFound,
- Expression.Call(
- CachedReflectionInfo.PSCreateInstanceBinder_GetTargetTypeName,
- target.Expression),
- Expression.Constant("new")).WriteToDebugLog(this);
+
+ return target.ThrowRuntimeError(
+ restrictions,
+ nameof(ParserStrings.MethodNotFound),
+ ParserStrings.MethodNotFound,
+ Expression.Call(
+ CachedReflectionInfo.PSCreateInstanceBinder_GetTargetTypeName,
+ target.Expression),
+ Expression.Constant("new")).WriteToDebugLog(this);
}
var ctors = instanceType.GetConstructors();
@@ -7304,7 +7395,19 @@ namespace System.Management.Automation.Language
}
///
- /// Check if the target type is not public
+ /// Check if the target type is ByRef-like.
+ ///
+ internal static bool IsTargetTypeByRefLike(object target)
+ {
+ var targetValue = PSObject.Base(target);
+ if (targetValue == null) { return false; }
+
+ var instanceType = targetValue as Type ?? targetValue.GetType();
+ return instanceType.IsByRefLike;
+ }
+
+ ///
+ /// Check if the target type is not public.
///
internal static bool IsTargetTypeNonPublic(object target)
{
@@ -7316,7 +7419,7 @@ namespace System.Management.Automation.Language
}
///
- /// Return the full name of the target type
+ /// Return the full name of the target type.
///
internal static string GetTargetTypeName(object target)
{
diff --git a/src/System.Management.Automation/resources/ExtendedTypeSystem.resx b/src/System.Management.Automation/resources/ExtendedTypeSystem.resx
index 9541ee6a0d..6a697cba88 100644
--- a/src/System.Management.Automation/resources/ExtendedTypeSystem.resx
+++ b/src/System.Management.Automation/resources/ExtendedTypeSystem.resx
@@ -370,4 +370,16 @@ PS> [System.Collections.Generic.Comparer``1]::get_Default()
Cannot convert value to type "{0}". Only core types are supported in this language mode.
+
+ Cannot convert to the ByRef-like type "{0}". ByRef-like types are not supported in PowerShell.
+
+
+ Cannot get or set the property or field "{0}" of the ByRef-like type "{1}". ByRef-like types are not supported in PowerShell.
+
+
+ Cannot invoke the method "{0}" of the ByRef-like return type "{1}". ByRef-like types are not supported in PowerShell.
+
+
+ Cannot create an instance of the ByRef-like type "{0}". ByRef-like types are not supported in PowerShell.
+
diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx
index c63a63d1a4..ccf40602e2 100644
--- a/src/System.Management.Automation/resources/ParserStrings.resx
+++ b/src/System.Management.Automation/resources/ParserStrings.resx
@@ -291,7 +291,10 @@ Possible matches are
Cannot index into a null array.
- Unable to index into an object of type {0}.
+ Unable to index into an object of type "{0}".
+
+
+ Unable to index into an object of type "{0}" with the ByRef-like return type "{1}". ByRef-like types are not supported in PowerShell.
Array assignment to [{0}] failed: {1}.
diff --git a/test/powershell/Language/Interop/DotNet/DotNetAPI.Tests.ps1 b/test/powershell/Language/Interop/DotNet/DotNetAPI.Tests.ps1
index f5e72690ad..d717a7bfb4 100644
--- a/test/powershell/Language/Interop/DotNet/DotNetAPI.Tests.ps1
+++ b/test/powershell/Language/Interop/DotNet/DotNetAPI.Tests.ps1
@@ -1,5 +1,6 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
+
Describe "DotNetAPI" -Tags "CI" {
$posh_E = 2.718281828459045
$posh_pi = 3.14159265358979
@@ -24,4 +25,8 @@ Describe "DotNetAPI" -Tags "CI" {
$guidVal | Should -BeOfType Guid
}
+
+ It "Should access types in System.Console" {
+ [System.Console]::TreatControlCAsInput | Should -BeFalse
+ }
}
diff --git a/test/powershell/Language/Interop/DotNet/DotNetInterop.Tests.ps1 b/test/powershell/Language/Interop/DotNet/DotNetInterop.Tests.ps1
index 63884843a9..cf7214ab51 100644
--- a/test/powershell/Language/Interop/DotNet/DotNetInterop.Tests.ps1
+++ b/test/powershell/Language/Interop/DotNet/DotNetInterop.Tests.ps1
@@ -1,7 +1,186 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
-Describe ".NET class interoperability" -Tags "CI" {
- It "Should access types in System.Console" {
- [System.Console]::TreatControlCAsInput | Should -BeFalse
+
+Describe "Handle ByRef-like types gracefully" -Tags "CI" {
+
+ BeforeAll {
+ $code = @'
+using System;
+namespace DotNetInterop
+{
+ public class Test
+ {
+ public Span this[int i]
+ {
+ get { return default(Span); }
+ set { DoNothing(value); }
+ }
+
+ public static Span Space
+ {
+ get { return default(Span); }
+ set { DoNothing(value); }
+ }
+
+ public Span Room
+ {
+ get { return default(Span); }
+ set { DoNothing(value); }
+ }
+
+ private static void DoNothing(Span param)
+ {
+ }
+
+ public string PrintMySpan(string str, Span mySpan = default)
+ {
+ return str;
+ }
+
+ public Span GetSpan(int[] array)
+ {
+ return array.AsSpan();
+ }
+ }
+
+ public ref struct MyByRefLikeType
+ {
+ public MyByRefLikeType(int i) { }
+ public static int Index;
+ }
+}
+'@
+ if (-not ("DotNetInterop.Test" -as [type]))
+ {
+ Add-Type -TypeDefinition $code -IgnoreWarnings
+ }
+
+ $testObj = [DotNetInterop.Test]::new()
+ }
+
+ It "New-Object should fail gracefully when used for a ByRef-like type" {
+ { New-Object -TypeName 'System.Span[string]' } | Should -Throw -ErrorId "CannotInstantiateBoxedByRefLikeType,Microsoft.PowerShell.Commands.NewObjectCommand"
+ { New-Object -TypeName 'DotNetInterop.MyByRefLikeType' } | Should -Throw -ErrorId "CannotInstantiateBoxedByRefLikeType,Microsoft.PowerShell.Commands.NewObjectCommand"
+ }
+
+ It "The 'new' method call should fail gracefully when used on a ByRef-like type" {
+ { [System.Span[string]]::new() } | Should -Throw -ErrorId "CannotInstantiateBoxedByRefLikeType"
+ { [DotNetInterop.MyByRefLikeType]::new() } | Should -Throw -ErrorId "CannotInstantiateBoxedByRefLikeType"
+ }
+
+ It "Calling constructor of a ByRef-like type via dotnet adapter should fail gracefully - " -TestCases @(
+ @{ Number = 1; Script = { [System.Span[string]]::new.Invoke("abc") } }
+ @{ Number = 2; Script = { [DotNetInterop.MyByRefLikeType]::new.Invoke(2) } }
+ ) {
+ param($Script)
+ $expectedError = $null
+ try {
+ & $Script
+ } catch {
+ $expectedError = $_
+ }
+
+ $expectedError | Should -Not -BeNullOrEmpty
+ $expectedError.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -BeExactly "CannotInstantiateBoxedByRefLikeType"
+ }
+
+ It "Cast to a ByRef-like type should fail gracefully" {
+ { [System.Span[int]] ([int[]]1,2,3) } | Should -Throw -ErrorId "InvalidCastToByRefLikeType"
+ { [DotNetInterop.MyByRefLikeType] "text" } | Should -Throw -ErrorId "InvalidCastToByRefLikeType"
+ }
+
+ It "LanguagePrimitives.ConvertTo should fail gracefully for a ByRef-like type ''" -TestCases @(
+ @{ Name = "Span"; Type = [System.Span[int]] }
+ @{ Name = "MyByRefLikeType"; Type = [DotNetInterop.MyByRefLikeType] }
+ ) {
+ param($Type)
+ $expectedError = $null
+ try {
+ [System.Management.Automation.LanguagePrimitives]::ConvertTo(([int[]]1,2,3), $Type)
+ } catch {
+ $expectedError = $_
+ }
+
+ $expectedError | Should -Not -BeNullOrEmpty
+ $expectedError.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -BeExactly "InvalidCastToByRefLikeType"
+ }
+
+ It "Getting value of a ByRef-like type instance property should not throw and should return null, even in strict mode - " -TestCases @(
+ @{ Mechanism = "Compiler/Binder"; Script = { [System.Text.Encoding]::ASCII.Preamble } }
+ @{ Mechanism = "Dotnet-Adapter"; Script = { [System.Text.Encoding]::ASCII.PSObject.Properties["Preamble"].Value } }
+ ) {
+ param($Script)
+
+ try {
+ Set-StrictMode -Version latest
+ & $Script | Should -Be $null
+ } finally {
+ Set-StrictMode -Off
+ }
+ }
+
+ It "Setting value of a ByRef-like type instance property should fail gracefully - " -TestCases @(
+ @{ Mechanism = "Compiler/Binder"; Script = { $testObj.Room = [int[]](1,2,3) } }
+ @{ Mechanism = "Dotnet-Adapter"; Script = { $testObj.PSObject.Properties["Room"].Value = [int[]](1,2,3) } }
+ ) {
+ param($Script)
+ $Script | Should -Throw -ErrorId "CannotAccessByRefLikePropertyOrField"
+ }
+
+ It " value of a ByRef-like type static property should fail gracefully" -TestCases @(
+ @{ Action = "Getting"; Script = { [DotNetInterop.Test]::Space } }
+ @{ Action = "Setting"; Script = { [DotNetInterop.Test]::Space = "blah" } }
+ ) {
+ param($Script)
+ $Script | Should -Throw -ErrorId "CannotAccessByRefLikePropertyOrField"
+ }
+
+ It "Invoke a method with optional ByRef-like parameter could work" {
+ $testObj.PrintMySpan("Hello") | Should -BeExactly "Hello"
+ }
+
+ It "Invoke a method with ByRef-like parameter should fail gracefully - " -TestCases @(
+ @{ Mechanism = "Compiler/Binder"; Script = { $testObj.PrintMySpan("Hello", 1) } }
+ @{ Mechanism = "Dotnet-Adapter"; Script = { $testObj.psobject.Methods["PrintMySpan"].Invoke("Hello", 1) } }
+ ) {
+ param($Script)
+ $Script | Should -Throw -ErrorId "MethodArgumentConversionInvalidCastArgument"
+ }
+
+ It "Invoke a method with ByRef-like return type should fail gracefully - Compiler/Binder" {
+ { $testObj.GetSpan([int[]]@(1,2,3)) } | Should -Throw -ErrorId "CannotCallMethodWithByRefLikeReturnType"
+ }
+
+ It "Invoke a method with ByRef-like return type should fail gracefully - Dotnet-Adapter" {
+ $expectedError = $null
+ try {
+ $testObj.psobject.Methods["GetSpan"].Invoke([int[]]@(1,2,3))
+ } catch {
+ $expectedError = $_
+ }
+ $expectedError | Should -Not -BeNullOrEmpty
+ $expectedError.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -BeExactly "CannotCallMethodWithByRefLikeReturnType"
+ }
+
+ It "Access static property of a ByRef-like type" {
+ [DotNetInterop.MyByRefLikeType]::Index = 10
+ [DotNetInterop.MyByRefLikeType]::Index | Should -Be 10
+ }
+
+ It "Get access of an indexer that returns ByRef-like type should return null in no-strict mode" {
+ $testObj[1] | Should -Be $null
+ }
+
+ It "Get access of an indexer that returns ByRef-like type should fail gracefully in strict mode" {
+ try {
+ Set-StrictMode -Version latest
+ { $testObj[1] } | Should -Throw -ErrorId "CannotIndexWithByRefLikeReturnType"
+ } finally {
+ Set-StrictMode -Off
+ }
+ }
+
+ It "Set access of an indexer that accepts ByRef-like type should fail gracefully" {
+ { $testObj[1] = 1 } | Should -Throw -ErrorId "InvalidCastToByRefLikeType"
}
}