Skip to content
This repository was archived by the owner on Sep 1, 2020. It is now read-only.

Commit 816cecf

Browse files
paulpjsuereth
authored andcommitted
More fix for invalid companions.
Eliminated InvalidCompanions exception entirely. Anyone's guess why we unholstered this exception every time someone calls "isCodefinedWith" rather than when symbols are created. I moved the check into Namers, where it can be done once and with sufficient finesse not to crash so much. With this patch in place, "playbench" can be built with java7.
1 parent e26104d commit 816cecf

File tree

7 files changed

+67
-47
lines changed

7 files changed

+67
-47
lines changed

src/compiler/scala/tools/nsc/typechecker/Infer.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -923,10 +923,13 @@ trait Infer {
923923
/** Is sym1 (or its companion class in case it is a module) a subclass of
924924
* sym2 (or its companion class in case it is a module)?
925925
*/
926-
def isProperSubClassOrObject(sym1: Symbol, sym2: Symbol): Boolean =
927-
sym1 != sym2 && sym1 != NoSymbol && (sym1 isSubClass sym2) ||
928-
sym1.isModuleClass && isProperSubClassOrObject(sym1.linkedClassOfClass, sym2) ||
929-
sym2.isModuleClass && isProperSubClassOrObject(sym1, sym2.linkedClassOfClass)
926+
def isProperSubClassOrObject(sym1: Symbol, sym2: Symbol): Boolean = (
927+
(sym1 != sym2) && (sym1 != NoSymbol) && (
928+
(sym1 isSubClass sym2)
929+
|| (sym1.isModuleClass && isProperSubClassOrObject(sym1.linkedClassOfClass, sym2))
930+
|| (sym2.isModuleClass && isProperSubClassOrObject(sym1, sym2.linkedClassOfClass))
931+
)
932+
)
930933

931934
/** is symbol `sym1` defined in a proper subclass of symbol `sym2`?
932935
*/

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -359,10 +359,39 @@ trait Namers extends MethodSynthesis {
359359
}
360360
}
361361

362+
/** Given a ClassDef or ModuleDef, verifies there isn't a companion which
363+
* has been defined in a separate file.
364+
*/
365+
private def validateCompanionDefs(tree: ImplDef) {
366+
val sym = tree.symbol
367+
if (sym eq NoSymbol) return
368+
369+
val ctx = if (context.owner.isPackageObjectClass) context.outer else context
370+
val module = if (sym.isModule) sym else ctx.scope lookup tree.name.toTermName
371+
val clazz = if (sym.isClass) sym else ctx.scope lookup tree.name.toTypeName
372+
val fails = (
373+
module.isModule
374+
&& clazz.isClass
375+
&& !module.isSynthetic
376+
&& !clazz.isSynthetic
377+
&& (clazz.sourceFile ne null)
378+
&& (module.sourceFile ne null)
379+
&& !(module isCoDefinedWith clazz)
380+
)
381+
if (fails) {
382+
context.unit.error(tree.pos, (
383+
s"Companions '$clazz' and '$module' must be defined in same file:\n"
384+
+ s" Found in ${clazz.sourceFile.canonicalPath} and ${module.sourceFile.canonicalPath}")
385+
)
386+
}
387+
}
388+
362389
def enterModuleDef(tree: ModuleDef) = {
363390
val sym = enterModuleSymbol(tree)
364391
sym.moduleClass setInfo namerOf(sym).moduleClassTypeCompleter(tree)
365392
sym setInfo completerOf(tree)
393+
validateCompanionDefs(tree)
394+
sym
366395
}
367396

