From 648867aecd03a1e8175307f7ab0f7f1c56951dbe Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 26 Sep 2020 13:37:47 +0200 Subject: [PATCH 1/6] Remove exception for SingletonTypes in typeSymbol typeSymbol now follows underlying type for SingletonTypes, same as for other TypeProxys. --- .../src/dotty/tools/dotc/ast/TreeInfo.scala | 2 +- .../dotty/tools/dotc/core/Definitions.scala | 22 +++++++++---------- .../tools/dotc/core/TypeApplications.scala | 2 +- .../dotty/tools/dotc/core/TypeComparer.scala | 4 ++-- .../dotty/tools/dotc/core/TypeErasure.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 5 ++--- .../dotty/tools/dotc/reporting/messages.scala | 2 +- .../tools/dotc/transform/ElimOpaque.scala | 2 +- .../dotty/tools/dotc/transform/Erasure.scala | 6 ++--- .../dotc/transform/InterceptedMethods.scala | 2 +- .../dotc/transform/TryCatchPatterns.scala | 2 +- .../tools/dotc/transform/patmat/Space.scala | 2 +- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../dotty/tools/dotc/typer/ImportInfo.scala | 2 +- .../tools/dotc/typer/QuotesAndSplices.scala | 4 ++-- .../dotty/tools/dotc/typer/RefChecks.scala | 2 +- 16 files changed, 31 insertions(+), 32 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index bce2265a8924..145864315875 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 88849ff6f798..79269d93ccc7 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -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 } } @@ -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 = @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index eaf0fa9ad420..3732968aa884 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -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 } diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 3d92cddd6d24..7d8a609c67db 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -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 @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index f259d9eec08d..e8726f9eb73b 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bba5b627b571..427e3d66ca53 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -420,7 +420,6 @@ object Types { @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 _: JavaArrayType => defn.ArrayClass case _ => NoSymbol @@ -775,8 +774,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 "." } diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index f4c46317ab98..07864790acaf 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -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._ diff --git a/compiler/src/dotty/tools/dotc/transform/ElimOpaque.scala b/compiler/src/dotty/tools/dotc/transform/ElimOpaque.scala index 55ad79dbe3e9..3eca6ea6b28c 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimOpaque.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimOpaque.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 1d628bb75daa..d27d67e014d0 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -161,7 +161,7 @@ class Erasure extends Phase with DenotTransformer { def assertErased(tp: Type, tree: tpd.Tree = tpd.EmptyTree)(using Context): Unit = { def isAllowed(cls: Symbol, sourceName: String) = - tp.widen.typeSymbol == cls && ctx.compilationUnit.source.file.name == sourceName + tp.typeSymbol == cls && ctx.compilationUnit.source.file.name == sourceName assert(isErasedType(tp) || isAllowed(defn.ArrayClass, "Array.scala") || isAllowed(defn.TupleClass, "Tuple.scala") || @@ -229,7 +229,7 @@ object Erasure { */ private def safelyRemovableUnboxArg(tree: Tree)(using Context): Tree = tree match { case Apply(fn, arg :: Nil) - if isUnbox(fn.symbol) && defn.ScalaBoxedClasses().contains(arg.tpe.widen.typeSymbol) => + if isUnbox(fn.symbol) && defn.ScalaBoxedClasses().contains(arg.tpe.typeSymbol) => arg case _ => EmptyTree @@ -640,7 +640,7 @@ object Erasure { if !sym.exists && tree.name == nme.apply then // PolyFunction apply Selects will not have a symbol, so deduce the owner // from the typed qual. - val owner = qual1.tpe.widen.typeSymbol + val owner = qual1.tpe.typeSymbol if defn.isFunctionClass(owner) then owner else NoSymbol else val owner = sym.maybeOwner diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala index 1b0359692b01..eaa77ff56c6c 100644 --- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -48,7 +48,7 @@ class InterceptedMethods extends MiniPhase { // TODO: add missing cases from scalac private def poundPoundValue(tree: Tree)(using Context) = { - val s = tree.tpe.widen.typeSymbol + val s = tree.tpe.typeSymbol def staticsCall(methodName: TermName): Tree = ref(defn.staticsMethodRef(methodName)).appliedTo(tree) diff --git a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala index cab2fa3328a4..6be58352e6dc 100644 --- a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala +++ b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala @@ -72,7 +72,7 @@ class TryCatchPatterns extends MiniPhase { private def isSimpleThrowable(tp: Type)(using Context): Boolean = tp.stripAnnots match { case tp @ TypeRef(pre, _) => - (pre == NoPrefix || pre.widen.typeSymbol.isStatic) && // Does not require outer class check + (pre == NoPrefix || pre.typeSymbol.isStatic) && // Does not require outer class check !tp.symbol.is(Flags.Trait) && // Traits not supported by JVM tp.derivesFrom(defn.ThrowableClass) case tp: AppliedType => diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index f7c3fc5b45a5..e0768e7d51f8 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -486,7 +486,7 @@ class SpaceEngine(using Context) extends SpaceLogic { case tp @ RefinedType(parent, _, _) => erase(parent) - case tref: TypeRef if tref.typeSymbol.isPatternBound => + case tref: TypeRef if tref.symbol.isPatternBound => if (inArray) tref.underlying else WildcardType case _ => tp diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index c9c6564abc30..f1f60f1a18f6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -116,7 +116,7 @@ object Applications { if (sel.exists) sel :: tupleSelectors(n + 1, tp) else Nil } def genTupleSelectors(n: Int, tp: Type): List[Type] = tp match { - case tp: AppliedType if !defn.isTupleClass(tp.typeSymbol) && tp.derivesFrom(defn.PairClass) => + case tp: AppliedType if !defn.isTupleClass(tp.tycon.typeSymbol) && tp.derivesFrom(defn.PairClass) => val List(head, tail) = tp.args head :: genTupleSelectors(n, tail) case _ => tupleSelectors(n, tp) diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index a88af260eed0..50ba3b13dc5f 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -186,7 +186,7 @@ class ImportInfo(symf: Context ?=> Symbol, def featureImported(feature: TermName, owner: Symbol)(using Context): Boolean = def compute = - val isImportOwner = site.widen.typeSymbol.eq(owner) + val isImportOwner = site.typeSymbol.eq(owner) if isImportOwner && forwardMapping.contains(feature) then true else if isImportOwner && excluded.contains(feature) then false else diff --git a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala index 473e9ea95d5b..f7c85c76ab72 100644 --- a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala +++ b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala @@ -327,7 +327,7 @@ trait QuotesAndSplices { val isFreshTypeBindings = freshTypeBindings.map(_.symbol).toSet val typeMap = new TypeMap() { def apply(tp: Type): Type = tp match { - case tp: TypeRef if tp.typeSymbol.isTypeSplice => + case tp: TypeRef if tp.symbol.isTypeSplice => val tp1 = tp.dealias if (isFreshTypeBindings(tp1.typeSymbol)) tp1 else tp @@ -408,7 +408,7 @@ trait QuotesAndSplices { class ReplaceBindings extends TypeMap() { override def apply(tp: Type): Type = tp match { case tp: TypeRef => - val tp1 = if (tp.typeSymbol.isTypeSplice) tp.dealias else tp + val tp1 = if (tp.symbol.isTypeSplice) tp.dealias else tp mapOver(typeBindings.get(tp1.typeSymbol).fold(tp)(_.symbol.typeRef)) case tp => mapOver(tp) } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index c85aee7aa65b..81ac626de2fe 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1166,7 +1166,7 @@ class RefChecks extends MiniPhase { thisPhase => case _ => false } def underlyingClass(tp: Type): Symbol = { - val sym = tp.widen.typeSymbol + val sym = tp.typeSymbol if (sym.isAbstractOrParamType) underlyingClass(sym.info.bounds.hi) else sym } From ff7e3b02ab3661a96f0e08f743c60de7fa2dbad1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 26 Sep 2020 13:40:59 +0200 Subject: [PATCH 2/6] Replace widenDealias.typeSymbol with typeSymbol in backend --- .../dotty/tools/backend/jvm/BCodeBodyBuilder.scala | 10 +++++----- .../dotty/tools/backend/jvm/BCodeSkelBuilder.scala | 2 +- .../src/dotty/tools/backend/sjs/JSCodeGen.scala | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala index e4a0e282a5a8..6d495c7d16f0 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala @@ -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) => @@ -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) @@ -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 @@ -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 @@ -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 diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index 2c575309d9f1..eff9c170c2df 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -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 } diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 3621b6fcb0ae..cd7b1ba1ce26 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -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)) @@ -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 @@ -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)) @@ -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 @@ -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 @@ -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()) From 23f0e6d787d136fceec2bf2a829b08b65df17861 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 26 Sep 2020 14:14:41 +0200 Subject: [PATCH 3/6] Drop ineffective condition The dropped condition is vacuously true for all singleton prefixes, since for them classSymbol is NoSymbol. If we make it work as was intended using widen in front of classSymbol on both sides, then EeraseAnd and dotty bootstrap fail. --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 427e3d66ca53..a067f78a5179 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2376,7 +2376,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, From 4fc58280a86a23f328a60a50649eba4d209581b1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 26 Sep 2020 17:44:30 +0200 Subject: [PATCH 4/6] Make classSymbol also work for SingletonTypes Analogius to the change for typeSymbol --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- .../dotc/core/PatternTypeConstrainer.scala | 4 +-- .../src/dotty/tools/dotc/core/TypeOps.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 2 -- .../dotc/transform/ArrayConstructors.scala | 2 +- .../dotty/tools/dotc/transform/Erasure.scala | 4 +-- .../tools/dotc/transform/ExplicitOuter.scala | 2 +- .../dotc/transform/FunctionalInterfaces.scala | 2 +- .../tools/dotc/transform/TypeUtils.scala | 7 ++-- .../tools/dotc/transform/patmat/Space.scala | 35 +++++++++---------- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- .../src/dotty/tools/dotc/typer/Inliner.scala | 4 +-- .../dotty/tools/dotc/typer/RefChecks.scala | 2 +- tests/neg/i6226.scala | 2 +- tests/neg/i8337.scala | 2 +- 16 files changed, 36 insertions(+), 40 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 80984541f050..a26c5e86cf34 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -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 } diff --git a/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala b/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala index 5935fbd91705..d0f9a49cf216 100644 --- a/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala +++ b/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala @@ -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) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index ba63eb48c8a3..73bdcad169c5 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -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 } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index a067f78a5179..8cae7654db3b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -437,8 +437,6 @@ object Types { if (sym.isClass) sym else tp.superType.classSymbol case tp: ClassInfo => tp.cls - case tp: SingletonType => - NoSymbol case tp: TypeProxy => tp.underlying.classSymbol case AndType(l, r) => diff --git a/compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala b/compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala index 6ba4244560ff..437ff0490822 100644 --- a/compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala +++ b/compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala @@ -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) => diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index d27d67e014d0..e66606fd2882 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -287,7 +287,7 @@ object Erasure { cast(tree1, pt) case _ => - val cls = pt.widen.classSymbol + val cls = pt.classSymbol if (cls eq defn.UnitClass) constant(tree, Literal(Constant(()))) else { assert(cls ne defn.ArrayClass) @@ -430,7 +430,7 @@ object Erasure { val implResultType = implType.resultType val samResultType = sam.resultType - if (!defn.isSpecializableFunction(implClosure.tpe.widen.classSymbol.asClass, implParamTypes, implResultType)) { + if (!defn.isSpecializableFunction(implClosure.tpe.classSymbol.asClass, implParamTypes, implResultType)) { def autoAdaptedParam(tp: Type) = !tp.isErasedValueType && !tp.isPrimitiveValueType val explicitSAMType = implClosure.tpt.tpe.exists def autoAdaptedResult(tp: Type) = !tp.isErasedValueType && diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 6c0b63e3c1cd..a8e43bc1adaa 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -398,7 +398,7 @@ object ExplicitOuter { count: Int = -1): Tree = try @tailrec def loop(tree: Tree, count: Int): Tree = - val treeCls = tree.tpe.widen.classSymbol + val treeCls = tree.tpe.classSymbol report.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${atPhaseNoLater(lambdaLiftPhase)(outerAccName(treeCls.asClass))} in $treeCls") if (count == 0 || count < 0 && treeCls == toCls) tree else diff --git a/compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala b/compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala index ba49b22ce263..26c67a2e504a 100644 --- a/compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala +++ b/compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala @@ -28,7 +28,7 @@ class FunctionalInterfaces extends MiniPhase { private val functionPackage = "dotty.runtime.function.".toTermName override def transformClosure(tree: Closure)(using Context): Tree = { - val cls = tree.tpe.widen.classSymbol.asClass + val cls = tree.tpe.classSymbol.asClass val implType = tree.meth.tpe.widen val List(implParamTypes) = implType.paramInfoss diff --git a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala index cd4b9695047a..d92812409ffe 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala @@ -41,8 +41,8 @@ object TypeUtils { case AppliedType(tycon, _ :: tl :: Nil) if tycon.isRef(defn.PairClass) => val arity = tl.tupleArity if (arity < 0) arity else arity + 1 - case self: TermRef if self.symbol == defn.EmptyTupleModule => - 0 + case self: SingletonType => + if self.termSymbol == defn.EmptyTupleModule then 0 else -1 case self if defn.isTupleClass(self.classSymbol) => self.dealias.argInfos.length case _ => @@ -53,7 +53,8 @@ object TypeUtils { def tupleElementTypes(using Context): List[Type] = self match { case AppliedType(tycon, hd :: tl :: Nil) if tycon.isRef(defn.PairClass) => hd :: tl.tupleElementTypes - case self: TermRef if self.symbol == defn.EmptyTupleModule => + case self: SingletonType => + assert(self.termSymbol == defn.EmptyTupleModule, "not a tuple") Nil case self if defn.isTupleClass(self.classSymbol) => self.dealias.argInfos diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index e0768e7d51f8..2120a00984cf 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -645,26 +645,22 @@ class SpaceEngine(using Context) extends SpaceLogic { /** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */ - def canDecompose(tp: Type): Boolean = { - val dealiasedTp = tp.dealias - val res = - (tp.classSymbol.is(Sealed) && - tp.classSymbol.isOneOf(AbstractOrTrait) && - !tp.classSymbol.hasAnonymousChild && - tp.classSymbol.children.nonEmpty ) || - dealiasedTp.isInstanceOf[OrType] || - (dealiasedTp.isInstanceOf[AndType] && { - val and = dealiasedTp.asInstanceOf[AndType] - canDecompose(and.tp1) || canDecompose(and.tp2) - }) || - tp.isRef(defn.BooleanClass) || - tp.isRef(defn.UnitClass) || - tp.classSymbol.isAllOf(JavaEnumTrait) - + def canDecompose(tp: Type): Boolean = + val res = tp.dealias match + case _: SingletonType => false + case _: OrType => true + case and: AndType => canDecompose(and.tp1) || canDecompose(and.tp2) + case _ => + val cls = tp.classSymbol + cls.is(Sealed) + && cls.isOneOf(AbstractOrTrait) + && !cls.hasAnonymousChild + && cls.children.nonEmpty + || cls.isAllOf(JavaEnumTrait) + || tp.isRef(defn.BooleanClass) + || tp.isRef(defn.UnitClass) debug.println(s"decomposable: ${tp.show} = $res") - res - } /** Show friendly type name with current scope in mind * @@ -765,7 +761,8 @@ class SpaceEngine(using Context) extends SpaceLogic { if (flattenList && tp <:< scalaNilType) "" else tp.symbol.showName case Typ(tp, decomposed) => - val sym = tp.widen.classSymbol + + val sym = tp.classSymbol if (ctx.definitions.isTupleType(tp)) params(tp).map(_ => "_").mkString("(", ", ", ")") diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index f1f60f1a18f6..a2113ce2946f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -2039,7 +2039,7 @@ trait Applications extends Compatibility { case ConstantType(c: Constant) if c.tag == IntTag => targetClass(ts1, cls, true) case t => - val sym = t.widen.classSymbol + val sym = t.classSymbol if (!sym.isNumericValueClass || cls.exists && cls != sym) NoSymbol else targetClass(ts1, sym, intLitSeen) } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index ad0d7406369c..9a01bb16a096 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -920,7 +920,7 @@ trait Checking { if (caller.is(Module)) { val traverser = new TreeTraverser { def traverse(tree: Tree)(using Context) = tree match { - case tree: RefTree if tree.isTerm && (tree.tpe.widen.classSymbol eq caller) => + case tree: RefTree if tree.isTerm && (tree.tpe.classSymbol eq caller) => report.error("super constructor cannot be passed a self reference", tree.srcPos) case _ => traverseChildren(tree) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 7326d77262b2..00db8df2a6e0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -466,7 +466,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { val sortedProxies = thisProxy.toList.map { case (cls, proxy) => // The class that the this-proxy `selfSym` represents - def classOf(selfSym: Symbol) = selfSym.info.widen.classSymbol + def classOf(selfSym: Symbol) = selfSym.info.classSymbol // The total nesting depth of the class represented by `selfSym`. def outerLevel(selfSym: Symbol): Int = classOf(selfSym).ownersIterator.length (outerLevel(cls), proxy.symbol) @@ -1082,7 +1082,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { scrut.widenTermRefExpr =:= pat.tpe case pat: RefTree => scrut =:= pat.tpe || - scrut.widen.classSymbol.is(Module) && scrut.widen =:= pat.tpe.widen && { + scrut.classSymbol.is(Module) && scrut.widen =:= pat.tpe.widen && { scrut.prefix match { case _: SingletonType | NoPrefix => true case _ => false diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 81ac626de2fe..d09dad5ca063 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -99,7 +99,7 @@ object RefChecks { def checkSelfConforms(other: ClassSymbol, category: String, relation: String) = { val otherSelf = other.declaredSelfTypeAsSeenFrom(cls.thisType) if otherSelf.exists && !(cinfo.selfType <:< otherSelf) then - report.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other.classSymbol), + report.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other), cls.srcPos) } val parents = cinfo.classParents diff --git a/tests/neg/i6226.scala b/tests/neg/i6226.scala index ed2dddc1b297..922038619e64 100644 --- a/tests/neg/i6226.scala +++ b/tests/neg/i6226.scala @@ -7,6 +7,6 @@ object O2 { } object O3 { // error - opaque type R[X] = T[X] + opaque type R[X] = T[X] // error opaque type T[X] = R[X] // error } diff --git a/tests/neg/i8337.scala b/tests/neg/i8337.scala index 71701acf7ef0..7955c471fb70 100644 --- a/tests/neg/i8337.scala +++ b/tests/neg/i8337.scala @@ -2,5 +2,5 @@ trait Foo[F <: Foo[F]] class Bar extends Foo[Bar] object Q { // error: recursion limit exceeded - opaque type X <: Foo[X] = Bar // error: out of bounds + opaque type X <: Foo[X] = Bar // error: out of bounds // error } \ No newline at end of file From d14a42c931e76170b9aca8e273bf7c205e0a8ebf Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 26 Sep 2020 17:50:46 +0200 Subject: [PATCH 5/6] Reorder cases in typeSymbol and classSymbol --- compiler/src/dotty/tools/dotc/core/Types.scala | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8cae7654db3b..03fbbed0c5ea 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -419,8 +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: TypeProxy => tp.underlying.typeSymbol + case tp: ClassInfo => tp.cls case _: JavaArrayType => defn.ArrayClass case _ => NoSymbol } @@ -430,15 +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: TypeProxy => tp.underlying.classSymbol + case tp: ClassInfo => + tp.cls case AndType(l, r) => val lsym = l.classSymbol val rsym = r.classSymbol @@ -456,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) => From 9ff320348e5e174a500800a72249cb240a85ea48 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 26 Sep 2020 18:52:11 +0200 Subject: [PATCH 6/6] Smaller tweaks --- compiler/src/dotty/tools/dotc/core/Types.scala | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 03fbbed0c5ea..c14942e12a67 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3828,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 @@ -5640,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