diff options
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 48 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 26 |
2 files changed, 36 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index bc078bbba0..e9383f19c6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -388,43 +388,37 @@ trait Infer extends Checkable { */ private def isCompatible(tp: Type, pt: Type): Boolean = { def isCompatibleByName(tp: Type, pt: Type): Boolean = ( - isByNameParamType(pt) && !isByNameParamType(tp) && isCompatible(tp, dropByName(pt)) + isByNameParamType(pt) + && !isByNameParamType(tp) + && isCompatible(tp, dropByName(pt)) ) val tp1 = normalize(tp) - (tp1 weak_<:< pt) || isCoercible(tp1, pt) || isCompatibleByName(tp, pt) + + ( (tp1 weak_<:< pt) + || isCoercible(tp1, pt) + || isCompatibleByName(tp, pt) + ) } - def isCompatibleArgs(tps: List[Type], pts: List[Type]) = - (tps corresponds pts)(isCompatible) + def isCompatibleArgs(tps: List[Type], pts: List[Type]) = (tps corresponds pts)(isCompatible) - def isWeaklyCompatible(tp: Type, pt: Type): Boolean = - pt.typeSymbol == UnitClass || // can perform unit coercion - isCompatible(tp, pt) || - tp.isInstanceOf[MethodType] && // can perform implicit () instantiation - tp.params.isEmpty && isCompatible(tp.resultType, pt) + def isWeaklyCompatible(tp: Type, pt: Type): Boolean = { + def isCompatibleNoParamsMethod = tp match { + case MethodType(Nil, restpe) => isCompatible(restpe, pt) + case _ => false + } + ( pt.typeSymbol == UnitClass // can perform unit coercion + || isCompatible(tp, pt) + || isCompatibleNoParamsMethod // can perform implicit () instantiation + ) + } - /** Like weakly compatible but don't apply any implicit conversions yet. + /* Like weakly compatible but don't apply any implicit conversions yet. * Used when comparing the result type of a method with its prototype. - * - * [Martin] I think Infer is also created by Erasure, with the default - * implementation of isCoercible - * [Paulp] (Assuming the above must refer to my comment on isCoercible) - * Nope, I examined every occurrence of Inferencer in trunk. It - * appears twice as a self-type, once at its definition, and once - * where it is instantiated in Typers. There are no others. - * - % ack -A0 -B0 --no-filename '\bInferencer\b' src - self: Inferencer => - self: Inferencer => - class Inferencer(context: Context) extends InferencerContextErrors with InferCheckable { - val infer = new Inferencer(context0) { */ def isConservativelyCompatible(tp: Type, pt: Type): Boolean = context.withImplicitsDisabled(isWeaklyCompatible(tp, pt)) - /** This is overridden in the Typer.infer with some logic, but since - * that's the only place in the compiler an Inferencer is ever created, - * I suggest this should either be abstract or have the implementation. - */ + // Overridden at the point of instantiation, where inferView is visible. def isCoercible(tp: Type, pt: Type): Boolean = false /* -- Type instantiation------------------------------------------------ */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5339f4b21c..8511428d90 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -107,6 +107,11 @@ trait Typers extends Adaptations with Tags { import typeDebug.{ ptTree, ptBlock, ptLine } import TyperErrorGen._ + val infer = new Inferencer(context0) { + // See SI-3281 re undoLog + override def isCoercible(tp: Type, pt: Type) = undoLog undo viewExists(tp, pt) + } + /** Overridden to false in scaladoc and/or interactive. */ def canAdaptConstantTypeToLiteral = true def canTranslateEmptyListToNil = true @@ -115,14 +120,6 @@ trait Typers extends Adaptations with Tags { def typedDocDef(docDef: DocDef, mode: Mode, pt: Type): Tree = typed(docDef.definition, mode, pt) - val infer = new Inferencer(context0) { - override def isCoercible(tp: Type, pt: Type): Boolean = undoLog undo { // #3281 - tp.isError || pt.isError || - context0.implicitsEnabled && // this condition prevents chains of views - inferView(EmptyTree, tp, pt, reportAmbiguous = false) != EmptyTree - } - } - /** Find implicit arguments and pass them to given tree. */ def applyImplicitArgs(fun: Tree): Tree = fun.tpe match { @@ -189,6 +186,13 @@ trait Typers extends Adaptations with Tags { fun } + def viewExists(from: Type, to: Type): Boolean = ( + !from.isError + && !to.isError + && context.implicitsEnabled + && (inferView(EmptyTree, from, to, reportAmbiguous = false) != EmptyTree) + ) + def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = inferView(tree, from, to, reportAmbiguous, saveErrors = true) @@ -207,10 +211,10 @@ trait Typers extends Adaptations with Tags { debuglog("infer view from "+from+" to "+to)//debug if (isPastTyper) EmptyTree else from match { - case MethodType(_, _) => EmptyTree + case MethodType(_, _) => EmptyTree case OverloadedType(_, _) => EmptyTree - case PolyType(_, _) => EmptyTree - case _ => + case PolyType(_, _) => EmptyTree + case _ => def wrapImplicit(from: Type): Tree = { val result = inferImplicit(tree, functionType(from.withoutAnnotations :: Nil, to), reportAmbiguous, isView = true, context, saveAmbiguousDivergent = saveErrors) if (result.subst != EmptyTreeTypeSubstituter) { |