From 55c6ad4f8a191e691efdbee0a1bbddc4efb66f35 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 28 Jun 2016 16:20:10 -0400 Subject: SI-9834 Improve error on failed op= If rewriting `x += y` fails to typecheck, emit error messages for both the original tree and the assignment. If rewrite is not attempted because `x` is a val, then say so. The error message at `tree.pos` is updated with the additional advice. SI-8763 Crash in update conversion When there are already errors, don't attempt mechanical rewrites. --- .../scala/tools/nsc/typechecker/Typers.scala | 59 ++++++++++++++++------ 1 file changed, 43 insertions(+), 16 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 508d205424..cddfece32d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4501,20 +4501,54 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val appStart = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null val opeqStart = if (Statistics.canEnable) Statistics.startTimer(failedOpEqNanos) else null - def onError(reportError: => Tree): Tree = fun match { - case Select(qual, name) if !mode.inPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) => + def isConversionCandidate(qual: Tree, name: Name): Boolean = + !mode.inPatternMode && nme.isOpAssignmentName(TermName(name.decode)) && !qual.exists(_.isErroneous) + + def reportError(error: SilentTypeError): Tree = { + error.reportableErrors foreach context.issue + error.warnings foreach { case (p, m) => context.warning(p, m) } + args foreach (arg => typed(arg, mode, ErrorType)) + setError(tree) + } + def advice1(errors: List[AbsTypeError], err: SilentTypeError): List[AbsTypeError] = + errors.map { e => + if (e.errPos == tree.pos) { + val header = f"${e.errMsg}%n Expression does not convert to assignment because:%n " + NormalTypeError(tree, err.errors.flatMap(_.errMsg.lines.toList).mkString(header, f"%n ", "")) + } else e + } + def advice2(errors: List[AbsTypeError]): List[AbsTypeError] = + errors.map { e => + if (e.errPos == tree.pos) { + val msg = f"${e.errMsg}%n Expression does not convert to assignment because receiver is not assignable." + NormalTypeError(tree, msg) + } else e + } + def onError(error: SilentTypeError): Tree = fun match { + case Select(qual, name) if isConversionCandidate(qual, name) => val qual1 = typedQualifier(qual) if (treeInfo.isVariableOrGetter(qual1)) { if (Statistics.canEnable) Statistics.stopTimer(failedOpEqNanos, opeqStart) - convertToAssignment(fun, qual1, name, args) + val erred = qual1.isErroneous || args.exists(_.isErroneous) + if (erred) reportError(error) else { + val convo = convertToAssignment(fun, qual1, name, args) + silent(op = _.typed1(convo, mode, pt)) match { + case SilentResultValue(t) => t + case err: SilentTypeError => reportError(SilentTypeError(advice1(error.errors, err), error.warnings)) + } + } } else { if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart) - reportError + val Apply(Select(qual2, _), args2) = tree + val erred = qual2.isErroneous || args2.exists(_.isErroneous) + reportError { + if (erred) error else SilentTypeError(advice2(error.errors), error.warnings) + } } case _ => if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart) - reportError + reportError(error) } val silentResult = silent( op = _.typed(fun, mode.forFunMode, funpt), @@ -4539,13 +4573,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper tryTypedApply(fun2, args) else doTypedApply(tree, fun2, args, mode, pt) - 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) - }) + case err: SilentTypeError => onError(err) } } @@ -4588,7 +4616,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper Select(vble.duplicate, prefix) setPos fun.pos.focus, args) setPos tree.pos.makeTransparent ) setPos tree.pos - def mkUpdate(table: Tree, indices: List[Tree]) = { + def mkUpdate(table: Tree, indices: List[Tree]) = gen.evalOnceAll(table :: indices, context.owner, context.unit) { case tab :: is => def mkCall(name: Name, extraArgs: Tree*) = ( @@ -4603,9 +4631,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper ) case _ => EmptyTree } - } - val tree1 = qual match { + val assignment = qual match { case Ident(_) => mkAssign(qual) @@ -4621,7 +4648,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case _ => UnexpectedTreeAssignmentConversionError(qual) } } - typed1(tree1, mode, pt) + assignment } def typedSuper(tree: Super) = { -- cgit v1.2.3