summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2016-03-24 14:50:44 -0700
committerAdriaan Moors <adriaan.moors@typesafe.com>2016-03-26 22:55:14 -0700
commit925b394dbf2fc8f9a0a6f64e374dc6ab5564ab37 (patch)
tree3971d6191046a498f2b48fc73ea5d29edfe9c70b
parentaa972dc100544179beecde48b52dfdb847162001 (diff)
downloadscala-925b394dbf2fc8f9a0a6f64e374dc6ab5564ab37.tar.gz
scala-925b394dbf2fc8f9a0a6f64e374dc6ab5564ab37.tar.bz2
scala-925b394dbf2fc8f9a0a6f64e374dc6ab5564ab37.zip
Refactor: simplify fallbackAfterVanillaAdapt.
Trying to figure out if we can avoid adapting to SAM, and just type them once and for all in typedFunction. Looks like overload resolution requires SAM adaptation to happen in adapt. Cleaned up while I was in the area.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala205
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala8
3 files changed, 107 insertions, 108 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 9b42841eb8..dc91d23011 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -1220,7 +1220,7 @@ trait Infer extends Checkable {
}
def inferModulePattern(pat: Tree, pt: Type) =
- if (!(pat.tpe <:< pt)) {
+ if ((pat.symbol ne null) && pat.symbol.isModule && !(pat.tpe <:< pt)) {
val ptparams = freeTypeParamsOfTerms(pt)
debuglog("free type params (2) = " + ptparams)
val ptvars = ptparams map freshVar
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 52242c10b3..ba6a9e20ea 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -807,7 +807,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
* (11) Widen numeric literals to their expected type, if necessary
* (12) When in mode EXPRmode, convert E to { E; () } if expected type is scala.Unit.
* (13) When in mode EXPRmode, apply AnnotationChecker conversion if expected type is annotated.
- * (14) When in mode EXPRmode, apply a view
+ * (14) When in mode EXPRmode, do SAM conversion
+ * (15) When in mode EXPRmode, apply a view
* If all this fails, error
*/
protected def adapt(tree: Tree, mode: Mode, pt: Type, original: Tree = EmptyTree): Tree = {
@@ -1019,78 +1020,70 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
- def fallbackAfterVanillaAdapt(): Tree = {
- def isPopulatedPattern = {
- if ((tree.symbol ne null) && tree.symbol.isModule)
- inferModulePattern(tree, pt)
-
- isPopulated(tree.tpe, approximateAbstracts(pt))
+ def adaptExprNotFunMode(): Tree = {
+ def lastTry(err: AbsTypeError = null): Tree = {
+ debuglog("error tree = " + tree)
+ if (settings.debug && settings.explaintypes) explainTypes(tree.tpe, pt)
+ if (err ne null) context.issue(err)
+ if (tree.tpe.isErroneous || pt.isErroneous) setError(tree)
+ else adaptMismatchedSkolems()
}
- if (mode.inPatternMode && isPopulatedPattern)
- return tree
- val tree1 = constfold(tree, pt) // (10) (11)
- if (tree1.tpe <:< pt)
- return adapt(tree1, mode, pt, original)
+ // TODO: should we even get to fallbackAfterVanillaAdapt for an ill-typed tree?
+ if (mode.typingExprNotFun && !tree.tpe.isErroneous) {
+ @inline def tpdPos(transformed: Tree) = typedPos(tree.pos, mode, pt)(transformed)
+ @inline def tpd(transformed: Tree) = typed(transformed, mode, pt)
- if (mode.typingExprNotFun) {
- // The <: Any requirement inhibits attempts to adapt continuation types
- // to non-continuation types.
- if (tree.tpe <:< AnyTpe) pt.dealias match {
- case TypeRef(_, UnitClass, _) => // (12)
- if (!isPastTyper && settings.warnValueDiscard)
- context.warning(tree.pos, "discarded non-Unit value")
- return typedPos(tree.pos, mode, pt)(Block(List(tree), Literal(Constant(()))))
- case TypeRef(_, sym, _) if isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt) =>
- if (!isPastTyper && settings.warnNumericWiden)
- context.warning(tree.pos, "implicit numeric widening")
- return typedPos(tree.pos, mode, pt)(Select(tree, "to" + sym.name))
- case _ =>
- }
- if (pt.dealias.annotations.nonEmpty && canAdaptAnnotations(tree, this, mode, pt)) // (13)
- return typed(adaptAnnotations(tree, this, mode, pt), mode, pt)
+ @inline def warnValueDiscard(): Unit =
+ if (!isPastTyper && settings.warnValueDiscard) context.warning(tree.pos, "discarded non-Unit value")
+ @inline def warnNumericWiden(): Unit =
+ if (!isPastTyper && settings.warnNumericWiden) context.warning(tree.pos, "implicit numeric widening")
- if (hasUndets)
- return instantiate(tree, mode, pt)
-
- // we know `!(tree.tpe <:< pt)`; try to remedy if there's a sam for pt
- val sam = samMatchingFunction(tree, pt) // this implies tree.isInstanceOf[Function]
- if (sam.exists && !tree.tpe.isErroneous) {
- val samTree = adaptToSAM(sam, tree.asInstanceOf[Function], pt, mode)
- if (samTree ne EmptyTree)
- return samTree.updateAttachment(SAMFunction(pt, sam))
- }
+ // The <: Any requirement inhibits attempts to adapt continuation types to non-continuation types.
+ val anyTyped = tree.tpe <:< AnyTpe
- if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) {
- // (14); the condition prevents chains of views
- inferView(tree, tree.tpe, pt) match {
- case EmptyTree => // didn't find a view -- fall through
- case coercion =>
- def msg = s"inferred view from ${tree.tpe} to $pt via $coercion: ${coercion.tpe}"
- if (settings.logImplicitConv) context.echo(tree.pos, msg)
- else debuglog(msg)
-
- val silentContext = context.makeImplicit(context.ambiguousErrors)
- val res = newTyper(silentContext).typed(
- new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
- silentContext.reporter.firstError match {
- case Some(err) => context.issue(err)
- case None => return res
+ pt.dealias match {
+ case TypeRef(_, UnitClass, _) if anyTyped => // (12)
+ warnValueDiscard() ; tpdPos(gen.mkUnitBlock(tree))
+ case TypeRef(_, numValueCls, _) if anyTyped && isNumericValueClass(numValueCls) && isNumericSubType(tree.tpe, pt) => // (10) (11)
+ warnNumericWiden() ; tpdPos(Select(tree, s"to${numValueCls.name}"))
+ case dealiased if dealiased.annotations.nonEmpty && canAdaptAnnotations(tree, this, mode, pt) => // (13)
+ tpd(adaptAnnotations(tree, this, mode, pt))
+ case _ =>
+ if (hasUndets) instantiate(tree, mode, pt)
+ else {
+ // (14) sam conversion
+ // TODO: figure out how to avoid partially duplicating typedFunction (samMatchingFunction)
+ // Could we infer the SAM type, assign it to the tree and add the attachment,
+ // all in one fell swoop at the end of typedFunction?
+ val samAttach = inferSamType(tree, pt, mode)
+
+ if (samAttach.samTp ne NoType) tree.setType(samAttach.samTp).updateAttachment(samAttach)
+ else { // (15) implicit view application
+ val coercion =
+ if (context.implicitsEnabled) inferView(tree, tree.tpe, pt)
+ else EmptyTree
+ if (coercion ne EmptyTree) {
+ def msg = s"inferred view from ${tree.tpe} to $pt via $coercion: ${coercion.tpe}"
+ if (settings.logImplicitConv) context.echo(tree.pos, msg)
+ else debuglog(msg)
+
+ val viewApplied = new ApplyImplicitView(coercion, List(tree)) setPos tree.pos
+ val silentContext = context.makeImplicit(context.ambiguousErrors)
+ val typedView = newTyper(silentContext).typed(viewApplied, mode, pt)
+
+ silentContext.reporter.firstError match {
+ case None => typedView
+ case Some(err) => lastTry(err)
+ }
+ } else lastTry()
}
- }
+ }
}
- }
-
- debuglog("error tree = " + tree)
- if (settings.debug && settings.explaintypes)
- explainTypes(tree.tpe, pt)
-
- if (tree.tpe.isErroneous || pt.isErroneous)
- setError(tree)
- else
- adaptMismatchedSkolems()
+ } else lastTry()
}
+
def vanillaAdapt(tree: Tree) = {
def applyPossible = {
def applyMeth = member(adaptToName(tree, nme.apply), nme.apply)
@@ -1124,8 +1117,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
else if (tree.tpe <:< pt)
tree
- else
- fallbackAfterVanillaAdapt()
+ else if (mode.inPatternMode && { inferModulePattern(tree, pt); isPopulated(tree.tpe, approximateAbstracts(pt)) })
+ tree
+ else {
+ val constFolded = constfold(tree, pt)
+ if (constFolded.tpe <:< pt) adapt(constFolded, mode, pt, original) // set stage for (0)
+ else adaptExprNotFunMode() // (10) -- (15)
+ }
}
// begin adapt
@@ -2751,54 +2749,63 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
* function type is a built-in FunctionN or some SAM type
*
*/
- def adaptToSAM(sam: Symbol, fun: Function, pt: Type, mode: Mode): Tree = {
+ def inferSamType(fun: Tree, pt: Type, mode: Mode): SAMFunction = {
+ val sam =
+ if (fun.isInstanceOf[Function] && !isFunctionType(pt)) {
+ val sam = samOf(pt)
+ if (samMatchesFunctionBasedOnArity(sam, fun.asInstanceOf[Function].vparams)) sam
+ else NoSymbol
+ } else NoSymbol
+
def fullyDefinedMeetsExpectedFunTp(pt: Type): Boolean = isFullyDefined(pt) && {
val samMethType = pt memberInfo sam
fun.tpe <:< functionType(samMethType.paramTypes, samMethType.resultType)
}
- if (fullyDefinedMeetsExpectedFunTp(pt)) fun.setType(pt)
- else try {
- val samClassSym = pt.typeSymbol
+ SAMFunction(
+ if (!sam.exists) NoType
+ else if (fullyDefinedMeetsExpectedFunTp(pt)) pt
+ else try {
+ val samClassSym = pt.typeSymbol
- // we're trying to fully define the type arguments for this type constructor
- val samTyCon = samClassSym.typeConstructor
+ // we're trying to fully define the type arguments for this type constructor
+ val samTyCon = samClassSym.typeConstructor
- // the unknowns
- val tparams = samClassSym.typeParams
- // ... as typevars
- val tvars = tparams map freshVar
+ // the unknowns
+ val tparams = samClassSym.typeParams
+ // ... as typevars
+ val tvars = tparams map freshVar
- val ptVars = appliedType(samTyCon, tvars)
+ val ptVars = appliedType(samTyCon, tvars)
- // carry over info from pt
- ptVars <:< pt
+ // carry over info from pt
+ ptVars <:< pt
- val samInfoWithTVars = ptVars.memberInfo(sam)
+ val samInfoWithTVars = ptVars.memberInfo(sam)
- // use function type subtyping, not method type subtyping (the latter is invariant in argument types)
- fun.tpe <:< functionType(samInfoWithTVars.paramTypes, samInfoWithTVars.finalResultType)
+ // use function type subtyping, not method type subtyping (the latter is invariant in argument types)
+ fun.tpe <:< functionType(samInfoWithTVars.paramTypes, samInfoWithTVars.finalResultType)
- val variances = tparams map varianceInType(sam.info)
+ val variances = tparams map varianceInType(sam.info)
- // solve constraints tracked by tvars
- val targs = solvedTypes(tvars, tparams, variances, upper = false, lubDepth(sam.info :: Nil))
+ // solve constraints tracked by tvars
+ val targs = solvedTypes(tvars, tparams, variances, upper = false, lubDepth(sam.info :: Nil))
- debuglog(s"sam infer: $pt --> ${appliedType(samTyCon, targs)} by ${fun.tpe} <:< $samInfoWithTVars --> $targs for $tparams")
+ debuglog(s"sam infer: $pt --> ${appliedType(samTyCon, targs)} by ${fun.tpe} <:< $samInfoWithTVars --> $targs for $tparams")
- val ptFullyDefined = appliedType(samTyCon, targs)
- if (ptFullyDefined <:< pt && fullyDefinedMeetsExpectedFunTp(ptFullyDefined)) {
- debuglog(s"sam fully defined expected type: $ptFullyDefined from $pt for ${fun.tpe}")
- fun.setType(ptFullyDefined)
- } else {
- debuglog(s"Could not define type $pt using ${fun.tpe} <:< ${pt memberInfo sam} (for $sam)")
- EmptyTree
- }
- } catch {
- case e@(_: NoInstance | _: TypeError) =>
- debuglog(s"Error during SAM synthesis: could not define type $pt using ${fun.tpe} <:< ${pt memberInfo sam} (for $sam)\n$e")
- EmptyTree
- }
+ val ptFullyDefined = appliedType(samTyCon, targs)
+ if (ptFullyDefined <:< pt && fullyDefinedMeetsExpectedFunTp(ptFullyDefined)) {
+ debuglog(s"sam fully defined expected type: $ptFullyDefined from $pt for ${fun.tpe}")
+ ptFullyDefined
+ } else {
+ debuglog(s"Could not define type $pt using ${fun.tpe} <:< ${pt memberInfo sam} (for $sam)")
+ NoType
+ }
+ } catch {
+ case e@(_: NoInstance | _: TypeError) =>
+ debuglog(s"Error during SAM synthesis: could not define type $pt using ${fun.tpe} <:< ${pt memberInfo sam} (for $sam)\n$e")
+ NoType
+ }, sam)
}
/** Type check a function literal.
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 81071e763d..28f6afee39 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -701,14 +701,6 @@ trait Definitions extends api.StandardDefinitions {
def samMatchesFunctionBasedOnArity(sam: Symbol, formals: List[Any]): Boolean =
sam.exists && sameLength(sam.info.params, formals)
- def samMatchingFunction(tree: Tree, pt: Type): Symbol = {
- if (tree.isInstanceOf[Function] && !isFunctionType(pt)) {
- val sam = samOf(pt)
- if (samMatchesFunctionBasedOnArity(sam, tree.asInstanceOf[Function].vparams)) sam
- else NoSymbol
- } else NoSymbol
- }
-
def isTupleType(tp: Type) = isTupleTypeDirect(tp.dealiasWiden)
def tupleComponents(tp: Type) = tp.dealiasWiden.typeArgs