aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Positioned.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Trees.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala10
-rw-r--r--compiler/src/dotty/tools/dotc/core/TyperState.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala18
-rw-r--r--compiler/src/dotty/tools/dotc/printing/Printer.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Implicits.scala28
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Namer.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala89
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala3
-rw-r--r--tests/pos/f-bounded-case-class.scala1
-rw-r--r--tests/run/generic/Color.scala30
-rw-r--r--tests/run/generic/Enum.scala18
-rw-r--r--tests/run/generic/List.scala89
-rw-r--r--tests/run/generic/SearchResult.scala64
-rw-r--r--tests/run/generic/Serialization.scala115
-rw-r--r--tests/run/generic/Shapes.scala22
-rw-r--r--tests/run/generic/Test.scala72
-rw-r--r--tests/run/generic/Tree.scala113
-rw-r--r--tests/run/t10170.check1
-rw-r--r--tests/run/t10170.scala7
22 files changed, 644 insertions, 64 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Positioned.scala b/compiler/src/dotty/tools/dotc/ast/Positioned.scala
index bb6817603..51949c6fe 100644
--- a/compiler/src/dotty/tools/dotc/ast/Positioned.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Positioned.scala
@@ -123,6 +123,8 @@ abstract class Positioned extends DotClass with Product {
private def unionPos(pos: Position, xs: List[_]): Position = xs match {
case (p: Positioned) :: xs1 => unionPos(pos union p.pos, xs1)
+ case (xs0: List[_]) :: xs1 => unionPos(unionPos(pos, xs0), xs1)
+ case _ :: xs1 => unionPos(pos, xs1)
case _ => pos
}
diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala
index 7ab8de39f..bf11a442e 100644
--- a/compiler/src/dotty/tools/dotc/ast/Trees.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala
@@ -3,7 +3,7 @@ package dotc
package ast
import core._
-import Types._, Names._, Flags._, util.Positions._, Contexts._, Constants._
+import Types._, Names._, NameOps._, Flags._, util.Positions._, Contexts._, Constants._
import SymDenotations._, Symbols._, Denotations._, StdNames._, Comments._
import annotation.tailrec
import language.higherKinds
@@ -316,7 +316,7 @@ object Trees {
def namePos =
if (pos.exists)
if (rawMods.is(Synthetic)) Position(pos.point, pos.point)
- else Position(pos.point, pos.point + name.length, pos.point)
+ else Position(pos.point, pos.point + name.stripModuleClassSuffix.length, pos.point)
else pos
}
diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 42df53fed..3aa20f15b 100644
--- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -79,12 +79,12 @@ trait ConstraintHandling {
if (Config.failOnInstantiationToNothing) assert(false, msg)
else ctx.log(msg)
}
- constr.println(i"adding $description")
+ constr.println(i"adding $description in ${ctx.typerState.hashesStr}")
val lower = constraint.lower(param)
val res =
addOneBound(param, bound, isUpper = true) &&
lower.forall(addOneBound(_, bound, isUpper = true))
- constr.println(i"added $description = $res")
+ constr.println(i"added $description = $res in ${ctx.typerState.hashesStr}")
res
}
@@ -95,7 +95,7 @@ trait ConstraintHandling {
val res =
addOneBound(param, bound, isUpper = false) &&
upper.forall(addOneBound(_, bound, isUpper = false))
- constr.println(i"added $description = $res")
+ constr.println(i"added $description = $res in ${ctx.typerState.hashesStr}")
res
}
@@ -108,12 +108,12 @@ trait ConstraintHandling {
val up2 = p2 :: constraint.exclusiveUpper(p2, p1)
val lo1 = constraint.nonParamBounds(p1).lo
val hi2 = constraint.nonParamBounds(p2).hi
- constr.println(i"adding $description down1 = $down1, up2 = $up2")
+ constr.println(i"adding $description down1 = $down1, up2 = $up2 ${ctx.typerState.hashesStr}")
constraint = constraint.addLess(p1, p2)
down1.forall(addOneBound(_, hi2, isUpper = true)) &&
up2.forall(addOneBound(_, lo1, isUpper = false))
}
- constr.println(i"added $description = $res")
+ constr.println(i"added $description = $res ${ctx.typerState.hashesStr}")
res
}
diff --git a/compiler/src/dotty/tools/dotc/core/TyperState.scala b/compiler/src/dotty/tools/dotc/core/TyperState.scala
index 5c476c1cb..206438d86 100644
--- a/compiler/src/dotty/tools/dotc/core/TyperState.scala
+++ b/compiler/src/dotty/tools/dotc/core/TyperState.scala
@@ -79,6 +79,9 @@ class TyperState(r: Reporter) extends DotClass with Showable {
def tryWithFallback[T](op: => T)(fallback: => T)(implicit ctx: Context): T = unsupported("tryWithFallBack")
override def toText(printer: Printer): Text = "ImmutableTyperState"
+
+ /** A string showing the hashes of all nested mutable typerstates */
+ def hashesStr: String = ""
}
class MutableTyperState(previous: TyperState, r: Reporter, override val isCommittable: Boolean)
@@ -207,4 +210,7 @@ extends TyperState(r) {
}
override def toText(printer: Printer): Text = constraint.toText(printer)
+
+ override def hashesStr: String = hashCode.toString + " -> " + previous.hashesStr
+
}
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index 5ed4fbdd7..3162f61b4 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -1763,12 +1763,8 @@ object Parsers {
TypeTree() // XX-METHOD-INFER
} else {
accept(COLON)
- if (in.token == ARROW) {
- if (owner.isTypeName && !(mods is Local))
- syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name")
- else if (imods.hasFlags)
- syntaxError("implicit parameters may not be call-by-name")
- }
+ if (in.token == ARROW && owner.isTypeName && !(mods is Local))
+ syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name")
paramType()
}
val default =
diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 61f23c214..ac25f7cfd 100644
--- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -6,6 +6,7 @@ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._, De
import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation
import StdNames.{nme, tpnme}
import ast.Trees._, ast._
+import typer.Implicits._
import config.Config
import java.lang.Integer.toOctalString
import config.Config.summarizeDepth
@@ -484,6 +485,23 @@ class PlainPrinter(_ctx: Context) extends Printer {
}
}.close // todo: override in refined printer
+ def toText(result: SearchResult): Text = result match {
+ case result: SearchSuccess =>
+ "SearchSuccess: " ~ toText(result.ref) ~ " via " ~ toText(result.tree)
+ case result: NonMatchingImplicit =>
+ "NoImplicitMatches"
+ case result: DivergingImplicit =>
+ "Diverging Implicit"
+ case result: ShadowedImplicit =>
+ "Shadowed Implicit"
+ case result: FailedImplicit =>
+ "Failed Implicit"
+ case result: AmbiguousImplicits =>
+ "Ambiguous Implicit: " ~ toText(result.alt1) ~ " and " ~ toText(result.alt2)
+ case _ =>
+ "?Unknown Implicit Result?"
+ }
+
private var maxSummarized = Int.MaxValue
def summarized[T](depth: Int)(op: => T): T = {
diff --git a/compiler/src/dotty/tools/dotc/printing/Printer.scala b/compiler/src/dotty/tools/dotc/printing/Printer.scala
index 14b63012e..506773a4b 100644
--- a/compiler/src/dotty/tools/dotc/printing/Printer.scala
+++ b/compiler/src/dotty/tools/dotc/printing/Printer.scala
@@ -5,6 +5,7 @@ import core._
import Texts._, ast.Trees._
import Types.Type, Symbols.Symbol, Contexts.Context, Scopes.Scope, Constants.Constant,
Names.Name, Denotations._, Annotations.Annotation
+import typer.Implicits.SearchResult
/** The base class of all printers
*/
@@ -94,7 +95,10 @@ abstract class Printer {
/** Textual representation of tree */
def toText[T >: Untyped](tree: Tree[T]): Text
- /** Perform string or text-producing operation `op` so that only a
+ /** Textual representation of implicit search result */
+ def toText(result: SearchResult): Text
+
+ /** Perform string or text-producing operation `op` so that only a
* summarized text with given recursion depth is shown
*/
def summarized[T](depth: Int)(op: => T): T
diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
index 592e80048..d4e74cf7d 100644
--- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
@@ -6,7 +6,8 @@ import core._
import ast.{Trees, untpd, tpd, TreeInfo}
import util.Positions._
import util.Stats.{track, record, monitored}
-import printing.Showable
+import printing.{Showable, Printer}
+import printing.Texts._
import Contexts._
import Types._
import Flags._
@@ -68,9 +69,9 @@ object Implicits {
case mt: MethodType =>
mt.isImplicit ||
mt.paramTypes.length != 1 ||
- !(argType relaxed_<:< wildApprox(mt.paramTypes.head)(ctx.fresh.setExploreTyperState))
+ !(argType relaxed_<:< wildApprox(mt.paramTypes.head, null, Set.empty)(ctx.fresh.setExploreTyperState))
case rtp =>
- discardForView(wildApprox(rtp), argType)
+ discardForView(wildApprox(rtp, null, Set.empty), argType)
}
case tpw: TermRef =>
false // can't discard overloaded refs
@@ -219,14 +220,16 @@ object Implicits {
}
/** The result of an implicit search */
- abstract class SearchResult
+ abstract class SearchResult extends Showable {
+ def toText(printer: Printer): Text = printer.toText(this)
+ }
/** A successful search
* @param ref The implicit reference that succeeded
* @param tree The typed tree that needs to be inserted
* @param ctx The context after the implicit search
*/
- case class SearchSuccess(tree: tpd.Tree, ref: TermRef, level: Int, tstate: TyperState) extends SearchResult {
+ case class SearchSuccess(tree: tpd.Tree, ref: TermRef, level: Int, tstate: TyperState) extends SearchResult with Showable {
override def toString = s"SearchSuccess($tree, $ref, $level)"
}
@@ -256,7 +259,7 @@ object Implicits {
}
/** An ambiguous implicits failure */
- class AmbiguousImplicits(alt1: TermRef, alt2: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
+ class AmbiguousImplicits(val alt1: TermRef, val alt2: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
def explanation(implicit ctx: Context): String =
em"both ${err.refStr(alt1)} and ${err.refStr(alt2)} $qualify"
override def postscript(implicit ctx: Context) =
@@ -380,7 +383,9 @@ trait ImplicitRunInfo { self: RunInfo =>
EmptyTermRefSet // on the other hand, the refs of `tp` are now not accurate, so `tp` is marked incomplete.
} else {
seen += t
- iscope(t).companionRefs
+ val is = iscope(t)
+ if (!implicitScopeCache.contains(t)) incomplete += tp
+ is.companionRefs
}
}
@@ -436,10 +441,8 @@ trait ImplicitRunInfo { self: RunInfo =>
if (ctx.typerState.ephemeral)
record("ephemeral cache miss: implicitScope")
else if (canCache &&
- ((tp eq rootTp) || // first type traversed is always cached
- !incomplete.contains(tp) && // other types are cached if they are not incomplete
- result.companionRefs.forall( // and all their companion refs are cached
- implicitScopeCache.contains)))
+ ((tp eq rootTp) || // first type traversed is always cached
+ !incomplete.contains(tp))) // other types are cached if they are not incomplete
implicitScopeCache(tp) = result
result
}
@@ -604,6 +607,7 @@ trait Implicits { self: Typer =>
result match {
case result: SearchSuccess =>
result.tstate.commit()
+ implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} ${ctx.typerState.hashesStr}")
result
case result: AmbiguousImplicits =>
val deepPt = pt.deepenProto
@@ -649,7 +653,7 @@ trait Implicits { self: Typer =>
}
/** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
- val wildProto = implicitProto(pt, wildApprox(_))
+ val wildProto = implicitProto(pt, wildApprox(_, null, Set.empty))
/** Search failures; overridden in ExplainedImplicitSearch */
protected def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]): SearchFailure = NoImplicitMatches
diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala
index 772d9385b..3860ba225 100644
--- a/compiler/src/dotty/tools/dotc/typer/Namer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala
@@ -972,7 +972,7 @@ class Namer { typer: Typer =>
ctx.defContext(sym).denotNamed(original)
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
case params :: paramss1 =>
- if (idx < params.length) wildApprox(params(idx))
+ if (idx < params.length) wildApprox(params(idx), null, Set.empty)
else paramProto(paramss1, idx - params.length)
case nil =>
WildcardType
diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
index eb46a131f..d666b563e 100644
--- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -437,65 +437,82 @@ object ProtoTypes {
/** Approximate occurrences of parameter types and uninstantiated typevars
* by wildcard types.
*/
- final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = tp match {
+ final def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[PolyParam])(implicit ctx: Context): Type = tp match {
case tp: NamedType => // default case, inlined for speed
if (tp.symbol.isStatic) tp
- else tp.derivedSelect(wildApprox(tp.prefix, theMap))
+ else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen))
case tp: RefinedType => // default case, inlined for speed
- tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
+ tp.derivedRefinedType(
+ wildApprox(tp.parent, theMap, seen),
+ tp.refinedName,
+ wildApprox(tp.refinedInfo, theMap, seen))
case tp: TypeAlias => // default case, inlined for speed
- tp.derivedTypeAlias(wildApprox(tp.alias, theMap))
+ tp.derivedTypeAlias(wildApprox(tp.alias, theMap, seen))
case tp @ PolyParam(poly, pnum) =>
- def unconstrainedApprox = WildcardType(wildApprox(poly.paramBounds(pnum)).bounds)
- if (ctx.mode.is(Mode.TypevarsMissContext))
- unconstrainedApprox
- else
- ctx.typerState.constraint.entry(tp) match {
- case bounds: TypeBounds => wildApprox(WildcardType(bounds))
- case NoType => unconstrainedApprox
- case inst => wildApprox(inst)
- }
+ def wildApproxBounds(bounds: TypeBounds) =
+ if (bounds.lo.isInstanceOf[NamedType] && bounds.hi.isInstanceOf[NamedType])
+ WildcardType(wildApprox(bounds, theMap, seen).bounds)
+ else if (seen.contains(tp)) WildcardType
+ else WildcardType(wildApprox(bounds, theMap, seen + tp).bounds)
+ def unconstrainedApprox = wildApproxBounds(poly.paramBounds(pnum))
+ def approxPoly =
+ if (ctx.mode.is(Mode.TypevarsMissContext)) unconstrainedApprox
+ else
+ ctx.typerState.constraint.entry(tp) match {
+ case bounds: TypeBounds => wildApproxBounds(bounds)
+ case NoType => unconstrainedApprox
+ case inst => wildApprox(inst, theMap, seen)
+ }
+ approxPoly
case MethodParam(mt, pnum) =>
- WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
+ WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum), theMap, seen)))
case tp: TypeVar =>
- wildApprox(tp.underlying)
+ wildApprox(tp.underlying, theMap, seen)
case tp @ HKApply(tycon, args) =>
- wildApprox(tycon) match {
+ wildApprox(tycon, theMap, seen) match {
case _: WildcardType => WildcardType // this ensures we get a * type
- case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_)))
+ case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_, theMap, seen)))
}
case tp: AndType =>
- val tp1a = wildApprox(tp.tp1)
- val tp2a = wildApprox(tp.tp2)
- def wildBounds(tp: Type) =
- if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
- if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
- WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
- else
- tp.derivedAndType(tp1a, tp2a)
+ def approxAnd = {
+ val tp1a = wildApprox(tp.tp1, theMap, seen)
+ val tp2a = wildApprox(tp.tp2, theMap, seen)
+ def wildBounds(tp: Type) =
+ if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
+ if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
+ WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
+ else
+ tp.derivedAndType(tp1a, tp2a)
+ }
+ approxAnd
case tp: OrType =>
- val tp1a = wildApprox(tp.tp1)
- val tp2a = wildApprox(tp.tp2)
- if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
- WildcardType(tp1a.bounds | tp2a.bounds)
- else
- tp.derivedOrType(tp1a, tp2a)
+ def approxOr = {
+ val tp1a = wildApprox(tp.tp1, theMap, seen)
+ val tp2a = wildApprox(tp.tp2, theMap, seen)
+ if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
+ WildcardType(tp1a.bounds | tp2a.bounds)
+ else
+ tp.derivedOrType(tp1a, tp2a)
+ }
+ approxOr
case tp: LazyRef =>
WildcardType
case tp: SelectionProto =>
- tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto), NoViewsAllowed)
+ tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap, seen), NoViewsAllowed)
case tp: ViewProto =>
- tp.derivedViewProto(wildApprox(tp.argType), wildApprox(tp.resultType))
+ tp.derivedViewProto(
+ wildApprox(tp.argType, theMap, seen),
+ wildApprox(tp.resultType, theMap, seen))
case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
tp
case _ =>
- (if (theMap != null) theMap else new WildApproxMap).mapOver(tp)
+ (if (theMap != null) theMap else new WildApproxMap(seen)).mapOver(tp)
}
@sharable object AssignProto extends UncachedGroundType with MatchAlways
- private[ProtoTypes] class WildApproxMap(implicit ctx: Context) extends TypeMap {
- def apply(tp: Type) = wildApprox(tp, this)
+ private[ProtoTypes] class WildApproxMap(val seen: Set[PolyParam])(implicit ctx: Context) extends TypeMap {
+ def apply(tp: Type) = wildApprox(tp, this, seen)
}
/** Dummy tree to be used as an argument of a FunProto or ViewProto type */
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 5ea36986f..652c89094 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1879,7 +1879,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
def implicitArgError(msg: String => String) =
errors += (() => msg(em"parameter $pname of $methodStr"))
- inferImplicitArg(formal, implicitArgError, tree.pos.endPos)
+ if (errors.nonEmpty) EmptyTree
+ else inferImplicitArg(formal.widenExpr, implicitArgError, tree.pos.endPos)
}
if (errors.nonEmpty) {
// If there are several arguments, some arguments might already
diff --git a/tests/pos/f-bounded-case-class.scala b/tests/pos/f-bounded-case-class.scala
new file mode 100644
index 000000000..82b8758b2
--- /dev/null
+++ b/tests/pos/f-bounded-case-class.scala
@@ -0,0 +1 @@
+case class Test[X <: List[Y], Y <: List[X]](x: X, y: Y)
diff --git a/tests/run/generic/Color.scala b/tests/run/generic/Color.scala
new file mode 100644
index 000000000..ed248295d
--- /dev/null
+++ b/tests/run/generic/Color.scala
@@ -0,0 +1,30 @@
+package generic
+
+import Shapes._
+
+/** enum Color {
+ * case Red
+ * case Green
+ * case Blue
+ * }
+ */
+sealed trait Color extends Enum
+
+object Color extends EnumValues[Color](3) {
+
+ private def $new(tag: Int, name: String) = new Color {
+ def enumTag = tag
+ override def toString = name
+ registerEnumValue(this)
+ }
+
+ val Red: Color = $new(0, "Red")
+ val Green: Color = $new(1, "Green")
+ val Blue: Color = $new(2, "Blue")
+
+ implicit val ColorShape: Color `shaped` EnumValue[Color] =
+ new (Color `shaped` EnumValue[Color]) {
+ def toShape(x: Color) = EnumValue(x.enumTag)
+ def fromShape(x: EnumValue[Color]) = Color.value(x.tag)
+ }
+} \ No newline at end of file
diff --git a/tests/run/generic/Enum.scala b/tests/run/generic/Enum.scala
new file mode 100644
index 000000000..dbdbfe8eb
--- /dev/null
+++ b/tests/run/generic/Enum.scala
@@ -0,0 +1,18 @@
+package generic
+
+import Shapes.Singleton
+
+trait Enum {
+ def enumTag: Int
+}
+
+trait FiniteEnum extends Enum
+
+abstract class EnumValues[E <: Enum](numVals: Int) {
+ private var myValues = new Array[AnyRef](numVals)
+
+ def registerEnumValue(v: E) =
+ myValues(v.enumTag) = v
+
+ def value: IndexedSeq[E] = (myValues: IndexedSeq[AnyRef]).asInstanceOf[IndexedSeq[E]]
+}
diff --git a/tests/run/generic/List.scala b/tests/run/generic/List.scala
new file mode 100644
index 000000000..3f3657656
--- /dev/null
+++ b/tests/run/generic/List.scala
@@ -0,0 +1,89 @@
+package generic
+
+import Shapes._
+
+/** enum List[T] {
+ * case Cons(x: T, xs: List[T])
+ * case Nil()
+ * }
+ */
+sealed trait List0[T] extends Enum
+object List0 {
+ abstract case class Cons[T](hd: T, tl: List0[T]) extends List0[T] {
+ def enumTag = 0
+ }
+ object Cons {
+ def apply[T](x: T, xs: List0[T]): List0[T] = new Cons(x, xs) {}
+ implicit def ConsShape[T]: Cons[T] `shaped` Prod[T, List0[T]] =
+ new (Cons[T] `shaped` Prod[T, List0[T]]) {
+ def toShape(x: Cons[T]) = Prod(x.hd, x.tl)
+ def fromShape(p: Prod[T, List0[T]]) = new Cons(p.fst, p.snd) {}
+ }
+ }
+
+ abstract case class Nil[T]() extends List0[T] {
+ def enumTag = 1
+ }
+ object Nil {
+ def apply[T](): List0[T] = new Nil[T]() {}
+ implicit def NilShape[T]: Nil[T] `shaped` Unit =
+ new (Nil[T] `shaped` Unit) {
+ def toShape(x: Nil[T]) = ()
+ def fromShape(x: Unit) = new Nil[T]() {}
+ }
+ }
+
+ implicit def List0Shape[T]: List0[T] `shaped` Sum[Cons[T], Nil[T]] =
+ new (List0[T] `shaped` Sum[Cons[T], Nil[T]]) {
+ def toShape(x: List0[T]) = x match {
+ case x: Cons[T] => Fst(x)
+ case x: Nil[T] => Snd(x)
+ }
+ def fromShape(x: Sum[Cons[T], Nil[T]]) = x match {
+ case Fst(c) => c
+ case Snd(n) => n
+ }
+ }
+}
+
+/** enum List[T] {
+ * case Cons(x: T, xs: List[T])
+ * case Nil extends List[Nothing]
+ * }
+ */
+sealed trait List[+T] extends Enum
+object List {
+ abstract case class Cons[T](hd: T, tl: List[T]) extends List[T] {
+ def enumTag = 0
+ }
+ object Cons {
+ def apply[T](x: T, xs: List[T]): List[T] = new Cons(x, xs) {}
+ type Shape[T] = Prod[T, List[T]]
+ implicit def ConsShape[T]: Cons[T] `shaped` Shape[T] =
+ new (Cons[T] `shaped` Shape[T]) {
+ def toShape(x: Cons[T]) = Prod(x.hd, x.tl)
+ def fromShape(p: Shape[T]) = new Cons(p.fst, p.snd) {}
+ }
+ }
+
+ val Nil = new List[Nothing] {
+ def enumTag = 1
+ override def toString = "Nil"
+ }
+
+ implicit def NilSingleton: Singleton[Nil.type] = new Singleton[Nil.type](Nil)
+
+ type Shape[T] = Sum[Cons[T], Nil.type]
+
+ implicit def ListShape[T]: List[T] `unfolds` Shape[T] =
+ new (List[T] `shaped` Shape[T]) {
+ def toShape(x: List[T]) = x match {
+ case x: Cons[T] => Fst(x)
+ case Nil => Snd(Nil)
+ }
+ def fromShape(x: Shape[T]): List[T] = x match {
+ case Fst(c) => c
+ case Snd(n) => n
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/run/generic/SearchResult.scala b/tests/run/generic/SearchResult.scala
new file mode 100644
index 000000000..1c86d1b4f
--- /dev/null
+++ b/tests/run/generic/SearchResult.scala
@@ -0,0 +1,64 @@
+package generic
+
+import Shapes._
+
+/** enum SearchResult {
+ * case Success(result: Color)
+ * case Diverging
+ * case NoMatch
+ * case Ambiguous(alt1: SearchResult, alt2: SearchResult)
+ * }
+ */
+sealed trait SearchResult extends Enum
+
+object SearchResult extends EnumValues[SearchResult](3) {
+
+ private def $new(tag: Int, name: String) = new SearchResult {
+ def enumTag = tag
+ override def toString = name
+ registerEnumValue(this)
+ }
+
+ abstract case class Success(result: Color) extends SearchResult {
+ def enumTag = 0
+ }
+ object Success {
+ def apply(result: Color): SearchResult = new Success(result) {}
+ implicit def SuccessShape: Success `shaped` Color =
+ new (Success `shaped` Color) {
+ def toShape(s: Success) = s.result
+ def fromShape(c: Color) = new Success(c) {}
+ }
+ }
+
+ val Diverging = $new(1, "Diverging")
+ val NoMatch = $new(2, "NoMatch")
+
+ abstract case class Ambiguous(alt1: SearchResult, alt2: SearchResult) extends SearchResult {
+ def enumTag = 3
+ }
+ object Ambiguous {
+ def apply(alt1: SearchResult, alt2: SearchResult): SearchResult = new Ambiguous(alt1, alt2) {}
+ implicit def AmbiguousShape: Ambiguous `shaped` Prod[SearchResult, SearchResult] =
+ new (Ambiguous `shaped` Prod[SearchResult, SearchResult]) {
+ def toShape(a: Ambiguous) = Prod(a.alt1, a.alt2)
+ def fromShape(p: Prod[SearchResult, SearchResult]) = new Ambiguous(p.fst, p.snd) {}
+ }
+ }
+
+ type Shape = Sum[Success, Sum[Ambiguous, EnumValue[SearchResult]]]
+
+ implicit def SearchResultShape: SearchResult `unfolds` Shape =
+ new (SearchResult `shaped` Shape) {
+ def toShape(x: SearchResult) = x match {
+ case x: Success => Fst(x)
+ case x: Ambiguous => Snd(Fst(x))
+ case x => Snd(Snd(EnumValue(x.enumTag)))
+ }
+ def fromShape(x: Sum[Success, Sum[Ambiguous, EnumValue[SearchResult]]]): SearchResult = x match {
+ case Fst(s) => s
+ case Snd(Fst(a)) => a
+ case Snd(Snd(ev)) => value(ev.tag)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/run/generic/Serialization.scala b/tests/run/generic/Serialization.scala
new file mode 100644
index 000000000..a82d6bc7a
--- /dev/null
+++ b/tests/run/generic/Serialization.scala
@@ -0,0 +1,115 @@
+package generic
+
+import java.io.{DataInputStream,DataOutputStream}
+import scala.collection.generic.GenericCompanion
+import scala.collection.mutable.ArrayBuffer
+import Shapes._
+
+object Serialization {
+
+ trait Serializable[T] {
+ def write(x: T, out: DataOutputStream): Unit
+ def read(in: DataInputStream): T
+ }
+
+ implicit val UnitSerializable: Serializable[Unit] =
+ new Serializable[Unit] {
+ def write(x: Unit, out: DataOutputStream) = ()
+ def read(in: DataInputStream) = ()
+ }
+
+ implicit def SingleSerializable[T](implicit
+ ev1: Singleton[T]
+ ): Serializable[T] = new Serializable[T] {
+ def write(x: T, out: DataOutputStream) = ()
+ def read(in: DataInputStream) = ev1.value
+ }
+
+ implicit def EnumValueSerializable[T]: Serializable[EnumValue[T]] =
+ new Serializable[EnumValue[T]] {
+ def write(x: EnumValue[T], out: DataOutputStream) = out.writeShort(x.tag)
+ def read(in: DataInputStream) = EnumValue(in.readShort())
+ }
+
+ implicit val BooleanSerializable: Serializable[Boolean] =
+ new Serializable[Boolean] {
+ def write(x: Boolean, out: DataOutputStream) = out.writeBoolean(x)
+ def read(in: DataInputStream) = in.readBoolean()
+ }
+
+ implicit val IntSerializable: Serializable[Int] =
+ new Serializable[Int] {
+ def write(x: Int, out: DataOutputStream) = out.writeInt(x)
+ def read(in: DataInputStream) = in.readInt()
+ }
+
+ implicit val StringSerializable: Serializable[String] =
+ new Serializable[String] {
+ def write(x: String, out: DataOutputStream) = out.writeUTF(x)
+ def read(in: DataInputStream) = in.readUTF()
+ }
+
+ def RecSerializable[T, U](implicit
+ ev1: T unfolds U,
+ ev2: Serializable[U]
+ ): Serializable[T] =
+ new Serializable[T] {
+ def write(x: T, out: DataOutputStream) = ev2.write(ev1.toShape(x), out)
+ def read(in: DataInputStream) = ev1.fromShape(ev2.read(in))
+ }
+
+ implicit def ShapedSerializable[T, U](implicit
+ ev1: T shaped U,
+ ev2: Serializable[U]
+ ): Serializable[T] =
+ new Serializable[T] {
+ def write(x: T, out: DataOutputStream) = ev2.write(ev1.toShape(x), out)
+ def read(in: DataInputStream) = ev1.fromShape(ev2.read(in))
+ }
+
+ implicit def SumSerializable[T, U](implicit
+ // parameters need to be call by name, or we get a recursive lazy val definition in materialized code
+ ev1: => Serializable[T],
+ ev2: => Serializable[U]
+ ): Serializable[Sum[T, U]] =
+ new Serializable[Sum[T, U]] {
+ def write(x: Sum[T, U], out: DataOutputStream): Unit = x match {
+ case Fst(y) => out.writeBoolean(false); ev1.write(y, out)
+ case Snd(y) => out.writeBoolean(true); ev2.write(y, out)
+ }
+ def read(in: DataInputStream) = in.readBoolean() match {
+ case false => Fst(ev1.read(in))
+ case true => Snd(ev2.read(in))
+ }
+ }
+
+ implicit def ProdSerializable[T, U](implicit
+ ev1: Serializable[T],
+ ev2: Serializable[U]
+ ): Serializable[Prod[T, U]] =
+ new Serializable[Prod[T, U]] {
+ def write(x: Prod[T, U], out: DataOutputStream): Unit = {
+ ev1.write(x.fst, out)
+ ev2.write(x.snd, out)
+ }
+ def read(in: DataInputStream) = {
+ Prod(ev1.read(in), ev2.read(in))
+ }
+ }
+
+ implicit def IterableSerializable[I[X] <: Iterable[X], Elem](implicit
+ ev1: GenericCompanion[I],
+ ev2: Serializable[Elem]
+ ): Serializable[I[Elem]] =
+ new Serializable[I[Elem]] {
+ def write(xs: I[Elem], out: DataOutputStream) = {
+ out.writeInt(xs.size)
+ xs.foreach(ev2.write(_, out))
+ }
+ def read(in: DataInputStream) = {
+ val bldr = ev1.newBuilder[Elem]
+ for (i <- 0 until in.readInt()) bldr += ev2.read(in)
+ bldr.result()
+ }
+ }
+}
diff --git a/tests/run/generic/Shapes.scala b/tests/run/generic/Shapes.scala
new file mode 100644
index 000000000..8304551e3
--- /dev/null
+++ b/tests/run/generic/Shapes.scala
@@ -0,0 +1,22 @@
+package generic
+
+object Shapes {
+
+ trait Sum[+S1, +S2]
+ case class Fst[+F](x: F) extends Sum[F, Nothing]
+ case class Snd[+S](x: S) extends Sum[Nothing, S]
+
+ case class Prod[+P1, +P2](fst: P1, snd: P2)
+
+ case class Singleton[SI](value: SI)
+
+ case class EnumValue[E](tag: Int)
+
+ trait shaped[SH1, SH2] extends unfolds[SH1, SH2]
+
+ trait unfolds[UN1, UN2] {
+ def toShape(x: UN1): UN2
+ def fromShape(x: UN2): UN1
+ }
+}
+
diff --git a/tests/run/generic/Test.scala b/tests/run/generic/Test.scala
new file mode 100644
index 000000000..ac0dc4d5a
--- /dev/null
+++ b/tests/run/generic/Test.scala
@@ -0,0 +1,72 @@
+import generic._
+import Tree._
+import List._
+import java.io._
+import Shapes._
+import SearchResult._
+
+object Test {
+ import Serialization._
+
+ private var lCount, tCount, sCount = 0
+
+// ------- Code that will eventually be produced by macros -------------
+
+ implicit def ListSerializable[Elem](implicit es: Serializable[Elem]): Serializable[List[Elem]] = {
+ implicit lazy val lsElem: Serializable[List[Elem]] = {
+ lCount += 1 // test code to verify we create bounded number of Serializables
+ RecSerializable[List[Elem], List.Shape[Elem]]
+ }
+ lsElem
+ }
+
+ implicit def TreeSerializable[R]: Serializable[Tree[R]] = {
+ implicit lazy val tR: Serializable[Tree[R]] = {
+ tCount += 1 // test code to verify we create bounded number of Serializables
+ RecSerializable[Tree[R], Tree.Shape[R]]
+ }
+ tR
+ }
+ implicit lazy val tsInt: Serializable[Tree[Int]] = TreeSerializable[Int]
+ implicit lazy val tsBoolean: Serializable[Tree[Boolean]] = TreeSerializable[Boolean]
+
+ implicit lazy val SearchResultSerializable: Serializable[SearchResult] = {
+ sCount += 1
+ RecSerializable[SearchResult, SearchResult.Shape]
+ }
+
+// ------- Test code --------------------------------------------------------
+
+ /** Serialize data, then deserialize it back and check that it is the same. */
+ def sds[D](data: D)(implicit ser: Serializable[D]) = {
+ val outBytes = new ByteArrayOutputStream
+ val out = new DataOutputStream(outBytes)
+ ser.write(data, out)
+ out.flush()
+ val inBytes = new ByteArrayInputStream(outBytes.toByteArray)
+ val in = new DataInputStream(inBytes)
+ val result = ser.read(in)
+ assert(data == result, s"$data != $result")
+ }
+
+ val data1 =
+ Cons(1, Cons(2, Cons(3, Nil)))
+
+ val data2 =
+ If(IsZero(Pred(Succ(Zero))), Succ(Succ(Zero)), Pred(Pred(Zero)))
+
+ val data3 = Cons(Color.Red, Cons(Color.Green, Cons(Color.Blue, Nil)))
+
+ val data4 = Ambiguous(Success(Color.Green), Diverging)
+
+ def main(args: Array[String]) = {
+ sds(data1)
+ assert(lCount == 1, lCount)
+ sds(data2)
+ assert(tCount == 2, tCount)
+ sds(data3)
+ assert(lCount == 2, lCount)
+ sds(data4)
+ assert(sCount == 1, sCount)
+ }
+} \ No newline at end of file
diff --git a/tests/run/generic/Tree.scala b/tests/run/generic/Tree.scala
new file mode 100644
index 000000000..f4e706944
--- /dev/null
+++ b/tests/run/generic/Tree.scala
@@ -0,0 +1,113 @@
+package generic
+
+import Shapes._
+
+/** enum Tree[TS] {
+ * case True extends Tree[Boolean]
+ * case False extends Tree[Boolean]
+ * case Zero extends Tree[Int]
+ * case Succ(n: Tree[Int]) extends Tree[Int]
+ * case Pred(n: Tree[Int]) extends Tree[Int]
+ * case IsZero(n: Tree[Int]) extends Tree[Boolean]
+ * case If(cond: Boolean, thenp: Tree[T], elsep: Tree[T]) extends Tree[T]
+ * }
+ */
+sealed trait Tree[TR] extends Enum
+
+object Tree {
+
+ val True: Tree[Boolean] = new Tree[Boolean] {
+ def enumTag = 0
+ override def toString = "True"
+ }
+ implicit def TrueSingleton: Singleton[True.type] = new Singleton[True.type](True)
+
+ val False: Tree[Boolean] = new Tree[Boolean] {
+ def enumTag = 1
+ override def toString = "False"
+ }
+ implicit def FalseSingleton: Singleton[False.type] = new Singleton[False.type](False)
+
+ val Zero: Tree[Int] = new Tree[Int] {
+ def enumTag = 2
+ override def toString = "Zero"
+ }
+ implicit def ZeroSingleton: Singleton[Zero.type] = new Singleton[Zero.type](Zero)
+
+ abstract case class Succ(n: Tree[Int]) extends Tree[Int] {
+ def enumTag = 3
+ }
+ object Succ {
+ def apply(x: Tree[Int]): Tree[Int] = new Succ(x) {}
+ implicit def SuccShape: Succ `shaped` Tree[Int] = new (Succ `shaped` Tree[Int]) {
+ def toShape(x: Succ) = x.n
+ def fromShape(x: Tree[Int]) = new Succ(x) {}
+ }
+ }
+
+ abstract case class Pred(n: Tree[Int]) extends Tree[Int] {
+ def enumTag = 4
+ }
+ object Pred {
+ def apply(x: Tree[Int]): Tree[Int] = new Pred(x) {}
+ implicit def PredShape: Pred `shaped` Tree[Int] = new (Pred `shaped` Tree[Int]) {
+ def toShape(x: Pred) = x.n
+ def fromShape(x: Tree[Int]) = new Pred(x) {}
+ }
+ }
+
+ abstract case class IsZero(n: Tree[Int]) extends Tree[Boolean] {
+ def enumTag = 5
+ }
+ object IsZero {
+ def apply(x: Tree[Int]): Tree[Boolean] = new IsZero(x) {}
+ implicit def IsZeroShape: IsZero `shaped` Tree[Int] = new (IsZero `shaped` Tree[Int]) {
+ def toShape(x: IsZero) = x.n
+ def fromShape(x: Tree[Int]) = new IsZero(x) {}
+ }
+ }
+
+ abstract case class If[T](cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T]) extends Tree[T] {
+ def enumTag = 6
+ }
+ object If {
+ def apply[T](cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T]): Tree[T] = new If(cond, thenp, elsep) {}
+ type Shape[T] = Prod[Tree[Boolean], Prod[Tree[T], Tree[T]]]
+ implicit def IfShape[T]: If[T] `shaped` Shape[T] =
+ new (If[T] `shaped` Shape[T]) {
+ def toShape(x: If[T]) = Prod(x.cond, Prod(x.thenp, x.elsep))
+ def fromShape(x: Shape[T]) = new If(x.fst, x.snd.fst, x.snd.snd) {}
+ }
+ }
+
+ type Shape[T] =
+ Sum[
+ Sum[
+ Sum[True.type, False.type],
+ Sum[Zero.type, Succ]],
+ Sum[
+ Sum[Pred, IsZero],
+ If[T]]]
+
+ implicit def TreeShape[TS]: Tree[TS] `unfolds` Shape[TS]
+ = new (Tree[TS] `shaped` Shape[TS]) {
+ def toShape(x: Tree[TS]) = x match {
+ case True => Fst(Fst(Fst(True)))
+ case False => Fst(Fst(Snd(False)))
+ case Zero => Fst(Snd(Fst(Zero)))
+ case x: Succ => Fst(Snd(Snd(x)))
+ case x: Pred => Snd(Fst(Fst(x)))
+ case x: IsZero => Snd(Fst(Snd(x)))
+ case x: If[TS] => Snd(Snd(x))
+ }
+ def fromShape(x: Shape[TS]): Tree[TS] = x match {
+ case Fst(Fst(Fst(_true))) => _true.asInstanceOf[Tree[TS]]
+ case Fst(Fst(Snd(_false))) => _false.asInstanceOf[Tree[TS]]
+ case Fst(Snd(Fst(zero))) => zero.asInstanceOf[Tree[TS]]
+ case Fst(Snd(Snd(succ))) => succ.asInstanceOf[Tree[TS]]
+ case Snd(Fst(Fst(pred))) => pred.asInstanceOf[Tree[TS]]
+ case Snd(Fst(Snd(isZero))) => isZero.asInstanceOf[Tree[TS]]
+ case Snd(Snd(_if)) => _if
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/run/t10170.check b/tests/run/t10170.check
new file mode 100644
index 000000000..29d6383b5
--- /dev/null
+++ b/tests/run/t10170.check
@@ -0,0 +1 @@
+100
diff --git a/tests/run/t10170.scala b/tests/run/t10170.scala
new file mode 100644
index 000000000..683bad371
--- /dev/null
+++ b/tests/run/t10170.scala
@@ -0,0 +1,7 @@
+object Test {
+ def main(args: Array[String]) = println(f)
+
+ def f = {
+ val a = 100; ({ val a = 0; (c: Int) => c })(a)
+ }
+}