2016-11-05 3 views
3

Я получаю ошибку компилятора от Swift 3.0.1, которая меня озадачила. Ошибка указывает, что существует двусмысленность в типе вычислимого свойства, но я не вижу, как это сделать.Неоднозначный вывод типа

У меня есть протокол Generic с домом root. Этот протокол имеет общее ограничение, которое root должно быть подклассом типа Root.

class Root { } 

protocol Generic { 
    associatedtype RootType: Root 
    var root: RootType { get } 
} 

Я тогда определить расширение протокола, который гласит:

Если Generic подкласс Root, вернуть self из root собственности.

Так что в принципе: если это уже Root, вы можете просто переслать self.

extension Generic where Self: Root { 
    var root: Self { 
     return self 
    } 
} 

У меня также есть GenericWrapper класса, который является подклассом Root и оборачивает экземпляр Generic (для выполнения операций Root с Generic прокси-сервером).

class GenericWrapper<T: Generic>: Root { 
    var generic: T 

    init(generic: T) { 
     self.generic = generic 
    } 
} 

Наконец, я определяю Specialised протокол и расширение к ней, что гласит:

Если Specialised реализует Generic, возвращают GenericWrapper из root собственности.

protocol Specialised { } 
extension Specialised where Self: Generic { 
    var root: GenericWrapper<Self> { 
     get { 
      return GenericWrapper(generic: self) 
     } 
    } 
} 

Тогда, когда я пытаюсь реализовать класс, который реализует Generic и Specialised, я получаю эту ошибку.

class SpecialisedImplementation: Generic, Specialised { 
    // errors: 
    // Ambiguous inference of associated type 'RootType': 'GenericWrapper<SpecialisedImplementation>' vs. 'SpecialisedImplementation' 
    // Matching requirement 'root' to this declaration inferred associated type to 'GenericWrapper<SpecialisedImplementation>' 
    // Matching requirement 'root' to this declaration inferred associated type to 'SpecialisedImplementation' 
} 

Причина я запутался потому, что неоднозначность утверждает, что SpecialisedImplementation класс соответствует требованию от расширения к Generic когда Generic: Root, но SpecialisedImplementation не наследует от Root, поэтому он не должен, конечно?

+0

Я открыл ошибку для этого: https://bugs.swift.org/просмотр/SR-3145 –

ответ

1

Я собираюсь с этим быть ошибкой компилятора и открыл bug report. Для тех, кто еще испытывает подобный вопрос, я сумел обойти его, удалив Self требование от Generic расширения:

class Root { } 

protocol Generic { 
    associatedtype RootType: Root 
    var root: RootType { get } 
} 

extension Generic where Self: Root { 
    // =================== 
    // don't use Self here 
    // =================== 
    var root: Root { 
     return self 
    } 
} 

class GenericWrapper<T: Generic>: Root { 
    var generic: T 

    init(generic: T) { 
     self.generic = generic 
    } 
} 

protocol Specialised { } 
extension Specialised where Self: Generic { 
    var root: GenericWrapper<Self> { 
     get { 
      return GenericWrapper(generic: self) 
     } 
    } 
} 

class SpecialisedImplementation: Generic, Specialised { 
    // no errors! 
} 
+0

Я слышал от команды компилятора, что ошибка, с которой я столкнулась, уже исправлена ​​на ветке мастера Swift, поэтому ее следует исправить в будущей версии. –

2

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

Он пытается решить Generic, и приходит к выводу, что не может не предполагая, что SpecialisedImplementation подкласс Root (который не является правдой, но отчаянно пытается найти способ, чтобы заставить его работать). И он пытается сделать работу Specialised, но это может сделать только это, если Generic уже работал, но единственный способ получить Generic - это сделать Root.

Вы хотите, чтобы все, что вы говорите, было истинным одновременно, но это не так уж умно. Он пытается построить его по частям, по одному протоколу за раз, и запутывается. Откройте bugreport на bugs.swift.org.

(Но это также почти наверняка дико слишком сложно, в частности, я бы работать, чтобы избавиться от этого Root класса, если это возможно;. Смешивания протоколов и классов и дженерики все вместе является рецептом для многих очень запутывающих проблем с компилятором.)

+0

Спасибо, Роб. Я согласен, что это ужасно сложно (к сожалению, «Root» отображает класс Foundation в моей абстракции, поэтому я не могу избавиться от него). Мое предположение заключалось в том, что компилятор должен игнорировать первое расширение, хотя, потому что для меня совершенно справедливо реализовать «Generic» и обеспечить реализацию для «var root» в этом классе/структуре. Но как только я предоставляю расширение 'SpecializedImplementation', которое предоставляет предполагаемый' RootType', он запутывается и дает мне ошибку. Несмотря на сложность, я думаю, что я пытаюсь сделать технически _valid_, поэтому я могу открыть ошибку. –