diff options
Diffstat (limited to 'src/compiler')
11 files changed, 109 insertions, 80 deletions
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 3ce8829af6..bb9549deba 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -97,7 +97,7 @@ trait Types extends api.Types { self: SymbolTable => */ private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints" - protected val enableTypeVarExperimentals = settings.Xexperimental.value + protected val enableTypeVarExperimentals = settings.Xexperimental.value || settings.YvirtPatmat.value /** Empty immutable maps to avoid allocations. */ private val emptySymMap = immutable.Map[Symbol, Symbol]() diff --git a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala index 0092f73fe3..b556c33aba 100644 --- a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala @@ -43,4 +43,5 @@ abstract class MutableSettings extends AbsSettings { def Yrecursion: IntSetting def maxClassfileName: IntSetting def Xexperimental: BooleanSetting + def YvirtPatmat: BooleanSetting }
\ No newline at end of file diff --git a/src/compiler/scala/reflect/runtime/Settings.scala b/src/compiler/scala/reflect/runtime/Settings.scala index 8b475da0d3..27e90c94bd 100644 --- a/src/compiler/scala/reflect/runtime/Settings.scala +++ b/src/compiler/scala/reflect/runtime/Settings.scala @@ -34,4 +34,5 @@ class Settings extends internal.settings.MutableSettings { val maxClassfileName = new IntSetting(255) val Xexperimental = new BooleanSetting(false) val deepCloning = new BooleanSetting (false) + val YvirtPatmat = new BooleanSetting(false) } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 41d9d93e7a..8e568eca79 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -944,11 +944,10 @@ abstract class GenICode extends SubComponent { "Trying to access the this of another class: " + "tree.symbol = " + tree.symbol + ", ctx.clazz.symbol = " + ctx.clazz.symbol + " compilation unit:"+unit) if (tree.symbol.isModuleClass && tree.symbol != ctx.clazz.symbol) { - debuglog("LOAD_MODULE from 'This': " + tree.symbol); - assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree) - genLoadModule(ctx, tree.symbol, tree.pos) + genLoadModule(ctx, tree) generatedType = REFERENCE(tree.symbol) - } else { + } + else { ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos) generatedType = REFERENCE( if (tree.symbol == ArrayClass) ObjectClass else ctx.clazz.symbol @@ -961,11 +960,7 @@ abstract class GenICode extends SubComponent { "Selection of non-module from empty package: " + tree + " sym: " + tree.symbol + " at: " + (tree.pos) ) - debuglog("LOAD_MODULE from Select(<emptypackage>): " + tree.symbol) - - assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree) - genLoadModule(ctx, tree.symbol, tree.pos) - ctx + genLoadModule(ctx, tree) case Select(qualifier, selector) => val sym = tree.symbol @@ -973,14 +968,13 @@ abstract class GenICode extends SubComponent { val hostClass = qualifier.tpe.typeSymbol.orElse(sym.owner) if (sym.isModule) { - debuglog("LOAD_MODULE from Select(qualifier, selector): " + sym) - assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree) - genLoadModule(ctx, sym, tree.pos) - ctx - } else if (sym.isStaticMember) { + genLoadModule(ctx, tree) + } + else if (sym.isStaticMember) { ctx.bb.emit(LOAD_FIELD(sym, true) setHostClass hostClass, tree.pos) ctx - } else { + } + else { val ctx1 = genLoadQualifier(tree, ctx) ctx1.bb.emit(LOAD_FIELD(sym, false) setHostClass hostClass, tree.pos) ctx1 @@ -990,11 +984,10 @@ abstract class GenICode extends SubComponent { val sym = tree.symbol if (!sym.isPackage) { if (sym.isModule) { - debuglog("LOAD_MODULE from Ident(name): " + sym) - assert(!sym.isPackageClass, "Cannot use package as value: " + tree) - genLoadModule(ctx, sym, tree.pos) + genLoadModule(ctx, tree) generatedType = toTypeKind(sym.info) - } else { + } + else { try { val Some(l) = ctx.method.lookupLocal(sym) ctx.bb.emit(LOAD_LOCAL(l), tree.pos) @@ -1207,8 +1200,19 @@ abstract class GenICode extends SubComponent { genLoad(arg, res, toTypeKind(tpe)) } - private def genLoadModule(ctx: Context, sym: Symbol, pos: Position) { - ctx.bb.emit(LOAD_MODULE(sym), pos) + private def genLoadModule(ctx: Context, tree: Tree): Context = { + // Working around SI-5604. Rather than failing the compile when we see + // a package here, check if there's a package object. + val sym = ( + if (!tree.symbol.isPackageClass) tree.symbol + else tree.symbol.info.member(nme.PACKAGE) match { + case NoSymbol => assert(false, "Cannot use package as value: " + tree) ; NoSymbol + case s => Console.err.println("Bug: found package class where package object expected. Converting.") ; s.moduleClass + } + ) + debuglog("LOAD_MODULE from %s: %s".format(tree.shortClass, sym)) + ctx.bb.emit(LOAD_MODULE(sym), tree.pos) + ctx } def genConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = { @@ -1567,9 +1571,10 @@ abstract class GenICode extends SubComponent { val ctx1 = genLoad(l, ctx, ObjectReference) val ctx2 = genLoad(r, ctx1, ObjectReference) - ctx2.bb.emit(CALL_METHOD(equalsMethod, if (settings.optimise.value) Dynamic else Static(false))) - ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) - ctx2.bb.close + ctx2.bb.emitOnly( + CALL_METHOD(equalsMethod, if (settings.optimise.value) Dynamic else Static(false)), + CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL) + ) } else { if (isNull(l)) diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index 9a025b0d14..f32564f097 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -8,7 +8,7 @@ package doc import scala.util.control.ControlThrowable import reporters.Reporter -import util.NoPosition +import util.{ NoPosition, BatchSourceFile} import io.{ File, Directory } import DocParser.Parsed @@ -46,13 +46,19 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor override def forScaladoc = true } - /** Creates a scaladoc site for all symbols defined in this call's `files`, - * as well as those defined in `files` of previous calls to the same processor. + /** Creates a scaladoc site for all symbols defined in this call's `source`, + * as well as those defined in `sources` of previous calls to the same processor. * @param files The list of paths (relative to the compiler's source path, * or absolute) of files to document. */ - def makeUniverse(files: List[String]): Option[Universe] = { + def makeUniverse(source: Either[List[String], String]): Option[Universe] = { assert(settings.docformat.value == "html") - new compiler.Run() compile files + source match { + case Left(files) => + new compiler.Run() compile files + case Right(sourceCode) => + new compiler.Run() compileSources List(new BatchSourceFile("newSource", sourceCode)) + } + if (reporter.hasErrors) return None @@ -111,7 +117,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor docletInstance match { case universer: Universer => - val universe = makeUniverse(files) getOrElse { throw NoCompilerRunException } + val universe = makeUniverse(Left(files)) getOrElse { throw NoCompilerRunException } universer setUniverse universe docletInstance match { diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index c8c5f1ec11..f059b5c0cb 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -35,7 +35,7 @@ class Template(universe: doc.Universe, tpl: DocTemplateEntity) extends HtmlPage </xml:group> val valueMembers = - tpl.methods.filterNot(_.isBridge) ++ tpl.values ++ tpl.templates.filter(x => x.isObject || x.isPackage) sorted + tpl.methods ++ tpl.values ++ tpl.templates.filter(x => x.isObject || x.isPackage) sorted val (absValueMembers, nonAbsValueMembers) = valueMembers partition (_.isAbstract) diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 496d004fd8..dd1c75c322 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -247,7 +247,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { protected lazy val memberSyms = // Only this class's constructors are part of its members, inherited constructors are not. - sym.info.members.filter(s => localShouldDocument(s) && (!s.isConstructor || s.owner == sym)) + sym.info.members.filter(s => localShouldDocument(s) && (!s.isConstructor || s.owner == sym) && !isPureBridge(sym) ) val members = memberSyms flatMap (makeMember(_, this)) val templates = members collect { case c: DocTemplateEntity => c } @@ -705,4 +705,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def localShouldDocument(aSym: Symbol): Boolean = { !aSym.isPrivate && (aSym.isProtected || aSym.privateWithin == NoSymbol) && !aSym.isSynthetic } + + /** Filter '@bridge' methods only if *they don't override non-bridge methods*. See SI-5373 for details */ + def isPureBridge(sym: Symbol) = sym.isBridge && sym.allOverriddenSymbols.forall(_.isBridge) } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index e37f5784c9..764823d786 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -376,21 +376,16 @@ trait ContextErrors { setError(tree) } - def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) = { - def anonMessage = ( - "\nThe argument types of an anonymous function must be fully known. (SLS 8.5)" + - "\nExpected type was: " + pt.toLongString - ) - - val suffix = - if (!vparam.mods.isSynthetic) "" - else " for expanded function" + (fun match { - case Function(_, Match(_, _)) => anonMessage - case _ => " " + fun - }) - - issueNormalTypeError(vparam, "missing parameter type" + suffix) - } + def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) = + if (vparam.mods.isSynthetic) fun match { + case Function(_, Match(_, _)) => MissingParameterTypeAnonMatchError(vparam, pt) + case _ => issueNormalTypeError(vparam, "missing parameter type for expanded function " + fun) + } else issueNormalTypeError(vparam, "missing parameter type") + + def MissingParameterTypeAnonMatchError(vparam: Tree, pt: Type) = + issueNormalTypeError(vparam, "missing parameter type for expanded function\n"+ + "The argument types of an anonymous function must be fully known. (SLS 8.5)\n"+ + "Expected type was: " + pt.toLongString) def ConstructorsOrderError(tree: Tree) = { issueNormalTypeError(tree, "called constructor's definition must precede calling constructor's definition") diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index bbc36e01c9..aff8368f75 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -1649,7 +1649,7 @@ class Foo(x: Other) { x._1 } // no error in this order def catchAll = matchFailGen map { matchFailGen => val scrutRef = if(scrutSym ne NoSymbol) REF(scrutSym) else EmptyTree // for alternatives - LabelDef(nextCase, Nil, matchEnd APPLY (matchFailGen(scrutRef))) // need to jump to matchEnd with result generated by matchFailGen (could be `FALSE` for isDefinedAt) + LabelDef(nextCase, Nil, matchEnd APPLY (_asInstanceOf(matchFailGen(scrutRef), restpe))) // need to jump to matchEnd with result generated by matchFailGen (could be `FALSE` for isDefinedAt) } toList // catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default) // if the last user-defined case is a default, it will never jump to the next case; it will go immediately to matchEnd diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index d98d248231..013a74da7e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1625,12 +1625,18 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R case _ => tree } + // skip refchecks in patterns.... result = result match { case CaseDef(pat, guard, body) => inPattern = true val pat1 = transform(pat) inPattern = false treeCopy.CaseDef(tree, pat1, transform(guard), transform(body)) + case LabelDef(_, _, _) if gen.hasSynthCaseSymbol(result) => + inPattern = true + val res = deriveLabelDef(result)(transform) + inPattern = false + res case _ => super.transform(result) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 95a1eafae2..06a7311f79 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2144,15 +2144,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case Annotated(Ident(nme.synthSwitch), selector) => (selector, false) case s => (s, true) } - val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) - val selectorTp = packCaptured(selector1.tpe.widen) - val casesTyped = typedCases(cases, selectorTp, resTp) + val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) + val selectorTp = packCaptured(selector1.tpe.widen) + + val casesTyped = typedCases(cases, selectorTp, resTp) val caseTypes = casesTyped map (c => packedType(c, context.owner).deconst) - val (ownType0, needAdapt) = if (isFullyDefined(resTp)) (resTp, false) else weakLub(caseTypes) - val ownType = ownType0.skolemizeExistential(context.owner, context.tree) - val casesAdapted = if (!needAdapt) casesTyped else casesTyped map (adaptCase(_, mode, ownType)) - // val (owntype0, needAdapt) = ptOrLub(casesTyped map (x => repackExistential(x.tpe))) - // val owntype = elimAnonymousClass(owntype0) + val (ownType, needAdapt) = if (isFullyDefined(resTp)) (resTp, false) else weakLub(caseTypes) + + val casesAdapted = if (!needAdapt) casesTyped else casesTyped map (adaptCase(_, mode, ownType)) + (selector1, selectorTp, casesAdapted, ownType, doTranslation) } @@ -2166,14 +2166,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { Match(selector1, casesAdapted) setType ownType // setType of the Match to avoid recursing endlessly } else { val scrutType = repeatedToSeq(elimAnonymousClass(selectorTp)) - MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownType), scrutType, matchFailGen) + // we've packed the type for each case in prepareTranslateMatch so that if all cases have the same existential case, we get a clean lub + // here, we should open up the existential again + // relevant test cases: pos/existentials-harmful.scala, pos/gadt-gilles.scala, pos/t2683.scala, pos/virtpatmat_exist4.scala + MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownType.skolemizeExistential(context.owner, context.tree)), scrutType, matchFailGen) } } def typedMatchAnonFun(tree: Tree, cases: List[CaseDef], mode: Int, pt0: Type, selOverride: Option[(List[ValDef], Tree)] = None) = { val pt = deskolemizeGADTSkolems(pt0) val targs = pt.normalize.typeArgs - val arity = if (isFunctionType(pt)) targs.length - 1 else 1 + val arity = if (isFunctionType(pt)) targs.length - 1 else 1 // TODO pt should always be a (Partial)Function, right? val ptRes = if (targs.isEmpty) WildcardType else targs.last // may not be fully defined val isPartial = pt.typeSymbol == PartialFunctionClass @@ -2185,6 +2188,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def mkParams(methodSym: Symbol) = { selOverride match { + case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree) case None => val ps = methodSym newSyntheticValueParams targs.init // is there anything we can do if targs.isEmpty?? val ids = ps map (p => Ident(p.name)) @@ -2210,44 +2214,52 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass) val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL) val (paramSyms, selector) = mkParams(methodSym) - methodSym setInfoAndEnter MethodType(paramSyms, AnyClass.tpe) - val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) + if (selector eq EmptyTree) EmptyTree + else { + methodSym setInfoAndEnter MethodType(paramSyms, AnyClass.tpe) + + val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) + paramSyms foreach (methodBodyTyper.context.scope enter _) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) - val formalTypes = paramSyms map (_.tpe) - val parents = - if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe) - else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe) + val formalTypes = paramSyms map (_.tpe) + val parents = + if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe) + else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe) - anonClass setInfo ClassInfoType(parents, newScope, anonClass) - methodSym setInfoAndEnter MethodType(paramSyms, resTp) + anonClass setInfo ClassInfoType(parents, newScope, anonClass) + methodSym setInfoAndEnter MethodType(paramSyms, resTp) - // use apply's parameter since the scrut's type has been widened - def missingCase(scrut_ignored: Tree) = (funThis DOT nme.missingCase) (REF(paramSyms.head)) + // use apply's parameter since the scrut's type has been widened + def missingCase(scrut_ignored: Tree) = (funThis DOT nme.missingCase) (REF(paramSyms.head)) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None) + val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None) - DefDef(methodSym, body) + DefDef(methodSym, body) + } } def isDefinedAtMethod = { val methodSym = anonClass.newMethod(nme._isDefinedAt, tree.pos, FINAL) val (paramSyms, selector) = mkParams(methodSym) - val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) - methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe) + if (selector eq EmptyTree) EmptyTree + else { + val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) + paramSyms foreach (methodBodyTyper.context.scope enter _) + methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, casesTrue, mode, BooleanClass.tpe) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, casesTrue, mode, BooleanClass.tpe) + val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) - DefDef(methodSym, body) + DefDef(methodSym, body) + } } val members = if (!isPartial) List(applyMethod) else List(applyMethod, isDefinedAtMethod) - typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt) + if (members.head eq EmptyTree) setError(tree) + else typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt) } /** |