diff options
Diffstat (limited to 'src')
8 files changed, 73 insertions, 79 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala index 4285858bf8..54d4a30553 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala @@ -19,7 +19,7 @@ final class BCodeAsmCommon[G <: Global](val global: G) { val ExcludedForwarderFlags = { import scala.tools.nsc.symtab.Flags._ // Should include DEFERRED but this breaks findMember. - ( SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO ) + SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO } /** @@ -30,10 +30,10 @@ final class BCodeAsmCommon[G <: Global](val global: G) { */ def isAnonymousOrLocalClass(classSym: Symbol): Boolean = { assert(classSym.isClass, s"not a class: $classSym") - val res = (classSym.isAnonymousClass || !classSym.originalOwner.isClass) - // lambda classes are always top-level classes. - if (res) assert(!classSym.isDelambdafyFunction) - res + // Here used to be an `assert(!classSym.isDelambdafyFunction)`: delambdafy lambda classes are + // always top-level. However, SI-8900 shows an example where the weak name-based implementation + // of isDelambdafyFunction failed (for a function declared in a package named "lambda"). + classSym.isAnonymousClass || !classSym.originalOwner.isClass } /** @@ -147,9 +147,16 @@ final class BCodeAsmCommon[G <: Global](val global: G) { annot.args.isEmpty } - def isRuntimeVisible(annot: AnnotationInfo): Boolean = - annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr) - .exists(_.assocs.contains((nme.value -> LiteralAnnotArg(Constant(AnnotationRetentionPolicyRuntimeValue))))) + def isRuntimeVisible(annot: AnnotationInfo): Boolean = { + annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr) match { + case Some(retentionAnnot) => + retentionAnnot.assocs.contains(nme.value -> LiteralAnnotArg(Constant(AnnotationRetentionPolicyRuntimeValue))) + case _ => + // SI-8926: if the annotation class symbol doesn't have a @RetentionPolicy annotation, the + // annotation is emitted with visibility `RUNTIME` + true + } + } private def retentionPolicyOf(annot: AnnotationInfo): Symbol = annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr).map(_.assocs).map(assoc => diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index fa53ef48b5..4662ef6224 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -77,8 +77,11 @@ abstract class Flatten extends InfoTransform { if (sym.isTerm && !sym.isStaticModule) { decls1 enter sym if (sym.isModule) { - // Nested, non-static moduls are transformed to methods. - assert(sym.isMethod, s"Non-static $sym should have the lateMETHOD flag from RefChecks") + // In theory, we could assert(sym.isMethod), because nested, non-static moduls are + // transformed to methods (lateMETHOD flag added in RefChecks). But this requires + // forcing sym.info (see comment on isModuleNotMethod), which forces stub symbols + // too eagerly (SI-8907). + // Note that module classes are not entered into the 'decls' of the ClassInfoType // of the outer class, only the module symbols are. So the current loop does // not visit module classes. Therefore we set the LIFTED flag here for module diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 908aa69310..9c81e31ad9 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -861,11 +861,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { debuglog("%s expands to %s in %s".format(sym, specMember.name.decode, pp(env))) info(specMember) = NormalizedMember(sym) newOverload(sym, specMember, env) - // if this is a class, we insert the normalized member in scope, - // if this is a method, there's no attached scope for it (EmptyScope) - val decls = owner.info.decls - if (decls != EmptyScope) - decls.enter(specMember) specMember } } @@ -1504,20 +1499,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val residualTargs = symbol.info.typeParams zip baseTargs collect { case (tvar, targ) if !env.contains(tvar) || !isPrimitiveValueClass(env(tvar).typeSymbol) => targ } - // See SI-5583. Don't know why it happens now if it didn't before. - if (specMember.info.typeParams.isEmpty && residualTargs.nonEmpty) { - devWarning("Type args to be applied, but symbol says no parameters: " + ((specMember.defString, residualTargs))) - baseTree - } - else { - ifDebug(assert(residualTargs.length == specMember.info.typeParams.length, - "residual: %s, tparams: %s, env: %s".format(residualTargs, specMember.info.typeParams, env)) - ) + ifDebug(assert(residualTargs.length == specMember.info.typeParams.length, + "residual: %s, tparams: %s, env: %s".format(residualTargs, specMember.info.typeParams, env)) + ) - val tree1 = gen.mkTypeApply(specTree, residualTargs) - debuglog("rewrote " + tree + " to " + tree1) - localTyper.typedOperator(atPos(tree.pos)(tree1)) // being polymorphic, it must be a method - } + val tree1 = gen.mkTypeApply(specTree, residualTargs) + debuglog("rewrote " + tree + " to " + tree1) + localTyper.typedOperator(atPos(tree.pos)(tree1)) // being polymorphic, it must be a method } curTree = tree diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala index 79f5e3bee8..7fcfdf4868 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala @@ -73,9 +73,7 @@ trait ScalacPatternExpanders { * Unfortunately the MethodType does not carry the information of whether * it was unapplySeq, so we have to funnel that information in separately. */ - def unapplyMethodTypes(method: Type, isSeq: Boolean): Extractor = { - val whole = firstParamType(method) - val result = method.finalResultType + def unapplyMethodTypes(whole: Type, result: Type, isSeq: Boolean): Extractor = { val expanded = ( if (result =:= BooleanTpe) Nil else typeOfMemberNamedGet(result) match { @@ -126,9 +124,10 @@ trait ScalacPatternExpanders { val patterns = newPatterns(args) val isSeq = sel.symbol.name == nme.unapplySeq val isUnapply = sel.symbol.name == nme.unapply + val extractor = sel.symbol.name match { - case nme.unapply => unapplyMethodTypes(fn.tpe, isSeq = false) - case nme.unapplySeq => unapplyMethodTypes(fn.tpe, isSeq = true) + case nme.unapply => unapplyMethodTypes(firstParamType(fn.tpe), sel.tpe, isSeq = false) + case nme.unapplySeq => unapplyMethodTypes(firstParamType(fn.tpe), sel.tpe, isSeq = true) case _ => applyMethodTypes(fn.tpe) } diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index a8731a51b1..d3a7db6968 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -253,7 +253,7 @@ trait TraversableLike[+A, +Repr] extends Any b.result } - private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { + private def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { val b = newBuilder for (x <- this) if (p(x) != isFlipped) b += x diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 91a4e1c43d..714d5117d3 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -499,16 +499,6 @@ self => ) else super.flatMap(f)(bf) - override private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Stream[A] = { - // optimization: drop leading prefix of elems for which f returns false - // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise - var rest = this - while (!rest.isEmpty && p(rest.head) == isFlipped) rest = rest.tail - // private utility func to avoid `this` on stack (would be needed for the lazy arg) - if (rest.nonEmpty) Stream.filteredTail(rest, p, isFlipped) - else Stream.Empty - } - /** Returns all the elements of this `Stream` that satisfy the predicate `p` * in a new `Stream` - i.e., it is still a lazy data structure. The order of * the elements is preserved @@ -522,7 +512,15 @@ self => * // produces * }}} */ - override def filter(p: A => Boolean): Stream[A] = filterImpl(p, isFlipped = false) // This override is only left in 2.11 because of binary compatibility, see PR #3925 + override def filter(p: A => Boolean): Stream[A] = { + // optimization: drop leading prefix of elems for which f returns false + // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise + var rest = this + while (!rest.isEmpty && !p(rest.head)) rest = rest.tail + // private utility func to avoid `this` on stack (would be needed for the lazy arg) + if (rest.nonEmpty) Stream.filteredTail(rest, p) + else Stream.Empty + } override final def withFilter(p: A => Boolean): StreamWithFilter = new StreamWithFilter(p) @@ -1286,8 +1284,8 @@ object Stream extends SeqFactory[Stream] { else cons(start, range(start + step, end, step)) } - private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean, isFlipped: Boolean) = { - cons(stream.head, stream.tail.filterImpl(p, isFlipped)) + private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean) = { + cons(stream.head, stream.tail filter p) } private[immutable] def collectedTail[A, B, That](head: B, stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = { diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 70375d974c..666a3a5e64 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -905,12 +905,14 @@ trait Definitions extends api.StandardDefinitions { ) } - def EnumType(sym: Symbol) = + def EnumType(sym: Symbol) = { // given (in java): "class A { enum E { VAL1 } }" // - sym: the symbol of the actual enumeration value (VAL1) // - .owner: the ModuleClassSymbol of the enumeration (object E) // - .linkedClassOfClass: the ClassSymbol of the enumeration (class E) - sym.owner.linkedClassOfClass.tpe + // SI-6613 Subsequent runs of the resident compiler demand the phase discipline here. + enteringPhaseNotLaterThan(picklerPhase)(sym.owner.linkedClassOfClass).tpe + } /** Given a class symbol C with type parameters T1, T2, ... Tn * which have upper/lower bounds LB1/UB1, LB1/UB2, ..., LBn/UBn, diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index f3f11076bd..51f06b1d6d 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -173,7 +173,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => with HasFlags with Annotatable[Symbol] with Attachable { - // makes sure that all symbols that runtime reflection deals with are synchronized private def isSynchronized = this.isInstanceOf[scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol] private def isAprioriThreadsafe = isThreadsafe(AllOps) @@ -735,31 +734,31 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def hasGetter = isTerm && nme.isLocalName(name) - /** A little explanation for this confusing situation. - * Nested modules which have no static owner when ModuleDefs - * are eliminated (refchecks) are given the lateMETHOD flag, - * which makes them appear as methods after refchecks. - * Here's an example where one can see all four of FF FT TF TT - * for (isStatic, isMethod) at various phases. + /** + * Nested modules which have no static owner when ModuleDefs are eliminated (refchecks) are + * given the lateMETHOD flag, which makes them appear as methods after refchecks. + * + * Note: the lateMETHOD flag is added lazily in the info transformer of the RefChecks phase. + * This means that forcing the `sym.info` may change the value of `sym.isMethod`. Forcing the + * info is in the responsability of the caller. Doing it eagerly here was tried (0ccdb151f) but + * has proven to lead to bugs (SI-8907). * - * trait A1 { case class Quux() } - * object A2 extends A1 { object Flax } - * // -- namer object Quux in trait A1 - * // -M flatten object Quux in trait A1 - * // S- flatten object Flax in object A2 - * // -M posterasure object Quux in trait A1 - * // -M jvm object Quux in trait A1 - * // SM jvm object Quux in object A2 + * Here's an example where one can see all four of FF FT TF TT for (isStatic, isMethod) at + * various phases. * - * So "isModuleNotMethod" exists not for its achievement in - * brevity, but to encapsulate the relevant condition. + * trait A1 { case class Quux() } + * object A2 extends A1 { object Flax } + * // -- namer object Quux in trait A1 + * // -M flatten object Quux in trait A1 + * // S- flatten object Flax in object A2 + * // -M posterasure object Quux in trait A1 + * // -M jvm object Quux in trait A1 + * // SM jvm object Quux in object A2 + * + * So "isModuleNotMethod" exists not for its achievement in brevity, but to encapsulate the + * relevant condition. */ - def isModuleNotMethod = { - if (isModule) { - if (phase.refChecked) this.info // force completion to make sure lateMETHOD is there. - !isMethod - } else false - } + def isModuleNotMethod = isModule && !isMethod // After RefChecks, the `isStatic` check is mostly redundant: all non-static modules should // be methods (and vice versa). There's a corner case on the vice-versa with mixed-in module @@ -1592,13 +1591,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => assert(isCompilerUniverse) if (infos == null || runId(infos.validFrom) == currentRunId) { infos - } else if (isPackageClass) { - // SI-7801 early phase package scopes are mutated in new runs (Namers#enterPackage), so we have to - // discard transformed infos, rather than just marking them as from this run. - val oldest = infos.oldest - oldest.validFrom = validTo - this.infos = oldest - oldest + } else if (infos ne infos.oldest) { + // SI-8871 Discard all but the first element of type history. Specialization only works in the resident + // compiler / REPL if re-run its info transformer in this run to correctly populate its + // per-run caches, e.g. typeEnv + adaptInfos(infos.oldest) } else { val prev1 = adaptInfos(infos.prev) if (prev1 ne infos.prev) prev1 |