aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-12-03 13:52:48 +0100
committerMartin Odersky <odersky@gmail.com>2016-12-17 18:34:27 +0100
commitad7edc7bd8af963b768afdc50b7038a8daa47ccb (patch)
treec4f437115a3e898f854a9977a7c4b1cf1c1bf19b /compiler
parentfd2c24c3159cefa583889a176f31d1e2325fe7e6 (diff)
downloaddotty-ad7edc7bd8af963b768afdc50b7038a8daa47ccb.tar.gz
dotty-ad7edc7bd8af963b768afdc50b7038a8daa47ccb.tar.bz2
dotty-ad7edc7bd8af963b768afdc50b7038a8daa47ccb.zip
Always insert apply for expressions of implicit function type
Diffstat (limited to 'compiler')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala29
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala21
2 files changed, 37 insertions, 13 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index b90cd597f..f04dac505 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -86,7 +86,25 @@ class Definitions {
newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer).entered
}
- /** The trait FunctionN, for some N */
+ /** The trait FunctionN or ImplicitFunctionN, for some N
+ * @param name The name of the trait to be created
+ *
+ * FunctionN traits follow this template:
+ *
+ * trait FunctionN[T0,...T{N-1}, R] extends Object {
+ * def apply($x0: T0, ..., $x{N_1}: T{N-1}): R
+ * }
+ *
+ * That is, they follow the template given for Function2..Function22 in the
+ * standard library, but without `tupled` and `curried` methods and without
+ * a `toString`.
+ *
+ * ImplicitFunctionN traits follow this template:
+ *
+ * trait ImplicitFunctionN[T0,...,T{N-1}, R] extends Object with FunctionN[T0,...,T{N-1}, R] {
+ * def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
+ * }
+ */
private def newFunctionNTrait(name: TypeName) = {
val completer = new LazyType {
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
@@ -97,17 +115,17 @@ class Definitions {
for (i <- List.range(0, arity)) yield
enterTypeParam(cls, name ++ "$T" ++ i.toString, Contravariant, decls)
val resParam = enterTypeParam(cls, name ++ "$R", Covariant, decls)
- val (implicitFlag, parentTraits) =
+ val (methodType, parentTraits) =
if (name.startsWith(tpnme.ImplicitFunction)) {
val superTrait =
FunctionType(arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil)
- (Implicit, ctx.normalizeToClassRefs(superTrait :: Nil, cls, decls))
+ (ImplicitMethodType, ctx.normalizeToClassRefs(superTrait :: Nil, cls, decls))
}
- else (EmptyFlags, Nil)
+ else (MethodType, Nil)
val applyMeth =
decls.enter(
newMethod(cls, nme.apply,
- MethodType(argParams.map(_.typeRef), resParam.typeRef), Deferred | implicitFlag))
+ methodType(argParams.map(_.typeRef), resParam.typeRef), Deferred))
denot.info =
ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: parentTraits, decls)
}
@@ -698,6 +716,7 @@ class Definitions {
tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass)
def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function)
+ def isImplicitFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.ImplicitFunction)
def isUnimplementedFunctionClass(cls: Symbol) =
isFunctionClass(cls) && cls.name.functionArity > MaxImplementedFunctionArity
def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction)
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index c8deda4bc..018a6064b 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1616,6 +1616,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
}
+ /** Is `pt` a prototype of an `apply` selection, or a parameterless function yielding one? */
+ def isApplyProto(pt: Type)(implicit ctx: Context): Boolean = pt match {
+ case pt: SelectionProto => pt.name == nme.apply
+ case pt: FunProto => pt.args.isEmpty && isApplyProto(pt.resultType)
+ case pt: IgnoredProto => isApplyProto(pt.ignored)
+ case _ => false
+ }
+
/** Add apply node or implicit conversions. Two strategies are tried, and the first
* that is successful is picked. If neither of the strategies are successful, continues with
* `fallBack`.
@@ -1629,14 +1637,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
*/
def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree = {
- /** Is `pt` a prototype of an `apply` selection, or a parameterless function yielding one? */
- def isApplyProto(pt: Type): Boolean = pt match {
- case pt: SelectionProto => pt.name == nme.apply
- case pt: FunProto => pt.args.isEmpty && isApplyProto(pt.resultType)
- case pt: IgnoredProto => isApplyProto(pt.ignored)
- case _ => false
- }
-
def tryApply(implicit ctx: Context) = {
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
if (sel.tpe.isError) sel else adapt(sel, pt)
@@ -1878,6 +1878,11 @@ 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) &&
+ !isApplyProto(pt) =>
+ typr.println(i"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) {