From 43ba65fa11456899b3c45be14bd3895d8d6b6b5a Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 28 Jul 2016 15:08:43 -0700 Subject: SI-7187 deprecate eta-expansion of zero-arg method values For backwards compatiblity with 2.11, we already don't adapt a zero-arg method value to a SAM. In 2.13, we won't do any eta-expansion for zero-arg method values, but we should deprecate first. --- .../scala/tools/nsc/typechecker/Typers.scala | 47 ++++++++++++++-------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ba104fb7a6..91cff54bc7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -872,16 +872,32 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case Block(_, tree1) => tree1.symbol case _ => tree.symbol } - def shouldEtaExpandToSam: Boolean = { - // SI-9536 don't adapt parameterless method types to a to SAM's, fall through to empty application - // instead for backwards compatiblity with 2.11. See comments of that ticket and SI-7187 - // for analogous trouble with non-SAM eta expansion. Suggestions there are: a) deprecate eta expansion to Function0, - // or b) switch the order of eta-expansion and empty application in this adaptation. - !mt.params.isEmpty && samOf(pt).exists - } - if (!meth.isConstructor && (isFunctionType(pt) || shouldEtaExpandToSam)) { // (4.2) + + def cantAdapt = + if (context.implicitsEnabled) MissingArgsForMethodTpeError(tree, meth) + else setError(tree) + + // constructors do not eta-expand + if (meth.isConstructor) cantAdapt + // (4.2) eta-expand method value when function or sam type is expected + else if (isFunctionType(pt) || (!mt.params.isEmpty && samOf(pt).exists)) { + // SI-9536 `!mt.params.isEmpty &&`: for backwards compatiblity with 2.11, + // we don't adapt a zero-arg method value to a SAM + // In 2.13, we won't do any eta-expansion for zero-arg method values, but we should deprecate first + debuglog(s"eta-expanding $tree: ${tree.tpe} to $pt") checkParamsConvertible(tree, tree.tpe) + + // SI-7187 eta-expansion of zero-arg method value is deprecated, switch order of (4.3) and (4.2) in 2.13 + def isExplicitEtaExpansion = original match { + case Typed(_, Function(Nil, EmptyTree)) => true // tree shape for `f _` + case _ => false + } + if (mt.params.isEmpty && !isExplicitEtaExpansion) { + currentRun.reporting.deprecationWarning(tree.pos, NoSymbol, + s"Eta-expansion of zero-argument method values is deprecated. Did you intend to write ${Apply(tree, Nil)}?", "2.12.0") + } + val tree0 = etaExpand(context.unit, tree, this) // #2624: need to infer type arguments for eta expansion of a polymorphic method @@ -895,12 +911,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper else typed(tree0, mode, pt) } - else if (!meth.isConstructor && mt.params.isEmpty) // (4.3) - adapt(typed(Apply(tree, Nil) setPos tree.pos), mode, pt, original) - else if (context.implicitsEnabled) - MissingArgsForMethodTpeError(tree, meth) - else - setError(tree) + // (4.3) apply to empty argument list -- TODO 2.13: move this one case up to avoid eta-expanding at arity 0 + else if (mt.params.isEmpty) adapt(typed(Apply(tree, Nil) setPos tree.pos), mode, pt, original) + else cantAdapt } def adaptType(): Tree = { @@ -4398,11 +4411,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * (2) If $e$ is a parameterless method or call-by-name parameter of type `=>$T$`, `$e$ _` represents * the function of type `() => $T$`, which evaluates $e$ when it is applied to the empty parameterlist `()`. */ - def typedEta(methodValue: Tree): Tree = methodValue.tpe match { + def typedEta(methodValue: Tree, original: Tree): Tree = methodValue.tpe match { case tp@(MethodType(_, _) | PolyType(_, MethodType(_, _))) => // (1) val formals = tp.params if (isFunctionType(pt) || samMatchesFunctionBasedOnArity(samOf(pt), formals)) methodValue - else adapt(methodValue, mode, checkArity(methodValue)(functionTypeWildcard(formals.length))) + else adapt(methodValue, mode, checkArity(methodValue)(functionTypeWildcard(formals.length)), original) case TypeRef(_, ByNameParamClass, _) | NullaryMethodType(_) => // (2) val pos = methodValue.pos @@ -5106,7 +5119,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case Typed(expr, Function(Nil, EmptyTree)) => typed1(suppressMacroExpansion(expr), mode, pt) match { case macroDef if treeInfo.isMacroApplication(macroDef) => MacroEtaError(macroDef) - case methodValue => typedEta(checkDead(methodValue)) + case methodValue => typedEta(checkDead(methodValue), tree) } case Typed(expr, tpt) => val tpt1 = typedType(tpt, mode) // type the ascribed type first -- cgit v1.2.3