aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala134
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala2
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala6
-rw-r--r--src/dotty/tools/dotc/core/transform/Erasure.scala4
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala7
-rw-r--r--src/dotty/tools/dotc/transform/InterceptedMethods.scala20
-rw-r--r--src/dotty/tools/dotc/transform/TypeTestsCasts.scala8
7 files changed, 92 insertions, 89 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 9497438f2..211d9e9cd 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -30,6 +30,12 @@ class Definitions {
private def newCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) =
ctx.newCompleteClassSymbol(owner, name, flags | Permanent, parents, decls).entered
+ private def newTopClassSymbol(name: TypeName, flags: FlagSet, parents: List[TypeRef]) = {
+ val cls = newCompleteClassSymbol(ScalaPackageClass, name, flags, parents)
+ ensureConstructor(cls, EmptyScope)
+ cls
+ }
+
private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
scope.enter(newSymbol(cls, name, flags | TypeParamCreationFlags, TypeBounds.empty))
@@ -74,7 +80,7 @@ class Definitions {
newPolyMethod(cls, name, 1, resultTypeFn, flags)
private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
- newPolyMethod(cls, name, 1, pt => MethodType(Nil, Nil, resultTypeFn(pt)), flags)
+ newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags)
private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[ClassSymbol] = {
val arr = new Array[ClassSymbol](arity + 1)
@@ -95,58 +101,69 @@ class Definitions {
lazy val JavaPackageVal = ctx.requiredPackage("java")
lazy val JavaLangPackageVal = ctx.requiredPackage("java.lang")
- lazy val ObjectClass = ctx.requiredClass("java.lang.Object")
- lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType)
-
- lazy val Object_## = newMethod(ObjectClass, nme.HASHHASH, ExprType(IntType), Final)
- lazy val Object_== = newMethod(ObjectClass, nme.EQ, methOfAny(BooleanType), Final)
- lazy val Object_!= = newMethod(ObjectClass, nme.NE, methOfAny(BooleanType), Final)
- lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
- lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
- lazy val Object_isInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic)
- lazy val Object_asInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic)
- lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
- pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
-
- def Object_getClass = objMethod(nme.getClass_)
- def Object_clone = objMethod(nme.clone_)
- def Object_finalize = objMethod(nme.finalize_)
- def Object_notify = objMethod(nme.notify_)
- def Object_notifyAll = objMethod(nme.notifyAll_)
- def Object_equals = objMethod(nme.equals_)
- def Object_hashCode = objMethod(nme.hashCode_)
- def Object_toString = objMethod(nme.toString_)
- private def objMethod(name: PreName) = ObjectClass.requiredMethod(name)
-
- lazy val AnyClass: ClassSymbol = {
- val cls = newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil)
- ensureConstructor(cls, EmptyScope)
- cls
- }
-
- lazy val AnyValClass: ClassSymbol = ctx.requiredClass("scala.AnyVal")
+ /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter)
+ * because after erasure the Any and AnyVal references get remapped to the Object methods
+ * which would result in a double binding assertion failure.
+ * Instead we do the following:
+ *
+ * - Have some methods exist only in Any, and remap them with the Erasure denotation
+ * transformer to be owned by Object.
+ * - Have other methods exist only in Object.
+ * To achieve this, we synthesize all Any and Object methods; Object methods no longer get
+ * loaded from a classfile.
+ *
+ * There's a remaining question about `getClass`. In Scala2.x `getClass` was handled by compiler magic.
+ * This is deemed too cumersome for Dotty and therefore right now `getClass` gets no special treatment;
+ * it's just a method on `Any` which returns the raw type `java.lang.Class`. An alternative
+ * way to get better `getClass` typing would be to treat `getClass` as a method of a generic
+ * decorator which gets remapped in a later phase to Object#getClass. Then we could give it
+ * the right type without changing the typechecker:
+ *
+ * implicit class AnyGetClass[T](val x: T) extends AnyVal {
+ * def getClass: java.lang.Class[T] = ???
+ * }
+ */
+ lazy val AnyClass: ClassSymbol = newTopClassSymbol(tpnme.Any, Abstract, Nil)
+ lazy val AnyValClass: ClassSymbol = newTopClassSymbol(tpnme.AnyVal, Abstract, AnyClass.typeRef :: Nil)
- lazy val AnyVal_getClass = AnyValClass.requiredMethod(nme.getClass_)
lazy val Any_== = newMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final)
lazy val Any_!= = newMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final)
lazy val Any_equals = newMethod(AnyClass, nme.equals_, methOfAny(BooleanType))
- lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, ExprType(IntType))
- lazy val Any_toString = newMethod(AnyClass, nme.toString_, ExprType(StringType))
+ lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType))
+ lazy val Any_toString = newMethod(AnyClass, nme.toString_, MethodType(Nil, StringType))
lazy val Any_## = newMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final)
-
- // Any_getClass requires special handling. The return type is determined on
- // a per-call-site basis as if the function being called were actually:
- //
- // // Assuming `target.getClass()`
- // def getClass[T](target: T): Class[_ <: T]
- //
- // Since getClass is not actually a polymorphic method, this requires compiler
- // participation. At the "Any" level, the return type is Class[_] as it is in
- // java.lang.Object. Java also special cases the return type.
- lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, ExprType(Object_getClass.info.resultType), Deferred)
+ lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef), Final)
lazy val Any_isInstanceOf = newT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
lazy val Any_asInstanceOf = newT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final)
+ def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode,
+ Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf)
+
+ lazy val ObjectClass: ClassSymbol = {
+ val cls = ctx.requiredClass("java.lang.Object")
+ assert(!cls.isCompleted, "race for completing java.lang.Object")
+ cls.info = ClassInfo(cls.owner.thisType, cls, AnyClass.typeRef :: Nil, newScope)
+ cls.linkedClass.info = NoType
+ ensureConstructor(cls, cls.decls)
+ cls
+ }
+ lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType)
+
+ lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
+ lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
+ lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
+ pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
+ lazy val Object_clone = newMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected)
+ lazy val Object_finalize = newMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected)
+ lazy val Object_notify = newMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType))
+ lazy val Object_notifyAll = newMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType))
+ lazy val Object_wait = newMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType))
+ lazy val Object_waitL = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType))
+ lazy val Object_waitLI = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType))
+
+ def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone,
+ Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI)
+
lazy val NotNullClass = ctx.requiredClass("scala.NotNull")
lazy val NothingClass: ClassSymbol = newCompleteClassSymbol(
@@ -380,8 +397,8 @@ class Definitions {
lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)
- lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf, Object_asInstanceOf)
- lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf, Object_isInstanceOf)
+ lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf)
+ lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf)
lazy val typeTestsOrCasts = asInstanceOfMethods ++ isInstanceOfMethods
lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)
@@ -518,11 +535,11 @@ class Definitions {
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
lazy val syntheticCoreClasses = List(
+ AnyClass,
AnyRefAlias,
RepeatedParamClass,
JavaRepeatedParamClass,
ByNameParamClass2x,
- AnyClass,
AnyValClass,
NullClass,
NothingClass,
@@ -531,26 +548,7 @@ class Definitions {
EmptyPackageVal)
/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
- lazy val syntheticCoreMethods = List(
- Any_==,
- Any_!=,
- Any_equals,
- Any_hashCode,
- Any_toString,
- Any_getClass,
- Any_isInstanceOf,
- Any_asInstanceOf,
- Any_##,
- Object_eq,
- Object_ne,
- Object_==,
- Object_!=,
- Object_##,
- Object_synchronized,
- Object_isInstanceOf,
- Object_asInstanceOf,
- String_+
- )
+ lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+)
private[this] var _isInitialized = false
def isInitialized = _isInitialized
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index cb4272f7a..593feb909 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -331,7 +331,6 @@ object StdNames {
val asType: N = "asType"
val asClass: N = "asClass"
val asInstanceOf_ : N = "asInstanceOf"
- val asInstanceOf_Ob : N = "$asInstanceOf"
val assert_ : N = "assert"
val assume_ : N = "assume"
val box: N = "box"
@@ -388,7 +387,6 @@ object StdNames {
val isDefinedAt: N = "isDefinedAt"
val isEmpty: N = "isEmpty"
val isInstanceOf_ : N = "isInstanceOf"
- val isInstanceOf_Ob : N = "$isInstanceOf"
val java: N = "java"
val keepUnions: N = "keepUnions"
val key: N = "key"
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index f5942dac2..0ed301732 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -891,8 +891,10 @@ class ClassfileParser(
def getType(index: Int)(implicit ctx: Context): Type =
sigToType(getExternalName(index))
- def getSuperClass(index: Int)(implicit ctx: Context): Symbol =
- if (index == 0) defn.AnyClass else getClassSymbol(index)
+ def getSuperClass(index: Int)(implicit ctx: Context): Symbol = {
+ assert(index != 0, "attempt to parse java.lang.Object from classfile")
+ getClassSymbol(index)
+ }
def getConstant(index: Int)(implicit ctx: Context): Constant = {
if (index <= 0 || len <= index) errorBadIndex(index)
diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala
index a7981b70f..f2e3355fb 100644
--- a/src/dotty/tools/dotc/core/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/core/transform/Erasure.scala
@@ -61,8 +61,8 @@ object Erasure {
*/
def transformInfo(sym: Symbol, tp: Type)(implicit ctx: Context): Type = {
val erase = erasureFn(sym is JavaDefined, isSemi = true, sym.isConstructor, wildcardOK = false)
- if ((sym eq defn.Object_asInstanceOf) ||
- (sym eq defn.Object_isInstanceOf) ||
+ if ((sym eq defn.Any_asInstanceOf) ||
+ (sym eq defn.Any_isInstanceOf) ||
(sym.owner eq defn.ArrayClass) && (sym.isType || sym.isConstructor)) sym.info
else if (sym.isAbstractType) TypeAlias(WildcardType)
else erase(tp)
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 791df341a..9473bf10a 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -33,7 +33,10 @@ class Erasure extends Phase with DenotTransformer {
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
case ref: SymDenotation =>
assert(ctx.phase == this, s"transforming $ref at ${ctx.phase}")
- ref.copySymDenotation(info = transformInfo(ref.symbol, ref.info))
+ val owner = ref.owner
+ ref.copySymDenotation(
+ owner = if (owner eq defn.AnyClass) defn.ObjectClass else owner,
+ info = transformInfo(ref.symbol, ref.info))
case ref =>
ref.derivedSingleDenotation(ref.symbol, erasure(ref.info))
}
@@ -136,7 +139,7 @@ object Erasure {
cast(runtimeCall(nme.toObjectArray, tree :: Nil), pt)
case _ =>
ctx.log(s"casting from ${tree.showSummary}: ${tree.tpe.show} to ${pt.show}")
- TypeApply(Select(tree, defn.Object_asInstanceOf), TypeTree(pt) :: Nil)
+ TypeApply(Select(tree, defn.Any_asInstanceOf), TypeTree(pt) :: Nil)
}
/** Adaptation of an expression `e` to an expected type `PT`, applying the following
diff --git a/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
index d5a4377d0..f5fed6fda 100644
--- a/src/dotty/tools/dotc/transform/InterceptedMethods.scala
+++ b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
@@ -28,6 +28,10 @@ import dotty.tools.dotc.core.Denotations.SingleDenotation
import dotty.tools.dotc.core.SymDenotations.SymDenotation
import StdNames._
+// @DarkDimius The getClass scheme changed. We no longer can have
+// two different methods in Any and Object. The tests pass but I
+// am not sure Intercepted methods treats getClass right now.
+// Please check and delete comment when done.
/** Replace member references as follows:
*
* - `x == y` for == in class Any becomes `x equals y` with equals in class Object.
@@ -50,12 +54,10 @@ class InterceptedMethods extends TreeTransform {
/** perform context-dependant initialization */
override def init(implicit ctx: Context, info: TransformerInfo): Unit = {
- getClassMethods = Set(defn.Any_getClass, defn.AnyVal_getClass)
- poundPoundMethods = Set(defn.Any_##, defn.Object_##)
+ poundPoundMethods = Set(defn.Any_##)
Any_comparisons = Set(defn.Any_==, defn.Any_!=)
- interceptedMethods = getClassMethods ++ poundPoundMethods ++ Any_comparisons
- primitiveGetClassMethods = Set[Symbol](defn.Any_getClass, defn.AnyVal_getClass) ++
- defn.ScalaValueClasses.map(x => x.requiredMethod(nme.getClass_))
+ interceptedMethods = poundPoundMethods ++ Any_comparisons
+ primitiveGetClassMethods = Set[Symbol]() ++ defn.ScalaValueClasses.map(x => x.requiredMethod(nme.getClass_))
}
// this should be removed if we have guarantee that ## will get Apply node
@@ -97,7 +99,7 @@ class InterceptedMethods extends TreeTransform {
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = {
def unknown = {
- assert(false, s"The symbol '${tree.fun.symbol}' was interecepted but didn't match any cases, " +
+ assert(false, s"The symbol '${tree.fun.symbol.showLocated}' was intercepted but didn't match any cases, " +
s"that means the intercepted methods set doesn't match the code")
tree
}
@@ -109,9 +111,9 @@ class InterceptedMethods extends TreeTransform {
PoundPoundValue(qual)
} else if (Any_comparisons contains tree.fun.symbol.asTerm) {
if (tree.fun.symbol eq defn.Any_==) {
- Apply(Select(qual, defn.Object_equals.termRef), tree.args)
+ Apply(Select(qual, defn.Any_equals), tree.args)
} else if (tree.fun.symbol eq defn.Any_!=) {
- Select(Apply(Select(qual, defn.Object_equals.termRef), tree.args), defn.Boolean_!.termRef)
+ Select(Apply(Select(qual, defn.Any_equals), tree.args), defn.Boolean_!)
} else unknown
} /* else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
// todo: this is needed to support value classes
@@ -128,7 +130,7 @@ class InterceptedMethods extends TreeTransform {
// we get a primitive form of _getClass trying to target a boxed value
// so we need replace that method name with Object_getClass to get correct behavior.
// See SI-5568.
- Apply(Select(qual, defn.Object_getClass.termRef), Nil)
+ Apply(Select(qual, defn.Any_getClass), Nil)
} else {
unknown
}
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
index a36bf6500..5f65ee414 100644
--- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
+++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
@@ -68,10 +68,10 @@ class TypeTestsCasts extends TreeTransform {
runtimeCall(nme.isArray, arg :: Literal(Constant(ndims)) :: Nil)
if (ndims == 1) isArrayTest(qual)
else evalOnce(qual) { qual1 =>
- mkAnd(derivedTree(qual1, defn.Object_isInstanceOf, qual1.tpe), isArrayTest(qual1))
+ mkAnd(derivedTree(qual1, defn.Any_isInstanceOf, qual1.tpe), isArrayTest(qual1))
}
case _ =>
- derivedTree(expr, defn.Object_isInstanceOf, argType)
+ derivedTree(expr, defn.Any_isInstanceOf, argType)
}
}
@@ -81,10 +81,10 @@ class TypeTestsCasts extends TreeTransform {
else if (qualCls.isPrimitiveValueClass) {
val argCls = argType.classSymbol
if (argCls.isPrimitiveValueClass) primitiveConversion(qual, argCls)
- else derivedTree(box(qual), defn.Object_asInstanceOf, argType)
+ else derivedTree(box(qual), defn.Any_asInstanceOf, argType)
}
else
- derivedTree(qual, defn.Object_asInstanceOf, argType)
+ derivedTree(qual, defn.Any_asInstanceOf, argType)
}
if (sym eq defn.Any_isInstanceOf)