aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-12-05 10:34:58 +0100
committerMartin Odersky <odersky@gmail.com>2016-12-17 18:34:27 +0100
commitbcc80ad1343a3ed01bef55f494d9658cf02226c6 (patch)
tree5fb2feecdf0df524128c72d14a6402fd6c547291 /compiler/src/dotty/tools
parent0336785a2280a4a1e51e739e9aac3d5015f7c16f (diff)
downloaddotty-bcc80ad1343a3ed01bef55f494d9658cf02226c6.tar.gz
dotty-bcc80ad1343a3ed01bef55f494d9658cf02226c6.tar.bz2
dotty-bcc80ad1343a3ed01bef55f494d9658cf02226c6.zip
Create implicit closures to math expected implicit functions
When the expected type is an implicit function, create an implicit closure to match it.
Diffstat (limited to 'compiler/src/dotty/tools')
-rw-r--r--compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala23
-rw-r--r--compiler/src/dotty/tools/dotc/ast/TreeInfo.scala12
-rw-r--r--compiler/src/dotty/tools/dotc/ast/untpd.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Implicits.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala33
7 files changed, 64 insertions, 27 deletions
diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
index ed32d2df9..3b1768ef5 100644
--- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
+++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -39,6 +39,10 @@ import dotty.tools.dotc.core.Names.TypeName
import scala.annotation.tailrec
class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Map[Symbol, Set[ClassSymbol]])(implicit ctx: Context) extends BackendInterface{
+ import Symbols.{toDenot, toClassDenot}
+ // Dotty deviation: Need to (re-)import implicit decorators here because otherwise
+ // they would be shadowed by the more deeply nested `symHelper` decorator.
+
type Symbol = Symbols.Symbol
type Type = Types.Type
type Tree = tpd.Tree
@@ -683,8 +687,6 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
else sym.enclosingClass(ctx.withPhase(ctx.flattenPhase.prev))
} //todo is handled specially for JavaDefined symbols in scalac
-
-
// members
def primaryConstructor: Symbol = toDenot(sym).primaryConstructor
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index 11f8b81eb..def2caabf 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -123,6 +123,13 @@ object desugar {
else vdef
}
+ def makeImplicitParameters(tpts: List[Tree], forPrimaryConstructor: Boolean)(implicit ctx: Context) =
+ for (tpt <- tpts) yield {
+ val paramFlags: FlagSet = if (forPrimaryConstructor) PrivateLocalParamAccessor else Param
+ val epname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName
+ ValDef(epname, tpt, EmptyTree).withFlags(paramFlags | Implicit)
+ }
+
/** Expand context bounds to evidence params. E.g.,
*
* def f[T >: L <: H : B](params)
@@ -143,19 +150,16 @@ object desugar {
val epbuf = new ListBuffer[ValDef]
def desugarContextBounds(rhs: Tree): Tree = rhs match {
case ContextBounds(tbounds, cxbounds) =>
- for (cxbound <- cxbounds) {
- val paramFlags: FlagSet = if (isPrimaryConstructor) PrivateLocalParamAccessor else Param
- val epname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName
- epbuf += ValDef(epname, cxbound, EmptyTree).withFlags(paramFlags | Implicit)
- }
+ for (cxbound <- cxbounds)
+ epbuf ++= makeImplicitParameters(cxbounds, isPrimaryConstructor)
tbounds
case PolyTypeTree(tparams, body) =>
cpy.PolyTypeTree(rhs)(tparams, desugarContextBounds(body))
case _ =>
rhs
}
- val tparams1 = tparams mapConserve { tdef =>
- cpy.TypeDef(tdef)(rhs = desugarContextBounds(tdef.rhs))
+ val tparams1 = tparams mapConserve { tparam =>
+ cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam))
}
val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList)
@@ -679,6 +683,11 @@ object desugar {
Function(param :: Nil, Block(vdefs, body))
}
+ def makeImplicitFunction(formals: List[Type], body: Tree)(implicit ctx: Context): Tree = {
+ val params = makeImplicitParameters(formals.map(TypeTree), forPrimaryConstructor = false)
+ new ImplicitFunction(params, body)
+ }
+
/** Add annotation with class `cls` to tree:
* tree @cls
*/
diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
index ae7c93784..da83d0644 100644
--- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -290,6 +290,16 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
case _ => false
}
+ /** Is `tree` an implicit function or closure, possibly nested in a block? */
+ def isImplicitClosure(tree: Tree)(implicit ctx: Context): Boolean = unsplice(tree) match {
+ case Function((param: untpd.ValDef) :: _, _) => param.mods.is(Implicit)
+ case Closure(_, meth, _) => true
+ case Block(Nil, expr) => isImplicitClosure(expr)
+ case Block(DefDef(nme.ANON_FUN, _, (param :: _) :: _, _, _) :: Nil, _: Closure) =>
+ param.mods.is(Implicit)
+ case _ => false
+ }
+
// todo: fill with other methods from TreeInfo that only apply to untpd.Tree's
}
@@ -507,8 +517,6 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
}
}
- def isClosure(tree: Tree) = closure.unapply(tree).isDefined
-
/** If tree is a closure, its body, otherwise tree itself */
def closureBody(tree: Tree)(implicit ctx: Context): Tree = tree match {
case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, Closure(_, _, _)) => meth.rhs
diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala
index 9707770d5..77755da81 100644
--- a/compiler/src/dotty/tools/dotc/ast/untpd.scala
+++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala
@@ -55,7 +55,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
}
/** An implicit function type */
- class ImplicitFunction(args: List[Tree], body: Tree) extends Function(args, body)
+ class ImplicitFunction(args: List[Tree], body: Tree) extends Function(args, body) {
+ override def toString = s"ImplicitFunction($args, $body"
+ }
/** A function created from a wildcard expression
* @param placeHolderParams a list of definitions of synthetic parameters
@@ -274,8 +276,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
// ------ Additional creation methods for untyped only -----------------
- // def TypeTree(tpe: Type): TypeTree = TypeTree().withType(tpe) todo: move to untpd/tpd
-
/** new pre.C[Ts](args1)...(args_n)
* ==>
* (new pre.C).<init>[Ts](args1)...(args_n)
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index ff259f184..814bbf48f 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -790,6 +790,9 @@ class Definitions {
def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1
+ def isImplicitFunctionType(tp: Type)(implicit ctx: Context) =
+ isFunctionType(tp) && tp.dealias.typeSymbol.name.startsWith(tpnme.ImplicitFunction)
+
// ----- primitive value class machinery ------------------------------------------
/** This class would also be obviated by the implicit function type design */
diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
index 79881dc5b..79cab8b74 100644
--- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
@@ -29,7 +29,7 @@ import Inferencing.fullyDefinedType
import Trees._
import Hashable._
import config.Config
-import config.Printers.{implicits, implicitsDetailed}
+import config.Printers.{implicits, implicitsDetailed, typr}
import collection.mutable
/** Implicit resolution */
@@ -146,7 +146,8 @@ object Implicits {
override val level: Int =
if (outerImplicits == null) 1
- else if (ctx.scope eq outerImplicits.ctx.scope) outerImplicits.level
+ else if ((ctx.owner eq outerImplicits.ctx.owner) &&
+ (ctx.scope eq outerImplicits.ctx.scope)) outerImplicits.level
else outerImplicits.level + 1
/** The implicit references that are eligible for type `tp`. */
@@ -211,7 +212,7 @@ object Implicits {
* @param ctx The context after the implicit search
*/
case class SearchSuccess(tree: tpd.Tree, ref: TermRef, level: Int, tstate: TyperState) extends SearchResult {
- override def toString = s"SearchSuccess($tree, $ref)"
+ override def toString = s"SearchSuccess($tree, $ref, $level)"
}
/** A failed search */
@@ -733,6 +734,7 @@ trait Implicits { self: Typer =>
case best :: alts =>
alts find (alt => isAsGood(alt.ref, best.ref, alt.level, best.level)(ctx.fresh.setExploreTyperState)) match {
case Some(alt) =>
+ typr.println(i"ambiguous implicits for $pt: ${best.ref} @ ${best.level}, ${alt.ref} @ ${alt.level}")
/* !!! DEBUG
println(i"ambiguous refs: ${hits map (_.ref) map (_.show) mkString ", "}")
isAsGood(best.ref, alt.ref, explain = true)(ctx.fresh.withExploreTyperState)
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 1967275e9..616c96019 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1494,6 +1494,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case tree: untpd.If => typedIf(tree, pt)
case tree: untpd.Function => typedFunction(tree, pt)
case tree: untpd.Closure => typedClosure(tree, pt)
+ case tree: untpd.Import => typedImport(tree, retrieveSym(tree))
case tree: untpd.Match => typedMatch(tree, pt)
case tree: untpd.Return => typedReturn(tree)
case tree: untpd.Try => typedTry(tree, pt)
@@ -1521,9 +1522,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case _ => typedUnadapted(desugar(tree), pt)
}
- xtree match {
+ if (defn.isImplicitFunctionType(pt) &&
+ xtree.isTerm &&
+ !untpd.isImplicitClosure(xtree) &&
+ !ctx.isAfterTyper)
+ makeImplicitFunction(xtree, pt)
+ else xtree match {
case xtree: untpd.NameTree => typedNamed(encodeName(xtree), pt)
- case xtree: untpd.Import => typedImport(xtree, retrieveSym(xtree))
case xtree => typedUnnamed(xtree)
}
}
@@ -1532,6 +1537,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
protected def encodeName(tree: untpd.NameTree)(implicit ctx: Context): untpd.NameTree =
untpd.rename(tree, tree.name.encode)
+ protected def makeImplicitFunction(tree: untpd.Tree, pt: Type)(implicit ctx: Context): Tree = {
+ val defn.FunctionOf(formals, resType, true) = pt.dealias
+ val paramTypes = formals.map(fullyDefinedType(_, "implicit function parameter", tree.pos))
+ val ifun = desugar.makeImplicitFunction(paramTypes, tree)
+ typr.println(i"make implicit function $tree / $pt ---> $ifun")
+ typedUnadapted(ifun)
+ }
+
def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = /*>|>*/ ctx.traceIndented (i"typing $tree", typr, show = true) /*<|<*/ {
assertPositioned(tree)
try adapt(typedUnadapted(tree, pt), pt, tree)
@@ -1878,16 +1891,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
err.typeMismatch(tree, pt)
else
missingArgs
- case wtp: RefinedType
- if defn.isImplicitFunctionClass(wtp.underlyingClassRef(refinementOK = false).classSymbol) &&
- !isClosure(tree) &&
- !isApplyProto(pt) &&
- !ctx.isAfterTyper =>
- typr.println("insert apply on implicit $tree")
- typed(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
case _ =>
ctx.typeComparer.GADTused = false
- if (ctx.mode is Mode.Pattern) {
+ if (defn.isImplicitFunctionClass(wtp.underlyingClassRef(refinementOK = false).classSymbol) &&
+ !untpd.isImplicitClosure(tree) &&
+ !isApplyProto(pt) &&
+ !ctx.isAfterTyper) {
+ typr.println("insert apply on implicit $tree")
+ typed(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
+ }
+ else if (ctx.mode is Mode.Pattern) {
tree match {
case _: RefTree | _: Literal
if !isVarPattern(tree) &&