diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2014-12-11 12:57:32 +0100 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2014-12-12 08:18:30 +0100 |
commit | a4a892fb0196f2f66d86f9cfa508deabe7d2aaae (patch) | |
tree | f86405ae87fe1ebac37f92bef3a01d94d8075c91 /src | |
parent | 36b1014ac63205a38e73ae18a05ac6f956c3410f (diff) | |
download | scala-a4a892fb0196f2f66d86f9cfa508deabe7d2aaae.tar.gz scala-a4a892fb0196f2f66d86f9cfa508deabe7d2aaae.tar.bz2 scala-a4a892fb0196f2f66d86f9cfa508deabe7d2aaae.zip |
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.
Diffstat (limited to 'src')
3 files changed, 43 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 866ca37303..6868f06606 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -45,6 +45,14 @@ trait ContextErrors { case class NormalTypeError(underlyingTree: Tree, errMsg: String) extends TreeTypeError + /** + * Marks a TypeError that was constructed from a CyclicReference (under silent). + * This is used for named arguments, where we need to know if an assignment expression + * failed with a cyclic reference or some other type error. + */ + class NormalTypeErrorFromCyclicReference(underlyingTree: Tree, errMsg: String) + extends NormalTypeError(underlyingTree, errMsg) + case class AccessTypeError(underlyingTree: Tree, errMsg: String) extends TreeTypeError @@ -1087,8 +1095,9 @@ trait ContextErrors { // hence we (together with reportTypeError in TypeDiagnostics) make sure that this CyclicReference // evades all the handlers on its way and successfully reaches `isCyclicOrErroneous` in Implicits throw ex - case CyclicReference(sym, info: TypeCompleter) => - issueNormalTypeError(tree, typer.cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) + case c @ CyclicReference(sym, info: TypeCompleter) => + val error = new NormalTypeErrorFromCyclicReference(tree, typer.cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage) + issueTypeError(error) case _ => contextNamerErrorGen.issue(TypeErrorWithUnderlyingTree(tree, ex)) } @@ -1275,8 +1284,8 @@ trait ContextErrors { } def WarnAfterNonSilentRecursiveInference(param: Symbol, arg: Tree)(implicit context: Context) = { - val note = "type-checking the invocation of "+ param.owner +" checks if the named argument expression '"+ param.name + " = ...' is a valid assignment\n"+ - "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.name +"." + val note = "failed to determine if '"+ param.name + " = ...' is a named argument or an assignment expression.\n"+ + "an explicit type is required for the definition mentioned in the error message above." context.warning(arg.pos, note) } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index b6387fd56b..4f943fcd28 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -521,8 +521,22 @@ trait NamesDefaults { self: Analyzer => WarnAfterNonSilentRecursiveInference(param, arg)(context) res } match { - case SilentResultValue(t) => !t.isErroneous // #4041 - case _ => false + case SilentResultValue(t) => + !t.isErroneous // #4041 + case SilentTypeError(e: NormalTypeErrorFromCyclicReference) => + // If we end up here, the CyclicReference was reported in a silent context. This can + // happen for local definitions, when the completer for a definition is created during + // type checking in silent mode. ContextErrors.TypeSigError catches that cyclic reference + // and transforms it into a NormalTypeErrorFromCyclicReference. + // The cycle needs to be reported, because the program cannot be typed: we don't know + // if we have an assignment or a named arg. + context.issue(e) + // 'err = true' is required because we're in a silent context + WarnAfterNonSilentRecursiveInference(param, arg)(context) + false + case _ => + // We got a type error, so it cannot be an assignment (it doesn't type check as one). + false } catch { // `silent` only catches and returns TypeErrors which are not diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index aaa75b5ee1..22cf8c6808 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -76,7 +76,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case s : SilentTypeError => f(s.reportableErrors) } } - class SilentTypeError private(val errors: List[AbsTypeError]) extends SilentResult[Nothing] { + class SilentTypeError private(val errors: List[AbsTypeError], val warnings: List[(Position, String)]) extends SilentResult[Nothing] { override def isEmpty = true def err: AbsTypeError = errors.head def reportableErrors = errors match { @@ -87,10 +87,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } } object SilentTypeError { - def apply(errors: AbsTypeError*): SilentTypeError = new SilentTypeError(errors.toList) + def apply(errors: AbsTypeError*): SilentTypeError = apply(errors.toList, Nil) + def apply(errors: List[AbsTypeError], warnings: List[(Position, String)]): SilentTypeError = new SilentTypeError(errors, warnings) + // todo: this extracts only one error, should be a separate extractor. def unapply(error: SilentTypeError): Option[AbsTypeError] = error.errors.headOption } + // todo: should include reporter warnings in SilentResultValue. + // e.g. tryTypedApply could print warnings on arguments when the typing succeeds. case class SilentResultValue[+T](value: T) extends SilentResult[T] { override def isEmpty = false } def newTyper(context: Context): Typer = new NormalTyper(context) @@ -661,7 +665,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper @inline def wrapResult(reporter: ContextReporter, result: T) = if (reporter.hasErrors) { stopStats() - SilentTypeError(reporter.errors: _*) + SilentTypeError(reporter.errors.toList, reporter.warnings.toList) } else SilentResultValue(result) try { @@ -4401,7 +4405,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def tryTypedApply(fun: Tree, args: List[Tree]): Tree = { val start = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null - def onError(typeErrors: Seq[AbsTypeError]): Tree = { + def onError(typeErrors: Seq[AbsTypeError], warnings: Seq[(Position, String)]): Tree = { if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, start) // If the problem is with raw types, copnvert to existentials and try again. @@ -4449,10 +4453,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } } typeErrors foreach context.issue + warnings foreach { case (p, m) => context.warning(p, m) } setError(treeCopy.Apply(tree, fun, args)) } - silent(_.doTypedApply(tree, fun, args, mode, pt)) orElse onError + silent(_.doTypedApply(tree, fun, args, mode, pt)) match { + case SilentResultValue(value) => value + case e: SilentTypeError => onError(e.errors, e.warnings) + } } def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = { @@ -4503,6 +4511,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case err: SilentTypeError => onError({ err.reportableErrors foreach context.issue + err.warnings foreach { case (p, m) => context.warning(p, m) } args foreach (arg => typed(arg, mode, ErrorType)) setError(tree) }) |