potential bug in the type system?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

potential bug in the type system?

Oscar Forero-2
Hello,

While using version 2.8.0.Beta1 for my dissertation project I hit a problem that I suspect may be a bug (or if not a limitation?)

Here are the classes:

abstract class Value[V, S <: Value[V, _]](protected[coretypes] val value: V) {
 protected[coretypes] def construct(myVal: V): S

 override def hashCode = value.hashCode

 override def equals(other: Any) = other match {
   case other: Value[v, s] if (this.getClass eq other.getClass) => this.value == other.value
   case _ => false
 }
}

abstract class ValueFactory[V, S <: Value[V, _]](implicit n: Numeric[V]) {
 import n._

 val ZERO: S

 protected def construct(myVal: V): S
 def apply(myVal: V): S = if (myVal == 0) ZERO else construct(myVal)
}


trait Addition[V, S <: Value[V, _]] {
 self: Value[V, S] =>
 def +(other: S)(implicit n: Numeric[V]) = {
   import n._
   construct(value + other.value)
 }
}

abstract class Adder[V, S <: Value[V, _]](zero: S) {
 def apply(values: S*)(implicit n: Numeric[V]): S = {
   val sum: V = (zero.value /: values) {
     import n._
     (acc: V, item: S) => acc + item.value
   }
   zero.construct(sum)                                                    <----- This lines does not type check
 }

 def apply(values: Seq[S])(implicit n: Numeric[V]): S = {
   apply(values.toSeq:_*)
 }
}

The compiler complaints that the type of the zero.construct(sum) result is any, but it should be S.
I explicitly typed the method construct to return S (mandatory because it is abstract) why does the compiler think that the type is Any?

Here is the output with the parameters -Xprint:typer -explaintypes, I see the type of construct is S and can't see any reason why it shouldn't compile

