Добавление стандартных имен в фиктивный модуль вместо стандартного модуля в Intellisense (#3387)

* Add forIntellisense checks in NameCorrectVisitor

* Refactor standard names adding in Intellisense

* Edit tuples compilation sample for SPython

* Delete char type in SPython Intellisense

* Fix ProcRealization documentation initialization

Нужно, чтобы метод WithRefreshedDescription корректно работал, когда описание задается вручную.
This commit is contained in:
Александр Земляк 2026-02-25 21:39:38 +03:00 committed by GitHub
parent 3de119c8fc
commit 2e678bf965
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 137 additions and 108 deletions

View file

@ -1026,7 +1026,7 @@ namespace Languages.SPython.Frontend.Data
case TypeCode.Double: return "float";
case TypeCode.Boolean: return "bool";
case TypeCode.String: return "str";
case TypeCode.Char: return "char";
case TypeCode.Char: return "str";
}
/*if (ctn.IsPointer)
if (ctn.FullName == "System.Void*")
@ -1106,7 +1106,7 @@ namespace Languages.SPython.Frontend.Data
case TypeCode.Double: return "float";
case TypeCode.Boolean: return "bool";
case TypeCode.String: return "str";
case TypeCode.Char: return "char";
case TypeCode.Char: return "str";
}
/*if (ctn.IsPointer)
if (ctn.FullName == "System.Void*")
@ -1280,7 +1280,6 @@ namespace Languages.SPython.Frontend.Data
{
case KeywordKind.IntType: return "int";
case KeywordKind.DoubleType: return "float";
case KeywordKind.CharType: return "char";
case KeywordKind.BoolType: return "bool";
case KeywordKind.StringType: return "str";
}

View file

@ -7,8 +7,11 @@ namespace Languages.SPython.Frontend.Converters
{
public HashSet<string> variablesUsedAsGlobal = new HashSet<string>();
public NameCorrectVisitor(string unitName, Dictionary<string, Dictionary<string, bool>> namesFromUsedUnits, HashSet<string> definedFunctionsNames) : base(unitName, namesFromUsedUnits)
private readonly bool forIntellisense;
public NameCorrectVisitor(string unitName, bool forIntellisense, Dictionary<string, Dictionary<string, bool>> namesFromUsedUnits, HashSet<string> definedFunctionsNames) : base(unitName, namesFromUsedUnits)
{
this.forIntellisense = forIntellisense;
foreach (string definedFunctionName in definedFunctionsNames)
{
symbolTable.Add(definedFunctionName, NameKind.ForwardDeclaredFunction);
@ -54,21 +57,24 @@ namespace Languages.SPython.Frontend.Converters
public override void visit(global_statement _global_statement)
{
foreach (ident _ident in _global_statement.idents.idents)
if (!forIntellisense)
{
NameKind nameType = symbolTable[_ident.name];
switch (nameType)
foreach (ident _ident in _global_statement.idents.idents)
{
case NameKind.GlobalVariable:
case NameKind.ImportedVariableAlias:
case NameKind.ImportedNotVariableAlias:
break;
case NameKind.Unknown:
throw new SPythonSyntaxVisitorError("UNKNOWN_NAME_{0}",
_ident.source_context, _ident.name);
default:
throw new SPythonSyntaxVisitorError("SCOPE_CONTAINS_NAME_{0}",
_ident.source_context, _ident.name);
NameKind nameType = symbolTable[_ident.name];
switch (nameType)
{
case NameKind.GlobalVariable:
case NameKind.ImportedVariableAlias:
case NameKind.ImportedNotVariableAlias:
break;
case NameKind.Unknown:
throw new SPythonSyntaxVisitorError("UNKNOWN_NAME_{0}",
_ident.source_context, _ident.name);
default:
throw new SPythonSyntaxVisitorError("SCOPE_CONTAINS_NAME_{0}",
_ident.source_context, _ident.name);
}
}
}
@ -77,6 +83,9 @@ namespace Languages.SPython.Frontend.Converters
public override void visit(named_type_reference _named_type_reference)
{
if (forIntellisense)
return;
ident id = _named_type_reference.names[0];
string name = id.name;
@ -107,6 +116,9 @@ namespace Languages.SPython.Frontend.Converters
// функция нужна для классов list, dict и set из-за наличия одноименных функций в другом модуле
public override void visit(template_type_reference _template_type_reference)
{
if (forIntellisense)
return;
named_type_reference _named_type_reference = _template_type_reference.name;
string name = _named_type_reference.names[0].name + '`';
@ -144,11 +156,17 @@ namespace Languages.SPython.Frontend.Converters
switch (nameKind)
{
case NameKind.ModuleAlias:
if (forIntellisense)
break;
_ident.name = symbolTable.AliasToRealName(_ident.name);
break;
case NameKind.ImportedVariableAlias:
case NameKind.ImportedNotVariableAlias:
if (forIntellisense)
break;
Replace(_ident, new dot_node(new ident(symbolTable.AliasToModuleName(_ident.name), sc)
, new ident(symbolTable.AliasToRealName(_ident.name), sc), sc));
break;
@ -160,12 +178,18 @@ namespace Languages.SPython.Frontend.Converters
break;
case NameKind.ForwardDeclaredFunction:
if (forIntellisense)
break;
if (!symbolTable.IsInFunctionBody)
throw new SPythonSyntaxVisitorError("FUNCTION_{0}_USED_BEFORE_DECLARATION",
sc, _ident.name);
break;
case NameKind.Unknown:
if (forIntellisense)
break;
throw new SPythonSyntaxVisitorError("UNKNOWN_NAME_{0}",
sc, _ident.name);
}
@ -219,7 +243,8 @@ namespace Languages.SPython.Frontend.Converters
else
symbolTable.Add(_ident.name, NameKind.LocalVariable);
CheckInitializationWithEmptyCollection(_assign);
if (!forIntellisense)
CheckInitializationWithEmptyCollection(_assign);
var _var_statement = SyntaxTreeBuilder.BuildVarStatementNodeFromAssignNode(_assign);

View file

@ -44,9 +44,9 @@ namespace Languages.SPython.Frontend.Converters
// Выносим выражения с лямбдами из заголовка foreach + считаем максимум 10 вложенных лямбд
// украл из паскаля
StandOutExprWithLambdaInForeachSequenceAndNestedLambdasVisitor.New.ProcessNode(root);
new VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer(root as compilation_unit).ProcessNode(root);
FindOnExceptVarsAndApplyRenameVisitor.New.ProcessNode(root);
new TryCatchDecorator(StandOutExprWithLambdaInForeachSequenceAndNestedLambdasVisitor.New, forIntellisense).ProcessNode(root);
new TryCatchDecorator(new VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer(root as compilation_unit), forIntellisense).ProcessNode(root);
new TryCatchDecorator(FindOnExceptVarsAndApplyRenameVisitor.New, forIntellisense).ProcessNode(root);
// дешугаризация составных сравнительных операций (e.g. a == b == c)
new TryCatchDecorator(new CompoundComparisonDesugarVisitor(), forIntellisense).ProcessNode(root);
@ -66,7 +66,7 @@ namespace Languages.SPython.Frontend.Converters
// на
// variable_name = str(single_length_string)
// чтобы при выведении типа правильно вывел str, а не char
new AssignmentCharAsStringVisitor().ProcessNode(root);
new TryCatchDecorator(new AssignmentCharAsStringVisitor(), forIntellisense).ProcessNode(root);
// Сохраняет множество имён функций, которые объявлены в программе для NameCorrectVisitor
var ffv = new FindFunctionsNamesVisitor();
@ -75,14 +75,14 @@ namespace Languages.SPython.Frontend.Converters
// проверка корректности имён, разрешение неоднозначности
// сохранение множества переменных, использующихся как глобальные в ncv.variablesUsedAsGlobal
var ncv = new NameCorrectVisitor(System.IO.Path.GetFileNameWithoutExtension(((compilation_unit)root).file_name),
var ncv = new NameCorrectVisitor(System.IO.Path.GetFileNameWithoutExtension(((compilation_unit)root).file_name), forIntellisense,
compilationArtifacts.NamesFromUsedUnits, ffv.definedFunctionsNames);
if (!new TryCatchDecorator(ncv, forIntellisense).ProcessNode(root))
return root;
new TryCatchDecorator(ncv, forIntellisense).ProcessNode(root);
// замена типов из SPython на типы из PascalABC.NET
new TryCatchDecorator(new TypeCorrectVisitor(forIntellisense), forIntellisense).ProcessNode(root);
if (!forIntellisense)
new TypeCorrectVisitor().ProcessNode(root);
// вынос forward объявлений для всех функций в начало
new TryCatchDecorator(new AddForwardDeclarationsVisitor(), forIntellisense).ProcessNode(root);

View file

@ -5,13 +5,6 @@ namespace Languages.SPython.Frontend.Converters
public class TypeCorrectVisitor : BaseChangeVisitor
{
private bool forIntellisense;
public TypeCorrectVisitor(bool forIntellisense)
{
this.forIntellisense = forIntellisense;
}
public override void visit(template_type_reference ttr)
{
int index = ttr.name.names.Count - 1;
@ -23,7 +16,8 @@ namespace Languages.SPython.Frontend.Converters
throw new SPythonSyntaxVisitorError("LONG_TUPLE_TYPENAME",
ttr.source_context, cnt);
}
ttr.name.names[index].name = "!tuple" + cnt;
if (cnt > 1)
ttr.name.names[index].name = "!tuple" + cnt;
}
base.visit(ttr);
@ -32,43 +26,40 @@ namespace Languages.SPython.Frontend.Converters
public override void visit(named_type_reference _named_type_reference)
{
ident id = _named_type_reference.names[_named_type_reference.names.Count - 1];
if (!forIntellisense)
{
switch (id.name)
{
case "int":
id.name = "integer";
break;
case "float":
id.name = "real";
break;
case "str":
id.name = "string";
break;
case "bool":
id.name = "boolean";
break;
case "bigint":
id.name = "biginteger";
break;
case "integer":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "int");
case "real":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "float");
case "string":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "str");
case "boolean":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "bool");
case "biginteger":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "bigint");
}
switch (id.name)
{
case "int":
id.name = "integer";
break;
case "float":
id.name = "real";
break;
case "str":
id.name = "string";
break;
case "bool":
id.name = "boolean";
break;
case "bigint":
id.name = "biginteger";
break;
case "integer":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "int");
case "real":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "float");
case "string":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "str");
case "boolean":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "bool");
case "biginteger":
throw new SPythonSyntaxVisitorError("PASCALABCNET_TYPE_{0}_INSTEAD_OF_SPYTHON_TYPE_{1}",
id.source_context, id.name, "bigint");
}
}
}

View file

@ -2530,7 +2530,7 @@ namespace CodeCompletion
// Пока что добавили возможость грубо отключить добавление NET пространств имен по умолчанию здесь (второе условие нужно, чтобы в стандартные модули языка они тоже не добавлялись) EVA
if (currentUnitLanguage.LanguageIntellisenseSupport.AddStandardNetNamespacesToUserScope && (languageUsingStandardUnit?.LanguageIntellisenseSupport.AddStandardNetNamespacesToUserScope ?? true))
namespaces.AddRange(PascalABCCompiler.NetHelper.NetHelper.GetNamespaces(_as));
InterfaceUnitScope unit_scope = null;
bool existed_ns = false;
is_namespace = _unit_module.unit_name.HeaderKeyword == UnitHeaderKeyword.Namespace;
@ -2654,20 +2654,8 @@ namespace CodeCompletion
}
}
// считаем основной модуль идущим первым в списке EVA
var language = Languages.Facade.LanguageProvider.Instance.Languages.Find(lang => lang.SystemUnitNames.First() == unitName);
if (language != null)
{
// добавление стандартных типов можно делать в отдельный фиктивный модуль, как в основном компиляторе
// это позволит работать директиве DisableStandardUnits, а также не будет засорять сам стандартный модуль типами EVA
add_standart_types(entry_scope, language.LanguageIntellisenseSupport);
if (language == Languages.Facade.LanguageProvider.Instance.MainLanguage)
{
AddPascalStandardProcedures();
}
}
// Добавляем стандартные имена языка EVA
AddStandardNamesFictiveUnitAsUsedUnit(cur_scope);
CodeCompletionController.comp_modules[_unit_module.file_name] = this.converter;
@ -2733,7 +2721,7 @@ namespace CodeCompletion
}
}
if (currentUnitLanguage.LanguageIntellisenseSupport.ApplySyntaxTreeConvertersForIntellisense
if (currentUnitLanguage.LanguageIntellisenseSupport.ApplySyntaxTreeConvertersForIntellisense
&& currentUnitLanguage.LanguageInformation.SyntaxTreeIsConvertedAfterUsedModulesCompilation)
{
var namesFromUsedUnits = CollectNamesFromUsedUnits(cur_scope);
@ -2745,7 +2733,7 @@ namespace CodeCompletion
_unit_module = (unit_module)converter.ConvertAfterUsedModulesCompilation(_unit_module, true, in artifacts);
}
}
DateTime start_time = DateTime.Now;
@ -2807,6 +2795,23 @@ namespace CodeCompletion
}
/// <summary>
/// Добавление в scopeToAdd использования фиктивного модуля со стандартными именами языка
/// </summary>
private void AddStandardNamesFictiveUnitAsUsedUnit(SymScope scopeToAdd)
{
var standardNamesUnit = new InterfaceUnitScope(new SymInfo(StringConstants.fictiveStandardNamesUnitName, SymbolKind.Namespace, ""), null);
add_standart_types(standardNamesUnit, currentUnitLanguage.LanguageIntellisenseSupport);
if (currentUnitLanguage == Languages.Facade.LanguageProvider.Instance.MainLanguage)
{
AddPascalStandardProcedures(standardNamesUnit);
}
scopeToAdd.AddUsedUnit(standardNamesUnit);
}
private Dictionary<string, Dictionary<string, bool>> CollectNamesFromUsedUnits(SymScope currentUnitScope)
{
var namesFromUsedUnits = new Dictionary<string, Dictionary<string, bool>>();
@ -3272,6 +3277,9 @@ namespace CodeCompletion
}
}
// Добавляем стандартные имена языка EVA
AddStandardNamesFictiveUnitAsUsedUnit(cur_scope);
if (currentUnitLanguage.LanguageIntellisenseSupport.ApplySyntaxTreeConvertersForIntellisense)
{
foreach (ISyntaxTreeConverter converter in currentUnitLanguage.SyntaxTreeConverters)
@ -3445,28 +3453,28 @@ namespace CodeCompletion
}
}
public void AddPascalStandardProcedures()
public void AddPascalStandardProcedures(SymScope scopeToAdd)
{
ProcScope ps = new ProcScope(StringConstants.set_length_procedure_name, null);
ps.AddParameter(new ElementScope(new SymInfo("arr", SymbolKind.Parameter, "arr"), new ArrayScope(), null, ps));
ps.parameters[0].param_kind = parametr_kind.var_parametr;
ps.AddParameter(new ElementScope(new SymInfo("length", SymbolKind.Parameter, "length"), TypeTable.int_type, null, ps));
ps.Complete();
cur_scope.AddName(StringConstants.set_length_procedure_name, ps);
cur_scope.AddName(StringConstants.true_const_name, new ElementScope(new SymInfo(StringConstants.true_const_name, SymbolKind.Constant, StringConstants.true_const_name), TypeTable.bool_type, true, null));
cur_scope.AddName(StringConstants.false_const_name, new ElementScope(new SymInfo(StringConstants.false_const_name, SymbolKind.Constant, StringConstants.false_const_name), TypeTable.bool_type, false, null));
scopeToAdd.AddName(StringConstants.set_length_procedure_name, ps);
scopeToAdd.AddName(StringConstants.true_const_name, new ElementScope(new SymInfo(StringConstants.true_const_name, SymbolKind.Constant, StringConstants.true_const_name), TypeTable.bool_type, true, null));
scopeToAdd.AddName(StringConstants.false_const_name, new ElementScope(new SymInfo(StringConstants.false_const_name, SymbolKind.Constant, StringConstants.false_const_name), TypeTable.bool_type, false, null));
ps = new ProcScope(StringConstants.new_procedure_name, null);
ElementScope prm = new ElementScope(new SymInfo("p", SymbolKind.Parameter, "p"), TypeTable.ptr_type, null, ps);
prm.param_kind = parametr_kind.var_parametr;
ps.AddParameter(prm);
ps.Complete();
cur_scope.AddName(StringConstants.new_procedure_name, ps);
scopeToAdd.AddName(StringConstants.new_procedure_name, ps);
ps = new ProcScope(StringConstants.dispose_procedure_name, null);
prm = new ElementScope(new SymInfo("p", SymbolKind.Parameter, "p"), TypeTable.ptr_type, null, ps);
prm.param_kind = parametr_kind.var_parametr;
ps.AddParameter(prm);
ps.Complete();
cur_scope.AddName(StringConstants.dispose_procedure_name, ps);
scopeToAdd.AddName(StringConstants.dispose_procedure_name, ps);
ps = new ProcScope(StringConstants.IncProcedure, null);
prm = new ElementScope(new SymInfo("i", SymbolKind.Parameter, "i"), TypeTable.int16_type, null, ps);
@ -3474,7 +3482,7 @@ namespace CodeCompletion
ps.AddParameter(prm);
ps.Complete();
ps.si.not_include = true;
cur_scope.AddName(StringConstants.IncProcedure, ps);
scopeToAdd.AddName(StringConstants.IncProcedure, ps);
ps = new ProcScope(StringConstants.IncProcedure, null);
prm = new ElementScope(new SymInfo("i", SymbolKind.Parameter, "i"), TypeTable.uint16_type, null, ps);
@ -3482,7 +3490,7 @@ namespace CodeCompletion
ps.AddParameter(prm);
ps.Complete();
ps.si.not_include = true;
cur_scope.AddName(StringConstants.IncProcedure, ps);
scopeToAdd.AddName(StringConstants.IncProcedure, ps);
ps = new ProcScope(StringConstants.IncProcedure, null);
prm = new ElementScope(new SymInfo("i", SymbolKind.Parameter, "i"), TypeTable.sbyte_type, null, ps);
@ -3490,7 +3498,7 @@ namespace CodeCompletion
ps.AddParameter(prm);
ps.Complete();
ps.si.not_include = true;
cur_scope.AddName(StringConstants.IncProcedure, ps);
scopeToAdd.AddName(StringConstants.IncProcedure, ps);
ps = new ProcScope(StringConstants.IncProcedure, null);
prm = new ElementScope(new SymInfo("i", SymbolKind.Parameter, "i"), TypeTable.int64_type, null, ps);
@ -3498,7 +3506,7 @@ namespace CodeCompletion
ps.AddParameter(prm);
ps.Complete();
ps.si.not_include = true;
cur_scope.AddName(StringConstants.IncProcedure, ps);
scopeToAdd.AddName(StringConstants.IncProcedure, ps);
ps = new ProcScope(StringConstants.IncProcedure, null);
prm = new ElementScope(new SymInfo("i", SymbolKind.Parameter, "i"), TypeTable.uint64_type, null, ps);
@ -3506,7 +3514,7 @@ namespace CodeCompletion
ps.AddParameter(prm);
ps.Complete();
ps.si.not_include = true;
cur_scope.AddName(StringConstants.IncProcedure, ps);
scopeToAdd.AddName(StringConstants.IncProcedure, ps);
ps = new ProcScope(StringConstants.IncProcedure, null);
prm = new ElementScope(new SymInfo("i", SymbolKind.Parameter, "i"), TypeTable.uint32_type, null, ps);
@ -3514,7 +3522,7 @@ namespace CodeCompletion
ps.AddParameter(prm);
ps.Complete();
ps.si.not_include = true;
cur_scope.AddName(StringConstants.IncProcedure, ps);
scopeToAdd.AddName(StringConstants.IncProcedure, ps);
}
public override void visit(hex_constant _hex_constant)

View file

@ -534,8 +534,9 @@ namespace CodeCompletion
public void AddUsedUnit(SymScope unit)
{
if (this.si.name != StringConstants.pascalSystemUnitName || unit is NamespaceScope)
used_units.Add(unit);
// Убрал условие EVA 14.02.2026
// if (this.si.name != StringConstants.pascalSystemUnitName || unit is NamespaceScope)
used_units.Add(unit);
}
public virtual string GetFullName()
@ -1814,9 +1815,9 @@ namespace CodeCompletion
this.def_proc = def_proc;
this.top_mod_scope = top_mod_scope;
def_proc.procRealization = this;
if (def_proc != null)
this.topScope = def_proc.topScope;
this.topScope = def_proc.topScope;
this.si = new SymInfo(def_proc.si.name, def_proc.si.kind, def_proc.si.description);
this.documentation = def_proc.documentation;
}
public override ScopeKind Kind

View file

@ -412,6 +412,8 @@ namespace PascalABCCompiler
}
}
public const string fictiveStandardNamesUnitName = "?StandardNamesUnit";
public static readonly string new_array_procedure_name = "__new_array";
public static readonly string new_procedure_name = "new";

View file

@ -3,7 +3,7 @@
a,b = divmod(-7, 3)
temp = divmod(-7, 3)
t: tuple[int, int] = divmod(-7, 3)
t1: tuple[int] = tuple.Create(0) # из одного эл-та пока так
t1: tuple[int, int, int, int] = (1, 2, 3, 4)
print(a == t.Item1)
print(b == t.Item2)

View file

@ -17,7 +17,7 @@ function input(): string;
function input(s: string): string;
///-
///--
type kwargs_gen<T> = class
public !kwargs: Dictionary<string, T>
:= new Dictionary<string, T>();
@ -550,8 +550,8 @@ function !CreateTuple<T1, T2, T3, T4, T5, T6, T7>(
type
biginteger = PABCSystem.BigInteger;
tuple = System.Tuple;
!tuple1<T> = System.Tuple<T>;
// tuple = System.Tuple;
tuple<T> = System.Tuple<T>;
!tuple2<T1, T2> = System.Tuple<T1, T2>;
!tuple3<T1, T2, T3> = System.Tuple<T1, T2, T3>;
!tuple4<T1, T2, T3, T4> = System.Tuple<T1, T2, T3, T4>;
@ -559,6 +559,7 @@ type
!tuple6<T1, T2, T3, T4, T5, T6> = System.Tuple<T1, T2, T3, T4, T5, T6>;
!tuple7<T1, T2, T3, T4, T5, T6, T7> = System.Tuple<T1, T2, T3, T4, T5, T6, T7>;
///--
empty_list = class
class function operator implicit<T>(x: empty_list): list<T>;
begin
@ -566,6 +567,7 @@ type
end;
end;
///--
empty_set = class
class function operator implicit<T>(x: empty_set): &set<T>;
begin
@ -573,6 +575,7 @@ type
end;
end;
///--
empty_dict = class
class function operator implicit<K, V>(x: empty_dict): dict<K, V>;
begin
@ -776,7 +779,7 @@ function get_values<K, V>(dct: Dictionary<K, V>):= dct.values;
// TUPLES BEGIN
function !CreateTuple<T>(v: T): System.Tuple<T> := Tuple.Create(v);
function !CreateTuple<T>(v: T): System.Tuple<T> := System.Tuple.Create(v);
function !CreateTuple<T1, T2>(
v1: T1; v2: T2