Skip to content

Commit 2669fac

Browse files
committed
First step towards Typer Reorganization.
Goal is better modularization and avoiding code duplication and divergence between Typer and tpd. As a first step, we split Inferencing into Inferencing, Checking, and ProtoTypes. Inferencing and Checking become Typer traits, while ProtoTypes remains a global object. Eventually: - we want to have a SimpleTyper, which does the main stuff in tpd, and can mixin either full checking or no checking. Each method in SimpleTyper takes an untyped tree (which is assumed to have typed arguments) and adds a toplevel type to that tree. The methods subsume the type-checking parts in Typers, except for (1) simplifications and expansions (2) computing prototypes and recursing with them into childtrees (3) adaptation. The method calls the necessary checking operations, which may however be stubbed out. The idea is already exercised in the typechecking code for Literal and New, except that for now it calls methods in tpd (they will become methods in SimpleTyper instead). - Typer should inherit from SimpleTyper, and forward all logic except for (1) - (3) to it. - tpd should call the simple typer it gets from ctx.typer - ctx.typer should be a SimpleTyper, not a complete one.
1 parent af3bfba commit 2669fac

File tree

10 files changed

+537
-503
lines changed

10 files changed

+537
-503
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,28 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
6868
}
6969

7070
def Literal(const: Constant)(implicit ctx: Context): Literal =
71-
untpd.Literal(const).withType(const.tpe).checked
71+
typedLiteral(untpd.Literal(const))
72+
73+
def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) =
74+
tree.withType {
75+
tree.const.tag match {
76+
case UnitTag => defn.UnitType
77+
case NullTag => defn.NullType
78+
case _ => ConstantType(tree.const)
79+
}
80+
}
7281

7382
def unitLiteral(implicit ctx: Context): Literal =
7483
Literal(Constant(()))
7584

7685
def New(tpt: Tree)(implicit ctx: Context): New =
7786
untpd.New(tpt).withType(tpt.tpe).checked
7887

88+
def typedNew(tree: untpd.New)(implicit ctx: Context) = {
89+
ctx.typer.checkClassTypeWithStablePrefix(tree.tpt.tpe, tree.tpt.pos, traitReq = false)
90+
tree.withType(tree.tpt.tpe)
91+
}
92+
7993
def New(tp: Type)(implicit ctx: Context): New = New(TypeTree(tp))
8094

8195
def Pair(left: Tree, right: Tree)(implicit ctx: Context): Pair =

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annot
77
import StdNames.nme
88
import ast.{Trees, untpd}
99
import typer.Namer
10-
import typer.Inferencing.{SelectionProto, ViewProto}
10+
import typer.ProtoTypes.{SelectionProto, ViewProto, FunProto}
1111
import Trees._
1212
import scala.annotation.switch
1313

