diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-04-09 09:58:11 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-04-09 09:58:11 -0700 |
commit | 2a22b86ea0dd2bc9cdda14e24f8ada8cd68b6837 (patch) | |
tree | eee51d9abb37ee6ec5a6c6f163e1165eb31f9364 | |
parent | e5cb848e6dd3afc571da75c7f7f61431c8bed27f (diff) | |
parent | 6a61e172d9de912c74af50e49f0057fbe8d4e500 (diff) | |
download | scala-2a22b86ea0dd2bc9cdda14e24f8ada8cd68b6837.tar.gz scala-2a22b86ea0dd2bc9cdda14e24f8ada8cd68b6837.tar.bz2 scala-2a22b86ea0dd2bc9cdda14e24f8ada8cd68b6837.zip |
Merge pull request #2354 from adriaanm/ticket-7289
SI-7289 Less strict type application for TypeVar.
-rw-r--r-- | bincompat-backward.whitelist.conf | 4 | ||||
-rw-r--r-- | bincompat-forward.whitelist.conf | 4 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 17 | ||||
-rw-r--r-- | test/files/neg/t7289.check | 4 | ||||
-rw-r--r-- | test/files/neg/t7289.scala | 39 | ||||
-rw-r--r-- | test/files/neg/t7289_status_quo.check | 22 | ||||
-rw-r--r-- | test/files/neg/t7289_status_quo.scala | 23 |
7 files changed, 106 insertions, 7 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index aa06e1d21c..3426dc72e1 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -186,6 +186,10 @@ filter { { matchName="scala.reflect.internal.ClassfileConstants.xxxunusedxxxx" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Types#TypeVar.setInst" + problemName=IncompatibleResultTypeProblem } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index d0893c5a28..c59d0a7dec 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -418,6 +418,10 @@ filter { { matchName="scala.reflect.internal.ClassfileConstants.CONSTANT_METHODTYPE" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Types#TypeVar.setInst" + problemName=IncompatibleResultTypeProblem } ] } diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index a2c9f1fadf..ee584bed2c 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3076,12 +3076,14 @@ trait Types extends api.Types { self: SymbolTable => /** The variable's skolemization 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`. + /** Applies this TypeVar to type arguments, if arity matches. * - * `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. + * Different applications of the same type constructor variable `?CC`, + * e.g. `?CC[Int]` and `?CC[String]`, are modeled as distinct instances of `TypeVar` + * that share a `TypeConstraint`, so that the comparisons `?CC[Int] <:< List[Int]` + * and `?CC[String] <:< Iterable[String]` result in `?CC` being upper-bounded by `List` and `Iterable`. + * + * Applying the wrong number of type args results in a TypeVar whose instance is set to `ErrorType`. */ def applyArgs(newArgs: List[Type]): TypeVar = ( if (newArgs.isEmpty && typeArgs.isEmpty) @@ -3091,7 +3093,7 @@ trait Types extends api.Types { self: SymbolTable => TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv) } else - throw new Error("Invalid type application in TypeVar: " + params + ", " + newArgs) + TypeVar(typeSymbol).setInst(ErrorType) ) // newArgs.length may differ from args.length (could've been empty before) // @@ -3121,13 +3123,14 @@ trait Types extends api.Types { self: SymbolTable => // <region name="constraint mutators + undoLog"> // invariant: before mutating constr, save old state in undoLog // (undoLog is used to reset constraints to avoid piling up unrelated ones) - def setInst(tp: Type) { + def setInst(tp: Type): this.type = { // assert(!(tp containsTp this), this) undoLog record this // if we were compared against later typeskolems, repack the existential, // because skolems are only compatible if they were created at the same level val res = if (shouldRepackType) repackExistential(tp) else tp constr.inst = TypeVar.trace("setInst", "In " + originLocation + ", " + originName + "=" + res)(res) + this } def addLoBound(tp: Type, isNumericBound: Boolean = false) { diff --git a/test/files/neg/t7289.check b/test/files/neg/t7289.check new file mode 100644 index 0000000000..e4aeebbc6c --- /dev/null +++ b/test/files/neg/t7289.check @@ -0,0 +1,4 @@ +t7289.scala:8: error: could not find implicit value for parameter e: Test.Schtroumpf[scala.collection.immutable.Nil.type] + implicitly[Schtroumpf[Nil.type]] + ^ +one error found diff --git a/test/files/neg/t7289.scala b/test/files/neg/t7289.scala new file mode 100644 index 0000000000..f4ed3daf76 --- /dev/null +++ b/test/files/neg/t7289.scala @@ -0,0 +1,39 @@ +object Test extends App { + trait Schtroumpf[T] + + implicit def schtroumpf[T, U <: Coll[T], Coll[X] <: Traversable[X]] + (implicit minorSchtroumpf: Schtroumpf[T]): Schtroumpf[U] = ??? + + implicit val qoo: Schtroumpf[Int] = new Schtroumpf[Int]{} + implicitly[Schtroumpf[Nil.type]] +} + +/* +info1 = {scala.tools.nsc.typechecker.Implicits$ImplicitInfo@3468}"qoo: => Test.Schtroumpf[Int]" +info2 = {scala.tools.nsc.typechecker.Implicits$ImplicitInfo@3469}"schtroumpf: [T, U <: Coll[T], Coll[_] <: Traversable[_]](implicit minorSchtroumpf: Test.Schtroumpf[T])Test.Schtroumpf[U]" +isStrictlyMoreSpecific(info1, info2) + isSubType(Test.Schtroumpf[Int], Test.Schtroumpf[U] forSome { T; U <: Coll[T]; Coll[_] <: Traversable[_] }) + isAsSpecificValueType(Test.Schtroumpf[Int], Test.Schtroumpf[U], undef2 = List(type T, type U, type Coll)) + + val et: ExistentialType = Test.Schtroumpf[U] forSome { T; U <: Coll[T]; Coll[_] <: Traversable[_] } + val tp1 = Test.Schtroumpf[Int] + et.withTypeVars(isSubType(tp1, _, depth)) + solve() + tvars = tList(=?Nothing, =?Int, =?=?Int) + + +[ create] ?T ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] ) +[ create] ?U ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] ) +[ create] ?Coll ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] ) +[ setInst] Nothing ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], T=Nothing ) +[ setInst] scala.collection.immutable.Nil.type( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], U=scala.collection.immutable.Nil.type ) +[ setInst] =?scala.collection.immutable.Nil.type( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], Coll==?scala.collection.immutable.Nil.type ) +[ create] ?T ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] ) +[ setInst] Int ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], T=Int ) +[ create] ?T ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] ) +[ create] ?U ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] ) +[ create] ?Coll ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] ) +[ setInst] Nothing ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], T=Nothing ) +[ setInst] Int ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], U=Int ) +[ setInst] =?Int ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], Coll==?Int ) +*/
\ No newline at end of file diff --git a/test/files/neg/t7289_status_quo.check b/test/files/neg/t7289_status_quo.check new file mode 100644 index 0000000000..31c072e969 --- /dev/null +++ b/test/files/neg/t7289_status_quo.check @@ -0,0 +1,22 @@ +t7289_status_quo.scala:9: error: could not find implicit value for parameter e: Test1.Ext[List[Int]] + implicitly[Ext[List[Int]]] // fails - not found + ^ +t7289_status_quo.scala:11: error: could not find implicit value for parameter e: Test1.Ext[List[List[List[Int]]]] + implicitly[Ext[List[List[List[Int]]]]] // fails - not found + ^ +t7289_status_quo.scala:15: error: ambiguous implicit values: + both method f in object Test1 of type [A, Coll <: CC[A], CC[X] <: Traversable[X]](implicit xi: Test1.Ext[A])Test1.Ext[Coll] + and value m in object Test1 of type => Test1.Ext[List[List[Int]]] + match expected type Test1.Ext[_ <: List[List[Int]]] + implicitly[Ext[_ <: List[List[Int]]]] // fails - ambiguous + ^ +t7289_status_quo.scala:20: error: could not find implicit value for parameter e: Test1.ExtCov[List[Int]] + implicitly[ExtCov[List[Int]]] // fails - not found + ^ +t7289_status_quo.scala:21: error: could not find implicit value for parameter e: Test1.ExtCov[List[List[Int]]] + implicitly[ExtCov[List[List[Int]]]] // fails - not found + ^ +t7289_status_quo.scala:22: error: could not find implicit value for parameter e: Test1.ExtCov[List[List[List[Int]]]] + implicitly[ExtCov[List[List[List[Int]]]]] // fails - not found + ^ +6 errors found diff --git a/test/files/neg/t7289_status_quo.scala b/test/files/neg/t7289_status_quo.scala new file mode 100644 index 0000000000..39621429a1 --- /dev/null +++ b/test/files/neg/t7289_status_quo.scala @@ -0,0 +1,23 @@ +// record the status quo after this fix +// not clear to @adriaanm why an upper-bounded existential in an invariant position +// is different from putting that upper bound in a covariant position +object Test1 { + trait Ext[T] + implicit def f[A, Coll <: CC[A], CC[X] <: Traversable[X]](implicit xi: Ext[A]): Ext[Coll] = ??? + implicit val m: Ext[List[List[Int]]] = new Ext[List[List[Int]]]{} + + implicitly[Ext[List[Int]]] // fails - not found + implicitly[Ext[List[List[Int]]]] // compiles + implicitly[Ext[List[List[List[Int]]]]] // fails - not found + + // Making Ext[+T] should incur the same behavior as these. (so says @paulp) + implicitly[Ext[_ <: List[Int]]] // compiles + implicitly[Ext[_ <: List[List[Int]]]] // fails - ambiguous + implicitly[Ext[_ <: List[List[List[Int]]]]] // compiles + + // But, we currently get: + trait ExtCov[+T] + implicitly[ExtCov[List[Int]]] // fails - not found + implicitly[ExtCov[List[List[Int]]]] // fails - not found + implicitly[ExtCov[List[List[List[Int]]]]] // fails - not found +}
\ No newline at end of file |