Skip to content

Commit 22d315d

Browse files
committed
Merge remote-tracking branch 'origin/2.10.x' into merge-210
* origin/2.10.x: Fix for paramaccessor alias regression. Expanded bytecode testing code. SI-5675 Discard duplicate feature warnings at a position accommodates pull request feedback term and type reftrees are now reified uniformly SI-6591 Reify and path-dependent types SI-7096 SubstSymMap copies trees before modifying their symbols SI-6961 no structural sharing in list serialization SI-6187 Make partial functions re-typable [backport] SI-6478 Fixing JavaTokenParser ident SI-7100 Fixed infinite recursion in duplicators SI-6146 More accurate prefixes for sealed subtypes. SI-5082 Cycle avoidance between case companions SI-6113 typeOf now works for type lambdas SI-5824 Fix crashes in reify with _* SI-7026: parseTree should never return a typed one SI-7070 Turn restriction on companions in pkg objs into warning Conflicts: src/compiler/scala/reflect/reify/codegen/GenSymbols.scala src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala src/compiler/scala/tools/nsc/typechecker/Typers.scala src/compiler/scala/tools/reflect/ToolBoxFactory.scala src/library/scala/collection/immutable/List.scala src/reflect/scala/reflect/internal/TreeInfo.scala src/reflect/scala/reflect/internal/Types.scala src/reflect/scala/reflect/internal/settings/MutableSettings.scala src/reflect/scala/reflect/runtime/Settings.scala test/files/buildmanager/t2650_1/t2650_1.check test/files/buildmanager/t2657/t2657.check test/files/neg/t3234.check test/files/run/idempotency-this.check test/files/run/macro-typecheck-macrosdisabled2.check test/files/run/showraw_tree.check test/files/run/showraw_tree_ids.check test/files/run/showraw_tree_kinds.check test/files/run/showraw_tree_types_ids.check test/files/run/showraw_tree_types_typed.check test/files/run/showraw_tree_types_untyped.check test/files/run/showraw_tree_ultimate.check test/files/run/t2886.check test/files/run/t5225_2.check test/files/run/t5374.check test/files/run/t5374.scala test/files/run/t6329_repl.check test/files/run/toolbox_typecheck_macrosdisabled2.check
2 parents ccf6bc7 + db5919a commit 22d315d

File tree

108 files changed

+1166
-350
lines changed

Some content is hidden

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

108 files changed

+1166
-350
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))

src/compiler/scala/tools/nsc/doc/ScaladocGlobal.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import typechecker.Analyzer
1212
import scala.reflect.internal.util.BatchSourceFile
1313

1414
trait ScaladocAnalyzer extends Analyzer {
15-
val global : ScaladocGlobal
15+
val global : Global // generally, a ScaladocGlobal
1616
import global._
1717

1818
override def newTyper(context: Context): ScaladocTyper = new ScaladocTyper(context)

src/compiler/scala/tools/nsc/interactive/CompilerControl.scala

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,12 @@ trait CompilerControl { self: Global =>
256256
}
257257

258258
/** Returns parse tree for source `source`. No symbols are entered. Syntax errors are reported.
259-
* Can be called asynchronously from presentation compiler.
259+
*
260+
* This method is thread-safe and as such can safely run outside of the presentation
261+
* compiler thread.
260262
*/
261-
def parseTree(source: SourceFile): Tree = ask { () =>
262-
getUnit(source) match {
263-
case Some(unit) if unit.status >= JustParsed =>
264-
unit.body
265-
case _ =>
266-
new UnitParser(new CompilationUnit(source)).parse()
267-
}
263+
def parseTree(source: SourceFile): Tree = {
264+
new UnitParser(new CompilationUnit(source)).parse()
268265
}
269266

270267
/** Asks for a computation to be done quickly on the presentation compiler thread */

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,10 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
221221
/** Called from parser, which signals hereby that a method definition has been parsed.
222222
*/
223223
override def signalParseProgress(pos: Position) {
224-
checkForMoreWork(pos)
224+
// We only want to be interruptible when running on the PC thread.
225+
if(onCompilerThread) {
226+
checkForMoreWork(pos)
227+
}
225228
}
226229

227230
/** Called from typechecker, which signals hereby that a node has been completely typechecked.
@@ -408,7 +411,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
408411
*/
409412
@elidable(elidable.WARNING)
410413
override def assertCorrectThread() {
411-
assert(initializing || (Thread.currentThread() eq compileRunner),
414+
assert(initializing || onCompilerThread,
412415
"Race condition detected: You are running a presentation compiler method outside the PC thread.[phase: %s]".format(globalPhase) +
413416
" Please file a ticket with the current stack trace at https://www.assembla.com/spaces/scala-ide/support/tickets")
414417
}

0 commit comments

Comments
 (0)