Skip to content

Commit

Permalink
Merge pull request #9887 from dotty-staging/optimize-widening
Browse files Browse the repository at this point in the history
Optimize typeSymbol and classSymbol
  • Loading branch information
liufengyun authored Sep 27, 2020
2 parents a50d5e4 + 9ff3203 commit d084b8b
Show file tree
Hide file tree
Showing 30 changed files with 93 additions and 104 deletions.
10 changes: 5 additions & 5 deletions compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
genLoad(rhs, symInfoTK(lhs.symbol))
lineNumber(tree)
// receiverClass is used in the bytecode to access the field. using sym.owner may lead to IllegalAccessError
val receiverClass = qual.tpe.widenDealias.typeSymbol
val receiverClass = qual.tpe.typeSymbol
fieldStore(lhs.symbol, receiverClass)

case Assign(lhs, rhs) =>
Expand Down Expand Up @@ -385,7 +385,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
def genLoadQualUnlessElidable(): Unit = { if (!qualSafeToElide) { genLoadQualifier(tree) } }

// receiverClass is used in the bytecode to access the field. using sym.owner may lead to IllegalAccessError
def receiverClass = qualifier.tpe.widenDealias.typeSymbol
def receiverClass = qualifier.tpe.typeSymbol
if (sym.is(Module)) {
genLoadQualUnlessElidable()
genLoadModule(tree)
Expand Down Expand Up @@ -806,7 +806,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
val receiverClass = if (!invokeStyle.isVirtual) null else {
// receiverClass is used in the bytecode to as the method receiver. using sym.owner
// may lead to IllegalAccessErrors, see 9954eaf / aladdin bug 455.
val qualSym = qual.tpe.widenDealias.typeSymbol
val qualSym = qual.tpe.typeSymbol
if (qualSym == defn.ArrayClass) {
// For invocations like `Array(1).hashCode` or `.wait()`, use Object as receiver
// in the bytecode. Using the array descriptor (like we do for clone above) seems
Expand Down Expand Up @@ -1373,7 +1373,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
(sym derivesFrom defn.BoxedCharClass) ||
(sym derivesFrom defn.BoxedBooleanClass)
}
!areSameFinals && isMaybeBoxed(l.tpe.widenDealias.typeSymbol) && isMaybeBoxed(r.tpe.widenDealias.typeSymbol)
!areSameFinals && isMaybeBoxed(l.tpe.typeSymbol) && isMaybeBoxed(r.tpe.typeSymbol)
}
def isNull(t: Tree): Boolean = t match {
case Literal(Constant(null)) => true
Expand Down Expand Up @@ -1467,7 +1467,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
if (invokeStyle != asm.Opcodes.H_INVOKESTATIC) capturedParamsTypes = lambdaTarget.owner.info :: capturedParamsTypes

// Requires https://github.com/scala/scala-java8-compat on the runtime classpath
val returnUnit = lambdaTarget.info.resultType.widenDealias.typeSymbol == defn.UnitClass
val returnUnit = lambdaTarget.info.resultType.typeSymbol == defn.UnitClass
val functionalInterfaceDesc: String = generatedType.descriptor
val desc = capturedParamsTypes.map(tpe => toTypeKind(tpe)).mkString(("("), "", ")") + functionalInterfaceDesc
// TODO specialization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
private def initJClass(jclass: asm.ClassVisitor): Unit = {

val ps = claszSymbol.info.parents
val superClass: String = if (ps.isEmpty) ObjectReference.internalName else internalName(ps.head.widenDealias.typeSymbol)
val superClass: String = if (ps.isEmpty) ObjectReference.internalName else internalName(ps.head.typeSymbol)
val interfaceNames0 = classBTypeFromSymbol(claszSymbol).info.interfaces map {
case classBType =>
if (classBType.isNestedClass) { innerClassBufferASM += classBType }
Expand Down
14 changes: 7 additions & 7 deletions compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1553,7 +1553,7 @@ class JSCodeGen()(using genCtx: Context) {
assert(ctor.isClassConstructor,
"'new' call to non-constructor: " + ctor.name)

val clsSym = tpe.widenDealias.typeSymbol
val clsSym = tpe.typeSymbol

if (isHijackedClass(clsSym)) {
genNewHijackedClass(clsSym, ctor, args.map(genExpr))
Expand Down Expand Up @@ -1922,8 +1922,8 @@ class JSCodeGen()(using genCtx: Context) {
private def genEqEqPrimitive(ltpe: Type, rtpe: Type, lsrc: js.Tree, rsrc: js.Tree)(
implicit pos: SourcePosition): js.Tree = {
report.debuglog(s"$ltpe == $rtpe")
val lsym = ltpe.widenDealias.typeSymbol.asClass
val rsym = rtpe.widenDealias.typeSymbol.asClass
val lsym = ltpe.typeSymbol.asClass
val rsym = rtpe.typeSymbol.asClass

/* True if the equality comparison is between values that require the
* use of the rich equality comparator
Expand Down Expand Up @@ -2098,7 +2098,7 @@ class JSCodeGen()(using genCtx: Context) {
val exception = args.head
val genException = genExpr(exception)
js.Throw {
if (exception.tpe.widenDealias.typeSymbol.derivesFrom(jsdefn.JavaScriptExceptionClass)) {
if (exception.tpe.typeSymbol.derivesFrom(jsdefn.JavaScriptExceptionClass)) {
genModuleApplyMethod(
jsdefn.Runtime_unwrapJavaScriptException,
List(genException))
Expand Down Expand Up @@ -2594,7 +2594,7 @@ class JSCodeGen()(using genCtx: Context) {
box(call, sym.info.finalResultType)
}

val funInterfaceSym = functionalInterface.tpe.widenDealias.typeSymbol
val funInterfaceSym = functionalInterface.tpe.typeSymbol

if (jsdefn.isJSThisFunctionClass(funInterfaceSym)) {
val thisParam :: otherParams = formalParams
Expand Down Expand Up @@ -2688,7 +2688,7 @@ class JSCodeGen()(using genCtx: Context) {
private def genAsInstanceOf(value: js.Tree, to: Type)(
implicit pos: Position): js.Tree = {

val sym = to.widenDealias.typeSymbol
val sym = to.typeSymbol

if (sym == defn.ObjectClass || isJSType(sym)) {
/* asInstanceOf[Object] always succeeds, and
Expand Down Expand Up @@ -2716,7 +2716,7 @@ class JSCodeGen()(using genCtx: Context) {
/** Gen JS code for an isInstanceOf test (for reference types only) */
private def genIsInstanceOf(value: js.Tree, to: Type)(
implicit pos: SourcePosition): js.Tree = {
val sym = to.widenDealias.typeSymbol
val sym = to.typeSymbol

if (sym == defn.ObjectClass) {
js.BinaryOp(js.BinaryOp.!==, value, js.Null())
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>

private def isSimpleThrowable(tp: Type)(using Context): Boolean = tp match {
case tp @ TypeRef(pre, _) =>
(pre == NoPrefix || pre.widen.typeSymbol.isStatic) &&
(pre == NoPrefix || pre.typeSymbol.isStatic) &&
(tp.symbol derivesFrom defn.ThrowableClass) && !tp.symbol.is(Trait)
case _ =>
false
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
private def followOuterLinks(t: Tree)(using Context) = t match {
case t: This if ctx.erasedTypes && !(t.symbol == ctx.owner.enclosingClass || t.symbol.isStaticOwner) =>
// after erasure outer paths should be respected
ExplicitOuter.OuterOps(ctx).path(toCls = t.tpe.widen.classSymbol)
ExplicitOuter.OuterOps(ctx).path(toCls = t.tpe.classSymbol)
case t =>
t
}
Expand Down
22 changes: 11 additions & 11 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -998,11 +998,10 @@ class Definitions {
FunctionType(args.length, isContextual, isErased).appliedTo(args ::: resultType :: Nil)
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean, Boolean)] = {
val tsym = ft.typeSymbol
if (isFunctionClass(tsym)) {
if isFunctionClass(tsym) && ft.isRef(tsym) then
val targs = ft.dealias.argInfos
if (targs.isEmpty) None
else Some(targs.init, targs.last, tsym.name.isContextFunction, tsym.name.isErasedFunction)
}
else None
}
}
Expand Down Expand Up @@ -1379,15 +1378,16 @@ class Definitions {
/** Is `tp` (an alias) of either a scala.FunctionN or a scala.ContextFunctionN
* instance?
*/
def isNonRefinedFunction(tp: Type)(using Context): Boolean = {
def isNonRefinedFunction(tp: Type)(using Context): Boolean =
val arity = functionArity(tp)
val sym = tp.dealias.typeSymbol

arity >= 0 &&
isFunctionClass(sym) &&
tp.isRef(FunctionType(arity, sym.name.isContextFunction, sym.name.isErasedFunction).typeSymbol) &&
!tp.isInstanceOf[RefinedType]
}
arity >= 0
&& isFunctionClass(sym)
&& tp.isRef(
FunctionType(arity, sym.name.isContextFunction, sym.name.isErasedFunction).typeSymbol,
skipRefined = false)
end isNonRefinedFunction

/** Is `tp` a representation of a (possibly dependent) function type or an alias of such? */
def isFunctionType(tp: Type)(using Context): Boolean =
Expand Down Expand Up @@ -1460,9 +1460,9 @@ class Definitions {
if ctx.erasedTypes then
atPhase(erasurePhase)(unapply(tp))
else
val tp1 = tp.dealias
if isContextFunctionClass(tp1.typeSymbol) then
val args = asContextFunctionType(tp).dropDependentRefinement.argInfos
val tp1 = asContextFunctionType(tp)
if tp1.exists then
val args = tp1.dropDependentRefinement.argInfos
Some((args.init, args.last, tp1.typeSymbol.name.isErasedFunction))
else None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ trait PatternTypeConstrainer { self: TypeComparer =>

def classesMayBeCompatible: Boolean = {
import Flags._
val patClassSym = pat.widenSingleton.classSymbol
val scrutClassSym = scrut.widenSingleton.classSymbol
val patClassSym = pat.classSymbol
val scrutClassSym = scrut.classSymbol
!patClassSym.exists || !scrutClassSym.exists || {
if (patClassSym.is(Final)) patClassSym.derivesFrom(scrutClassSym)
else if (scrutClassSym.is(Final)) scrutClassSym.derivesFrom(patClassSym)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ class TypeApplications(val self: Type) extends AnyVal {
* otherwise return Nil.
* Existential types in arguments are returned as TypeBounds instances.
*/
final def argInfos(using Context): List[Type] = self.stripTypeVar.stripAnnots match {
final def argInfos(using Context): List[Type] = self.stripped match {
case AppliedType(tycon, args) => args
case _ => Nil
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
def compareThis = {
val cls2 = tp2.cls
tp1 match {
case tp1: NamedType if cls2.is(Module) && cls2.eq(tp1.widen.typeSymbol) =>
case tp1: NamedType if cls2.is(Module) && cls2.eq(tp1.typeSymbol) =>
cls2.isStaticOwner ||
recur(tp1.prefix, cls2.owner.thisType) ||
secondTry
Expand Down Expand Up @@ -391,7 +391,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
case tp1: ThisType =>
val cls1 = tp1.cls
tp2 match {
case tp2: TermRef if cls1.is(Module) && cls1.eq(tp2.widen.typeSymbol) =>
case tp2: TermRef if cls1.is(Module) && cls1.eq(tp2.typeSymbol) =>
cls1.isStaticOwner ||
recur(cls1.owner.thisType, tp2.prefix) ||
thirdTry
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
/** The erasure of a function result type. */
private def eraseResult(tp: Type)(using Context): Type = tp match {
case tp: TypeRef =>
val sym = tp.typeSymbol
val sym = tp.symbol
if (sym eq defn.UnitClass) sym.typeRef
// For a value class V, "new V(x)" should have type V for type adaptation to work
// correctly (see SIP-15 and [[Erasure.Boxing.adaptToType]]), so the return type of a
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ object TypeOps:
// variance. As this logic is only needed in exhaustivity check,
// we manually patch subtyping check instead of changing TypeComparer.
// See tests/patmat/i3645b.scala
def parentQualify(tp1: Type, tp2: Type) = tp1.widen.classSymbol.info.parents.exists { parent =>
def parentQualify(tp1: Type, tp2: Type) = tp1.classSymbol.info.parents.exists { parent =>
parent.argInfos.nonEmpty && approximateTypeParams(parent) <:< tp2
}

Expand Down
39 changes: 15 additions & 24 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -419,9 +419,8 @@ object Types {
/** The type symbol associated with the type */
@tailrec final def typeSymbol(using Context): Symbol = this match {
case tp: TypeRef => tp.symbol
case tp: ClassInfo => tp.cls
case tp: SingletonType => NoSymbol
case tp: TypeProxy => tp.underlying.typeSymbol
case tp: ClassInfo => tp.cls
case _: JavaArrayType => defn.ArrayClass
case _ => NoSymbol
}
Expand All @@ -431,17 +430,13 @@ object Types {
* value type, or because superclasses are ambiguous).
*/
final def classSymbol(using Context): Symbol = this match {
case ConstantType(constant) =>
constant.tpe.classSymbol
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass) sym else tp.superType.classSymbol
case tp: ClassInfo =>
tp.cls
case tp: SingletonType =>
NoSymbol
case tp: TypeProxy =>
tp.underlying.classSymbol
case tp: ClassInfo =>
tp.cls
case AndType(l, r) =>
val lsym = l.classSymbol
val rsym = r.classSymbol
Expand All @@ -459,13 +454,13 @@ object Types {
/** The least (wrt <:<) set of symbols satisfying the `include` predicate of which this type is a subtype
*/
final def parentSymbols(include: Symbol => Boolean)(using Context): List[Symbol] = this match {
case tp: ClassInfo =>
tp.cls :: Nil
case tp: TypeRef =>
val sym = tp.symbol
if (include(sym)) sym :: Nil else tp.superType.parentSymbols(include)
case tp: TypeProxy =>
tp.underlying.parentSymbols(include)
case tp: ClassInfo =>
tp.cls :: Nil
case AndType(l, r) =>
l.parentSymbols(include) | r.parentSymbols(include)
case OrType(l, r) =>
Expand Down Expand Up @@ -775,8 +770,8 @@ object Types {
core.println(s"findMember exception for $this member $name, pre = $pre, recCount = $recCount")

def showPrefixSafely(pre: Type)(using Context): String = pre.stripTypeVar match {
case pre: TermRef => i"${pre.termSymbol.name}."
case pre: TypeRef => i"${pre.typeSymbol.name}#"
case pre: TermRef => i"${pre.symbol.name}."
case pre: TypeRef => i"${pre.symbol.name}#"
case pre: TypeProxy => showPrefixSafely(pre.underlying)
case _ => if (pre.typeSymbol.exists) i"${pre.typeSymbol.name}#" else "."
}
Expand Down Expand Up @@ -2377,7 +2372,7 @@ object Types {
/** A reference like this one, but with the given prefix. */
final def withPrefix(prefix: Type)(using Context): NamedType = {
def reload(): NamedType = {
val allowPrivate = !lastSymbol.exists || lastSymbol.is(Private) && prefix.classSymbol == this.prefix.classSymbol
val allowPrivate = !lastSymbol.exists || lastSymbol.is(Private)
var d = memberDenot(prefix, name, allowPrivate)
if (d.isOverloaded && lastSymbol.exists)
d = disambiguate(d,
Expand Down Expand Up @@ -3833,18 +3828,14 @@ object Types {

private var validSuper: Period = Nowhere
private var cachedSuper: Type = _
private var myStableHash: Byte = 0

private var isGroundKnown: Boolean = false
private var isGroundCache: Boolean = _
// Boolean caches: 0 = uninitialized, -1 = false, 1 = true
private var myStableHash: Byte = 0
private var myGround: Byte = 0

def isGround(acc: TypeAccumulator[Boolean])(using Context): Boolean = {
if (!isGroundKnown) {
isGroundCache = acc.foldOver(true, this)
isGroundKnown = true
}
isGroundCache
}
def isGround(acc: TypeAccumulator[Boolean])(using Context): Boolean =
if myGround == 0 then myGround = if acc.foldOver(true, this) then 1 else -1
myGround > 0

override def underlying(using Context): Type = tycon

Expand Down Expand Up @@ -5645,7 +5636,7 @@ object Types {
foldOver(cs + tp.typeSymbol, tp)
case tp: TypeRef if tp.info.isTypeAlias =>
apply(cs, tp.superType)
case tp: TypeRef if tp.typeSymbol.isClass =>
case tp: TypeRef if tp.symbol.isClass =>
foldOver(cs + tp.typeSymbol, tp)
case tp: TermRef =>
val tsym = if (tp.termSymbol.is(Param)) tp.underlying.typeSymbol else tp.termSymbol
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ import ast.tpd

class NotAMember(site: Type, val name: Name, selected: String, addendum: => String = "")(using Context)
extends NotFoundMsg(NotAMemberID) {
//println(i"site = $site, decls = ${site.decls}, source = ${site.widen.typeSymbol.sourceFile}") //DEBUG
//println(i"site = $site, decls = ${site.decls}, source = ${site.typeSymbol.sourceFile}") //DEBUG

def msg = {
import core.Flags._
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ArrayConstructors extends MiniPhase {
}
else if ((tree.fun.symbol.maybeOwner eq defn.ArrayModule.moduleClass) && (tree.fun.symbol.name eq nme.ofDim) && !tree.tpe.isInstanceOf[MethodicType]) {
val Apply(Apply(TypeApply(_, List(tp)), _), _) = tree
val cs = tp.tpe.widen.classSymbol
val cs = tp.tpe.classSymbol
tree.fun match {
case Apply(TypeApply(t: Ident, targ), dims)
if !TypeErasure.isGeneric(targ.head.tpe) && !ValueClasses.isDerivedValueClass(cs) =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/ElimOpaque.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ElimOpaque extends MiniPhase with DenotTransformer {
if sym == defn.Any_== || sym == defn.Any_!= then
tree match
case Apply(Select(receiver, name: TermName), args)
if atPhase(thisPhase)(receiver.tpe.widen.dealias.typeSymbol.isOpaqueAlias) =>
if atPhase(thisPhase)(receiver.tpe.widenDealias.typeSymbol.isOpaqueAlias) =>
applyOverloaded(receiver, name, args, Nil, defn.BooleanType)
case _ =>
tree
Expand Down
Loading

0 comments on commit d084b8b

Please sign in to comment.