From a4a892fb0196f2f66d86f9cfa508deabe7d2aaae Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Thu, 11 Dec 2014 12:57:32 +0100 Subject: SI-8841 report named arg / assignment ambiguity also in silent mode. For local definitions (eg. in a block that is an argument of a method call), the type completer may have a silent context. A CyclicReference is then not thrown but transformed into a NormalTypeError. When deciding if 'x = e' is an assignment or a named arg, we need to report cyclic references, but not other type errors. In the above case, the cyclic reference was not reported. Also makes sure that warnings are printed after typing argument expressions. --- test/files/neg/names-defaults-neg.check | 12 ++++++------ test/files/neg/t5044.check | 4 ++-- test/files/neg/t5091.check | 4 ++-- test/files/neg/t8463.check | 19 ++++++++++++++++++- test/files/neg/t8841.check | 9 +++++++++ test/files/neg/t8841.scala | 15 +++++++++++++++ 6 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 test/files/neg/t8841.check create mode 100644 test/files/neg/t8841.scala (limited to 'test/files/neg') diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index 20ddd55f1f..2db24b6f32 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -151,15 +151,15 @@ names-defaults-neg.scala:144: error: variable definition needs type because 'x' names-defaults-neg.scala:147: error: variable definition needs type because 'x' is used as a named argument in its body. object t6 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:147: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment -in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x. +names-defaults-neg.scala:147: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. +an explicit type is required for the definition mentioned in the error message above. object t6 { var x = t.f(x = 1) } ^ names-defaults-neg.scala:150: error: variable definition needs type because 'x' is used as a named argument in its body. class t9 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:150: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment -in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x. +names-defaults-neg.scala:150: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. +an explicit type is required for the definition mentioned in the error message above. class t9 { var x = t.f(x = 1) } ^ names-defaults-neg.scala:164: error: variable definition needs type because 'x' is used as a named argument in its body. @@ -174,8 +174,8 @@ names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both a m names-defaults-neg.scala:177: error: variable definition needs type because 'x' is used as a named argument in its body. class u15 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:177: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment -in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x. +names-defaults-neg.scala:177: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. +an explicit type is required for the definition mentioned in the error message above. class u15 { var x = u.f(x = 1) } ^ names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. diff --git a/test/files/neg/t5044.check b/test/files/neg/t5044.check index 197da2a4e8..dc3708123f 100644 --- a/test/files/neg/t5044.check +++ b/test/files/neg/t5044.check @@ -1,8 +1,8 @@ t5044.scala:7: error: recursive value a needs type val id = m(a) ^ -t5044.scala:6: warning: type-checking the invocation of method foo checks if the named argument expression 'id = ...' is a valid assignment -in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for id. +t5044.scala:6: warning: failed to determine if 'id = ...' is a named argument or an assignment expression. +an explicit type is required for the definition mentioned in the error message above. val a = foo(id = 1) ^ one warning found diff --git a/test/files/neg/t5091.check b/test/files/neg/t5091.check index abd24e3145..156f695f41 100644 --- a/test/files/neg/t5091.check +++ b/test/files/neg/t5091.check @@ -1,8 +1,8 @@ t5091.scala:8: error: recursive value xxx needs type val param = bar(xxx) ^ -t5091.scala:7: warning: type-checking the invocation of method foo checks if the named argument expression 'param = ...' is a valid assignment -in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for param. +t5091.scala:7: warning: failed to determine if 'param = ...' is a named argument or an assignment expression. +an explicit type is required for the definition mentioned in the error message above. val xxx = foo(param = null) ^ one warning found diff --git a/test/files/neg/t8463.check b/test/files/neg/t8463.check index 1a3eea2870..9aaacf8391 100644 --- a/test/files/neg/t8463.check +++ b/test/files/neg/t8463.check @@ -7,4 +7,21 @@ Note that implicit conversions are not applicable because they are ambiguous: are possible conversion functions from Long to ?T[Long] insertCell(Foo(5)) ^ -one error found +t8463.scala:5: error: no type parameters for method apply: (activity: T[Long])Test.Foo[T] in object Foo exist so that it can be applied to arguments (Long) + --- because --- +argument expression's type is not compatible with formal parameter type; + found : Long + required: ?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)) + ^ +four errors found diff --git a/test/files/neg/t8841.check b/test/files/neg/t8841.check new file mode 100644 index 0000000000..ad525dc3f8 --- /dev/null +++ b/test/files/neg/t8841.check @@ -0,0 +1,9 @@ +t8841.scala:13: error: recursive value c needs type + val ambiguousName = c.ambiguousName + ^ +t8841.scala:12: warning: failed to determine if 'ambiguousName = ...' is a named argument or an assignment expression. +an explicit type is required for the definition mentioned in the error message above. + val c = new Cell(ambiguousName = Some("bla")) + ^ +one warning found +one error found diff --git a/test/files/neg/t8841.scala b/test/files/neg/t8841.scala new file mode 100644 index 0000000000..80430d997e --- /dev/null +++ b/test/files/neg/t8841.scala @@ -0,0 +1,15 @@ +class Cell(val ambiguousName: Option[String]) + +class Test { + def wrap(f: Any): Nothing = ??? + + wrap { + // the namer for these two ValDefs is created when typing the argument expression + // of wrap. This happens to be in a silent context (tryTypedApply). Therefore, the + // cyclic reference will not be thrown, but transformed into a NormalTypeError by + // `silent`. This requires different handling in NamesDefaults. + + val c = new Cell(ambiguousName = Some("bla")) + val ambiguousName = c.ambiguousName + } +} -- cgit v1.2.3 From c30ed29f6cee9d4e0bd4a99c4be804ffcb20d281 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 19 Jan 2015 13:42:35 +1000 Subject: SI-9093 Fix value discarding / multiple param list crasher The type error stemming from missing argument list was being swallowed when the expected type was `Unit` and there were undetermined type parameters in the expression. This commit modifies `adapt` to avoid using `instantiateExpectingUnit` when the tree is typed with `MethodType`. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 +- test/files/neg/t9093.check | 6 ++++++ test/files/neg/t9093.scala | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/t9093.check create mode 100644 test/files/neg/t9093.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e6fa9a0142..9773028b76 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1177,7 +1177,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } def instantiatePossiblyExpectingUnit(tree: Tree, mode: Mode, pt: Type): Tree = { - if (mode.typingExprNotFun && pt.typeSymbol == UnitClass) + if (mode.typingExprNotFun && pt.typeSymbol == UnitClass && !tree.tpe.isInstanceOf[MethodType]) instantiateExpectingUnit(tree, mode) else instantiate(tree, mode, pt) diff --git a/test/files/neg/t9093.check b/test/files/neg/t9093.check new file mode 100644 index 0000000000..085a433f0b --- /dev/null +++ b/test/files/neg/t9093.check @@ -0,0 +1,6 @@ +t9093.scala:3: error: polymorphic expression cannot be instantiated to expected type; + found : [C](f: C)Null + required: Unit + val x: Unit = apply2(0)/*(0)*/ + ^ +one error found diff --git a/test/files/neg/t9093.scala b/test/files/neg/t9093.scala new file mode 100644 index 0000000000..d9922ad70e --- /dev/null +++ b/test/files/neg/t9093.scala @@ -0,0 +1,5 @@ +object Main { + def apply2[C](fa: Any)(f: C) = null + val x: Unit = apply2(0)/*(0)*/ +} + -- cgit v1.2.3 From 43818d4e5d8369387e7b315eafde01aae73acaa6 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 18 Dec 2014 00:47:00 -0800 Subject: SI-7623 Trailing sequence wildcard warning An -Xlint:stars-align warning for the case of patterns with at least one "fixed" component and a varargs component. Warn if the fixed patterns don't exactly align with the fixed value components, such that a sequence wildcard aligns exactly with the varargs component (either a T* parameter in a case class or a Seq[T] in an extractor result). This addresses the case of the xml.Elem extractor, which does not correspond to the Elem class constructor. One can be fooled into supplying an extra field for extraction. Vanilla extractors of type `Option[Seq[_]]` are unaffected by this flag. It's OK to ask for `case X(a, b, c)` in the expectation that three results are forthcoming. There is no semantic confusion over where the varargs begin. --- .../scala/tools/nsc/settings/Warnings.scala | 13 +++++--- .../transform/patmat/ScalacPatternExpanders.scala | 4 ++- test/files/neg/t7623.check | 21 ++++++++++++ test/files/neg/t7623.flags | 1 + test/files/neg/t7623.scala | 38 ++++++++++++++++++++++ 5 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 test/files/neg/t7623.check create mode 100644 test/files/neg/t7623.flags create mode 100644 test/files/neg/t7623.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index d174dc86c7..41ce0837cb 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -28,10 +28,11 @@ trait Warnings { val warnUnusedImport = BooleanSetting("-Ywarn-unused-import", "Warn when imports are unused.") // Experimental lint warnings that are turned off, but which could be turned on programmatically. - // These warnings are said to blind those who dare enable them. - // They are not activated by -Xlint and can't be enabled on the command line. - val warnValueOverrides = { // Currently turned off as experimental. Created using constructor (new BS), so not available on the command line. - val flag = new BooleanSetting("value-overrides", "Generated value class method overrides an implementation") + // They are not activated by -Xlint and can't be enabled on the command line because they are not + // created using the standard factory methods. + + val warnValueOverrides = { + val flag = new BooleanSetting("value-overrides", "Generated value class method overrides an implementation.") flag.value = false flag } @@ -53,10 +54,11 @@ trait Warnings { val TypeParameterShadow = LintWarning("type-parameter-shadow", "A local type parameter shadows a type already in scope.") val PolyImplicitOverload = LintWarning("poly-implicit-overload", "Parameterized overloaded implicit methods are not visible as view bounds.") val OptionImplicit = LintWarning("option-implicit", "Option.apply used implicit view.") - val DelayedInitSelect = LintWarning("delayedinit-select", "Selecting member of DelayedInit") + val DelayedInitSelect = LintWarning("delayedinit-select", "Selecting member of DelayedInit.") val ByNameRightAssociative = LintWarning("by-name-right-associative", "By-name parameter of right associative operator.") val PackageObjectClasses = LintWarning("package-object-classes", "Class or object defined in package object.") val UnsoundMatch = LintWarning("unsound-match", "Pattern match may not be typesafe.") + val StarsAlign = LintWarning("stars-align", "Pattern sequence wildcard must align with sequence component.") def allLintWarnings = values.toSeq.asInstanceOf[Seq[LintWarning]] } @@ -77,6 +79,7 @@ trait Warnings { def warnByNameRightAssociative = lint contains ByNameRightAssociative def warnPackageObjectClasses = lint contains PackageObjectClasses def warnUnsoundMatch = lint contains UnsoundMatch + def warnStarsAlign = lint contains StarsAlign // Lint warnings that are currently -Y, but deprecated in that usage @deprecated("Use warnAdaptedArgs", since="2.11.2") diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala index 8924394b72..2753baa51d 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala @@ -110,8 +110,10 @@ trait ScalacPatternExpanders { err("Star pattern must correspond with varargs or unapplySeq") else if (elementArity < 0) arityError("not enough") - else if (elementArity > 0 && !extractor.hasSeq) + else if (elementArity > 0 && !isSeq) arityError("too many") + else if (settings.warnStarsAlign && isSeq && productArity > 0 && (elementArity > 0 || !isStar)) + warn("A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*).") aligned } diff --git a/test/files/neg/t7623.check b/test/files/neg/t7623.check new file mode 100644 index 0000000000..db368dd369 --- /dev/null +++ b/test/files/neg/t7623.check @@ -0,0 +1,21 @@ +t7623.scala:19: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def f = "" match { case X(s) => } + ^ +t7623.scala:21: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def g = "" match { case X(s, t) => } + ^ +t7623.scala:23: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def h = "" match { case X(s, t, u @ _*) => } + ^ +t7623.scala:9: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def f = C("") match { case C(s) => } + ^ +t7623.scala:11: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def g = C("") match { case C(s, t) => } + ^ +t7623.scala:13: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def h = C("") match { case C(s, t, u @ _*) => } + ^ +error: No warnings can be incurred under -Xfatal-warnings. +6 warnings found +one error found diff --git a/test/files/neg/t7623.flags b/test/files/neg/t7623.flags new file mode 100644 index 0000000000..74c9e38323 --- /dev/null +++ b/test/files/neg/t7623.flags @@ -0,0 +1 @@ +-Xlint:stars-align -Xfatal-warnings diff --git a/test/files/neg/t7623.scala b/test/files/neg/t7623.scala new file mode 100644 index 0000000000..5c40f37bc1 --- /dev/null +++ b/test/files/neg/t7623.scala @@ -0,0 +1,38 @@ + + +case class C(s: String, xs: Int*) + +object X { def unapplySeq(a: Any): Option[(String, Seq[Int])] = Some("", List(1,2,3)) } + +// for case classes with varargs, avoid misaligned patterns +trait Ctest { + def f = C("") match { case C(s) => } + + def g = C("") match { case C(s, t) => } + + def h = C("") match { case C(s, t, u @ _*) => } + + def ok = C("") match { case C(s, u @ _*) => } +} +// for extractors that unapplySeq: Option[(Something, Seq[_])], avoid misaligned patterns +trait Xtest { + def f = "" match { case X(s) => } + + def g = "" match { case X(s, t) => } + + def h = "" match { case X(s, t, u @ _*) => } + + def ok = "" match { case X(s, u @ _*) => } +} +// for extractors that unapplySeq: Option[Seq[_]], anything goes +trait Rtest { + val r = "(a+)".r + + def f = "" match { case r(s) => } + + def g = "" match { case r(s, t) => } + + def h = "" match { case r(s, t, u @ _*) => } + + def whatever = "" match { case r(u @ _*) => } +} -- cgit v1.2.3 From 1970a8315ed3b2ff8877dfef2afcee936d59871b Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 15 Dec 2014 16:21:26 +1000 Subject: SI-9041 Avoid unreported type error with overloading, implicits If `qual.foo(args)` fails to typecheck, we fall back to `ImplicitView(qual).foo(args)`. However, if the original type error stemmed from an overload ambiguity, the tree `Select(qual, 'foo')` holds onto an error symbol. The fall back attempt just returns an `Apply` tree containing the erroneous qualifier, as it does not want to issue cascading type errors. This commit replaces the error symbol with a `NoSymbol`, which triggers the second try typechecking to perform overload resolution again. A more principled fix might be to more pervasively duplicate trees before mutating their types and symbols, that this is beyond the scope of this bug fix. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 10 ++++++++++ test/files/neg/t9041.check | 4 ++++ test/files/neg/t9041.scala | 17 +++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 test/files/neg/t9041.check create mode 100644 test/files/neg/t9041.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e6fa9a0142..fb47f45bc7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -825,6 +825,16 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } orElse { _ => val resetTree = resetAttrs(original) + resetTree match { + case treeInfo.Applied(fun, targs, args) => + if (fun.symbol != null && fun.symbol.isError) + // SI-9041 Without this, we leak error symbols past the typer! + // because the fallback typechecking notices the error-symbol, + // refuses to re-attempt typechecking, and presumes that someone + // else was responsible for issuing the related type error! + fun.setSymbol(NoSymbol) + case _ => + } debuglog(s"fallback on implicits: ${tree}/$resetTree") val tree1 = typed(resetTree, mode) // Q: `typed` already calls `pluginsTyped` and `adapt`. the only difference here is that diff --git a/test/files/neg/t9041.check b/test/files/neg/t9041.check new file mode 100644 index 0000000000..669e9434e0 --- /dev/null +++ b/test/files/neg/t9041.check @@ -0,0 +1,4 @@ +t9041.scala:11: error: could not find implicit value for parameter cellSetter: CellSetter[scala.math.BigDecimal] + def setCell(cell: Cell, data: math.BigDecimal) { cell.setCellValue(data) } + ^ +one error found diff --git a/test/files/neg/t9041.scala b/test/files/neg/t9041.scala new file mode 100644 index 0000000000..2bdef0d3ae --- /dev/null +++ b/test/files/neg/t9041.scala @@ -0,0 +1,17 @@ +// False negative test, requires overloading in Cell. + +trait Cell { def setCellValue(i: Int) = () ; def setCellValue(d: Double) = () } + +trait Nope { + def f = { + trait CellSetter[A] { + def setCell(cell: Cell, data: A): Unit + } + implicit val bigDecimalCellSetter = new CellSetter[math.BigDecimal]() { + def setCell(cell: Cell, data: math.BigDecimal) { cell.setCellValue(data) } + } + implicit class RichCell(cell: Cell) { + def setCellValue[A](data: A)(implicit cellSetter: CellSetter[A]) = cellSetter.setCell(cell, data) + } + } +} -- cgit v1.2.3