aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/Main.scala4
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala12
-rw-r--r--src/dotty/tools/dotc/ast/untpd.scala45
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala45
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala4
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala31
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala4
-rw-r--r--src/dotty/tools/dotc/core/Types.scala26
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala2
-rw-r--r--src/dotty/tools/dotc/core/transform/Erasure.scala2
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala39
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala90
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala28
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala27
15 files changed, 214 insertions, 147 deletions
diff --git a/src/dotty/tools/dotc/Main.scala b/src/dotty/tools/dotc/Main.scala
index 955304dda..72f29fe6e 100644
--- a/src/dotty/tools/dotc/Main.scala
+++ b/src/dotty/tools/dotc/Main.scala
@@ -9,9 +9,7 @@ import core.Contexts.Context
import reporting.Reporter
/* To do:
- * - simplify hk types
- * - Don't open package objects from class files if they are present in source
- * - Revise the way classes are inherited - when not followed by [...] or (...),
+s * - Revise the way classes are inherited - when not followed by [...] or (...),
* assume the unparameterized type and forward type parameters as we do now for the synthetic head class.
*/
object Main extends Driver {
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index 0f1d1010a..027c3238d 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -226,7 +226,7 @@ object desugar {
def productConstr(n: Int) = {
val tycon = ref(defn.ProductNClass(n).typeRef)
val targs = vparamss.head map (_.tpt)
- New(AppliedTypeTree(tycon, targs), Nil)
+ AppliedTypeTree(tycon, targs)
}
// Case classes get a ProductN parent
@@ -241,7 +241,7 @@ object desugar {
moduleDef(
ModuleDef(
Modifiers(Synthetic), name.toTermName,
- Template(emptyConstructor, New(parentTpt, Nil) :: Nil, EmptyValDef, defs))).toList
+ Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs))).toList
// The companion object defifinitions, if a companion is needed, Nil otherwise.
// companion definitions include:
@@ -713,13 +713,15 @@ object desugar {
/** Create a class definition with the same info as this refined type.
* parent { refinements }
* ==>
- * class <refinement> extends parent { refinements }
+ * trait <refinement> extends parent { refinements }
*
+ * If the parent is missing, Object is assumed.
* The result is used for validity checking, is thrown away afterwards.
*/
def refinedTypeToClass(tree: RefinedTypeTree)(implicit ctx: Context): TypeDef = {
- val impl = Template(emptyConstructor, tree.tpt :: Nil, EmptyValDef, tree.refinements)
- TypeDef(Modifiers(), tpnme.REFINE_CLASS, impl)
+ val parent = if (tree.tpt.isEmpty) TypeTree(defn.ObjectType) else tree.tpt
+ val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, tree.refinements)
+ TypeDef(Modifiers(Trait), tpnme.REFINE_CLASS, impl)
}
/** If tree is a variable pattern, return its name and type, otherwise return None.
diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala
index 879393a0a..4aff9da5d 100644
--- a/src/dotty/tools/dotc/ast/untpd.scala
+++ b/src/dotty/tools/dotc/ast/untpd.scala
@@ -13,8 +13,16 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] {
// ----- Tree cases that exist in untyped form only ------------------
+ trait OpTree extends Tree {
+ def op: Name
+ override def isTerm = op.isTermName
+ override def isType = op.isTypeName
+ }
+
/** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice */
- case class TypedSplice(tree: tpd.Tree) extends Tree
+ case class TypedSplice(tree: tpd.Tree) extends ProxyTree {
+ def forwardTo = tree
+ }
/** mods object name impl */
case class ModuleDef(mods: Modifiers, name: TermName, impl: Template)
@@ -25,12 +33,20 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] {
case class SymbolLit(str: String) extends TermTree
case class InterpolatedString(id: TermName, strings: List[Literal], elems: List[Tree]) extends TermTree
- case class Function(args: List[Tree], body: Tree) extends Tree
- case class InfixOp(left: Tree, op: Name, right: Tree) extends Tree
- case class PostfixOp(od: Tree, op: Name) extends Tree
- case class PrefixOp(op: Name, od: Tree) extends Tree
- case class Parens(t: Tree) extends Tree
- case class Tuple(trees: List[Tree]) extends Tree
+ case class Function(args: List[Tree], body: Tree) extends Tree {
+ override def isTerm = body.isTerm
+ override def isType = body.isType
+ }
+ case class InfixOp(left: Tree, op: Name, right: Tree) extends OpTree
+ case class PostfixOp(od: Tree, op: Name) extends OpTree
+ case class PrefixOp(op: Name, od: Tree) extends OpTree
+ case class Parens(t: Tree) extends ProxyTree {
+ def forwardTo = t
+ }
+ case class Tuple(trees: List[Tree]) extends Tree {
+ override def isTerm = trees.isEmpty || trees.head.isTerm
+ override def isType = !isTerm
+ }
case class WhileDo(cond: Tree, body: Tree) extends TermTree
case class DoWhile(body: Tree, cond: Tree) extends TermTree
case class ForYield(enums: List[Tree], expr: Tree) extends TermTree
@@ -101,10 +117,19 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] {
* ==>
* (new pre.C).<init>[Ts](args1)...(args_n)
*/
- def New(tpt: Tree, argss: List[List[Tree]]): Tree = {
+ def New(tpt: Tree, argss: List[List[Tree]])(implicit ctx: Context): Tree = {
val (tycon, targs) = tpt match {
- case AppliedTypeTree(tycon, targs) => (tycon, targs)
- case _ => (tpt, Nil)
+ case AppliedTypeTree(tycon, targs) =>
+ (tycon, targs)
+ case TypedSplice(AppliedTypeTree(tycon, targs)) =>
+ (TypedSplice(tycon), targs map TypedSplice)
+ case TypedSplice(tpt1: Tree) =>
+ val argTypes = tpt1.tpe.typeArgs
+ val tycon = tpt1.tpe.withoutArgs(argTypes)
+ def wrap(tpe: Type) = TypeTree(tpe) withPos tpt.pos
+ (wrap(tycon), argTypes map wrap)
+ case _ =>
+ (tpt, Nil)
}
var prefix: Tree = Select(New(tycon), nme.CONSTRUCTOR)
if (targs.nonEmpty) prefix = TypeApply(prefix, targs)
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index a867253b7..ebe52d522 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -269,6 +269,9 @@ object SymDenotations {
/** Is this denotation a class? */
final def isClass: Boolean = isInstanceOf[ClassDenotation]
+ /** Is this denotation a non-trait class? */
+ final def isRealClass(implicit ctx: Context) = isClass && !is(Trait)
+
/** Cast to class denotation */
final def asClass: ClassDenotation = asInstanceOf[ClassDenotation]
@@ -446,7 +449,7 @@ object SymDenotations {
| ${owner.showLocated} where target is defined""".stripMargin)
else if (
!( isType // allow accesses to types from arbitrary subclasses fixes #4737
- || pre.baseType(cls).exists
+ || pre.baseTypeRef(cls).exists // ??? why not use derivesFrom ???
|| isConstructor
|| (owner is ModuleClass) // don't perform this check for static members
))
@@ -847,12 +850,12 @@ object SymDenotations {
private[this] var myBaseClasses: List[ClassSymbol] = null
private[this] var mySuperClassBits: BitSet = null
- /** Invalidate baseTypeCache and superClassBits on new run */
+ /** Invalidate baseTypeRefCache and superClassBits on new run */
private def checkBasesUpToDate()(implicit ctx: Context) =
- if (baseTypeValid != ctx.runId) {
- baseTypeCache = new java.util.HashMap[CachedType, Type]
+ if (baseTypeRefValid != ctx.runId) {
+ baseTypeRefCache = new java.util.HashMap[CachedType, Type]
mySuperClassBits = null
- baseTypeValid = ctx.runId
+ baseTypeRefValid = ctx.runId
}
private def computeBases(implicit ctx: Context): Unit = {
@@ -1062,18 +1065,18 @@ object SymDenotations {
raw.filterExcluded(excluded).asSeenFrom(pre).toDenot(pre)
}
- private[this] var baseTypeCache: java.util.HashMap[CachedType, Type] = null
- private[this] var baseTypeValid: RunId = NoRunId
+ private[this] var baseTypeRefCache: java.util.HashMap[CachedType, Type] = null
+ private[this] var baseTypeRefValid: RunId = NoRunId
- /** Compute tp.baseType(this) */
- final def baseTypeOf(tp: Type)(implicit ctx: Context): Type = {
+ /** Compute tp.baseTypeRef(this) */
+ final def baseTypeRefOf(tp: Type)(implicit ctx: Context): Type = {
def foldGlb(bt: Type, ps: List[Type]): Type = ps match {
- case p :: ps1 => foldGlb(bt & baseTypeOf(p), ps1)
+ case p :: ps1 => foldGlb(bt & baseTypeRefOf(p), ps1)
case _ => bt
}
- def computeBaseTypeOf(tp: Type): Type = {
+ def computeBaseTypeRefOf(tp: Type): Type = {
Stats.record("computeBaseTypeOf")
if (symbol.isStatic && tp.derivesFrom(symbol))
symbol.typeRef
@@ -1087,34 +1090,34 @@ object SymDenotations {
if (cdenot.superClassBits contains symbol.superId) foldGlb(NoType, tp.parents)
else NoType
case _ =>
- baseTypeOf(tp.underlying)
+ baseTypeRefOf(tp.underlying)
}
case tp: TypeProxy =>
- baseTypeOf(tp.underlying)
+ baseTypeRefOf(tp.underlying)
case AndType(tp1, tp2) =>
- baseTypeOf(tp1) & baseTypeOf(tp2)
+ baseTypeRefOf(tp1) & baseTypeRefOf(tp2)
case OrType(tp1, tp2) =>
- baseTypeOf(tp1) | baseTypeOf(tp2)
+ baseTypeRefOf(tp1) | baseTypeRefOf(tp2)
case _ =>
NoType
}
}
- /*>|>*/ ctx.debugTraceIndented(s"$tp.baseType($this)") /*<|<*/ {
+ /*>|>*/ ctx.debugTraceIndented(s"$tp.baseTypeRef($this)") /*<|<*/ {
tp match {
case tp: CachedType =>
checkBasesUpToDate()
- var basetp = baseTypeCache get tp
+ var basetp = baseTypeRefCache get tp
if (basetp == null) {
- baseTypeCache.put(tp, NoPrefix)
- basetp = computeBaseTypeOf(tp)
- baseTypeCache.put(tp, basetp)
+ baseTypeRefCache.put(tp, NoPrefix)
+ basetp = computeBaseTypeRefOf(tp)
+ baseTypeRefCache.put(tp, basetp)
} else if (basetp == NoPrefix) {
throw new CyclicReference(this)
}
basetp
case _ =>
- computeBaseTypeOf(tp)
+ computeBaseTypeRefOf(tp)
}
}
}
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index 9f742fcc2..e854e672f 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -150,6 +150,10 @@ class TypeApplications(val self: Type) extends AnyVal {
NoType
}
+ /** The base type including all type arguments of this type */
+ final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type =
+ self.baseTypeRef(base).appliedTo(baseTypeArgs(base))
+
/** Translate a type of the form From[T] to To[T], keep other types as they are.
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
*/
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index a714cdf35..0af6ebf97 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -405,7 +405,7 @@ class TypeComparer(initctx: Context) extends DotClass {
case _ =>
val cls2 = tp2.symbol
if (cls2.isClass) {
- val base = tp1.baseType(cls2)
+ val base = tp1.baseTypeRef(cls2)
if (base.exists && (base ne tp1)) return isSubType(base, tp2)
if ( cls2 == defn.SingletonClass && tp1.isStable
|| cls2 == defn.NotNullClass && tp1.isNotNull
@@ -720,7 +720,7 @@ class TypeComparer(initctx: Context) extends DotClass {
else isSubType(tp1, tp2) && isSubType(tp2, tp1)
/** The greatest lower bound of two types */
- def glb(tp1: Type, tp2: Type): Type =
+ def glb(tp1: Type, tp2: Type): Type = /*>|>*/ ctx.traceIndented(s"glb(${tp1.show}, ${tp2.show})", typr, show = true) /*<|<*/ {
if (tp1 eq tp2) tp1
else if (!tp1.exists) tp2
else if (!tp2.exists) tp1
@@ -743,6 +743,7 @@ class TypeComparer(initctx: Context) extends DotClass {
}
}
}
+ }
/** The greatest lower bound of a list types */
final def glb(tps: List[Type]): Type =
@@ -870,17 +871,10 @@ class TypeComparer(initctx: Context) extends DotClass {
/** Try to distribute `&` inside type, detect and handle conflicts */
private def distributeAnd(tp1: Type, tp2: Type): Type = tp1 match {
- case tp1 @ TypeBounds(lo1, hi1) =>
+ case tp1: TypeBounds =>
tp2 match {
- case tp2 @ TypeBounds(lo2, hi2) =>
- if ((lo1 eq hi1) && (lo2 eq hi2)) {
- val v = tp1 commonVariance tp2
- if (v > 0) return TypeAlias(hi1 & hi2, v)
- if (v < 0) return TypeAlias(lo1 | lo2, v)
- }
- TypeBounds(lo1 | lo2, hi1 & hi2)
- case _ =>
- andConflict(tp1, tp2)
+ case tp2: TypeBounds => tp1 & tp2
+ case _ => andConflict(tp1, tp2)
}
case tp1: ClassInfo =>
tp2 match {
@@ -944,17 +938,10 @@ class TypeComparer(initctx: Context) extends DotClass {
/** Try to distribute `|` inside type, detect and handle conflicts */
private def distributeOr(tp1: Type, tp2: Type): Type = tp1 match {
- case tp1 @ TypeBounds(lo1, hi1) =>
+ case tp1: TypeBounds =>
tp2 match {
- case tp2 @ TypeBounds(lo2, hi2) =>
- if ((lo1 eq hi1) && (lo2 eq hi2)) {
- val v = tp1 commonVariance tp2
- if (v > 0) return TypeAlias(hi1 | hi2, v)
- if (v < 0) return TypeAlias(lo1 & lo2, v)
- }
- TypeBounds(lo1 & lo2, hi1 | hi2)
- case _ =>
- orConflict(tp1, tp2)
+ case tp2: TypeBounds => tp1 | tp2
+ case _ => orConflict(tp1, tp2)
}
case tp1: ClassInfo =>
tp2 match {
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 272e93dd3..ca69ab615 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -12,13 +12,13 @@ trait TypeOps { this: Context =>
def toPrefix(pre: Type, cls: Symbol, thiscls: ClassSymbol): Type = /*>|>*/ ctx.debugTraceIndented(s"toPrefix($pre, $cls, $thiscls)") /*<|<*/ {
if ((pre eq NoType) || (pre eq NoPrefix) || (cls is PackageClass))
tp
- else if (thiscls.derivesFrom(cls) && pre.baseType(thiscls).exists)
+ else if (thiscls.derivesFrom(cls) && pre.baseTypeRef(thiscls).exists)
pre match {
case SuperType(thispre, _) => thispre
case _ => pre
}
else
- toPrefix(pre.baseType(cls).normalizedPrefix, cls.owner, thiscls)
+ toPrefix(pre.baseTypeRef(cls).normalizedPrefix, cls.owner, thiscls)
}
/*>|>*/ ctx.conditionalTraceIndented(TypeOps.track , s"asSeen ${tp.show} from (${pre.show}, ${cls.show})", show = true) /*<|<*/ { // !!! DEBUG
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 6973af726..bc8d7dfd2 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -495,10 +495,12 @@ object Types {
this, that, alwaysMatchSimple = !ctx.phase.erasedTypes)
}
- /** The basetype of this type with given class symbol */
- final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ /*>|>*/ track("baseType") /*<|<*/ {
+ /** The basetype TypeRef of this type with given class symbol,
+ * but without including any type arguments
+ */
+ final def baseTypeRef(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseTypeRef $base")*/ /*>|>*/ track("baseTypeRef") /*<|<*/ {
base.denot match {
- case classd: ClassDenotation => classd.baseTypeOf(this)//widen.dealias)
+ case classd: ClassDenotation => classd.baseTypeRefOf(this)//widen.dealias)
case _ => NoType
}
}
@@ -1883,11 +1885,21 @@ object Types {
def contains(tp: Type)(implicit ctx: Context) = lo <:< tp && tp <:< hi
- def & (that: TypeBounds)(implicit ctx: Context): TypeBounds =
- derivedTypeBounds(this.lo | that.lo, this.hi & that.hi, this commonVariance that)
+ def & (that: TypeBounds)(implicit ctx: Context): TypeBounds = {
+ val v = this commonVariance that
+ if (v != 0 && (this.lo eq this.hi) && (that.lo eq that.hi))
+ if (v > 0) derivedTypeAlias(this.hi & that.hi, v)
+ else derivedTypeAlias(this.lo | that.lo, v)
+ else derivedTypeBounds(this.lo | that.lo, this.hi & that.hi, v)
+ }
- def | (that: TypeBounds)(implicit ctx: Context): TypeBounds =
- derivedTypeBounds(this.lo & that.lo, this.hi | that.hi, this commonVariance that)
+ def | (that: TypeBounds)(implicit ctx: Context): TypeBounds = {
+ val v = this commonVariance that
+ if (v == 0 && (this.lo eq this.hi) && (that.lo eq that.hi))
+ if (v > 0) derivedTypeAlias(this.hi | that.hi, v)
+ else derivedTypeAlias(this.lo & that.lo, v)
+ else derivedTypeBounds(this.lo & that.lo, this.hi | that.hi, v)
+ }
override def & (that: Type)(implicit ctx: Context) = that match {
case that: TypeBounds => this & that
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index 84b300a2a..c48e71052 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -631,7 +631,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
if (sym.owner != cls) {
val overriding = cls.decls.lookup(sym.name)
if (overriding.exists && overriding != sym) {
- val base = pre.baseType(sym.owner)
+ val base = pre.baseTypeWithArgs(sym.owner)
assert(base.exists)
pre = SuperType(pre, base)
}
diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala
index 34f339d9a..eaeb3c8e7 100644
--- a/src/dotty/tools/dotc/core/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/core/transform/Erasure.scala
@@ -51,7 +51,7 @@ object Erasure {
case AndType(tp1, tp2) =>
erasure(tp1)
case OrType(tp1, tp2) =>
- erasure(tp.baseType(lubClass(tp1, tp2)))
+ erasure(tp.baseTypeRef(lubClass(tp1, tp2)))
case tp: MethodType =>
tp.derivedMethodType(
tp.paramNames, tp.paramTypes.mapConserve(erasure), resultErasure(tp.resultType))
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index ceb4ebe42..37a0a3ce1 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -1050,9 +1050,12 @@ object Parsers {
case NEW =>
canApply = false
val start = in.skipToken()
- templateOrNew(emptyConstructor()) match {
- case impl: Template => atPos(start) { New(impl) }
- case nu => adjustStart(start) { nu }
+ val (impl, missingBody) = template(emptyConstructor())
+ impl.parents match {
+ case parent :: Nil if missingBody =>
+ if (parent.isType) ensureApplied(wrapNew(parent)) else parent
+ case _ =>
+ New(impl)
}
case _ =>
if (isLiteral) literal()
@@ -1825,38 +1828,36 @@ object Parsers {
/** ConstrApp ::= SimpleType {ParArgumentExprs}
*/
- val constrApp = () =>
- ensureApplied(parArgumentExprss(wrapNew(simpleType())))
+ val constrApp = () => {
+ val t = simpleType()
+ if (in.token == LPAREN) parArgumentExprss(wrapNew(t))
+ else t
+ }
/** Template ::= ConstrApps [TemplateBody] | TemplateBody
* ConstrApps ::= ConstrApp {`with' ConstrApp}
+ *
+ * @return a pair consisting of the template, and a boolean which indicates
+ * whether the template misses a body (i.e. no {...} part).
*/
- def template(constr: DefDef): Template = templateOrNew(constr) match {
- case impl: Template => impl
- case parent => Template(constr, parent :: Nil, EmptyValDef, Nil)
- }
-
- /** Same as template, but if {...} is missing and there's only one
- * parent return the parent instead of a template. Called from New.
- */
- def templateOrNew(constr: DefDef): Tree = {
+ def template(constr: DefDef): (Template, Boolean) = {
newLineOptWhenFollowedBy(LBRACE)
- if (in.token == LBRACE) templateBodyOpt(constr, Nil)
+ if (in.token == LBRACE) (templateBodyOpt(constr, Nil), false)
else {
val parents = tokenSeparated(WITH, constrApp)
newLineOptWhenFollowedBy(LBRACE)
- if (in.token != LBRACE && parents.length == 1) parents.head
- else templateBodyOpt(constr, parents)
+ val missingBody = in.token != LBRACE
+ (templateBodyOpt(constr, parents), missingBody)
}
}
/** TemplateOpt = [`extends' Template | TemplateBody]
*/
def templateOpt(constr: DefDef): Template =
- if (in.token == EXTENDS) { in.nextToken(); template(constr) }
+ if (in.token == EXTENDS) { in.nextToken(); template(constr)._1 }
else {
newLineOptWhenFollowedBy(LBRACE)
- if (in.token == LBRACE) template(constr)
+ if (in.token == LBRACE) template(constr)._1
else Template(constr, Nil, EmptyValDef, Nil).withPos(constr.pos.toSynthetic)
}
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 15dd0e9ad..4b43aa8b7 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -222,7 +222,7 @@ trait Applications extends Compatibility { self: Typer =>
val pre =
if (meth.isClassConstructor) {
// default getters for class constructors are found in the companion object
- mpre.baseType(cls) match {
+ mpre.baseTypeRef(cls) match {
case tp: TypeRef => ref(tp.prefix, cls.companionModule)
case _ => NoType
}
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 986ddf570..ea3109afa 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -410,13 +410,15 @@ object Inferencing {
def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
if (!tp.isStable) ctx.error(i"Prefix of type ${tp.widenIfUnstable} is not stable", pos)
- /** Check that `tp` is a class type with a stable prefix.
- * @return Underlying class type if type checks out OK, ObjectClass.typeRef if not.
+ /** Check that `tp` is a class type with a stable prefix. Also, if `isFirst` is
+ * false check that `tp` is a trait.
+ * @return `tp` itself if it is a class or trait ref, ObjectClass.typeRef if not.
*/
- def checkClassTypeWithStablePrefix(tp: Type, pos: Position)(implicit ctx: Context): TypeRef =
+ def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type =
tp.underlyingClassRef match {
- case tp: TypeRef =>
- checkStable(tp.prefix, pos)
+ case tref: TypeRef =>
+ checkStable(tref.prefix, pos)
+ if (traitReq && !(tref.symbol is Trait)) ctx.error(i"$tref is not a trait", pos)
tp
case _ =>
ctx.error(i"$tp is not a class type", pos)
@@ -441,45 +443,59 @@ object Inferencing {
case _ =>
}
- /** Ensure that first typeref in a list of parents points to a non-trait class.
- * If that's not already the case, add one.
+ /** Ensure that the first type in a list of parent types Ps points to a non-trait class.
+ * If that's not already the case, add one. The added class type CT is determined as follows.
+ * First, let C be the unique class such that
+ * - there is a parent P_i such that P_i derives from C, and
+ * - for every class D: If some parent P_j, j <= i derives from D, then C derives from D.
+ * Then, let CT be the smallest type which
+ * - has C as its class symbol, and
+ * - for all parents P_i: If P_i derives from C then P_i <:< CT.
*/
- def ensureFirstIsClass(prefs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = {
- def isRealClass(sym: Symbol) = sym.isClass && !(sym is Trait)
- def realClassParent(tref: TypeRef): TypeRef =
- if (isRealClass(tref.symbol)) tref
- else tref.info.parents match {
- case pref :: _ => if (isRealClass(pref.symbol)) pref else realClassParent(pref)
- case nil => defn.ObjectClass.typeRef
+ def ensureFirstIsClass(parents: List[Type])(implicit ctx: Context): List[Type] = {
+ def realClassParent(cls: Symbol): ClassSymbol =
+ if (!cls.isClass) defn.ObjectClass
+ else if (!(cls is Trait)) cls.asClass
+ else cls.asClass.classParents match {
+ case parentRef :: _ => realClassParent(parentRef.symbol)
+ case nil => defn.ObjectClass
}
- def improve(clsRef: TypeRef, parent: TypeRef): TypeRef = {
- val pclsRef = realClassParent(parent)
- if (pclsRef.symbol derivesFrom clsRef.symbol) pclsRef else clsRef
+ def improve(candidate: ClassSymbol, parent: Type): ClassSymbol = {
+ val pcls = realClassParent(parent.classSymbol)
+ if (pcls derivesFrom candidate) pcls else candidate
}
- prefs match {
- case pref :: _ if isRealClass(pref.symbol) => prefs
- case _ => (defn.ObjectClass.typeRef /: prefs)(improve) :: prefs
+ parents match {
+ case p :: _ if p.classSymbol.isRealClass => parents
+ case _ =>
+ val pcls = (defn.ObjectClass /: parents)(improve)
+ typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseTypeWithArgs pcls)}%, %")
+ val ptype = ctx.typeComparer.glb(
+ defn.ObjectType :: (parents map (_ baseTypeWithArgs pcls)))
+ ptype :: parents
}
}
- /** Forward bindings of all type parameters of `pcls`. That is, if the type parameter
- * if instantiated in a parent class, include its type binding in the current class.
+ /** Ensure that first parent tree refers to a real class. */
+ def ensureFirstIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match {
+ case p :: ps if p.tpe.classSymbol.isRealClass => parents
+ case _ =>
+ // add synthetic class type
+ val first :: _ = ensureFirstIsClass(parents.tpes)
+ TypeTree(checkFeasible(first, pos, i"\n in inferred parent $first")).withPos(pos) :: parents
+ }
+
+ /** Check that any top-level type arguments in this type are feasible, i.e. that
+ * their lower bound conforms to their upper cound. If a type argument is
+ * infeasible, issue and error and continue with upper bound.
*/
- def forwardTypeParams(pcls: ClassSymbol, cls: ClassSymbol, decls: Scope)(implicit ctx: Context): Unit = {
- for (tparam <- pcls.typeParams) {
- val argSym: Symbol = cls.thisType.member(tparam.name).symbol
- argSym.info match {
- case TypeAlias(TypeRef(ThisType(_), name)) =>
- val from = cls.thisType.member(name).symbol
- from.info match {
- case bounds: TypeBounds =>
- typr.println(s"forward ref $argSym $from $bounds")
- ctx.forwardRef(argSym, from, bounds, cls, decls)
- case _ =>
- }
- case _ =>
- }
- }
+ def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match {
+ case tp: RefinedType =>
+ tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where))
+ case tp @ TypeBounds(lo, hi) if !(lo <:< hi) =>
+ ctx.error(i"no type exists between low bound $lo and high bound $hi$where", pos)
+ tp.derivedTypeAlias(hi)
+ case _ =>
+ tp
}
/** Check that class does not define */
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 4f4e8300e..019432c61 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -409,11 +409,11 @@ class Namer { typer: Typer =>
/** The type of a parent constructor. Types constructor arguments
* only if parent type contains uninstantiated type parameters.
*/
- def parentType(constr: untpd.Tree)(implicit ctx: Context): Type =
- if (constr.isType) { // this case applies to desugared refined types
- typedAheadType(constr).tpe
+ def parentType(parent: untpd.Tree)(implicit ctx: Context): Type =
+ if (parent.isType) {
+ typedAheadType(parent).tpe
} else {
- val (core, targs) = stripApply(constr) match {
+ val (core, targs) = stripApply(parent) match {
case TypeApply(core, targs) => (core, targs)
case core => (core, Nil)
}
@@ -421,29 +421,27 @@ class Namer { typer: Typer =>
val targs1 = targs map (typedAheadType(_))
val ptype = typedAheadType(tpt).tpe appliedTo targs1.tpes
if (ptype.uninstantiatedTypeParams.isEmpty) ptype
- else typedAheadExpr(constr).tpe
+ else typedAheadExpr(parent).tpe
}
+ def checkedParentType(parent: untpd.Tree): Type = {
+ val ptype = parentType(parent)(ctx.fresh addMode Mode.InSuperCall)
+ checkClassTypeWithStablePrefix(ptype, parent.pos, traitReq = parent ne parents.head)
+ }
+
val selfInfo =
if (self.isEmpty) NoType
else if (cls is Module) cls.owner.thisType select sourceModule
else createSymbol(self)
// pre-set info, so that parent types can refer to type params
denot.info = ClassInfo(cls.owner.thisType, cls, Nil, decls, selfInfo)
- val parentTypes = parents map (parentType(_)(ctx.fresh addMode Mode.InSuperCall))
+ val parentTypes = ensureFirstIsClass(parents map checkedParentType)
val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls)
- val parentClsRefs =
- for ((parentRef, constr) <- parentRefs zip parents)
- yield checkClassTypeWithStablePrefix(parentRef, constr.pos)
- val normalizedParentClsRefs = ensureFirstIsClass(parentClsRefs)
+ typr.println(s"completing $denot, parents = $parents, parentTypes = $parentTypes, parentRefs = $parentRefs")
index(constr)
index(rest)(inClassContext(selfInfo))
- denot.info = ClassInfo(cls.owner.thisType, cls, normalizedParentClsRefs, decls, selfInfo)
- if (parentClsRefs ne normalizedParentClsRefs) {
- forwardTypeParams(normalizedParentClsRefs.head.symbol.asClass, cls, decls)
- typr.println(i"expanded parents of $denot: $normalizedParentClsRefs%, %")
- }
+ denot.info = ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo)
}
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 7e44f6a76..400a1407a 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -431,7 +431,7 @@ class Typer extends Namer with Applications with Implicits {
typed(cpy.Block(tree, clsDef :: Nil, New(Ident(x), Nil)), pt)
case _ =>
val tpt1 = typedType(tree.tpt)
- val clsref = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos)
+ val clsref = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos, traitReq = false)
// todo in a later phase: checkInstantiatable(cls, tpt1.pos)
cpy.New(tree, tpt1).withType(tpt1.tpe)
}
@@ -798,7 +798,7 @@ class Typer extends Namer with Applications with Implicits {
}
def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") {
- val tpt1 = typedAheadType(tree.tpt)
+ val tpt1 = if (tree.tpt.isEmpty) TypeTree(defn.ObjectType) else typedAheadType(tree.tpt)
val refineClsDef = desugar.refinedTypeToClass(tree)
val refineCls = createSymbol(refineClsDef).asClass
val TypeDef(_, _, Template(_, _, _, refinements1)) = typed(refineClsDef)
@@ -904,10 +904,31 @@ class Typer extends Namer with Applications with Implicits {
}
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") {
+ val superCtx = ctx.fresh addMode Mode.InSuperCall
+ def typedParent(tree: untpd.Tree): Tree =
+ if (tree.isType) typedType(tree)(superCtx)
+ else {
+ val result = typedExpr(tree)(superCtx)
+ if ((cls is Trait) && result.tpe.classSymbol.isRealClass)
+ ctx.error(s"trait may not call constructor of ${result.tpe.classSymbol}", tree.pos)
+ result
+ }
+
+ /** If this is a real class, make sure its first parent is a
+ * constructor call. Cannot simply use a type.
+ */
+ def ensureConstrCall(parents: List[Tree]): List[Tree] = {
+ val firstParent :: otherParents = parents
+ if (firstParent.isType && !(cls is Trait))
+ typed(untpd.New(untpd.TypedSplice(firstParent), Nil))(superCtx) :: otherParents
+ else parents
+ }
+
val TypeDef(mods, name, impl @ Template(constr, parents, self, body)) = cdef
val mods1 = typedModifiers(mods)
val constr1 = typed(constr).asInstanceOf[DefDef]
- val parents1 = parents mapconserve (typed(_)(ctx.fresh addMode Mode.InSuperCall))
+ val parents1 = ensureConstrCall(ensureFirstIsClass(
+ parents mapconserve typedParent, cdef.pos.toSynthetic))
val self1 = typed(self).asInstanceOf[ValDef]
val localDummy = ctx.newLocalDummy(cls, impl.pos)
val body1 = typedStats(body, localDummy)(inClassContext(self1.symbol))