From e28c3edda4dd405ed382227d2a688b799bf33c72 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 May 2013 16:27:03 -0700 Subject: SI-1786 incorporate defined bounds in inference Also fixes SI-5459. Look, you don't have to redeclare the bounds, isn't it exciting? For instance, there are eight places in JavaMirrors with this: jTypeVariable[_ <: GenericDeclaration] After this code is in starr, those can look like this: jTypeVariable[_] Since TypeVariable's definition looks like this: interface TypeVariable We already know that! --- .../scala/tools/nsc/typechecker/Typers.scala | 54 ++++++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 001808e6bc..b41df05c3d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4867,19 +4867,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) => @@ -4888,19 +4892,39 @@ 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) + ) + 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 -- cgit v1.2.3 From b4751a679a1e01d1d8826c4c2d68af269a1c0443 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 14 May 2013 16:18:15 -0700 Subject: No bounds-driven inference for the named. This is a variation on the previous commit which excludes named type parameters, so this works def f(x: Class[_]) = x.foo.bar But this does not: def f[T](x: Class[T]) = x.foo.bar This seems undesirable to me, but I offer it in case it makes the patch more attractive to others. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 1 + test/files/neg/t5687.check | 7 +++++-- test/files/pos/t1786.scala | 12 ++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b41df05c3d..491634cf3b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4914,6 +4914,7 @@ trait Typers extends Adaptations with Tags { && !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() diff --git a/test/files/neg/t5687.check b/test/files/neg/t5687.check index f8d02fdcc3..5096077ee5 100644 --- a/test/files/neg/t5687.check +++ b/test/files/neg/t5687.check @@ -1,5 +1,8 @@ -t5687.scala:20: error: overriding type Repr in class Template with bounds[T <: AnyRef] <: Template[T]; +t5687.scala:4: error: type arguments [T] do not conform to class Template's type parameter bounds [T <: AnyRef] + type Repr[T]<:Template[T] + ^ +t5687.scala:20: error: overriding type Repr in class Template with bounds[T] <: Template[T]; type Repr has incompatible type type Repr = CurveTemplate[T] ^ -one error found +two errors found diff --git a/test/files/pos/t1786.scala b/test/files/pos/t1786.scala index 22bd659609..32d6c06f6e 100644 --- a/test/files/pos/t1786.scala +++ b/test/files/pos/t1786.scala @@ -5,15 +5,15 @@ 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 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 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 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 } + // 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 } } -- cgit v1.2.3