From fd1d77767e234586dce5188ce7fff79c53e47ecd Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 13:08:03 +0000 Subject: [PATCH] inferencer: significantly improve the op-assignment diagnostic. Before this commit, it displayed incorrect output if an error appeared on 2nd run and beyond, and displayed messages for trying to do "num32 -= num64" that made very little sense. --- artiq/compiler/transforms/inferencer.py | 41 +++++++++++++---------- artiq/test/lit/inferencer/error_coerce.py | 4 +-- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 920343b44..3a1dbe32f 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -1049,22 +1049,10 @@ class Inferencer(algorithm.Visitor): if coerced: return_type, target_type, value_type = coerced - try: - node.target.type.unify(target_type) - except types.UnificationError as e: - printer = types.TypePrinter() - note = diagnostic.Diagnostic("note", - "expression of type {typec}", - {"typec": printer.name(node.value.type)}, - node.value.loc) - diag = diagnostic.Diagnostic("error", - "expression of type {typea} has to be coerced to {typeb}, " - "which makes assignment invalid", - {"typea": printer.name(node.target.type), - "typeb": printer.name(target_type)}, - node.op.loc, [node.target.loc], [note]) - self.engine.process(diag) - return + if isinstance(node.value, asttyped.CoerceT): + orig_value_type = node.value.value.type + else: + orig_value_type = node.value.type try: node.target.type.unify(return_type) @@ -1072,17 +1060,34 @@ class Inferencer(algorithm.Visitor): printer = types.TypePrinter() note = diagnostic.Diagnostic("note", "expression of type {typec}", - {"typec": printer.name(node.value.type)}, + {"typec": printer.name(orig_value_type)}, node.value.loc) diag = diagnostic.Diagnostic("error", "the result of this operation has type {typeb}, " - "which makes assignment to a slot of type {typea} invalid", + "which cannot be assigned to a left-hand side of type {typea}", {"typea": printer.name(node.target.type), "typeb": printer.name(return_type)}, node.op.loc, [node.target.loc], [note]) self.engine.process(diag) return + try: + node.target.type.unify(target_type) + except types.UnificationError as e: + printer = types.TypePrinter() + note = diagnostic.Diagnostic("note", + "expression of type {typec}", + {"typec": printer.name(orig_value_type)}, + node.value.loc) + diag = diagnostic.Diagnostic("error", + "this operation requires the left-hand side of type {typea} " + "to be coerced to {typeb}, which cannot be done", + {"typea": printer.name(node.target.type), + "typeb": printer.name(target_type)}, + node.op.loc, [node.target.loc], [note]) + self.engine.process(diag) + return + node.value = self._coerce_one(value_type, node.value, other_node=node.target) def visit_ForT(self, node): diff --git a/artiq/test/lit/inferencer/error_coerce.py b/artiq/test/lit/inferencer/error_coerce.py index 8afb83e6b..c4f732e7e 100644 --- a/artiq/test/lit/inferencer/error_coerce.py +++ b/artiq/test/lit/inferencer/error_coerce.py @@ -28,10 +28,10 @@ # CHECK-L: ${LINE:+1}: error: cannot coerce list(elt='a) to a numeric type [] - 1.0 -# CHECK-L: ${LINE:+2}: error: expression of type numpy.int? has to be coerced to float, which makes assignment invalid +# CHECK-L: ${LINE:+2}: error: the result of this operation has type float, which cannot be assigned to a left-hand side of type numpy.int? # CHECK-L: ${LINE:+1}: note: expression of type float a = 1; a += 1.0 -# CHECK-L: ${LINE:+2}: error: the result of this operation has type (numpy.int?, float), which makes assignment to a slot of type (numpy.int?,) invalid +# CHECK-L: ${LINE:+2}: error: the result of this operation has type (numpy.int?, float), which cannot be assigned to a left-hand side of type (numpy.int?,) # CHECK-L: ${LINE:+1}: note: expression of type (float,) b = (1,); b += (1.0,)