diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2016-03-31 11:36:02 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2016-03-31 11:36:02 -0700 |
commit | 5e5ab186fe5b8cf047fd3da58da29dbc8f9fbd71 (patch) | |
tree | dabd389628cc48b730575786e7ef43d9f6657a00 /src/compiler/scala/tools/nsc/typechecker/Typers.scala | |
parent | 5d7d64482011f72596a634a58138e253b7fe3531 (diff) | |
download | scala-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.scala | 25 |
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 |