@@ -120,7 +120,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
120120
}
121121
case ExprType(result) =>
122122
return "=> " ~ toText(result)
123-
case typer.Inferencing.FunProto(args, resultType, _) =>
123+
case FunProto(args, resultType, _) =>
124124
return "funproto(" ~ toTextGlobal(args, ", ") ~ "):" ~ toText(resultType)
125125
case _ =>
126126
}

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import ErrorReporting._
1919
import Trees._
2020
import Names._
2121
import StdNames._
22-
import Inferencing._
22+
import ProtoTypes._
2323
import EtaExpansion._
2424
import collection.mutable
2525
import reflect.ClassTag
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package dotty.tools
2+
package dotc
3+
package typer
4+
5+
import core._
6+
import ast._
7+
import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._
8+
import Trees._
9+
import Constants._
10+
import Scopes._
11+
import annotation.unchecked
12+
import util.Positions._
13+
import util.{Stats, SimpleMap}
14+
import util.common._
15+
import Decorators._
16+
import Uniques._
17+
import ErrorReporting.{errorType, InfoString}
18+
import config.Printers._
19+
import collection.mutable
20+
21+
trait Checking {
22+
23+
import tpd._
24+
25+
/** Check that type arguments `args` conform to corresponding bounds in `poly` */
26+
def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit =
27+
for ((arg, bounds) <- args zip poly.paramBounds) {
28+
def notConforms(which: String, bound: Type) =
29+
ctx.error(i"Type argument ${arg.tpe} does not conform to $which bound $bound", arg.pos)
30+
if (!(arg.tpe <:< bounds.hi)) notConforms("upper", bounds.hi)
31+
if (!(bounds.lo <:< arg.tpe)) notConforms("lower", bounds.lo)
32+
}
33+
34+
/** Check that type `tp` is stable.
35+
* @return The type itself
36+
*/
37+
def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
38+
if (!tp.isStable) ctx.error(i"Prefix of type ${tp.widenIfUnstable} is not stable", pos)
39+
40+
/** Check that `tp` is a class type with a stable prefix. Also, if `isFirst` is
41+
* false check that `tp` is a trait.
42+
* @return `tp` itself if it is a class or trait ref, ObjectClass.typeRef if not.
43+
*/
44+
def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type =
45+
tp.underlyingClassRef match {
46+
case tref: TypeRef =>
47+
checkStable(tref.prefix, pos)
48+
if (traitReq && !(tref.symbol is Trait)) ctx.error(i"$tref is not a trait", pos)
49+
tp
50+
case _ =>
51+
ctx.error(i"$tp is not a class type", pos)
52+
defn.ObjectClass.typeRef
53+
}
54+
55+
/** Check that (return) type of implicit definition is not empty */
56+
def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = defTree.tpt match {
57+
case TypeTree(original) if original.isEmpty =>
58+
val resStr = if (defTree.isInstanceOf[untpd.DefDef]) "result " else ""
59+
ctx.error(i"${resStr}type of implicit definition needs to be given explicitly", defTree.pos)
60+
case _ =>
61+
}
62+
63+
/** Check that a non-implicit parameter making up the first parameter section of an
64+
* implicit conversion is not a singleton type.
65+
*/
66+
def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = vparamss match {
67+
case (vparam :: Nil) :: _ if !(vparam.symbol is Implicit) =>
68+
if (vparam.tpt.tpe.isInstanceOf[SingletonType])
69+
ctx.error(s"implicit conversion may not have a parameter of singleton type", vparam.tpt.pos)
70+
case _ =>
71+
}
72+
73+
/** Check that any top-level type arguments in this type are feasible, i.e. that
74+
* their lower bound conforms to their upper cound. If a type argument is
75+
* infeasible, issue and error and continue with upper bound.
76+
*/
77+
def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match {
78+
case tp: RefinedType =>
79+
tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where))
80+
case tp @ TypeBounds(lo, hi) if !(lo <:< hi) =>
81+
ctx.error(i"no type exists between low bound $lo and high bound $hi$where", pos)
82+
tp.derivedTypeAlias(hi)
83+
case _ =>
84+
tp
85+
}
86+
87+
/** Check that class does not define */
88+
def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = {
89+
val seen = new mutable.HashMap[Name, List[Symbol]] {
90+
override def default(key: Name) = Nil
91+
}
92+
typr.println(i"check no double defs $cls")
93+
for (decl <- cls.info.decls) {
94+
for (other <- seen(decl.name)) {
95+
typr.println(i"conflict? $decl $other")
96+
if (decl.signature matches other.signature) {
97+
def doubleDefError(decl: Symbol, other: Symbol): Unit = {
98+
def ofType = if (decl.isType) "" else i": ${other.info}"
99+
def explanation =
100+
if (!decl.isSourceMethod) ""
101+
else "\n (both definitions have the same erased type signature)"
102+
ctx.error(i"$decl is already defined as $other$ofType$explanation", decl.pos)
103+
}
104+
if (decl is Synthetic) doubleDefError(other, decl)
105+
else doubleDefError(decl, other)
106+
}
107+
if ((decl is HasDefaultParams) && (other is HasDefaultParams)) {
108+
ctx.error(i"two or more overloaded variants of $decl have default arguments")
109+
decl resetFlag HasDefaultParams
110+
}
111+
}
112+
seen(decl.name) = decl :: seen(decl.name)
113+
}
114+
}
115+
116+
def checkInstantiatable(cls: ClassSymbol, pos: Position): Unit = {
117+
??? // to be done in later phase: check that class `cls` is legal in a new.
118+
}
119+
}

src/dotty/tools/dotc/typer/ErrorReporting.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package typer
55
import ast._
66
import core._
77
import Trees._
8-
import Types._, Inferencing._, Contexts._, Decorators._, Denotations._, Symbols._
8+
import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._
99
import Applications._, Implicits._
1010
import util.Positions._
1111
import printing.Showable

src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import Decorators._
2020
import Names._
2121
import StdNames._
2222
import Constants._
23-
import Inferencing._
2423
import Applications._
24+
import ProtoTypes._
2525
import ErrorReporting._
2626
import Hashable._
2727
import config.Config

0 commit comments

Comments
 (0)