Skip to content

Ycheck that methods defined in ClassInfo exist in tree. #735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Aug 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c76d63d
Make trees have predictable hash codes.
DarkDimius Jun 23, 2015
d898560
SpecializeNames: Duplicate scalac behaviour, sort tparams
DarkDimius Jun 25, 2015
9185428
Fix ClassCastException in patmat when using Product1.
DarkDimius Jun 25, 2015
ef536f0
Enable 61 tests that succeed.
DarkDimius Jun 25, 2015
04b1253
Make symbols have predictable hash codes.
DarkDimius Jun 30, 2015
91772a6
Patmat: fix sub patterns of Product-1's
DarkDimius Jun 30, 2015
5481589
Upgrade shared backend.
DarkDimius Jul 13, 2015
18a034c
Update version of shared backend.
DarkDimius Jul 14, 2015
843ec4f
Remove warning from .check file that is not emitted by Dotty
DarkDimius Jul 14, 2015
10ea712
Fixes to name comparison
DarkDimius Jul 20, 2015
9bc9578
Address review comments of #693
DarkDimius Jul 20, 2015
a1087a4
Compile dotty.*, not only dotty.tools.
DarkDimius Jul 23, 2015
5766b99
Add Symdenotation. isValueClassConvertMethod
DarkDimius Jul 23, 2015
31010b6
YCheck that all methods are defined in tree
DarkDimius Jul 23, 2015
9d609fb
YCheck that methods, fields and variables have names that are valid o…
DarkDimius Jul 23, 2015
868591c
Lazy initialisers names do not get mangled.
DarkDimius Jul 24, 2015
0261ed0
Workaround an issue in mixin.
DarkDimius Jul 24, 2015
1847038
Survive Nodenotation in computeDenot
odersky Jul 27, 2015
f018c38
Fix enumeration of all members of the class
DarkDimius Jul 28, 2015
1512957
Fix lazy vals in mixin
DarkDimius Jul 28, 2015
a43d39a
Workaround #742 and add a test for it.
DarkDimius Jul 28, 2015
e147fbe
Add a test for #743 to pending.
DarkDimius Jul 28, 2015
7cfa2e1
Fix #744
DarkDimius Jul 28, 2015
3377de5
Fix #745, memoise should be able to get type of field from setter.
DarkDimius Jul 28, 2015
d528035
Applied review comments
odersky Aug 4, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ object DottyBuild extends Build {
resolvers += Resolver.sonatypeRepo("releases"),

// get libraries onboard
partestDeps := Seq("me.d-d" % "scala-compiler" % "2.11.5-20150619-173733-3bcd390afa",
partestDeps := Seq("me.d-d" % "scala-compiler" % "2.11.5-20150714-145300-2ad68448c5",
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.scala-lang" % "scala-library" % scalaVersion.value % "test"),
libraryDependencies ++= partestDeps.value,
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/backend/jvm/DottyBackendInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
def decls: List[Symbol] = tp.decls.map(_.symbol).toList

def members: List[Symbol] =
tp.memberDenots(takeAllFilter, (name, buf) => buf ++= member(name).alternatives).map(_.symbol).toList
tp.memberDenots(takeAllFilter, (name, buf) => buf ++= tp.member(name).alternatives).map(_.symbol).toList

def typeSymbol: Symbol = tp.widenDealias.typeSymbol

Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ object Trees {

override def toText(printer: Printer) = printer.toText(this)

override def hashCode(): Int = System.identityHashCode(this)
override def hashCode(): Int = uniqueId // for debugging; was: System.identityHashCode(this)
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
}

Expand Down
37 changes: 19 additions & 18 deletions src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -177,25 +177,26 @@ object Contexts {
/** The new implicit references that are introduced by this scope */
private var implicitsCache: ContextualImplicits = null
def implicits: ContextualImplicits = {
if (implicitsCache == null )
implicitsCache = {
val implicitRefs: List[TermRef] =
if (isClassDefContext)
try owner.thisType.implicitMembers
catch {
case ex: CyclicReference => Nil
}
else if (isImportContext) importInfo.importedImplicits
else if (isNonEmptyScopeContext) scope.implicitDecls
else Nil
val outerImplicits =
if (isImportContext && importInfo.hiddenRoot.exists)
outer.implicits exclude importInfo.hiddenRoot
else
outer.implicits
if (implicitRefs.isEmpty) outerImplicits
else new ContextualImplicits(implicitRefs, outerImplicits)(this)
if (implicitsCache == null ) {
val outerImplicits =
if (isImportContext && importInfo.hiddenRoot.exists)
outer.implicits exclude importInfo.hiddenRoot
else
outer.implicits
try
implicitsCache = {
val implicitRefs: List[TermRef] =
if (isClassDefContext) owner.thisType.implicitMembers
else if (isImportContext) importInfo.importedImplicits
else if (isNonEmptyScopeContext) scope.implicitDecls
else Nil
if (implicitRefs.isEmpty) outerImplicits
else new ContextualImplicits(implicitRefs, outerImplicits)(this)
}
catch {
case ex: CyclicReference => implicitsCache = outerImplicits
}
}
implicitsCache
}

Expand Down
9 changes: 6 additions & 3 deletions src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ object NameOps {
case nme.clone_ => nme.clone_
}

def specializedFor(returnType: Types.Type, args: List[Types.Type])(implicit ctx: Context): name.ThisName = {
def specializedFor(classTargs: List[Types.Type], classTargsNames: List[Name], methodTargs: List[Types.Type], methodTarsNames: List[Name])(implicit ctx: Context): name.ThisName = {

def typeToTag(tp: Types.Type): Name = {
tp.classSymbol match {
Expand All @@ -253,9 +253,12 @@ object NameOps {
}
}

val methodTags: Seq[Name] = (methodTargs zip methodTarsNames).sortBy(_._2).map(x => typeToTag(x._1))
val classTags: Seq[Name] = (classTargs zip classTargsNames).sortBy(_._2).map(x => typeToTag(x._1))

name.fromName(name ++ nme.specializedTypeNames.prefix ++
args.map(typeToTag).foldRight(typeToTag(returnType))(_ ++ _) ++
nme.specializedTypeNames.suffix)
methodTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.separator ++
classTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.suffix)
}

/** If name length exceeds allowable limit, replace part of it by hash */
Expand Down
21 changes: 21 additions & 0 deletions src/dotty/tools/dotc/core/Names.scala
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,25 @@ object Names {
StringBuilder.newBuilder.mapResult(s => from.fromChars(s.toCharArray, 0, s.length))
def apply(): Builder[Char, Name] = termNameBuilder
}

implicit val NameOrdering: Ordering[Name] = new Ordering[Name] {
def compare(x: Name, y: Name): Int = {
if (x.isTermName && y.isTypeName) 1
else if (x.isTypeName && y.isTermName) -1
else if (x eq y) 0
else {
val until = x.length min y.length
var i = 0

while (i < until && x(i) == y(i)) i = i + 1

if (i < until) {
if (x(i) < y(i)) -1
else /*(x(i) > y(i))*/ 1
} else {
x.length - y.length
}
}
}
}
}
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,8 @@ object StdNames {
final val Void: N = "V"
final val Object: N = "L"

final val prefix: N = "$mc"
final val prefix: N = "$m"
final val separator: N = "c"
final val suffix: N = "$sp"
}

Expand Down
8 changes: 8 additions & 0 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,14 @@ object SymDenotations {
name.toTermName == nme.COMPANION_CLASS_METHOD ||
name.toTermName == nme.COMPANION_MODULE_METHOD

/** Is this a syntetic method that represents conversions between representations of a value class
* These methods are generated in ExtensionMethods
* and used in ElimErasedValueType.
*/
final def isValueClassConvertMethod(implicit ctx: Context) =
name.toTermName == nme.U2EVT ||
name.toTermName == nme.EVT2U

/** Is symbol a primitive value class? */
def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains symbol

Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ object Symbols {
def showKind(implicit ctx: Context): String = ctx.kindString(this)
def showName(implicit ctx: Context): String = ctx.nameString(this)
def showFullName(implicit ctx: Context): String = ctx.fullNameString(this)

override def hashCode() = id // for debugging.
}

type TermSymbol = Symbol { type ThisName = TermName }
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1296,7 +1296,7 @@ object Types {
case d: SymDenotation =>
if (this.isInstanceOf[WithFixedSym]) d.current
else if (d.validFor.runId == ctx.runId || ctx.stillValid(d))
if (prefix.isTightPrefix(d.owner) || d.isConstructor) d.current
if (d.exists && prefix.isTightPrefix(d.owner) || d.isConstructor) d.current
else recomputeMember(d) // symbol could have been overridden, recompute membership
else {
val newd = loadDenot
Expand Down
3 changes: 1 addition & 2 deletions src/dotty/tools/dotc/transform/ElimErasedValueType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,11 @@ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer {

override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = {
val Apply(fun, args) = tree
val name = fun.symbol.name

// The casts to and from ErasedValueType are no longer needed once ErasedValueType
// has been eliminated.
val t =
if ((name eq nme.U2EVT) || (name eq nme.EVT2U))
if (fun.symbol.isValueClassConvertMethod)
args.head
else
tree
Expand Down
7 changes: 6 additions & 1 deletion src/dotty/tools/dotc/transform/FunctionalInterfaces.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ class FunctionalInterfaces extends MiniPhaseTransform {
val m = tree.meth.tpe.widen.asInstanceOf[MethodType]

if (shouldSpecialize(m)) {
val interfaceName = (functionName ++ m.paramTypes.length.toString).specializedFor(m.resultType, m.paramTypes)
val functionSymbol = tree.tpe.widenDealias.classSymbol
val names = ctx.atPhase(ctx.erasurePhase) {
implicit ctx => functionSymbol.typeParams.map(_.name)
}
val interfaceName = (functionName ++ m.paramTypes.length.toString).specializedFor(m.paramTypes ::: m.resultType :: Nil, names, Nil, Nil)

// symbols loaded from classpath aren't defined in periods earlier than when they where loaded
val interface = ctx.withPhase(ctx.typerPhase).getClassIfDefined(functionPackage ++ interfaceName)
if (interface.exists) {
Expand Down
22 changes: 14 additions & 8 deletions src/dotty/tools/dotc/transform/Memoize.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,20 @@ import Decorators._
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
val sym = tree.symbol

def newField = ctx.newSymbol(
owner = ctx.owner,
name = sym.name.asTermName.fieldName,
flags = Private | (if (sym is Stable) EmptyFlags else Mutable),
info = sym.info.resultType,
coord = tree.pos)
.withAnnotationsCarrying(sym, defn.FieldMetaAnnot)
.enteredAfter(thisTransform)
def newField = {
val fieldType =
if (sym.isGetter) sym.info.resultType
else /*sym.isSetter*/ sym.info.firstParamTypes.head

ctx.newSymbol(
owner = ctx.owner,
name = sym.name.asTermName.fieldName,
flags = Private | (if (sym is Stable) EmptyFlags else Mutable),
info = fieldType,
coord = tree.pos)
.withAnnotationsCarrying(sym, defn.FieldMetaAnnot)
.enteredAfter(thisTransform)
}

/** Can be used to filter annotations on getters and setters; not used yet */
def keepAnnotations(denot: SymDenotation, meta: ClassSymbol) = {
Expand Down
8 changes: 4 additions & 4 deletions src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure])

override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation =
if (sym.is(Accessor, butNot = Deferred) && sym.owner.is(Trait))
if (sym.is(Accessor, butNot = Deferred | Lazy) && sym.owner.is(Trait))
sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred).ensureNotPrivate
else if (sym.isConstructor && sym.owner.is(Trait))
sym.copySymDenotation(
Expand All @@ -108,8 +108,8 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
sym

private def initializer(sym: Symbol)(implicit ctx: Context): TermSymbol = {
val initName = InitializerName(sym.name.asTermName)
sym.owner.info.decl(initName).symbol
val initName = if(!sym.is(Lazy)) InitializerName(sym.name.asTermName) else sym.name.asTermName
sym.owner.info.decl(initName).suchThat(_.is(Lazy) == sym.is(Lazy)).symbol
.orElse(
ctx.newSymbol(
sym.owner,
Expand Down Expand Up @@ -229,7 +229,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>

def setters(mixin: ClassSymbol): List[Tree] =
for (setter <- mixin.info.decls.filter(setr => setr.isSetter && !wasDeferred(setr)).toList)
yield DefDef(implementation(setter.asTerm), unitLiteral.withPos(cls.pos))
yield transformFollowing(DefDef(implementation(setter.asTerm), unitLiteral.withPos(cls.pos)))

cpy.Template(impl)(
constr =
Expand Down
8 changes: 6 additions & 2 deletions src/dotty/tools/dotc/transform/PatternMatcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,11 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans

def emitVars = storedBinders.nonEmpty

private lazy val (stored, substed) = (subPatBinders, subPatRefs).zipped.partition{ case (sym, _) => storedBinders(sym) }
lazy val storedSubsted = (subPatBinders, subPatRefs).zipped.partition{ case (sym, _) => storedBinders(sym) }

def stored = storedSubsted._1

def substed = storedSubsted._2

// dd: this didn't yet trigger error. But I believe it would. if this causes double denition of symbol error this can be replaced with NoRebindings
protected lazy val introducedRebindings: Rebindings = if (!emitVars) Rebindings(subPatBinders, subPatRefs)
Expand Down Expand Up @@ -1443,7 +1447,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
// require (nbSubPats > 0 && (!lastIsStar || isSeq))
protected def subPatRefs(binder: Symbol): List[Tree] = {
val refs = if (totalArity > 0 && isSeq) subPatRefsSeq(binder)
else if (totalArity > 1 && !isSeq) productElemsToN(binder, totalArity)
else if (binder.info.member(nme._1).exists && !isSeq) productElemsToN(binder, totalArity)
else ref(binder):: Nil
refs
}
Expand Down
20 changes: 20 additions & 0 deletions src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dotty.tools.dotc
package transform

import TreeTransforms._
import core.Names.Name
import core.DenotTransformers._
import core.Denotations._
import core.SymDenotations._
Expand Down Expand Up @@ -42,6 +43,12 @@ class TreeChecker extends Phase with SymTransformer {
private val seenClasses = collection.mutable.HashMap[String, Symbol]()
private val seenModuleVals = collection.mutable.HashMap[String, Symbol]()

def isValidJVMName(name: Name) =
!name.exists(c => c == '.' || c == ';' || c =='[' || c == '/')

def isValidJVMMethodName(name: Name) =
!name.exists(c => c == '.' || c == ';' || c =='[' || c == '/' || c == '<' || c == '>')

def printError(str: String)(implicit ctx: Context) = {
ctx.println(Console.RED + "[error] " + Console.WHITE + str)
}
Expand Down Expand Up @@ -130,6 +137,7 @@ class TreeChecker extends Phase with SymTransformer {
def withDefinedSym[T](tree: untpd.Tree)(op: => T)(implicit ctx: Context): T = tree match {
case tree: DefTree =>
val sym = tree.symbol
assert(isValidJVMName(sym.name), s"${sym.fullName} name is invalid on jvm")
everDefinedSyms.get(sym) match {
case Some(t) =>
if (t ne tree)
Expand Down Expand Up @@ -256,12 +264,24 @@ class TreeChecker extends Phase with SymTransformer {
assert(cls.primaryConstructor == constr.symbol, i"mismatch, primary constructor ${cls.primaryConstructor}, in tree = ${constr.symbol}")
checkOwner(impl)
checkOwner(impl.constr)

def isNonMagicalMethod(x: Symbol) =
x.is(Method) &&
!x.isCompanionMethod &&
!x.isValueClassConvertMethod &&
x != defn.newRefArrayMethod

val symbolsNotDefined = cls.classInfo.decls.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol

assert(symbolsNotDefined.isEmpty, i" $cls tree does not define methods: $symbolsNotDefined")

super.typedClassDef(cdef, cls)
}

override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) =
withDefinedSyms(ddef.tparams) {
withDefinedSymss(ddef.vparamss) {
if (!sym.isClassConstructor) assert(isValidJVMMethodName(sym.name), s"${sym.fullName} name is invalid on jvm")
super.typedDefDef(ddef, sym)
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/dotc/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class tests extends CompilerTest {

@Test def run_all = runFiles(runDir)

@Test def dotty = compileDir(dottyDir, "tools", "-deep" :: "-Ycheck-reentrant" :: allowDeepSubtypes ++ twice) // note the -deep argument
@Test def dotty = compileDir(dottyDir, ".", "-deep" :: "-Ycheck-reentrant" :: allowDeepSubtypes) // note the -deep argument


@Test def dotc_ast = compileDir(dotcDir, "ast")
Expand Down
6 changes: 6 additions & 0 deletions tests/pending/pos/i743.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object NonLocalReturn {
def foo(a: List[Int]): Int = {
a.foreach(x => return x)
0
}
}
7 changes: 7 additions & 0 deletions tests/pending/run/StackMap.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
object Test {
var implicitsCache = null

def main(args: Array[String]): Unit = {
implicitsCache = try{null} catch { case ex: Exception => null }
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
exceptions-2.scala:267: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
try { 1 } catch { case e: java.io.IOException => () }
^
nested1:
Innermost finally
Outermost finally
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions tests/run/i744.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
8 changes: 8 additions & 0 deletions tests/run/i744.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
trait A{
private var s = 1
def getS = s
}

object Test extends A {
def main(args: Array[String]): Unit = println(getS)
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion tests/run/value-class-extractor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object NonNullChar {
@inline final val None = new NonNullChar(0.toChar)
}

final class SomeProduct /*extends Product3[String, Int, List[String]]*/ {
final class SomeProduct extends Product3[String, Int, List[String]] {
def canEqual(x: Any) = x.isInstanceOf[SomeProduct]
def _1 = "abc"
def _2 = 5
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.