368397
/** Enter a module symbol. The tree parameter can be either
@@ -635,6 +664,7 @@ trait Namers extends MethodSynthesis {
635664
}
636665
else context.unit.error(tree.pos, "implicit classes must accept exactly one primary constructor parameter")
637666
}
667+
validateCompanionDefs(tree)
638668
}
639669

640670
// this logic is needed in case typer was interrupted half
@@ -699,7 +729,7 @@ trait Namers extends MethodSynthesis {
699729
// }
700730
}
701731

702-
def moduleClassTypeCompleter(tree: Tree) = {
732+
def moduleClassTypeCompleter(tree: ModuleDef) = {
703733
mkTypeCompleter(tree) { sym =>
704734
val moduleSymbol = tree.symbol
705735
assert(moduleSymbol.moduleClass == sym, moduleSymbol.moduleClass)
@@ -1545,18 +1575,11 @@ trait Namers extends MethodSynthesis {
15451575
* call this method?
15461576
*/
15471577
def companionSymbolOf(original: Symbol, ctx: Context): Symbol = {
1548-
try {
1549-
original.companionSymbol orElse {
1550-
ctx.lookup(original.name.companionName, original.owner).suchThat(sym =>
1551-
(original.isTerm || sym.hasModuleFlag) &&
1552-
(sym isCoDefinedWith original)
1553-
)
1554-
}
1555-
}
1556-
catch {
1557-
case e: InvalidCompanions =>
1558-
ctx.unit.error(original.pos, e.getMessage)
1559-
NoSymbol
1578+
original.companionSymbol orElse {
1579+
ctx.lookup(original.name.companionName, original.owner).suchThat(sym =>
1580+
(original.isTerm || sym.hasModuleFlag) &&
1581+
(sym isCoDefinedWith original)
1582+
)
15601583
}
15611584
}
15621585
}

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,26 +1790,16 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
17901790
} else owner.enclosingTopLevelClass
17911791

17921792
/** Is this symbol defined in the same scope and compilation unit as `that` symbol? */
1793-
def isCoDefinedWith(that: Symbol) = {
1794-
(this.rawInfo ne NoType) &&
1795-
(this.effectiveOwner == that.effectiveOwner) && {
1796-
!this.effectiveOwner.isPackageClass ||
1797-
(this.sourceFile eq null) ||
1798-
(that.sourceFile eq null) ||
1799-
(this.sourceFile == that.sourceFile) || {
1800-
// recognize companion object in separate file and fail, else compilation
1801-
// appears to succeed but highly opaque errors come later: see bug #1286
1802-
if (this.sourceFile.path != that.sourceFile.path) {
1803-
// The cheaper check can be wrong: do the expensive normalization
1804-
// before failing.
1805-
if (this.sourceFile.canonicalPath != that.sourceFile.canonicalPath)
1806-
throw InvalidCompanions(this, that)
1807-
}
1808-
1809-
false
1810-
}
1811-
}
1812-
}
1793+
def isCoDefinedWith(that: Symbol) = (
1794+
(this.rawInfo ne NoType)
1795+
&& (this.effectiveOwner == that.effectiveOwner)
1796+
&& ( !this.effectiveOwner.isPackageClass
1797+
|| (this.sourceFile eq null)
1798+
|| (that.sourceFile eq null)
1799+
|| (this.sourceFile.path == that.sourceFile.path) // Cheap possibly wrong check, then expensive normalization
1800+
|| (this.sourceFile.canonicalPath == that.sourceFile.canonicalPath)
1801+
)
1802+
)
18131803

18141804
/** The internal representation of classes and objects:
18151805
*
@@ -3202,13 +3192,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
32023192
if (settings.debug.value) printStackTrace()
32033193
}
32043194

3205-
case class InvalidCompanions(sym1: Symbol, sym2: Symbol) extends Throwable({
3206-
"Companions '" + sym1 + "' and '" + sym2 + "' must be defined in same file:\n" +
3207-
" Found in " + sym1.sourceFile.canonicalPath + " and " + sym2.sourceFile.canonicalPath
3208-
}) {
3209-
override def toString = getMessage
3210-
}
3211-
32123195
/** A class for type histories */
32133196
private sealed case class TypeHistory(var validFrom: Period, info: Type, prev: TypeHistory) {
32143197
assert((prev eq null) || phaseId(validFrom) > phaseId(prev.validFrom), this)

test/files/neg/t5031.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Id.scala:3: error: Companions 'class Test' and 'object Test' must be defined in same file:
1+
package.scala:2: error: Companions 'class Test' and 'object Test' must be defined in same file:
22
Found in t5031/package.scala and t5031/Id.scala
3-
object Test
4-
^
3+
class Test
4+
^
55
one error found

test/files/neg/t5031b.check

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
b.scala:3: error: Companions 'class Bippy' and 'object Bippy' must be defined in same file:
2+
Found in t5031b/a.scala and t5031b/b.scala
3+
object Bippy
4+
^
5+
one error found

test/files/neg/t5031b/a.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package foo
2+
3+
class Bippy

test/files/neg/t5031b/b.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package foo
2+
3+
object Bippy

0 commit comments

Comments
 (0)