diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeTypeMap.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/config/ScalaSettings.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Hashable.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Constructors.scala | 14 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ExpandPrivate.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ExplicitOuter.scala | 41 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/FirstTransform.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Mixin.scala | 36 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/PostTyper.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeChecker.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Checking.scala | 55 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 3 |
14 files changed, 111 insertions, 82 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/src/dotty/tools/dotc/ast/TreeTypeMap.scala index d714a3d21..a35fe2e8f 100644 --- a/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -82,7 +82,8 @@ final class TreeTypeMap( constr = tmap.transformSub(constr), parents = parents mapconserve transform, self = tmap.transformSub(self), - body = impl.body mapconserve tmap.transform + body = impl.body mapconserve + (tmap.transform(_)(ctx.withOwner(mapOwner(impl.symbol.owner)))) ).withType(tmap.mapType(impl.tpe)) case tree1 => tree1.withType(mapType(tree1.tpe)) match { diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala index aa264329c..b1d53c90d 100644 --- a/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -105,10 +105,10 @@ class ScalaSettings extends Settings.SettingGroup { val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync") val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness") val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after") - val Xcloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.") + val Ycloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.") val Ycompacttrees = BooleanSetting("-Ycompact-trees", "Use compact tree printer when displaying trees.") val noCompletion = BooleanSetting("-Yno-completion", "Disable tab-completion in the REPL.") - val Xdce = BooleanSetting("-Ydead-code", "Perform dead code elimination.") + val Ydce = BooleanSetting("-Ydead-code", "Perform dead code elimination.") val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.") val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names") val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations") @@ -119,7 +119,7 @@ class ScalaSettings extends Settings.SettingGroup { val inline = BooleanSetting("-Yinline", "Perform inlining when possible.") val inlineHandlers = BooleanSetting("-Yinline-handlers", "Perform exception handler inlining when possible.") val YinlinerWarnings = BooleanSetting("-Yinline-warnings", "Emit inlining warnings. (Normally surpressed due to high volume)") - val Xlinearizer = ChoiceSetting("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") + val Ylinearizer = ChoiceSetting("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") val log = PhasesSetting("-Ylog", "Log operations during") val Ylogcp = BooleanSetting("-Ylog-classpath", "Output information about what classpath is being applied.") val Ynogenericsig = BooleanSetting("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.") @@ -127,9 +127,9 @@ class ScalaSettings extends Settings.SettingGroup { val nopredef = BooleanSetting("-Yno-predef", "Compile without importing Predef.") val noAdaptedArgs = BooleanSetting("-Yno-adapted-args", "Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.") val selfInAnnots = BooleanSetting("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.") - val Xshowtrees = BooleanSetting("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs in formatted form.") - val XshowtreesCompact = BooleanSetting("-Yshow-trees-compact", "(Requires -Xprint:) Print detailed ASTs in compact form.") - val XshowtreesStringified = BooleanSetting("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.") + val Yshowtrees = BooleanSetting("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs in formatted form.") + val YshowtreesCompact = BooleanSetting("-Yshow-trees-compact", "(Requires -Xprint:) Print detailed ASTs in compact form.") + val YshowtreesStringified = BooleanSetting("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.") val Yshowsyms = BooleanSetting("-Yshow-syms", "Print the AST symbol hierarchy after each phase.") val Yshowsymkinds = BooleanSetting("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.") val Yskip = PhasesSetting("-Yskip", "Skip") diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index ebf4c637a..f866621f2 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -448,7 +448,7 @@ object Flags { final val FromStartFlags = AccessFlags | Module | Package | Deferred | Final | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon | InSuperCall | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed | - CaseAccessorOrBaseTypeArg | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent | + CaseAccessorOrBaseTypeArg | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent | Synthetic | LazyOrTrait | SuperAccessorOrScala2x | SelfNameOrImplClass assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags) diff --git a/src/dotty/tools/dotc/core/Hashable.scala b/src/dotty/tools/dotc/core/Hashable.scala index 6a64f8655..12a408fbd 100644 --- a/src/dotty/tools/dotc/core/Hashable.scala +++ b/src/dotty/tools/dotc/core/Hashable.scala @@ -92,7 +92,9 @@ trait Hashable { protected final def doHash(x1: Int, x2: Int): Int = finishHash(hashing.mix(hashing.mix(hashSeed, x1), x2), 1) - protected final def addDelta(hc: Int, delta: Int) = avoidNotCached(hc + delta) + protected final def addDelta(elemHash: Int, delta: Int) = + if (elemHash == NotCached) NotCached + else avoidNotCached(elemHash + delta) private def avoidNotCached(h: Int) = if (h == NotCached) NotCachedAlt else h } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index dd12a0188..17c2ec4ca 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2479,7 +2479,7 @@ object Types { def copyBoundType(bt: BT) = new MethodParamImpl(bt, paramNum) // need to customize hashCode and equals to prevent infinite recursion for dep meth types. - override def computeHash = addDelta(System.identityHashCode(binder), paramNum) + override def computeHash = addDelta(binder.identityHash, paramNum) override def equals(that: Any) = that match { case that: MethodParam => (this.binder eq that.binder) && this.paramNum == that.paramNum diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala index b6ebd7d90..44638ce48 100644 --- a/src/dotty/tools/dotc/transform/Constructors.scala +++ b/src/dotty/tools/dotc/transform/Constructors.scala @@ -26,7 +26,7 @@ import collection.mutable * - also moves private fields that are accessed only from constructor * into the constructor if possible. */ -class Constructors extends MiniPhaseTransform with SymTransformer { thisTransform => +class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform => import tpd._ override def phaseName: String = "constructors" @@ -99,18 +99,6 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor } } - /** Symbols that are owned by either <local dummy> or a class field move into the - * primary constructor. - */ - override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = { - def ownerBecomesConstructor(owner: Symbol): Boolean = - (owner.isLocalDummy || owner.isTerm && !owner.is(MethodOrLazy)) && - owner.owner.isClass - if (ownerBecomesConstructor(sym.owner)) - sym.copySymDenotation(owner = sym.owner.enclosingClass.primaryConstructor) - else sym - } - /** @return true if after ExplicitOuter, all references from this tree go via an * outer link, so no parameter accessors need to be rewired to parameters */ diff --git a/src/dotty/tools/dotc/transform/ExpandPrivate.scala b/src/dotty/tools/dotc/transform/ExpandPrivate.scala index f44be3958..a6f203478 100644 --- a/src/dotty/tools/dotc/transform/ExpandPrivate.scala +++ b/src/dotty/tools/dotc/transform/ExpandPrivate.scala @@ -57,8 +57,11 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t * static members of the companion class, we should tighten the condition below. */ private def ensurePrivateAccessible(d: SymDenotation)(implicit ctx: Context) = - if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) + if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) { + assert(d.symbol.sourceFile == ctx.source.file, + i"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.source.file}") d.ensureNotPrivate.installAfter(thisTransform) + } override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = { ensurePrivateAccessible(tree.symbol) diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 4cf076c45..9170cd277 100644 --- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -212,27 +212,34 @@ object ExplicitOuter { /** Tree references an outer class of `cls` which is not a static owner. */ def referencesOuter(cls: Symbol, tree: Tree)(implicit ctx: Context): Boolean = { - def isOuter(sym: Symbol) = + def isOuterSym(sym: Symbol) = !sym.isStaticOwner && cls.isProperlyContainedIn(sym) + def isOuterRef(ref: Type): Boolean = ref match { + case ref: ThisType => + isOuterSym(ref.cls) + case ref: TermRef => + if (ref.prefix ne NoPrefix) + !ref.symbol.isStatic && isOuterRef(ref.prefix) + else if (ref.symbol is Hoistable) + // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need + // an outer path then. + isOuterSym(ref.symbol.owner.enclosingClass) + else + // ref.symbol will get a proxy in immediately enclosing class. If this properly + // contains the current class, it needs an outer path. + ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner) + case _ => false + } + def hasOuterPrefix(tp: Type) = tp match { + case TypeRef(prefix, _) => isOuterRef(prefix) + case _ => false + } tree match { - case thisTree @ This(_) => - isOuter(thisTree.symbol) - case id: Ident => - id.tpe match { - case ref @ TermRef(NoPrefix, _) => - if (ref.symbol is Hoistable) - // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need - // an outer path then. - isOuter(ref.symbol.owner.enclosingClass) - else - // ref.symbol will get a proxy in immediately enclosing class. If this properly - // contains the current class, it needs an outer path. - ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner) - case _ => false - } + case _: This | _: Ident => isOuterRef(tree.tpe) case nw: New => val newCls = nw.tpe.classSymbol - isOuter(newCls.owner.enclosingClass) || + isOuterSym(newCls.owner.enclosingClass) || + hasOuterPrefix(nw.tpe) || newCls.owner.isTerm && cls.isProperlyContainedIn(newCls) // newCls might get proxies for free variables. If current class is // properly contained in newCls, it needs an outer path to newCls access the diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala index 6b13d46b2..37ae1d94e 100644 --- a/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -124,7 +124,7 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi private def newCompanion(name: TermName, forClass: Symbol)(implicit ctx: Context) = { val modul = ctx.newCompleteModuleSymbol(forClass.owner, name, Synthetic, Synthetic, - defn.ObjectType :: Nil, Scopes.newScope) + defn.ObjectType :: Nil, Scopes.newScope, assocFile = forClass.asClass.assocFile) val mc = modul.moduleClass val mcComp = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, forClass, mc) diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala index 32b268fc7..b0d1e5c5f 100644 --- a/src/dotty/tools/dotc/transform/Mixin.scala +++ b/src/dotty/tools/dotc/transform/Mixin.scala @@ -98,8 +98,12 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure]) override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = - if (sym.is(Accessor, butNot = Deferred | Lazy) && sym.owner.is(Trait)) - sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred).ensureNotPrivate + if (sym.is(Accessor, butNot = Deferred) && sym.owner.is(Trait)) { + val sym1 = + if (sym is Lazy) sym + else sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred) + sym1.ensureNotPrivate + } else if (sym.isConstructor && sym.owner.is(Trait)) sym.copySymDenotation( name = nme.TRAIT_CONSTRUCTOR, @@ -108,17 +112,19 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => sym private def initializer(sym: Symbol)(implicit ctx: Context): TermSymbol = { - val initName = if(!sym.is(Lazy)) InitializerName(sym.name.asTermName) else sym.name.asTermName - sym.owner.info.decl(initName).suchThat(_.is(Lazy) == sym.is(Lazy)).symbol - .orElse( - ctx.newSymbol( - sym.owner, - initName, - Protected | Synthetic | Method, - sym.info, - coord = sym.symbol.coord).enteredAfter(thisTransform)) - .asTerm - } + if (sym is Lazy) sym + else { + val initName = InitializerName(sym.name.asTermName) + sym.owner.info.decl(initName).symbol + .orElse( + ctx.newSymbol( + sym.owner, + initName, + Protected | Synthetic | Method, + sym.info, + coord = sym.symbol.coord).enteredAfter(thisTransform)) + } + }.asTerm override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = { val cls = impl.symbol.owner.asClass @@ -134,8 +140,8 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => val vsym = stat.symbol val isym = initializer(vsym) val rhs = Block( - initBuf.toList.map(_.changeOwner(impl.symbol, isym)), - stat.rhs.changeOwner(vsym, isym).wildcardToDefault) + initBuf.toList.map(_.changeOwnerAfter(impl.symbol, isym, thisTransform)), + stat.rhs.changeOwnerAfter(vsym, isym, thisTransform).wildcardToDefault) initBuf.clear() cpy.DefDef(stat)(rhs = EmptyTree) :: DefDef(isym, rhs) :: Nil case stat: DefDef if stat.symbol.isSetter => diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala index ea5c28fb1..01f9f6317 100644 --- a/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/src/dotty/tools/dotc/transform/PostTyper.scala @@ -131,8 +131,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran annot.derivedAnnotation(transformAnnot(annot.tree)) private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = { - tree.symbol.transformAnnotations(transformAnnot) - Checking.checkNoPrivateLeaks(tree) + val sym = tree.symbol + sym.transformAnnotations(transformAnnot) + if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) { + val info1 = Checking.checkNoPrivateLeaks(sym, tree.pos) + if (info1 ne sym.info) + sym.copySymDenotation(info = info1).installAfter(thisTransformer) + } } private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = { diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index 150a632a1..a260963e9 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -282,7 +282,10 @@ class TreeChecker extends Phase with SymTransformer { val symbolsNotDefined = cls.classInfo.decls.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol - assert(symbolsNotDefined.isEmpty, i" $cls tree does not define methods: $symbolsNotDefined") + assert(symbolsNotDefined.isEmpty, + i" $cls tree does not define methods: ${symbolsNotDefined.toList}%, %\n" + + i"expected: ${cls.classInfo.decls.toSet.filter(isNonMagicalMethod).toList}%, %\n" + + i"defined: ${impl.body.map(_.symbol)}%, %") super.typedClassDef(cdef, cls) } diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 0ca121925..9b1f756b7 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -327,40 +327,53 @@ object Checking { * to a private type or value which is invisible at a point where `M` is still * visible. As an exception, we allow references to type aliases if the underlying * type of the alias is not a leak. So type aliases are transparent as far as - * leak testing is concerned. See 997.scala for tests. + * leak testing is concerned. + * @return The `info` of `sym`, with problematic aliases expanded away. + * See i997.scala for tests, i1130.scala for a case where it matters that we + * transform leaky aliases away. */ - def checkNoPrivateLeaks(tree: MemberDef)(implicit ctx: Context): Unit = { - type Errors = List[(String, Position)] - val sym = tree.symbol - val notPrivate = new TypeAccumulator[Errors] { + def checkNoPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = { + class NotPrivate extends TypeMap { + type Errors = List[(String, Position)] + var errors: Errors = Nil def accessBoundary(sym: Symbol): Symbol = if (sym.is(Private)) sym.owner else if (sym.privateWithin.exists) sym.privateWithin else if (sym.is(Package)) sym else accessBoundary(sym.owner) - def apply(errors: Errors, tp: Type): Errors = tp match { + def apply(tp: Type): Type = tp match { case tp: NamedType => - val errors1 = + val prevErrors = errors + var tp1 = if (tp.symbol.is(Private) && - !accessBoundary(sym).isContainedIn(tp.symbol.owner)) { - (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", tree.pos) :: errors - } else foldOver(errors, tp) - if ((errors1 ne errors) && tp.info.isAlias) { + !accessBoundary(sym).isContainedIn(tp.symbol.owner)) { + errors = (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", + pos) :: errors + tp + } + else mapOver(tp) + if ((errors ne prevErrors) && tp.info.isAlias) { // try to dealias to avoid a leak error - val errors2 = apply(errors, tp.info.bounds.hi) - if (errors2 eq errors) errors2 - else errors1 - } else errors1 + val savedErrors = errors + errors = prevErrors + val tp2 = apply(tp.info.bounds.hi) + if (errors eq prevErrors) tp1 = tp2 + else errors = savedErrors + } + tp1 case tp: ClassInfo => - (apply(errors, tp.prefix) /: tp.parentsWithArgs)(apply) + tp.derivedClassInfo( + prefix = apply(tp.prefix), + classParents = tp.parentsWithArgs.map(p => + apply(p).underlyingClassRef(refinementOK = false).asInstanceOf[TypeRef])) case _ => - foldOver(errors, tp) + mapOver(tp) } } - if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) { - val errors = notPrivate(Nil, sym.info) - errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) } - } + val notPrivate = new NotPrivate + val info = notPrivate(sym.info) + notPrivate.errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) } + info } } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 84344dbb1..fdb92a40b 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -232,7 +232,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } val curImport = ctx.importInfo - if (curImport != null && curImport.isRootImport && previous.exists) return previous + if (ctx.owner.is(Package) && curImport != null && curImport.isRootImport && previous.exists) + return previous // no more conflicts possible in this case // would import of kind `prec` be not shadowed by a nested higher-precedence definition? def isPossibleImport(prec: Int) = prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope) |