diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 134 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/StdNames.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/ClassfileParser.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/transform/Erasure.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Erasure.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/InterceptedMethods.scala | 20 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 8 |
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) |