diff --git a/NETGenerator/NETGenerator.cs b/NETGenerator/NETGenerator.cs index 762bb8c39..112c30a7b 100644 --- a/NETGenerator/NETGenerator.cs +++ b/NETGenerator/NETGenerator.cs @@ -7612,7 +7612,7 @@ namespace PascalABCCompiler.NETGenerator { if (value.obj.type.is_generic_parameter) il.Emit(OpCodes.Constrained, helper.GetTypeReference(value.obj.type).tp); - else if (value.obj.conversion_type != null && value.obj.conversion_type.is_generic_parameter) + else if (value.obj.conversion_type != null && value.obj.conversion_type.is_generic_parameter && (!value.obj.type.IsInterface || value.obj.conversion_type.ImplementingInterfaces.Count > 0)) il.Emit(OpCodes.Constrained, helper.GetTypeReference(value.obj.conversion_type).tp); il.EmitCall(OpCodes.Callvirt, mi, null); } diff --git a/TestSuite/Deconstructs2.pas b/TestSuite/Deconstructs2.pas new file mode 100644 index 000000000..e846eae64 --- /dev/null +++ b/TestSuite/Deconstructs2.pas @@ -0,0 +1,18 @@ +var i: integer; +type + t1 = class + procedure Deconstruct; + begin + i := 1; + end; + end; + +begin + var o := new t1; + if o is t1(var a) then + begin + i := 2; + assert(o = a); + end; + assert(i = 2); +end. \ No newline at end of file diff --git a/TestSuite/Deconstructs3.pas b/TestSuite/Deconstructs3.pas new file mode 100644 index 000000000..8d0be3249 --- /dev/null +++ b/TestSuite/Deconstructs3.pas @@ -0,0 +1,45 @@ +type + Person = class + name: string; + age: integer; + + constructor(name: string; age: integer); + begin + self.name := name; + self.age := age; + end; + + procedure Deconstruct(var name: string; var age: integer); + begin + name := self.name; + age := self.age; + end; + end; + +begin + var p := new Person('John', 25); + var s := ''; + var i := 0; + if p is Person(var name, var age) then + begin + s := name; + i := age; + end; + + assert(s = 'John'); + assert(i = 25); + + s := ''; + i := 0; + + match p with + Person(name, age): + begin + s := name; + i := age; + end; + end; + + assert(s = 'John'); + assert(i = 25); +end. \ No newline at end of file diff --git a/TestSuite/case7.pas b/TestSuite/case7.pas new file mode 100644 index 000000000..e035cb270 --- /dev/null +++ b/TestSuite/case7.pas @@ -0,0 +1,13 @@ +var i: integer; + +procedure p1(s: string) := +case s of + else Inc(i); +end; + +begin + p1('abc'); + p1(''); + p1(nil); + assert(i = 3); +end. \ No newline at end of file diff --git a/TestSuite/generics68.pas b/TestSuite/generics68.pas new file mode 100644 index 000000000..137729a96 --- /dev/null +++ b/TestSuite/generics68.pas @@ -0,0 +1,21 @@ +var i: integer; +type + I1 = interface + procedure p1; + end; + + // Обязательно класс, не запись + t2 = class(I1) + public procedure p1; + begin + i := 1; + end; + end; + +// Обязательно I1(o), (o as I1) работает без проблем +procedure p0(o: T) := I1(o).p1; + +begin + p0(new t2); + assert(i = 1); +end. \ No newline at end of file diff --git a/TestSuite/units/u_deconstruct1.pas b/TestSuite/units/u_deconstruct1.pas new file mode 100644 index 000000000..5903955f1 --- /dev/null +++ b/TestSuite/units/u_deconstruct1.pas @@ -0,0 +1,7 @@ +unit u_deconstruct1; + +type + t1 = class + procedure Deconstruct(var a,b: byte) := exit; + end; +end. \ No newline at end of file diff --git a/TestSuite/usesunits/use_deconstruct1.pas b/TestSuite/usesunits/use_deconstruct1.pas new file mode 100644 index 000000000..8c380c810 --- /dev/null +++ b/TestSuite/usesunits/use_deconstruct1.pas @@ -0,0 +1,10 @@ +uses u_deconstruct1; + +begin + var i := 0; + if new t1 is t1(var a) then + begin + i := 1; + end; + assert(i = 1); +end. \ No newline at end of file diff --git a/TreeConverter/SymbolTable/DSST/SymbolTable.cs b/TreeConverter/SymbolTable/DSST/SymbolTable.cs index 491d1f77e..c31992d0f 100644 --- a/TreeConverter/SymbolTable/DSST/SymbolTable.cs +++ b/TreeConverter/SymbolTable/DSST/SymbolTable.cs @@ -926,7 +926,7 @@ namespace SymbolTable ((to.symbol_kind == symbol_kind.sk_overload_function) && (add.symbol_kind == symbol_kind.sk_overload_function)) || ((to.symbol_kind == symbol_kind.sk_overload_procedure) && (add.symbol_kind == symbol_kind.sk_overload_procedure)) - || to.sym_info != add.sym_info && to.sym_info is PascalABCCompiler.TreeRealization.function_node && add.sym_info is PascalABCCompiler.TreeRealization.function_node + || to.sym_info != add.sym_info && (to.sym_info is PascalABCCompiler.TreeRealization.function_node || to.symbol_kind == symbol_kind.sk_overload_function) && add.sym_info is PascalABCCompiler.TreeRealization.function_node /*&& (to.sym_info as PascalABCCompiler.TreeRealization.function_node).is_extension_method*/ && (add.sym_info as PascalABCCompiler.TreeRealization.function_node).is_extension_method ); } diff --git a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Patterns.cs b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Patterns.cs index 99dc7da6f..f9795205f 100644 --- a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Patterns.cs +++ b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Patterns.cs @@ -93,7 +93,8 @@ namespace PascalABCCompiler.TreeConverter out type_node[] parameterTypes) { parameterTypes = new type_node[givenParameterTypes.Length]; - candidate.parameters[0].name = "Self"; // SSM 23.06.20 #2268 - это если в NET где-то такое нашли + if (candidate.parameters.Count > 0) + candidate.parameters[0].name = "Self"; // SSM 23.06.20 #2268 - это если в NET где-то такое нашли var selfParameter = candidate.is_extension_method ? candidate.parameters.FirstOrDefault(IsSelfParameter) : null; Debug.Assert(!candidate.is_extension_method || selfParameter != null, "Couldn't find self parameter in extension method"); var candidateParameterTypes = diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index 1de65161c..763ece523 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -10928,7 +10928,7 @@ namespace PascalABCCompiler.TreeConverter context.leave_code_block(); if (ifn == null) { - ifn = new if_node(en, new statements_list(null), null, get_location(_case_node)); + ifn = new if_node(new bool_const_node(false, null), new statements_list(null), null, get_location(_case_node)); main_ifn = ifn; } ifn.else_body = else_statement;