Скалярное сообщение об ошибке закрывающей фигурной скобки со странным номером строки
Поскольку я изучал Scala, мне часто вспоминают g++
ошибки компилятора при чтении загадочного вывода из scalac
, Однако сегодня я столкнулся с чем-то, что, я сомневаюсь, случится даже в g++
Вселенная.
Друг прислал мне очень простой фрагмент кода с довольно распространенной ошибкой:
case class Var(name: String) extends ArithExpr {
override def eval(env: Env) = env.lookup(name) match {
case Some(d) => d
case None => throw new IllegalArgumentException("Env " + env + " does not contain a binding for " + name)
}
override def exprString = name
// } // <-- MISSING THIS BRACE
Полный исходный файл размещен здесь. Так как case class Var
в объявлении класса отсутствует закрывающая фигурная скобка, вы можете подумать, что компилятор скажет вам, что в открывающей фигурной скобке для этого объявления (в строке 11) отсутствует закрывающая фигурная скобка. Тем не мение, scalac
сообщает, что он "предполагает" отсутствие закрывающей скобки в середине предыдущего case class
декларация (в строке 7). (Полный вывод ошибок включен внизу размещенного кода.)
Наиболее scalac
Сообщения об ошибках имеют смысл, если вы понимаете внутренности языка, но я в полном недоумении. Как пропущенная закрывающая фигурная скобка в более позднем объявлении класса приводит к распространению ранее успешно проанализированного определения класса в файле?
Как, черт возьми, вы объясняете это новичку в Scala? Оставить закрывающую скобку - это именно та ошибка, которую обычно совершает кто-то новичок в Scala, но здесь появляется сообщение об ошибке, которое может привести пользователя в такое замешательство, что, вероятно, будет полезнее просто сообщить что-то вроде error: you seem to be missing a '}' somewhere
вместо.
Примечание: я знаю, что обычный ответ на такие вопросы - просто "используйте IDE, и пошаговая компиляция сразу же отметит его" или "подсветка синтаксиса должна сделать эту ошибку очевидной", но мой вопрос касается именно scalac
вывод, так что, пожалуйста, имейте в виду, что я знаю, что это правильные точки, но я действительно просто хочу понять, что здесь происходит с компилятором.
Обновить:
Позвольте мне попробовать другой подход к объяснению моей путаницы. Ошибка связана с отсутствующей закрывающей скобкой, поэтому, очевидно, это проблема с вложенностью фигурной скобки. Преобразуя текст (код) во фрагменте, который я разместил, в серию пар строка-номер + фигурные скобки, мы получаем это:
1{ 4}
6{ 9}
11{ 12{ 15}
19{ 22}
24{ 26}
28{ 33}
У нас, очевидно, отсутствует закрывающая скобка. Я мог понять scalac
предположив, что пропавшая фигурная скобка может пойти в любом из этих мест (каждый из которых представлен x
):
1{ 4}
6{ 9}
11{ x 12{ x 15} x <-- HERE OR HERE OR HERE
19{ x 22} x <-- OR HERE OR HERE
24{ x 26} x <-- OR HERE OR HERE
28{ x 33} x <-- OR HERE OR HERE
Тем не менее, это то, что на выходе scalac
говорит:
+----- I THINK YOU ARE MISSING A
| CLOSING BRACE RIGHT HERE!
1{ V 4}
6{ x 9}
11{ 12{ 15}
19{ 22}
24{ 26}
28{ 33}
Эта часть ввода уже хорошо вложена! Как можно добавить еще одну закрывающую скобку?
Редактировать: я чувствую, что должен повторить свой главный вопрос еще раз: как бы вы объяснили это сообщение об ошибке (и как найти корень ошибки в источнике) новичку в Scala?
2 ответа
Следуя предложению Йорга В. Миттага в его комментарии к моему вопросу, я снова открыл старый тикет в трекере проблем Scala: Confused Unmatched ошибки закрывающей скобки. Я добавил код из этого вопроса в качестве нового, короткого, воспроизводимого примера этого класса запутанных сообщений об ошибках.
Рассмотрим следующий пример (я специально удалил отступы):
case class Foo( i: Int ) {
case class Bar( d: Double ) {
def get = d
}
Он не компилируется, но есть несколько возможных правильных кодов:
case class Foo( i: Int ) {
}
case class Bar( d: Double ) {
def get = d
}
//OR
case class Foo( i: Int ) {
case class Bar( d: Double ) {
def get = d
}
}
//OR even (still won't compile but the structure is correct so the compiler will proceed with
//another error)
case class Foo( i: Int ) {
case class Bar( d: Double ) { }
def get = d
}
Так как же компилятору угадать, какая версия верна? В этом случае он выбирает первое местоположение, которое может иметь смысл:
hello.scala:3: error: Missing closing brace `}' assumed here
def get = d
Что соответствует третьему варианту.