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.
This commit is contained in:
whitequark 2016-11-21 13:08:03 +00:00
parent 3485c83429
commit 35f4449ef2
2 changed files with 25 additions and 20 deletions

View File

@ -1043,22 +1043,10 @@ class Inferencer(algorithm.Visitor):
if coerced: if coerced:
return_type, target_type, value_type = coerced return_type, target_type, value_type = coerced
try: if isinstance(node.value, asttyped.CoerceT):
node.target.type.unify(target_type) orig_value_type = node.value.value.type
except types.UnificationError as e: else:
printer = types.TypePrinter() orig_value_type = node.value.type
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
try: try:
node.target.type.unify(return_type) node.target.type.unify(return_type)
@ -1066,17 +1054,34 @@ class Inferencer(algorithm.Visitor):
printer = types.TypePrinter() printer = types.TypePrinter()
note = diagnostic.Diagnostic("note", note = diagnostic.Diagnostic("note",
"expression of type {typec}", "expression of type {typec}",
{"typec": printer.name(node.value.type)}, {"typec": printer.name(orig_value_type)},
node.value.loc) node.value.loc)
diag = diagnostic.Diagnostic("error", diag = diagnostic.Diagnostic("error",
"the result of this operation has type {typeb}, " "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), {"typea": printer.name(node.target.type),
"typeb": printer.name(return_type)}, "typeb": printer.name(return_type)},
node.op.loc, [node.target.loc], [note]) node.op.loc, [node.target.loc], [note])
self.engine.process(diag) self.engine.process(diag)
return 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) node.value = self._coerce_one(value_type, node.value, other_node=node.target)
def visit_ForT(self, node): def visit_ForT(self, node):

View File

@ -28,10 +28,10 @@
# CHECK-L: ${LINE:+1}: error: cannot coerce list(elt='a) to a numeric type # CHECK-L: ${LINE:+1}: error: cannot coerce list(elt='a) to a numeric type
[] - 1.0 [] - 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 # CHECK-L: ${LINE:+1}: note: expression of type float
a = 1; a += 1.0 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,) # CHECK-L: ${LINE:+1}: note: expression of type (float,)
b = (1,); b += (1.0,) b = (1,); b += (1.0,)