fix #1229
This commit is contained in:
parent
50338b6f4c
commit
62b2a4ac10
|
|
@ -515,6 +515,7 @@ namespace PascalABCCompiler.NETGenerator {
|
||||||
private Hashtable processing_types = new Hashtable();
|
private Hashtable processing_types = new Hashtable();
|
||||||
private MethodInfo arr_mi=null;
|
private MethodInfo arr_mi=null;
|
||||||
private Hashtable pas_defs = new Hashtable();
|
private Hashtable pas_defs = new Hashtable();
|
||||||
|
private Hashtable memoized_exprs = new Hashtable();
|
||||||
|
|
||||||
public Helper() {}
|
public Helper() {}
|
||||||
|
|
||||||
|
|
@ -873,6 +874,16 @@ namespace PascalABCCompiler.NETGenerator {
|
||||||
return processing_types[type] != null;
|
return processing_types[type] != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void LinkExpressionToLocalBuilder(IExpressionNode expr, LocalBuilder lb)
|
||||||
|
{
|
||||||
|
memoized_exprs[expr] = lb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalBuilder GetLocalBuilderForExpression(IExpressionNode expr)
|
||||||
|
{
|
||||||
|
return memoized_exprs[expr] as LocalBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
//получение типа
|
//получение типа
|
||||||
public TypeInfo GetTypeReference(ITypeNode type)
|
public TypeInfo GetTypeReference(ITypeNode type)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9307,6 +9307,10 @@ namespace PascalABCCompiler.NETGenerator
|
||||||
SemanticTree.ICommonMethodCallNode cmcall = ifc as SemanticTree.ICommonMethodCallNode;
|
SemanticTree.ICommonMethodCallNode cmcall = ifc as SemanticTree.ICommonMethodCallNode;
|
||||||
if (cmcall != null)
|
if (cmcall != null)
|
||||||
{
|
{
|
||||||
|
LocalBuilder memoized_lb = helper.GetLocalBuilderForExpression(cmcall.obj);
|
||||||
|
if (memoized_lb != null)
|
||||||
|
il.Emit(OpCodes.Ldloc, memoized_lb);
|
||||||
|
else
|
||||||
cmcall.obj.visit(this);
|
cmcall.obj.visit(this);
|
||||||
if (cmcall.obj.type.is_value_type)
|
if (cmcall.obj.type.is_value_type)
|
||||||
il.Emit(OpCodes.Box, helper.GetTypeReference(cmcall.obj.type).tp);
|
il.Emit(OpCodes.Box, helper.GetTypeReference(cmcall.obj.type).tp);
|
||||||
|
|
@ -9323,6 +9327,10 @@ namespace PascalABCCompiler.NETGenerator
|
||||||
SemanticTree.ICompiledMethodCallNode cmccall = ifc as SemanticTree.ICompiledMethodCallNode;
|
SemanticTree.ICompiledMethodCallNode cmccall = ifc as SemanticTree.ICompiledMethodCallNode;
|
||||||
if (cmccall != null)
|
if (cmccall != null)
|
||||||
{
|
{
|
||||||
|
LocalBuilder memoized_lb = helper.GetLocalBuilderForExpression(cmccall.obj);
|
||||||
|
if (memoized_lb != null)
|
||||||
|
il.Emit(OpCodes.Ldloc, memoized_lb);
|
||||||
|
else
|
||||||
cmccall.obj.visit(this);
|
cmccall.obj.visit(this);
|
||||||
if (cmccall.obj.type.is_value_type)
|
if (cmccall.obj.type.is_value_type)
|
||||||
il.Emit(OpCodes.Box, helper.GetTypeReference(cmccall.obj.type).tp);
|
il.Emit(OpCodes.Box, helper.GetTypeReference(cmccall.obj.type).tp);
|
||||||
|
|
@ -9902,7 +9910,27 @@ namespace PascalABCCompiler.NETGenerator
|
||||||
bool tmp_is_addr = is_addr;
|
bool tmp_is_addr = is_addr;
|
||||||
is_dot_expr = false;//don't box the condition expression
|
is_dot_expr = false;//don't box the condition expression
|
||||||
is_addr = false;
|
is_addr = false;
|
||||||
|
LocalBuilder funcptr_lb = null;
|
||||||
|
if (value.condition is IBasicFunctionCallNode &&
|
||||||
|
(value.condition as IBasicFunctionCallNode).real_parameters[0].type.IsDelegate &&
|
||||||
|
(value.condition as IBasicFunctionCallNode).real_parameters[1] is INullConstantNode &&
|
||||||
|
(value.condition as IBasicFunctionCallNode).basic_function.basic_function_type == basic_function_type.objeq)
|
||||||
|
{
|
||||||
|
IBasicFunctionCallNode eq = (value.condition as IBasicFunctionCallNode);
|
||||||
|
funcptr_lb = il.DeclareLocal(helper.GetTypeReference((value.condition as IBasicFunctionCallNode).real_parameters[0].type).tp);
|
||||||
|
eq.real_parameters[0].visit(this);
|
||||||
|
il.Emit(OpCodes.Stloc, funcptr_lb);
|
||||||
|
il.Emit(OpCodes.Ldloc, funcptr_lb);
|
||||||
|
il.Emit(OpCodes.Ldnull);
|
||||||
|
il.Emit(OpCodes.Ceq);
|
||||||
|
if (value.ret_if_false is ICommonConstructorCall)
|
||||||
|
helper.LinkExpressionToLocalBuilder((value.condition as IBasicFunctionCallNode).real_parameters[0], funcptr_lb);
|
||||||
|
else if (value.ret_if_false is ICompiledConstructorCall)
|
||||||
|
helper.LinkExpressionToLocalBuilder((value.condition as IBasicFunctionCallNode).real_parameters[0], funcptr_lb);
|
||||||
|
}
|
||||||
|
else
|
||||||
value.condition.visit(this);
|
value.condition.visit(this);
|
||||||
|
|
||||||
is_dot_expr = tmp_is_dot_expr;
|
is_dot_expr = tmp_is_dot_expr;
|
||||||
is_addr = tmp_is_addr;
|
is_addr = tmp_is_addr;
|
||||||
il.Emit(OpCodes.Brfalse, FalseLabel);
|
il.Emit(OpCodes.Brfalse, FalseLabel);
|
||||||
|
|
|
||||||
23
TestSuite/delegates10.pas
Normal file
23
TestSuite/delegates10.pas
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
var i: integer;
|
||||||
|
|
||||||
|
function f1: procedure;
|
||||||
|
begin
|
||||||
|
Inc(i);
|
||||||
|
Result := procedure ()->exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure test(p: procedure);
|
||||||
|
begin
|
||||||
|
p();
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
var p: procedure;
|
||||||
|
p := f1();
|
||||||
|
p();
|
||||||
|
assert(i = 1);
|
||||||
|
test(f1);
|
||||||
|
assert(i = 2);
|
||||||
|
p := f1 <> nil ? f1 : nil;
|
||||||
|
assert(i = 4);
|
||||||
|
end.
|
||||||
Loading…
Reference in a new issue