Вывод типа ведет себя по-разному для аналогичных случаев - PullRequest
1 голос
/ 24 мая 2019

Запуск следующего кода (Dart 2.3) вызывает исключение: type 'List<dynamic>' is not a subtype of type 'List<bool>'

bar() => 0;
foo() => [bar()];

main() {
  var l = [1, 2, 3];
  l = foo();
}

Однако этот слегка измененный пример работает правильно:

main() {
  bar() => 0;
  var l = [1, 2, 3];
  l = [bar()];
}

Как это сделать:

main() {
  bar() => 0;
  foo() => [bar()];
  var l = [1, 2, 3];
  l = foo();
}

Что в алгоритме логического вывода Дарта заставляет эти случаи вести себя по-разному? Похоже, что типы функций foo и bar должны быть довольно легко вывести, так как они всегда возвращают одно и то же значение. Для меня также не очевидно, почему перемещение по сайту объявления функции изменит вывод типа в этих случаях.

Кто-нибудь знает, что здесь происходит?

Ответы [ 2 ]

1 голос
/ 25 мая 2019

Лист Петерсен объясняет это в комментарии к dart-lang / sdk проблема # 33137: вывод типа возвращаемого значения функции :

Это по замыслу. Мы делаем вывод возвращаемых типов нерекурсивных локальных функции (функции, объявленные внутри области видимости другой функции или метод), но для функций и методов верхнего уровня мы не делаем вывод возвращаемые типы (кроме как через вывод переопределения). Причины как следующим образом:

  • Методы и функции верхнего уровня обычно являются частью API программы, и очень важно иметь возможность быстрого считывания API кусок кода. Выполнение метода на основе тела возвращает вывод что понимание подписи API требует прочтения тело метода.
  • Методы и функции верхнего уровня могут быть произвольно взаимно рекурсивными, что делает проблему вывода намного сложнее и более дорогой.

По этим причинам мы не выводим типы возвращаемых значений для функций и методов верхнего уровня. Оставить тип возврата - это просто еще один способ сказать dynamic.

Если вы установите

analyzer:
  strong-mode:
    implicit-dynamic: false

в вашем файле analysis_options.yaml, тогда dartanalyzer сгенерирует ошибки, когда функции верхнего уровня имеют неявный dynamic возвращаемый тип:

  error • Missing return type for 'bar' at example.dart:1:1 • strong_mode_implicit_dynamic_return
  error • Missing return type for 'foo' at example.dart:2:1 • strong_mode_implicit_dynamic_return
0 голосов
/ 25 мая 2019

Похоже, что вложенные функции обрабатываются иначе, чем функции верхнего уровня. Это, вероятно, ошибка. Я получаю следующее от Dartpad на Dart 2.3.1.

foo() => 0;
bar() => [foo()];

main() {
  baz() => 0;
  qux() => [baz()];
  print(foo.runtimeType);
  print(bar.runtimeType);
  print(baz.runtimeType);
  print(qux.runtimeType);
}

// () => dynamic
// () => dynamic
// () => int
// () => List<int>

Объяснение здесь :

Это ожидаемое поведение.Локальные функции используют вывод типа для вывода своего возвращаемого типа, а функции верхнего уровня / уровня класса - нет.

Основная причина различия заключается в том, что функции верхнего уровня и уровня класса существуют на том же уровне, что и функции.объявления типа.Решение циклических зависимостей между типами и функциями становится еще сложнее, если мы также должны анализировать тела функций в то время, когда мы еще даже не знаем сигнатуру классов.

Когда завершен вывод верхнего уровня, мы делаемзнать иерархии типов, и там, где функции верхнего уровня неупорядочены, они могут ссылаться друг на друга произвольным образом, локальные функции линейны и могут зависеть только от глобальных функций или предшествующих локальных функций.Это означает, что мы можем анализировать тело функции локально, чтобы найти тип возвращаемого значения, не обращая внимания ни на что, кроме самого тела и вещей, которые мы уже проанализировали.

...