[INFO] Compiling 2 source files to /Users/Oscar/Projects/dissertation/implementation/scala.old/scala-valuator-core-types/target/classes at 1269468860083
[ERROR] /Users/Oscar/Projects/dissertation/implementation/scala.old/scala-valuator-core-types/src/main/scala/uk/ac/liv/oforero/coretypes/OpsOnCollections.scala:42: error: type mismatch;
[INFO]  found   : Any
[INFO]  required: S
[INFO]     zero.construct(sum)
[INFO]                   ^
[INFO] Any <: S?
[INFO]   Any <: Nothing?
[INFO]     <notype> <: Nothing?
[INFO]     false
[INFO]   false
[INFO] false
[INFO] [[syntax trees at end of typer]]// Scala source: OpsOnCollections.scala
[INFO] package uk.ac.liv.oforero.coretypes {
[INFO]   abstract class Adder[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends java.lang.Object with ScalaObject {
[INFO]     <paramaccessor> private[this] val zero: S = _;
[INFO]     def this(zero: S): uk.ac.liv.oforero.coretypes.Adder[V,S] = {
[INFO]       Adder.super.this();
[INFO]       ()
[INFO]     };
[INFO]     def apply(values: S*)(implicit n: Numeric[V]): S = {
[INFO]       val sum: V = {
[INFO]         <synthetic> val x$1: V = Adder.this.zero.value;
[INFO]         values./:[V](x$1)({
[INFO]           import n._;
[INFO]           ((acc: V, item: S) => n.mkNumericOps(acc).+(item.value))
[INFO]         })
[INFO]       };
[INFO]       Adder.this.zero.construct(sum)
[INFO]     };
[INFO]     def apply(values: Seq[S])(implicit n: Numeric[V]): S = Adder.this.apply((values.toSeq: _*))(n)
[INFO]   }
[INFO] }
[INFO]
[INFO] // Scala source: ValuesAndOps.scala
[INFO] package uk.ac.liv.oforero.coretypes {
[INFO]   abstract class Value[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends java.lang.Object with ScalaObject {
[INFO]     <paramaccessor> private[this] val value: V = _;
[INFO]     def this(value: V): uk.ac.liv.oforero.coretypes.Value[V,S] = {
[INFO]       Value.super.this();
[INFO]       ()
[INFO]     };
[INFO]     protected[coretypes] def construct(myVal: V): S;
[INFO]     override def hashCode: Int = Value.this.value.hashCode();
[INFO]     override def equals(other: Any): Boolean = other match {
[INFO]       case (other @ (_: uk.ac.liv.oforero.coretypes.Value[v,s])) if this.getClass().eq(other.getClass()) => this.value.==(other.value)
[INFO]       case _ => false
[INFO]     }
[INFO]   };
[INFO]   abstract class ValueFactory[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends java.lang.Object with ScalaObject {
[INFO]     implicit <paramaccessor> private[this] val n: Numeric[V] = _;
[INFO]     def this()(implicit n: Numeric[V]): uk.ac.liv.oforero.coretypes.ValueFactory[V,S] = {
[INFO]       ValueFactory.super.this();
[INFO]       ()
[INFO]     };
[INFO]     import n._;
[INFO]     <stable> <accessor> val ZERO: => S;
[INFO]     protected def construct(myVal: V): S;
[INFO]     def apply(myVal: V): S = if (myVal.==(0))
[INFO]       ValueFactory.this.ZERO
[INFO]     else
[INFO]       ValueFactory.this.construct(myVal)
[INFO]   };
[INFO]   abstract trait Addition[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends java.lang.Object with ScalaObject { self: uk.ac.liv.oforero.coretypes.Addition[V,S] with uk.ac.liv.oforero.coretypes.Value[V,S] =>
[INFO]     def /*Addition*/$init$(): Unit = {
[INFO]       ()
[INFO]     };
[INFO]     def +(other: S)(implicit n: Numeric[V]): S = {
[INFO]       import n._;
[INFO]       Addition.this.construct(n.mkNumericOps(Addition.this.value).+(other.value))
[INFO]     }
[INFO]   };
[INFO]   abstract trait Subtraction[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends java.lang.Object with ScalaObject { self: uk.ac.liv.oforero.coretypes.Subtraction[V,S] with uk.ac.liv.oforero.coretypes.Value[V,S] =>
[INFO]     def /*Subtraction*/$init$(): Unit = {
[INFO]       ()
[INFO]     };
[INFO]     def -(other: S)(implicit n: Numeric[V]): S = {
[INFO]       import n._;
[INFO]       Subtraction.this.construct(n.mkNumericOps(this.value).-(other.value))
[INFO]     }
[INFO]   };
[INFO]   abstract trait AddSub[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends java.lang.Object with uk.ac.liv.oforero.coretypes.Addition[V,S] with uk.ac.liv.oforero.coretypes.Subtraction[V,S] { self: uk.ac.liv.oforero.coretypes.AddSub[V,S] with uk.ac.liv.oforero.coretypes.Value[V,S] =>
[INFO]     <empty>
[INFO]   };
[INFO]   abstract class ValueWithBasicOps[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends uk.ac.liv.oforero.coretypes.Value[V,S] with uk.ac.liv.oforero.coretypes.AddSub[V,S] with ScalaObject { self: uk.ac.liv.oforero.coretypes.ValueWithBasicOps[V,S] with uk.ac.liv.oforero.coretypes.Value[V,S] =>
[INFO]     <paramaccessor> private[this] val value: V = _;
[INFO]     def this(value: V): uk.ac.liv.oforero.coretypes.ValueWithBasicOps[V,S] = {
[INFO]       ValueWithBasicOps.super.this(value);
[INFO]       ()
[INFO]     };
[INFO]     <empty>
[INFO]   };
[INFO]   abstract trait Multiplication[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends java.lang.Object with ScalaObject { self: uk.ac.liv.oforero.coretypes.Multiplication[V,S] with uk.ac.liv.oforero.coretypes.Value[V,S] =>
[INFO]     def /*Multiplication*/$init$(): Unit = {
[INFO]       ()
[INFO]     };
[INFO]     def *(other: S)(implicit n: Numeric[V]): S = {
[INFO]       import n._;
[INFO]       Multiplication.this.construct(n.mkNumericOps(this.value).*(other.value))
[INFO]     }
[INFO]   };
[INFO]   abstract trait Division[V >: Nothing <: Any, S >: Nothing <: uk.ac.liv.oforero.coretypes.Value[V, _]] extends java.lang.Object with ScalaObject { self: uk.ac.liv.oforero.coretypes.Division[V,S] with uk.ac.liv.oforero.coretypes.Value[V,S] =>
[INFO]     def /*Division*/$init$(): Unit = {
[INFO]       ()
[INFO]     };
[INFO]     def /(other: S)(implicit n: Fractional[V]): S = {
[INFO]       import n._;
[INFO]       Division.this.construct(n.mkNumericOps(this.value)./(other.value))
[INFO]     }
[INFO]   }
[INFO] }
[INFO]
[ERROR] one error found

Best regards,

Oscar Forero
Reply | Threaded
Open this post in threaded view
|

Re: potential bug in the type system?

Eric Willigers
Oscar Forero wrote:
> abstract class Value[V, S <: Value[V, _]](protected[coretypes] val value: V) {
>  protected[coretypes] def construct(myVal: V): S

Note the return type of construct is the second type parameter of Value

> abstract class Adder[V, S <: Value[V, _]](zero: S) {

Note the second type parameter of Value is _ i.e. Any

I don't see a type system bug.


Simple compiling code is attached.


/*
abstract class Value[V, S <: Value[V, _]](val value: V) {
    def construct(myVal: V): S
}

abstract class Adder[V, S <: Value[V, _]](zero: S) {
    def sum: V

    def f(): S = {
        // type mismatch
        zero.construct(sum)
    }
}
*/

/*
abstract class Value[V, S <: Value[V, _]](val value: V) {
    def construct(myVal: V): S
}

// illegal cyclic reference involving type S
abstract class Adder[V, S <: Value[V, T] forSome { type T <: S } ](zero: S) {
    def sum: V

    def f(): S = {
        zero.construct(sum)
    }
}
*/

abstract class Value[V, +S <: Value[V, _]](val value: V) {
    def construct(myVal: V): S
}

// illegal cyclic reference involving type S
abstract class Adder[V, S <: Value[V, S]](zero: S) {
    def sum: V

    def f(): S = {
        zero.construct(sum)
    }
}