From 6ed666c4be5bc4904c926a265d711b85f729d4b3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Dec 2013 18:34:00 +0100 Subject: Typing by-name parameters with ExprTypes. To avoid duplication between by-name parameters and expr types, we treat by-name parameters as as having ExprType. A part of this is introducing ByNameTypeTree, a specific tree class for => T types. --- src/dotty/tools/dotc/ast/Desugar.scala | 5 +---- src/dotty/tools/dotc/ast/TreeInfo.scala | 7 ------- src/dotty/tools/dotc/ast/Trees.scala | 15 +++++++++++++++ src/dotty/tools/dotc/ast/tpd.scala | 3 +++ src/dotty/tools/dotc/ast/untpd.scala | 1 + src/dotty/tools/dotc/core/Definitions.scala | 4 ++-- src/dotty/tools/dotc/core/Types.scala | 4 ---- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 6 ++---- src/dotty/tools/dotc/parsing/Parsers.scala | 4 ++-- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 5 +++-- src/dotty/tools/dotc/typer/Applications.scala | 4 ++-- src/dotty/tools/dotc/typer/EtaExpansion.scala | 2 +- src/dotty/tools/dotc/typer/Implicits.scala | 2 +- src/dotty/tools/dotc/typer/Inferencing.scala | 2 +- src/dotty/tools/dotc/typer/Typer.scala | 6 ++++++ 15 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index bf32ffcd9..e6c43acbb 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -651,10 +651,7 @@ object desugar { Select(t, op) } case PrefixOp(op, t) => - if ((ctx.mode is Mode.Type) && op == nme.ARROWkw) - AppliedTypeTree(ref(defn.ByNameParamClass.typeRef), t) - else - Select(t, nme.UNARY_PREFIX ++ op) + Select(t, nme.UNARY_PREFIX ++ op) case Parens(t) => t case Tuple(ts) => diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 0d3f1970f..29ff492d4 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -176,13 +176,6 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => case _ => false } - /** Is tpt a by-name parameter type of the form => T? */ - def isByNameParamType(tpt: Tree)(implicit ctx: Context) = tpt match { - case tpt: TypeTree => tpt.typeOpt isRef defn.ByNameParamClass - case AppliedTypeTree(Select(_, tpnme.BYNAME_PARAM_CLASS), _) => true - case _ => false - } - /** Is name a left-associative operator? */ def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.last != ':') diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 183e5a2e4..12d71e32f 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -620,6 +620,12 @@ object Trees { def forwardTo = tpt } + /** => T */ + case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T]) + extends Tree[T] { + type ThisTree[-T >: Untyped] = ByNameTypeTree[T] + } + /** >: lo <: hi */ case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T]) extends Tree[T] { @@ -841,6 +847,7 @@ object Trees { type OrTypeTree = Trees.OrTypeTree[T] type RefinedTypeTree = Trees.RefinedTypeTree[T] type AppliedTypeTree = Trees.AppliedTypeTree[T] + type ByNameTypeTree = Trees.ByNameTypeTree[T] type TypeBoundsTree = Trees.TypeBoundsTree[T] type Bind = Trees.Bind[T] type Alternative = Trees.Alternative[T] @@ -1014,6 +1021,10 @@ object Trees { case tree: AppliedTypeTree if (tpt eq tree.tpt) && (args eq tree.args) => tree case _ => finalize(tree, untpd.AppliedTypeTree(tpt, args)) } + def ByNameTypeTree(tree: Tree, result: Tree): ByNameTypeTree = tree match { + case tree: ByNameTypeTree if (result eq tree.result) => tree + case _ => finalize(tree, untpd.ByNameTypeTree(result)) + } def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree): TypeBoundsTree = tree match { case tree: TypeBoundsTree if (lo eq tree.lo) && (hi eq tree.hi) => tree case _ => finalize(tree, untpd.TypeBoundsTree(lo, hi)) @@ -1128,6 +1139,8 @@ object Trees { cpy.RefinedTypeTree(tree, transform(tpt), transformSub(refinements)) case AppliedTypeTree(tpt, args) => cpy.AppliedTypeTree(tree, transform(tpt), transform(args)) + case ByNameTypeTree(result) => + cpy.ByNameTypeTree(tree, transform(result)) case TypeBoundsTree(lo, hi) => cpy.TypeBoundsTree(tree, transform(lo), transform(hi)) case Bind(name, body) => @@ -1233,6 +1246,8 @@ object Trees { this(this(x, tpt), refinements) case AppliedTypeTree(tpt, args) => this(this(x, tpt), args) + case ByNameTypeTree(result) => + this(x, result) case TypeBoundsTree(lo, hi) => this(this(x, lo), hi) case Bind(name, body) => diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 8d079fa72..3e2b0d7f9 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -196,6 +196,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = untpd.AppliedTypeTree(tpt, args).withType(tpt.tpe.appliedTo(args map (_.tpe))).checked + def ByNameTypeTree(result: Tree)(implicit ctx: Context): ByNameTypeTree = + untpd.ByNameTypeTree(result).withType(ExprType(result.tpe)).checked + def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = untpd.TypeBoundsTree(lo, hi).withType(TypeBounds(lo.tpe, hi.tpe)).checked diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index afb3ba63a..3fb21feb7 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -79,6 +79,7 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] { def OrTypeTree(left: Tree, right: Tree): OrTypeTree = new OrTypeTree(left, right) def RefinedTypeTree(tpt: Tree, refinements: List[Tree]): RefinedTypeTree = new RefinedTypeTree(tpt, refinements) def AppliedTypeTree(tpt: Tree, args: List[Tree]): AppliedTypeTree = new AppliedTypeTree(tpt, args) + def ByNameTypeTree(result: Tree): ByNameTypeTree = new ByNameTypeTree(result) def TypeBoundsTree(lo: Tree, hi: Tree): TypeBoundsTree = new TypeBoundsTree(lo, hi) def Bind(name: Name, body: Tree): Bind = new Bind(name, body) def Alternative(trees: List[Tree]): Alternative = new Alternative(trees) diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index a2527c9f2..a24bdd7d8 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -182,7 +182,7 @@ class Definitions(implicit ctx: Context) { lazy val BoxedFloatClass = requiredClass("java.lang.Float") lazy val BoxedDoubleClass = requiredClass("java.lang.Double") - lazy val ByNameParamClass = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, AnyType) + lazy val ByNameParamClass2x = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, AnyType) lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, AnyType) lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, SeqType) @@ -451,7 +451,7 @@ class Definitions(implicit ctx: Context) { AnyRefAlias, RepeatedParamClass, JavaRepeatedParamClass, - ByNameParamClass, + ByNameParamClass2x, AnyClass, AnyValClass, NullClass, diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index f7308c1f1..93db5d624 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -550,10 +550,6 @@ object Types { case _ => this } - /** Widen from => T to T */ - final def widenByName(implicit ctx: Context): Type = - if (this isRef defn.ByNameParamClass) this.typeArgs.head else this - /** Widen type if it is unstable (i.e. an EpxprType, or Termref to unstable symbol */ final def widenIfUnstable(implicit ctx: Context): Type = this match { case tp: ExprType => tp.resultType.widenIfUnstable diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 2f063fd4c..e7a87b220 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -638,10 +638,8 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: } else TypeRef(pre, sym.name.asTypeName) val args = until(end, readTypeRef) -// if (args.nonEmpty) { // DEBUG -// println(s"reading app type $tycon $args") -// } - tycon.appliedTo(args) + if (sym == defn.ByNameParamClass2x) ExprType(args.head) + else tycon.appliedTo(args) case TYPEBOUNDStpe => TypeBounds(readTypeRef(), readTypeRef()) case REFINEDtpe => diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 85289ee0f..f3f87daff 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -647,7 +647,7 @@ object Parsers { atPos(start, in.skipToken()) { Function(ts, typ()) } else { for (t <- ts) - if (isByNameParamType(t)) + if (t.isInstanceOf[ByNameTypeTree]) syntaxError("no by-name parameter type allowed here", t.pos) val tuple = atPos(start) { makeTupleOrParens(ts) } infixTypeRest(refinedTypeRest(withTypeRest(simpleTypeRest(tuple)))) @@ -748,7 +748,7 @@ object Parsers { /** FunArgType ::= ArgType | `=>' ArgType */ val funArgType = () => - if (in.token == ARROW) atPos(in.skipToken()) { PrefixOp(nme.ARROWkw, argType()) } + if (in.token == ARROW) atPos(in.skipToken()) { ByNameTypeTree(argType()) } else argType() /** ParamType ::= FunArgType | ArgType `*' diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 3636731aa..df9986d5f 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -99,7 +99,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { val cls = tycon.typeSymbol if (cls.typeParams.length == args.length) { if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*" - if (cls == defn.ByNameParamClass) return "=> " ~ toText(args.head) if (defn.FunctionClasses contains cls) return toTextFunction(args) if (defn.TupleClasses contains cls) return toTextTuple(args) } @@ -112,8 +111,10 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case _ => nameString(tp.symbol) } } + case ExprType(result) => + return "=> " ~ toText(result) case typer.Inferencing.FunProto(args, resultType, _) => - "funproto(" ~ toTextGlobal(args, ", ") ~ "):" ~ toText(resultType) + return "funproto(" ~ toTextGlobal(args, ", ") ~ "):" ~ toText(resultType) case _ => } super.toText(tp) diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 860a7be80..9efa7d49e 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -360,7 +360,7 @@ trait Applications extends Compatibility { self: Typer => init() def addArg(arg: Tree, formal: Type): Unit = - typedArgBuf += adaptInterpolated(arg, formal.widenByName) + typedArgBuf += adaptInterpolated(arg, formal.widenExpr) def makeVarArg(n: Int, elemFormal: Type): Unit = { val args = typedArgBuf.takeRight(n).toList @@ -433,7 +433,7 @@ trait Applications extends Compatibility { self: Typer => /** Subclass of Application for type checking an Apply node with untyped arguments. */ class ApplyToUntyped(app: untpd.Apply, fun: Tree, methRef: TermRef, proto: FunProto, resultType: Type)(implicit ctx: Context) extends TypedApply(app, fun, methRef, proto.args, resultType) { - def typedArg(arg: untpd.Tree, formal: Type): TypedArg = proto.typedArg(arg, formal.widenByName) + def typedArg(arg: untpd.Tree, formal: Type): TypedArg = proto.typedArg(arg, formal.widenExpr) def treeToArg(arg: Tree): untpd.Tree = untpd.TypedSplice(arg) } diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala index 782e5382f..16a02ba5c 100644 --- a/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -58,7 +58,7 @@ object EtaExpansion { methType match { case MethodType(paramNames, paramTypes) => (args, paramNames, paramTypes).zipped map { (arg, name, tp) => - if (tp isRef defn.ByNameParamClass) arg + if (tp.isInstanceOf[ExprType]) arg else liftArg(defs, arg, if (name contains '$') "" else name.toString + "$") } case _ => diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index b32535167..3878e5235 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -263,7 +263,7 @@ trait Implicits { self: Typer => */ def inferImplicit(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context): SearchResult = track("inferImplicit") { ctx.traceIndented(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", show = true) { - assert(!(pt isRef defn.ByNameParamClass)) + assert(!pt.isInstanceOf[ExprType]) val isearch = if (ctx.settings.explaintypes.value) new ExplainedImplicitSearch(pt, argument, pos) else new ImplicitSearch(pt, argument, pos) diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 81e03f696..c306b07f3 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -30,7 +30,7 @@ object Inferencing { * 3. there is an implicit conversion from `tp` to `pt`. */ def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean = - tp.widenByName <:< pt.widenByName || viewExists(tp, pt) + tp.widenExpr <:< pt.widenExpr || viewExists(tp, pt) /** Test compatibility after normalization in a fresh typerstate. */ def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = { diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 54a299291..99d5f6b98 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -707,6 +707,11 @@ class Typer extends Namer with Applications with Implicits { cpy.AppliedTypeTree(tree, tpt1, args1) withType tpt1.tpe.appliedTo(args1.tpes) } + def typedByNameTypeTree(tree: untpd.ByNameTypeTree)(implicit ctx: Context): ByNameTypeTree = track("typedByNameTypeTree") { + val result1 = typed(tree.result) + cpy.ByNameTypeTree(tree, result1) withType ExprType(result1.tpe) + } + def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = track("typedTypeBoundsTree") { val TypeBoundsTree(lo, hi) = desugar.typeBoundsTree(tree) val lo1 = typed(lo) @@ -875,6 +880,7 @@ class Typer extends Namer with Applications with Implicits { case tree: untpd.OrTypeTree => typedOrTypeTree(tree) case tree: untpd.RefinedTypeTree => typedRefinedTypeTree(tree) case tree: untpd.AppliedTypeTree => typedAppliedTypeTree(tree) + case tree: untpd.ByNameTypeTree => typedByNameTypeTree(tree) case tree: untpd.TypeBoundsTree => typedTypeBoundsTree(tree) case tree: untpd.Alternative => typedAlternative(tree, pt) case tree: untpd.Import => typedImport(tree, sym) -- cgit v1.2.3