@@ -1994,7 +1994,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
19941994 }
19951995 }
19961996
1997- def adaptImplicitMethod (wtp : ImplicitMethodType ): Tree = {
1997+ def adaptNoArgsImplicitMethod (wtp : ImplicitMethodType ): Tree = {
19981998 val tvarsToInstantiate = tvarsInParams(tree)
19991999 wtp.paramInfos.foreach(instantiateSelected(_, tvarsToInstantiate))
20002000 val constr = ctx.typerState.constraint
@@ -2041,6 +2041,100 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
20412041 addImplicitArgs(argCtx(tree))
20422042 }
20432043
2044+ /** A synthetic apply should be eta-expanded if it is the apply of an implicit function
2045+ * class, and the expected type is a function type. This rule is needed so we can pass
2046+ * an implicit function to a regular function type. So the following is OK
2047+ *
2048+ * val f: implicit A => B = ???
2049+ * val g: A => B = f
2050+ *
2051+ * and the last line expands to
2052+ *
2053+ * val g: A => B = (x$0: A) => f.apply(x$0)
2054+ *
2055+ * One could be tempted not to eta expand the rhs, but that would violate the invariant
2056+ * that expressions of implicit function types are always implicit closures, which is
2057+ * exploited by ShortcutImplicits.
2058+ *
2059+ * On the other hand, the following would give an error if there is no implicit
2060+ * instance of A available.
2061+ *
2062+ * val x: AnyRef = f
2063+ *
2064+ * That's intentional, we want to fail here, otherwise some unsuccesful implicit searches
2065+ * would go undetected.
2066+ *
2067+ * Examples for these cases are found in run/implicitFuns.scala and neg/i2006.scala.
2068+ */
2069+ def adaptNoArgsUnappliedMethod (wtp : MethodType , functionExpected : Boolean , arity : Int ): Tree = {
2070+ def isExpandableApply =
2071+ defn.isImplicitFunctionClass(tree.symbol.maybeOwner) && functionExpected
2072+
2073+ /** Is reference to this symbol `f` automatically expanded to `f()`? */
2074+ def isAutoApplied (sym : Symbol ): Boolean = {
2075+ sym.isConstructor ||
2076+ sym.matchNullaryLoosely ||
2077+ ctx.testScala2Mode(em " ${sym.showLocated} requires () argument " , tree.pos,
2078+ patch(tree.pos.endPos, " ()" ))
2079+ }
2080+
2081+ // Reasons NOT to eta expand:
2082+ // - we reference a constructor
2083+ // - we are in a pattern
2084+ // - the current tree is a synthetic apply which is not expandable (eta-expasion would simply undo that)
2085+ if (arity >= 0 &&
2086+ ! tree.symbol.isConstructor &&
2087+ ! ctx.mode.is(Mode .Pattern ) &&
2088+ ! (isSyntheticApply(tree) && ! isExpandableApply))
2089+ typed(etaExpand(tree, wtp, arity), pt)
2090+ else if (wtp.paramInfos.isEmpty && isAutoApplied(tree.symbol))
2091+ adaptInterpolated(tpd.Apply (tree, Nil ), pt)
2092+ else if (wtp.isImplicit)
2093+ err.typeMismatch(tree, pt)
2094+ else
2095+ missingArgs(wtp)
2096+ }
2097+
2098+ def adaptNoArgsOther (wtp : Type ) = {
2099+ ctx.typeComparer.GADTused = false
2100+ if (defn.isImplicitFunctionClass(wtp.underlyingClassRef(refinementOK = false ).classSymbol) &&
2101+ ! untpd.isImplicitClosure(tree) &&
2102+ ! isApplyProto(pt) &&
2103+ ! ctx.isAfterTyper) {
2104+ typr.println(i " insert apply on implicit $tree" )
2105+ typed(untpd.Select (untpd.TypedSplice (tree), nme.apply), pt)
2106+ }
2107+ else if (ctx.mode is Mode .Pattern ) {
2108+ checkEqualityEvidence(tree, pt)
2109+ tree
2110+ }
2111+ else if (tree.tpe <:< pt) {
2112+ if (pt.hasAnnotation(defn.InlineParamAnnot ))
2113+ checkInlineConformant(tree, " argument to inline parameter" )
2114+ if (Inliner .hasBodyToInline(tree.symbol) &&
2115+ ! ctx.owner.ownersIterator.exists(_.isInlineMethod) &&
2116+ ! ctx.settings.YnoInline .value &&
2117+ ! ctx.isAfterTyper &&
2118+ ! ctx.reporter.hasErrors)
2119+ adapt(Inliner .inlineCall(tree, pt), pt)
2120+ else if (ctx.typeComparer.GADTused && pt.isValueType)
2121+ // Insert an explicit cast, so that -Ycheck in later phases succeeds.
2122+ // I suspect, but am not 100% sure that this might affect inferred types,
2123+ // if the expected type is a supertype of the GADT bound. It would be good to come
2124+ // up with a test case for this.
2125+ tree.asInstance(pt)
2126+ else
2127+ tree
2128+ }
2129+ else wtp match {
2130+ case wtp : MethodType => missingArgs(wtp)
2131+ case _ =>
2132+ typr.println(i " adapt to subtype ${tree.tpe} !<:< $pt" )
2133+ // typr.println(TypeComparer.explained(implicit ctx => tree.tpe <:< pt))
2134+ adaptToSubType(wtp)
2135+ }
2136+ }
2137+
20442138 // Follow proxies and approximate type paramrefs by their upper bound
20452139 // in the current constraint in order to figure out robustly
20462140 // whether an expected type is some sort of function type.
@@ -2060,111 +2154,25 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
20602154 adaptInterpolated(tree.withType(wtp.resultType), pt)
20612155 case wtp : ImplicitMethodType
20622156 if constrainResult(wtp, followAlias(pt)) || ! functionExpected =>
2063- adaptImplicitMethod (wtp)
2157+ adaptNoArgsImplicitMethod (wtp)
20642158 case wtp : MethodType if ! pt.isInstanceOf [SingletonType ] =>
2065- val arity =
2066- if (functionExpected)
2067- if (! isFullyDefined(pt, ForceDegree .none) && isFullyDefined(wtp, ForceDegree .none))
2068- // if method type is fully defined, but expected type is not,
2069- // prioritize method parameter types as parameter types of the eta-expanded closure
2070- 0
2071- else defn.functionArity(ptNorm)
2072- else {
2073- val nparams = wtp.paramInfos.length
2074- if (nparams > 0 || pt.eq(AnyFunctionProto )) nparams
2075- else - 1 // no eta expansion in this case
2076- }
2077-
2078- /** A synthetic apply should be eta-expanded if it is the apply of an implicit function
2079- * class, and the expected type is a function type. This rule is needed so we can pass
2080- * an implicit function to a regular function type. So the following is OK
2081- *
2082- * val f: implicit A => B = ???
2083- * val g: A => B = f
2084- *
2085- * and the last line expands to
2086- *
2087- * val g: A => B = (x$0: A) => f.apply(x$0)
2088- *
2089- * One could be tempted not to eta expand the rhs, but that would violate the invariant
2090- * that expressions of implicit function types are always implicit closures, which is
2091- * exploited by ShortcutImplicits.
2092- *
2093- * On the other hand, the following would give an error if there is no implicit
2094- * instance of A available.
2095- *
2096- * val x: AnyRef = f
2097- *
2098- * That's intentional, we want to fail here, otherwise some unsuccesful implicit searches
2099- * would go undetected.
2100- *
2101- * Examples for these cases are found in run/implicitFuns.scala and neg/i2006.scala.
2102- */
2103- def isExpandableApply =
2104- defn.isImplicitFunctionClass(tree.symbol.maybeOwner) && defn.isFunctionType(ptNorm)
2105-
2106- /** Is reference to this symbol `f` automatically expanded to `f()`? */
2107- def isAutoApplied (sym : Symbol ): Boolean = {
2108- sym.isConstructor ||
2109- sym.matchNullaryLoosely ||
2110- ctx.testScala2Mode(em " ${sym.showLocated} requires () argument " , tree.pos,
2111- patch(tree.pos.endPos, " ()" ))
2112- }
2113-
2114- // Reasons NOT to eta expand:
2115- // - we reference a constructor
2116- // - we are in a pattern
2117- // - the current tree is a synthetic apply which is not expandable (eta-expasion would simply undo that)
2118- if (arity >= 0 &&
2119- ! tree.symbol.isConstructor &&
2120- ! ctx.mode.is(Mode .Pattern ) &&
2121- ! (isSyntheticApply(tree) && ! isExpandableApply))
2122- typed(etaExpand(tree, wtp, arity), pt)
2123- else if (wtp.paramInfos.isEmpty && isAutoApplied(tree.symbol))
2124- adaptInterpolated(tpd.Apply (tree, Nil ), pt)
2125- else if (wtp.isImplicit)
2126- err.typeMismatch(tree, pt)
2127- else
2128- missingArgs(wtp)
2129- case _ =>
2130- ctx.typeComparer.GADTused = false
2131- if (defn.isImplicitFunctionClass(wtp.underlyingClassRef(refinementOK = false ).classSymbol) &&
2132- ! untpd.isImplicitClosure(tree) &&
2133- ! isApplyProto(pt) &&
2134- ! ctx.isAfterTyper) {
2135- typr.println(i " insert apply on implicit $tree" )
2136- typed(untpd.Select (untpd.TypedSplice (tree), nme.apply), pt)
2137- }
2138- else if (ctx.mode is Mode .Pattern ) {
2139- checkEqualityEvidence(tree, pt)
2140- tree
2141- }
2142- else if (tree.tpe <:< pt) {
2143- if (pt.hasAnnotation(defn.InlineParamAnnot ))
2144- checkInlineConformant(tree, " argument to inline parameter" )
2145- if (Inliner .hasBodyToInline(tree.symbol) &&
2146- ! ctx.owner.ownersIterator.exists(_.isInlineMethod) &&
2147- ! ctx.settings.YnoInline .value &&
2148- ! ctx.isAfterTyper &&
2149- ! ctx.reporter.hasErrors)
2150- adapt(Inliner .inlineCall(tree, pt), pt)
2151- else if (ctx.typeComparer.GADTused && pt.isValueType)
2152- // Insert an explicit cast, so that -Ycheck in later phases succeeds.
2153- // I suspect, but am not 100% sure that this might affect inferred types,
2154- // if the expected type is a supertype of the GADT bound. It would be good to come
2155- // up with a test case for this.
2156- tree.asInstance(pt)
2157- else
2158- tree
2159- }
2160- else wtp match {
2161- case wtp : MethodType => missingArgs(wtp)
2162- case _ =>
2163- typr.println(i " adapt to subtype ${tree.tpe} !<:< $pt" )
2164- // typr.println(TypeComparer.explained(implicit ctx => tree.tpe <:< pt))
2165- adaptToSubType(wtp)
2166- }
2167- }}
2159+ val arity =
2160+ if (functionExpected)
2161+ if (! isFullyDefined(pt, ForceDegree .none) && isFullyDefined(wtp, ForceDegree .none))
2162+ // if method type is fully defined, but expected type is not,
2163+ // prioritize method parameter types as parameter types of the eta-expanded closure
2164+ 0
2165+ else defn.functionArity(ptNorm)
2166+ else {
2167+ val nparams = wtp.paramInfos.length
2168+ if (nparams > 0 || pt.eq(AnyFunctionProto )) nparams
2169+ else - 1 // no eta expansion in this case
2170+ }
2171+ adaptNoArgsUnappliedMethod(wtp, functionExpected, arity)
2172+ case _ =>
2173+ adaptNoArgsOther(wtp)
2174+ }
2175+ }
21682176
21692177 /** Adapt an expression of constant type to a different constant type `tpe`. */
21702178 def adaptConstant (tree : Tree , tpe : ConstantType ): Tree = {
0 commit comments