full support of Nullable<T> (bug fix #405)

This commit is contained in:
Бондарев Иван 2017-05-25 19:44:06 +02:00
parent 32404786fb
commit 0494a67b32
8 changed files with 444 additions and 62 deletions

View file

@ -6598,8 +6598,19 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Stloc, start_index_lb);
il.MarkLabel(lbl);
}
//len_lb = EmitArguments(parameters, real_parameters, mi);
for (int i = 0; i < real_parameters.Length; i++)
{
if (real_parameters[i] is INullConstantNode && parameters[i].type.is_nullable_type)
{
Type tp = helper.GetTypeReference(parameters[i].type).tp;
LocalBuilder lb = il.DeclareLocal(tp);
il.Emit(OpCodes.Ldloca, lb);
il.Emit(OpCodes.Initobj, tp);
il.Emit(OpCodes.Ldloc, lb);
continue;
}
if (parameters[i].parameter_type == parameter_type.var)
is_addr = true;
//TODO:Переделать.
@ -6695,7 +6706,8 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Ldloca, lb);
}
is_dot_expr = false;
for (int i = 0; i < real_parameters.Length; i++)
EmitArguments(parameters, real_parameters);
/*for (int i = 0; i < real_parameters.Length; i++)
{
if (parameters[i].parameter_type == parameter_type.var)
is_addr = true;
@ -6707,7 +6719,7 @@ namespace PascalABCCompiler.NETGenerator
if (ctn2 != null && (ctn3.is_value_type || ctn3.is_generic_parameter) && ctn2.compiled_type == TypeFactory.ObjectType)
il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp);
is_addr = false;
}
}*/
MethodInfo mi = value.compiled_method.method_info;
if (value.compiled_method.comperehensive_type.is_value_type || !value.virtual_call && value.compiled_method.polymorphic_state == polymorphic_state.ps_virtual || value.compiled_method.polymorphic_state == polymorphic_state.ps_static)
{
@ -6751,7 +6763,8 @@ namespace PascalABCCompiler.NETGenerator
is_dot_expr = false;
bool is_comp_gen = false;
IParameterNode[] parameters = value.static_method.parameters;
for (int i = 0; i < real_parameters.Length; i++)
EmitArguments(parameters, real_parameters);
/*for (int i = 0; i < real_parameters.Length; i++)
{
if (parameters[i].parameter_type == parameter_type.var)
is_addr = true;
@ -6779,7 +6792,7 @@ namespace PascalABCCompiler.NETGenerator
if (box_awaited)
il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp);
is_addr = false;
}
}*/
//if (save_debug_info && need_fee)
// MarkSequencePoint(il, value.Location);
il.EmitCall(OpCodes.Call, mi, null);
@ -6851,7 +6864,8 @@ namespace PascalABCCompiler.NETGenerator
//bool is_comp_gen = false;
//bool need_fee = false;
IParameterNode[] parameters = value.method.parameters;
for (int i = 0; i < real_parameters.Length; i++)
EmitArguments(parameters, real_parameters);
/*for (int i = 0; i < real_parameters.Length; i++)
{
if (parameters[i].parameter_type == parameter_type.var)
is_addr = true;
@ -6881,7 +6895,7 @@ namespace PascalABCCompiler.NETGenerator
if (box_awaited)
il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp);
is_addr = false;
}
}*/
//вызов метода
//(ssyy) Функции размерных типов всегда вызываются через call
if (value.method.comperehensive_type.is_value_type || !value.virtual_call && value.method.polymorphic_state == polymorphic_state.ps_virtual || value.method.polymorphic_state == polymorphic_state.ps_static /*|| !value.virtual_call || (value.method.polymorphic_state != polymorphic_state.ps_virtual && value.method.polymorphic_state != polymorphic_state.ps_virtual_abstract && !value.method.common_comprehensive_type.IsInterface)*/)
@ -7241,41 +7255,10 @@ namespace PascalABCCompiler.NETGenerator
}
bool tmp_dot = is_dot_expr;
is_dot_expr = false;
bool is_comp_gen = false;
MethodInfo mi = meth.mi;
IParameterNode[] parameters = value.namespace_function.parameters;
for (int i = 0; i < real_parameters.Length; i++)
{
if (parameters[i].parameter_type == parameter_type.var)
is_addr = true;
ITypeNode ctn = real_parameters[i].type;
TypeInfo ti = null;
//(ssyy) moved up
ITypeNode tn2 = parameters[i].type;
ICompiledTypeNode ctn2 = tn2 as ICompiledTypeNode;
ITypeNode ctn3 = real_parameters[i].type;
//(ssyy) 07.12.2007 При боксировке нужно вызывать Ldsfld вместо Ldsflda.
//Дополнительная проверка введена именно для этого.
bool box_awaited =
(ctn2 != null && ctn2.compiled_type == TypeFactory.ObjectType || tn2.IsInterface) && !(real_parameters[i] is SemanticTree.INullConstantNode) && (ctn3.is_value_type || ctn3.is_generic_parameter);
if (!(real_parameters[i] is INullConstantNode))
{
ti = helper.GetTypeReference(ctn);
if (ti.clone_meth != null && ti.tp != null && ti.tp.IsValueType && !box_awaited && !parameters[i].is_const)
is_dot_expr = true;
}
//if (is_comp_gen == false)
is_comp_gen = CheckForCompilerGenerated(real_parameters[i]);
real_parameters[i].visit(this);
is_dot_expr = false;
CallCloneIfNeed(il, parameters[i], real_parameters[i]);
if (box_awaited)
{
il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp);
}
is_addr = false;
}
EmitArguments(parameters, real_parameters);
il.EmitCall(OpCodes.Call, mi, null);
EmitFreePinnedVariables();
if (tmp_dot == true)
@ -7295,7 +7278,52 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Nop);
//if (is_stmt == true) il.Emit(OpCodes.Pop);
}
private void EmitArguments(IParameterNode[] parameters, IExpressionNode[] real_parameters)
{
bool is_comp_gen = false;
for (int i = 0; i < real_parameters.Length; i++)
{
if (real_parameters[i] is INullConstantNode && parameters[i].type.is_nullable_type)
{
Type tp = helper.GetTypeReference(parameters[i].type).tp;
LocalBuilder lb = il.DeclareLocal(tp);
il.Emit(OpCodes.Ldloca, lb);
il.Emit(OpCodes.Initobj, tp);
il.Emit(OpCodes.Ldloc, lb);
continue;
}
if (parameters[i].parameter_type == parameter_type.var)
is_addr = true;
ITypeNode ctn = real_parameters[i].type;
TypeInfo ti = null;
//(ssyy) moved up
ITypeNode tn2 = parameters[i].type;
ICompiledTypeNode ctn2 = tn2 as ICompiledTypeNode;
ITypeNode ctn3 = real_parameters[i].type;
//(ssyy) 07.12.2007 При боксировке нужно вызывать Ldsfld вместо Ldsflda.
//Дополнительная проверка введена именно для этого.
bool box_awaited =
(ctn2 != null && ctn2.compiled_type == TypeFactory.ObjectType || tn2.IsInterface) && !(real_parameters[i] is SemanticTree.INullConstantNode) && (ctn3.is_value_type || ctn3.is_generic_parameter);
if (!(real_parameters[i] is INullConstantNode))
{
ti = helper.GetTypeReference(ctn);
if (ti.clone_meth != null && ti.tp != null && ti.tp.IsValueType && !box_awaited && !parameters[i].is_const)
is_dot_expr = true;
}
is_comp_gen = CheckForCompilerGenerated(real_parameters[i]);
real_parameters[i].visit(this);
is_dot_expr = false;
CallCloneIfNeed(il, parameters[i], real_parameters[i]);
if (box_awaited)
{
il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp);
}
is_addr = false;
}
}
private void EmitFreePinnedVariables()
{
/*foreach (LocalBuilder lb in pinned_variables)
@ -7317,7 +7345,7 @@ namespace PascalABCCompiler.NETGenerator
if (to.type.is_value_type)
{
//ti = helper.GetTypeReference(to.type);
if (ti.assign_meth != null)
if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type)
il.Emit(OpCodes.Ldsflda, fb);
}
else if (to.type.type_special_kind == type_special_kind.set_type && !in_var_init)
@ -7328,6 +7356,11 @@ namespace PascalABCCompiler.NETGenerator
return;
}
else ti = null;
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
//что присвоить
from.visit(this);
if (ti != null && ti.assign_meth != null)
@ -7335,7 +7368,7 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Call, ti.assign_meth);
return;
}
//это если например переменной типа object присваивается число
EmitBox(from, fb.FieldType);
@ -7409,8 +7442,9 @@ namespace PascalABCCompiler.NETGenerator
if (to.type.is_value_type)
{
//ti = helper.GetTypeReference(to.type);
if (ti.assign_meth != null)
if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type)
il.Emit(OpCodes.Ldloca, lb);
}
else if (to.type.type_special_kind == type_special_kind.set_type && !in_var_init)
{
@ -7420,6 +7454,11 @@ namespace PascalABCCompiler.NETGenerator
return;
}
else ti = null;
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
//что присвоить
from.visit(this);
if (ti != null && ti.assign_meth != null)
@ -7446,7 +7485,8 @@ namespace PascalABCCompiler.NETGenerator
if (to.type.is_value_type)
{
//ti = helper.GetTypeReference(to.type);
if (ti.assign_meth != null) il.Emit(OpCodes.Ldflda, fb);
if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type)
il.Emit(OpCodes.Ldflda, fb);
}
else if (to.type.type_special_kind == type_special_kind.set_type && !in_var_init)
{
@ -7456,6 +7496,11 @@ namespace PascalABCCompiler.NETGenerator
return;
}
else ti = null;
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
//что присвоить
from.visit(this);
if (ti != null && ti.assign_meth != null)
@ -7463,6 +7508,7 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Call, ti.assign_meth);
return;
}
EmitBox(from, fb.FieldType);
CheckArrayAssign(to, from, il);
il.Emit(OpCodes.Stfld, fb);
@ -7506,7 +7552,8 @@ namespace PascalABCCompiler.NETGenerator
TypeInfo ti = helper.GetTypeReference(to.type);
if (to.type.is_value_type)
{
if (ti.assign_meth != null) il.Emit(OpCodes.Ldarga, pos);
if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type)
il.Emit(OpCodes.Ldarga, pos);
}
else if (to.type.type_special_kind == type_special_kind.set_type)
{
@ -7516,6 +7563,11 @@ namespace PascalABCCompiler.NETGenerator
return;
}
else ti = null;
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
//что присвоить
from.visit(this);
if (ti != null && ti.assign_meth != null)
@ -7523,10 +7575,13 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Call, ti.assign_meth);
return;
}
BoxAssignToParameter(to, from);
//il.Emit(OpCodes.Dup);
if (pos <= 255) il.Emit(OpCodes.Starg_S, pos);
else il.Emit(OpCodes.Starg, pos);
if (pos <= 255)
il.Emit(OpCodes.Starg_S, pos);
else
il.Emit(OpCodes.Starg, pos);
}
else
{
@ -7542,6 +7597,12 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Call, ti.assign_meth);
return;
}
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Ldarg, pos);
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
}
else if (to.type.type_special_kind == type_special_kind.set_type)
{
@ -7578,7 +7639,8 @@ namespace PascalABCCompiler.NETGenerator
if (to.type.is_value_type)
{
//ti = helper.GetTypeReference(to.type);
if (ti.assign_meth != null) il.Emit(OpCodes.Ldflda, fb);
if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type)
il.Emit(OpCodes.Ldflda, fb);
}
else if (to.type.type_special_kind == type_special_kind.set_type)
{
@ -7588,6 +7650,11 @@ namespace PascalABCCompiler.NETGenerator
return;
}
else ti = null;
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
//что присвоить
from.visit(this);
if (ti != null && ti.assign_meth != null)
@ -7595,6 +7662,7 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Call, ti.assign_meth);
return;
}
BoxAssignToParameter(to, from);
//il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Stfld, fb);
@ -7612,6 +7680,11 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Call, ti.assign_meth);
return;
}
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
}
else if (to.type.type_special_kind == type_special_kind.set_type)
{
@ -7648,7 +7721,7 @@ namespace PascalABCCompiler.NETGenerator
TypeInfo ti = helper.GetTypeReference(to.type);
if (to.type.is_value_type)
{
if (ti.assign_meth != null)
if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type)
il.Emit(OpCodes.Ldflda, fi);
}
else if (to.type.type_special_kind == type_special_kind.set_type && !in_var_init)
@ -7659,6 +7732,11 @@ namespace PascalABCCompiler.NETGenerator
return;
}
else ti = null;
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
//что присвоить
from.visit(this);
if (ti != null && ti.assign_meth != null)
@ -7677,6 +7755,7 @@ namespace PascalABCCompiler.NETGenerator
}
return;
}
EmitBox(from, fi_info.field_type);
CheckArrayAssign(to, from, il);
il.Emit(OpCodes.Stfld, fi);
@ -7699,7 +7778,8 @@ namespace PascalABCCompiler.NETGenerator
if (to.type.is_value_type)
{
//ti = helper.GetTypeReference(to.type);
if (ti.assign_meth != null) il.Emit(OpCodes.Ldsflda, fi);
if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type)
il.Emit(OpCodes.Ldsflda, fi);
}
else if (to.type.type_special_kind == type_special_kind.set_type)
{
@ -7709,6 +7789,11 @@ namespace PascalABCCompiler.NETGenerator
return;
}
else ti = null;
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, ti.tp);
return;
}
//что присвоить
from.visit(this);
if (ti != null && ti.assign_meth != null)
@ -7716,6 +7801,7 @@ namespace PascalABCCompiler.NETGenerator
il.Emit(OpCodes.Call, ti.assign_meth);
return;
}
EmitBox(from, fi.FieldType);
CheckArrayAssign(to, from, il);
il.Emit(OpCodes.Stsfld, fi);
@ -7794,12 +7880,10 @@ namespace PascalABCCompiler.NETGenerator
for (int i = 0; i < value.indices.Length; i++)
value.indices[i].visit(this);
}
if (elem_type.IsValueType == true && TypeFactory.IsStandType(elem_type) == false && !TypeIsEnum(elem_type))
if (elem_type.IsValueType && !TypeFactory.IsStandType(elem_type) && !TypeIsEnum(elem_type) || to.type.is_nullable_type)
{
if (value.indices == null)
il.Emit(OpCodes.Ldelema, elem_type);
//else
// il.Emit(OpCodes.Call, addr_meth);
}
else if (elem_ti != null && elem_ti.assign_meth != null)
{
@ -7808,6 +7892,11 @@ namespace PascalABCCompiler.NETGenerator
else
il.Emit(OpCodes.Call, get_meth);
}
if (from is INullConstantNode && to.type.is_nullable_type)
{
il.Emit(OpCodes.Initobj, elem_ti.tp);
return;
}
from.visit(this);
if (elem_ti != null && elem_ti.assign_meth != null)
{
@ -8258,6 +8347,43 @@ namespace PascalABCCompiler.NETGenerator
case basic_function_type.booldec:
case basic_function_type.cdec: ConvertDec(real_parameters[0]); return;
}
if (real_parameters.Length > 1)
{
if (real_parameters[0].type.is_nullable_type && real_parameters[1] is INullConstantNode)
{
bool tmp = is_dot_expr;
is_dot_expr = true;
TypeInfo ti = helper.GetTypeReference(real_parameters[0].type);
real_parameters[0].visit(this);
is_dot_expr = tmp;
MethodInfo mi = null;
if (real_parameters[0].type is IGenericTypeInstance)
mi = TypeBuilder.GetMethod(ti.tp, typeof(Nullable<>).GetMethod("get_HasValue"));
else
mi = ti.tp.GetMethod("get_HasValue");
il.Emit(OpCodes.Call, mi);
if (ft == basic_function_type.objeq)
il.Emit(OpCodes.Not);
return;
}
else if (real_parameters[1].type.is_nullable_type && real_parameters[0] is INullConstantNode)
{
bool tmp = is_dot_expr;
is_dot_expr = true;
TypeInfo ti = helper.GetTypeReference(real_parameters[1].type);
real_parameters[1].visit(this);
is_dot_expr = tmp;
MethodInfo mi = null;
if (real_parameters[1].type is IGenericTypeInstance)
mi = TypeBuilder.GetMethod(ti.tp, typeof(Nullable<>).GetMethod("get_HasValue"));
else
mi = ti.tp.GetMethod("get_HasValue");
il.Emit(OpCodes.Call, mi);
if (ft == basic_function_type.objeq)
il.Emit(OpCodes.Not);
return;
}
}
real_parameters[0].visit(this);
if (real_parameters.Length > 1)
real_parameters[1].visit(this);
@ -9138,8 +9264,8 @@ namespace PascalABCCompiler.NETGenerator
is_dot_expr = false;
bool need_fee = false;
bool is_comp_gen = false;
for (int i = 0; i < real_parameters.Length; i++)
EmitArguments(parameters, real_parameters);
/*for (int i = 0; i < real_parameters.Length; i++)
{
if (parameters[i].parameter_type == parameter_type.var)
is_addr = true;
@ -9175,7 +9301,7 @@ namespace PascalABCCompiler.NETGenerator
if (box_awaited)
il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp);
is_addr = false;
}
}*/
/*if (save_debug_info && need_fee)
{
MarkSequencePoint(il, value.Location);
@ -9255,7 +9381,8 @@ namespace PascalABCCompiler.NETGenerator
//\ssyy
is_dot_expr = false;
for (int i = 0; i < real_parameters.Length; i++)
EmitArguments(parameters, real_parameters);
/*for (int i = 0; i < real_parameters.Length; i++)
{
if (parameters[i].parameter_type == parameter_type.var)
is_addr = true;
@ -9265,7 +9392,7 @@ namespace PascalABCCompiler.NETGenerator
if (ctn2 != null && !(real_parameters[i] is SemanticTree.INullConstantNode) && value.type != null && (ctn3.is_value_type || ctn3.is_generic_parameter) && ctn2.compiled_type == TypeFactory.ObjectType)
il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp);
is_addr = false;
}
}*/
//ssyy изменил
if (value.new_obj_awaited())
{

View file

@ -477,7 +477,17 @@ namespace VisualPascalABCPlugins
IValue ObjectValue { get; }
object PrimitiveValue { get; }
}
public interface IProcess
{
bool HasExited { get; }
}
public interface IProcessEventArgs
{
IProcess Process { get; }
}
public interface IDebuggerManager
{
bool IsRunning { get; }
@ -491,6 +501,7 @@ namespace VisualPascalABCPlugins
void StepInto();
void StepOver();
void RunToCursor();
event EventHandler<EventArgs> DebuggeeStateChanged;
}
public interface ILanguageManager

View file

@ -166,7 +166,12 @@ namespace PascalABCCompiler.SemanticTree
{
get;
}
bool is_nullable_type
{
get;
}
type_special_kind type_special_kind
{
get;

166
TestSuite/nullable.pas Normal file
View file

@ -0,0 +1,166 @@
type TRec = record
a: integer;
b: real;
end;
type TClass = class
v1: System.Nullable<integer>;
v2: System.Nullable<TRec>;
constructor;
begin
v1 := nil;
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
v2 := nil;
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
procedure Test(v1 : System.Nullable<integer>; v2: System.Nullable<TRec>);
begin
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
end;
type TClass2 = class
class v1: System.Nullable<integer>;
class v2: System.Nullable<TRec>;
class procedure Test;
begin
v1 := nil;
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
v2 := nil;
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
class procedure Test2(v1 : System.Nullable<integer>; v2: System.Nullable<TRec>);
begin
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
end;
procedure Test3(v1 : System.Nullable<integer>; v2: System.Nullable<TRec>);
begin
v1 := nil;
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
v2 := nil;
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
procedure Test4(var v1 : System.Nullable<integer>; var v2: System.Nullable<TRec>);
begin
v1 := nil;
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
v2 := nil;
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
procedure Test2;
begin
var v1 : System.Nullable<integer>;
var v2 : System.Nullable<TRec>;
v1 := nil;
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
v2 := nil;
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
procedure Test;
var
v1 : System.Nullable<integer>;
v2 : System.Nullable<TRec>;
begin
v1 := nil;
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
v2 := nil;
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
procedure Test6;
var
v1 : System.Nullable<integer>;
v2 : System.Nullable<TRec>;
procedure Nested;
begin
v1 := nil;
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
v2 := nil;
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
begin
Nested;
end;
procedure Test5(v1 : System.Nullable<integer>; v2: System.Nullable<TRec>);
begin
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
end;
var
v1 : System.Nullable<integer>;
v2 : System.Nullable<TRec>;
begin
v1 := nil;
assert(v1 = nil);
v1 := 4;
assert(v1 <> nil);
v2 := nil;
assert(v2 = nil);
v2 := new TRec;
assert(v2 <> nil);
Test;
Test2;
var obj := new TClass;
obj.Test(nil, nil);
TClass2.Test;
Test3(v1, v2);
Test4(v1, v2);
v1 := nil;
v2 := nil;
Test5(v1, v2);
Test6;
Test5(nil, nil);
TClass2.Test2(nil, nil);
end.

View file

@ -282,6 +282,10 @@ namespace PascalABCCompiler.TreeRealization
{
return true;
}
else if (tn.is_nullable_type)
{
return true;
}
else
{
return !tn.is_value || tn is null_type_node;

View file

@ -53,7 +53,9 @@ namespace PascalABCCompiler.TreeRealization
}
*/
internal bool is_ref_inited;
internal bool is_nullable_inited;
private bool _is_nullable_type;
public virtual bool IsSealed
{
get { return false; }
@ -64,6 +66,22 @@ namespace PascalABCCompiler.TreeRealization
get { return false; }
}
public bool is_nullable_type
{
get
{
if (is_nullable_inited)
return _is_nullable_type;
string fname = full_name;
if (this is compiled_type_node)
_is_nullable_type = fname != null && fname.StartsWith("System.Nullable");
else if (original_generic != null)
return original_generic.is_nullable_type;
is_nullable_inited = true;
return _is_nullable_type;
}
}
public virtual bool IsInterface
{
get
@ -1734,7 +1752,7 @@ namespace PascalABCCompiler.TreeRealization
public override string full_name {
get
{
if (!string.IsNullOrEmpty(_comprehensive_namespace.namespace_name))
if (_comprehensive_namespace != null && !string.IsNullOrEmpty(_comprehensive_namespace.namespace_name))
return _comprehensive_namespace.namespace_name+"."+_name;
return _name;
}

View file

@ -239,6 +239,42 @@ namespace VisualPascalABC
}
}
public class ProcessDelegator : IProcess
{
private Process process;
public ProcessDelegator(Process process)
{
this.process = process;
}
public bool HasExited
{
get
{
return process.HasExited;
}
}
}
public class ProcessEventArgsDelegator : EventArgs, IProcessEventArgs
{
private ProcessDelegator process;
public ProcessEventArgsDelegator(ProcessDelegator process)
{
this.process = process;
}
public IProcess Process
{
get
{
return process;
}
}
}
/// <summary>
/// Класс для отладки программ
/// </summary>
@ -259,6 +295,7 @@ namespace VisualPascalABC
public string ExeFileName;
public bool show_debug_tabs=true;
public PascalABCCompiler.Parsers.IParser parser = null;
EventHandler<EventArgs> debuggerStateEvent;
public DebugHelper()
{
@ -275,7 +312,20 @@ namespace VisualPascalABC
return debuggedProcess;
}
}
event EventHandler<EventArgs> IDebuggerManager.DebuggeeStateChanged
{
add
{
debuggerStateEvent += value;
}
remove
{
debuggerStateEvent -= value;
}
}
public Breakpoint CurrentBreakpoint
{
get { return currentBreakpoint; }
@ -434,6 +484,8 @@ namespace VisualPascalABC
//if (e.Process.IsPaused)
WorkbenchServiceFactory.DebuggerOperationsService.RefreshPad(new FunctionItem(e.Process.SelectedFunction).SubItems);
workbench.WidgetController.SetStartDebugEnabled();
if (debuggerStateEvent != null)
debuggerStateEvent(this, new ProcessEventArgsDelegator(new ProcessDelegator(this.debuggedProcess)));
}
private void debugBreakpointHit(object sender, BreakpointEventArgs e)

View file

@ -43,7 +43,6 @@ namespace VisualPascalABCPlugins
this.Workbench = Workbench;
VisualEnvironmentCompiler = Workbench.VisualEnvironmentCompiler;
testForm.VisualEnvironmentCompiler = VisualEnvironmentCompiler;
}
public void GetGUI(List<IPluginGUIItem> MenuItems, List<IPluginGUIItem> ToolBarItems)