Carlos López-Camey
Carlos López-Camey

Reputation: 2515

Expected type of Parser in method "|"

I have the following code being compiled against scala 2.8.0:

import scala.util.parsing.combinator.{syntactical,PackratParsers}
import syntactical.StandardTokenParsers

object MyParser extends StandardTokenParsers with PackratParsers{
  lexical.reserved ++= Set("int","char","boolean")

  lazy val primitiveType:PackratParser[PrimitiveType[_]] = primitiveChar | primitiveInt | primitiveBool

  lazy val primitiveInt:PackratParser[PrimitiveType[Int]] = "int" ^^ { _ => PrimitiveType[Int]() }

  lazy val primitiveChar:PackratParser[PrimitiveType[Char]] = "char" ^^ { _ => PrimitiveType[Char]() }

  lazy val primitiveBool:PackratParser[PrimitiveType[Boolean]] = "boolean" ^^ { _ => PrimitiveType[Boolean]() }
}

object MyParser2 extends StandardTokenParsers with PackratParsers{
  lexical.reserved ++= Set("int","char","boolean")

  lazy val primitiveType:PackratParser[PrimitiveType[_]] =  primitiveChar | primitiveIntOrBool

  lazy val primitiveIntOrBool:PackratParser[PrimitiveType[_]] = "int" ^^ { _ => PrimitiveType[Int]() } | "boolean" ^^ {_ => PrimitiveType[Boolean]()}

  lazy val primitiveChar:PackratParser[PrimitiveType[Char]] = "char" ^^ { _ => PrimitiveType[Char]()} 
}

case class PrimitiveType[T]()

Compiling MyParser1 gives:

error: inferred type arguments  [this.PrimitiveType[_ >: _1 with Boolean <: AnyVal]] do not conform to method |'s type parameter bounds [U >: this.PrimitiveType[_ >: Char with Int <: AnyVal]]

I believe it fails because of the | method type signature, defined as:

def | [U >: T](q: => Parser[U]): Parser[U]

why does U have to be a supertype of T? What should be the return value of "primitiveType"?

Upvotes: 4

Views: 324

Answers (2)

Ben Lings
Ben Lings

Reputation: 29423

You might be better changing your generic case class PrimitiveType[T] to a class hierarchy. The generic type parameters aren't available at runtime, so you won't be able to do much with your parse results...

This would give you the following (untested code now tested):

object MyParser extends StandardTokenParsers with PackratParsers{
  lexical.reserved ++= Set("int","char","boolean")

  lazy val primitiveType:Parser[PrimitiveType] = primitiveChar | primitiveInt | primitiveBool

  lazy val primitiveInt:PackratParser[PrimitiveType] = "int" ^^^ PrimitiveInt

  lazy val primitiveChar:PackratParser[PrimitiveType] = "char" ^^^ PrimitiveChar

  lazy val primitiveBool:PackratParser[PrimitiveType] = "boolean" ^^^ PrimitiveBoolean
}

sealed trait PrimitiveType
case object PrimitiveInt extends PrimitiveType
case object PrimitiveChar extends PrimitiveType
case object PrimitiveBoolean extends PrimitiveType

Upvotes: 3

Stefan Endrullis
Stefan Endrullis

Reputation: 4208

You need to change your last line into

case class PrimitiveType[+T]()

This allows for PrimitiveType[Int] <: PrimitiveType[AnyVal] which is needed when you want to merge the results of PrimitiveType[Boolean] and PrimitiveType[Int] parsers via |.

BTW, I would also suggest to write

PrimitiveType[AnyVal]

instead of

PrimitiveType[_]

since this is more precise in your case.

Upvotes: 5

Related Questions