summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2016-03-31 11:36:02 -0700
committerAdriaan Moors <adriaan.moors@typesafe.com>2016-03-31 11:36:02 -0700
commit5e5ab186fe5b8cf047fd3da58da29dbc8f9fbd71 (patch)
treedabd389628cc48b730575786e7ef43d9f6657a00 /src/compiler/scala/tools/nsc/typechecker/Typers.scala
parent5d7d64482011f72596a634a58138e253b7fe3531 (diff)
downloadscala-5e5ab186fe5b8cf047fd3da58da29dbc8f9fbd71.tar.gz
scala-5e5ab186fe5b8cf047fd3da58da29dbc8f9fbd71.tar.bz2
scala-5e5ab186fe5b8cf047fd3da58da29dbc8f9fbd71.zip
Clarify how/when typedFunction unrolls eta-expansion
Jason points out the recursion will be okay if type checking the function inside the eta-expansion provides fully determined argument types, as the result type is not relevant for this phase of typedFunction.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala25
1 files changed, 20 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 8d3e9a0a91..fdf7058ab1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -244,6 +244,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
var context = context0
def context1 = context
+ // for use with silent type checking to when we can't have results with undetermined type params
+ // note that this captures the context var
+ val isMonoContext = (_: Any) => context.undetparams.isEmpty
+
def dropExistential(tp: Type): Type = tp match {
case ExistentialType(tparams, tpe) =>
new SubstWildcardMap(tparams).apply(tp)
@@ -2888,20 +2892,31 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// If we're typing `(a1: T1, ..., aN: TN) => m(a1,..., aN)`, where some Ti are not fully defined,
// type `m` directly (undoing eta-expansion of method m) to determine the argument types.
+ // This tree is the result from one of:
+ // - manual eta-expansion with named arguments (x => f(x));
+ // - wildcard-style eta expansion (`m(_, _,)`);
+ // - instantiateToMethodType adapting a tree of method type to a function type using etaExpand.
+ //
+ // Note that method values are a separate thing (`m _`): they have the idiosyncratic shape
+ // of `Typed(expr, Function(Nil, EmptyTree))`
val ptUnrollingEtaExpansion =
if (paramsMissingType.nonEmpty && pt != ErrorType) fun.body match {
+ // we can compare arguments and parameters by name because there cannot be a binder between
+ // the function's valdefs and the Apply's arguments
case Apply(meth, args) if (vparams corresponds args) { case (p, Ident(name)) => p.name == name case _ => false } =>
+ // We're looking for a method (as indicated by FUNmode in the silent typed below),
+ // so let's make sure our expected type is a MethodType
val methArgs = NoSymbol.newSyntheticValueParams(argpts map { case NoType => WildcardType case tp => tp })
- // we're looking for a method (as indicated by FUNmode), so let's make sure our expected type is a MethodType
- val methPt = MethodType(methArgs, respt)
-
- silent(_.typed(meth, mode.forFunMode, methPt)) filter (_ => context.undetparams.isEmpty) map { methTyped =>
+ silent(_.typed(meth, mode.forFunMode, MethodType(methArgs, respt))) filter (isMonoContext) map { methTyped =>
// if context.undetparams is not empty, the method was polymorphic,
// so we need the missing arguments to infer its type. See #871
val funPt = normalize(methTyped.tpe) baseType FunctionClass(numVparams)
// println(s"typeUnEtaExpanded $meth : ${methTyped.tpe} --> normalized: $funPt")
- if (isFunctionType(funPt) && isFullyDefined(funPt)) funPt
+ // If we are sure this function type provides all the necesarry info, so that we won't have
+ // any undetermined argument types, go ahead an recurse below (`typedFunction(fun, mode, ptUnrollingEtaExpansion)`)
+ // and rest assured we won't end up right back here (and keep recursing)
+ if (isFunctionType(funPt) && funPt.typeArgs.iterator.take(numVparams).forall(isFullyDefined)) funPt
else null
} orElse { _ => null }
case _ => null