diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 30 | ||||
-rw-r--r-- | test/files/neg/t8463.check | 10 | ||||
-rw-r--r-- | test/files/neg/t8463.scala | 38 | ||||
-rw-r--r-- | test/files/pos/t8329.scala | 29 |
4 files changed, 93 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e3901be546..3690750e42 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -197,7 +197,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper !from.isError && !to.isError && context.implicitsEnabled - && (inferView(EmptyTree, from, to, reportAmbiguous = false) != EmptyTree) + && (inferView(context.tree, from, to, reportAmbiguous = false, saveErrors = true) != EmptyTree) + // SI-8230 / SI-8463 We'd like to change this to `saveErrors = false`, but can't. + // For now, we can at least pass in `context.tree` rather then `EmptyTree` so as + // to avoid unpositioned type errors. ) def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = @@ -2479,7 +2482,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * an alternative TODO: add partial function AST node or equivalent and get rid of this synthesis --> do everything in uncurry (or later) * however, note that pattern matching codegen is designed to run *before* uncurry */ - def synthesizePartialFunction(paramName: TermName, paramPos: Position, tree: Tree, mode: Mode, pt: Type): Tree = { + def synthesizePartialFunction(paramName: TermName, paramPos: Position, paramSynthetic: Boolean, + tree: Tree, mode: Mode, pt: Type): Tree = { assert(pt.typeSymbol == PartialFunctionClass, s"PartialFunction synthesis for match in $tree requires PartialFunction expected type, but got $pt.") val targs = pt.dealiasWiden.typeArgs @@ -2507,7 +2511,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val casesTrue = cases map (c => deriveCaseDef(c)(x => atPos(x.pos.focus)(TRUE)).duplicate.asInstanceOf[CaseDef]) // must generate a new tree every time - def selector: Tree = gen.mkUnchecked( + def selector(paramSym: Symbol): Tree = gen.mkUnchecked( if (sel != EmptyTree) sel.duplicate else atPos(tree.pos.focusStart)( // SI-6925: subsume type of the selector to `argTp` @@ -2518,7 +2522,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // hence the cast, which will be erased in posterasure // (the cast originally caused extremely weird types to show up // in test/scaladoc/run/SI-5933.scala because `variantToSkolem` was missing `tpSym.initialize`) - gen.mkCastPreservingAnnotations(Ident(paramName), argTp) + gen.mkCastPreservingAnnotations(Ident(paramSym), argTp) )) def mkParam(methodSym: Symbol, tp: Type = argTp) = @@ -2546,14 +2550,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper methodSym setInfo polyType(List(A1, B1), MethodType(paramSyms, B1.tpe)) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) - // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) + if (!paramSynthetic) methodBodyTyper.context.scope enter x // First, type without the default case; only the cases provided // by the user are typed. The LUB of these becomes `B`, the lower // bound of `B1`, which in turn is the result type of the default // case - val match0 = methodBodyTyper.typedMatch(selector, cases, mode, resTp) + val match0 = methodBodyTyper.typedMatch(selector(x), cases, mode, resTp) val matchResTp = match0.tpe B1 setInfo TypeBounds.lower(matchResTp) // patch info @@ -2627,11 +2630,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val paramSym = mkParam(methodSym) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - methodBodyTyper.context.scope enter paramSym + if (!paramSynthetic) methodBodyTyper.context.scope enter paramSym methodSym setInfo MethodType(List(paramSym), BooleanTpe) val defaultCase = mkDefaultCase(FALSE) - val match_ = methodBodyTyper.typedMatch(selector, casesTrue :+ defaultCase, mode, BooleanTpe) + val match_ = methodBodyTyper.typedMatch(selector(paramSym), casesTrue :+ defaultCase, mode, BooleanTpe) DefDef(methodSym, methodBodyTyper.virtualizedMatch(match_, mode, BooleanTpe)) } @@ -2645,10 +2648,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper methodSym setInfo MethodType(List(paramSym), AnyTpe) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) - // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - methodBodyTyper.context.scope enter paramSym + if (!paramSynthetic) methodBodyTyper.context.scope enter paramSym - val match_ = methodBodyTyper.typedMatch(selector, cases, mode, resTp) + val match_ = methodBodyTyper.typedMatch(selector(paramSym), cases, mode, resTp) val matchResTp = match_.tpe methodSym setInfo MethodType(List(paramSym), matchResTp) // patch info @@ -2920,7 +2922,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val p = fun.vparams.head if (p.tpt.tpe == null) p.tpt setType outerTyper.typedType(p.tpt).tpe - outerTyper.synthesizePartialFunction(p.name, p.pos, fun.body, mode, pt) + outerTyper.synthesizePartialFunction(p.name, p.pos, paramSynthetic = false, fun.body, mode, pt) // Use synthesizeSAMFunction to expand `(p1: T1, ..., pN: TN) => body` // to an instance of the corresponding anonymous subclass of `pt`. @@ -4207,7 +4209,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val cases = tree.cases if (selector == EmptyTree) { if (pt.typeSymbol == PartialFunctionClass) - synthesizePartialFunction(newTermName(context.unit.fresh.newName("x")), tree.pos, tree, mode, pt) + synthesizePartialFunction(newTermName(context.unit.fresh.newName("x")), tree.pos, paramSynthetic = true, tree, mode, pt) else { val arity = if (isFunctionType(pt)) pt.dealiasWiden.typeArgs.length - 1 else 1 val params = for (i <- List.range(0, arity)) yield diff --git a/test/files/neg/t8463.check b/test/files/neg/t8463.check new file mode 100644 index 0000000000..1a3eea2870 --- /dev/null +++ b/test/files/neg/t8463.check @@ -0,0 +1,10 @@ +t8463.scala:5: error: type mismatch; + found : Long + required: ?T[Long] +Note that implicit conversions are not applicable because they are ambiguous: + both method longWrapper in class LowPriorityImplicits of type (x: Long)scala.runtime.RichLong + and method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A] + are possible conversion functions from Long to ?T[Long] + insertCell(Foo(5)) + ^ +one error found diff --git a/test/files/neg/t8463.scala b/test/files/neg/t8463.scala new file mode 100644 index 0000000000..7c954fd834 --- /dev/null +++ b/test/files/neg/t8463.scala @@ -0,0 +1,38 @@ +object Test { + case class Foo[+T[_]](activity:T[Long]) + type Cell[T] = T + def insertCell(u:Foo[Cell]) = ??? + insertCell(Foo(5)) +} + +/* If SI-8230 is fixed, and `viewExists` is changed to no longer leak + ambiguity errors, you might expect the check file for this test to + change as folloes: + +@@ -1,18 +1,10 @@ +-t8463.scala:5: error: no type parameters for method apply: (activity: +- --- because --- +-argument expression's type is not compatible with formal parameter ty ++t8463.scala:5: error: type mismatch; + found : Long + required: ?T[Long] ++Note that implicit conversions are not applicable because they are am ++ both method longWrapper in class LowPriorityImplicits of type (x: Lo ++ and method ArrowAssoc in object Predef of type [A](self: A)ArrowAsso ++ are possible conversion functions from Long to ?T[Long] + insertCell(Foo(5)) +- ^ +-t8463.scala:5: error: type mismatch; +- found : Long(5L) +- required: T[Long] +- insertCell(Foo(5)) +- ^ +-t8463.scala:5: error: type mismatch; +- found : Test.Foo[T] +- required: Test.Foo[Test.Cell] +- insertCell(Foo(5)) +- ^ +-three errors found ++ ^ ++one error found +*/ diff --git a/test/files/pos/t8329.scala b/test/files/pos/t8329.scala new file mode 100644 index 0000000000..fcd5e50b37 --- /dev/null +++ b/test/files/pos/t8329.scala @@ -0,0 +1,29 @@ +object Test { + def pf(pf: PartialFunction[Any, Unit]) = () + def f1(pf: Function[Any, Unit]) = () + + class A1; class B1 + def test1(x: String, x1: String, default: String) = pf { + case _ if ( + x.isEmpty + && default.isEmpty // was binding to synthetic param + && x1.isEmpty // was binding to synthetic param + ) => + x.isEmpty + default.isEmpty // was binding to synthetic param + x1.isEmpty // was binding to synthetic param + new A1; new B1 + } + + def test2(x: String, x1: String, default: String) = f1 { + case _ if ( + x.isEmpty + && default.isEmpty + && x1.isEmpty + ) => + x.isEmpty + default.isEmpty + x1.isEmpty + new A1; new B1 + } +} |