diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala | 7 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala | 159 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Macros.scala | 2 | ||||
-rw-r--r-- | test/files/neg/t6963a.check | 4 | ||||
-rw-r--r-- | test/files/neg/t6963b.check | 13 | ||||
-rw-r--r-- | test/files/neg/t6963b.flags | 1 | ||||
-rw-r--r-- | test/files/neg/t6963b.scala | 20 |
7 files changed, 90 insertions, 116 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 0e991a5d72..45ec73ab99 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -462,13 +462,6 @@ abstract class ExplicitOuter extends InfoTransform } case _ => - if (settings.Xmigration.value < ScalaVersion.twoDotEight) tree match { - case TypeApply(fn @ Select(qual, _), args) if fn.symbol == Object_isInstanceOf || fn.symbol == Any_isInstanceOf => - if (isArraySeqTest(qual.tpe, args.head.tpe)) - unit.warning(tree.pos, "An Array will no longer match as Seq[_].") - case _ => () - } - val x = super.transform(tree) if (x.tpe eq null) x else x setType transformInfo(currentOwner, x.tpe) diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index f929b1c48e..672d9d232a 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -83,7 +83,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { | | ${candidates.map(c => c.name+":"+normalize(c.tpe, imeth.owner)).mkString("\n")} | - | Eligible Names: ${extensionNames(imeth).mkString(",")}"""") + | Eligible Names: ${extensionNames(imeth).mkString(",")}" """) matching.head } @@ -98,7 +98,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { object ExtensionMethodType { def unapply(tp: Type) = tp match { case MethodType(thiz :: rest, restpe) if thiz.name == nme.SELF => - Some( if (rest.isEmpty) restpe else MethodType(rest, restpe) ) + Some((thiz, if (rest.isEmpty) restpe else MethodType(rest, restpe) )) case _ => None } @@ -107,36 +107,22 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { /** This method removes the `$this` argument from the parameter list a method. * * A method may be a `PolyType`, in which case we tear out the `$this` and the class - * type params from its nested `MethodType`. - * It may be a `MethodType`, either with a curried parameter list in which the first argument - * is a `$this` - we just return the rest of the list. - * This means that the corresponding symbol was generated during `extmethods`. - * - * It may also be a `MethodType` in which the `$this` does not appear in a curried parameter list. - * The curried lists disappear during `uncurry`, and the methods may be duplicated afterwards, - * for instance, during `specialize`. - * In this case, the first argument is `$this` and we just get rid of it. + * type params from its nested `MethodType`. Or it may be a MethodType, as + * described at the ExtensionMethodType extractor. */ private def normalize(stpe: Type, clazz: Symbol): Type = stpe match { case PolyType(tparams, restpe) => - // Split the type parameters of the extension method into two groups, - // corresponding the to class and method type parameters. - val numClassParams = clazz.typeParams.length - val methTParams = tparams dropRight numClassParams - val classTParams = tparams takeRight numClassParams - - GenPolyType(methTParams, - normalize(restpe.substSym(classTParams, clazz.typeParams), clazz)) - case MethodType(List(thiz), restpe) if thiz.name == nme.SELF => - restpe.substituteTypes(thiz :: Nil, clazz.thisType :: Nil) - case MethodType(thiz :: params, restpe) => - MethodType(params, restpe) + // method type parameters, class type parameters + val (mtparams, ctparams) = tparams splitAt (tparams.length - clazz.typeParams.length) + GenPolyType(mtparams, + normalize(restpe.substSym(ctparams, clazz.typeParams), clazz)) + case ExtensionMethodType(thiz, etpe) => + etpe.substituteTypes(thiz :: Nil, clazz.thisType :: Nil) case _ => stpe } class Extender(unit: CompilationUnit) extends TypingTransformer(unit) { - private val extensionDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]() def checkNonCyclic(pos: Position, seen: Set[Symbol], clazz: Symbol): Unit = @@ -164,28 +150,36 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { * some higher level facilities. */ def extensionMethInfo(extensionMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { - // No variance for method type parameters - var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) map (_ resetFlag COVARIANT | CONTRAVARIANT) - val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpeHK)) + val GenPolyType(tparamsFromMethod, methodResult) = origInfo cloneInfo extensionMeth + // Start with the class type parameters - clones will be method type parameters + // so must drop their variance. + val tparamsFromClass = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) map (_ resetFlag COVARIANT | CONTRAVARIANT) + + val thisParamType = appliedType(clazz, tparamsFromClass map (_.tpeHK): _*) val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType - def transform(clonedType: Type): Type = clonedType match { - case MethodType(params, restpe) => - // I assume it was a bug that this was dropping params... [Martin]: No, it wasn't; it's curried. - MethodType(List(thisParam), clonedType) - case NullaryMethodType(restpe) => - MethodType(List(thisParam), restpe) - } - val GenPolyType(tparams, restpe) = origInfo cloneInfo extensionMeth - val selfParamSingletonType = singleType(currentOwner.companionModule.thisType, thisParam) - GenPolyType( - tparams ::: newTypeParams, - transform(restpe) substThisAndSym (clazz, selfParamSingletonType, clazz.typeParams, newTypeParams) - ) - } + val resultType = MethodType(List(thisParam), dropNullaryMethod(methodResult)) + val selfParamType = singleType(currentOwner.companionModule.thisType, thisParam) - private def allParams(tpe: Type): List[Symbol] = tpe match { - case MethodType(params, res) => params ::: allParams(res) - case _ => List() + def fixres(tp: Type) = tp substThisAndSym (clazz, selfParamType, clazz.typeParams, tparamsFromClass) + def fixtparam(tp: Type) = tp substSym (clazz.typeParams, tparamsFromClass) + + // We can't substitute symbols on the entire polytype because we + // need to modify the bounds of the cloned type parameters, but we + // don't want to substitute for the cloned type parameters themselves. + val tparams = tparamsFromMethod ::: tparamsFromClass + GenPolyType(tparams map (_ modifyInfo fixtparam), fixres(resultType)) + + // For reference, calling fix on the GenPolyType plays out like this: + // error: scala.reflect.internal.Types$TypeError: type arguments [B#7344,A#6966] + // do not conform to method extension$baz#16148's type parameter bounds + // + // And the difference is visible here. See how B is bounded from below by A#16149 + // in both cases, but in the failing case, the other type parameter has turned into + // a different A. (What is that A? It is a clone of the original A created in + // SubstMap during the call to substSym, but I am not clear on all the particulars.) + // + // bad: [B#16154 >: A#16149, A#16155 <: AnyRef#2189]($this#16156: Foo#6965[A#16155])(x#16157: B#16154)List#2457[B#16154] + // good: [B#16151 >: A#16149, A#16149 <: AnyRef#2189]($this#16150: Foo#6965[A#16149])(x#16153: B#16151)List#2457[B#16151] } override def transform(tree: Tree): Tree = { @@ -202,37 +196,56 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { super.transform(tree) } else tree case DefDef(_, _, tparams, vparamss, _, rhs) if tree.symbol.isMethodWithExtension => - val companion = currentOwner.companionModule - val origMeth = tree.symbol - val extensionName = extensionNames(origMeth).head - val extensionMeth = companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE & ~PROTECTED | FINAL) - .setAnnotations(origMeth.annotations) - companion.info.decls.enter(extensionMeth) - val newInfo = extensionMethInfo(extensionMeth, origMeth.info, currentOwner) + val origMeth = tree.symbol + val origThis = currentOwner + val origTpeParams = tparams.map(_.symbol) ::: origThis.typeParams // method type params ++ class type params + val origParams = vparamss.flatten map (_.symbol) + val companion = origThis.companionModule + + def makeExtensionMethodSymbol = { + val extensionName = extensionNames(origMeth).head.toTermName + val extensionMeth = ( + companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE & ~PROTECTED | FINAL) + setAnnotations origMeth.annotations + ) + companion.info.decls.enter(extensionMeth) + } + + val extensionMeth = makeExtensionMethodSymbol + val newInfo = extensionMethInfo(extensionMeth, origMeth.info, origThis) extensionMeth setInfo newInfo - log("Value class %s spawns extension method.\n Old: %s\n New: %s".format( - currentOwner, - origMeth.defString, - extensionMeth.defString)) // extensionMeth.defStringSeenAs(origInfo - - def thisParamRef = gen.mkAttributedStableRef(extensionMeth.info.params.head setPos extensionMeth.pos) - val GenPolyType(extensionTpeParams, extensionMono) = extensionMeth.info - val origTpeParams = (tparams map (_.symbol)) ::: currentOwner.typeParams - val extensionBody = rhs + + log(s"Value class $origThis spawns extension method.\n Old: ${origMeth.defString}\n New: ${extensionMeth.defString}") + + val GenPolyType(extensionTpeParams, MethodType(thiz :: Nil, extensionMono)) = newInfo + val extensionParams = allParameters(extensionMono) + val extensionThis = gen.mkAttributedStableRef(thiz setPos extensionMeth.pos) + + val extensionBody = ( + rhs .substituteSymbols(origTpeParams, extensionTpeParams) - .substituteSymbols(vparamss.flatten map (_.symbol), allParams(extensionMono).tail) - .substituteThis(currentOwner, thisParamRef) - .changeOwner((origMeth, extensionMeth)) - extensionDefs(companion) += atPos(tree.pos) { DefDef(extensionMeth, extensionBody) } - val extensionCallPrefix = Apply( - gen.mkTypeApply(gen.mkAttributedRef(companion), extensionMeth, origTpeParams map (_.tpeHK)), - List(This(currentOwner))) - val extensionCall = atOwner(origMeth) { - localTyper.typedPos(rhs.pos) { - gen.mkForwarder(extensionCallPrefix, mmap(vparamss)(_.symbol)) - } - } - deriveDefDef(tree)(_ => extensionCall) + .substituteSymbols(origParams, extensionParams) + .substituteThis(origThis, extensionThis) + .changeOwner(origMeth -> extensionMeth) + ) + + // Record the extension method ( FIXME: because... ? ) + extensionDefs(companion) += atPos(tree.pos)(DefDef(extensionMeth, extensionBody)) + + // These three lines are assembling Foo.bar$extension[T1, T2, ...]($this) + // which leaves the actual argument application for extensionCall. + val sel = Select(gen.mkAttributedRef(companion), extensionMeth) + val targs = origTpeParams map (_.tpeHK) + val callPrefix = gen.mkMethodCall(sel, targs, This(origThis) :: Nil) + + // Apply all the argument lists. + deriveDefDef(tree)(_ => + atOwner(origMeth)( + localTyper.typedPos(rhs.pos)( + gen.mkForwarder(callPrefix, mmap(vparamss)(_.symbol)) + ) + ) + ) case _ => super.transform(tree) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 7d6d47b410..fb8d6b934f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -450,7 +450,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { if (aparam.name != rparam.name && !rparam.isSynthetic) MacroImplParamNameMismatchError(aparam, rparam) if (isRepeated(aparam) ^ isRepeated(rparam)) MacroImplVarargMismatchError(aparam, rparam) val aparamtpe = aparam.tpe.dealias match { - case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe + case RefinedType(List(tpe), Scope(sym)) if tpe =:= MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe case tpe => tpe } checkMacroImplParamTypeMismatch(atpeToRtpe(aparamtpe), rparam) diff --git a/test/files/neg/t6963a.check b/test/files/neg/t6963a.check index 159896fd10..5858e7740a 100644 --- a/test/files/neg/t6963a.check +++ b/test/files/neg/t6963a.check @@ -1,5 +1,7 @@ -t6963a.scala:4: error: method scanRight in trait TraversableLike has changed semantics in version 2.9.0: +t6963a.scala:4: warning: method scanRight in trait TraversableLike has changed semantics in version 2.9.0: The behavior of `scanRight` has changed. The previous behavior can be reproduced with scanRight.reverse. List(1,2,3,4,5).scanRight(0)(_+_) ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found one error found diff --git a/test/files/neg/t6963b.check b/test/files/neg/t6963b.check deleted file mode 100644 index 7e205a41d0..0000000000 --- a/test/files/neg/t6963b.check +++ /dev/null @@ -1,13 +0,0 @@ -t6963b.scala:2: error: An Array will no longer match as Seq[_]. - def f1(x: Any) = x.isInstanceOf[Seq[_]] - ^ -t6963b.scala:4: error: An Array will no longer match as Seq[_]. - case _: Seq[_] => true - ^ -t6963b.scala:16: error: An Array will no longer match as Seq[_]. - case (Some(_: Seq[_]), Nil, _) => 1 - ^ -t6963b.scala:17: error: An Array will no longer match as Seq[_]. - case (None, List(_: List[_], _), _) => 2 - ^ -four errors found diff --git a/test/files/neg/t6963b.flags b/test/files/neg/t6963b.flags deleted file mode 100644 index 83caa2b147..0000000000 --- a/test/files/neg/t6963b.flags +++ /dev/null @@ -1 +0,0 @@ --Xmigration:2.7 -Xfatal-warnings
\ No newline at end of file diff --git a/test/files/neg/t6963b.scala b/test/files/neg/t6963b.scala deleted file mode 100644 index 3cfa8f0dca..0000000000 --- a/test/files/neg/t6963b.scala +++ /dev/null @@ -1,20 +0,0 @@ -object Test { - def f1(x: Any) = x.isInstanceOf[Seq[_]] - def f2(x: Any) = x match { - case _: Seq[_] => true - case _ => false - } - - def f3(x: Any) = x match { - case _: Array[_] => true - case _ => false - } - - def f4(x: Any) = x.isInstanceOf[Traversable[_]] - - def f5(x1: Any, x2: Any, x3: AnyRef) = (x1, x2, x3) match { - case (Some(_: Seq[_]), Nil, _) => 1 - case (None, List(_: List[_], _), _) => 2 - case _ => 3 - } -} |