aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-05-01 11:30:11 +0200
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-05-08 21:51:47 +0200
commit4ae473eff25335d2b6b0f5900eed55ffa5141d2a (patch)
tree6b3a120e9fcc98d45122dbae54a73ccacc1a1ca7 /src/dotty/tools/dotc
parent620b2f4435249cc651d31dbabcb3c902da3b160c (diff)
downloaddotty-4ae473eff25335d2b6b0f5900eed55ffa5141d2a.tar.gz
dotty-4ae473eff25335d2b6b0f5900eed55ffa5141d2a.tar.bz2
dotty-4ae473eff25335d2b6b0f5900eed55ffa5141d2a.zip
Tightening of rules for explicit types for implicit defs
1) We now demand that all implicit defs have an implicit type, not just class members. If we admitted implicit term members without explicit types, the rules and algorithms for dteremining eligible implicits would be greatly complicated (because there's always the danger that inferring the type by typechecking the rhs causes a cyclic reference). 2) We check for violations of this rule earlier, during type completion, in order to avoid cyclic references happening before we do the check.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala10
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala140
-rw-r--r--src/dotty/tools/dotc/typer/ReTyper.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala6
4 files changed, 77 insertions, 81 deletions
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index ae325af2a..5e52c5d7e 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -69,15 +69,6 @@ trait Checking {
defn.ObjectClass.typeRef
}
- /** Check that (return) type of implicit definition is not empty */
- def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = defTree.tpt match {
- case tpt: untpd.DerivedTypeTree =>
- case TypeTree(untpd.EmptyTree) =>
- val resStr = if (defTree.isInstanceOf[untpd.DefDef]) "result " else ""
- ctx.error(d"${resStr}type of implicit definition needs to be given explicitly", defTree.pos)
- case _ =>
- }
-
/** Check that a non-implicit parameter making up the first parameter section of an
* implicit conversion is not a singleton type.
*/
@@ -150,7 +141,6 @@ trait NoChecking extends Checking {
override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
override def checkLegalPrefix(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
override def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp
- override def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = ()
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = ()
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 2d4bf8099..c3f1dcc81 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -519,80 +519,92 @@ class Namer { typer: Typer =>
* defined symbol, given its final return type
*/
def valOrDefDefSig(mdef: ValOrDefDef, sym: Symbol, typeParams: List[Symbol], paramFn: Type => Type)(implicit ctx: Context): Type = {
- val pt =
- if (!mdef.tpt.isEmpty) WildcardType
- else {
- /** An type for this definition that might be inherited from elsewhere:
- * If this is a setter parameter, the corresponding getter type.
- * If this is a class member, the conjunction of all result types
- * of overridden methods.
- * NoType if neither case holds.
- */
- val inherited =
- if (sym.owner.isTerm) NoType
- else {
- // TODO: Look only at member of supertype instead?
- lazy val schema = paramFn(WildcardType)
- val site = sym.owner.thisType
- ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) =>
- val iRawInfo =
- cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info
- val iInstInfo = iRawInfo match {
- case iRawInfo: PolyType =>
- if (iRawInfo.paramNames.length == typeParams.length)
- iRawInfo.instantiate(typeParams map (_.typeRef))
- else NoType
- case _ =>
- if (typeParams.isEmpty) iRawInfo
- else NoType
- }
- val iResType = iInstInfo.finalResultType.asSeenFrom(site, cls)
- if (iResType.exists)
- typr.println(s"using inherited type; raw: $iRawInfo, inst: $iInstInfo, inherited: $iResType")
- tp & iResType
+ def inferredType = {
+ /** A type for this definition that might be inherited from elsewhere:
+ * If this is a setter parameter, the corresponding getter type.
+ * If this is a class member, the conjunction of all result types
+ * of overridden methods.
+ * NoType if neither case holds.
+ */
+ val inherited =
+ if (sym.owner.isTerm) NoType
+ else {
+ // TODO: Look only at member of supertype instead?
+ lazy val schema = paramFn(WildcardType)
+ val site = sym.owner.thisType
+ ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) =>
+ val iRawInfo =
+ cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info
+ val iInstInfo = iRawInfo match {
+ case iRawInfo: PolyType =>
+ if (iRawInfo.paramNames.length == typeParams.length)
+ iRawInfo.instantiate(typeParams map (_.typeRef))
+ else NoType
+ case _ =>
+ if (typeParams.isEmpty) iRawInfo
+ else NoType
}
+ val iResType = iInstInfo.finalResultType.asSeenFrom(site, cls)
+ if (iResType.exists)
+ typr.println(s"using inherited type; raw: $iRawInfo, inst: $iInstInfo, inherited: $iResType")
+ tp & iResType
}
+ }
- /** The proto-type to be used when inferring the result type from
- * the right hand side. This is `WildcardType` except if the definition
- * is a default getter. In that case, the proto-type is the type of
- * the corresponding parameter where bound parameters are replaced by
- * Wildcards.
- */
- def rhsProto = {
- val name = sym.asTerm.name
- val idx = name.defaultGetterIndex
- if (idx < 0) WildcardType
- else {
- val original = name.defaultGetterToMethod
- val meth: Denotation =
- if (original.isConstructorName && (sym.owner is ModuleClass))
- sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
- else
- ctx.defContext(sym).denotNamed(original)
- def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
- case params :: paramss1 =>
- if (idx < params.length) wildApprox(params(idx))
- else paramProto(paramss1, idx - params.length)
- case nil =>
- WildcardType
- }
- val defaultAlts = meth.altsWith(_.hasDefaultParams)
- if (defaultAlts.length == 1)
- paramProto(defaultAlts.head.info.widen.paramTypess, idx)
+ /** The proto-type to be used when inferring the result type from
+ * the right hand side. This is `WildcardType` except if the definition
+ * is a default getter. In that case, the proto-type is the type of
+ * the corresponding parameter where bound parameters are replaced by
+ * Wildcards.
+ */
+ def rhsProto = {
+ val name = sym.asTerm.name
+ val idx = name.defaultGetterIndex
+ if (idx < 0) WildcardType
+ else {
+ val original = name.defaultGetterToMethod
+ val meth: Denotation =
+ if (original.isConstructorName && (sym.owner is ModuleClass))
+ sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
else
+ ctx.defContext(sym).denotNamed(original)
+ def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
+ case params :: paramss1 =>
+ if (idx < params.length) wildApprox(params(idx))
+ else paramProto(paramss1, idx - params.length)
+ case nil =>
WildcardType
}
+ val defaultAlts = meth.altsWith(_.hasDefaultParams)
+ if (defaultAlts.length == 1)
+ paramProto(defaultAlts.head.info.widen.paramTypess, idx)
+ else
+ WildcardType
}
+ }
- // println(s"final inherited for $sym: ${inherited.toString}") !!!
- // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
- val rhsCtx = ctx.fresh addMode Mode.InferringReturnType
- def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion
- def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos)
- inherited orElse lhsType orElse WildcardType
+ // println(s"final inherited for $sym: ${inherited.toString}") !!!
+ // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
+ val rhsCtx = ctx.fresh addMode Mode.InferringReturnType
+ def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion
+ def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos)
+ if (inherited.exists) inherited
+ else {
+ if (sym is Implicit) {
+ val resStr = if (mdef.isInstanceOf[DefDef]) "result " else ""
+ ctx.error(d"${resStr}type of implicit definition needs to be given explicitly", mdef.pos)
+ sym.resetFlag(Implicit)
+ }
+ lhsType orElse WildcardType
}
+ }
+
+ val pt = mdef.tpt match {
+ case _: untpd.DerivedTypeTree => WildcardType
+ case TypeTree(untpd.EmptyTree) => inferredType
+ case _ => WildcardType
+ }
paramFn(typedAheadType(mdef.tpt, pt).tpe)
}
diff --git a/src/dotty/tools/dotc/typer/ReTyper.scala b/src/dotty/tools/dotc/typer/ReTyper.scala
index 8d8134781..76817fd16 100644
--- a/src/dotty/tools/dotc/typer/ReTyper.scala
+++ b/src/dotty/tools/dotc/typer/ReTyper.scala
@@ -59,6 +59,4 @@ class ReTyper extends Typer {
override def localTyper(sym: Symbol) = this
override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx
-
- override def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = ()
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index c79ecdf85..f4b52ce09 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -753,7 +753,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val ValDef(mods, name, tpt, rhs) = vdef
val mods1 = typedModifiers(mods, sym)
val tpt1 = typedType(tpt)
- if ((sym is Implicit) && sym.owner.isType) checkImplicitTptNonEmpty(vdef)
val rhs1 = rhs match {
case Ident(nme.WILDCARD) => rhs withType tpt1.tpe
case _ => typedExpr(rhs, tpt1.tpe)
@@ -766,10 +765,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val mods1 = typedModifiers(mods, sym)
val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef])
val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef])
- if (sym is Implicit) {
- if (sym.owner.isType) checkImplicitTptNonEmpty(ddef)
- checkImplicitParamsNotSingletons(vparamss1)
- }
+ if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1)
val tpt1 = typedType(tpt)
val rhs1 = typedExpr(rhs, tpt1.tpe)
assignType(cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1), sym)