Ответ 1
Я прочитал не менее 20 статей и нашел один (Francois Pottier: Тип вывода в присутствии подтипинга: от теории к практике), который я мог бы использовать:
Input:
Type = { TypeVariable, ConcreteType }
TypeRelation = { Left: Type, Right: Type }
TypeRelations = Deque<TypeRelation>
Вспомогательные функции:
ExtendsOrEquals = #(ConcreteType, ConcreteType) => Boolean
Union = #(ConcreteType, ConcreteType) => ConcreteType | fail
Intersection = #(ConcreteType, ConcreteType) => ConcreteType
SubC = #(Type, Type) => List<TypeRelation>
ExtendsOrEquals может рассказать о двух конкретных типах, если первый расширяет или равен второму, например (String, Object) == true, (Object, String) == false.
Союз вычисляет общий подтип двух конкретных типов, если это возможно, например, (Object, Serializable) == Object & Serializable, (Integer, String) == null.
Пересечение вычисляет ближайший супертип двух конкретных типов, например, (List, Set) == Collection, (Integer, String) == Object.
SubC - это структурная функция декомпозиции, которая в этом простом случае просто вернет одноэлементный список, содержащий новое TypeRelation его параметров.
Структуры отслеживания:
UpperBounds = Map<TypeVariable, Set<Type>>
LowerBounds = Map<TypeVariable, Set<Type>>
Reflexives = List<TypeRelation>
UpperBounds отслеживает типы, которые могут быть супертипами переменной типа, LowerBounds отслеживает типы, которые могут быть подтипами переменной типа. Reflexives отслеживает отношения между переменными типа пары, чтобы помочь в переписывании алгоритма.
Алгоритм выглядит следующим образом:
While TypeRelations is not empty, take a relation rel
[Case 1] If rel is (left: TypeVariable, right: TypeVariable) and
Reflexives does not have an entry with (left, right) {
found1 = false;
found2 = false
for each ab in Reflexives
// apply a >= b, b >= c then a >= c rule
if (ab.right == rel.left)
found1 = true
add (ab.left, rel.right) to Reflexives
union and set upper bounds of ab.left
with upper bounds of rel.right
if (ab.left == rel.right)
found2 = true
add (rel.left, ab.right) to Reflexives
intersect and set lower bounds of ab.right
with lower bounds of rel.left
if !found1
union and set upper bounds of rel.left
with upper bounds of rel.right
if !found2
intersect and set lower bounds of rel.right
with lower bounds of rel.left
add TypeRelation(rel.left, rel.right) to Reflexives
for each lb in LowerBounds of rel.left
for each ub in UpperBounds of rel.right
add all SubC(lb, ub) to TypeRelations
}
[Case 2] If rel is (left: TypeVariable, right: ConcreteType) and
UpperBound of rel.left does not contain rel.right {
found = false
for each ab in Reflexives
if (ab.right == rel.left)
found = true
union and set upper bounds of ab.left with rel.right
if !found
union the upper bounds of rel.left with rel.right
for each lb in LowerBounds of rel.left
add all SubC(lb, rel.right) to TypeRelations
}
[Case 3] If rel is (left: ConcreteType, right: TypeVariable) and
LowerBound of rel.right does not contain rel.left {
found = false;
for each ab in Reflexives
if (ab.left == rel.right)
found = true;
intersect and set lower bounds of ab.right with rel.left
if !found
intersect and set lower bounds of rel.right with rel.left
for each ub in UpperBounds of rel.right
add each SubC(rel.left, ub) to TypeRelations
}
[Case 4] if rel is (left: ConcreteType, Right: ConcreteType) and
!ExtendsOrEquals(rel.left, rel.right)
fail
}
Основной пример:
Merge = (T, T) => T
Sink = U => Void
Sink(Merge("String", 1))
Отношения этого выражения:
String >= T
Integer >= T
T >= U
1.) rel is (String, T); Случай 3 активирован. Поскольку Reflexives пуст, LowerBounds of T устанавливается в String. Нет UpperBounds для T, поэтому TypeRelations остается неизменным.
2.) rel is (Integer, T); Случай 3 снова активирован. Reflexives все еще пуст, нижняя граница T установлена на пересечение String и Integer, давая Object, Тем не менее верхние границы для T и никаких изменений в TypeRelations
3.) rel - T >= U. Случай 1 активирован. Поскольку Reflexives пуст, верхние границы T объединены с верхними границами U, который остается пустым. Тогда нижние оценки U задаются нижними границами ot T, что дает Object >= U. TypeRelation (T, U) добавляется к Reflexives.
4.) алгоритм завершается. Из границ Object >= T и Object >= U
В другом примере демонстрируется конфликт типа:
Merge = (T, T) => T
Sink = Integer => Void
Sink(Merge("String", 1))
Отношения:
String >= T
Integer >= T
T >= Integer
Шаги 1.) и 2.) являются такими же, как указано выше.
3.) rel - T >= U. Случай 2 активирован. Случай пытается объединить верхнюю границу T (которая является объектом в этой точке) с Integer, которая терпит неудачу и алгоритм терпит неудачу.
Расширения системы Type
Добавление общих типов в систему типов требует расширения в основных случаях и в функции SubC.
Type = { TypeVariable, ConcreteType, ParametricType<Type,...>)
Некоторые идеи:
- Если встречается ConcreteType и ParametricType, это ошибка.
- Если TypeVariable и ParametricType встречаются, например, T = C (U1,..., Un), то создайте новые переменные типа и отношения как T1 >= U1,..., Tn >= Un и работайте с ними.
- Если два параметра ParametricType встречаются (D < > и C < > ), проверьте, что D >= C и количество аргументов типа одинаковы, а затем извлекайте каждую пару в качестве отношений.