Ошибки PascalABC.NET

А предыдущий код не работает?

Да я, в общем-то, вам на слово верю. Просто у меня были проблемы в более сложных программах. Найду конкретный пример — опубликую.

type CNode<T> = class
  where T: System.IComparable;
  data: T;
  left, right: CNode<T>;
end;
 
(7)procedure Insert<T>(var root: CNode<T>; x: T);
  where T: System.IComparable;
begin
  //..
end;

Program1.pas(7) : Невозможно инстанцировать, так как тип T не реализует интерфейс IComparable

type TA = class
public
  function ToString(): string; override;
  begin
    result := 'meow';
  end;
end;

type TB = class(TA)

end;

begin
  var x := new TB();
  writeln(x);
end.

output: ()

и в чем ошибка?

В первом случае в том, что тип T в строке 7 как раз реализует интерфейс IComparable, а во втором в том, что вывод должен быть meow. TB должен был унаследовать ToString от TA.

Нет, тут нет ошибки. Такова логика writeln - он выводит только публичные поля если в классе (не в предках) не определена ToString.

Да, тут ошибка компилятора. Будем разбираться

Данный код вызывает внутреннюю ошибку компилятора:

unit MyUnit1;

interface

function MyFunc1<T>(x: T): T;
  where T: System.IComparable<T>;

function MyFunc2<T>(x: T): T;
  where T: System.IComparable<T>;

implementation

function MyFunc1<T>(x: T): T;
begin
  Result := x;
end;

function MyFunc2<T>(x: T): T;
begin
  Result := MyFunc1(x);
end;
  
begin
  
end.

Ошибка происходит именно в том случае, когда определены две обобщенные функции с секцией where (где вместо System.IComparable<T> может быть указан любой интерфейс с шаблонным параметром), и одна функция в своем теле вызывает другую (либо вызывает сама себя рекурсивно).

Причем ошибки не происходит, если:

  1. Строки
  where T: System.IComparable<T>;

заменить на

  where T: System.IComparable;
  1. Не определять функции в интерфейсе модуля, а только в реализации, т. е. такой код не приводит к сбою:
unit MyUnit2;

interface

implementation

function MyFunc1<T>(x: T): T;
  where T: System.IComparable<T>;
begin
  Result := x;
end;

function MyFunc2<T>(x: T): T;
  where T: System.IComparable<T>;
begin
  Result := MyFunc1(x);
end;
  
begin
  
end.

Сообщение об ошибке:

23.05.2015 18:00:37
PascalABCCompiler.Core v2.2.0.951 (20.05.2015), debug version
Runtime version: 4.0.30319.34014
OS version: Microsoft Windows NT 6.2.9200.0
Processor count: 2
WorkingSet: 87288 kb
StatesList: 
BeginCompileFile MyUnit1.pas
BeginParsingFile MyUnit1.pas
EndParsingFile MyUnit1.pas
ReadPCUFile PABCSystem.pcu
ReadDLL System.dll
ReadDLL mscorlib.dll
ReadDLL System.Core.dll
ReadDLL System.Numerics.dll
CompileInterface MyUnit1.pas
CompileImplementation MyUnit1.pas
CompilationFinished MyUnit1.pas
Ready

Error[0]: Внутренняя ошибка компилятора в модуле [pabcnetc.exe] :'System.Exception: System.ArgumentOutOfRangeException: Индекс за пределами диапазона. Индекс должен быть положительным числом, а его размер не должен превышать размер коллекции.
Имя параметра: index
   в System.ThrowHelper.ThrowArgumentOutOfRangeException()
   в PascalABCCompiler.TreeRealization.generic_convertions.determine_type(type_node tn, List`1 param_types, Boolean method_param_types)
   в PascalABCCompiler.TreeRealization.generic_convertions.determine_type(type_node tn, List`1 param_types, Boolean method_param_types)
   в PascalABCCompiler.TreeRealization.generic_parameter_eliminations.check_type_list(List`1 tparams, List`1 gpe_list, Boolean method_param_types, Int32& i)
   в PascalABCCompiler.TreeRealization.common_namespace_function_node.get_instance(List`1 param_types, Boolean stop_on_error, location loc)
   в PascalABCCompiler.TreeRealization.generic_convertions.DeduceFunction(function_node func, expressions_list fact, Boolean alone, location loc, List`1 syntax_nodes_parameters)
   в PascalABCCompiler.TreeConverter.convertion_data_and_alghoritms.select_function(expressions_list parameters, SymbolInfo functions, location loc, List`1 syntax_nodes_parameters)
   в PascalABCCompiler.TreeConverter.convertion_data_and_alghoritms.create_full_function_call(expressions_list exprs, SymbolInfo si, location loc, common_type_node converted_type, common_function_node top_function, Boolean allow_procedure)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit_method_call(method_call _method_call)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(method_call _method_call)
   в PascalABCCompiler.TreeConverter.returner.visit(expression expr)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(expression expr)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(assign _assign)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(statement st)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(statement_list _statement_list)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(statement st)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit_program_code(statement_list program_code)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(block _block)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(procedure_definition _procedure_definition)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(declarations _subprogram_definitions)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(implementation_node _implementation_node)
   в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit_implementation(unit_module _unit_module)
   в PascalABCCompiler.TreeConverter.SyntaxTreeToSemanticTreeConverter.CompileImplementation(common_unit_node SemanticUnit, compilation_unit SyntaxUnit, unit_node_list UsedUnits, List`1 ErrorsList, List`1 WarningsList, SyntaxError parser_error, Hashtable bad_nodes, using_namespace_list interface_namespaces, using_namespace_list imlementation_namespaces, Dictionary`2 docs, Boolean debug, Boolean debugging)
   в PascalABCCompiler.Compiler.CompileUnit(unit_node_list Units, unit_or_namespace SyntaxUsesUnit)
   в PascalABCCompiler.Compiler.Compile()'
