@@ -1994,7 +1994,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
1994
1994
}
1995
1995
}
1996
1996
1997
- def adaptImplicitMethod (wtp : ImplicitMethodType ): Tree = {
1997
+ def adaptNoArgsImplicitMethod (wtp : ImplicitMethodType ): Tree = {
1998
1998
val tvarsToInstantiate = tvarsInParams(tree)
1999
1999
wtp.paramInfos.foreach(instantiateSelected(_, tvarsToInstantiate))
2000
2000
val constr = ctx.typerState.constraint
@@ -2041,6 +2041,100 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
2041
2041
addImplicitArgs(argCtx(tree))
2042
2042
}
2043
2043
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
+
2044
2138
// Follow proxies and approximate type paramrefs by their upper bound
2045
2139
// in the current constraint in order to figure out robustly
2046
2140
// 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
2060
2154
adaptInterpolated(tree.withType(wtp.resultType), pt)
2061
2155
case wtp : ImplicitMethodType
2062
2156
if constrainResult(wtp, followAlias(pt)) || ! functionExpected =>
2063
- adaptImplicitMethod (wtp)
2157
+ adaptNoArgsImplicitMethod (wtp)
2064
2158
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
+ }
2168
2176
2169
2177
/** Adapt an expression of constant type to a different constant type `tpe`. */
2170
2178
def adaptConstant (tree : Tree , tpe : ConstantType ): Tree = {
0 commit comments