Skip to content

Commit 8a46441

Browse files
committed
Merge pull request scala#2112 from paulp/pr/merge-210x
merge 2.10.x into master
2 parents ce32c1a + 22d315d commit 8a46441

File tree

216 files changed

+3187
-912
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

216 files changed

+3187
-912
lines changed

src/compiler/scala/reflect/reify/codegen/GenSymbols.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package scala.reflect.reify
22
package codegen
33

4+
import scala.reflect.internal.Flags._
5+
46
trait GenSymbols {
57
self: Reifier =>
68

@@ -99,6 +101,33 @@ trait GenSymbols {
99101
reifyIntoSymtab(binding.symbol) { sym =>
100102
if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym + "(" + sym.accurateKindString + ")")
101103
val name = newTermName("" + nme.REIFY_FREE_PREFIX + sym.name + (if (sym.isType) nme.REIFY_FREE_THIS_SUFFIX else ""))
104+
// We need to note whether the free value being reified is stable or not to guide subsequent reflective compilation.
105+
// Here's why reflection compilation needs our help.
106+
//
107+
// When dealing with a tree, which contain free values, toolboxes extract those and wrap the entire tree in a Function
108+
// having parameters defined for every free values in the tree. For example, evaluating
109+
//
110+
// Ident(setTypeSignature(newFreeTerm("x", 2), <Int>))
111+
//
112+
// Will generate something like
113+
//
114+
// object wrapper {
115+
// def wrapper(x: () => Int) = {
116+
// x()
117+
// }
118+
// }
119+
//
120+
// Note that free values get transformed into, effectively, by-name parameters. This is done to make sure
121+
// that evaluation order is kept intact. And indeed, we cannot just evaluate all free values at once in order
122+
// to obtain arguments for wrapper.wrapper, because if some of the free values end up being unused during evaluation,
123+
// we might end up doing unnecessary calculations.
124+
//
125+
// So far, so good - we didn't need any flags at all. However, if the code being reified contains path-dependent types,
126+
// we're in trouble, because valid code like `free.T` ends up being transformed into `free.apply().T`, which won't compile.
127+
//
128+
// To overcome this glitch, we note whether a given free term is stable or not (because vars can also end up being free terms).
129+
// Then, if a free term is stable, we tell the compiler to treat `free.apply()` specially and assume that it's stable.
130+
if (!sym.isMutable) sym setFlag STABLE
102131
if (sym.isCapturedVariable) {
103132
assert(binding.isInstanceOf[Ident], showRaw(binding))
104133
val capturedBinding = referenceCapturedVariable(sym)

src/compiler/scala/reflect/reify/codegen/GenTrees.scala

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -155,29 +155,31 @@ trait GenTrees {
155155
else mirrorCall(nme.Ident, reify(name))
156156

157157
case Select(qual, name) =>
158-
if (sym == NoSymbol || sym.name == name)
159-
reifyProduct(tree)
160-
else
161-
reifyProduct(Select(qual, sym.name))
158+
if (qual.symbol != null && qual.symbol.isPackage) {
159+
mirrorBuildCall(nme.Ident, reify(sym))
160+
} else {
161+
val effectiveName = if (sym != null && sym != NoSymbol) sym.name else name
162+
reifyProduct(Select(qual, effectiveName))
163+
}
162164

163165
case _ =>
164166
throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
165167
}
166168
}
167169

168-
private def reifyBoundType(tree: Tree): Tree = {
170+
private def reifyBoundType(tree: RefTree): Tree = {
169171
val sym = tree.symbol
170172
val tpe = tree.tpe
171173

172-
def reifyBoundType(tree: Tree): Tree = {
174+
def reifyBoundType(tree: RefTree): Tree = {
173175
assert(tpe != null, "unexpected: bound type that doesn't have a tpe: " + showRaw(tree))
174176

175177
// if a symbol or a type of the scrutinee are local to reifee
176178
// (e.g. point to a locally declared class or to a path-dependent thingie that depends on a local variable)
177179
// then we can reify the scrutinee as a symless AST and that will definitely be hygienic
178180
// why? because then typechecking of a scrutinee doesn't depend on the environment external to the quasiquote
179181
// otherwise we need to reify the corresponding type
180-
if (sym.isLocalToReifee || tpe.isLocalToReifee)
182+
if (sym.isLocalToReifee || tpe.isLocalToReifee || treeInfo.isWildcardStarType(tree))
181183
reifyProduct(tree)
182184
else {
183185
if (reifyDebug) println("reifying bound type %s (underlying type is %s)".format(sym, tpe))
@@ -198,13 +200,19 @@ trait GenTrees {
198200
mirrorBuildCall(nme.TypeTree, spliced)
199201
}
200202
}
201-
else if (sym.isLocatable) {
202-
if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym))
203-
mirrorBuildCall(nme.Ident, reify(sym))
204-
}
205-
else {
206-
if (reifyDebug) println("tpe is not locatable: reify as TypeTree(%s)".format(tpe))
207-
mirrorBuildCall(nme.TypeTree, reify(tpe))
203+
else tree match {
204+
case Select(qual, name) if !qual.symbol.isPackage =>
205+
if (reifyDebug) println(s"reifying Select($qual, $name)")
206+
mirrorCall(nme.Select, reify(qual), reify(name))
207+
case SelectFromTypeTree(qual, name) =>
208+
if (reifyDebug) println(s"reifying SelectFromTypeTree($qual, $name)")
209+
mirrorCall(nme.SelectFromTypeTree, reify(qual), reify(name))
210+
case _ if sym.isLocatable =>
211+
if (reifyDebug) println(s"tpe is locatable: reify as Ident($sym)")
212+
mirrorBuildCall(nme.Ident, reify(sym))
213+
case _ =>
214+
if (reifyDebug) println(s"tpe is not locatable: reify as TypeTree($tpe)")
215+
mirrorBuildCall(nme.TypeTree, reify(tpe))
208216
}
209217
}
210218
}

src/compiler/scala/reflect/reify/codegen/GenTypes.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ trait GenTypes {
6969
def reificationIsConcrete: Boolean = state.reificationIsConcrete
7070

7171
def spliceType(tpe: Type): Tree = {
72-
val quantified = currentQuantified
73-
if (tpe.isSpliceable && !(quantified contains tpe.typeSymbol)) {
72+
if (tpe.isSpliceable && !(boundSymbolsInCallstack contains tpe.typeSymbol)) {
7473
if (reifyDebug) println("splicing " + tpe)
7574

7675
val tagFlavor = if (concrete) tpnme.TypeTag.toString else tpnme.WeakTypeTag.toString

src/compiler/scala/reflect/reify/phases/Reify.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ trait Reify extends GenSymbols
2626
finally currents = currents.tail
2727
}
2828
}
29-
def currentQuantified = flatCollect(reifyStack.currents)({ case ExistentialType(quantified, _) => quantified })
29+
def boundSymbolsInCallstack = flatCollect(reifyStack.currents) {
30+
case ExistentialType(quantified, _) => quantified
31+
case PolyType(typeParams, _) => typeParams
32+
}
3033
def current = reifyStack.currents.head
3134
def currents = reifyStack.currents
3235

src/compiler/scala/reflect/reify/phases/Reshape.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,24 +187,28 @@ trait Reshape {
187187
}
188188

189189
private def toPreTyperTypedOrAnnotated(tree: Tree): Tree = tree match {
190-
case ty @ Typed(expr1, tt @ TypeTree()) =>
190+
case ty @ Typed(expr1, tpt) =>
191191
if (reifyDebug) println("reify typed: " + tree)
192+
val original = tpt match {
193+
case tt @ TypeTree() => tt.original
194+
case tpt => tpt
195+
}
192196
val annotatedArg = {
193197
def loop(tree: Tree): Tree = tree match {
194198
case annotated1 @ Annotated(ann, annotated2 @ Annotated(_, _)) => loop(annotated2)
195199
case annotated1 @ Annotated(ann, arg) => arg
196200
case _ => EmptyTree
197201
}
198202

199-
loop(tt.original)
203+
loop(original)
200204
}
201205
if (annotatedArg != EmptyTree) {
202206
if (annotatedArg.isType) {
203207
if (reifyDebug) println("verdict: was an annotated type, reify as usual")
204208
ty
205209
} else {
206-
if (reifyDebug) println("verdict: was an annotated value, equivalent is " + tt.original)
207-
toPreTyperTypedOrAnnotated(tt.original)
210+
if (reifyDebug) println("verdict: was an annotated value, equivalent is " + original)
211+
toPreTyperTypedOrAnnotated(original)
208212
}
209213
} else {
210214
if (reifyDebug) println("verdict: wasn't annotated, reify as usual")

src/compiler/scala/reflect/reify/utils/Extractors.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,12 @@ trait Extractors {
263263
}
264264

265265
object BoundType {
266-
def unapply(tree: Tree): Option[Tree] = tree match {
267-
case Select(_, name) if name.isTypeName =>
266+
def unapply(tree: Tree): Option[RefTree] = tree match {
267+
case tree @ Select(_, name) if name.isTypeName =>
268268
Some(tree)
269-
case SelectFromTypeTree(_, name) if name.isTypeName =>
269+
case tree @ SelectFromTypeTree(_, _) =>
270270
Some(tree)
271-
case Ident(name) if name.isTypeName =>
271+
case tree @ Ident(name) if name.isTypeName =>
272272
Some(tree)
273273
case _ =>
274274
None

src/compiler/scala/tools/nsc/Global.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,13 +1107,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
11071107

11081108
/** Collects for certain classes of warnings during this run. */
11091109
class ConditionalWarning(what: String, option: Settings#BooleanSetting) {
1110-
val warnings = new mutable.ListBuffer[(Position, String)]
1110+
val warnings = mutable.LinkedHashMap[Position, String]()
11111111
def warn(pos: Position, msg: String) =
11121112
if (option.value) reporter.warning(pos, msg)
1113-
else warnings += ((pos, msg))
1113+
else if (!(warnings contains pos)) warnings += ((pos, msg))
11141114
def summarize() =
1115-
if (option.isDefault && warnings.nonEmpty)
1116-
reporter.warning(NoPosition, "there were %d %s warnings; re-run with %s for details".format(warnings.size, what, option.name))
1115+
if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings.value))
1116+
warning("there were %d %s warning(s); re-run with %s for details".format(warnings.size, what, option.name))
11171117
}
11181118

11191119
def newUnitParser(code: String) = new syntaxAnalyzer.UnitParser(newCompilationUnit(code))

0 commit comments

Comments
 (0)