From ad7edc7bd8af963b768afdc50b7038a8daa47ccb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 3 Dec 2016 13:52:48 +0100 Subject: Always insert apply for expressions of implicit function type --- .../src/dotty/tools/dotc/core/Definitions.scala | 29 ++++++++++++++++++---- compiler/src/dotty/tools/dotc/typer/Typer.scala | 21 ++++++++++------ 2 files changed, 37 insertions(+), 13 deletions(-) (limited to 'compiler') 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) { -- cgit v1.2.3