diff options
37 files changed, 703 insertions, 497 deletions
diff --git a/docs/syntax-summary.txt b/docs/syntax-summary.txt index 0a52ec802..04e149de6 100644 --- a/docs/syntax-summary.txt +++ b/docs/syntax-summary.txt @@ -160,7 +160,7 @@ grammar. SimpleExpr1 ::= Literal | Path | `_' - | `(' ExprsInParens `)' Parens(exprs) + | `(' ExprsInParens2 `)' Parens(exprs) | SimpleExpr `.' id Select(expr, id) | SimpleExpr (TypeArgs | NamedTypeArgs) TypeApply(expr, args) | SimpleExpr1 ArgumentExprs Apply(expr, args) @@ -210,7 +210,7 @@ grammar. | SimplePattern1 `.' id PatVar ::= varid | `_' - Patterns ::= Pattern [`,' Pattern] + Patterns ::= Pattern {`,' Pattern} ArgumentPatterns ::= `(' [Patterns] `)' Apply(fn, pats) | `(' [Patterns `,'] Pattern2 `:' `_' `*' ') diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 03c4315fe..a7c449947 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -973,7 +973,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } object This extends ThisDeconstructor { - def get = field.qual + def get = field.qual.name def apply(s: Symbol): This = tpd.This(s.asClass) } @@ -1020,7 +1020,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } object Super extends SuperDeconstructor { def _1: Tree = field.qual - def _2: Name = field.mix + def _2: Name = field.mix.name } object ArrayValue extends ArrayValueDeconstructor { def _1: Type = field.tpe match { diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index d568e3d31..366a0e225 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -234,7 +234,7 @@ object desugar { if (tdef.mods is PrivateLocalParam) { val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner)) .withMods(tdef.mods &~ PrivateLocal | ExpandedName) - val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam), tparams = Nil) + val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam)) .withMods(tdef.mods & VarianceFlags | PrivateLocalParamAccessor | Synthetic) Thicket(tparam, alias) } @@ -341,7 +341,7 @@ object desugar { val isDefinedMeth = syntheticProperty(nme.isDefined, Literal(Constant(true))) val caseParams = constrVparamss.head.toArray val productElemMeths = for (i <- 0 until arity) yield - syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeName), caseParams(i).name)) + syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeIdent), caseParams(i).name)) def isRepeated(tree: Tree): Boolean = tree match { case PostfixOp(_, nme.raw.STAR) => true case ByNameTypeTree(tree1) => isRepeated(tree1) @@ -463,8 +463,7 @@ object desugar { cpy.TypeDef(cdef)( name = className, rhs = cpy.Template(impl)(constr, parents1, self1, - tparamAccessors ::: vparamAccessors ::: normalizedBody ::: caseClassMeths), - tparams = Nil) + tparamAccessors ::: vparamAccessors ::: normalizedBody ::: caseClassMeths)) } // install the watch on classTycon diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 8b2915174..d1e6bd38a 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -272,7 +272,12 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] case mdef: ValOrDefDef => mdef.unforcedRhs == EmptyTree && !mdef.name.isConstructorName && !mdef.mods.is(ParamAccessor) case mdef: TypeDef => - mdef.rhs.isEmpty || mdef.rhs.isInstanceOf[TypeBoundsTree] + def isBounds(rhs: Tree): Boolean = rhs match { + case _: TypeBoundsTree => true + case PolyTypeTree(_, body) => isBounds(body) + case _ => false + } + mdef.rhs.isEmpty || isBounds(mdef.rhs) case _ => false } @@ -382,9 +387,9 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => def isIdempotentRef(tree: Tree)(implicit ctx: Context) = refPurity(tree) >= Idempotent - /** If `tree` is a constant expression, its value as a Literal, + /** If `tree` is a constant expression, its value as a Literal, * or `tree` itself otherwise. - * + * * Note: Demanding idempotency instead of purity in literalize is strictly speaking too loose. * Example * @@ -410,11 +415,11 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => * * Revisit this issue once we have implemented `inline`. Then we can demand * purity of the prefix unless the selection goes to an inline val. - * + * * Note: This method should be applied to all term tree nodes that are not literals, * that can be idempotent, and that can have constant types. So far, only nodes - * of the following classes qualify: - * + * of the following classes qualify: + * * Ident * Select * TypeApply diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 9108a4d22..2801bcae2 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -60,18 +60,18 @@ object Trees { with Cloneable { if (Stats.enabled) ntrees += 1 - + private def nxId = { nextId += 1 //assert(nextId != 199, this) - nextId + nextId } /** A unique identifier for this tree. Used for debugging, and potentially * tracking presentation compiler interactions */ private var myUniqueId: Int = nxId - + def uniqueId = myUniqueId /** The type constructor at the root of the tree */ @@ -159,7 +159,7 @@ object Trees { /** Does this tree define a new symbol that is not defined elsewhere? */ def isDef: Boolean = false - /** Is this tree either the empty tree or the empty ValDef? */ + /** Is this tree either the empty tree or the empty ValDef or an empty type ident? */ def isEmpty: Boolean = false /** Convert tree to a list. Gives a singleton list, except @@ -192,7 +192,7 @@ object Trees { override def hashCode(): Int = uniqueId // for debugging; was: System.identityHashCode(this) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] - + override def clone: Tree[T] = { val tree = super.clone.asInstanceOf[Tree[T]] tree.myUniqueId = nxId @@ -353,7 +353,7 @@ object Trees { } /** qual.this */ - case class This[-T >: Untyped] private[ast] (qual: TypeName) + case class This[-T >: Untyped] private[ast] (qual: untpd.Ident) extends DenotingTree[T] with TermTree[T] { type ThisTree[-T >: Untyped] = This[T] // Denotation of a This tree is always the underlying class; needs correction for modules. @@ -368,7 +368,7 @@ object Trees { } /** C.super[mix], where qual = C.this */ - case class Super[-T >: Untyped] private[ast] (qual: Tree[T], mix: TypeName) + case class Super[-T >: Untyped] private[ast] (qual: Tree[T], mix: untpd.Ident) extends ProxyTree[T] with TermTree[T] { type ThisTree[-T >: Untyped] = Super[T] def forwardTo = qual @@ -653,12 +653,6 @@ object Trees { /** Is this a definition of a class? */ def isClassDef = rhs.isInstanceOf[Template[_]] - - /** If this a non-class type definition, its type parameters. - * Can be different from Nil only for PolyTypeDefs, which are always - * untyped and get eliminated during desugaring. - */ - def tparams: List[untpd.TypeDef] = Nil } /** extends parents { self => body } */ @@ -896,12 +890,12 @@ object Trees { case tree: Select if (qualifier eq tree.qualifier) && (name == tree.name) => tree case _ => finalize(tree, untpd.Select(qualifier, name)) } - def This(tree: Tree)(qual: TypeName): This = tree match { - case tree: This if qual == tree.qual => tree + def This(tree: Tree)(qual: untpd.Ident): This = tree match { + case tree: This if qual eq tree.qual => tree case _ => finalize(tree, untpd.This(qual)) } - def Super(tree: Tree)(qual: Tree, mix: TypeName): Super = tree match { - case tree: Super if (qual eq tree.qual) && (mix == tree.mix) => tree + def Super(tree: Tree)(qual: Tree, mix: untpd.Ident): Super = tree match { + case tree: Super if (qual eq tree.qual) && (mix eq tree.mix) => tree case _ => finalize(tree, untpd.Super(qual, mix)) } def Apply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): Apply = tree match { @@ -1023,9 +1017,9 @@ object Trees { case tree: DefDef if (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree case _ => finalize(tree, untpd.DefDef(name, tparams, vparamss, tpt, rhs)) } - def TypeDef(tree: Tree)(name: TypeName, rhs: Tree, tparams: List[untpd.TypeDef]): TypeDef = tree match { - case tree: TypeDef if (name == tree.name) && (rhs eq tree.rhs) && (tparams eq tree.tparams) => tree - case _ => finalize(tree, untpd.TypeDef(name, tparams, rhs)) + def TypeDef(tree: Tree)(name: TypeName, rhs: Tree): TypeDef = tree match { + case tree: TypeDef if (name == tree.name) && (rhs eq tree.rhs) => tree + case _ => finalize(tree, untpd.TypeDef(name, rhs)) } def Template(tree: Tree)(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList): Template = tree match { case tree: Template if (constr eq tree.constr) && (parents eq tree.parents) && (self eq tree.self) && (body eq tree.unforcedBody) => tree @@ -1064,8 +1058,8 @@ object Trees { ValDef(tree: Tree)(name, tpt, rhs) def DefDef(tree: DefDef)(name: TermName = tree.name, tparams: List[TypeDef] = tree.tparams, vparamss: List[List[ValDef]] = tree.vparamss, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs): DefDef = DefDef(tree: Tree)(name, tparams, vparamss, tpt, rhs) - def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs, tparams: List[untpd.TypeDef] = tree.tparams): TypeDef = - TypeDef(tree: Tree)(name, rhs, tparams) + def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs): TypeDef = + TypeDef(tree: Tree)(name, rhs) def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody): Template = Template(tree: Tree)(constr, parents, self, body) } @@ -1146,7 +1140,7 @@ object Trees { case tree @ DefDef(name, tparams, vparamss, tpt, _) => cpy.DefDef(tree)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(tree.rhs)) case tree @ TypeDef(name, rhs) => - cpy.TypeDef(tree)(name, transform(rhs), tree.tparams) + cpy.TypeDef(tree)(name, transform(rhs)) case tree @ Template(constr, parents, self, _) => cpy.Template(tree)(transformSub(constr), transform(parents), transformSub(self), transformStats(tree.body)) case Import(expr, selectors) => @@ -1294,7 +1288,6 @@ object Trees { case tree: Bind => cpy.Bind(tree)(newName, tree.body) case tree: ValDef => cpy.ValDef(tree)(name = newName.asTermName) case tree: DefDef => cpy.DefDef(tree)(name = newName.asTermName) - case tree: untpd.PolyTypeDef => untpd.cpy.PolyTypeDef(tree)(newName.asTypeName, tree.tparams, tree.rhs).withMods(tree.rawMods) case tree: TypeDef => cpy.TypeDef(tree)(name = newName.asTypeName) } }.asInstanceOf[tree.ThisTree[T]] diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index fc96735b0..44e1cf188 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -31,11 +31,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { untpd.Select(qualifier, tp.name).withType(tp) def This(cls: ClassSymbol)(implicit ctx: Context): This = - untpd.This(cls.name).withType(cls.thisType) + untpd.This(untpd.Ident(cls.name)).withType(cls.thisType) - def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super = + def Super(qual: Tree, mix: untpd.Ident, inConstrCall: Boolean, mixinClass: Symbol)(implicit ctx: Context): Super = ta.assignType(untpd.Super(qual, mix), qual, inConstrCall, mixinClass) + def Super(qual: Tree, mixName: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super = + Super(qual, if (mixName.isEmpty) untpd.EmptyTypeIdent else untpd.Ident(mixName), inConstrCall, mixinClass) + def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply = ta.assignType(untpd.Apply(fn, args), fn, args) @@ -133,7 +136,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = ta.assignType(untpd.OrTypeTree(left, right), left, right) - // RefinedTypeTree is missing, handled specially in Typer and Unpickler. + def RefinedTypeTree(parent: Tree, refinements: List[Tree], refineCls: ClassSymbol)(implicit ctx: Context): Tree = + ta.assignType(untpd.RefinedTypeTree(parent, refinements), parent, refinements, refineCls) def AppliedTypeTree(tycon: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = ta.assignType(untpd.AppliedTypeTree(tycon, args), tycon, args) @@ -141,6 +145,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def ByNameTypeTree(result: Tree)(implicit ctx: Context): ByNameTypeTree = ta.assignType(untpd.ByNameTypeTree(result), result) + def PolyTypeTree(tparams: List[TypeDef], body: Tree)(implicit ctx: Context): PolyTypeTree = + ta.assignType(untpd.PolyTypeTree(tparams, body), tparams, body) + def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = ta.assignType(untpd.TypeBoundsTree(lo, hi), lo, hi) diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index f259bdc57..6c5210287 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -80,8 +80,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree]) extends TypTree case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) extends DefTree - class PolyTypeDef(name: TypeName, override val tparams: List[TypeDef], rhs: Tree) - extends TypeDef(name, rhs) + @sharable object EmptyTypeIdent extends Ident(tpnme.EMPTY) with WithoutTypeOrPos[Untyped] { + override def isEmpty = true + } /** A block arising from a right-associative infix operation, where, e.g. * @@ -228,8 +229,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def BackquotedIdent(name: Name): BackquotedIdent = new BackquotedIdent(name) def Select(qualifier: Tree, name: Name): Select = new Select(qualifier, name) def SelectWithSig(qualifier: Tree, name: Name, sig: Signature): Select = new SelectWithSig(qualifier, name, sig) - def This(qual: TypeName): This = new This(qual) - def Super(qual: Tree, mix: TypeName): Super = new Super(qual, mix) + def This(qual: Ident): This = new This(qual) + def Super(qual: Tree, mix: Ident): Super = new Super(qual, mix) def Apply(fun: Tree, args: List[Tree]): Apply = new Apply(fun, args) def TypeApply(fun: Tree, args: List[Tree]): TypeApply = new TypeApply(fun, args) def Literal(const: Constant): Literal = new Literal(const) @@ -310,9 +311,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def TypeTree(tpe: Type)(implicit ctx: Context): TypedSplice = TypedSplice(TypeTree().withTypeUnchecked(tpe)) - def TypeDef(name: TypeName, tparams: List[TypeDef], rhs: Tree): TypeDef = - if (tparams.isEmpty) TypeDef(name, rhs) else new PolyTypeDef(name, tparams, rhs) - def unitLiteral = Literal(Constant(())) def ref(tp: NamedType)(implicit ctx: Context): Tree = @@ -348,6 +346,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def makeSyntheticParameter(n: Int = 1, tpt: Tree = TypeTree())(implicit ctx: Context): ValDef = ValDef(nme.syntheticParamName(n), tpt, EmptyTree).withFlags(SyntheticTermParam) + def lambdaAbstract(tparams: List[TypeDef], tpt: Tree)(implicit ctx: Context) = + if (tparams.isEmpty) tpt else PolyTypeTree(tparams, tpt) + /** A reference to given definition. If definition is a repeated * parameter, the reference will be a repeated argument. */ @@ -392,10 +393,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree case _ => untpd.ParsedTry(expr, handler, finalizer).withPos(tree.pos) } - def PolyTypeDef(tree: Tree)(name: TypeName, tparams: List[TypeDef], rhs: Tree) = tree match { - case tree: PolyTypeDef if (name eq tree.name) && (tparams eq tree.tparams) && (rhs eq tree.rhs) => tree - case _ => new PolyTypeDef(name, tparams, rhs).withPos(tree.pos) - } def SymbolLit(tree: Tree)(str: String) = tree match { case tree: SymbolLit if str == tree.str => tree case _ => untpd.SymbolLit(str).withPos(tree.pos) @@ -506,8 +503,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { cpy.ContextBounds(tree)(transformSub(bounds), transform(cxBounds)) case PatDef(mods, pats, tpt, rhs) => cpy.PatDef(tree)(mods, transform(pats), transform(tpt), transform(rhs)) - case tree: PolyTypeDef => - cpy.PolyTypeDef(tree)(tree.name, transformSub(tree.tparams), transform(tree.rhs)) case _ => super.transform(tree) } @@ -553,8 +548,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { this(this(x, bounds), cxBounds) case PatDef(mods, pats, tpt, rhs) => this(this(this(x, pats), tpt), rhs) - case tree: PolyTypeDef => - this(this(x, tree.tparams), tree.rhs) case TypedSplice(tree) => this(x, tree) case _ => @@ -566,10 +559,4 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { class UntypedDeepFolder[X](f: (X, Tree) => X) extends UntypedTreeAccumulator[X] { def apply(x: X, tree: Tree)(implicit ctx: Context): X = foldOver(f(x, tree), tree) } - - override def rename(tree: NameTree, newName: Name)(implicit ctx: Context): tree.ThisTree[Untyped] = tree match { - case t: PolyTypeDef => - cpy.PolyTypeDef(t)(newName.asTypeName, t.tparams, t.rhs).asInstanceOf[tree.ThisTree[Untyped]] - case _ => super.rename(tree, newName) - } } diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 920c9635e..c2a14b36f 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -735,15 +735,11 @@ object StdNames { class ScalaTypeNames extends ScalaNames[TypeName] { protected implicit def fromString(s: String): TypeName = typeName(s) - def syntheticTypeParamName(i: Int): TypeName = "T" + i - def syntheticLambdaParamName(i: Int): TypeName = "X" + i + def syntheticTypeParamName(i: Int): TypeName = "X" + i def syntheticTypeParamNames(num: Int): List[TypeName] = (0 until num).map(syntheticTypeParamName)(breakOut) - def syntheticLambdaParamNames(num: Int): List[TypeName] = - (0 until num).map(syntheticLambdaParamName)(breakOut) - final val Conforms = encode("<:<") final val Uninstantiated: TypeName = "?$" diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 8aaf77032..70819e590 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -340,10 +340,11 @@ class TypeApplications(val self: Type) extends AnyVal { def LambdaAbstract(tparams: List[TypeParamInfo])(implicit ctx: Context): Type = { def expand(tp: Type) = PolyType( - tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.paramVariance))( + tparams.map(_.paramName), tparams.map(_.paramVariance))( tl => tparams.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds), tl => tl.lifted(tparams, tp)) - self match { + if (tparams.isEmpty) self + else self match { case self: TypeAlias => self.derivedTypeAlias(expand(self.alias)) case self @ TypeBounds(lo, hi) => diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 0e1d373a8..f78820fff 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1267,7 +1267,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { original(tp1.appliedTo(tp1.typeParams.map(_.paramBoundsAsSeenFrom(tp1))), tp2) else PolyType( - paramNames = tpnme.syntheticLambdaParamNames(tparams1.length), + paramNames = tpnme.syntheticTypeParamNames(tparams1.length), variances = (tparams1, tparams2).zipped.map((tparam1, tparam2) => (tparam1.paramVariance + tparam2.paramVariance) / 2))( paramBoundsExp = tl => (tparams1, tparams2).zipped.map((tparam1, tparam2) => diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index ae248295c..89bc21929 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2526,7 +2526,7 @@ object Types { case _: MethodType => true case _ => false } - + /** Is this polytype a higher-kinded type lambda as opposed to a polymorphic? * method type? Only type lambdas get created with variances, that's how we can tell. */ @@ -2621,17 +2621,11 @@ object Types { unique(new PolyType(paramNames, vs)(paramBoundsExp, resultTypeExp)) } - def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context): Type = - if (tparams.isEmpty) resultType - else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))( - pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds), - pt => pt.lifted(tparams, resultType)) - def unapply(tl: PolyType): Some[(List[LambdaParam], Type)] = Some((tl.typeParams, tl.resType)) def any(n: Int)(implicit ctx: Context) = - apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))( + apply(tpnme.syntheticTypeParamNames(n), List.fill(n)(0))( pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType) } diff --git a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 1570dbca0..97a82e80d 100644 --- a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -217,7 +217,7 @@ class ClassfileParser( if (isEnum) denot.info = ConstantType(Constant(sym)) if (isConstructor) stripOuterParamFromConstructor() setPrivateWithin(denot, jflags) - denot.info = depoly(parseAttributes(sym, denot.info), denot) + denot.info = translateTempPoly(parseAttributes(sym, denot.info)) if (isConstructor) normalizeConstructorInfo() if ((denot is Flags.Method) && (jflags & JAVA_ACC_VARARGS) != 0) diff --git a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala index 4b67bc188..546894a9e 100644 --- a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala +++ b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala @@ -13,7 +13,7 @@ import collection.mutable import TastyBuffer._ import util.Positions._ -class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr]) { +class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr]) { val buf = new TastyBuffer(5000) pickler.newSection("Positions", buf) import buf._ @@ -21,21 +21,6 @@ class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr] private val remainingAddrs = new java.util.IdentityHashMap[Tree, Iterator[Addr]] - def nextTreeAddr(tree: Tree): Option[Addr] = remainingAddrs.get(tree) match { - case null => - addrsOfTree(tree) match { - case Nil => - None - case addr :: Nil => - Some(addr) - case addrs => - remainingAddrs.put(tree, addrs.iterator) - nextTreeAddr(tree) - } - case it: Iterator[_] => - if (it.hasNext) Some(it.next) else None - } - def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean, hasPoint: Boolean) = { def toInt(b: Boolean) = if (b) 1 else 0 (addrDelta << 3) | (toInt(hasStartDelta) << 2) | (toInt(hasEndDelta) << 1) | toInt(hasPoint) @@ -60,8 +45,7 @@ class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr] */ def alwaysNeedsPos(x: Positioned) = x match { case _: WithLazyField[_] // initialPos is inaccurate for trees with lazy field - | _: Trees.PackageDef[_] => true // package defs might be split into several Tasty files - case x: Trees.Tree[_] => x.isType // types are unpickled as TypeTrees, so child positions are not available + | _: Trees.PackageDef[_] => true // package defs might be split into several Tasty files case _ => false } @@ -69,7 +53,7 @@ class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr] case x: Tree @unchecked => val pos = if (x.isInstanceOf[MemberDef]) x.pos else x.pos.toSynthetic if (pos.exists && (pos != x.initialPos.toSynthetic || alwaysNeedsPos(x))) { - nextTreeAddr(x) match { + addrOfTree(x) match { case Some(addr) => //println(i"pickling $x with $pos at $addr") pickleDeltas(addr.index, pos) @@ -79,13 +63,15 @@ class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr] } //else if (x.pos.exists) println(i"skipping $x") x match { - case x: MemberDef @unchecked => + case x: MemberDef @unchecked => for (ann <- x.symbol.annotations) traverse(ann.tree) case _ => } traverse(x.productIterator) case xs: TraversableOnce[_] => xs.foreach(traverse) + case x: Annotation => + traverse(x.tree) case _ => } traverse(roots) diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index f9743d9d2..cb1b56c3c 100644 --- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -71,10 +71,11 @@ Standard-Section: "ASTs" TopLevelStat* Term = Path Application - IDENT NameRef Type // used when ident’s type is not a TermRef + IDENT NameRef Type // used when term ident’s type is not a TermRef SELECT possiblySigned_NameRef qual_Term + QUALTHIS typeIdent_Tree NEW cls_Type - SUPER Length this_Term mixinTrait_Type? + SUPER Length this_Term mixinTypeIdent_Tree? TYPED Length expr_Term ascription_Type NAMEDARG Length paramName_NameRef arg_Term ASSIGN Length lhs_Term rhs_Term @@ -89,6 +90,17 @@ Standard-Section: "ASTs" TopLevelStat* BIND Length boundName_NameRef patType_Type pat_Term ALTERNATIVE Length alt_Term* UNAPPLY Length fun_Term ImplicitArg* pat_Type pat_Term* + IDENTtpt NameRef Type // used for all type idents + SELECTtpt NameRef qual_Term + SINGLETONtpt Path + REFINEDtpt Length underlying_Term refinement_Stat* + APPLIEDtpt Length tycon_Term arg_Term* + POLYtpt Length TypeParam* body_Term + TYPEBOUNDStpt Length low_Term high_Term + ANNOTATEDtpt Length underlying_Term fullAnnotation_Term + ANDtpt Length left_Term right_Term + ORtpt Length left_Term right_Term + BYNAMEtpt underlying_Term EMPTYTREE SHARED term_ASTRef Application = APPLY Length fn_Term arg_Term* @@ -133,7 +145,7 @@ Standard-Section: "ASTs" TopLevelStat* APPLIEDtype Length tycon_Type arg_Type* TYPEBOUNDS Length low_Type high_Type TYPEALIAS Length alias_Type (COVARIANT | CONTRAVARIANT)? - ANNOTATED Length underlying_Type fullAnnotation_Term + ANNOTATEDtype Length underlying_Type fullAnnotation_Term ANDtype Length left_Type right_Type ORtype Length left_Type right_Type BIND Length boundName_NameRef bounds_Type @@ -268,22 +280,27 @@ object TastyFormat { final val RENAMED = 79 final val THIS = 96 - final val CLASSconst = 97 - final val ENUMconst = 98 - final val BYNAMEtype = 99 - final val NEW = 100 - final val IMPLICITarg = 101 - final val PRIVATEqualified = 102 - final val PROTECTEDqualified = 103 - final val RECtype = 104 + final val QUALTHIS = 97 + final val CLASSconst = 98 + final val ENUMconst = 99 + final val BYNAMEtype = 100 + final val BYNAMEtpt = 101 + final val NEW = 102 + final val IMPLICITarg = 103 + final val PRIVATEqualified = 104 + final val PROTECTEDqualified = 105 + final val RECtype = 106 + final val SINGLETONtpt = 107 final val IDENT = 112 - final val SELECT = 113 - final val TERMREFsymbol = 114 - final val TERMREF = 115 - final val TYPEREFsymbol = 116 - final val TYPEREF = 117 - final val SELFDEF = 118 + final val IDENTtpt = 113 + final val SELECT = 114 + final val SELECTtpt = 115 + final val TERMREFsymbol = 116 + final val TERMREF = 117 + final val TYPEREFsymbol = 118 + final val TYPEREF = 119 + final val SELFDEF = 120 final val PACKAGE = 128 final val VALDEF = 129 @@ -293,39 +310,44 @@ object TastyFormat { final val TYPEPARAM = 133 final val PARAMS = 134 final val PARAM = 136 - - final val APPLY = 139 - final val TYPEAPPLY = 140 - - final val TYPED = 143 - final val NAMEDARG = 144 - final val ASSIGN = 145 - final val BLOCK = 146 - final val IF = 147 - final val LAMBDA = 148 - final val MATCH = 149 - final val RETURN = 150 - final val TRY = 151 - final val INLINED = 152 - final val REPEATED = 153 - final val BIND = 154 - final val ALTERNATIVE = 155 - final val UNAPPLY = 156 - final val ANNOTATED = 157 - final val CASEDEF = 158 - final val TEMPLATE = 160 - final val SUPER = 163 - final val SUPERtype = 166 - final val REFINEDtype = 167 - final val APPLIEDtype = 168 - final val TYPEBOUNDS = 169 - final val TYPEALIAS = 170 - final val ANDtype = 171 - final val ORtype = 172 - final val METHODtype = 174 - final val POLYtype = 175 - final val PARAMtype = 176 - final val ANNOTATION = 177 + final val APPLY = 137 + final val TYPEAPPLY = 138 + final val TYPED = 139 + final val NAMEDARG = 140 + final val ASSIGN = 141 + final val BLOCK = 142 + final val IF = 143 + final val LAMBDA = 144 + final val MATCH = 145 + final val RETURN = 146 + final val TRY = 147 + final val INLINED = 148 + final val REPEATED = 149 + final val BIND = 150 + final val ALTERNATIVE = 151 + final val UNAPPLY = 152 + final val ANNOTATEDtype = 153 + final val ANNOTATEDtpt = 154 + final val CASEDEF = 155 + final val TEMPLATE = 156 + final val SUPER = 157 + final val SUPERtype = 158 + final val REFINEDtype = 159 + final val REFINEDtpt = 160 + final val APPLIEDtype = 161 + final val APPLIEDtpt = 162 + final val TYPEBOUNDS = 163 + final val TYPEBOUNDStpt = 164 + final val TYPEALIAS = 165 + final val ANDtype = 166 + final val ANDtpt = 167 + final val ORtype = 168 + final val ORtpt = 169 + final val METHODtype = 170 + final val POLYtype = 171 + final val POLYtpt = 172 + final val PARAMtype = 173 + final val ANNOTATION = 174 final val firstSimpleTreeTag = UNITconst final val firstNatTreeTag = SHARED @@ -367,7 +389,22 @@ object TastyFormat { | PRIVATEqualified | PROTECTEDqualified => true case _ => false - } + } + + def isTypeTreeTag(tag: Int) = tag match { + case IDENTtpt + | SELECTtpt + | SINGLETONtpt + | REFINEDtpt + | APPLIEDtpt + | POLYtpt + | TYPEBOUNDStpt + | ANNOTATEDtpt + | ANDtpt + | ORtpt + | BYNAMEtpt => true + case _ => false + } def nameTagToString(tag: Int): String = tag match { case UTF8 => "UTF8" @@ -429,7 +466,9 @@ object TastyFormat { case RECtype => "RECtype" case IDENT => "IDENT" + case IDENTtpt => "IDENTtpt" case SELECT => "SELECT" + case SELECTtpt => "SELECTtpt" case TERMREFsymbol => "TERMREFsymbol" case TERMREF => "TERMREF" case TYPEREFsymbol => "TYPEREFsymbol" @@ -462,24 +501,34 @@ object TastyFormat { case BIND => "BIND" case ALTERNATIVE => "ALTERNATIVE" case UNAPPLY => "UNAPPLY" - case ANNOTATED => "ANNOTATED" + case ANNOTATEDtype => "ANNOTATEDtype" + case ANNOTATEDtpt => "ANNOTATEDtpt" case CASEDEF => "CASEDEF" case IMPLICITarg => "IMPLICITarg" case TEMPLATE => "TEMPLATE" case SELFDEF => "SELFDEF" case THIS => "THIS" + case QUALTHIS => "QUALTHIS" case SUPER => "SUPER" case CLASSconst => "CLASSconst" case ENUMconst => "ENUMconst" + case SINGLETONtpt => "SINGLETONtpt" case SUPERtype => "SUPERtype" case REFINEDtype => "REFINEDtype" + case REFINEDtpt => "REFINEDtpt" case APPLIEDtype => "APPLIEDtype" + case APPLIEDtpt => "APPLIEDtpt" case TYPEBOUNDS => "TYPEBOUNDS" + case TYPEBOUNDStpt => "TYPEBOUNDStpt" case TYPEALIAS => "TYPEALIAS" case ANDtype => "ANDtype" + case ANDtpt => "ANDtpt" case ORtype => "ORtype" + case ORtpt => "ORtpt" case BYNAMEtype => "BYNAMEtype" + case BYNAMEtpt => "BYNAMEtpt" case POLYtype => "POLYtype" + case POLYtpt => "POLYtpt" case METHODtype => "METHODtype" case PARAMtype => "PARAMtype" case ANNOTATION => "ANNOTATION" diff --git a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala index f847dda68..c844d522e 100644 --- a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala @@ -54,14 +54,11 @@ class TastyPickler { all.bytes } - /** - * Addresses in TASTY file of trees, stored by pickling. - * Note that trees are checked for reference equality, - * so one can reliably use this function only directly after `pickler`. - * Note that a tree can have several addresses, if it is shared, - * i.e. accessible from different paths. Any such sharing is undone by pickling. + /** The address in the TASTY file of a given tree, or None if unknown. + * Note that trees are looked up by reference equality, + * so one can reliably use this function only directly after `pickler`. */ - var addrsOfTree: tpd.Tree => List[Addr] = (_ => Nil) + var addrOfTree: tpd.Tree => Option[Addr] = (_ => None) /** * Addresses in TASTY file of symbols, stored by pickling. diff --git a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala index f2681ecde..6c7982d78 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala @@ -17,26 +17,17 @@ class TreeBuffer extends TastyBuffer(50000) { private var delta: Array[Int] = _ private var numOffsets = 0 - private type TreeAddrs = Any // really: Addr | List[Addr] + /** A map from trees to the address at which a tree is pickled. */ + private val treeAddrs = new java.util.IdentityHashMap[Tree, Any] // really: Addr | Null - /** A map from trees to the address(es) at which a tree is pickled. There may be several - * such addresses if the tree is shared. To keep the map compact, the value type is a - * disjunction of a single address (which is the common case) and a list of addresses. - */ - private val treeAddrs = new java.util.IdentityHashMap[Tree, TreeAddrs] + def registerTreeAddr(tree: Tree): Addr = treeAddrs.get(tree) match { + case null => treeAddrs.put(tree, currentAddr); currentAddr + case addr: Addr => addr + } - def registerTreeAddr(tree: Tree) = - treeAddrs.put(tree, - treeAddrs.get(tree) match { - case null => currentAddr - case x: Addr => x :: currentAddr :: Nil - case xs: List[_] => xs :+ currentAddr - }) - - def addrsOfTree(tree: Tree): List[Addr] = treeAddrs.get(tree) match { - case null => Nil - case addr: Addr => addr :: Nil - case addrs: List[Addr] => addrs + def addrOfTree(tree: Tree): Option[Addr] = treeAddrs.get(tree) match { + case null => None + case addr: Addr => Some(addr) } private def offset(i: Int): Addr = Addr(offsets(i)) diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 9dfb78798..80270aa25 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -10,6 +10,7 @@ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annot import collection.mutable import typer.Inliner import NameOps._ +import StdNames.nme import TastyBuffer._ import TypeApplications._ @@ -49,10 +50,6 @@ class TreePickler(pickler: TastyPickler) { case None => } } - - def rhs(tdef: TypeDef)(implicit ctx: Context) = - if (tdef.symbol.isClass) tdef.rhs - else TypeTree(tdef.symbol.info).withPos(tdef.rhs.pos) private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index) private def pickleName(name: TastyName): Unit = writeNat(nameIndex(name).index) @@ -157,11 +154,6 @@ class TreePickler(pickler: TastyPickler) { throw ex } - def pickleTypeWithPos(tpe: Type, tree: Tree)(implicit ctx: Context): Unit = { - registerTreeAddr(tree) - pickleType(tpe) - } - private def pickleNewType(tpe: Type, richTypes: Boolean)(implicit ctx: Context): Unit = try { tpe match { case AppliedType(tycon, args) => writeByte(APPLIEDtype) @@ -253,7 +245,7 @@ class TreePickler(pickler: TastyPickler) { writeByte(TYPEBOUNDS) withLength { pickleType(tpe.lo, richTypes); pickleType(tpe.hi, richTypes) } case tpe: AnnotatedType => - writeByte(ANNOTATED) + writeByte(ANNOTATEDtype) withLength { pickleType(tpe.tpe, richTypes); pickleTree(tpe.annot.tree) } case tpe: AndOrType => writeByte(if (tpe.isAnd) ANDtype else ORtype) @@ -310,7 +302,7 @@ class TreePickler(pickler: TastyPickler) { } def pickleTpt(tpt: Tree)(implicit ctx: Context): Unit = - pickleTypeWithPos(tpt.tpe, tpt) // TODO correlate with original when generating positions + pickleTree(tpt) def pickleTreeUnlessEmpty(tree: Tree)(implicit ctx: Context): Unit = if (!tree.isEmpty) pickleTree(tree) @@ -336,7 +328,7 @@ class TreePickler(pickler: TastyPickler) { tree match { case tree: ValDef => pickleDef(PARAM, tree.symbol, tree.tpt) case tree: DefDef => pickleDef(PARAM, tree.symbol, tree.tpt, tree.rhs) - case tree: TypeDef => pickleDef(TYPEPARAM, tree.symbol, rhs(tree)) + case tree: TypeDef => pickleDef(TYPEPARAM, tree.symbol, tree.rhs) } } @@ -350,181 +342,231 @@ class TreePickler(pickler: TastyPickler) { stats.foreach(stat => if (!stat.isEmpty) pickleTree(stat)) } - def pickleTree(tree: Tree)(implicit ctx: Context): Unit = try { - registerTreeAddr(tree) - tree match { - case tree if tree.isType => - pickleTpt(tree) - case Ident(name) => - tree.tpe match { - case tp: TermRef => pickleType(tp) - case _ => - writeByte(IDENT) - pickleName(name) - pickleType(tree.tpe) - } - case This(_) => - pickleType(tree.tpe) - case Select(qual, name) => - writeByte(SELECT) - val realName = tree.tpe match { - case tp: NamedType if tp.name.isShadowedName => tp.name - case _ => name - } - val sig = tree.tpe.signature - if (sig == Signature.NotAMethod) pickleName(realName) - else pickleNameAndSig(realName, sig) - pickleTree(qual) - case Apply(fun, args) => - writeByte(APPLY) - withLength { - pickleTree(fun) - args.foreach(pickleTree) - } - case TypeApply(fun, args) => - writeByte(TYPEAPPLY) - withLength { - pickleTree(fun) - args.foreach(pickleTpt) - } - case Literal(const1) => - pickleConstant { + def pickleTree(tree: Tree)(implicit ctx: Context): Unit = { + val addr = registerTreeAddr(tree) + if (addr != currentAddr) { + writeByte(SHARED) + writeRef(addr) + } + else + try tree match { + case Ident(name) => tree.tpe match { - case ConstantType(const2) => const2 - case _ => const1 + case tp: TermRef if name != nme.WILDCARD => + // wildcards are pattern bound, need to be preserved as ids. + pickleType(tp) + case _ => + writeByte(if (tree.isType) IDENTtpt else IDENT) + pickleName(name) + pickleType(tree.tpe) } - } - case Super(qual, mix) => - writeByte(SUPER) - withLength { - pickleTree(qual); - if (!mix.isEmpty) { - val SuperType(_, mixinType) = tree.tpe - pickleType(mixinType) + case This(qual) => + if (qual.isEmpty) pickleType(tree.tpe) + else { + writeByte(QUALTHIS) + val ThisType(tref) = tree.tpe + pickleTree(qual.withType(tref)) } - } - case New(tpt) => - writeByte(NEW) - pickleTpt(tpt) - case Typed(expr, tpt) => - writeByte(TYPED) - withLength { pickleTree(expr); pickleTpt(tpt) } - case NamedArg(name, arg) => - writeByte(NAMEDARG) - withLength { pickleName(name); pickleTree(arg) } - case Assign(lhs, rhs) => - writeByte(ASSIGN) - withLength { pickleTree(lhs); pickleTree(rhs) } - case Block(stats, expr) => - writeByte(BLOCK) - stats.foreach(preRegister) - withLength { pickleTree(expr); stats.foreach(pickleTree) } - case If(cond, thenp, elsep) => - writeByte(IF) - withLength{ pickleTree(cond); pickleTree(thenp); pickleTree(elsep) } - case Closure(env, meth, tpt) => - writeByte(LAMBDA) - assert(env.isEmpty) - withLength{ - pickleTree(meth) - if (tpt.tpe.exists) pickleTpt(tpt) - } - case Match(selector, cases) => - writeByte(MATCH) - withLength { pickleTree(selector); cases.foreach(pickleTree) } - case CaseDef(pat, guard, rhs) => - writeByte(CASEDEF) - withLength { pickleTree(pat); pickleTree(rhs); pickleTreeUnlessEmpty(guard) } - case Return(expr, from) => - writeByte(RETURN) - withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) } - case Try(block, cases, finalizer) => - writeByte(TRY) - withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) } - case SeqLiteral(elems, elemtpt) => - writeByte(REPEATED) - withLength { pickleTree(elemtpt); elems.foreach(pickleTree) } - case Inlined(call, bindings, expansion) => - writeByte(INLINED) - bindings.foreach(preRegister) - withLength { pickleTree(call); pickleTree(expansion); bindings.foreach(pickleTree) } - case Bind(name, body) => - registerDef(tree.symbol) - writeByte(BIND) - withLength { pickleName(name); pickleType(tree.symbol.info); pickleTree(body) } - case Alternative(alts) => - writeByte(ALTERNATIVE) - withLength { alts.foreach(pickleTree) } - case UnApply(fun, implicits, patterns) => - writeByte(UNAPPLY) - withLength { - pickleTree(fun) - for (implicitArg <- implicits) { - writeByte(IMPLICITarg) - pickleTree(implicitArg) + case Select(qual, name) => + writeByte(if (name.isTypeName) SELECTtpt else SELECT) + val realName = tree.tpe match { + case tp: NamedType if tp.name.isShadowedName => tp.name + case _ => name } - pickleType(tree.tpe) - patterns.foreach(pickleTree) - } - case tree: ValDef => - pickleDef(VALDEF, tree.symbol, tree.tpt, tree.rhs) - case tree: DefDef => - def pickleAllParams = { - pickleParams(tree.tparams) - for (vparams <- tree.vparamss) { - writeByte(PARAMS) - withLength { pickleParams(vparams) } + val sig = tree.tpe.signature + if (sig == Signature.NotAMethod) pickleName(realName) + else pickleNameAndSig(realName, sig) + pickleTree(qual) + case Apply(fun, args) => + writeByte(APPLY) + withLength { + pickleTree(fun) + args.foreach(pickleTree) } - } - pickleDef(DEFDEF, tree.symbol, tree.tpt, tree.rhs, pickleAllParams) - case tree: TypeDef => - pickleDef(TYPEDEF, tree.symbol, rhs(tree)) - case tree: Template => - registerDef(tree.symbol) - writeByte(TEMPLATE) - val (params, rest) = tree.body partition { - case stat: TypeDef => stat.symbol is Flags.Param - case stat: ValOrDefDef => - stat.symbol.is(Flags.ParamAccessor) && !stat.symbol.isSetter - case _ => false - } - withLength { - pickleParams(params) - tree.parents.foreach(pickleTree) - val cinfo @ ClassInfo(_, _, _, _, selfInfo) = tree.symbol.owner.info - if ((selfInfo ne NoType) || !tree.self.isEmpty) { - writeByte(SELFDEF) - pickleName(tree.self.name) - if (!tree.self.isEmpty) registerTreeAddr(tree.self.tpt) - pickleType { - cinfo.selfInfo match { - case sym: Symbol => sym.info - case tp: Type => tp + case TypeApply(fun, args) => + writeByte(TYPEAPPLY) + withLength { + pickleTree(fun) + args.foreach(pickleTpt) + } + case Literal(const1) => + pickleConstant { + tree.tpe match { + case ConstantType(const2) => const2 + case _ => const1 + } + } + case Super(qual, mix) => + writeByte(SUPER) + withLength { + pickleTree(qual); + if (!mix.isEmpty) { + val SuperType(_, mixinType: TypeRef) = tree.tpe + pickleTree(mix.withType(mixinType)) + } + } + case New(tpt) => + writeByte(NEW) + pickleTpt(tpt) + case Typed(expr, tpt) => + writeByte(TYPED) + withLength { pickleTree(expr); pickleTpt(tpt) } + case NamedArg(name, arg) => + writeByte(NAMEDARG) + withLength { pickleName(name); pickleTree(arg) } + case Assign(lhs, rhs) => + writeByte(ASSIGN) + withLength { pickleTree(lhs); pickleTree(rhs) } + case Block(stats, expr) => + writeByte(BLOCK) + stats.foreach(preRegister) + withLength { pickleTree(expr); stats.foreach(pickleTree) } + case If(cond, thenp, elsep) => + writeByte(IF) + withLength { pickleTree(cond); pickleTree(thenp); pickleTree(elsep) } + case Closure(env, meth, tpt) => + writeByte(LAMBDA) + assert(env.isEmpty) + withLength { + pickleTree(meth) + if (tpt.tpe.exists) pickleTpt(tpt) + } + case Match(selector, cases) => + writeByte(MATCH) + withLength { pickleTree(selector); cases.foreach(pickleTree) } + case CaseDef(pat, guard, rhs) => + writeByte(CASEDEF) + withLength { pickleTree(pat); pickleTree(rhs); pickleTreeUnlessEmpty(guard) } + case Return(expr, from) => + writeByte(RETURN) + withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) } + case Try(block, cases, finalizer) => + writeByte(TRY) + withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) } + case SeqLiteral(elems, elemtpt) => + writeByte(REPEATED) + withLength { pickleTree(elemtpt); elems.foreach(pickleTree) } + case Inlined(call, bindings, expansion) => + writeByte(INLINED) + bindings.foreach(preRegister) + withLength { pickleTree(call); pickleTree(expansion); bindings.foreach(pickleTree) } + case Bind(name, body) => + registerDef(tree.symbol) + writeByte(BIND) + withLength { pickleName(name); pickleType(tree.symbol.info); pickleTree(body) } + case Alternative(alts) => + writeByte(ALTERNATIVE) + withLength { alts.foreach(pickleTree) } + case UnApply(fun, implicits, patterns) => + writeByte(UNAPPLY) + withLength { + pickleTree(fun) + for (implicitArg <- implicits) { + writeByte(IMPLICITarg) + pickleTree(implicitArg) + } + pickleType(tree.tpe) + patterns.foreach(pickleTree) + } + case tree: ValDef => + pickleDef(VALDEF, tree.symbol, tree.tpt, tree.rhs) + case tree: DefDef => + def pickleAllParams = { + pickleParams(tree.tparams) + for (vparams <- tree.vparamss) { + writeByte(PARAMS) + withLength { pickleParams(vparams) } + } + } + pickleDef(DEFDEF, tree.symbol, tree.tpt, tree.rhs, pickleAllParams) + case tree: TypeDef => + pickleDef(TYPEDEF, tree.symbol, tree.rhs) + case tree: Template => + registerDef(tree.symbol) + writeByte(TEMPLATE) + val (params, rest) = tree.body partition { + case stat: TypeDef => stat.symbol is Flags.Param + case stat: ValOrDefDef => + stat.symbol.is(Flags.ParamAccessor) && !stat.symbol.isSetter + case _ => false + } + withLength { + pickleParams(params) + tree.parents.foreach(pickleTree) + val cinfo @ ClassInfo(_, _, _, _, selfInfo) = tree.symbol.owner.info + if ((selfInfo ne NoType) || !tree.self.isEmpty) { + writeByte(SELFDEF) + pickleName(tree.self.name) + + if (!tree.self.tpt.isEmpty) pickleTree(tree.self.tpt) + else { + if (!tree.self.isEmpty) registerTreeAddr(tree.self) + pickleType { + cinfo.selfInfo match { + case sym: Symbol => sym.info + case tp: Type => tp + } + } } } + pickleStats(tree.constr :: rest) } - pickleStats(tree.constr :: rest) - } - case Import(expr, selectors) => - writeByte(IMPORT) - withLength { - pickleTree(expr) - selectors foreach { - case Thicket((from @ Ident(_)) :: (to @ Ident(_)) :: Nil) => - pickleSelector(IMPORTED, from) - pickleSelector(RENAMED, to) - case id @ Ident(_) => - pickleSelector(IMPORTED, id) + case Import(expr, selectors) => + writeByte(IMPORT) + withLength { + pickleTree(expr) + selectors foreach { + case Thicket((from @ Ident(_)) :: (to @ Ident(_)) :: Nil) => + pickleSelector(IMPORTED, from) + pickleSelector(RENAMED, to) + case id @ Ident(_) => + pickleSelector(IMPORTED, id) + } } - } - case PackageDef(pid, stats) => - writeByte(PACKAGE) - withLength { pickleType(pid.tpe); pickleStats(stats) } - }} - catch { - case ex: AssertionError => - println(i"error when pickling tree $tree") - throw ex + case PackageDef(pid, stats) => + writeByte(PACKAGE) + withLength { pickleType(pid.tpe); pickleStats(stats) } + case tree: TypeTree => + pickleType(tree.tpe) + case SingletonTypeTree(ref) => + writeByte(SINGLETONtpt) + pickleTree(ref) + case RefinedTypeTree(parent, refinements) => + if (refinements.isEmpty) pickleTree(parent) + else { + val refineCls = refinements.head.symbol.owner.asClass + pickledTypes.put(refineCls.typeRef, currentAddr) + writeByte(REFINEDtpt) + refinements.foreach(preRegister) + withLength { pickleTree(parent); refinements.foreach(pickleTree) } + } + case AppliedTypeTree(tycon, args) => + writeByte(APPLIEDtpt) + withLength { pickleTree(tycon); args.foreach(pickleTree) } + case AndTypeTree(tp1, tp2) => + writeByte(ANDtpt) + withLength { pickleTree(tp1); pickleTree(tp2) } + case OrTypeTree(tp1, tp2) => + writeByte(ORtpt) + withLength { pickleTree(tp1); pickleTree(tp2) } + case ByNameTypeTree(tp) => + writeByte(BYNAMEtpt) + pickleTree(tp) + case Annotated(tree, annot) => + writeByte(ANNOTATEDtpt) + withLength { pickleTree(tree); pickleTree(annot.tree) } + case PolyTypeTree(tparams, body) => + writeByte(POLYtpt) + withLength { pickleParams(tparams); pickleTree(body) } + case TypeBoundsTree(lo, hi) => + writeByte(TYPEBOUNDStpt) + withLength { pickleTree(lo); pickleTree(hi) } + } + catch { + case ex: AssertionError => + println(i"error when pickling tree $tree") + throw ex + } } def pickleSelector(tag: Int, id: untpd.Ident)(implicit ctx: Context): Unit = { diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index d2605afea..eba9ab533 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -256,7 +256,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle else if (nextByte == CONTRAVARIANT) { readByte(); -1 } else 0 TypeAlias(alias, variance) - case ANNOTATED => + case ANNOTATEDtype => AnnotatedType(readType(), Annotation(readTerm())) case ANDtype => AndType(readType(), readType()) @@ -368,7 +368,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle private def readPackageRef()(implicit ctx: Context): TermSymbol = { val name = readName() - if (name == nme.ROOT) defn.RootPackage + if (name == nme.ROOT || name == nme.ROOTPKG) defn.RootPackage else if (name == nme.EMPTY_PACKAGE) defn.EmptyPackageVal else ctx.requiredPackage(name) } @@ -389,11 +389,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle if (owner.isClass) lctx.setScope(owner.unforcedDecls) else lctx.setNewScope } - private def normalizeFlags(tag: Int, givenFlags: FlagSet, name: Name, isAbstractType: Boolean, rhsIsEmpty: Boolean)(implicit ctx: Context): FlagSet = { + private def normalizeFlags(tag: Int, givenFlags: FlagSet, name: Name, isAbsType: Boolean, rhsIsEmpty: Boolean)(implicit ctx: Context): FlagSet = { val lacksDefinition = rhsIsEmpty && name.isTermName && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) || - isAbstractType + isAbsType var flags = givenFlags if (lacksDefinition && tag != PARAM) flags |= Deferred if (tag == DEFDEF) flags |= Method @@ -407,6 +407,17 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle flags } + def isAbstractType(ttag: Int)(implicit ctx: Context): Boolean = nextUnsharedTag match { + case POLYtpt => + val rdr = fork + rdr.reader.readByte() // tag + rdr.reader.readNat() // length + rdr.skipParams() // tparams + rdr.isAbstractType(rdr.nextUnsharedTag) + case TYPEBOUNDS | TYPEBOUNDStpt => true + case _ => false + } + /** Create symbol of definition node and enter in symAtAddr map * @return the created symbol */ @@ -433,7 +444,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName skipParams() val ttag = nextUnsharedTag - val isAbstractType = ttag == TYPEBOUNDS + val isAbsType = isAbstractType(ttag) val isClass = ttag == TEMPLATE val templateStart = currentAddr skipTree() // tpt @@ -447,7 +458,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle case _ => EmptyFlags } pickling.println(i"creating symbol $name at $start with flags $givenFlags") - val flags = normalizeFlags(tag, givenFlags | nameFlags(rawName), name, isAbstractType, rhsIsEmpty) + val flags = normalizeFlags(tag, givenFlags | nameFlags(rawName), name, isAbsType, rhsIsEmpty) def adjustIfModule(completer: LazyType) = if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer val sym = @@ -623,11 +634,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val tag = readByte() val end = readEnd() - def readParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = { - fork.indexParams(tag)(localContext(sym)) - readIndexedParams(tag) - } - def readParamss(implicit ctx: Context): List[List[ValDef]] = { collectWhile(nextByte == PARAMS) { readByte() @@ -696,7 +702,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle TypeDef(readTemplate(localCtx)) } else { val rhs = readTpt() - sym.info = rhs.tpe + sym.info = rhs.tpe match { + case _: TypeBounds | _: ClassInfo => rhs.tpe + case _ => TypeAlias(rhs.tpe, sym.variance) + } TypeDef(rhs) } case PARAM => @@ -846,9 +855,14 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle def readIndexedParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = collectWhile(nextByte == tag) { readIndexedDef().asInstanceOf[T] } -// ------ Reading terms ----------------------------------------------------- + def readParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = { + fork.indexParams(tag) + readIndexedParams(tag) + } - def readTerm()(implicit ctx: Context): Tree = { +// ------ Reading trees ----------------------------------------------------- + + def readTerm()(implicit ctx: Context): Tree = { // TODO: rename to readTree val start = currentAddr val tag = readByte() pickling.println(s"reading term ${astTagToString(tag)} at $start") @@ -856,34 +870,52 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle def readPathTerm(): Tree = { goto(start) readType() match { + case path: TypeRef => TypeTree(path) case path: TermRef => ref(path) case path: ThisType => This(path.cls) case path: ConstantType => Literal(path.value) } } + def completeSelect(name: Name, tpf: Type => Type): Select = { + val localCtx = + if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx + val qual = readTerm()(localCtx) + val unshadowed = if (name.isShadowedName) name.revertShadowed else name + untpd.Select(qual, unshadowed).withType(tpf(qual.tpe.widenIfUnstable)) + } + + def readQualId(): (untpd.Ident, TypeRef) = { + val qual = readTerm().asInstanceOf[untpd.Ident] + (untpd.Ident(qual.name).withPos(qual.pos), qual.tpe.asInstanceOf[TypeRef]) + } + def readSimpleTerm(): Tree = tag match { + case SHARED => + forkAt(readAddr()).readTerm() case IDENT => untpd.Ident(readName()).withType(readType()) + case IDENTtpt => + untpd.Ident(readName().toTypeName).withType(readType()) case SELECT => - def readQual(name: Name) = { - val localCtx = - if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx - readTerm()(localCtx) - } - def readRest(name: Name, sig: Signature) = { - val unshadowed = if (name.isShadowedName) name.revertShadowed else name - val qual = readQual(name) - untpd.Select(qual, unshadowed) - .withType(TermRef.withSig(qual.tpe.widenIfUnstable, name.asTermName, sig)) - } + def readRest(name: Name, sig: Signature) = + completeSelect(name, TermRef.withSig(_, name.asTermName, sig)) readNameSplitSig match { case name: Name => readRest(name, Signature.NotAMethod) case (name: Name, sig: Signature) => readRest(name, sig) } - + case SELECTtpt => + val name = readName().toTypeName + completeSelect(name, TypeRef(_, name)) + case QUALTHIS => + val (qual, tref) = readQualId() + untpd.This(qual).withType(ThisType.raw(tref)) case NEW => New(readTpt()) + case SINGLETONtpt => + SingletonTypeTree(readTerm()) + case BYNAMEtpt => + ByNameTypeTree(readTpt()) case _ => readPathTerm() } @@ -891,10 +923,15 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle def readLengthTerm(): Tree = { val end = readEnd() + def localNonClassCtx = { + val ctx1 = ctx.fresh.setNewScope + if (ctx.owner.isClass) ctx1.setOwner(ctx1.newLocalDummy(ctx.owner)) else ctx1 + } + def readBlock(mkTree: (List[Tree], Tree) => Tree): Tree = { val exprReader = fork skipTree() - val localCtx = ctx.fresh.setNewScope + val localCtx = localNonClassCtx val stats = readStats(ctx.owner, end)(localCtx) val expr = exprReader.readTerm()(localCtx) mkTree(stats, expr) @@ -904,9 +941,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle (tag: @switch) match { case SUPER => val qual = readTerm() - val mixClass = ifBefore(end)(readType().typeSymbol, NoSymbol) - val mixName = if (mixClass.exists) mixClass.name.asTypeName else tpnme.EMPTY - tpd.Super(qual, mixName, ctx.mode.is(Mode.InSuperCall), mixClass) + val (mixId, mixTpe) = ifBefore(end)(readQualId(), (untpd.EmptyTypeIdent, NoType)) + tpd.Super(qual, mixId, ctx.mode.is(Mode.InSuperCall), mixTpe.typeSymbol) case APPLY => val fn = readTerm() val isJava = fn.symbol.is(JavaDefined) @@ -934,7 +970,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle case BLOCK => readBlock(Block) case INLINED => - val call = setPos(currentAddr, TypeTree(readType())) + val call = readTerm() readBlock((defs, expr) => Inlined(call, defs.asInstanceOf[List[MemberDef]], expr)) case IF => If(readTerm(), readTerm(), readTerm()) @@ -971,6 +1007,28 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val patType = readType() val argPats = until(end)(readTerm()) UnApply(fn, implicitArgs, argPats, patType) + case REFINEDtpt => + val refineCls = ctx.newCompleteClassSymbol( + ctx.owner, tpnme.REFINE_CLASS, Fresh, parents = Nil) + typeAtAddr(start) = refineCls.typeRef + val parent = readTpt() + val refinements = readStats(refineCls, end)(localContext(refineCls)) + RefinedTypeTree(parent, refinements, refineCls) + case APPLIEDtpt => + AppliedTypeTree(readTpt(), until(end)(readTpt())) + case ANDtpt => + AndTypeTree(readTpt(), readTpt()) + case ORtpt => + OrTypeTree(readTpt(), readTpt()) + case ANNOTATEDtpt => + Annotated(readTpt(), readTerm()) + case POLYtpt => + val localCtx = localNonClassCtx + val tparams = readParams[TypeDef](TYPEPARAM)(localCtx) + val body = readTpt()(localCtx) + PolyTypeTree(tparams, body) + case TYPEBOUNDStpt => + TypeBoundsTree(readTpt(), readTpt()) case _ => readPathTerm() } @@ -983,11 +1041,13 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle setPos(start, tree) } - def readTpt()(implicit ctx: Context) = { - val start = currentAddr - val tp = readType() - if (tp.exists) setPos(start, TypeTree(tp)) else EmptyTree - } + def readTpt()(implicit ctx: Context) = + if (isTypeTreeTag(nextUnsharedTag)) readTerm() + else { + val start = currentAddr + val tp = readType() + if (tp.exists) setPos(start, TypeTree(tp)) else EmptyTree + } def readCases(end: Addr)(implicit ctx: Context): List[CaseDef] = collectWhile(nextByte == CASEDEF && currentAddr != end) { readCase()(ctx.fresh.setNewScope) } diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 70148b3e2..b01f6cc6a 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -40,29 +40,15 @@ object Scala2Unpickler { /** Temporary type for classinfos, will be decomposed on completion of the class */ case class TempClassInfoType(parentTypes: List[Type], decls: Scope, clazz: Symbol) extends UncachedGroundType - /** Convert temp poly type to some native Dotty idiom. - * @param denot The denotation that gets the converted type as info. - * If `denot` is not an abstract type, this simply returns an equivalent `PolyType`. - * If `denot` is an abstract type, it converts a - * - * TempPolyType(List(v_1 T_1, ..., v_n T_n), lo .. hi) - * - * to a type lambda using `parameterizeWith/LambdaAbstract`. - */ - def depoly(tp: Type, denot: SymDenotation)(implicit ctx: Context): Type = tp match { - case TempPolyType(tparams, restpe) => - if (denot.isType) { - assert(!denot.isClass) - restpe.LambdaAbstract(tparams) - } - else - PolyType.fromSymbols(tparams, restpe) + /** Convert temp poly type to poly type and leave other types alone. */ + def translateTempPoly(tp: Type)(implicit ctx: Context): Type = tp match { + case TempPolyType(tparams, restpe) => restpe.LambdaAbstract(tparams) case tp => tp } def addConstructorTypeParams(denot: SymDenotation)(implicit ctx: Context) = { assert(denot.isConstructor) - denot.info = PolyType.fromSymbols(denot.owner.typeParams, denot.info) + denot.info = denot.info.LambdaAbstract(denot.owner.typeParams) } /** Convert array parameters denoting a repeated parameter of a Java method @@ -549,7 +535,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val selfInfo = if (atEnd) NoType else readTypeRef() setClassInfo(denot, tp, selfInfo) case denot => - val tp1 = depoly(tp, denot) + val tp1 = translateTempPoly(tp) denot.info = if (tag == ALIASsym) TypeAlias(tp1) else if (denot.isType) checkNonCyclic(denot.symbol, tp1, reportErrors = false) diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala index b6a423dc7..0f63b25bb 100644 --- a/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -417,7 +417,7 @@ object JavaParsers { atPos(in.offset) { val name = identForType() val hi = if (in.token == EXTENDS) { in.nextToken() ; bound() } else EmptyTree - TypeDef(name, Nil, TypeBoundsTree(EmptyTree, hi)).withMods(Modifiers(flags)) + TypeDef(name, TypeBoundsTree(EmptyTree, hi)).withMods(Modifiers(flags)) } def bound(): Tree = @@ -625,8 +625,7 @@ object JavaParsers { val template = cdef.rhs.asInstanceOf[Template] cpy.TypeDef(cdef)(cdef.name, cpy.Template(template)(template.constr, template.parents, template.self, - importCompanionObject(cdef) :: template.body), - cdef.tparams).withMods(cdef.mods) + importCompanionObject(cdef) :: template.body)).withMods(cdef.mods) } List(makeCompanionObject(cdefNew, statics), cdefNew) @@ -715,7 +714,7 @@ object JavaParsers { val (statics, body) = typeBody(INTERFACE, name, tparams) val iface = atPos(start, nameOffset) { TypeDef( - name, tparams, + name, makeTemplate(parents, body, tparams, false)).withMods(mods | Flags.Trait | Flags.JavaInterface | Flags.Abstract) } addCompanionObject(statics, iface) @@ -830,7 +829,7 @@ object JavaParsers { Select(New(javaLangDot(tpnme.Enum)), nme.CONSTRUCTOR), List(enumType)), List(Literal(Constant(null)),Literal(Constant(0)))) val enum = atPos(start, nameOffset) { - TypeDef(name, List(), + TypeDef(name, makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.Enum) } addCompanionObject(consts ::: statics ::: predefs, enum) diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index bb76de6cc..fa0576c7a 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -527,27 +527,28 @@ object Parsers { */ def path(thisOK: Boolean, finish: Tree => Tree = id): Tree = { val start = in.offset - def handleThis(name: TypeName) = { + def handleThis(qual: Ident) = { in.nextToken() - val t = atPos(start) { This(name) } + val t = atPos(start) { This(qual) } if (!thisOK && in.token != DOT) syntaxError("`.' expected") dotSelectors(t, finish) } - def handleSuper(name: TypeName) = { + def handleSuper(qual: Ident) = { in.nextToken() val mix = mixinQualifierOpt() - val t = atPos(start) { Super(This(name), mix) } + val t = atPos(start) { Super(This(qual), mix) } accept(DOT) dotSelectors(selector(t), finish) } - if (in.token == THIS) handleThis(tpnme.EMPTY) - else if (in.token == SUPER) handleSuper(tpnme.EMPTY) + if (in.token == THIS) handleThis(EmptyTypeIdent) + else if (in.token == SUPER) handleSuper(EmptyTypeIdent) else { val t = termIdent() if (in.token == DOT) { + def qual = cpy.Ident(t)(t.name.toTypeName) in.nextToken() - if (in.token == THIS) handleThis(t.name.toTypeName) - else if (in.token == SUPER) handleSuper(t.name.toTypeName) + if (in.token == THIS) handleThis(qual) + else if (in.token == SUPER) handleSuper(qual) else selectors(t, finish) } else t @@ -556,9 +557,9 @@ object Parsers { /** MixinQualifier ::= `[' Id `]' */ - def mixinQualifierOpt(): TypeName = - if (in.token == LBRACKET) inBrackets(ident().toTypeName) - else tpnme.EMPTY + def mixinQualifierOpt(): Ident = + if (in.token == LBRACKET) inBrackets(atPos(in.offset) { typeIdent() }) + else EmptyTypeIdent /** StableId ::= Id * | Path `.' Id @@ -617,7 +618,7 @@ object Parsers { termIdent() else if (in.token == THIS) { in.nextToken() - This(tpnme.EMPTY) + This(EmptyTypeIdent) } else if (in.token == LBRACE) if (inPattern) Block(Nil, inBraces(pattern())) @@ -1646,7 +1647,7 @@ object Parsers { val bounds = if (isConcreteOwner) typeParamBounds(name) else typeBounds() - TypeDef(name, hkparams, bounds).withMods(mods) + TypeDef(name, lambdaAbstract(hkparams, bounds)).withMods(mods) } } commaSeparated(typeParam) @@ -1956,9 +1957,9 @@ object Parsers { in.token match { case EQUALS => in.nextToken() - TypeDef(name, tparams, typ()).withMods(mods).setComment(docstring) + TypeDef(name, lambdaAbstract(tparams, typ())).withMods(mods).setComment(docstring) case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | EOF => - TypeDef(name, tparams, typeBounds()).withMods(mods).setComment(docstring) + TypeDef(name, lambdaAbstract(tparams, typeBounds())).withMods(mods).setComment(docstring) case _ => syntaxErrorOrIncomplete("`=', `>:', or `<:' expected") EmptyTree @@ -2145,7 +2146,7 @@ object Parsers { val first = expr1() if (in.token == ARROW) { first match { - case Typed(tree @ This(tpnme.EMPTY), tpt) => + case Typed(tree @ This(EmptyTypeIdent), tpt) => self = makeSelfDef(nme.WILDCARD, tpt).withPos(first.pos) case _ => val ValDef(name, tpt, _) = convertToParam(first, expected = "self type clause") diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index 785f57897..4894fa019 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -127,7 +127,10 @@ class PlainPrinter(_ctx: Context) extends Printer { homogenize(tp) match { case tp: TypeType => toTextRHS(tp) - case tp: TermRef if !tp.denotationIsCurrent || tp.symbol.is(Module) || tp.symbol.name.isImportName => + case tp: TermRef + if !tp.denotationIsCurrent && !homogenizedView || // always print underyling when testing picklers + tp.symbol.is(Module) || + tp.symbol.name.isImportName => toTextRef(tp) ~ ".type" case tp: TermRef if tp.denot.isOverloaded => "<overloaded " ~ toTextRef(tp) ~ ">" @@ -231,9 +234,10 @@ class PlainPrinter(_ctx: Context) extends Printer { protected def trimPrefix(text: Text) = text.stripPrefix(objectPrefix).stripPrefix(packagePrefix) - protected def selectionString(tp: NamedType) = - if (tp.currentSymbol.exists) nameString(tp.symbol) - else nameString(tp.name) + protected def selectionString(tp: NamedType) = { + val sym = if (homogenizedView) tp.symbol else tp.currentSymbol + if (sym.exists) nameString(sym) else nameString(tp.name) + } /** The string representation of this type used as a prefix */ protected def toTextRef(tp: SingletonType): Text = controlled { diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 7aaf2e190..29e1d4869 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -21,6 +21,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { /** A stack of enclosing DefDef, TypeDef, or ClassDef, or ModuleDefs nodes */ private var enclosingDef: untpd.Tree = untpd.EmptyTree private var myCtx: Context = _ctx + private var printPos = ctx.settings.Yprintpos.value override protected[this] implicit def ctx: Context = myCtx def withEnclosingDef(enclDef: Tree[_ >: Untyped])(op: => Text): Text = { @@ -35,6 +36,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } } + def inPattern(op: => Text): Text = { + val savedCtx = myCtx + myCtx = ctx.addMode(Mode.Pattern) + try op finally myCtx = savedCtx + } + + def withoutPos(op: => Text): Text = { + val savedPrintPos = printPos + printPos = false + try op finally printPos = savedPrintPos + } + private def enclDefIsClass = enclosingDef match { case owner: TypeDef[_] => owner.isClassDef case owner: untpd.ModuleDef => true @@ -134,6 +147,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { return toTextParents(tp.parentsWithArgs) ~ "{...}" case JavaArrayType(elemtp) => return toText(elemtp) ~ "[]" + case tp: AnnotatedType if homogenizedView => + // Positions of annotations in types are not serialized + // (they don't need to because we keep the original type tree with + // the original annotation anyway. Therefore, there will always be + // one version of the annotation tree that has the correct positions). + withoutPos(super.toText(tp)) case tp: SelectionProto => return "?{ " ~ toText(tp.name) ~ (" " provided !tp.name.decode.last.isLetterOrDigit) ~ ": " ~ toText(tp.memberProto) ~ " }" @@ -249,7 +268,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } def nameIdText(tree: untpd.NameTree): Text = - toText(tree.name) ~ idText(tree) + if (tree.hasType && tree.symbol.exists) nameString(tree.symbol) + else toText(tree.name) ~ idText(tree) def toTextTemplate(impl: Template, ofNew: Boolean = false): Text = { val Template(constr @ DefDef(_, tparams, vparamss, _, _), parents, self, _) = impl @@ -284,7 +304,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case tp: NamedType if name != nme.WILDCARD => val pre = if (tp.symbol is JavaStatic) tp.prefix.widen else tp.prefix toTextPrefix(pre) ~ selectionString(tp) - case _ => toText(name) + case _ => + toText(name) } case tree @ Select(qual, name) => if (qual.isType) toTextLocal(qual) ~ "#" ~ toText(name) @@ -337,7 +358,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (sel.isEmpty) blockText(cases) else changePrec(GlobalPrec) { toText(sel) ~ " match " ~ blockText(cases) } case CaseDef(pat, guard, body) => - "case " ~ toText(pat) ~ optText(guard)(" if " ~ _) ~ " => " ~ caseBlockText(body) + "case " ~ inPattern(toText(pat)) ~ optText(guard)(" if " ~ _) ~ " => " ~ caseBlockText(body) case Return(expr, from) => changePrec(GlobalPrec) { "return" ~ optText(expr)(" " ~ _) } case Try(expr, cases, finalizer) => @@ -351,7 +372,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case SeqLiteral(elems, elemtpt) => "[" ~ toTextGlobal(elems, ",") ~ " : " ~ toText(elemtpt) ~ "]" case tree @ Inlined(call, bindings, body) => - (("/* inlined from " ~ toText(call) ~ "*/ ") provided !homogenizedView) ~ + (("/* inlined from " ~ toText(call) ~ "*/ ") provided !homogenizedView) ~ blockText(bindings :+ body) case tpt: untpd.DerivedTypeTree => "<derived typetree watching " ~ summarized(toText(tpt.watched)) ~ ">" @@ -402,24 +423,27 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } } case tree @ TypeDef(name, rhs) => - def typeDefText(rhsText: Text) = + def typeDefText(tparamsText: => Text, rhsText: => Text) = dclTextOr { modText(tree.mods, "type") ~~ (varianceText(tree.mods) ~ nameIdText(tree)) ~ withEnclosingDef(tree) { - val rhsText1 = if (tree.hasType) toText(tree.symbol.info) else rhsText - tparamsText(tree.tparams) ~ rhsText1 + if (tree.hasType) toText(tree.symbol.info) // TODO: always print RHS, once we pickle/unpickle type trees + else tparamsText ~ rhsText } } - rhs match { + def recur(rhs: Tree, tparamsTxt: => Text): Text = rhs match { case impl: Template => modText(tree.mods, if ((tree).mods is Trait) "trait" else "class") ~~ nameIdText(tree) ~ withEnclosingDef(tree) { toTextTemplate(impl) } ~ (if (tree.hasType && ctx.settings.verbose.value) i"[decls = ${tree.symbol.info.decls}]" else "") case rhs: TypeBoundsTree => - typeDefText(toText(rhs)) - case _ => - typeDefText(optText(rhs)(" = " ~ _)) + typeDefText(tparamsTxt, toText(rhs)) + case PolyTypeTree(tparams, body) => + recur(body, tparamsText(tparams)) + case rhs => + typeDefText(tparamsTxt, optText(rhs)(" = " ~ _)) } + recur(rhs, "") case Import(expr, selectors) => def selectorText(sel: Tree): Text = sel match { case Thicket(l :: r :: Nil) => toTextGlobal(l) ~ " => " ~ toTextGlobal(r) @@ -516,22 +540,40 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case _ => tree.fallbackToText(this) } + var txt = toTextCore(tree) + + def suppressTypes = + tree.isType || tree.isDef || // don't print types of types or defs + homogenizedView && ctx.mode.is(Mode.Pattern) + // When comparing pickled info, disregard types of patterns. + // The reason is that GADT matching can rewrite types of pattern trees + // without changing the trees themselves. (see Typer.typedCase.indexPatterns.transform). + // But then pickling and unpickling the original trees will yield trees + // with the original types before they are rewritten, which causes a discrepancy. + + def suppressPositions = tree match { + case _: WithoutTypeOrPos[_] | _: TypeTree => true // TypeTrees never have an interesting position + case _ => false + } + if (ctx.settings.printtypes.value && tree.hasType) { - val tp = tree.typeOpt match { + // add type to term nodes; replace type nodes with their types unless -Yprintpos is also set. + def tp = tree.typeOpt match { case tp: TermRef if tree.isInstanceOf[RefTree] && !tp.denot.isOverloaded => tp.underlying case tp => tp } - if (tree.isType) txt = toText(tp) - else if (!tree.isDef) txt = ("<" ~ txt ~ ":" ~ toText(tp) ~ ">").close + if (!suppressTypes) + txt = ("<" ~ txt ~ ":" ~ toText(tp) ~ ">").close + else if (tree.isType && !homogenizedView) + txt = toText(tp) } - else if (homogenizedView && tree.isType) - txt = toText(tree.typeOpt) - if (ctx.settings.Yprintpos.value && !tree.isInstanceOf[WithoutTypeOrPos[_]]) { - val pos = - if (homogenizedView && !tree.isInstanceOf[MemberDef]) tree.pos.toSynthetic + if (printPos && !suppressPositions) { + // add positions + val pos = + if (homogenizedView && !tree.isInstanceOf[MemberDef]) tree.pos.toSynthetic else tree.pos - val clsStr = "" // DEBUG: if (tree.isType) tree.getClass.toString else "" + val clsStr = ""//if (tree.isType) tree.getClass.toString else "" txt = (txt ~ "@" ~ pos.toString ~ clsStr).close } tree match { diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index a503d55e5..069176111 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -352,10 +352,10 @@ object Erasure extends TypeTestsCasts{ assignType(untpd.cpy.Select(tree)(qual, tree.name.primitiveArrayOp), qual) def adaptIfSuper(qual: Tree): Tree = qual match { - case Super(thisQual, tpnme.EMPTY) => + case Super(thisQual, untpd.EmptyTypeIdent) => val SuperType(thisType, supType) = qual.tpe if (sym.owner is Flags.Trait) - cpy.Super(qual)(thisQual, sym.owner.asClass.name) + cpy.Super(qual)(thisQual, untpd.Ident(sym.owner.asClass.name)) .withType(SuperType(thisType, sym.owner.typeRef)) else qual.withType(SuperType(thisType, thisType.firstParent)) diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index fc70ac4f2..2fb85b6c0 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -46,10 +46,10 @@ class Pickler extends Phase { val treePkl = pickler.treePkl treePkl.pickle(tree :: Nil) treePkl.compactify() - pickler.addrsOfTree = treePkl.buf.addrsOfTree + pickler.addrOfTree = treePkl.buf.addrOfTree pickler.addrOfSym = treePkl.addrOfSym if (tree.pos.exists) - new PositionPickler(pickler, treePkl.buf.addrsOfTree).picklePositions(tree :: Nil) + new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil) def rawBytes = // not needed right now, but useful to print raw format. pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map { diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala index 7e51635e5..1ed47d92e 100644 --- a/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/src/dotty/tools/dotc/transform/PostTyper.scala @@ -175,7 +175,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran Checking.checkRealizable(qual.tpe, qual.pos.focus) super.transform(tree) } - else + else transformSelect(paramFwd.adaptRef(fixSignature(tree)), Nil) case tree: Super => if (ctx.owner.enclosingMethod.isInlineMethod) diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index 10be6db65..fea478c9b 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -106,7 +106,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { ctx.error(s"super not allowed here: use this.${sel.name.decode} instead", sel.pos) else if (sym is Deferred) { val member = sym.overridingSymbol(clazz) - if (mix != tpnme.EMPTY || + if (!mix.name.isEmpty || !member.exists || !((member is AbsOverride) && member.isIncompleteIn(clazz))) ctx.error( @@ -114,7 +114,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { sel.pos) else ctx.log(i"ok super $sel ${sym.showLocated} $member $clazz ${member.isIncompleteIn(clazz)}") } - else if (mix == tpnme.EMPTY && !(sym.owner is Trait)) + else if (mix.name.isEmpty && !(sym.owner is Trait)) // SI-4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract. for (intermediateClass <- clazz.info.baseClasses.tail.takeWhile(_ != sym.owner)) { val overriding = sym.overridingSymbol(intermediateClass) @@ -124,7 +124,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { sel.pos) } - if (name.isTermName && mix == tpnme.EMPTY && + if (name.isTermName && mix.name.isEmpty && ((clazz is Trait) || clazz != ctx.owner.enclosingClass || !validCurrentClass)) superAccessorCall(sel)(ctx.withPhase(thisTransformer.next)) else sel diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index a1ccf0e63..5385ca720 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -977,7 +977,7 @@ object TreeTransforms { if (mutatedInfo eq null) tree else { val rhs = transform(tree.rhs, mutatedInfo, cur)(localContext(tree.symbol)) - goTypeDef(cpy.TypeDef(tree)(tree.name, rhs, tree.tparams), mutatedInfo.nx.nxTransTypeDef(cur)) + goTypeDef(cpy.TypeDef(tree)(tree.name, rhs), mutatedInfo.nx.nxTransTypeDef(cur)) } case _ => tree diff --git a/src/dotty/tools/dotc/typer/Inliner.scala b/src/dotty/tools/dotc/typer/Inliner.scala index 6499167ad..3931fcaf4 100644 --- a/src/dotty/tools/dotc/typer/Inliner.scala +++ b/src/dotty/tools/dotc/typer/Inliner.scala @@ -120,7 +120,7 @@ object Inliner { // Abstract accessed type over local refs def abstractQualType(mtpe: Type): Type = if (localRefs.isEmpty) mtpe - else PolyType.fromSymbols(localRefs.map(_.symbol), mtpe).asInstanceOf[PolyType].flatten + else mtpe.LambdaAbstract(localRefs.map(_.symbol)).asInstanceOf[PolyType].flatten val accessorType = abstractQualType(addQualType(dealiasMap(accessedType))) val accessor = accessorSymbol(tree, accessorType).asTerm @@ -290,8 +290,20 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { */ private val paramProxy = new mutable.HashMap[Type, Type] - /** A map from (direct and outer) this references in `rhs` to references of their proxies */ - private val thisProxy = new mutable.HashMap[Type, TermRef] + /** A map from the classes of (direct and outer) this references in `rhs` + * 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. + * + * ThisType(TypeRef(ThisType(p), cls)) + * + * vs + * + * ThisType(TypeRef(TermRef(ThisType(<root>), p), cls)) + * + * These are different (wrt ==) types but represent logically the same key + */ + private val thisProxy = new mutable.HashMap[ClassSymbol, TermRef] /** A buffer for bindings that define proxies for actual arguments */ val bindingsBuf = new mutable.ListBuffer[ValOrDefDef] @@ -349,13 +361,13 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { private def registerType(tpe: Type): Unit = tpe match { case tpe: ThisType if !ctx.owner.isContainedIn(tpe.cls) && !tpe.cls.is(Package) && - !thisProxy.contains(tpe) => + !thisProxy.contains(tpe.cls) => if (tpe.cls.isStaticOwner) - thisProxy(tpe) = tpe.cls.sourceModule.termRef + thisProxy(tpe.cls) = tpe.cls.sourceModule.termRef else { val proxyName = s"${tpe.cls.name}_this".toTermName val proxyType = tpe.asSeenFrom(prefix.tpe, meth.owner) - thisProxy(tpe) = newSym(proxyName, EmptyFlags, proxyType).termRef + thisProxy(tpe.cls) = newSym(proxyName, EmptyFlags, proxyType).termRef registerType(meth.owner.thisType) // make sure we have a base from which to outer-select } case tpe: NamedType @@ -408,7 +420,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { // and parameters to type references of their arguments or proxies. val typeMap = new TypeMap { def apply(t: Type) = t match { - case t: ThisType => thisProxy.getOrElse(t, t) + case t: ThisType => thisProxy.getOrElse(t.cls, t) case t: TypeRef => paramProxy.getOrElse(t, mapOver(t)) case t: SingletonType => paramProxy.getOrElse(t, mapOver(t)) case t => mapOver(t) @@ -420,9 +432,13 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { def treeMap(tree: Tree) = { tree match { case _: This => - thisProxy.get(tree.tpe) match { - case Some(t) => ref(t).withPos(tree.pos) - case None => tree + tree.tpe match { + case thistpe: ThisType => + thisProxy.get(thistpe.cls) match { + case Some(t) => ref(t).withPos(tree.pos) + case None => tree + } + case _ => tree } case _: Ident => paramProxy.get(tree.tpe) match { diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 78f0da1f0..148cf1da7 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -114,7 +114,7 @@ trait NamerContextOps { this: Context => if (param.info.isDirectRef(defn.ObjectClass)) param.info = defn.AnyType make.fromSymbols(params, resultType) } - if (typeParams.nonEmpty) PolyType.fromSymbols(typeParams, monotpe) + if (typeParams.nonEmpty) monotpe.LambdaAbstract(typeParams) else if (valueParamss.isEmpty) ExprType(monotpe) else monotpe } @@ -294,7 +294,7 @@ class Namer { typer: Typer => val inSuperCall1 = if (tree.mods is ParamOrAccessor) EmptyFlags else inSuperCall // suppress inSuperCall for constructor parameters val higherKinded = tree match { - case tree: TypeDef if tree.tparams.nonEmpty && isDeferred => HigherKinded + case TypeDef(_, PolyTypeTree(_, _)) if isDeferred => HigherKinded case _ => EmptyFlags } @@ -616,8 +616,12 @@ class Namer { typer: Typer => nestedCtx = localContext(sym).setNewScope myTypeParams = { implicit val ctx: Context = nestedCtx - completeParams(original.tparams) - original.tparams.map(symbolOfTree(_).asType) + val tparams = original.rhs match { + case PolyTypeTree(tparams, _) => tparams + case _ => Nil + } + completeParams(tparams) + tparams.map(symbolOfTree(_).asType) } } myTypeParams @@ -1025,7 +1029,11 @@ class Namer { typer: Typer => // inspects a TypeRef's info, instead of simply dealiasing alias types. val isDerived = tdef.rhs.isInstanceOf[untpd.DerivedTypeTree] - val rhsBodyType = typedAheadType(tdef.rhs).tpe + val rhs = tdef.rhs match { + case PolyTypeTree(_, body) => body + case rhs => rhs + } + val rhsBodyType = typedAheadType(rhs).tpe val rhsType = if (isDerived) rhsBodyType else abstracted(rhsBodyType) val unsafeInfo = rhsType match { case bounds: TypeBounds => bounds diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index b1fed308c..ee2d68278 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -282,7 +282,7 @@ trait TypeAssigner { } def assignType(tree: untpd.This)(implicit ctx: Context) = { - val cls = qualifyingClass(tree, tree.qual, packageOK = false) + val cls = qualifyingClass(tree, tree.qual.name, packageOK = false) tree.withType(cls.thisType) } @@ -291,7 +291,7 @@ trait TypeAssigner { val qtype @ ThisType(_) = qual.tpe val cls = qtype.cls - def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match { + def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix.name) match { case p :: Nil => p case Nil => @@ -431,7 +431,18 @@ trait TypeAssigner { def assignType(tree: untpd.OrTypeTree, left: Tree, right: Tree)(implicit ctx: Context) = tree.withType(left.tpe | right.tpe) - // RefinedTypeTree is missing, handled specially in Typer and Unpickler. + /** Assign type of RefinedType. + * Refinements are typed as if they were members of refinement class `refineCls`. + */ + def assignType(tree: untpd.RefinedTypeTree, parent: Tree, refinements: List[Tree], refineCls: ClassSymbol)(implicit ctx: Context) = { + def addRefinement(parent: Type, refinement: Tree): Type = { + val rsym = refinement.symbol + val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info + RefinedType(parent, rsym.name, rinfo) + } + val refined = (parent.tpe /: refinements)(addRefinement) + tree.withType(RecType.closeOver(rt => refined.substThis(refineCls, RecThis(rt)))) + } def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = { val tparams = tycon.tpe.typeParams @@ -456,7 +467,7 @@ trait TypeAssigner { } def assignType(tree: untpd.PolyTypeTree, tparamDefs: List[TypeDef], body: Tree)(implicit ctx: Context) = - tree.withType(PolyType.fromSymbols(tparamDefs.map(_.symbol), body.tpe)) + tree.withType(body.tpe.LambdaAbstract(tparamDefs.map(_.symbol))) def assignType(tree: untpd.ByNameTypeTree, result: Tree)(implicit ctx: Context) = tree.withType(ExprType(result.tpe)) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 0ee9a2799..64936e106 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1008,23 +1008,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val refineCls = createSymbol(refineClsDef).asClass val TypeDef(_, impl: Template) = typed(refineClsDef) val refinements1 = impl.body - val seen = mutable.Set[Symbol]() assert(tree.refinements.length == refinements1.length, s"${tree.refinements} != $refinements1") - def addRefinement(parent: Type, refinement: Tree): Type = { + val seen = mutable.Set[Symbol]() + for (refinement <- refinements1) { // TODO: get clarity whether we want to enforce these conditions typr.println(s"adding refinement $refinement") checkRefinementNonCyclic(refinement, refineCls, seen) val rsym = refinement.symbol if (rsym.is(Method) && rsym.allOverriddenSymbols.isEmpty) - ctx.error(i"refinement $rsym without matching type in parent $parent", refinement.pos) - val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info - RefinedType(parent, rsym.name, rinfo) - // todo later: check that refinement is within bounds + ctx.error(i"refinement $rsym without matching type in parent $tpt1", refinement.pos) } - val refined = (tpt1.tpe /: refinements1)(addRefinement) - val res = cpy.RefinedTypeTree(tree)(tpt1, refinements1).withType( - RecType.closeOver(rt => refined.substThis(refineCls, RecThis(rt)))) - typr.println(i"typed refinement: ${res.tpe}") - res + assignType(cpy.RefinedTypeTree(tree)(tpt1, refinements1), tpt1, refinements1, refineCls) } def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): Tree = track("typedAppliedTypeTree") { @@ -1192,7 +1185,15 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): Tree = track("typedTypeDef") { val TypeDef(name, rhs) = tdef completeAnnotations(tdef, sym) - assignType(cpy.TypeDef(tdef)(name, typedType(rhs), Nil), sym) + val rhs1 = tdef.rhs match { + case rhs @ PolyTypeTree(tparams, body) => + val tparams1 = tparams.map(typed(_)).asInstanceOf[List[TypeDef]] + val body1 = typedType(body) + assignType(cpy.PolyTypeTree(rhs)(tparams1, body1), tparams1, body1) + case rhs => + typedType(rhs) + } + assignType(cpy.TypeDef(tdef)(name, rhs1), sym) } def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") { @@ -1257,7 +1258,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit .withType(dummy.nonMemberTermRef) checkVariance(impl1) if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.typeRef, cdef.namePos) - val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1, Nil), cls) + val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls) if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) { val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass)) ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true, diff --git a/test/test/DeSugarTest.scala b/test/test/DeSugarTest.scala index 1365f3222..d7a056e42 100644 --- a/test/test/DeSugarTest.scala +++ b/test/test/DeSugarTest.scala @@ -62,7 +62,7 @@ class DeSugarTest extends ParserTest { case tree1 @ DefDef(name, tparams, vparamss, tpt, _) => cpy.DefDef(tree1)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt, Type), transform(tree1.rhs)) case tree1 @ TypeDef(name, rhs) => - cpy.TypeDef(tree1)(name, transform(rhs, Type), transformSub(tree1.tparams)) + cpy.TypeDef(tree1)(name, transform(rhs, Type)) case impl @ Template(constr, parents, self, _) => cpy.Template(tree1)(transformSub(constr), transform(parents), transformSub(self), transform(impl.body, Expr)) case Thicket(trees) => diff --git a/tests/neg/i1605.scala b/tests/neg/i1605.scala index 776f2df47..f5fd9f29b 100644 --- a/tests/neg/i1605.scala +++ b/tests/neg/i1605.scala @@ -1,5 +1,5 @@ object Test { def foo = inlineMe - inline def inlineMe = 1 + x // error + inline def inlineMe = 1 + x2233 // error } diff --git a/tests/pickling/annot.scala b/tests/pickling/annot.scala new file mode 100644 index 000000000..d20a6cbf4 --- /dev/null +++ b/tests/pickling/annot.scala @@ -0,0 +1,12 @@ +trait Type +class RefinedType extends Type + + +object TestAnnot { + def toText(tp: Type) = tp match { + case tp: RefinedType => + val parent :: (refined: List[RefinedType @unchecked]) = ??? + ??? + } + val xs: List[RefinedType @unchecked] = ??? +} diff --git a/tests/pickling/pickleTypes.scala b/tests/pickling/pickleTypes.scala new file mode 100644 index 000000000..ef322816a --- /dev/null +++ b/tests/pickling/pickleTypes.scala @@ -0,0 +1,13 @@ +object pickleTypes { + + abstract class C { type T; val x: T; def f: T; def g(y: T): T; def h[U](z: U, y: T): U } + + val x1: Int = ??? + val x2: List[List[Int]] = ??? + val x3: C { type T <: C } = ??? + val x4: C { type T = Int; val x: Int } = ??? + val x5: C { type T = String; def f: String; def g(y: String): String } = ??? + val x6: C { type T = String; def f: String; def g(y: String): String; def h[U](z: U, y: T): U } = ??? + + +} diff --git a/tests/pickling/simple.scala b/tests/pickling/simple.scala new file mode 100644 index 000000000..243b41117 --- /dev/null +++ b/tests/pickling/simple.scala @@ -0,0 +1,6 @@ +object Simple {} +/*class Simple { + val x = 3 + val y: String = "" +}*/ + |