diff options
34 files changed, 214 insertions, 153 deletions
diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala index 973e50e8e..a9ae34213 100644 --- a/src/dotty/tools/dotc/TypeErasure.scala +++ b/src/dotty/tools/dotc/TypeErasure.scala @@ -108,7 +108,9 @@ object TypeErasure { def erasedRef(tp: Type)(implicit ctx: Context): Type = tp match { case tp: TermRef => assert(tp.symbol.exists, tp) - TermRef(erasedRef(tp.prefix), tp.symbol.asTerm) + val tp1 = ctx.makePackageObjPrefixExplicit(tp) + if (tp1 ne tp) erasedRef(tp1) + else TermRef(erasedRef(tp.prefix), tp.symbol.asTerm) case tp: ThisType => tp case tp => 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/config/CompilerCommand.scala b/src/dotty/tools/dotc/config/CompilerCommand.scala index ec8b17b0d..aa8e7abbf 100644 --- a/src/dotty/tools/dotc/config/CompilerCommand.scala +++ b/src/dotty/tools/dotc/config/CompilerCommand.scala @@ -19,11 +19,13 @@ object CompilerCommand extends DotClass { |Where multiple values are accepted, they should be comma-separated. | example: -Xplugin:plugin1,plugin2 |<phases> means one or a comma-separated list of: - | (partial) phase names, phase ids, phase id ranges, or the string "all". + | - (partial) phase names with an optional "+" suffix to include the next phase + | - the string "all" | example: -Xprint:all prints all phases. - | example: -Xprint:expl,24-26 prints phases explicitouter, closelim, dce, jvm. - | example: -Xprint:-4 prints only the phases up to typer. - | + | example: -Xprint:front,mixin prints the frontend and mixin phases. + | example: -Ylog:erasure+ logs the erasure phase and the phase after the erasure phase. + | This is useful because during the tree transform of phase X, we often + | already are in phase X+1. """.stripMargin.trim + "\n" def shortUsage = s"Usage: $cmdName <options> <source files>" diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 98a71dd98..635390ef5 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -146,6 +146,11 @@ object Contexts { protected def diagnostics_=(diagnostics: Option[StringBuilder]) = _diagnostics = diagnostics def diagnostics: Option[StringBuilder] = _diagnostics + /** The current bounds in force for type parameters appearing in a GADT */ + private var _gadt: GADTMap = _ + protected def gadt_=(gadt: GADTMap) = _gadt = gadt + def gadt: GADTMap = _gadt + /** A map in which more contextual properties can be stored */ private var _moreProperties: Map[String, Any] = _ protected def moreProperties_=(moreProperties: Map[String, Any]) = _moreProperties = moreProperties @@ -418,6 +423,8 @@ object Contexts { def setSetting[T](setting: Setting[T], value: T): this.type = setSettings(setting.updateIn(sstate, value)) + def setFreshGADTBounds: this.type = { this.gadt = new GADTMap(gadt.bounds); this } + def setDebug = setSetting(base.settings.debug, true) } @@ -439,6 +446,7 @@ object Contexts { moreProperties = Map.empty typeComparer = new TypeComparer(this) searchHistory = new SearchHistory(0, Map()) + gadt = new GADTMap(SimpleMap.Empty) } object NoContext extends Context { @@ -593,6 +601,13 @@ object Contexts { implicit val ctx: Context = initctx } + class GADTMap(initBounds: SimpleMap[Symbol, TypeBounds]) { + private var myBounds = initBounds + def setBounds(sym: Symbol, b: TypeBounds): Unit = + myBounds = myBounds.updated(sym, b) + def bounds = myBounds + } + /** Initial size of superId table */ private final val InitialSuperIdsSize = 4096 diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index e0d7fae33..882729063 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -128,15 +128,22 @@ object Decorators { def show(implicit ctx: Context) = text.mkString(ctx.settings.pageWidth.value) } - /** Implements a test whether a list of strings representing phases contains - * a given phase. The test returns true if the given phase starts with - * one of the names in the list of strings, or if the list of strings - * contains "all". + /** Test whether a list of strings representing phases contains + * a given phase. See [[config.CompilerCommand#explainAdvanced]] for the + * exact meaning of "contains" here. */ implicit class PhaseListDecorator(val names: List[String]) extends AnyVal { - def containsPhase(phase: Phase): Boolean = phase match { + def containsPhase(phase: Phase): Boolean = phase match { case phase: TreeTransformer => phase.transformations.exists(trans => containsPhase(trans.phase)) - case _ => names exists (n => n == "all" || phase.phaseName.startsWith(n)) + case _ => + names exists { name => + name == "all" || { + val strippedName = name.stripSuffix("+") + val logNextPhase = name ne strippedName + phase.phaseName.startsWith(strippedName) || + (logNextPhase && phase.prev.phaseName.startsWith(strippedName)) + } + } } } 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/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 0e86a2936..53beae838 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -301,9 +301,6 @@ object Flags { /** Method is assumed to be stable */ final val Stable = termFlag(24, "<stable>") - /** Info can be refined during GADT pattern match */ - final val GADTFlexType = typeFlag(24, "<gadt-flex-type>") - /** A case parameter accessor */ final val CaseAccessor = termFlag(25, "<caseaccessor>") @@ -553,7 +550,7 @@ object Flags { /** A Java interface, potentially with default methods */ final val JavaTrait = allOf(JavaDefined, Trait, NoInits) - + /** A Java interface */ final val JavaInterface = allOf(JavaDefined, Trait) 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/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index eccdcbfb9..b4927b5d4 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 { @@ -234,24 +234,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 ---------------------------------------------- @@ -997,7 +1004,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 @@ -1228,7 +1235,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) @@ -1258,7 +1265,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 } @@ -1269,7 +1276,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) @@ -1281,7 +1288,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) } @@ -1311,7 +1318,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 { @@ -1458,14 +1465,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 9be75c11a..13b61c0fd 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -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 => @@ -450,31 +450,6 @@ object Symbols { */ def pos: Position = if (coord.isPosition) coord.toPosition else NoPosition -// -------- GADT handling ----------------------------------------------- - - /** Perform given operation `op` where this symbol allows tightening of - * its type bounds. - */ - private[dotc] def withGADTFlexType[T](op: () => T)(implicit ctx: Context): () => T = { () => - assert((denot is TypeParam) && denot.owner.isTerm) - val saved = denot - denot = denot.copySymDenotation(initFlags = denot.flags | GADTFlexType) - try op() - finally denot = saved - } - - /** Disallow tightening of type bounds for this symbol from now on */ - private[dotc] def resetGADTFlexType()(implicit ctx: Context): Unit = { - assert(denot is GADTFlexType) - denot = denot.copySymDenotation(initFlags = denot.flags &~ GADTFlexType) - } - - /** Change info of this symbol to new, tightened type bounds */ - private[core] def changeGADTInfo(bounds: TypeBounds)(implicit ctx: Context): Unit = { - assert(denot is GADTFlexType) - denot = denot.copySymDenotation(info = bounds) - } - // -------- Printing -------------------------------------------------------- /** The prefix string to be used when displaying this symbol without denotation */ diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 6443c5054..539ef5e0d 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 34f9bfbb9..cae4500e4 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -618,9 +618,12 @@ class TypeComparer(initctx: Context) extends DotClass { secondTry(OrType.make(derivedRef(tp11), derivedRef(tp12)), tp2) */ case TypeBounds(lo1, hi1) => - if ((ctx.mode is Mode.GADTflexible) && (tp1.symbol is GADTFlexType) && - !isSubTypeWhenFrozen(hi1, tp2)) - trySetType(tp1, TypeBounds(lo1, hi1 & tp2)) + val gbounds1 = ctx.gadt.bounds(tp1.symbol) + if (gbounds1 != null) + isSubTypeWhenFrozen(gbounds1.hi, tp2) || + (ctx.mode is Mode.GADTflexible) && + narrowGADTBounds(tp1, TypeBounds(gbounds1.lo, gbounds1.hi & tp2)) || + tryRebase2nd else if (lo1 eq hi1) isSubType(hi1, tp2) else tryRebase2nd case _ => @@ -637,9 +640,12 @@ class TypeComparer(initctx: Context) extends DotClass { } def compareNamed: Boolean = tp2.info match { case TypeBounds(lo2, hi2) => - if ((ctx.mode is Mode.GADTflexible) && (tp2.symbol is GADTFlexType) && - !isSubTypeWhenFrozen(tp1, lo2)) - trySetType(tp2, TypeBounds(lo2 | tp1, hi2)) + val gbounds2 = ctx.gadt.bounds(tp2.symbol) + if (gbounds2 != null) + isSubTypeWhenFrozen(tp1, gbounds2.lo) || + (ctx.mode is Mode.GADTflexible) && + narrowGADTBounds(tp2, TypeBounds(gbounds2.lo | tp1, gbounds2.hi)) || + tryRebase3rd else ((frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2) || tryRebase3rd) @@ -912,9 +918,9 @@ class TypeComparer(initctx: Context) extends DotClass { tp.exists && !tp.isLambda } - def trySetType(tr: NamedType, bounds: TypeBounds): Boolean = + def narrowGADTBounds(tr: NamedType, bounds: TypeBounds): Boolean = isSubType(bounds.lo, bounds.hi) && - { tr.symbol.changeGADTInfo(bounds); true } + { ctx.gadt.setBounds(tr.symbol, bounds); true } // Tests around `matches` diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index 8190b8cb6..260e2f6d6 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -2,7 +2,7 @@ package dotty.tools.dotc package core import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._ -import SymDenotations._ +import SymDenotations._, Denotations.Denotation import config.Printers._ import Decorators._ import StdNames._ @@ -224,6 +224,25 @@ trait TypeOps { this: Context => cls.enter(sym, decls) } + /** If `tpe` is of the form `p.x` where `p` refers to a package + * but `x` is not owned by a package, expand it to + * + * p.package.x + */ + def makePackageObjPrefixExplicit(tpe: NamedType): Type = { + def tryInsert(pkgClass: SymDenotation): Type = pkgClass match { + case pkgCls: PackageClassDenotation if !(tpe.symbol.maybeOwner is Package) => + tpe.derivedSelect(pkgCls.packageObj.valRef) + case _ => + tpe + } + tpe.prefix match { + case pre: ThisType if pre.cls is Package => tryInsert(pre.cls) + case pre: TermRef if pre.symbol is Package => tryInsert(pre.symbol.moduleClass) + case _ => tpe + } + } + /** If we have member definitions * * type argSym v= from diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index a1ca7796f..e520ea172 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -895,7 +895,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. @@ -2515,10 +2515,7 @@ object Types { object TypeAlias { def apply(alias: Type, variance: Int = 0)(implicit ctx: Context) = ctx.uniqueTypeAliases.enterIfNew(alias, variance) - def unapply(tp: TypeAlias): Option[Type] = tp match { - case tp: TypeAlias => Some(tp.alias) - case _ => None - } + def unapply(tp: TypeAlias): Option[Type] = Some(tp.alias) } // ----- Annotated and Import types ----------------------------------------------- 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 728048700..f7aef3aaf 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -343,7 +343,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 @@ -445,7 +445,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 } @@ -475,7 +475,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 } @@ -637,7 +637,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/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala index dc6d8c6ab..41f007e66 100644 --- a/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/src/dotty/tools/dotc/reporting/Reporter.scala @@ -101,16 +101,12 @@ trait Reporting { this: Context => def incompleteInputError(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = reporter.incomplete(new Error(msg, pos))(ctx) - /** Log msg if current phase or its precedessor is mentioned in - * settings.log. - * The reason we also pick the predecessor is that during the - * tree transform of phase X, we often are already in phase X+1. - * It's convenient to have logging work independently of whether - * we have advanced the phase or not. + /** Log msg if settings.log contains the current phase. + * See [[config.CompilerCommand#explainAdvanced]] for the exact meaning of + * "contains" here. */ def log(msg: => String): Unit = - if (this.settings.log.value.containsPhase(phase) || - this.settings.log.value.containsPhase(phase.prev)) + if (this.settings.log.value.containsPhase(phase)) echo(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg") def debuglog(msg: => String): Unit = 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/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/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/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 86376356c..ea2fd40de 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 diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 445987e0d..f4b0ef4f2 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -112,21 +112,6 @@ trait TypeAssigner { * that the package object shows up as the prefix. */ def ensureAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = { - - def tryInsertPackageObj(tpe: NamedType, d: Denotation): Type = { - def tryInsert(pkgClass: SymDenotation): Type = pkgClass match { - case pkgCls: PackageClassDenotation if !(d.symbol.maybeOwner is Package) => - tpe.derivedSelect(pkgCls.packageObj.valRef) - case _ => - tpe - } - tpe.prefix match { - case pre: ThisType if pre.cls is Package => tryInsert(pre.cls) - case pre: TermRef if pre.symbol is Package => tryInsert(pre.symbol.moduleClass) - case _ => tpe - } - } - def test(tpe: Type, firstTry: Boolean): Type = tpe match { case tpe: NamedType => val pre = tpe.prefix @@ -159,7 +144,7 @@ trait TypeAssigner { else if (d.symbol is TypeParamAccessor) // always dereference type param accessors ensureAccessible(d.info.bounds.hi, superAccess, pos) else - tryInsertPackageObj(tpe withDenot d, d) + ctx.makePackageObjPrefixExplicit(tpe withDenot d) case _ => tpe } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 5d388e7de..dedff0e3a 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) } @@ -628,10 +628,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedCases(cases: List[untpd.CaseDef], selType: Type, pt: Type)(implicit ctx: Context) = { /** gadtSyms = "all type parameters of enclosing methods that appear - * non-variantly in the selector type" todo: should typevars - * which appear with variances +1 and -1 (in different - * places) be considered as well? - */ + * non-variantly in the selector type" todo: should typevars + * which appear with variances +1 and -1 (in different + * places) be considered as well? + */ val gadtSyms: Set[Symbol] = ctx.traceIndented(i"GADT syms of $selType", gadts) { val accu = new TypeAccumulator[Set[Symbol]] { def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = { @@ -650,9 +650,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit cases mapconserve (typedCase(_, pt, selType, gadtSyms)) } + /** Type a case. Overridden in ReTyper, that's why it's separate from + * typedCases. + */ def typedCase(tree: untpd.CaseDef, pt: Type, selType: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = track("typedCase") { + val originalCtx = ctx + def caseRest(pat: Tree)(implicit ctx: Context) = { - gadtSyms foreach (_.resetGADTFlexType) pat foreachSubTree { case b: Bind => if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol) @@ -661,11 +665,21 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val guard1 = typedExpr(tree.guard, defn.BooleanType) val body1 = typedExpr(tree.body, pt) + .ensureConforms(pt)(originalCtx) // insert a cast if body does not conform to expected type if we disregard gadt bounds assignType(cpy.CaseDef(tree)(pat, guard1, body1), body1) } - val doCase: () => CaseDef = - () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.setNewScope) - (doCase /: gadtSyms)((op, tsym) => tsym.withGADTFlexType(op))() + + val gadtCtx = + if (gadtSyms.isEmpty) ctx + else { + val c = ctx.fresh.setFreshGADTBounds + for (sym <- gadtSyms) + if (!c.gadt.bounds.contains(sym)) + c.gadt.setBounds(sym, TypeBounds.empty) + c + } + val pat1 = typedPattern(tree.pat, selType)(gadtCtx) + caseRest(pat1)(gadtCtx.fresh.setNewScope) } def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = track("typedReturn") { diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index b156d8878..3f1170e40 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -68,6 +68,7 @@ class tests extends CompilerTest { @Test def pos_nullarify = compileFile(posDir, "nullarify", "-Ycheck:nullarify" :: Nil) @Test def pos_subtyping = compileFile(posDir, "subtyping") @Test def pos_t2613 = compileFile(posSpecialDir, "t2613")(allowDeepSubtypes) + @Test def pos_packageObj = compileFile(posDir, "i0239") @Test def pos_all = compileFiles(posDir, failedOther) diff --git a/test/test/DottyTest.scala b/test/test/DottyTest.scala index 90a0154ec..21eebd660 100644 --- a/test/test/DottyTest.scala +++ b/test/test/DottyTest.scala @@ -14,7 +14,7 @@ import dotty.tools.dotc.Compiler import dotty.tools.dotc import dotty.tools.dotc.core.Phases.Phase -class DottyTest extends ContextEscapeDetection{ +class DottyTest /*extends ContextEscapeDetection*/ { dotty.tools.dotc.parsing.Scanners // initialize keywords @@ -36,11 +36,12 @@ class DottyTest extends ContextEscapeDetection{ base.definitions.init(ctx) ctx } - +/* override def getCtx: Context = ctx override def clearCtx() = { ctx = null } +*/ private def compilerWithChecker(phase: String)(assertion:(tpd.Tree, Context) => Unit) = new Compiler { self => override def phases = { diff --git a/tests/pending/pos/annot.scala b/tests/pending/pos/annot.scala deleted file mode 100644 index 8e21803b4..000000000 --- a/tests/pending/pos/annot.scala +++ /dev/null @@ -1,5 +0,0 @@ -class Test { - - @SuppressWarnings("hi") def foo() = ??? - -} diff --git a/tests/pos/annot-bootstrap.scala b/tests/pos/annot-bootstrap.scala new file mode 100644 index 000000000..bef877dcd --- /dev/null +++ b/tests/pos/annot-bootstrap.scala @@ -0,0 +1,8 @@ +package scala.annotation.unchecked + +// note: if the case class is not inside an object, the error disappears +object test { + case class L(a: Int) +} + +final class uncheckedVariance extends scala.annotation.StaticAnnotation {} diff --git a/tests/pos/annot.scala b/tests/pos/annot.scala index ab80aba27..c3a17ff1d 100644 --- a/tests/pos/annot.scala +++ b/tests/pos/annot.scala @@ -2,11 +2,11 @@ import java.beans.Transient class Test { - @SuppressWarnings(Array("hi")) def foo() = ??? // evalutation of annotation on type cannot be deffered as requires implicit resolution(only generic Array$.apply applies here) + @SuppressWarnings(Array("hi")) def foo() = ??? // evalutation of annotation on type cannot be deferred as requires implicit resolution(only generic Array$.apply applies here) - @SuppressWarnings(Array("hi", "foo")) def foo2() = ??? //can be deffered as there is a non-generic method + @SuppressWarnings(Array("hi", "foo")) def foo2() = ??? //can be deferred as there is a non-generic method -// @SuppressWarnings("hi") def foo3() = ??? // can be written in java and is serialized this way in bytecode. doesn't typecheck + @SuppressWarnings("hi") def foo3() = ??? // can be written in java and is serialized this way in bytecode. doesn't typecheck @Transient(false) def bar = ??? diff --git a/tests/pos/i0268.scala b/tests/pos/i0268.scala new file mode 100644 index 000000000..6ac0c5c90 --- /dev/null +++ b/tests/pos/i0268.scala @@ -0,0 +1,15 @@ +package typespatmat + +sealed trait Box2[T] +final case class Int2(x: Int) extends Box2[Int] +final case class Str2(x: String) + extends Box2[String] +final case class Gen[T](x: T) extends Box2[T] + +object Box2 { + def double2[T](x: Box2[T]): T = x match { + case Int2(i) => i * 2 + case Str2(s) => s + s + case Gen(x) => x + } +} |