Skip to content

Commit c292f01

Browse files
committed
First stab at type methods
Allow types to be parameterized over terms. Parameterized type definitions are treated analogously to transparent methods.
1 parent d5619ae commit c292f01

17 files changed

+206
-116
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
106106
Closure(Nil, call, targetTpt))
107107
}
108108

109-
/** A closure whole anonymous function has the given method type */
109+
/** A closure whose anonymous function has the given method type */
110110
def Lambda(tpe: MethodType, rhsFn: List[Tree] => Tree)(implicit ctx: Context): Block = {
111111
val meth = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Synthetic | Method, tpe)
112112
Closure(meth, tss => rhsFn(tss.head).changeOwner(ctx.owner, meth))

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,8 @@ object SymDenotations {
792792
is(InlineMethod, butNot = Accessor)
793793

794794
def isTransparentMethod(implicit ctx: Context): Boolean =
795-
is(TransparentMethod, butNot = AccessorOrSynthetic)
795+
is(TransparentMethod, butNot = AccessorOrSynthetic) ||
796+
is(TypeMethod)
796797

797798
def isInlineableMethod(implicit ctx: Context) = isInlinedMethod || isTransparentMethod
798799

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,14 @@ object Types {
993993
case _ => this
994994
}
995995

996+
/** Widen, and if result is a typeref with a type lambda as alias or upper bound,
997+
* widen again to the lambda
998+
*/
999+
final def widenToLambda(implicit ctx: Context): Type = widen match {
1000+
case tp: TypeRef if tp.info.hiBound.isInstanceOf[LambdaType] => tp.info.hiBound
1001+
case tp => tp
1002+
}
1003+
9961004
/** If this type contains embedded union types, replace them by their joins.
9971005
* "Embedded" means: inside intersectons or recursive types, or in prefixes of refined types.
9981006
* If an embedded union is found, we first try to simplify or eliminate it by

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -770,11 +770,11 @@ class TreeUnpickler(reader: TastyReader,
770770
val tparams = readParams[TypeDef](TYPEPARAM)(localCtx)
771771
val vparamss = readParamss(localCtx)
772772
val tpt = readTpt()(localCtx)
773-
val typeParams = tparams.map(_.symbol)
773+
val typeParams = tparams.map(_.symbol.asType)
774774
val valueParamss = ctx.normalizeIfConstructor(
775-
vparamss.nestedMap(_.symbol), name == nme.CONSTRUCTOR)
775+
vparamss.nestedMap(_.symbol.asTerm), name == nme.CONSTRUCTOR)
776776
val resType = ctx.effectiveResultType(sym, typeParams, tpt.tpe)
777-
sym.info = ctx.methodType(typeParams, valueParamss, resType)
777+
sym.info = ctx.termLambda(typeParams, valueParamss, resType, sym)
778778
DefDef(tparams, vparamss, tpt)
779779
case VALDEF =>
780780
val tpt = readTpt()(localCtx)

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
167167
"<notype>"
168168
case NoPrefix =>
169169
"<noprefix>"
170-
case tp: MethodType =>
170+
case tp: TermLambda =>
171171
changePrec(GlobalPrec) {
172172
("(" + (if (tp.isErasedMethod) "erased " else "")
173173
+ (if (tp.isImplicitMethod) "implicit " else "")

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
208208
": " ~ toText(tp.memberProto) ~ " }"
209209
case tp: ViewProto =>
210210
return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType)
211-
case tp @ FunProto(args, resultType, _) =>
212-
val argsText = args match {
211+
case tp: FunProto =>
212+
val argsText = tp.args match {
213213
case dummyTreeOfType(tp) :: Nil if !(tp isRef defn.NullClass) => "null: " ~ toText(tp)
214-
case _ => toTextGlobal(args, ", ")
214+
case _ => toTextGlobal(tp.args, ", ")
215215
}
216-
return "FunProto(" ~ argsText ~ "):" ~ toText(resultType)
216+
return "FunProto(" ~ argsText ~ "):" ~ toText(tp.resultType)
217217
case tp: IgnoredProto =>
218218
return "?"
219219
case tp @ PolyProto(targs, resType) =>
@@ -593,7 +593,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
593593
if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY,
594594
sym.annotations map (_.tree))
595595

596-
protected def optAscription[T >: Untyped](tpt: Tree[T]) = optText(tpt)(": " ~ _)
596+
protected def optAscription[T >: Untyped](tpt: Tree[T])(implicit ctx: Context) =
597+
if (tpt.typeOpt.isInstanceOf[TypeBounds]) toText(tpt)
598+
else optText(tpt)(": " ~ _)
597599

598600
private def idText(tree: untpd.Tree): Text = {
599601
if ((ctx.settings.uniqid.value || Printer.debugPrintUnique) && tree.hasType && tree.symbol.exists) s"#${tree.symbol.id}" else ""
@@ -641,7 +643,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
641643
protected def defDefToText[T >: Untyped](tree: DefDef[T]): Text = {
642644
import untpd.{modsDeco => _, _}
643645
dclTextOr(tree) {
644-
val prefix = modText(tree.mods, tree.symbol, keywordStr("def")) ~~ valDefText(nameIdText(tree))
646+
val keyword = if (tree.symbol.isType) "type" else "def"
647+
val prefix = modText(tree.mods, tree.symbol, keywordStr(keyword)) ~~ valDefText(nameIdText(tree))
645648
withEnclosingDef(tree) {
646649
addVparamssText(prefix ~ tparamsText(tree.tparams), tree.vparamss) ~ optAscription(tree.tpt) ~
647650
optText(tree.rhs)(" = " ~ _)

compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ class StoreReporter(outer: Reporter) extends Reporter {
2323
protected[this] var infos: mutable.ListBuffer[MessageContainer] = null
2424

2525
def doReport(m: MessageContainer)(implicit ctx: Context): Unit = {
26-
typr.println(s">>>> StoredError: ${m.message}") // !!! DEBUG
26+
typr.println(s">>>> StoredError: ${m.message}")
27+
// new AssertionError().printStackTrace() // DEBUG
2728
if (infos == null) infos = new mutable.ListBuffer
2829
infos += m
2930
}

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -540,35 +540,37 @@ object Erasure {
540540
* with more than `MaxImplementedFunctionArity` parameters to ise a single
541541
* parameter of type `[]Object`.
542542
*/
543-
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = {
544-
val restpe =
545-
if (sym.isConstructor) defn.UnitType
546-
else sym.info.resultType
547-
var vparamss1 = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil
548-
var rhs1 = ddef.rhs match {
549-
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
550-
case _ => ddef.rhs
551-
}
552-
if (sym.isAnonymousFunction && vparamss1.head.length > MaxImplementedFunctionArity) {
553-
val bunchedParam = ctx.newSymbol(sym, nme.ALLARGS, Flags.TermParam, JavaArrayType(defn.ObjectType))
554-
def selector(n: Int) = ref(bunchedParam)
555-
.select(defn.Array_apply)
556-
.appliedTo(Literal(Constant(n)))
557-
val paramDefs = vparamss1.head.zipWithIndex.map {
558-
case (paramDef, idx) =>
559-
assignType(untpd.cpy.ValDef(paramDef)(rhs = selector(idx)), paramDef.symbol)
543+
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) =
544+
if (sym.isType) EmptyTree
545+
else {
546+
val restpe =
547+
if (sym.isConstructor) defn.UnitType
548+
else sym.info.resultType
549+
var vparamss1 = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil
550+
var rhs1 = ddef.rhs match {
551+
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
552+
case _ => ddef.rhs
560553
}
561-
vparamss1 = (tpd.ValDef(bunchedParam) :: Nil) :: Nil
562-
rhs1 = untpd.Block(paramDefs, rhs1)
554+
if (sym.isAnonymousFunction && vparamss1.head.length > MaxImplementedFunctionArity) {
555+
val bunchedParam = ctx.newSymbol(sym, nme.ALLARGS, Flags.TermParam, JavaArrayType(defn.ObjectType))
556+
def selector(n: Int) = ref(bunchedParam)
557+
.select(defn.Array_apply)
558+
.appliedTo(Literal(Constant(n)))
559+
val paramDefs = vparamss1.head.zipWithIndex.map {
560+
case (paramDef, idx) =>
561+
assignType(untpd.cpy.ValDef(paramDef)(rhs = selector(idx)), paramDef.symbol)
562+
}
563+
vparamss1 = (tpd.ValDef(bunchedParam) :: Nil) :: Nil
564+
rhs1 = untpd.Block(paramDefs, rhs1)
565+
}
566+
vparamss1 = vparamss1.mapConserve(_.filterConserve(!_.symbol.is(Flags.Erased)))
567+
val ddef1 = untpd.cpy.DefDef(ddef)(
568+
tparams = Nil,
569+
vparamss = vparamss1,
570+
tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)),
571+
rhs = rhs1)
572+
super.typedDefDef(ddef1, sym)
563573
}
564-
vparamss1 = vparamss1.mapConserve(_.filterConserve(!_.symbol.is(Flags.Erased)))
565-
val ddef1 = untpd.cpy.DefDef(ddef)(
566-
tparams = Nil,
567-
vparamss = vparamss1,
568-
tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)),
569-
rhs = rhs1)
570-
super.typedDefDef(ddef1, sym)
571-
}
572574

