diff options
Diffstat (limited to 'src/compiler')
111 files changed, 975 insertions, 442 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 26b6a3cd14..72fca5da12 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -924,6 +924,18 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val ClassTargetClass = getMetaAnnotation("companionClass") lazy val ObjectTargetClass = getMetaAnnotation("companionObject") lazy val MethodTargetClass = getMetaAnnotation("companionMethod") // TODO: module, moduleClass? package, packageObject? + lazy val LanguageFeatureAnnot = getMetaAnnotation("languageFeature") + + // Language features + lazy val languageFeatureModule = getRequiredModule("scala.languageFeature") + lazy val experimentalModule = getMember(languageFeatureModule, newTermName("experimental")) + lazy val MacrosFeature = getLanguageFeature("macros", experimentalModule) + lazy val DynamicsFeature = getLanguageFeature("dynamics") + lazy val PostfixOpsFeature = getLanguageFeature("postfixOps") + lazy val ReflectiveCallsFeature = getLanguageFeature("reflectiveCalls") + lazy val ImplicitConversionsFeature = getLanguageFeature("implicitConversions") + lazy val HigherKindsFeature = getLanguageFeature("higherKinds") + lazy val ExistentialsFeature = getLanguageFeature("existentials") private def getMetaAnnotation(name: String) = getRequiredClass("scala.annotation.meta." + name) def isMetaAnnotation(sym: Symbol): Boolean = metaAnnotations(sym) || ( @@ -975,6 +987,9 @@ trait Definitions extends reflect.api.StandardDefinitions { try getModule(fullname.toTermName) catch { case _: MissingRequirementError => NoSymbol } + def getLanguageFeature(name: String, owner: Symbol = languageFeatureModule) = + getMember(owner, newTypeName(name)) + def termMember(owner: Symbol, name: String): Symbol = owner.info.member(newTermName(name)) def typeMember(owner: Symbol, name: String): Symbol = owner.info.member(newTypeName(name)) @@ -994,7 +1009,13 @@ trait Definitions extends reflect.api.StandardDefinitions { def getMember(owner: Symbol, name: Name): Symbol = { getMemberIfDefined(owner, name) orElse { - throw new FatalError(owner + " does not have a member " + name) + if (phase.flatClasses && name.isTypeName && !owner.isPackageObjectOrClass) { + val pkg = owner.owner + val flatname = nme.flattenedName(owner.name, name) + getMember(pkg, flatname) + } else { + throw new FatalError(owner + " does not have a member " + name) + } } } def getMemberIfDefined(owner: Symbol, name: Name): Symbol = @@ -1011,7 +1032,7 @@ trait Definitions extends reflect.api.StandardDefinitions { } def getDeclIfDefined(owner: Symbol, name: Name): Symbol = owner.info.nonPrivateDecl(name) - + def packageExists(packageName: String): Boolean = getModuleIfDefined(packageName).isPackage diff --git a/src/compiler/scala/reflect/internal/Names.scala b/src/compiler/scala/reflect/internal/Names.scala index 5f38374f20..d2b55d9d39 100644 --- a/src/compiler/scala/reflect/internal/Names.scala +++ b/src/compiler/scala/reflect/internal/Names.scala @@ -8,6 +8,7 @@ package internal import scala.io.Codec import java.security.MessageDigest +import language.implicitConversions /** The class Names ... * diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index 04f67a3196..ac2cf178bf 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -9,12 +9,13 @@ package internal import scala.collection.immutable import NameTransformer.MODULE_SUFFIX_STRING import annotation.switch +import language.implicitConversions trait StdNames extends NameManglers { self: SymbolTable => def encode(str: String): TermName = newTermNameCached(NameTransformer.encode(str)) - implicit def lowerTermNames(n: TermName): String = "" + n + implicit def lowerTermNames(n: TermName): String = n.toString // implicit def stringToTermName(s: String): TermName = newTermName(s) @@ -56,6 +57,7 @@ trait StdNames extends NameManglers { self: SymbolTable => final val RETURNkw: TermName = kw("return") final val SEALEDkw: TermName = kw("sealed") final val SUPERkw: TermName = kw("super") + final val THENkw: TermName = kw("then") final val THISkw: TermName = kw("this") final val THROWkw: TermName = kw("throw") final val TRAITkw: TermName = kw("trait") @@ -323,6 +325,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val append: NameType = "append" val apply: NameType = "apply" val applyDynamic: NameType = "applyDynamic" + val applyDynamicNamed: NameType = "applyDynamicNamed" val applyOrElse: NameType = "applyOrElse" val args : NameType = "args" val argv : NameType = "argv" @@ -424,6 +427,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val runtime: NameType = "runtime" val sameElements: NameType = "sameElements" val scala_ : NameType = "scala" + val selectDynamic: NameType = "selectDynamic" val selectOverloadedMethod: NameType = "selectOverloadedMethod" val selectTerm: NameType = "selectTerm" val selectType: NameType = "selectType" @@ -453,6 +457,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val unapplySeq: NameType = "unapplySeq" val unbox: NameType = "unbox" val update: NameType = "update" + val updateDynamic: NameType = "updateDynamic" val value: NameType = "value" val valueOf : NameType = "valueOf" val values : NameType = "values" diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 5ed37c04ad..0268339ed0 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -267,6 +267,8 @@ abstract class SymbolTable extends api.Universe import java.lang.ref.WeakReference import scala.runtime.ScalaRunTime.stringOf + import language.reflectiveCalls + // We can allow ourselves a structural type, these methods // amount to a few calls per run at most. This does suggest // a "Clearable" trait may be useful. diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index fc94e96acd..3bb57cea04 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -850,6 +850,16 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isStructuralRefinement: Boolean = (isClass || isType || isModule) && info.normalize/*.underlying*/.isStructuralRefinement + /** Is this a term symbol only defined in a refinement (so that it needs + * to be accessed by reflection)? + */ + def isOnlyRefinementMember: Boolean = + isTerm && // type members are not affected + owner.isRefinementClass && // owner must be a refinement class + (owner.info decl name) == this && // symbol must be explicitly declared in the refinement (not synthesized from glb) + allOverriddenSymbols.isEmpty && // symbol must not override a symbol in a base class + !isConstant // symbol must not be a constant. Question: Can we exclude @inline methods as well? + final def isStructuralRefinementMember = owner.isStructuralRefinement && isPossibleInRefinement && isPublic final def isPossibleInRefinement = !isConstructor && !isOverridingSymbol @@ -1751,7 +1761,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => } else owner.enclosingTopLevelClass /** Is this symbol defined in the same scope and compilation unit as `that` symbol? */ - def isCoDefinedWith(that: Symbol) = ( + def isCoDefinedWith(that: Symbol) = { + import language.reflectiveCalls (this.rawInfo ne NoType) && (this.effectiveOwner == that.effectiveOwner) && { !this.effectiveOwner.isPackageClass || @@ -1770,7 +1781,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => false } } - ) + } /** The internal representation of classes and objects: * @@ -1874,7 +1885,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => site.nonPrivateMemberAdmitting(name, admit).filter(sym => !sym.isTerm || (site.memberType(this) matches site.memberType(sym))) - /** The symbol overridden by this symbol in given class `ofclazz`. + /** The symbol, in class `ofclazz`, that is overridden by this symbol. * * @param ofclazz is a base class of this symbol's owner. */ @@ -3093,10 +3104,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (settings.debug.value) printStackTrace() } - case class InvalidCompanions(sym1: Symbol, sym2: Symbol) extends Throwable( + case class InvalidCompanions(sym1: Symbol, sym2: Symbol) extends Throwable({ + import language.reflectiveCalls "Companions '" + sym1 + "' and '" + sym2 + "' must be defined in same file:\n" + " Found in " + sym1.sourceFile.canonicalPath + " and " + sym2.sourceFile.canonicalPath - ) { + }) { override def toString = getMessage } diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index ed22cad730..a8cca1625f 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -532,6 +532,21 @@ abstract class TreeInfo { } } + def isApplyDynamicName(name: Name) = (name == nme.updateDynamic) || (name == nme.selectDynamic) || (name == nme.applyDynamic) || (name == nme.applyDynamicNamed) + + class DynamicApplicationExtractor(nameTest: Name => Boolean) { + def unapply(tree: Tree) = tree match { + case Apply(TypeApply(Select(qual, oper), _), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name)) + case Apply(Select(qual, oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name)) + case Apply(Ident(oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((EmptyTree, name)) + case _ => None + } + } + object DynamicUpdate extends DynamicApplicationExtractor(_ == nme.updateDynamic) + object DynamicApplication extends DynamicApplicationExtractor(isApplyDynamicName) + object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed) + + // domain-specific extractors for reification import definitions._ diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala index 9b4c18ce86..486a3d3567 100644 --- a/src/compiler/scala/reflect/internal/TreePrinters.scala +++ b/src/compiler/scala/reflect/internal/TreePrinters.scala @@ -103,6 +103,16 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => } } + def printLabelParams(ps: List[Ident]) { + print("(") + printSeq(ps){printLabelParam}{print(", ")} + print(")") + } + + def printLabelParam(p: Ident) { + print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe) + } + def printValueParams(ts: List[ValDef]) { print("(") if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "") @@ -219,7 +229,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => } case LabelDef(name, params, rhs) => - print(symName(tree, name)); printRow(params, "(", ",", ")"); printBlock(rhs) + print(symName(tree, name)); printLabelParams(params); printBlock(rhs) case Import(expr, selectors) => // Is this selector remapping a name (i.e, {name1 => name2}) diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 0d7e68aee3..5f1a8f3fbe 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -103,9 +103,7 @@ trait Trees extends api.Trees { self: SymbolTable => // --- extension methods -------------------------------------------------------- - implicit def treeOps(tree: Tree): TreeOps = new TreeOps(tree) - - class TreeOps(tree: Tree) { + implicit class TreeOps(tree: Tree) { def isErroneous = (tree.tpe ne null) && tree.tpe.isErroneous def isTyped = (tree.tpe ne null) && !tree.tpe.isErroneous @@ -146,11 +144,9 @@ trait Trees extends api.Trees { self: SymbolTable => * less than the whole tree. */ def summaryString: String = tree match { - case Select(qual, name) => qual.summaryString + "." + name.decode - case Ident(name) => name.longString case Literal(const) => "Literal(" + const + ")" - case t: DefTree => t.shortClass + " `" + t.name.decode + "`" - case t: RefTree => t.shortClass + " `" + t.name.longString + "`" + case Select(qual, name) => qual.summaryString + "." + name.decode + case t: NameTree => t.name.longString case t => t.shortClass + ( if (t.symbol != null && t.symbol != NoSymbol) " " + t.symbol diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index c6b320b444..17c9b955ca 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 || settings.YvirtPatmat.value + protected val enableTypeVarExperimentals = settings.Xexperimental.value || !settings.XoldPatmat.value /** Empty immutable maps to avoid allocations. */ private val emptySymMap = immutable.Map[Symbol, Symbol]() @@ -712,7 +712,9 @@ trait Types extends api.Types { self: SymbolTable => /** Returns all parts of this type which satisfy predicate `p` */ def filter(p: Type => Boolean): List[Type] = new FilterTypeCollector(p) collect this - def withFilter(p: Type => Boolean) = new FilterTypeCollector(p) { + def withFilter(p: Type => Boolean) = new FilterMapForeach(p) + + class FilterMapForeach(p: Type => Boolean) extends FilterTypeCollector(p){ def foreach[U](f: Type => U): Unit = collect(Type.this) foreach f def map[T](f: Type => T): List[T] = collect(Type.this) map f } @@ -2518,39 +2520,46 @@ trait Types extends api.Types { self: SymbolTable => override def skolemizeExistential(owner: Symbol, origin: AnyRef) = deriveType(quantified, tparam => (owner orElse tparam.owner).newExistentialSkolem(tparam, origin))(underlying) - private def wildcardArgsString(available: Set[Symbol], args: List[Type]): List[String] = args match { - case TypeRef(_, sym, _) :: args1 if (available contains sym) => - ("_"+sym.infoString(sym.info)) :: wildcardArgsString(available - sym, args1) - case arg :: args1 if !(quantified exists (arg contains _)) => - arg.toString :: wildcardArgsString(available, args1) - case _ => - List() + private def wildcardArgsString(qset: Set[Symbol], args: List[Type]): List[String] = args map { + case TypeRef(_, sym, _) if (qset contains sym) => + "_"+sym.infoString(sym.info) + case arg => + arg.toString } + /** An existential can only be printed with wildcards if: * - the underlying type is a typeref - * - where there is a 1-to-1 correspondence between underlying's typeargs and quantified - * - and none of the existential parameters is referenced from anywhere else in the type - * - and none of the existential parameters are singleton types + * - every quantified variable appears at most once as a type argument and + * nowhere inside a type argument + * - no quantified type argument contains a quantified variable in its bound + * - the typeref's symbol is not itself quantified + * - the prefix is not quanitified */ - private def isRepresentableWithWildcards = !settings.debug.value && { + def isRepresentableWithWildcards = { val qset = quantified.toSet - !qset.exists(_.isSingletonExistential) && (underlying match { - case TypeRef(_, sym, args) => - sameLength(args, quantified) && { - args forall { arg => - qset(arg.typeSymbol) && !qset.exists(arg.typeSymbol.info.bounds contains _) - } + underlying match { + case TypeRef(pre, sym, args) => + def isQuantified(tpe: Type): Boolean = { + (tpe exists (t => qset contains t.typeSymbol)) || + tpe.typeSymbol.isRefinementClass && (tpe.parents exists isQuantified) } + val (wildcardArgs, otherArgs) = args partition (arg => qset contains arg.typeSymbol) + wildcardArgs.distinct == wildcardArgs && + !(otherArgs exists (arg => isQuantified(arg))) && + !(wildcardArgs exists (arg => isQuantified(arg.typeSymbol.info.bounds))) && + !(qset contains sym) && + !isQuantified(pre) case _ => false - }) + } } + override def safeToString: String = { def clauses = { val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }") if (settings.explaintypes.value) "(" + str + ")" else str } underlying match { - case TypeRef(pre, sym, args) if isRepresentableWithWildcards => + case TypeRef(pre, sym, args) if !settings.debug.value && isRepresentableWithWildcards => "" + TypeRef(pre, sym, Nil) + wildcardArgsString(quantified.toSet, args).mkString("[", ", ", "]") case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) => "(" + underlying + ")" + clauses diff --git a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala index b556c33aba..45ba4ed3e6 100644 --- a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala @@ -43,5 +43,5 @@ abstract class MutableSettings extends AbsSettings { def Yrecursion: IntSetting def maxClassfileName: IntSetting def Xexperimental: BooleanSetting - def YvirtPatmat: BooleanSetting + def XoldPatmat: BooleanSetting }
\ No newline at end of file diff --git a/src/compiler/scala/reflect/makro/runtime/Errors.scala b/src/compiler/scala/reflect/makro/runtime/AbortMacroException.scala index d78eae9237..d78eae9237 100644 --- a/src/compiler/scala/reflect/makro/runtime/Errors.scala +++ b/src/compiler/scala/reflect/makro/runtime/AbortMacroException.scala diff --git a/src/compiler/scala/reflect/reify/Reifiers.scala b/src/compiler/scala/reflect/reify/Reifier.scala index 16c26734b2..16c26734b2 100644 --- a/src/compiler/scala/reflect/reify/Reifiers.scala +++ b/src/compiler/scala/reflect/reify/Reifier.scala diff --git a/src/compiler/scala/reflect/reify/phases/Calculate.scala b/src/compiler/scala/reflect/reify/phases/Calculate.scala index 59a36f0ba4..e4f3fce407 100644 --- a/src/compiler/scala/reflect/reify/phases/Calculate.scala +++ b/src/compiler/scala/reflect/reify/phases/Calculate.scala @@ -8,14 +8,12 @@ trait Calculate { import definitions._ import treeInfo._ - implicit def sym2richSym(sym: Symbol): RichSymbol = new RichSymbol(sym) - class RichSymbol(sym: Symbol) { + implicit class RichSymbol(sym: Symbol) { def metalevel: Int = { assert(sym != NoSymbol); localSymbols.getOrElse(sym, 0) } def isLocalToReifee = (localSymbols contains sym) // [Eugene] how do I account for local skolems? } - implicit def tpe2richTpe(tpe: Type): RichType = new RichType(tpe) - class RichType(tpe: Type) { + implicit class RichType(tpe: Type) { def isLocalToReifee = tpe != null && (tpe exists (tp => (localSymbols contains tp.typeSymbol) || (localSymbols contains tp.termSymbol))) } @@ -58,4 +56,4 @@ trait Calculate { super.traverse(tree) } } -}
\ 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 27e90c94bd..bbe4d60e9c 100644 --- a/src/compiler/scala/reflect/runtime/Settings.scala +++ b/src/compiler/scala/reflect/runtime/Settings.scala @@ -34,5 +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) + val XoldPatmat = new BooleanSetting(false) } diff --git a/src/compiler/scala/tools/cmd/gen/AnyVals.scala b/src/compiler/scala/tools/cmd/gen/AnyVals.scala index 0869350dd3..e8230b8ca4 100644 --- a/src/compiler/scala/tools/cmd/gen/AnyVals.scala +++ b/src/compiler/scala/tools/cmd/gen/AnyVals.scala @@ -14,20 +14,34 @@ trait AnyValReps { sealed abstract class AnyValNum(name: String, repr: Option[String], javaEquiv: String) extends AnyValRep(name,repr,javaEquiv) { case class Op(val op : String, val doc : String) + + private def companionCoercions(tos: String*) = { + tos.toList map (to => + """implicit def %s2%s(x: %s): %s = x.to%s""".format(javaEquiv, to, name, to.capitalize, to.capitalize) + ) + } + def implicitCoercions: List[String] = javaEquiv match { + case "byte" => companionCoercions("short", "int", "long", "float", "double") + case "short" | "char" => companionCoercions("int", "long", "float", "double") + case "int" => companionCoercions("long", "float", "double") + case "long" => companionCoercions("float", "double") + case "float" => companionCoercions("double") + case _ => Nil + } def isCardinal: Boolean = isIntegerType(this) def unaryOps = { val ops = List( Op("+", "/**\n" + - " * @return this value, unmodified\n" + + " * Returns this value, unmodified.\n" + " */"), Op("-", "/**\n" + - " * @return the negation of this value\n" + + " * Returns the negation of this value.\n" + " */")) if(isCardinal) Op("~", "/**\n" + - " * @return the bitwise negation of this value\n" + + " * Returns the bitwise negation of this value.\n" + " * @example {{{\n" + " * ~5 == -6\n" + " * // in binary: ~00000101 ==\n" + @@ -41,7 +55,7 @@ trait AnyValReps { if (isCardinal) List( Op("|", "/**\n" + - " * @return the bitwise OR of this value and x\n" + + " * Returns the bitwise OR of this value and `x`.\n" + " * @example {{{\n" + " * (0xf0 | 0xaa) == 0xfa\n" + " * // in binary: 11110000\n" + @@ -51,7 +65,7 @@ trait AnyValReps { " * }}}\n" + " */"), Op("&", "/**\n" + - " * @return the bitwise AND of this value and x\n" + + " * Returns the bitwise AND of this value and `x`.\n" + " * @example {{{\n" + " * (0xf0 & 0xaa) == 0xa0\n" + " * // in binary: 11110000\n" + @@ -61,7 +75,7 @@ trait AnyValReps { " * }}}\n" + " */"), Op("^", "/**\n" + - " * @return the bitwise XOR of this value and x\n" + + " * Returns the bitwise XOR of this value and `x`.\n" + " * @example {{{\n" + " * (0xf0 ^ 0xaa) == 0x5a\n" + " * // in binary: 11110000\n" + @@ -76,13 +90,13 @@ trait AnyValReps { if (isCardinal) List( Op("<<", "/**\n" + - " * @return this value bit-shifted left by the specified number of bits,\n" + + " * Returns this value bit-shifted left by the specified number of bits,\n" + " * filling in the new right bits with zeroes.\n" + " * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}\n" + " */"), Op(">>>", "/**\n" + - " * @return this value bit-shifted right by the specified number of bits,\n" + + " * Returns this value bit-shifted right by the specified number of bits,\n" + " * filling the new left bits with zeroes.\n" + " * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}\n" + " * @example {{{\n" + @@ -93,7 +107,7 @@ trait AnyValReps { " */"), Op(">>", "/**\n" + - " * @return this value bit-shifted left by the specified number of bits,\n" + + " * Returns this value bit-shifted left by the specified number of bits,\n" + " * filling in the right bits with the same value as the left-most bit of this.\n" + " * The effect of this is to retain the sign of the value.\n" + " * @example {{{\n" + @@ -105,19 +119,19 @@ trait AnyValReps { else Nil def comparisonOps = List( - Op("==", "/**\n * @return `true` if this value is equal x, `false` otherwise\n */"), - Op("!=", "/**\n * @return `true` if this value is not equal to x, `false` otherwise\n */"), - Op("<", "/**\n * @return `true` if this value is less than x, `false` otherwise\n */"), - Op("<=", "/**\n * @return `true` if this value is less than or equal to x, `false` otherwise\n */"), - Op(">", "/**\n * @return `true` if this value is greater than x, `false` otherwise\n */"), - Op(">=", "/**\n * @return `true` if this value is greater than or equal to x, `false` otherwise\n */")) + Op("==", "/**\n * Returns `true` if this value is equal to x, `false` otherwise.\n */"), + Op("!=", "/**\n * Returns `true` if this value is not equal to x, `false` otherwise.\n */"), + Op("<", "/**\n * Returns `true` if this value is less than x, `false` otherwise.\n */"), + Op("<=", "/**\n * Returns `true` if this value is less than or equal to x, `false` otherwise.\n */"), + Op(">", "/**\n * Returns `true` if this value is greater than x, `false` otherwise.\n */"), + Op(">=", "/**\n * Returns `true` if this value is greater than or equal to x, `false` otherwise.\n */")) def otherOps = List( - Op("+", "/**\n * @return the sum of this value and x\n */"), - Op("-", "/**\n * @return the difference of this value and x\n */"), - Op("*", "/**\n * @return the product of this value and x\n */"), - Op("/", "/**\n * @return the quotient of this value and x\n */"), - Op("%", "/**\n * @return the remainder of the division of this value by x\n */")) + Op("+", "/**\n * Returns the sum of this value and `x`.\n */"), + Op("-", "/**\n * Returns the difference of this value and `x`.\n */"), + Op("*", "/**\n * Returns the product of this value and `x`.\n */"), + Op("/", "/**\n * Returns the quotient of this value and `x`.\n */"), + Op("%", "/**\n * Returns the remainder of the division of this value by `x`.\n */")) // Given two numeric value types S and T , the operation type of S and T is defined as follows: // If both S and T are subrange types then the operation type of S and T is Int. @@ -160,7 +174,7 @@ trait AnyValReps { } def objectLines = { val comp = if (isCardinal) cardinalCompanion else floatingCompanion - (comp + allCompanions).trim.lines map interpolate toList + ((comp + allCompanions).trim.lines map interpolate).toList ++ implicitCoercions } /** Makes a set of binary operations based on the given set of ops, args, and resultFn. @@ -224,8 +238,8 @@ trait AnyValReps { def classDoc = interpolate(classDocTemplate) def objectDoc = "" def mkImports = "" - def mkClass = assemble("final class", "AnyVal", classLines) + "\n" - def mkObject = assemble("object", "AnyValCompanion", objectLines) + "\n" + def mkClass = assemble("final class", "private", "AnyVal", classLines) + "\n" + def mkObject = assemble("object", "", "AnyValCompanion", objectLines) + "\n" def make() = List[String]( headerTemplate, mkImports, @@ -235,8 +249,8 @@ trait AnyValReps { mkObject ) mkString "" - def assemble(what: String, parent: String, lines: List[String]): String = { - val decl = "%s %s extends %s ".format(what, name, parent) + def assemble(what: String, ctor: String, parent: String, lines: List[String]): String = { + val decl = "%s %s %s extends %s ".format(what, name, ctor, parent) val body = if (lines.isEmpty) "{ }\n\n" else lines map indent mkString ("{\n", "\n", "\n}\n") decl + body diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index d6f57801e7..92a0efff1e 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -61,6 +61,9 @@ trait CompilationUnits { self: Global => /** things to check at end of compilation unit */ val toCheck = new ListBuffer[() => Unit] + /** The features that were already checked for this unit */ + var checkedFeatures = Set[Symbol]() + def position(pos: Int) = source.position(pos) /** The position of a targeted type check @@ -85,12 +88,10 @@ trait CompilationUnits { self: Global => reporter.warning(pos, msg) def deprecationWarning(pos: Position, msg: String) = - if (opt.deprecation) warning(pos, msg) - else currentRun.deprecationWarnings ::= ((pos, msg)) + currentRun.deprecationWarnings.warn(pos, msg) def uncheckedWarning(pos: Position, msg: String) = - if (opt.unchecked) warning(pos, msg) - else currentRun.uncheckedWarnings ::= ((pos, msg)) + currentRun.uncheckedWarnings.warn(pos, msg) def incompleteInputError(pos: Position, msg:String) = reporter.incompleteInputError(pos, msg) @@ -104,10 +105,14 @@ trait CompilationUnits { self: Global => override def toString() = source.toString() def clear() { - fresh = null - body = null + fresh = new FreshNameCreator.Default + body = EmptyTree depends.clear() defined.clear() + synthetics.clear() + toCheck.clear() + checkedFeatures = Set() + icode.clear() } } } diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala index a0c39f71fb..a4a8e1fd11 100644 --- a/src/compiler/scala/tools/nsc/CompileSocket.scala +++ b/src/compiler/scala/tools/nsc/CompileSocket.scala @@ -93,7 +93,7 @@ class CompileSocket extends CompileOutputCommon { /** Start a new server. */ private def startNewServer(vmArgs: String) = { - val cmd = serverCommand(vmArgs split " " toSeq) + val cmd = serverCommand((vmArgs split " ").toSeq) info("[Executing command: %s]" format cmd.mkString(" ")) // Hiding inadequate daemonized implementation from public API for now @@ -206,7 +206,7 @@ class CompileSocket extends CompileOutputCommon { Thread sleep 100 ff.length } - if (Iterator continually check take 50 find (_ > 0) isEmpty) { + if ((Iterator continually check take 50 find (_ > 0)).isEmpty) { ff.delete() fatal("Unable to establish connection to server.") } diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala index 54bc218912..4c8a27083a 100644 --- a/src/compiler/scala/tools/nsc/CompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala @@ -47,7 +47,7 @@ class CompilerCommand(arguments: List[String], val settings: Settings) { /** Creates a help message for a subset of options based on cond */ def createUsageMsg(cond: Setting => Boolean): String = { val baseList = (settings.visibleSettings filter cond).toList sortBy (_.name) - val width = baseList map (_.helpSyntax.length) max + val width = (baseList map (_.helpSyntax.length)).max def format(s: String) = ("%-" + width + "s") format s def helpStr(s: Setting) = { val str = format(s.helpSyntax) + " " + s.helpDescription diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala index b9e9a14adf..f91cb854c6 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala @@ -8,7 +8,7 @@ package scala.tools.nsc import scala.tools.util.PathResolver class GenericRunnerSettings(error: String => Unit) extends Settings(error) { - def classpathURLs = new PathResolver(this) asURLs + def classpathURLs = new PathResolver(this).asURLs val howtorun = ChoiceSetting( diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index b7d7f5d16f..403b5717b0 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -31,6 +31,7 @@ import backend.{ ScalaPrimitives, Platform, MSILPlatform, JavaPlatform } import backend.jvm.GenJVM import backend.opt.{ Inliners, InlineExceptionHandlers, ClosureElimination, DeadCodeElimination } import backend.icode.analysis._ +import language.postfixOps class Global(var currentSettings: Settings, var reporter: NscReporter) extends SymbolTable with ClassLoaders @@ -346,7 +347,7 @@ class Global(var currentSettings: Settings, var reporter: NscReporter) extends S override protected val etaExpandKeepsStar = settings.etaExpandKeepsStar.value // Here comes another one... override protected val enableTypeVarExperimentals = ( - settings.Xexperimental.value || settings.YvirtPatmat.value + settings.Xexperimental.value || !settings.XoldPatmat.value ) // True if -Xscript has been set, indicating a script run. @@ -938,6 +939,17 @@ class Global(var currentSettings: Settings, var reporter: NscReporter) extends S inform("[running phase " + ph.name + " on " + currentRun.size + " compilation units]") } + /** Collects for certain classes of warnings during this run. */ + class ConditionalWarning(what: String, option: Settings#BooleanSetting) { + val warnings = new mutable.ListBuffer[(Position, String)] + def warn(pos: Position, msg: String) = + if (option.value) reporter.warning(pos, msg) + else warnings += ((pos, msg)) + def summarize() = + if (option.isDefault && warnings.nonEmpty) + reporter.warning(NoPosition, "there were %d %s warnings; re-run with %s for details".format(warnings.size, what, option.name)) + } + /** A Run is a single execution of the compiler on a sets of units */ class Run { @@ -949,9 +961,12 @@ class Global(var currentSettings: Settings, var reporter: NscReporter) extends S /** The currently compiled unit; set from GlobalPhase */ var currentUnit: CompilationUnit = NoCompilationUnit - /** Counts for certain classes of warnings during this run. */ - var deprecationWarnings: List[(Position, String)] = Nil - var uncheckedWarnings: List[(Position, String)] = Nil + val deprecationWarnings = new ConditionalWarning("deprecation", settings.deprecation) + val uncheckedWarnings = new ConditionalWarning("unchecked", settings.unchecked) + val featureWarnings = new ConditionalWarning("feature", settings.feature) + val allConditionalWarnings = List(deprecationWarnings, uncheckedWarnings, featureWarnings) + + var reportedFeature = Set[Symbol]() /** A flag whether macro expansions failed */ var macroExpansionFailed = false @@ -1241,12 +1256,8 @@ class Global(var currentSettings: Settings, var reporter: NscReporter) extends S } } else { - def warn(count: Int, what: String, option: Settings#BooleanSetting) = ( - if (option.isDefault && count > 0) - warning("there were %d %s warnings; re-run with %s for details".format(count, what, option.name)) - ) - warn(deprecationWarnings.size, "deprecation", settings.deprecation) - warn(uncheckedWarnings.size, "unchecked", settings.unchecked) + allConditionalWarnings foreach (_.summarize) + if (macroExpansionFailed) warning("some macros could not be expanded and code fell back to overridden methods;"+ "\nrecompiling with generated classfiles on the classpath might help.") diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index a627b982b6..a9e029e485 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -8,6 +8,7 @@ package scala.tools.nsc import java.io.{ BufferedWriter, FileWriter } import scala.collection.mutable +import language.postfixOps /** * PhaseAssembly diff --git a/src/compiler/scala/tools/nsc/Phases.scala b/src/compiler/scala/tools/nsc/Phases.scala index d18495458c..1fa576afb6 100644 --- a/src/compiler/scala/tools/nsc/Phases.scala +++ b/src/compiler/scala/tools/nsc/Phases.scala @@ -7,6 +7,7 @@ package scala.tools.nsc import symtab.Flags import util.TableDef +import language.postfixOps object Phases { val MaxPhases = 64 diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index c79ca1206e..108c8fcbfa 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -8,6 +8,7 @@ package ast import compat.Platform.EOL import symtab.Flags._ +import language.postfixOps /** The object `nodePrinter` converts the internal tree * representation to a string. diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index 3302c11127..b4beb231ab 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -18,6 +18,7 @@ import scala.concurrent.Lock import scala.text._ import symtab.Flags._ import symtab.SymbolTable +import language.implicitConversions /** * Tree browsers can show the AST in a graphical and interactive diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala index 2b75925d9a..283bdecf26 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala @@ -9,6 +9,7 @@ package ast import PartialFunction._ import symtab.Flags +import language.implicitConversions /** A DSL for generating scala code. The goal is that the * code generating code should look a lot like the code it diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 19d1e0a51a..d3e64811d3 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -9,6 +9,7 @@ package ast import scala.collection.mutable.ListBuffer import symtab.Flags._ import symtab.SymbolTable +import language.postfixOps /** XXX to resolve: TreeGen only assumes global is a SymbolTable, but * TreeDSL at the moment expects a Global. Can we get by with SymbolTable? @@ -71,14 +72,6 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { Annotated(Ident(nme.synthSwitch), expr) } - // must be kept in synch with the codegen in PatMatVirtualiser - object VirtualCaseDef { - def unapply(b: Block): Option[(Assign, Tree, Tree)] = b match { - case Block(List(assign@Assign(keepGoingLhs, falseLit), matchRes), zero) => Some((assign, matchRes, zero)) // TODO: check tree annotation - case _ => None - } - } - def hasSynthCaseSymbol(t: Tree) = (t.symbol ne null) && (t.symbol hasFlag (CASE | SYNTHETIC)) // TODO: would be so much nicer if we would know during match-translation (i.e., type checking) @@ -86,9 +79,11 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { class MatchMatcher { def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = unknownTree(orig) def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = unknownTree(orig) - def caseVirtualizedMatchOpt(orig: Tree, zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], epilogue: Tree, wrap: Tree => Tree): Tree = unknownTree(orig) + def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree): Tree = unknownTree(orig) - def apply(matchExpr: Tree): Tree = (matchExpr: @unchecked) match { + def genVirtualizedMatch(prologue: List[Tree], cases: List[Tree], matchEndDef: Tree): Tree = Block(prologue ++ cases, matchEndDef) + + def apply(matchExpr: Tree): Tree = matchExpr match { // old-style match or virtpatmat switch case Match(selector, cases) => // println("simple match: "+ (selector, cases) + "for:\n"+ matchExpr ) caseMatch(matchExpr, selector, cases, identity) @@ -99,11 +94,15 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { case Apply(Apply(TypeApply(Select(tgt, nme.runOrElse), targs), List(scrut)), List(matcher)) if opt.virtPatmat => // println("virt match: "+ (tgt, targs, scrut, matcher) + "for:\n"+ matchExpr ) caseVirtualizedMatch(matchExpr, tgt, targs, scrut, matcher) // optimized version of virtpatmat - case Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, epilogue) if opt.virtPatmat => // TODO: check tree annotation // println("virtopt match: "+ (zero, x, matchRes, keepGoing, stats) + "for:\n"+ matchExpr ) - caseVirtualizedMatchOpt(matchExpr, zero, x, matchRes, keepGoing, stats, epilogue, identity) + case Block(stats, matchEndDef) if opt.virtPatmat && (stats forall hasSynthCaseSymbol) => + // the assumption is once we encounter a case, the remainder of the block will consist of cases + // the prologue may be empty, usually it is the valdef that stores the scrut + val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef]) + caseVirtualizedMatchOpt(matchExpr, prologue, cases, matchEndDef, identity) // optimized version of virtpatmat - case Block(outerStats, orig@Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, epilogue)) if opt.virtPatmat => // TODO: check tree annotation // println("virt opt block match: "+ (zero, x, matchRes, keepGoing, stats, outerStats) + "for:\n"+ matchExpr ) - caseVirtualizedMatchOpt(matchExpr, zero, x, matchRes, keepGoing, stats, epilogue, m => copyBlock(matchExpr, outerStats, m)) + case Block(outerStats, orig@Block(stats, matchEndDef)) if opt.virtPatmat && (stats forall hasSynthCaseSymbol) => + val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef]) + caseVirtualizedMatchOpt(matchExpr, prologue, cases, matchEndDef, m => copyBlock(matchExpr, outerStats, m)) case other => unknownTree(other) } @@ -119,35 +118,6 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { } } - def withDefaultCase(matchExpr: Tree, defaultAction: Tree/*scrutinee*/ => Tree): Tree = { - object withDefaultTransformer extends MatchMatcher { - override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { - val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) - if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) orig - else { - val defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, defaultAction(selector.duplicate)) - wrap(Match(selector, casesNoSynthCatchAll :+ defaultCase)) - } - } - override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = { import CODE._ - ((matcher APPLY (scrut)) DOT nme.getOrElse) APPLY (defaultAction(scrut.duplicate)) // TODO: pass targs - } - override def caseVirtualizedMatchOpt(orig: Tree, zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], epilogue: Tree, wrap: Tree => Tree): Tree = { import CODE._ - wrap(Block( - zero :: - x :: - matchRes :: - keepGoing :: - stats, - // replace `if (keepGoing) throw new MatchError(...) else matchRes` by `if (keepGoing) ${defaultAction(`x`)} else matchRes` - (IF (REF(keepGoing.symbol)) THEN defaultAction(x.rhs.duplicate) ELSE REF(matchRes.symbol)) - )) - } - } - withDefaultTransformer(matchExpr) - } - - def mkCached(cvar: Symbol, expr: Tree): Tree = { val cvarRef = mkUnattributedRef(cvar) Block( diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 66704680ae..04452c68e5 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -58,6 +58,8 @@ trait Trees extends reflect.internal.Trees { self: Global => case class InjectDerivedValue(arg: Tree) extends SymTree + class PostfixSelect(qual: Tree, name: Name) extends Select(qual, name) + /** emitted by typer, eliminated by refchecks */ case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree @@ -253,6 +255,7 @@ trait Trees extends reflect.internal.Trees { self: Global => def resetAllAttrs[A <: Tree](x: A, leaveAlone: Tree => Boolean = null): A = new ResetAttrs(false, leaveAlone).transform(x) def resetLocalAttrs[A <: Tree](x: A, leaveAlone: Tree => Boolean = null): A = new ResetAttrs(true, leaveAlone).transform(x) + def resetLocalAttrsKeepLabels[A<:Tree](x: A, leaveAlone: Tree => Boolean = null): A = new ResetAttrs(true, leaveAlone, true).transform(x) /** A transformer which resets symbol and tpe fields of all nodes in a given tree, * with special treatment of: @@ -263,7 +266,7 @@ trait Trees extends reflect.internal.Trees { self: Global => * * (bq:) This transformer has mutable state and should be discarded after use */ - private class ResetAttrs(localOnly: Boolean, leaveAlone: Tree => Boolean = null) { + private class ResetAttrs(localOnly: Boolean, leaveAlone: Tree => Boolean = null, keepLabels: Boolean = false) { val debug = settings.debug.value val trace = scala.tools.nsc.util.trace when debug @@ -326,18 +329,18 @@ trait Trees extends reflect.internal.Trees { self: Global => case EmptyTree => tree case _ => - if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol))) + if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel)) tree.symbol = NoSymbol tree.tpe = null tree } } - } + } } def transform[T <: Tree](x: T): T = { if (localOnly) - new MarkLocals().traverse(x) + new MarkLocals().traverse(x) if (localOnly && debug) { assert(locals.size == orderedLocals.size) @@ -361,4 +364,4 @@ trait Trees extends reflect.internal.Trees { self: Global => */ - }
\ No newline at end of file + } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index daabfae6b3..eb4deeeee2 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -70,6 +70,9 @@ trait ParsersCommon extends ScannersCommon { @inline final def inBracesOrNil[T](body: => List[T]): List[T] = inBracesOrError(body, Nil) @inline final def inBracesOrUnit[T](body: => Tree): Tree = inBracesOrError(body, Literal(Constant())) + @inline final def dropAnyBraces[T](body: => T): T = + if (in.token == LBRACE) inBraces(body) + else body @inline final def inBrackets[T](body: => T): T = { accept(LBRACKET) @@ -1106,7 +1109,7 @@ self => * }}} * @note The returned tree does not yet have a position */ - def literal(isNegated: Boolean = false): Tree = { + def literal(isNegated: Boolean = false, inPattern: Boolean = false): Tree = { def finish(value: Any): Tree = { val t = Literal(Constant(value)) in.nextToken() @@ -1115,7 +1118,7 @@ self => if (in.token == SYMBOLLIT) Apply(scalaDot(nme.Symbol), List(finish(in.strVal))) else if (in.token == INTERPOLATIONID) - interpolatedString() + interpolatedString(inPattern) else finish(in.token match { case CHARLIT => in.charVal case INTLIT => in.intVal(isNegated).toInt @@ -1141,7 +1144,7 @@ self => } } - private def interpolatedString(): Tree = atPos(in.offset) { + private def interpolatedString(inPattern: Boolean = false): Tree = atPos(in.offset) { val start = in.offset val interpolator = in.name @@ -1151,8 +1154,11 @@ self => while (in.token == STRINGPART) { partsBuf += literal() exprBuf += { - if (in.token == IDENTIFIER) atPos(in.offset)(Ident(ident())) - else expr() + if (inPattern) dropAnyBraces(pattern()) + else { + if (in.token == IDENTIFIER) atPos(in.offset)(Ident(ident())) + else expr() + } } } if (in.token == STRINGLIT) partsBuf += literal() @@ -1456,11 +1462,12 @@ self => return reduceStack(true, base, top, 0, true) top = next } else { + // postfix expression val topinfo = opstack.head opstack = opstack.tail val od = stripParens(reduceStack(true, base, topinfo.operand, 0, true)) return atPos(od.pos.startOrPoint, topinfo.offset) { - Select(od, topinfo.operator.encode) + new PostfixSelect(od, topinfo.operator.encode) } } } @@ -1772,21 +1779,7 @@ self => */ def pattern2(): Tree = { val nameOffset = in.offset - def warnIfMacro(tree: Tree): Unit = { - def check(name: Name): Unit = if (name.toString == nme.MACROkw.toString) - warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.") - tree match { - case _: BackQuotedIdent => - ; - case Ident(name) => - check(name) - case _ => - ; - } - } - val p = pattern3() - warnIfMacro(p) if (in.token != AT) p else p match { @@ -1850,7 +1843,7 @@ self => case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => t match { case Ident(nme.MINUS) => - return atPos(start) { literal(isNegated = true) } + return atPos(start) { literal(isNegated = true, inPattern = true) } case _ => } case _ => @@ -1868,7 +1861,7 @@ self => atPos(start, start) { Ident(nme.WILDCARD) } case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | INTERPOLATIONID | SYMBOLLIT | TRUE | FALSE | NULL => - atPos(start) { literal() } + atPos(start) { literal(inPattern = true) } case LPAREN => atPos(start)(makeParens(noSeq.patterns())) case XMLSTART => @@ -2462,8 +2455,6 @@ self => val nameOffset = in.offset val isBackquoted = in.token == BACKQUOTED_IDENT val name = ident() - if (name.toString == nme.MACROkw.toString && !isBackquoted) - warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.") funDefRest(start, nameOffset, mods, name) } } @@ -2479,7 +2470,7 @@ self => val vparamss = paramClauses(name, contextBoundBuf.toList, false) newLineOptWhenFollowedBy(LBRACE) var restype = fromWithinReturnType(typedOpt()) - val rhs = + val rhs = if (isStatSep || in.token == RBRACE) { if (restype.isEmpty) restype = scalaUnitConstr newmods |= Flags.DEFERRED @@ -2488,10 +2479,15 @@ self => restype = scalaUnitConstr blockExpr() } else { - accept(EQUALS) - if (settings.Xmacros.value && in.token == MACRO) { - in.nextToken() - newmods |= Flags.MACRO + if (in.token == EQUALS) { + in.nextTokenAllow(nme.MACROkw) + if (settings.Xmacros.value && in.token == MACRO || // [Martin] Xmacros can be retired now + in.token == IDENTIFIER && in.name == nme.MACROkw) { + in.nextToken() + newmods |= Flags.MACRO + } + } else { + accept(EQUALS) } expr() } @@ -2554,8 +2550,6 @@ self => val nameOffset = in.offset val isBackquoted = in.token == BACKQUOTED_IDENT val name = identForType() - if (name.toString == nme.MACROkw.toString && !isBackquoted) - warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.") // @M! a type alias as well as an abstract type may declare type parameters val tparams = typeParamClauseOpt(name, null) in.token match { @@ -2615,15 +2609,12 @@ self => val nameOffset = in.offset val isBackquoted = in.token == BACKQUOTED_IDENT val name = identForType() - if (name.toString == nme.MACROkw.toString && !isBackquoted) - warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.") - atPos(start, if (name == tpnme.ERROR) start else nameOffset) { savingClassContextBounds { val contextBoundBuf = new ListBuffer[Tree] val tparams = typeParamClauseOpt(name, contextBoundBuf) classContextBounds = contextBoundBuf.toList - val tstart = in.offset :: classContextBounds.map(_.pos.startOrPoint) min; + val tstart = (in.offset :: classContextBounds.map(_.pos.startOrPoint)).min if (!classContextBounds.isEmpty && mods.isTrait) { syntaxError("traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'", false) classContextBounds = List() @@ -2659,8 +2650,6 @@ self => val nameOffset = in.offset val isBackquoted = in.token == BACKQUOTED_IDENT val name = ident() - if (name.toString == nme.MACROkw.toString && !isBackquoted) - warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.") val tstart = in.offset atPos(start, if (name == nme.ERROR) start else nameOffset) { val mods1 = if (in.token == SUBTYPE) mods | Flags.DEFERRED else mods @@ -2839,24 +2828,7 @@ self => */ def packaging(start: Int): Tree = { val nameOffset = in.offset - def warnIfMacro(tree: Tree): Unit = { - def check(name: Name): Unit = if (name.toString == nme.MACROkw.toString) - warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.") - tree match { - case _: BackQuotedIdent => - ; - case Ident(name) => - check(name) - case Select(qual, name) => - warnIfMacro(qual) - check(name) - case _ => - ; - } - } - val pkg = pkgQualId() - warnIfMacro(pkg) val stats = inBracesOrNil(topStatSeq()) makePackaging(start, pkg, stats) } @@ -3059,27 +3031,8 @@ self => } } else { val nameOffset = in.offset - def warnIfMacro(tree: Tree): Unit = { - def check(name: Name): Unit = if (name.toString == nme.MACROkw.toString) - warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.") - tree match { - // [Eugene] pkgQualId never returns BackQuotedIdents - // this means that we'll get spurious warnings even if we wrap macro package name in backquotes - case _: BackQuotedIdent => - ; - case Ident(name) => - check(name) - case Select(qual, name) => - warnIfMacro(qual) - check(name) - case _ => - ; - } - } - in.flushDoc val pkg = pkgQualId() - warnIfMacro(pkg) if (in.token == EOF) { ts += makePackaging(start, pkg, List()) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index ce38f034cf..87072f3172 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -113,10 +113,18 @@ trait Scanners extends ScannersCommon { } /** Clear buffer and set name and token */ - private def finishNamed() { + private def finishNamed(idtoken: Int = IDENTIFIER) { name = newTermName(cbuf.toString) - token = name2token(name) cbuf.clear() + token = idtoken + if (idtoken == IDENTIFIER) { + val idx = name.start - kwOffset + if (idx >= 0 && idx < kwArray.length) { + token = kwArray(idx) + if (token == IDENTIFIER && allowIdent != name) + deprecationWarning(name+" is now a reserved word; usage as an identifier is deprecated") + } + } } /** Clear buffer and set string */ @@ -190,6 +198,20 @@ trait Scanners extends ScannersCommon { off } + /** Allow an otherwise deprecated ident here */ + private var allowIdent: Name = nme.EMPTY + + /** Get next token, and allow the otherwise deprecated ident `name` */ + def nextTokenAllow(name: Name) = { + val prev = allowIdent + allowIdent = name + try { + nextToken() + } finally { + allowIdent = prev + } + } + /** Produce next token, filling TokenData fields of Scanner. */ def nextToken() { @@ -568,9 +590,8 @@ trait Scanners extends ScannersCommon { getLitChars('`') if (ch == '`') { nextChar() - finishNamed() + finishNamed(BACKQUOTED_IDENT) if (name.length == 0) syntaxError("empty quoted identifier") - token = BACKQUOTED_IDENT } else syntaxError("unclosed quoted identifier") } @@ -1130,9 +1151,9 @@ trait Scanners extends ScannersCommon { nme.VIEWBOUNDkw -> VIEWBOUND, nme.SUPERTYPEkw -> SUPERTYPE, nme.HASHkw -> HASH, - nme.ATkw -> AT - ) ++ - (if (settings.Xmacros.value) List(nme.MACROkw -> MACRO) else List()) + nme.ATkw -> AT, + nme.MACROkw -> IDENTIFIER, + nme.THENkw -> IDENTIFIER) private var kwOffset: Int = -1 private val kwArray: Array[Int] = { @@ -1141,14 +1162,7 @@ trait Scanners extends ScannersCommon { arr } - final val token2name = allKeywords map (_.swap) toMap - - /** Convert name to token */ - final def name2token(name: Name) = { - val idx = name.start - kwOffset - if (idx >= 0 && idx < kwArray.length) kwArray(idx) - else IDENTIFIER - } + final val token2name = (allKeywords map (_.swap)).toMap // Token representation ---------------------------------------------------- diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index 849437e4ff..0f2a3e0395 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -11,6 +11,7 @@ import xml.{ EntityRef, Text } import xml.XML.{ xmlns } import symtab.Flags.MUTABLE import scala.tools.util.StringOps.splitWhere +import language.implicitConversions /** This class builds instance of `Tree` that represent XML. * diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index e17bbf5e46..a4a062609b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -110,7 +110,8 @@ object Tokens extends Tokens { final val MATCH = 58 final val FORSOME = 59 final val LAZY = 61 - final val MACRO = 62 + final val MACRO = 62 // not yet used in 2.10 + final val THEN = 63 // not yet used in 2.10 def isKeyword(code: Int) = code >= IF && code <= LAZY diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 4f3b0bf951..dcbabd6517 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -11,6 +11,7 @@ import scala.collection.{ mutable, immutable } import mutable.{ ListBuffer, ArrayBuffer } import util.{ Position, NoPosition } import backend.icode.analysis.ProgramPoint +import language.postfixOps trait BasicBlocks { self: ICodes => diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index ec303d76ee..ff58de5f12 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -13,6 +13,7 @@ import scala.collection.mutable.{ ListBuffer, Buffer } import scala.tools.nsc.symtab._ import scala.annotation.switch import PartialFunction._ +import language.postfixOps /** This class ... * diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 36651541b2..71795a02aa 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -44,7 +44,7 @@ trait Members { def blocksList: List[BasicBlock] = blocks.toList def instructions = blocksList flatMap (_.iterator) def blockCount = blocks.size - def instructionCount = blocks map (_.length) sum + def instructionCount = (blocks map (_.length)).sum def touched = _touched def touched_=(b: Boolean): Unit = { diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 7ad7cadd92..f61f78ebb2 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -44,7 +44,7 @@ trait TypeKinds { self: ICodes => } /** Reverse map for toType */ private lazy val reversePrimitiveMap: Map[TypeKind, Symbol] = - primitiveTypeMap map (_.swap) toMap + (primitiveTypeMap map (_.swap)).toMap /** This class represents a type kind. Type kinds * represent the types that the VM know (or the ICode diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index f5be82a776..4427da92c8 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -566,8 +566,8 @@ abstract class CopyPropagation { method.blocks map { b => "\nIN(%s):\t Bindings: %s".format(b.label, in(b).bindings) + "\nIN(%s):\t Stack: %s".format(b.label, in(b).stack) - } mkString - ) + } + ).mkString } /* class CopyAnalysis */ } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala index 49f5b51d51..5f261ba05e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala @@ -97,6 +97,6 @@ abstract class Liveness { } } override def toString() = - method.blocks map (b => "\nlive-in(%s)=%s\nlive-out(%s)=%s".format(b, in(b), b, out(b))) mkString + (method.blocks map (b => "\nlive-in(%s)=%s\nlive-out(%s)=%s".format(b, in(b), b, out(b)))).mkString } /* Liveness analysis */ } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index c217869a48..0bc41b51bb 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -13,6 +13,7 @@ import scala.tools.nsc.util.ScalaClassLoader import scala.tools.util.JavapClass import java.util.jar.{ JarEntry, JarOutputStream, Attributes } import Attributes.Name +import language.postfixOps /** For the last mile: turning generated bytecode in memory into * something you can use. Has implementations for writing to class diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index c04be1721e..f7898f2aa2 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -19,6 +19,7 @@ import JAccessFlags._ import JObjectType.{ JAVA_LANG_STRING, JAVA_LANG_OBJECT } import java.util.jar.{ JarEntry, JarOutputStream } import scala.tools.nsc.io.AbstractFile +import language.postfixOps /** This class ... * diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index 98c1fc2f63..66e7becb12 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -15,6 +15,7 @@ import scala.tools.nsc.symtab._ import ch.epfl.lamp.compiler.msil.{Type => MsilType, _} import ch.epfl.lamp.compiler.msil.emit._ import ch.epfl.lamp.compiler.msil.util.PECustomMod +import language.postfixOps abstract class GenMSIL extends SubComponent { import global._ diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index 95c371fa8b..d4ee9b6b48 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -82,7 +82,7 @@ abstract class DeadCodeElimination extends SubComponent { mark sweep(m) accessedLocals = accessedLocals.distinct - if (m.locals diff accessedLocals nonEmpty) { + if ((m.locals diff accessedLocals).nonEmpty) { log("Removed dead locals: " + (m.locals diff accessedLocals)) m.locals = accessedLocals.reverse } diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index ec137203bf..0d47352215 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -360,7 +360,7 @@ abstract class InlineExceptionHandlers extends SubComponent { val caughtException = toTypeKind(caughtClass.tpe) // copy the exception handler code once again, dropping the LOAD_EXCEPTION val copy = handler.code.newBlock - copy.emitOnly(handler.iterator drop dropCount toSeq: _*) + copy.emitOnly((handler.iterator drop dropCount).toSeq: _*) // extend the handlers of the handler to the copy for (parentHandler <- handler.method.exh ; if parentHandler covers handler) { diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index dfe9081ee5..cf51a5b926 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -854,7 +854,7 @@ abstract class Inliners extends SubComponent { def lookupIMethod(meth: Symbol, receiver: Symbol): Option[IMethod] = { def tryParent(sym: Symbol) = icodes icode sym flatMap (_ lookupMethod meth) - receiver.info.baseClasses.iterator map tryParent find (_.isDefined) flatten + (receiver.info.baseClasses.iterator map tryParent find (_.isDefined)).flatten } } /* class Inliner */ } /* class Inliners */ diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala index 3da87bf763..17bfb7d21d 100644 --- a/src/compiler/scala/tools/nsc/doc/Settings.scala +++ b/src/compiler/scala/tools/nsc/doc/Settings.scala @@ -8,6 +8,7 @@ package doc import java.io.File import java.lang.System +import language.postfixOps /** An extended version of compiler settings, with additional Scaladoc-specific options. * @param error A function that prints a string to the appropriate error stream. */ diff --git a/src/compiler/scala/tools/nsc/doc/Uncompilable.scala b/src/compiler/scala/tools/nsc/doc/Uncompilable.scala index dbeca46c25..8f426a443d 100644 --- a/src/compiler/scala/tools/nsc/doc/Uncompilable.scala +++ b/src/compiler/scala/tools/nsc/doc/Uncompilable.scala @@ -5,6 +5,8 @@ package scala.tools.nsc package doc +import language.implicitConversions +import language.postfixOps /** Some glue between DocParser (which reads source files which can't be compiled) * and the scaladoc model. 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 680957c64c..d3f42ffe6e 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -10,6 +10,7 @@ package page import model._ import scala.xml.{ NodeSeq, Text, UnprefixedAttribute } +import language.postfixOps class Template(universe: doc.Universe, tpl: DocTemplateEntity) extends HtmlPage { diff --git a/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala index ef3c2beffb..6392de22ff 100755 --- a/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala @@ -8,6 +8,7 @@ package doc package model import scala.collection._ +import language.reflectiveCalls object IndexModelFactory { @@ -15,7 +16,7 @@ object IndexModelFactory { lazy val firstLetterIndex: Map[Char, SymbolMap] = { - val result = new mutable.HashMap[Char,SymbolMap] { + object result extends mutable.HashMap[Char,SymbolMap] { /* Owner template ordering */ implicit def orderingSet = math.Ordering.String.on { x: MemberEntity => x.name.toLowerCase } diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index f295e4d211..124a7509e8 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -398,11 +398,13 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { else if (bSym.isPackage) makeTemplate(bSym.owner) match { case inPkg: PackageImpl => makePackage(bSym, inPkg) getOrElse (new NoDocTemplateImpl(bSym, inPkg)) + case inNoDocTpl: NoDocTemplateImpl => new NoDocTemplateImpl(bSym, inNoDocTpl) case _ => throw new Error("'" + bSym + "' must be in a package") } else if (templateShouldDocument(bSym)) makeTemplate(bSym.owner) match { case inDTpl: DocTemplateImpl => makeDocTemplate(bSym, inDTpl) + case inNoDocTpl: NoDocTemplateImpl => new NoDocTemplateImpl(bSym, inNoDocTpl) case _ => throw new Error("'" + bSym + "' must be in documentable template") } else @@ -693,9 +695,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { nameBuffer append '⇒' appendType0(result) /* Polymorphic types */ - case PolyType(tparams, result) => assert(tparams nonEmpty) + case PolyType(tparams, result) => assert(tparams.nonEmpty) // throw new Error("Polymorphic type '" + tpe + "' cannot be printed as a type") - def typeParamsToString(tps: List[Symbol]): String = if(tps isEmpty) "" else + def typeParamsToString(tps: List[Symbol]): String = if (tps.isEmpty) "" else tps.map{tparam => tparam.varianceString + tparam.name + typeParamsToString(tparam.typeParams) }.mkString("[", ", ", "]") diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala index 23bef02bed..0e44933ac6 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala @@ -137,8 +137,8 @@ trait ModelFactoryImplicitSupport { // Members inherited by implicit conversions cannot override actual members memberSyms = memberSyms.filterNot((sym1: Symbol) => - existingMembers.exists(sym2 => sym1.name == sym2.name && - isSameType(toType.memberInfo(sym1), sym.info.memberInfo(sym2)))) + existingMembers.exists(sym2 => sym1.name == sym2.name && + !isDistinguishableFrom(toType.memberInfo(sym1), sym.info.memberInfo(sym2)))) debug(" -> full type: " + toType) if (constraints.length != 0) { @@ -498,4 +498,22 @@ trait ModelFactoryImplicitSupport { (aSym.isMethod || aSym.isGetter || aSym.isSetter) && (aSym.nameString != "getClass") } + + /* To put it very bluntly: checks if you can call implicitly added method with t1 when t2 is already there in the + * class. We suppose the name of the two members coincides + * + * The trick here is that the resultType does not matter - the condition for removal it that paramss have the same + * structure (A => B => C may not override (A, B) => C) and that all the types involved are + * of the implcit conversion's member are subtypes of the parent members' parameters */ + def isDistinguishableFrom(t1: Type, t2: Type): Boolean = + if (t1.paramss.map(_.length) == t2.paramss.map(_.length)) { + for ((t1p, t2p) <- t1.paramss.flatten zip t2.paramss.flatten) + if (!isSubType(t1 memberInfo t1p, t2 memberInfo t2p)) + return true // if on the corresponding parameter you give a type that is in t1 but not in t2 + // example: + // def foo(a: Either[Int, Double]): Int = 3 + // def foo(b: Left[T1]): Int = 6 + // a.foo(Right(4.5d)) prints out 3 :) + false + } else true // the member structure is different foo(3, 5) vs foo(3)(5) }
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index bc5cd4a958..e6bc76f676 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -13,6 +13,7 @@ import scala.collection._ import scala.util.matching.Regex import scala.annotation.switch import util.{NoPosition, Position} +import language.postfixOps /** The comment parser transforms raw comment strings into `Comment` objects. * Call `parse` to run the parser. Note that the parser is stateless and diff --git a/src/compiler/scala/tools/nsc/interactive/BuildManager.scala b/src/compiler/scala/tools/nsc/interactive/BuildManager.scala index 2ef34cdd96..0f89236861 100644 --- a/src/compiler/scala/tools/nsc/interactive/BuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/BuildManager.scala @@ -13,6 +13,7 @@ import util.FakePos import dependencies._ import io.AbstractFile +import language.implicitConversions trait BuildManager { diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 12a3c4b3c6..ec73af4dca 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -19,6 +19,7 @@ import scala.tools.nsc.io.Pickler._ import scala.tools.nsc.typechecker.DivergentImplicit import scala.annotation.tailrec import symtab.Flags.{ACCESSOR, PARAMACCESSOR} +import language.implicitConversions /** The main class of the presentation compiler in an interactive environment such as an IDE */ @@ -530,6 +531,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") unit.defined.clear() unit.synthetics.clear() unit.toCheck.clear() + unit.checkedFeatures = Set() unit.targetPos = NoPosition unit.contexts.clear() unit.problems.clear() diff --git a/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala b/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala index 34a0a4abb6..e2dcc48709 100644 --- a/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala +++ b/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala @@ -79,7 +79,7 @@ trait ScratchPadMaker { self: Global => addSandbox(stat) } else { val resName = nextRes() - val dispResName = resName filter ('$' !=) + val dispResName = resName filter ('$' != _) patches += Patch(stat.pos.start, "val " + resName + " = ") addSandbox(stat) toPrint += resultString(nameType(dispResName, stat.tpe), resName) diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala index 40bbd3fa8e..99541ff4b4 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala @@ -81,7 +81,7 @@ private[tests] trait CoreTestDefs else { reporter.println("\naskHyperlinkPos for `" + tree.symbol.name + "` at " + format(pos) + " " + pos.source.file.name) val r = new Response[Position] - // `tree.symbol.sourceFile` was discovered to be null when testing -Yvirtpatmat on the akka presentation test, where a position had shifted to point to `Int` + // `tree.symbol.sourceFile` was discovered to be null when testing using virtpatmat on the akka presentation test, where a position had shifted to point to `Int` // askHyperlinkPos for `Int` at (73,19) pi.scala --> class Int in package scala has null sourceFile! val treePath = if (tree.symbol.sourceFile ne null) tree.symbol.sourceFile.path else null val treeName = if (tree.symbol.sourceFile ne null) tree.symbol.sourceFile.name else null diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 108d4377a8..bf386d8a12 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -23,6 +23,7 @@ import scala.reflect.NameTransformer._ import util.ScalaClassLoader import ScalaClassLoader._ import scala.tools.util._ +import language.{implicitConversions, existentials} /** The Scala interactive shell. It provides a read-eval-print loop * around the Interpreter class. diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index c0f7d8412a..43e01bebfd 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -24,6 +24,7 @@ import scala.collection.{ mutable, immutable } import scala.util.control.Exception.{ ultimately } import IMain._ import java.util.concurrent.Future +import language.implicitConversions /** directory to save .class files to */ private class ReplVirtualDirectory(out: JPrintWriter) extends VirtualDirectory("(memory)", None) { @@ -203,8 +204,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends }).toList } - implicit def installReplTypeOps(tp: Type): ReplTypeOps = new ReplTypeOps(tp) - class ReplTypeOps(tp: Type) { + implicit class ReplTypeOps(tp: Type) { def orElse(other: => Type): Type = if (tp ne NoType) tp else other def andAlso(fn: Type => Type): Type = if (tp eq NoType) tp else fn(tp) } @@ -825,7 +825,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends } def lastWarnings: List[(Position, String)] = ( if (lastRun == null) Nil - else removeDupWarnings(lastRun.deprecationWarnings.reverse) ++ lastRun.uncheckedWarnings.reverse + else removeDupWarnings(lastRun.allConditionalWarnings flatMap (_.warnings)) ) private var lastRun: Run = _ private def evalMethod(name: String) = evalClass.getMethods filter (_.getName == name) match { diff --git a/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala b/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala index 9469baa4e2..3520a60ee5 100644 --- a/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala +++ b/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala @@ -8,6 +8,7 @@ package interpreter import collection.{ mutable, immutable } import mutable.ListBuffer +import language.implicitConversions class ProcessResult(val line: String) { import sys.process._ diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala index 099034fe97..40993eb916 100644 --- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -9,6 +9,7 @@ package interpreter import scala.collection.{ mutable, immutable } import scala.PartialFunction.cond import scala.reflect.internal.Chars +import language.implicitConversions trait MemberHandlers { val intp: IMain diff --git a/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala b/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala index e92888d89b..e2b1bf34d6 100644 --- a/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala +++ b/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala @@ -7,6 +7,7 @@ package scala.tools.nsc package interpreter import NamedParam._ +import language.implicitConversions trait NamedParamCreator { protected def freshName: () => String @@ -43,4 +44,4 @@ trait NamedParam { def tpe: String def value: Any override def toString = name + ": " + tpe -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/interpreter/Phased.scala b/src/compiler/scala/tools/nsc/interpreter/Phased.scala index d164d1cbb0..f39c025a86 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Phased.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Phased.scala @@ -7,6 +7,7 @@ package scala.tools.nsc package interpreter import scala.collection.{ mutable, immutable } +import language.implicitConversions /** Mix this into an object and use it as a phasing * swiss army knife. diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala index cc06100f5f..ecf9dd219b 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Power.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala @@ -13,6 +13,7 @@ import session.{ History } import scala.io.Codec import java.net.{ URL, MalformedURLException } import io.{ Path } +import language.implicitConversions /** Collecting some power mode examples. diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplTokens.scala b/src/compiler/scala/tools/nsc/interpreter/ReplTokens.scala index 1c7b256c33..e63fabf151 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplTokens.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplTokens.scala @@ -9,6 +9,7 @@ package interpreter import util.{ BatchSourceFile, Indenter } import scala.tools.nsc.ast.parser.Tokens._ import java.lang.Integer.toOctalString +import language.{implicitConversions, existentials} /** This began as an attempt at a completely minimal * pretty printer for a token stream, but as it turns out diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala index e293c0fed9..8b891e0010 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala @@ -6,6 +6,8 @@ package scala.tools.nsc package interpreter +import language.implicitConversions + /** A class which the repl utilizes to expose predefined objects. * The base implementation is empty; the standard repl implementation * is StdReplVals. diff --git a/src/compiler/scala/tools/nsc/interpreter/package.scala b/src/compiler/scala/tools/nsc/interpreter/package.scala index e78e92c8f8..7d2610e3c8 100644 --- a/src/compiler/scala/tools/nsc/interpreter/package.scala +++ b/src/compiler/scala/tools/nsc/interpreter/package.scala @@ -5,6 +5,8 @@ package scala.tools.nsc +import language.implicitConversions + /** The main REPL related classes and values are as follows. * In addition to standard compiler classes Global and Settings, there are: * @@ -33,6 +35,8 @@ package object interpreter extends ReplConfig with ReplStrings { val IR = Results + implicit def postfixOps = language.postfixOps // make all postfix ops in this package compile without warning + private[interpreter] implicit def javaCharSeqCollectionToScala(xs: JCollection[_ <: CharSequence]): List[String] = { import collection.JavaConverters._ xs.asScala.toList map ("" + _) diff --git a/src/compiler/scala/tools/nsc/interpreter/session/package.scala b/src/compiler/scala/tools/nsc/interpreter/session/package.scala index 8fbba2f05e..4e5b08c8cb 100644 --- a/src/compiler/scala/tools/nsc/interpreter/session/package.scala +++ b/src/compiler/scala/tools/nsc/interpreter/session/package.scala @@ -5,6 +5,7 @@ package scala.tools.nsc package interpreter +import language.implicitConversions /** Files having to do with the state of a repl session: * lines of text entered, types and terms defined, etc. diff --git a/src/compiler/scala/tools/nsc/io/File.scala b/src/compiler/scala/tools/nsc/io/File.scala index cc512493d9..06cb20e4ac 100644 --- a/src/compiler/scala/tools/nsc/io/File.scala +++ b/src/compiler/scala/tools/nsc/io/File.scala @@ -15,6 +15,7 @@ import java.io.{ BufferedInputStream, BufferedOutputStream, IOException, PrintStream, PrintWriter, Closeable => JCloseable } import java.nio.channels.{ Channel, FileChannel } import scala.io.Codec +import language.{reflectiveCalls, implicitConversions} object File { def pathSeparator = java.io.File.pathSeparator diff --git a/src/compiler/scala/tools/nsc/io/Jar.scala b/src/compiler/scala/tools/nsc/io/Jar.scala index bbed5a9e20..b322df986c 100644 --- a/src/compiler/scala/tools/nsc/io/Jar.scala +++ b/src/compiler/scala/tools/nsc/io/Jar.scala @@ -11,6 +11,7 @@ import java.util.jar._ import collection.JavaConverters._ import Attributes.Name import util.ClassPath +import language.implicitConversions // Attributes.Name instances: // diff --git a/src/compiler/scala/tools/nsc/io/Path.scala b/src/compiler/scala/tools/nsc/io/Path.scala index a1b8e5e4d5..b8cf15bfcf 100644 --- a/src/compiler/scala/tools/nsc/io/Path.scala +++ b/src/compiler/scala/tools/nsc/io/Path.scala @@ -11,6 +11,7 @@ import java.io.{ BufferedInputStream, BufferedOutputStream, RandomAccessFile } import java.net.{ URI, URL } import scala.util.Random.alphanumeric +import language.implicitConversions /** An abstraction for filesystem paths. The differences between * Path, File, and Directory are primarily to communicate intent. diff --git a/src/compiler/scala/tools/nsc/io/Pickler.scala b/src/compiler/scala/tools/nsc/io/Pickler.scala index 80b6e086da..86c7ca7b9a 100644 --- a/src/compiler/scala/tools/nsc/io/Pickler.scala +++ b/src/compiler/scala/tools/nsc/io/Pickler.scala @@ -3,6 +3,7 @@ package scala.tools.nsc.io import annotation.unchecked import Lexer._ import java.io.Writer +import language.implicitConversions /** An abstract class for writing and reading Scala objects to and * from a legible representation. The presesentation follows the following grammar: @@ -168,14 +169,11 @@ object Pickler { case class ~[+S, +T](fst: S, snd: T) /** A wrapper class to be able to use `~` s an infix method */ - class TildeDecorator[S](x: S) { + implicit class TildeDecorator[S](x: S) { /** Infix method that forms a `~`-pair. */ def ~ [T](y: T): S ~ T = new ~ (x, y) } - /** An implicit wrapper that adds `~` as a method to any value. */ - implicit def tildeDecorator[S](x: S): TildeDecorator[S] = new TildeDecorator(x) - /** A converter from binary functions to functions over `~`-pairs */ implicit def fromTilde[T1, T2, R](f: (T1, T2) => R): T1 ~ T2 => R = { case x1 ~ x2 => f(x1, x2) } diff --git a/src/compiler/scala/tools/nsc/io/package.scala b/src/compiler/scala/tools/nsc/io/package.scala index 88679e6dce..52e6de0bed 100644 --- a/src/compiler/scala/tools/nsc/io/package.scala +++ b/src/compiler/scala/tools/nsc/io/package.scala @@ -8,8 +8,11 @@ package scala.tools.nsc import java.util.concurrent.{ Future, Callable } import java.util.{ Timer, TimerTask } import java.util.jar.{ Attributes } +import language.implicitConversions package object io { + implicit def postfixOps = language.postfixOps // make all postfix ops in this package compile without warning + type JManifest = java.util.jar.Manifest type JFile = java.io.File @@ -41,4 +44,4 @@ package object io { alarm.schedule(tt, seconds * 1000) alarm } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 06b06c50a6..ca3f3ff635 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -12,6 +12,7 @@ import scala.tools.nsc.util.OffsetPosition import scala.collection.mutable.ListBuffer import symtab.Flags import JavaTokens._ +import language.implicitConversions trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val global : Global diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index 45b63b0ca0..d47756e757 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -10,6 +10,7 @@ import scala.tools.nsc.util._ import scala.reflect.internal.Chars._ import JavaTokens._ import scala.annotation.switch +import language.implicitConversions // Todo merge these better with Scanners trait JavaScanners extends ast.parser.ScannersCommon { diff --git a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala index 371f4bc4d8..249f754e8f 100644 --- a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala +++ b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala @@ -10,6 +10,7 @@ import transform.ExplicitOuter import ast.{ TreePrinters, Trees } import java.io.{ StringWriter, PrintWriter } import annotation.elidable +import language.postfixOps /** Ancillary bits of ParallelMatching which are better off * out of the way. @@ -29,11 +30,10 @@ trait MatchSupport extends ast.TreeDSL { self: ParallelMatching => object Types { import definitions._ - implicit def enrichType(x: Type): RichType = new RichType(x) val subrangeTypes = Set(ByteClass, ShortClass, CharClass, IntClass) - class RichType(undecodedTpe: Type) { + implicit class RichType(undecodedTpe: Type) { def tpe = decodedEqualsType(undecodedTpe) def isAnyRef = tpe <:< AnyRefClass.tpe diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index e1ff88557e..b29fac225a 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -9,6 +9,7 @@ package matching import transform.ExplicitOuter import symtab.Flags import scala.collection.mutable +import language.implicitConversions trait Matrix extends MatrixAdditions { self: ExplicitOuter with ParallelMatching => @@ -255,4 +256,4 @@ trait Matrix extends MatrixAdditions { recordSyntheticSym(owner.newVariable(n, pos, flagsLong) setInfo tpe) } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 43aad9f591..7346d9c59f 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -14,6 +14,7 @@ import transform.ExplicitOuter import symtab.Flags import mutable.ListBuffer import annotation.elidable +import language.postfixOps trait ParallelMatching extends ast.TreeDSL with MatchSupport diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala index 56297f0195..b2a721c586 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala @@ -8,6 +8,7 @@ package matching import transform.ExplicitOuter import PartialFunction._ +import language.postfixOps trait PatternBindings extends ast.TreeDSL { @@ -133,4 +134,4 @@ trait PatternBindings extends ast.TreeDSL } val NoBinding: Bindings = new Bindings(Nil) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index 9254ec8628..48c4a9b5b3 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -138,7 +138,7 @@ object Plugin { } yield entry)).distinct val loader = loaderFor(alljars) - alljars map (loadFrom(_, loader)) flatten + (alljars map (loadFrom(_, loader))).flatten } /** Instantiate a plugin class, given the class and diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index da913a1601..ba042b7b78 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -70,7 +70,7 @@ trait Plugins { } } - val plugs = pick(roughPluginsList, Set(), phasesSet map (_.phaseName) toSet) + val plugs = pick(roughPluginsList, Set(), (phasesSet map (_.phaseName)).toSet) /** Verify requirements are present. */ for (req <- settings.require.value ; if !(plugs exists (_.name == req))) @@ -112,5 +112,5 @@ trait Plugins { def pluginOptionsHelp: String = (for (plug <- roughPluginsList ; help <- plug.optionsHelp) yield { "\nOptions for plugin '%s':\n%s\n".format(plug.name, help) - }) mkString + }).mkString } diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala index 9cea935a63..c1dad2da82 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala @@ -35,7 +35,7 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings { case s: AbsSettings => this.userSetSettings == s.userSetSettings case _ => false } - override def toString() = "Settings {\n%s}\n" format (userSetSettings map (" " + _ + "\n") mkString) + override def toString() = "Settings {\n%s}\n" format (userSetSettings map (" " + _ + "\n")).mkString def toConciseString = userSetSettings.mkString("(", " ", ")") def checkDependencies = diff --git a/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala b/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala index c010c6a3ea..63775ff1c5 100644 --- a/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala @@ -23,6 +23,7 @@ trait AestheticSettings { def deprecation = settings.deprecation.value def experimental = settings.Xexperimental.value def fatalWarnings = settings.fatalWarnings.value + def feature = settings.feature.value def future = settings.future.value def logClasspath = settings.Ylogcp.value def printStats = settings.Ystatistics.value @@ -30,7 +31,7 @@ trait AestheticSettings { def target = settings.target.value def unchecked = settings.unchecked.value def verbose = settings.verbose.value - def virtPatmat = settings.YvirtPatmat.value + def virtPatmat = !settings.XoldPatmat.value /** Derived values */ def jvm = target startsWith "jvm" diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index ea12300785..a52e3b8bbe 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -136,7 +136,7 @@ class MutableSettings(val errorFn: String => Unit) val (p, args) = StringOps.splitWhere(s, _ == ':', true) getOrElse (return None) // any non-Nil return value means failure and we return s unmodified - tryToSetIfExists(p, args split "," toList, (s: Setting) => s.tryToSetColon _) + tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon _) } // if arg is of form -Xfoo or -Xfoo bar (name = "-Xfoo") diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index e9a7e3dab4..d4c2ffa832 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -11,6 +11,7 @@ package settings import annotation.elidable import scala.tools.util.PathResolver.Defaults import scala.collection.mutable +import language.{implicitConversions, existentials} trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings @@ -62,6 +63,7 @@ trait ScalaSettings extends AbsScalaSettings val classpath = PathSetting ("-classpath", "Specify where to find user class files.", defaultClasspath) withAbbreviation "-cp" val d = OutputSetting (outputDirs, ".") val nospecialization = BooleanSetting ("-no-specialization", "Ignore @specialize annotations.") + val language = MultiStringSetting("-language", "feature", "Enable one or more language features.") /** * -X "Advanced" settings @@ -106,6 +108,8 @@ trait ScalaSettings extends AbsScalaSettings val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases.") val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "") + val XoldPatmat = BooleanSetting ("-Xoldpatmat", "Use the pre-2.10 pattern matcher. Otherwise, the 'virtualizing' pattern matcher is used in 2.10.") + /** Compatibility stubs for options whose value name did * not previously match the option name. */ @@ -173,7 +177,6 @@ trait ScalaSettings extends AbsScalaSettings val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.") 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 noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.") - val YvirtPatmat = BooleanSetting ("-Yvirtpatmat", "Translate pattern matches into flatMap/orElse calls. See scala.MatchingStrategy.") 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() @@ -203,7 +206,7 @@ trait ScalaSettings extends AbsScalaSettings val Xexperimental = BooleanSetting("-Xexperimental", "Enable experimental extensions.") enabling experimentalSettings // Feature extensions - val Xmacros = BooleanSetting("-Xmacros", "Enable macros.") + val Xmacros = BooleanSetting("-Xmacros", "Enable macros.") // [Martin] Can be retired now. val XmacroSettings = MultiStringSetting("-Xmacro-settings", "option", "Custom settings for macros.") val XmacroPrimaryClasspath = PathSetting("-Xmacro-primary-classpath", "Classpath to load macros implementations from, defaults to compilation classpath (aka \"library classpath\".", "") val XmacroFallbackClasspath = PathSetting("-Xmacro-fallback-classpath", "Classpath to load macros implementations from if they cannot be loaded from library classpath.", "") diff --git a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala index c5b477c7bd..a69b88a5df 100644 --- a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala @@ -32,6 +32,7 @@ trait StandardScalaSettings { val deprecation = BooleanSetting ("-deprecation", "Emit warning and location for usages of deprecated APIs.") val encoding = StringSetting ("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding) val explaintypes = BooleanSetting ("-explaintypes", "Explain type errors in more detail.") + val feature = BooleanSetting ("-feature", "Emit warning and location for usages of features that should be imported explicitly.") val g = ChoiceSetting ("-g", "level", "Set level of generated debugging info.", List("none", "source", "line", "vars", "notailcalls"), "vars") val help = BooleanSetting ("-help", "Print a synopsis of standard options") val make = ChoiceSetting ("-make", "policy", "Recompilation detection policy", List("all", "changed", "immediate", "transitive", "transitivenocp"), "all") diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala index e62070a239..3cf5cc2f54 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala @@ -7,6 +7,8 @@ package scala.tools.nsc package symtab import scala.collection.{ mutable, immutable } +import language.implicitConversions +import language.postfixOps /** Printing the symbol graph (for those symbols attached to an AST node) * after each phase. diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index edbe6df472..52648380ec 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -149,7 +149,7 @@ abstract class Pickler extends SubComponent { putChildren(sym, children.toList sortBy (_.sealedSortName)) } - for (annot <- sym.annotations filter (ann => ann.isStatic && !ann.isErroneous) reverse) + for (annot <- (sym.annotations filter (ann => ann.isStatic && !ann.isErroneous)).reverse) putAnnotation(sym, annot) } else if (sym != NoSymbol) { diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 4b847fa94a..028d6f2484 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -12,6 +12,7 @@ import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, import scala.collection.{ mutable, immutable } import scala.reflect.internal.pickling.UnPickler import ch.epfl.lamp.compiler.msil.Type.TMVarUsage +import language.implicitConversions /** * @author Nikolay Mihaylov diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index eea87c8ba6..fd15d92e37 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -9,6 +9,7 @@ package transform import symtab._ import Flags._ import scala.collection._ +import language.postfixOps abstract class CleanUp extends Transform with ast.TreeDSL { import global._ diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index e2ce3b62b4..5e61359a25 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -210,7 +210,7 @@ abstract class Erasure extends AddInterfaces } else parents ) - ps map boxedSig mkString + (ps map boxedSig).mkString } def boxedSig(tp: Type) = jsig(tp, primitiveOK = false) def boundsSig(bounds: List[Type]) = traceSig("boundsSig", bounds) { @@ -480,11 +480,10 @@ abstract class Erasure extends AddInterfaces // TODO: should we do this for user-defined unapplies as well? // does the first argument list have exactly one argument -- for user-defined unapplies we can't be sure def maybeWrap(bridgingCall: Tree): Tree = { - val canReturnNone = afterErasure( - member.isSynthetic - && (member.name == nme.unapply || member.name == nme.unapplySeq) - && !(member.tpe <:< other.tpe) // no static guarantees (TODO: is the subtype test ever true?) - ) + val canReturnNone = ( // can't statically know which member is going to be selected, so don't let this depend on member.isSynthetic + (member.name == nme.unapply || member.name == nme.unapplySeq) + && !afterErasure((member.tpe <:< other.tpe))) // no static guarantees (TODO: is the subtype test ever true?) + if (canReturnNone) { import CODE._ val typeTest = gen.mkIsInstanceOf(REF(bridge.firstParam), member.tpe.params.head.tpe) diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 16c7c3c3ff..8daad8a2ac 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -357,7 +357,7 @@ abstract class ExplicitOuter extends InfoTransform */ def mixinOuterAccessorDef(mixinClass: Symbol): Tree = { val outerAcc = outerAccessor(mixinClass) overridingSymbol currentClass - def mixinPrefix = currentClass.thisType baseType mixinClass prefix; + def mixinPrefix = (currentClass.thisType baseType mixinClass).prefix assert(outerAcc != NoSymbol, "No outer accessor for inner mixin " + mixinClass + " in " + currentClass) // I added the mixinPrefix.typeArgs.nonEmpty condition to address the // crash in SI-4970. I feel quite sure this can be improved. diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 3515c1d521..007457ef7b 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -50,7 +50,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { val index = alts indexOf imeth assert(index >= 0, alts+" does not contain "+imeth) def altName(index: Int) = newTermName("extension"+index+"$"+imeth.name) - altName(index) #:: ((0 until alts.length).toStream filter (index !=) map altName) + altName(index) #:: ((0 until alts.length).toStream filter (index != _) map altName) case tpe => assert(tpe != NoType, imeth.name+" not found in "+imeth.owner+"'s decls: "+imeth.owner.info.decls) Stream(newTermName("extension$"+imeth.name)) diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 0e4975c04c..19f32a5411 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -123,7 +123,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { */ private def rebindSuper(base: Symbol, member: Symbol, mixinClass: Symbol): Symbol = afterPickler { - var bcs = base.info.baseClasses.dropWhile(mixinClass !=).tail + var bcs = base.info.baseClasses.dropWhile(mixinClass != _).tail var sym: Symbol = NoSymbol debuglog("starting rebindsuper " + base + " " + member + ":" + member.tpe + " " + mixinClass + " " + base.info.baseClasses + "/" + bcs) @@ -778,7 +778,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { val fields0 = usedBits(cl) if (requiredBitmaps(fields0) < bitmapNum) { - val fields1 = cl.info.decls filter isNonLocalFieldWithBitmap size; + val fields1 = (cl.info.decls filter isNonLocalFieldWithBitmap).size return { if (requiredBitmaps(fields0 + fields1) >= bitmapNum) Some(bitmapFor(cl, offset, valSym, false)) diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 8d08888a1f..ff671088ac 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -8,6 +8,7 @@ package transform import scala.tools.nsc.symtab.Flags import scala.collection.{ mutable, immutable } +import language.postfixOps /** Specialize code on types. * diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 11f06a0541..57cd51ad35 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -8,6 +8,7 @@ package transform import symtab.Flags._ import scala.collection.{ mutable, immutable } +import language.postfixOps /*<export> */ /** - uncurry all symbol and tree types (@see UnCurryPhase) -- this includes normalizing all proper types. @@ -240,7 +241,6 @@ abstract class UnCurry extends InfoTransform def owner = fun.symbol.owner def targs = fun.tpe.typeArgs def isPartial = fun.tpe.typeSymbol == PartialFunctionClass - assert(!(opt.virtPatmat && isPartial)) // empty-selector matches have already been translated into instantiations of anonymous (partial) functions def parents = if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) @@ -281,7 +281,44 @@ abstract class UnCurry extends InfoTransform val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x)) val body = localTyper.typedPos(fun.pos) { import CODE._ - gen.mkUncheckedMatch(gen.withDefaultCase(substParam(fun.body), scrut => REF(default) APPLY (REF(x)))) + def defaultAction(scrut: Tree) = REF(default) APPLY (REF(x)) + + object withDefaultTransformer extends gen.MatchMatcher { + override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { + val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) + if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) orig + else { + val defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, defaultAction(selector.duplicate)) + wrap(Match(/*gen.mkUnchecked*/(selector), casesNoSynthCatchAll :+ defaultCase)) + } + } + override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = { import CODE._ + ((matcher APPLY (scrut)) DOT nme.getOrElse) APPLY (defaultAction(scrut.duplicate)) // TODO: pass targs + } + override def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree): Tree = { import CODE._ + val scrutRef = REF(prologue.head.symbol) // scrut valdef is always emitted (except for nested matchers that handle alternatives) + + val casesNewSynthCatchAll = cases.init :+ (deriveLabelDef(cases.last){ + case Apply(matchEnd, List(Throw(Apply(Select(New(exTpt), nme.CONSTRUCTOR), _)))) if exTpt.tpe.typeSymbol eq MatchErrorClass => + assert(matchEnd.symbol == matchEndDef.symbol, "matchEnd discrepancy "+(matchEnd, matchEndDef)) + matchEnd APPLY (defaultAction(scrutRef)) + case x => x + } setSymbol cases.last.symbol setType null) + + val LabelDef(_, List(matchRes), rhs) = matchEndDef + val matchEnd = matchEndDef.symbol + matchRes setType B1.tpe + rhs setType B1.tpe + matchEndDef setType B1.tpe + matchRes.symbol setInfo B1.tpe + matchEnd setInfo MethodType(List(matchRes.symbol), B1.tpe) + cases foreach (c => c.symbol setInfo MethodType(List(), B1.tpe)) + + wrap(Block(prologue ++ casesNewSynthCatchAll, matchEndDef)) + } + } + + withDefaultTransformer(substParam(fun.body)) } body.changeOwner(fun.symbol -> methSym) @@ -293,30 +330,115 @@ abstract class UnCurry extends InfoTransform methDef } - // duplicate before applyOrElseMethodDef is run so we start with the same symbols as applyOrElseMethodDef + // duplicate before applyOrElseMethodDef is run so that it does not mess up our trees and label symbols (we have a fresh set) // otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already - val bodyForIDA = fun.body.duplicate + val bodyForIDA = { + val duped = fun.body.duplicate + val oldParams = new mutable.ListBuffer[Symbol]() + val newParams = new mutable.ListBuffer[Symbol]() + + val oldSyms0 = + duped filter { + case l@LabelDef(_, params, _) => + params foreach {p => + val oldSym = p.symbol + p.symbol = oldSym.cloneSymbol + oldParams += oldSym + newParams += p.symbol + } + true + case _ => false + } map (_.symbol) + val oldSyms = oldParams.toList ++ oldSyms0 + val newSyms = newParams.toList ++ (oldSyms0 map (_.cloneSymbol)) + // println("duping "+ oldSyms +" --> "+ (newSyms map (_.ownerChain))) + + val substLabels = new TreeSymSubstituter(oldSyms, newSyms) + + substLabels(duped) + } + def isDefinedAtMethodDef = { val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL) val params = methSym newSyntheticValueParams formals methSym setInfoAndEnter MethodType(params, BooleanClass.tpe) val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params) - def doSubst(x: Tree) = substParam(resetLocalAttrs(x)) // see pos/t1761 for why `resetLocalAttrs` + def doSubst(x: Tree) = substParam(resetLocalAttrsKeepLabels(x)) // see pos/t1761 for why `resetLocalAttrs`, but must keep label symbols around + object isDefinedAtTransformer extends gen.MatchMatcher { // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { import CODE._ - gen.mkUncheckedMatch( - if (cases exists treeInfo.isDefaultCase) TRUE_typed + val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) + if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) TRUE_typed else doSubst(wrap( - Match(selector, - (cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ ( + Match(/*gen.mkUnchecked*/(selector), + (casesNoSynthCatchAll map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ ( DEFAULT ==> FALSE_typed) ))) - ) + } + override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = { + object noOne extends Transformer { + override val treeCopy = newStrictTreeCopier // must duplicate everything + val one = _match.tpe member newTermName("one") + override def transform(tree: Tree): Tree = tree match { + case Apply(fun, List(a)) if fun.symbol == one => + // blow one's argument away since all we want to know is whether the match succeeds or not + // (the alternative, making `one` CBN, would entail moving away from Option) + Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe))) + case _ => + super.transform(tree) + } + } + doSubst(Apply(Apply(TypeApply(Select(_match.duplicate, _match.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), List(scrut.duplicate)), List(noOne.transform(matcher)))) + } + + override def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree) = { + val matchEnd = matchEndDef.symbol + val LabelDef(_, List(matchRes), rhs) = matchEndDef + matchRes setType BooleanClass.tpe + rhs setType BooleanClass.tpe + matchEndDef setType BooleanClass.tpe + matchRes.symbol setInfo BooleanClass.tpe + matchEnd setInfo MethodType(List(matchRes.symbol), BooleanClass.tpe) + cases foreach (c => c.symbol setInfo MethodType(List(), BooleanClass.tpe)) + // println("matchEnd: "+ matchEnd) + + // when the type of the selector contains a skolem owned by the applyOrElseMethod, should reskolemize everything, + // for now, just cast the RHS (since we're just trying to keep the typer happy, the cast is meaningless) + // ARGH -- this is why I would prefer the typedMatchAnonFun approach (but alas, CPS blocks that) + val newPrologue = prologue match { + case List(vd@ValDef(mods, name, tpt, rhs)) => List(treeCopy.ValDef(vd, mods, name, tpt, gen.mkAsInstanceOf(rhs, tpt.tpe, true, false))) + case _ => prologue + } + object casesReturnTrue extends Transformer { + // override val treeCopy = newStrictTreeCopier // will duplicate below + override def transform(tree: Tree): Tree = tree match { + // don't compute the result of the match, return true instead + case Apply(fun, List(res)) if fun.symbol eq matchEnd => + // println("matchend call "+ fun.symbol) + Apply(fun, List(TRUE_typed)) setType BooleanClass.tpe + case _ => super.transform(tree) + } + } + val newCatchAll = cases.last match { + case LabelDef(n, ps, Apply(matchEnd1, List(Throw(Apply(Select(New(exTpt), nme.CONSTRUCTOR), _))))) if exTpt.tpe.typeSymbol eq MatchErrorClass => + assert(matchEnd1.symbol == matchEnd, "matchEnd discrepancy "+(matchEnd, matchEndDef)) + List(treeCopy.LabelDef(cases.last, n, ps, matchEnd APPLY (FALSE_typed)) setSymbol cases.last.symbol) + case x => Nil + } + val casesWithoutCatchAll = if(newCatchAll.isEmpty) cases else cases.init + doSubst(wrap(Block(newPrologue ++ casesReturnTrue.transformTrees(casesWithoutCatchAll) ++ newCatchAll, matchEndDef))) + + // val duped = idaBlock //.duplicate // TODO: duplication of labeldefs is BROKEN + // duped foreach { + // case l@LabelDef(name, params, rhs) if gen.hasSynthCaseSymbol(l) => println("newInfo"+ l.symbol.info) + // case _ => + // } } } + val body = isDefinedAtTransformer(bodyForIDA) body.changeOwner(fun.symbol -> methSym) @@ -327,11 +449,14 @@ abstract class UnCurry extends InfoTransform if (isPartial) List(applyOrElseMethodDef, isDefinedAtMethodDef) else List(applyMethodDef) - localTyper.typedPos(fun.pos) { + // println("MEMBERS "+ members) + val res = localTyper.typedPos(fun.pos) { Block( List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } + // println("MEMBERS TYPED "+ members) + res } def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index edc69be827..e9c3bef737 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -483,7 +483,7 @@ trait ContextErrors { val keep = missing take 3 map (_.name) ".\nUnspecified value parameter%s %s".format( if (missing.tail.isEmpty) "" else "s", - if (missing drop 3 nonEmpty) (keep :+ "...").mkString(", ") + if ((missing drop 3).nonEmpty) (keep :+ "...").mkString(", ") else keep.mkString("", ", ", ".") ) } @@ -504,6 +504,9 @@ trait ContextErrors { def ApplyWithoutArgsError(tree: Tree, fun: Tree) = NormalTypeError(tree, fun.tpe+" does not take parameters") + def DynamicVarArgUnsupported(tree: Tree, name: String) = + issueNormalTypeError(tree, name+ " does not support passing a vararg parameter") + //checkClassType def TypeNotAStablePrefixError(tpt: Tree, pre: Type) = { issueNormalTypeError(tpt, "type "+pre+" is not a stable prefix") @@ -644,7 +647,7 @@ trait ContextErrors { private def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = { def asParams(xs: List[Any]) = xs.mkString("(", ", ", ")") - def resType = if (pt isWildcard) "" else " with expected result type " + pt + def resType = if (pt.isWildcard) "" else " with expected result type " + pt def allTypes = (alternatives(tree) flatMap (_.paramTypes)) ++ argtpes :+ pt def locals = alternatives(tree) flatMap (_.typeParams) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index fe1c90fe67..e2d4efab83 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -67,6 +67,7 @@ trait Contexts { self: Analyzer => val c = sc.make(unit, tree, sc.owner, sc.scope, sc.imports) if (erasedTypes) c.setThrowErrors() else c.setReportErrors() c.implicitsEnabled = !erasedTypes + c.enrichmentEnabled = c.implicitsEnabled c } @@ -106,7 +107,7 @@ trait Contexts { self: Analyzer => var depth: Int = 0 var imports: List[ImportInfo] = List() // currently visible imports var openImplicits: List[(Type,Tree)] = List() // types for which implicit arguments - // are currently searched + // are currently searched // for a named application block (Tree) the corresponding NamedApplyInfo var namedApplyBlockInfo: Option[(Tree, NamedApplyInfo)] = None var prefix: Type = NoPrefix @@ -120,6 +121,7 @@ trait Contexts { self: Analyzer => var diagnostic: List[String] = Nil // these messages are printed when issuing an error var implicitsEnabled = false var macrosEnabled = true + var enrichmentEnabled = false // to selectively allow enrichment in patterns, where other kinds of implicit conversions are not allowed var checking = false var retyping = false @@ -192,8 +194,25 @@ trait Contexts { self: Analyzer => def withImplicitsDisabled[T](op: => T): T = { val saved = implicitsEnabled implicitsEnabled = false + val savedP = enrichmentEnabled + enrichmentEnabled = false try op - finally implicitsEnabled = saved + finally { + implicitsEnabled = saved + enrichmentEnabled = savedP + } + } + + def withImplicitsDisabledAllowEnrichment[T](op: => T): T = { + val saved = implicitsEnabled + implicitsEnabled = false + val savedP = enrichmentEnabled + enrichmentEnabled = true + try op + finally { + implicitsEnabled = saved + enrichmentEnabled = savedP + } } def withMacrosEnabled[T](op: => T): T = { @@ -246,6 +265,7 @@ trait Contexts { self: Analyzer => c.typingIndentLevel = typingIndentLevel c.implicitsEnabled = this.implicitsEnabled c.macrosEnabled = this.macrosEnabled + c.enrichmentEnabled = this.enrichmentEnabled c.checking = this.checking c.retyping = this.retyping c.openImplicits = this.openImplicits @@ -298,6 +318,7 @@ trait Contexts { self: Analyzer => def makeImplicit(reportAmbiguousErrors: Boolean) = { val c = makeSilent(reportAmbiguousErrors) c.implicitsEnabled = false + c.enrichmentEnabled = false c } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index eb8bef3b58..4fb9362ccc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -166,7 +166,7 @@ trait Implicits { } def isCyclicOrErroneous = - try containsError(tpe) + try sym.hasFlag(LOCKED) || containsError(tpe) catch { case _: CyclicReference => true } var useCountArg: Int = 0 @@ -710,7 +710,7 @@ trait Implicits { def comesBefore(sym: Symbol, owner: Symbol) = { val ownerPos = owner.pos.pointOrElse(Int.MaxValue) sym.pos.pointOrElse(0) < ownerPos && ( - if (sym hasAccessorFlag) { + if (sym.hasAccessorFlag) { val symAcc = sym.accessed // #3373 symAcc.pos.pointOrElse(0) < ownerPos && !(owner.ownerChain exists (o => (o eq sym) || (o eq symAcc))) // probably faster to iterate only once, don't feel like duplicating hasTransOwner for this case @@ -830,7 +830,7 @@ trait Implicits { /** Returns all eligible ImplicitInfos and their SearchResults in a map. */ - def findAll() = eligible map (info => (info, typedImplicit(info, false))) toMap + def findAll() = (eligible map (info => (info, typedImplicit(info, false)))).toMap /** Returns the SearchResult of the best match. */ @@ -1251,7 +1251,7 @@ trait Implicits { // where `X` refers to a type parameter of `sym` def check(sym: Symbol): Option[String] = sym.getAnnotation(ImplicitNotFoundClass).flatMap(_.stringArg(0) match { - case Some(m) => new Message(sym, m) validate + case Some(m) => new Message(sym, m).validate case None => Some("Missing argument `msg` on implicitNotFound annotation.") }) @@ -1276,7 +1276,7 @@ trait Implicits { val decls = typeParamNames.toSet (refs &~ decls) match { - case s if s isEmpty => None + case s if s.isEmpty => None case unboundNames => val singular = unboundNames.size == 1 Some("The type parameter"+( if(singular) " " else "s " )+ unboundNames.mkString(", ") + diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index d2fe106b14..fb0616c890 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -446,7 +446,7 @@ trait Infer { type Result = collection.mutable.LinkedHashMap[Symbol, Option[Type]] def unapply(m: Result): Some[(List[Symbol], List[Type])] = Some(toLists( - m collect {case (p, Some(a)) => (p, a)} unzip )) + (m collect {case (p, Some(a)) => (p, a)}).unzip )) object Undets { def unapply(m: Result): Some[(List[Symbol], List[Type], List[Symbol])] = Some(toLists{ @@ -766,7 +766,7 @@ trait Infer { isAsSpecific(res, ftpe2) case mt: MethodType if mt.isImplicit => isAsSpecific(ftpe1.resultType, ftpe2) - case MethodType(params, _) if params nonEmpty => + case MethodType(params, _) if params.nonEmpty => var argtpes = params map (_.tpe) if (isVarArgsList(params) && isVarArgsList(ftpe2.params)) argtpes = argtpes map (argtpe => @@ -776,7 +776,7 @@ trait Infer { isAsSpecific(PolyType(tparams, res), ftpe2) case PolyType(tparams, mt: MethodType) if mt.isImplicit => isAsSpecific(PolyType(tparams, mt.resultType), ftpe2) - case PolyType(_, MethodType(params, _)) if params nonEmpty => + case PolyType(_, MethodType(params, _)) if params.nonEmpty => isApplicable(List(), ftpe2, params map (_.tpe), WildcardType) // case NullaryMethodType(res) => // isAsSpecific(res, ftpe2) @@ -1189,6 +1189,50 @@ trait Infer { } } + /** Does `tp` contain any types that cannot be checked at run-time (i.e., after erasure, will isInstanceOf[erased(tp)] imply conceptualIsInstanceOf[tp]?) + * we should find a way to ask erasure: hey, is `tp` going to make it through you with all of its isInstanceOf resolving powers intact? + * TODO: at the very least, reduce duplication wrt checkCheckable + */ + def containsUnchecked(tp: Type): Boolean = { + def check(tp: Type, bound: List[Symbol]): Boolean = { + def isSurroundingTypeParam(sym: Symbol) = { + val e = context.scope.lookupEntry(sym.name) + ( (e ne null) + && (e.sym == sym ) + && !e.sym.isTypeParameterOrSkolem + && (e.owner == context.scope) + ) + } + def isLocalBinding(sym: Symbol) = ( + sym.isAbstractType && ( + (bound contains sym) + || (sym.name == tpnme.WILDCARD) + || isSurroundingTypeParam(sym) + ) + ) + tp.normalize match { + case SingleType(pre, _) => + check(pre, bound) + case TypeRef(_, ArrayClass, arg :: _) => + check(arg, bound) + case tp @ TypeRef(pre, sym, args) => + ( (sym.isAbstractType && !isLocalBinding(sym)) + || (args exists (x => !isLocalBinding(x.typeSymbol))) + || check(pre, bound) + ) + // case RefinedType(_, decls) if decls.nonEmpty => + // patternWarning(tp, "refinement ") + case RefinedType(parents, _) => + parents exists (p => check(p, bound)) + case ExistentialType(quantified, tp1) => + check(tp1, bound ::: quantified) + case _ => + false + } + } + check(tp, Nil) + } + def checkCheckable(tree: Tree, tp: Type, kind: String) { def patternWarning(tp0: Type, prefix: String) = { context.unit.uncheckedWarning(tree.pos, prefix+tp0+" in type "+kind+tp+" is unchecked since it is eliminated by erasure") diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index be7db9a920..b7e0eaef2b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -185,8 +185,21 @@ trait Macros { self: Analyzer => import typer.context if (macroDebug) println("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos)) - implicit def augmentString(s: String) = new AugmentedString(s) - class AugmentedString(s: String) { + typer.checkFeature(ddef.pos, MacrosFeature) + + // [Eugene to Martin] todo. copy/pasted this from checkFeature, because don't know a better way + // this is necessary to prevent macros from typechecking/expanding when they are not enabled + // `checkFeature` call alone is not enough, because it merely posts validation callback to unit.toCheck + def hasImport = inferImplicit(EmptyTree: Tree, MacrosFeature.tpe, true, false, typer.context) != SearchFailure + val nestedOwners = MacrosFeature.owner.ownerChain.takeWhile(_ != languageFeatureModule.moduleClass).reverse + val featureName = (nestedOwners map (_.name + ".")).mkString + MacrosFeature.name + def hasOption = settings.language.value contains featureName + if (!hasImport && !hasOption) { + ddef.symbol setFlag IS_ERROR + return EmptyTree + } + + implicit class AugmentedString(s: String) { def abbreviateCoreAliases: String = { // hack! var result = s result = result.replace("c.mirror.TypeTag", "c.TypeTag") @@ -544,14 +557,14 @@ trait Macros { self: Analyzer => val implCtxParam = if (implParamss.length > 0 && implParamss(0).length > 0) implParamss(0)(0) else null def implParamToDefParam(implParam: Symbol): Symbol = { - val indices = (implParamss drop 1 zipWithIndex) map { case (implParams, index) => (index, implParams indexOf implParam) } filter (_._2 != -1) headOption; + val indices = (((implParamss drop 1).zipWithIndex) map { case (implParams, index) => (index, implParams indexOf implParam) } filter (_._2 != -1)).headOption val defParam = indices flatMap { case (plistIndex, pIndex) => if (defParamss.length <= plistIndex) None else if (defParamss(plistIndex).length <= pIndex) None else Some(defParamss(plistIndex)(pIndex)) } - defParam orNull + defParam.orNull } class UnsigmaTypeMap extends TypeMap { diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index e1c12adbcc..9e06cbe0d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -8,6 +8,7 @@ package typechecker import symtab.Flags._ import scala.collection.{ mutable, immutable } import scala.tools.util.StringOps.{ ojoin } +import language.higherKinds /** Logic related to method synthesis which involves cooperation between * Namer and Typer. @@ -377,7 +378,7 @@ trait MethodSynthesis { } def derivedTree: DefDef = factoryMeth(mods & flagsMask | flagsExtra, name, tree, symbolic = false) - def flagsExtra: Long = METHOD | IMPLICIT + def flagsExtra: Long = METHOD | IMPLICIT | SYNTHETIC def flagsMask: Long = AccessFlags def name: TermName = tree.name.toTermName } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 4d84bf4af2..be269cf4b2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -48,7 +48,7 @@ trait NamesDefaults { self: Analyzer => /** @param pos maps indices from new to old (!) */ def reorderArgsInv[T: ClassManifest](args: List[T], pos: Int => Int): List[T] = { val argsArray = args.toArray - argsArray.indices map (i => argsArray(pos(i))) toList + (argsArray.indices map (i => argsArray(pos(i)))).toList } /** returns `true` if every element is equal to its index */ diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index aff8368f75..1fd9f6fc13 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -8,6 +8,7 @@ package typechecker import symtab._ import Flags.{MUTABLE, METHOD, LABEL, SYNTHETIC} +import language.postfixOps /** Translate pattern matching into method calls (these methods form a zero-plus monad), similar in spirit to how for-comprehensions are compiled. * @@ -21,7 +22,7 @@ import Flags.{MUTABLE, METHOD, LABEL, SYNTHETIC} * - Array patterns * - implement spec more closely (see TODO's) * - DCE - * - use manifests for type testing + * - use TypeTags for type testing * * (longer-term) TODO: * - user-defined unapplyProd @@ -118,6 +119,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => trait MatchTranslation extends MatchMonadInterface { self: TreeMakers with CodegenCore => import typer.{typed, context, silent, reallyExists} + // import typer.infer.containsUnchecked /** Implement a pattern match by turning its cases (including the implicit failure case) * into the corresponding (monadic) extractors, and combining them with the `orElse` combinator. @@ -130,10 +132,10 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => * this could probably optimized... (but note that the matchStrategy must be solved for each nested patternmatch) */ def translateMatch(scrut: Tree, cases: List[CaseDef], pt: Type, scrutType: Type, matchFailGenOverride: Option[Tree => Tree] = None): Tree = { - // we don't transform after typers - // (that would require much more sophistication when generating trees, + // we don't transform after uncurry + // (that would require more sophistication when generating trees, // and the only place that emits Matches after typers is for exception handling anyway) - assert(phase.id <= currentRun.typerPhase.id, phase) + assert(phase.id < currentRun.uncurryPhase.id, phase) val scrutSym = freshSym(scrut.pos, pureType(scrutType)) setFlag SYNTH_CASE // pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental @@ -157,12 +159,12 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => (caseScrutSym, propagateSubstitution(translateCase(caseScrutSym, pt)(caseDef), EmptySubstitution)) } - for(cases <- emitTypeSwitch(bindersAndCases, pt) toList; + for(cases <- emitTypeSwitch(bindersAndCases, pt).toList; if cases forall treeInfo.isCatchCase; // must check again, since it's not guaranteed -- TODO: can we eliminate this? e.g., a type test could test for a trait or a non-trivial prefix, which are not handled by the back-end cse <- cases) yield fixerUpper(matchOwner, pos)(cse).asInstanceOf[CaseDef] } - val catches = if (swatches nonEmpty) swatches else { + val catches = if (swatches.nonEmpty) swatches else { val scrutSym = freshSym(pos, pureType(ThrowableClass.tpe)) val casesNoSubstOnly = caseDefs map { caseDef => (propagateSubstitution(translateCase(scrutSym, pt)(caseDef), EmptySubstitution))} @@ -819,13 +821,34 @@ class Foo(x: Other) { x._1 } // no error in this order cond } - // TODO: also need to test when erasing pt loses crucial information (and if we can recover it using a manifest) - def needsTypeTest(tp: Type, pt: Type) = !(tp <:< pt) - private def typeTest(binder: Symbol, pt: Type) = maybeWithOuterCheck(binder, pt)(codegen._isInstanceOf(binder, pt)) + // containsUnchecked: also need to test when erasing pt loses crucial information (maybe we can recover it using a TypeTag) + def needsTypeTest(tp: Type, pt: Type): Boolean = !(tp <:< pt) // || containsUnchecked(pt) + // TODO: try to find the TypeTag for the binder's type and the expected type, and if they exists, + // check that the TypeTag of the binder's type conforms to the TypeTag of the expected type + private def typeTest(binderToTest: Symbol, expectedTp: Type, disableOuterCheck: Boolean = false, dynamic: Boolean = false): Tree = { import CODE._ + // def coreTest = + if (disableOuterCheck) codegen._isInstanceOf(binderToTest, expectedTp) else maybeWithOuterCheck(binderToTest, expectedTp)(codegen._isInstanceOf(binderToTest, expectedTp)) + // if (opt.experimental && containsUnchecked(expectedTp)) { + // if (dynamic) { + // val expectedTpTagTree = findManifest(expectedTp, true) + // if (!expectedTpTagTree.isEmpty) + // ((expectedTpTagTree DOT "erasure".toTermName) DOT "isAssignableFrom".toTermName)(REF(binderToTest) DOT nme.getClass_) + // else + // coreTest + // } else { + // val expectedTpTagTree = findManifest(expectedTp, true) + // val binderTpTagTree = findManifest(binderToTest.info, true) + // if(!(expectedTpTagTree.isEmpty || binderTpTagTree.isEmpty)) + // coreTest AND (binderTpTagTree DOT nme.CONFORMS)(expectedTpTagTree) + // else + // coreTest + // } + // } else coreTest + } // need to substitute since binder may be used outside of the next extractor call (say, in the body of the case) case class TypeTestTreeMaker(prevBinder: Symbol, nextBinderTp: Type, pos: Position) extends CondTreeMaker { - val cond = typeTest(prevBinder, nextBinderTp) + val cond = typeTest(prevBinder, nextBinderTp, dynamic = true) val res = codegen._asInstanceOf(prevBinder, nextBinderTp) override def toString = "TT"+(prevBinder, nextBinderTp) } @@ -865,7 +888,7 @@ class Foo(x: Other) { x._1 } // no error in this order // TODO: `null match { x : T }` will yield a check that (indirectly) tests whether `null ne null` // don't bother (so that we don't end up with the warning "comparing values of types Null and Null using `ne' will always yield false") def genEqualsAndInstanceOf(sym: Symbol): Tree - = codegen._equals(REF(sym), patBinder) AND codegen._isInstanceOf(patBinder, pt.widen) + = codegen._equals(REF(sym), patBinder) AND typeTest(patBinder, pt.widen, disableOuterCheck = true) def isRefTp(tp: Type) = tp <:< AnyRefClass.tpe @@ -873,7 +896,7 @@ class Foo(x: Other) { x._1 } // no error in this order def isMatchUnlessNull = isRefTp(pt) && !needsTypeTest(patBinderTp, pt) // TODO: [SPEC] type test for Array - // TODO: use manifests to improve tests (for erased types we can do better when we have a manifest) + // TODO: use TypeTags to improve tests (for erased types we can do better when we have a TypeTag) pt match { case SingleType(_, sym) /*this implies sym.isStable*/ => genEqualsAndInstanceOf(sym) // TODO: [SPEC] the spec requires `eq` instead of `==` here case ThisType(sym) if sym.isModule => genEqualsAndInstanceOf(sym) // must use == to support e.g. List() == Nil @@ -1082,22 +1105,14 @@ class Foo(x: Other) { x._1 } // no error in this order def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya def and(a: Tree, b: Tree): Tree = a AND b + // drop annotations generated by CPS plugin etc, since its annotationchecker rejects T @cps[U] <: Any + // let's assume for now annotations don't affect casts, drop them there, and bring them back using the outer Typed tree + private def mkCast(t: Tree, tp: Type) = Typed(gen.mkAsInstanceOf(t, tp.withoutAnnotations, true, false), TypeTree() setType tp) // the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly) - def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = { val tpX = /*repackExistential*/(tp) - if (!force && (t.tpe ne NoType) && t.isTyped && typesConform(t.tpe, tpX)) t //{ println("warning: emitted redundant asInstanceOf: "+(t, t.tpe, tp)); t } //.setType(tpX) - else gen.mkAsInstanceOf(t, tpX, true, false) - } - - def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), /*repackExistential*/(tp), true, false) - // { val tpX = /*repackExistential*/(tp) + def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = if (!force && (t.tpe ne NoType) && t.isTyped && typesConform(t.tpe, tp)) t else mkCast(t, tp) + def _asInstanceOf(b: Symbol, tp: Type): Tree = if (typesConform(b.info, tp)) REF(b) else mkCast(REF(b), tp) + def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), tp.withoutAnnotations, true, false) // if (typesConform(b.info, tpX)) { println("warning: emitted spurious isInstanceOf: "+(b, tp)); TRUE } - // else gen.mkIsInstanceOf(REF(b), tpX, true, false) - // } - - def _asInstanceOf(b: Symbol, tp: Type): Tree = { val tpX = /*repackExistential*/(tp) - if (typesConform(b.info, tpX)) REF(b) //{ println("warning: emitted redundant asInstanceOf: "+(b, b.info, tp)); REF(b) } //.setType(tpX) - else gen.mkAsInstanceOf(REF(b), tpX, true, false) - } // duplicated out of frustration with cast generation def mkZero(tp: Type): Tree = { @@ -1635,7 +1650,7 @@ class Foo(x: Other) { x._1 } // no error in this order */ def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree = { val matchEnd = NoSymbol.newLabel(freshName("matchEnd"), NoPosition) setFlag SYNTH_CASE - val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, SYNTHETIC) setInfo restpe + val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, SYNTHETIC) setInfo restpe.withoutAnnotations // matchEnd setInfo MethodType(List(matchRes), restpe) def newCaseSym = NoSymbol.newLabel(freshName("case"), NoPosition) setInfo MethodType(Nil, restpe) setFlag SYNTH_CASE @@ -1649,7 +1664,11 @@ 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 (_asInstanceOf(matchFailGen(scrutRef), restpe))) // need to jump to matchEnd with result generated by matchFailGen (could be `FALSE` for isDefinedAt) + // must jump to matchEnd, use result generated by matchFailGen (could be `FALSE` for isDefinedAt) + LabelDef(nextCase, Nil, matchEnd APPLY (matchFailGen(scrutRef))) + // don't cast the arg to matchEnd when using PartialFun synth in uncurry, since it won't detect the throw (see gen.withDefaultCase) + // the cast is necessary when using typedMatchAnonFun-style PartialFun synth: + // (_asInstanceOf(matchFailGen(scrutRef), restpe)) } 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 ad727d4082..21336c2375 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -10,6 +10,7 @@ import symtab.Flags._ import collection.{ mutable, immutable } import transform.InfoTransform import scala.collection.mutable.ListBuffer +import language.postfixOps /** <p> * Post-attribution checking and transformation. @@ -358,7 +359,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R /** Is the intersection between given two lists of overridden symbols empty? */ def intersectionIsEmpty(syms1: List[Symbol], syms2: List[Symbol]) = - !(syms1 exists (syms2 contains)) + !(syms1 exists (syms2 contains _)) if (typesOnly) checkOverrideTypes() else { @@ -1065,12 +1066,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // equals. def isUsingWarnableEquals = { val m = receiver.info.member(nme.equals_) - def n = actual.info.member(nme.equals_) - ( (m == Object_equals) - || (m == Any_equals) - || (m.isSynthetic && m.owner.isCase && !n.owner.isCase) - ) + ((m == Object_equals) || (m == Any_equals) || isMethodCaseEquals(m)) } + def isMethodCaseEquals(m: Symbol) = m.isSynthetic && m.owner.isCase + def isCaseEquals = isMethodCaseEquals(receiver.info.member(nme.equals_)) // Whether this == or != is one of those defined in Any/AnyRef or an overload from elsewhere. def isUsingDefaultScalaOp = { val s = fn.symbol @@ -1093,9 +1092,11 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R val msg = alwaysEqual == (name == nme.EQ || name == nme.eq) unit.warning(pos, "comparing "+what+" using `"+name.decode+"' will always yield " + msg) } - def nonSensible(pre: String, alwaysEqual: Boolean) = nonSensibleWarning(pre+"values of types "+typesString, alwaysEqual) + def nonSensiblyEq() = nonSensible("", true) + def nonSensiblyNeq() = nonSensible("", false) + def nonSensiblyNew() = nonSensibleWarning("a fresh object", false) def unrelatedTypes() = { val msg = if (name == nme.EQ || name == nme.eq) @@ -1103,52 +1104,73 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R unit.warning(pos, typesString + " are unrelated: they will most likely " + msg) } - if (nullCount == 2) - nonSensible("", true) // null == null + if (nullCount == 2) // null == null + nonSensiblyEq() else if (nullCount == 1) { if (onSyms(_ exists isPrimitiveValueClass)) // null == 5 - nonSensible("", false) + nonSensiblyNeq() else if (onTrees( _ exists isNew)) // null == new AnyRef - nonSensibleWarning("a fresh object", false) + nonSensiblyNew() } else if (isBoolean(receiver)) { if (!isBoolean(actual) && !isMaybeValue(actual)) // true == 5 - nonSensible("", false) + nonSensiblyNeq() } else if (isUnit(receiver)) { if (isUnit(actual)) // () == () - nonSensible("", true) + nonSensiblyEq() else if (!isUnit(actual) && !isMaybeValue(actual)) // () == "abc" - nonSensible("", false) + nonSensiblyNeq() } else if (isNumeric(receiver)) { if (!isNumeric(actual) && !forMSIL) if (isUnit(actual) || isBoolean(actual) || !isMaybeValue(actual)) // 5 == "abc" - nonSensible("", false) + nonSensiblyNeq() } - else if (isWarnable) { + else if (isWarnable && !isCaseEquals) { if (isNew(qual)) // new X == y - nonSensibleWarning("a fresh object", false) + nonSensiblyNew() else if (isNew(args.head) && (receiver.isEffectivelyFinal || isReferenceOp)) // object X ; X == new Y - nonSensibleWarning("a fresh object", false) + nonSensiblyNew() else if (receiver.isEffectivelyFinal && !(receiver isSubClass actual)) { // object X, Y; X == Y if (isEitherNullable) nonSensible("non-null ", false) else - nonSensible("", false) + nonSensiblyNeq() } } // possibleNumericCount is insufficient or this will warn on e.g. Boolean == j.l.Boolean if (isWarnable && nullCount == 0 && !(isSpecial(receiver) && isSpecial(actual))) { - if (actual isSubClass receiver) () - else if (receiver isSubClass actual) () - // warn only if they have no common supertype below Object - else { + // better to have lubbed and lost + def warnIfLubless(): Unit = { val common = global.lub(List(actual.tpe, receiver.tpe)) if (ObjectClass.tpe <:< common) unrelatedTypes() } + def eitherSubclasses = (actual isSubClass receiver) || (receiver isSubClass actual) + // warn if actual has a case parent that is not same as receiver's; + // if actual is not a case, then warn if no common supertype, as below + if (isCaseEquals) { + def thisCase = receiver.info.member(nme.equals_).owner + actual.info.baseClasses.find(_.isCase) match { + case Some(p) if (p != thisCase) => nonSensible("case class ", false) + case None => + // stronger message on (Some(1) == None) + //if (receiver.isCase && receiver.isEffectivelyFinal && !(receiver isSubClass actual)) nonSensiblyNeq() + //else + // if a class, it must be super to thisCase (and receiver) since not <: thisCase + if (!actual.isTrait && !(receiver isSubClass actual)) nonSensiblyNeq() + else if (!eitherSubclasses) warnIfLubless() + case _ => + } + } + else if (actual isSubClass receiver) () + else if (receiver isSubClass actual) () + // warn only if they have no common supertype below Object + else { + warnIfLubless() + } } case _ => } @@ -1654,9 +1676,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R inPattern = false treeCopy.CaseDef(tree, pat1, transform(guard), transform(body)) case LabelDef(_, _, _) if gen.hasSynthCaseSymbol(result) => + val old = inPattern inPattern = true val res = deriveLabelDef(result)(transform) - inPattern = false + inPattern = old res case _ => super.transform(result) diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index da87d38ab0..868c236ee9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -50,7 +50,7 @@ trait SyntheticMethods extends ast.TreeDSL { import synthesizer._ if (clazz0 == AnyValClass || isPrimitiveValueClass(clazz0)) return { - if (clazz0.info member nme.getClass_ isDeferred) { + if ((clazz0.info member nme.getClass_).isDeferred) { // XXX dummy implementation for now val getClassMethod = createMethod(nme.getClass_, getClassReturnType(clazz.tpe))(_ => NULL) deriveTemplate(templ)(_ :+ getClassMethod) @@ -303,7 +303,7 @@ trait SyntheticMethods extends ast.TreeDSL { lb += logResult("case accessor new")(newAcc) } - lb ++= templ.body ++= synthesize() toList + (lb ++= templ.body ++= synthesize()).toList } if (phase.id > currentRun.typerPhase.id) templ diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index 8895905ca7..4319dd10c7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -14,8 +14,9 @@ import util.returning abstract class TreeCheckers extends Analyzer { import global._ - private val everything = ListBuffer[(Phase, Map[Tree, (Symbol, Type)])]() + private val everything = ListBuffer[(Phase, Map[Tree, (Symbol, Type)])]() private val currentTrees = mutable.Map[Tree, (Symbol, Type)]() + private val tpeOfTree = mutable.HashMap[Tree, Type]() if (settings.debug.value) { sys addShutdownHook { @@ -28,7 +29,7 @@ abstract class TreeCheckers extends Analyzer { } } - private def classstr(x: AnyRef) = x.getClass.getName split """\\.|\\$""" last; + private def classstr(x: AnyRef) = (x.getClass.getName split """\\.|\\$""").last private def typestr(x: Type) = " (tpe = " + x + ")" private def treestr(t: Tree) = t + " [" + classstr(t) + "]" + typestr(t.tpe) private def ownerstr(s: Symbol) = "'" + s + "'" + s.locationString @@ -49,12 +50,13 @@ abstract class TreeCheckers extends Analyzer { object SymbolTracker extends Traverser { type PhaseMap = mutable.HashMap[Symbol, List[Tree]] + val defSyms = mutable.HashMap[Symbol, List[DefTree]]() withDefaultValue Nil + val newSyms = mutable.HashSet[Symbol]() val maps = ListBuffer[(Phase, PhaseMap)]() + val movedMsgs = ListBuffer[String]() + def prev = maps.init.last._2 def latest = maps.last._2 - val defSyms = mutable.HashMap[Symbol, List[DefTree]]() - val newSyms = mutable.HashSet[Symbol]() - val movedMsgs = new ListBuffer[String] def sortedNewSyms = newSyms.toList.distinct sortBy (_.name.toString) def inPrev(sym: Symbol) = { @@ -119,10 +121,8 @@ abstract class TreeCheckers extends Analyzer { if (sym != null && sym != NoSymbol) { record(sym, tree) tree match { - case x: DefTree => - if (defSyms contains sym) defSyms(sym) = defSyms(sym) :+ x - else defSyms(sym) = List(x) - case _ => () + case x: DefTree => defSyms(sym) :+= x + case _ => () } } @@ -130,8 +130,6 @@ abstract class TreeCheckers extends Analyzer { } } - lazy val tpeOfTree = mutable.HashMap[Tree, Type]() - def posstr(p: Position) = try p.source.path + ":" + p.line catch { case _: UnsupportedOperationException => p.toString } @@ -147,9 +145,7 @@ abstract class TreeCheckers extends Analyzer { if (!cond) errorFn(msg) def checkTrees() { - if (settings.verbose.value) - Console.println("[consistency check at the beginning of phase " + phase + "]") - + informFn("[consistency check at the beginning of phase " + phase + "]") currentRun.units foreach check } @@ -172,7 +168,7 @@ abstract class TreeCheckers extends Analyzer { informProgress("checking "+unit) val context = rootContext(unit) context.checking = true - tpeOfTree.clear + tpeOfTree.clear() SymbolTracker.check(phase, unit) val checker = new TreeChecker(context) runWithUnit(unit) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2d1c62d347..0541f85f31 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -512,7 +512,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { res } - /** The typer for a label definition. If this is part of a template we * first have to enter the label definition. */ @@ -675,7 +674,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } if (tree.tpe.isInstanceOf[MethodType] && pre.isStable && sym.tpe.params.isEmpty && (isStableContext(tree, mode, pt) || sym.isModule)) - tree.setType(MethodType(List(), singleType(pre, sym))) + tree.setType(MethodType(List(), singleType(pre, sym))) // TODO: should this be a NullaryMethodType? else tree } @@ -734,6 +733,39 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } + def checkFeature(pos: Position, featureTrait: Symbol, construct: => String = "") = + if (!isPastTyper) { + val nestedOwners = + featureTrait.owner.ownerChain.takeWhile(_ != languageFeatureModule.moduleClass).reverse + val featureName = (nestedOwners map (_.name + ".")).mkString + featureTrait.name + unit.toCheck += { () => + def hasImport = inferImplicit(EmptyTree: Tree, featureTrait.tpe, true, false, context) != SearchFailure + def hasOption = settings.language.value contains featureName + if (!hasImport && !hasOption) { + val Some(AnnotationInfo(_, List(Literal(Constant(featureDesc: String)), Literal(Constant(required: Boolean))), _)) = + featureTrait getAnnotation LanguageFeatureAnnot + val req = if (required) "needs to" else "should" + var raw = featureDesc + " " + req + " be enabled\n" + + "by making the implicit value language." + featureName + " visible." + if (!(currentRun.reportedFeature contains featureTrait)) + raw += "\nThis can be achieved by adding the import clause 'import language." + featureName + "'\n" + + "or by setting the compiler option -language:" + featureName + ".\n" + + "See the Scala docs for value scala.language." + featureName + " for a discussion\n" + + "why the feature " + req + " be explicitly enabled." + currentRun.reportedFeature += featureTrait + val msg = raw replace ("#", construct) + if (required) unit.error(pos, msg) + else currentRun.featureWarnings.warn(pos, msg) + } + } + } + + def checkExistentialsFeature(pos: Position, tpe: Type, prefix: String) = tpe match { + case extp: ExistentialType if !extp.isRepresentableWithWildcards => + checkFeature(pos, ExistentialsFeature, prefix+" "+tpe) + case _ => + } + /** Perform the following adaptations of expression, pattern or type `tree` wrt to * given mode `mode` and given prototype `pt`: * (-1) For expressions with annotated types, let AnnotationCheckers decide what to do @@ -773,7 +805,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { protected def adapt(tree: Tree, mode: Int, pt: Type, original: Tree = EmptyTree): Tree = { def adaptToImplicitMethod(mt: MethodType): Tree = { - if (context.undetparams nonEmpty) { // (9) -- should revisit dropped condition `(mode & POLYmode) == 0` + if (context.undetparams.nonEmpty) { // (9) -- should revisit dropped condition `(mode & POLYmode) == 0` // dropped so that type args of implicit method are inferred even if polymorphic expressions are allowed // needed for implicits in 2.8 collection library -- maybe once #3346 is fixed, we can reinstate the condition? context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt, @@ -1171,7 +1203,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { && !qtpe.typeSymbol.isBottomClass && qtpe != WildcardType && !qual.isInstanceOf[ApplyImplicitView] // don't chain views - && context.implicitsEnabled + && (context.implicitsEnabled || context.enrichmentEnabled) // Elaborating `context.implicitsEnabled`: // don't try to adapt a top-level type that's the subject of an implicit search // this happens because, if isView, typedImplicit tries to apply the "current" implicit value to @@ -1941,6 +1973,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (meth.isStructuralRefinementMember) checkMethodStructuralCompatible(meth) + if (meth.isImplicit && !meth.isSynthetic) meth.info.paramss match { + case List(param) :: _ if !param.isImplicit => + checkFeature(ddef.pos, ImplicitConversionsFeature, meth.toString) + case _ => + } + treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType } @@ -1972,6 +2010,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case TypeBounds(lo1, hi1) if (!(lo1 <:< hi1)) => LowerBoundError(tdef, lo1, hi1) case _ => () } + + if (tdef.symbol.isDeferred && tdef.symbol.info.isHigherKinded) + checkFeature(tdef.pos, HigherKindsFeature) + treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType } @@ -2115,7 +2157,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { var body1: Tree = typed(cdef.body, pt) val contextWithTypeBounds = context.nextEnclosing(_.tree.isInstanceOf[CaseDef]) - if (contextWithTypeBounds.savedTypeBounds nonEmpty) { + if (contextWithTypeBounds.savedTypeBounds.nonEmpty) { body1.tpe = contextWithTypeBounds restoreTypeBounds body1.tpe // insert a cast if something typechecked under the GADT constraints, @@ -2151,13 +2193,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def adaptCase(cdef: CaseDef, mode: Int, tpe: Type): CaseDef = deriveCaseDef(cdef)(adapt(_, mode, tpe)) - def prepareTranslateMatch(selector0: Tree, cases: List[CaseDef], mode: Int, resTp: Type) = { + def typedMatch(selector0: Tree, cases: List[CaseDef], mode: Int, resTp: Type) = { val (selector, doTranslation) = selector0 match { 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 selectorTp = packCaptured(selector1.tpe.widen.withoutAnnotations) val casesTyped = typedCases(cases, selectorTp, resTp) val caseTypes = casesTyped map (c => packedType(c, context.owner).deconst) @@ -2168,7 +2210,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { (selector1, selectorTp, casesAdapted, ownType, doTranslation) } - def translateMatch(selector1: Tree, selectorTp: Type, casesAdapted: List[CaseDef], ownType: Type, doTranslation: Boolean, matchFailGen: Option[Tree => Tree] = None) = { + def translatedMatch(selector1: Tree, selectorTp: Type, casesAdapted: List[CaseDef], ownType: Type, doTranslation: Boolean, matchFailGen: Option[Tree => Tree] = None) = { def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match { case TypeRef(_, RepeatedParamClass, arg :: Nil) => seqType(arg) case _ => tp @@ -2178,10 +2220,12 @@ 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)) - // 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 + // we've packed the type for each case in typedMatch 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) + // TODO: fix skolemizeExistential (it should preserve annotations, right?) + val ownTypeSkolemized = ownType.skolemizeExistential(context.owner, context.tree) withAnnotations ownType.annotations + MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownTypeSkolemized), scrutType, matchFailGen) } } @@ -2241,7 +2285,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { 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.typedMatch(selector, cases, mode, ptRes) val methFormals = paramSyms map (_.tpe) val parents = List(abstractFunctionType(methFormals, resTp), SerializableClass.tpe) @@ -2249,7 +2293,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { anonClass setInfo ClassInfoType(parents, newScope, anonClass) methodSym setInfoAndEnter MethodType(paramSyms, resTp) - DefDef(methodSym, methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation)) + DefDef(methodSym, methodBodyTyper.translatedMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation)) } } @@ -2279,7 +2323,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { 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.typedMatch(selector, cases, mode, ptRes) anonClass setInfo ClassInfoType(parents(List(argTp, resTp)), newScope, anonClass) B1 setInfo TypeBounds.lower(resTp) @@ -2288,7 +2332,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // use applyOrElse's first parameter since the scrut's type has been widened def doDefault(scrut_ignored: Tree) = REF(default) APPLY (REF(x)) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, B1.tpe, doTranslation, Some(doDefault)) + val body = methodBodyTyper.translatedMatch(selector1, selectorTp, casesAdapted, B1.tpe, doTranslation, Some(doDefault)) DefDef(methodSym, body) } @@ -2303,8 +2347,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { 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.typedMatch(selector, casesTrue, mode, BooleanClass.tpe) + val body = methodBodyTyper.translatedMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) DefDef(methodSym, body) } @@ -2365,29 +2409,21 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - fun.body match { - case Match(sel, cases) if opt.virtPatmat => - // go to outer context -- must discard the context that was created for the Function since we're discarding the function - // thus, its symbol, which serves as the current context.owner, is not the right owner - // you won't know you're using the wrong owner until lambda lift crashes (unless you know better than to use the wrong owner) - newTyper(context.outer).typedMatchAnonFun(fun, cases, mode, pt, Some((fun.vparams, sel))) - case _ => - val vparamSyms = fun.vparams map { vparam => - enterSym(context, vparam) - if (context.retyping) context.scope enter vparam.symbol - vparam.symbol - } - val vparams = fun.vparams mapConserve (typedValDef) - // for (vparam <- vparams) { - // checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () - // } - val formals = vparamSyms map (_.tpe) - val body1 = typed(fun.body, respt) - val restpe = packedType(body1, fun.symbol).deconst.resultType - val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe) - // body = checkNoEscaping.locals(context.scope, restpe, body) - treeCopy.Function(fun, vparams, body1).setType(funtpe) + val vparamSyms = fun.vparams map { vparam => + enterSym(context, vparam) + if (context.retyping) context.scope enter vparam.symbol + vparam.symbol } + val vparams = fun.vparams mapConserve (typedValDef) +// for (vparam <- vparams) { +// checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () +// } + val formals = vparamSyms map (_.tpe) + val body1 = typed(fun.body, respt) + val restpe = packedType(body1, fun.symbol).deconst.resultType + val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe) +// body = checkNoEscaping.locals(context.scope, restpe, body) + treeCopy.Function(fun, vparams, body1).setType(funtpe) } } @@ -2817,7 +2853,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { (args exists isNamed) || // uses a named argument isNamedApplyBlock(fun)) { // fun was transformed to a named apply block => // integrate this application into the block - tryNamesDefaults + if (dyna.isApplyDynamicNamed(fun)) dyna.typedNamedApply(tree, fun, args, mode, pt) + else tryNamesDefaults } else { val tparams = context.extractUndetparams() if (tparams.isEmpty) { // all type params are defined @@ -3438,7 +3475,108 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ErrorType => setError(treeCopy.TypeApply(tree, fun, args)) case _ => - TypedApplyDoesNotTakeTpeParametersError(tree, fun) + fun match { + // drop the application for an applyDynamic or selectDynamic call since it has been pushed down + case treeInfo.DynamicApplication(_, _) => fun + case _ => TypedApplyDoesNotTakeTpeParametersError(tree, fun) + } + } + + object dyna { + import treeInfo.{isApplyDynamicName, DynamicUpdate, DynamicApplicationNamed} + + def acceptsApplyDynamic(tp: Type) = tp.typeSymbol isNonBottomSubClass DynamicClass + + /** Returns `Some(t)` if `name` can be selected dynamically on `qual`, `None` if not. + * `t` specifies the type to be passed to the applyDynamic/selectDynamic call (unless it is NoType) + * NOTE: currently either returns None or Some(NoType) (scala-virtualized extends this to Some(t) for selections on staged Structs) + */ + def acceptsApplyDynamicWithType(qual: Tree, name: Name): Option[Type] = + // don't selectDynamic selectDynamic, do select dynamic at unknown type, + // in scala-virtualized, we may return a Some(tp) where tp ne NoType + if (!isApplyDynamicName(name) && acceptsApplyDynamic(qual.tpe.widen)) Some(NoType) + else None + + def isDynamicallyUpdatable(tree: Tree) = tree match { + case DynamicUpdate(qual, name) => + // if the qualifier is a Dynamic, that's all we need to know + acceptsApplyDynamic(qual.tpe) + case _ => false + } + + def isApplyDynamicNamed(fun: Tree): Boolean = fun match { + case DynamicApplicationNamed(qual, _) if acceptsApplyDynamic(qual.tpe.widen) => true + case _ => false + // look deeper? + // val methPart = treeInfo.methPart(fun) + // println("methPart of "+ fun +" is "+ methPart) + // if (methPart ne fun) isApplyDynamicNamed(methPart) + // else false + } + + def typedNamedApply(orig: Tree, fun: Tree, args: List[Tree], mode: Int, pt: Type): Tree = { + def argToBinding(arg: Tree): Tree = arg match { + case AssignOrNamedArg(Ident(name), rhs) => gen.mkTuple(List(CODE.LIT(name.toString), rhs)) + case _ => gen.mkTuple(List(CODE.LIT(""), arg)) + } + typed(treeCopy.Apply(orig, fun, args map argToBinding), mode, pt) + } + + /** Translate selection that does not typecheck according to the normal rules into a selectDynamic/applyDynamic. + * + * foo.method("blah") ~~> foo.applyDynamic("method")("blah") + * foo.method(x = "blah") ~~> foo.applyDynamicNamed("method")(("x", "blah")) + * foo.varia = 10 ~~> foo.updateDynamic("varia")(10) + * foo.field ~~> foo.selectDynamic("field") + * foo.arr(10) = 13 ~~> foo.selectDynamic("arr").update(10, 13) + * + * what if we want foo.field == foo.selectDynamic("field") == 1, but `foo.field = 10` == `foo.selectDynamic("field").update(10)` == () + * what would the signature for selectDynamic be? (hint: it needs to depend on whether an update call is coming or not) + * + * need to distinguish selectDynamic and applyDynamic somehow: the former must return the selected value, the latter must accept an apply or an update + * - could have only selectDynamic and pass it a boolean whether more is to come, + * so that it can either return the bare value or something that can handle the apply/update + * HOWEVER that makes it hard to return unrelated values for the two cases + * --> selectDynamic's return type is now dependent on the boolean flag whether more is to come + * - simplest solution: have two method calls + * + */ + def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = + acceptsApplyDynamicWithType(qual, name) map { tp => + // tp eq NoType => can call xxxDynamic, but not passing any type args (unless specified explicitly by the user) + // in scala-virtualized, when not NoType, tp is passed as type argument (for selection on a staged Struct) + + // strip off type application -- we're not doing much with outer, so don't bother preserving cxTree's attributes etc + val (outer, explicitTargs) = cxTree match { + case TypeApply(fun, targs) => (fun, targs) + case Apply(TypeApply(fun, targs), args) => (Apply(fun, args), targs) + case t => (t, Nil) + } + + @inline def hasNamedArg(as: List[Tree]) = as collectFirst {case AssignOrNamedArg(lhs, rhs) =>} nonEmpty + + // note: context.tree includes at most one Apply node + // thus, we can't use it to detect we're going to receive named args in expressions such as: + // qual.sel(a)(a2, arg2 = "a2") + val oper = outer match { + case Apply(`tree`, as) => + val oper = + if (hasNamedArg(as)) nme.applyDynamicNamed + else nme.applyDynamic + // not supported: foo.bar(a1,..., an: _*) + if (treeInfo.isWildcardStarArgList(as)) { + DynamicVarArgUnsupported(tree, oper) + return Some(setError(tree)) + } else oper + case Assign(`tree`, _) => nme.updateDynamic + case _ => nme.selectDynamic + } + + val dynSel = Select(qual, oper) + val tappSel = if (explicitTargs nonEmpty) TypeApply(dynSel, explicitTargs) else dynSel + + atPos(qual.pos)(Apply(tappSel, List(Literal(Constant(name.decode))))) + } } @inline final def deindentTyping() = context.typingIndentLevel -= 2 @@ -3611,10 +3749,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case _ => } } +// if (varsym.isVariable || +// // setter-rewrite has been done above, so rule out methods here, but, wait a minute, why are we assigning to non-variables after erasure?! +// (phase.erasedTypes && varsym.isValue && !varsym.isMethod)) { if (varsym.isVariable || varsym.isValue && phase.erasedTypes) { val rhs1 = typed(rhs, EXPRmode | BYVALmode, lhs1.tpe) treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe } + else if(dyna.isDynamicallyUpdatable(lhs1)) { + val rhs1 = typed(rhs, EXPRmode | BYVALmode, WildcardType) + typed1(Apply(lhs1, List(rhs1)), mode, pt) + } else fail() } @@ -3629,12 +3774,16 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { lazy val thenTp = packedType(thenp1, context.owner) lazy val elseTp = packedType(elsep1, context.owner) + // println("typedIf: "+(thenp1.tpe, elsep1.tpe, ptOrLub(List(thenp1.tpe, elsep1.tpe)),"\n", thenTp, elseTp, thenTp =:= elseTp)) val (owntype, needAdapt) = // in principle we should pack the types of each branch before lubbing, but lub doesn't really work for existentials anyway // in the special (though common) case where the types are equal, it pays to pack before comparing // especially virtpatmat needs more aggressive unification of skolemized types // this breaks src/library/scala/collection/immutable/TrieIterator.scala - if (opt.virtPatmat && !isPastTyper && thenTp =:= elseTp) (thenp1.tpe, false) // use unpacked type + if ( opt.virtPatmat && !isPastTyper + && thenp1.tpe.annotations.isEmpty && elsep1.tpe.annotations.isEmpty // annotated types need to be lubbed regardless (at least, continations break if you by pass them like this) + && thenTp =:= elseTp + ) (thenp1.tpe, false) // use unpacked type // TODO: skolemize (lub of packed types) when that no longer crashes on files/pos/t4070b.scala else ptOrLub(List(thenp1.tpe, elsep1.tpe)) @@ -3646,13 +3795,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - def typedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree = { - if (opt.virtPatmat && !isPastTyper) { - if (selector ne EmptyTree) { - val (selector1, selectorTp, casesAdapted, ownType, doTranslation) = prepareTranslateMatch(selector, cases, mode, pt) - typed(translateMatch(selector1, selectorTp, casesAdapted, ownType, doTranslation), mode, pt) - } else typedMatchAnonFun(tree, cases, mode, pt) - } else if (selector == EmptyTree) { + // translation only happens when (selector != EmptyTree) && !isPastTyper && opt.virtPatmat + def typedTranslatedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree = { + if (selector == EmptyTree) { val arity = if (isFunctionType(pt)) pt.normalize.typeArgs.length - 1 else 1 val params = for (i <- List.range(0, arity)) yield atPos(tree.pos.focusStart) { @@ -3663,7 +3808,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val selector1 = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) } val body = treeCopy.Match(tree, selector1, cases) typed1(atPos(tree.pos) { Function(params, body) }, mode, pt) - } else { + } else if (!((phase.id < currentRun.uncurryPhase.id) && opt.virtPatmat)) { val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) var cases1 = typedCases(cases, packCaptured(selector1.tpe.widen), pt) val (owntype, needAdapt) = ptOrLub(cases1 map (_.tpe)) @@ -3671,6 +3816,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { cases1 = cases1 map (adaptCase(_, mode, owntype)) } treeCopy.Match(tree, selector1, cases1) setType owntype + } else { + val (selector1, selectorTp, casesAdapted, ownType, doTranslation) = typedMatch(selector, cases, mode, pt) + typed(translatedMatch(selector1, selectorTp, casesAdapted, ownType, doTranslation), mode, pt) } } @@ -4062,7 +4210,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } else { member(qual, name) } - if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) { + + // symbol not found? --> try to convert implicitly to a type that does have the required member + // added `| PATTERNmode` to allow enrichment in patterns (so we can add e.g., an xml member to StringContext, which in turn has an unapply[Seq] method) + if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & (EXPRmode | PATTERNmode)) != 0) { val qual1 = if (member(qual, name) != NoSymbol) qual else adaptToMemberWithArgs(tree, qual, name, mode, true, true) @@ -4070,6 +4221,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt) } + if (!reallyExists(sym)) { if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) { val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) } @@ -4077,16 +4229,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } // try to expand according to Dynamic rules. - - if (settings.Xexperimental.value && (qual.tpe.widen.typeSymbol isNonBottomSubClass DynamicClass)) { - var dynInvoke = Apply(Select(qual, nme.applyDynamic), List(Literal(Constant(name.decode)))) - context.tree match { - case Apply(tree1, args) if tree1 eq tree => - ; - case _ => - dynInvoke = Apply(dynInvoke, List()) - } - return typed1(util.trace("dynatype: ")(dynInvoke), mode, pt) + dyna.mkInvoke(context.tree, tree, qual, name) match { + case Some(invocation) => + return typed1(invocation, mode, pt) + case _ => } if (settings.debug.value) { @@ -4145,7 +4291,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { result match { // could checkAccessible (called by makeAccessible) potentially have skipped checking a type application in qual? - case SelectFromTypeTree(qual@TypeTree(), name) if qual.tpe.typeArgs nonEmpty => // TODO: somehow the new qual is not checked in refchecks + case SelectFromTypeTree(qual@TypeTree(), name) if qual.tpe.typeArgs.nonEmpty => // TODO: somehow the new qual is not checked in refchecks treeCopy.SelectFromTypeTree( result, (TypeTreeWithDeferredRefCheck(){ () => val tp = qual.tpe; val sym = tp.typeSymbolDirect @@ -4536,7 +4682,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { typedIf(cond, thenp, elsep) case tree @ Match(selector, cases) => - typedMatch(tree, selector, cases) + typedTranslatedMatch(tree, selector, cases) case Return(expr) => typedReturn(expr) @@ -4552,7 +4698,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { catches1 = catches1 map (adaptCase(_, mode, owntype)) } - if(!isPastTyper && opt.virtPatmat) { + if((phase.id < currentRun.uncurryPhase.id) && opt.virtPatmat) { catches1 = (MatchTranslator(this)).translateTry(catches1, owntype, tree.pos) } @@ -4708,6 +4854,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { else typedSelect(qual1, name) + if (tree.isInstanceOf[PostfixSelect]) + checkFeature(tree.pos, PostfixOpsFeature, name.decode) + if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember) + checkFeature(tree1.pos, ReflectiveCallsFeature, tree1.symbol.toString) + if (qual1.symbol == RootPackage) treeCopy.Ident(tree1, name) else tree1 @@ -4753,9 +4904,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { treeCopy.TypeBoundsTree(tree, lo1, hi1) setType TypeBounds(lo1.tpe, hi1.tpe) case etpt @ ExistentialTypeTree(_, _) => - typerWithLocalContext(context.makeNewScope(tree, context.owner)){ + val tree1 = typerWithLocalContext(context.makeNewScope(tree, context.owner)){ _.typedExistentialTypeTree(etpt, mode) } + checkExistentialsFeature(tree1.pos, tree1.tpe, "the existential type") + tree1 case dc@TypeTreeWithDeferredRefCheck() => dc // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure) case tpt @ TypeTree() => @@ -4805,6 +4958,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { ptLine("typing %s: pt = %s".format(ptTree(tree), pt), "undetparams" -> context.undetparams, "implicitsEnabled" -> context.implicitsEnabled, + "enrichmentEnabled" -> context.enrichmentEnabled, + "mode" -> modeString(mode), "silent" -> context.bufferErrors, "context.owner" -> context.owner ) @@ -4908,7 +5063,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // We disable implicits because otherwise some constructs will // type check which should not. The pattern matcher does not // perform implicit conversions in an attempt to consummate a match. - context.withImplicitsDisabled(typed(tree, PATTERNmode, pt)) + + // on the one hand, + // "abc" match { case Seq('a', 'b', 'c') => true } + // should be ruled out statically, otherwise this is a runtime + // error both because there is an implicit from String to Seq + // (even though such implicits are not used by the matcher) and + // because the typer is fine with concluding that "abc" might + // be of type "String with Seq[T]" and thus eligible for a call + // to unapplySeq. + + // on the other hand, we want to be able to use implicits to add members retro-actively (e.g., add xml to StringContext) + + // as a compromise, context.enrichmentEnabled tells adaptToMember to go ahead and enrich, + // but arbitrary conversions (in adapt) are disabled + // TODO: can we achieve the pattern matching bit of the string interpolation SIP without this? + context.withImplicitsDisabledAllowEnrichment(typed(tree, PATTERNmode, pt)) } /** Types a (fully parameterized) type tree */ @@ -4965,7 +5135,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { assert(!context.owner.isTermMacro, context.owner) val tree1 = typed(tree, pt) transformed(tree) = tree1 - packedType(tree1, context.owner) + val tpe = packedType(tree1, context.owner) + checkExistentialsFeature(tree.pos, tpe, "inferred existential type") + tpe } def computeMacroDefType(tree: Tree, pt: Type): Type = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 1f79d8212d..1ebcea4a07 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -200,7 +200,7 @@ trait Unapplies extends ast.TreeDSL def caseClassCopyMeth(cdef: ClassDef): Option[DefDef] = { def isDisallowed(vd: ValDef) = isRepeatedParamType(vd.tpt) || isByNameParamType(vd.tpt) val cparamss = constrParamss(cdef) - val flat = cparamss flatten + val flat = cparamss.flatten if (cdef.symbol.hasAbstractFlag || (flat exists isDisallowed)) None else { diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 11d7db5180..5dd9ce0e02 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -29,7 +29,7 @@ object ClassPath { def infoFor[T](value: T) = info(value.getClass) def info[T](clazz: Class[T]) = new ClassAndJarInfo()(ClassManifest[T](clazz)) def info[T: ClassManifest] = new ClassAndJarInfo[T] - def locate[T: ClassManifest] = info[T] rootClasspath + def locate[T: ClassManifest] = info[T].rootClasspath def locateJar[T: ClassManifest] = info[T].rootPossibles find (x => isJarOrZip(x)) map (x => File(x)) def locateDir[T: ClassManifest] = info[T].rootPossibles find (_.isDirectory) map (_.toDirectory) @@ -373,7 +373,7 @@ extends ClassPath[T] { this(entries.toIndexedSeq, context) def name = entries.head.name - def asURLs = entries flatMap (_.asURLs) toList + def asURLs = (entries flatMap (_.asURLs)).toList lazy val sourcepaths: IndexedSeq[AbstractFile] = entries flatMap (_.sourcepaths) override def origin = Some(entries map (x => x.origin getOrElse x.name) mkString ("Merged(", ", ", ")")) diff --git a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala b/src/compiler/scala/tools/nsc/util/CommandLineParser.scala index 00fe49d36a..78bfd5e908 100644 --- a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala +++ b/src/compiler/scala/tools/nsc/util/CommandLineParser.scala @@ -20,11 +20,10 @@ import scala.collection.mutable.ListBuffer */ trait ParserUtil extends Parsers { - class ParserPlus[+T](underlying: Parser[T]) { + protected implicit class ParserPlus[+T](underlying: Parser[T]) { def !~>[U](p: => Parser[U]): Parser[U] = (underlying ~! p) ^^ { case a~b => b } def <~![U](p: => Parser[U]): Parser[T] = (underlying ~! p) ^^ { case a~b => a } } - protected implicit def parser2parserPlus[T](p: Parser[T]): ParserPlus[T] = new ParserPlus(p) } case class CommandLine( diff --git a/src/compiler/scala/tools/nsc/util/Exceptional.scala b/src/compiler/scala/tools/nsc/util/Exceptional.scala index 667b7d15a6..7452aa1b67 100644 --- a/src/compiler/scala/tools/nsc/util/Exceptional.scala +++ b/src/compiler/scala/tools/nsc/util/Exceptional.scala @@ -5,6 +5,7 @@ import java.util.concurrent.ExecutionException import java.lang.reflect.{ InvocationTargetException, UndeclaredThrowableException } import io.{ Sources, Fileish } import scala.tools.util.StringOps._ +import language.implicitConversions /** A simple throwable wrapper so it looks more like a parade of * glittering frame-shaped beauties than the other thing. diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala index fda713c5c6..700fe0c1a6 100644 --- a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala +++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala @@ -14,6 +14,8 @@ import java.net.URL import scala.reflect.ReflectionUtils.unwrapHandler import ScalaClassLoader._ import scala.util.control.Exception.{ catching } +import language.implicitConversions + // import Exceptional.unwrap trait HasClassPath { diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index 88e6c51e9f..1336cca3c5 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -9,6 +9,8 @@ import java.io.{ OutputStream, PrintStream, ByteArrayOutputStream, PrintWriter, package object util { + implicit def postfixOps = language.postfixOps // make all postfix ops in this package compile without warning + // forwarder for old code that builds against 2.9 and 2.10 val Chars = scala.reflect.internal.Chars |