diff options
36 files changed, 422 insertions, 49 deletions
diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala index 7aa87dc2f8..bb7e1f9b56 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala @@ -69,8 +69,7 @@ trait GenTypes { def reificationIsConcrete: Boolean = state.reificationIsConcrete def spliceType(tpe: Type): Tree = { - val quantified = currentQuantified - if (tpe.isSpliceable && !(quantified contains tpe.typeSymbol)) { + if (tpe.isSpliceable && !(boundSymbolsInCallstack contains tpe.typeSymbol)) { if (reifyDebug) println("splicing " + tpe) val tagFlavor = if (concrete) tpnme.TypeTag.toString else tpnme.WeakTypeTag.toString diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala index dc0028be38..8e13a45cdb 100644 --- a/src/compiler/scala/reflect/reify/phases/Reify.scala +++ b/src/compiler/scala/reflect/reify/phases/Reify.scala @@ -28,7 +28,10 @@ trait Reify extends GenSymbols finally currents = currents.tail } } - def currentQuantified = flatCollect(reifyStack.currents)({ case ExistentialType(quantified, _) => quantified }) + def boundSymbolsInCallstack = flatCollect(reifyStack.currents) { + case ExistentialType(quantified, _) => quantified + case PolyType(typeParams, _) => typeParams + } def current = reifyStack.currents.head def currents = reifyStack.currents diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index b66f081fb9..73738ebd21 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -259,15 +259,12 @@ trait CompilerControl { self: Global => } /** Returns parse tree for source `source`. No symbols are entered. Syntax errors are reported. - * Can be called asynchronously from presentation compiler. + * + * This method is thread-safe and as such can safely run outside of the presentation + * compiler thread. */ - def parseTree(source: SourceFile): Tree = ask { () => - getUnit(source) match { - case Some(unit) if unit.status >= JustParsed => - unit.body - case _ => - new UnitParser(new CompilationUnit(source)).parse() - } + def parseTree(source: SourceFile): Tree = { + new UnitParser(new CompilationUnit(source)).parse() } /** Asks for a computation to be done quickly on the presentation compiler thread */ diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index c93f258997..105b0e4833 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -225,7 +225,10 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") /** Called from parser, which signals hereby that a method definition has been parsed. */ override def signalParseProgress(pos: Position) { - checkForMoreWork(pos) + // We only want to be interruptible when running on the PC thread. + if(onCompilerThread) { + checkForMoreWork(pos) + } } /** Called from typechecker, which signals hereby that a node has been completely typechecked. @@ -447,7 +450,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") */ @elidable(elidable.WARNING) override def assertCorrectThread() { - assert(initializing || (Thread.currentThread() eq compileRunner), + assert(initializing || onCompilerThread, "Race condition detected: You are running a presentation compiler method outside the PC thread.[phase: %s]".format(globalPhase) + " Please file a ticket with the current stack trace at https://www.assembla.com/spaces/scala-ide/support/tickets") } diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index a55f0af116..bed8570bd0 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -262,7 +262,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends protected def newCompiler(settings: Settings, reporter: Reporter): ReplGlobal = { settings.outputDirs setSingleOutput virtualDirectory settings.exposeEmptyPackage.value = true - new Global(settings, reporter) with ReplGlobal + new Global(settings, reporter) with ReplGlobal { + override def toString: String = "<global>" + } } /** Parent classloader. Overridable. */ diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 0a98d45cac..3df6334ec1 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -175,7 +175,6 @@ trait ScalaSettings extends AbsScalaSettings val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.") val Yinvalidate = StringSetting ("-Yinvalidate", "classpath-entry", "Invalidate classpath entry before run", "") val noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.") - val companionsInPkgObjs = BooleanSetting("-Ycompanions-in-pkg-objs", "Allow companion objects and case classes in package objects. See issue SI-5954.") val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes") val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 0b46582cbf..f6142a81be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -388,7 +388,7 @@ abstract class Duplicators extends Analyzer { cases } - super.typedPos(tree.pos, mode, pt)(Match(scrut, cases1)) + super.typed(atPos(tree.pos)(Match(scrut, cases1)), mode, pt) case EmptyTree => // no need to do anything, in particular, don't set the type to null, EmptyTree.tpe_= asserts diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index 80d628d7ac..f7579ad249 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -2819,7 +2819,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // compare to the fully known type `tp` (modulo abstract types), // so that we can rule out stuff like: sealed trait X[T]; class XInt extends X[Int] --> XInt not valid when enumerating X[String] // however, must approximate abstract types in - val subTp = appliedType(pre.memberType(sym), sym.typeParams.map(_ => WildcardType)) + + val memberType = nestedMemberType(sym, pre, tpApprox.typeSymbol.owner) + val subTp = appliedType(memberType, sym.typeParams.map(_ => WildcardType)) val subTpApprox = typer.infer.approximateAbstracts(subTp) // TODO: needed? // patmatDebug("subtp"+(subTpApprox <:< tpApprox, subTpApprox, tpApprox)) if (subTpApprox <:< tpApprox) Some(checkableType(subTp)) diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 39f6f764e7..242eb9c9fe 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -50,6 +50,10 @@ trait SyntheticMethods extends ast.TreeDSL { else if (clazz.isDerivedValueClass) valueSymbols else Nil } + private lazy val renamedCaseAccessors = perRunCaches.newMap[Symbol, mutable.Map[TermName, TermName]]() + /** Does not force the info of `caseclazz` */ + final def caseAccessorName(caseclazz: Symbol, paramName: TermName) = + (renamedCaseAccessors get caseclazz).fold(paramName)(_(paramName)) /** Add the synthetic methods to case classes. */ @@ -384,6 +388,8 @@ trait SyntheticMethods extends ast.TreeDSL { // TODO: shouldn't the next line be: `original resetFlag CASEACCESSOR`? ddef.symbol resetFlag CASEACCESSOR lb += logResult("case accessor new")(newAcc) + val renamedInClassMap = renamedCaseAccessors.getOrElseUpdate(clazz, mutable.Map() withDefault(x => x)) + renamedInClassMap(original.name.toTermName) = newAcc.symbol.name.toTermName } (lb ++= templ.body ++= synthesize()).toList diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5add9b4991..dc5491a509 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1801,29 +1801,29 @@ trait Typers extends Modes with Adaptations with Tags { // SI-5954. On second compile of a companion class contained in a package object we end up // with some confusion of names which leads to having two symbols with the same name in the - // same owner. Until that can be straightened out we can't allow companion objects in package + // same owner. Until that can be straightened out we will warn on companion objects in package // objects. But this code also tries to be friendly by distinguishing between case classes and // user written companion pairs - def restrictPackageObjectMembers(mdef : ModuleDef) = for (m <- mdef.symbol.info.members) { + def warnPackageObjectMembers(mdef : ModuleDef) = for (m <- mdef.symbol.info.members) { // ignore synthetic objects, because the "companion" object to a case class is synthetic and // we only want one error per case class if (!m.isSynthetic) { // can't handle case classes in package objects - if (m.isCaseClass) pkgObjectRestriction(m, mdef, "case") + if (m.isCaseClass) pkgObjectWarning(m, mdef, "case") // can't handle companion class/object pairs in package objects else if ((m.isClass && m.companionModule != NoSymbol && !m.companionModule.isSynthetic) || (m.isModule && m.companionClass != NoSymbol && !m.companionClass.isSynthetic)) - pkgObjectRestriction(m, mdef, "companion") + pkgObjectWarning(m, mdef, "companion") } - def pkgObjectRestriction(m : Symbol, mdef : ModuleDef, restricted : String) = { + def pkgObjectWarning(m : Symbol, mdef : ModuleDef, restricted : String) = { val pkgName = mdef.symbol.ownerChain find (_.isPackage) map (_.decodedName) getOrElse mdef.symbol.toString - context.error(if (m.pos.isDefined) m.pos else mdef.pos, s"implementation restriction: package object ${pkgName} cannot contain ${restricted} ${m}. Instead, ${m} should be placed directly in package ${pkgName}.") + context.warning(if (m.pos.isDefined) m.pos else mdef.pos, s"${m} should be placed directly in package ${pkgName} instead of package object ${pkgName}. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954.") } } - if (!settings.companionsInPkgObjs.value && mdef.symbol.isPackageObject) - restrictPackageObjectMembers(mdef) + if (mdef.symbol.isPackageObject) + warnPackageObjectMembers(mdef) treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType } diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 69074e4c0c..b51dc0ccd5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -94,12 +94,33 @@ trait Unapplies extends ast.TreeDSL * @param param The name of the parameter of the unapply method, assumed to be of type C[Ts] * @param caseclazz The case class C[Ts] */ - private def caseClassUnapplyReturnValue(param: Name, caseclazz: Symbol) = { - def caseFieldAccessorValue(selector: Symbol): Tree = Ident(param) DOT selector + private def caseClassUnapplyReturnValue(param: Name, caseclazz: ClassDef) = { + def caseFieldAccessorValue(selector: ValDef): Tree = { + val accessorName = selector.name + val privateLocalParamAccessor = caseclazz.impl.body.collectFirst { + case dd: ValOrDefDef if dd.name == accessorName && dd.mods.isPrivateLocal => dd.symbol + } + privateLocalParamAccessor match { + case None => + // Selecting by name seems to be the most straight forward way here to + // avoid forcing the symbol of the case class in order to list the accessors. + val maybeRenamedAccessorName = caseAccessorName(caseclazz.symbol, accessorName) + Ident(param) DOT maybeRenamedAccessorName + case Some(sym) => + // But, that gives a misleading error message in neg/t1422.scala, where a case + // class has an illegal private[this] parameter. We can detect this by checking + // the modifiers on the param accessors. + // + // We just generate a call to that param accessor here, which gives us an inaccessible + // symbol error, as before. + Ident(param) DOT sym + } + } - caseclazz.caseFieldAccessors match { - case Nil => TRUE - case xs => SOME(xs map caseFieldAccessorValue: _*) + // Working with trees, rather than symbols, to avoid cycles like SI-5082 + constrParamss(caseclazz).take(1).flatten match { + case Nil => TRUE + case xs => SOME(xs map caseFieldAccessorValue: _*) } } @@ -158,7 +179,7 @@ trait Unapplies extends ast.TreeDSL } val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName, classType(cdef, tparams), EmptyTree)) val ifNull = if (constrParamss(cdef).head.isEmpty) FALSE else REF(NoneModule) - val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef.symbol) }, ifNull)(Ident(unapplyParamName)) + val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef) }, ifNull)(Ident(unapplyParamName)) atPos(cdef.pos.focus)( DefDef(caseMods, method, tparams, List(cparams), TypeTree(), body) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 72ad84edec..4ffd198dc4 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -2515,7 +2515,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => } override def outerSource: Symbol = - if (originalName == nme.OUTER) initialize.referenced + // SI-6888 Approximate the name to workaround the deficiencies in `nme.originalName` + // in the face of clases named '$'. SI-2806 remains open to address the deeper problem. + if (originalName endsWith (nme.OUTER)) initialize.referenced else NoSymbol def setModuleClass(clazz: Symbol): TermSymbol = { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 0dd98fb6ae..b708ca0fd6 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -586,9 +586,9 @@ trait Types extends api.Types { self: SymbolTable => * Expands type aliases and converts higher-kinded TypeRefs to PolyTypes. * Functions on types are also implemented as PolyTypes. * - * Example: (in the below, <List> is the type constructor of List) - * TypeRef(pre, <List>, List()) is replaced by - * PolyType(X, TypeRef(pre, <List>, List(X))) + * Example: (in the below, `<List>` is the type constructor of List) + * TypeRef(pre, `<List>`, List()) is replaced by + * PolyType(X, TypeRef(pre, `<List>`, List(X))) */ def normalize = this // @MAT @@ -4974,6 +4974,51 @@ trait Types extends api.Types { self: SymbolTable => } } + /** + * A more persistent version of `Type#memberType` which does not require + * that the symbol is a direct member of the prefix. + * + * For instance: + * + * {{{ + * class C[T] { + * sealed trait F[A] + * object X { + * object S1 extends F[T] + * } + * class S2 extends F[T] + * } + * object O extends C[Int] { + * def foo(f: F[Int]) = f match {...} // need to enumerate sealed subtypes of the scrutinee here. + * } + * class S3 extends O.F[String] + * + * nestedMemberType(<S1>, <O.type>, <C>) = O.X.S1.type + * nestedMemberType(<S2>, <O.type>, <C>) = O.S2.type + * nestedMemberType(<S3>, <O.type>, <C>) = S3.type + * }}} + * + * @param sym The symbol of the subtype + * @param pre The prefix from which the symbol is seen + * @param owner + */ + def nestedMemberType(sym: Symbol, pre: Type, owner: Symbol): Type = { + def loop(tp: Type): Type = + if (tp.isTrivial) tp + else if (tp.prefix.typeSymbol isNonBottomSubClass owner) { + val widened = tp match { + case _: ConstantType => tp // Java enum constants: don't widen to the enum type! + case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect. + } + widened asSeenFrom (pre, tp.typeSymbol.owner) + } + else loop(tp.prefix) memberType tp.typeSymbol + + val result = loop(sym.tpeHK) + assert(sym.isTerm || result.typeSymbol == sym, s"($result).typeSymbol = ${result.typeSymbol}; expected ${sym}") + result + } + /** The most deeply nested owner that contains all the symbols * of thistype or prefixless typerefs/singletype occurrences in given type. */ diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index ec3501d5bc..81368df7a6 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -47,6 +47,4 @@ abstract class MutableSettings extends AbsSettings { def XoldPatmat: BooleanSetting def XnoPatmatAnalysis: BooleanSetting def XfullLubs: BooleanSetting - def companionsInPkgObjs: BooleanSetting - } diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index 2d5b76f094..0e0cf3fc40 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -43,7 +43,6 @@ private[reflect] class Settings extends MutableSettings { val printtypes = new BooleanSetting(false) val uniqid = new BooleanSetting(false) val verbose = new BooleanSetting(false) - val companionsInPkgObjs = new BooleanSetting(false) val Yrecursion = new IntSetting(0) val maxClassfileName = new IntSetting(255) diff --git a/test/files/neg/t5954.check b/test/files/neg/t5954.check index 3ca47cd430..ed10658b24 100644 --- a/test/files/neg/t5954.check +++ b/test/files/neg/t5954.check @@ -1,16 +1,16 @@ -t5954.scala:36: error: implementation restriction: package object A cannot contain case class D. Instead, class D should be placed directly in package A. +t5954.scala:36: error: class D should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. case class D() ^ -t5954.scala:35: error: implementation restriction: package object A cannot contain companion object C. Instead, object C should be placed directly in package A. +t5954.scala:35: error: object C should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. object C ^ -t5954.scala:34: error: implementation restriction: package object A cannot contain companion trait C. Instead, trait C should be placed directly in package A. +t5954.scala:34: error: trait C should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. trait C ^ -t5954.scala:33: error: implementation restriction: package object A cannot contain companion object B. Instead, object B should be placed directly in package A. +t5954.scala:33: error: object B should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. object B ^ -t5954.scala:32: error: implementation restriction: package object A cannot contain companion class B. Instead, class B should be placed directly in package A. +t5954.scala:32: error: class B should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. class B ^ 5 errors found diff --git a/test/files/neg/t5954.flags b/test/files/neg/t5954.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t5954.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/t5954.scala b/test/files/neg/t5954.scala index 9e6f5392c7..3ccb5ed3ff 100644 --- a/test/files/neg/t5954.scala +++ b/test/files/neg/t5954.scala @@ -1,4 +1,4 @@ -// if you ever think you've fixed the underlying reason for the implementation restrictions +// if you ever think you've fixed the underlying reason for the warning // imposed by SI-5954, then here's a test that should pass with two "succes"es // //import scala.tools.partest._ diff --git a/test/files/pos/SI-7100.scala b/test/files/pos/SI-7100.scala new file mode 100644 index 0000000000..7cb6356ec8 --- /dev/null +++ b/test/files/pos/SI-7100.scala @@ -0,0 +1,6 @@ +class Buffer { + def f[@specialized(Int) T](): T = 0 match { + case 0 => 0.asInstanceOf[T] + case 1 => 0.asInstanceOf[T] + } +} diff --git a/test/files/pos/package-case.flags b/test/files/pos/package-case.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/package-case.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t2130-1.flags b/test/files/pos/t2130-1.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t2130-1.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t2130-2.flags b/test/files/pos/t2130-2.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t2130-2.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t3999b.flags b/test/files/pos/t3999b.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t3999b.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t4052.flags b/test/files/pos/t4052.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t4052.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t5082.scala b/test/files/pos/t5082.scala new file mode 100644 index 0000000000..63eeda38ba --- /dev/null +++ b/test/files/pos/t5082.scala @@ -0,0 +1,14 @@ +trait Something[T] +object Test { class A } +case class Test() extends Something[Test.A] + +object User { + val Test() = Test() +} + +object Wrap { + trait Something[T] + object Test { class A } + case class Test(a: Int, b: Int)(c: String) extends Something[Test.A] + val Test(x, y) = Test(1, 2)(""); (x + y).toString +} diff --git a/test/files/pos/t6146.flags b/test/files/pos/t6146.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/pos/t6146.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/t6146.scala b/test/files/pos/t6146.scala new file mode 100644 index 0000000000..b5bde826b1 --- /dev/null +++ b/test/files/pos/t6146.scala @@ -0,0 +1,60 @@ +// No unreachable or exhaustiveness warnings, please. + +// +// The reported bug +// + +trait AxisCompanion { + sealed trait Format + object Format { + case object Decimal extends Format + case object Integer extends Format + // Gives an unrelated warning: The outer reference in this type test cannot be checked at run time. + //final case class Time( hours: Boolean = false, millis: Boolean = true ) extends Format + } +} +object Axis extends AxisCompanion +class Axis { + import Axis._ + def test( f: Format ) = f match { + case Format.Integer => "Int" + // case Format.Time( hours, millis ) => "Time" + case Format.Decimal => "Dec" + } +} + + +// +// Some tricksier variations +// + +trait T1[X] { + trait T2[Y] { + sealed trait Format + object Format { + case object Decimal extends Format + case object Integer extends Format + } + } +} + +object O1 extends T1[Any] { + object O2 extends T2[Any] { + + } +} + +case object Shorty extends O1.O2.Format + +class Test1 { + import O1.O2._ + val FI: Format.Integer.type = Format.Integer + def test( f: Format ) = { + val ff: f.type = f + ff match { + case FI => "Int" + case Format.Decimal => "Dec" + case Shorty => "Sho" + } + } +} diff --git a/test/files/presentation/ide-t1001326.check b/test/files/presentation/ide-t1001326.check new file mode 100644 index 0000000000..0ac15faed4 --- /dev/null +++ b/test/files/presentation/ide-t1001326.check @@ -0,0 +1,4 @@ +Unique OK +Unattributed OK +NeverModify OK +AlwaysParseTree OK
\ No newline at end of file diff --git a/test/files/presentation/ide-t1001326/Test.scala b/test/files/presentation/ide-t1001326/Test.scala new file mode 100644 index 0000000000..3091da4b40 --- /dev/null +++ b/test/files/presentation/ide-t1001326/Test.scala @@ -0,0 +1,91 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest +import scala.reflect.internal.util.SourceFile +import scala.tools.nsc.interactive.Response + +object Test extends InteractiveTest { + + override def execute(): Unit = { + val sf = sourceFiles.find(_.file.name == "A.scala").head + uniqueParseTree_t1001326(sf) + unattributedParseTree_t1001326(sf) + neverModifyParseTree_t1001326(sf) + shouldAlwaysReturnParseTree_t1001326(sf) + } + + /** + * Asking twice for a parseTree on the same source should always return a new tree + */ + private def uniqueParseTree_t1001326(sf: SourceFile) { + val parseTree1 = compiler.parseTree(sf) + val parseTree2 = compiler.parseTree(sf) + if (parseTree1 != parseTree2) { + reporter.println("Unique OK") + } else { + reporter.println("Unique FAILED") + } + } + + /** + * A parseTree should never contain any symbols or types + */ + private def unattributedParseTree_t1001326(sf: SourceFile) { + if (noSymbolsOrTypes(compiler.parseTree(sf))) { + reporter.println("Unattributed OK") + } else { + reporter.println("Unattributed FAILED") + } + } + + /** + * Once you have obtained a parseTree it should never change + */ + private def neverModifyParseTree_t1001326(sf: SourceFile) { + val parsedTree = compiler.parseTree(sf) + loadSourceAndWaitUntilTypechecked(sf) + if (noSymbolsOrTypes(parsedTree)) { + reporter.println("NeverModify OK") + } else { + reporter.println("NeverModify FAILED") + } + } + + /** + * Should always return a parse tree + */ + private def shouldAlwaysReturnParseTree_t1001326(sf: SourceFile) { + loadSourceAndWaitUntilTypechecked(sf) + if (noSymbolsOrTypes(compiler.parseTree(sf))) { + reporter.println("AlwaysParseTree OK") + } else { + reporter.println("AlwaysParseTree FAILED") + } + } + + /** + * Load a source and block while it is type-checking. + */ + private def loadSourceAndWaitUntilTypechecked(sf: SourceFile): Unit = { + compiler.askToDoFirst(sf) + val res = new Response[Unit] + compiler.askReload(List(sf), res) + res.get + askLoadedTyped(sf).get + } + + /** + * Traverses a tree and makes sure that there are no types or symbols present in the tree with + * the exception of the symbol for the package 'scala'. This is because that symbol will be + * present in some of the nodes that the compiler generates. + */ + private def noSymbolsOrTypes(tree: compiler.Tree): Boolean = { + tree.forAll { t => + (t.symbol == null || + t.symbol == compiler.NoSymbol || + t.symbol == compiler.definitions.ScalaPackage // ignore the symbol for the scala package for now + ) && ( + t.tpe == null || + t.tpe == compiler.NoType) + } + } + +}
\ No newline at end of file diff --git a/test/files/presentation/ide-t1001326/src/a/A.scala b/test/files/presentation/ide-t1001326/src/a/A.scala new file mode 100644 index 0000000000..c82ca02231 --- /dev/null +++ b/test/files/presentation/ide-t1001326/src/a/A.scala @@ -0,0 +1,5 @@ +package a + +class A { + def foo(s: String) = s + s +}
\ No newline at end of file diff --git a/test/files/run/t6113.check b/test/files/run/t6113.check new file mode 100644 index 0000000000..65fb3cd090 --- /dev/null +++ b/test/files/run/t6113.check @@ -0,0 +1 @@ +Foo[[X](Int, X)] diff --git a/test/files/run/t6113.scala b/test/files/run/t6113.scala new file mode 100644 index 0000000000..321cae86a3 --- /dev/null +++ b/test/files/run/t6113.scala @@ -0,0 +1,6 @@ +trait Foo[C[_]] + +object Test extends App { + import scala.reflect.runtime.universe._ + println(typeOf[Foo[({type l[X] = (Int, X)})#l]]) +}
\ No newline at end of file diff --git a/test/files/run/t6146b.check b/test/files/run/t6146b.check new file mode 100644 index 0000000000..b664d1152a --- /dev/null +++ b/test/files/run/t6146b.check @@ -0,0 +1,52 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> :power +** Power User mode enabled - BEEP WHIR GYVE ** +** :phase has been set to 'typer'. ** +** scala.tools.nsc._ has been imported ** +** global._, definitions._ also imported ** +** Try :help, :vals, power.<tab> ** + +scala> val u = rootMirror.universe; import u._, language._ +u: $r.intp.global.type = <global> +import u._ +import language._ + +scala> val S1 = typeOf[c.X.S1.type forSome { val c: C[_] }].typeSymbol.tpeHK +S1: u.Type = C.X.S1.type + +scala> val S2 = typeOf[O.S2].typeSymbol.tpeHK +S2: u.Type = C.this.S2 + +scala> val S3 = typeOf[O.S3].typeSymbol.tpeHK +S3: u.Type = O.S3 + +scala> val S4 = typeOf[S4].typeSymbol.tpeHK +S4: u.Type = S4 + +scala> val F = typeOf[c.F[_] forSome { val c: C[_] }].typeSymbol.tpeHK +F: u.Type = C.this.F + +scala> val fTpe = typeOf[O.type].decl(newTermName("foo")).paramss.head.head.tpe +fTpe: u.Type = O.F[Int] + +scala> def memType(sub: Type, scrut: Type): Type = + nestedMemberType(sub.typeSymbol, scrut.prefix, scrut.typeSymbol.owner) +memType: (sub: u.Type, scrut: u.Type)u.Type + +scala> + +scala> memType(S1, fTpe) +res0: u.Type = O.X.S1.type + +scala> memType(S2, fTpe) +res1: u.Type = O.S2 + +scala> memType(S3, fTpe) +res2: u.Type = O.S3 + +scala> memType(S4, fTpe) +res3: u.Type = S4 + +scala> diff --git a/test/files/run/t6146b.scala b/test/files/run/t6146b.scala new file mode 100644 index 0000000000..adcd40d2ee --- /dev/null +++ b/test/files/run/t6146b.scala @@ -0,0 +1,39 @@ +import scala.tools.partest.ReplTest + +class A { + sealed trait F[A] +} + +class C[T] extends A { + sealed trait F[A] + object X { + object S1 extends F[T] + } + class S2 extends F[T] +} +object O extends C[Int] { + def foo(f: F[Int]) = f match { case X.S1 => } + + class S3 extends F[Int] +} +class S4 extends O.F[String] + +object Test extends ReplTest { + override def code = """ +:power +val u = rootMirror.universe; import u._, language._ +val S1 = typeOf[c.X.S1.type forSome { val c: C[_] }].typeSymbol.tpeHK +val S2 = typeOf[O.S2].typeSymbol.tpeHK +val S3 = typeOf[O.S3].typeSymbol.tpeHK +val S4 = typeOf[S4].typeSymbol.tpeHK +val F = typeOf[c.F[_] forSome { val c: C[_] }].typeSymbol.tpeHK +val fTpe = typeOf[O.type].decl(newTermName("foo")).paramss.head.head.tpe +def memType(sub: Type, scrut: Type): Type = + nestedMemberType(sub.typeSymbol, scrut.prefix, scrut.typeSymbol.owner) + +memType(S1, fTpe) +memType(S2, fTpe) +memType(S3, fTpe) +memType(S4, fTpe) + """.stripMargin.trim +}
\ No newline at end of file diff --git a/test/files/run/t6888.check b/test/files/run/t6888.check new file mode 100644 index 0000000000..4e8a2de2db --- /dev/null +++ b/test/files/run/t6888.check @@ -0,0 +1,3 @@ +2 +3 +3 diff --git a/test/files/run/t6888.scala b/test/files/run/t6888.scala new file mode 100644 index 0000000000..0c64cbe5b6 --- /dev/null +++ b/test/files/run/t6888.scala @@ -0,0 +1,19 @@ +class C { + val x = 1 + object $ { + val y = x + x + class abc$ { + def xy = x + y + } + object abc$ { + def xy = x + y + } + } +} + +object Test extends App { + val c = new C() + println(c.$.y) + println(c.$.abc$.xy) + println(new c.$.abc$().xy) +} |