summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/Flags.scala2
-rw-r--r--src/compiler/scala/reflect/internal/Importers.scala2
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala23
-rw-r--r--src/compiler/scala/reflect/internal/TreePrinters.scala2
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala7
-rw-r--r--src/compiler/scala/tools/nsc/ast/NodePrinters.scala524
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala147
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RangePositions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Naming.scala20
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala47
-rw-r--r--src/library/scala/reflect/api/TreePrinters.scala2
-rw-r--r--src/library/scala/reflect/api/Trees.scala25
-rw-r--r--test/files/neg/t3015.check2
-rw-r--r--test/files/neg/t3481.check6
-rw-r--r--test/files/neg/t4515.check2
-rw-r--r--test/files/neg/t5189b.check11
-rw-r--r--test/files/neg/t5189b.scala18
19 files changed, 405 insertions, 441 deletions
diff --git a/src/compiler/scala/reflect/internal/Flags.scala b/src/compiler/scala/reflect/internal/Flags.scala
index 8aae80eed4..3110d73461 100644
--- a/src/compiler/scala/reflect/internal/Flags.scala
+++ b/src/compiler/scala/reflect/internal/Flags.scala
@@ -107,7 +107,7 @@ class ModifierFlags {
// pre: PRIVATE or PROTECTED are also set
final val JAVA = 0x00100000 // symbol was defined by a Java class
final val STATIC = 0x00800000 // static field, method or class
- final val CASEACCESSOR = 0x01000000 // symbol is a case parameter (or its accessor)
+ final val CASEACCESSOR = 0x01000000 // symbol is a case parameter (or its accessor, or a GADT skolem)
final val TRAIT = 0x02000000 // symbol is a trait
final val DEFAULTPARAM = 0x02000000 // the parameter has a default value
final val PARAMACCESSOR = 0x20000000 // for field definitions generated for primary constructor
diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala
index 1003fa804f..04381937d1 100644
--- a/src/compiler/scala/reflect/internal/Importers.scala
+++ b/src/compiler/scala/reflect/internal/Importers.scala
@@ -351,6 +351,8 @@ trait Importers { self: SymbolTable =>
new ApplyToImplicitArgs(importTree(fun), args map importTree)
case _: from.ApplyImplicitView =>
new ApplyImplicitView(importTree(fun), args map importTree)
+ case _: from.ApplyConstructor =>
+ new ApplyConstructor(importTree(fun), args map importTree)
case _ =>
new Apply(importTree(fun), args map importTree)
}
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 9678d2b8cd..907f7d1237 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -269,11 +269,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Create a new existential type skolem with this symbol its owner,
* based on the given symbol and origin.
*/
- def newExistentialSkolem(basis: Symbol, origin: AnyRef, name: TypeName = null, info: Type = null): TypeSkolem = {
- val skolem = newTypeSkolemSymbol(if (name eq null) basis.name.toTypeName else name, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM)
- skolem setInfo (if (info eq null) basis.info cloneInfo skolem else info)
+ def newExistentialSkolem(basis: Symbol, origin: AnyRef): TypeSkolem = {
+ val skolem = newTypeSkolemSymbol(basis.name.toTypeName, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM)
+ skolem setInfo (basis.info cloneInfo skolem)
}
+ // flags set up to maintain TypeSkolem's invariant: origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL)
+ // CASEACCESSOR | SYNTHETIC used to single this symbol out in deskolemizeGADT
+ def newGADTSkolem(name: TypeName, origin: Symbol, info: Type): TypeSkolem =
+ newTypeSkolemSymbol(name, origin, origin.pos, origin.flags & ~(EXISTENTIAL | PARAM) | CASEACCESSOR | SYNTHETIC) setInfo info
+
+
final def newExistential(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol =
newAbstractType(name, pos, EXISTENTIAL | newFlags)
@@ -495,6 +501,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// List[T] forSome { type T }
final def isExistentialSkolem = isExistentiallyBound && isSkolem
final def isExistentialQuantified = isExistentiallyBound && !isSkolem
+ final def isGADTSkolem = isSkolem && hasFlag(CASEACCESSOR | SYNTHETIC)
// class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor
final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR)
@@ -1985,6 +1992,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (isTrait) ("trait", "trait", "TRT")
else if (isClass) ("class", "class", "CLS")
else if (isType) ("type", "type", "TPE")
+ else if (isClassConstructor && isPrimaryConstructor) ("primary constructor", "constructor", "PCTOR")
else if (isClassConstructor) ("constructor", "constructor", "CTOR")
else if (isSourceMethod) ("method", "method", "METH")
else if (isTerm) ("value", "value", "VAL")
@@ -2129,12 +2137,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE
else ExplicitFlags
+ // make the error message more googlable
+ def flagsExplanationString =
+ if (isGADTSkolem) " (this is a GADT skolem)"
+ else ""
+
def accessString = hasFlagsToString(PRIVATE | PROTECTED | LOCAL)
def defaultFlagString = hasFlagsToString(defaultFlagMask)
private def defStringCompose(infoString: String) = compose(
defaultFlagString,
keyString,
- varianceString + nameString + infoString
+ varianceString + nameString + infoString + flagsExplanationString
)
/** String representation of symbol's definition. It uses the
* symbol's raw info to avoid forcing types.
@@ -2477,7 +2490,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* where the skolem was introduced (this is important for knowing when to pack it
* again into ab Existential). origin is `null` only in skolemizeExistentials called
* from <:< or isAsSpecific, because here its value does not matter.
- * I elieve the following invariant holds:
+ * I believe the following invariant holds:
*
* origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL)
*/
diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala
index f823110440..8ed0ee6357 100644
--- a/src/compiler/scala/reflect/internal/TreePrinters.scala
+++ b/src/compiler/scala/reflect/internal/TreePrinters.scala
@@ -433,7 +433,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
/** Hook for extensions */
def xprintTree(treePrinter: TreePrinter, tree: Tree) =
- treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")"))
+ treePrinter.print(tree.printingPrefix+tree.productIterator.mkString("(", ", ", ")"))
def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream))
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 2382413a9a..549c9e4607 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -1041,8 +1041,8 @@ trait Types extends api.Types { self: SymbolTable =>
baseClasses.head.newOverloaded(this, members.toList)
}
}
- /** The existential skolems and existentially quantified variables which are free in this type */
- def existentialSkolems: List[Symbol] = {
+ /** The (existential or otherwise) skolems and existentially quantified variables which are free in this type */
+ def skolemsExceptMethodTypeParams: List[Symbol] = {
var boundSyms: List[Symbol] = List()
var skolems: List[Symbol] = List()
for (t <- this) {
@@ -1050,7 +1050,8 @@ trait Types extends api.Types { self: SymbolTable =>
case ExistentialType(quantified, qtpe) =>
boundSyms = boundSyms ::: quantified
case TypeRef(_, sym, _) =>
- if ((sym hasFlag EXISTENTIAL) && !(boundSyms contains sym) && !(skolems contains sym))
+ if ((sym.isExistentialSkolem || sym.isGADTSkolem) && // treat GADT skolems like existential skolems
+ !((boundSyms contains sym) || (skolems contains sym)))
skolems = sym :: skolems
case _ =>
}
diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
index 9466d1c1f2..3d4253f941 100644
--- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
@@ -9,14 +9,13 @@ package ast
import compat.Platform.EOL
import symtab.Flags._
-/** The object <code>nodePrinter</code> converts the internal tree
- * representation to a string formatted as a Scala expression.
+/** The object `nodePrinter` converts the internal tree
+ * representation to a string.
*
* @author Stephane Micheloud
- * @version 1.0
+ * @author Paul Phillips
*/
abstract class NodePrinters {
-
val global: Global
import global._
@@ -25,262 +24,293 @@ abstract class NodePrinters {
}
var infolevel = InfoLevel.Quiet
- object nodeToString extends Function1[Tree, String] {
+ def nodeToString: Tree => String =
+ if (sys.props contains "scala.colors") nodeToColorizedString
+ else nodeToRegularString
+
+ object nodeToRegularString extends DefaultPrintAST with (Tree => String) {
+ def apply(tree: Tree) = stringify(tree)
+ }
+
+ object nodeToColorizedString extends ColorPrintAST with (Tree => String) {
+ def apply(tree: Tree) = stringify(tree)
+ }
+
+ trait ColorPrintAST extends DefaultPrintAST {
+ import scala.tools.util.color._
+
+ def keywordColor = Cyan
+ def typeColor = Yellow
+ def termColor = Blue
+ def flagColor = Red
+ def literalColor = Green
+
+ override def showFlags(tree: MemberDef) = "" + (
+ super.showFlags(tree) in flagColor.bright
+ )
+ override def showDefTreeName(tree: DefTree) = "" + (
+ if (tree.name.isTermName) tree.name.decode in termColor.bright
+ else tree.name.decode in typeColor.bright
+ )
+ override def showName(name: Name): String = "" + (
+ if (name == nme.EMPTY || name == tpnme.EMPTY) "<empty>" in keywordColor
+ else if (name.isTermName) name.decode in termColor
+ else name.decode in typeColor
+ )
+ override def showLiteral(lit: Literal) = "" + (
+ super.showLiteral(lit) in literalColor.bright
+ )
+ }
+
+ trait DefaultPrintAST extends PrintAST {
+ def showDefTreeName(tree: DefTree) = showName(tree.name)
+ def showFlags(tree: MemberDef) = flagsToString(tree.symbol.flags | tree.mods.flags)
+ def showLiteral(lit: Literal) = lit.value.escapedStringValue
+ def showTypeTree(tt: TypeTree) = "<tpt>" + showAttributes(tt)
+ def showName(name: Name) = name match {
+ case nme.EMPTY | tpnme.EMPTY => "<empty>"
+ case name => "\"" + name + "\""
+ }
+
+ def showSymbol(tree: Tree): String = {
+ val sym = tree.symbol
+ if (sym == null || sym == NoSymbol) ""
+ else " sym/owner/tpe=%s %s/%s/%s".format(sym.accurateKindString, sym.name, sym.owner, sym.tpe)
+ }
+ def showType(tree: Tree): String = {
+ val tpe = tree.tpe
+ if (tpe == null || tpe == NoType) ""
+ else " tree.tpe=" + tpe
+ }
+
+ def showAttributes(tree: Tree): String = {
+ if (infolevel == InfoLevel.Quiet) ""
+ else {
+ try { showSymbol(tree) + showType(tree) trim }
+ catch { case ex: Throwable => "sym= <error> " + ex.getMessage }
+ }
+ }
+ }
+
+ trait PrintAST {
private val buf = new StringBuilder
+ private var level = 0
- def apply(tree: Tree): String = {
- def traverse(tree: Tree, level: Int, comma: Boolean) {
- def println(s: String) {
- for (i <- 0 until level) buf.append(" ")
- buf.append(s)
- buf.append(EOL)
- }
- def printcln(s: String) {
- for (i <- 0 until level) buf.append(" ")
- buf.append(s)
- if (comma) buf.append(",")
- buf.append(EOL)
- }
- def annotationInfoToString(annot: AnnotationInfo): String = {
- val str = new StringBuilder
- str.append(annot.atp.toString())
- if (!annot.args.isEmpty)
- str.append(annot.args.mkString("(", ",", ")"))
- if (!annot.assocs.isEmpty)
- for (((name, value), index) <- annot.assocs.zipWithIndex) {
- if (index > 0)
- str.append(", ")
- str.append(name).append(" = ").append(value)
- }
- str.toString
- }
- def symflags(tree: Tree): String = {
- val buf = new StringBuffer
- val sym = tree.symbol
- buf append flagsToString(sym.flags)
+ def showName(name: Name): String
+ def showDefTreeName(defTree: DefTree): String
+ def showFlags(tree: MemberDef): String
+ def showLiteral(lit: Literal): String
+ def showTypeTree(tt: TypeTree): String
+ def showAttributes(tree: Tree): String // symbol and type
+
+ def showRefTreeName(tree: Tree): String = tree match {
+ case SelectFromTypeTree(qual, name) => showRefTreeName(qual) + "#" + showName(name)
+ case Select(qual, name) => showRefTreeName(qual) + "." + showName(name)
+ case Ident(name) => showName(name)
+ case _ => "" + tree
+ }
+ def showRefTree(tree: RefTree): String = {
+ def prefix0 = showRefTreeName(tree.qualifier)
+ def prefix = if (prefix0 == "") "" else (tree match {
+ case SelectFromTypeTree(_, _) => prefix0 + "#"
+ case Select(_, _) => prefix0 + "."
+ case _ => ""
+ })
+ def attrs = showAttributes(tree) match {
+ case "" => ""
+ case s => " // " + s
+ }
+ prefix + showName(tree.name) + attrs
+ }
+
+ def stringify(tree: Tree): String = {
+ buf.clear()
+ level = 0
+ traverse(tree)
+ buf.toString
+ }
+ def traverseAny(x: Any) {
+ x match {
+ case t: Tree => traverse(t)
+ case xs: List[_] => printMultiline("List", "")(xs foreach traverseAny)
+ case _ => println("" + x)
+ }
+ }
+ def println(s: String) = printLine(s, "")
+
+ def printLine(value: String, comment: String) {
+ buf append " " * level
+ buf append value
+ if (comment != "") {
+ buf append " // "
+ buf append comment
+ }
+ buf append EOL
+ }
- val annots = ", annots=" + (
- if (!sym.annotations.isEmpty)
- sym.annotations.map(annotationInfoToString).mkString("[", ",", "]")
- else
- tree.asInstanceOf[MemberDef].mods.annotations)
- (if (buf.length() > 2) buf.substring(3)
- else "0") + ", // flags=" + flagsToString(sym.flags) + annots
+ def annotationInfoToString(annot: AnnotationInfo): String = {
+ val str = new StringBuilder
+ str.append(annot.atp.toString())
+ if (!annot.args.isEmpty)
+ str.append(annot.args.mkString("(", ",", ")"))
+ if (!annot.assocs.isEmpty)
+ for (((name, value), index) <- annot.assocs.zipWithIndex) {
+ if (index > 0)
+ str.append(", ")
+ str.append(name).append(" = ").append(value)
}
+ str.toString
+ }
+ def printModifiers(tree: MemberDef) {
+ val annots0 = tree.symbol.annotations match {
+ case Nil => tree.mods.annotations
+ case xs => xs map annotationInfoToString
+ }
+ val annots = annots0 match {
+ case Nil => ""
+ case xs => " " + xs.mkString("@{ ", ", ", " }")
+ }
+ val flagString = showFlags(tree) match {
+ case "" => "0"
+ case s => s
+ }
+ println(flagString + annots)
+ }
- def nodeinfo(tree: Tree): String =
- if (infolevel == InfoLevel.Quiet) ""
- else {
- try {
- val buf = new StringBuilder(" // sym=" + tree.symbol)
- if (tree.hasSymbol) {
- if (tree.symbol.isPrimaryConstructor)
- buf.append(", isPrimaryConstructor")
- else if (tree.symbol.isConstructor)
- buf.append(", isConstructor")
- if (tree.symbol != NoSymbol)
- buf.append(", sym.owner=" + tree.symbol.owner)
- buf.append(", sym.tpe=" + tree.symbol.tpe)
- }
- buf.append(", tpe=" + tree.tpe)
- if (tree.tpe != null) {
- var sym = tree.tpe.termSymbol
- if (sym == NoSymbol) sym = tree.tpe.typeSymbol
- buf.append(", tpe.sym=" + sym)
- if (sym != NoSymbol) {
- buf.append(", tpe.sym.owner=" + sym.owner)
- if ((infolevel > InfoLevel.Normal) &&
- !(sym.owner eq definitions.ScalaPackageClass) &&
- !sym.isModuleClass && !sym.isPackageClass &&
- !sym.isJavaDefined) {
- val members = for (m <- tree.tpe.decls)
- yield m.toString() + ": " + m.tpe + ", "
- buf.append(", tpe.decls=" + members)
- }
+ def applyCommon(tree: Tree, fun: Tree, args: List[Tree]) {
+ printMultiline(tree) {
+ traverse(fun)
+ traverseList("Nil", _ + " arguments(s)")(args)
+ }
+ }
+
+ def printMultiline(tree: Tree)(body: => Unit) {
+ printMultiline(tree.printingPrefix, showAttributes(tree))(body)
+ }
+ def printMultiline(prefix: String, comment: String)(body: => Unit) {
+ printLine(prefix + "(", comment)
+ indent(body)
+ println(")")
+ }
+ @inline private def indent[T](body: => T): T = {
+ level += 1
+ try body
+ finally level -= 1
+ }
+
+ def traverseList(ifEmpty: String, comment: Int => String)(trees: List[Tree]) {
+ if (trees.isEmpty)
+ println(ifEmpty)
+ else
+ printMultiline("List", comment(trees.length))(trees foreach traverse)
+ }
+
+ def traverse(tree: Tree) {
+ tree match {
+ case AppliedTypeTree(tpt, args) => applyCommon(tree, tpt, args)
+ case ApplyDynamic(fun, args) => applyCommon(tree, fun, args)
+ case Apply(fun, args) => applyCommon(tree, fun, args)
+
+ case Block(stats, expr) =>
+ printMultiline(tree) {
+ traverseList("{}", _ + " statement(s)")(stats)
+ traverse(expr)
+ }
+ case cd @ ClassDef(mods, name, tparams, impl) =>
+ printMultiline(tree) {
+ printModifiers(cd)
+ println(showDefTreeName(cd))
+ traverseList("[]", _ + " type parameter(s)")(tparams)
+ traverse(impl)
+ }
+ case md @ ModuleDef(mods, name, impl) =>
+ printMultiline(tree) {
+ printModifiers(md)
+ println(showDefTreeName(md))
+ traverse(impl)
+ }
+ case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ printMultiline(tree) {
+ printModifiers(dd)
+ println(showDefTreeName(dd))
+ traverseList("[]", _ + " type parameter(s)")(tparams)
+ vparamss match {
+ case Nil => println("Nil")
+ case Nil :: Nil => println("List(Nil)")
+ case xss =>
+ printMultiline("List", xss.length + " parameter list(s)") {
+ xss foreach (xs => traverseList("()", _ + " parameter(s)")(xs))
}
+ }
+ traverse(tpt)
+ traverse(rhs)
+ }
+ case EmptyTree =>
+ println(showName(nme.EMPTY))
+ case lit @ Literal(value) =>
+ println(showLiteral(lit))
+ case New(tpt) =>
+ printMultiline(tree)(traverse(tpt))
+ case Super(This(qual), mix) =>
+ println("Super(This(" + showName(qual) + "), " + showName(mix) + ")")
+ case Super(qual, mix) =>
+ printMultiline(tree) {
+ traverse(qual)
+ showName(mix)
+ }
+ case Template(parents, self, body) =>
+ printMultiline(tree) {
+ val ps0 = parents map { p =>
+ if (p.tpe eq null) p match {
+ case x: RefTree => showRefTree(x)
+ case x => "" + x
}
- buf.toString
- } catch {
- case ex: Throwable =>
- return " // sym= <error> " + ex.getMessage
+ else showName(newTypeName(p.tpe.typeSymbol.fullName))
}
+ printLine(ps0 mkString ", ", "parents")
+ traverse(self)
+ traverseList("{}", _ + " statements in body")(body)
}
- def nodeinfo2(tree: Tree): String =
- (if (comma) "," else "") + nodeinfo(tree)
-
- def applyCommon(name: String, tree: Tree, fun: Tree, args: List[Tree]) {
- println(name + "(" + nodeinfo(tree))
- traverse(fun, level + 1, true)
- if (args.isEmpty)
- println(" Nil // no argument")
- else {
- val n = args.length
- println(" List( // " + n + " arguments(s)")
- for (i <- 0 until n)
- traverse(args(i), level + 2, i < n-1)
- println(" )")
+ case This(qual) =>
+ println("This(\"" + showName(qual) + "\")" + showAttributes(tree))
+ case TypeApply(fun, args) =>
+ printMultiline(tree) {
+ traverse(fun)
+ traverseList("[]", _ + " type argument(s)")(args)
}
- printcln(")")
- }
+ case tt @ TypeTree() =>
+ println(showTypeTree(tt))
- tree match {
- case AppliedTypeTree(tpt, args) => applyCommon("AppliedTypeTree", tree, tpt, args)
- case Apply(fun, args) => applyCommon("Apply", tree, fun, args)
- case ApplyDynamic(fun, args) => applyCommon("ApplyDynamic", tree, fun, args)
+ case Typed(expr, tpt) =>
+ printMultiline(tree) {
+ traverse(expr)
+ traverse(tpt)
+ }
+ case vd @ ValDef(mods, name, tpt, rhs) =>
+ printMultiline(tree) {
+ printModifiers(vd)
+ println(showDefTreeName(vd))
+ traverse(tpt)
+ traverse(rhs)
+ }
+ case td @ TypeDef(mods, name, tparams, rhs) =>
+ printMultiline(tree) {
+ printModifiers(td)
+ println(showDefTreeName(td))
+ traverseList("[]", _ + " type parameter(s)")(tparams)
+ traverse(rhs)
+ }
+
+ case PackageDef(pid, stats) =>
+ printMultiline("PackageDef", "")(pid :: stats foreach traverse)
- case Block(stats, expr) =>
- println("Block(" + nodeinfo(tree))
- if (stats.isEmpty)
- println(" List(), // no statement")
- else {
- val n = stats.length
- println(" List( // " + n + " statement(s)")
- for (i <- 0 until n)
- traverse(stats(i), level + 2, i < n-1)
- println(" ),")
- }
- traverse(expr, level + 1, false)
- printcln(")")
- case ClassDef(mods, name, tparams, impl) =>
- println("ClassDef(" + nodeinfo(tree))
- println(" " + symflags(tree))
- println(" \"" + name + "\",")
- if (tparams.isEmpty)
- println(" List(), // no type parameter")
- else {
- val n = tparams.length
- println(" List( // " + n + " type parameter(s)")
- for (i <- 0 until n)
- traverse(tparams(i), level + 2, i < n-1)
- println(" ),")
- }
- traverse(impl, level + 1, false)
- printcln(")")
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- println("DefDef(" + nodeinfo(tree))
- println(" " + symflags(tree))
- println(" \"" + name + "\",")
- if (tparams.isEmpty)
- println(" List(), // no type parameter")
- else {
- val n = tparams.length
- println(" List( // " + n + " type parameter(s)")
- for (i <- 0 until n)
- traverse(tparams(i), level + 2, i < n-1)
- println(" ),")
- }
- val n = vparamss.length
- if (n == 1 && vparamss(0).isEmpty)
- println(" List(List()), // no parameter")
- else {
- println(" List(")
- for (i <- 0 until n) {
- val m = vparamss(i).length
- println(" List( // " + m + " parameter(s)")
- for (j <- 0 until m)
- traverse(vparamss(i)(j), level + 3, j < m-1)
- println(" )")
- }
- println(" ),")
- }
- println(" " + tpt + ",")
- traverse(rhs, level + 1, false)
- printcln(")")
- case EmptyTree =>
- printcln("EmptyTree")
- case Ident(name) =>
- printcln("Ident(\"" + name + "\")" + nodeinfo2(tree))
- case Literal(value) =>
- printcln("Literal(" + value + ")")
- case New(tpt) =>
- println("New(" + nodeinfo(tree))
- traverse(tpt, level + 1, false)
- printcln(")")
- case Select(qualifier, selector) =>
- println("Select(" + nodeinfo(tree))
- traverse(qualifier, level + 1, true)
- printcln(" \"" + selector + "\")")
- case Super(qual, mix) =>
- println("Super(\"" + mix + "\")" + nodeinfo(tree))
- traverse(qual, level + 1, true)
- case Template(parents, self, body) =>
- println("Template(" + nodeinfo(tree))
- println(" " + parents.map(p =>
- if (p.tpe ne null) p.tpe.typeSymbol else "null-" + p
- ) + ", // parents")
- traverse(self, level + 1, true)
- if (body.isEmpty)
- println(" List() // no body")
- else {
- val n = body.length
- println(" List( // body")
- for (i <- 0 until n)
- traverse(body(i), level + 2, i < n-1)
- println(" )")
- }
- printcln(")")
- case This(qual) =>
- println("This(\"" + qual + "\")" + nodeinfo2(tree))
- case TypeApply(fun, args) =>
- println("TypeApply(" + nodeinfo(tree))
- traverse(fun, level + 1, true)
- if (args.isEmpty)
- println(" List() // no argument")
- else {
- val n = args.length
- println(" List(")
- for (i <- 0 until n)
- traverse(args(i), level + 1, i < n-1)
- println(" )")
- }
- printcln(")")
- case TypeTree() =>
- printcln("TypeTree()" + nodeinfo2(tree))
- case Typed(expr, tpt) =>
- println("Typed(" + nodeinfo(tree))
- traverse(expr, level + 1, true)
- traverse(tpt, level + 1, false)
- printcln(")")
- case ValDef(mods, name, tpt, rhs) =>
- println("ValDef(" + nodeinfo(tree))
- println(" " + symflags(tree))
- println(" \"" + name + "\",")
- traverse(tpt, level + 1, true)
- traverse(rhs, level + 1, false)
- printcln(")")
- case PackageDef(pid, stats) =>
- println("PackageDef(")
- traverse(pid, level + 1, false)
- println(",\n")
- for (stat <- stats)
- traverse(stat, level + 1, false)
- printcln(")")
- case _ =>
- tree match {
- case p: Product =>
- if (p.productArity != 0) {
- println(p.productPrefix+"(")
- for (elem <- (0 until p.productArity) map p.productElement) {
- def printElem(elem: Any, level: Int): Unit = elem match {
- case t: Tree =>
- traverse(t, level, false)
- case xs: List[_] =>
- print("List(")
- for (x <- xs) printElem(x, level+1)
- printcln(")")
- case _ =>
- println(elem.toString)
- }
- printElem(elem, level+1)
- }
- printcln(")")
- } else printcln(p.productPrefix)
- }
- }
+ case _ =>
+ tree match {
+ case t: RefTree => println(showRefTree(t))
+ case t if t.productArity == 0 => println(tree.printingPrefix)
+ case t => printMultiline(tree)(tree.productIterator foreach traverseAny)
+ }
}
- buf setLength 0
- traverse(tree, 0, false)
- buf.toString
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
index c1d6c1a4d4..3302c11127 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
@@ -352,144 +352,17 @@ abstract class TreeBrowsers {
* Tree.
*/
object TreeInfo {
-
/** Return the case class name and the Name, if the node defines one */
- def treeName(t: Tree): (String, Name) = t match {
- case ProgramTree(units) =>
- ("Program", EMPTY)
-
- case UnitTree(unit) =>
- ("CompilationUnit", newTermName("" + unit))
-
- case DocDef(comment, definition) =>
- ("DocDef", EMPTY)
-
- case ClassDef(mods, name, tparams, impl) =>
- ("ClassDef", name)
-
- case PackageDef(packaged, impl) =>
- ("PackageDef", EMPTY)
-
- case ModuleDef(mods, name, impl) =>
- ("ModuleDef", name)
-
- case ValDef(mods, name, tpe, rhs) =>
- ("ValDef", name)
-
- case DefDef(mods, name, tparams, vparams, tpe, rhs) =>
- ("DefDef", name)
-
- case TypeDef(mods, name, tparams, rhs) =>
- ("TypeDef", name)
-
- case Import(expr, selectors) =>
- ("Import", EMPTY)
-
- case CaseDef(pat, guard, body) =>
- ("CaseDef", EMPTY)
-
- case Template(parents, self, body) =>
- ("Template", EMPTY)
-
- case LabelDef(name, params, rhs) =>
- ("LabelDef", name)
-
- case Block(stats, expr) =>
- ("Block", EMPTY)
-
- case Alternative(trees) =>
- ("Alternative", EMPTY)
-
- case Bind(name, rhs) =>
- ("Bind", name)
-
- case UnApply(fun, args) =>
- ("UnApply", EMPTY)
-
- case Match(selector, cases) =>
- ("Visitor", EMPTY)
-
- case Function(vparams, body) =>
- ("Function", EMPTY)
-
- case Assign(lhs, rhs) =>
- ("Assign", EMPTY)
-
- case If(cond, thenp, elsep) =>
- ("If", EMPTY)
-
- case Return(expr) =>
- ("Return", EMPTY)
-
- case Throw(expr) =>
- ("Throw", EMPTY)
-
- case New(init) =>
- ("New", EMPTY)
-
- case Typed(expr, tpe) =>
- ("Typed", EMPTY)
-
- case TypeApply(fun, args) =>
- ("TypeApply", EMPTY)
-
- case Apply(fun, args) =>
- ("Apply", EMPTY)
-
- case ApplyDynamic(qual, args) =>
- ("Apply", EMPTY)
-
- case Super(qualif, mix) =>
- ("Super", newTermName("mix: " + mix))
-
- case This(qualifier) =>
- ("This", qualifier)
-
- case Select(qualifier, selector) =>
- ("Select", selector)
-
- case Ident(name) =>
- ("Ident", name)
-
- case Literal(value) =>
- ("Literal", EMPTY)
-
- case TypeTree() =>
- ("TypeTree", EMPTY)
-
- case Annotated(annot, arg) =>
- ("Annotated", EMPTY)
-
- case SingletonTypeTree(ref) =>
- ("SingletonType", EMPTY)
-
- case SelectFromTypeTree(qualifier, selector) =>
- ("SelectFromType", selector)
-
- case CompoundTypeTree(template) =>
- ("CompoundType", EMPTY)
-
- case AppliedTypeTree(tpe, args) =>
- ("AppliedType", EMPTY)
-
- case TypeBoundsTree(lo, hi) =>
- ("TypeBoundsTree", EMPTY)
-
- case ExistentialTypeTree(tpt, whereClauses) =>
- ("ExistentialTypeTree", EMPTY)
-
- case Try(block, catcher, finalizer) =>
- ("Try", EMPTY)
-
- case EmptyTree =>
- ("Empty", EMPTY)
-
- case ArrayValue(elemtpt, trees) =>
- ("ArrayValue", EMPTY)
-
- case Star(t) =>
- ("Star", EMPTY)
- }
+ def treeName(t: Tree): (String, Name) = ((t.printingPrefix, t match {
+ case UnitTree(unit) => newTermName("" + unit)
+ case Super(_, mix) => newTermName("mix: " + mix)
+ case This(qual) => qual
+ case Select(_, selector) => selector
+ case Ident(name) => name
+ case SelectFromTypeTree(_, selector) => selector
+ case x: DefTree => x.name
+ case _ => EMPTY
+ }))
/** Return a list of children for the given tree node */
def children(t: Tree): List[Tree] = t match {
diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
index d08a363a9d..88e3827403 100644
--- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
+++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
@@ -189,7 +189,7 @@ self: scala.tools.nsc.Global =>
override def validatePositions(tree: Tree) {
def reportTree(prefix : String, tree : Tree) {
val source = if (tree.pos.isDefined) tree.pos.source else ""
- inform("== "+prefix+" tree ["+tree.id+"] of type "+tree.productPrefix+" at "+tree.pos.show+source)
+ inform("== "+prefix+" tree ["+tree.id+"] of type "+tree.printingPrefix+" at "+tree.pos.show+source)
inform("")
inform(treeStatus(tree))
inform("")
diff --git a/src/compiler/scala/tools/nsc/interpreter/Naming.scala b/src/compiler/scala/tools/nsc/interpreter/Naming.scala
index 8e215cf63b..19266442cb 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Naming.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Naming.scala
@@ -11,16 +11,18 @@ package interpreter
*/
trait Naming {
def unmangle(str: String): String = {
+ val ESC = '\u001b'
val cleaned = removeIWPackages(removeLineWrapper(str))
- var ctrlChars = 0
- cleaned map { ch =>
- if (ch.isControl && !ch.isWhitespace) {
- ctrlChars += 1
- if (ctrlChars > 5) return "[line elided for control chars: possibly a scala signature]"
- else '?'
- }
- else ch
- }
+ // Looking to exclude binary data which hoses the terminal, but
+ // let through the subset of it we need, like whitespace and also
+ // <ESC> for ansi codes.
+ val binaryChars = cleaned count (ch => ch < 32 && !ch.isWhitespace && ch != ESC)
+ // Lots of binary chars - translate all supposed whitespace into spaces
+ if (binaryChars > 5)
+ cleaned map (ch => if (ch.isWhitespace) ' ' else if (ch < 32) '?' else ch)
+ // Not lots - preserve whitespace and ESC
+ else
+ cleaned map (ch => if (ch.isWhitespace || ch == ESC) ch else if (ch < 32) '?' else ch)
}
// The two name forms this is catching are the two sides of this assignment:
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 8b3bc253fd..a59622d4df 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -1099,7 +1099,7 @@ trait Infer {
// since instantiateTypeVar wants to modify the skolem that corresponds to the method's type parameter,
// and it uses the TypeVar's origin to locate it, deskolemize the existential skolem to the method tparam skolem
// (the existential skolem was created by adaptConstrPattern to introduce the type slack necessary to soundly deal with variant type parameters)
- case skolem if skolem.isExistentialSkolem => freshVar(skolem.deSkolemize.asInstanceOf[TypeSymbol])
+ case skolem if skolem.isGADTSkolem => freshVar(skolem.deSkolemize.asInstanceOf[TypeSymbol])
case p => freshVar(p)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 1434002121..e17a271dd0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -157,7 +157,7 @@ trait TypeDiagnostics {
}
// todo: use also for other error messages
- def existentialContext(tp: Type) = tp.existentialSkolems match {
+ def existentialContext(tp: Type) = tp.skolemsExceptMethodTypeParams match {
case Nil => ""
case xs => " where " + (disambiguate(xs map (_.existentialToString)) mkString ", ")
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 25f3e7af5c..0dd4b37131 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -909,8 +909,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def apply(tp: Type) = mapOver(tp) match {
case TypeRef(NoPrefix, tpSym, Nil) if variance != 0 && tpSym.isTypeParameterOrSkolem && tpSym.owner.isTerm =>
val bounds = if (variance == 1) TypeBounds.upper(tpSym.tpe) else TypeBounds.lower(tpSym.tpe)
- val skolem = context.owner.newExistentialSkolem(tpSym, tpSym, unit.freshTypeName("?"+tpSym.name), bounds)
- // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt)
+ // origin must be the type param so we can deskolemize
+ val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?"+tpSym.name), tpSym, bounds)
+ // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt +" in "+ context.owner +" at "+ context.tree )
skolems += skolem
skolem.tpe
case tp1 => tp1
@@ -928,9 +929,19 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
freeVars foreach ctorContext.scope.enter
newTyper(ctorContext).infer.inferConstructorInstance(tree1, clazz.typeParams, ptSafe)
- // tree1's type-slack skolems will be deskolemized (to the method type parameter skolems)
- // once the containing CaseDef has been type checked (see typedCase)
- tree1
+ // simplify types without losing safety,
+ // so that error messages don't unnecessarily refer to skolems
+ val extrapolate = new ExistentialExtrapolation(freeVars) extrapolate (_: Type)
+ val extrapolated = tree1.tpe match {
+ case MethodType(ctorArgs, res) => // ctorArgs are actually in a covariant position, since this is the type of the subpatterns of the pattern represented by this Apply node
+ ctorArgs foreach (p => p.info = extrapolate(p.info)) // no need to clone, this is OUR method type
+ copyMethodType(tree1.tpe, ctorArgs, extrapolate(res))
+ case tp => tp
+ }
+
+ // once the containing CaseDef has been type checked (see typedCase),
+ // tree1's remaining type-slack skolems will be deskolemized (to the method type parameter skolems)
+ tree1 setType extrapolated
} else {
tree
}
@@ -1095,7 +1106,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val found = tree.tpe
val req = pt
if (!found.isErroneous && !req.isErroneous) {
- if (!context.reportErrors && isPastTyper && req.existentialSkolems.nonEmpty) {
+ if (!context.reportErrors && isPastTyper && req.skolemsExceptMethodTypeParams.nonEmpty) {
// Ignore type errors raised in later phases that are due to mismatching types with existential skolems
// We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
// Here's my hypothsis why this happens. The pattern matcher defines a variable of type
@@ -1112,7 +1123,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
//
// val x = expr
context.unit.warning(tree.pos, "recovering from existential Skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree)
- adapt(tree, mode, deriveTypeWithWildcards(pt.existentialSkolems)(pt))
+ adapt(tree, mode, deriveTypeWithWildcards(pt.skolemsExceptMethodTypeParams)(pt))
} else {
// create an actual error
AdaptTypeError(tree, found, req)
@@ -2112,21 +2123,21 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// body1 = checkNoEscaping.locals(context.scope, pt, body1)
val treeWithSkolems = treeCopy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe
- // undo adaptConstrPattern's evil deeds, as they confuse the old pattern matcher
- // TODO: Paul, can we do the deskolemization lazily in the old pattern matcher
- object deskolemizeOnce extends TypeMap {
- def apply(tp: Type): Type = mapOver(tp) match {
- case TypeRef(pre, sym, args) if sym.isExistentialSkolem && sym.deSkolemize.isSkolem && sym.deSkolemize.owner.isTerm =>
- typeRef(NoPrefix, sym.deSkolemize, args)
- case tp1 => tp1
- }
- }
-
- new TypeMapTreeSubstituter(deskolemizeOnce).traverse(treeWithSkolems)
+ new TypeMapTreeSubstituter(deskolemizeGADTSkolems).traverse(treeWithSkolems)
treeWithSkolems // now without skolems, actually
}
+ // undo adaptConstrPattern's evil deeds, as they confuse the old pattern matcher
+ // the flags are used to avoid accidentally deskolemizing unrelated skolems of skolems
+ object deskolemizeGADTSkolems extends TypeMap {
+ def apply(tp: Type): Type = mapOver(tp) match {
+ case TypeRef(pre, sym, args) if sym.isGADTSkolem =>
+ typeRef(NoPrefix, sym.deSkolemize, args)
+ case tp1 => tp1
+ }
+ }
+
def typedCases(cases: List[CaseDef], pattp: Type, pt: Type): List[CaseDef] =
cases mapConserve { cdef =>
newTyper(context.makeNewScope(cdef, context.owner)).typedCase(cdef, pattp, pt)
diff --git a/src/library/scala/reflect/api/TreePrinters.scala b/src/library/scala/reflect/api/TreePrinters.scala
index 21b55e9c0e..43865915d3 100644
--- a/src/library/scala/reflect/api/TreePrinters.scala
+++ b/src/library/scala/reflect/api/TreePrinters.scala
@@ -41,7 +41,7 @@ trait TreePrinters { self: Universe =>
else if (tree.original != null)
print(".setOriginal(", tree.original, ")")
case tree: Tree =>
- print(tree.productPrefix+"(")
+ print(tree.printingPrefix+"(")
val it = tree.productIterator
while (it.hasNext) {
it.next() match {
diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala
index a355207ff0..a8276dc853 100644
--- a/src/library/scala/reflect/api/Trees.scala
+++ b/src/library/scala/reflect/api/Trees.scala
@@ -76,6 +76,12 @@ trait Trees { self: Universe =>
private[this] var rawpos: Position = NoPosition
+ /** Prefix under which to print this tree type. Defaults to product
+ * prefix (e.g. DefTree) but because that is used in reification
+ * it cannot be altered without breaking reflection.
+ */
+ def printingPrefix = productPrefix
+
def pos = rawpos
def pos_=(pos: Position) = rawpos = pos
def setPos(pos: Position): this.type = { rawpos = pos; this }
@@ -249,6 +255,7 @@ trait Trees { self: Universe =>
* are in DefTrees.
*/
trait RefTree extends SymTree {
+ def qualifier: Tree // empty for Idents
def name: Name
}
@@ -489,16 +496,14 @@ trait Trees { self: Universe =>
/** Factory method for object creation `new tpt(args_1)...(args_n)`
* A `New(t, as)` is expanded to: `(new t).<init>(as)`
*/
- def New(tpt: Tree, argss: List[List[Tree]]): Tree = {
- // todo. we need to expose names in scala.reflect.api
- val superRef: Tree = Select(New(tpt), nme.CONSTRUCTOR)
- if (argss.isEmpty) Apply(superRef, Nil)
- else (superRef /: argss) (Apply)
+ def New(tpt: Tree, argss: List[List[Tree]]): Tree = argss match {
+ case Nil => new ApplyConstructor(tpt, Nil)
+ case xs :: rest => rest.foldLeft(new ApplyConstructor(tpt, xs): Tree)(Apply)
}
/** 0-1 argument list new, based on a type.
*/
def New(tpe: Type, args: Tree*): Tree =
- New(TypeTree(tpe), List(args.toList))
+ new ApplyConstructor(TypeTree(tpe), args.toList)
/** Type annotation, eliminated by explicit outer */
case class Typed(expr: Tree, tpt: Tree)
@@ -537,6 +542,10 @@ trait Trees { self: Universe =>
class ApplyImplicitView(fun: Tree, args: List[Tree]) extends Apply(fun, args)
+ class ApplyConstructor(tpt: Tree, args: List[Tree]) extends Apply(Select(New(tpt), nme.CONSTRUCTOR), args) {
+ override def printingPrefix = "ApplyConstructor"
+ }
+
/** Dynamic value application.
* In a dynamic application q.f(as)
* - q is stored in qual
@@ -575,7 +584,9 @@ trait Trees { self: Universe =>
Select(qualifier, sym.name) setSymbol sym
/** Identifier <name> */
- case class Ident(name: Name) extends RefTree
+ case class Ident(name: Name) extends RefTree {
+ def qualifier: Tree = EmptyTree
+ }
def Ident(name: String): Ident =
Ident(newTermName(name))
diff --git a/test/files/neg/t3015.check b/test/files/neg/t3015.check
index 53221b7ca0..6948392bb0 100644
--- a/test/files/neg/t3015.check
+++ b/test/files/neg/t3015.check
@@ -1,5 +1,5 @@
t3015.scala:7: error: scrutinee is incompatible with pattern type;
- found : _$1 where type +_$1
+ found : _$1
required: String
val b(foo) = "foo"
^
diff --git a/test/files/neg/t3481.check b/test/files/neg/t3481.check
index 48e6ff357b..debe07275b 100644
--- a/test/files/neg/t3481.check
+++ b/test/files/neg/t3481.check
@@ -1,17 +1,17 @@
t3481.scala:5: error: type mismatch;
found : String("hello")
- required: _$1 where type +_$1
+ required: _$1
f[A[Int]]("hello")
^
t3481.scala:11: error: type mismatch;
- found : _$2 where type +_$2
+ found : _$2
required: b.T
(which expands to) _$2
def f[T <: B[_]](a: T#T, b: T) = b.m(a)
^
t3481.scala:12: error: type mismatch;
found : String("Hello")
- required: _$2 where type +_$2
+ required: _$2
f("Hello", new B[Int])
^
t3481.scala:18: error: type mismatch;
diff --git a/test/files/neg/t4515.check b/test/files/neg/t4515.check
index ce5350b35f..a60d16295f 100644
--- a/test/files/neg/t4515.check
+++ b/test/files/neg/t4515.check
@@ -1,6 +1,6 @@
t4515.scala:37: error: type mismatch;
found : _0(in value $anonfun) where type _0(in value $anonfun)
- required: (some other)_0(in value $anonfun) where type +(some other)_0(in value $anonfun)
+ required: (some other)_0(in value $anonfun)
handler.onEvent(target, ctx.getEvent, node, ctx)
^
one error found
diff --git a/test/files/neg/t5189b.check b/test/files/neg/t5189b.check
index 7f78cbb438..46996e96d0 100644
--- a/test/files/neg/t5189b.check
+++ b/test/files/neg/t5189b.check
@@ -1,8 +1,11 @@
-t5189b.scala:25: error: type mismatch;
- found : TestNeg.Wrapped[?T2] where type ?T2 <: T
+t5189b.scala:38: error: type mismatch;
+ found : TestNeg.Wrapped[?T7] where type ?T7 <: T (this is a GADT skolem)
required: TestNeg.Wrapped[T]
-Note: ?T2 <: T, but class Wrapped is invariant in type W.
+Note: ?T7 <: T, but class Wrapped is invariant in type W.
You may wish to define W as +W instead. (SLS 4.5)
case Wrapper/*[_ <: T ]*/(wrapped) => wrapped // : Wrapped[_ <: T], which is a subtype of Wrapped[T] if and only if Wrapped is covariant in its type parameter
^
-one error found
+t5189b.scala:51: error: value foo is not a member of type parameter T
+ case Some(xs) => xs.foo // the error message should not refer to a skolem (testing extrapolation)
+ ^
+two errors found
diff --git a/test/files/neg/t5189b.scala b/test/files/neg/t5189b.scala
index 1750f14084..7c1871dc97 100644
--- a/test/files/neg/t5189b.scala
+++ b/test/files/neg/t5189b.scala
@@ -5,8 +5,21 @@ class TestPos {
def unwrap[T](x: AbsWrapperCov[T]): T = x match {
case Wrapper/*[_ <: T ]*/(x) => x // _ <: T, which is a subtype of T
}
+
+ def unwrapOption[T](x: Option[T]): T = x match {
+ case Some(xs) => xs
+ }
+
+
+ case class Down[+T](x: T)
+ case class Up[-T](f: T => Unit)
+
+ def f1[T](x1: Down[T])(x2: Up[T]) = ((x1, x2)) match {
+ case (Down(x), Up(f)) => f(x)
+ }
}
+
object TestNeg extends App {
class AbsWrapperCov[+A]
case class Wrapper[B](x: Wrapped[B]) extends AbsWrapperCov[B]
@@ -33,6 +46,11 @@ object TestNeg extends App {
// val w = new Wrapped(new A)
// unwrap[Any](Wrapper(w)).cell = new B
// w.cell.imNotAB
+
+ def unwrapOption[T](x: Option[T]): T = x match {
+ case Some(xs) => xs.foo // the error message should not refer to a skolem (testing extrapolation)
+ }
+
}
// class TestPos1 {