2016-02-07 7 views
2

L'erreur est illustrée ci-après:types Résumé + auto + types dérogatoire type, et erreur « Valeur xxx est pas membre de Component.this.T »

trait Base { type T } 

trait Component { self: Base => 
    override type T <: MyT 

    val factory: Factory 

    trait Factory { def get_t: T } 

    trait MyT { def xxx: Unit } 

    class User { 
    val t: T = factory.get_t 

    def yyy = t.xxx 
    } 
} 

trait ComponentImpl { self: Component => 
    type T = TImpl 

    class TImpl extends MyT { 
    def xxx = println("xxx") 
    } 

    val factory = new Factory { 
    def get_t: T = new TImpl 
    } 
} 

Et je reçois l'erreur:

<console>:26: error: value xxx is not a member of Component.this.T 
     def yyy = t.xxx 

Avec une certaine redondance, je poste aussi l'exemple minimal comme suggéré par @slouc et @Kolmar

trait Base { type T } 

trait MyT { def xxx: Unit } 

trait Component { self: Base => 
    override type T <: MyT 
    val t: T 
    def yyy = t.xxx // error 
} 

Il semble que je Caho t tirer parti de la connaissance partielle, incrémentale donnée par la contrainte.

Ma question ne concerne pas l'approche, plutôt je suis intéressé à comprendre les raisons de l'erreur.

Pour fournir plus de contexte, j'ajouterais aussi que j'ai eu ce problème en essayant de convertir une relation d'héritage en une relation basée sur le type de soi entre deux composants.

+1

Un exemple un peu plus simple: 'trait Base {type T}; classe MyT; trait Component {self: Base => type T <: MyT; implicitement [T <: Kolmar

Répondre

2

Avec l'annotation de type auto que vous dites essentiellement le compilateur que l'auto-référence a un autre type

self: Base 

Si vous devez faire cela avec une expression normale, le seul type auto a maintenant, est Base. D'une certaine façon de type annotations sont traitées comme un cas particulier et de maintenir leur type d'origine aussi bien, le type nous semble réellement obtenir est

Maintenant, en quelque sorte, si vous faites référence à Component.this il semble perdre cette information en cas des membres de type écrasés (ou peut-être l'écrasement est tout simplement le mauvais sens, mais je ne vois aucune explication que ce n'est pas un bug)

maintenant, si vous annoter effectivement ce type le problème disparaît:

trait Component { self: Base with Component => ... } 

Qui montre aussi clairement c'est un bug parce que cela fonctionne très bien:

trait Component { self: Base => 
    val v: Base with Component = self 
} 

Ceci est en fait un bug connu:

https://issues.scala-lang.org/browse/SI-7255?jql=text%20~%20%22override%20self%20type%20abstract%22

+0

merci pour le lien vers le bug – slouc

1

question intéressante. Voici un exemple simplifié:

trait Base { type T } 

trait MyT { def xxx: Unit } 

trait Component { self: Base => 
    override type T <: MyT 
    val t: T 
    def yyy = t.xxx // error 
} 

note trois choses ici:

1.Changing annotation auto de type à l'héritage rend tout fonctionne sur:

trait Component extends Base { 
    override type T <: MyT 
    val t: T 
    def yyy = t.xxx 
} 

méthodes de 2.Overriding de l'auto-type est non problématique:

trait Base { def foo } 

trait Component { self: Base => 
    override def foo = println("foo") 
} 

3.Si, au lieu du type de rétrécissement T nous faisons le béton, le primordial fonctionne:

trait Base { type T } 

trait Component { self: Base => 
    override type T = List[Int] 
    val t: T 
    def yyy = t.reverse 
} 

Alors, ma formulation de la question serait - comment se fait qu'en cas de succession les trois cas fonctionnent très bien (1 primordial méthode, 2. membre abstrait du type abstrait en se rétrécissant, 3. membre abstrait du type abstrait en le rendant concret), mais en cas de self-types, le deuxième cas est problématique, alors que les deux autres fonctionnent bien?

Envisagez de modifier votre question (suppression de ComponentImpl, Factory etc.) pour simplifier pour d'autres lecteurs.