Mono C # компилятор интерпретирует совершенно корректное выражение как аргумент ошибочного типа - PullRequest
0 голосов
/ 01 ноября 2019

Я работал над созданием своего собственного статически типизированного языка, когда понял, что может быть невозможно различить выражение с помощью оператора < и аргумент типа для класса или метода.

Основная причина этого заключается в том, что, как и в C #, классы не обязательно должны быть объявлены вперед перед использованием, поэтому, когда идентификатор анализируется после <, это может быть либо выражение типа valueA < valueB, либоэто может быть аргумент типа, например valueA<valueB>.

Итак, я подумал, может быть, если есть закрывающий >, то его можно проанализировать как аргумент типа, но потом я вспомнил, что мне нужен мой языкиметь перегрузку операторов, поэтому выражения типа valueA < valueB > (valueC) могут быть совершенно корректными.

Я решил поэкспериментировать с другими языками и обнаружил, что C # наиболее похож на язык, который я пытался создать, и явозможно, сломал его.

Выражение foo < bar > (2) в приведенном ниже коде должно быть совершенно допустимым выражением из-за класса остроумияh перегружены операторы < и >.

Насколько мне известно, выражение должно быть проанализировано как (foo < bar) > (2), но вместо этого я получаю сообщение об ошибке "The variable 'foo' cannot be used with type arguments." Чтобы доказать, что это выражение если будет действительным, я щелкнул по знакам < и >, чтобы выражение выглядело как foo > bar < (2), и эта программа скомпилировала и распечатала в точности то, что вы ожидаете, MainClass+baz.

В этом конкретном примере компилятор, вероятно, мог бы это выяснить, поскольку он знает, что foo является переменной, и мог бы предположить, что < означает выражение, но если бы foo был статическим членом другого класса, тоне может быть никакого различия между выражением < и аргументом типа.

using System;

class MainClass {
  public static void Main (string[] args) {

    baz foo = new baz();

    baz bar = new baz();

    // perfectly valid expression, results in error: The variable `foo' cannot be used with type arguments
    Console.WriteLine(foo < bar > (2));

  }

  class baz {
    public static baz operator<(baz l, baz r) {
      return l;
    }

    public static baz operator>(baz l, baz r) {
      return l;
    }

    public static baz operator<(baz l, int r) {
      return l;
    }

    public static baz operator>(baz l, int r) {
      return l;
    }

  }

  public String toString() {
    return "baz";
  }

}

Мой вопрос: как решить эту проблему в компиляторе C # и других языках?

Я вижу несколько вариантов:

  1. Сообщить об ошибке в неоднозначных ситуациях
  2. Возможно, есть еще какой-то контекст, который можно использовать для устранения этой неоднозначности
  3. C # по существу не работает, и мы должны разработать новый синтаксис для аргументов типа в будущих языках. Если да, то как это должно выглядеть?

Может быть, есть какой-то стандарт на это, но я думаю, что принятие этого было бы просто халатностью, и мы должны по крайней мере пойти с вариантом 1.

1 Ответ

0 голосов
/ 01 ноября 2019

foo - локальная переменная, но вы пытаетесь использовать ее в качестве имени типа класса ...

Поэтому это не совершенно правильное выражение вообще.

Вы не можете написать:

baz foo = new baz();
baz bar = new baz();

Console.WriteLine(foo<bar>(2));

Но вы можете написать:

var instance = baz<int>(2);

Если у вас есть:

class baz<T>
{
}

Здесь вы пытаетесь создатьэкземпляр класса baz с параметром универсального типа int без использования ключевого слова new или, возможно, он был приведен неверно, но компилятор не может знать.

Когда вы определяете класс baz<T>, этото, что называется открытый универсальный тип .

И когда вы создаете экземпляр baz<int>, это то, что называется замкнутый построенный универсальный тип .

Вы пишете код ниже должен быть совершенно корректным выражением из-за класса с перегруженными операторами <и> ...

Но компилятор не может интерпретировать val1 < val2 > (val3) как val1 < val2 && val2 > (val3)как с математическим правилом или как (val1 < val2) > (val3), как вы пишете, вы ожидаете, потому что оператор <>() имеет приоритет над < и >.

Компилятор считает, что вы пытаетесь использовать baz of T, поэтому компилятор выводит ошибку, поскольку компилятор не может выбирать между двумя вариантами, между <>() и < следующий >.

Таким образом, компилятор интерпретирует это как Type<Type>(parameter) и ничего больше.

...