Fix type inference for all scope vars (#18758)

This commit is contained in:
MartinGC94
2022-12-20 15:38:25 +05:00
committed by GitHub
parent 9a7db33ee0
commit 8f7c980ca3
3 changed files with 52 additions and 17 deletions
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Management.Automation.Internal;
namespace System.Management.Automation
{
@@ -357,22 +358,22 @@ namespace System.Management.Automation
// 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>
(
@@ -1846,7 +1846,7 @@ namespace System.Management.Automation
// 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.
@@ -1961,6 +1961,23 @@ namespace System.Management.Automation
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]))
@@ -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 {