diff options
Diffstat (limited to 'src')
35 files changed, 332 insertions, 194 deletions
diff --git a/src/dotty/runtime/Arrays.scala b/src/dotty/runtime/Arrays.scala index e7f819df8..5767991e5 100644 --- a/src/dotty/runtime/Arrays.scala +++ b/src/dotty/runtime/Arrays.scala @@ -2,7 +2,7 @@ package dotty.runtime import scala.reflect.ClassTag -/** All but the first operation should be short-circuited and implemented specially by +/** All but the first two operations should be short-circuited and implemented specially by * the backend. */ object Arrays { @@ -12,7 +12,14 @@ object Arrays { */ def newGenericArray[T](length: Int)(implicit tag: ClassTag[T]): Array[T] = tag.newArray(length) - + + /** Convert a sequence to a Java array with element type given by `clazz`. */ + def seqToArray[T](xs: Seq[T], clazz: Class[_]): Array[T] = { + val arr = java.lang.reflect.Array.newInstance(clazz, xs.length).asInstanceOf[Array[T]] + xs.copyToArray(arr) + arr + } + /** Create an array of type T. T must be of form Array[E], with * E being a reference type. */ diff --git a/src/dotty/runtime/LazyHolders.scala b/src/dotty/runtime/LazyHolders.scala index 86c5d34ec..1e31cda66 100644 --- a/src/dotty/runtime/LazyHolders.scala +++ b/src/dotty/runtime/LazyHolders.scala @@ -3,38 +3,42 @@ package dotty.runtime /** * Classes used as holders for local lazy vals */ -class LazyInt(init: => Int) { - lazy val value = init +class LazyInt { + var value: Int = _ + @volatile var initialized: Boolean = false } -class LazyLong(init: => Long) { - lazy val value = init +class LazyLong { + var value: Long = _ + @volatile var initialized: Boolean = false } -class LazyBoolean(init: => Boolean) { - lazy val value = init +class LazyBoolean { + var value: Boolean = _ + @volatile var initialized: Boolean = false } -class LazyDouble(init: => Double) { - lazy val value = init +class LazyDouble { + var value: Double = _ + @volatile var initialized: Boolean = false } -class LazyFloat(init: => Float) { - lazy val value = init +class LazyByte { + var value: Byte = _ + @volatile var initialized: Boolean = false } -class LazyByte(init: => Byte) { - lazy val value = init +class LazyRef { + var value: AnyRef = _ + @volatile var initialized: Boolean = false } -class LazyRef(init: => AnyRef) { - lazy val value = init +class LazyShort { + var value: Short = _ + @volatile var initialized: Boolean = false } -class LazyShort(init: => Short) { - lazy val value = init -} - -class LazyChar(init: => Char) { - lazy val value = init +class LazyChar { + var value: Char = _ + @volatile var initialized: Boolean = false } diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 672e00a5c..14408ce7d 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -282,6 +282,9 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{ Some(tpd.ref(prefix).select(i.symbol)) case TermRef(prefix: ThisType, name) => Some(tpd.This(prefix.cls).select(i.symbol)) + case TermRef(NoPrefix, name) => + if(i.symbol is Flags.Method) Some(This(i.symbol.enclosingClass).select(i.symbol)) // workaround #342 todo: remove after fixed + else None case _ => None } } diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index c5c1d8713..721b52b2e 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -52,7 +52,8 @@ class Compiler { List(new PatternMatcher, new ExplicitOuter, new Splitter), - List(new ElimByName, + List(new LazyVals, + new ElimByName, new SeqLiterals, new InterceptedMethods, new Literalize, @@ -60,7 +61,7 @@ class Compiler { new ResolveSuper), List(new Erasure), List(new Mixin, - new Memoize, // TODO: Make LazyVals a part of this phase + new Memoize, new CapturedVars, new Constructors), List(new LambdaLift, diff --git a/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/src/dotty/tools/dotc/ast/TreeTypeMap.scala index 846c661f5..98027cd39 100644 --- a/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -170,7 +170,7 @@ final class TreeTypeMap( val symsChanged = syms ne mapped val substMap = withSubstitution(syms, mapped) val fullMap = (substMap /: mapped.filter(_.isClass)) { (tmap, cls) => - val origDcls = cls.decls.toList + val origDcls = cls.info.decls.toList val mappedDcls = ctx.mapSymbols(origDcls, tmap) val tmap1 = tmap.withMappedSyms(origDcls, mappedDcls) if (symsChanged) (origDcls, mappedDcls).zipped.foreach(cls.asClass.replace) diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index a7c7ac3c6..5daeed0f8 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -64,7 +64,7 @@ class Definitions { private def newAliasType(name: TypeName, tpe: Type, flags: FlagSet = EmptyFlags): TypeSymbol = { val sym = newSymbol(ScalaPackageClass, name, flags, TypeAlias(tpe)) - ScalaPackageClass.preDecls.enter(sym) + ScalaPackageClass.currentPackageDecls.enter(sym) sym } diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala index cd1eacc91..70bcbdee6 100644 --- a/src/dotty/tools/dotc/core/Scopes.scala +++ b/src/dotty/tools/dotc/core/Scopes.scala @@ -93,7 +93,7 @@ object Scopes { /** Lookup next entry with same name as this one */ def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry - + /** Lookup a symbol */ final def lookup(name: Name)(implicit ctx: Context): Symbol = { val e = lookupEntry(name) @@ -138,7 +138,9 @@ object Scopes { } def implicitDecls(implicit ctx: Context): List[TermRef] = Nil - + + def openForMutations: MutableScope = unsupported("openForMutations") + final def toText(printer: Printer): Text = printer.toText(this) } @@ -374,6 +376,8 @@ object Scopes { } syms } + + override def openForMutations: MutableScope = this } /** Create a new scope */ @@ -404,7 +408,7 @@ object Scopes { /** The empty scope (immutable). */ object EmptyScope extends Scope { - override def lastEntry = null + override private[dotc] def lastEntry = null override def size = 0 override def nestingLevel = 0 override def toList = Nil diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 27aa00392..b7cc1e03f 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -226,6 +226,7 @@ object StdNames { val FAKE_LOCAL_THIS: N = "this$" val IMPLCLASS_CONSTRUCTOR: N = "$init$" val LAZY_LOCAL: N = "$lzy" + val LAZY_LOCAL_INIT: N = "$lzyINIT" val LAZY_FIELD_OFFSET: N = "OFFSET$" val LAZY_SLOW_SUFFIX: N = "$lzycompute" val LOCAL_SUFFIX: N = "$$local" @@ -469,6 +470,7 @@ object StdNames { val selectTerm: N = "selectTerm" val selectType: N = "selectType" val self: N = "self" + val seqToArray: N = "seqToArray" val setAccessible: N = "setAccessible" val setAnnotations: N = "setAnnotations" val setSymbol: N = "setSymbol" diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index c8fbb3d03..6b3532944 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -45,7 +45,7 @@ trait SymDenotations { this: Context => val owner = denot.owner.denot stillValid(owner) && ( !owner.isClass - || (owner.decls.lookupAll(denot.name) contains denot.symbol) + || (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) || denot.isSelfSym ) } catch { @@ -239,24 +239,31 @@ object SymDenotations { final def ensureCompleted()(implicit ctx: Context): Unit = info /** The symbols defined in this class or object. + * Careful! This coes not force the type, so is compilation order dependent. + * This method should be used only in the following circumstances: + * + * 1. When accessing type parameters or type parameter accessors (both are entered before + * completion). + * 2. When obtaining the current scope in order to enter, rename or delete something there. + * 3. When playing it safe in order not to raise CylicReferences, e.g. for printing things + * or taking more efficient shortcuts (e.g. the stillValid test). */ - final def decls(implicit ctx: Context): Scope = myInfo match { + final def unforcedDecls(implicit ctx: Context): Scope = myInfo match { case cinfo: LazyType => val knownDecls = cinfo.decls if (knownDecls ne EmptyScope) knownDecls - else { completeFrom(cinfo); decls } // complete-once + else { completeFrom(cinfo); unforcedDecls } // complete-once case _ => info.decls } /** If this is a package class, the symbols entered in it * before it is completed. (this is needed to eagerly enter synthetic * aliases such as AnyRef into a package class without forcing it. - * Right now, I believe the only usage is for the AnyRef alias - * in Definitions. + * Right now, the only usage is for the AnyRef alias in Definitions. */ - final def preDecls(implicit ctx: Context): MutableScope = myInfo match { - case pinfo: SymbolLoaders # PackageLoader => pinfo.preDecls - case _ => decls.asInstanceOf[MutableScope] + final private[core] def currentPackageDecls(implicit ctx: Context): MutableScope = myInfo match { + case pinfo: SymbolLoaders # PackageLoader => pinfo.currentDecls + case _ => unforcedDecls.openForMutations } // ------ Names ---------------------------------------------- @@ -1002,7 +1009,7 @@ object SymDenotations { def computeTypeParams = { if (ctx.erasedTypes || is(Module)) Nil // fast return for modules to avoid scanning package decls else if (this ne initial) initial.asSymDenotation.typeParams - else decls.filter(sym => + else unforcedDecls.filter(sym => (sym is TypeParam) && sym.owner == symbol).asInstanceOf[List[TypeSymbol]] } if (myTypeParams == null) myTypeParams = computeTypeParams @@ -1233,7 +1240,7 @@ object SymDenotations { def enter(sym: Symbol, scope: Scope = EmptyScope)(implicit ctx: Context): Unit = { val mscope = scope match { case scope: MutableScope => scope - case _ => decls.asInstanceOf[MutableScope] + case _ => unforcedDecls.openForMutations } if (this is PackageClass) { val entry = mscope.lookupEntry(sym.name) @@ -1263,7 +1270,7 @@ object SymDenotations { */ def replace(prev: Symbol, replacement: Symbol)(implicit ctx: Context): Unit = { require(!(this is Frozen)) - decls.asInstanceOf[MutableScope].replace(prev, replacement) + unforcedDecls.openForMutations.replace(prev, replacement) if (myMemberCache != null) myMemberCache invalidate replacement.name } @@ -1274,7 +1281,7 @@ object SymDenotations { */ def delete(sym: Symbol)(implicit ctx: Context) = { require(!(this is Frozen)) - info.decls.asInstanceOf[MutableScope].unlink(sym) + info.decls.openForMutations.unlink(sym) if (myMemberFingerPrint != FingerPrint.unknown) computeMemberFingerPrint if (myMemberCache != null) @@ -1286,7 +1293,7 @@ object SymDenotations { * have existing symbols. */ final def membersNamed(name: Name)(implicit ctx: Context): PreDenotation = { - val privates = decls.denotsNamed(name, selectPrivate) + val privates = info.decls.denotsNamed(name, selectPrivate) privates union nonPrivateMembersNamed(name).filterDisjoint(privates) } @@ -1316,7 +1323,7 @@ object SymDenotations { (memberFingerPrint contains name)) { Stats.record("computeNPMembersNamed after fingerprint") ensureCompleted() - val ownDenots = decls.denotsNamed(name, selectNonPrivate) + val ownDenots = info.decls.denotsNamed(name, selectNonPrivate) if (debugTrace) // DEBUG println(s"$this.member($name), ownDenots = $ownDenots") def collect(denots: PreDenotation, parents: List[TypeRef]): PreDenotation = parents match { @@ -1463,14 +1470,14 @@ object SymDenotations { override def primaryConstructor(implicit ctx: Context): Symbol = { val cname = if (this is ImplClass) nme.IMPLCLASS_CONSTRUCTOR else nme.CONSTRUCTOR - decls.denotsNamed(cname).last.symbol // denotsNamed returns Symbols in reverse order of occurrence + info.decls.denotsNamed(cname).last.symbol // denotsNamed returns Symbols in reverse order of occurrence } /** The parameter accessors of this class. Term and type accessors, * getters and setters are all returned int his list */ def paramAccessors(implicit ctx: Context): List[Symbol] = - decls.filter(_ is ParamAccessor).toList + unforcedDecls.filter(_ is ParamAccessor).toList /** If this class has the same `decls` scope reference in `phase` and * `phase.next`, install a new denotation with a cloned scope in `phase.next`. diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala index 76ba3885e..0ad34e16a 100644 --- a/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -148,13 +148,13 @@ class SymbolLoaders { override def sourceModule(implicit ctx: Context) = _sourceModule def description = "package loader " + classpath.name - private[core] val preDecls: MutableScope = newScope + private[core] val currentDecls: MutableScope = newScope def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { assert(root is PackageClass, root) def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' val pre = root.owner.thisType - root.info = ClassInfo(pre, root.symbol.asClass, Nil, preDecls, pre select sourceModule) + root.info = ClassInfo(pre, root.symbol.asClass, Nil, currentDecls, pre select sourceModule) if (!sourceModule.isCompleted) sourceModule.completer.complete(sourceModule) if (!root.isRoot) { @@ -162,7 +162,7 @@ class SymbolLoaders { if (!maybeModuleClass(classRep)) initializeFromClassPath(root.symbol, classRep) for (classRep <- classpath.classes) - if (maybeModuleClass(classRep) && !root.decls.lookup(classRep.name.toTypeName).exists) + if (maybeModuleClass(classRep) && !root.unforcedDecls.lookup(classRep.name.toTypeName).exists) initializeFromClassPath(root.symbol, classRep) } if (!root.isEmptyPackage) diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index bff743fea..f6e4119ea 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -25,7 +25,7 @@ import Denotations.{ Denotation, SingleDenotation, MultiDenotation } import collection.mutable import io.AbstractFile import language.implicitConversions -import util.DotClass +import util.{NoSource, DotClass} /** Creation methods for symbols */ trait Symbols { this: Context => @@ -192,7 +192,7 @@ trait Symbols { this: Context => def stubCompleter = new StubInfo() val normalizedOwner = if (owner is ModuleVal) owner.moduleClass else owner println(s"creating stub for ${name.show}, owner = ${normalizedOwner.denot.debugString}, file = $file") - println(s"decls = ${normalizedOwner.decls.toList.map(_.debugString).mkString("\n ")}") // !!! DEBUG + println(s"decls = ${normalizedOwner.unforcedDecls.toList.map(_.debugString).mkString("\n ")}") // !!! DEBUG //if (base.settings.debug.value) throw new Error() val stub = name match { case name: TermName => @@ -518,6 +518,8 @@ object Symbols { object NoSymbol extends Symbol(NoCoord) { denot = NoDenotation + + override def associatedFile(implicit ctx: Context): AbstractFile = NoSource.file } implicit class Copier[N <: Name](sym: Symbol { type ThisName = N })(implicit ctx: Context) { diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index e59c60959..998b4f944 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -141,7 +141,7 @@ class TypeApplications(val self: Type) extends AnyVal { case arg :: args1 => if (tparams.isEmpty) { println(s"applied type mismatch: $self $args, typeParams = $typeParams, tsym = ${self.typeSymbol.debugString}") // !!! DEBUG - println(s"precomplete decls = ${self.typeSymbol.decls.toList.map(_.denot).mkString("\n ")}") + println(s"precomplete decls = ${self.typeSymbol.unforcedDecls.toList.map(_.denot).mkString("\n ")}") } val tparam = tparams.head val arg1 = diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 9826a23ea..b40baafdf 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -41,7 +41,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi result } - /** For stastics: count how many isSubTypes are part of succesful comparisons */ + /** For statistics: count how many isSubTypes are part of successful comparisons */ private var successCount = 0 private var totalCount = 0 @@ -140,21 +140,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi private def firstTry(tp1: Type, tp2: Type): Boolean = tp2 match { case tp2: NamedType => - def compareHKOrAlias(info1: Type) = - tp2.name == tpnme.Apply && { - val lambda2 = tp2.prefix.LambdaClass(forcing = true) - lambda2.exists && !tp1.isLambda && - tp1.testLifted(lambda2.typeParams, isSubType(_, tp2.prefix)) - } || { - tp2.info match { - case info2: TypeAlias => isSubType(tp1, info2.alias) - case _ => info1 match { - case info1: TypeAlias => isSubType(info1.alias, tp2) - case NoType => secondTry(tp1, tp2) - case _ => thirdTryNamed(tp1, tp2) - } - } + def compareAlias(info1: Type) = tp2.info match { + case info2: TypeAlias => isSubType(tp1, info2.alias) + case _ => info1 match { + case info1: TypeAlias => isSubType(info1.alias, tp2) + case NoType => secondTry(tp1, tp2) + case _ => thirdTryNamed(tp1, tp2) } + } def compareNamed = { implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type tp1 match { @@ -183,9 +176,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi !tp1.isInstanceOf[WithFixedSym] && !tp2.isInstanceOf[WithFixedSym] ) || - compareHKOrAlias(tp1.info) + compareHK(tp1, tp2, inOrder = true) || + compareHK(tp2, tp1, inOrder = false) || + compareAlias(tp1.info) case _ => - compareHKOrAlias(NoType) + compareHK(tp2, tp1, inOrder = false) || + compareAlias(NoType) } } compareNamed @@ -243,7 +239,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case tp1: NamedType => tp1.info match { case info1: TypeAlias => isSubType(info1.alias, tp2) - case _ => thirdTry(tp1, tp2) + case _ => compareHK(tp1, tp2, inOrder = true) || thirdTry(tp1, tp2) + // Note: If we change the order here, doing compareHK first and following aliases second, + // we get a -Ycheck error when compiling dotc/transform. Need to investigate. } case tp1: PolyParam => def flagNothingBound = { @@ -460,6 +458,18 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi false } + /** If `projection` is of the form T # Apply where `T` is an instance of a Lambda class, + * and `other` is not a type lambda projection, then convert `other` to a type lambda `U`, and + * continue with `T <:< U` if `inOrder` is true and `U <:< T` otherwise. + */ + def compareHK(projection: NamedType, other: Type, inOrder: Boolean) = + projection.name == tpnme.Apply && { + val lambda = projection.prefix.LambdaClass(forcing = true) + lambda.exists && !other.isLambda && + other.testLifted(lambda.typeParams, + if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix)) + } + /** Returns true iff either `tp11 <:< tp21` or `tp12 <:< tp22`, trying at the same time * to keep the constraint as wide as possible. Specifically, if * @@ -524,7 +534,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case mbr: SingleDenotation => qualifies(mbr) case _ => mbr hasAltWith qualifies } - /*>|>*/ ctx.traceIndented(i"hasMatchingMember($tp1 . $name :? ${tp2.refinedInfo}) ${tp1.member(name).info.show} $rinfo2", subtyping) /*<|<*/ { + /*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${base.member(name).info.show} $rinfo2", subtyping) /*<|<*/ { memberMatches(base member name) || tp1.isInstanceOf[SingletonType] && { // special case for situations like: diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index e986e680d..6c87d44e6 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -419,6 +419,8 @@ object Types { if mt.paramTypes.isEmpty && (tp.symbol is Stable) => mt.resultType case tp1 => tp1 }) + case tp: PolyParam => + goParam(tp) case tp: TypeProxy => go(tp.underlying) case tp: ClassInfo => @@ -460,6 +462,16 @@ object Types { // loadClassWithPrivateInnerAndSubSelf in ShowClassTests go(tp.cls.typeRef) orElse d } + def goParam(tp: PolyParam) = { + val next = tp.underlying + ctx.typerState.constraint.entry(tp) match { + case bounds: TypeBounds if bounds ne next => + ctx.typerState.ephemeral = true + go(bounds.hi) + case _ => + go(next) + } + } def goAnd(l: Type, r: Type) = go(l) & (go(r), pre) def goOr(l: Type, r: Type) = go(l) | (go(r), pre) go(this) @@ -581,7 +593,7 @@ object Types { } /** Is this type close enough to that type so that members - * with the two type would override each other?d + * with the two types would override each other? * This means: * - Either both types are polytypes with the same number of * type parameters and their result types match after renaming @@ -668,14 +680,14 @@ object Types { case _ => this } - /** Widen type if it is unstable (i.e. an EpxprType, or Termref to unstable symbol */ + /** Widen type if it is unstable (i.e. an ExprType, or TermRef to unstable symbol */ final def widenIfUnstable(implicit ctx: Context): Type = stripTypeVar match { case tp: ExprType => tp.resultType.widenIfUnstable case tp: TermRef if !tp.symbol.isStable => tp.underlying.widenIfUnstable case _ => this } - /** Follow aliases and derefernces LazyRefs and instantiated TypeVars until type + /** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type * is no longer alias type, LazyRef, or instantiated type variable. */ final def dealias(implicit ctx: Context): Type = this match { @@ -694,7 +706,7 @@ object Types { case tp => tp } - /** Peform successive widenings and dealiasings until none can be applied anymore */ + /** Perform successive widenings and dealiasings until none can be applied anymore */ final def widenDealias(implicit ctx: Context): Type = { val res = this.widen.dealias if (res eq this) res else res.widenDealias @@ -891,7 +903,7 @@ object Types { * no symbol it tries `member` as an alternative. */ def typeParamNamed(name: TypeName)(implicit ctx: Context): Symbol = - classSymbol.decls.lookup(name) orElse member(name).symbol + classSymbol.unforcedDecls.lookup(name) orElse member(name).symbol /** If this is a prototype with some ignored component, reveal one more * layer of it. Otherwise the type itself. @@ -916,9 +928,9 @@ object Types { } /** Same as `subst` but follows aliases as a fallback. When faced with a reference - * to an alias type, where normal substiution does not yield a new type, the + * to an alias type, where normal substitution does not yield a new type, the * substitution is instead applied to the alias. If that yields a new type, - * this type is returned, outherwise the original type (not the alias) is returned. + * this type is returned, otherwise the original type (not the alias) is returned. * A use case for this method is if one wants to substitute the type parameters * of a class and also wants to substitute any parameter accessors that alias * the type parameters. @@ -1141,7 +1153,7 @@ object Types { def map(tm: TypeMap)(implicit ctx: Context): ProtoType } - /** Implementations of this trait cache the resukts of `narrow`. */ + /** Implementations of this trait cache the results of `narrow`. */ trait NarrowCached extends Type { private var myNarrow: TermRef = null override def narrow(implicit ctx: Context): TermRef = { @@ -1182,7 +1194,7 @@ object Types { * timing dependent. It should only be used if the outcome of the * essential computation does not depend on the symbol being present or not. * It's currently used to take an optimized path in substituters and - * type accumulators, as well as to be safe in diagnostiic printing. + * type accumulators, as well as to be safe in diagnostic printing. * Normally, it's better to use `symbol`, not `currentSymbol`. */ def currentSymbol(implicit ctx: Context) = @@ -2048,6 +2060,7 @@ object Types { unique(new ImplicitMethodType(paramNames, paramTypes)(resultTypeExp)) } + /** A by-name parameter type of the form `=> T`, or the type of a method with no parameter list. */ abstract case class ExprType(override val resultType: Type) extends CachedProxyType with TermType with MethodicType { override def underlying(implicit ctx: Context): Type = resultType @@ -2200,13 +2213,16 @@ object Types { // ------------ Type variables ---------------------------------------- - /** A type variable is essentially a switch that models some part of a substitution. + /** In a TypeApply tree, a TypeVar is created for each argument type to be inferred. + * Every type variable is referred to by exactly one inferred type parameter of some + * TypeApply tree. + * + * A type variable is essentially a switch that models some part of a substitution. * It is first linked to `origin`, a poly param that's in the current constraint set. * It can then be (once) instantiated to some other type. The instantiation is * recorded in the type variable itself, or else, if the current type state * is different from the variable's creation state (meaning unrolls are possible) - * in the current typer state. Every type variable is referred to by exactly - * one inferred type parameter in a TypeApply tree. + * in the current typer state. * * @param origin The parameter that's tracked by the type variable. * @param creatorState The typer state in which the variable was created. @@ -2571,7 +2587,7 @@ object Types { /** The type of an import clause tree */ case class ImportType(expr: Tree) extends UncachedGroundType - /** Sentinal for "missing type" */ + /** Sentinel for "missing type" */ case object NoType extends CachedGroundType { override def exists = false override def computeHash = hashSeed @@ -2739,7 +2755,7 @@ object Types { case tp @ AnnotatedType(annot, underlying) => val underlying1 = this(underlying) - if (underlying1 eq underlying) tp else underlying1 + if (underlying1 eq underlying) tp else tp.derivedAnnotatedType(mapOver(annot), underlying1) case tp @ WildcardType => tp.derivedWildcardType(mapOver(tp.optBounds)) diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index cc3d3eb7f..a8be0bb94 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -368,7 +368,7 @@ class ClassfileParser( val s = ctx.newSymbol( owner, expname, owner.typeParamCreationFlags, typeParamCompleter(index), coord = indexCoord(index)) - if (owner.isClass) owner.asClass.enter(s, owner.decls) + if (owner.isClass) owner.asClass.enter(s) tparams = tparams + (tpname -> s) sig2typeBounds(tparams, skiptvs = true) newTParams += s @@ -553,12 +553,15 @@ class ClassfileParser( newType } - /** Add a synthetic constructor and potentially also default getters which + /** Add synthetic constructor(s) and potentially also default getters which * reflects the fields of the annotation with given `classInfo`. * Annotations in Scala are assumed to get all their arguments as constructor * parameters. For Java annotations we need to fake it by making up the constructor. * Note that default getters have type Nothing. That's OK because we need * them only to signal that the corresponding parameter is optional. + * If the constructor takes as last parameter an array, it can also accept + * a vararg argument. We solve this by creating two constructors, one with + * an array, the other with a repeated parameter. */ def addAnnotationConstructor(classInfo: Type, tparams: List[Symbol] = Nil)(implicit ctx: Context): Unit = { def addDefaultGetter(attr: Symbol, n: Int) = @@ -574,21 +577,33 @@ class ClassfileParser( case classInfo: TempClassInfoType => val attrs = classInfo.decls.toList.filter(_.isTerm) val targs = tparams.map(_.typeRef) - val methType = MethodType( - attrs.map(_.name.asTermName), - attrs.map(_.info.resultType), - classRoot.typeRef.appliedTo(targs)) - val constr = ctx.newSymbol( + val paramNames = attrs.map(_.name.asTermName) + val paramTypes = attrs.map(_.info.resultType) + + def addConstr(ptypes: List[Type]) = { + val mtype = MethodType(paramNames, ptypes, classRoot.typeRef.appliedTo(targs)) + val constrType = if (tparams.isEmpty) mtype else TempPolyType(tparams, mtype) + val constr = ctx.newSymbol( owner = classRoot.symbol, name = nme.CONSTRUCTOR, flags = Flags.Synthetic, - info = if (tparams.isEmpty) methType else TempPolyType(tparams, methType) + info = constrType ).entered - for ((attr, i) <- attrs.zipWithIndex) - if (attr.hasAnnotation(defn.AnnotationDefaultAnnot)) { - constr.setFlag(Flags.HasDefaultParams) - addDefaultGetter(attr, i) - } + for ((attr, i) <- attrs.zipWithIndex) + if (attr.hasAnnotation(defn.AnnotationDefaultAnnot)) { + constr.setFlag(Flags.HasDefaultParams) + addDefaultGetter(attr, i) + } + } + + addConstr(paramTypes) + if (paramTypes.nonEmpty) + paramTypes.last match { + case defn.ArrayType(elemtp) => + addConstr(paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp)) + case _ => + } + } } diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 894ad8f80..160bf620c 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -340,7 +340,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: if (denot.exists && !denot1.exists) { // !!!DEBUG val alts = denot.alternatives map (d => d+":"+d.info+"/"+d.signature) System.err.println(s"!!! disambiguation failure: $alts") - val members = denot.alternatives.head.symbol.owner.decls.toList map (d => d+":"+d.info+"/"+d.signature) + val members = denot.alternatives.head.symbol.owner.info.decls.toList map (d => d+":"+d.info+"/"+d.signature) System.err.println(s"!!! all members: $members") } if (tag == EXTref) sym else sym.moduleClass @@ -442,7 +442,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ) owner.asClass.enter(sym, symScope(owner)) else if (isRefinementClass(owner)) - symScope(owner).asInstanceOf[MutableScope].enter(sym) + symScope(owner).openForMutations.enter(sym) sym } @@ -472,7 +472,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: val unpickler = new LocalUnpickler() withDecls symScope(cls) if (flags is ModuleClass) unpickler withSourceModule (implicit ctx => - cls.owner.decls.lookup(cls.name.sourceModuleName) + cls.owner.info.decls.lookup(cls.name.sourceModuleName) .suchThat(_ is Module).symbol) else unpickler } @@ -632,7 +632,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: // and also for the inner Transform class in all views. We fix it by // replacing the this with the appropriate super. if (sym.owner != thispre.cls) { - val overriding = thispre.cls.decls.lookup(sym.name) + val overriding = thispre.cls.info.decls.lookup(sym.name) if (overriding.exists && overriding != sym) { val base = pre.baseTypeWithArgs(sym.owner) assert(base.exists) diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index 1a6cc77b2..f34135431 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -371,7 +371,7 @@ class PlainPrinter(_ctx: Context) extends Printer { def toText(const: Constant): Text = const.tag match { case StringTag => "\"" + escapedString(const.value.toString) + "\"" - case ClazzTag => "classOf[" ~ toText(const.tpe) ~ "]" + case ClazzTag => "classOf[" ~ toText(const.tpe.firstBaseArgInfo(defn.ClassClass)) ~ "]" case CharTag => s"'${escapedChar(const.charValue)}'" case LongTag => const.longValue.toString + "L" case EnumTag => const.symbolValue.name.toString diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index ff56ae872..28131e1e9 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -3,12 +3,14 @@ package transform import core._ import Names._ +import StdNames.nme import Types._ import dotty.tools.dotc.transform.TreeTransforms.{AnnotationTransformer, TransformerInfo, MiniPhaseTransform, TreeTransformer} -import ast.Trees.flatten +import ast.Trees._ import Flags._ import Contexts.Context import Symbols._ +import Constants._ import Denotations._, SymDenotations._ import Decorators.StringInterpolators import dotty.tools.dotc.ast.tpd @@ -56,9 +58,33 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree = transformTypeOfTree(tree) - override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = - transformTypeOfTree(tree) // should also transform the tree if argument needs adaptation + override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = { + val args1 = tree.args.map { + case arg: Typed if isWildcardStarArg(arg) => + if (tree.fun.symbol.is(JavaDefined) && arg.expr.tpe.derivesFrom(defn.SeqClass)) + seqToArray(arg.expr) + else arg.expr + case arg => arg + } + transformTypeOfTree(cpy.Apply(tree)(tree.fun, args1)) + } + /** Convert sequence argument to Java array */ + private def seqToArray(tree: Tree)(implicit ctx: Context): Tree = tree match { + case SeqLiteral(elems) => + JavaSeqLiteral(elems) + case _ => + val elemType = tree.tpe.firstBaseArgInfo(defn.SeqClass) + var elemClass = elemType.classSymbol + if (defn.PhantomClasses contains elemClass) elemClass = defn.ObjectClass + ref(defn.DottyArraysModule) + .select(nme.seqToArray) + .appliedToType(elemType) + .appliedTo(tree, Literal(Constant(elemClass.typeRef))) + .ensureConforms(defn.ArrayType(elemType)) + // Because of phantomclasses, the Java array's type might not conform to the resturn type + } + override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = transformTypeOfTree(tree) diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index 933252ccd..a0370feca 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -443,7 +443,7 @@ object Erasure extends TypeTestsCasts{ if (isRequired) { // check for clashes - val clash: Option[Symbol] = oldSymbol.owner.decls.lookupAll(bridge.name).find { + val clash: Option[Symbol] = oldSymbol.owner.info.decls.lookupAll(bridge.name).find { sym => (sym.name eq bridge.name) && sym.info.widen =:= bridge.info.widen }.orElse( diff --git a/src/dotty/tools/dotc/transform/FullParameterization.scala b/src/dotty/tools/dotc/transform/FullParameterization.scala index 698a57c61..4b205e542 100644 --- a/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -85,13 +85,13 @@ trait FullParameterization { * * If a self type is present, $this has this self type as its type. */ - def fullyParameterizedType(info: Type, clazz: ClassSymbol)(implicit ctx: Context): Type = { + def fullyParameterizedType(info: Type, clazz: ClassSymbol, abstractOverClass: Boolean = true)(implicit ctx: Context): Type = { val (mtparamCount, origResult) = info match { case info @ PolyType(mtnames) => (mtnames.length, info.resultType) case info: ExprType => (0, info.resultType) case _ => (0, info) } - val ctparams = clazz.typeParams + val ctparams = if(abstractOverClass) clazz.typeParams else Nil val ctnames = ctparams.map(_.name.unexpandedName()) /** The method result type */ @@ -104,7 +104,7 @@ trait FullParameterization { /** Replace class type parameters by the added type parameters of the polytype `pt` */ def mapClassParams(tp: Type, pt: PolyType): Type = { val classParamsRange = (mtparamCount until mtparamCount + ctparams.length).toList - tp.substDealias(clazz.typeParams, classParamsRange map (PolyParam(pt, _))) + tp.substDealias(ctparams, classParamsRange map (PolyParam(pt, _))) } /** The bounds for the added type paraneters of the polytype `pt` */ @@ -141,19 +141,23 @@ trait FullParameterization { /** The type parameters (skolems) of the method definition `originalDef`, * followed by the class parameters of its enclosing class. */ - private def allInstanceTypeParams(originalDef: DefDef)(implicit ctx: Context): List[Symbol] = - originalDef.tparams.map(_.symbol) ::: originalDef.symbol.enclosingClass.typeParams + private def allInstanceTypeParams(originalDef: DefDef, abstractOverClass: Boolean)(implicit ctx: Context): List[Symbol] = + if (abstractOverClass) + originalDef.tparams.map(_.symbol) ::: originalDef.symbol.enclosingClass.typeParams + else originalDef.tparams.map(_.symbol) /** Given an instance method definition `originalDef`, return a * fully parameterized method definition derived from `originalDef`, which * has `derived` as symbol and `fullyParameterizedType(originalDef.symbol.info)` * as info. + * `abstractOverClass` defines weather the DefDef should abstract over type parameters + * of class that contained original defDef */ - def fullyParameterizedDef(derived: TermSymbol, originalDef: DefDef)(implicit ctx: Context): Tree = + def fullyParameterizedDef(derived: TermSymbol, originalDef: DefDef, abstractOverClass: Boolean = true)(implicit ctx: Context): Tree = polyDefDef(derived, trefs => vrefss => { val origMeth = originalDef.symbol val origClass = origMeth.enclosingClass.asClass - val origTParams = allInstanceTypeParams(originalDef) + val origTParams = allInstanceTypeParams(originalDef, abstractOverClass) val origVParams = originalDef.vparamss.flatten map (_.symbol) val thisRef :: argRefs = vrefss.flatten @@ -214,13 +218,13 @@ trait FullParameterization { }) /** A forwarder expression which calls `derived`, passing along - * - the type parameters and enclosing class parameters of `originalDef`, + * - if `abstractOverClass` the type parameters and enclosing class parameters of originalDef`, * - the `this` of the enclosing class, * - the value parameters of the original method `originalDef`. */ - def forwarder(derived: TermSymbol, originalDef: DefDef)(implicit ctx: Context): Tree = + def forwarder(derived: TermSymbol, originalDef: DefDef, abstractOverClass: Boolean = true)(implicit ctx: Context): Tree = ref(derived.termRef) - .appliedToTypes(allInstanceTypeParams(originalDef).map(_.typeRef)) + .appliedToTypes(allInstanceTypeParams(originalDef, abstractOverClass).map(_.typeRef)) .appliedTo(This(originalDef.symbol.enclosingClass.asClass)) .appliedToArgss(originalDef.vparamss.nestedMap(vparam => ref(vparam.symbol))) .withPos(originalDef.rhs.pos) diff --git a/src/dotty/tools/dotc/transform/Getters.scala b/src/dotty/tools/dotc/transform/Getters.scala index e018a45cc..918a92a04 100644 --- a/src/dotty/tools/dotc/transform/Getters.scala +++ b/src/dotty/tools/dotc/transform/Getters.scala @@ -58,7 +58,7 @@ class Getters extends MiniPhaseTransform with SymTransformer { thisTransform => } else d } - private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic + private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic | Lazy override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = if (tree.symbol is Method) DefDef(tree.symbol.asTerm, tree.rhs) else tree diff --git a/src/dotty/tools/dotc/transform/LambdaLift.scala b/src/dotty/tools/dotc/transform/LambdaLift.scala index c8dacd1d7..1363615a5 100644 --- a/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -275,7 +275,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform initFlags = local.flags | Private | maybeStatic | maybeNotJavaPrivate, info = liftedInfo(local)).installAfter(thisTransform) if (local.isClass) - for (member <- local.asClass.decls) + for (member <- local.asClass.info.decls) if (member.isConstructor) { val linfo = liftedInfo(member) if (linfo ne member.info) diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala index 7b6135dc0..dde086089 100644 --- a/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/src/dotty/tools/dotc/transform/LazyVals.scala @@ -12,23 +12,34 @@ import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform import dotty.tools.dotc.ast.Trees._ import dotty.tools.dotc.ast.{untpd, tpd} import dotty.tools.dotc.core.Constants.Constant -import dotty.tools.dotc.core.Types.MethodType +import dotty.tools.dotc.core.Types.{ExprType, NoType, MethodType} import dotty.tools.dotc.core.Names.Name -import dotty.runtime.LazyVals +import dotty.runtime.{LazyVals => RLazyVals} // dotty deviation import SymUtils._ import scala.collection.mutable.ListBuffer import dotty.tools.dotc.core.Denotations.SingleDenotation import dotty.tools.dotc.core.SymDenotations.SymDenotation -import dotty.tools.dotc.core.DenotTransformers.{IdentityDenotTransformer, DenotTransformer} +import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, IdentityDenotTransformer, DenotTransformer} -class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer { +class LazyVals extends MiniPhaseTransform with SymTransformer { import tpd._ - def transformer = new LazyValsTransform + def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = { + if(d is(Flags.Lazy, butNot = Flags.ModuleVal | Flags.Method)) { + // Method flag is set on lazy vals coming from Unpickler. They are already methods and shouldn't be transformed twice + d.copySymDenotation( + initFlags = d.flags | Flags.Method, + info = ExprType(d.info)) + } + else d + } + + def transformer = new LazyVals - val containerFlags = Flags.Synthetic | Flags.Mutable + val containerFlags = Flags.Synthetic | Flags.Mutable | Flags.Lazy + val initFlags = Flags.Synthetic | Flags.Method /** this map contains mutable state of transformation: OffsetDefs to be appended to companion object definitions, * and number of bits currently used */ @@ -72,9 +83,9 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer * dotty.runtime(eg dotty.runtime.LazyInt) */ def transformLocalValDef(x: ValDef)(implicit ctx: Context) = x match { - case x@ValDef(name, tpt, rhs) => - val valueInitter = rhs + case x@ValDef(name, tpt, valueInitter) => val holderName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL).toTermName + val initName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL_INIT).toTermName val tpe = x.tpe.widen val holderType = @@ -88,21 +99,35 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer else if (tpe isRef defn.ShortClass) "LazyShort" else "LazyRef" + val holderImpl = ctx.requiredClass("dotty.runtime." + holderType) - val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.symbol.coord) - val holderTree = ValDef(holderSymbol, New(holderImpl.typeRef, List(valueInitter.changeOwner(x.symbol, holderSymbol)))) + val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos) + val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType(Nil, tpe), coord = x.pos) + val result = ref(holderSymbol).select("value".toTermName) + val flag = ref(holderSymbol).select("initialized".toTermName) + val initer = valueInitter.changeOwner(x.symbol, initSymbol) + val initBody = + ref(holderSymbol).select(defn.Object_synchronized).appliedToType(tpe).appliedTo( + mkNonThreadSafeDef(result, flag, initer).ensureConforms(tpe)) + val initTree = DefDef(initSymbol, initBody) + val holderTree = ValDef(holderSymbol, New(holderImpl.typeRef, List())) val methodBody = { - val prefix = ref(holderSymbol).select("value".toTermName) - if (holderType != "LazyRef") prefix - else prefix.select(defn.Any_asInstanceOf).appliedToType(tpe) + tpd.If(flag, EmptyTree, ref(initSymbol)) + result.ensureConforms(tpe) } val methodTree = DefDef(x.symbol.asTerm, methodBody) ctx.debuglog(s"found a lazy val ${x.show},\n rewrote with ${holderTree.show}") - Thicket(holderTree, methodTree) + Thicket(holderTree, initTree, methodTree) } - /** Create non-threadsafe lazy accessor equivalent to such code + + override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context, info: TransformerInfo): List[tpd.Tree] = { + val (holders, stats) = trees.partition { _.symbol.flags == containerFlags} + holders:::stats + } + + /** Create non-threadsafe lazy accessor equivalent to such code * def methodSymbol() = { * if (flag) target * else { @@ -113,13 +138,11 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer * } */ - def mkNonThreadSafeDef(target: Symbol, flag: Symbol, rhs: Tree)(implicit ctx: Context) = { - val cond = ref(flag) - val exp = ref(target) - val setFlag = Assign(cond, Literal(Constants.Constant(true))) - val setTarget = Assign(exp, rhs) - val init = Block(List(setFlag, setTarget), exp) - If(cond, exp, init) + def mkNonThreadSafeDef(target: Tree, flag: Tree, rhs: Tree)(implicit ctx: Context) = { + val setFlag = Assign(flag, Literal(Constants.Constant(true))) + val setTarget = Assign(target, rhs) + val init = Block(List(setFlag, setTarget), target) + If(flag, target, init) } /** Create non-threadsafe lazy accessor for not-nullable types equivalent to such code @@ -155,7 +178,7 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer val flagName = ctx.freshName(name.toString + StdNames.nme.BITMAP_PREFIX).toTermName val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags, defn.BooleanType) val flag = ValDef(flagSymbol, Literal(Constants.Constant(false))) - val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(containerSymbol, flagSymbol, rhs)) + val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), rhs)) Thicket(List(containerTree, flag, slowPath)) } @@ -266,7 +289,7 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer val thiz = This(claz)(ctx.fresh.setOwner(claz)) val companion = claz.companionModule val helperModule = ctx.requiredModule("dotty.runtime.LazyVals") - val getOffset = Select(ref(helperModule), LazyVals.Names.getOffset.toTermName) + val getOffset = Select(ref(helperModule), RLazyVals.Names.getOffset.toTermName) var offsetSymbol: TermSymbol = null var flag: Tree = EmptyTree var ord = 0 @@ -274,7 +297,7 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer // compute or create appropriate offsetSymol, bitmap and bits used by current ValDef appendOffsetDefs.get(companion.name.moduleClassName) match { case Some(info) => - val flagsPerLong = 64 / LazyVals.BITS_PER_LAZY_VAL + val flagsPerLong = 64 / RLazyVals.BITS_PER_LAZY_VAL info.ord += 1 ord = info.ord % flagsPerLong val id = info.ord / flagsPerLong @@ -305,11 +328,11 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer val containerTree = ValDef(containerSymbol, initValue(tpe)) val offset = Select(ref(companion), offsetSymbol.name) - val getFlag = Select(ref(helperModule), LazyVals.Names.get.toTermName) - val setFlag = Select(ref(helperModule), LazyVals.Names.setFlag.toTermName) - val wait = Select(ref(helperModule), LazyVals.Names.wait4Notification.toTermName) - val state = Select(ref(helperModule), LazyVals.Names.state.toTermName) - val cas = Select(ref(helperModule), LazyVals.Names.cas.toTermName) + val getFlag = Select(ref(helperModule), RLazyVals.Names.get.toTermName) + val setFlag = Select(ref(helperModule), RLazyVals.Names.setFlag.toTermName) + val wait = Select(ref(helperModule), RLazyVals.Names.wait4Notification.toTermName) + val state = Select(ref(helperModule), RLazyVals.Names.state.toTermName) + val cas = Select(ref(helperModule), RLazyVals.Names.cas.toTermName) val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, rhs, tpe, offset, getFlag, state, cas, setFlag, wait) if(flag eq EmptyTree) diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala index 230763fae..7e307c736 100644 --- a/src/dotty/tools/dotc/transform/Mixin.scala +++ b/src/dotty/tools/dotc/transform/Mixin.scala @@ -148,13 +148,13 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred } def traitInits(mixin: ClassSymbol): List[Tree] = - for (getter <- mixin.decls.filter(getr => getr.isGetter && !wasDeferred(getr)).toList) + for (getter <- mixin.info.decls.filter(getr => getr.isGetter && !wasDeferred(getr)).toList) yield { DefDef(implementation(getter.asTerm), superRef(initializer(getter)).appliedToNone) } def setters(mixin: ClassSymbol): List[Tree] = - for (setter <- mixin.decls.filter(setr => setr.isSetter && !wasDeferred(setr)).toList) + for (setter <- mixin.info.decls.filter(setr => setr.isSetter && !wasDeferred(setr)).toList) yield DefDef(implementation(setter.asTerm), unitLiteral.withPos(cls.pos)) cpy.Template(impl)( diff --git a/src/dotty/tools/dotc/transform/OverridingPairs.scala b/src/dotty/tools/dotc/transform/OverridingPairs.scala index bc3c085a9..f631dcf9a 100644 --- a/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -53,7 +53,7 @@ object OverridingPairs { def fillDecls(bcs: List[Symbol], deferred: Boolean): Unit = bcs match { case bc :: bcs1 => fillDecls(bcs1, deferred) - var e = bc.info.decls.asInstanceOf[MutableScope].lastEntry + var e = bc.info.decls.lastEntry while (e != null) { if (e.sym.is(Deferred) == deferred && !exclude(e.sym)) decls.enter(e.sym) diff --git a/src/dotty/tools/dotc/transform/ResolveSuper.scala b/src/dotty/tools/dotc/transform/ResolveSuper.scala index 9f952f6de..953c8b74d 100644 --- a/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -75,7 +75,7 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th import ops._ def superAccessors(mixin: ClassSymbol): List[Tree] = - for (superAcc <- mixin.decls.filter(_ is SuperAccessor).toList) + for (superAcc <- mixin.info.decls.filter(_ is SuperAccessor).toList) yield polyDefDef(implementation(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc))) def methodOverrides(mixin: ClassSymbol): List[Tree] = { @@ -84,7 +84,7 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th meth.is(Method, butNot = PrivateOrDeferred) && !isOverridden(meth) && !meth.allOverriddenSymbols.forall(_ is Deferred) - for (meth <- mixin.decls.toList if needsDisambiguation(meth)) + for (meth <- mixin.info.decls.toList if needsDisambiguation(meth)) yield polyDefDef(implementation(meth.asTerm), forwarder(meth)) } diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index f727201b2..0d89e9d74 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -146,7 +146,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this if (needsExpansion(s)) { ctx.deprecationWarning(s"private qualified with a class has been deprecated, use package enclosing ${s.privateWithin} instead", s.pos) /* disabled for now - decls.asInstanceOf[MutableScope].unlink(s) + decls.openForMutations.unlink(s) s.copySymDenotation(name = s.name.expandedName(s.privateWithin)) .installAfter(thisTransformer) decls1.enter(s)(nextCtx) diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala index 9274150b1..0a5854ea7 100644 --- a/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/src/dotty/tools/dotc/transform/SymUtils.scala @@ -80,7 +80,7 @@ class SymUtils(val self: Symbol) extends AnyVal { self.owner.info.decl(name).suchThat(_ is Accessor).symbol def caseAccessors(implicit ctx:Context) = - self.decls.filter(_ is CaseAccessor).toList + self.info.decls.filter(_ is CaseAccessor).toList def getter(implicit ctx: Context): Symbol = if (self.isGetter) self else accessorNamed(self.asTerm.name.getterName) diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala index f4e95830d..b747636c7 100644 --- a/src/dotty/tools/dotc/transform/TailRec.scala +++ b/src/dotty/tools/dotc/transform/TailRec.scala @@ -74,23 +74,25 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete final val labelPrefix = "tailLabel" final val labelFlags = Flags.Synthetic | Flags.Label - private def mkLabel(method: Symbol)(implicit c: Context): TermSymbol = { + private def mkLabel(method: Symbol, abstractOverClass: Boolean)(implicit c: Context): TermSymbol = { val name = c.freshName(labelPrefix) - c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass)) + c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass)) } override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + val sym = tree.symbol tree match { case dd@DefDef(name, tparams, vparamss0, tpt, rhs0) - if (dd.symbol.isEffectivelyFinal) && !((dd.symbol is Flags.Accessor) || (rhs0 eq EmptyTree) || (dd.symbol is Flags.Label)) => - val mandatory = dd.symbol.hasAnnotation(defn.TailrecAnnotationClass) + if (sym.isEffectivelyFinal) && !((sym is Flags.Accessor) || (rhs0 eq EmptyTree) || (sym is Flags.Label)) => + val mandatory = sym.hasAnnotation(defn.TailrecAnnotationClass) atGroupEnd { implicit ctx: Context => cpy.DefDef(dd)(rhs = { - val origMeth = tree.symbol - val label = mkLabel(dd.symbol) + val defIsTopLevel = sym.owner.isClass + val origMeth = sym + val label = mkLabel(sym, abstractOverClass = defIsTopLevel) val owner = ctx.owner.enclosingClass.asClass val thisTpe = owner.thisType.widen @@ -101,7 +103,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete // and second one will actually apply, // now this speculatively transforms tree and throws away result in many cases val rhsSemiTransformed = { - val transformer = new TailRecElimination(dd.symbol, owner, thisTpe, mandatory, label) + val transformer = new TailRecElimination(origMeth, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel) val rhs = atGroupEnd(transformer.transform(rhs0)(_)) rewrote = transformer.rewrote rhs @@ -109,8 +111,8 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete if (rewrote) { val dummyDefDef = cpy.DefDef(tree)(rhs = rhsSemiTransformed) - val res = fullyParameterizedDef(label, dummyDefDef) - val call = forwarder(label, dd) + val res = fullyParameterizedDef(label, dummyDefDef, abstractOverClass = defIsTopLevel) + val call = forwarder(label, dd, abstractOverClass = defIsTopLevel) Block(List(res), call) } else { if (mandatory) @@ -130,7 +132,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete } - class TailRecElimination(method: Symbol, enclosingClass: Symbol, thisType: Type, isMandatory: Boolean, label: Symbol) extends tpd.TreeMap { + class TailRecElimination(method: Symbol, enclosingClass: Symbol, thisType: Type, isMandatory: Boolean, label: Symbol, abstractOverClass: Boolean) extends tpd.TreeMap { import dotty.tools.dotc.ast.tpd._ @@ -179,9 +181,11 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete val targs = typeArguments.map(noTailTransform) val argumentss = arguments.map(noTailTransforms) - val receiverIsSame = enclosingClass.typeRef.widen =:= recv.tpe.widen - val receiverIsSuper = (method.name eq sym) && enclosingClass.typeRef.widen <:< recv.tpe.widen - val receiverIsThis = recv.tpe.widen =:= thisType + val recvWiden = recv.tpe.widenDealias + + val receiverIsSame = enclosingClass.typeRef.widenDealias =:= recvWiden + val receiverIsSuper = (method.name eq sym) && enclosingClass.typeRef.widen <:< recvWiden + val receiverIsThis = recv.tpe =:= thisType val isRecursiveCall = (method eq sym) @@ -204,9 +208,13 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete c.debuglog("Rewriting tail recursive call: " + tree.pos) rewrote = true val reciever = noTailTransform(recv) - val classTypeArgs = recv.tpe.baseTypeWithArgs(enclosingClass).argInfos - val trz = classTypeArgs.map(x => ref(x.typeSymbol)) - val callTargs: List[tpd.Tree] = targs ::: trz + + val callTargs: List[tpd.Tree] = + if(abstractOverClass) { + val classTypeArgs = recv.tpe.baseTypeWithArgs(enclosingClass).argInfos + targs ::: classTypeArgs.map(x => ref(x.typeSymbol)) + } else targs + val method = Apply(if (callTargs.nonEmpty) TypeApply(Ident(label.termRef), callTargs) else Ident(label.termRef), List(reciever)) diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index 8e8cf58f9..2ed720f83 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -96,7 +96,7 @@ object ErrorReporting { def patternConstrStr(tree: Tree): String = ??? def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree = { - errorTree(tree, typeMismatchStr(tree.tpe, pt) + implicitFailure.postscript) + errorTree(tree, typeMismatchStr(normalize(tree.tpe, pt), pt) + implicitFailure.postscript) } /** A subtype log explaining why `found` does not conform to `expected` */ diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 5111f10bd..53968ae91 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -337,25 +337,29 @@ trait ImplicitRunInfo { self: RunInfo => /** The implicit scope of type `tp` * @param isLifted Type `tp` is the result of a `liftToClasses` application */ - def iscope(tp: Type, isLifted: Boolean = false): OfTypeImplicits = + def iscope(tp: Type, isLifted: Boolean = false): OfTypeImplicits = { + def computeIScope(cacheResult: Boolean) = { + val savedEphemeral = ctx.typerState.ephemeral + ctx.typerState.ephemeral = false + try { + val liftedTp = if (isLifted) tp else liftToClasses(tp) + val result = + if (liftedTp ne tp) iscope(liftedTp, isLifted = true) + else ofTypeImplicits(collectCompanions(tp)) + if (ctx.typerState.ephemeral) record("ephemeral cache miss: implicitScope") + else if(cacheResult) implicitScopeCache(tp) = result + result + } + finally ctx.typerState.ephemeral |= savedEphemeral + } + if (tp.hash == NotCached || !Config.cacheImplicitScopes) - ofTypeImplicits(collectCompanions(tp)) + computeIScope(cacheResult = false) else implicitScopeCache get tp match { case Some(is) => is - case None => - val savedEphemeral = ctx.typerState.ephemeral - ctx.typerState.ephemeral = false - try { - val liftedTp = if (isLifted) tp else liftToClasses(tp) - val result = - if (liftedTp ne tp) iscope(liftedTp, isLifted = true) - else ofTypeImplicits(collectCompanions(tp)) - if (ctx.typerState.ephemeral) record("ephemeral cache miss: implicitScope") - else implicitScopeCache(tp) = result - result - } - finally ctx.typerState.ephemeral |= savedEphemeral - } + case None => computeIScope(cacheResult = true) + } + } iscope(tp) } diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index e41b2d194..38c1e49c5 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -99,6 +99,7 @@ trait Inferencing { this: Checking => /** Recursively widen and also follow type declarations and type aliases. */ def widenForMatchSelector(tp: Type)(implicit ctx: Context): Type = tp.widen match { case tp: TypeRef if !tp.symbol.isClass => widenForMatchSelector(tp.info.bounds.hi) + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, widenForMatchSelector(tp.tpe)) case tp => tp } diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 323a1100b..854af688a 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -27,7 +27,7 @@ trait NamerContextOps { this: Context => def enter(sym: Symbol): Symbol = { ctx.owner match { case cls: ClassSymbol => cls.enter(sym) - case _ => this.scope.asInstanceOf[MutableScope].enter(sym) + case _ => this.scope.openForMutations.enter(sym) } sym } @@ -37,7 +37,7 @@ trait NamerContextOps { this: Context => if (owner.isClass) if (outer.owner == owner) { // inner class scope; check whether we are referring to self if (scope.size == 1) { - val elem = scope.asInstanceOf[MutableScope].lastEntry + val elem = scope.lastEntry if (elem.name == name) return elem.sym.denot // return self } assert(scope.size <= 1, scope) @@ -52,7 +52,7 @@ trait NamerContextOps { this: Context => * the declarations of the current class. */ def effectiveScope: Scope = - if (owner != null && owner.isClass) owner.asClass.decls + if (owner != null && owner.isClass) owner.asClass.unforcedDecls else scope /** The symbol (stored in some typer's symTree) of an enclosing context definition */ @@ -306,7 +306,7 @@ class Namer { typer: Typer => val localCtx: Context = ctx.fresh.setNewScope selfInfo match { case sym: Symbol if sym.exists && sym.name != nme.WILDCARD => - localCtx.scope.asInstanceOf[MutableScope].enter(sym) + localCtx.scope.openForMutations.enter(sym) case _ => } localCtx @@ -656,6 +656,7 @@ class Namer { typer: Typer => (paramSymss :\ restpe1) { (params, restpe) => val make = if (params.nonEmpty && (params.head is Implicit)) ImplicitMethodType + else if (ddef.mods.is(JavaDefined)) JavaMethodType else MethodType make.fromSymbols(params, restpe) } diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 46aa2e953..f4b0ef4f2 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -43,7 +43,7 @@ trait TypeAssigner { } def apply(tp: Type) = tp match { case tp: TermRef if toAvoid(tp) && variance > 0 => - apply(tp.info) + apply(tp.info.widenExpr) case tp: TypeRef if (forbidden contains tp.symbol) || toAvoid(tp.prefix) => tp.info match { case TypeAlias(ref) => diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 9958b3b64..ce07ba74c 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -454,7 +454,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def classLeaks(sym: ClassSymbol): Boolean = (ctx.owner is Method) || // can't hoist classes out of method bodies (sym.info.parents exists typeLeaks) || - (sym.decls.toList exists (t => typeLeaks(t.info))) + (sym.info.decls.toList exists (t => typeLeaks(t.info))) leakingTypes(block.tpe) } |