573575
override def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = {
574576
val xxl = defn.isXXLFunctionClass(tree.typeOpt.typeSymbol)

compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ class ResolveSuper extends MiniPhase with IdentityDenotTransformer { thisPhase =
8080
}
8181

8282
override def transformDefDef(ddef: DefDef)(implicit ctx: Context) = {
83-
val meth = ddef.symbol.asTerm
83+
val meth = ddef.symbol
8484
if (meth.isSuperAccessor && !meth.is(Deferred)) {
8585
assert(ddef.rhs.isEmpty)
8686
val cls = meth.owner.asClass
8787
val ops = new MixinOps(cls, thisPhase)
8888
import ops._
89-
polyDefDef(meth, forwarder(rebindSuper(cls, meth)))
89+
polyDefDef(meth.asTerm, forwarder(rebindSuper(cls, meth)))
9090
}
9191
else ddef
9292
}

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,10 +300,12 @@ class TreeChecker extends Phase with SymTransformer {
300300
tree
301301
}
302302

303-
/** Check that all methods have MethodicType */
304-
def isMethodType(pt: Type)(implicit ctx: Context): Boolean = pt match {
305-
case at: AnnotatedType => isMethodType(at.parent)
306-
case _: MethodicType => true // MethodType, ExprType, PolyType
303+
/** Check that all methods have LambdaType or ExprType */
304+
def isDefType(tp: Type)(implicit ctx: Context): Boolean = tp match {
305+
case _: MethodicType => true // MethodType, ExprType, PolyType
306+
case _: LambdaType => true
307+
case tp: TypeBounds => isDefType(tp.hi)
308+
case tp: AnnotatedType => isDefType(tp.parent)
307309
case _ => false
308310
}
309311

@@ -406,7 +408,7 @@ class TreeChecker extends Phase with SymTransformer {
406408
})
407409

408410
val tpdTree = super.typedDefDef(ddef, sym)
409-
assert(isMethodType(sym.info), i"wrong type, expect a method type for ${sym.fullName}, but found: ${sym.info}")
411+
assert(isDefType(sym.info), i"wrong type, expect a method type for ${sym.fullName}, but found: ${sym.info}")
410412
tpdTree
411413
}
412414
}

0 commit comments

Comments
 (0)