diff options
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/api/Universe.scala | 10 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Symbols.scala | 13 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 37 |
3 files changed, 27 insertions, 33 deletions
diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 4928b8bb38..15fa11c6cf 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -75,14 +75,14 @@ abstract class Universe extends Symbols with Printers with Importers { - /** Use `refiy` to produce the abstract syntax tree representing a given Scala expression. + /** Use `reify` to produce the abstract syntax tree representing a given Scala expression. * * For example: * * {{{ - * val five = reify{ 5 } // Literal(Constant(5)) - * reify{ 2 + 4 } // Apply( Select( Literal(Constant(2)), newTermName("\$plus")), List( Literal(Constant(4)) ) ) - * reify{ five.splice + 4 } // Apply( Select( Literal(Constant(5)), newTermName("\$plus")), List( Literal(Constant(4)) ) ) + * val five = reify{ 5 } // Literal(Constant(5)) + * reify{ 5.toString } // Apply(Select(Literal(Constant(5)), TermName("toString")), List()) + * reify{ five.splice.toString } // Apply(Select(five, TermName("toString")), List()) * }}} * * The produced tree is path dependent on the Universe `reify` was called from. @@ -93,4 +93,4 @@ abstract class Universe extends Symbols // implementation is hardwired to `scala.reflect.reify.Taggers` // using the mechanism implemented in `scala.tools.reflect.FastTrack` def reify[T](expr: T): Expr[T] = ??? // macro -}
\ No newline at end of file +} diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 45c16b7302..579f7684fd 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -709,7 +709,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isMonomorphicType = isType && { val info = originalInfo - info.isComplete && !info.isHigherKinded + ( (info eq null) + || (info.isComplete && !info.isHigherKinded) + ) } def isStrictFP = hasAnnotation(ScalaStrictFPAttr) || (enclClass hasAnnotation ScalaStrictFPAttr) @@ -1282,6 +1284,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => def hasRawInfo: Boolean = infos ne null def hasCompleteInfo = hasRawInfo && rawInfo.isComplete + // does not run adaptToNewRun, which is prone to trigger cycles (SI-8029) + // TODO: give this a better name if you understand the intent of the caller. + // Is it something to do with `reallyExists` or `isStale`? + final def rawInfoIsNoType: Boolean = { + hasRawInfo && (infos.info eq NoType) + } + /** Return info without checking for initialization or completing */ def rawInfo: Type = { var infos = this.infos @@ -1928,7 +1937,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Is this symbol defined in the same scope and compilation unit as `that` symbol? */ def isCoDefinedWith(that: Symbol) = ( - (this.rawInfo ne NoType) + !rawInfoIsNoType && (this.effectiveOwner == that.effectiveOwner) && ( !this.effectiveOwner.isPackageClass || (this.sourceFile eq null) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index cfa6f927b5..2f49995030 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -2626,7 +2626,7 @@ trait Types extends api.Types { self: SymbolTable => private var isdepmeth: ThreeValue = UNKNOWN override def isDependentMethodType: Boolean = { - if (isdepmeth == UNKNOWN) isdepmeth = fromBoolean(IsDependentCollector.collect(resultType)) + if (isdepmeth == UNKNOWN) isdepmeth = fromBoolean(IsDependentCollector.collect(resultType.dealias)) toBoolean(isdepmeth) } @@ -4807,7 +4807,7 @@ trait Types extends api.Types { self: SymbolTable => object IsDependentCollector extends TypeCollector(false) { def traverse(tp: Type) { if (tp.isImmediatelyDependent) result = true - else if (!result) mapOver(tp) + else if (!result) mapOver(tp.dealias) } } @@ -5230,30 +5230,15 @@ trait Types extends api.Types { self: SymbolTable => } } - class SubTypePair(val tp1: Type, val tp2: Type) { - override def hashCode = tp1.hashCode * 41 + tp2.hashCode - override def equals(other: Any) = other match { - case stp: SubTypePair => - // suspend TypeVars in types compared by =:=, - // since we don't want to mutate them simply to check whether a subtype test is pending - // in addition to making subtyping "more correct" for type vars, - // it should avoid the stackoverflow that's been plaguing us (https://groups.google.com/d/topic/scala-internals/2gHzNjtB4xA/discussion) - // this method is only called when subtyping hits a recursion threshold (subsametypeRecursions >= LogPendingSubTypesThreshold) - def suspend(tp: Type) = - if (tp.isGround) null else suspendTypeVarsInType(tp) - def revive(suspension: List[TypeVar]) = - if (suspension ne null) suspension foreach (_.suspended = false) - - val suspensions = Array(tp1, stp.tp1, tp2, stp.tp2) map suspend - - val sameTypes = (tp1 =:= stp.tp1) && (tp2 =:= stp.tp2) - - suspensions foreach revive + final case class SubTypePair(tp1: Type, tp2: Type) { + // SI-8146 we used to implement equality here in terms of pairwise =:=. + // But, this was inconsistent with hashCode, which was based on the + // Type#hashCode, based on the structure of types, not the meaning. + // Now, we use `Type#{equals,hashCode}` as the (consistent) basis for + // detecting cycles (aka keeping subtyping decidable.) + // + // I added tests to show that we detect the cycle: neg/t8146-no-finitary* - sameTypes - case _ => - false - } override def toString = tp1+" <:<? "+tp2 } @@ -5819,7 +5804,7 @@ trait Types extends api.Types { self: SymbolTable => if (subsametypeRecursions >= LogPendingSubTypesThreshold) { val p = new SubTypePair(tp1, tp2) if (pendingSubTypes(p)) - false + false // see neg/t8146-no-finitary* else try { pendingSubTypes += p |