summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala55
-rw-r--r--test/files/pos/t1786.scala19
-rw-r--r--test/files/pos/t5459.scala (renamed from test/pending/pos/t5459.scala)0
-rw-r--r--test/pending/pos/t1786.scala20
4 files changed, 59 insertions, 35 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 1fa536bb0b..8303441890 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4852,19 +4852,23 @@ trait Typers extends Adaptations with Tags {
}
def typedAppliedTypeTree(tree: AppliedTypeTree) = {
- val tpt = tree.tpt
- val args = tree.args
- val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
+ val tpt = tree.tpt
+ val args = tree.args
+ val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
+ def isPoly = tpt1.tpe.isInstanceOf[PolyType]
+ def isComplete = tpt1.symbol.rawInfo.isComplete
+
if (tpt1.isErrorTyped) {
tpt1
} else if (!tpt1.hasSymbolField) {
AppliedTypeNoParametersError(tree, tpt1.tpe)
} else {
val tparams = tpt1.symbol.typeParams
+
if (sameLength(tparams, args)) {
// @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
val args1 =
- if (!tpt1.symbol.rawInfo.isComplete)
+ if (!isComplete)
args mapConserve (typedHigherKindedType(_, mode))
// if symbol hasn't been fully loaded, can't check kind-arity
else map2Conserve(args, tparams) { (arg, tparam) =>
@@ -4873,19 +4877,40 @@ trait Typers extends Adaptations with Tags {
}
val argtypes = args1 map (_.tpe)
- foreach2(args, tparams)((arg, tparam) => arg match {
- // note: can't use args1 in selector, because Bind's got replaced
- case Bind(_, _) =>
- if (arg.symbol.isAbstractType)
- arg.symbol setInfo // XXX, feedback. don't trackSymInfo here!
- TypeBounds(
- lub(List(arg.symbol.info.bounds.lo, tparam.info.bounds.lo.subst(tparams, argtypes))),
- glb(List(arg.symbol.info.bounds.hi, tparam.info.bounds.hi.subst(tparams, argtypes))))
- case _ =>
- })
+ foreach2(args, tparams) { (arg, tparam) =>
+ // note: can't use args1 in selector, because Binds got replaced
+ val asym = arg.symbol
+ def abounds = asym.info.bounds
+ def tbounds = tparam.info.bounds
+ def enhanceBounds(): Unit = {
+ val TypeBounds(lo0, hi0) = abounds
+ val TypeBounds(lo1, hi1) = tbounds.subst(tparams, argtypes)
+ val lo = lub(List(lo0, lo1))
+ val hi = glb(List(hi0, hi1))
+ if (!(lo =:= lo0 && hi =:= hi0))
+ asym setInfo logResult(s"Updating bounds of ${asym.fullLocationString} in $tree from '$abounds' to")(TypeBounds(lo, hi))
+ }
+ if (asym != null && asym.isAbstractType) {
+ // See pos/t1786 to follow what's happening here.
+ def canEnhanceIdent = (
+ asym.hasCompleteInfo
+ && tparam.exists /* sometimes it is NoSymbol */
+ && tparam.hasCompleteInfo /* SI-2940 */
+ && !tparam.isFBounded /* SI-2251 */
+ && !tparam.isHigherOrderTypeParameter
+ && !(abounds.hi <:< tbounds.hi)
+ && asym.isSynthetic /* this limits us to placeholder tparams, excluding named ones */
+ )
+ arg match {
+ case Bind(_, _) => enhanceBounds()
+ case Ident(name) if canEnhanceIdent => enhanceBounds()
+ case _ =>
+ }
+ }
+ }
val original = treeCopy.AppliedTypeTree(tree, tpt1, args1)
val result = TypeTree(appliedType(tpt1.tpe, argtypes)) setOriginal original
- if(tpt1.tpe.isInstanceOf[PolyType]) // did the type application (performed by appliedType) involve an unchecked beta-reduction?
+ if (isPoly) // did the type application (performed by appliedType) involve an unchecked beta-reduction?
TypeTreeWithDeferredRefCheck(){ () =>
// wrap the tree and include the bounds check -- refchecks will perform this check (that the beta reduction was indeed allowed) and unwrap
// we can't simply use original in refchecks because it does not contains types
diff --git a/test/files/pos/t1786.scala b/test/files/pos/t1786.scala
new file mode 100644
index 0000000000..32d6c06f6e
--- /dev/null
+++ b/test/files/pos/t1786.scala
@@ -0,0 +1,19 @@
+class SomeClass(val intValue:Int)
+class MyClass[T <: SomeClass](val myValue:T)
+class Flooz[A >: Null <: SomeClass, T >: Null <: A](var value: T)
+
+class A {
+ def f1(i:MyClass[_]) = i.myValue.intValue
+ def f2(i:MyClass[_ <: SomeClass]) = i.myValue.intValue
+ // def f3[T](i: MyClass[T]) = i.myValue.intValue
+ def f4[T <: SomeClass](i: MyClass[T]) = i.myValue.intValue
+ // def f5[T >: Null](i: MyClass[T]) = i.myValue.intValue
+ // def f6[T >: Null <: String](i: MyClass[T]) = i.myValue.intValue + i.myValue.charAt(0)
+
+ // def g1[A, T](x: Flooz[A, T]) = { x.value = null ; x.value.intValue }
+ def g2(x: Flooz[_, _]) = { x.value = null ; x.value.intValue }
+
+ class MyClass2(x: MyClass[_]) { val p = x.myValue.intValue }
+ // class MyClass3[T <: String](x: MyClass[T]) { val p = x.myValue.intValue + x.myValue.length }
+ // class MyClass4[T >: Null](x: MyClass[T]) { val p = x.myValue.intValue }
+}
diff --git a/test/pending/pos/t5459.scala b/test/files/pos/t5459.scala
index 971e6f896d..971e6f896d 100644
--- a/test/pending/pos/t5459.scala
+++ b/test/files/pos/t5459.scala
diff --git a/test/pending/pos/t1786.scala b/test/pending/pos/t1786.scala
deleted file mode 100644
index dca2edaab4..0000000000
--- a/test/pending/pos/t1786.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-/** This a consequence of the current type checking algorithm, where bounds
- * are checked only after variables are instantiated. I believe this will change once we go to contraint-based type inference. Assigning low priority until then.
- *
- *
- */
-class SomeClass(val intValue:Int)
-class MyClass[T <: SomeClass](val myValue:T)
-
-object Test extends Application {
- def myMethod(i:MyClass[_]) {
- i.myValue.intValue/2 // << error i is of type Any
- }
-
- def myMethod(i:MyClass[_ <: SomeClass]) {
- i.myValue.intValue/2 // << works
- }
-}
-/*
-The below code shows a compiler flaw in that the wildcard "_" as value for a bounded type parameter either breaks the boundry - as it result in Any - or doesnt (as id hoped it to be) evaluates to the boundy.
-*/