procedure GenericProceudre<T>(x: T);
begin
  Seq(x).Print(); // Ошибка: нельзя преобразовать тип T к array of T
end;

но, в не generic процедуре всё хорошо

procedure NonGenericProceudre(x: integer);
begin
  Seq(x).Print(); // Ошибки нет
end;

Создаю структуру данных Dictionary.

type
      point = class
        x, y: integer;
      end;
      Dic = Dictionary<string, point>;
    begin
      var d:= new Dic;

Этот Dictionary работает и может быть заполнен значениями, например:

d['key1'] := new point;
d['key1'].x:= 10;
d['key1'].y:= 20;

Но метод удаления по ключу (Remove) не работает:


d.Remove('key1');

Ошибка компиляции:

 Нет перегруженной подпрограммы с таким количеством параметров

Remove можно применить, только если значения Dictionary являются стандартными типами данных, или же array of стандартный тип. Это ошибка, или так и должно быть? Но ведь сама структура Dictionary может быть создана с любым типом значений, почему же именно Remove не работает? Тем более, что “ключевой” тип здесь самый обычный String.

Только что скачал PABC, скопировал код и без проблем его запустил. Никаких ошибок нет. Ключ удаляется.

Обновил версию 966 на последнюю сборку 969 от 30.06.2015. И правда, заработало! Не успеваю уследить за темпами обновлений :smile:

Нет, всё таки есть еще некоторые негоразды с этим Dictionary. Вот объявлен и создан словарь:

type
  point = class
    x,y : integer;
  end;
  
  dic = Dictionary<string, point>;

begin
  var d:= new dic;
  d['key1']:= new point;
  d['key1'].x:= 10;
  d['key1'].y:= 20;

При попытке его обхода циклом foreach

Редактор почему то предполагает, что переменная цикла kv должна иметь поле x (как point). Но это нелепо, что и замечает компилятор:

  foreach var kv in d do
    writeln( kv.x );
x не объявлен в типе KeyValuePair<,>

Резонно, так как kv в данном случае, это пара (key, value) - KeyValuePair, поэтому должен иметь поля key и value. Но при попытке к ним обратиться:

foreach var kv in d do
    writeln( kv.key );

или:

foreach var kv in d do
    writeln( kv.value );

компиляция OK, но во время выполнения:

Ошибка времени выполнения: System.BadImageFormatException: Была сделана попытка загрузить программу, имеющую неверный формат. (Исключение из HRESULT: 0x8007000B)

Обращения сразу к полю x у значения не пропускается даже компилятором:

  foreach var kv in d do
    writeln( kv.value.x );

 x не объявлен в типе

Обойти этот Dictionary можно только по ключам:

  foreach var k in d.Keys do
    writeln( d[k].x );

Вот теперь всё OK и при компиляции и при выполнении.

Что это, недоделки компилятора, или я чего то неправильно понимаю?

Версия программы:

Ошибка не воспроизводится. Давайте по порядку.

Ошибка времени выполнения: System.BadImageFormatException - это самая грозная ошибка. Думаю, она единственная, и система Intellisense по этой причине ничего не может распознать.

Опубликуйте здесь пожалуйста полный код программы, которая при выполнении падает с таким сообщением. В архив приложите pas и exe.

Еще попробуйте в конце программы написать writeln(d); Что получилось?

В архиве программа pas и откомпилированный exe Dictionary_error.zip (8.3 КБ)

Вот программа:

type
  point = class
    x, y: integer;
  end;
  Dic = Dictionary<string, point>;

begin
  var d := new Dic;
  
  d['key1']:= new point; // Один ключ инициализируется для примера
  d['key1'].x:= 10; // если даже исключить эти строки
  d['key1'].y:= 10; // при foreach ошибка будет такая же.
      
  foreach var kv in d do
    writeln(kv.key);
    
  writeln(d); // программа вылетает не доходя до этого оператора
end.

Результат выполнения:

Ошибка времени выполнения: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
Стек:
   at dic_error2.Program.$Main()
   at dic_error2.Program.Main()

Если убрать цикл foreach тогда writeln(d) нормально выводит:

{(key1,dic_error2.point)}

Да, увидели ошибку. Вывод типов неправильно работает. Будем исправлять.

Нет я рано радовался, что заработало. То есть оно временами заработало, но как то очень странно, и причина не в обновлении. Описываю как получить глюк, и как его “устранить”.

Делаем консольную программу:

type
  point = class
    x, y: integer;
  end;
  
  Dic = Dictionary<String, point>;

begin
  var d := new Dic;
  d.remove('key1');
end.

Компилируется нормально.

Теперь делаем новый проект и в файле описания формы в разделе implementation вставляем точно такой же код. Компилируем — всё OK. Сохраняем проект, закрываем среду pascal и открываем проект не через меню, а через файл на диске: Project.pabcproj

Компилируем:

Через меню открываем наше консольное приложение, которое ранее компилировалось, и получаем ту же ошибку в строке d.remove(‘key1’);

Нет перегруженной подпрограммы с таким количеством параметров

Закрываем pascal, открываем консольное приложение через pas файл — и оно опять компилируется! Интересно это только у меня такой глюк, или этот Dictionary больше никому не нужен? Воспроизведено на 3-х компьютерах: windows XP, 7, 10.

Удалите из проекта ссылку на System.Xml.Linq (в нем есть какой-то extension-метод remove, который всю малину портит) и перезапустите среду. Ошибку исправим

Честно говоря, так и думал, что с методами расширений очень скоро начнутся такие проблемы.

1 лайк