aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-12-15 12:26:04 +0100
committerMartin Odersky <odersky@gmail.com>2013-12-15 12:26:04 +0100
commit99393624e3bf001a6c20c7615ac88ef4201a93f8 (patch)
tree1f3a8800364fcfb1001b08a335acdfe8fa288c01 /src
parent01db9a68e5e68f08c8236c23c905009789d51587 (diff)
downloaddotty-99393624e3bf001a6c20c7615ac88ef4201a93f8.tar.gz
dotty-99393624e3bf001a6c20c7615ac88ef4201a93f8.tar.bz2
dotty-99393624e3bf001a6c20c7615ac88ef4201a93f8.zip
Fixes related to SAM types.
1. Changes to SAMType extractor 2. Self names are no longer members of enclosing class 3. SAM-Type closures now print with their result type. 4. refactoring newSkolemSingleon ==> narrow
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala3
-rw-r--r--src/dotty/tools/dotc/core/Types.scala39
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala5
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala21
6 files changed, 50 insertions, 24 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 7a8df114b..b441da6b4 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -413,7 +413,7 @@ class TypeComparer(initctx: Context) extends DotClass {
val tparams = tp1.typeParams
val hkArgs = tp2.typeArgs
(hkArgs.length == tparams.length) && {
- val base = ctx.newSkolemSingleton(tp1)
+ val base = tp1.narrow
(tparams, hkArgs).zipped.forall { (tparam, hkArg) =>
base.memberInfo(tparam) <:< hkArg.bounds // TODO: base.memberInfo needed?
} &&
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index d9e5d7f96..cce6cc350 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -6,9 +6,6 @@ import util.SimpleMap
trait TypeOps { this: Context =>
- /** A prefix-less termRef to a new skolem symbol that has the given type as info */
- def newSkolemSingleton(underlying: Type) = TermRef(NoPrefix, newSkolem(underlying))
-
final def asSeenFrom(tp: Type, pre: Type, cls: Symbol, theMap: AsSeenFromMap): Type = {
def toPrefix(pre: Type, cls: Symbol, thiscls: ClassSymbol): Type = ctx.debugTraceIndented(s"toPrefix($pre, $cls, $thiscls)") {
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 1b05594e6..22d84c4e1 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -596,6 +596,9 @@ object Types {
def underlyingIfRepeated(implicit ctx: Context): Type =
this.translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
+ /** A prefix-less termRef to a new skolem symbol that has the given type as info */
+ def narrow(implicit ctx: Context): TermRef = TermRef(NoPrefix, ctx.newSkolem(this))
+
// ----- Normalizing typerefs over refined types ----------------------------
/** If this is a refinement type that has a refinement for `name` (which might be followed
@@ -1987,7 +1990,7 @@ object Types {
/** An extractor for single abstract method types.
* A type is a SAM type if it is a reference to a class or trait, which
*
- * - has a single abstract method with a non-dependent method type (ExprType
+ * - has a single abstract method with a method type (ExprType
* and PolyType not allowed!)
* - can be instantiated without arguments or with just () as argument.
*
@@ -1995,34 +1998,50 @@ object Types {
* denotation of the single abstract method as a member of the type.
*/
object SAMType {
- def isInstantiatable(tp: Type)(implicit ctx: Context): Boolean = tp match {
- case tp: TypeRef =>
- isInstantiatable(tp.info)
+ def zeroParamClass(tp: Type)(implicit ctx: Context): Type = tp match {
case tp: ClassInfo =>
def zeroParams(tp: Type): Boolean = tp match {
- case pt: PolyType => zeroParams(pt)
+ case pt: PolyType => zeroParams(pt.resultType)
case mt: MethodType => mt.paramTypes.isEmpty && !mt.resultType.isInstanceOf[MethodType]
case et: ExprType => true
case _ => false
}
- val noParamsNeeded = (tp.cls is Trait) || zeroParams(tp.cls.primaryConstructor.info) // !!! needs to be adapted once traits have parameters
- val selfTypeFeasible = tp.typeRef <:< tp.selfType
- noParamsNeeded && selfTypeFeasible
+ if ((tp.cls is Trait) || zeroParams(tp.cls.primaryConstructor.info)) tp // !!! needs to be adapted once traits have parameters
+ else NoType
+ case tp: TypeRef =>
+ zeroParamClass(tp.underlying)
case tp: RefinedType =>
- isInstantiatable(tp.underlying)
+ zeroParamClass(tp.underlying)
case tp: TypeVar =>
- isInstantiatable(tp.underlying)
+ zeroParamClass(tp.underlying)
+ case _ =>
+ NoType
+ }
+ def isInstantiatable(tp: Type)(implicit ctx: Context): Boolean = zeroParamClass(tp) match {
+ case cinfo: ClassInfo =>
+ val tref = tp.narrow
+ val selfType = cinfo.selfType.asSeenFrom(tref, cinfo.cls)
+ tref <:< selfType
case _ =>
false
}
def unapply(tp: Type)(implicit ctx: Context): Option[SingleDenotation] =
if (isInstantiatable(tp)) {
val absMems = tp.abstractTermMembers
+ // println(s"absMems: ${absMems map (_.show) mkString ", "}")
if (absMems.size == 1)
absMems.head.info match {
case mt: MethodType if !mt.isDependent => Some(absMems.head)
case _=> None
}
+ else if (tp isRef defn.PartialFunctionClass)
+ // To maintain compatibility with 2.x, we treat PartialFunction specially,
+ // pretending it is a SAM type. In the future it would be better to merge
+ // Function and PartialFunction, have Function1 contain a isDefinedAt method
+ // def isDefinedAt(x: T) = true
+ // and overwrite that method whenever the function body is a sequence of
+ // case clauses.
+ absMems.find(_.symbol.name == nme.apply)
else None
}
else None
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 9fc8cb513..d652feb51 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -201,9 +201,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
changePrec(GlobalPrec) {
"if " ~ toText(cond) ~ (" then" provided !cond.isInstanceOf[Parens]) ~~ toText(thenp) ~ optText(elsep)(" else " ~ _)
}
- case Closure(env, ref, _) =>
+ case Closure(env, ref, target) =>
"closure(" ~ (toTextGlobal(env, ", ") ~ " | " provided env.nonEmpty) ~
- toTextGlobal(ref) ~ ")"
+ toTextGlobal(ref) ~ (":" ~ toText(target) provided !target.isEmpty) ~ ")"
case Match(sel, cases) =>
if (sel.isEmpty) blockText(cases)
else changePrec(GlobalPrec) { toText(sel) ~ " match " ~ blockText(cases) }
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 3ddd3980b..9627065b2 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -229,7 +229,8 @@ class Namer { typer: Typer =>
def inClassContext(selfInfo: DotClass /* Should be Type | Symbol*/)(implicit ctx: Context): Context = {
val localCtx: Context = ctx.fresh.withNewScope
selfInfo match {
- case sym: Symbol if sym.exists && sym.name != nme.WILDCARD => localCtx.enter(sym)
+ case sym: Symbol if sym.exists && sym.name != nme.WILDCARD =>
+ localCtx.scope.asInstanceOf[MutableScope].enter(sym)
case _ =>
}
localCtx
@@ -409,7 +410,7 @@ class Namer { typer: Typer =>
tp & itpe
}
}
- // println(s"final inherited for $sym: ${inherited.toString}") !!!
+ // println(s"final inherited for $sym: ${inherited.toString}") !!!
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
def rhsType = adapt(typedAheadExpr(mdef.rhs), WildcardType).tpe.widen
def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index b2796f62f..dda50a323 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -506,16 +506,18 @@ class Typer extends Namer with Applications with Implicits {
val untpd.Function(args, body) = tree
if (ctx.mode is Mode.Type)
typed(cpy.AppliedTypeTree(tree,
- ref(defn.FunctionClass(args.length).typeRef), args :+ body), pt)
+ untpd.TypeTree(defn.FunctionClass(args.length).typeRef), args :+ body), pt)
else {
val params = args.asInstanceOf[List[ValDef]]
val protoFormals: List[Type] = pt match {
case _ if pt isRef defn.FunctionClass(params.length) =>
pt.typeArgs take params.length
case SAMType(meth) =>
+ // println(s"SAMType $pt")
val MethodType(_, paramTypes) = meth.info
paramTypes
case _ =>
+ // println(s"Neither fucntion nor SAM type $pt")
params map alwaysWildcardType
}
val inferredParams: List[untpd.ValDef] =
@@ -527,7 +529,7 @@ class Typer extends Namer with Applications with Implicits {
else {
val ofFun =
if (nme.syntheticParamNames(args.length + 1) contains param.name)
- s" for expanded function ${tree.show}"
+ s" of expanded function ${tree.show}"
else ""
errorType(s"missing parameter type for parameter ${param.name}$ofFun, expected = ${pt.show}", param.pos)
}
@@ -540,14 +542,21 @@ class Typer extends Namer with Applications with Implicits {
def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = track("typedClosure") {
val env1 = tree.env mapconserve (typed(_))
val meth1 = typedUnadapted(tree.meth)
- val ownType = meth1.tpe.widen match {
+ val (ownType, target) = meth1.tpe.widen match {
case mt: MethodType =>
- if (!mt.isDependent) mt.toFunctionType
- else throw new Error(s"internal error: cannot turn dependent method type $mt into closure, position = ${tree.pos}") // !!! DEBUG. Eventually, convert to an error?
+ pt match {
+ case SAMType(meth) if !defn.isFunctionType(pt) && mt <:< meth.info =>
+ if (!isFullyDefined(pt, ForceDegree.all))
+ ctx.error(i"result type of closure is an underspecified SAM type $pt", tree.pos)
+ (pt, TypeTree(pt))
+ case _ =>
+ if (!mt.isDependent) (mt.toFunctionType, EmptyTree)
+ else throw new Error(s"internal error: cannot turn dependent method type $mt into closure, position = ${tree.pos}") // !!! DEBUG. Eventually, convert to an error?
+ }
case tp =>
throw new Error(i"internal error: closing over non-method $tp, pos = ${tree.pos}")
}
- cpy.Closure(tree, env1, meth1, EmptyTree).withType(ownType)
+ cpy.Closure(tree, env1, meth1, target).withType(ownType)
}
def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context) = track("typedMatch") {