| 604 | } // namespace |
| 605 | |
| 606 | Status OpDefCompatible(const OpDef& old_op, const OpDef& new_op) { |
| 607 | #define VALIDATE(CONDITION, ...) \ |
| 608 | if (!(CONDITION)) { \ |
| 609 | return errors::InvalidArgument("Incompatible Op change: ", __VA_ARGS__, \ |
| 610 | "; old: ", SummarizeOpDef(old_op), \ |
| 611 | "; new: ", SummarizeOpDef(new_op)); \ |
| 612 | } |
| 613 | |
| 614 | VALIDATE(old_op.name() == new_op.name(), "Name mismatch"); |
| 615 | |
| 616 | AttrMap new_attrs, old_attrs; |
| 617 | FillAttrMap(old_op, &old_attrs); |
| 618 | FillAttrMap(new_op, &new_attrs); |
| 619 | for (const auto& old_attr : old_op.attr()) { |
| 620 | const OpDef::AttrDef* new_attr = |
| 621 | gtl::FindPtrOrNull(new_attrs, old_attr.name()); |
| 622 | VALIDATE(new_attr != nullptr, "Attr '", old_attr.name(), "' removed"); |
| 623 | VALIDATE(old_attr.type() == new_attr->type(), "Attr '", old_attr.name(), |
| 624 | "' changed type '", old_attr.type(), "' -> '", new_attr->type(), |
| 625 | "'"); |
| 626 | VALIDATE(!MoreRestrictive(old_attr, *new_attr), "Attr '", old_attr.name(), |
| 627 | "' has a stricter set of allowed values; from ", |
| 628 | AllowedStr(old_attr), " to ", AllowedStr(*new_attr)); |
| 629 | VALIDATE(!HigherMinimum(old_attr, *new_attr), "Attr '", old_attr.name(), |
| 630 | "' has a higher minimum; from ", MinStr(old_attr), " to ", |
| 631 | MinStr(*new_attr)); |
| 632 | } |
| 633 | |
| 634 | for (const auto& new_attr : new_op.attr()) { |
| 635 | const OpDef::AttrDef* old_attr = |
| 636 | gtl::FindPtrOrNull(old_attrs, new_attr.name()); |
| 637 | VALIDATE(old_attr != nullptr || new_attr.has_default_value(), "Attr '", |
| 638 | new_attr.name(), "' added without default"); |
| 639 | } |
| 640 | |
| 641 | std::vector<bool> old_in_ref, new_in_ref, old_out_ref, new_out_ref; |
| 642 | const string old_in_sig = ComputeArgSignature( |
| 643 | old_op.input_arg(), old_attrs, new_attrs, &old_in_ref, false /* names */); |
| 644 | const string new_in_sig = ComputeArgSignature( |
| 645 | new_op.input_arg(), old_attrs, new_attrs, &new_in_ref, false /* names */); |
| 646 | VALIDATE(old_in_sig == new_in_sig, "Input signature mismatch '", old_in_sig, |
| 647 | "' vs. '", new_in_sig, "'"); |
| 648 | VALIDATE(old_in_ref.size() == new_in_ref.size(), // Should not happen |
| 649 | "Unexpected change in input ref lists."); |
| 650 | for (int i = 0; i < old_in_ref.size(); ++i) { |
| 651 | // Allowed to remove "ref" from an input (or leave it unchanged). |
| 652 | VALIDATE(old_in_ref[i] || !new_in_ref[i], "Input ", i, |
| 653 | " changed from non-ref to ref"); |
| 654 | } |
| 655 | |
| 656 | const string old_out_sig = |
| 657 | ComputeArgSignature(old_op.output_arg(), old_attrs, new_attrs, |
| 658 | &old_out_ref, true /* names */); |
| 659 | const string new_out_sig = |
| 660 | ComputeArgSignature(new_op.output_arg(), old_attrs, new_attrs, |
| 661 | &new_out_ref, true /* names */); |
| 662 | VALIDATE(old_out_sig == new_out_sig, "Output signature mismatch '", |
| 663 | old_out_sig, "' vs. '", new_out_sig, "'"); |