summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala73
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--src/library/scala/Tuple2.scala128
-rw-r--r--test/files/neg/names-defaults-neg.check7
-rw-r--r--test/files/neg/t0226.check3
-rw-r--r--test/files/neg/tcpoly_infer_ticket1162.check4
-rw-r--r--test/files/neg/tcpoly_infer_ticket1162.scala8
-rw-r--r--test/files/pos/tcpoly_infer_easy.scala5
-rw-r--r--test/files/pos/tcpoly_infer_explicit_tuple_wrapper.scala16
-rw-r--r--test/files/pos/tcpoly_infer_implicit_tuple_wrapper.scala18
-rw-r--r--test/files/pos/tcpoly_infer_ticket1864.scala51
-rw-r--r--test/files/pos/tcpoly_infer_ticket474.scala27
-rw-r--r--test/files/pos/tcpoly_infer_ticket716.scala26
14 files changed, 273 insertions, 100 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index cdb3a2eb8e..933c122d6b 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1963,8 +1963,9 @@ A type's typeSymbol should never be inspected directly.
// now, pattern-matching returns the most recent constr
object TypeVar {
def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr))
- def apply(origin: Type, constr: TypeConstraint) = new TypeVar(origin, constr)
- def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint(List(),List()))
+ def apply(origin: Type, constr: TypeConstraint) = new TypeVar(origin, constr, List(), List())
+ def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint(List(),List()), List(), tparam.typeParams)
+ def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]) = new TypeVar(origin, constr, args, params)
}
/** A class representing a type variable
@@ -1973,7 +1974,9 @@ A type's typeSymbol should never be inspected directly.
* A TypeVar whose list of args is non-empty can only be instantiated by a higher-kinded type that can be applied to these args
* NOTE:
*/
- class TypeVar(val origin: Type, val constr0: TypeConstraint) extends Type {
+ class TypeVar(val origin: Type, val constr0: TypeConstraint, override val typeArgs: List[Type], override val params: List[Symbol]) extends Type {
+ // params are needed to keep track of variance (see mapOverArgs in SubstMap)
+ assert(typeArgs.isEmpty || typeArgs.length == params.length)
// var tid = { tidCount += 1; tidCount } //DEBUG
/** The constraint associated with the variable */
@@ -1983,6 +1986,24 @@ A type's typeSymbol should never be inspected directly.
/** The variable's skolemizatuon level */
val level = skolemizationLevel
+ /**
+ * two occurrences of a higher-kinded typevar, e.g. ?CC[Int] and ?CC[String], correspond to
+ * *two instances* of TypeVar that share the *same* TypeConstraint
+ * constr for ?CC only tracks type constructors anyway, so when ?CC[Int] <:< List[Int] and ?CC[String] <:< Iterable[String]
+ * ?CC's hibounds contains List and Iterable
+ */
+ def applyArgs(newArgs: List[Type]): TypeVar =
+ if(newArgs.isEmpty) this // SubstMap relies on this (though this check is redundant when called from appliedType...)
+ else TypeVar(origin, constr, newArgs, params) // @M TODO: interaction with undoLog??
+ // newArgs.length may differ from args.length (could've been empty before)
+ // OBSOLETE BEHAVIOUR: imperatively update args to new args
+ // this initialises a TypeVar's arguments to the arguments of the type
+ // example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A]
+ // thus, we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver)
+ // OBSOLETE BECAUSE: can't update imperatively because TypeVars do get applied to different arguments over type (in asSeenFrom) -- see pos/tcpoly_infer_implicit_tuplewrapper.scala
+ // CONSEQUENCE: make new TypeVar's for every application of a TV to args,
+ // inference may generate several TypeVar's for a single type parameter that must be inferred,
+ // one of them is in the set of tvars that need to be solved, and they all share the same constr instance
def setInst(tp: Type) {
@@ -2024,12 +2045,24 @@ A type's typeSymbol should never be inspected directly.
else constr.hibounds = tp :: constr.hibounds
// println("addedBound: "+(this, tp)) // @MDEBUG
}
+ def checkArgs(args1: List[Type], args2: List[Type], params: List[Symbol]) =
+ if(isLowerBound) isSubArgs(args1, args2, params)
+ else isSubArgs(args2, args1, params)
if (constr.instValid) // type var is already set
checkSubtype(tp, constr.inst)
else isRelatable(tp) && {
- addBound(tp)
- true
+ if(params.isEmpty) { // type var has kind *
+ addBound(tp)
+ true
+ } else // higher-kinded type var with same arity as tp
+ (typeArgs.length == tp.typeArgs.length) && {
+ // register type constructor (the type without its type arguments) as bound
+ addBound(tp.typeConstructor)
+ // check subtyping of higher-order type vars
+ // use variances as defined in the type parameter that we're trying to infer (the result is sanity-checked later)
+ checkArgs(tp.typeArgs, typeArgs, params)
+ }
}
}
@@ -2050,17 +2083,24 @@ A type's typeSymbol should never be inspected directly.
}
}
- override val isHigherKinded = false
+ override val isHigherKinded = typeArgs.isEmpty && !params.isEmpty
override def normalize: Type =
if (constr.instValid) constr.inst
- else super.normalize
+ else if (isHigherKinded) { // get here when checking higher-order subtyping of the typevar by itself (TODO: check whether this ever happens?)
+ // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
+ PolyType(params, applyArgs(params map (_.typeConstructor)))
+ } else {
+ super.normalize
+ }
override def typeSymbol = origin.typeSymbol
override def safeToString: String = {
- def varString = "?"+(if (settings.explaintypes.value) level else "")+origin// +"#"+tid //DEBUG
+ def varString = "?"+(if (settings.explaintypes.value) level else "")+
+ origin+
+ (if(typeArgs.isEmpty) "" else (typeArgs map (_.safeToString)).mkString("[ ", ", ", " ]")) // +"#"+tid //DEBUG
if (constr.inst eq null) "<null " + origin + ">"
- else if (settings.debug.value) varString+constr.toString
+ else if (settings.debug.value) varString+"(@"+constr.hashCode+")"+constr.toString
else if (constr.inst eq NoType) varString
else constr.inst.toString
}
@@ -2068,7 +2108,7 @@ A type's typeSymbol should never be inspected directly.
override def isVolatile = origin.isVolatile
override def kind = "TypeVar"
- def cloneInternal = TypeVar(origin, constr cloneInternal)
+ def cloneInternal = TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params?
}
/** A type carrying some annotations. Created by the typechecker
@@ -2385,7 +2425,7 @@ A type's typeSymbol should never be inspected directly.
case st: SingletonType => appliedType(st.widen, args) // @M TODO: what to do? see bug1
case RefinedType(parents, decls) => RefinedType(parents map (appliedType(_, args)), decls) // MO to AM: please check
case TypeBounds(lo, hi) => TypeBounds(appliedType(lo, args), appliedType(hi, args))
- case tv@TypeVar(_, _) => tv //@M: for tcpoly inference, this becomes: tv.applyArgs(args)
+ case tv@TypeVar(_, constr) => tv.applyArgs(args)
case ErrorType => tycon
case WildcardType => tycon // needed for neg/t0226
case _ => throw new Error(debugString(tycon))
@@ -2678,7 +2718,7 @@ A type's typeSymbol should never be inspected directly.
else AntiPolyType(pre1, args1)
case tv@TypeVar(_, constr) =>
if (constr.instValid) this(constr.inst)
- else tv
+ else tv.applyArgs(mapOverArgs(tv.typeArgs, tv.params)) //@M !args.isEmpty implies !typeParams.isEmpty
case NotNullType(tp) =>
val tp1 = this(tp)
if (tp1 eq tp) tp
@@ -4079,15 +4119,6 @@ A type's typeSymbol should never be inspected directly.
case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2))
if !(tp1.isHigherKinded || tp2.isHigherKinded) =>
//Console.println("isSubType " + tp1 + " " + tp2);//DEBUG
- def isSubArgs(tps1: List[Type], tps2: List[Type],
- tparams: List[Symbol]): Boolean = (
- tps1.isEmpty && tps2.isEmpty
- ||
- !tps1.isEmpty && !tps2.isEmpty &&
- (tparams.head.isCovariant || (tps2.head <:< tps1.head)) &&
- (tparams.head.isContravariant || (tps1.head <:< tps2.head)) &&
- isSubArgs(tps1.tail, tps2.tail, tparams.tail)
- );
((if (sym1 == sym2) phase.erasedTypes || pre1 <:< pre2
else (sym1.name == sym2.name) && isUnifiable(pre1, pre2)) &&
(sym2 == AnyClass || isSubArgs(args1, args2, sym1.typeParams)) //@M: Any is kind-polymorphic
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 637e0e3659..96dad06e0f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -583,7 +583,9 @@ trait Infer {
List.map2(tparams, targs) {(tparam, targ) =>
if (targ.typeSymbol == NothingClass && (restpe == WildcardType || (varianceInType(restpe)(tparam) & COVARIANT) == 0)) {
uninstantiated += tparam
- tparam.tpe
+ tparam.tpeHK //@M tparam.tpe was wrong: we only want the type constructor,
+ // not the type constructor applied to dummy arguments
+ // see ticket 474 for an example that crashes if we use .tpe instead of .tpeHK)
} else if (targ.typeSymbol == RepeatedParamClass) {
targ.baseType(SeqClass)
} else if (targ.typeSymbol == JavaRepeatedParamClass) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 269e9ca938..5726e4be58 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -783,11 +783,12 @@ trait Typers { self: Analyzer =>
val tparams1 = cloneSymbols(tparams)
val tree1 = if (tree.isType) tree
else TypeApply(tree, tparams1 map (tparam =>
- TypeTree(tparam.tpe) setPos tree.pos.focus)) setPos tree.pos
+ TypeTree(tparam.tpeHK) setPos tree.pos.focus)) setPos tree.pos //@M/tcpolyinfer: changed tparam.tpe to tparam.tpeHK
context.undetparams = context.undetparams ::: tparams1
adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt, original)
case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1)
if (!context.undetparams.isEmpty/* && (mode & POLYmode) == 0 disabled to make implicits in new collection work; we should revisit this. */) { // (9)
+ // println("adapt IMT: "+(context.undetparams, pt)) //@MDEBUG
context.undetparams = inferExprInstance(
tree, context.extractUndetparams(), pt, mt.paramTypes exists isManifest)
// if we are looking for a manifest, instantiate type to Nothing anyway,
diff --git a/src/library/scala/Tuple2.scala b/src/library/scala/Tuple2.scala
index 7edea7db15..db499b3070 100644
--- a/src/library/scala/Tuple2.scala
+++ b/src/library/scala/Tuple2.scala
@@ -13,86 +13,15 @@
package scala
import annotation.unchecked.uncheckedVariance
-
-object Tuple2 {
-
- import collection.generic._
-/* !!! todo: enable
- class IterableOps[CC[+B] <: Iterable[B] with IterableTemplate[CC, B @uncheckedVariance], A1, A2](tuple: (CC[A1], Iterable[A2])) {
- def zip: CC[(A1, A2)] = {
- val elems1 = tuple._1.iterator
- val elems2 = tuple._2.iterator
- val b = (tuple._1: IterableTemplate[CC, A1]).newBuilder[(A1, A2)]
- // : needed because otherwise it picks Iterable's builder.
- while (elems1.hasNext && elems2.hasNext)
- b += ((elems1.next, elems2.next))
- b.result
- }
- def map[B](f: (A1, A2) => B): CC[B] = {
- val elems1 = tuple._1.iterator
- val elems2 = tuple._2.iterator
- val b = (tuple._1: IterableTemplate[CC, A1]).newBuilder[B]
- while (elems1.hasNext && elems2.hasNext)
- b += f(elems1.next, elems2.next)
- b.result
- }
- def flatMap[B](f: (A1, A2) => CC[B]): CC[B] = {
- val elems1 = tuple._1.iterator
- val elems2 = tuple._2.iterator
- val b = (tuple._1: IterableTemplate[CC, A1]).newBuilder[B]
- while (elems1.hasNext && elems2.hasNext)
- b ++= f(elems1.next, elems2.next)
- b.result
- }
- def foreach[U](f: (A1, A2) => U) {
- val elems1 = tuple._1.iterator
- val elems2 = tuple._2.iterator
- while (elems1.hasNext && elems2.hasNext)
- f(elems1.next, elems2.next)
- }
- def forall(p: (A1, A2) => Boolean): Boolean = {
- val elems1 = tuple._1.iterator
- val elems2 = tuple._2.iterator
- while (elems1.hasNext && elems2.hasNext)
- if (!p(elems1.next, elems2.next)) return false
- true
- }
- def exists(p: (A1, A2) => Boolean): Boolean = {
- val elems1 = tuple._1.iterator
- val elems2 = tuple._2.iterator
- while (elems1.hasNext && elems2.hasNext)
- if (p(elems1.next, elems2.next)) return true
- false
- }
- }
- implicit def tupleOfIterableWrapper[CC[+B] <: Iterable[B] with IterableTemplate[CC, B], A1, A2](tuple: (CC[A1], Iterable[A2])) =
- new IterableOps[CC, A1, A2](tuple)
+import scala.collection.Traversable
+import scala.collection.generic.GenericTraversableTemplate
+import scala.collection.mutable.Builder
-/* A more general version which will probably not work.
- implicit def tupleOfIterableWrapper[CC[+B] <: Iterable[B] with IterableTemplate[CC, B], A1, A2, B1 <: CC[A1]](tuple: B1, Iterable[A2]) =
- new IterableOps[CC, A1, A2](tuple)
-*/
-
- // Adriaan: If you drop the type parameters it will infer the wrong types.
- tupleOfIterableWrapper[collection.immutable.List, Int, Int]((collection.immutable.Nil, collection.immutable.Nil)) forall (_ + _ < 10)
-*/
-}
-
/** Tuple2 is the canonical representation of a @see Product2
*
*/
case class Tuple2[+T1, +T2](_1:T1, _2:T2) extends Product2[T1, T2] {
-/*
- def map[CC[X] <: Traversable[X], A1, A2, B](implicit fst: T1 => CC[A1], snd: T2 => Traversable[A2]) = (f: (A1, A2) => B) => {
- val b = fst(_1).genericBuilder[B]
- val it1 = _1.iterator
- val it2 = _2.iterator
- while (it1.hasNext && it2.hasNext)
- b += f(it1.next, it2.next)
- b.result
- }
-*/
override def toString() = {
val sb = new StringBuilder
sb.append('(').append(_1).append(',').append(_2).append(')')
@@ -102,4 +31,55 @@ case class Tuple2[+T1, +T2](_1:T1, _2:T2) extends Product2[T1, T2] {
/** Swap the elements of the tuple */
def swap: Tuple2[T2,T1] = Tuple2(_2, _1)
+/*
+ type Traverserable[CC[X] <: Traversable[X], X] = GenericTraversableTemplate[X, CC] with Iterable[X]
+
+ // TODO: benchmark factored version vs inlining forall2 everywhere (specialisation?)
+ // factor further? (use fold2)
+ // must use <:< instead of =>, otherwise bogus any2stringadd conversion is also eligible (in case of type errors)
+
+
+ def forall2[CC[X] <: Traverserable[CC, X], A1, A2](f: (A1, A2) => Boolean)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): Boolean = {
+ val it1 = _1.iterator
+ val it2 = _2.iterator
+ var res = true
+ while (res && it1.hasNext && it2.hasNext)
+ res = f(it1.next, it2.next)
+ res
+ }
+
+ def exists2[CC[X] <: Traverserable[CC, X], A1, A2](f: (A1, A2) => Boolean)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): Boolean = {
+ val it1 = _1.iterator
+ val it2 = _2.iterator
+ var res = false
+ while (!res && it1.hasNext && it2.hasNext)
+ res = f(it1.next, it2.next)
+ res
+ }
+
+ def foreach2[CC[X] <: Traverserable[CC, X], A1, A2, U](f: (A1, A2) => U)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): Unit
+ = forall2[CC, A1, A2]{(x, y) => f(x, y); true} // XXX: remove type args and fix crash in type infer
+
+ def build2[CC[X] <: Traverserable[CC, X], A1, A2, B](f: Builder[B, CC[B]] => (A1, A2) => Unit)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): CC[B] = {
+ val b = _1.genericBuilder[B]
+ foreach2[CC, A1, A2, Unit](f(b)) // XXX: remove type args and fix crash in type infer
+ b.result
+ }
+
+ def zip2[CC[X] <: Traverserable[CC, X], A1, A2](implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): CC[(A1, A2)]
+ = build2[CC, A1, A2, (A1, A2)]{b => (x, y) => // XXX: remove type args and fix crash in type infer
+ b += Tuple2(x, y)
+ }
+
+ def map2[CC[X] <: Traverserable[CC, X], A1, A2, B](f: (A1, A2) => B)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): CC[B]
+ = build2[CC, A1, A2, B]{b => (x, y) => // XXX: remove type args and fix crash in type infer
+ b += f(x, y)
+ }
+
+ def flatMap2[CC[X] <: Traverserable[CC, X], A1, A2, B](f: (A1, A2) => CC[B])(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): CC[B]
+ = build2[CC, A1, A2, B]{b => (x, y) => // XXX: remove type args and fix crash in type infer
+ b ++= f(x, y)
+ }
+*/
+
}
diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check
index 057a0519d7..e47cf8c420 100644
--- a/test/files/neg/names-defaults-neg.check
+++ b/test/files/neg/names-defaults-neg.check
@@ -88,8 +88,11 @@ match argument types (a: Int,b: java.lang.String) and expected result type Any
names-defaults-neg.scala:70: error: wrong number of arguments for <none>: (x: Int,y: String)A1
A1() match { case A1(_) => () }
^
-names-defaults-neg.scala:77: error: inferred kinds of the type arguments (List[Int]) do not conform to the expected kinds of the type parameters (type T).
-List[Int]'s type parameters do not match type T's expected parameters: class List has one type parameter, but type T has one
+names-defaults-neg.scala:77: error: no type parameters for method test4: (x: T[T[List[T[X forSome { type X }]]]])T[T[List[T[X forSome { type X }]]]] exist so that it can be applied to arguments (List[Int])
+ --- because ---
+argument expression's type is not compatible with formal parameter type;
+ found : List[Int]
+ required: ?T[ ?T[ scala.List[?T[ X forSome { type X } ]] ] ]
Error occured in an application involving default arguments.
test4()
^
diff --git a/test/files/neg/t0226.check b/test/files/neg/t0226.check
index af81e41a6a..e27ffbc1e1 100644
--- a/test/files/neg/t0226.check
+++ b/test/files/neg/t0226.check
@@ -4,7 +4,8 @@ t0226.scala:5: error: not found: type A1
t0226.scala:5: error: not found: type A1
(implicit _1: Foo[List[A1]], _2: Foo[A2]): Foo[Tuple2[List[A1], A2]] =
^
-t0226.scala:8: error: could not find implicit value for parameter rep: Test.this.Foo[((List[Char], Int), (object Nil, Int))]
+t0226.scala:8: error: diverging implicit expansion for type Test.this.Foo[((List[Char], Int), (object Nil, Int))]
+starting with method list2Foo in class Test
foo(((List('b'), 3), (Nil, 4)))
^
three errors found
diff --git a/test/files/neg/tcpoly_infer_ticket1162.check b/test/files/neg/tcpoly_infer_ticket1162.check
new file mode 100644
index 0000000000..03334222c1
--- /dev/null
+++ b/test/files/neg/tcpoly_infer_ticket1162.check
@@ -0,0 +1,4 @@
+tcpoly_infer_ticket1162.scala:6: error: wrong number of type parameters for method apply: [A,B,F[_]]()Test.Lift[A,B,F] in object Lift
+ def simplify[A,B]: Expression[A,B] = Lift[A,B]()
+ ^
+one error found
diff --git a/test/files/neg/tcpoly_infer_ticket1162.scala b/test/files/neg/tcpoly_infer_ticket1162.scala
new file mode 100644
index 0000000000..0552b42a22
--- /dev/null
+++ b/test/files/neg/tcpoly_infer_ticket1162.scala
@@ -0,0 +1,8 @@
+object Test {
+ trait Expression[A,B]
+
+ case class Lift[A,B,F[_]]() extends Expression[F[A],F[B]]
+
+ def simplify[A,B]: Expression[A,B] = Lift[A,B]()
+}
+
diff --git a/test/files/pos/tcpoly_infer_easy.scala b/test/files/pos/tcpoly_infer_easy.scala
new file mode 100644
index 0000000000..0f1929502c
--- /dev/null
+++ b/test/files/pos/tcpoly_infer_easy.scala
@@ -0,0 +1,5 @@
+object Test {
+ def test[CC[+X] <: Iterable[X], A](xs: CC[A]): CC[A] = xs
+ val xs = test(List(1,2))
+ val xs2: List[Int] = test(List(1,2))
+}
diff --git a/test/files/pos/tcpoly_infer_explicit_tuple_wrapper.scala b/test/files/pos/tcpoly_infer_explicit_tuple_wrapper.scala
new file mode 100644
index 0000000000..de31efd565
--- /dev/null
+++ b/test/files/pos/tcpoly_infer_explicit_tuple_wrapper.scala
@@ -0,0 +1,16 @@
+import scala.collection.generic.GenericTraversableTemplate
+import scala.collection.Iterable
+
+class IterableOps[CC[+B] <: Iterable[B] with GenericTraversableTemplate[B, CC], A1, A2](tuple: (CC[A1], Iterable[A2])) {
+ def unzip: (CC[A1], CC[A2]) = error("foo")
+}
+
+object Test {
+
+ implicit def tupleOfIterableWrapper[CC[+B] <: Iterable[B] with GenericTraversableTemplate[B, CC], A1, A2](tuple: (CC[A1], Iterable[A2]))
+ = new IterableOps[CC, A1, A2](tuple)
+
+ val t = (List(1, 2, 3), List(6, 5, 4))
+
+ tupleOfIterableWrapper(t) unzip
+} \ No newline at end of file
diff --git a/test/files/pos/tcpoly_infer_implicit_tuple_wrapper.scala b/test/files/pos/tcpoly_infer_implicit_tuple_wrapper.scala
new file mode 100644
index 0000000000..3073b298de
--- /dev/null
+++ b/test/files/pos/tcpoly_infer_implicit_tuple_wrapper.scala
@@ -0,0 +1,18 @@
+import scala.collection.generic.GenericTraversableTemplate
+import scala.collection.Iterable
+
+class IterableOps[CC[+B] <: Iterable[B] with GenericTraversableTemplate[B, CC], A1, A2](tuple: (CC[A1], Iterable[A2])) {
+ def unzip: (CC[A1], CC[A2]) = error("foo")
+}
+
+object Test {
+
+ implicit def tupleOfIterableWrapper[CC[+B] <: Iterable[B] with GenericTraversableTemplate[B, CC], A1, A2](tuple: (CC[A1], Iterable[A2]))
+ = new IterableOps[CC, A1, A2](tuple)
+
+ val t = (List(1, 2, 3), List(6, 5, 4))
+
+ tupleOfIterableWrapper(t) unzip
+
+ t unzip
+} \ No newline at end of file
diff --git a/test/files/pos/tcpoly_infer_ticket1864.scala b/test/files/pos/tcpoly_infer_ticket1864.scala
new file mode 100644
index 0000000000..587483287d
--- /dev/null
+++ b/test/files/pos/tcpoly_infer_ticket1864.scala
@@ -0,0 +1,51 @@
+import scala.collection.mutable.{Buffer, ArrayBuffer}
+
+class RichBuffer[T, B[U] <: Buffer[U]](buffer: Buffer[T]) {
+ def mymap[S](f: T => S)(implicit rv: B[S]): B[S] = {
+ buffer.foreach{ e =>
+ rv += f(e)
+ }
+ rv
+ }
+}
+
+object Application {
+ def mymap2[T, B[U] <: Buffer[U], S](buffer: B[T], f: T => S)(implicit rv: B[S]): B[S] = {
+ buffer.foreach{ e =>
+ rv += f(e)
+ }
+ rv
+ }
+
+ def mymap3[T, B <: Buffer[T], S](buffer: B, f: T => T)(implicit rv: B): B = {
+ buffer.foreach{ e =>
+ rv += f(e)
+ }
+ rv
+ }
+
+ def mymap4[T, B[U] <: Buffer[U], S](buffer: B[T])(f: T => S) (implicit rv: B[S]): B[S] = {
+ buffer.foreach{ e =>
+ rv += f(e)
+ }
+ rv
+ }
+
+
+ def main(args: Array[String]) {
+ implicit def richBuffer[T, B[U] <: Buffer[U]](buffer: B[T]): RichBuffer[T, B] =
+ new RichBuffer[T, B](buffer)
+
+ implicit val rv = new ArrayBuffer[Int]
+ val buf = new ArrayBuffer[Int]
+ (1 to 5).foreach(buf += _)
+ buf.mymap(x => x*x)
+ richBuffer(buf).mymap[Int](x => x*x)
+ richBuffer[Int, ArrayBuffer](buf).mymap[Int](x => x*x)
+ mymap2(buf, (x: Int) => x*x)
+ mymap2[Int, ArrayBuffer, Int](buf, (x: Int) => x*x)
+ // mymap3(buf, x => x*x) // compiler error
+ mymap3(buf, (x: Int) => x*x)
+ mymap4(buf)(x => x*x)
+ }
+}
diff --git a/test/files/pos/tcpoly_infer_ticket474.scala b/test/files/pos/tcpoly_infer_ticket474.scala
new file mode 100644
index 0000000000..8c9be4d5c4
--- /dev/null
+++ b/test/files/pos/tcpoly_infer_ticket474.scala
@@ -0,0 +1,27 @@
+trait Builder[C[_], T] {
+ def +=(x: T)
+ def finalise: C[T]
+}
+
+trait Buildable[C[_]] {
+ def builder[T]: Builder[C,T]
+}
+
+object Test {
+
+ implicit object buildableList extends Buildable[List] {
+ def builder[T] = new Builder[List,T] {
+ val buf = new scala.collection.mutable.ListBuffer[T]
+ def +=(x: T) = buf += x
+ def finalise = buf.toList
+ }
+ }
+
+ def foo[C[_],T](x: T)(implicit b: Buildable[C]): C[T] = {
+ val builder = b.builder[T]
+ builder += x
+ builder.finalise
+ }
+
+ val l: List[Int] = foo(8)
+} \ No newline at end of file
diff --git a/test/files/pos/tcpoly_infer_ticket716.scala b/test/files/pos/tcpoly_infer_ticket716.scala
new file mode 100644
index 0000000000..cfba07fa43
--- /dev/null
+++ b/test/files/pos/tcpoly_infer_ticket716.scala
@@ -0,0 +1,26 @@
+
+trait Functor[F[_]] {
+ def fmap[A,B](fun: A=>B, arg:F[A]): F[B]
+}
+object Functor{
+ implicit val ListFunctor: Functor[List] = new Functor[List] {
+ def fmap[A, B](f: A => B, arg: List[A]):List[B] = arg map f
+ }
+
+ final class OOFunctor[F[_],A](arg:F[A])(implicit ftr: Functor[F]) {
+ def fmap[B](fun: A=>B):F[B] = ftr.fmap(fun,arg)
+ }
+
+ //breaks if uncommented
+ implicit def lifttoOO[F[_],A](arg:F[A])(implicit ftr: Functor[F]) = new OOFunctor[F,A](arg)(ftr)
+
+ //works if uncommented
+ //implicit def liftListtoOO[A](arg:List[A]):OOFunctor[List,A] = new OOFunctor[List,A](arg)
+}
+
+object GeneralLiftingDemo extends Application {
+ import Functor._
+ val l = List(1,2,3)
+ val res = l fmap( 1+) // TODO: should not need explicit call to lifttoOO
+ println("OO : " + res )
+} \ No newline at end of file