diff --git a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala index 8e7cfc688724..bccdf6fd6fc1 100644 --- a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala @@ -49,8 +49,8 @@ object CollectEntryPoints{ def isJavaMainMethod(sym: Symbol)(implicit ctx: Context) = { (sym.name == nme.main) && (sym.info match { case r@MethodTpe(_, List(defn.ArrayOf(t)), _) => - (t.widenDealias =:= defn.StringType) && ( - r.resultType.widenDealias =:= defn.UnitType) + (t.widenDealiasStripAnnots =:= defn.StringType) && ( + r.resultType.widenDealiasStripAnnots =:= defn.UnitType) case _ => false }) } diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index c3ad297c860b..c2192bcf0d06 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -898,7 +898,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def members: List[Symbol] = tp.allMembers.map(_.symbol).toList - def typeSymbol: Symbol = tp.widenDealias.typeSymbol + def typeSymbol: Symbol = tp.widenDealiasStripAnnots.typeSymbol def =:=(other: Type): Boolean = tp =:= other @@ -932,7 +932,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma ObjectReference.asInstanceOf[ct.bTypes.ClassBType] } - tp.widenDealias match { + tp.widenDealiasStripAnnots match { case JavaArrayType(el) =>ArrayBType(el.toTypeKind(ct)(storage)) // Array type such as Array[Int] (kept by erasure) case t: TypeRef => t.info match { @@ -1190,8 +1190,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma val t = field.tpt.tpe.typeSymbol if (t.exists) t else { - val arity = field.meth.tpe.widenDealias.paramTypes.size - _1.size - val returnsUnit = field.meth.tpe.widenDealias.resultType.classSymbol == UnitClass + val arity = field.meth.tpe.widenDealiasStripAnnots.paramTypes.size - _1.size + val returnsUnit = field.meth.tpe.widenDealiasStripAnnots.resultType.classSymbol == UnitClass if (returnsUnit) ctx.requiredClass(("scala.compat.java8.JProcedure" + arity).toTermName) else ctx.requiredClass(("scala.compat.java8.JFunction" + arity).toTermName) diff --git a/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala b/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala index fed7aeb81f63..978218767cdd 100644 --- a/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala +++ b/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala @@ -66,7 +66,7 @@ class DottyPrimitives(ctx: Context) { case _ => getPrimitive(fun) } - def elementType: Type = tpe.widenDealias match { + def elementType: Type = tpe.widenDealiasStripAnnots match { case defn.ArrayOf(el) => el case JavaArrayType(el) => el case _ => diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index c7017a8f547c..5f42c748bd33 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -78,7 +78,7 @@ object desugar { case tp: NamedType if tp.symbol.exists && (tp.symbol.owner eq originalOwner) => val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next() var local = defctx.denotNamed(tp.name ++ suffix).suchThat(_.isParamOrAccessor).symbol - if (local.exists) (defctx.owner.thisType select local).dealias + if (local.exists) (defctx.owner.thisType select local).dealiasKeepAnnots else { def msg = s"no matching symbol for ${tp.symbol.showLocated} in ${defctx.owner} / ${defctx.effectiveScope.toList}" diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index b817131c0ce6..9d5ac0554877 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -551,6 +551,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => /** An extractor for def of a closure contained the block of the closure. */ object closureDef { def unapply(tree: Tree): Option[DefDef] = tree match { + case Block(Nil, expr) => unapply(expr) case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, closure: Closure) => Some(meth) case _ => None @@ -690,7 +691,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => */ def isStructuralTermSelect(tree: Tree)(implicit ctx: Context) = tree match { case tree: Select => - def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match { + def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealiasStripAnnots match { case RefinedType(parent, rname, rinfo) => rname == tree.name || hasRefinement(parent) case tp: TypeProxy => diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 3fcc107bc8b1..9f72feb216b9 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -213,6 +213,31 @@ object Trees { override def toText(printer: Printer) = printer.toText(this) + def sameTree(that: Tree[_]): Boolean = { + def isSame(x: Any, y: Any): Boolean = + x.asInstanceOf[AnyRef].eq(y.asInstanceOf[AnyRef]) || { + x match { + case x: Tree[_] => + y match { + case y: Tree[_] => x.sameTree(y) + case _ => false + } + case x: List[_] => + y match { + case y: List[_] => x.corresponds(y)(isSame) + case _ => false + } + case _ => + false + } + } + this.getClass == that.getClass && { + val it1 = this.productIterator + val it2 = that.productIterator + it1.corresponds(it2)(isSame) + } + } + override def hashCode(): Int = uniqueId // for debugging; was: System.identityHashCode(this) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index e77b56e4c27f..7285254b49e3 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -353,7 +353,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { Ident(tp) else { val pre = tp.prefix - if (pre.isSingleton) followOuterLinks(singleton(pre.dealias)).select(tp) + if (pre.isSingleton) followOuterLinks(singleton(pre.dealiasStripAnnots)).select(tp) else Select(TypeTree(pre), tp) } @@ -791,7 +791,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { applyOverloaded(tree, nme.EQ, that :: Nil, Nil, defn.BooleanType) /** `tree.isInstanceOf[tp]`, with special treatment of singleton types */ - def isInstance(tp: Type)(implicit ctx: Context): Tree = tp.dealias match { + def isInstance(tp: Type)(implicit ctx: Context): Tree = tp.dealiasStripAnnots match { case tp: SingletonType => if (tp.widen.derivesFrom(defn.ObjectClass)) tree.ensureConforms(defn.ObjectType).select(defn.Object_eq).appliedTo(singleton(tp)) @@ -963,7 +963,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val alternatives = ctx.typer.resolveOverloaded(allAlts, proto) assert(alternatives.size == 1, i"${if (alternatives.isEmpty) "no" else "multiple"} overloads available for " + - i"$method on ${receiver.tpe.widenDealias} with targs: $targs%, %; args: $args%, % of types ${args.tpes}%, %; expectedType: $expectedType." + + i"$method on ${receiver.tpe.widenDealiasKeepAnnots} with targs: $targs%, %; args: $args%, % of types ${args.tpes}%, %; expectedType: $expectedType." + i" isAnnotConstructor = $isAnnotConstructor.\n" + i"all alternatives: ${allAlts.map(_.symbol.showDcl).mkString(", ")}\n" + i"matching alternatives: ${alternatives.map(_.symbol.showDcl).mkString(", ")}.") // this is parsed from bytecode tree. there's nothing user can do about it diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 5d68de1bb284..80e4365a943c 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -132,6 +132,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class Inline() extends Mod(Flags.Inline) + case class Transparent() extends Mod(Flags.Transparent) + case class Enum() extends Mod(Flags.Enum) } diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 2da8c95f0b71..3d66c876f6b7 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -34,6 +34,9 @@ object Annotations { def isEvaluated: Boolean = true def ensureCompleted(implicit ctx: Context): Unit = tree + + def sameAnnotation(that: Annotation)(implicit ctx: Context) = + symbol == that.symbol && tree.sameTree(that.tree) } case class ConcreteAnnotation(t: Tree) extends Annotation { diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala index bac81942f8e3..3b3948107533 100644 --- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala +++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala @@ -69,7 +69,7 @@ class CheckRealizable(implicit ctx: Context) { private def isLateInitialized(sym: Symbol) = sym.is(Lazy, butNot = Module) /** The realizability status of given type `tp`*/ - def realizability(tp: Type): Realizability = tp.dealias match { + def realizability(tp: Type): Realizability = tp.dealiasStripAnnots match { case tp: TermRef => val sym = tp.symbol if (sym.is(Stable)) realizability(tp.prefix) @@ -85,7 +85,7 @@ class CheckRealizable(implicit ctx: Context) { case _: SingletonType | NoPrefix => Realizable case tp => - def isConcrete(tp: Type): Boolean = tp.dealias match { + def isConcrete(tp: Type): Boolean = tp.dealiasStripAnnots match { case tp: TypeRef => tp.symbol.isClass case tp: TypeProxy => isConcrete(tp.underlying) case tp: AndType => isConcrete(tp.tp1) && isConcrete(tp.tp2) @@ -96,7 +96,7 @@ class CheckRealizable(implicit ctx: Context) { else boundsRealizability(tp).andAlso(memberRealizability(tp)) } - private def refinedNames(tp: Type): Set[Name] = tp.dealias match { + private def refinedNames(tp: Type): Set[Name] = tp.dealiasStripAnnots match { case tp: RefinedType => refinedNames(tp.parent) + tp.refinedName case tp: AndType => refinedNames(tp.tp1) ++ refinedNames(tp.tp2) case tp: OrType => refinedNames(tp.tp1) ++ refinedNames(tp.tp2) diff --git a/compiler/src/dotty/tools/dotc/core/Constants.scala b/compiler/src/dotty/tools/dotc/core/Constants.scala index 38cdac21d7fe..33fb1eab5797 100644 --- a/compiler/src/dotty/tools/dotc/core/Constants.scala +++ b/compiler/src/dotty/tools/dotc/core/Constants.scala @@ -152,7 +152,7 @@ object Constants { /** Convert constant value to conform to given type. */ def convertTo(pt: Type)(implicit ctx: Context): Constant = { - def classBound(pt: Type): Type = pt.dealias.stripTypeVar match { + def classBound(pt: Type): Type = pt.dealiasStripAnnots.stripTypeVar match { case tref: TypeRef if !tref.symbol.isClass && tref.info.exists => classBound(tref.info.bounds.lo) case param: TypeParamRef => diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index cfb11cde9fc0..eb4df22483b5 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -50,7 +50,7 @@ trait ConstraintHandling { private def addOneBound(param: TypeParamRef, bound: Type, isUpper: Boolean): Boolean = !constraint.contains(param) || { def occursIn(bound: Type): Boolean = { - val b = bound.dealias + val b = bound.dealiasStripAnnots (b eq param) || { b match { case b: AndType => occursIn(b.tp1) || occursIn(b.tp2) @@ -275,7 +275,7 @@ trait ConstraintHandling { case tp: OrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2) case _ => true } - def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match { + def isOrType(tp: Type): Boolean = tp.dealiasStripAnnots match { case tp: OrType => true case tp: RefinedOrRecType => isOrType(tp.parent) case AndType(tp1, tp2) => isOrType(tp1) | isOrType(tp2) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index c87ff6b059ba..fbe101a63688 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -694,6 +694,8 @@ class Definitions { def ClassfileAnnotationClass(implicit ctx: Context) = ClassfileAnnotationType.symbol.asClass lazy val StaticAnnotationType = ctx.requiredClassRef("scala.annotation.StaticAnnotation") def StaticAnnotationClass(implicit ctx: Context) = StaticAnnotationType.symbol.asClass + lazy val SubTypeAnnotationType = ctx.requiredClassRef("scala.annotation.SubTypeAnnotation") + def SubTypeAnnotationClass(implicit ctx: Context) = SubTypeAnnotationType.symbol.asClass // Annotation classes lazy val AliasAnnotType = ctx.requiredClassRef("scala.annotation.internal.Alias") @@ -795,7 +797,7 @@ class Definitions { def unapply(ft: Type)(implicit ctx: Context) = { val tsym = ft.typeSymbol if (isFunctionClass(tsym)) { - val targs = ft.dealias.argInfos + val targs = ft.dealiasStripAnnots.argInfos if (targs.isEmpty) None else Some(targs.init, targs.last, tsym.name.isImplicitFunction, tsym.name.isErasedFunction) } @@ -808,7 +810,7 @@ class Definitions { PartialFunctionType.appliedTo(arg :: result :: Nil) def unapply(pft: Type)(implicit ctx: Context) = { if (pft.isRef(PartialFunctionClass)) { - val targs = pft.dealias.argInfos + val targs = pft.dealiasStripAnnots.argInfos if (targs.length == 2) Some((targs.head, targs.tail)) else None } else None @@ -819,7 +821,7 @@ class Definitions { def apply(elem: Type)(implicit ctx: Context) = if (ctx.erasedTypes) JavaArrayType(elem) else ArrayType.appliedTo(elem :: Nil) - def unapply(tp: Type)(implicit ctx: Context): Option[Type] = tp.dealias match { + def unapply(tp: Type)(implicit ctx: Context): Option[Type] = tp.dealiasStripAnnots match { case AppliedType(at, arg :: Nil) if at isRef ArrayType.symbol => Some(arg) case _ => None } @@ -840,7 +842,7 @@ class Definitions { if (ndims == 0) elem else ArrayOf(apply(elem, ndims - 1)) def unapply(tp: Type)(implicit ctx: Context): Option[(Type, Int)] = tp match { case ArrayOf(elemtp) => - def recur(elemtp: Type): Option[(Type, Int)] = elemtp.dealias match { + def recur(elemtp: Type): Option[(Type, Int)] = elemtp.dealiasStripAnnots match { case TypeBounds(lo, hi) => recur(hi) case MultiArrayOf(finalElemTp, n) => Some(finalElemTp, n + 1) case _ => Some(elemtp, 1) @@ -1020,7 +1022,7 @@ class Definitions { (sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf) def isTupleType(tp: Type)(implicit ctx: Context) = { - val arity = tp.dealias.argInfos.length + val arity = tp.dealiasStripAnnots.argInfos.length arity <= MaxTupleArity && TupleType(arity) != null && (tp isRef TupleType(arity).symbol) } @@ -1036,7 +1038,7 @@ class Definitions { */ def isNonDepFunctionType(tp: Type)(implicit ctx: Context) = { val arity = functionArity(tp) - val sym = tp.dealias.typeSymbol + val sym = tp.dealiasStripAnnots.typeSymbol arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction, sym.name.isErasedFunction).typeSymbol) } @@ -1082,7 +1084,7 @@ class Definitions { false }) - def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1 + def functionArity(tp: Type)(implicit ctx: Context) = tp.dealiasStripAnnots.argInfos.length - 1 /** Return underlying immplicit function type (i.e. instance of an ImplicitFunctionN class) * or NoType if none exists. The following types are considered as underlying types: @@ -1091,7 +1093,7 @@ class Definitions { * - the upper bound of a TypeParamRef in the current constraint */ def asImplicitFunctionType(tp: Type)(implicit ctx: Context): Type = - tp.stripTypeVar.dealias match { + tp.stripTypeVar.dealiasStripAnnots match { case tp1: TypeParamRef if ctx.typerState.constraint.contains(tp1) => asImplicitFunctionType(ctx.typeComparer.bounds(tp1).hiBound) case tp1 => @@ -1104,7 +1106,7 @@ class Definitions { asImplicitFunctionType(tp).exists def isErasedFunctionType(tp: Type)(implicit ctx: Context) = - isFunctionType(tp) && tp.dealias.typeSymbol.name.isErasedFunction + isFunctionType(tp) && tp.dealiasStripAnnots.typeSymbol.name.isErasedFunction // ----- primitive value class machinery ------------------------------------------ diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index ad052f84c7fb..2fc48608dfe6 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -363,7 +363,10 @@ object Flags { /** Symbol is a Java default method */ final val DefaultMethod = termFlag(38, "") - /** Symbol is a Java enum */ + /** Labelled with `transparent` modifier */ + final val Transparent = termFlag(39, "transparent") + + /** Symbol is an enum class or enum case (if used with case) */ final val Enum = commonFlag(40, "") /** Labeled with `erased` modifier (erased value) */ @@ -436,7 +439,7 @@ object Flags { /** Flags representing source modifiers */ final val SourceModifierFlags = - commonFlags(Private, Protected, Abstract, Final, Inline, + commonFlags(Private, Protected, Abstract, Final, Inline, Transparent, Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic, Erased) /** Flags representing modifiers that can appear in trees */ @@ -457,7 +460,7 @@ object Flags { Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | CaseAccessor.toCommonFlags | NonMember | ImplicitCommon | Permanent | Synthetic | - SuperAccessorOrScala2x | Inline + SuperAccessorOrScala2x | Inline | Transparent.toCommonFlags /** Flags that are not (re)set when completing the denotation, or, if symbol is * a top-level class or object, when completing the denotation once the class @@ -513,7 +516,7 @@ object Flags { /** Flags that can apply to a module val */ final val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags | Override | Final | Method | Implicit | Lazy | - Accessor | AbsOverride | Stable | Captured | Synchronized | Inline | Erased + Accessor | AbsOverride | Stable | Captured | Synchronized | Erased /** Flags that can apply to a module class */ final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | ImplClass | Enum @@ -548,8 +551,8 @@ object Flags { /** Either method or lazy or deferred */ final val MethodOrLazyOrDeferred = Method | Lazy | Deferred - /** Labeled `private`, `final`, or `inline` */ - final val PrivateOrFinalOrInline = Private | Final | Inline + /** Labeled `private`, `final`, `inline`, or `transparent` */ + final val EffectivelyFinal = Private | Final | Inline | Transparent.toCommonFlags /** A private method */ final val PrivateMethod = allOf(Private, Method) @@ -560,6 +563,9 @@ object Flags { /** An inline method */ final val InlineMethod = allOf(Inline, Method) + /** An transparent method */ + final val TransparentMethod = allOf(Transparent, Method) + /** An inline parameter */ final val InlineParam = allOf(Inline, Param) @@ -575,6 +581,9 @@ object Flags { /** An accessor or label */ final val AccessorOrLabel = Accessor | Label + /** An accessor or a synthetic symbol */ + final val AccessorOrSynthetic = Accessor | Synthetic + /** A synthetic or private definition */ final val SyntheticOrPrivate = Synthetic | Private @@ -584,8 +593,8 @@ object Flags { /** A deferred type member or parameter (these don't have right hand sides) */ final val DeferredOrTypeParam = Deferred | TypeParam - /** value that's final or inline */ - final val FinalOrInline = Final | Inline + /** value that's final, inline, or transparent */ + final val FinalOrInlineOrTransparent = Final | Inline | Transparent.toCommonFlags /** A covariant type parameter instance */ final val LocalCovariant = allOf(Local, Covariant) diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index 6689a5371244..c97e20a88d49 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -93,5 +93,4 @@ object Mode { /** We are in the IDE */ val Interactive = newMode(20, "Interactive") - } diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index 0eeb99e66928..086bb68064fd 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -387,7 +387,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, * that are not top-level are not affected. */ def replace(param: TypeParamRef, tp: Type)(implicit ctx: Context): OrderingConstraint = { - val replacement = tp.dealias.stripTypeVar + val replacement = tp.dealiasKeepAnnots.stripTypeVar if (param == replacement) this else { assert(replacement.isValueTypeOrLambda) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 7d2ecdf21436..a8a53da9ffa5 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -779,7 +779,13 @@ object SymDenotations { def isSkolem: Boolean = name == nme.SKOLEM - def isInlineMethod(implicit ctx: Context): Boolean = is(InlineMethod, butNot = Accessor) + def isInlinedMethod(implicit ctx: Context): Boolean = + is(InlineMethod, butNot = Accessor) + + def isTransparentMethod(implicit ctx: Context): Boolean = + is(TransparentMethod, butNot = Accessor) + + def isInlineableMethod(implicit ctx: Context) = isInlinedMethod || isTransparentMethod /** ()T and => T types should be treated as equivalent for this symbol. * Note: For the moment, we treat Scala-2 compiled symbols as loose matching, @@ -905,7 +911,7 @@ object SymDenotations { /** A symbol is effectively final if it cannot be overridden in a subclass */ final def isEffectivelyFinal(implicit ctx: Context): Boolean = - is(PrivateOrFinalOrInline) || !owner.isClass || owner.is(ModuleOrFinal) || owner.isAnonymousClass + is(EffectivelyFinal) || !owner.isClass || owner.is(ModuleOrFinal) || owner.isAnonymousClass /** The class containing this denotation which has the given effective name. */ final def enclosingClassNamed(name: Name)(implicit ctx: Context): Symbol = { diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 7cae7b1822ab..0e9aa8a0834c 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -125,7 +125,7 @@ trait Symbols { this: Context => def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { val cls = denot.asClass.classSymbol val decls = newScope - denot.info = ClassInfo(owner.thisType, cls, parentTypes.map(_.dealias), decls) + denot.info = ClassInfo(owner.thisType, cls, parentTypes.map(_.dealiasStripAnnots), decls) } } newClassSymbol(owner, name, flags, completer, privateWithin, coord, assocFile) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 75732475ac73..d0e7ac731a0d 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -220,7 +220,7 @@ class TypeApplications(val self: Type) extends AnyVal { /** If self type is higher-kinded, its result type, otherwise NoType. * Note: The hkResult of an any-kinded type is again AnyKind. */ - def hkResult(implicit ctx: Context): Type = self.dealias match { + def hkResult(implicit ctx: Context): Type = self.dealiasStripAnnots match { case self: TypeRef => if (self.symbol == defn.AnyKindClass) self else self.info.hkResult case self: AppliedType => diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 52c39ab473cc..0e822ecbcd15 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -236,8 +236,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { compareWild case tp2: LazyRef => !tp2.evaluating && recur(tp1, tp2.ref) - case tp2: AnnotatedType => - recur(tp1, tp2.tpe) // todo: refine? + case tp2: AnnotatedType if !tp2.isSubTypeAnnotated => + recur(tp1, tp2.tpe) case tp2: ThisType => def compareThis = { val cls2 = tp2.cls @@ -345,13 +345,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { // because that would cause an assertionError. Return false instead. // See i859.scala for an example where we hit this case. !tp1.evaluating && recur(tp1.ref, tp2) - case tp1: AnnotatedType => + case tp1: AnnotatedType if !tp1.isSubTypeAnnotated => recur(tp1.tpe, tp2) case AndType(tp11, tp12) => if (tp11.stripTypeVar eq tp12.stripTypeVar) recur(tp11, tp2) else thirdTry case tp1 @ OrType(tp11, tp12) => - def joinOK = tp2.dealias match { + def joinOK = tp2.dealiasKeepAnnots match { case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass => // If we apply the default algorithm for `A[X] | B[Y] <: C[Z]` where `C` is a // type parameter, we will instantiate `C` to `A` and then fail when comparing @@ -510,7 +510,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } compareTypeLambda case OrType(tp21, tp22) => - val tp1a = tp1.widenDealias + val tp1a = tp1.widenDealiasKeepAnnots if (tp1a ne tp1) // Follow the alias; this might avoid truncating the search space in the either below // Note that it's safe to widen here because singleton types cannot be part of `|`. @@ -567,6 +567,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { false } compareTypeBounds + case tp2: AnnotatedType if tp2.isSubTypeAnnotated => + (tp1.derivesAnnotWith(tp2.annot.sameAnnotation) || defn.isBottomType(tp1)) && + recur(tp1, tp2.tpe) case ClassInfo(pre2, cls2, _, _, _) => def compareClassInfo = tp1 match { case ClassInfo(pre1, cls1, _, _, _) => @@ -598,7 +601,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } isSubType(hi1, tp2, approx.addLow) || compareGADT case _ => - def isNullable(tp: Type): Boolean = tp.widenDealias match { + def isNullable(tp: Type): Boolean = tp.widenDealiasStripAnnots match { case tp: TypeRef => tp.symbol.isNullableClass case tp: RefinedOrRecType => isNullable(tp.parent) case tp: AppliedType => isNullable(tp.tycon) @@ -616,7 +619,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { /** if `tp2 == p.type` and `p: q.type` then try `tp1 <:< q.type` as a last effort.*/ def comparePaths = tp2 match { case tp2: TermRef => - tp2.info.widenExpr.dealias match { + tp2.info.widenExpr.dealiasStripAnnots match { case tp2i: SingletonType => recur(tp1, tp2i) // see z1720.scala for a case where this can arise even in typer. @@ -641,7 +644,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } compareHKLambda case AndType(tp11, tp12) => - val tp2a = tp2.dealias + val tp2a = tp2.dealiasKeepAnnots if (tp2a ne tp2) // Follow the alias; this might avoid truncating the search space in the either below return recur(tp1, tp2a) @@ -661,6 +664,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case _ => } either(recur(tp11, tp2), recur(tp12, tp2)) + case tp1: AnnotatedType if tp1.isSubTypeAnnotated => + isNewSubType(tp1.tpe) case JavaArrayType(elem1) => def compareJavaArray = tp2 match { case JavaArrayType(elem2) => isSubType(elem1, elem2) @@ -685,13 +690,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { */ def isMatchingApply(tp1: Type): Boolean = tp1 match { case AppliedType(tycon1, args1) => - tycon1.dealias match { + tycon1.dealiasKeepSubTypeAnnots match { case tycon1: TypeParamRef => (tycon1 == tycon2 || canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) && isSubArgs(args1, args2, tp1, tparams) case tycon1: TypeRef => - tycon2.dealias match { + tycon2.dealiasKeepSubTypeAnnots match { case tycon2: TypeRef if tycon1.symbol == tycon2.symbol => isSubType(tycon1.prefix, tycon2.prefix) && isSubArgs(args1, args2, tp1, tparams) @@ -700,7 +705,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } case tycon1: TypeVar => isMatchingApply(tycon1.underlying) - case tycon1: AnnotatedType => + case tycon1: AnnotatedType if !tycon1.isSubTypeAnnotated => isMatchingApply(tycon1.underlying) case _ => false @@ -811,7 +816,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { fourthTry } } - case _: TypeVar | _: AnnotatedType => + case _: TypeVar => + recur(tp1, tp2.superType) + case tycon2: AnnotatedType if !tycon2.isSubTypeAnnotated => recur(tp1, tp2.superType) case tycon2: AppliedType => fallback(tycon2.lowerBound) @@ -1097,11 +1104,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { * is some combination of TypeRefs that point to classes, where the * combiners are AppliedTypes, RefinedTypes, RecTypes, And/Or-Types or AnnotatedTypes. */ - private def isCovered(tp: Type): Boolean = tp.dealias.stripTypeVar match { + private def isCovered(tp: Type): Boolean = tp.dealiasKeepSubTypeAnnots.stripTypeVar match { case tp: TypeRef => tp.symbol.isClass && tp.symbol != NothingClass && tp.symbol != NullClass case tp: AppliedType => isCovered(tp.tycon) case tp: RefinedOrRecType => isCovered(tp.parent) - case tp: AnnotatedType => isCovered(tp.underlying) case tp: AndType => isCovered(tp.tp1) && isCovered(tp.tp2) case tp: OrType => isCovered(tp.tp1) && isCovered(tp.tp2) case _ => false @@ -1546,7 +1552,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } case tp1: TypeVar if tp1.isInstantiated => tp1.underlying & tp2 - case tp1: AnnotatedType => + case tp1: AnnotatedType if !tp1.isSubTypeAnnotated => tp1.underlying & tp2 case _ => NoType @@ -1565,7 +1571,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { ExprType(rt1 | tp2.widenExpr) case tp1: TypeVar if tp1.isInstantiated => tp1.underlying | tp2 - case tp1: AnnotatedType => + case tp1: AnnotatedType if !tp1.isSubTypeAnnotated => tp1.underlying | tp2 case _ => NoType diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index a4566e729b72..4f1ab25ca595 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -195,7 +195,7 @@ object TypeErasure { * or a universal trait as upper bound and that is not Java defined? Arrays of such types are * erased to `Object` instead of `Object[]`. */ - def isUnboundedGeneric(tp: Type)(implicit ctx: Context): Boolean = tp.dealias match { + def isUnboundedGeneric(tp: Type)(implicit ctx: Context): Boolean = tp.dealiasStripAnnots match { case tp: TypeRef => !tp.symbol.isClass && !tp.derivesFrom(defn.ObjectClass) && @@ -212,7 +212,7 @@ object TypeErasure { } /** Is `tp` an abstract type or polymorphic type parameter, or another unbounded generic type? */ - def isGeneric(tp: Type)(implicit ctx: Context): Boolean = tp.dealias match { + def isGeneric(tp: Type)(implicit ctx: Context): Boolean = tp.dealiasStripAnnots match { case tp: TypeRef => !tp.symbol.isClass case tp: TypeParamRef => true case tp: TypeProxy => isGeneric(tp.underlying) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 3e85582bef81..a66271aba3de 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -171,7 +171,7 @@ object Types { case this1: RefinedOrRecType => this1.parent.isRef(sym) case this1: AppliedType => - val this2 = this1.dealias + val this2 = this1.dealiasStripAnnots if (this2 ne this1) this2.isRef(sym) else this1.underlying.isRef(sym) case _ => false @@ -244,7 +244,7 @@ object Types { } /** Is this type a (possibly aliased) singleton type? */ - def isSingleton(implicit ctx: Context) = dealias.isInstanceOf[SingletonType] + def isSingleton(implicit ctx: Context) = dealiasStripAnnots.isInstanceOf[SingletonType] /** Is this type of kind `AnyKind`? */ def hasAnyKind(implicit ctx: Context): Boolean = { @@ -283,6 +283,15 @@ object Types { case _ => false } + /** Does this type have a supertype with an annotation satisfying given predicate `p`? */ + def derivesAnnotWith(p: Annotation => Boolean)(implicit ctx: Context): Boolean = this match { + case tp: AnnotatedType => p(tp.annot) || tp.tpe.derivesAnnotWith(p) + case tp: TypeProxy => tp.superType.derivesAnnotWith(p) + case AndType(l, r) => l.derivesAnnotWith(p) || r.derivesAnnotWith(p) + case OrType(l, r) => l.derivesAnnotWith(p) && r.derivesAnnotWith(p) + case _ => false + } + /** Does this type occur as a part of type `that`? */ final def occursIn(that: Type)(implicit ctx: Context): Boolean = that existsPart (this == _) @@ -922,6 +931,11 @@ object Types { */ def stripAnnots(implicit ctx: Context): Type = this + def rewrapAnnots(tp: Type)(implicit ctx: Context): Type = tp.stripTypeVar match { + case AnnotatedType(tp1, annot) => AnnotatedType(rewrapAnnots(tp1), annot) + case _ => this + } + /** Strip PolyType prefix */ def stripPoly(implicit ctx: Context): Type = this match { case tp: PolyType => tp.resType.stripPoly @@ -1008,48 +1022,55 @@ object Types { this } - private def dealias1(keepAnnots: Boolean)(implicit ctx: Context): Type = this match { + private def dealias1(keep: AnnotatedType => Context => Boolean)(implicit ctx: Context): Type = this match { case tp: TypeRef => if (tp.symbol.isClass) tp else tp.info match { - case TypeAlias(alias) => alias.dealias1(keepAnnots): @tailrec + case TypeAlias(alias) => alias.dealias1(keep): @tailrec case _ => tp } case app @ AppliedType(tycon, args) => - val tycon1 = tycon.dealias1(keepAnnots) - if (tycon1 ne tycon) app.superType.dealias1(keepAnnots): @tailrec + val tycon1 = tycon.dealias1(keep) + if (tycon1 ne tycon) app.superType.dealias1(keep): @tailrec else this case tp: TypeVar => val tp1 = tp.instanceOpt - if (tp1.exists) tp1.dealias1(keepAnnots): @tailrec else tp + if (tp1.exists) tp1.dealias1(keep): @tailrec else tp case tp: AnnotatedType => - val tp1 = tp.tpe.dealias1(keepAnnots) - if (keepAnnots) tp.derivedAnnotatedType(tp1, tp.annot) else tp1 + val tp1 = tp.tpe.dealias1(keep) + if (keep(tp)(ctx)) tp.derivedAnnotatedType(tp1, tp.annot) else tp1 case tp: LazyRef => - tp.ref.dealias1(keepAnnots): @tailrec + tp.ref.dealias1(keep): @tailrec case _ => this } + /** Follow aliases and dereferences LazyRefs, annotated types and instantiated + * TypeVars until type is no longer alias type, annotated type, LazyRef, + * or instantiated type variable. + */ + final def dealiasStripAnnots(implicit ctx: Context): Type = dealias1(keepNever) + /** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type * is no longer alias type, LazyRef, or instantiated type variable. * Goes through annotated types and rewraps annotations on the result. */ - final def dealiasKeepAnnots(implicit ctx: Context): Type = - dealias1(keepAnnots = true) + final def dealiasKeepAnnots(implicit ctx: Context): Type = dealias1(keepAlways) - /** Follow aliases and dereferences LazyRefs, annotated types and instantiated - * TypeVars until type is no longer alias type, annotated type, LazyRef, - * or instantiated type variable. - */ - final def dealias(implicit ctx: Context): Type = - dealias1(keepAnnots = false) + final def dealiasKeepSubTypeAnnots(implicit ctx: Context): Type = dealias1(keepIfSubTypeAnnotated) + + final def dealias(implicit ctx: Context): Type = dealiasStripAnnots /** Perform successive widenings and dealiasings until none can be applied anymore */ - @tailrec final def widenDealias(implicit ctx: Context): Type = { - val res = this.widen.dealias - if (res eq this) res else res.widenDealias + private def widenDealias1(keep: AnnotatedType => Context => Boolean)(implicit ctx: Context): Type = { + val res = this.widen.dealias1(keep) + if (res eq this) res else res.widenDealias1(keep) } + final def widenDealiasStripAnnots(implicit ctx: Context): Type = widenDealias1(keepNever) + final def widenDealiasKeepAnnots(implicit ctx: Context): Type = widenDealias1(keepAlways) + final def widenDealiasKeepSubTyoeAnnots(implicit ctx: Context): Type = widenDealias1(keepIfSubTypeAnnotated) + final def widenDealias(implicit ctx: Context): Type = widenDealiasStripAnnots + /** Widen from constant type to its underlying non-constant * base type. */ @@ -1059,7 +1080,7 @@ object Types { } /** Dealias, and if result is a dependent function type, drop the `apply` refinement. */ - final def dropDependentRefinement(implicit ctx: Context): Type = dealias match { + final def dropDependentRefinement(implicit ctx: Context): Type = dealiasStripAnnots match { case RefinedType(parent, nme.apply, _) => parent case tp => tp } @@ -1074,7 +1095,7 @@ object Types { * a class, the class type ref, otherwise NoType. * @param refinementOK If `true` we also skip refinements. */ - def underlyingClassRef(refinementOK: Boolean)(implicit ctx: Context): Type = dealias match { + def underlyingClassRef(refinementOK: Boolean)(implicit ctx: Context): Type = dealiasStripAnnots match { case tp: TypeRef => if (tp.symbol.isClass) tp else if (tp.symbol.isAliasType) tp.underlying.underlyingClassRef(refinementOK) @@ -1796,8 +1817,8 @@ object Types { case arg: TypeBounds => val v = param.paramVariance val pbounds = param.paramInfo - if (v > 0 && pbounds.loBound.dealias.isBottomType) TypeAlias(arg.hiBound & rebase(pbounds.hiBound)) - else if (v < 0 && pbounds.hiBound.dealias.isTopType) TypeAlias(arg.loBound | rebase(pbounds.loBound)) + if (v > 0 && pbounds.loBound.dealiasKeepAnnots.isBottomType) TypeAlias(arg.hiBound & rebase(pbounds.hiBound)) + else if (v < 0 && pbounds.hiBound.dealiasKeepAnnots.isTopType) TypeAlias(arg.loBound | rebase(pbounds.loBound)) else arg recoverable_& rebase(pbounds) case arg => TypeAlias(arg) } @@ -3693,6 +3714,17 @@ object Types { override def stripAnnots(implicit ctx: Context): Type = tpe.stripAnnots + private[this] var isSubTypeAnnotatedKnown = false + private[this] var isSubTypeAnnotatedCache: Boolean = _ + + def isSubTypeAnnotated(implicit ctx: Context) = { + if (!isSubTypeAnnotatedKnown) { + isSubTypeAnnotatedCache = annot.symbol.derivesFrom(defn.SubTypeAnnotationClass) + isSubTypeAnnotatedKnown = true + } + isSubTypeAnnotatedCache + } + override def iso(that: Any, bs: BinderPairs): Boolean = that match { case that: AnnotatedType => tpe.equals(that.tpe, bs) && (annot `eq` that.annot) case _ => false @@ -4145,11 +4177,12 @@ object Types { */ def tryWiden(tp: NamedType, pre: Type): Type = pre.member(tp.name) match { case d: SingleDenotation => - d.info.dealias match { + val tp1 = d.info.dealiasKeepAnnots + tp1.stripAnnots match { case TypeAlias(alias) => // if H#T = U, then for any x in L..H, x.T =:= U, // hence we can replace with U under all variances - reapply(alias) + reapply(alias.rewrapAnnots(tp1)) case TypeBounds(lo, hi) => // If H#T = _ >: S <: U, then for any x in L..H, S <: x.T <: U, // hence we can replace with S..U under all variances @@ -4575,7 +4608,7 @@ object Types { case _ => false } - // ----- Decorator implicits -------------------------------------------- + // ----- Helpers and Decorator implicits -------------------------------------- implicit def decorateTypeApplications(tpe: Type): TypeApplications = new TypeApplications(tpe) @@ -4588,4 +4621,9 @@ object Types { else tps2.nonEmpty && tps1.head.equals(tps2.head, bs) && tps1.tail.equalElements(tps2.tail, bs) } } + + private val keepAlways: AnnotatedType => Context => Boolean = _ => _ => true + private val keepNever: AnnotatedType => Context => Boolean = _ => _ => false + private val keepIfSubTypeAnnotated: AnnotatedType => Context => Boolean = + tp => ctx => tp.isSubTypeAnnotated(ctx) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 751304b31c4c..1d659828abfe 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -179,7 +179,8 @@ Standard-Section: "ASTs" TopLevelStat* ERASED LAZY OVERRIDE - INLINE // inline method + INLINE + TRANSPARENT MACRO // inline method containing toplevel splices STATIC // mapped to static Java member OBJECT // an object or its class @@ -280,25 +281,26 @@ object TastyFormat { final val LAZY = 14 final val OVERRIDE = 15 final val INLINE = 16 - final val STATIC = 17 - final val OBJECT = 18 - final val TRAIT = 19 - final val ENUM = 20 - final val LOCAL = 21 - final val SYNTHETIC = 22 - final val ARTIFACT = 23 - final val MUTABLE = 24 - final val LABEL = 25 - final val FIELDaccessor = 26 - final val CASEaccessor = 27 - final val COVARIANT = 28 - final val CONTRAVARIANT = 29 - final val SCALA2X = 30 - final val DEFAULTparameterized = 31 - final val STABLE = 32 - final val MACRO = 33 - final val ERASED = 34 - final val PARAMsetter = 35 + final val TRANSPARENT = 17 + final val STATIC = 18 + final val OBJECT = 19 + final val TRAIT = 20 + final val ENUM = 21 + final val LOCAL = 22 + final val SYNTHETIC = 23 + final val ARTIFACT = 24 + final val MUTABLE = 25 + final val LABEL = 26 + final val FIELDaccessor = 27 + final val CASEaccessor = 28 + final val COVARIANT = 29 + final val CONTRAVARIANT = 30 + final val SCALA2X = 31 + final val DEFAULTparameterized = 32 + final val STABLE = 33 + final val MACRO = 34 + final val ERASED = 35 + final val PARAMsetter = 36 // Cat. 2: tag Nat @@ -446,6 +448,7 @@ object TastyFormat { | LAZY | OVERRIDE | INLINE + | TRANSPARENT | MACRO | STATIC | OBJECT @@ -502,6 +505,7 @@ object TastyFormat { case LAZY => "LAZY" case OVERRIDE => "OVERRIDE" case INLINE => "INLINE" + case TRANSPARENT => "TRANSPARENT" case MACRO => "MACRO" case STATIC => "STATIC" case OBJECT => "OBJECT" diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 32816fcbc98f..df0ebfd89b01 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -589,6 +589,7 @@ class TreePickler(pickler: TastyPickler) { if (flags is Case) writeByte(CASE) if (flags is Override) writeByte(OVERRIDE) if (flags is Inline) writeByte(INLINE) + if (flags is Transparent) writeByte(TRANSPARENT) if (flags is Macro) writeByte(MACRO) if (flags is JavaStatic) writeByte(STATIC) if (flags is Module) writeByte(OBJECT) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index c77006510a06..aa65be12298f 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -513,7 +513,7 @@ class TreeUnpickler(reader: TastyReader, val rhsStart = currentAddr val rhsIsEmpty = nothingButMods(end) if (!rhsIsEmpty) skipTree() - val (givenFlags, annots, privateWithin) = readModifiers(end) + val (givenFlags, annotFns, privateWithin) = readModifiers(end) pickling.println(i"creating symbol $name at $start with flags $givenFlags") val flags = normalizeFlags(tag, givenFlags, name, isAbsType, rhsIsEmpty) def adjustIfModule(completer: LazyType) = @@ -532,13 +532,12 @@ class TreeUnpickler(reader: TastyReader, rootd.symbol case _ => val completer = adjustIfModule(new Completer(ctx.owner, subReader(start, end))) - if (isClass) ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord) else ctx.newSymbol(ctx.owner, name, flags, completer, privateWithin, coord) } - sym.annotations = annots + sym.annotations = annotFns.map(_(sym)) ctx.owner match { case cls: ClassSymbol => cls.enter(sym) case _ => @@ -548,7 +547,7 @@ class TreeUnpickler(reader: TastyReader, sym.completer.withDecls(newScope) forkAt(templateStart).indexTemplateParams()(localContext(sym)) } - else if (sym.isInlineMethod) + else if (sym.isInlineableMethod) sym.addAnnotation(LazyBodyAnnotation { ctx0 => implicit val ctx: Context = localContext(sym)(ctx0).addMode(Mode.ReadPositions) // avoids space leaks by not capturing the current context @@ -561,9 +560,9 @@ class TreeUnpickler(reader: TastyReader, /** Read modifier list into triplet of flags, annotations and a privateWithin * boundary symbol. */ - def readModifiers(end: Addr)(implicit ctx: Context): (FlagSet, List[Annotation], Symbol) = { + def readModifiers(end: Addr)(implicit ctx: Context): (FlagSet, List[Symbol => Annotation], Symbol) = { var flags: FlagSet = EmptyFlags - var annots: List[Annotation] = Nil + var annotFns: List[Symbol => Annotation] = Nil var privateWithin: Symbol = NoSymbol while (currentAddr.index != end.index) { def addFlag(flag: FlagSet) = { @@ -588,6 +587,7 @@ class TreeUnpickler(reader: TastyReader, case LAZY => addFlag(Lazy) case OVERRIDE => addFlag(Override) case INLINE => addFlag(Inline) + case TRANSPARENT => addFlag(Transparent) case MACRO => addFlag(Macro) case STATIC => addFlag(JavaStatic) case OBJECT => addFlag(Module) @@ -614,23 +614,25 @@ class TreeUnpickler(reader: TastyReader, addFlag(Protected) privateWithin = readType().typeSymbol case ANNOTATION => - annots = readAnnot(ctx) :: annots + annotFns = readAnnot(ctx) :: annotFns case tag => assert(false, s"illegal modifier tag $tag at $currentAddr, end = $end") } } - (flags, annots.reverse, privateWithin) + (flags, annotFns.reverse, privateWithin) } - private val readAnnot: Context => Annotation = { + private val readAnnot: Context => Symbol => Annotation = { implicit ctx => readByte() val end = readEnd() val tp = readType() - val lazyAnnotTree = readLater(end, rdr => ctx => rdr.readTerm()(ctx)) - Annotation.deferredSymAndTree( - implicit ctx => tp.typeSymbol, - implicit ctx => lazyAnnotTree.complete) + val lazyAnnotTree = readLaterWithOwner(end, rdr => ctx => rdr.readTerm()(ctx)) + + owner => + Annotation.deferredSymAndTree( + implicit ctx => tp.typeSymbol, + implicit ctx => lazyAnnotTree(owner).complete) } /** Create symbols for the definitions in the statement sequence between @@ -840,7 +842,7 @@ class TreeUnpickler(reader: TastyReader, case _ => readTpt()(parentCtx) } } - val parentTypes = parents.map(_.tpe.dealias) + val parentTypes = parents.map(_.tpe.dealiasStripAnnots) val self = if (nextByte == SELFDEF) { readByte() @@ -1153,10 +1155,13 @@ class TreeUnpickler(reader: TastyReader, setPos(start, CaseDef(pat, guard, rhs)) } - def readLater[T <: AnyRef](end: Addr, op: TreeReader => Context => T)(implicit ctx: Context): Trees.Lazy[T] = { + def readLater[T <: AnyRef](end: Addr, op: TreeReader => Context => T)(implicit ctx: Context): Trees.Lazy[T] = + readLaterWithOwner(end, op)(ctx)(ctx.owner) + + def readLaterWithOwner[T <: AnyRef](end: Addr, op: TreeReader => Context => T)(implicit ctx: Context): Symbol => Trees.Lazy[T] = { val localReader = fork goto(end) - new LazyReader(localReader, ctx.owner, ctx.mode, op) + owner => new LazyReader(localReader, owner, ctx.mode, op) } def readHole(end: Addr, isType: Boolean)(implicit ctx: Context): Tree = { diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index f7dbda218e0e..ec54d9672ef0 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -109,7 +109,7 @@ object Scala2Unpickler { denot.info = tempInfo // first rough info to avoid CyclicReferences val normalizedParents = if (parents.isEmpty) defn.ObjectType :: Nil - else parents.map(_.dealias) + else parents.map(_.dealiasStripAnnots) for (tparam <- tparams) { val tsym = decls.lookup(tparam.name) if (tsym.exists) tsym.setFlag(TypeParam) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 0024a285a025..9ffa8cf9c52e 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1675,16 +1675,17 @@ object Parsers { /* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */ private def modOfToken(tok: Int): Mod = tok match { - case ABSTRACT => Mod.Abstract() - case FINAL => Mod.Final() - case IMPLICIT => Mod.Implicit() - case ERASED => Mod.Erased() - case INLINE => Mod.Inline() - case LAZY => Mod.Lazy() - case OVERRIDE => Mod.Override() - case PRIVATE => Mod.Private() - case PROTECTED => Mod.Protected() - case SEALED => Mod.Sealed() + case ABSTRACT => Mod.Abstract() + case FINAL => Mod.Final() + case IMPLICIT => Mod.Implicit() + case ERASED => Mod.Erased() + case INLINE => Mod.Inline() + case TRANSPARENT => Mod.Transparent() + case LAZY => Mod.Lazy() + case OVERRIDE => Mod.Override() + case PRIVATE => Mod.Private() + case PROTECTED => Mod.Protected() + case SEALED => Mod.Sealed() } /** Drop `private' modifier when followed by a qualifier. diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 0cc0cc16fcea..17b3e055f418 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -176,8 +176,9 @@ object Tokens extends TokensCommon { final val THEN = 60; enter(THEN, "then") final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate final val INLINE = 62; enter(INLINE, "inline") - final val ENUM = 63; enter(ENUM, "enum") - final val ERASED = 64; enter(ERASED, "erased") + final val TRANSPARENT = 63; enter(TRANSPARENT, "transparent") + final val ENUM = 64; enter(ENUM, "enum") + final val ERASED = 65; enter(ERASED, "erased") /** special symbols */ final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line") @@ -226,7 +227,7 @@ object Tokens extends TokensCommon { final val defIntroTokens = templateIntroTokens | dclIntroTokens final val localModifierTokens = BitSet( - ABSTRACT, FINAL, SEALED, IMPLICIT, INLINE, LAZY, ERASED) + ABSTRACT, FINAL, SEALED, IMPLICIT, INLINE, TRANSPARENT, LAZY, ERASED) final val accessModifierTokens = BitSet( PRIVATE, PROTECTED) diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index f3153592a73c..e26222bf7a01 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -59,7 +59,7 @@ class PlainPrinter(_ctx: Context) extends Printer { case tp: LazyRef => homogenize(tp.ref) case AppliedType(tycon, args) => - tycon.dealias.appliedTo(args) + tycon.dealiasStripAnnots.appliedTo(args) case _ => tp } diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index d9c5aa83f582..f1cf87ad9c1f 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -612,7 +612,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } private def toTextOwner(tree: Tree[_]) = - "[owner = " ~ tree.symbol.owner.show ~ "]" provided ctx.settings.YprintDebugOwners.value + "[owner = " ~ tree.symbol.maybeOwner.show ~ "]" provided ctx.settings.YprintDebugOwners.value protected def dclTextOr[T >: Untyped](tree: Tree[T])(treeText: => Text) = toTextOwner(tree) ~ { diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 5fde8885f0d0..b8123e6d039b 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1575,7 +1575,7 @@ object messages { private val varNote = if (sym.is(Mutable)) "Note that variables need to be initialized to be defined." else "" - val msg = hl"""only classes can have declared but undefined members""" + val msg = hl"""declaration of $sym not allowed here: only classes can have declared but undefined members""" val kind = "Syntax" val explanation = s"$varNote" } diff --git a/compiler/src/dotty/tools/dotc/transform/CollectNullableFields.scala b/compiler/src/dotty/tools/dotc/transform/CollectNullableFields.scala index 201ae4e21def..f7a507556a1e 100644 --- a/compiler/src/dotty/tools/dotc/transform/CollectNullableFields.scala +++ b/compiler/src/dotty/tools/dotc/transform/CollectNullableFields.scala @@ -67,7 +67,7 @@ class CollectNullableFields extends MiniPhase { !sym.is(Lazy) && !sym.owner.is(Trait) && sym.initial.is(PrivateLocal) && - sym.info.widenDealias.typeSymbol.isNullableClass + sym.info.widenDealiasStripAnnots.typeSymbol.isNullableClass if (isNullablePrivateField) nullability.get(sym) match { diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index d401ce5aa3c4..a6bbffe9c321 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -421,7 +421,7 @@ object Erasure { def recur(qual: Tree): Tree = { val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType val symIsPrimitive = sym.owner.isPrimitiveValueClass - if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType) + if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealiasStripAnnots.isErasedValueType) recur(box(qual)) else if (!qualIsPrimitive && symIsPrimitive) recur(unbox(qual, sym.owner.typeRef)) diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 201609078802..bebfb3c2f9f5 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -127,7 +127,7 @@ class ExpandSAMs extends MiniPhase { } } - private def checkRefinements(tpe: Type, pos: Position)(implicit ctx: Context): Type = tpe.dealias match { + private def checkRefinements(tpe: Type, pos: Position)(implicit ctx: Context): Type = tpe.dealiasStripAnnots match { case RefinedType(parent, name, _) => if (name.isTermName && tpe.member(name).symbol.ownersIterator.isEmpty) // if member defined in the refinement ctx.error("Lambda does not define " + name, pos) diff --git a/compiler/src/dotty/tools/dotc/transform/FunctionXXLForwarders.scala b/compiler/src/dotty/tools/dotc/transform/FunctionXXLForwarders.scala index feacc647f917..164a3e3b6787 100644 --- a/compiler/src/dotty/tools/dotc/transform/FunctionXXLForwarders.scala +++ b/compiler/src/dotty/tools/dotc/transform/FunctionXXLForwarders.scala @@ -32,7 +32,7 @@ class FunctionXXLForwarders extends MiniPhase with IdentityDenotTransformer { def forwarderRhs(receiver: Tree, xsTree: Tree): Tree = { val argsApply = ref(xsTree.symbol).select(nme.apply) var idx = -1 - val argss = receiver.tpe.widenDealias.paramInfoss.map(_.map { param => + val argss = receiver.tpe.widenDealiasStripAnnots.paramInfoss.map(_.map { param => idx += 1 argsApply.appliedToArgs(List(Literal(Constant(idx)))).asInstance(param) }) diff --git a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala index 276e45a9eac8..b71d6e0fcf3a 100644 --- a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala +++ b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala @@ -60,7 +60,7 @@ object GenericSignatures { ps.foreach(boxedSig) } - def boxedSig(tp: Type): Unit = jsig(tp.widenDealias, primitiveOK = false) + def boxedSig(tp: Type): Unit = jsig(tp.widenDealiasStripAnnots, primitiveOK = false) def boundsSig(bounds: List[Type]): Unit = { val (isTrait, isClass) = bounds partition (_.typeSymbol.is(Trait)) @@ -125,7 +125,7 @@ object GenericSignatures { @noinline def jsig(tp0: Type, toplevel: Boolean = false, primitiveOK: Boolean = true): Unit = { - val tp = tp0.dealias + val tp = tp0.dealiasStripAnnots tp match { case ref @ TypeParamRef(_: PolyType, _) => @@ -363,7 +363,7 @@ object GenericSignatures { leaves.toList } - private def hiBounds(bounds: TypeBounds)(implicit ctx: Context): List[Type] = bounds.hi.widenDealias match { + private def hiBounds(bounds: TypeBounds)(implicit ctx: Context): List[Type] = bounds.hi.widenDealiasStripAnnots match { case AndType(tp1, tp2) => hiBounds(tp1.bounds) ::: hiBounds(tp2.bounds) case tp => tp :: Nil } @@ -427,7 +427,7 @@ object GenericSignatures { /** Is `tp` an unbounded generic type (i.e. which could be instantiated * with primitive as well as class types)?. */ - private def genericCore(tp: Type)(implicit ctx: Context): Type = tp.widenDealias match { + private def genericCore(tp: Type)(implicit ctx: Context): Type = tp.widenDealiasStripAnnots match { /* A Java Array is erased to Array[Object] (T can only be a reference type), where as a Scala Array[T] is * erased to Object. However, there is only symbol for the Array class. So to make the distinction between * a Java and a Scala array, we check if the owner of T comes from a Java class. @@ -452,7 +452,7 @@ object GenericSignatures { * then Some((N, T)) where N is the number of Array constructors enclosing `T`, * otherwise None. Existentials on any level are ignored. */ - def unapply(tp: Type)(implicit ctx: Context): Option[(Type, Int)] = tp.widenDealias match { + def unapply(tp: Type)(implicit ctx: Context): Option[(Type, Int)] = tp.widenDealiasStripAnnots match { case defn.ArrayOf(arg) => genericCore(arg) match { case NoType => diff --git a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfChecker.scala b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfChecker.scala index f2d10f3fc677..5831641e2b8b 100644 --- a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfChecker.scala @@ -64,7 +64,7 @@ object Checkable { * 8. otherwise, TRUE */ def checkable(X: Type, P: Type, pos: Position)(implicit ctx: Context): Boolean = { - def isAbstract(P: Type) = !P.dealias.typeSymbol.isClass + def isAbstract(P: Type) = !P.dealiasStripAnnots.typeSymbol.isClass def isPatternTypeSymbol(sym: Symbol) = !sym.isClass && sym.is(Case) def replaceP(tp: Type)(implicit ctx: Context) = new TypeMap { diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala index aee354a077c7..bd3d83e86e0b 100644 --- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala +++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala @@ -130,7 +130,7 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase => var rhs = tree.rhs.changeOwnerAfter(sym, field, thisPhase) if (isWildcardArg(rhs)) rhs = EmptyTree val fieldDef = transformFollowing(ValDef(field, adaptToField(rhs))) - val rhsClass = tree.tpt.tpe.widenDealias.classSymbol + val rhsClass = tree.tpt.tpe.widenDealiasStripAnnots.classSymbol val getterRhs = if (isErasableBottomField(rhsClass)) erasedBottomTree(rhsClass) else transformFollowingDeep(ref(field))(ctx.withOwner(sym)) diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index ebaca5b626b1..c98108da991c 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -788,7 +788,7 @@ object PatternMatcher { def outerTestNeeded: Boolean = { // See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest` // generates an outer test based on `patType.prefix` with automatically dealises. - expectedTp.dealias match { + expectedTp.dealiasStripAnnots match { case tref @ TypeRef(pre: SingletonType, _) => tref.symbol.isClass && ExplicitOuter.needsOuterIfReferenced(tref.symbol.asClass) @@ -799,7 +799,7 @@ object PatternMatcher { def outerTest: Tree = thisPhase.transformFollowingDeep { val expectedOuter = singleton(expectedTp.normalizedPrefix) - val expectedClass = expectedTp.dealias.classSymbol.asClass + val expectedClass = expectedTp.dealiasStripAnnots.classSymbol.asClass ExplicitOuter.ensureOuterAccessors(expectedClass) scrutinee.ensureConforms(expectedTp) .outerSelect(1, expectedClass.owner.typeRef) @@ -807,7 +807,7 @@ object PatternMatcher { .appliedTo(expectedOuter) } - expectedTp.dealias match { + expectedTp.dealiasStripAnnots match { case expectedTp: SingletonType => scrutinee.isInstance(expectedTp) // will be translated to an equality test case _ => diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index e7266b48a7aa..918d85afeca6 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -165,7 +165,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase def markAsMacro(c: Context): Unit = if (c.owner eq c.outer.owner) markAsMacro(c.outer) - else if (c.owner.isInlineMethod) c.owner.setFlag(Macro) + else if (c.owner.isInlineableMethod) c.owner.setFlag(Macro) else if (!c.outer.owner.is(Package)) markAsMacro(c.outer) if (sym.isSplice || sym.isQuote) { @@ -192,10 +192,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase } else transformSelect(tree, Nil) - case tree: Super => - if (ctx.owner.enclosingMethod.isInlineMethod) - ctx.error(SuperCallsNotAllowedInline(ctx.owner), tree.pos) - super.transform(tree) case tree: Apply => methPart(tree) match { case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) => diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index f8cbbb033391..1d51a446c60c 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -213,7 +213,7 @@ class TailRec extends MiniPhase with FullParameterization { val argumentss = arguments.map(noTailTransforms) val isRecursiveCall = (method eq sym) - val recvWiden = prefix.tpe.widenDealias + val recvWiden = prefix.tpe.widenDealiasStripAnnots def continue = { val method = noTailTransform(call) diff --git a/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala b/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala index c0825c7e8bea..e729c60d2157 100644 --- a/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala +++ b/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala @@ -38,7 +38,7 @@ abstract class TransformByNameApply extends MiniPhase { thisPhase: DenotTransfor override def transformApply(tree: Apply)(implicit ctx: Context): Tree = trace(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) { - def transformArg(arg: Tree, formal: Type): Tree = formal.dealias match { + def transformArg(arg: Tree, formal: Type): Tree = formal.dealiasStripAnnots match { case formalExpr: ExprType => var argType = arg.tpe.widenIfUnstable if (defn.isBottomType(argType)) argType = formal.widenExpr diff --git a/compiler/src/dotty/tools/dotc/transform/TreeExtractors.scala b/compiler/src/dotty/tools/dotc/transform/TreeExtractors.scala index 7a5c5df9db98..d506f590b10f 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeExtractors.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeExtractors.scala @@ -36,7 +36,7 @@ object TreeExtractors { object ValueClassUnbox { def unapply(t: Tree)(implicit ctx: Context): Option[Tree] = t match { case Apply(sel @ Select(ref, _), Nil) => - val d = ref.tpe.widenDealias.typeSymbol.denot + val d = ref.tpe.widenDealiasStripAnnots.typeSymbol.denot if (isDerivedValueClass(d) && (sel.symbol eq valueClassUnbox(d.asClass))) { Some(ref) } else diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index c40cc7b213f2..58a8f4eae70a 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -132,7 +132,7 @@ object TypeTestsCasts { * The transform happens before erasure of `testType`, thus cannot be merged * with `transformIsInstanceOf`, which depends on erased type of `testType`. */ - def transformTypeTest(expr: Tree, testType: Type, flagUnrelated: Boolean): Tree = testType.dealias match { + def transformTypeTest(expr: Tree, testType: Type, flagUnrelated: Boolean): Tree = testType.dealiasStripAnnots match { case _: SingletonType => expr.isInstance(testType).withPos(tree.pos) case OrType(tp1, tp2) => diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/Devalify.scala b/compiler/src/dotty/tools/dotc/transform/localopt/Devalify.scala index 419c94765b76..599f9cf76273 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/Devalify.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/Devalify.scala @@ -193,7 +193,7 @@ class Devalify extends Optimisation { case t @ Select(qual, _) if !isEffectivelyMutable(t) => readingOnlyVals(qual) - case t: Ident if !t.symbol.is(Mutable | Method) && !t.symbol.info.dealias.isInstanceOf[ExprType] => + case t: Ident if !t.symbol.is(Mutable | Method) && !t.symbol.info.dealiasStripAnnots.isInstanceOf[ExprType] => desugarIdent(t) match { case s: Select => readingOnlyVals(s); case _ => true } case t: This => true diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala b/compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala index cdb4d3e74066..ec52b8d7b799 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala @@ -48,7 +48,7 @@ class InlineCaseIntrinsics(val simplifyPhase: Simplify) extends Optimisation { case _ => fun } val constructor = a.symbol.owner.companionClass.primaryConstructor.asTerm - evalreceiver(a, rollInArgs(argss.tail, New(a.tpe.widenDealias.simplified, constructor, argss.head))) + evalreceiver(a, rollInArgs(argss.tail, New(a.tpe.widenDealiasStripAnnots.simplified, constructor, argss.head))) // For synthetic dotty unapplies on case classes: // - CC.unapply(arg): CC → arg @@ -80,7 +80,7 @@ class InlineCaseIntrinsics(val simplifyPhase: Simplify) extends Optimisation { // CC.unapply(arg): Option[CC] → new Some(new scala.TupleN(arg._1, ..., arg._N)) // The output is defined as a Tree => Tree to go thought tpd.evalOnce. def some(e: Tree) = { - val accessors = e.tpe.widenDealias.classSymbol.caseAccessors.filter(_.is(Method)) + val accessors = e.tpe.widenDealiasStripAnnots.classSymbol.caseAccessors.filter(_.is(Method)) val fields = accessors.map(x => e.select(x).ensureApplied) val tplType = noBounds(a.tpe.baseType(defn.OptionClass).argInfos.head) val someTpe = a.tpe.translateParameterized(defn.OptionClass, defn.SomeClass) @@ -110,8 +110,8 @@ class InlineCaseIntrinsics(val simplifyPhase: Simplify) extends Optimisation { case t: TypeApply => receiver(t.fun) case t: Ident => val prefix = desugarIdentPrefix(t) - prefix.tpe.widenDealias - case t: Select => t.qualifier.tpe.widenDealias + prefix.tpe.widenDealiasStripAnnots + case t: Select => t.qualifier.tpe.widenDealiasStripAnnots } val recv = receiver(a) diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/InlineLocalObjects.scala b/compiler/src/dotty/tools/dotc/transform/localopt/InlineLocalObjects.scala index 8134764fd3cf..406c9e98caf2 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/InlineLocalObjects.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/InlineLocalObjects.scala @@ -55,7 +55,7 @@ class InlineLocalObjects(val simplifyPhase: Simplify) extends Optimisation { val owner: Symbol = refVal.owner val name: Name = LocalOptInlineLocalObj.fresh() val flags: FlagSet = Synthetic - val info: Type = x.asSeenFrom(refVal.info).info.finalResultType.widenDealias + val info: Type = x.asSeenFrom(refVal.info).info.finalResultType.widenDealiasStripAnnots ctx.newSymbol(owner, name, flags, info) } (refVal, LinkedHashMap[Symbol, Symbol](accessors.zip(newLocals): _*)) @@ -72,7 +72,7 @@ class InlineLocalObjects(val simplifyPhase: Simplify) extends Optimisation { !t.symbol.is(Lazy | Mutable) && // is lhs a val? !t.symbol.info.classSymbol.caseAccessors.exists(_.is(Mutable)) && // is the case class immutable? fun.symbol.isConstructor && // is rhs a new? - t.tpe.widenDealias == t.symbol.info.finalResultType.widenDealias => // no case class inheritance or enums + t.tpe.widenDealiasStripAnnots == t.symbol.info.finalResultType.widenDealiasStripAnnots => // no case class inheritance or enums Some((fun, args)) case _ => None } diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/Varify.scala b/compiler/src/dotty/tools/dotc/transform/localopt/Varify.scala index a97e117ae9fb..387d537e3473 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/Varify.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/Varify.scala @@ -43,7 +43,7 @@ import scala.collection.mutable case t: ValDef if t.symbol.is(Mutable) => t.rhs.foreachSubTree { subtree => if (paramsTimesUsed.contains(subtree.symbol) && - t.symbol.info.widenDealias <:< subtree.symbol.info.widenDealias) { + t.symbol.info.widenDealiasStripAnnots <:< subtree.symbol.info.widenDealiasStripAnnots) { val newSet = possibleRenames.getOrElse(t.symbol, Set.empty) + subtree.symbol possibleRenames.update(t.symbol, newSet) } diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index a3cfefb12d07..073660be8497 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -445,7 +445,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { debug.println(s"candidates for ${tp.show} : [${children.map(_.show).mkString(", ")}]") - tp.dealias match { + tp.dealiasStripAnnots match { case AndType(tp1, tp2) => intersect(Typ(tp1, false), Typ(tp2, false)) match { case Or(spaces) => spaces @@ -520,7 +520,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { } else { debug.println(s"$child instantiated ------> $resTp") - resTp.dealias + resTp.dealiasStripAnnots } } @@ -563,17 +563,17 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { tp } - def isSingleton(tp: Type): Boolean = tp.dealias match { + def isSingleton(tp: Type): Boolean = tp.dealiasStripAnnots match { case AndType(l, r) => isSingleton(l) || isSingleton(r) case OrType(l, r) => isSingleton(l) && isSingleton(r) case tp => tp.isSingleton } - def recur(tp: Type): Boolean = tp.dealias match { + def recur(tp: Type): Boolean = tp.dealiasStripAnnots match { case AndType(tp1, tp2) => recur(tp1) && recur(tp2) && { - val bases1 = tp1.widenDealias.classSymbols - val bases2 = tp2.widenDealias.classSymbols + val bases1 = tp1.widenDealiasStripAnnots.classSymbols + val bases2 = tp2.widenDealiasStripAnnots.classSymbols debug.println(s"bases of ${tp1.show}: " + bases1) debug.println(s"bases of ${tp2.show}: " + bases2) @@ -718,7 +718,7 @@ class SpaceEngine(implicit ctx: 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 dealiasedTp = tp.dealiasStripAnnots val res = (tp.classSymbol.is(Sealed) && tp.classSymbol.is(AbstractOrTrait) && @@ -865,7 +865,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { // Possible to check everything, but be compatible with scalac by default def isCheckable(tp: Type): Boolean = !tp.hasAnnotation(defn.UncheckedAnnot) && { - val tpw = tp.widen.dealias + val tpw = tp.widen.dealiasStripAnnots ctx.settings.YcheckAllPatmat.value || tpw.typeSymbol.is(Sealed) || tpw.isInstanceOf[OrType] || @@ -895,7 +895,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { def checkExhaustivity(_match: Match): Unit = { val Match(sel, cases) = _match - val selTyp = sel.tpe.widen.dealias + val selTyp = sel.tpe.widen.dealiasStripAnnots if (!exhaustivityCheckable(sel)) return @@ -921,7 +921,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { def checkRedundancy(_match: Match): Unit = { val Match(sel, cases) = _match - val selTyp = sel.tpe.widen.dealias + val selTyp = sel.tpe.widen.dealiasStripAnnots if (!redundancyCheckable(sel)) return diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 7776d198f38b..11ed46942e08 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -46,7 +46,7 @@ object Applications { val ref = extractorMember(tp, name) if (ref.isOverloaded) errorType(i"Overloaded reference to $ref is not allowed in extractor", errorPos) - ref.info.widenExpr.annotatedToRepeated.dealias + ref.info.widenExpr.annotatedToRepeated.dealiasKeepAnnots } /** Does `tp` fit the "product match" conditions as an unapply result type diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index fdfa66031f50..2cc45bedff87 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -404,6 +404,8 @@ object Checking { checkCombination(Private, Protected) checkCombination(Abstract, Override) checkCombination(Lazy, Inline) + checkCombination(Module, Inline) + checkCombination(Transparent, Inline) checkNoConflict(Lazy, ParamAccessor, s"parameter may not be `lazy`") if (sym.is(Inline)) checkApplicable(Inline, sym.isTerm && !sym.is(Mutable | Module)) if (sym.is(Lazy)) checkApplicable(Lazy, !sym.is(Method | Mutable)) @@ -483,9 +485,10 @@ object Checking { prefix = apply(tp.prefix), classParents = tp.parents.map { p => - apply(p).stripAnnots match { - case ref: TypeRef => ref - case ref: AppliedType => ref + val p1 = apply(p) + p1.stripAnnots match { + case ref: TypeRef => p1 + case ref: AppliedType => p1 case _ => defn.ObjectType // can happen if class files are missing } } @@ -682,7 +685,8 @@ trait Checking { case tp => tp.widenTermRefExpr match { case tp: ConstantType if exprPurity(tree) >= purityLevel => // ok case _ => - if (!ctx.erasedTypes) ctx.error(em"$what must be a constant expression", tree.pos) + val allow = ctx.erasedTypes || ctx.owner.ownersIterator.exists(_.isInlineableMethod) + if (!allow) ctx.error(em"$what must be a constant expression", tree.pos) } } } diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 6f39e041322d..31fd2d2026e5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -763,7 +763,7 @@ trait Implicits { self: Typer => tree match { case Select(qual, nme.apply) if defn.isFunctionType(qual.tpe.widen) => val qt = qual.tpe.widen - val qt1 = qt.dealias + val qt1 = qt.dealiasKeepAnnots def addendum = if (qt1 eq qt) "" else (i"\nwhich is an alias of: $qt1") em"parameter of ${qual.tpe.widen}$addendum" case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 9b6c128d023b..e711bf263cae 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -98,7 +98,7 @@ object Inferencing { inst } private[this] var toMaximize: Boolean = false - def apply(x: Boolean, tp: Type): Boolean = tp.dealias match { + def apply(x: Boolean, tp: Type): Boolean = tp.dealiasStripAnnots match { case _: WildcardType | _: ProtoType => false case tvar: TypeVar diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 3db32b4a08f3..a678ac20701c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -53,23 +53,13 @@ object Inliner { // This is quite tricky, as such types can appear anywhere, including as parts // of types of other things. For the moment we do nothing and complain // at the implicit expansion site if there's a reference to an inaccessible type. - override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match { - case tree: Assign => - transform(tree.lhs) match { - case lhs1: RefTree => - lhs1.name match { - case InlineAccessorName(name) => - cpy.Apply(tree)(useSetter(lhs1), transform(tree.rhs) :: Nil) - case _ => - super.transform(tree) - } - case _ => - super.transform(tree) - } - case _ => - super.transform(accessorIfNeeded(tree)) - } - + override def transform(tree: Tree)(implicit ctx: Context): Tree = + super.transform(accessorIfNeeded(tree)) match { + case tree1 @ Assign(lhs: RefTree, rhs) if lhs.symbol.name.is(InlineAccessorName) => + cpy.Apply(tree1)(useSetter(lhs), rhs :: Nil) + case tree1 => + tree1 + } } /** Adds accessors for all non-public term members accessed @@ -90,6 +80,11 @@ object Inliner { } } + def isLocal(sym: Symbol, inlineMethod: Symbol)(implicit ctx: Context) = + sym.isContainedIn(inlineMethod) && + sym != inlineMethod && + (!sym.is(Param) || sym.owner != inlineMethod) + /** Register inline info for given inline method `sym`. * * @param sym The symbol denotatioon of the inline method for which info is registered @@ -99,14 +94,14 @@ object Inliner { * to have the inlined method as owner. */ def registerInlineInfo( - sym: SymDenotation, treeExpr: Context => Tree)(implicit ctx: Context): Unit = { - sym.unforcedAnnotation(defn.BodyAnnot) match { + inlined: Symbol, treeExpr: Context => Tree)(implicit ctx: Context): Unit = { + inlined.unforcedAnnotation(defn.BodyAnnot) match { case Some(ann: ConcreteBodyAnnotation) => case Some(ann: LazyBodyAnnotation) if ann.isEvaluated => case _ => if (!ctx.isAfterTyper) { val inlineCtx = ctx - sym.updateAnnotation(LazyBodyAnnotation { _ => + inlined.updateAnnotation(LazyBodyAnnotation { _ => implicit val ctx = inlineCtx val body = treeExpr(ctx) if (ctx.reporter.hasErrors) body else ctx.compilationUnit.inlineAccessors.makeInlineable(body) @@ -119,7 +114,7 @@ object Inliner { * from Scala2x class files might be `@inline`, but still lack that body. */ def hasBodyToInline(sym: SymDenotation)(implicit ctx: Context): Boolean = - sym.isInlineMethod && sym.hasAnnotation(defn.BodyAnnot) + sym.isInlinedMethod && sym.hasAnnotation(defn.BodyAnnot) // TODO: Open this up for transparent methods as well /** The body to inline for method `sym`. * @pre hasBodyToInline(sym) @@ -168,10 +163,10 @@ object Inliner { /** Produces an inlined version of `call` via its `inlined` method. * - * @param call The original call to a `@inline` method - * @param rhs The body of the inline method that replaces the call. + * @param call the original call to a `@inline` method + * @param rhsToInline the body of the inline method that replaces the call. */ -class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { +class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { import tpd._ import Inliner._ @@ -195,7 +190,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { */ private val paramProxy = new mutable.HashMap[Type, Type] - /** A map from the classes of (direct and outer) this references in `rhs` + /** A map from the classes of (direct and outer) this references in `rhsToInline` * to references of their proxies. * Note that we can't index by the ThisType itself since there are several * possible forms to express what is logicaly the same ThisType. E.g. @@ -229,8 +224,8 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { */ private def paramBindingDef(name: Name, paramtp: Type, arg: Tree, bindingsBuf: mutable.ListBuffer[ValOrDefDef]): ValOrDefDef = { - val argtpe = arg.tpe.dealias - val isByName = paramtp.dealias.isInstanceOf[ExprType] + val argtpe = arg.tpe.dealiasKeepAnnots + val isByName = paramtp.dealiasStripAnnots.isInstanceOf[ExprType] val inlineFlag = if (paramtp.hasAnnotation(defn.InlineParamAnnot)) Inline else EmptyFlags val (bindingFlags, bindingType) = if (isByName) (Method, ExprType(argtpe.widen)) @@ -255,7 +250,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { computeParamBindings(tp.resultType, Nil, argss) case tp: MethodType => (tp.paramNames, tp.paramInfos, argss.head).zipped.foreach { (name, paramtp, arg) => - paramBinding(name) = arg.tpe.dealias match { + paramBinding(name) = arg.tpe.dealiasStripAnnots match { case _: SingletonType if isIdempotentExpr(arg) => arg.tpe case _ => paramBindingDef(name, paramtp, arg, bindingsBuf).symbol.termRef } @@ -310,7 +305,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { if (!isIdempotentExpr(prefix)) registerType(meth.owner.thisType) // Register types of all leaves of inlined body so that the `paramProxy` and `thisProxy` maps are defined. - rhs.foreachSubTree(registerLeaf) + rhsToInline.foreachSubTree(registerLeaf) // The class that the this-proxy `selfSym` represents def classOf(selfSym: Symbol) = selfSym.info.widen.classSymbol @@ -328,7 +323,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { var lastSelf: Symbol = NoSymbol var lastLevel: Int = 0 for ((level, selfSym) <- sortedProxies) { - lazy val rhsClsSym = selfSym.info.widenDealias.classSymbol + lazy val rhsClsSym = selfSym.info.widenDealiasStripAnnots.classSymbol val rhs = if (lastSelf.exists) ref(lastSelf).outerSelect(lastLevel - level, selfSym.info) @@ -382,7 +377,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { // the owner from the inlined method to the current owner. val inliner = new TreeTypeMap(typeMap, treeMap, meth :: Nil, ctx.owner :: Nil)(inlineCtx) - val expansion = inliner(rhs.withPos(call.pos)) + val expansion = inliner(rhsToInline.withPos(call.pos)) trace(i"inlining $call\n, BINDINGS =\n${bindingsBuf.toList}%\n%\nEXPANSION =\n$expansion", inlining, show = true) { // The final expansion runs a typing pass over the inlined tree. See InlineTyper for details. @@ -421,7 +416,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { /** A typer for inlined code. Its purpose is: * 1. Implement constant folding over inlined code * 2. Selectively expand ifs with constant conditions - * 3. Inline arguments that are inlineable closures + * 3. Inline arguments that are by-name closures * 4. Make sure inlined code is type-correct. * 5. Make sure that the tree's typing is idempotent (so that future -Ycheck passes succeed) */ @@ -485,7 +480,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { case mt: MethodType if ddef.vparamss.head.length == args.length => val bindingsBuf = new mutable.ListBuffer[ValOrDefDef] val argSyms = (mt.paramNames, mt.paramInfos, args).zipped.map { (name, paramtp, arg) => - arg.tpe.dealias match { + arg.tpe.dealiasStripAnnots match { case ref @ TermRef(NoPrefix, _) => ref.symbol case _ => paramBindingDef(name, paramtp, arg, bindingsBuf).symbol } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 592006e2b57f..d6220794cb03 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -821,12 +821,12 @@ class Namer { typer: Typer => else completeInCreationContext(denot) } - private def addInlineInfo(denot: SymDenotation) = original match { - case original: untpd.DefDef if denot.isInlineMethod => + private def addInlineInfo(sym: Symbol) = original match { + case original: untpd.DefDef if sym.isInlineableMethod => Inliner.registerInlineInfo( - denot, + sym, implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs - )(localContext(denot.symbol)) + )(localContext(sym)) case _ => } @@ -839,7 +839,7 @@ class Namer { typer: Typer => case original: MemberDef => addAnnotations(sym, original) case _ => } - addInlineInfo(denot) + addInlineInfo(sym) denot.info = typeSig(sym) Checking.checkWellFormed(sym) denot.info = avoidPrivateLeaks(sym, sym.pos) @@ -929,7 +929,7 @@ class Namer { typer: Typer => * (4) If the class is sealed, it is defined in the same compilation unit as the current class */ def checkedParentType(parent: untpd.Tree): Type = { - val ptype = parentType(parent)(ctx.superCallContext).dealias + val ptype = parentType(parent)(ctx.superCallContext).dealiasStripAnnots if (cls.isRefinementClass) ptype else { val pt = checkClassType(ptype, parent.pos, @@ -1113,7 +1113,7 @@ class Namer { typer: Typer => // println(s"final inherited for $sym: ${inherited.toString}") !!! // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") - def isInline = sym.is(FinalOrInline, butNot = Method | Mutable) + def isInline = sym.is(FinalOrInlineOrTransparent, butNot = Method | Mutable) // Widen rhs type and eliminate `|' but keep ConstantTypes if // definition is inline (i.e. final in Scala2) and keep module singleton types diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 5a32fcf19364..d49813a34628 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -45,7 +45,7 @@ object ProtoTypes { isCompatible(normTp, pt) || pt.isRef(defn.UnitClass) && normTp.isParameterless } - private def disregardProto(pt: Type)(implicit ctx: Context): Boolean = pt.dealias match { + private def disregardProto(pt: Type)(implicit ctx: Context): Boolean = pt.dealiasKeepSubTypeAnnots match { case _: OrType => true case pt => pt.isRef(defn.UnitClass) } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 9bb608be7736..5744ea03db7f 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -93,7 +93,7 @@ trait TypeAssigner { def apply(tp: Type): Type = tp match { case tp: TermRef if toAvoid(tp.symbol) || partsToAvoid(mutable.Set.empty, tp.info).nonEmpty => - tp.info.widenExpr.dealias match { + tp.info.widenExpr.dealiasStripAnnots match { case info: SingletonType => apply(info) case info => range(defn.NothingType, apply(info)) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f05e7c61818c..331fe5fd829a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -476,6 +476,9 @@ class Typer extends Namer case pt: SelectionProto if pt.name == nme.CONSTRUCTOR => true case _ => false } + val enclosingInlineable = ctx.owner.ownersIterator.findSymbol(_.isInlineableMethod) + if (enclosingInlineable.exists && !Inliner.isLocal(qual1.symbol, enclosingInlineable)) + ctx.error(SuperCallsNotAllowedInline(enclosingInlineable), tree.pos) pt match { case pt: SelectionProto if pt.name.isTypeName => qual1 // don't do super references for types; they are meaningless anyway @@ -509,7 +512,7 @@ class Typer extends Namer case _ => var tpt1 = typedType(tree.tpt) tpt1 = tpt1.withType(ensureAccessible(tpt1.tpe, superAccess = false, tpt1.pos)) - tpt1.tpe.dealias match { + tpt1.tpe.dealiasStripAnnots match { case TypeApplications.EtaExpansion(tycon) => tpt1 = tpt1.withType(tycon) case _ => } @@ -578,7 +581,7 @@ class Typer extends Namer * exists, rewrite to `ctag(e)`. * @pre We are in pattern-matching mode (Mode.Pattern) */ - def tryWithClassTag(tree: Typed, pt: Type)(implicit ctx: Context) = tree.tpt.tpe.dealias match { + def tryWithClassTag(tree: Typed, pt: Type)(implicit ctx: Context) = tree.tpt.tpe.dealiasKeepSubTypeAnnots match { case tref: TypeRef if !tref.symbol.isClass && !ctx.isAfterTyper => require(ctx.mode.is(Mode.Pattern)) inferImplicit(defn.ClassTagType.appliedTo(tref), @@ -732,7 +735,7 @@ class Typer extends Namer // if expected parameter type(s) are wildcards, approximate from below. // if expected result type is a wildcard, approximate from above. // this can type the greatest set of admissible closures. - val funType = pt.dealias + val funType = pt.dealiasStripAnnots (funType.argTypesLo.init, typeTree(funType.argTypesHi.last)) case SAMType(sam @ MethodTpe(_, formals, restpe)) => (formals, @@ -1068,7 +1071,7 @@ class Typer extends Namer (EmptyTree, WildcardType) } else if (owner != cx.outer.owner && owner.isRealMethod) { - if (owner.isInlineMethod) + if (owner.isInlineableMethod) (EmptyTree, errorType(NoReturnFromInline(owner), tree.pos)) else if (!owner.isCompleted) (EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.pos)) @@ -1428,7 +1431,7 @@ class Typer extends Namer val rhs1 = normalizeErasedRhs(typedExpr(ddef.rhs, tpt1.tpe)(rhsCtx), sym) // Overwrite inline body to make sure it is not evaluated twice - if (sym.isInlineMethod) Inliner.registerInlineInfo(sym, _ => rhs1) + if (sym.isInlineableMethod) Inliner.registerInlineInfo(sym, _ => rhs1) if (sym.isConstructor && !sym.isPrimaryConstructor) for (param <- tparams1 ::: vparamss1.flatten) @@ -2343,7 +2346,7 @@ class Typer extends Namer if (pt.hasAnnotation(defn.InlineParamAnnot)) checkInlineConformant(tree, isFinal = false, "argument to inline parameter") if (Inliner.hasBodyToInline(tree.symbol) && - !ctx.owner.ownersIterator.exists(_.isInlineMethod) && + !ctx.owner.ownersIterator.exists(_.isInlineableMethod) && !ctx.settings.YnoInline.value && !ctx.isAfterTyper && !ctx.reporter.hasErrors) @@ -2524,7 +2527,7 @@ class Typer extends Namer if (pt.isInstanceOf[PolyProto]) tree else { var typeArgs = tree match { - case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo.map(TypeTree) + case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealiasStripAnnots.argTypesLo.map(TypeTree) case _ => Nil } if (typeArgs.isEmpty) typeArgs = constrained(poly, tree)._2 diff --git a/compiler/src/dotty/tools/dotc/util/common.scala b/compiler/src/dotty/tools/dotc/util/common.scala index d9798aec5ebe..7b81416a7f74 100644 --- a/compiler/src/dotty/tools/dotc/util/common.scala +++ b/compiler/src/dotty/tools/dotc/util/common.scala @@ -8,6 +8,7 @@ import core.Types.WildcardType object common { val alwaysTrue = Function.const(true) _ + val alwaysFalse = Function.const(false) _ val alwaysZero = Function.const(0) _ val alwaysWildcardType = Function.const(WildcardType) _ diff --git a/library/src/scala/annotation/SubTypeAnnotation.scala b/library/src/scala/annotation/SubTypeAnnotation.scala new file mode 100644 index 000000000000..b5aa9e6eae74 --- /dev/null +++ b/library/src/scala/annotation/SubTypeAnnotation.scala @@ -0,0 +1,3 @@ +package scala.annotation + +trait SubTypeAnnotation extends StaticAnnotation diff --git a/tests/neg/i2421.scala b/tests/neg/i2421.scala index c09da6a8a3f2..759145119e7b 100644 --- a/tests/neg/i2421.scala +++ b/tests/neg/i2421.scala @@ -1,4 +1,4 @@ -inline object Foo // error: modifier(s) `inline' incompatible with type definition +inline object Foo // OK (error would be detected later, in PostTyper) inline class Bar // error: modifier(s) `inline' incompatible with type definition inline abstract class Baz // error: modifier(s) `inline' incompatible with type definition inline trait Qux // error: modifier(s) `inline' incompatible with type definition diff --git a/tests/pos/immutableAnnot.scala b/tests/pos/immutableAnnot.scala new file mode 100644 index 000000000000..557ab1995069 --- /dev/null +++ b/tests/pos/immutableAnnot.scala @@ -0,0 +1,26 @@ +import scala.annotation._ +class Immutable extends Annotation with SubTypeAnnotation + +object Test extends App { + + def assertImmutable[T](n: T): T @ Immutable = ??? + + def g[S](x: S, y: S) = if (???) x else y + + def f(n: Int @ Immutable): Int @ Immutable = + if n == 0 then assertImmutable(0) + else { + val n1 = f(f(n)) + val x = g(n1, n1) + val y = g(n1, assertImmutable(3)) + val z = g(x, y) + val r = + if (???) x + else if (???) y + else if (???) z + else assertImmutable(n1 - 1) + val s = g(assertImmutable(List(1, 2, 3)), assertImmutable("a")) + val scheck: java.io.Serializable = s + r + } +} \ No newline at end of file diff --git a/tests/run/inline-implicits.check b/tests/run/inline-implicits.check new file mode 100644 index 000000000000..17a1d370d730 --- /dev/null +++ b/tests/run/inline-implicits.check @@ -0,0 +1 @@ +(X(),Y()) diff --git a/tests/run/inline-implicits.scala b/tests/run/inline-implicits.scala new file mode 100644 index 000000000000..6d46a61d28e4 --- /dev/null +++ b/tests/run/inline-implicits.scala @@ -0,0 +1,26 @@ +case class X() +case class Y() + +object impl { + implicit val y: Y = new Y() +} + +object inlines { + import impl._ + + class C { + implicit val x: X = new X() + + inline + def f(): (X, Y) = + (implicitly[X], implicitly[Y]) + } +} + +object Test { + def main(args: Array[String]) = { + val c = new inlines.C + val xy = c.f() + println(xy) + } +} diff --git a/tests/run/typelevel.check b/tests/run/typelevel.check new file mode 100644 index 000000000000..e85e836bb30b --- /dev/null +++ b/tests/run/typelevel.check @@ -0,0 +1,3 @@ +ToNat(Z) +ToNat(S(Z)) +ToNat(S(S(Z))) diff --git a/tests/run/typelevel.scala b/tests/run/typelevel.scala new file mode 100644 index 000000000000..9a836565ef51 --- /dev/null +++ b/tests/run/typelevel.scala @@ -0,0 +1,31 @@ +object Test extends App { + + trait Nat + + case object Z extends Nat + type Z = Z.type + case class S[N <: Nat](n: Nat) extends Nat + + abstract class HasResult[T] { type Result = T } + case class ToNat[+T](val value: T) extends HasResult[T] + + transparent def ToNat(inline n: Int): ToNat[Nat] = + if n == 0 then new ToNat(Z) + else { + val n1 = ToNat(n - 1) + new ToNat[S[n1.Result]](S(n1.value)) + } + + val x0 = ToNat(0) + //val y0: Z = x0.value + //val z0: x0.Result = y0 + val x1 = ToNat(1) + //val y1: S[Z] = x1.value + //val z1: x1.Result = y1 + val x2 = ToNat(2) + //val y2: S[S[Z]] = x2.value + //val z2: x2.Result = y2 + println(x0) + println(x1) + println(x2) +} \ No newline at end of file