diff options
53 files changed, 675 insertions, 139 deletions
@@ -2672,7 +2672,12 @@ DISTRIBUTION <target name="dist.base" depends="dist.start"> <mkdir dir="${dist.dir}/lib"/> <copy toDir="${dist.dir}/lib"> - <fileset dir="${build-pack.dir}/lib"/> + <fileset dir="${build-pack.dir}/lib"> + <include name="jline.jar"/> + <include name="scalacheck.jar"/> + <include name="scala-partest.jar"/> + <include name="scalap.jar"/> + </fileset> </copy> <mkdir dir="${dist.dir}/bin"/> <!-- TODO - Stop being inefficient and don't copy OSGi bundles overtop other jars. --> diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala index 0ff098e1da..3a68794c97 100644 --- a/src/compiler/scala/reflect/reify/Errors.scala +++ b/src/compiler/scala/reflect/reify/Errors.scala @@ -27,10 +27,10 @@ trait Errors { } def CannotConvertManifestToTagWithoutScalaReflect(tpe: Type, manifestInScope: Tree) = { - val msg = s""" - |to create a type tag here, it is necessary to interoperate with the manifest `$manifestInScope` in scope. - |however manifest -> typetag conversion requires Scala reflection, which is not present on the classpath. - |to proceed put scala-reflect.jar on your compilation classpath and recompile.""".trim.stripMargin + val msg = + sm"""to create a type tag here, it is necessary to interoperate with the manifest `$manifestInScope` in scope. + |however manifest -> typetag conversion requires Scala reflection, which is not present on the classpath. + |to proceed put scala-reflect.jar on your compilation classpath and recompile.""" throw new ReificationException(defaultErrorPosition, msg) } diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index c78c40dcd3..e796258967 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -56,7 +56,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => * The class `C` is stored as a tree attachment. */ case class InjectDerivedValue(arg: Tree) - extends SymTree + extends SymTree with TermTree class PostfixSelect(qual: Tree, name: Name) extends Select(qual, name) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index f430f1fc34..9bb7e1c3df 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1898,7 +1898,7 @@ self => case _ => } val typeAppliedTree = in.token match { - case LBRACKET => atPos(start, in.offset)(TypeApply(convertToTypeId(t), typeArgs())) + case LBRACKET => atPos(start, in.offset)(AppliedTypeTree(convertToTypeId(t), typeArgs())) case _ => t } in.token match { diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index cfc3d0a377..ba799f9186 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -437,19 +437,19 @@ abstract class Erasure extends AddInterfaces noclash = false unit.error( if (member.owner == root) member.pos else root.pos, - s"""bridge generated for member ${fulldef(member)} - |which overrides ${fulldef(other)} - |clashes with definition of $what; - |both have erased type ${exitingPostErasure(bridge.tpe)}""".stripMargin) + sm"""bridge generated for member ${fulldef(member)} + |which overrides ${fulldef(other)} + |clashes with definition of $what; + |both have erased type ${exitingPostErasure(bridge.tpe)}""") } for (bc <- root.baseClasses) { if (settings.debug.value) exitingPostErasure(println( - s"""check bridge overrides in $bc - ${bc.info.nonPrivateDecl(bridge.name)} - ${site.memberType(bridge)} - ${site.memberType(bc.info.nonPrivateDecl(bridge.name) orElse IntClass)} - ${(bridge.matchingSymbol(bc, site))}""".stripMargin)) + sm"""check bridge overrides in $bc + |${bc.info.nonPrivateDecl(bridge.name)} + |${site.memberType(bridge)} + |${site.memberType(bc.info.nonPrivateDecl(bridge.name) orElse IntClass)} + |${(bridge.matchingSymbol(bc, site))}""")) def overriddenBy(sym: Symbol) = sym.matchingSymbol(bc, site).alternatives filter (sym => !sym.isBridge) @@ -693,7 +693,7 @@ abstract class Erasure extends AddInterfaces adaptToType(unbox(tree, pt), pt) else if (isPrimitiveValueType(tree.tpe) && !isPrimitiveValueType(pt)) { adaptToType(box(tree, pt.toString), pt) - } else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.params.isEmpty) { + } else if (isMethodTypeWithEmptyParams(tree.tpe)) { // [H] this assert fails when trying to typecheck tree !(SomeClass.this.bitmap) for single lazy val //assert(tree.symbol.isStable, "adapt "+tree+":"+tree.tpe+" to "+pt) adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt) @@ -774,16 +774,21 @@ abstract class Erasure extends AddInterfaces else if (!isPrimitiveValueType(qual1.tpe) && isPrimitiveValueMember(tree.symbol)) qual1 = unbox(qual1, tree.symbol.owner.tpe) - if (isPrimitiveValueMember(tree.symbol) && !isPrimitiveValueType(qual1.tpe)) + def selectFrom(qual: Tree) = treeCopy.Select(tree, qual, name) + + if (isPrimitiveValueMember(tree.symbol) && !isPrimitiveValueType(qual1.tpe)) { tree.symbol = NoSymbol - else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.params.isEmpty) { + selectFrom(qual1) + } else if (isMethodTypeWithEmptyParams(qual1.tpe)) { assert(qual1.symbol.isStable, qual1.symbol); - qual1 = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType + val applied = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType + adaptMember(selectFrom(applied)) } else if (!(qual1.isInstanceOf[Super] || (qual1.tpe.typeSymbol isSubClass tree.symbol.owner))) { assert(tree.symbol.owner != ArrayClass) - qual1 = cast(qual1, tree.symbol.owner.tpe) + selectFrom(cast(qual1, tree.symbol.owner.tpe)) + } else { + selectFrom(qual1) } - treeCopy.Select(tree, qual1, name) } case SelectFromArray(qual, name, erasure) => var qual1 = typedQualifier(qual) @@ -861,6 +866,11 @@ abstract class Erasure extends AddInterfaces tree1 } } + + private def isMethodTypeWithEmptyParams(tpe: Type) = tpe match { + case MethodType(Nil, _) => true + case _ => false + } } /** The erasure transformer */ diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 4f889a1d86..8ae9490dbe 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -371,7 +371,7 @@ abstract class UnCurry extends InfoTransform } val isDefinedAtMethodDef = { - val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL) + val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL | SYNTHETIC) val params = methSym newSyntheticValueParams formals methSym setInfoAndEnter MethodType(params, BooleanClass.tpe) diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index bfc9f08553..a6d11f13d4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -106,9 +106,9 @@ trait ContextErrors { s"$name extends Any, not AnyRef" ) if (isPrimitiveValueType(found) || isTrivialTopType(tp)) "" else "\n" + - s"""|Note that $what. - |Such types can participate in value classes, but instances - |cannot appear in singleton types or in reference comparisons.""".stripMargin + sm"""|Note that $what. + |Such types can participate in value classes, but instances + |cannot appear in singleton types or in reference comparisons.""" } import ErrorUtils._ @@ -1125,9 +1125,9 @@ trait ContextErrors { (isView: Boolean, pt: Type, tree: Tree)(implicit context0: Context) = { if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) { def coreMsg = - s"""| $pre1 ${info1.sym.fullLocationString} of type ${info1.tpe} - | $pre2 ${info2.sym.fullLocationString} of type ${info2.tpe} - | $trailer""".stripMargin + sm"""| $pre1 ${info1.sym.fullLocationString} of type ${info1.tpe} + | $pre2 ${info2.sym.fullLocationString} of type ${info2.tpe} + | $trailer""" def viewMsg = { val found :: req :: _ = pt.typeArgs def explanation = { @@ -1138,19 +1138,19 @@ trait ContextErrors { // involving Any, are further explained from foundReqMsg. if (AnyRefClass.tpe <:< req) ( if (sym == AnyClass || sym == UnitClass) ( - s"""|Note: ${sym.name} is not implicitly converted to AnyRef. You can safely - |pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so.""".stripMargin + sm"""|Note: ${sym.name} is not implicitly converted to AnyRef. You can safely + |pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so.""" ) else boxedClass get sym map (boxed => - s"""|Note: an implicit exists from ${sym.fullName} => ${boxed.fullName}, but - |methods inherited from Object are rendered ambiguous. This is to avoid - |a blanket implicit which would convert any ${sym.fullName} to any AnyRef. - |You may wish to use a type ascription: `x: ${boxed.fullName}`.""".stripMargin + sm"""|Note: an implicit exists from ${sym.fullName} => ${boxed.fullName}, but + |methods inherited from Object are rendered ambiguous. This is to avoid + |a blanket implicit which would convert any ${sym.fullName} to any AnyRef. + |You may wish to use a type ascription: `x: ${boxed.fullName}`.""" ) getOrElse "" ) else - s"""|Note that implicit conversions are not applicable because they are ambiguous: - |${coreMsg}are possible conversion functions from $found to $req""".stripMargin + sm"""|Note that implicit conversions are not applicable because they are ambiguous: + |${coreMsg}are possible conversion functions from $found to $req""" } typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req)) + ( if (explanation == "") "" else "\n" + explanation diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index eb45f9b847..739e28bf0c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1298,17 +1298,17 @@ trait Implicits { else { if (ReflectRuntimeUniverse == NoSymbol) { // todo. write a test for this - context.error(pos, s""" - |to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope. - |however typetag -> manifest conversion requires Scala reflection, which is not present on the classpath. - |to proceed put scala-reflect.jar on your compilation classpath and recompile.""".trim.stripMargin) + context.error(pos, + sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope. + |however typetag -> manifest conversion requires Scala reflection, which is not present on the classpath. + |to proceed put scala-reflect.jar on your compilation classpath and recompile.""") return SearchFailure } if (resolveClassTag(pos, tp, allowMaterialization = true) == EmptyTree) { - context.error(pos, s""" - |to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope. - |however typetag -> manifest conversion requires a class tag for the corresponding type to be present. - |to proceed add a class tag to the type `$tp` (e.g. by introducing a context bound) and recompile.""".trim.stripMargin) + context.error(pos, + sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope. + |however typetag -> manifest conversion requires a class tag for the corresponding type to be present. + |to proceed add a class tag to the type `$tp` (e.g. by introducing a context bound) and recompile.""") return SearchFailure } val cm = typed(Ident(ReflectRuntimeCurrentMirror)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 4b534b0d2e..e40d978e6d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -117,16 +117,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { } def pickle(macroImplRef: Tree): Tree = { - val macroImpl = macroImplRef.symbol + val MacroImplReference(owner, macroImpl, targs) = macroImplRef val paramss = macroImpl.paramss - // this logic relies on the assumptions that were valid for the old macro prototype - // namely that macro implementations can only be defined in top-level classes and modules - // with the new prototype that materialized in a SIP, macros need to be statically accessible, which is different - // for example, a macro def could be defined in a trait that is implemented by an object - // there are some more clever cases when seemingly non-static method ends up being statically accessible - // however, the code below doesn't account for these guys, because it'd take a look of time to get it right - // for now I leave it as a todo and move along to more the important stuff // todo. refactor when fixing SI-5498 def className: String = { def loop(sym: Symbol): String = sym match { @@ -138,7 +131,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { loop(sym.owner) + separator + sym.javaSimpleName.toString } - loop(macroImpl.owner.enclClass) + loop(owner) } def signature: List[Int] = { @@ -159,7 +152,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { // I just named it "macro", because it's macro-related, but I could as well name it "foobar" val nucleus = Ident(newTermName("macro")) val wrapped = Apply(nucleus, payload map { case (k, v) => Assign(pickleAtom(k), pickleAtom(v)) }) - val pickle = gen.mkTypeApply(wrapped, treeInfo.typeArguments(macroImplRef.duplicate)) + val pickle = gen.mkTypeApply(wrapped, targs map (_.duplicate)) // assign NoType to all freshly created AST nodes // otherwise pickler will choke on tree.tpe being null diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index c5245c4e9e..42c34526d7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -1151,7 +1151,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // ExplicitOuter replaces `Select(q, outerSym) OBJ_EQ expectedPrefix` by `Select(q, outerAccessor(outerSym.owner)) OBJ_EQ expectedPrefix` // if there's an outer accessor, otherwise the condition becomes `true` -- TODO: can we improve needsOuterTest so there's always an outerAccessor? - val outer = expectedTp.typeSymbol.newMethod(vpmName.outer) setInfo expectedTp.prefix setFlag SYNTHETIC | ARTIFACT + val outer = expectedTp.typeSymbol.newMethod(vpmName.outer, newFlags = SYNTHETIC | ARTIFACT) setInfo expectedTp.prefix (Select(codegen._asInstanceOf(testedBinder, expectedTp), outer)) OBJ_EQ expectedOuter } @@ -1413,7 +1413,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // assert(owner ne null); assert(owner ne NoSymbol) def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") = - NoSymbol.newTermSymbol(freshName(prefix), pos) setInfo tp + NoSymbol.newTermSymbol(freshName(prefix), pos, newFlags = SYNTHETIC) setInfo tp def newSynthCaseLabel(name: String) = NoSymbol.newLabel(freshName(name), NoPosition) setFlag treeInfo.SYNTH_CASE_FLAGS @@ -3600,7 +3600,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL */ def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree = { val matchEnd = newSynthCaseLabel("matchEnd") - val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, SYNTHETIC) setInfo restpe.withoutAnnotations + val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, newFlags = SYNTHETIC) setInfo restpe.withoutAnnotations matchEnd setInfo MethodType(List(matchRes), restpe) def newCaseSym = newSynthCaseLabel("case") setInfo MethodType(Nil, restpe) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 7a7c7c7d25..0ae225ccee 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1382,8 +1382,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans private def checkCompileTimeOnly(sym: Symbol, pos: Position) = { if (sym.isCompileTimeOnly) { def defaultMsg = - s"""|Reference to ${sym.fullLocationString} should not have survived past type checking, - |it should have been processed and eliminated during expansion of an enclosing macro.""".stripMargin + sm"""Reference to ${sym.fullLocationString} should not have survived past type checking, + |it should have been processed and eliminated during expansion of an enclosing macro.""" // The getOrElse part should never happen, it's just here as a backstop. unit.error(pos, sym.compileTimeOnlyMessage getOrElse defaultMsg) } diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 5fb9a5e67e..0992cd7955 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -525,8 +525,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } def isJavaProtected = host.isTrait && sym.isJavaDefined && { restrictionError(pos, unit, - s"""|$clazz accesses protected $sym inside a concrete trait method. - |Add an accessor in a class extending ${sym.enclClass} as a workaround.""".stripMargin + sm"""$clazz accesses protected $sym inside a concrete trait method. + |Add an accessor in a class extending ${sym.enclClass} as a workaround.""" ) true } diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index be7554abe2..fb95c952d2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -268,11 +268,9 @@ abstract class TreeCheckers extends Analyzer { if (sym.owner != currentOwner) { val expected = currentOwner.ownerChain find (x => cond(x)) getOrElse { fail("DefTree can't find owner: ") ; NoSymbol } if (sym.owner != expected) - fail("""| - | currentOwner chain: %s - | symbol chain: %s""".stripMargin.format( - currentOwner.ownerChain take 3 mkString " -> ", - sym.ownerChain mkString " -> ") + fail(sm"""| + | currentOwner chain: ${currentOwner.ownerChain take 3 mkString " -> "} + | symbol chain: ${sym.ownerChain mkString " -> "}""" ) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 42c7d4a6b8..e534e36a0d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3763,54 +3763,45 @@ trait Typers extends Modes with Adaptations with Tags { * */ def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = { - debuglog(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)") + log(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)") + val treeSelection = treeInfo.methPart(tree) + def isDesugaredApply = treeSelection match { + case Select(`qual`, nme.apply) => true + case _ => false + } 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 cxTree1 = cxTree match { - case t: ValOrDefDef => t.rhs - case t => t - } - val cxTree2 = cxTree1 match { - case Typed(t, tpe) => t // ignore outer type annotation - case t => t - } - val (outer, explicitTargs) = cxTree2 match { - case TypeApply(fun, targs) => (fun, targs) - case Apply(TypeApply(fun, targs), args) => (Apply(fun, args), targs) - case Select(TypeApply(fun, targs), nme) => (Select(fun, nme), targs) - case t => (t, Nil) - } - def hasNamedArg(as: List[Tree]) = as.collectFirst{case AssignOrNamedArg(lhs, rhs) =>}.nonEmpty - - def desugaredApply = tree match { - case Select(`qual`, nme.apply) => true - case _ => false + // If tp == NoType, pass only explicit type arguments to applyXXX. Not used at all + // here - it is for scala-virtualized, where tp will be passed as an argument (for + // selection on a staged Struct) + def hasNamed(args: List[Tree]): Boolean = args exists (_.isInstanceOf[AssignOrNamedArg]) + // not supported: foo.bar(a1,..., an: _*) + def hasStar(args: List[Tree]) = treeInfo.isWildcardStarArgList(args) + def applyOp(args: List[Tree]) = if (hasNamed(args)) nme.applyDynamicNamed else nme.applyDynamic + def matches(t: Tree) = isDesugaredApply || treeInfo.methPart(t) == treeSelection + + /** Note that the trees which arrive here are potentially some distance from + * the trees of direct interest. `cxTree` is some enclosing expression which + * may apparently be arbitrarily larger than `tree`; and `tree` itself is + * too small, having at least in some cases lost its explicit type parameters. + * This logic is designed to use `tree` to pinpoint the immediately surrounding + * Apply/TypeApply/Select node, and only then creates the dynamic call. + * See SI-6731 among others. + */ + def findSelection(t: Tree): Option[(TermName, Tree)] = t match { + case Apply(fn, args) if hasStar(args) => DynamicVarArgUnsupported(tree, applyOp(args)) ; None + case Apply(fn, args) if matches(fn) => Some((applyOp(args), fn)) + case Assign(lhs, _) if matches(lhs) => Some((nme.updateDynamic, lhs)) + case _ if matches(t) => Some((nme.selectDynamic, t)) + case _ => t.children flatMap findSelection headOption } - // 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(q, as) if q == tree || desugaredApply => - 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 + findSelection(cxTree) match { + case Some((opName, tapply)) => + val targs = treeInfo.typeArguments(tapply) + val fun = gen.mkTypeApply(Select(qual, opName), targs) + atPos(qual.pos)(Apply(fun, Literal(Constant(name.decode)) :: Nil)) + case _ => + setError(tree) } - - 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))))) } } @@ -5015,7 +5006,7 @@ trait Typers extends Modes with Adaptations with Tags { case tt @ TypeTree() => tree setOriginal tt.original case _ => tree } - } + } else // we should get here only when something before failed // and we try again (@see tryTypedApply). In that case we can assign diff --git a/src/library/scala/Symbol.scala b/src/library/scala/Symbol.scala index 723c05a30c..4fead7a50c 100644 --- a/src/library/scala/Symbol.scala +++ b/src/library/scala/Symbol.scala @@ -69,6 +69,11 @@ private[scala] abstract class UniquenessCache[K, V >: Null] val res = cached() if (res != null) res else { + // If we don't remove the old String key from the map, we can + // wind up with one String as the key and a different String as + // as the name field in the Symbol, which can lead to surprising + // GC behavior and duplicate Symbols. See SI-6706. + map remove name val sym = valueFromKey(name) map.put(name, new WeakReference(sym)) sym diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index 94242260a1..7ab99fcda2 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -110,24 +110,23 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { /** Finds an entry in the hash table if such an element exists. */ protected def findEntry(elem: A): Option[A] = { - var h = index(elemHashCode(elem)) - var entry = table(h) - while (null != entry && entry != elem) { - h = (h + 1) % table.length - entry = table(h) - } + val entry = findEntryImpl(elem) if (null == entry) None else Some(entry.asInstanceOf[A]) } /** Checks whether an element is contained in the hash table. */ protected def containsEntry(elem: A): Boolean = { + null != findEntryImpl(elem) + } + + private def findEntryImpl(elem: A): AnyRef = { var h = index(elemHashCode(elem)) var entry = table(h) while (null != entry && entry != elem) { h = (h + 1) % table.length entry = table(h) } - null != entry + entry } /** Add entry if not yet in table. diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index a0e5851a6e..1298fc17ed 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -344,6 +344,11 @@ abstract class SymbolTable extends macros.Universe @inline final def atPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph)(op) @deprecated("Use enteringPhaseNotLaterThan", "2.10.0") @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T = enteringPhaseNotLaterThan(target)(op) + + /** + * Adds the `sm` String interpolator to a [[scala.StringContext]]. + */ + implicit val StringContextStripMarginOps: StringContext => StringContextStripMarginOps = util.StringContextStripMarginOps } object SymbolTableStats { diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index ad7dbe5ef1..7de53a7731 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -77,7 +77,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isImplementationArtifact: Boolean = (this hasFlag BRIDGE) || (this hasFlag VBRIDGE) || (this hasFlag ARTIFACT) def isJava: Boolean = isJavaDefined def isVal: Boolean = isTerm && !isModule && !isMethod && !isMutable - def isVar: Boolean = isTerm && !isModule && !isMethod && isMutable + def isVar: Boolean = isTerm && !isModule && !isMethod && !isLazy && isMutable def newNestedSymbol(name: Name, pos: Position, newFlags: Long, isClass: Boolean): Symbol = name match { case n: TermName => newTermSymbol(n, pos, newFlags) diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index f944e1d5d1..5c1d109662 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -392,6 +392,9 @@ trait Trees extends api.Trees { self: SymbolTable => case class TypeApply(fun: Tree, args: List[Tree]) extends GenericApply with TypeApplyApi { + + assert(fun.isTerm, fun) + override def symbol: Symbol = fun.symbol override def symbol_=(sym: Symbol) { fun.symbol = sym } } @@ -437,7 +440,11 @@ trait Trees extends api.Trees { self: SymbolTable => object This extends ThisExtractor case class Select(qualifier: Tree, name: Name) - extends RefTree with SelectApi + extends RefTree with SelectApi { + + // !!! assert disabled due to test case pos/annotDepMethType.scala triggering it. + // assert(qualifier.isTerm, qualifier) + } object Select extends SelectExtractor case class Ident(name: Name) extends RefTree with IdentContextApi { @@ -469,7 +476,10 @@ trait Trees extends api.Trees { self: SymbolTable => object SingletonTypeTree extends SingletonTypeTreeExtractor case class SelectFromTypeTree(qualifier: Tree, name: TypeName) - extends RefTree with TypTree with SelectFromTypeTreeApi + extends RefTree with TypTree with SelectFromTypeTreeApi { + + assert(qualifier.isType, qualifier) + } object SelectFromTypeTree extends SelectFromTypeTreeExtractor case class CompoundTypeTree(templ: Template) @@ -478,6 +488,9 @@ trait Trees extends api.Trees { self: SymbolTable => case class AppliedTypeTree(tpt: Tree, args: List[Tree]) extends TypTree with AppliedTypeTreeApi { + + assert(tpt.isType, tpt) + override def symbol: Symbol = tpt.symbol override def symbol_=(sym: Symbol) { tpt.symbol = sym } } diff --git a/src/reflect/scala/reflect/internal/util/StripMarginInterpolator.scala b/src/reflect/scala/reflect/internal/util/StripMarginInterpolator.scala new file mode 100644 index 0000000000..e7579229b2 --- /dev/null +++ b/src/reflect/scala/reflect/internal/util/StripMarginInterpolator.scala @@ -0,0 +1,40 @@ +package scala.reflect +package internal +package util + +trait StripMarginInterpolator { + def stringContext: StringContext + + /** + * A safe combination of `[[scala.collection.immutable.StringLike#stripMargin]] + * and [[scala.StringContext#raw]]. + * + * The margin of each line is defined by whitespace leading up to a '|' character. + * This margin is stripped '''before''' the arguments are interpolated into to string. + * + * String escape sequences are '''not''' processed; this interpolater is designed to + * be used with triple quoted Strings. + * + * {{{ + * scala> val foo = "f|o|o" + * foo: String = f|o|o + * scala> sm"""|${foo} + * |""" + * res0: String = + * "f|o|o + * " + * }}} + */ + final def sm(args: Any*): String = { + def isLineBreak(c: Char) = c == '\n' || c == '\f' // compatible with StringLike#isLineBreak + def stripTrailingPart(s: String) = { + val (pre, post) = s.span(c => !isLineBreak(c)) + pre + post.stripMargin + } + val stripped: List[String] = stringContext.parts.toList match { + case head :: tail => head.stripMargin :: (tail map stripTrailingPart) + case Nil => Nil + } + new StringContext(stripped: _*).raw(args: _*) + } +} diff --git a/src/reflect/scala/reflect/internal/util/package.scala b/src/reflect/scala/reflect/internal/util/package.scala index 83c8bf67ba..1ca57b81ed 100644 --- a/src/reflect/scala/reflect/internal/util/package.scala +++ b/src/reflect/scala/reflect/internal/util/package.scala @@ -31,4 +31,8 @@ package object util { } else shortenName(name) } + /** + * Adds the `sm` String interpolator to a [[scala.StringContext]]. + */ + implicit class StringContextStripMarginOps(val stringContext: StringContext) extends StripMarginInterpolator } diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index d264cc06b4..54d02f3371 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -126,11 +126,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def ErrorStaticModule(sym: Symbol) = throw new ScalaReflectionException(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror") private def ErrorNotMember(sym: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}") private def ErrorNotField(sym: Symbol) = throw new ScalaReflectionException(s"expected a field or an accessor method symbol, you provided $sym") - private def ErrorNonExistentField(sym: Symbol) = throw new ScalaReflectionException(s""" - |Scala field ${sym.name} isn't represented as a Java field, neither it has a Java accessor method - |note that private parameters of class constructors don't get mapped onto fields and/or accessors, - |unless they are used outside of their declaring constructors. - """.trim.stripMargin) + private def ErrorNonExistentField(sym: Symbol) = throw new ScalaReflectionException( + sm"""Scala field ${sym.name} isn't represented as a Java field, neither it has a Java accessor method + |note that private parameters of class constructors don't get mapped onto fields and/or accessors, + |unless they are used outside of their declaring constructors.""") private def ErrorSetImmutableField(sym: Symbol) = throw new ScalaReflectionException(s"cannot set an immutable field ${sym.name}") private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a constructor of $owner, you provided $sym") private def ErrorFree(member: Symbol, freeType: Symbol) = throw new ScalaReflectionException(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}") @@ -535,8 +534,8 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val result = anns find (_.annotationType == annotClass) if (result.isEmpty && (anns exists (_.annotationType.getName == name))) throw new ClassNotFoundException( - s"""Mirror classloader mismatch: $jclazz (loaded by ${ReflectionUtils.show(jclazz.getClassLoader)}) - |is unrelated to the mirror's classloader: (${ReflectionUtils.show(classLoader)})""".stripMargin) + sm"""Mirror classloader mismatch: $jclazz (loaded by ${ReflectionUtils.show(jclazz.getClassLoader)}) + |is unrelated to the mirror's classloader: (${ReflectionUtils.show(classLoader)})""") result } def loadBytes[T: ClassTag](name: String): Option[T] = @@ -935,8 +934,8 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni javaTypeToValueClass(jclazz) orElse lookupClass assert (cls.isType, - s"""${if (cls == NoSymbol) "not a type: symbol" else "no symbol could be"} - | loaded from $jclazz in $owner with name $simpleName and classloader $classLoader""".stripMargin) + sm"""${if (cls == NoSymbol) "not a type: symbol" else "no symbol could be"} + | loaded from $jclazz in $owner with name $simpleName and classloader $classLoader""") cls.asClass } diff --git a/test/files/neg/gadts1.check b/test/files/neg/gadts1.check index a61231a27a..9b7ea5556a 100644 --- a/test/files/neg/gadts1.check +++ b/test/files/neg/gadts1.check @@ -1,6 +1,6 @@ -gadts1.scala:20: error: class Cell of type Test.Cell does not take type parameters. +gadts1.scala:20: error: Test.Cell[a] does not take parameters case Cell[a](x: Int) => c.x = 5 - ^ + ^ gadts1.scala:20: error: type mismatch; found : Int(5) required: a diff --git a/test/files/neg/t5753.check b/test/files/neg/t5753.check new file mode 100644 index 0000000000..76602de17d --- /dev/null +++ b/test/files/neg/t5753.check @@ -0,0 +1,4 @@ +Test_2.scala:9: error: macro implementation not found: foo (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them) + println(foo(42)) + ^ +one error found diff --git a/test/files/neg/t5753.flags b/test/files/neg/t5753.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/neg/t5753.flags @@ -0,0 +1 @@ +-language:experimental.macros
\ No newline at end of file diff --git a/test/files/neg/t5753/Impls$class.class b/test/files/neg/t5753/Impls$class.class Binary files differnew file mode 100644 index 0000000000..476329174e --- /dev/null +++ b/test/files/neg/t5753/Impls$class.class diff --git a/test/files/neg/t5753/Impls.class b/test/files/neg/t5753/Impls.class Binary files differnew file mode 100644 index 0000000000..dfcf89ed44 --- /dev/null +++ b/test/files/neg/t5753/Impls.class diff --git a/test/files/neg/t5753/Impls_Macros_1.scala b/test/files/neg/t5753/Impls_Macros_1.scala new file mode 100644 index 0000000000..1d9c26458c --- /dev/null +++ b/test/files/neg/t5753/Impls_Macros_1.scala @@ -0,0 +1,6 @@ +import scala.reflect.macros.{Context => Ctx} + +trait Impls { +def impl(c: Ctx)(x: c.Expr[Any]) = x +} + diff --git a/test/files/neg/t5753/Test_2.scala b/test/files/neg/t5753/Test_2.scala new file mode 100644 index 0000000000..2369b18e76 --- /dev/null +++ b/test/files/neg/t5753/Test_2.scala @@ -0,0 +1,11 @@ +import scala.reflect.macros.{Context => Ctx} + +object Macros extends Impls { + def foo(x: Any) = macro impl +} + +object Test extends App { + import Macros._ + println(foo(42)) +} + diff --git a/test/files/pos/t5726.scala b/test/files/pos/t5726.scala new file mode 100644 index 0000000000..b28ebd8674 --- /dev/null +++ b/test/files/pos/t5726.scala @@ -0,0 +1,17 @@ +import scala.language.dynamics + +class DynamicTest extends Dynamic { + def selectDynamic(name: String) = s"value of $name" + def updateDynamic(name: String)(value: Any) { + println(s"You have just updated property '$name' with value: $value") + } +} + +object MyApp extends App { + def testing() { + val test = new DynamicTest + test.firstName = "John" + } + + testing() +} diff --git a/test/files/pos/t6551.scala b/test/files/pos/t6551.scala index fb68663809..8bb396a19f 100644 --- a/test/files/pos/t6551.scala +++ b/test/files/pos/t6551.scala @@ -1,4 +1,4 @@ -import language.dynamics +import scala.language.dynamics object Test { def main(args: Array[String]) { diff --git a/test/files/pos/t6722.scala b/test/files/pos/t6722.scala new file mode 100644 index 0000000000..576746c915 --- /dev/null +++ b/test/files/pos/t6722.scala @@ -0,0 +1,11 @@ +import scala.language.dynamics + +class Dyn extends Dynamic { + def selectDynamic(s: String): Dyn = new Dyn + def get[T]: T = null.asInstanceOf[T] +} + +object Foo { + val dyn = new Dyn + dyn.foo.bar.baz.get[String] +} diff --git a/test/files/run/showraw_aliases.check b/test/files/run/showraw_aliases.check index 1838bf9bec..aebd354031 100644 --- a/test/files/run/showraw_aliases.check +++ b/test/files/run/showraw_aliases.check @@ -1,2 +1,2 @@ -Block(List(Import(Select(Select(Ident(scala), scala.reflect), scala.reflect.runtime), List(ImportSelector(newTermName("universe"), 52, newTermName("ru"), 64)))), Select(Select(Select(Select(Ident(scala), scala.reflect), scala.reflect.runtime), scala.reflect.runtime.package), [newTermName("universe") aka newTermName("ru")])) -Block(List(Import(Select(Select(Ident(scala#<id>), scala.reflect#<id>), scala.reflect.runtime#<id>), List(ImportSelector(newTermName("universe"), 52, newTermName("ru"), 64)))), Select(Select(Select(Select(Ident(scala#<id>), scala.reflect#<id>), scala.reflect.runtime#<id>), scala.reflect.runtime.package#<id>), [newTermName("universe")#<id> aka newTermName("ru")])) +Block(List(Import(Select(Select(Ident(scala), scala.reflect), scala.reflect.runtime), List(ImportSelector(newTermName("universe"), <offset>, newTermName("ru"), <offset>)))), Select(Select(Select(Select(Ident(scala), scala.reflect), scala.reflect.runtime), scala.reflect.runtime.package), [newTermName("universe") aka newTermName("ru")])) +Block(List(Import(Select(Select(Ident(scala#<id>), scala.reflect#<id>), scala.reflect.runtime#<id>), List(ImportSelector(newTermName("universe"), <offset>, newTermName("ru"), <offset>)))), Select(Select(Select(Select(Ident(scala#<id>), scala.reflect#<id>), scala.reflect.runtime#<id>), scala.reflect.runtime.package#<id>), [newTermName("universe")#<id> aka newTermName("ru")])) diff --git a/test/files/run/showraw_aliases.scala b/test/files/run/showraw_aliases.scala index 3a68ca37b2..65b4fcb1cd 100644 --- a/test/files/run/showraw_aliases.scala +++ b/test/files/run/showraw_aliases.scala @@ -9,7 +9,9 @@ object Test extends App { """) val ttree = tb.typeCheck(tree) - def stabilize(s: String) = """#\d+""".r.replaceAllIn(s, "#<id>") - println(showRaw(ttree)) + def stabilizeIds(s: String) = """#\d+""".r.replaceAllIn(s, "#<id>") + def stabilizePositions(s: String) = """\d+""".r.replaceAllIn(s, "<offset>") + def stabilize(s: String) = stabilizePositions(stabilizeIds(s)) + println(stabilize(showRaw(ttree))) println(stabilize(showRaw(ttree, printIds = true))) }
\ No newline at end of file diff --git a/test/files/run/sm-interpolator.scala b/test/files/run/sm-interpolator.scala new file mode 100644 index 0000000000..7f7b9f061a --- /dev/null +++ b/test/files/run/sm-interpolator.scala @@ -0,0 +1,41 @@ +object Test extends App { + import scala.reflect.internal.util.StringContextStripMarginOps + def check(actual: Any, expected: Any) = if (actual != expected) sys.error(s"expected: [$expected], actual: [$actual])") + + val bar = "|\n ||" + + check( + sm"""|ab + |de + |${bar} | ${1}""", + "ab \nde\n|\n || | 1") + + check( + sm"|", + "") + + check( + sm"${0}", + "0") + + check( + sm"${0}", + "0") + + check( + sm"""${0}|${1} + |""", + "0|1\n") + + check( + sm""" ||""", + "|") + + check( + sm""" ${" "} ||""", + " ||") + + check( + sm"\n", + raw"\n".stripMargin) +} diff --git a/test/files/run/t5733.check b/test/files/run/t5733.check new file mode 100644 index 0000000000..e697046a94 --- /dev/null +++ b/test/files/run/t5733.check @@ -0,0 +1,2 @@ +Running ABTest asserts +Done diff --git a/test/files/run/t5733.scala b/test/files/run/t5733.scala new file mode 100644 index 0000000000..360264e4ed --- /dev/null +++ b/test/files/run/t5733.scala @@ -0,0 +1,53 @@ +import scala.language.dynamics + +object A extends Dynamic { + var a = "a" + + def selectDynamic(method:String): String = a + + def updateDynamic(method:String)(v:String) { a = v } +} + +class B extends Dynamic { + var b = "b" + + def selectDynamic(method:String): String = b + + def updateDynamic(method:String)(v:String) { b = v } +} + +object Test extends App { + assert( A.foo == "a" ) + assert( A.bar == "a" ) + A.aaa = "aaa" + assert( A.bar == "aaa" ) + + val b = new B + assert( b.foo == "b" ) + assert( b.bar == "b" ) + b.bbb = "bbb" + assert( b.bar == "bbb" ) + + { + println("Running ABTest asserts") + A.a = "a" + (new ABTest).test() + } + + println("Done") +} + +class ABTest { + def test() { + assert( A.foo == "a" ) + assert( A.bar == "a" ) + A.aaa = "aaa" + assert( A.bar == "aaa" ) + + val b = new B + assert( b.foo == "b" ) + assert( b.bar == "b" ) + b.bbb = "bbb" + assert( b.bar == "bbb" ) + } +} diff --git a/test/files/run/t5753_1.check b/test/files/run/t5753_1.check new file mode 100644 index 0000000000..f70d7bba4a --- /dev/null +++ b/test/files/run/t5753_1.check @@ -0,0 +1 @@ +42
\ No newline at end of file diff --git a/test/files/run/t5753_1.flags b/test/files/run/t5753_1.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/run/t5753_1.flags @@ -0,0 +1 @@ +-language:experimental.macros
\ No newline at end of file diff --git a/test/files/run/t5753_1/Impls_Macros_1.scala b/test/files/run/t5753_1/Impls_Macros_1.scala new file mode 100644 index 0000000000..1664301f5f --- /dev/null +++ b/test/files/run/t5753_1/Impls_Macros_1.scala @@ -0,0 +1,10 @@ +import scala.reflect.macros.Context +import language.experimental.macros + +trait Impls { + def impl(c: Context)(x: c.Expr[Any]) = x +} + +object Macros extends Impls { + def foo(x: Any) = macro impl +}
\ No newline at end of file diff --git a/test/files/run/t5753_1/Test_2.scala b/test/files/run/t5753_1/Test_2.scala new file mode 100644 index 0000000000..a2777638bc --- /dev/null +++ b/test/files/run/t5753_1/Test_2.scala @@ -0,0 +1,4 @@ +object Test extends App { + import Macros._ + println(foo(42)) +}
\ No newline at end of file diff --git a/test/files/run/t5753_2.check b/test/files/run/t5753_2.check new file mode 100644 index 0000000000..f70d7bba4a --- /dev/null +++ b/test/files/run/t5753_2.check @@ -0,0 +1 @@ +42
\ No newline at end of file diff --git a/test/files/run/t5753_2.flags b/test/files/run/t5753_2.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/run/t5753_2.flags @@ -0,0 +1 @@ +-language:experimental.macros
\ No newline at end of file diff --git a/test/files/run/t5753_2/Impls_Macros_1.scala b/test/files/run/t5753_2/Impls_Macros_1.scala new file mode 100644 index 0000000000..e23c0b938b --- /dev/null +++ b/test/files/run/t5753_2/Impls_Macros_1.scala @@ -0,0 +1,10 @@ +import scala.reflect.macros.{Context => Ctx} + +trait Macro_T { + def foo[T](c: Ctx)(s: c.Expr[T]) = s +} + +object Macros { + def foo[T](s: T) = macro Impls.foo[T] + object Impls extends Macro_T +} diff --git a/test/files/run/t5753_2/Test_2.scala b/test/files/run/t5753_2/Test_2.scala new file mode 100644 index 0000000000..a2777638bc --- /dev/null +++ b/test/files/run/t5753_2/Test_2.scala @@ -0,0 +1,4 @@ +object Test extends App { + import Macros._ + println(foo(42)) +}
\ No newline at end of file diff --git a/test/files/run/t6320.check b/test/files/run/t6320.check new file mode 100644 index 0000000000..e56bacd223 --- /dev/null +++ b/test/files/run/t6320.check @@ -0,0 +1,17 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> import scala.language.dynamics +import scala.language.dynamics + +scala> class Dyn(m: Map[String, Any]) extends Dynamic { def selectDynamic[T](s: String): T = m(s).asInstanceOf[T] } +defined class Dyn + +scala> new Dyn(Map("foo" -> 10)).foo[Int] +res0: Int = 10 + +scala> + +scala> diff --git a/test/files/run/t6320.scala b/test/files/run/t6320.scala new file mode 100644 index 0000000000..26085a3d7d --- /dev/null +++ b/test/files/run/t6320.scala @@ -0,0 +1,9 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ +import scala.language.dynamics +class Dyn(m: Map[String, Any]) extends Dynamic { def selectDynamic[T](s: String): T = m(s).asInstanceOf[T] } +new Dyn(Map("foo" -> 10)).foo[Int] + """ +} diff --git a/test/files/run/t6677.scala b/test/files/run/t6677.scala new file mode 100644 index 0000000000..e6eaf6a498 --- /dev/null +++ b/test/files/run/t6677.scala @@ -0,0 +1,28 @@ + +class Test { + val cm: reflect.runtime.universe.Mirror = reflect.runtime.currentMirror + def error { + new cm.universe.Traverser // java.lang.VerifyError: (class: Test, method: error signature: ()V) Incompatible object argument for function call + + } + + def okay1 { + val cm: reflect.runtime.universe.Mirror = reflect.runtime.currentMirror + + new cm.universe.Traverser + } + + def okay2 { + val cm: reflect.runtime.universe.Mirror = reflect.runtime.currentMirror + val u: reflect.runtime.universe.type = cm.universe + new u.Traverser + } +} + +object Test { + def main(args: Array[String]) { + new Test().error + new Test().okay1 + new Test().okay2 + } +} diff --git a/test/files/run/t6677b.scala b/test/files/run/t6677b.scala new file mode 100644 index 0000000000..e4fe5e3722 --- /dev/null +++ b/test/files/run/t6677b.scala @@ -0,0 +1,33 @@ +trait U { + trait U1 { + class X + } + type U11 <: U1 + val u : U11 = null.asInstanceOf[U11] +} +trait A extends U + +trait B extends U { + def foo = "" + class U11 extends U1 { class X extends super.X { foo } } // refer to foo to add $outer pointer + override val u = new U11 +} +class C { + val ab: A with B = new A with B // `B with A` works. + + def foo { + // fails + new ab.u.X + + // works: + val u = ab.u + new u.X + } +} +object Test { + def main(args: Array[String]) { + // java.lang.NoSuchMethodError: A.u()LB$U11; + // at C.foo(t6677b.scala:23) + new C().foo + } +} diff --git a/test/files/run/t6687.scala b/test/files/run/t6687.scala new file mode 100644 index 0000000000..ee44e5f0d2 --- /dev/null +++ b/test/files/run/t6687.scala @@ -0,0 +1,10 @@ +import scala.reflect.runtime.universe._ + +class A { lazy val x = 1 } + +object Test { + def main(args: Array[String]): Unit = { + val vars = typeOf[A].members.toList filter (x => x.isTerm && x.asTerm.isVar) + assert(vars.isEmpty, vars) + } +} diff --git a/test/files/run/t6706.scala b/test/files/run/t6706.scala new file mode 100644 index 0000000000..905494ca8d --- /dev/null +++ b/test/files/run/t6706.scala @@ -0,0 +1,14 @@ +object Test { + var name = "foo" + 1 + var s1 = Symbol(name) + s1 = null + System.gc + val s2 = Symbol("foo1") + name = null + System.gc + val s3 = Symbol("foo1") + + def main(args: Array[String]): Unit = { + assert(s2 eq s3, ((s2, System.identityHashCode(s2), s3, System.identityHashCode(s3)))) + } +} diff --git a/test/files/run/t6731.check b/test/files/run/t6731.check new file mode 100644 index 0000000000..a5d59bd378 --- /dev/null +++ b/test/files/run/t6731.check @@ -0,0 +1,40 @@ +Mono$.bar() +Mono$.bar +Mono$.bar() +Mono$.bar +Mono$.bar +Mono$.baz +Mono$.bar(bippy=1, boppy=2) +Mono$.baz +Poly.bar[Nothing] +Poly.bar[Int] +Poly.bar[Nothing]() +Poly.bar[Int]() +Poly.bar[Int](1, 2, 3) +Poly.bar[Nothing] +Poly.bar[Int] +Poly.bar[Nothing]() +Poly.bar[Int]() +Poly.bar[Int](1, 2, 3) +Updating.bar +Updating.bar = b +Nest1$Nest2$Nest3$.bippy(1, 2, 3) +Nest1$Nest2$Nest3$.bippy +Named.bippy(a=1, b=2) +Named.boppy(c=3, d=4) +Named.apply() +Named.apply() +Named.apply(e=5, f=6) +Named2.bippy(1)(q0, c) +Named2.bippy(1)(q0, c) +Named2.bippy(1)(b, q0) +Named2.bippy(1)(q0, c) +Named2.bippy(1)(c, b) +Named2.bippy(1)(b, c) +Named2.bippy(1)(q0, c) +Named2.bippy(2)(b, c) +Named2.bippy(1)(q0, c) +Named2.bippy(5)(b, c) +Named2.dingus(100)(b, dong) +Named2.bippy(1)(q0, q1) +Named2.hello(100)(!!, !!) diff --git a/test/files/run/t6731.scala b/test/files/run/t6731.scala new file mode 100644 index 0000000000..89d212e91e --- /dev/null +++ b/test/files/run/t6731.scala @@ -0,0 +1,143 @@ +import scala.language.dynamics +import scala.reflect.{ ClassTag, classTag } + +object Util { + def show[T](x: T): T = { println(x) ; x } + def mkArgs(xs: Any*) = xs map { case ((k, v)) => k + "=" + v ; case x => "" + x } mkString ("(", ", ", ")") +} +import Util._ + +abstract class MonoDynamic extends Dynamic { + def selectDynamic(name: String): String = show(this + "." + name) + def applyDynamic(name: String)(args: Any*): String = show(this + "." + name + mkArgs(args: _*)) + def applyDynamicNamed(name: String)(args: (String, Any)*): String = show(this + "." + name + mkArgs(args: _*)) + + override def toString = this.getClass.getName split '.' last +} + +object Mono extends MonoDynamic { + def f(s: String): String = s + + def f1 = this.bar() + def f2 = this.bar + def f3 = f(this.bar()) + def f4 = f(this.bar) + def f5 = f(f(f(f(f(f(this.bar)))))) + f(f(f(f(f(f(this.baz)))))) + def f6 = f(f(f(f(f(f(this.bar(bippy = 1, boppy = 2))))))) + f(f(f(f(f(f(this.baz)))))) +} + +object Poly extends Dynamic { + def selectDynamic[T: ClassTag](name: String): String = show(s"$this.$name[${classTag[T]}]") + def applyDynamic[T: ClassTag](name: String)(args: Any*): String = show(args.mkString(s"$this.$name[${classTag[T]}](", ", ", ")")) + + def f(s: String): String = s + + def f1 = this.bar + def f2 = this.bar[Int] + def f3 = this.bar() + def f4 = this.bar[Int]() + def f5 = this.bar[Int](1, 2, 3) + + def f6 = f(f(this.bar)) + def f7 = f(f(this.bar[Int])) + def f8 = f(f(this.bar())) + def f9 = f(f(this.bar[Int]())) + def f10 = f(f(this.bar[Int](1, 2, 3))) + + override def toString = "Poly" +} + +object Updating extends Dynamic { + def selectDynamic(name: String): String = show(s"$this.$name") + def updateDynamic(name: String)(value: Any): String = show(s"$this.$name = $value") + + def f1 = this.bar + def f2 = this.bar = "b" + + override def toString = "Updating" +} + +object Nest1 extends Dynamic { + def applyDynamic(name: String)(args: Any*): Nest2.type = Nest2 + + object Nest2 extends Dynamic { + def applyDynamicNamed(name: String)(args: (String, Any)*): Nest3.type = Nest3 + + object Nest3 extends MonoDynamic { + + } + } + + def f1 = Nest1.bip().bop(foo = "bar").bippy(1, 2, 3) + def f2 = Nest1.bip("abc").bop(foo = 5).bippy +} + +object Named extends Dynamic { + def applyDynamic(name: String)(args: Any*): Named.type = { + show(this + "." + name + mkArgs(args: _*)) + this + } + def applyDynamicNamed(name: String)(args: (String, Any)*): Named.type = { + show(this + "." + name + mkArgs(args: _*)) + this + } + + def f1 = this.bippy(a = 1, b = 2).boppy(c = 3, d = 4)()()(e = 5, f = 6) + override def toString = "Named" +} + +object Named2 extends Dynamic { + def applyDynamic(name: String)(a: Any)(b: Any = "b", c: Any = "c"): Named2.type = { + show(this + "." + name + mkArgs(a) + mkArgs(b, c)) + this + } + def applyDynamicNamed(name: String)(a: (String, Any))(b: (String, Any), c: (String, Any)): Named2.type = { + show(this + "." + name + mkArgs(a) + mkArgs(b, c)) + this + } + + def f1 = this.bippy(1)(b = "q0") + def f2 = this.bippy(1)("q0") + def f3 = this.bippy(1)(c = "q0") + def f4 = this.bippy(1)("q0") + def f5 = this.bippy(1)(c = "b", b = "c") + def f6 = this.bippy(1)("b", "c") + def f7 = this.bippy(1)(b = "q0").bippy(2)() + def f8 = this.bippy(1)("q0").bippy(5)(c = "c").dingus(100)(c = "dong") + def f9 = this.bippy(1)(b = "q0", c = "q1").hello(100)("!!", "!!") + + override def toString = "Named2" +} + + +object Test { + def main(args: Array[String]): Unit = { + { + import Mono._ + f1 ; f2 ; f3 ; f4 ; f5 + f6 + } + { + import Poly._ + f1 ; f2 ; f3 ; f4 ; f5 + f6 ; f7 ; f8 ; f9 ; f10 + } + { + import Updating._ + f1 ; f2 + } + { + import Nest1._ + f1 ; f2 + } + { + import Named._ + f1 + } + { + import Named2._ + f1 ; f2 ; f3 ; f4 ; f5 + f6 ; f7 ; f8 ; f9 + } + } +} |