Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions src/System.Management.Automation/engine/SpecialVariables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System.Collections.Generic;
using System.Management.Automation.Internal;

namespace System.Management.Automation
{
Expand Down Expand Up @@ -357,22 +358,22 @@ internal static class SpecialVariables
// see an assignment to any of these variables so that they get handled properly (either throwing an exception
// because they are constant/readonly, or having the value persist in parent scopes where the allscope variable
// also exists.
internal static readonly string[] AllScopeVariables = {
SpecialVariables.Question,
SpecialVariables.ExecutionContext,
SpecialVariables.False,
SpecialVariables.Home,
SpecialVariables.Host,
SpecialVariables.PID,
SpecialVariables.PSCulture,
SpecialVariables.PSHome,
SpecialVariables.PSUICulture,
SpecialVariables.PSVersionTable,
SpecialVariables.PSEdition,
SpecialVariables.ShellId,
SpecialVariables.True,
SpecialVariables.EnabledExperimentalFeatures,
};
internal static readonly Dictionary<string, Type> AllScopeVariables = new(StringComparer.OrdinalIgnoreCase) {
{ Question, typeof(bool) },
{ ExecutionContext, typeof(EngineIntrinsics) },
{ False, typeof(bool) },
{ Home, typeof(string) },
{ Host, typeof(object) },
{ PID, typeof(int) },
{ PSCulture, typeof(string) },
{ PSHome, typeof(string) },
{ PSUICulture, typeof(string) },
{ PSVersionTable, typeof(PSVersionHashTable) },
{ PSEdition, typeof(string) },
{ ShellId, typeof(string) },
{ True, typeof(bool) },
{ EnabledExperimentalFeatures, typeof(ReadOnlyBag<string>) }
};

private static readonly HashSet<string> s_classMethodsAccessibleVariables = new HashSet<string>
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1846,7 +1846,7 @@ private void InferTypeFrom(VariableExpressionAst variableExpressionAst, List<PST
// We don't need to handle drive qualified variables, we can usually get those values
// without needing to "guess" at the type.
var astVariablePath = variableExpressionAst.VariablePath;
if (!astVariablePath.IsVariable)
if (!astVariablePath.IsVariable || astVariablePath.UserPath.EqualsOrdinalIgnoreCase(SpecialVariables.Null))
{
// Not a variable - the caller should have already tried going to session state
// to get the item and hence it's type, but that must have failed. Don't try again.
Expand Down Expand Up @@ -1961,6 +1961,23 @@ private void InferTypeFrom(VariableExpressionAst variableExpressionAst, List<PST
var isThis = astVariablePath.UserPath.EqualsOrdinalIgnoreCase(SpecialVariables.This);
if (!isThis || (_context.CurrentTypeDefinitionAst == null && _context.CurrentThisType == null))
{
if (SpecialVariables.AllScopeVariables.TryGetValue(astVariablePath.UserPath, out Type knownType))
{
if (knownType == typeof(object))
{
if (_context.TryGetRepresentativeTypeNameFromExpressionSafeEval(variableExpressionAst, out var psType))
{
inferredTypes.Add(psType);
}
}
else
{
inferredTypes.Add(new PSTypeName(knownType));
}

return;
}

for (int i = 0; i < SpecialVariables.AutomaticVariables.Length; i++)
{
if (!astVariablePath.UserPath.EqualsOrdinalIgnoreCase(SpecialVariables.AutomaticVariables[i]))
Expand Down
17 changes: 17 additions & 0 deletions test/powershell/engine/Api/TypeInference.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,23 @@ Describe "Type inference Tests" -tags "CI" {
$res.Count | Should -Be 2
$res.Name -join ' ' | Should -Be "System.IO.FileInfo System.IO.DirectoryInfo"
}

It 'Infers type of $null after variable assignment' {
$res = [AstTypeInference]::InferTypeOf( { $null = "Hello";$null }.Ast)
$res.Count | Should -Be 0
}

It 'Infers type of all scope variable after variable assignment' {
$res = [AstTypeInference]::InferTypeOf( { $true = "Hello";$true }.Ast)
$res.Count | Should -Be 1
$res.Name | Should -Be 'System.Boolean'
}

It 'Infers type of all scope variable host after variable assignment' {
$res = [AstTypeInference]::InferTypeOf( { $Host = "Hello";$Host }.Ast, [TypeInferenceRuntimePermissions]::AllowSafeEval)
$res.Count | Should -Be 1
$res.Name | Should -Be 'System.Management.Automation.Internal.Host.InternalHost'
}
}

Describe "AstTypeInference tests" -Tags CI {
Expand Down