Manifest and Abstract Type Resolution

I encounter a compiler problem when the compiler needs to solve the manifest for a class with an abstract type parameter. The following snippet shows the problem

trait MyStuff trait SecurityMutatorFactory[X]{ def apply(x1:X,x2:X) } object Example{ trait LEdge[N] { type L1 } type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X]} val a:Manifest[MyEdge[MyStuff]] = implicitly[Manifest[MyEdge[MyStuff]]] } 

As a result, the compiler generates the following type error:

 type mismatch; found : scala.reflect.Manifest[LEdge[MyStuff]] required: Manifest[MyEdge[MyStuff]] Note: LEdge[MyStuff] >: MyEdge[MyStuff], but trait Manifest is invariant in type T. You may wish to investigate a wildcard type such as `_ >: MyEdge[MyStuff]`. (SLS 3.2.10) val a:Manifest[MyEdge[MyStuff]] = implicitly[Manifest[MyEdge[MyStuff]]] 

What happens at the compiler level? ^

+4
source share
2 answers

According to others, the problem arises from

 type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X] } 

Declarations of the form type F[X] = ... represent type synonyms, that is, new names for existing types. They do not create new traits or classes. However, LEdge[X] { type L1 = SecurityMutatorFactory[X] } creates a new anonymous class. So your example is roughly equivalent

 trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] } 

(which you most likely want), but the original definition in the example defines a synonym for an anonymous class instead of defining a new class MyEdge[X] . Thus, in the example, the new class is not actually called MyEdge . When constructing an implicit manifest, the compiler replaces the synonym for the type of the base type, but cannot build a manifest for this, because this type is anonymous.

Replace MyEdge either a standard extension:

 trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] } 

or with a synonym of the usual type:

 type MyEdge[X] = LEdge[X] 

both compiled successfully.

EDIT

Here is the specific reason why generating implicit manifests for anonymous classes fails. In the language, the specification of the expaces type of the BaseType form BaseType { ... } is called refined types. According to the language specification, a manifest for a specified type is simply a manifest of its base class. However, this is not type- Manifest[LEdge[MyStuff]{ type L1 = SecurityMutatorFactory[X] }] because you requested Manifest[LEdge[MyStuff]{ type L1 = SecurityMutatorFactory[X] }] , but the algorithm returns Manifest[LEdge[MyStuff]] . This means that you can create implicit manifests for types with refined types only in contravariant positions. For example, using:

 type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X] } => AnyRef 

in your example allows you to compile it, although this is clearly not what you need.

A complete algorithm for constructing implicit manifests is given at the end of section 7.5 of the language specification. This question falls under paragraph 6:

6) If T is a refined type of T '{R}, a manifest is created for T'. (That is, clarifications are never reflected in the manifest).

+3
source

Well, I'm not so familiar with this pattern:

 type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X]} 

but I tend to consider types defined with the type keyword as aliases (notions) rather than an implementation guarantee ( EDIT more precisely, I believe that type provides guarantees in terms of prototyping / specifying, but that AST / code is not generated until there is no urgent need to replace the pseudonym with the signs / classes on which it is based). Therefore, even if the compiler states in its error message:

 LEdge[MyStuff] >: MyEdge[MyStuff] 

I'm not sure if at the bytecode level it implements MyEdge respectively, with interfaces / methods / etc. Thus, he may not recognize the wanted relationship between LEdge and MyEdge, after all:

 found : scala.reflect.Manifest[LEdge[MyStuff]] required: Manifest[MyEdge[MyStuff]] 

(and is the absence of the scala.reflect. package a hint? (1) )

About your code, how do you use a ? In any case, if your intention is as follows:

 trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] } 

instead it compiles (scala 2.10) ... ( EDIT I just noticed now that dmitry already said this) ... what it does at runtime, I don't know

As a note to the note, Manifest deprecated after scala 2.9; therefore, you can use TypeTag[T] as described in scaladoc.

EDIT:
(1) I suspect the following is happening:
- at the stage of parsing, the compiler literally registers what you specified, that is, the method implicitly should return Manifest[MyEdge[MyStuff]] .
- at the stage of code generation, aliases are β€œconsistent” with their nearest classes or features; if implicitly the result type Manifest[MyEdge[MyStuff]] becomes a scala.reflect.Manifest[LEdge[MyStuff]]]
- due to some restrictions on the type inference involved in Manifest and the type of β€œsmoothing” in the type parameters, however, somehow the specified requirement Manifest[MyEdge[MyStuff]] remains under its original form
- (this is a pure hypothesis because I did not read the scala compiler source code for this answer), on the one hand, the compiler would have the correct AST / code, but the prototype / specification of the method, which is still under its source code / literal form , on the other hand; which does not fit, so it emits an error.

Hope this helps ...

+3
source

Source: https://habr.com/ru/post/1500915/


All Articles