Context
The parameter dtype coercion machinery of #828 and #829 rewrites a parameter's reported dtype to the one its consumers impose eagerly. The declared set is currently exactly the operator-spelled elementwise operations: ElementWiseOperation implements OperandDTypeCoercing, and the walk reaches it through SSABinaryOpInstruction uses. Every other consumer that takes a second operand falls into the unaccounted-consumer guard, which declines the whole parameter to its fed dtype by design; the guard's own comment names tf.matmul and the tensordot/einsum shapes as the known coverage debt.
Witness
import numpy as np
import tensorflow as tf
M = tf.Variable(tf.zeros([2, 2])) # float32
def matmuled(x):
return tf.reduce_sum(tf.matmul(M, x))
matmuled(np.array([[1.5, 2.5], [3.5, 4.5]])) # float64 fed; converts at the matmul
Eagerly, tf.matmul converts the non-tensor operand to its tensor partner's dtype, so the body computes with float32. The analysis reports the fed float64: the tf.matmul consumer declares no coercion, the parameter is declined by the unaccounted guard, and the fed dtype is kept. A client writing an input signature from the reported dtype names a dtype no op in the body computes with, and the resulting declaration breaks the function that ran fine undecorated (the consumer-side report is ponder-lab/Hybridize-Functions-Refactoring#907).
Expected
The call-form coercing families declared under the same eager criterion the operator forms use: an op that converts a non-tensor operand through convert_to_tensor against its tensor partner's dtype imposes that dtype on a parameter operand. The tensor-tensor mismatch case raises eagerly and so is excluded by the premise that the undecorated program ran, exactly as the OperandDTypeCoercing contract already states for chained consumers.
Scope
Beyond tf.matmul, tf.tensordot, and tf.einsum, the function-form spellings of the already-declared elementwise operations sit in the same undeclared position: the spelling tf.multiply(V, x) is a call, not a binary op instruction, so only the operator spelling V * x is covered today. The same family includes tf.add, tf.subtract, tf.divide, tf.pow, tf.maximum, tf.minimum, and tf.squared_difference. The unaccounted-consumer guard keeps all of these safe (declined to the fed dtype) rather than wrong, so this is a coverage gap, not a soundness bug.
Context
The parameter dtype coercion machinery of #828 and #829 rewrites a parameter's reported dtype to the one its consumers impose eagerly. The declared set is currently exactly the operator-spelled elementwise operations:
ElementWiseOperationimplementsOperandDTypeCoercing, and the walk reaches it throughSSABinaryOpInstructionuses. Every other consumer that takes a second operand falls into the unaccounted-consumer guard, which declines the whole parameter to its fed dtype by design; the guard's own comment namestf.matmuland thetensordot/einsumshapes as the known coverage debt.Witness
Eagerly,
tf.matmulconverts the non-tensor operand to its tensor partner's dtype, so the body computes withfloat32. The analysis reports the fedfloat64: thetf.matmulconsumer declares no coercion, the parameter is declined by the unaccounted guard, and the fed dtype is kept. A client writing an input signature from the reported dtype names a dtype no op in the body computes with, and the resulting declaration breaks the function that ran fine undecorated (the consumer-side report is ponder-lab/Hybridize-Functions-Refactoring#907).Expected
The call-form coercing families declared under the same eager criterion the operator forms use: an op that converts a non-tensor operand through
convert_to_tensoragainst its tensor partner's dtype imposes that dtype on a parameter operand. The tensor-tensor mismatch case raises eagerly and so is excluded by the premise that the undecorated program ran, exactly as theOperandDTypeCoercingcontract already states for chained consumers.Scope
Beyond
tf.matmul,tf.tensordot, andtf.einsum, the function-form spellings of the already-declared elementwise operations sit in the same undeclared position: the spellingtf.multiply(V, x)is a call, not a binary op instruction, so only the operator spellingV * xis covered today. The same family includestf.add,tf.subtract,tf.divide,tf.pow,tf.maximum,tf.minimum, andtf.squared_difference. The unaccounted-consumer guard keeps all of these safe (declined to the fed dtype) rather than wrong, so this is a coverage gap, not a soundness bug.