diff options
Diffstat (limited to 'src')
35 files changed, 424 insertions, 164 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 8114be20d5..f8342444c8 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -22,15 +22,17 @@ trait Definitions extends reflect.api.StandardDefinitions { */ private type PolyMethodCreator = List[Symbol] => (Option[List[Type]], Type) - private def newClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = { + private def enterNewClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = { val clazz = owner.newClassSymbol(name, NoPosition, flags) clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) } private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): Symbol = { val msym = owner.newMethod(name.encode, NoPosition, flags) val params = msym.newSyntheticValueParams(formals) - msym setInfoAndEnter MethodType(params, restpe) + msym setInfo MethodType(params, restpe) } + private def enterNewMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): Symbol = + owner.info.decls enter newMethod(owner, name, formals, restpe, flags) // the scala value classes trait ValueClassDefinitions { @@ -206,7 +208,7 @@ trait Definitions extends reflect.api.StandardDefinitions { } // top types - lazy val AnyClass = newClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) + lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.typeConstructor) lazy val ObjectClass = getClass(sn.Object) lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") initFlags (SEALED | ABSTRACT | TRAIT) @@ -311,7 +313,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // .setInfo(UnitClass.tpe) lazy val TypeConstraintClass = getRequiredClass("scala.annotation.TypeConstraint") - lazy val SingletonClass = newClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) + lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) lazy val SerializableClass = getRequiredClass("scala.Serializable") lazy val JavaSerializableClass = getClass(sn.JavaSerializable) lazy val ComparableClass = getRequiredClass("java.lang.Comparable") @@ -640,12 +642,12 @@ trait Definitions extends reflect.api.StandardDefinitions { } // members of class scala.Any - lazy val Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) - lazy val Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) - lazy val Any_equals = newMethod(AnyClass, nme.equals_, anyparam, booltype) - lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, Nil, inttype) - lazy val Any_toString = newMethod(AnyClass, nme.toString_, Nil, stringtype) - lazy val Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype, FINAL) + lazy val Any_== = enterNewMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) + lazy val Any_!= = enterNewMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) + lazy val Any_equals = enterNewMethod(AnyClass, nme.equals_, anyparam, booltype) + lazy val Any_hashCode = enterNewMethod(AnyClass, nme.hashCode_, Nil, inttype) + lazy val Any_toString = enterNewMethod(AnyClass, nme.toString_, Nil, stringtype) + lazy val Any_## = enterNewMethod(AnyClass, nme.HASHHASH, Nil, 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: @@ -656,22 +658,60 @@ trait Definitions extends reflect.api.StandardDefinitions { // 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_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED) + lazy val Any_getClass = enterNewMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED) lazy val Any_isInstanceOf = newT1NullaryMethod(AnyClass, nme.isInstanceOf_, FINAL)(_ => booltype) lazy val Any_asInstanceOf = newT1NullaryMethod(AnyClass, nme.asInstanceOf_, FINAL)(_.typeConstructor) + // AnyVal_getClass is defined here. Once we have a new strap, it could also be + // defined directly in the AnyVal trait. Right now this does not work, because + // strap complains about overriding a final getClass method in Any. + lazy val AnyVal_getClass = newMethod(AnyValClass, nme.getClass_, Nil, getClassReturnType(AnyValClass.tpe)) + + // A type function from T => Class[U], used to determine the return + // type of getClass calls. The returned type is: + // + // 1. If T is a value type, Class[T]. + // 2. If T is a phantom type (Any or AnyVal), Class[_]. + // 3. If T is a local class, Class[_ <: |T|]. + // 4. Otherwise, Class[_ <: T]. + // + // Note: AnyVal cannot be Class[_ <: AnyVal] because if the static type of the + // receiver is AnyVal, it implies the receiver is boxed, so the correct + // class object is that of java.lang.Integer, not Int. + // + // TODO: If T is final, return type could be Class[T]. Should it? + def getClassReturnType(tp: Type): Type = { + val sym = tp.typeSymbol + + if (phase.erasedTypes) ClassClass.tpe + else if (isValueClass(sym)) ClassType(tp.widen) + else { + val eparams = typeParamsToExistentials(ClassClass, ClassClass.typeParams) + val upperBound = ( + if (isPhantomClass(sym)) AnyClass.tpe + else if (sym.isLocalClass) erasure.intersectionDominator(tp.parents) + else tp.widen + ) + + existentialAbstraction( + eparams, + ClassType(eparams.head setInfo TypeBounds.upper(upperBound) tpe) + ) + } + } + // members of class java.lang.{ Object, String } - lazy val Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) - lazy val Object_== = newMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL) - lazy val Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL) - lazy val Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL) - lazy val Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) + lazy val Object_## = enterNewMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) + lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL) + lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL) + lazy val Object_eq = enterNewMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL) + lazy val Object_ne = enterNewMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC)(_ => booltype) lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC)(_.typeConstructor) lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps => (Some(List(tps.head.typeConstructor)), tps.head.typeConstructor) ) - lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL) + lazy val String_+ = enterNewMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL) def Object_getClass = getMember(ObjectClass, nme.getClass_) def Object_clone = getMember(ObjectClass, nme.clone_) @@ -756,7 +796,7 @@ trait Definitions extends reflect.api.StandardDefinitions { ) lazy val AnnotationDefaultAttr: Symbol = { - val attr = newClass(RuntimePackageClass, tpnme.AnnotationDefaultATTR, List(AnnotationClass.typeConstructor)) + val attr = enterNewClass(RuntimePackageClass, tpnme.AnnotationDefaultATTR, List(AnnotationClass.typeConstructor)) // This attribute needs a constructor so that modifiers in parsed Java code make sense attr.info.decls enter attr.newClassConstructor(NoPosition) attr @@ -830,11 +870,11 @@ trait Definitions extends reflect.api.StandardDefinitions { owner.newAliasType(name) setInfoAndEnter alias private def specialPolyClass(name: TypeName, flags: Long)(parentFn: Symbol => Type): Symbol = { - val clazz = newClass(ScalaPackageClass, name, Nil) + val clazz = enterNewClass(ScalaPackageClass, name, Nil) val tparam = clazz.newSyntheticTypeParam("T0", flags) val parents = List(AnyRefClass.tpe, parentFn(tparam)) - clazz setInfo polyType(List(tparam), ClassInfoType(parents, newScope, clazz)) + clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz)) } def newPolyMethod(typeParamCount: Int, owner: Symbol, name: TermName, flags: Long)(createFn: PolyMethodCreator): Symbol = { @@ -983,7 +1023,8 @@ trait Definitions extends reflect.api.StandardDefinitions { Object_synchronized, Object_isInstanceOf, Object_asInstanceOf, - String_+ + String_+, + AnyVal_getClass ) /** Removing the anyref parent they acquire from having a source file. @@ -1005,7 +1046,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // tparam => resultType, which is the resultType of PolyType, i.e. the result type after applying the // type parameter =-> a MethodType in this case // TODO: set type bounds manually (-> MulticastDelegate), see newTypeParam - val newCaller = newMethod(DelegateClass, name, paramTypes, delegateType, FINAL | STATIC) + val newCaller = enterNewMethod(DelegateClass, name, paramTypes, delegateType, FINAL | STATIC) // val newCaller = newPolyMethod(DelegateClass, name, // tparam => MethodType(paramTypes, tparam.typeConstructor)) setFlag (FINAL | STATIC) Delegate_scalaCallers = Delegate_scalaCallers ::: List(newCaller) diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index 23b443919a..aaf586b074 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -70,7 +70,7 @@ trait Importers { self: SymbolTable => case from.PolyType(_, res) => res case result => result } - s setInfo polyType(mytypeParams, importType(result)) + s setInfo GenPolyType(mytypeParams, importType(result)) s setAnnotations (sym.annotations map importAnnotationInfo) } } @@ -157,7 +157,7 @@ trait Importers { self: SymbolTable => val myclazz = importSymbol(clazz) val myscope = if (myclazz.isPackageClass) newPackageScope(myclazz) else newScope val myclazzTpe = ClassInfoType(parents map importType, myscope, myclazz) - myclazz setInfo polyType(myclazz.typeParams, myclazzTpe) // needed so that newly created symbols find their scope + myclazz setInfo GenPolyType(myclazz.typeParams, myclazzTpe) // needed so that newly created symbols find their scope decls foreach importSymbol // will enter itself into myclazz myclazzTpe case from.RefinedType(parents, decls) => diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 94d764067f..e504cea8cf 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -489,6 +489,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => // class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR) + final def isInlineClass = isClass && hasAnnotation(ScalaInlineClass) + final def isAnonymousClass = isClass && (name containsName tpnme.ANON_CLASS_NAME) final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME) final def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass @@ -2467,7 +2469,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final override def isAbstractType = false final override def isAliasType = false - override def existentialBound = polyType(this.typeParams, TypeBounds.upper(this.classBound)) + override def existentialBound = GenPolyType(this.typeParams, TypeBounds.upper(this.classBound)) override def sourceFile = if (owner.isPackageClass) source @@ -2697,7 +2699,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** An exception for cyclic references of symbol definitions */ case class CyclicReference(sym: Symbol, info: Type) extends TypeError("illegal cyclic reference involving " + sym) { - // printStackTrace() // debug + if (settings.debug.value) printStackTrace() } case class InvalidCompanions(sym1: Symbol, sym2: Symbol) extends Throwable( diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index e3ee39d2a0..4380487555 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -440,15 +440,6 @@ abstract class TreeInfo { EmptyTree } - /** Is the tree Predef, scala.Predef, or _root_.scala.Predef? - */ - def isPredefExpr(t: Tree) = t match { - case Ident(nme.Predef) => true - case Select(Ident(nme.scala_), nme.Predef) => true - case Select(Select(Ident(nme.ROOTPKG), nme.scala_), nme.Predef) => true - case _ => false - } - /** Does list of trees start with a definition of * a class of module with given name (ignoring imports) */ @@ -468,7 +459,7 @@ abstract class TreeInfo { // Top-level definition whose leading imports include Predef. def containsLeadingPredefImport(defs: List[Tree]): Boolean = defs match { case PackageDef(_, defs1) :: _ => containsLeadingPredefImport(defs1) - case Import(expr, _) :: rest => isPredefExpr(expr) || containsLeadingPredefImport(rest) + case Import(expr, _) :: rest => isReferenceToPredef(expr) || containsLeadingPredefImport(rest) case _ => false } diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala index 63e4c9f1fa..e7ba0c793d 100644 --- a/src/compiler/scala/reflect/internal/TreePrinters.scala +++ b/src/compiler/scala/reflect/internal/TreePrinters.scala @@ -245,6 +245,10 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => case Template(parents, self, body) => val currentOwner1 = currentOwner if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner + if (parents exists isReferenceToAnyVal) { + print("AnyVal") + } + else { printRow(parents, " with ") if (!body.isEmpty) { if (self.name != nme.WILDCARD) { @@ -256,6 +260,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => } printColumn(body, "", ";", "}") } + } currentOwner = currentOwner1 case Block(stats, expr) => diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 5bb0c98bfb..3c339ad8e2 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -11,6 +11,18 @@ import api.Modifier trait Trees extends api.Trees { self: SymbolTable => + // Belongs in TreeInfo but then I can't reach it from TreePrinters. + def isReferenceToScalaMember(t: Tree, Id: Name) = t match { + case Ident(Id) => true + case Select(Ident(nme.scala_), Id) => true + case Select(Select(Ident(nme.ROOTPKG), nme.scala_), Id) => true + case _ => false + } + /** Is the tree Predef, scala.Predef, or _root_.scala.Predef? + */ + def isReferenceToPredef(t: Tree) = isReferenceToScalaMember(t, nme.Predef) + def isReferenceToAnyVal(t: Tree) = isReferenceToScalaMember(t, tpnme.AnyVal) + // --- modifiers implementation --------------------------------------- /** @param privateWithin the qualifier for a private (a type name) @@ -122,11 +134,14 @@ trait Trees extends api.Trees { self: SymbolTable => } } - def substTreeSyms(pairs: (Symbol, Symbol)*): Tree = { - val list = pairs.toList - val subst = new TreeSymSubstituter(list map (_._1), list map (_._2)) - subst(tree) - } + def substTreeSyms(pairs: (Symbol, Symbol)*): Tree = + substTreeSyms(pairs.map(_._1).toList, pairs.map(_._2).toList) + + def substTreeSyms(from: List[Symbol], to: List[Symbol]): Tree = + new TreeSymSubstituter(from, to)(tree) + + def substTreeThis(clazz: Symbol, to: Tree): Tree = new ThisSubstituter(clazz, to) transform tree + def shallowDuplicate: Tree = new ShallowDuplicator(tree) transform tree def shortClass: String = tree.getClass.getName split "[.$]" last @@ -340,6 +355,13 @@ trait Trees extends api.Trees { self: SymbolTable => override def toString = substituterString("Symbol", "Tree", from, to) } + class ThisSubstituter(clazz: Symbol, to: => Tree) extends Transformer { + override def transform(tree: Tree) = tree match { + case This(_) if tree.symbol == clazz => to + case _ => super.transform(tree) + } + } + class TypeMapTreeSubstituter(val typeMap: TypeMap) extends Traverser { override def traverse(tree: Tree) { if (tree.tpe ne null) diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 371fb8d585..bf0017d989 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -1417,7 +1417,7 @@ trait Types extends api.Types { self: SymbolTable => } protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = { - val period = tpe.baseTypeSeqPeriod; + val period = tpe.baseTypeSeqPeriod if (period != currentPeriod) { tpe.baseTypeSeqPeriod = currentPeriod if (!isValidForBaseClasses(period)) { @@ -3260,7 +3260,7 @@ trait Types extends api.Types { self: SymbolTable => case _ => abort(debugString(tycon)) } - /** A creator for type parameterizations that strips empty type parameter lists. + /** A creator and extractor for type parameterizations that strips empty type parameter lists. * Use this factory method to indicate the type has kind * (it's a polymorphic value) * until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty). * @@ -3269,9 +3269,18 @@ trait Types extends api.Types { self: SymbolTable => * can we instead say this is the canonical creator for polyTypes which * may or may not be poly? (It filched the standard "canonical creator" name.) */ - def polyType(tparams: List[Symbol], tpe: Type): Type = + object GenPolyType { + def apply(tparams: List[Symbol], tpe: Type): Type = if (tparams nonEmpty) typeFun(tparams, tpe) else tpe // it's okay to be forgiving here + def unapply(tpe: Type): Option[(List[Symbol], Type)] = tpe match { + case PolyType(tparams, restpe) => Some(tparams, restpe) + case _ => Some(List(), tpe) + } + } + + @deprecated("use GenPolyType(...) instead") + def polyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe) /** A creator for anonymous type functions, where the symbol for the type function still needs to be created. * @@ -6392,7 +6401,9 @@ trait Types extends api.Types { self: SymbolTable => // but that would be a big change. Left for further refactoring. /** An exception for cyclic references from which we can recover */ case class RecoverableCyclicReference(sym: Symbol) - extends TypeError("illegal cyclic reference involving " + sym) + extends TypeError("illegal cyclic reference involving " + sym) { + if (settings.debug.value) printStackTrace() + } class NoCommonType(tps: List[Type]) extends Throwable( "lub/glb of incompatible types: " + tps.mkString("", " and ", "")) with ControlThrowable diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala index d59fc6d564..9faa399cad 100644 --- a/src/compiler/scala/reflect/internal/transform/Erasure.scala +++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala @@ -101,7 +101,7 @@ trait Erasure { ClassInfoType( if (clazz == ObjectClass || isValueClass(clazz)) Nil else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass)) - else removeDoubleObject(parents map this), + else removeLaterObjects(parents map this), decls, clazz) case _ => mapOver(tp) @@ -220,11 +220,9 @@ trait Erasure { typeRef(erasure(sym, sym.owner.tpe), sym, List()) /** Remove duplicate references to class Object in a list of parent classes */ - private def removeDoubleObject(tps: List[Type]): List[Type] = tps match { - case List() => List() - case tp :: tps1 => - if (tp.typeSymbol == ObjectClass) tp :: tps1.filter(_.typeSymbol != ObjectClass) - else tp :: removeDoubleObject(tps1) + private def removeLaterObjects(tps: List[Type]): List[Type] = tps match { + case tp :: rest => tp :: (rest filter (_.typeSymbol != ObjectClass)) + case _ => tps } /** The symbol's erased info. This is the type's erasure, except for the following symbols: diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala index b4bcc52a23..813c66e1f0 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -186,7 +186,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => } finally { parentsLevel -= 1 } - clazz setInfo polyType(tparams, new ClassInfoType(parents, newScope, clazz)) + clazz setInfo GenPolyType(tparams, new ClassInfoType(parents, newScope, clazz)) if (module != NoSymbol) { module.moduleClass setInfo new ClassInfoType(List(), newScope, module.moduleClass) } @@ -478,7 +478,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => } private def setMethType(meth: Symbol, tparams: List[Symbol], paramtpes: List[Type], restpe: Type) = { - meth setInfo polyType(tparams, MethodType(meth.owner.newSyntheticValueParams(paramtpes map objToAny), restpe)) + meth setInfo GenPolyType(tparams, MethodType(meth.owner.newSyntheticValueParams(paramtpes map objToAny), restpe)) } /** @@ -516,7 +516,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => val tparams = jconstr.getTypeParameters.toList map createTypeParameter val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala setMethType(constr, tparams, paramtpes, clazz.tpe) - constr setInfo polyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe)) + constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe)) copyAnnotations(constr, jconstr) constr } diff --git a/src/compiler/scala/tools/cmd/gen/AnyVals.scala b/src/compiler/scala/tools/cmd/gen/AnyVals.scala index 8f82c997db..ab4a4a4402 100644 --- a/src/compiler/scala/tools/cmd/gen/AnyVals.scala +++ b/src/compiler/scala/tools/cmd/gen/AnyVals.scala @@ -182,7 +182,7 @@ trait AnyValReps { def classLines: List[String] def objectLines: List[String] def commonClassLines = List( - "def getClass(): Class[@name@]" + "override def getClass(): Class[@name@]" ) def lcname = name.toLowerCase @@ -429,7 +429,7 @@ def &(x: Boolean): Boolean = sys.error("stub") */ def ^(x: Boolean): Boolean = sys.error("stub") -def getClass(): Class[Boolean] = sys.error("stub") +override def getClass(): Class[Boolean] = sys.error("stub") """.trim.lines.toList def objectLines = interpolate(allCompanions).lines.toList @@ -443,7 +443,7 @@ def getClass(): Class[Boolean] = sys.error("stub") */ """ def classLines = List( - """def getClass(): Class[Unit] = sys.error("stub")""" + """override def getClass(): Class[Unit] = sys.error("stub")""" ) def objectLines = interpolate(allCompanions).lines.toList diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 797ed7e047..c63070b18f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -436,66 +436,72 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb val global: Global.this.type = Global.this } with Analyzer + object extensionMethods extends { + val global: Global.this.type = Global.this + val runsAfter = List("typer") + val runsRightAfter = None + } with ExtensionMethods + // phaseName = "superaccessors" object superAccessors extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("typer") + val runsAfter = List("typer") val runsRightAfter = None } with SuperAccessors // phaseName = "pickler" object pickler extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("superaccessors") + val runsAfter = List("superaccessors") val runsRightAfter = None } with Pickler // phaseName = "refchecks" override object refChecks extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("pickler") + val runsAfter = List("pickler") val runsRightAfter = None } with RefChecks // phaseName = "liftcode" object liftcode extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("refchecks") + val runsAfter = List("refchecks") val runsRightAfter = None } with LiftCode // phaseName = "uncurry" override object uncurry extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("refchecks", "liftcode") + val runsAfter = List("refchecks", "liftcode") val runsRightAfter = None } with UnCurry // phaseName = "tailcalls" object tailCalls extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("uncurry") + val runsAfter = List("uncurry") val runsRightAfter = None } with TailCalls // phaseName = "explicitouter" object explicitOuter extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("tailcalls") + val runsAfter = List("tailcalls") val runsRightAfter = None } with ExplicitOuter // phaseName = "specialize" object specializeTypes extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("") + val runsAfter = List("") val runsRightAfter = Some("tailcalls") } with SpecializeTypes // phaseName = "erasure" override object erasure extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("explicitouter") + val runsAfter = List("explicitouter") val runsRightAfter = Some("explicitouter") } with Erasure @@ -503,84 +509,84 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb object lazyVals extends { final val FLAGS_PER_WORD = 32 val global: Global.this.type = Global.this - val runsAfter = List[String]("erasure") + val runsAfter = List("erasure") val runsRightAfter = None } with LazyVals // phaseName = "lambdalift" object lambdaLift extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("lazyvals") + val runsAfter = List("lazyvals") val runsRightAfter = None } with LambdaLift // phaseName = "constructors" object constructors extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("lambdalift") + val runsAfter = List("lambdalift") val runsRightAfter = None } with Constructors // phaseName = "flatten" object flatten extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("constructors") + val runsAfter = List("constructors") val runsRightAfter = None } with Flatten // phaseName = "mixin" object mixer extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("flatten", "constructors") + val runsAfter = List("flatten", "constructors") val runsRightAfter = None } with Mixin // phaseName = "cleanup" object cleanup extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("mixin") + val runsAfter = List("mixin") val runsRightAfter = None } with CleanUp // phaseName = "icode" object genicode extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("cleanup") + val runsAfter = List("cleanup") val runsRightAfter = None } with GenICode // phaseName = "inliner" object inliner extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("icode") + val runsAfter = List("icode") val runsRightAfter = None } with Inliners // phaseName = "inlineExceptionHandlers" object inlineExceptionHandlers extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("inliner") + val runsAfter = List("inliner") val runsRightAfter = None } with InlineExceptionHandlers // phaseName = "closelim" object closureElimination extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("inlineExceptionHandlers") + val runsAfter = List("inlineExceptionHandlers") val runsRightAfter = None } with ClosureElimination // phaseName = "dce" object deadCode extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("closelim") + val runsAfter = List("closelim") val runsRightAfter = None } with DeadCodeElimination // phaseName = "jvm" object genJVM extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("dce") + val runsAfter = List("dce") val runsRightAfter = None } with GenJVM @@ -596,7 +602,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb object terminal extends { val global: Global.this.type = Global.this val phaseName = "terminal" - val runsAfter = List[String]("jvm", "msil") + val runsAfter = List("jvm", "msil") val runsRightAfter = None } with SubComponent { private var cache: Option[GlobalPhase] = None @@ -650,6 +656,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb analyzer.packageObjects -> "load package objects", analyzer.typerFactory -> "the meat and potatoes: type the trees", superAccessors -> "add super accessors in traits and nested classes", + extensionMethods -> "add extension methods for inline classes", pickler -> "serialize symbol tables", refChecks -> "reference/override checking, translate nested objects", liftcode -> "reify trees", @@ -1024,6 +1031,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb val namerPhase = phaseNamed("namer") // packageobjects val typerPhase = phaseNamed("typer") + val inlineclassesPhase = phaseNamed("inlineclasses") // superaccessors val picklerPhase = phaseNamed("pickler") val refchecksPhase = phaseNamed("refchecks") diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index b16b3c89a0..662e03d155 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -6,6 +6,7 @@ package scala.tools.nsc package ast +import reflect.internal.HasFlags import reflect.internal.Flags._ import symtab._ @@ -41,4 +42,7 @@ abstract class TreeInfo extends reflect.internal.TreeInfo { case ClassDef(_, `name`, _, _) :: Nil => true case _ => super.firstDefinesClassOrObject(trees, name) } + + def isInterface(mods: HasFlags, body: List[Tree]) = + mods.hasTraitFlag && (body forall isInterfaceMember) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index fe6dcc9138..eb7c5a6699 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -290,11 +290,11 @@ self => inScalaPackage = false currentPackage = "" } - private lazy val anyValNames: Set[Name] = tpnme.ScalaValueNames.toSet + tpnme.AnyVal + private lazy val primitiveNames: Set[Name] = tpnme.ScalaValueNames.toSet private def inScalaRootPackage = inScalaPackage && currentPackage == "scala" private def isScalaArray(name: Name) = inScalaRootPackage && name == tpnme.Array - private def isAnyValType(name: Name) = inScalaRootPackage && anyValNames(name) + private def isPrimitiveType(name: Name) = inScalaRootPackage && primitiveNames(name) def parseStartRule: () => Tree @@ -2753,9 +2753,15 @@ self => val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart atPos(tstart0) { - if (isAnyValType(name)) { - val parent = if (name == tpnme.AnyVal) tpnme.Any else tpnme.AnyVal - Template(List(scalaDot(parent)), self, body) + if (isPrimitiveType(name)) { + Template(List(scalaDot(tpnme.AnyVal)), self, body) + } + else if (parents0 exists isReferenceToAnyVal) { + // TODO - enforce @inline annotation, and no other parents + Template(parents0, self, body) + } + else if (name == tpnme.AnyVal) { + Template(List(scalaDot(tpnme.Any)), self, body) } else { val parents = ( diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala index c742ab89c0..37dd032135 100644 --- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -182,7 +182,7 @@ trait MemberHandlers { // TODO: Need to track these specially to honor Predef masking attempts, // because they must be the leading imports in the code generated for each // line. We can use the same machinery as Contexts now, anyway. - def isPredefImport = treeInfo.isPredefExpr(expr) + def isPredefImport = isReferenceToPredef(expr) // wildcard imports, e.g. import foo._ private def selectorWild = selectors filter (_.name == nme.USCOREkw) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index ac6dca4422..a0826c19c3 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -841,7 +841,7 @@ abstract class ClassfileParser { } ClassInfoType(parents.toList, instanceDefs, sym) } - polyType(ownTypeParams, tpe) + GenPolyType(ownTypeParams, tpe) } // sigToType class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType { diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index e11a5a4ad9..736d1c78a3 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -224,14 +224,14 @@ abstract class TypeParser { if (canBeTakenAddressOf) { clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata - else polyType(ownTypeParams, classInfoAsInMetadata) ) + else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) clazzBoxed.setFlag(flags) val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz) clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType - else polyType(ownTypeParams, rawValueInfoType) ) + else GenPolyType(ownTypeParams, rawValueInfoType) ) } else { clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata - else polyType(ownTypeParams, classInfoAsInMetadata) ) + else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) } // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params @@ -480,7 +480,7 @@ abstract class TypeParser { val mtype = methodType(method, rettype); if (mtype == null) return; /* START CLR generics (snippet 4) */ - val mInfo = if (method.IsGeneric) polyType(newMethodTParams, mtype(methodSym)) + val mInfo = if (method.IsGeneric) GenPolyType(newMethodTParams, mtype(methodSym)) else mtype(methodSym) /* END CLR generics (snippet 4) */ /* START CLR non-generics (snippet 4) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index fe479a5375..30bfdbaf5b 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -31,39 +31,6 @@ abstract class Erasure extends AddInterfaces // -------- erasure on types -------------------------------------------------------- - // A type function from T => Class[U], used to determine the return - // type of getClass calls. The returned type is: - // - // 1. If T is a value type, Class[T]. - // 2. If T is a phantom type (Any or AnyVal), Class[_]. - // 3. If T is a local class, Class[_ <: |T|]. - // 4. Otherwise, Class[_ <: T]. - // - // Note: AnyVal cannot be Class[_ <: AnyVal] because if the static type of the - // receiver is AnyVal, it implies the receiver is boxed, so the correct - // class object is that of java.lang.Integer, not Int. - // - // TODO: If T is final, return type could be Class[T]. Should it? - def getClassReturnType(tp: Type): Type = { - val sym = tp.typeSymbol - - if (phase.erasedTypes) ClassClass.tpe - else if (isValueClass(sym)) ClassType(tp.widen) - else { - val eparams = typeParamsToExistentials(ClassClass, ClassClass.typeParams) - val upperBound = ( - if (isPhantomClass(sym)) AnyClass.tpe - else if (sym.isLocalClass) intersectionDominator(tp.parents) - else tp.widen - ) - - existentialAbstraction( - eparams, - ClassType(eparams.head setInfo TypeBounds.upper(upperBound) tpe) - ) - } - } - // convert a numeric with a toXXX method def numericConversion(tree: Tree, numericSym: Symbol): Tree = { val mname = newTermName("to" + numericSym.name) @@ -602,7 +569,7 @@ abstract class Erasure extends AddInterfaces Console.println("exception when typing " + tree) Console.println(er.msg + " in file " + context.owner.sourceFile) er.printStackTrace - abort() + abort("unrecoverable error") case ex: Exception => //if (settings.debug.value) try Console.println("exception when typing " + tree) @@ -931,6 +898,10 @@ abstract class Erasure extends AddInterfaces tree case Apply(fn, args) => + def qualifier = fn match { + case Select(qual, _) => qual + case TypeApply(Select(qual, _), _) => qual + } if (fn.symbol == Any_asInstanceOf) (fn: @unchecked) match { case TypeApply(Select(qual, _), List(targ)) => @@ -980,20 +951,13 @@ abstract class Erasure extends AddInterfaces } case _ => tree } - } - else { - def doDynamic(fn: Tree, qual: Tree): Tree = { - if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) - ApplyDynamic(qual, args) setSymbol fn.symbol setPos tree.pos - else tree - } - fn match { - case Select(qual, _) => doDynamic(fn, qual) - case TypeApply(fni@Select(qual, _), _) => doDynamic(fni, qual)// type parameters are irrelevant in case of dynamic call - case _ => + } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) { + ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos + } else if (fn.symbol.owner.isInlineClass && extensionMethods.hasExtension(fn.symbol)) { + Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args) + } else { tree } - } case Select(qual, name) => val owner = tree.symbol.owner diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala new file mode 100644 index 0000000000..5f62dfab39 --- /dev/null +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -0,0 +1,161 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Gilles Dubochet + * @author Martin Odersky + */ + +package scala.tools.nsc +package transform + +import symtab._ +import Flags._ +import scala.collection.{ mutable, immutable } +import scala.collection.mutable +import scala.tools.nsc.util.FreshNameCreator +import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple } +import sun.tools.tree.OrExpression + +/** + * Perform Step 1 in the inline classes SIP + * + * @author Martin Odersky + * @version 2.10 + */ +abstract class ExtensionMethods extends Transform with TypingTransformers { + + import global._ // the global environment + import definitions._ // standard classes and methods + import typer.{ typed, atOwner } // methods to type trees + + /** the following two members override abstract members in Transform */ + val phaseName: String = "extmethods" + + def newTransformer(unit: CompilationUnit): Transformer = + new Extender(unit) + + def hasExtension(sym: Symbol) = + !sym.isParamAccessor && !sym.isConstructor + + /** Generate stream of possible names for the extension version of given instance method `imeth`. + * If the method is not overloaded, this stream consists of just "extension$imeth". + * If the method is overloaded, the stream has as first element "extensionX$imeth", where X is the + * index of imeth in the sequence of overloaded alternatives with the same name. This choice will + * always be picked as the name of the generated extension method. + * After this first choice, all other possible indices in the range of 0 until the number + * of overloaded alternatives are returned. The secondary choices are used to find a matching method + * in `extensionMethod` if the first name has the wrong type. We thereby gain a level of insensitivity + * of how overloaded types are ordered between phases and picklings. + */ + private def extensionNames(imeth: Symbol): Stream[Name] = + imeth.owner.info.decl(imeth.name).tpe match { + case OverloadedType(_, alts) => + val index = alts indexOf imeth + assert(index >= 0, alts+" does not contain "+imeth) + def altName(index: Int) = newTermName("extension"+index+"$"+imeth.name) + altName(index) #:: ((0 until alts.length).toStream filter (index !=) map altName) + case tpe => + assert(tpe != NoType, imeth.name+" not found in "+imeth.owner+"'s decls: "+imeth.owner.info.decls) + Stream(newTermName("extension$"+imeth.name)) + } + + /** Return the extension method that corresponds to given instance method `meth`. + */ + def extensionMethod(imeth: Symbol): Symbol = atPhase(currentRun.refchecksPhase) { + val companionInfo = imeth.owner.companionModule.info + val candidates = extensionNames(imeth) map (companionInfo.decl(_)) + val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe) + assert(matching.nonEmpty, "no extension method found for "+imeth+" among "+candidates+"/"+extensionNames(imeth)) + matching.head + } + + private def normalize(stpe: Type, clazz: Symbol): Type = stpe match { + case PolyType(tparams, restpe) => + GenPolyType(tparams dropRight clazz.typeParams.length, normalize(restpe, clazz)) + case MethodType(tparams, restpe) => + restpe + case _ => + stpe + } + + class Extender(unit: CompilationUnit) extends TypingTransformer(unit) { + + private val extensionDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]() + + def extensionMethInfo(extensionMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { + var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) + val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpe)) + val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType + def transform(clonedType: Type): Type = clonedType match { + case MethodType(params, restpe) => + MethodType(List(thisParam), clonedType) + case NullaryMethodType(restpe) => + MethodType(List(thisParam), restpe) + } + val GenPolyType(tparams, restpe) = origInfo cloneInfo extensionMeth + GenPolyType(tparams ::: newTypeParams, transform(restpe)) + } + + private def allParams(tpe: Type): List[Symbol] = tpe match { + case MethodType(params, res) => params ::: allParams(res) + case _ => List() + } + + override def transform(tree: Tree): Tree = { + tree match { + case Template(_, _, _) => + if (currentOwner.isInlineClass) { + extensionDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree] + super.transform(tree) + } + else tree + case DefDef(mods, name, tparams, vparamss, tpt, rhs) + if currentOwner.isInlineClass && hasExtension(tree.symbol) => + val companion = currentOwner.companionModule + val origMeth = tree.symbol + val extensionName = extensionNames(origMeth).head + val extensionMeth = companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE | FINAL) + .setAnnotations(origMeth.annotations) + companion.info.decls.enter(extensionMeth) + extensionMeth.setInfo(extensionMethInfo(extensionMeth, origMeth.info, currentOwner)) + def thisParamRef = gen.mkAttributedIdent(extensionMeth.info.params.head setPos extensionMeth.pos) + val GenPolyType(extensionTpeParams, extensionMono) = extensionMeth.info + val origTpeParams = origMeth.typeParams ::: currentOwner.typeParams + val extensionBody = rhs + .substTreeSyms(origTpeParams, extensionTpeParams) + .substTreeSyms(vparamss.flatten map (_.symbol), allParams(extensionMono).tail) + .substTreeThis(currentOwner, thisParamRef) + .changeOwner((origMeth, extensionMeth)) + extensionDefs(companion) += atPos(tree.pos) { DefDef(extensionMeth, extensionBody) } + val extensionCallPrefix = Apply( + gen.mkTypeApply(gen.mkAttributedRef(companion), extensionMeth, origTpeParams map (_.tpe)), + List(This(currentOwner))) + val extensionCall = atOwner(origMeth) { + localTyper.typed { + atPos(rhs.pos) { + (extensionCallPrefix /: vparamss) { + case (fn, params) => Apply(fn, params map (param => Ident(param.symbol))) + } + } + } + } + treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, extensionCall) + case _ => + super.transform(tree) + } + } + + override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = + super.transformStats(stats, exprOwner) map { + case stat @ ModuleDef(mods, name, tmpl @ Template(parents, self, body)) => + extensionDefs.remove(stat.symbol) match { + case Some(buf) => + val extensionDefs = buf.toList map { mdef => atOwner(stat.symbol) { localTyper.typed(mdef) }} + treeCopy.ModuleDef(stat, mods, name, treeCopy.Template(tmpl, parents, self, body ++ buf)) + case None => + stat + } + case stat => + stat + } + } +} diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index c5475fa0f2..26568b4edc 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -1,6 +1,7 @@ /* NSC -- new Scala compiler * Copyright 2005-2011 LAMP/EPFL * @author Gilles Dubochet + * @author Martin Odersky */ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 4a104857db..7d49c98dfb 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -556,7 +556,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { " => " + sClass.defStringSeenAs(sClass.typeOfThis) ) } - polyType(newClassTParams, ClassInfoType(parents ::: extraSpecializedMixins, decls1, sClass)) + GenPolyType(newClassTParams, ClassInfoType(parents ::: extraSpecializedMixins, decls1, sClass)) } atPhase(phase.next)(sClass setInfo specializedInfoType) @@ -787,7 +787,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // the cloneInfo is necessary so that method parameter symbols are cloned at the new owner val methodType = sym.info.resultType.instantiateTypeParams(keys ++ tps, vals ++ tps1.map(_.tpe)).cloneInfo(specMember) - specMember setInfo polyType(tps1, methodType) + specMember setInfo GenPolyType(tps1, methodType) debuglog("expanded member: " + sym + ": " + sym.info + " -> " + specMember + @@ -1091,7 +1091,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { ) val newScope = newScopeWith(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz): _*) // If tparams.isEmpty, this is just the ClassInfoType. - polyType(tparams, ClassInfoType(parents1, newScope, clazz)) + GenPolyType(tparams, ClassInfoType(parents1, newScope, clazz)) case _ => tpe } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 6ee09d064f..68bc80ffc4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -534,7 +534,7 @@ trait ContextErrors { NormalTypeError(parent, "illegal inheritance from final "+mixin) def ParentSealedInheritanceError(parent: Tree, psym: Symbol) = - NormalTypeError(parent, "illegal inheritance from sealed " + psym + ": " + context.unit.source.file.canonicalPath + " != " + psym.sourceFile.canonicalPath) + NormalTypeError(parent, "illegal inheritance from sealed " + psym ) def ParentSelfTypeConformanceError(parent: Tree, selfType: Type) = NormalTypeError(parent, @@ -765,7 +765,7 @@ trait ContextErrors { def PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) = issueNormalTypeError(tree, "polymorphic expression cannot be instantiated to expected type" + - foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt)) + foundReqMsg(GenPolyType(undetparams, skipImplicit(tree.tpe)), pt)) //checkCheckable def TypePatternOrIsInstanceTestError(tree: Tree, tp: Type) = diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 0ff2b418f4..b9f3adec75 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -836,6 +836,11 @@ trait Namers extends MethodSynthesis { } val parents = typer.parentTypes(templ) map checkParent + +// not yet: +// if (!treeInfo.isInterface(clazz, templ.body) && clazz != ArrayClass) +// ensureParent(ScalaObjectClass) + enterSelf(templ.self) val decls = newScope @@ -886,7 +891,7 @@ trait Namers extends MethodSynthesis { val tparams0 = typer.reenterTypeParams(tparams) val resultType = templateSig(impl) - polyType(tparams0, resultType) + GenPolyType(tparams0, resultType) } private def methodSig(ddef: DefDef, mods: Modifiers, tparams: List[TypeDef], @@ -929,7 +934,7 @@ trait Namers extends MethodSynthesis { // DEPMETTODO: check not needed when they become on by default checkDependencies(restpe) - polyType( + GenPolyType( tparamSyms, // deSkolemized symbols -- TODO: check that their infos don't refer to method args? if (vparamSymss.isEmpty) NullaryMethodType(restpe) // vparamss refer (if they do) to skolemized tparams @@ -1183,7 +1188,7 @@ trait Namers extends MethodSynthesis { // However, separate compilation requires the symbol info to be // loaded to do this check, but loading the info will probably // lead to spurious cyclic errors. So omit the check. - polyType(tparamSyms, tp) + GenPolyType(tparamSyms, tp) } /** Given a case class @@ -1247,8 +1252,12 @@ trait Namers extends MethodSynthesis { if (sym.isModule) annotate(sym.moduleClass) def getSig = tree match { - case ClassDef(_, _, tparams, impl) => - createNamer(tree).classSig(tparams, impl) + case cdef @ ClassDef(_, _, tparams, impl) => + val clazz = tree.symbol + val result = createNamer(tree).classSig(tparams, impl) + clazz setInfo result + if (clazz.isInlineClass) ensureCompanionObject(cdef) + result case ModuleDef(_, _, impl) => val clazz = sym.moduleClass @@ -1381,6 +1390,27 @@ trait Namers extends MethodSynthesis { if (sym.info.typeSymbol == FunctionClass(0) && sym.isValueParameter && sym.owner.isCaseClass) fail(ByNameParameter) + def includeParent(tpe: Type, parent: Symbol): Type = tpe match { + case PolyType(tparams, restpe) => + PolyType(tparams, includeParent(restpe, parent)) + case ClassInfoType(parents, decls, clazz) => + if (parents exists (_.typeSymbol == parent)) tpe + else ClassInfoType(parents :+ parent.tpe, decls, clazz) + case _ => + tpe + } + + def ensureParent(parent: Symbol) = { + val info0 = sym.info + val info1 = includeParent(info0, parent) + if (info0 ne info1) sym setInfo info1 + } + + if (sym.isClass && sym.hasAnnotation(ScalaInlineClass) && !phase.erasedTypes) { + ensureParent(NotNullClass) + sym setFlag FINAL + } + if (sym.isDeferred) { // Is this symbol type always allowed the deferred flag? def symbolAllowsDeferred = ( diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index a99d09173e..4449116fd1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -685,12 +685,14 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R unit.error(clazz.pos, abstractErrorMessage) } else if (clazz.isTrait) { // prevent abstract methods in interfaces that override final members in Object; see #4431 + if (!(clazz isSubClass AnyValClass)) { for (decl <- clazz.info.decls.iterator) { val overridden = decl.overriddenSymbol(ObjectClass) if (overridden.isFinal) unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") } } + } /** Returns whether there is a symbol declared in class `inclazz` * (which must be different from `clazz`) whose name and type diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 4ea21b1c44..3ee5bf601d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -47,6 +47,17 @@ trait SyntheticMethods extends ast.TreeDSL { newTyper( if (reporter.hasErrors) context makeSilent false else context ) ) import synthesizer._ + + if (clazz0 isSubClass AnyValClass) return { + if (clazz0.info member nme.getClass_ isDeferred) { + val getClassMethod = createMethod(nme.getClass_, getClassReturnType(clazz.tpe)) { sym => + // XXX dummy implementation for now + NULL + } + treeCopy.Template(templ, templ.parents, templ.self, templ.body :+ getClassMethod) + } + else templ + } val originalAccessors = clazz.caseFieldAccessors // private ones will have been renamed -- make sure they are entered diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d3ff331f98..b6f555e42a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1336,13 +1336,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (psym.isFinal) pending += ParentFinalInheritanceError(parent, psym) - if (psym.isSealed && !phase.erasedTypes) { - // AnyVal is sealed, but we have to let the value classes through manually - if (context.unit.source.file == psym.sourceFile || isValueClass(context.owner)) + if (psym.isSealed && !phase.erasedTypes) + if (context.unit.source.file == psym.sourceFile) psym addChild context.owner else pending += ParentSealedInheritanceError(parent, psym) - } + if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes && !context.owner.isSynthetic && // don't check synthetic concrete classes for virtuals (part of DEVIRTUALIZE) @@ -3056,7 +3055,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // as we don't know which alternative to choose... here we do map2Conserve(args, tparams) { //@M! the polytype denotes the expected kind - (arg, tparam) => typedHigherKindedType(arg, mode, polyType(tparam.typeParams, AnyClass.tpe)) + (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe)) } } else // @M: there's probably something wrong when args.length != tparams.length... (triggered by bug #320) // Martin, I'm using fake trees, because, if you use args or arg.map(typedType), @@ -3824,7 +3823,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { && qual.tpe.typeSymbol.isPublic ) if (isRefinableGetClass) - selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe)) + selection setType MethodType(Nil, getClassReturnType(qual.tpe)) else selection } @@ -4068,7 +4067,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // if symbol hasn't been fully loaded, can't check kind-arity else map2Conserve(args, tparams) { (arg, tparam) => //@M! the polytype denotes the expected kind - typedHigherKindedType(arg, mode, polyType(tparam.typeParams, AnyClass.tpe)) + typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe)) } val argtypes = args1 map (_.tpe) @@ -4276,7 +4275,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // @M maybe the well-kindedness check should be done when checking the type arguments conform to the type parameters' bounds? val args1 = if (sameLength(args, tparams)) map2Conserve(args, tparams) { //@M! the polytype denotes the expected kind - (arg, tparam) => typedHigherKindedType(arg, mode, polyType(tparam.typeParams, AnyClass.tpe)) + (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe)) } else { //@M this branch is correctly hit for an overloaded polymorphic type. It also has to handle erroneous cases. // Until the right alternative for an overloaded method is known, be very liberal, diff --git a/src/library/scala/AnyVal.scala b/src/library/scala/AnyVal.scala index cd2c04dbd8..fb36d61c57 100644 --- a/src/library/scala/AnyVal.scala +++ b/src/library/scala/AnyVal.scala @@ -25,4 +25,8 @@ package scala * The ''integer types'' include the subrange types as well as [[scala.Int]] and [[scala.Long]]. * The ''floating point types'' are [[scala.Float]] and [[scala.Double]]. */ -sealed trait AnyVal +trait AnyVal { +// disabled for now to make the standard build go through. +// Once we have a new strap we can uncomment this and delete the AnyVal_getClass entry in Definitions. +// def getClass(): Class[_ <: AnyVal] = ??? +} diff --git a/src/library/scala/Boolean.scala b/src/library/scala/Boolean.scala index 0adcde3aba..5078e59d28 100644 --- a/src/library/scala/Boolean.scala +++ b/src/library/scala/Boolean.scala @@ -107,7 +107,7 @@ final class Boolean extends AnyVal { */ def ^(x: Boolean): Boolean = sys.error("stub") - def getClass(): Class[Boolean] = sys.error("stub") + override def getClass(): Class[Boolean] = sys.error("stub") } object Boolean extends AnyValCompanion { diff --git a/src/library/scala/Byte.scala b/src/library/scala/Byte.scala index 4923cc9786..f9c5f6003e 100644 --- a/src/library/scala/Byte.scala +++ b/src/library/scala/Byte.scala @@ -590,7 +590,7 @@ final class Byte extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Byte] = sys.error("stub") + override def getClass(): Class[Byte] = sys.error("stub") } object Byte extends AnyValCompanion { diff --git a/src/library/scala/Char.scala b/src/library/scala/Char.scala index b4e6445899..3d459782cd 100644 --- a/src/library/scala/Char.scala +++ b/src/library/scala/Char.scala @@ -590,7 +590,7 @@ final class Char extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Char] = sys.error("stub") + override def getClass(): Class[Char] = sys.error("stub") } object Char extends AnyValCompanion { diff --git a/src/library/scala/Double.scala b/src/library/scala/Double.scala index 68a1a01299..01414265c4 100644 --- a/src/library/scala/Double.scala +++ b/src/library/scala/Double.scala @@ -356,7 +356,7 @@ final class Double extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Double] = sys.error("stub") + override def getClass(): Class[Double] = sys.error("stub") } object Double extends AnyValCompanion { diff --git a/src/library/scala/Float.scala b/src/library/scala/Float.scala index 709d73d408..ff5b3cb112 100644 --- a/src/library/scala/Float.scala +++ b/src/library/scala/Float.scala @@ -356,7 +356,7 @@ final class Float extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Float] = sys.error("stub") + override def getClass(): Class[Float] = sys.error("stub") } object Float extends AnyValCompanion { diff --git a/src/library/scala/Int.scala b/src/library/scala/Int.scala index 519a0486ac..316bbced2d 100644 --- a/src/library/scala/Int.scala +++ b/src/library/scala/Int.scala @@ -590,7 +590,7 @@ final class Int extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Int] = sys.error("stub") + override def getClass(): Class[Int] = sys.error("stub") } object Int extends AnyValCompanion { diff --git a/src/library/scala/Long.scala b/src/library/scala/Long.scala index 9c7a803f08..ce8618c22a 100644 --- a/src/library/scala/Long.scala +++ b/src/library/scala/Long.scala @@ -590,7 +590,7 @@ final class Long extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Long] = sys.error("stub") + override def getClass(): Class[Long] = sys.error("stub") } object Long extends AnyValCompanion { diff --git a/src/library/scala/Short.scala b/src/library/scala/Short.scala index a9210d3555..5664c3b44c 100644 --- a/src/library/scala/Short.scala +++ b/src/library/scala/Short.scala @@ -590,7 +590,7 @@ final class Short extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Short] = sys.error("stub") + override def getClass(): Class[Short] = sys.error("stub") } object Short extends AnyValCompanion { diff --git a/src/library/scala/Unit.scala b/src/library/scala/Unit.scala index 57970b021b..f6ed0121ab 100644 --- a/src/library/scala/Unit.scala +++ b/src/library/scala/Unit.scala @@ -17,7 +17,7 @@ package scala * method which is declared `void`. */ final class Unit extends AnyVal { - def getClass(): Class[Unit] = sys.error("stub") + override def getClass(): Class[Unit] = sys.error("stub") } object Unit extends AnyValCompanion { |