diff options
Diffstat (limited to 'src/reflect')
25 files changed, 394 insertions, 366 deletions
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index fa19103d0c..cfde164754 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -175,15 +175,6 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => case (Nil, defaults) => defaults contains category case (metas, _) => metas exists (_ matches category) } - - def mkFilter(categories: List[Symbol], defaultRetention: Boolean)(ann: AnnotationInfo) = - (ann.metaAnnotations, ann.defaultTargets) match { - case (Nil, Nil) => defaultRetention - case (Nil, defaults) => categories exists defaults.contains - case (metas, _) => - val metaSyms = metas collect { case ann if !ann.symbol.isInstanceOf[StubSymbol] => ann.symbol } - categories exists (category => metaSyms exists (_ isNonBottomSubClass category)) - } } class CompleteAnnotationInfo( @@ -305,10 +296,13 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => } /** The default kind of members to which this annotation is attached. - * For instance, for scala.deprecated defaultTargets = - * List(getter, setter, beanGetter, beanSetter). - */ - def defaultTargets = symbol.annotations map (_.symbol) filter isMetaAnnotation + * For instance, for scala.deprecated defaultTargets = + * List(getter, setter, beanGetter, beanSetter). + * + * NOTE: have to call symbol.initialize, since we won't get any annotations if the symbol hasn't yet been completed + */ + def defaultTargets = symbol.initialize.annotations map (_.symbol) filter isMetaAnnotation + // Test whether the typeSymbol of atp conforms to the given class. def matches(clazz: Symbol) = !symbol.isInstanceOf[StubSymbol] && (symbol isNonBottomSubClass clazz) // All subtrees of all args are considered. diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala index 81281b5eb4..78f9721713 100644 --- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala @@ -56,42 +56,44 @@ trait BaseTypeSeqs { if(pending contains i) { pending.clear() throw CyclicInheritance - } else - elems(i) match { - case rtp @ RefinedType(variants, decls) => - // can't assert decls.isEmpty; see t0764 - //if (!decls.isEmpty) abort("computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j)) - //Console.println("compute closure of "+this+" => glb("+variants+")") - pending += i - try { - mergePrefixAndArgs(variants, Variance.Contravariant, lubDepth(variants)) match { - case NoType => typeError("no common type instance of base types "+(variants mkString ", and ")+" exists.") - case tp0 => - pending(i) = false - elems(i) = tp0 - tp0 - } - } - catch { - case CyclicInheritance => - typeError( - "computing the common type instance of base types "+(variants mkString ", and ")+" leads to a cycle.") + } else { + def computeLazyType(rtp: RefinedType): Type = { + if (!isIntersectionTypeForLazyBaseType(rtp)) + devWarning("unexpected RefinedType in base type seq, lazy BTS elements should be created via intersectionTypeForLazyBaseType: " + rtp) + val variants = rtp.parents + // can't assert decls.isEmpty; see t0764 + //if (!decls.isEmpty) abort("computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j)) + //Console.println("compute closure of "+this+" => glb("+variants+")") + pending += i + try { + mergePrefixAndArgs(variants, Variance.Contravariant, lubDepth(variants)) match { + case NoType => typeError("no common type instance of base types " + (variants mkString ", and ") + " exists.") + case tp0 => + pending(i) = false + elems(i) = tp0 + tp0 } + } + catch { + case CyclicInheritance => + typeError( + "computing the common type instance of base types " + (variants mkString ", and ") + " leads to a cycle.") + } + } + elems(i) match { + case rtp@RefinedType(variants, decls) => + computeLazyType(rtp) + case et @ ExistentialType(quantified, rtp: RefinedType) => + existentialAbstraction(quantified, computeLazyType(rtp)) case tp => tp } + } def rawElem(i: Int) = elems(i) - /** The type symbol of the type at i'th position in this sequence; - * no evaluation needed. - */ - def typeSymbol(i: Int): Symbol = { - elems(i) match { - case RefinedType(v :: vs, _) => v.typeSymbol - case tp => tp.typeSymbol - } - } + /** The type symbol of the type at i'th position in this sequence */ + def typeSymbol(i: Int): Symbol = elems(i).typeSymbol /** Return all evaluated types in this sequence as a list */ def toList: List[Type] = elems.toList @@ -215,7 +217,7 @@ trait BaseTypeSeqs { } i += 1 } - buf += intersectionType(minTypes) + buf += intersectionTypeForLazyBaseType(minTypes) // TODO this reverses the order. Does this matter? Or should this be minTypes.reverse? btsSize += 1 } } diff --git a/src/reflect/scala/reflect/internal/Constants.scala b/src/reflect/scala/reflect/internal/Constants.scala index 85d0efdcba..7b47798ff7 100644 --- a/src/reflect/scala/reflect/internal/Constants.scala +++ b/src/reflect/scala/reflect/internal/Constants.scala @@ -7,7 +7,6 @@ package scala package reflect package internal -import java.lang.Integer.toOctalString import scala.annotation.switch trait Constants extends api.Constants { @@ -212,7 +211,7 @@ trait Constants extends api.Constants { case '"' => "\\\"" case '\'' => "\\\'" case '\\' => "\\\\" - case _ => if (ch.isControl) "\\0" + toOctalString(ch.toInt) else String.valueOf(ch) + case _ => if (ch.isControl) "\\u%04X".format(ch.toInt) else String.valueOf(ch) } def escapedStringValue: String = { diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index fe6d88e7c7..d0539dfd42 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -362,7 +362,6 @@ trait Definitions extends api.StandardDefinitions { // classes with special meanings lazy val StringAddClass = requiredClass[scala.runtime.StringAdd] lazy val ScalaNumberClass = requiredClass[scala.math.ScalaNumber] - lazy val TraitSetterAnnotationClass = requiredClass[scala.runtime.TraitSetter] lazy val DelayedInitClass = requiredClass[scala.DelayedInit] def delayedInitMethod = getMemberMethod(DelayedInitClass, nme.delayedInit) @@ -675,8 +674,10 @@ trait Definitions extends api.StandardDefinitions { // Note that these call .dealiasWiden and not .normalize, the latter of which // tends to change the course of events by forcing types. def isFunctionType(tp: Type) = isFunctionTypeDirect(tp.dealiasWiden) + // the number of arguments expected by the function described by `tp` (a FunctionN or SAM type), // or `-1` if `tp` does not represent a function type or SAM + // for use during typers (after fields, samOf will be confused by abstract accessors for trait fields) def functionArityFromType(tp: Type) = { val dealiased = tp.dealiasWiden if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.length - 1 @@ -686,13 +687,14 @@ trait Definitions extends api.StandardDefinitions { } } - // the result type of a function or corresponding SAM type - def functionResultType(tp: Type): Type = { + // the argument types expected by the function described by `tp` (a FunctionN or SAM type), + // or `Nil` if `tp` does not represent a function type or SAM (or if it happens to be Function0...) + def functionOrSamArgTypes(tp: Type): List[Type] = { val dealiased = tp.dealiasWiden - if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.last + if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.init else samOf(tp) match { - case samSym if samSym.exists => tp.memberInfo(samSym).resultType.deconst - case _ => NoType + case samSym if samSym.exists => tp.memberInfo(samSym).paramTypes + case _ => Nil } } @@ -837,9 +839,9 @@ trait Definitions extends api.StandardDefinitions { * The class defining the method is a supertype of `tp` that * has a public no-arg primary constructor. */ - def samOf(tp: Type): Symbol = if (!doSam) NoSymbol else { + def samOf(tp: Type): Symbol = if (!doSam) NoSymbol else if (!isNonRefinementClassType(unwrapToClass(tp))) NoSymbol else { // look at erased type because we (only) care about what ends up in bytecode - // (e.g., an alias type or intersection type is fine as long as the intersection dominator compiles to an interface) + // (e.g., an alias type is fine as long as is compiles to a single-abstract-method) val tpSym: Symbol = erasure.javaErasure(tp).typeSymbol if (tpSym.exists && tpSym.isClass @@ -864,7 +866,7 @@ trait Definitions extends api.StandardDefinitions { // must filter out "universal" members (getClass is deferred for some reason) val deferredMembers = ( tp.membersBasedOnFlags(excludedFlags = BridgeAndPrivateFlags, requiredFlags = METHOD).toList.filter( - mem => mem.isDeferredNotJavaDefault && !isUniversalMember(mem) + mem => mem.isDeferred && !isUniversalMember(mem) ) // TODO: test ) @@ -1049,11 +1051,7 @@ trait Definitions extends api.StandardDefinitions { } } - /** Remove references to class Object (other than the head) in a list of parents */ - def removeLaterObjects(tps: List[Type]): List[Type] = tps match { - case Nil => Nil - case x :: xs => x :: xs.filterNot(_.typeSymbol == ObjectClass) - } + /** Remove all but one reference to class Object from a list of parents. */ def removeRedundantObjects(tps: List[Type]): List[Type] = tps match { case Nil => Nil @@ -1470,6 +1468,7 @@ trait Definitions extends api.StandardDefinitions { lazy val StringAdd_+ = getMemberMethod(StringAddClass, nme.PLUS) // The given symbol represents either String.+ or StringAdd.+ + // TODO: this misses Predef.any2stringadd def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+ lazy val StringContext_f = getMemberMethod(StringContextClass, nme.f) diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index e06decea6d..a146f9aea5 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -169,17 +169,23 @@ class Flags extends ModifierFlags { final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED + final val SYNTHESIZE_IMPL_IN_SUBCLASS = 1L << 50 // used in fields phase to indicate this accessor should receive an implementation in a subclass + + // flags used strictly internally in the Fields phase (info/tree transform): + final val NEEDS_TREES = 1L << 59 // this symbol needs a tree. (distinct from SYNTHESIZE_IMPL_IN_SUBCLASS) + // ------- shift definitions ------------------------------------------------------- // // Flags from 1L to (1L << 50) are normal flags. // - // The flags DEFERRED (1L << 4) to MODULE (1L << 8) have a `late` counterpart. Late flags change - // their counterpart from 0 to 1 after a specific phase (see below). The first late flag - // (lateDEFERRED) is at (1L << 51), i.e., late flags are shifted by 47. The last one is (1L << 55). + // The "late" counterpart to flags DEFERRED (1L << 4) to MODULE (1L << 8) + // show up in `sym.flags` as their regular counterpart once the phase mask admits them (see below). + // The first late flag (lateDEFERRED) is at (1L << 51), i.e., late flags are shifted by 47. The last one is (1L << 55). + // Think of it as a poor man's flag history akin to the type history for a symbol's info. // - // The flags PROTECTED (1L) to PRIVATE (1L << 2) have a `not` counterpart. Negated flags change - // their counterpart from 1 to 0 after a specific phase (see below). They are shifted by 56, i.e., - // the first negated flag (notPROTECTED) is at (1L << 56), the last at (1L << 58). + // The "not" counterpart to flags PROTECTED (1L) to PRIVATE (1L << 2) + // are negated flags that suppress their counterpart after a specific phase (see below). + // They are shifted by 56, i.e., the first negated flag (notPROTECTED) is at (1L << 56), the last at (1L << 58). // // Late and negative flags are only enabled after certain phases, implemented by the phaseNewFlags // method of the SubComponent, so they implement a bit of a flag history. @@ -211,20 +217,15 @@ class Flags extends ModifierFlags { // erasure 15 [START] <latedeferred> // mixin 20 [START] <latemodule> <notoverride> // - // lateMETHOD set in RefChecks#transformInfo. - // lateFINAL set in Symbols#makeNotPrivate. // notPRIVATE set in Symbols#makeNotPrivate, IExplicitOuter#transform, Inliners. // notPROTECTED set in ExplicitOuter#transform. - // lateDEFERRED set in AddInterfaces, Mixin, etc. - // lateMODULE set in Mixin#transformInfo. - // notOVERRIDE set in Mixin#preTransform. - final val lateDEFERRED = (DEFERRED: Long) << LateShift - final val lateFINAL = (FINAL: Long) << LateShift - final val lateMETHOD = (METHOD: Long) << LateShift - final val lateMODULE = (MODULE: Long) << LateShift +// final val lateDEFERRED = (DEFERRED: Long) << LateShift // unused +// final val lateFINAL = (FINAL: Long) << LateShift // only used for inliner -- could be subsumed by notPRIVATE? +// final val lateMETHOD = (METHOD: Long) << LateShift // unused +// final val lateMODULE = (MODULE: Long) << LateShift // unused - final val notOVERRIDE = (OVERRIDE: Long) << AntiShift +// final val notOVERRIDE = (OVERRIDE: Long) << AntiShift // unused final val notPRIVATE = (PRIVATE: Long) << AntiShift final val notPROTECTED = (PROTECTED: Long) << AntiShift @@ -257,7 +258,8 @@ class Flags extends ModifierFlags { /** These modifiers appear in TreePrinter output. */ final val PrintableFlags = ExplicitFlags | BridgeFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO | - ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED | ARTIFACT + ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED | ARTIFACT | + SYNTHESIZE_IMPL_IN_SUBCLASS | NEEDS_TREES /** When a symbol for a field is created, only these flags survive * from Modifiers. Others which may be applied at creation time are: @@ -442,16 +444,16 @@ class Flags extends ModifierFlags { case JAVA_DEFAULTMETHOD => "<defaultmethod>" // (1L << 47) case JAVA_ENUM => "<enum>" // (1L << 48) case JAVA_ANNOTATION => "<annotation>" // (1L << 49) - case 0x4000000000000L => "" // (1L << 50) - case `lateDEFERRED` => "<latedeferred>" // (1L << 51) - case `lateFINAL` => "<latefinal>" // (1L << 52) - case `lateMETHOD` => "<latemethod>" // (1L << 53) - case 0x80000000000000L => "" // (1L << 54) - case `lateMODULE` => "<latemodule>" // (1L << 55) + case SYNTHESIZE_IMPL_IN_SUBCLASS => "<sub_synth>" // (1L << 50) + case 0x08000000000000L => "<latedeferred>" // (1L << 51) + case 0x10000000000000L => "<latefinal>" // (1L << 52) + case 0x20000000000000L => "<latemethod>" // (1L << 53) + case 0x40000000000000L => "" // (1L << 54) + case 0x80000000000000L => "<latemodule>" // (1L << 55) case `notPROTECTED` => "<notprotected>" // (1L << 56) - case `notOVERRIDE` => "<notoverride>" // (1L << 57) + case 0x200000000000000L => "<notoverride>" // (1L << 57) case `notPRIVATE` => "<notprivate>" // (1L << 58) - case 0x800000000000000L => "" // (1L << 59) + case NEEDS_TREES => "<needs_trees>" // (1L << 59) case 0x1000000000000000L => "" // (1L << 60) case 0x2000000000000000L => "" // (1L << 61) case 0x4000000000000000L => "" // (1L << 62) diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala index e793586e18..dfada48c5e 100644 --- a/src/reflect/scala/reflect/internal/HasFlags.scala +++ b/src/reflect/scala/reflect/internal/HasFlags.scala @@ -122,9 +122,6 @@ trait HasFlags { def isTrait = hasFlag(TRAIT) && !hasFlag(PARAM) def isTraitOrInterface = isTrait || isInterface - def isDeferredOrJavaDefault = hasFlag(DEFERRED | JAVA_DEFAULTMETHOD) - def isDeferredNotJavaDefault = isDeferred && !hasFlag(JAVA_DEFAULTMETHOD) - def flagBitsToString(bits: Long): String = { // Fast path for common case if (bits == 0L) "" else { diff --git a/src/reflect/scala/reflect/internal/Phase.scala b/src/reflect/scala/reflect/internal/Phase.scala index a761f686e6..eb193adbf2 100644 --- a/src/reflect/scala/reflect/internal/Phase.scala +++ b/src/reflect/scala/reflect/internal/Phase.scala @@ -47,6 +47,10 @@ abstract class Phase(val prev: Phase) { final val specialized: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "specialize" || prev.specialized) final val refChecked: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "refchecks" || prev.refChecked) + // are we past the fields phase, so that: + // - we should allow writing to vals (as part of type checking trait setters) + // - modules have module accessors + final val assignsFields: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "fields" || prev.assignsFields) /** This is used only in unsafeTypeParams, and at this writing is * overridden to false in parser, namer, typer, and erasure. (And NoPhase.) diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 37b99c4345..9602a2859b 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -1045,23 +1045,23 @@ trait Printers extends api.Printers { self: SymbolTable => print("") } - case l @ Literal(x) => - import Chars.LF - x match { - case Constant(v: String) if { - val strValue = x.stringValue - strValue.contains(LF) && strValue.contains("\"\"\"") && strValue.size > 1 - } => - val splitValue = x.stringValue.split(s"$LF").toList - val multilineStringValue = if (x.stringValue.endsWith(s"$LF")) splitValue :+ "" else splitValue - val trQuotes = "\"\"\"" - print(trQuotes); printSeq(multilineStringValue) { print(_) } { print(LF) }; print(trQuotes) - case _ => - // processing Float constants - val printValue = x.escapedStringValue + (if (x.value.isInstanceOf[Float]) "F" else "") - print(printValue) + case Literal(k @ Constant(s: String)) if s.contains(Chars.LF) => + val tq = "\"" * 3 + val lines = s.lines.toList + if (lines.lengthCompare(1) <= 0) print(k.escapedStringValue) + else { + val tqp = """["]{3}""".r + val tqq = """""\\"""" // ""\" is triple-quote quoted + print(tq) + printSeq(lines.map(x => tqp.replaceAllIn(x, tqq)))(print(_))(print(Chars.LF)) + print(tq) } + case Literal(x) => + // processing Float constants + val suffix = x.value match { case _: Float => "F" case _ => "" } + print(s"${x.escapedStringValue}${suffix}") + case an @ Annotated(ap, tree) => val printParentheses = needsParentheses(tree)() parenthesize(printParentheses) { print(tree) }; print(if (tree.isType) " " else ": ") diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala index 30f2efd7e3..026438e421 100644 --- a/src/reflect/scala/reflect/internal/ReificationSupport.scala +++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala @@ -285,6 +285,7 @@ trait ReificationSupport { self: SymbolTable => val (gvdefs, etdefs) = rawEdefs.partition(treeInfo.isEarlyValDef) val (fieldDefs, UnCtor(ctorMods, ctorVparamss, lvdefs) :: body) = rest.splitAt(indexOfCtor(rest)) val evdefs = gvdefs.zip(lvdefs).map { + // TODO: in traits, early val defs are defdefs case (gvdef @ ValDef(_, _, tpt: TypeTree, _), ValDef(_, _, _, rhs)) => copyValDef(gvdef)(tpt = tpt.original, rhs = rhs) case (tr1, tr2) => @@ -725,6 +726,7 @@ trait ReificationSupport { self: SymbolTable => } // match call to either withFilter or filter + // TODO: now that we no longer rewrite `filter` to `withFilter`, maybe this extractor should only look for `withFilter`? protected object FilterCall { def unapply(tree: Tree): Option[(Tree,Tree)] = tree match { case Apply(Select(obj, nme.withFilter | nme.filter), arg :: Nil) => diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala index 27fda9a7d4..c1f0140479 100644 --- a/src/reflect/scala/reflect/internal/Reporting.scala +++ b/src/reflect/scala/reflect/internal/Reporting.scala @@ -7,6 +7,8 @@ package scala package reflect package internal +import settings.MutableSettings + /** Provides delegates to the reporter doing the actual work. * All forwarding methods should be marked final, * but some subclasses out of our reach still override them. @@ -105,6 +107,13 @@ abstract class Reporter { /** Finish reporting: print summaries, release resources. */ def finish(): Unit = () + + /** After reporting, offer advice on getting more details. */ + def rerunWithDetails(setting: MutableSettings#Setting, name: String): String = + setting.value match { + case b: Boolean if !b => s"; re-run with ${name} for details" + case _ => s"; re-run enabling ${name} for details, or try -help" + } } // TODO: move into superclass once partest cuts tie on Severity diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 76e34153c9..78f360409d 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -76,4 +76,6 @@ trait StdAttachments { * in place of the outer parameter, can help callers to avoid capturing the outer instance. */ case object OuterArgCanBeElided extends PlainAttachment + + case object UseInvokeSpecial extends PlainAttachment } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 4f5a545c95..925018d3a6 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -95,6 +95,8 @@ trait StdNames { val NAME_JOIN_STRING: String = NameTransformer.NAME_JOIN_STRING val MODULE_SUFFIX_STRING: String = NameTransformer.MODULE_SUFFIX_STRING val LOCAL_SUFFIX_STRING: String = NameTransformer.LOCAL_SUFFIX_STRING + val LAZY_LOCAL_SUFFIX_STRING: String = NameTransformer.LAZY_LOCAL_SUFFIX_STRING + val TRAIT_SETTER_SEPARATOR_STRING: String = NameTransformer.TRAIT_SETTER_SEPARATOR_STRING val SINGLETON_SUFFIX: String = ".type" @@ -337,7 +339,6 @@ trait StdNames { val DEFAULT_CASE: NameType = "defaultCase$" val EQEQ_LOCAL_VAR: NameType = "eqEqTemp$" val FAKE_LOCAL_THIS: NameType = "this$" - val LAZY_LOCAL: NameType = "$lzy" val LAZY_SLOW_SUFFIX: NameType = "$lzycompute" val UNIVERSE_BUILD_PREFIX: NameType = "$u.internal.reificationSupport." val UNIVERSE_PREFIX: NameType = "$u." @@ -1171,6 +1172,7 @@ trait StdNames { final val Invoke: TermName = newTermName("invoke") final val InvokeExact: TermName = newTermName("invokeExact") + final val Metafactory: TermName = newTermName("metafactory") final val AltMetafactory: TermName = newTermName("altMetafactory") final val Bootstrap: TermName = newTermName("bootstrap") diff --git a/src/reflect/scala/reflect/internal/SymbolPairs.scala b/src/reflect/scala/reflect/internal/SymbolPairs.scala index a52d2d8510..320c814696 100644 --- a/src/reflect/scala/reflect/internal/SymbolPairs.scala +++ b/src/reflect/scala/reflect/internal/SymbolPairs.scala @@ -30,27 +30,6 @@ abstract class SymbolPairs { val global: SymbolTable import global._ - /** Type operations relative to a prefix. All operations work on Symbols, - * and the types are the member types of those symbols in the prefix. - */ - class RelativeTo(val prefix: Type) { - def this(clazz: Symbol) = this(clazz.thisType) - import scala.language.implicitConversions // geez, it even has to hassle me when it's private - private implicit def symbolToType(sym: Symbol): Type = prefix memberType sym - - def erasureOf(sym: Symbol): Type = erasure.erasure(sym)(sym: Type) - def signature(sym: Symbol): String = sym defStringSeenAs (sym: Type) - def erasedSignature(sym: Symbol): String = sym defStringSeenAs erasureOf(sym) - - def isSameType(sym1: Symbol, sym2: Symbol): Boolean = sym1 =:= sym2 - def isSubType(sym1: Symbol, sym2: Symbol): Boolean = sym1 <:< sym2 - def isSuperType(sym1: Symbol, sym2: Symbol): Boolean = sym2 <:< sym1 - def isSameErasure(sym1: Symbol, sym2: Symbol): Boolean = erasureOf(sym1) =:= erasureOf(sym2) - def matches(sym1: Symbol, sym2: Symbol): Boolean = (sym1: Type) matches (sym2: Type) - - override def toString = s"RelativeTo($prefix)" - } - /** Are types tp1 and tp2 equivalent seen from the perspective * of `baseClass`? For instance List[Int] and Seq[Int] are =:= * when viewed from IterableClass. @@ -58,10 +37,11 @@ abstract class SymbolPairs { def sameInBaseClass(baseClass: Symbol)(tp1: Type, tp2: Type) = (tp1 baseType baseClass) =:= (tp2 baseType baseClass) - case class SymbolPair(base: Symbol, low: Symbol, high: Symbol) { + final case class SymbolPair(base: Symbol, low: Symbol, high: Symbol) { + private[this] val self = base.thisType + def pos = if (low.owner == base) low.pos else if (high.owner == base) high.pos else base.pos - def self: Type = base.thisType - def rootType: Type = base.thisType + def rootType: Type = self def lowType: Type = self memberType low def lowErased: Type = erasure.specialErasure(base)(low.tpe) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index ab52a875f8..487aadf5e5 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -96,8 +96,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isByNameParam: Boolean = this.isValueParameter && (this hasFlag BYNAMEPARAM) def isImplementationArtifact: Boolean = (this hasFlag BRIDGE) || (this hasFlag VBRIDGE) || (this hasFlag ARTIFACT) def isJava: Boolean = isJavaDefined - def isVal: Boolean = isTerm && !isModule && !isMethod && !isMutable - def isVar: Boolean = isTerm && !isModule && !isMethod && !isLazy && isMutable + + def isField: Boolean = isTerm && !isModule && (!isMethod || owner.isTrait && isAccessor) + def isMutableVal = if (owner.isTrait) !hasFlag(STABLE) else isMutable + def isVal: Boolean = isField && !isMutableVal + def isVar: Boolean = isField && !isLazy && isMutableVal + def isAbstract: Boolean = isAbstractClass || isDeferred || isAbstractType def isPrivateThis = (this hasFlag PRIVATE) && (this hasFlag LOCAL) def isProtectedThis = (this hasFlag PROTECTED) && (this hasFlag LOCAL) @@ -320,17 +324,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def newImport(pos: Position): TermSymbol = newTermSymbol(nme.IMPORT, pos) - def newModuleVarSymbol(accessor: Symbol): TermSymbol = { - val newName = nme.moduleVarName(accessor.name.toTermName) - val newFlags = MODULEVAR | ( if (this.isClass) PrivateLocal | SYNTHETIC else 0 ) - val newInfo = thisType.memberType(accessor).finalResultType - val mval = newVariable(newName, accessor.pos.focus, newFlags.toLong) addAnnotation VolatileAttr - - if (this.isClass) - mval setInfoAndEnter newInfo - else - mval setInfo newInfo - } final def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = newTermSymbol(name, pos, newFlags).asInstanceOf[ModuleSymbol] @@ -753,10 +746,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def hasGetter = isTerm && nme.isLocalName(name) /** - * 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. + * Nested modules with a non-static owner receive the METHOD flag during UnCurry's info transform. + * (They are replaced by a ClassDef and DefDef for the module accessor during the fields phase.) * - * Note: the lateMETHOD flag is added lazily in the info transformer of the RefChecks phase. + * Note: the METHOD flag is added lazily in the info transformer of the UnCurry phase. * This means that forcing the `sym.info` may change the value of `sym.isMethod`. Forcing the * info is in the responsibility of the caller. Doing it eagerly here was tried (0ccdb151f) but * has proven to lead to bugs (SI-8907). @@ -992,10 +985,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isEffectivelyFinal: Boolean = ( (this hasFlag FINAL | PACKAGE) || isModuleOrModuleClass && (isTopLevel || !settings.overrideObjects) - || isTerm && ( - isPrivate - || isLocalToBlock - ) + || isTerm && (isPrivate || isLocalToBlock || (hasAllFlags(notPRIVATE | METHOD) && !hasFlag(DEFERRED))) || isClass && originalOwner.isTerm && children.isEmpty // we track known subclasses of term-owned classes, use that infer finality ) /** Is this symbol effectively final or a concrete term member of sealed class whose children do not override it */ @@ -1532,7 +1522,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def setInfo(info: Type): this.type = { info_=(info); this } /** Modifies this symbol's info in place. */ def modifyInfo(f: Type => Type): this.type = setInfo(f(info)) - /** Substitute second list of symbols for first in current info. */ + /** Substitute second list of symbols for first in current info. + * + * NOTE: this discards the type history (uses setInfo) + */ def substInfo(syms0: List[Symbol], syms1: List[Symbol]): this.type = if (syms0.isEmpty) this else modifyInfo(_.substSym(syms0, syms1)) @@ -2048,7 +2041,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => assert(hasAccessorFlag, this) val localField = owner.info decl localName - if (localField == NoSymbol && this.hasFlag(MIXEDIN)) { + if (localField == NoSymbol && this.hasFlag(MIXEDIN)) { // TODO: fields phase does not (yet?) add MIXEDIN in setMixedinAccessorFlags // SI-8087: private[this] fields don't have a `localName`. When searching the accessed field // for a mixin accessor of such a field, we need to look for `name` instead. // The phase travel ensures that the field is found (`owner` is the trait class symbol, the @@ -2088,8 +2081,15 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** If this is a lazy value, the lazy accessor; otherwise this symbol. */ def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this - /** If this is an accessor, the accessed symbol. Otherwise, this symbol. */ - def accessedOrSelf: Symbol = if (hasAccessorFlag) accessed else this + /** `accessed`, if this is an accessor that should have an underlying field. Otherwise, `this`. + * Note that a "regular" accessor in a trait does not have a field, as an interface cannot define a field. + * "non-regular" vals are: early initialized or lazy vals. + * Eventually, we should delay introducing symbols for all val/vars until the fields (or lazyvals) phase, + * as they are an implementation detail that's irrelevant to type checking. + */ + def accessedOrSelf: Symbol = + if (hasAccessorFlag && (!owner.isTrait || hasFlag(PRESUPER | LAZY))) accessed + else this /** For an outer accessor: The class from which the outer originates. * For all other symbols: NoSymbol @@ -2447,14 +2447,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def makeNotPrivate(base: Symbol) { if (this.isPrivate) { - setFlag(notPRIVATE) - // Marking these methods final causes problems for proxies which use subclassing. If people - // write their code with no usage of final, we probably shouldn't introduce it ourselves - // unless we know it is safe. ... Unfortunately if they aren't marked final the inliner - // thinks it can't inline them. So once again marking lateFINAL, and in genjvm we no longer - // generate ACC_FINAL on "final" methods which are actually lateFINAL. - if (isMethod && !isDeferred) - setFlag(lateFINAL) + setFlag(notPRIVATE) // this makes it effectively final (isEffectivelyFinal) + // don't set FINAL -- methods not marked final by user should not end up final in bytecode + // inliner will know it's effectively final (notPRIVATE non-deferred method) if (!isStaticModule && !isClassConstructor) { expandName(base) if (isModule) moduleClass.makeNotPrivate(base) @@ -2532,30 +2527,34 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def symbolKind: SymbolKind = { var kind = - if (isTermMacro) ("term macro", "macro method", "MACM") - else if (isInstanceOf[FreeTermSymbol]) ("free term", "free term", "FTE") - else if (isInstanceOf[FreeTypeSymbol]) ("free type", "free type", "FTY") - else if (isPackageClass) ("package class", "package", "PKC") - else if (hasPackageFlag) ("package", "package", "PK") - else if (isPackageObject) ("package object", "package", "PKO") - else if (isPackageObjectClass) ("package object class", "package", "PKOC") - else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC") - else if (isRefinementClass) ("refinement class", "", "RC") - else if (isModule) ("module", "object", "MOD") - else if (isModuleClass) ("module class", "object", "MODC") - else if (isGetter) ("getter", if (isSourceMethod) "method" else "value", "GET") - else if (isSetter) ("setter", if (isSourceMethod) "method" else "value", "SET") - else if (isTerm && isLazy) ("lazy value", "lazy value", "LAZ") - else if (isVariable) ("field", "variable", "VAR") - else if (isTrait) ("trait", "trait", "TRT") - else if (isClass) ("class", "class", "CLS") - else if (isType) ("type", "type", "TPE") - else if (isClassConstructor && (owner.hasCompleteInfo && isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR") - else if (isClassConstructor) ("constructor", "constructor", "CTOR") - else if (isSourceMethod) ("method", "method", "METH") - else if (isTerm) ("value", "value", "VAL") - else ("", "", "???") + if (isTermMacro) ("term macro", "macro method", "MACM") + else if (isInstanceOf[FreeTermSymbol]) ("free term", "free term", "FTE") + else if (isInstanceOf[FreeTypeSymbol]) ("free type", "free type", "FTY") + else if (isPackageClass) ("package class", "package", "PKC") + else if (hasPackageFlag) ("package", "package", "PK") + else if (isPackageObject) ("package object", "package", "PKO") + else if (isPackageObjectClass) ("package object class", "package", "PKOC") + else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC") + else if (isRefinementClass) ("refinement class", "", "RC") + else if (isModule) ("module", "object", "MOD") + else if (isModuleClass) ("module class", "object", "MODC") + else if (isAccessor && + !hasFlag(STABLE | LAZY)) ("setter", "variable", "SET") + else if (isAccessor && !hasFlag(LAZY)) ("getter", "value", "GET") + else if (isTerm && hasFlag(LAZY)) ("lazy value", "lazy value", "LAZ") + else if (isVariable) ("field", "variable", "VAR") + else if (isTrait) ("trait", "trait", "TRT") + else if (isClass) ("class", "class", "CLS") + else if (isType) ("type", "type", "TPE") + else if (isClassConstructor && (owner.hasCompleteInfo && + isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR") + else if (isClassConstructor) ("constructor", "constructor", "CTOR") + else if (isMethod) ("method", "method", "METH") + else if (isTerm) ("value", "value", "VAL") + else ("", "", "???") + if (isSkolem) kind = (kind._1, kind._2, kind._3 + "#SKO") + SymbolKind(kind._1, kind._2, kind._3) } @@ -2623,12 +2622,17 @@ trait Symbols extends api.Symbols { self: SymbolTable => * If hasMeaninglessName is true, uses the owner's name to disambiguate identity. */ override def toString: String = { - if (isPackageObjectOrClass && !settings.debug) - s"package object ${owner.decodedName}" - else compose( - kindString, - if (hasMeaninglessName) owner.decodedName + idString else nameString - ) + val simplifyNames = !settings.debug + if (isPackageObjectOrClass && simplifyNames) s"package object ${owner.decodedName}" + else { + val kind = kindString + val _name: String = + if (hasMeaninglessName) owner.decodedName + idString + else if (simplifyNames && (kind == "variable" || kind == "value")) unexpandedName.getterName.decode.toString // TODO: make condition less gross? + else nameString + + compose(kind, _name) + } } /** String representation of location. @@ -2764,18 +2768,21 @@ trait Symbols extends api.Symbols { self: SymbolTable => ) ***/ override def isValueParameter = this hasFlag PARAM - override def isSetterParameter = isValueParameter && owner.isSetter - override def isAccessor = this hasFlag ACCESSOR - override def isGetter = isAccessor && !isSetter + override def isDefaultGetter = name containsName nme.DEFAULT_GETTER_STRING - override def isSetter = isAccessor && nme.isSetterName(name) // todo: make independent of name, as this can be forged. + + override def isAccessor = this hasFlag ACCESSOR + override def isGetter = isAccessor && !nme.isSetterName(name) // TODO: make independent of name, as this can be forged. + override def isSetter = isAccessor && nme.isSetterName(name) // TODO: make independent of name, as this can be forged. + override def isLocalDummy = nme.isLocalDummyName(name) + override def isClassConstructor = name == nme.CONSTRUCTOR override def isMixinConstructor = name == nme.MIXIN_CONSTRUCTOR - override def isConstructor = nme.isConstructorName(name) + override def isConstructor = isClassConstructor || isMixinConstructor - override def isPackageObject = isModule && (name == nme.PACKAGE) + override def isPackageObject = isModule && (name == nme.PACKAGE) // The name in comments is what it is being disambiguated from. // TODO - rescue CAPTURED from BYNAMEPARAM so we can see all the names. @@ -2871,7 +2878,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def owner = { if (Statistics.hotEnabled) Statistics.incCounter(ownerCount) - // a module symbol may have the lateMETHOD flag after refchecks, see isModuleNotMethod + // a non-static module symbol gets the METHOD flag in uncurry's info transform -- see isModuleNotMethod if (!isMethod && needsFlatClasses) rawowner.owner else rawowner } @@ -2891,38 +2898,23 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** A class for method symbols */ class MethodSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName) extends TermSymbol(initOwner, initPos, initName) with MethodSymbolApi { - private[this] var mtpePeriod = NoPeriod - private[this] var mtpePre: Type = _ - private[this] var mtpeResult: Type = _ - private[this] var mtpeInfo: Type = _ - override def isLabel = this hasFlag LABEL override def isVarargsMethod = this hasFlag VARARGS override def isLiftedMethod = this hasFlag LIFTED - // TODO - this seems a strange definition for "isSourceMethod", given that - // it does not make any specific effort to exclude synthetics. Figure out what - // this method is really for and what logic makes sense. - override def isSourceMethod = !(this hasFlag STABLE) // exclude all accessors + // TODO: this definition of isSourceMethod makes no sense -- inline it and re-evaluate at each call site. + // I'm guessing it meant "method written by user, and not generated by the compiler" + // (And then assuming those generated by the compiler don't require certain transformations?) + // Use SYNTHETIC/ARTIFACT instead as an indicator? I don't see how it makes sense to only exclude getters. + // Note also that trait vals are modelled as getters, and thus that user-supplied code appears in their rhs. + // Originally, it may have been an optimization to skip methods that were not user-defined (getters), + // but it doesn't even exclude setters, contrary to its original comment (// exclude all accessors) + override def isSourceMethod = !(this hasFlag STABLE) + // unfortunately having the CASEACCESSOR flag does not actually mean you // are a case accessor (you can also be a field.) override def isCaseAccessorMethod = isCaseAccessor - def typeAsMemberOf(pre: Type): Type = { - if (mtpePeriod == currentPeriod) { - if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult - } else if (isValid(mtpePeriod)) { - mtpePeriod = currentPeriod - if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult - } - val res = pre.computeMemberType(this) - mtpePeriod = currentPeriod - mtpePre = pre - mtpeInfo = info - mtpeResult = res - res - } - override def isVarargs: Boolean = definitions.isVarArgsList(paramss.flatten) override def returnType: Type = { @@ -3231,7 +3223,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * returned, otherwise, `NoSymbol` is returned. */ protected final def companionModule0: Symbol = - flatOwnerInfo.decl(name.toTermName).suchThat(sym => sym.isModuleNotMethod && (sym isCoDefinedWith this)) + flatOwnerInfo.decl(name.toTermName).suchThat(sym => sym.isModule && (sym isCoDefinedWith this)) override def companionModule = companionModule0 override def companionSymbol = companionModule0 diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 86b70643c9..b9f3e987ee 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -263,6 +263,12 @@ abstract class TreeInfo { true } + def isFunctionMissingParamType(tree: Tree): Boolean = tree match { + case Function(vparams, _) => vparams.exists(_.tpt.isEmpty) + case _ => false + } + + /** Is symbol potentially a getter of a variable? */ def mayBeVarGetter(sym: Symbol): Boolean = sym.info match { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 895bb60a08..f8679616d1 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -172,11 +172,16 @@ trait Types trait RewrappingTypeProxy extends SimpleTypeProxy { protected def maybeRewrap(newtp: Type) = ( if (newtp eq underlying) this - // BoundedWildcardTypes reach here during erroneous compilation: neg/t6258 - // Higher-kinded exclusion is because [x]CC[x] compares =:= to CC: pos/t3800 - // Otherwise, if newtp =:= underlying, don't rewrap it. - else if (!newtp.isWildcard && !newtp.isHigherKinded && (newtp =:= underlying)) this - else rewrap(newtp) + else { + // - BoundedWildcardTypes reach here during erroneous compilation: neg/t6258 + // - Higher-kinded exclusion is because [x]CC[x] compares =:= to CC: pos/t3800 + // - Avoid reusing the existing Wrapped(RefinedType) when we've be asked to wrap an =:= RefinementTypeRef, the + // distinction is important in base type sequences. See TypesTest.testExistentialRefinement + // - Otherwise, if newtp =:= underlying, don't rewrap it. + val hasSpecialMeaningBeyond_=:= = newtp.isWildcard || newtp.isHigherKinded || newtp.isInstanceOf[RefinementTypeRef] + if (!hasSpecialMeaningBeyond_=:= && (newtp =:= underlying)) this + else rewrap(newtp) + } ) protected def rewrap(newtp: Type): Type @@ -686,23 +691,21 @@ trait Types * }}} */ def memberInfo(sym: Symbol): Type = { - require(sym ne NoSymbol, this) +// assert(sym ne NoSymbol, this) sym.info.asSeenFrom(this, sym.owner) } /** The type of `sym`, seen as a member of this type. */ - def memberType(sym: Symbol): Type = sym match { - case meth: MethodSymbol => - meth.typeAsMemberOf(this) - case _ => - computeMemberType(sym) - } - - def computeMemberType(sym: Symbol): Type = sym.tpeHK match { //@M don't prematurely instantiate higher-kinded types, they will be instantiated by transform, typedTypeApply, etc. when really necessary - case OverloadedType(_, alts) => - OverloadedType(this, alts) + def memberType(sym: Symbol): Type = sym.tpeHK match { + case OverloadedType(_, alts) => OverloadedType(this, alts) case tp => - if (sym eq NoSymbol) NoType else tp.asSeenFrom(this, sym.owner) + // Correct caching is nearly impossible because `sym.tpeHK.asSeenFrom(pre, sym.owner)` + // may have different results even for reference-identical `sym.tpeHK` and `pre` (even in the same period). + // For example, `pre` could be a `ThisType`. For such a type, `tpThen eq tpNow` does not imply + // `tpThen` and `tpNow` mean the same thing, because `tpThen.typeSymbol.info` could have been different + // from what it is now, and the cache won't know simply by looking at `pre`. + if (sym eq NoSymbol) NoType + else tp.asSeenFrom(this, sym.owner) } /** Substitute types `to` for occurrences of references to @@ -1591,13 +1594,11 @@ trait Types */ case class RefinedType(override val parents: List[Type], override val decls: Scope) extends CompoundType with RefinedTypeApi { - override def isHigherKinded = ( parents.nonEmpty && (parents forall typeIsHigherKinded) && !phase.erasedTypes ) - override def typeParams = if (isHigherKinded) firstParent.typeParams else super.typeParams @@ -1899,7 +1900,7 @@ trait Types require(sym.isRefinementClass, sym) // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers - override protected def normalizeImpl: Type = sym.info.normalize + override protected def normalizeImpl: Type = pre.memberInfo(sym).normalize override protected def finishPrefix(rest: String) = "" + sym.info } @@ -2706,6 +2707,7 @@ trait Types def isRepresentableWithWildcards = { val qset = quantified.toSet underlying match { + case _: RefinementTypeRef => false case TypeRef(pre, sym, args) => def isQuantified(tpe: Type): Boolean = { (tpe exists (t => qset contains t.typeSymbol)) || @@ -3471,10 +3473,10 @@ trait Types if (!sym.isOverridableMember || sym.owner == pre.typeSymbol) sym else pre.nonPrivateMember(sym.name).suchThat { sym => // SI-7928 `isModuleNotMethod` is here to avoid crashing with spuriously "overloaded" module accessor and module symbols. - // These appear after refchecks eliminates ModuleDefs that implement an interface. + // These appear after the fields phase eliminates ModuleDefs that implement an interface. // Here, we exclude the module symbol, which allows us to bind to the accessor. - // SI-8054 We must only do this after refchecks, otherwise we exclude the module symbol which does not yet have an accessor! - val isModuleWithAccessor = phase.refChecked && sym.isModuleNotMethod + // SI-8054 We must only do this after fields, otherwise we exclude the module symbol which does not yet have an accessor! + val isModuleWithAccessor = phase.assignsFields && sym.isModuleNotMethod sym.isType || (!isModuleWithAccessor && sym.isStable && !sym.hasVolatileType) } orElse sym } @@ -3523,7 +3525,9 @@ trait Types if ((parents eq original.parents) && (decls eq original.decls)) original else { val owner = original.typeSymbol.owner - val result = refinedType(parents, owner) + val result = + if (isIntersectionTypeForLazyBaseType(original)) intersectionTypeForLazyBaseType(parents) + else refinedType(parents, owner) val syms1 = decls.toList for (sym <- syms1) result.decls.enter(sym.cloneSymbol(result.typeSymbol)) @@ -3598,6 +3602,14 @@ trait Types case tp :: Nil => tp case _ => refinedType(tps, commonOwner(tps)) } + def intersectionTypeForLazyBaseType(tps: List[Type]) = tps match { + case tp :: Nil => tp + case _ => RefinedType(tps, newScope, tps.head.typeSymbolDirect) + } + def isIntersectionTypeForLazyBaseType(tp: RefinedType) = tp.parents match { + case head :: _ => tp.typeSymbolDirect eq head.typeSymbolDirect + case _ => false + } /**** This implementation to merge parents was checked in in commented-out form and has languished unaltered for five years. I think we should @@ -4405,89 +4417,120 @@ trait Types finally foreach2(tvs, saved)(_.suspended = _) } + final def stripExistentialsAndTypeVars(ts: List[Type], expandLazyBaseType: Boolean = false): (List[Type], List[Symbol]) = { + val needsStripping = ts.exists { + case _: RefinedType | _: TypeVar | _: ExistentialType => true + case _ => false + } + if (!needsStripping) (ts, Nil) // fast path for common case + else { + val tparams = mutable.ListBuffer[Symbol]() + val stripped = mutable.ListBuffer[Type]() + def stripType(tp: Type): Unit = tp match { + case rt: RefinedType if isIntersectionTypeForLazyBaseType(rt) => + if (expandLazyBaseType) + rt.parents foreach stripType + else { + devWarning(s"Unexpected RefinedType in stripExistentialsAndTypeVars $ts, not expanding") + stripped += tp + } + case ExistentialType(qs, underlying) => + tparams ++= qs + stripType(underlying) + case tv@TypeVar(_, constr) => + if (tv.instValid) stripType(constr.inst) + else if (tv.untouchable) stripped += tv + else abort("trying to do lub/glb of typevar " + tv) + case tp => stripped += tp + } + ts foreach stripType + (stripped.toList, tparams.toList) + } + } + /** Compute lub (if `variance == Covariant`) or glb (if `variance == Contravariant`) of given list * of types `tps`. All types in `tps` are typerefs or singletypes * with the same symbol. * Return `x` if the computation succeeds with result `x`. * Return `NoType` if the computation fails. */ - def mergePrefixAndArgs(tps: List[Type], variance: Variance, depth: Depth): Type = tps match { - case tp :: Nil => tp - case TypeRef(_, sym, _) :: rest => - val pres = tps map (_.prefix) // prefix normalizes automatically + def mergePrefixAndArgs(tps0: List[Type], variance: Variance, depth: Depth): Type = { + val (tps, tparams) = stripExistentialsAndTypeVars(tps0, expandLazyBaseType = true) + + val merged = tps match { + case tp :: Nil => tp + case TypeRef(_, sym, _) :: rest => + val pres = tps map (_.prefix) // prefix normalizes automatically val pre = if (variance.isPositive) lub(pres, depth) else glb(pres, depth) - val argss = tps map (_.normalize.typeArgs) // symbol equality (of the tp in tps) was checked using typeSymbol, which normalizes, so should normalize before retrieving arguments + val argss = tps map (_.normalize.typeArgs) // symbol equality (of the tp in tps) was checked using typeSymbol, which normalizes, so should normalize before retrieving arguments val capturedParams = new ListBuffer[Symbol] - try { - if (sym == ArrayClass && phase.erasedTypes) { - // special treatment for lubs of array types after erasure: - // if argss contain one value type and some other type, the lub is Object - // if argss contain several reference types, the lub is an array over lub of argtypes - if (argss exists typeListIsEmpty) { - NoType // something is wrong: an array without a type arg. - } - else { - val args = argss map (_.head) - if (args.tail forall (_ =:= args.head)) typeRef(pre, sym, List(args.head)) - else if (args exists (arg => isPrimitiveValueClass(arg.typeSymbol))) ObjectTpe - else typeRef(pre, sym, List(lub(args))) + try { + if (sym == ArrayClass && phase.erasedTypes) { + // special treatment for lubs of array types after erasure: + // if argss contain one value type and some other type, the lub is Object + // if argss contain several reference types, the lub is an array over lub of argtypes + if (argss exists typeListIsEmpty) { + NoType // something is wrong: an array without a type arg. + } + else { + val args = argss map (_.head) + if (args.tail forall (_ =:= args.head)) typeRef(pre, sym, List(args.head)) + else if (args exists (arg => isPrimitiveValueClass(arg.typeSymbol))) ObjectTpe + else typeRef(pre, sym, List(lub(args))) + } } - } - else transposeSafe(argss) match { - case None => - // transpose freaked out because of irregular argss - // catching just in case (shouldn't happen, but also doesn't cost us) - // [JZ] It happens: see SI-5683. - debuglog(s"transposed irregular matrix!? tps=$tps argss=$argss") - NoType - case Some(argsst) => - val args = map2(sym.typeParams, argsst) { (tparam, as0) => - val as = as0.distinct - if (as.size == 1) as.head - else if (depth.isZero) { - log("Giving up merging args: can't unify %s under %s".format(as.mkString(", "), tparam.fullLocationString)) - // Don't return "Any" (or "Nothing") when we have to give up due to - // recursion depth. Return NoType, which prevents us from poisoning - // lublist's results. It can recognize the recursion and deal with it, but - // only if we aren't returning invalid types. - NoType - } - else { - if (tparam.variance == variance) lub(as, depth.decr) - else if (tparam.variance == variance.flip) glb(as, depth.decr) + else transposeSafe(argss) match { + case None => + // transpose freaked out because of irregular argss + // catching just in case (shouldn't happen, but also doesn't cost us) + // [JZ] It happens: see SI-5683. + debuglog(s"transposed irregular matrix!? tps=$tps argss=$argss") + NoType + case Some(argsst) => + val args = map2(sym.typeParams, argsst) { (tparam, as0) => + val as = as0.distinct + if (as.size == 1) as.head + else if (depth.isZero) { + log("Giving up merging args: can't unify %s under %s".format(as.mkString(", "), tparam.fullLocationString)) + // Don't return "Any" (or "Nothing") when we have to give up due to + // recursion depth. Return NoType, which prevents us from poisoning + // lublist's results. It can recognize the recursion and deal with it, but + // only if we aren't returning invalid types. + NoType + } else { - val l = lub(as, depth.decr) - val g = glb(as, depth.decr) - if (l <:< g) l - else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we - // just err on the conservative side, i.e. with a bound that is too high. - // if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251 - - val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l) - capturedParams += qvar - qvar.tpe + if (tparam.variance == variance) lub(as, depth.decr) + else if (tparam.variance == variance.flip) glb(as, depth.decr) + else { + val l = lub(as, depth.decr) + val g = glb(as, depth.decr) + if (l <:< g) l + else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we + // just err on the conservative side, i.e. with a bound that is too high. + // if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251 + + val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l) + capturedParams += qvar + qvar.tpe + } } } } - } - if (args contains NoType) NoType - else existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)) + if (args contains NoType) NoType + else existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)) + } + } catch { + case ex: MalformedType => NoType } - } catch { - case ex: MalformedType => NoType - } - case SingleType(_, sym) :: rest => - val pres = tps map (_.prefix) - val pre = if (variance.isPositive) lub(pres, depth) else glb(pres, depth) - try singleType(pre, sym) - catch { case ex: MalformedType => NoType } - case ExistentialType(tparams, quantified) :: rest => - mergePrefixAndArgs(quantified :: rest, variance, depth) match { - case NoType => NoType - case tpe => existentialAbstraction(tparams, tpe) - } - case _ => - abort(s"mergePrefixAndArgs($tps, $variance, $depth): unsupported tps") + case SingleType(_, sym) :: rest => + val pres = tps map (_.prefix) + val pre = if (variance.isPositive) lub(pres, depth) else glb(pres, depth) + try singleType(pre, sym) + catch { case ex: MalformedType => NoType } + case _ => + abort(s"mergePrefixAndArgs($tps, $variance, $depth): unsupported tps") + } + existentialAbstraction(tparams, merged) } def addMember(thistp: Type, tp: Type, sym: Symbol): Unit = addMember(thistp, tp, sym, AnyDepth) diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index 24a2f46b75..98b4e881af 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -171,7 +171,9 @@ trait Variances { case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) => validateVariance(sym) super.traverse(tree) - // ModuleDefs need not be considered because they have been eliminated already + case ModuleDef(_, _, _) => + validateVariance(sym.moduleClass) + super.traverse(tree) case ValDef(_, _, _, _) => validateVariance(sym) case DefDef(_, _, tparams, vparamss, _, _) => diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala index 123b44aa05..108ce45cca 100644 --- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala +++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala @@ -118,7 +118,7 @@ private[internal] trait GlbLubs { // ts0 is the 1-dimensional frontier of symbols cutting through 2-dimensional tsBts. // Invariant: all symbols "under" (closer to the first row) the frontier // are smaller (according to _.isLess) than the ones "on and beyond" the frontier - val ts0 = tsBts map (_.head) + val ts0 = tsBts map (_.head) // Is the frontier made up of types with the same symbol? val isUniformFrontier = (ts0: @unchecked) match { @@ -210,24 +210,6 @@ private[internal] trait GlbLubs { } } - private def stripExistentialsAndTypeVars(ts: List[Type]): (List[Type], List[Symbol]) = { - val quantified = ts flatMap { - case ExistentialType(qs, _) => qs - case t => List() - } - def stripType(tp: Type): Type = tp match { - case ExistentialType(_, res) => - res - case tv@TypeVar(_, constr) => - if (tv.instValid) stripType(constr.inst) - else if (tv.untouchable) tv - else abort("trying to do lub/glb of typevar "+tp) - case t => t - } - val strippedTypes = ts mapConserve stripType - (strippedTypes, quantified) - } - /** Does this set of types have the same weak lub as * it does regular lub? This is exposed so lub callers * can discover whether the trees they are typing will diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index c3f92f1bce..ba4f2bec4b 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -610,11 +610,26 @@ private[internal] trait TypeMaps { } // Does the candidate symbol match the given prefix and class? - // Since pre may be something like ThisType(A) where trait A { self: B => }, - // we have to test the typeSymbol of the widened type, not pre.typeSymbol, or - // B will not be considered. - private def matchesPrefixAndClass(pre: Type, clazz: Symbol)(candidate: Symbol) = - (clazz == candidate) && (pre.widen.typeSymbol isSubClass clazz) + private def matchesPrefixAndClass(pre: Type, clazz: Symbol)(candidate: Symbol) = (clazz == candidate) && { + val pre1 = pre match { + case tv: TypeVar => + // Needed with existentials in prefixes, e.g. test/files/pos/typevar-in-prefix.scala + // Perhaps the base type sequence of a type var should include its bounds? + tv.origin + case _ => pre + } + // widen needed (at least) because of https://github.com/scala/scala-dev/issues/166 + ( + if (clazz.isRefinementClass) + // base type seqs of aliases over refinement types have copied refinement types based on beta reduction + // for reliable lookup we need to consult the base type of the type symbol. (example: pos/t8177b.scala) + pre1.widen.typeSymbol isSubClass clazz + else + // In the general case, we look at the base type sequence of the prefix itself, + // which can have more concrete base classes than `.typeSymbol.baseClasses` (example: t5294, t6161) + pre1.widen.baseTypeIndex(clazz) != -1 + ) + } // Whether the annotation tree currently being mapped over has had a This(_) node rewritten. private[this] var wroteAnnotation = false @@ -1012,6 +1027,9 @@ private[internal] trait TypeMaps { case _ => tp.normalize match { case TypeRef(_, sym1, _) if (sym == sym1) => result = true + case refined: RefinedType => + mapOver(tp.prefix) + mapOver(refined) case SingleType(_, sym1) if (sym == sym1) => result = true case _ => mapOver(tp) } diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index 412c49f571..62ca50d035 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -148,9 +148,19 @@ trait Erasure { apply(atp) case ClassInfoType(parents, decls, clazz) => ClassInfoType( - if (clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil + if (clazz == ObjectClass || isPrimitiveValueClass(clazz) || parents.isEmpty) Nil else if (clazz == ArrayClass) ObjectTpe :: Nil - else removeLaterObjects(parents map this), + else { + val erasedParents = parents map this + + // drop first parent for traits -- it has been normalized to a class by now, + // but we should drop that in bytecode + val firstParent = + if (clazz.hasFlag(Flags.TRAIT) && !clazz.hasFlag(Flags.JAVA)) ObjectTpe + else erasedParents.head + + firstParent :: erasedParents.tail.filter(_.typeSymbol != ObjectClass) + }, decls, clazz) case _ => mapOver(tp) diff --git a/src/reflect/scala/reflect/internal/transform/RefChecks.scala b/src/reflect/scala/reflect/internal/transform/RefChecks.scala index 4ca114e781..e69de29bb2 100644 --- a/src/reflect/scala/reflect/internal/transform/RefChecks.scala +++ b/src/reflect/scala/reflect/internal/transform/RefChecks.scala @@ -1,14 +0,0 @@ -package scala -package reflect -package internal -package transform - -trait RefChecks { - - val global: SymbolTable - import global._ - - def transformInfo(sym: Symbol, tp: Type): Type = - if (sym.isModule && !sym.isStatic) NullaryMethodType(tp) - else tp -} diff --git a/src/reflect/scala/reflect/internal/transform/Transforms.scala b/src/reflect/scala/reflect/internal/transform/Transforms.scala index 0d2f355aa5..de5bfbd39a 100644 --- a/src/reflect/scala/reflect/internal/transform/Transforms.scala +++ b/src/reflect/scala/reflect/internal/transform/Transforms.scala @@ -23,12 +23,10 @@ trait Transforms { self: SymbolTable => } } - private val refChecksLazy = new Lazy(new { val global: Transforms.this.type = self } with RefChecks) private val uncurryLazy = new Lazy(new { val global: Transforms.this.type = self } with UnCurry) private val erasureLazy = new Lazy(new { val global: Transforms.this.type = self } with Erasure) private val postErasureLazy = new Lazy(new { val global: Transforms.this.type = self } with PostErasure) - def refChecks = refChecksLazy.force def uncurry = uncurryLazy.force def erasure = erasureLazy.force def postErasure = postErasureLazy.force @@ -36,8 +34,7 @@ trait Transforms { self: SymbolTable => def transformedType(sym: Symbol) = postErasure.transformInfo(sym, erasure.transformInfo(sym, - uncurry.transformInfo(sym, - refChecks.transformInfo(sym, sym.info)))) + uncurry.transformInfo(sym, sym.info))) def transformedType(tpe: Type) = postErasure.elimErasedValueType(erasure.scalaErasure(uncurry.uncurry(tpe))) diff --git a/src/reflect/scala/reflect/internal/transform/UnCurry.scala b/src/reflect/scala/reflect/internal/transform/UnCurry.scala index 85e3ac60e8..a50084f40d 100644 --- a/src/reflect/scala/reflect/internal/transform/UnCurry.scala +++ b/src/reflect/scala/reflect/internal/transform/UnCurry.scala @@ -83,5 +83,10 @@ trait UnCurry { * @MAT: starting with this phase, the info of every symbol will be normalized */ def transformInfo(sym: Symbol, tp: Type): Type = - if (sym.isType) uncurryType(tp) else uncurry(tp) + if (sym.isType) uncurryType(tp) + else if ((sym hasFlag MODULE) && !sym.isStatic) { // see Fields::nonStaticModuleToMethod + sym setFlag METHOD | STABLE + MethodType(Nil, uncurry(tp)) + } + else uncurry(tp) } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 0a90a141d3..f55b33959a 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -46,6 +46,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.NoInlineCallsiteAttachment this.InlineCallsiteAttachment this.OuterArgCanBeElided + this.UseInvokeSpecial this.noPrint this.typeDebug this.Range @@ -247,7 +248,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.SymbolModule definitions.StringAddClass definitions.ScalaNumberClass - definitions.TraitSetterAnnotationClass definitions.DelayedInitClass definitions.TypeConstraintClass definitions.SingletonClass diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 313ec89311..237afa082b 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -199,12 +199,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb trait SynchronizedTermSymbol extends SynchronizedSymbol - trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol { - // we can keep this lock fine-grained, because it's just a cache over asSeenFrom, which makes deadlocks impossible - // unfortunately we cannot elide this lock, because the cache depends on `pre` - private lazy val typeAsMemberOfLock = new Object - override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotThreadsafe { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } } - } + trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol |